diff options
author | Tom Stellard <thomas.stellard@amd.com> | 2013-09-09 11:47:07 -0700 |
---|---|---|
committer | Tom Stellard <thomas.stellard@amd.com> | 2013-09-27 20:21:52 -0700 |
commit | 529e7ce52ea6b9532f6313d04cd04288383c46ee (patch) | |
tree | 9ca3108766fe3c12195378c16b060d17a2ae9812 /generated_tests/genclbuiltins.py | |
parent | 94bf660e98c4601b4511c841bd703663bb691e37 (diff) |
cl: Move common code from generate-cl-int-builtins.py into its own module
Diffstat (limited to 'generated_tests/genclbuiltins.py')
-rw-r--r-- | generated_tests/genclbuiltins.py | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/generated_tests/genclbuiltins.py b/generated_tests/genclbuiltins.py new file mode 100644 index 000000000..29dfe3972 --- /dev/null +++ b/generated_tests/genclbuiltins.py @@ -0,0 +1,395 @@ +__all__ = ['gen', 'DATA_SIZES', 'MAX_VALUES', 'MAX', 'MIN', 'BMIN', 'BMAX', + 'SMIN', 'SMAX', 'UMIN', 'UMAX', 'TYPE', 'T', 'U', 'B'] + +import os + + +DATA_SIZES = { + 'char': 8, + 'uchar': 8, + 'short': 16, + 'ushort': 16, + 'int': 32, + 'uint': 32, + 'long': 64, + 'ulong': 64 +} + +# By default, just test what is part of the CL1.1 spec, leave vec3 for later +# VEC_WIDTHS = [2, 3, 4, 8, 16] +VEC_WIDTHS = [2, 4, 8, 16] + +# ALL_WIDTHS = [1, 2, 3, 4, 8, 16] +ALL_WIDTHS = [1, 2, 4, 8, 16] + +MIN_VALUES = { + 'char': -128, + 'uchar': 0, + 'short': -32768, + 'ushort': 0, + 'int': -2147483648, + 'uint': 0, + 'long': -9223372036854775808, + 'ulong': 0 +} + +MAX_VALUES = { + 'char': 127, + 'uchar': 255, + 'short': 32767, + 'ushort': 65535, + 'int': 2147483647, + 'uint': 4294967295, + 'long': 9223372036854775807, + 'ulong': 18446744073709551615 +} + +# Define placeholders to reduce magic number usage +MAX = 'MAX_VAL' +MIN = 'MIN_VAL' +BMIN = 'min_for_larger_type' +BMAX = 'max_for_larger_type' +SMIN = 'signed_min_for_type' +SMAX = 'signed_max_for_type' +UMIN = 'unsigned_min_for_type' +UMAX = 'unsigned_max_for_type' +TYPE = 'TYPE' +SIZE = 'SIZE' + +# Identity type list +T = { + 'char': 'char', + 'uchar': 'uchar', + 'short': 'short', + 'ushort': 'ushort', + 'int': 'int', + 'uint': 'uint', + 'long': 'long', + 'ulong': 'ulong' +} +# Signed type for each type +SIGNED = { + 'char': 'char', + 'uchar': 'char', + 'short': 'short', + 'ushort': 'short', + 'int': 'int', + 'uint': 'int', + 'long': 'long', + 'ulong': 'long' +} +# Unsigned type for each source type +U = { + 'char': 'uchar', + 'uchar': 'uchar', + 'short': 'ushort', + 'ushort': 'ushort', + 'int': 'uint', + 'uint': 'uint', + 'long': 'ulong', + 'ulong': 'ulong' +} +# Next larger type with same signedness +B = { + 'char': 'short', + 'uchar': 'ushort', + 'short': 'int', + 'ushort': 'uint', + 'int': 'long', + 'uint': 'ulong', +} + + +# vecSizes has the layout [in0width, ..., inNwidth] where outType width is +# assumed to match the width of the first input +def gen_kernel(f, fnName, inTypes, outType, vecSizes, typePrefix): + f.write('kernel void test_' + typePrefix + str(vecSizes[0]) + '_' + fnName + + '_' + inTypes[0]+'(global '+outType+'* out') + for arg in range(0, len(inTypes)): + f.write(', global '+inTypes[arg]+'* in'+str(arg)) + f.write('){\n') + + suffix = ';' + if (vecSizes[0] == 1): + f.write(' *out = ') + else: + f.write(' vstore'+str(vecSizes[0])+'(') + suffix = ', 0, out)' + suffix + + f.write(fnName+'(') + suffix = ')' + suffix + + for arg in range(0, len(inTypes)): + if (arg > 0): + f.write(', ') + # if scalar, don't print vload/vstore + if (vecSizes[arg] == 1): + f.write('*in'+str(arg)) + else: + f.write('vload'+str(vecSizes[arg])+'(0, in'+str(arg)+')') + + f.write(suffix+'\n}\n\n') + + + +def gen_kernel_1_arg(f, fnName, inType, outType): + for vecSize in ALL_WIDTHS: + gen_kernel(f, fnName, [inType], outType, [vecSize], '') + + +# 2 argument kernel with input types that match +def gen_kernel_2_arg_same_type(f, fnName, inType, outType): + for vecSize in ALL_WIDTHS: + gen_kernel(f, fnName, [inType, inType], outType, [vecSize, vecSize], + '') + + +# 2 argument kernel with 1 vector and one scalar input argument +def gen_kernel_2_arg_mixed_size(f, fnName, inType, outType): + for vecSize in VEC_WIDTHS: + gen_kernel(f, fnName, [inType, inType], outType, [vecSize, 1], 'tss_') + + +# 2 argument kernel with 1 vector and one scalar input argument with multiple +# input data types +def gen_kernel_2_arg_mixed_sign(f, fnName, inType1, inType2, outType): + for vecSize in ALL_WIDTHS: + gen_kernel(f, fnName, [inType1, inType2], outType, [vecSize, vecSize], + '') + + +# 3-argument built-in functions + + +def gen_kernel_3_arg_same_type(f, fnName, inType, outType): + for vecSize in ALL_WIDTHS: + gen_kernel(f, fnName, [inType, inType, inType], outType, + [vecSize, vecSize, vecSize], '' + ) + + +def gen_kernel_3_arg_mixed_size_vector(f, fnName, inType, outType, vecSize): + f.write('kernel void test_tss_' + vecSize + '_' + fnName + '_' + inType + + '(global ' + outType + '* out, global ' + inType + '* in1, global ' + + inType+'* in2, global '+inType+'* in3){\n' + ' vstore' + vecSize + + '(' + fnName + '(vload' + vecSize + + '(0, in1), *in2, *in3), 0, out);\n' + '}\n\n') + + +def gen_kernel_3_arg_mixed_size(f, fnName, inType, outType): + for vecSize in VEC_WIDTHS: + gen_kernel(f, fnName, [inType, inType, inType], outType, + [vecSize, 1, 1], 'tss_') + + +def generate_kernels(f, dataType, fnName, fnDef): + argTypes = getArgTypes(dataType, fnDef['arg_types']) + + # For len(argTypes), remember that this includes the output arg + if (len(argTypes) == 2): + gen_kernel_1_arg(f, fnName, argTypes[1], argTypes[0]) + return + + if (len(argTypes) == 3 and not fnName is 'upsample'): + gen_kernel_2_arg_same_type(f, fnName, argTypes[1], argTypes[0]) + if (fnDef['function_type'] is 'tss'): + gen_kernel_2_arg_mixed_size(f, fnName, argTypes[1], argTypes[0]) + return + + if (len(argTypes) == 4): + gen_kernel_3_arg_same_type(f, fnName, argTypes[1], argTypes[0]) + if (fnDef['function_type'] is 'tss'): + gen_kernel_3_arg_mixed_size(f, fnName, argTypes[1], argTypes[0]) + return + + if (fnName is 'upsample'): + gen_kernel_2_arg_mixed_sign(f, fnName, argTypes[1], argTypes[2], + argTypes[0]) + return + +def getValue(type, val): + # Check if val is a str, list, or value + if (isinstance(val, str)): + if (val == MIN): + return MIN_VALUES[type] + elif (val == MAX): + return MAX_VALUES[type] + elif (val == BMIN): + return MIN_VALUES[B[type]] + elif (val == BMAX): + return MAX_VALUES[B[type]] + elif (val == SMIN): + return MIN_VALUES[SIGNED[type]] + elif (val == SMAX): + return MAX_VALUES[SIGNED[type]] + elif (val == UMIN): + return MIN_VALUES[U[type]] + elif (val == UMAX): + return MAX_VALUES[U[type]] + elif (val == TYPE): + return type + elif (val == SIZE): + return DATA_SIZES[type] + else: + print('Unknown string value: ' + val + '\n') + elif (isinstance(val, list)): + # The list should be of the format: [op, arg1, ... argN] where op is a + # Fn ref and arg[1-n] are either MIN/MAX or numbers (They could be + # nested lists). The exception for arg1 is TYPE, which means to + # substitute the data type + + # Evaluate the value of the requested function and arguments + # TODO: Change to varargs calls after unshifting the first list element + if (len(val) == 2): + return (val[0])(getValue(type, val[1])) + elif (len(val) == 3): + return (val[0])(getValue(type, val[1]), getValue(type, val[2])) + elif (len(val) == 4): + return (val[0])(getValue(type, val[1]), getValue(type, val[2]), + getValue(type, val[3])) + else: + return (val[0])(getValue(type, val[1]), getValue(type, val[2]), + getValue(type, val[3]), getValue(type, val[4])) + + # At this point, we should have been passed a number + if (isinstance(val, (int, long))): + return val + + print('Invalid value '+repr(val)+' encountered in getValue\n') + + + +def getStrVal(type, val): + return str(getValue(type, val)) + + +def getArgType(baseType, argType): + # If the argType is a string, it's a literal data type... return it + if (isinstance(argType, str)): + return argType + # otherwise it's a list to pick from + return argType[baseType] + + +def getArgTypes(baseType, argTypes): + ret = [] + for argType in argTypes: + ret.append(getArgType(baseType, argType)) + return ret + + +# Print a test with all-vector inputs/outputs and/or mixed vector/scalar args +def print_test(f, fnName, argType, functionDef, tests, testIdx, vecSize, tss): + # If the test allows mixed vector/scalar arguments, handle the case with + # only vector arguments through a recursive call. + if (tss): + print_test(f, fnName, argType, functionDef, tests, testIdx, vecSize, + False) + + # The tss && vecSize==1 case is handled in the non-tss case. + if (tss and vecSize == 1): + return + + # If we're handling mixed vector/scalar input widths, the kernels have + # different names than when the vector widths match + tssStr = 'tss_' + if (not tss): + tssStr = '' + + # Write the test header + f.write('[test]\n' + 'name: ' + fnName + ' ' + argType + str(vecSize) + + '\n' + 'kernel_name: test_' + tssStr + str(vecSize) + '_' + fnName + + '_' + argType + '\n' + ) + + argTypes = getArgTypes(argType, functionDef['arg_types']) + argCount = len(argTypes) + + # For each argument, write a line containing its type, index, and values + for arg in range(0, argCount): + argInOut = '' + argVal = getStrVal(argType, tests[arg][testIdx]) + if arg == 0: + argInOut = 'arg_out: ' + else: + argInOut = 'arg_in: ' + + # The output argument and first tss argument are vectors, any that + # follow are scalar. If !tss, then everything has a matching vector + # width + if (arg < 2 or not tss): + f.write(argInOut + str(arg) + ' buffer ' + argTypes[arg] + + '[' + str(vecSize) + '] ' + ' '.join([argVal]*vecSize) + + '\n' + ) + else: + argInOut = 'arg_in: ' + f.write(argInOut + str(arg) + ' buffer ' + argTypes[arg] + '[1] ' + + argVal + '\n' + ) + + # Blank line between tests for formatting reasons + f.write('\n') + + +def gen(types, minVersions, functions, testDefs, dirName): + # Create the output directory if required + if not os.path.exists(dirName): + os.makedirs(dirName) + + # Loop over all data types being tested. Create one output file per data + # type + for dataType in types: + for fnName in functions: + # Merge all of the generic/signed/unsigned/custom test definitions + if not testDefs.has_key((dataType, fnName)): + continue + functionDef = testDefs[(dataType, fnName)] + + # Check if the function actually exists for this data type + if (not functionDef.keys()): + continue + + clcVersionMin = minVersions[fnName] + + fileName = 'builtin-' + dataType + '-' + fnName + '-' + \ + str(float(clcVersionMin)/10)+'.generated.cl' + + fileName = os.path.join(dirName, fileName) + + f = open(fileName, 'w') + print(fileName) + # Write the file header + f.write('/*!\n' + + '[config]\n' + + 'name: Test '+dataType+' '+fnName+' built-in on CL 1.1\n' + + 'clc_version_min: '+str(clcVersionMin)+'\n' + + 'dimensions: 1\n' + + 'global_size: 1 0 0\n\n' + ) + + # Write all tests for the built-in function + tests = functionDef['values'] + argCount = len(functionDef['arg_types']) + fnType = functionDef['function_type'] + + outputValues = tests[0] + numTests = len(outputValues) + + # Handle all available scalar/vector widths + sizes = sorted(VEC_WIDTHS) + sizes.insert(0, 1) # Add 1-wide scalar to the vector widths + for vecSize in sizes: + for testIdx in range(0, numTests): + print_test(f, fnName, dataType, functionDef, tests, + testIdx, vecSize, (fnType is 'tss')) + + # Terminate the header section + f.write('!*/\n\n') + + # Generate the actual kernels + generate_kernels(f, dataType, fnName, functionDef) + + f.close() + + |