4 __all__
= ['gen', 'DATA_SIZES', 'MAX_VALUES', 'MAX', 'MIN', 'BMIN', 'BMAX',
5 'SMIN', 'SMAX', 'UMIN', 'UMAX', 'TYPE', 'T', 'U', 'B']
7 _NUMERIC_TYPES
= tuple([int, float])
21 # By default, just test what is part of the CL1.1 spec, leave vec3 for later
22 # VEC_WIDTHS = [2, 3, 4, 8, 16]
23 VEC_WIDTHS
= [2, 4, 8, 16]
25 # ALL_WIDTHS = [1, 2, 3, 4, 8, 16]
26 ALL_WIDTHS
= [1, 2, 4, 8, 16]
35 'long': -9223372036854775808,
46 'long': 9223372036854775807,
47 'ulong': 18446744073709551615
50 # Define placeholders to reduce magic number usage
53 BMIN
= 'min_for_larger_type'
54 BMAX
= 'max_for_larger_type'
55 SMIN
= 'signed_min_for_type'
56 SMAX
= 'signed_max_for_type'
57 UMIN
= 'unsigned_min_for_type'
58 UMAX
= 'unsigned_max_for_type'
61 TRUE
= 'true_value_for_type' #1 for scalar, -1 for vector
62 NEGNAN
= 'Negative NAN as a string, because float("-nan") just produces nan'
75 # Signed type for each type
86 # Unsigned type for each source type
97 # Next larger type with same signedness
108 # vecSizes has the layout [in0width, ..., inNwidth] where outType width is
109 # assumed to match the width of the first input
110 def gen_kernel(f
, fnName
, inTypes
, outTypes
, vecSizes
, typePrefix
, outLoc
='private'):
111 f
.write('kernel void test_' + typePrefix
+ str(vecSizes
[0]) + '_' + fnName
112 + (('_' + outLoc
) if len(outTypes
) > 1 else '')
113 + '_' + inTypes
[0] + '(global ' + outTypes
[0] + '* out')
114 for arg
in range(1, len(outTypes
)):
115 f
.write(', global '+outTypes
[arg
]+'* out'+str(arg
))
116 for arg
in range(0, len(inTypes
)):
117 f
.write(', global '+inTypes
[arg
]+'* in'+str(arg
))
120 for arg
in range(1, len(outTypes
)):
121 f
.write(' ' + outLoc
+ ' ' + outTypes
[arg
] + ('' if vecSizes
[0] == 1 else str(vecSizes
[0])));
122 if (outLoc
== 'global'):
123 f
.write(' *tmp' + str(arg
) + ' = out' + str(arg
) + ';\n');
125 #FIXME: This assumes WG size of 1
126 f
.write(' tmp' + str(arg
) + ';\n');
129 if (vecSizes
[0] == 1):
130 f
.write(' out[get_global_id(0)] = ')
132 f
.write(' vstore'+str(vecSizes
[0])+'(')
133 suffix
= ', get_global_id(0), out)' + suffix
136 suffix
= ')' + suffix
138 for arg
in range(0, len(inTypes
)):
141 # if scalar, don't print vload/vstore
142 if (vecSizes
[arg
] == 1):
143 f
.write('in'+str(arg
)+'[get_global_id(0)]')
145 f
.write('vload'+str(vecSizes
[arg
])+'(get_global_id(0), in'+str(arg
)+')')
146 for arg
in range(1, len(outTypes
)):
147 if (outLoc
== 'global'):
148 f
.write(', &tmp' + str(arg
) + '[get_global_id(0)]')
150 f
.write(', &tmp' + str(arg
))
152 f
.write(suffix
+ '\n')
154 if (outLoc
!= 'global'):
155 for arg
in range(1, len(outTypes
)):
156 if (vecSizes
[0] == 1):
157 f
.write(' out'+ str(arg
) +'[get_global_id(0)] = tmp' + str(arg
))
159 f
.write(' vstore' + str(vecSizes
[0]) + '(tmp' + str(arg
) + ', get_global_id(0), out' + str(arg
) + ')')
167 def gen_kernel_1_arg(f
, fnName
, inType
, outTypes
, loc
= 'private'):
168 for vecSize
in ALL_WIDTHS
:
169 gen_kernel(f
, fnName
, [inType
], outTypes
, [vecSize
], '', loc
)
172 # 2 argument kernel with input types that match their vector size
173 def gen_kernel_2_arg_same_size(f
, fnName
, inTypes
, outTypes
, loc
= 'private'):
174 for vecSize
in ALL_WIDTHS
:
175 gen_kernel(f
, fnName
, inTypes
, outTypes
, [vecSize
, vecSize
],
179 # 2 argument kernel with 1 vector and one scalar input argument
180 def gen_kernel_2_arg_mixed_size(f
, fnName
, inTypes
, outTypes
):
181 for vecSize
in VEC_WIDTHS
:
182 gen_kernel(f
, fnName
, inTypes
, outTypes
, [vecSize
, 1], 'tss_')
185 # 2 argument kernel with 1 vector and one scalar input argument with multiple
187 def gen_kernel_2_arg_mixed_sign(f
, fnName
, inTypes
, outTypes
):
188 for vecSize
in ALL_WIDTHS
:
189 gen_kernel(f
, fnName
, inTypes
, outTypes
, [vecSize
, vecSize
],
193 # 3-argument built-in functions
196 def gen_kernel_3_arg_same_type(f
, fnName
, inTypes
, outTypes
):
197 for vecSize
in ALL_WIDTHS
:
198 gen_kernel(f
, fnName
, inTypes
, outTypes
,
199 [vecSize
, vecSize
, vecSize
], ''
202 def gen_kernel_3_arg_mixed_size_tss(f
, fnName
, inTypes
, outTypes
):
203 for vecSize
in VEC_WIDTHS
:
204 gen_kernel(f
, fnName
, inTypes
, outTypes
,
205 [vecSize
, 1, 1], 'tss_')
207 def gen_kernel_3_arg_mixed_size_tts(f
, fnName
, inTypes
, outTypes
):
208 for vecSize
in VEC_WIDTHS
:
209 gen_kernel(f
, fnName
, inTypes
, outTypes
,
210 [vecSize
, vecSize
, 1], 'tts_')
213 def generate_kernels(f
, dataType
, fnName
, fnDef
):
215 argTypes
= getArgTypes(dataType
, fnDef
['arg_types'])
217 # For len(argTypes), remember that this includes the output arg
218 if (len(argTypes
) == 2):
219 gen_kernel_1_arg(f
, fnName
, argTypes
[1], [argTypes
[0]])
222 if (len(argTypes
) == 3 and fnName
!= 'upsample'):
223 if (getNumOutArgs(fnDef
) == 2):
224 gen_kernel_1_arg(f
, fnName
,
225 argTypes
[2], [argTypes
[0], argTypes
[1]], 'private')
226 gen_kernel_1_arg(f
, fnName
,
227 argTypes
[2], [argTypes
[0], argTypes
[1]], 'local')
228 gen_kernel_1_arg(f
, fnName
,
229 argTypes
[2], [argTypes
[0], argTypes
[1]], 'global')
231 gen_kernel_2_arg_same_size(f
, fnName
,
232 [argTypes
[1], argTypes
[2]], [argTypes
[0]])
233 if (fnDef
['function_type'] == 'tss'):
234 gen_kernel_2_arg_mixed_size(f
, fnName
,
235 [argTypes
[1], argTypes
[2]], [argTypes
[0]])
238 if (len(argTypes
) == 4):
239 if (getNumOutArgs(fnDef
) == 2):
240 gen_kernel_2_arg_same_size(f
, fnName
, [argTypes
[2], argTypes
[3]],
241 [argTypes
[0], argTypes
[1]], 'private')
242 gen_kernel_2_arg_same_size(f
, fnName
, [argTypes
[2], argTypes
[3]],
243 [argTypes
[0], argTypes
[1]], 'local')
244 gen_kernel_2_arg_same_size(f
, fnName
, [argTypes
[2], argTypes
[3]],
245 [argTypes
[0], argTypes
[1]], 'global')
247 gen_kernel_3_arg_same_type(f
, fnName
,
248 [argTypes
[1], argTypes
[2], argTypes
[3]], [argTypes
[0]])
249 if (fnDef
['function_type'] == 'tss'):
250 gen_kernel_3_arg_mixed_size_tss(f
, fnName
,
251 [argTypes
[1], argTypes
[2], argTypes
[3]], [argTypes
[0]])
252 if (fnDef
['function_type'] == 'tts'):
253 gen_kernel_3_arg_mixed_size_tts(f
, fnName
,
254 [argTypes
[1], argTypes
[2], argTypes
[3]], [argTypes
[0]])
257 if (fnName
== 'upsample'):
258 gen_kernel_2_arg_mixed_sign(f
, fnName
,
259 [argTypes
[1], argTypes
[2]],
263 def getValue(type, val
, isVector
):
264 # Check if val is a str, list, or value
265 if (isinstance(val
, str)):
267 return MIN_VALUES
[type]
269 return MAX_VALUES
[type]
271 return MIN_VALUES
[B
[type]]
273 return MAX_VALUES
[B
[type]]
275 return MIN_VALUES
[SIGNED
[type]]
277 return MAX_VALUES
[SIGNED
[type]]
279 return MIN_VALUES
[U
[type]]
281 return MAX_VALUES
[U
[type]]
285 return DATA_SIZES
[type]
291 elif (val
== NEGNAN
):
292 return '-nan' #cl-program-tester translates this for us
294 print('Unknown string value: ' + val
+ '\n')
295 elif (isinstance(val
, list)):
296 # The list should be of the format: [op, arg1, ... argN] where op is a
297 # Fn ref and arg[1-n] are either MIN/MAX or numbers (They could be
298 # nested lists). The exception for arg1 is TYPE, which means to
299 # substitute the data type
301 # Evaluate the value of the requested function and arguments
302 # TODO: Change to varargs calls after unshifting the first list element
303 if (callable(val
[0])):
305 return (val
[0])(getValue(type, val
[1], isVector
))
306 elif (len(val
) == 3):
307 return (val
[0])(getValue(type, val
[1], isVector
), getValue(type, val
[2], isVector
))
308 elif (len(val
) == 4):
309 return (val
[0])(getValue(type, val
[1], isVector
), getValue(type, val
[2], isVector
),
310 getValue(type, val
[3], isVector
))
312 return (val
[0])(getValue(type, val
[1], isVector
), getValue(type, val
[2], isVector
),
313 getValue(type, val
[3], isVector
), getValue(type, val
[4], isVector
))
315 return map(lambda x
: getValue(type, x
, isVector
), val
);
317 # At this point, we should have been passed a number
318 if (isinstance(val
, _NUMERIC_TYPES
)):
321 print('Invalid value '+repr(val
)+' encountered in getValue\n')
325 def getStrVal(type, val
, isVector
):
326 return " ".join(map(str, getValue(type, val
, isVector
)))
329 def getArgType(baseType
, argType
):
330 # If the argType is a string, it's a literal data type... return it
331 if (isinstance(argType
, str)):
333 # otherwise it's a list to pick from
334 return argType
[baseType
]
337 def getArgTypes(baseType
, argTypes
):
339 for argType
in argTypes
:
340 ret
.append(getArgType(baseType
, argType
))
346 def getNumOutArgs(functionDef
):
347 if 'num_out_args' in functionDef
:
348 return functionDef
['num_out_args']
352 def isOutArg(functionDef
, argIdx
):
353 return argIdx
< getNumOutArgs(functionDef
)
355 # Print a test with all-vector inputs/outputs and/or mixed vector/scalar args
356 def print_test(f
, fnName
, argType
, functionDef
, tests
, numTests
, vecSize
, fntype
):
357 # If the test allows mixed vector/scalar arguments, handle the case with
358 # only vector arguments through a recursive call.
359 if (fntype
== 'tss' or fntype
== 'tts'):
360 print_test(f
, fnName
, argType
, functionDef
, tests
, numTests
, vecSize
,
363 # The tss && vecSize==1 case is handled in the non-tss case.
364 if ((fntype
!= 'ttt') and vecSize
== 1):
367 # If we're handling mixed vector/scalar input widths, the kernels have
368 # different names than when the vector widths match
369 tssStr
= fntype
+ '_' if (fntype
!= 'ttt') else ''
371 argTypes
= getArgTypes(argType
, functionDef
['arg_types'])
372 argCount
= len(argTypes
)
373 tolerance
= functionDef
['tolerance'] if 'tolerance' in functionDef
else 0
375 # Write the test header
376 f
.write('[test]\n' + 'name: ' + tssStr
+ fnName
+ ' ' + argType
377 + str(vecSize
) + '\n' + 'kernel_name: test_' + tssStr
+ str(vecSize
)
378 + '_' + fnName
+ '_' + argType
+ '\n' + 'global_size: '
379 + str(numTests
) + ' 0 0\n\n'
382 # For each argument, write a line containing its type, index, and values
383 for arg
in range(0, argCount
):
385 argVal
= getStrVal(argType
, tests
[arg
], (vecSize
> 1))
386 if isOutArg(functionDef
, arg
):
387 argInOut
= 'arg_out: '
389 argInOut
= 'arg_in: '
391 # The output argument and first tss argument are vectors, any that
392 # follow are scalar. If !tss, then everything has a matching vector
394 if (fntype
== 'ttt' or (arg
< 2 and fntype
== 'tss') or (arg
< 3 and fntype
== 'tts')):
395 f
.write(argInOut
+ str(arg
) + ' buffer ' + argTypes
[arg
] +
396 '[' + str(numTests
* vecSize
) + '] ' +
397 ''.join(map(lambda x
: (x
+ ' ') * vecSize
, argVal
.split()))
399 if isOutArg(functionDef
, arg
) :
400 f
.write(' tolerance {0} '.format(tolerance
))
401 # Use ulp tolerance for float types
402 if isFloatType(argTypes
[arg
]):
406 argInOut
= 'arg_in: '
407 f
.write(argInOut
+ str(arg
) + ' buffer ' + argTypes
[arg
] + '[' +
408 str(numTests
) + '] ' + argVal
+ '\n'
411 # Blank line between tests for formatting reasons
415 def gen(types
, minVersions
, functions
, testDefs
, dirName
):
416 # Create the output directory if required
417 if not os
.path
.exists(dirName
):
421 if e
.errno
== 17: # file exists
425 # Loop over all data types being tested. Create one output file per data
427 for dataType
in types
:
428 for fnName
in functions
:
429 # Merge all of the generic/signed/unsigned/custom test definitions
430 if (dataType
, fnName
) not in testDefs
:
432 functionDef
= testDefs
[(dataType
, fnName
)]
434 # Check if the function actually exists for this data type
435 if (not functionDef
.keys()):
438 clcVersionMin
= minVersions
[fnName
]
440 fileName
= 'builtin-' + dataType
+ '-' + fnName
+ '-' + \
441 str(float(clcVersionMin
)/10)+'.generated.cl'
443 fileName
= os
.path
.join(dirName
, fileName
)
445 with
open(fileName
, 'w') as f
:
447 # Write the file header
450 'name: Test '+dataType
+' '+fnName
+' built-in on CL 1.1\n' +
451 'clc_version_min: '+str(clcVersionMin
)+'\n' +
454 if (dataType
== 'double'):
455 f
.write('require_device_extensions: cl_khr_fp64\n')
457 # Blank line to provide separation between config header and tests
460 # Write all tests for the built-in function
461 tests
= functionDef
['values']
462 argCount
= len(functionDef
['arg_types'])
463 fnType
= functionDef
['function_type']
465 outputValues
= tests
[0]
466 numTests
= len(outputValues
)
468 # Handle all available scalar/vector widths
469 sizes
= sorted(VEC_WIDTHS
)
470 sizes
.insert(0, 1) # Add 1-wide scalar to the vector widths
471 for vecSize
in sizes
:
472 if (getNumOutArgs(functionDef
) == 1):
473 print_test(f
, fnName
, dataType
, functionDef
, tests
,
474 numTests
, vecSize
, fnType
)
476 for loc
in ['_private', '_local', '_global']:
477 print_test(f
, fnName
+ loc
, dataType
, functionDef
, tests
,
478 numTests
, vecSize
, fnType
)
480 # Terminate the header section
483 if (dataType
== 'double'):
484 f
.write('#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n\n')
486 # Generate the actual kernels
487 generate_kernels(f
, dataType
, fnName
, functionDef
)