Add clTerminateContextKHR in testsuite
[ocl-icd] / icd_generator.rb
1 =begin
2 Copyright (c) 2012, Brice Videau <brice.videau@imag.fr>
3 Copyright (c) 2012, Vincent Danjean <Vincent.Danjean@ens-lyon.org>
4 All rights reserved.
5       
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8     
9 1. Redistributions of source code must retain the above copyright notice, this
10    list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright notice,
12    this list of conditions and the following disclaimer in the documentation
13    and/or other materials provided with the distribution.
14         
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 =end
26
27 require 'yaml'
28
29 module IcdGenerator
30   $api_entries = {}
31   $api_entries_array = []
32   $cl_objects = ["platform_id", "device_id", "context", "command_queue", "mem", "program", "kernel", "event", "sampler"]
33   $known_entries= { 1 => "clGetPlatformInfo", 0 => "clGetPlatformIDs" }
34   # do not call these functions when trying to discover the mapping
35   $forbidden_funcs = ["clGetExtensionFunctionAddress", "clGetPlatformIDs",
36     "clGetPlatformInfo", "clGetGLContextInfoKHR", "clUnloadCompiler"]
37   $windows_funcs = ["clGetDeviceIDsFromD3D10KHR", "clCreateFromD3D10BufferKHR",
38     "clCreateFromD3D10Texture2DKHR", "clCreateFromD3D10Texture3DKHR",
39     "clEnqueueAcquireD3D10ObjectsKHR", "clEnqueueReleaseD3D10ObjectsKHR",
40     "clGetDeviceIDsFromD3D11KHR", "clCreateFromD3D11BufferKHR",
41     "clCreateFromD3D11Texture2DKHR", "clCreateFromD3D11Texture3DKHR",
42     "clEnqueueAcquireD3D11ObjectsKHR", "clEnqueueReleaseD3D11ObjectsKHR",
43     "clGetDeviceIDsFromDX9MediaAdapterKHR", "clCreateFromDX9MediaSurfaceKHR",
44     "clEnqueueAcquireDX9MediaSurfacesKHR", "clEnqueueReleaseDX9MediaSurfacesKHR"]
45   # do not create weak functions for these ones in the discovering program
46   $noweak_funcs = ["clGetExtensionFunctionAddress", "clGetPlatformIDs",
47     "clGetPlatformInfo", "clGetGLContextInfoKHR", "clUnloadCompiler",
48     "clCreateContext", "clCreateContextFromType", "clWaitForEvents"]
49   # functions written specifically in the loader
50   $specific_loader_funcs = ["clGetExtensionFunctionAddress","clGetPlatformIDs",
51                          "clGetGLContextInfoKHR", "clUnloadCompiler",
52     "clCreateContext", "clCreateContextFromType", "clWaitForEvents"]
53   $header_files = ["/usr/include/CL/cl.h", "/usr/include/CL/cl_gl.h",
54     "/usr/include/CL/cl_ext.h", "/usr/include/CL/cl_gl_ext.h"]
55   $windows_header_files = ["/usr/include/CL/cl_dx9_media_sharing.h", "/usr/include/CL/cl_d3d11.h", "/usr/include/CL/cl_d3d10.h"]
56   $versions_entries = []
57   $buff=20
58   $license = <<EOF
59 Copyright (c) 2012, Brice Videau <brice.videau@imag.fr>
60 Copyright (c) 2012, Vincent Danjean <Vincent.Danjean@ens-lyon.org>
61 All rights reserved.
62       
63 Redistribution and use in source and binary forms, with or without
64 modification, are permitted provided that the following conditions are met:
65     
66 1. Redistributions of source code must retain the above copyright notice, this
67    list of conditions and the following disclaimer.
68 2. Redistributions in binary form must reproduce the above copyright notice,
69    this list of conditions and the following disclaimer in the documentation
70    and/or other materials provided with the distribution.
71         
72 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
73 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
74 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
75 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
76 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
77 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
78 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
79 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
80 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
81 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
82
83 Do not edit this file. It is automatically generated.
84 EOF
85
86   def self.parse_headers
87     api_entries = []
88     $header_files.each{ |fname|
89       f = File::open(fname)
90       doc = f.read
91       api_entries += doc.scan(/CL_API_ENTRY.*?;/m)
92       f.close
93     }
94     api_entries.each{ |entry|
95 #      puts entry
96       begin 
97         entry_name = entry.match(/CL_API_CALL(.*?)\(/m)[1].strip
98         next if entry_name.match('\*')
99         next if entry_name.match("INTEL")
100         next if entry_name.match("APPLE")
101         $api_entries[entry_name] = entry
102        
103       rescue
104         entry_name = entry.match(/(\S*?)\(/m)[1].strip
105         next if entry_name.match('\*')
106         next if entry_name.match("INTEL")
107         next if entry_name.match("APPLE")
108         $api_entries[entry_name] = entry
109       end
110     }
111 #    $api_entries.each{ |key, value|
112 #      puts "#{key}: #{value}"
113 #    }
114   end
115
116   def self.include_headers
117     headers =""
118     $header_files.each { |h|
119       if h.match('^/usr/include/') then
120         headers += "#include <#{h[13..-1]}>\n"
121       else
122         headers += "#include \"#{h}\"\n"
123       end
124     }
125     return headers
126   end
127
128   def self.generate_ocl_icd_header
129     ocl_icd_header = "/**\n#{$license}\n*/\n\n"
130     ocl_icd_header += "#pragma GCC diagnostic push\n"
131     ocl_icd_header += "#  pragma GCC diagnostic ignored \"-Wcpp\"\n"
132     ocl_icd_header += "#  define CL_USE_DEPRECATED_OPENCL_1_0_APIS\n"
133     ocl_icd_header += "#  define CL_USE_DEPRECATED_OPENCL_1_1_APIS\n"
134     ocl_icd_header += "#  include <CL/opencl.h>\n"
135     ocl_icd_header += self.include_headers
136     ocl_icd_header += "#pragma GCC diagnostic pop\n"
137     ocl_icd_header += <<EOF
138
139 #define OCL_ICD_API_VERSION     1
140 #define OCL_ICD_IDENTIFIED_FUNCTIONS    #{$known_entries.count}
141
142 struct _cl_icd_dispatch {
143 EOF
144     $api_entries_array.each { |entry|
145       ocl_icd_header += entry.gsub("\r","").
146         sub(/CL_API_CALL\n?(.*?)\(/m,'(CL_API_CALL*\1)('+"\n  ").
147         gsub(/\) (CL_API_SUFFIX__VERSION)/m,"\n) \\1").gsub(/\s*$/,'').
148         gsub(/^[\t ]+/,"    ").gsub(/^([^\t ])/, '  \1') + "\n\n"
149     }
150     ocl_icd_header += "};\n\n"
151     return ocl_icd_header
152   end
153
154   def self.generate_ocl_icd_loader_header
155     ocl_icd_header = "/**\n#{$license}\n*/\n\n"
156     ocl_icd_header += "#include \"ocl_icd.h\"\n\n"
157     ocl_icd_header += <<EOF
158
159 struct func_desc {
160   const char* name;
161   void(*const addr)(void);
162 };
163
164 extern const struct func_desc function_description[];
165
166 EOF
167     ocl_icd_header += "extern struct _cl_icd_dispatch master_dispatch;\n"
168     $cl_objects.each { |o|
169       ocl_icd_header += "struct _cl_#{o} { struct _cl_icd_dispatch *dispatch; };\n"
170     }
171     return ocl_icd_header
172   end
173
174   def self.generate_ocl_icd_bindings_source
175     ocl_icd_bindings_source = "/**\n#{$license}\n*/\n"
176     ocl_icd_bindings_source += "#include \"ocl_icd.h\"\n"
177     ocl_icd_bindings_source += "struct _cl_icd_dispatch master_dispatch = {\n"
178     ($api_entries.length+$buff-1).times { |i|
179       if( $known_entries[i] ) then 
180         ocl_icd_bindings_source += "  #{$known_entries[i]},\n"
181       else
182         ocl_icd_bindings_source += "  (void *) NULL,\n"
183       end
184     }
185     if( $known_entries[$api_entries.length+$buff-1] ) then
186       ocl_icd_bindings_source += "  #{$known_entries[i]}\n"
187     else
188       ocl_icd_bindings_source += "  (void *) NULL\n"
189     end
190     ocl_icd_bindings_source += "};\n"
191     ocl_icd_bindings_source += <<EOF
192
193 CL_API_ENTRY cl_int CL_API_CALL clIcdGetPlatformIDsKHR(  
194              cl_uint num_entries, 
195              cl_platform_id *platforms,
196              cl_uint *num_platforms) {
197   if( platforms == NULL && num_platforms == NULL )
198     return CL_INVALID_VALUE;
199   if( num_entries == 0 && platforms != NULL )
200     return CL_INVALID_VALUE;
201 #error You have to fill the commented lines with corresponding variables from your library
202 //  if( your_number_of_platforms == 0)
203 //    return CL_PLATFORM_NOT_FOUND_KHR;
204 //  if( num_platforms != NULL )
205 //    *num_platforms = your_number_of_platforms;
206   if( platforms != NULL ) {
207     cl_uint i;
208 //    for( i=0; i<(your_number_of_platforms<num_entries?your_number_of_platforms:num_entries); i++)
209 //      platforms[i] = &your_platforms[i];
210   }
211   return CL_SUCCESS;
212 }
213
214 CL_API_ENTRY void * CL_API_CALL clGetExtensionFunctionAddress(
215              const char *   func_name) CL_API_SUFFIX__VERSION_1_0 {
216 #error You have to fill this function with your extensions of incorporate these lines in your version
217   if( func_name != NULL &&  strcmp("clIcdGetPlatformIDsKHR", func_name) == 0 )
218     return (void *)clIcdGetPlatformIDsKHR;
219   return NULL;
220 }
221 CL_API_ENTRY cl_int CL_API_CALL clGetPlatformInfo(
222              cl_platform_id   platform, 
223              cl_platform_info param_name,
224              size_t           param_value_size, 
225              void *           param_value,
226              size_t *         param_value_size_ret) CL_API_SUFFIX__VERSION_1_0 {
227 #error You ahve to fill this function with your information or assert that your version responds to CL_PLATFORM_ICD_SUFFIX_KHR
228 //  char cl_platform_profile[] = "FULL_PROFILE";
229 //  char cl_platform_version[] = "OpenCL 1.1";
230 //  char cl_platform_name[] = "DummyCL";
231 //  char cl_platform_vendor[] = "LIG";
232 //  char cl_platform_extensions[] = "cl_khr_icd";
233 //  char cl_platform_icd_suffix_khr[] = "DUMMY";
234   size_t size_string;
235   char * string_p;
236   if( platform != NULL ) {
237     int found = 0;
238     int i;
239     for(i=0; i<num_master_platforms; i++) {
240       if( platform == &master_platforms[i] )
241         found = 1;
242     }
243     if(!found)
244       return CL_INVALID_PLATFORM;
245   }
246   switch ( param_name ) {
247     case CL_PLATFORM_PROFILE:
248       string_p = cl_platform_profile;
249       size_string = sizeof(cl_platform_profile);
250       break;
251     case CL_PLATFORM_VERSION:
252       string_p = cl_platform_version;
253       size_string = sizeof(cl_platform_version);
254       break;
255     case CL_PLATFORM_NAME:
256       string_p = cl_platform_name;
257       size_string = sizeof(cl_platform_name);
258       break;
259     case CL_PLATFORM_VENDOR:
260       string_p = cl_platform_vendor;
261       size_string = sizeof(cl_platform_vendor);
262       break;
263     case CL_PLATFORM_EXTENSIONS:
264       string_p = cl_platform_extensions;
265       size_string = sizeof(cl_platform_extensions);
266       break;
267     case CL_PLATFORM_ICD_SUFFIX_KHR:
268       string_p = cl_platform_icd_suffix_khr;
269       size_string = sizeof(cl_platform_icd_suffix_khr);
270       break;
271     default:
272       return CL_INVALID_VALUE;
273       break;
274   }
275   if( param_value != NULL ) {
276     if( size_string > param_value_size )
277       return CL_INVALID_VALUE;
278     memcpy(param_value, string_p, size_string);
279   }
280   if( param_value_size_ret != NULL )
281     *param_value_size_ret = size_string;
282   return CL_SUCCESS;
283 }
284 EOF
285     return ocl_icd_bindings_source
286   end
287  
288   def self.generate_ocl_icd_loader_gen_source
289     skip_funcs = $specific_loader_funcs
290     ocl_icd_loader_gen_source = "/**\n#{$license}\n*/\n"
291     ocl_icd_loader_gen_source += "#include \"ocl_icd_loader.h\"\n"
292     ocl_icd_loader_gen_source += "#define DEBUG_OCL_ICD_PROVIDE_DUMP_FIELD\n"
293     ocl_icd_loader_gen_source += "#include \"ocl_icd_debug.h\"\n"
294     ocl_icd_loader_gen_source += ""
295     $api_entries.each { |func_name, entry|
296       next if skip_funcs.include?(func_name)
297       clean_entry = entry.sub(/(.*\)).*/m,'\1').gsub("/*","").gsub("*/","").gsub("\r","") + "{\n"
298       parameters = clean_entry.match(/\(.*\)/m)[0][1..-2]
299       parameters.gsub!(/\[.*?\]/,"")
300       parameters.sub!(/\(.*?\*\s*(.*?)\)\s*\(.*?\)/,'\1')
301       ocl_icd_loader_gen_source += clean_entry.gsub(/\[.*?\]/,"")
302       first_parameter = parameters.match(/.*?\,/m)
303       if not first_parameter then
304         first_parameter =  parameters.match(/.*/m)[0]
305       else
306         first_parameter = first_parameter[0][0..-2]
307       end
308       fps = first_parameter.split
309       ocl_icd_loader_gen_source += "  debug_trace();\n"
310       ocl_icd_loader_gen_source += "  RETURN(((struct _#{fps[0]} *)#{fps[1]})->dispatch->#{func_name}("
311       ps = parameters.split(",")
312       ps = ps.collect { |p|
313         p = p.split
314         p = p[-1].gsub("*","")
315       }
316       ocl_icd_loader_gen_source += ps.join(", ")
317       ocl_icd_loader_gen_source += "));\n"
318       ocl_icd_loader_gen_source += "}\n\n"
319     }
320     ocl_icd_loader_gen_source += "#pragma GCC visibility push(hidden)\n\n"
321     skip_funcs = $specific_loader_funcs
322     $api_entries.each { |func_name, entry|
323       #next if func_name.match(/EXT$/)
324       #next if func_name.match(/KHR$/)
325       if (skip_funcs.include?(func_name)) then
326         ocl_icd_loader_gen_source += "extern typeof(#{func_name}) #{func_name}_hid;\n"
327       else
328         ocl_icd_loader_gen_source += "typeof(#{func_name}) #{func_name}_hid __attribute__ ((alias (\"#{func_name}\"), visibility(\"hidden\")));\n"
329       end
330     }
331     ocl_icd_loader_gen_source += "\n\nstruct func_desc const function_description[]= {\n"
332     $api_entries.each { |func_name, entry|
333       #next if func_name.match(/EXT$/)
334       #next if func_name.match(/KHR$/)
335       ocl_icd_loader_gen_source += "  {\"#{func_name}\", (void(* const)(void))&#{func_name}_hid },\n"
336     }
337     ocl_icd_loader_gen_source += <<EOF
338   {NULL, NULL}
339 };
340
341 #ifdef DEBUG_OCL_ICD
342 void dump_platform(clGEFA_t f, cl_platform_id pid) {
343   debug(D_ALWAYS, "platform @%p:  name=field_in_struct [clGetExtensionFunctionAddress(name)/clGetExtensionFunctionAddressForPlatform(name)]", pid);
344 EOF
345     $api_entries_array.each { |entry|
346       e = entry.gsub("\r"," ").gsub("\n"," ").gsub("\t"," ").
347         sub(/.*CL_API_CALL *([^ ()]*)[ ()].*$/m, '\1')
348       ocl_icd_loader_gen_source += "  dump_field(pid, f, #{e});\n"
349     }
350
351     ocl_icd_loader_gen_source += <<EOF
352 }
353 #endif
354
355 #pragma GCC visibility pop
356
357 EOF
358     return ocl_icd_loader_gen_source;
359   end
360   
361   def self.generate_libdummy_icd_header
362     libdummy_icd_structures = "/**\n#{$license}\n*/\n"
363     libdummy_icd_structures +=  "#include <CL/opencl.h>\n"
364     libdummy_icd_structures += self.include_headers
365     libdummy_icd_structures += "\n\nstruct _cl_icd_dispatch;\n"
366     libdummy_icd_structures += "struct _cl_platform_id { struct _cl_icd_dispatch *dispatch; };\n\n"
367     libdummy_icd_structures += "struct _cl_icd_dispatch {\n"
368     ($api_entries.length+$buff).times { |i|
369       if( $known_entries[i] ) then
370         libdummy_icd_structures += "  void(*known#{i})(void);\n"
371       else
372         libdummy_icd_structures += "  void(*unknown#{i})(void);\n"
373       end
374     }
375     libdummy_icd_structures += "};\n\n"
376     libdummy_icd_structures += "#pragma GCC visibility push(hidden)\n\n"
377     libdummy_icd_structures += "struct _cl_icd_dispatch master_dispatch; \n\n"
378     $known_entries.each { |k, f|
379       libdummy_icd_structures += "typeof(#{f}) INT#{f};\n"
380     }
381     libdummy_icd_structures += "#pragma GCC visibility pop\n\n"
382     return libdummy_icd_structures
383   end
384
385   def self.generate_libdummy_icd_source
386     libdummy_icd_source = "/**\n#{$license}\n*/\n\n"
387     libdummy_icd_source += "#include <stdio.h>\n\n"
388     libdummy_icd_source += "#include \"libdummy_icd_gen.h\"\n\n"
389     libdummy_icd_source += "#include \"libdummy_icd.h\"\n\n"
390     (0...$api_entries.length+$buff).each { |i|
391       libdummy_icd_source += "void dummyFunc#{i}(void){ printf(\"#{i}  : \"); fflush(NULL); }\n"
392     }
393     libdummy_icd_source += "\nstruct _cl_icd_dispatch master_dispatch = {\n"
394     comma=","
395     ($api_entries.length+$buff).times { |i|
396       comma="" if (i == $api_entries.length+$buff-1)
397       if( $known_entries[i] ) then 
398         libdummy_icd_source += "  (void(*)(void))& INT#{$known_entries[i]}#{comma}\n"
399       else
400         libdummy_icd_source += "  (void(*)(void))& dummyFunc#{i}#{comma}\n"
401       end
402     }
403     libdummy_icd_source += "};\n"
404     return libdummy_icd_source
405   end
406   
407   def self.generate_run_dummy_icd_weak_source
408     run_dummy_icd_weak = "/**\n#{$license}\n*/\n"
409     run_dummy_icd_weak += <<EOF
410 #define _GNU_SOURCE 1
411 #include <stdio.h>
412 #include <dlfcn.h>
413
414 #define F(f) \\
415 __attribute__((weak)) int f (void* arg, void* arg2) { \\
416   void (* p)(void*, void*)=NULL; \\
417   p=dlsym(RTLD_NEXT, #f); \\
418   if (p) { \\
419     (*p)(arg, arg2); \\
420   } else { \\
421     printf("-1 : "); \\
422   } \\
423   return 0; \\
424
425
426 EOF
427     $api_entries.each_key { |func_name|
428        next if $noweak_funcs.include?(func_name)
429        run_dummy_icd_weak += "F(#{func_name})\n"
430     }
431     return run_dummy_icd_weak
432   end
433   def self.generate_run_dummy_icd_source
434     run_dummy_icd = "/**\n#{$license}\n*/\n"
435     run_dummy_icd += "#include <stdlib.h>\n"
436     run_dummy_icd += "#include <stdio.h>\n"
437     run_dummy_icd += "#pragma GCC diagnostic push\n"
438     run_dummy_icd += "#  pragma GCC diagnostic ignored \"-Wcpp\"\n"
439     run_dummy_icd += "#  define CL_USE_DEPRECATED_OPENCL_1_0_APIS\n"
440     run_dummy_icd += "#  define CL_USE_DEPRECATED_OPENCL_1_1_APIS\n"
441     run_dummy_icd += "#  include <CL/opencl.h>\n"
442     run_dummy_icd += self.include_headers
443     run_dummy_icd += "#pragma GCC diagnostic pop\n"
444     run_dummy_icd += "\n\n"
445     run_dummy_icd += "typedef CL_API_ENTRY cl_int (CL_API_CALL* oclFuncPtr_fn)(cl_platform_id platform);\n\n"
446     run_dummy_icd += "void call_all_OpenCL_functions(cl_platform_id chosen_platform) {\n"
447     run_dummy_icd += "  oclFuncPtr_fn oclFuncPtr;\n"
448     run_dummy_icd += "  cl_context_properties properties[] = { CL_CONTEXT_PLATFORM, (cl_context_properties)chosen_platform, 0 };\n"
449     $api_entries.each_key { |func_name|
450        next if $forbidden_funcs.include?(func_name)
451        if func_name == "clCreateContext" then
452          run_dummy_icd += "  #{func_name}(properties,1,(cl_device_id*)&chosen_platform,NULL,NULL,NULL);\n"
453        elsif func_name == "clGetGLContextInfoKHR" then
454          run_dummy_icd += "  #{func_name}(properties,CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR, 0, NULL, NULL);\n"
455        elsif func_name == "clCreateContextFromType" then
456          run_dummy_icd += "  #{func_name}(properties,CL_DEVICE_TYPE_CPU,NULL,NULL,NULL);\n"
457        elsif func_name == "clWaitForEvents" then
458          run_dummy_icd += "  #{func_name}(1,(cl_event*)&chosen_platform);\n"
459        elsif func_name == "clGetExtensionFunctionAddressForPlatform" then
460          run_dummy_icd += "  #{func_name}((cl_platform_id)chosen_platform, \"clIcdGetPlatformIDsKHR\");\n"
461        else
462          run_dummy_icd += "  oclFuncPtr = (oclFuncPtr_fn)" + func_name + ";\n"
463          run_dummy_icd += "  oclFuncPtr(chosen_platform);\n"
464        end
465        run_dummy_icd += "  printf(\"%s\\n\", \"#{func_name}\");"
466        run_dummy_icd += "  fflush(NULL);\n"
467     }
468     run_dummy_icd += "  return;\n}\n"
469     return run_dummy_icd
470   end
471
472   def self.generate_ocl_icd_loader_map
473     ocl_icd_loader_map = "/**\n#{$license}\n*/\n\n"
474     prev_version=""
475     $versions_entries.keys.sort.each { |version|
476       ocl_icd_loader_map += "OPENCL_#{version.sub('_','.')} {\n";
477       ocl_icd_loader_map += "  global:\n";
478       $versions_entries[version].each { |symb|
479         ocl_icd_loader_map += "    #{symb};\n"
480       }
481       if (prev_version == "") then
482         ocl_icd_loader_map += "  local:\n";
483         ocl_icd_loader_map += "    *;\n";
484       end
485       ocl_icd_loader_map += "} #{prev_version};\n\n";
486       prev_version="OPENCL_#{version.sub('_','.')}";
487     }
488     return ocl_icd_loader_map
489   end
490
491   def self.generate_sources
492     parse_headers
493     File.open('libdummy_icd_gen.h','w') { |f|
494       f.puts generate_libdummy_icd_header
495     }
496     File.open('libdummy_icd_gen.c','w') { |f|
497       f.puts generate_libdummy_icd_source
498     }
499     File.open('run_dummy_icd_gen.c','w') { |f|
500       f.puts generate_run_dummy_icd_source
501     }
502     File.open('run_dummy_icd_weak.c','w') { |f|
503       f.puts generate_run_dummy_icd_weak_source
504     }
505   end
506
507   def self.savedb(yamlfile)
508     api_db = {}
509     begin
510       File::open(yamlfile,"r") { |f|
511         api_db = YAML::load(f.read)
512 #        puts api_db.inspect
513       }
514     rescue
515       api_db = {}
516     end
517     $known_entries.each_key {|i|
518       next if api_db[i]
519       api_db[i] = $api_entries[$known_entries[i]].gsub("\r","")
520     }
521     File::open(yamlfile,"w") { |f|
522       f.write($license.gsub(/^/,"# "))
523       f.write( <<EOF
524
525 # In Intel (OpenCL 1.1):
526 # * clSetCommandQueueProperty(13): nil (deprecated in 1.1)
527 # * clGetGLContextInfoKHR(74): function present with its symbol
528 # * 75-80: nil
529 # * 92: correspond to symbol clGetKernelArgInfo (first abandonned version?)
530 # * 93-: garbage
531 # In nvidia (OpenCL 1.1):
532 # * clGetGLContextInfoKHR(74): function present but no symbol
533 # * 75-80: nil
534 # * 89-: nil
535 # * only two OpenCL symbols: clGetPlatformInfo(1) and clGetExtensionFunctionAddress(65)
536 # In AMD (OpenCL 1.2):
537 # * clGetPlatformIDs(0): nil (symbol present)
538 # * clGetGLContextInfoKHR(74): function present but no symbol
539 # * 75-80: nil
540 # * 92: nil
541 # * 109-118: nil
542 # * 119-: garbage
543
544 EOF
545 )
546       # Not using YAML::dump as:
547       # * keys are not ordered
548       # * strings are badly formatted in new YAML ruby implementation (psych)
549       # * it is very easy to do it ourself
550       #f.write(YAML::dump(api_db))
551       f.write("--- ")
552       api_db.keys.sort.each { |k|
553         f.write("\n#{k}: |-\n  ")
554         f.write(api_db[k].gsub("\n","\n  "))
555       }
556       f.write("\n")
557     }
558   end
559
560   def self.finalize(yamlfile)
561     parse_headers
562     doc = YAML::load(`./run_dummy_icd`)
563     doc.delete(-1)
564     $known_entries.merge!(doc)
565     self.savedb(yamlfile)
566     unknown=0
567     $api_entries_array = []
568     ($known_entries.length+$buff).times { |i|
569       #puts $known_entries[i]
570       if $known_entries[i] then
571         $api_entries_array.push( $api_entries[$known_entries[i]] )
572       else
573         $api_entries_array.push( "CL_API_ENTRY cl_int CL_API_CALL clUnknown#{i}(void);" )
574         unknown += 1
575       end
576     }
577   end
578   
579   def self.generate_from_database(yamlfile)
580     doc={}
581     File::open(yamlfile) { |f|
582       doc = YAML:: load(f.read)
583     }
584     $known_entries = {}
585     $api_entries = {}
586     $versions_entries = Hash::new { |hash,key| hash[key]=[] }
587     entry_name = ""
588     version = ""
589     doc.each { |key, value|
590       begin
591         entry_name = value.match(/CL_API_CALL(.*?)\(/m)[1].strip
592       rescue
593         entry_name = value.match(/(\S*?)\(/m)[1].strip
594       end
595       next if $windows_funcs.include?(entry_name)
596       version = value.match(/SUFFIX__VERSION_(\d_\d)/m)[1]
597       $versions_entries[version].push(entry_name)
598       $known_entries[key] = entry_name
599       $api_entries[entry_name] = value
600     }
601     $api_entries_array = []
602     unknown=0
603     ($known_entries.length+$buff).times { |i|
604       #puts $known_entries[i]
605       if $known_entries[i] then
606         $api_entries_array.push( $api_entries[$known_entries[i]] )
607       else
608         $api_entries_array.push( "CL_API_ENTRY cl_int CL_API_CALL clUnknown#{i}(void);" )
609         unknown += 1
610       end
611     }
612     File.open('ocl_icd.h','w') { |f|
613       f.puts generate_ocl_icd_header
614     }
615     File.open('ocl_icd_loader.h','w') { |f|
616       f.puts generate_ocl_icd_loader_header
617     }
618     File.open('ocl_icd_loader.map','w') { |f|
619       f.puts generate_ocl_icd_loader_map
620     }
621     File.open('ocl_icd_bindings.c','w') { |f|
622       f.puts generate_ocl_icd_bindings_source
623     }
624     File.open('ocl_icd_loader_gen.c','w') { |f|
625       f.puts generate_ocl_icd_loader_gen_source
626     }
627   end
628 end
629
630 require 'optparse'
631
632 options = {}
633 OptionParser.new do |opts|
634   opts.banner = "Usage: cd_generator.rb [options] mode"
635
636   opts.on("-f", "--file FILE", String, "YAML file (default ocl_interface.yaml)") do |v|
637     options[:file] = v
638   end
639   opts.on("-m", "--mode [MODE]", [:database, :generate, :finalize],
640           "Select mode (database, generate, finalize)") do |m|
641     options[:mode] = m
642   end
643 end.parse!
644
645 if !options[:file] then
646   options[:file] = "ocl_interface.yaml"
647 end
648
649 if !options[:mode] then
650   raise "--mode option required"
651 end
652 if options[:mode] == :generate then
653   IcdGenerator.generate_sources
654 elsif options[:mode] == :finalize then
655   IcdGenerator.finalize(options[:file])
656 elsif options[:mode] == :database then
657   IcdGenerator.generate_from_database(options[:file])
658 else
659   raise "Mode must be one of generate, database or finalize not #{options[:mode]}" 
660 end
661