diff options
author | Zancanaro; Carlo <czan8762@plang3.cs.usyd.edu.au> | 2012-09-24 09:58:17 +1000 |
---|---|---|
committer | Zancanaro; Carlo <czan8762@plang3.cs.usyd.edu.au> | 2012-09-24 09:58:17 +1000 |
commit | 222e2a7620e6520ffaf4fc4e69d79c18da31542e (patch) | |
tree | 7bfbc05bfa3b41c8f9d2e56d53a0bc3e310df239 /clang/utils/ABITest | |
parent | 3d206f03985b50beacae843d880bccdc91a9f424 (diff) |
Add the clang library to the repo (with some of my changes, too).
Diffstat (limited to 'clang/utils/ABITest')
-rwxr-xr-x | clang/utils/ABITest/ABITestGen.py | 672 | ||||
-rw-r--r-- | clang/utils/ABITest/Enumeration.py | 276 | ||||
-rw-r--r-- | clang/utils/ABITest/Makefile.test.common | 170 | ||||
-rw-r--r-- | clang/utils/ABITest/TypeGen.py | 471 | ||||
-rwxr-xr-x | clang/utils/ABITest/build-and-summarize-all.sh | 15 | ||||
-rwxr-xr-x | clang/utils/ABITest/build-and-summarize.sh | 14 | ||||
-rwxr-xr-x | clang/utils/ABITest/build.sh | 12 | ||||
-rw-r--r-- | clang/utils/ABITest/layout/Makefile | 68 | ||||
-rw-r--r-- | clang/utils/ABITest/return-types-32/Makefile | 7 | ||||
-rw-r--r-- | clang/utils/ABITest/return-types-64/Makefile | 7 | ||||
-rw-r--r-- | clang/utils/ABITest/single-args-32/Makefile | 7 | ||||
-rw-r--r-- | clang/utils/ABITest/single-args-64/Makefile | 13 | ||||
-rwxr-xr-x | clang/utils/ABITest/summarize.sh | 15 |
13 files changed, 1747 insertions, 0 deletions
diff --git a/clang/utils/ABITest/ABITestGen.py b/clang/utils/ABITest/ABITestGen.py new file mode 100755 index 0000000..62925e7 --- /dev/null +++ b/clang/utils/ABITest/ABITestGen.py @@ -0,0 +1,672 @@ +#!/usr/bin/env python + +from pprint import pprint +import random, atexit, time +from random import randrange +import re + +from Enumeration import * +from TypeGen import * + +#### + +class TypePrinter: + def __init__(self, output, outputHeader=None, + outputTests=None, outputDriver=None, + headerName=None, info=None): + self.output = output + self.outputHeader = outputHeader + self.outputTests = outputTests + self.outputDriver = outputDriver + self.writeBody = outputHeader or outputTests or outputDriver + self.types = {} + self.testValues = {} + self.testReturnValues = {} + self.layoutTests = [] + self.declarations = set() + + if info: + for f in (self.output,self.outputHeader,self.outputTests,self.outputDriver): + if f: + print >>f,info + + if self.writeBody: + print >>self.output, '#include <stdio.h>\n' + if self.outputTests: + print >>self.outputTests, '#include <stdio.h>' + print >>self.outputTests, '#include <string.h>' + print >>self.outputTests, '#include <assert.h>\n' + + if headerName: + for f in (self.output,self.outputTests,self.outputDriver): + if f is not None: + print >>f, '#include "%s"\n'%(headerName,) + + if self.outputDriver: + print >>self.outputDriver, '#include <stdio.h>' + print >>self.outputDriver, '#include <stdlib.h>\n' + print >>self.outputDriver, 'int main(int argc, char **argv) {' + print >>self.outputDriver, ' int index = -1;' + print >>self.outputDriver, ' if (argc > 1) index = atoi(argv[1]);' + + def finish(self): + if self.layoutTests: + print >>self.output, 'int main(int argc, char **argv) {' + print >>self.output, ' int index = -1;' + print >>self.output, ' if (argc > 1) index = atoi(argv[1]);' + for i,f in self.layoutTests: + print >>self.output, ' if (index == -1 || index == %d)' % i + print >>self.output, ' %s();' % f + print >>self.output, ' return 0;' + print >>self.output, '}' + + if self.outputDriver: + print >>self.outputDriver, ' printf("DONE\\n");' + print >>self.outputDriver, ' return 0;' + print >>self.outputDriver, '}' + + def addDeclaration(self, decl): + if decl in self.declarations: + return False + + self.declarations.add(decl) + if self.outputHeader: + print >>self.outputHeader, decl + else: + print >>self.output, decl + if self.outputTests: + print >>self.outputTests, decl + return True + + def getTypeName(self, T): + name = self.types.get(T) + if name is None: + # Reserve slot + self.types[T] = None + self.types[T] = name = T.getTypeName(self) + return name + + def writeLayoutTest(self, i, ty): + tyName = self.getTypeName(ty) + tyNameClean = tyName.replace(' ','_').replace('*','star') + fnName = 'test_%s' % tyNameClean + + print >>self.output,'void %s(void) {' % fnName + self.printSizeOfType(' %s'%fnName, tyName, ty, self.output) + self.printAlignOfType(' %s'%fnName, tyName, ty, self.output) + self.printOffsetsOfType(' %s'%fnName, tyName, ty, self.output) + print >>self.output,'}' + print >>self.output + + self.layoutTests.append((i,fnName)) + + def writeFunction(self, i, FT): + args = ', '.join(['%s arg%d'%(self.getTypeName(t),i) for i,t in enumerate(FT.argTypes)]) + if not args: + args = 'void' + + if FT.returnType is None: + retvalName = None + retvalTypeName = 'void' + else: + retvalTypeName = self.getTypeName(FT.returnType) + if self.writeBody or self.outputTests: + retvalName = self.getTestReturnValue(FT.returnType) + + fnName = 'fn%d'%(FT.index,) + if self.outputHeader: + print >>self.outputHeader,'%s %s(%s);'%(retvalTypeName, fnName, args) + elif self.outputTests: + print >>self.outputTests,'%s %s(%s);'%(retvalTypeName, fnName, args) + + print >>self.output,'%s %s(%s)'%(retvalTypeName, fnName, args), + if self.writeBody: + print >>self.output, '{' + + for i,t in enumerate(FT.argTypes): + self.printValueOfType(' %s'%fnName, 'arg%d'%i, t) + + if retvalName is not None: + print >>self.output, ' return %s;'%(retvalName,) + print >>self.output, '}' + else: + print >>self.output, '{}' + print >>self.output + + if self.outputDriver: + print >>self.outputDriver, ' if (index == -1 || index == %d) {' % i + print >>self.outputDriver, ' extern void test_%s(void);' % fnName + print >>self.outputDriver, ' test_%s();' % fnName + print >>self.outputDriver, ' }' + + if self.outputTests: + if self.outputHeader: + print >>self.outputHeader, 'void test_%s(void);'%(fnName,) + + if retvalName is None: + retvalTests = None + else: + retvalTests = self.getTestValuesArray(FT.returnType) + tests = map(self.getTestValuesArray, FT.argTypes) + print >>self.outputTests, 'void test_%s(void) {'%(fnName,) + + if retvalTests is not None: + print >>self.outputTests, ' printf("%s: testing return.\\n");'%(fnName,) + print >>self.outputTests, ' for (int i=0; i<%d; ++i) {'%(retvalTests[1],) + args = ', '.join(['%s[%d]'%(t,randrange(l)) for t,l in tests]) + print >>self.outputTests, ' %s RV;'%(retvalTypeName,) + print >>self.outputTests, ' %s = %s[i];'%(retvalName, retvalTests[0]) + print >>self.outputTests, ' RV = %s(%s);'%(fnName, args) + self.printValueOfType(' %s_RV'%fnName, 'RV', FT.returnType, output=self.outputTests, indent=4) + self.checkTypeValues('RV', '%s[i]' % retvalTests[0], FT.returnType, output=self.outputTests, indent=4) + print >>self.outputTests, ' }' + + if tests: + print >>self.outputTests, ' printf("%s: testing arguments.\\n");'%(fnName,) + for i,(array,length) in enumerate(tests): + for j in range(length): + args = ['%s[%d]'%(t,randrange(l)) for t,l in tests] + args[i] = '%s[%d]'%(array,j) + print >>self.outputTests, ' %s(%s);'%(fnName, ', '.join(args),) + print >>self.outputTests, '}' + + def getTestReturnValue(self, type): + typeName = self.getTypeName(type) + info = self.testReturnValues.get(typeName) + if info is None: + name = '%s_retval'%(typeName.replace(' ','_').replace('*','star'),) + print >>self.output, '%s %s;'%(typeName,name) + if self.outputHeader: + print >>self.outputHeader, 'extern %s %s;'%(typeName,name) + elif self.outputTests: + print >>self.outputTests, 'extern %s %s;'%(typeName,name) + info = self.testReturnValues[typeName] = name + return info + + def getTestValuesArray(self, type): + typeName = self.getTypeName(type) + info = self.testValues.get(typeName) + if info is None: + name = '%s_values'%(typeName.replace(' ','_').replace('*','star'),) + print >>self.outputTests, 'static %s %s[] = {'%(typeName,name) + length = 0 + for item in self.getTestValues(type): + print >>self.outputTests, '\t%s,'%(item,) + length += 1 + print >>self.outputTests,'};' + info = self.testValues[typeName] = (name,length) + return info + + def getTestValues(self, t): + if isinstance(t, BuiltinType): + if t.name=='float': + for i in ['0.0','-1.0','1.0']: + yield i+'f' + elif t.name=='double': + for i in ['0.0','-1.0','1.0']: + yield i + elif t.name in ('void *'): + yield '(void*) 0' + yield '(void*) -1' + else: + yield '(%s) 0'%(t.name,) + yield '(%s) -1'%(t.name,) + yield '(%s) 1'%(t.name,) + elif isinstance(t, EnumType): + for i in range(0, len(t.enumerators)): + yield 'enum%dval%d' % (t.index, i) + elif isinstance(t, RecordType): + nonPadding = [f for f in t.fields + if not f.isPaddingBitField()] + + if not nonPadding: + yield '{ }' + return + + # FIXME: Use designated initializers to access non-first + # fields of unions. + if t.isUnion: + for v in self.getTestValues(nonPadding[0]): + yield '{ %s }' % v + return + + fieldValues = map(list, map(self.getTestValues, nonPadding)) + for i,values in enumerate(fieldValues): + for v in values: + elements = map(random.choice,fieldValues) + elements[i] = v + yield '{ %s }'%(', '.join(elements)) + + elif isinstance(t, ComplexType): + for t in self.getTestValues(t.elementType): + yield '%s + %s * 1i'%(t,t) + elif isinstance(t, ArrayType): + values = list(self.getTestValues(t.elementType)) + if not values: + yield '{ }' + for i in range(t.numElements): + for v in values: + elements = [random.choice(values) for i in range(t.numElements)] + elements[i] = v + yield '{ %s }'%(', '.join(elements)) + else: + raise NotImplementedError,'Cannot make tests values of type: "%s"'%(t,) + + def printSizeOfType(self, prefix, name, t, output=None, indent=2): + print >>output, '%*sprintf("%s: sizeof(%s) = %%ld\\n", (long)sizeof(%s));'%(indent, '', prefix, name, name) + def printAlignOfType(self, prefix, name, t, output=None, indent=2): + print >>output, '%*sprintf("%s: __alignof__(%s) = %%ld\\n", (long)__alignof__(%s));'%(indent, '', prefix, name, name) + def printOffsetsOfType(self, prefix, name, t, output=None, indent=2): + if isinstance(t, RecordType): + for i,f in enumerate(t.fields): + if f.isBitField(): + continue + fname = 'field%d' % i + print >>output, '%*sprintf("%s: __builtin_offsetof(%s, %s) = %%ld\\n", (long)__builtin_offsetof(%s, %s));'%(indent, '', prefix, name, fname, name, fname) + + def printValueOfType(self, prefix, name, t, output=None, indent=2): + if output is None: + output = self.output + if isinstance(t, BuiltinType): + value_expr = name + if t.name.split(' ')[-1] == '_Bool': + # Hack to work around PR5579. + value_expr = "%s ? 2 : 0" % name + + if t.name.endswith('long long'): + code = 'lld' + elif t.name.endswith('long'): + code = 'ld' + elif t.name.split(' ')[-1] in ('_Bool','char','short', + 'int','unsigned'): + code = 'd' + elif t.name in ('float','double'): + code = 'f' + elif t.name == 'long double': + code = 'Lf' + else: + code = 'p' + print >>output, '%*sprintf("%s: %s = %%%s\\n", %s);'%( + indent, '', prefix, name, code, value_expr) + elif isinstance(t, EnumType): + print >>output, '%*sprintf("%s: %s = %%d\\n", %s);'%(indent, '', prefix, name, name) + elif isinstance(t, RecordType): + if not t.fields: + print >>output, '%*sprintf("%s: %s (empty)\\n");'%(indent, '', prefix, name) + for i,f in enumerate(t.fields): + if f.isPaddingBitField(): + continue + fname = '%s.field%d'%(name,i) + self.printValueOfType(prefix, fname, f, output=output, indent=indent) + elif isinstance(t, ComplexType): + self.printValueOfType(prefix, '(__real %s)'%name, t.elementType, output=output,indent=indent) + self.printValueOfType(prefix, '(__imag %s)'%name, t.elementType, output=output,indent=indent) + elif isinstance(t, ArrayType): + for i in range(t.numElements): + # Access in this fashion as a hackish way to portably + # access vectors. + if t.isVector: + self.printValueOfType(prefix, '((%s*) &%s)[%d]'%(t.elementType,name,i), t.elementType, output=output,indent=indent) + else: + self.printValueOfType(prefix, '%s[%d]'%(name,i), t.elementType, output=output,indent=indent) + else: + raise NotImplementedError,'Cannot print value of type: "%s"'%(t,) + + def checkTypeValues(self, nameLHS, nameRHS, t, output=None, indent=2): + prefix = 'foo' + if output is None: + output = self.output + if isinstance(t, BuiltinType): + print >>output, '%*sassert(%s == %s);' % (indent, '', nameLHS, nameRHS) + elif isinstance(t, EnumType): + print >>output, '%*sassert(%s == %s);' % (indent, '', nameLHS, nameRHS) + elif isinstance(t, RecordType): + for i,f in enumerate(t.fields): + if f.isPaddingBitField(): + continue + self.checkTypeValues('%s.field%d'%(nameLHS,i), '%s.field%d'%(nameRHS,i), + f, output=output, indent=indent) + if t.isUnion: + break + elif isinstance(t, ComplexType): + self.checkTypeValues('(__real %s)'%nameLHS, '(__real %s)'%nameRHS, t.elementType, output=output,indent=indent) + self.checkTypeValues('(__imag %s)'%nameLHS, '(__imag %s)'%nameRHS, t.elementType, output=output,indent=indent) + elif isinstance(t, ArrayType): + for i in range(t.numElements): + # Access in this fashion as a hackish way to portably + # access vectors. + if t.isVector: + self.checkTypeValues('((%s*) &%s)[%d]'%(t.elementType,nameLHS,i), + '((%s*) &%s)[%d]'%(t.elementType,nameRHS,i), + t.elementType, output=output,indent=indent) + else: + self.checkTypeValues('%s[%d]'%(nameLHS,i), '%s[%d]'%(nameRHS,i), + t.elementType, output=output,indent=indent) + else: + raise NotImplementedError,'Cannot print value of type: "%s"'%(t,) + +import sys + +def main(): + from optparse import OptionParser, OptionGroup + parser = OptionParser("%prog [options] {indices}") + parser.add_option("", "--mode", dest="mode", + help="autogeneration mode (random or linear) [default %default]", + type='choice', choices=('random','linear'), default='linear') + parser.add_option("", "--count", dest="count", + help="autogenerate COUNT functions according to MODE", + type=int, default=0) + parser.add_option("", "--min", dest="minIndex", metavar="N", + help="start autogeneration with the Nth function type [default %default]", + type=int, default=0) + parser.add_option("", "--max", dest="maxIndex", metavar="N", + help="maximum index for random autogeneration [default %default]", + type=int, default=10000000) + parser.add_option("", "--seed", dest="seed", + help="random number generator seed [default %default]", + type=int, default=1) + parser.add_option("", "--use-random-seed", dest="useRandomSeed", + help="use random value for initial random number generator seed", + action='store_true', default=False) + parser.add_option("", "--skip", dest="skipTests", + help="add a test index to skip", + type=int, action='append', default=[]) + parser.add_option("-o", "--output", dest="output", metavar="FILE", + help="write output to FILE [default %default]", + type=str, default='-') + parser.add_option("-O", "--output-header", dest="outputHeader", metavar="FILE", + help="write header file for output to FILE [default %default]", + type=str, default=None) + parser.add_option("-T", "--output-tests", dest="outputTests", metavar="FILE", + help="write function tests to FILE [default %default]", + type=str, default=None) + parser.add_option("-D", "--output-driver", dest="outputDriver", metavar="FILE", + help="write test driver to FILE [default %default]", + type=str, default=None) + parser.add_option("", "--test-layout", dest="testLayout", metavar="FILE", + help="test structure layout", + action='store_true', default=False) + + group = OptionGroup(parser, "Type Enumeration Options") + # Builtins - Ints + group.add_option("", "--no-char", dest="useChar", + help="do not generate char types", + action="store_false", default=True) + group.add_option("", "--no-short", dest="useShort", + help="do not generate short types", + action="store_false", default=True) + group.add_option("", "--no-int", dest="useInt", + help="do not generate int types", + action="store_false", default=True) + group.add_option("", "--no-long", dest="useLong", + help="do not generate long types", + action="store_false", default=True) + group.add_option("", "--no-long-long", dest="useLongLong", + help="do not generate long long types", + action="store_false", default=True) + group.add_option("", "--no-unsigned", dest="useUnsigned", + help="do not generate unsigned integer types", + action="store_false", default=True) + + # Other builtins + group.add_option("", "--no-bool", dest="useBool", + help="do not generate bool types", + action="store_false", default=True) + group.add_option("", "--no-float", dest="useFloat", + help="do not generate float types", + action="store_false", default=True) + group.add_option("", "--no-double", dest="useDouble", + help="do not generate double types", + action="store_false", default=True) + group.add_option("", "--no-long-double", dest="useLongDouble", + help="do not generate long double types", + action="store_false", default=True) + group.add_option("", "--no-void-pointer", dest="useVoidPointer", + help="do not generate void* types", + action="store_false", default=True) + + # Enumerations + group.add_option("", "--no-enums", dest="useEnum", + help="do not generate enum types", + action="store_false", default=True) + + # Derived types + group.add_option("", "--no-array", dest="useArray", + help="do not generate record types", + action="store_false", default=True) + group.add_option("", "--no-complex", dest="useComplex", + help="do not generate complex types", + action="store_false", default=True) + group.add_option("", "--no-record", dest="useRecord", + help="do not generate record types", + action="store_false", default=True) + group.add_option("", "--no-union", dest="recordUseUnion", + help="do not generate union types", + action="store_false", default=True) + group.add_option("", "--no-vector", dest="useVector", + help="do not generate vector types", + action="store_false", default=True) + group.add_option("", "--no-bit-field", dest="useBitField", + help="do not generate bit-field record members", + action="store_false", default=True) + group.add_option("", "--no-builtins", dest="useBuiltins", + help="do not use any types", + action="store_false", default=True) + + # Tuning + group.add_option("", "--no-function-return", dest="functionUseReturn", + help="do not generate return types for functions", + action="store_false", default=True) + group.add_option("", "--vector-types", dest="vectorTypes", + help="comma separated list of vector types (e.g., v2i32) [default %default]", + action="store", type=str, default='v2i16, v1i64, v2i32, v4i16, v8i8, v2f32, v2i64, v4i32, v8i16, v16i8, v2f64, v4f32, v16f32', metavar="N") + group.add_option("", "--bit-fields", dest="bitFields", + help="comma separated list 'type:width' bit-field specifiers [default %default]", + action="store", type=str, default=( + "char:0,char:4,int:0,unsigned:1,int:1,int:4,int:13,int:24")) + group.add_option("", "--max-args", dest="functionMaxArgs", + help="maximum number of arguments per function [default %default]", + action="store", type=int, default=4, metavar="N") + group.add_option("", "--max-array", dest="arrayMaxSize", + help="maximum array size [default %default]", + action="store", type=int, default=4, metavar="N") + group.add_option("", "--max-record", dest="recordMaxSize", + help="maximum number of fields per record [default %default]", + action="store", type=int, default=4, metavar="N") + group.add_option("", "--max-record-depth", dest="recordMaxDepth", + help="maximum nested structure depth [default %default]", + action="store", type=int, default=None, metavar="N") + parser.add_option_group(group) + (opts, args) = parser.parse_args() + + if not opts.useRandomSeed: + random.seed(opts.seed) + + # Contruct type generator + builtins = [] + if opts.useBuiltins: + ints = [] + if opts.useChar: ints.append(('char',1)) + if opts.useShort: ints.append(('short',2)) + if opts.useInt: ints.append(('int',4)) + # FIXME: Wrong size. + if opts.useLong: ints.append(('long',4)) + if opts.useLongLong: ints.append(('long long',8)) + if opts.useUnsigned: + ints = ([('unsigned %s'%i,s) for i,s in ints] + + [('signed %s'%i,s) for i,s in ints]) + builtins.extend(ints) + + if opts.useBool: builtins.append(('_Bool',1)) + if opts.useFloat: builtins.append(('float',4)) + if opts.useDouble: builtins.append(('double',8)) + if opts.useLongDouble: builtins.append(('long double',16)) + # FIXME: Wrong size. + if opts.useVoidPointer: builtins.append(('void*',4)) + + btg = FixedTypeGenerator([BuiltinType(n,s) for n,s in builtins]) + + bitfields = [] + for specifier in opts.bitFields.split(','): + if not specifier.strip(): + continue + name,width = specifier.strip().split(':', 1) + bitfields.append(BuiltinType(name,None,int(width))) + bftg = FixedTypeGenerator(bitfields) + + charType = BuiltinType('char',1) + shortType = BuiltinType('short',2) + intType = BuiltinType('int',4) + longlongType = BuiltinType('long long',8) + floatType = BuiltinType('float',4) + doubleType = BuiltinType('double',8) + sbtg = FixedTypeGenerator([charType, intType, floatType, doubleType]) + + atg = AnyTypeGenerator() + artg = AnyTypeGenerator() + def makeGenerator(atg, subgen, subfieldgen, useRecord, useArray, useBitField): + atg.addGenerator(btg) + if useBitField and opts.useBitField: + atg.addGenerator(bftg) + if useRecord and opts.useRecord: + assert subgen + atg.addGenerator(RecordTypeGenerator(subfieldgen, opts.recordUseUnion, + opts.recordMaxSize)) + if opts.useComplex: + # FIXME: Allow overriding builtins here + atg.addGenerator(ComplexTypeGenerator(sbtg)) + if useArray and opts.useArray: + assert subgen + atg.addGenerator(ArrayTypeGenerator(subgen, opts.arrayMaxSize)) + if opts.useVector: + vTypes = [] + for i,t in enumerate(opts.vectorTypes.split(',')): + m = re.match('v([1-9][0-9]*)([if][1-9][0-9]*)', t.strip()) + if not m: + parser.error('Invalid vector type: %r' % t) + count,kind = m.groups() + count = int(count) + type = { 'i8' : charType, + 'i16' : shortType, + 'i32' : intType, + 'i64' : longlongType, + 'f32' : floatType, + 'f64' : doubleType, + }.get(kind) + if not type: + parser.error('Invalid vector type: %r' % t) + vTypes.append(ArrayType(i, True, type, count * type.size)) + + atg.addGenerator(FixedTypeGenerator(vTypes)) + if opts.useEnum: + atg.addGenerator(EnumTypeGenerator([None, '-1', '1', '1u'], 1, 4)) + + if opts.recordMaxDepth is None: + # Fully recursive, just avoid top-level arrays. + subFTG = AnyTypeGenerator() + subTG = AnyTypeGenerator() + atg = AnyTypeGenerator() + makeGenerator(subFTG, atg, atg, True, True, True) + makeGenerator(subTG, atg, subFTG, True, True, False) + makeGenerator(atg, subTG, subFTG, True, False, False) + else: + # Make a chain of type generators, each builds smaller + # structures. + base = AnyTypeGenerator() + fbase = AnyTypeGenerator() + makeGenerator(base, None, None, False, False, False) + makeGenerator(fbase, None, None, False, False, True) + for i in range(opts.recordMaxDepth): + n = AnyTypeGenerator() + fn = AnyTypeGenerator() + makeGenerator(n, base, fbase, True, True, False) + makeGenerator(fn, base, fbase, True, True, True) + base = n + fbase = fn + atg = AnyTypeGenerator() + makeGenerator(atg, base, fbase, True, False, False) + + if opts.testLayout: + ftg = atg + else: + ftg = FunctionTypeGenerator(atg, opts.functionUseReturn, opts.functionMaxArgs) + + # Override max,min,count if finite + if opts.maxIndex is None: + if ftg.cardinality is aleph0: + opts.maxIndex = 10000000 + else: + opts.maxIndex = ftg.cardinality + opts.maxIndex = min(opts.maxIndex, ftg.cardinality) + opts.minIndex = max(0,min(opts.maxIndex-1, opts.minIndex)) + if not opts.mode=='random': + opts.count = min(opts.count, opts.maxIndex-opts.minIndex) + + if opts.output=='-': + output = sys.stdout + else: + output = open(opts.output,'w') + atexit.register(lambda: output.close()) + + outputHeader = None + if opts.outputHeader: + outputHeader = open(opts.outputHeader,'w') + atexit.register(lambda: outputHeader.close()) + + outputTests = None + if opts.outputTests: + outputTests = open(opts.outputTests,'w') + atexit.register(lambda: outputTests.close()) + + outputDriver = None + if opts.outputDriver: + outputDriver = open(opts.outputDriver,'w') + atexit.register(lambda: outputDriver.close()) + + info = '' + info += '// %s\n'%(' '.join(sys.argv),) + info += '// Generated: %s\n'%(time.strftime('%Y-%m-%d %H:%M'),) + info += '// Cardinality of function generator: %s\n'%(ftg.cardinality,) + info += '// Cardinality of type generator: %s\n'%(atg.cardinality,) + + if opts.testLayout: + info += '\n#include <stdio.h>' + + P = TypePrinter(output, + outputHeader=outputHeader, + outputTests=outputTests, + outputDriver=outputDriver, + headerName=opts.outputHeader, + info=info) + + def write(N): + try: + FT = ftg.get(N) + except RuntimeError,e: + if e.args[0]=='maximum recursion depth exceeded': + print >>sys.stderr,'WARNING: Skipped %d, recursion limit exceeded (bad arguments?)'%(N,) + return + raise + if opts.testLayout: + P.writeLayoutTest(N, FT) + else: + P.writeFunction(N, FT) + + if args: + [write(int(a)) for a in args] + + skipTests = set(opts.skipTests) + for i in range(opts.count): + if opts.mode=='linear': + index = opts.minIndex + i + else: + index = opts.minIndex + int((opts.maxIndex-opts.minIndex) * random.random()) + if index in skipTests: + continue + write(index) + + P.finish() + +if __name__=='__main__': + main() + diff --git a/clang/utils/ABITest/Enumeration.py b/clang/utils/ABITest/Enumeration.py new file mode 100644 index 0000000..47e4702 --- /dev/null +++ b/clang/utils/ABITest/Enumeration.py @@ -0,0 +1,276 @@ +"""Utilities for enumeration of finite and countably infinite sets. +""" +### +# Countable iteration + +# Simplifies some calculations +class Aleph0(int): + _singleton = None + def __new__(type): + if type._singleton is None: + type._singleton = int.__new__(type) + return type._singleton + def __repr__(self): return '<aleph0>' + def __str__(self): return 'inf' + + def __cmp__(self, b): + return 1 + + def __sub__(self, b): + raise ValueError,"Cannot subtract aleph0" + __rsub__ = __sub__ + + def __add__(self, b): + return self + __radd__ = __add__ + + def __mul__(self, b): + if b == 0: return b + return self + __rmul__ = __mul__ + + def __floordiv__(self, b): + if b == 0: raise ZeroDivisionError + return self + __rfloordiv__ = __floordiv__ + __truediv__ = __floordiv__ + __rtuediv__ = __floordiv__ + __div__ = __floordiv__ + __rdiv__ = __floordiv__ + + def __pow__(self, b): + if b == 0: return 1 + return self +aleph0 = Aleph0() + +def base(line): + return line*(line+1)//2 + +def pairToN((x,y)): + line,index = x+y,y + return base(line)+index + +def getNthPairInfo(N): + # Avoid various singularities + if N==0: + return (0,0) + + # Gallop to find bounds for line + line = 1 + next = 2 + while base(next)<=N: + line = next + next = line << 1 + + # Binary search for starting line + lo = line + hi = line<<1 + while lo + 1 != hi: + #assert base(lo) <= N < base(hi) + mid = (lo + hi)>>1 + if base(mid)<=N: + lo = mid + else: + hi = mid + + line = lo + return line, N - base(line) + +def getNthPair(N): + line,index = getNthPairInfo(N) + return (line - index, index) + +def getNthPairBounded(N,W=aleph0,H=aleph0,useDivmod=False): + """getNthPairBounded(N, W, H) -> (x, y) + + Return the N-th pair such that 0 <= x < W and 0 <= y < H.""" + + if W <= 0 or H <= 0: + raise ValueError,"Invalid bounds" + elif N >= W*H: + raise ValueError,"Invalid input (out of bounds)" + + # Simple case... + if W is aleph0 and H is aleph0: + return getNthPair(N) + + # Otherwise simplify by assuming W < H + if H < W: + x,y = getNthPairBounded(N,H,W,useDivmod=useDivmod) + return y,x + + if useDivmod: + return N%W,N//W + else: + # Conceptually we want to slide a diagonal line across a + # rectangle. This gives more interesting results for large + # bounds than using divmod. + + # If in lower left, just return as usual + cornerSize = base(W) + if N < cornerSize: + return getNthPair(N) + + # Otherwise if in upper right, subtract from corner + if H is not aleph0: + M = W*H - N - 1 + if M < cornerSize: + x,y = getNthPair(M) + return (W-1-x,H-1-y) + + # Otherwise, compile line and index from number of times we + # wrap. + N = N - cornerSize + index,offset = N%W,N//W + # p = (W-1, 1+offset) + (-1,1)*index + return (W-1-index, 1+offset+index) +def getNthPairBoundedChecked(N,W=aleph0,H=aleph0,useDivmod=False,GNP=getNthPairBounded): + x,y = GNP(N,W,H,useDivmod) + assert 0 <= x < W and 0 <= y < H + return x,y + +def getNthNTuple(N, W, H=aleph0, useLeftToRight=False): + """getNthNTuple(N, W, H) -> (x_0, x_1, ..., x_W) + + Return the N-th W-tuple, where for 0 <= x_i < H.""" + + if useLeftToRight: + elts = [None]*W + for i in range(W): + elts[i],N = getNthPairBounded(N, H) + return tuple(elts) + else: + if W==0: + return () + elif W==1: + return (N,) + elif W==2: + return getNthPairBounded(N, H, H) + else: + LW,RW = W//2, W - (W//2) + L,R = getNthPairBounded(N, H**LW, H**RW) + return (getNthNTuple(L,LW,H=H,useLeftToRight=useLeftToRight) + + getNthNTuple(R,RW,H=H,useLeftToRight=useLeftToRight)) +def getNthNTupleChecked(N, W, H=aleph0, useLeftToRight=False, GNT=getNthNTuple): + t = GNT(N,W,H,useLeftToRight) + assert len(t) == W + for i in t: + assert i < H + return t + +def getNthTuple(N, maxSize=aleph0, maxElement=aleph0, useDivmod=False, useLeftToRight=False): + """getNthTuple(N, maxSize, maxElement) -> x + + Return the N-th tuple where len(x) < maxSize and for y in x, 0 <= + y < maxElement.""" + + # All zero sized tuples are isomorphic, don't ya know. + if N == 0: + return () + N -= 1 + if maxElement is not aleph0: + if maxSize is aleph0: + raise NotImplementedError,'Max element size without max size unhandled' + bounds = [maxElement**i for i in range(1, maxSize+1)] + S,M = getNthPairVariableBounds(N, bounds) + else: + S,M = getNthPairBounded(N, maxSize, useDivmod=useDivmod) + return getNthNTuple(M, S+1, maxElement, useLeftToRight=useLeftToRight) +def getNthTupleChecked(N, maxSize=aleph0, maxElement=aleph0, + useDivmod=False, useLeftToRight=False, GNT=getNthTuple): + # FIXME: maxsize is inclusive + t = GNT(N,maxSize,maxElement,useDivmod,useLeftToRight) + assert len(t) <= maxSize + for i in t: + assert i < maxElement + return t + +def getNthPairVariableBounds(N, bounds): + """getNthPairVariableBounds(N, bounds) -> (x, y) + + Given a finite list of bounds (which may be finite or aleph0), + return the N-th pair such that 0 <= x < len(bounds) and 0 <= y < + bounds[x].""" + + if not bounds: + raise ValueError,"Invalid bounds" + if not (0 <= N < sum(bounds)): + raise ValueError,"Invalid input (out of bounds)" + + level = 0 + active = range(len(bounds)) + active.sort(key=lambda i: bounds[i]) + prevLevel = 0 + for i,index in enumerate(active): + level = bounds[index] + W = len(active) - i + if level is aleph0: + H = aleph0 + else: + H = level - prevLevel + levelSize = W*H + if N<levelSize: # Found the level + idelta,delta = getNthPairBounded(N, W, H) + return active[i+idelta],prevLevel+delta + else: + N -= levelSize + prevLevel = level + else: + raise RuntimError,"Unexpected loop completion" + +def getNthPairVariableBoundsChecked(N, bounds, GNVP=getNthPairVariableBounds): + x,y = GNVP(N,bounds) + assert 0 <= x < len(bounds) and 0 <= y < bounds[x] + return (x,y) + +### + +def testPairs(): + W = 3 + H = 6 + a = [[' ' for x in range(10)] for y in range(10)] + b = [[' ' for x in range(10)] for y in range(10)] + for i in range(min(W*H,40)): + x,y = getNthPairBounded(i,W,H) + x2,y2 = getNthPairBounded(i,W,H,useDivmod=True) + print i,(x,y),(x2,y2) + a[y][x] = '%2d'%i + b[y2][x2] = '%2d'%i + + print '-- a --' + for ln in a[::-1]: + if ''.join(ln).strip(): + print ' '.join(ln) + print '-- b --' + for ln in b[::-1]: + if ''.join(ln).strip(): + print ' '.join(ln) + +def testPairsVB(): + bounds = [2,2,4,aleph0,5,aleph0] + a = [[' ' for x in range(15)] for y in range(15)] + b = [[' ' for x in range(15)] for y in range(15)] + for i in range(min(sum(bounds),40)): + x,y = getNthPairVariableBounds(i, bounds) + print i,(x,y) + a[y][x] = '%2d'%i + + print '-- a --' + for ln in a[::-1]: + if ''.join(ln).strip(): + print ' '.join(ln) + +### + +# Toggle to use checked versions of enumeration routines. +if False: + getNthPairVariableBounds = getNthPairVariableBoundsChecked + getNthPairBounded = getNthPairBoundedChecked + getNthNTuple = getNthNTupleChecked + getNthTuple = getNthTupleChecked + +if __name__ == '__main__': + testPairs() + + testPairsVB() + diff --git a/clang/utils/ABITest/Makefile.test.common b/clang/utils/ABITest/Makefile.test.common new file mode 100644 index 0000000..3c208ad --- /dev/null +++ b/clang/utils/ABITest/Makefile.test.common @@ -0,0 +1,170 @@ +# -*- Makefile -*- + +# Usage: make test.N.report +# +# COUNT can be over-ridden to change the number of tests generated per +# file, and TESTARGS is used to change the type generation. Make sure +# to 'make clean' after changing either of these parameters. + +TESTARGS := --no-unsigned --no-vector --no-complex --no-bool + +COUNT := 1 +TIMEOUT := 5 + +CFLAGS := -std=gnu99 + +X_COMPILER := gcc +X_LL_CFLAGS := -emit-llvm -S +Y_COMPILER := clang +Y_LL_CFLAGS := -emit-llvm -S +CC := gcc + +### + +ABITESTGEN := ../ABITestGen.py + +ifndef VERBOSE + Verb := @ +endif + +.PHONY: test.%.report +test.%.report: temps/test.%.xx.diff temps/test.%.xy.diff temps/test.%.yx.diff temps/test.%.yy.diff + @ok=1;\ + for t in $^; do \ + if [ -s $$t ]; then \ + echo "TEST $*: $$t failed"; \ + ok=0;\ + fi; \ + done; \ + if [ $$ok -eq 1 ]; then \ + true; \ + else \ + false; \ + fi + + +.PHONY: test.%.defs-report +test.%.defs-report: temps/test.%.defs.diff + @for t in $^; do \ + if [ -s $$t ]; then \ + echo "TEST $*: $$t failed"; \ + cat $$t; \ + fi; \ + done + +.PHONY: test.%.build +test.%.build: temps/test.%.ref temps/test.%.xx temps/test.%.xy temps/test.%.yx temps/test.%.yy temps/test.%.x.defs temps/test.%.y.defs + @true + +### + +# Diffs and output + +.PRECIOUS: temps/.dir + +.PRECIOUS: temps/test.%.xx.diff +temps/test.%.xx.diff: temps/test.%.ref.out temps/test.%.xx.out + $(Verb) diff $^ > $@ || true +.PRECIOUS: temps/test.%.xy.diff +temps/test.%.xy.diff: temps/test.%.ref.out temps/test.%.xy.out + $(Verb) diff $^ > $@ || true +.PRECIOUS: temps/test.%.yx.diff +temps/test.%.yx.diff: temps/test.%.ref.out temps/test.%.yx.out + $(Verb) diff $^ > $@ || true +.PRECIOUS: temps/test.%.yy.diff +temps/test.%.yy.diff: temps/test.%.ref.out temps/test.%.yy.out + $(Verb) diff $^ > $@ || true +.PRECIOUS: temps/test.%.defs.diff +temps/test.%.defs.diff: temps/test.%.x.defs temps/test.%.y.defs + $(Verb) zipdifflines \ + --replace "%struct.T[0-9]+" "%struct.s" \ + --replace "%union.T[0-9]+" "%struct.s" \ + --replace "byval align [0-9]+" "byval" \ + $^ > $@ + +.PRECIOUS: temps/test.%.out +temps/test.%.out: temps/test.% + -$(Verb) ./$< > $@ + +# Executables + +.PRECIOUS: temps/test.%.ref +temps/test.%.ref: temps/test.%.driver.ref.o temps/test.%.a.ref.o temps/test.%.b.ref.o + $(Verb) $(CC) $(CFLAGS) $(CC_CFLAGS) -O3 -o $@ $^ +.PRECIOUS: temps/test.%.xx +temps/test.%.xx: temps/test.%.driver.ref.o temps/test.%.a.x.o temps/test.%.b.x.o + $(Verb) $(CC) $(CFLAGS) $(CC_CFLAGS) -O3 -o $@ $^ +.PRECIOUS: temps/test.%.xy +temps/test.%.xy: temps/test.%.driver.ref.o temps/test.%.a.x.o temps/test.%.b.y.o + $(Verb) $(CC) $(CFLAGS) $(CC_CFLAGS) -O3 -o $@ $^ +.PRECIOUS: temps/test.%.yx +temps/test.%.yx: temps/test.%.driver.ref.o temps/test.%.a.y.o temps/test.%.b.x.o + $(Verb) $(CC) $(CFLAGS) $(CC_CFLAGS) -O3 -o $@ $^ +.PRECIOUS: temps/test.%.yy +temps/test.%.yy: temps/test.%.driver.ref.o temps/test.%.a.y.o temps/test.%.b.y.o + $(Verb) $(CC) $(CFLAGS) $(CC_CFLAGS) -O3 -o $@ $^ + +# Object files + +.PRECIOUS: temps/test.%.ref.o +temps/test.%.ref.o: inputs/test.%.c temps/.dir + $(Verb) $(CC) -c $(CFLAGS) $(CC_CFLAGS) -o $@ $< +.PRECIOUS: temps/test.%.x.o +temps/test.%.x.o: inputs/test.%.c temps/.dir + $(Verb) $(X_COMPILER) -c $(CFLAGS) $(X_CFLAGS) -o $@ $< +.PRECIOUS: temps/test.%.y.o +temps/test.%.y.o: inputs/test.%.c temps/.dir + $(Verb) $(Y_COMPILER) -c $(CFLAGS) $(Y_CFLAGS) -o $@ $< + +.PRECIOUS: temps/test.%.x.defs +temps/test.%.x.defs: temps/test.%.a.x.ll temps/.dir + -$(Verb) -grep '^define ' $< > $@ +.PRECIOUS: temps/test.%.y.defs +temps/test.%.y.defs: temps/test.%.a.y.ll temps/.dir + -$(Verb) -grep '^define ' $< > $@ + +.PRECIOUS: temps/test.%.a.x.ll +temps/test.%.a.x.ll: inputs/test.%.a.c temps/.dir + $(Verb) $(X_COMPILER) $(CFLAGS) $(X_LL_CFLAGS) $(X_CFLAGS) -o $@ $< +.PRECIOUS: temps/test.%.b.x.ll +temps/test.%.b.x.ll: inputs/test.%.b.c temps/.dir + $(Verb) $(X_COMPILER) $(CFLAGS) $(X_LL_CFLAGS) $(X_CFLAGS) -o $@ $< +.PRECIOUS: temps/test.%.a.y.ll +temps/test.%.a.y.ll: inputs/test.%.a.c temps/.dir + $(Verb) $(Y_COMPILER) $(CFLAGS) $(Y_LL_CFLAGS) $(Y_CFLAGS) -o $@ $< +.PRECIOUS: temps/test.%.b.y.ll +temps/test.%.b.y.ll: inputs/test.%.b.c temps/.dir + $(Verb) $(Y_COMPILER) $(CFLAGS) $(Y_LL_CFLAGS) $(Y_CFLAGS) -o $@ $< + +# Input generation + +.PHONY: test.%.top +test.%.top: inputs/test.%.a.c inputs/test.%.b.c inputs/test.%.driver.c + @true + +.PRECIOUS: inputs/test.%.a.c inputs/test.%.b.c inputs/test.%.driver.c +inputs/test.%.a.c: test.%.generate + @true +inputs/test.%.b.c: test.%.generate + @true +inputs/test.%.driver.c: test.%.generate + @true + +.PHONY: test.%.generate +.PRECIOUS: inputs/.dir +test.%.generate: $(ABITESTGEN) inputs/.dir + $(Verb) $(ABITESTGEN) $(TESTARGS) -o inputs/test.$*.a.c -T inputs/test.$*.b.c -D inputs/test.$*.driver.c --min=$(shell expr $* '*' $(COUNT)) --count=$(COUNT) + +# Cleaning + +clean-temps: + $(Verb) rm -rf temps + +clean: + $(Verb) rm -rf temps inputs + +# Etc. + +%/.dir: + $(Verb) mkdir -p $* > /dev/null + $(Verb) $(DATE) > $@ diff --git a/clang/utils/ABITest/TypeGen.py b/clang/utils/ABITest/TypeGen.py new file mode 100644 index 0000000..7a99d62 --- /dev/null +++ b/clang/utils/ABITest/TypeGen.py @@ -0,0 +1,471 @@ +"""Flexible enumeration of C types.""" + +from Enumeration import * + +# TODO: + +# - struct improvements (flexible arrays, packed & +# unpacked, alignment) +# - objective-c qualified id +# - anonymous / transparent unions +# - VLAs +# - block types +# - K&R functions +# - pass arguments of different types (test extension, transparent union) +# - varargs + +### +# Actual type types + +class Type: + def isBitField(self): + return False + + def isPaddingBitField(self): + return False + + def getTypeName(self, printer): + name = 'T%d' % len(printer.types) + typedef = self.getTypedefDef(name, printer) + printer.addDeclaration(typedef) + return name + +class BuiltinType(Type): + def __init__(self, name, size, bitFieldSize=None): + self.name = name + self.size = size + self.bitFieldSize = bitFieldSize + + def isBitField(self): + return self.bitFieldSize is not None + + def isPaddingBitField(self): + return self.bitFieldSize is 0 + + def getBitFieldSize(self): + assert self.isBitField() + return self.bitFieldSize + + def getTypeName(self, printer): + return self.name + + def sizeof(self): + return self.size + + def __str__(self): + return self.name + +class EnumType(Type): + def __init__(self, index, enumerators): + self.index = index + self.enumerators = enumerators + + def getEnumerators(self): + result = '' + for i, init in enumerate(self.enumerators): + if i > 0: + result = result + ', ' + result = result + 'enum%dval%d' % (self.index, i) + if init: + result = result + ' = %s' % (init) + + return result + + def __str__(self): + return 'enum { %s }' % (self.getEnumerators()) + + def getTypedefDef(self, name, printer): + return 'typedef enum %s { %s } %s;'%(name, self.getEnumerators(), name) + +class RecordType(Type): + def __init__(self, index, isUnion, fields): + self.index = index + self.isUnion = isUnion + self.fields = fields + self.name = None + + def __str__(self): + def getField(t): + if t.isBitField(): + return "%s : %d;" % (t, t.getBitFieldSize()) + else: + return "%s;" % t + + return '%s { %s }'%(('struct','union')[self.isUnion], + ' '.join(map(getField, self.fields))) + + def getTypedefDef(self, name, printer): + def getField((i, t)): + if t.isBitField(): + if t.isPaddingBitField(): + return '%s : 0;'%(printer.getTypeName(t),) + else: + return '%s field%d : %d;'%(printer.getTypeName(t),i, + t.getBitFieldSize()) + else: + return '%s field%d;'%(printer.getTypeName(t),i) + fields = map(getField, enumerate(self.fields)) + # Name the struct for more readable LLVM IR. + return 'typedef %s %s { %s } %s;'%(('struct','union')[self.isUnion], + name, ' '.join(fields), name) + +class ArrayType(Type): + def __init__(self, index, isVector, elementType, size): + if isVector: + # Note that for vectors, this is the size in bytes. + assert size > 0 + else: + assert size is None or size >= 0 + self.index = index + self.isVector = isVector + self.elementType = elementType + self.size = size + if isVector: + eltSize = self.elementType.sizeof() + assert not (self.size % eltSize) + self.numElements = self.size // eltSize + else: + self.numElements = self.size + + def __str__(self): + if self.isVector: + return 'vector (%s)[%d]'%(self.elementType,self.size) + elif self.size is not None: + return '(%s)[%d]'%(self.elementType,self.size) + else: + return '(%s)[]'%(self.elementType,) + + def getTypedefDef(self, name, printer): + elementName = printer.getTypeName(self.elementType) + if self.isVector: + return 'typedef %s %s __attribute__ ((vector_size (%d)));'%(elementName, + name, + self.size) + else: + if self.size is None: + sizeStr = '' + else: + sizeStr = str(self.size) + return 'typedef %s %s[%s];'%(elementName, name, sizeStr) + +class ComplexType(Type): + def __init__(self, index, elementType): + self.index = index + self.elementType = elementType + + def __str__(self): + return '_Complex (%s)'%(self.elementType) + + def getTypedefDef(self, name, printer): + return 'typedef _Complex %s %s;'%(printer.getTypeName(self.elementType), name) + +class FunctionType(Type): + def __init__(self, index, returnType, argTypes): + self.index = index + self.returnType = returnType + self.argTypes = argTypes + + def __str__(self): + if self.returnType is None: + rt = 'void' + else: + rt = str(self.returnType) + if not self.argTypes: + at = 'void' + else: + at = ', '.join(map(str, self.argTypes)) + return '%s (*)(%s)'%(rt, at) + + def getTypedefDef(self, name, printer): + if self.returnType is None: + rt = 'void' + else: + rt = str(self.returnType) + if not self.argTypes: + at = 'void' + else: + at = ', '.join(map(str, self.argTypes)) + return 'typedef %s (*%s)(%s);'%(rt, name, at) + +### +# Type enumerators + +class TypeGenerator(object): + def __init__(self): + self.cache = {} + + def setCardinality(self): + abstract + + def get(self, N): + T = self.cache.get(N) + if T is None: + assert 0 <= N < self.cardinality + T = self.cache[N] = self.generateType(N) + return T + + def generateType(self, N): + abstract + +class FixedTypeGenerator(TypeGenerator): + def __init__(self, types): + TypeGenerator.__init__(self) + self.types = types + self.setCardinality() + + def setCardinality(self): + self.cardinality = len(self.types) + + def generateType(self, N): + return self.types[N] + +# Factorial +def fact(n): + result = 1 + while n > 0: + result = result * n + n = n - 1 + return result + +# Compute the number of combinations (n choose k) +def num_combinations(n, k): + return fact(n) / (fact(k) * fact(n - k)) + +# Enumerate the combinations choosing k elements from the list of values +def combinations(values, k): + # From ActiveState Recipe 190465: Generator for permutations, + # combinations, selections of a sequence + if k==0: yield [] + else: + for i in xrange(len(values)-k+1): + for cc in combinations(values[i+1:],k-1): + yield [values[i]]+cc + +class EnumTypeGenerator(TypeGenerator): + def __init__(self, values, minEnumerators, maxEnumerators): + TypeGenerator.__init__(self) + self.values = values + self.minEnumerators = minEnumerators + self.maxEnumerators = maxEnumerators + self.setCardinality() + + def setCardinality(self): + self.cardinality = 0 + for num in range(self.minEnumerators, self.maxEnumerators + 1): + self.cardinality += num_combinations(len(self.values), num) + + def generateType(self, n): + # Figure out the number of enumerators in this type + numEnumerators = self.minEnumerators + valuesCovered = 0 + while numEnumerators < self.maxEnumerators: + comb = num_combinations(len(self.values), numEnumerators) + if valuesCovered + comb > n: + break + numEnumerators = numEnumerators + 1 + valuesCovered += comb + + # Find the requested combination of enumerators and build a + # type from it. + i = 0 + for enumerators in combinations(self.values, numEnumerators): + if i == n - valuesCovered: + return EnumType(n, enumerators) + + i = i + 1 + + assert False + +class ComplexTypeGenerator(TypeGenerator): + def __init__(self, typeGen): + TypeGenerator.__init__(self) + self.typeGen = typeGen + self.setCardinality() + + def setCardinality(self): + self.cardinality = self.typeGen.cardinality + + def generateType(self, N): + return ComplexType(N, self.typeGen.get(N)) + +class VectorTypeGenerator(TypeGenerator): + def __init__(self, typeGen, sizes): + TypeGenerator.__init__(self) + self.typeGen = typeGen + self.sizes = tuple(map(int,sizes)) + self.setCardinality() + + def setCardinality(self): + self.cardinality = len(self.sizes)*self.typeGen.cardinality + + def generateType(self, N): + S,T = getNthPairBounded(N, len(self.sizes), self.typeGen.cardinality) + return ArrayType(N, True, self.typeGen.get(T), self.sizes[S]) + +class FixedArrayTypeGenerator(TypeGenerator): + def __init__(self, typeGen, sizes): + TypeGenerator.__init__(self) + self.typeGen = typeGen + self.sizes = tuple(size) + self.setCardinality() + + def setCardinality(self): + self.cardinality = len(self.sizes)*self.typeGen.cardinality + + def generateType(self, N): + S,T = getNthPairBounded(N, len(self.sizes), self.typeGen.cardinality) + return ArrayType(N, false, self.typeGen.get(T), self.sizes[S]) + +class ArrayTypeGenerator(TypeGenerator): + def __init__(self, typeGen, maxSize, useIncomplete=False, useZero=False): + TypeGenerator.__init__(self) + self.typeGen = typeGen + self.useIncomplete = useIncomplete + self.useZero = useZero + self.maxSize = int(maxSize) + self.W = useIncomplete + useZero + self.maxSize + self.setCardinality() + + def setCardinality(self): + self.cardinality = self.W * self.typeGen.cardinality + + def generateType(self, N): + S,T = getNthPairBounded(N, self.W, self.typeGen.cardinality) + if self.useIncomplete: + if S==0: + size = None + S = None + else: + S = S - 1 + if S is not None: + if self.useZero: + size = S + else: + size = S + 1 + return ArrayType(N, False, self.typeGen.get(T), size) + +class RecordTypeGenerator(TypeGenerator): + def __init__(self, typeGen, useUnion, maxSize): + TypeGenerator.__init__(self) + self.typeGen = typeGen + self.useUnion = bool(useUnion) + self.maxSize = int(maxSize) + self.setCardinality() + + def setCardinality(self): + M = 1 + self.useUnion + if self.maxSize is aleph0: + S = aleph0 * self.typeGen.cardinality + else: + S = 0 + for i in range(self.maxSize+1): + S += M * (self.typeGen.cardinality ** i) + self.cardinality = S + + def generateType(self, N): + isUnion,I = False,N + if self.useUnion: + isUnion,I = (I&1),I>>1 + fields = map(self.typeGen.get,getNthTuple(I,self.maxSize,self.typeGen.cardinality)) + return RecordType(N, isUnion, fields) + +class FunctionTypeGenerator(TypeGenerator): + def __init__(self, typeGen, useReturn, maxSize): + TypeGenerator.__init__(self) + self.typeGen = typeGen + self.useReturn = useReturn + self.maxSize = maxSize + self.setCardinality() + + def setCardinality(self): + if self.maxSize is aleph0: + S = aleph0 * self.typeGen.cardinality() + elif self.useReturn: + S = 0 + for i in range(1,self.maxSize+1+1): + S += self.typeGen.cardinality ** i + else: + S = 0 + for i in range(self.maxSize+1): + S += self.typeGen.cardinality ** i + self.cardinality = S + + def generateType(self, N): + if self.useReturn: + # Skip the empty tuple + argIndices = getNthTuple(N+1, self.maxSize+1, self.typeGen.cardinality) + retIndex,argIndices = argIndices[0],argIndices[1:] + retTy = self.typeGen.get(retIndex) + else: + retTy = None + argIndices = getNthTuple(N, self.maxSize, self.typeGen.cardinality) + args = map(self.typeGen.get, argIndices) + return FunctionType(N, retTy, args) + +class AnyTypeGenerator(TypeGenerator): + def __init__(self): + TypeGenerator.__init__(self) + self.generators = [] + self.bounds = [] + self.setCardinality() + self._cardinality = None + + def getCardinality(self): + if self._cardinality is None: + return aleph0 + else: + return self._cardinality + def setCardinality(self): + self.bounds = [g.cardinality for g in self.generators] + self._cardinality = sum(self.bounds) + cardinality = property(getCardinality, None) + + def addGenerator(self, g): + self.generators.append(g) + for i in range(100): + prev = self._cardinality + self._cardinality = None + for g in self.generators: + g.setCardinality() + self.setCardinality() + if (self._cardinality is aleph0) or prev==self._cardinality: + break + else: + raise RuntimeError,"Infinite loop in setting cardinality" + + def generateType(self, N): + index,M = getNthPairVariableBounds(N, self.bounds) + return self.generators[index].get(M) + +def test(): + fbtg = FixedTypeGenerator([BuiltinType('char', 4), + BuiltinType('char', 4, 0), + BuiltinType('int', 4, 5)]) + + fields1 = AnyTypeGenerator() + fields1.addGenerator( fbtg ) + + fields0 = AnyTypeGenerator() + fields0.addGenerator( fbtg ) +# fields0.addGenerator( RecordTypeGenerator(fields1, False, 4) ) + + btg = FixedTypeGenerator([BuiltinType('char', 4), + BuiltinType('int', 4)]) + etg = EnumTypeGenerator([None, '-1', '1', '1u'], 0, 3) + + atg = AnyTypeGenerator() + atg.addGenerator( btg ) + atg.addGenerator( RecordTypeGenerator(fields0, False, 4) ) + atg.addGenerator( etg ) + print 'Cardinality:',atg.cardinality + for i in range(100): + if i == atg.cardinality: + try: + atg.get(i) + raise RuntimeError,"Cardinality was wrong" + except AssertionError: + break + print '%4d: %s'%(i, atg.get(i)) + +if __name__ == '__main__': + test() diff --git a/clang/utils/ABITest/build-and-summarize-all.sh b/clang/utils/ABITest/build-and-summarize-all.sh new file mode 100755 index 0000000..23e34a4 --- /dev/null +++ b/clang/utils/ABITest/build-and-summarize-all.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +set -eu + +if [ $# != 1 ]; then + echo "usage: $0 <num-tests>" + exit 1 +fi + +for bits in 32 64; do + for kind in return-types single-args; do + echo "-- $kind-$bits --" + (cd $kind-$bits && ../build-and-summarize.sh $1) + done +done diff --git a/clang/utils/ABITest/build-and-summarize.sh b/clang/utils/ABITest/build-and-summarize.sh new file mode 100755 index 0000000..602728b --- /dev/null +++ b/clang/utils/ABITest/build-and-summarize.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +set -eu + +if [ $# != 1 ]; then + echo "usage: $0 <num-tests>" + exit 1 +fi + +dir=$(dirname $0) +$dir/build.sh $1 &> /dev/null || true +../summarize.sh $1 &> fails-x.txt +cat fails-x.txt +wc -l fails-x.txt diff --git a/clang/utils/ABITest/build.sh b/clang/utils/ABITest/build.sh new file mode 100755 index 0000000..a50d14a --- /dev/null +++ b/clang/utils/ABITest/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +set -eu + +if [ $# != 1 ]; then + echo "usage: $0 <num-tests>" + exit 1 +fi + +CPUS=2 +make -j $CPUS \ + $(for i in $(seq 0 $1); do echo test.$i.report; done) -k diff --git a/clang/utils/ABITest/layout/Makefile b/clang/utils/ABITest/layout/Makefile new file mode 100644 index 0000000..0520625 --- /dev/null +++ b/clang/utils/ABITest/layout/Makefile @@ -0,0 +1,68 @@ +# Usage: make test.N.report +# +# COUNT can be over-ridden to change the number of tests generated per +# file, and TESTARGS is used to change the type generation. Make sure +# to 'make clean' after changing either of these parameters. + +ABITESTGEN := ../ABITestGen.py +TESTARGS := --max-args 0 --test-layout +COUNT := 1000 +TIMEOUT := 5 + +CFLAGS := -std=gnu99 + +X_COMPILER := llvm-gcc +Y_COMPILER := clang +CC := gcc + +ifeq (0, 0) +X_CFLAGS := -m32 +Y_CFLAGS := -m32 +CC_CFLAGS := -m32 +else +X_CFLAGS := -m64 +Y_CFLAGS := -m64 +CC_CFLAGS := -m64 +endif + +.PHONY: test.%.report +test.%.report: test.%.x.diff test.%.y.diff + @for t in $^; do \ + if [ -s $$t ]; then \ + echo "TEST $*: $$t failed"; \ + fi; \ + done + +.PHONY: test.%.build +test.%.build: test.%.ref test.%.x test.%.y + @true + +### + +.PRECIOUS: test.%.x.diff +test.%.x.diff: test.%.ref.out test.%.x.out + -diff $^ > $@ +.PRECIOUS: test.%.y.diff +test.%.y.diff: test.%.ref.out test.%.y.out + -diff $^ > $@ + +.PRECIOUS: test.%.out +test.%.out: test.% + -./$< > $@ + +.PRECIOUS: test.%.ref +test.%.ref: test.%.c + $(CC) $(CFLAGS) $(CC_CFLAGS) -o $@ $^ +.PRECIOUS: test.%.x +test.%.x: test.%.c + $(X_COMPILER) $(CFLAGS) $(X_CFLAGS) -o $@ $^ +.PRECIOUS: test.%.y +test.%.y: test.%.c + $(Y_COMPILER) $(CFLAGS) $(Y_CFLAGS) -o $@ $^ + +.PRECIOUS: test.%.c +test.%.c: $(ABITESTGEN) + $(ABITESTGEN) $(TESTARGS) -o $@ --min=$(shell expr $* '*' $(COUNT)) --count=$(COUNT) + +clean: + rm -f test.* *~ diff --git a/clang/utils/ABITest/return-types-32/Makefile b/clang/utils/ABITest/return-types-32/Makefile new file mode 100644 index 0000000..df1c53f --- /dev/null +++ b/clang/utils/ABITest/return-types-32/Makefile @@ -0,0 +1,7 @@ +X_CFLAGS := -m32 +Y_CFLAGS := -m32 +CC_CFLAGS := -m32 + +include ../Makefile.test.common + +TESTARGS += --max-args 0 diff --git a/clang/utils/ABITest/return-types-64/Makefile b/clang/utils/ABITest/return-types-64/Makefile new file mode 100644 index 0000000..9616e45 --- /dev/null +++ b/clang/utils/ABITest/return-types-64/Makefile @@ -0,0 +1,7 @@ +X_CFLAGS := -m64 +Y_CFLAGS := -m64 +CC_CFLAGS := -m64 + +include ../Makefile.test.common + +TESTARGS += --max-args 0 diff --git a/clang/utils/ABITest/single-args-32/Makefile b/clang/utils/ABITest/single-args-32/Makefile new file mode 100644 index 0000000..9ff417f --- /dev/null +++ b/clang/utils/ABITest/single-args-32/Makefile @@ -0,0 +1,7 @@ +X_CFLAGS := -m32 +Y_CFLAGS := -m32 +CC_CFLAGS := -m32 + +include ../Makefile.test.common + +TESTARGS += --no-function-return --max-args 1 diff --git a/clang/utils/ABITest/single-args-64/Makefile b/clang/utils/ABITest/single-args-64/Makefile new file mode 100644 index 0000000..b8acb70 --- /dev/null +++ b/clang/utils/ABITest/single-args-64/Makefile @@ -0,0 +1,13 @@ +# Usage: make test.N.report +# +# COUNT can be over-ridden to change the number of tests generated per +# file, and TESTARGS is used to change the type generation. Make sure +# to 'make clean' after changing either of these parameters. + +X_CFLAGS := -m64 +Y_CFLAGS := -m64 +CC_CFLAGS := -m64 + +include ../Makefile.test.common + +TESTARGS += --no-function-return --max-args 1 diff --git a/clang/utils/ABITest/summarize.sh b/clang/utils/ABITest/summarize.sh new file mode 100755 index 0000000..3efb52b --- /dev/null +++ b/clang/utils/ABITest/summarize.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +set -eu + +if [ $# != 1 ]; then + echo "usage: $0 <num-tests>" + exit 1 +fi + +for i in $(seq 0 $1); do + if (! make test.$i.report &> /dev/null); then + echo "FAIL: $i"; + fi; +done + |