1 from __future__
import print_function
, division
, absolute_import
6 __all__
= ['gen', 'DATA_SIZES', 'MAX_VALUES', 'MAX', 'MIN', 'BMIN', 'BMAX',
7 'SMIN', 'SMAX', 'UMIN', 'UMAX', 'TYPE', 'T', 'U', 'B']
9 _NUMERIC_TYPES
= tuple(list(six
.integer_types
) + [float])
23 # By default, just test what is part of the CL1.1 spec, leave vec3 for later
24 # VEC_WIDTHS = [2, 3, 4, 8, 16]
25 VEC_WIDTHS
= [2, 4, 8, 16]
27 # ALL_WIDTHS = [1, 2, 3, 4, 8, 16]
28 ALL_WIDTHS
= [1, 2, 4, 8, 16]
37 'long': -9223372036854775808,
48 'long': 9223372036854775807,
49 'ulong': 18446744073709551615
52 # Define placeholders to reduce magic number usage
55 BMIN
= 'min_for_larger_type'
56 BMAX
= 'max_for_larger_type'
57 SMIN
= 'signed_min_for_type'
58 SMAX
= 'signed_max_for_type'
59 UMIN
= 'unsigned_min_for_type'
60 UMAX
= 'unsigned_max_for_type'
63 TRUE
= 'true_value_for_type' #1 for scalar, -1 for vector
64 NEGNAN
= 'Negative NAN as a string, because float("-nan") just produces nan'
77 # Signed type for each type
88 # Unsigned type for each source type
99 # Next larger type with same signedness
110 # vecSizes has the layout [in0width, ..., inNwidth] where outType width is
111 # assumed to match the width of the first input
112 def gen_kernel(f
, fnName
, inTypes
, outType
, vecSizes
, typePrefix
):
113 f
.write('kernel void test_' + typePrefix
+ str(vecSizes
[0]) + '_' + fnName
114 + '_' + inTypes
[0]+'(global '+outType
+'* out')
115 for arg
in range(0, len(inTypes
)):
116 f
.write(', global '+inTypes
[arg
]+'* in'+str(arg
))
120 if (vecSizes
[0] == 1):
121 f
.write(' out[get_global_id(0)] = ')
123 f
.write(' vstore'+str(vecSizes
[0])+'(')
124 suffix
= ', get_global_id(0), out)' + suffix
127 suffix
= ')' + suffix
129 for arg
in range(0, len(inTypes
)):
132 # if scalar, don't print vload/vstore
133 if (vecSizes
[arg
] == 1):
134 f
.write('in'+str(arg
)+'[get_global_id(0)]')
136 f
.write('vload'+str(vecSizes
[arg
])+'(get_global_id(0), in'+str(arg
)+')')
138 f
.write(suffix
+'\n}\n\n')
142 def gen_kernel_1_arg(f
, fnName
, inType
, outType
):
143 for vecSize
in ALL_WIDTHS
:
144 gen_kernel(f
, fnName
, [inType
], outType
, [vecSize
], '')
147 # 2 argument kernel with input types that match their vector size
148 def gen_kernel_2_arg_same_size(f
, fnName
, inTypes
, outType
):
149 for vecSize
in ALL_WIDTHS
:
150 gen_kernel(f
, fnName
, inTypes
, outType
, [vecSize
, vecSize
],
154 # 2 argument kernel with 1 vector and one scalar input argument
155 def gen_kernel_2_arg_mixed_size(f
, fnName
, inTypes
, outType
):
156 for vecSize
in VEC_WIDTHS
:
157 gen_kernel(f
, fnName
, inTypes
, outType
, [vecSize
, 1], 'tss_')
160 # 2 argument kernel with 1 vector and one scalar input argument with multiple
162 def gen_kernel_2_arg_mixed_sign(f
, fnName
, inTypes
, outType
):
163 for vecSize
in ALL_WIDTHS
:
164 gen_kernel(f
, fnName
, inTypes
, outType
, [vecSize
, vecSize
],
168 # 3-argument built-in functions
171 def gen_kernel_3_arg_same_type(f
, fnName
, inTypes
, outType
):
172 for vecSize
in ALL_WIDTHS
:
173 gen_kernel(f
, fnName
, inTypes
, outType
,
174 [vecSize
, vecSize
, vecSize
], ''
177 def gen_kernel_3_arg_mixed_size_tss(f
, fnName
, inTypes
, outType
):
178 for vecSize
in VEC_WIDTHS
:
179 gen_kernel(f
, fnName
, inTypes
, outType
,
180 [vecSize
, 1, 1], 'tss_')
182 def gen_kernel_3_arg_mixed_size_tts(f
, fnName
, inTypes
, outType
):
183 for vecSize
in VEC_WIDTHS
:
184 gen_kernel(f
, fnName
, inTypes
, outType
,
185 [vecSize
, vecSize
, 1], 'tts_')
188 def generate_kernels(f
, dataType
, fnName
, fnDef
):
189 argTypes
= getArgTypes(dataType
, fnDef
['arg_types'])
191 # For len(argTypes), remember that this includes the output arg
192 if (len(argTypes
) == 2):
193 gen_kernel_1_arg(f
, fnName
, argTypes
[1], argTypes
[0])
196 if (len(argTypes
) == 3 and not fnName
is 'upsample'):
197 gen_kernel_2_arg_same_size(f
, fnName
,
198 [argTypes
[1], argTypes
[2]], argTypes
[0])
199 if (fnDef
['function_type'] is 'tss'):
200 gen_kernel_2_arg_mixed_size(f
, fnName
,
201 [argTypes
[1], argTypes
[2]], argTypes
[0])
204 if (len(argTypes
) == 4):
205 gen_kernel_3_arg_same_type(f
, fnName
,
206 [argTypes
[1], argTypes
[2], argTypes
[3]], argTypes
[0])
207 if (fnDef
['function_type'] is 'tss'):
208 gen_kernel_3_arg_mixed_size_tss(f
, fnName
,
209 [argTypes
[1], argTypes
[2], argTypes
[3]], argTypes
[0])
210 if (fnDef
['function_type'] is 'tts'):
211 gen_kernel_3_arg_mixed_size_tts(f
, fnName
,
212 [argTypes
[1], argTypes
[2], argTypes
[3]], argTypes
[0])
215 if (fnName
is 'upsample'):
216 gen_kernel_2_arg_mixed_sign(f
, fnName
,
217 [argTypes
[1], argTypes
[2]],
221 def getValue(type, val
, isVector
):
222 # Check if val is a str, list, or value
223 if (isinstance(val
, str)):
225 return MIN_VALUES
[type]
227 return MAX_VALUES
[type]
229 return MIN_VALUES
[B
[type]]
231 return MAX_VALUES
[B
[type]]
233 return MIN_VALUES
[SIGNED
[type]]
235 return MAX_VALUES
[SIGNED
[type]]
237 return MIN_VALUES
[U
[type]]
239 return MAX_VALUES
[U
[type]]
243 return DATA_SIZES
[type]
249 elif (val
== NEGNAN
):
250 return '-nan' #cl-program-tester translates this for us
252 print('Unknown string value: ' + val
+ '\n')
253 elif (isinstance(val
, list)):
254 # The list should be of the format: [op, arg1, ... argN] where op is a
255 # Fn ref and arg[1-n] are either MIN/MAX or numbers (They could be
256 # nested lists). The exception for arg1 is TYPE, which means to
257 # substitute the data type
259 # Evaluate the value of the requested function and arguments
260 # TODO: Change to varargs calls after unshifting the first list element
261 if (callable(val
[0])):
263 return (val
[0])(getValue(type, val
[1], isVector
))
264 elif (len(val
) == 3):
265 return (val
[0])(getValue(type, val
[1], isVector
), getValue(type, val
[2], isVector
))
266 elif (len(val
) == 4):
267 return (val
[0])(getValue(type, val
[1], isVector
), getValue(type, val
[2], isVector
),
268 getValue(type, val
[3], isVector
))
270 return (val
[0])(getValue(type, val
[1], isVector
), getValue(type, val
[2], isVector
),
271 getValue(type, val
[3], isVector
), getValue(type, val
[4], isVector
))
273 return map(lambda x
: getValue(type, x
, isVector
), val
);
275 # At this point, we should have been passed a number
276 if (isinstance(val
, _NUMERIC_TYPES
)):
279 print('Invalid value '+repr(val
)+' encountered in getValue\n')
283 def getStrVal(type, val
, isVector
):
284 return " ".join(map(str, getValue(type, val
, isVector
)))
287 def getArgType(baseType
, argType
):
288 # If the argType is a string, it's a literal data type... return it
289 if (isinstance(argType
, str)):
291 # otherwise it's a list to pick from
292 return argType
[baseType
]
295 def getArgTypes(baseType
, argTypes
):
297 for argType
in argTypes
:
298 ret
.append(getArgType(baseType
, argType
))
304 # Print a test with all-vector inputs/outputs and/or mixed vector/scalar args
305 def print_test(f
, fnName
, argType
, functionDef
, tests
, numTests
, vecSize
, fntype
):
306 # If the test allows mixed vector/scalar arguments, handle the case with
307 # only vector arguments through a recursive call.
308 if (fntype
is 'tss' or fntype
is 'tts'):
309 print_test(f
, fnName
, argType
, functionDef
, tests
, numTests
, vecSize
,
312 # The tss && vecSize==1 case is handled in the non-tss case.
313 if ((not fntype
is 'ttt') and vecSize
== 1):
316 # If we're handling mixed vector/scalar input widths, the kernels have
317 # different names than when the vector widths match
318 tssStr
= fntype
+ '_' if (not fntype
is 'ttt') else ''
320 argTypes
= getArgTypes(argType
, functionDef
['arg_types'])
321 argCount
= len(argTypes
)
322 tolerance
= functionDef
['tolerance'] if 'tolerance' in functionDef
else 0
324 # Write the test header
325 f
.write('[test]\n' + 'name: ' + tssStr
+ fnName
+ ' ' + argType
326 + str(vecSize
) + '\n' + 'kernel_name: test_' + tssStr
+ str(vecSize
)
327 + '_' + fnName
+ '_' + argType
+ '\n' + 'global_size: '
328 + str(numTests
) + ' 0 0\n\n'
331 # For each argument, write a line containing its type, index, and values
332 for arg
in range(0, argCount
):
334 argVal
= getStrVal(argType
, tests
[arg
], (vecSize
> 1))
336 argInOut
= 'arg_out: '
338 argInOut
= 'arg_in: '
340 # The output argument and first tss argument are vectors, any that
341 # follow are scalar. If !tss, then everything has a matching vector
343 if (fntype
is 'ttt' or (arg
< 2 and fntype
is 'tss') or (arg
< 3 and fntype
is 'tts')):
344 f
.write(argInOut
+ str(arg
) + ' buffer ' + argTypes
[arg
] +
345 '[' + str(numTests
* vecSize
) + '] ' +
346 ''.join(map(lambda x
: (x
+ ' ') * vecSize
, argVal
.split()))
349 f
.write(' tolerance {0} '.format(tolerance
))
350 # Use ulp tolerance for float types
351 if isFloatType(argTypes
[arg
]):
355 argInOut
= 'arg_in: '
356 f
.write(argInOut
+ str(arg
) + ' buffer ' + argTypes
[arg
] + '[' +
357 str(numTests
) + '] ' + argVal
+ '\n'
360 # Blank line between tests for formatting reasons
364 def gen(types
, minVersions
, functions
, testDefs
, dirName
):
365 # Create the output directory if required
366 if not os
.path
.exists(dirName
):
370 if e
.errno
== 17: # file exists
374 # Loop over all data types being tested. Create one output file per data
376 for dataType
in types
:
377 for fnName
in functions
:
378 # Merge all of the generic/signed/unsigned/custom test definitions
379 if (dataType
, fnName
) not in testDefs
:
381 functionDef
= testDefs
[(dataType
, fnName
)]
383 # Check if the function actually exists for this data type
384 if (not functionDef
.keys()):
387 clcVersionMin
= minVersions
[fnName
]
389 fileName
= 'builtin-' + dataType
+ '-' + fnName
+ '-' + \
390 str(float(clcVersionMin
)/10)+'.generated.cl'
392 fileName
= os
.path
.join(dirName
, fileName
)
394 f
= open(fileName
, 'w')
396 # Write the file header
399 'name: Test '+dataType
+' '+fnName
+' built-in on CL 1.1\n' +
400 'clc_version_min: '+str(clcVersionMin
)+'\n' +
403 if (dataType
== 'double'):
404 f
.write('require_device_extensions: cl_khr_fp64\n')
406 # Blank line to provide separation between config header and tests
409 # Write all tests for the built-in function
410 tests
= functionDef
['values']
411 argCount
= len(functionDef
['arg_types'])
412 fnType
= functionDef
['function_type']
414 outputValues
= tests
[0]
415 numTests
= len(outputValues
)
417 # Handle all available scalar/vector widths
418 sizes
= sorted(VEC_WIDTHS
)
419 sizes
.insert(0, 1) # Add 1-wide scalar to the vector widths
420 for vecSize
in sizes
:
421 print_test(f
, fnName
, dataType
, functionDef
, tests
,
422 numTests
, vecSize
, fnType
)
424 # Terminate the header section
427 if (dataType
== 'double'):
428 f
.write('#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n\n')
430 # Generate the actual kernels
431 generate_kernels(f
, dataType
, fnName
, functionDef
)