xref: /aosp_15_r20/external/clang/utils/ABITest/ABITestGen.py (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li#!/usr/bin/env python
2*67e74705SXin Li
3*67e74705SXin Lifrom pprint import pprint
4*67e74705SXin Liimport random, atexit, time
5*67e74705SXin Lifrom random import randrange
6*67e74705SXin Liimport re
7*67e74705SXin Li
8*67e74705SXin Lifrom Enumeration import *
9*67e74705SXin Lifrom TypeGen import *
10*67e74705SXin Li
11*67e74705SXin Li####
12*67e74705SXin Li
13*67e74705SXin Liclass TypePrinter:
14*67e74705SXin Li    def __init__(self, output, outputHeader=None,
15*67e74705SXin Li                 outputTests=None, outputDriver=None,
16*67e74705SXin Li                 headerName=None, info=None):
17*67e74705SXin Li        self.output = output
18*67e74705SXin Li        self.outputHeader = outputHeader
19*67e74705SXin Li        self.outputTests = outputTests
20*67e74705SXin Li        self.outputDriver = outputDriver
21*67e74705SXin Li        self.writeBody = outputHeader or outputTests or outputDriver
22*67e74705SXin Li        self.types = {}
23*67e74705SXin Li        self.testValues = {}
24*67e74705SXin Li        self.testReturnValues = {}
25*67e74705SXin Li        self.layoutTests = []
26*67e74705SXin Li        self.declarations = set()
27*67e74705SXin Li
28*67e74705SXin Li        if info:
29*67e74705SXin Li            for f in (self.output,self.outputHeader,self.outputTests,self.outputDriver):
30*67e74705SXin Li                if f:
31*67e74705SXin Li                    print >>f,info
32*67e74705SXin Li
33*67e74705SXin Li        if self.writeBody:
34*67e74705SXin Li            print >>self.output, '#include <stdio.h>\n'
35*67e74705SXin Li            if self.outputTests:
36*67e74705SXin Li                print >>self.outputTests, '#include <stdio.h>'
37*67e74705SXin Li                print >>self.outputTests, '#include <string.h>'
38*67e74705SXin Li                print >>self.outputTests, '#include <assert.h>\n'
39*67e74705SXin Li
40*67e74705SXin Li        if headerName:
41*67e74705SXin Li            for f in (self.output,self.outputTests,self.outputDriver):
42*67e74705SXin Li                if f is not None:
43*67e74705SXin Li                    print >>f, '#include "%s"\n'%(headerName,)
44*67e74705SXin Li
45*67e74705SXin Li        if self.outputDriver:
46*67e74705SXin Li            print >>self.outputDriver, '#include <stdio.h>'
47*67e74705SXin Li            print >>self.outputDriver, '#include <stdlib.h>\n'
48*67e74705SXin Li            print >>self.outputDriver, 'int main(int argc, char **argv) {'
49*67e74705SXin Li            print >>self.outputDriver, '  int index = -1;'
50*67e74705SXin Li            print >>self.outputDriver, '  if (argc > 1) index = atoi(argv[1]);'
51*67e74705SXin Li
52*67e74705SXin Li    def finish(self):
53*67e74705SXin Li        if self.layoutTests:
54*67e74705SXin Li            print >>self.output, 'int main(int argc, char **argv) {'
55*67e74705SXin Li            print >>self.output, '  int index = -1;'
56*67e74705SXin Li            print >>self.output, '  if (argc > 1) index = atoi(argv[1]);'
57*67e74705SXin Li            for i,f in self.layoutTests:
58*67e74705SXin Li                print >>self.output, '  if (index == -1 || index == %d)' % i
59*67e74705SXin Li                print >>self.output, '    %s();' % f
60*67e74705SXin Li            print >>self.output, '  return 0;'
61*67e74705SXin Li            print >>self.output, '}'
62*67e74705SXin Li
63*67e74705SXin Li        if self.outputDriver:
64*67e74705SXin Li            print >>self.outputDriver, '  printf("DONE\\n");'
65*67e74705SXin Li            print >>self.outputDriver, '  return 0;'
66*67e74705SXin Li            print >>self.outputDriver, '}'
67*67e74705SXin Li
68*67e74705SXin Li    def addDeclaration(self, decl):
69*67e74705SXin Li        if decl in self.declarations:
70*67e74705SXin Li            return False
71*67e74705SXin Li
72*67e74705SXin Li        self.declarations.add(decl)
73*67e74705SXin Li        if self.outputHeader:
74*67e74705SXin Li            print >>self.outputHeader, decl
75*67e74705SXin Li        else:
76*67e74705SXin Li            print >>self.output, decl
77*67e74705SXin Li            if self.outputTests:
78*67e74705SXin Li                print >>self.outputTests, decl
79*67e74705SXin Li        return True
80*67e74705SXin Li
81*67e74705SXin Li    def getTypeName(self, T):
82*67e74705SXin Li        name = self.types.get(T)
83*67e74705SXin Li        if name is None:
84*67e74705SXin Li            # Reserve slot
85*67e74705SXin Li            self.types[T] = None
86*67e74705SXin Li            self.types[T] = name = T.getTypeName(self)
87*67e74705SXin Li        return name
88*67e74705SXin Li
89*67e74705SXin Li    def writeLayoutTest(self, i, ty):
90*67e74705SXin Li        tyName = self.getTypeName(ty)
91*67e74705SXin Li        tyNameClean = tyName.replace(' ','_').replace('*','star')
92*67e74705SXin Li        fnName = 'test_%s' % tyNameClean
93*67e74705SXin Li
94*67e74705SXin Li        print >>self.output,'void %s(void) {' % fnName
95*67e74705SXin Li        self.printSizeOfType('    %s'%fnName, tyName, ty, self.output)
96*67e74705SXin Li        self.printAlignOfType('    %s'%fnName, tyName, ty, self.output)
97*67e74705SXin Li        self.printOffsetsOfType('    %s'%fnName, tyName, ty, self.output)
98*67e74705SXin Li        print >>self.output,'}'
99*67e74705SXin Li        print >>self.output
100*67e74705SXin Li
101*67e74705SXin Li        self.layoutTests.append((i,fnName))
102*67e74705SXin Li
103*67e74705SXin Li    def writeFunction(self, i, FT):
104*67e74705SXin Li        args = ', '.join(['%s arg%d'%(self.getTypeName(t),i) for i,t in enumerate(FT.argTypes)])
105*67e74705SXin Li        if not args:
106*67e74705SXin Li            args = 'void'
107*67e74705SXin Li
108*67e74705SXin Li        if FT.returnType is None:
109*67e74705SXin Li            retvalName = None
110*67e74705SXin Li            retvalTypeName = 'void'
111*67e74705SXin Li        else:
112*67e74705SXin Li            retvalTypeName = self.getTypeName(FT.returnType)
113*67e74705SXin Li            if self.writeBody or self.outputTests:
114*67e74705SXin Li                retvalName = self.getTestReturnValue(FT.returnType)
115*67e74705SXin Li
116*67e74705SXin Li        fnName = 'fn%d'%(FT.index,)
117*67e74705SXin Li        if self.outputHeader:
118*67e74705SXin Li            print >>self.outputHeader,'%s %s(%s);'%(retvalTypeName, fnName, args)
119*67e74705SXin Li        elif self.outputTests:
120*67e74705SXin Li            print >>self.outputTests,'%s %s(%s);'%(retvalTypeName, fnName, args)
121*67e74705SXin Li
122*67e74705SXin Li        print >>self.output,'%s %s(%s)'%(retvalTypeName, fnName, args),
123*67e74705SXin Li        if self.writeBody:
124*67e74705SXin Li            print >>self.output, '{'
125*67e74705SXin Li
126*67e74705SXin Li            for i,t in enumerate(FT.argTypes):
127*67e74705SXin Li                self.printValueOfType('    %s'%fnName, 'arg%d'%i, t)
128*67e74705SXin Li
129*67e74705SXin Li            if retvalName is not None:
130*67e74705SXin Li                print >>self.output, '  return %s;'%(retvalName,)
131*67e74705SXin Li            print >>self.output, '}'
132*67e74705SXin Li        else:
133*67e74705SXin Li            print >>self.output, '{}'
134*67e74705SXin Li        print >>self.output
135*67e74705SXin Li
136*67e74705SXin Li        if self.outputDriver:
137*67e74705SXin Li            print >>self.outputDriver, '  if (index == -1 || index == %d) {' % i
138*67e74705SXin Li            print >>self.outputDriver, '    extern void test_%s(void);' % fnName
139*67e74705SXin Li            print >>self.outputDriver, '    test_%s();' % fnName
140*67e74705SXin Li            print >>self.outputDriver, '   }'
141*67e74705SXin Li
142*67e74705SXin Li        if self.outputTests:
143*67e74705SXin Li            if self.outputHeader:
144*67e74705SXin Li                print >>self.outputHeader, 'void test_%s(void);'%(fnName,)
145*67e74705SXin Li
146*67e74705SXin Li            if retvalName is None:
147*67e74705SXin Li                retvalTests = None
148*67e74705SXin Li            else:
149*67e74705SXin Li                retvalTests = self.getTestValuesArray(FT.returnType)
150*67e74705SXin Li            tests = map(self.getTestValuesArray, FT.argTypes)
151*67e74705SXin Li            print >>self.outputTests, 'void test_%s(void) {'%(fnName,)
152*67e74705SXin Li
153*67e74705SXin Li            if retvalTests is not None:
154*67e74705SXin Li                print >>self.outputTests, '  printf("%s: testing return.\\n");'%(fnName,)
155*67e74705SXin Li                print >>self.outputTests, '  for (int i=0; i<%d; ++i) {'%(retvalTests[1],)
156*67e74705SXin Li                args = ', '.join(['%s[%d]'%(t,randrange(l)) for t,l in tests])
157*67e74705SXin Li                print >>self.outputTests, '    %s RV;'%(retvalTypeName,)
158*67e74705SXin Li                print >>self.outputTests, '    %s = %s[i];'%(retvalName, retvalTests[0])
159*67e74705SXin Li                print >>self.outputTests, '    RV = %s(%s);'%(fnName, args)
160*67e74705SXin Li                self.printValueOfType('  %s_RV'%fnName, 'RV', FT.returnType, output=self.outputTests, indent=4)
161*67e74705SXin Li                self.checkTypeValues('RV', '%s[i]' % retvalTests[0], FT.returnType, output=self.outputTests, indent=4)
162*67e74705SXin Li                print >>self.outputTests, '  }'
163*67e74705SXin Li
164*67e74705SXin Li            if tests:
165*67e74705SXin Li                print >>self.outputTests, '  printf("%s: testing arguments.\\n");'%(fnName,)
166*67e74705SXin Li            for i,(array,length) in enumerate(tests):
167*67e74705SXin Li                for j in range(length):
168*67e74705SXin Li                    args = ['%s[%d]'%(t,randrange(l)) for t,l in tests]
169*67e74705SXin Li                    args[i] = '%s[%d]'%(array,j)
170*67e74705SXin Li                    print >>self.outputTests, '  %s(%s);'%(fnName, ', '.join(args),)
171*67e74705SXin Li            print >>self.outputTests, '}'
172*67e74705SXin Li
173*67e74705SXin Li    def getTestReturnValue(self, type):
174*67e74705SXin Li        typeName = self.getTypeName(type)
175*67e74705SXin Li        info = self.testReturnValues.get(typeName)
176*67e74705SXin Li        if info is None:
177*67e74705SXin Li            name = '%s_retval'%(typeName.replace(' ','_').replace('*','star'),)
178*67e74705SXin Li            print >>self.output, '%s %s;'%(typeName,name)
179*67e74705SXin Li            if self.outputHeader:
180*67e74705SXin Li                print >>self.outputHeader, 'extern %s %s;'%(typeName,name)
181*67e74705SXin Li            elif self.outputTests:
182*67e74705SXin Li                print >>self.outputTests, 'extern %s %s;'%(typeName,name)
183*67e74705SXin Li            info = self.testReturnValues[typeName] = name
184*67e74705SXin Li        return info
185*67e74705SXin Li
186*67e74705SXin Li    def getTestValuesArray(self, type):
187*67e74705SXin Li        typeName = self.getTypeName(type)
188*67e74705SXin Li        info = self.testValues.get(typeName)
189*67e74705SXin Li        if info is None:
190*67e74705SXin Li            name = '%s_values'%(typeName.replace(' ','_').replace('*','star'),)
191*67e74705SXin Li            print >>self.outputTests, 'static %s %s[] = {'%(typeName,name)
192*67e74705SXin Li            length = 0
193*67e74705SXin Li            for item in self.getTestValues(type):
194*67e74705SXin Li                print >>self.outputTests, '\t%s,'%(item,)
195*67e74705SXin Li                length += 1
196*67e74705SXin Li            print >>self.outputTests,'};'
197*67e74705SXin Li            info = self.testValues[typeName] = (name,length)
198*67e74705SXin Li        return info
199*67e74705SXin Li
200*67e74705SXin Li    def getTestValues(self, t):
201*67e74705SXin Li        if isinstance(t, BuiltinType):
202*67e74705SXin Li            if t.name=='float':
203*67e74705SXin Li                for i in ['0.0','-1.0','1.0']:
204*67e74705SXin Li                    yield i+'f'
205*67e74705SXin Li            elif t.name=='double':
206*67e74705SXin Li                for i in ['0.0','-1.0','1.0']:
207*67e74705SXin Li                    yield i
208*67e74705SXin Li            elif t.name in ('void *'):
209*67e74705SXin Li                yield '(void*) 0'
210*67e74705SXin Li                yield '(void*) -1'
211*67e74705SXin Li            else:
212*67e74705SXin Li                yield '(%s) 0'%(t.name,)
213*67e74705SXin Li                yield '(%s) -1'%(t.name,)
214*67e74705SXin Li                yield '(%s) 1'%(t.name,)
215*67e74705SXin Li        elif isinstance(t, EnumType):
216*67e74705SXin Li            for i in range(0, len(t.enumerators)):
217*67e74705SXin Li                yield 'enum%dval%d_%d' % (t.index, i, t.unique_id)
218*67e74705SXin Li        elif isinstance(t, RecordType):
219*67e74705SXin Li            nonPadding = [f for f in t.fields
220*67e74705SXin Li                          if not f.isPaddingBitField()]
221*67e74705SXin Li
222*67e74705SXin Li            if not nonPadding:
223*67e74705SXin Li                yield '{ }'
224*67e74705SXin Li                return
225*67e74705SXin Li
226*67e74705SXin Li            # FIXME: Use designated initializers to access non-first
227*67e74705SXin Li            # fields of unions.
228*67e74705SXin Li            if t.isUnion:
229*67e74705SXin Li                for v in self.getTestValues(nonPadding[0]):
230*67e74705SXin Li                    yield '{ %s }' % v
231*67e74705SXin Li                return
232*67e74705SXin Li
233*67e74705SXin Li            fieldValues = map(list, map(self.getTestValues, nonPadding))
234*67e74705SXin Li            for i,values in enumerate(fieldValues):
235*67e74705SXin Li                for v in values:
236*67e74705SXin Li                    elements = map(random.choice,fieldValues)
237*67e74705SXin Li                    elements[i] = v
238*67e74705SXin Li                    yield '{ %s }'%(', '.join(elements))
239*67e74705SXin Li
240*67e74705SXin Li        elif isinstance(t, ComplexType):
241*67e74705SXin Li            for t in self.getTestValues(t.elementType):
242*67e74705SXin Li                yield '%s + %s * 1i'%(t,t)
243*67e74705SXin Li        elif isinstance(t, ArrayType):
244*67e74705SXin Li            values = list(self.getTestValues(t.elementType))
245*67e74705SXin Li            if not values:
246*67e74705SXin Li                yield '{ }'
247*67e74705SXin Li            for i in range(t.numElements):
248*67e74705SXin Li                for v in values:
249*67e74705SXin Li                    elements = [random.choice(values) for i in range(t.numElements)]
250*67e74705SXin Li                    elements[i] = v
251*67e74705SXin Li                    yield '{ %s }'%(', '.join(elements))
252*67e74705SXin Li        else:
253*67e74705SXin Li            raise NotImplementedError,'Cannot make tests values of type: "%s"'%(t,)
254*67e74705SXin Li
255*67e74705SXin Li    def printSizeOfType(self, prefix, name, t, output=None, indent=2):
256*67e74705SXin Li        print >>output, '%*sprintf("%s: sizeof(%s) = %%ld\\n", (long)sizeof(%s));'%(indent, '', prefix, name, name)
257*67e74705SXin Li    def printAlignOfType(self, prefix, name, t, output=None, indent=2):
258*67e74705SXin Li        print >>output, '%*sprintf("%s: __alignof__(%s) = %%ld\\n", (long)__alignof__(%s));'%(indent, '', prefix, name, name)
259*67e74705SXin Li    def printOffsetsOfType(self, prefix, name, t, output=None, indent=2):
260*67e74705SXin Li        if isinstance(t, RecordType):
261*67e74705SXin Li            for i,f in enumerate(t.fields):
262*67e74705SXin Li                if f.isBitField():
263*67e74705SXin Li                    continue
264*67e74705SXin Li                fname = 'field%d' % i
265*67e74705SXin Li                print >>output, '%*sprintf("%s: __builtin_offsetof(%s, %s) = %%ld\\n", (long)__builtin_offsetof(%s, %s));'%(indent, '', prefix, name, fname, name, fname)
266*67e74705SXin Li
267*67e74705SXin Li    def printValueOfType(self, prefix, name, t, output=None, indent=2):
268*67e74705SXin Li        if output is None:
269*67e74705SXin Li            output = self.output
270*67e74705SXin Li        if isinstance(t, BuiltinType):
271*67e74705SXin Li            value_expr = name
272*67e74705SXin Li            if t.name.split(' ')[-1] == '_Bool':
273*67e74705SXin Li                # Hack to work around PR5579.
274*67e74705SXin Li                value_expr = "%s ? 2 : 0" % name
275*67e74705SXin Li
276*67e74705SXin Li            if t.name.endswith('long long'):
277*67e74705SXin Li                code = 'lld'
278*67e74705SXin Li            elif t.name.endswith('long'):
279*67e74705SXin Li                code = 'ld'
280*67e74705SXin Li            elif t.name.split(' ')[-1] in ('_Bool','char','short',
281*67e74705SXin Li                                           'int','unsigned'):
282*67e74705SXin Li                code = 'd'
283*67e74705SXin Li            elif t.name in ('float','double'):
284*67e74705SXin Li                code = 'f'
285*67e74705SXin Li            elif t.name == 'long double':
286*67e74705SXin Li                code = 'Lf'
287*67e74705SXin Li            else:
288*67e74705SXin Li                code = 'p'
289*67e74705SXin Li            print >>output, '%*sprintf("%s: %s = %%%s\\n", %s);'%(
290*67e74705SXin Li                indent, '', prefix, name, code, value_expr)
291*67e74705SXin Li        elif isinstance(t, EnumType):
292*67e74705SXin Li            print >>output, '%*sprintf("%s: %s = %%d\\n", %s);'%(indent, '', prefix, name, name)
293*67e74705SXin Li        elif isinstance(t, RecordType):
294*67e74705SXin Li            if not t.fields:
295*67e74705SXin Li                print >>output, '%*sprintf("%s: %s (empty)\\n");'%(indent, '', prefix, name)
296*67e74705SXin Li            for i,f in enumerate(t.fields):
297*67e74705SXin Li                if f.isPaddingBitField():
298*67e74705SXin Li                    continue
299*67e74705SXin Li                fname = '%s.field%d'%(name,i)
300*67e74705SXin Li                self.printValueOfType(prefix, fname, f, output=output, indent=indent)
301*67e74705SXin Li        elif isinstance(t, ComplexType):
302*67e74705SXin Li            self.printValueOfType(prefix, '(__real %s)'%name, t.elementType, output=output,indent=indent)
303*67e74705SXin Li            self.printValueOfType(prefix, '(__imag %s)'%name, t.elementType, output=output,indent=indent)
304*67e74705SXin Li        elif isinstance(t, ArrayType):
305*67e74705SXin Li            for i in range(t.numElements):
306*67e74705SXin Li                # Access in this fashion as a hackish way to portably
307*67e74705SXin Li                # access vectors.
308*67e74705SXin Li                if t.isVector:
309*67e74705SXin Li                    self.printValueOfType(prefix, '((%s*) &%s)[%d]'%(t.elementType,name,i), t.elementType, output=output,indent=indent)
310*67e74705SXin Li                else:
311*67e74705SXin Li                    self.printValueOfType(prefix, '%s[%d]'%(name,i), t.elementType, output=output,indent=indent)
312*67e74705SXin Li        else:
313*67e74705SXin Li            raise NotImplementedError,'Cannot print value of type: "%s"'%(t,)
314*67e74705SXin Li
315*67e74705SXin Li    def checkTypeValues(self, nameLHS, nameRHS, t, output=None, indent=2):
316*67e74705SXin Li        prefix = 'foo'
317*67e74705SXin Li        if output is None:
318*67e74705SXin Li            output = self.output
319*67e74705SXin Li        if isinstance(t, BuiltinType):
320*67e74705SXin Li            print >>output, '%*sassert(%s == %s);' % (indent, '', nameLHS, nameRHS)
321*67e74705SXin Li        elif isinstance(t, EnumType):
322*67e74705SXin Li            print >>output, '%*sassert(%s == %s);' % (indent, '', nameLHS, nameRHS)
323*67e74705SXin Li        elif isinstance(t, RecordType):
324*67e74705SXin Li            for i,f in enumerate(t.fields):
325*67e74705SXin Li                if f.isPaddingBitField():
326*67e74705SXin Li                    continue
327*67e74705SXin Li                self.checkTypeValues('%s.field%d'%(nameLHS,i), '%s.field%d'%(nameRHS,i),
328*67e74705SXin Li                                     f, output=output, indent=indent)
329*67e74705SXin Li                if t.isUnion:
330*67e74705SXin Li                    break
331*67e74705SXin Li        elif isinstance(t, ComplexType):
332*67e74705SXin Li            self.checkTypeValues('(__real %s)'%nameLHS, '(__real %s)'%nameRHS, t.elementType, output=output,indent=indent)
333*67e74705SXin Li            self.checkTypeValues('(__imag %s)'%nameLHS, '(__imag %s)'%nameRHS, t.elementType, output=output,indent=indent)
334*67e74705SXin Li        elif isinstance(t, ArrayType):
335*67e74705SXin Li            for i in range(t.numElements):
336*67e74705SXin Li                # Access in this fashion as a hackish way to portably
337*67e74705SXin Li                # access vectors.
338*67e74705SXin Li                if t.isVector:
339*67e74705SXin Li                    self.checkTypeValues('((%s*) &%s)[%d]'%(t.elementType,nameLHS,i),
340*67e74705SXin Li                                         '((%s*) &%s)[%d]'%(t.elementType,nameRHS,i),
341*67e74705SXin Li                                         t.elementType, output=output,indent=indent)
342*67e74705SXin Li                else:
343*67e74705SXin Li                    self.checkTypeValues('%s[%d]'%(nameLHS,i), '%s[%d]'%(nameRHS,i),
344*67e74705SXin Li                                         t.elementType, output=output,indent=indent)
345*67e74705SXin Li        else:
346*67e74705SXin Li            raise NotImplementedError,'Cannot print value of type: "%s"'%(t,)
347*67e74705SXin Li
348*67e74705SXin Liimport sys
349*67e74705SXin Li
350*67e74705SXin Lidef main():
351*67e74705SXin Li    from optparse import OptionParser, OptionGroup
352*67e74705SXin Li    parser = OptionParser("%prog [options] {indices}")
353*67e74705SXin Li    parser.add_option("", "--mode", dest="mode",
354*67e74705SXin Li                      help="autogeneration mode (random or linear) [default %default]",
355*67e74705SXin Li                      type='choice', choices=('random','linear'), default='linear')
356*67e74705SXin Li    parser.add_option("", "--count", dest="count",
357*67e74705SXin Li                      help="autogenerate COUNT functions according to MODE",
358*67e74705SXin Li                      type=int, default=0)
359*67e74705SXin Li    parser.add_option("", "--min", dest="minIndex", metavar="N",
360*67e74705SXin Li                      help="start autogeneration with the Nth function type  [default %default]",
361*67e74705SXin Li                      type=int, default=0)
362*67e74705SXin Li    parser.add_option("", "--max", dest="maxIndex", metavar="N",
363*67e74705SXin Li                      help="maximum index for random autogeneration  [default %default]",
364*67e74705SXin Li                      type=int, default=10000000)
365*67e74705SXin Li    parser.add_option("", "--seed", dest="seed",
366*67e74705SXin Li                      help="random number generator seed [default %default]",
367*67e74705SXin Li                      type=int, default=1)
368*67e74705SXin Li    parser.add_option("", "--use-random-seed", dest="useRandomSeed",
369*67e74705SXin Li                      help="use random value for initial random number generator seed",
370*67e74705SXin Li                      action='store_true', default=False)
371*67e74705SXin Li    parser.add_option("", "--skip", dest="skipTests",
372*67e74705SXin Li                      help="add a test index to skip",
373*67e74705SXin Li                      type=int, action='append', default=[])
374*67e74705SXin Li    parser.add_option("-o", "--output", dest="output", metavar="FILE",
375*67e74705SXin Li                      help="write output to FILE  [default %default]",
376*67e74705SXin Li                      type=str, default='-')
377*67e74705SXin Li    parser.add_option("-O", "--output-header", dest="outputHeader", metavar="FILE",
378*67e74705SXin Li                      help="write header file for output to FILE  [default %default]",
379*67e74705SXin Li                      type=str, default=None)
380*67e74705SXin Li    parser.add_option("-T", "--output-tests", dest="outputTests", metavar="FILE",
381*67e74705SXin Li                      help="write function tests to FILE  [default %default]",
382*67e74705SXin Li                      type=str, default=None)
383*67e74705SXin Li    parser.add_option("-D", "--output-driver", dest="outputDriver", metavar="FILE",
384*67e74705SXin Li                      help="write test driver to FILE  [default %default]",
385*67e74705SXin Li                      type=str, default=None)
386*67e74705SXin Li    parser.add_option("", "--test-layout", dest="testLayout", metavar="FILE",
387*67e74705SXin Li                      help="test structure layout",
388*67e74705SXin Li                      action='store_true', default=False)
389*67e74705SXin Li
390*67e74705SXin Li    group = OptionGroup(parser, "Type Enumeration Options")
391*67e74705SXin Li    # Builtins - Ints
392*67e74705SXin Li    group.add_option("", "--no-char", dest="useChar",
393*67e74705SXin Li                     help="do not generate char types",
394*67e74705SXin Li                     action="store_false", default=True)
395*67e74705SXin Li    group.add_option("", "--no-short", dest="useShort",
396*67e74705SXin Li                     help="do not generate short types",
397*67e74705SXin Li                     action="store_false", default=True)
398*67e74705SXin Li    group.add_option("", "--no-int", dest="useInt",
399*67e74705SXin Li                     help="do not generate int types",
400*67e74705SXin Li                     action="store_false", default=True)
401*67e74705SXin Li    group.add_option("", "--no-long", dest="useLong",
402*67e74705SXin Li                     help="do not generate long types",
403*67e74705SXin Li                     action="store_false", default=True)
404*67e74705SXin Li    group.add_option("", "--no-long-long", dest="useLongLong",
405*67e74705SXin Li                     help="do not generate long long types",
406*67e74705SXin Li                     action="store_false", default=True)
407*67e74705SXin Li    group.add_option("", "--no-unsigned", dest="useUnsigned",
408*67e74705SXin Li                     help="do not generate unsigned integer types",
409*67e74705SXin Li                     action="store_false", default=True)
410*67e74705SXin Li
411*67e74705SXin Li    # Other builtins
412*67e74705SXin Li    group.add_option("", "--no-bool", dest="useBool",
413*67e74705SXin Li                     help="do not generate bool types",
414*67e74705SXin Li                     action="store_false", default=True)
415*67e74705SXin Li    group.add_option("", "--no-float", dest="useFloat",
416*67e74705SXin Li                     help="do not generate float types",
417*67e74705SXin Li                     action="store_false", default=True)
418*67e74705SXin Li    group.add_option("", "--no-double", dest="useDouble",
419*67e74705SXin Li                     help="do not generate double types",
420*67e74705SXin Li                     action="store_false", default=True)
421*67e74705SXin Li    group.add_option("", "--no-long-double", dest="useLongDouble",
422*67e74705SXin Li                     help="do not generate long double types",
423*67e74705SXin Li                     action="store_false", default=True)
424*67e74705SXin Li    group.add_option("", "--no-void-pointer", dest="useVoidPointer",
425*67e74705SXin Li                     help="do not generate void* types",
426*67e74705SXin Li                     action="store_false", default=True)
427*67e74705SXin Li
428*67e74705SXin Li    # Enumerations
429*67e74705SXin Li    group.add_option("", "--no-enums", dest="useEnum",
430*67e74705SXin Li                     help="do not generate enum types",
431*67e74705SXin Li                     action="store_false", default=True)
432*67e74705SXin Li
433*67e74705SXin Li    # Derived types
434*67e74705SXin Li    group.add_option("", "--no-array", dest="useArray",
435*67e74705SXin Li                     help="do not generate record types",
436*67e74705SXin Li                     action="store_false", default=True)
437*67e74705SXin Li    group.add_option("", "--no-complex", dest="useComplex",
438*67e74705SXin Li                     help="do not generate complex types",
439*67e74705SXin Li                     action="store_false", default=True)
440*67e74705SXin Li    group.add_option("", "--no-record", dest="useRecord",
441*67e74705SXin Li                     help="do not generate record types",
442*67e74705SXin Li                     action="store_false", default=True)
443*67e74705SXin Li    group.add_option("", "--no-union", dest="recordUseUnion",
444*67e74705SXin Li                     help="do not generate union types",
445*67e74705SXin Li                     action="store_false", default=True)
446*67e74705SXin Li    group.add_option("", "--no-vector", dest="useVector",
447*67e74705SXin Li                     help="do not generate vector types",
448*67e74705SXin Li                     action="store_false", default=True)
449*67e74705SXin Li    group.add_option("", "--no-bit-field", dest="useBitField",
450*67e74705SXin Li                     help="do not generate bit-field record members",
451*67e74705SXin Li                     action="store_false", default=True)
452*67e74705SXin Li    group.add_option("", "--no-builtins", dest="useBuiltins",
453*67e74705SXin Li                     help="do not use any types",
454*67e74705SXin Li                     action="store_false", default=True)
455*67e74705SXin Li
456*67e74705SXin Li    # Tuning
457*67e74705SXin Li    group.add_option("", "--no-function-return", dest="functionUseReturn",
458*67e74705SXin Li                     help="do not generate return types for functions",
459*67e74705SXin Li                     action="store_false", default=True)
460*67e74705SXin Li    group.add_option("", "--vector-types", dest="vectorTypes",
461*67e74705SXin Li                     help="comma separated list of vector types (e.g., v2i32) [default %default]",
462*67e74705SXin Li                     action="store", type=str, default='v2i16, v1i64, v2i32, v4i16, v8i8, v2f32, v2i64, v4i32, v8i16, v16i8, v2f64, v4f32, v16f32', metavar="N")
463*67e74705SXin Li    group.add_option("", "--bit-fields", dest="bitFields",
464*67e74705SXin Li                     help="comma separated list 'type:width' bit-field specifiers [default %default]",
465*67e74705SXin Li                     action="store", type=str, default=(
466*67e74705SXin Li            "char:0,char:4,int:0,unsigned:1,int:1,int:4,int:13,int:24"))
467*67e74705SXin Li    group.add_option("", "--max-args", dest="functionMaxArgs",
468*67e74705SXin Li                     help="maximum number of arguments per function [default %default]",
469*67e74705SXin Li                     action="store", type=int, default=4, metavar="N")
470*67e74705SXin Li    group.add_option("", "--max-array", dest="arrayMaxSize",
471*67e74705SXin Li                     help="maximum array size [default %default]",
472*67e74705SXin Li                     action="store", type=int, default=4, metavar="N")
473*67e74705SXin Li    group.add_option("", "--max-record", dest="recordMaxSize",
474*67e74705SXin Li                     help="maximum number of fields per record [default %default]",
475*67e74705SXin Li                     action="store", type=int, default=4, metavar="N")
476*67e74705SXin Li    group.add_option("", "--max-record-depth", dest="recordMaxDepth",
477*67e74705SXin Li                     help="maximum nested structure depth [default %default]",
478*67e74705SXin Li                     action="store", type=int, default=None, metavar="N")
479*67e74705SXin Li    parser.add_option_group(group)
480*67e74705SXin Li    (opts, args) = parser.parse_args()
481*67e74705SXin Li
482*67e74705SXin Li    if not opts.useRandomSeed:
483*67e74705SXin Li        random.seed(opts.seed)
484*67e74705SXin Li
485*67e74705SXin Li    # Construct type generator
486*67e74705SXin Li    builtins = []
487*67e74705SXin Li    if opts.useBuiltins:
488*67e74705SXin Li        ints = []
489*67e74705SXin Li        if opts.useChar: ints.append(('char',1))
490*67e74705SXin Li        if opts.useShort: ints.append(('short',2))
491*67e74705SXin Li        if opts.useInt: ints.append(('int',4))
492*67e74705SXin Li        # FIXME: Wrong size.
493*67e74705SXin Li        if opts.useLong: ints.append(('long',4))
494*67e74705SXin Li        if opts.useLongLong: ints.append(('long long',8))
495*67e74705SXin Li        if opts.useUnsigned:
496*67e74705SXin Li            ints = ([('unsigned %s'%i,s) for i,s in ints] +
497*67e74705SXin Li                    [('signed %s'%i,s) for i,s in ints])
498*67e74705SXin Li        builtins.extend(ints)
499*67e74705SXin Li
500*67e74705SXin Li        if opts.useBool: builtins.append(('_Bool',1))
501*67e74705SXin Li        if opts.useFloat: builtins.append(('float',4))
502*67e74705SXin Li        if opts.useDouble: builtins.append(('double',8))
503*67e74705SXin Li        if opts.useLongDouble: builtins.append(('long double',16))
504*67e74705SXin Li        # FIXME: Wrong size.
505*67e74705SXin Li        if opts.useVoidPointer:  builtins.append(('void*',4))
506*67e74705SXin Li
507*67e74705SXin Li    btg = FixedTypeGenerator([BuiltinType(n,s) for n,s in builtins])
508*67e74705SXin Li
509*67e74705SXin Li    bitfields = []
510*67e74705SXin Li    for specifier in opts.bitFields.split(','):
511*67e74705SXin Li        if not specifier.strip():
512*67e74705SXin Li            continue
513*67e74705SXin Li        name,width = specifier.strip().split(':', 1)
514*67e74705SXin Li        bitfields.append(BuiltinType(name,None,int(width)))
515*67e74705SXin Li    bftg = FixedTypeGenerator(bitfields)
516*67e74705SXin Li
517*67e74705SXin Li    charType = BuiltinType('char',1)
518*67e74705SXin Li    shortType = BuiltinType('short',2)
519*67e74705SXin Li    intType = BuiltinType('int',4)
520*67e74705SXin Li    longlongType = BuiltinType('long long',8)
521*67e74705SXin Li    floatType = BuiltinType('float',4)
522*67e74705SXin Li    doubleType = BuiltinType('double',8)
523*67e74705SXin Li    sbtg = FixedTypeGenerator([charType, intType, floatType, doubleType])
524*67e74705SXin Li
525*67e74705SXin Li    atg = AnyTypeGenerator()
526*67e74705SXin Li    artg = AnyTypeGenerator()
527*67e74705SXin Li    def makeGenerator(atg, subgen, subfieldgen, useRecord, useArray, useBitField):
528*67e74705SXin Li        atg.addGenerator(btg)
529*67e74705SXin Li        if useBitField and opts.useBitField:
530*67e74705SXin Li            atg.addGenerator(bftg)
531*67e74705SXin Li        if useRecord and opts.useRecord:
532*67e74705SXin Li            assert subgen
533*67e74705SXin Li            atg.addGenerator(RecordTypeGenerator(subfieldgen, opts.recordUseUnion,
534*67e74705SXin Li                                                 opts.recordMaxSize))
535*67e74705SXin Li        if opts.useComplex:
536*67e74705SXin Li            # FIXME: Allow overriding builtins here
537*67e74705SXin Li            atg.addGenerator(ComplexTypeGenerator(sbtg))
538*67e74705SXin Li        if useArray and opts.useArray:
539*67e74705SXin Li            assert subgen
540*67e74705SXin Li            atg.addGenerator(ArrayTypeGenerator(subgen, opts.arrayMaxSize))
541*67e74705SXin Li        if opts.useVector:
542*67e74705SXin Li            vTypes = []
543*67e74705SXin Li            for i,t in enumerate(opts.vectorTypes.split(',')):
544*67e74705SXin Li                m = re.match('v([1-9][0-9]*)([if][1-9][0-9]*)', t.strip())
545*67e74705SXin Li                if not m:
546*67e74705SXin Li                    parser.error('Invalid vector type: %r' % t)
547*67e74705SXin Li                count,kind = m.groups()
548*67e74705SXin Li                count = int(count)
549*67e74705SXin Li                type = { 'i8'  : charType,
550*67e74705SXin Li                         'i16' : shortType,
551*67e74705SXin Li                         'i32' : intType,
552*67e74705SXin Li                         'i64' : longlongType,
553*67e74705SXin Li                         'f32' : floatType,
554*67e74705SXin Li                         'f64' : doubleType,
555*67e74705SXin Li                         }.get(kind)
556*67e74705SXin Li                if not type:
557*67e74705SXin Li                    parser.error('Invalid vector type: %r' % t)
558*67e74705SXin Li                vTypes.append(ArrayType(i, True, type, count * type.size))
559*67e74705SXin Li
560*67e74705SXin Li            atg.addGenerator(FixedTypeGenerator(vTypes))
561*67e74705SXin Li        if opts.useEnum:
562*67e74705SXin Li            atg.addGenerator(EnumTypeGenerator([None, '-1', '1', '1u'], 1, 4))
563*67e74705SXin Li
564*67e74705SXin Li    if opts.recordMaxDepth is None:
565*67e74705SXin Li        # Fully recursive, just avoid top-level arrays.
566*67e74705SXin Li        subFTG = AnyTypeGenerator()
567*67e74705SXin Li        subTG = AnyTypeGenerator()
568*67e74705SXin Li        atg = AnyTypeGenerator()
569*67e74705SXin Li        makeGenerator(subFTG, atg, atg, True, True, True)
570*67e74705SXin Li        makeGenerator(subTG, atg, subFTG, True, True, False)
571*67e74705SXin Li        makeGenerator(atg, subTG, subFTG, True, False, False)
572*67e74705SXin Li    else:
573*67e74705SXin Li        # Make a chain of type generators, each builds smaller
574*67e74705SXin Li        # structures.
575*67e74705SXin Li        base = AnyTypeGenerator()
576*67e74705SXin Li        fbase = AnyTypeGenerator()
577*67e74705SXin Li        makeGenerator(base, None, None, False, False, False)
578*67e74705SXin Li        makeGenerator(fbase, None, None, False, False, True)
579*67e74705SXin Li        for i in range(opts.recordMaxDepth):
580*67e74705SXin Li            n = AnyTypeGenerator()
581*67e74705SXin Li            fn = AnyTypeGenerator()
582*67e74705SXin Li            makeGenerator(n, base, fbase, True, True, False)
583*67e74705SXin Li            makeGenerator(fn, base, fbase, True, True, True)
584*67e74705SXin Li            base = n
585*67e74705SXin Li            fbase = fn
586*67e74705SXin Li        atg = AnyTypeGenerator()
587*67e74705SXin Li        makeGenerator(atg, base, fbase, True, False, False)
588*67e74705SXin Li
589*67e74705SXin Li    if opts.testLayout:
590*67e74705SXin Li        ftg = atg
591*67e74705SXin Li    else:
592*67e74705SXin Li        ftg = FunctionTypeGenerator(atg, opts.functionUseReturn, opts.functionMaxArgs)
593*67e74705SXin Li
594*67e74705SXin Li    # Override max,min,count if finite
595*67e74705SXin Li    if opts.maxIndex is None:
596*67e74705SXin Li        if ftg.cardinality is aleph0:
597*67e74705SXin Li            opts.maxIndex = 10000000
598*67e74705SXin Li        else:
599*67e74705SXin Li            opts.maxIndex = ftg.cardinality
600*67e74705SXin Li    opts.maxIndex = min(opts.maxIndex, ftg.cardinality)
601*67e74705SXin Li    opts.minIndex = max(0,min(opts.maxIndex-1, opts.minIndex))
602*67e74705SXin Li    if not opts.mode=='random':
603*67e74705SXin Li        opts.count = min(opts.count, opts.maxIndex-opts.minIndex)
604*67e74705SXin Li
605*67e74705SXin Li    if opts.output=='-':
606*67e74705SXin Li        output = sys.stdout
607*67e74705SXin Li    else:
608*67e74705SXin Li        output = open(opts.output,'w')
609*67e74705SXin Li        atexit.register(lambda: output.close())
610*67e74705SXin Li
611*67e74705SXin Li    outputHeader = None
612*67e74705SXin Li    if opts.outputHeader:
613*67e74705SXin Li        outputHeader = open(opts.outputHeader,'w')
614*67e74705SXin Li        atexit.register(lambda: outputHeader.close())
615*67e74705SXin Li
616*67e74705SXin Li    outputTests = None
617*67e74705SXin Li    if opts.outputTests:
618*67e74705SXin Li        outputTests = open(opts.outputTests,'w')
619*67e74705SXin Li        atexit.register(lambda: outputTests.close())
620*67e74705SXin Li
621*67e74705SXin Li    outputDriver = None
622*67e74705SXin Li    if opts.outputDriver:
623*67e74705SXin Li        outputDriver = open(opts.outputDriver,'w')
624*67e74705SXin Li        atexit.register(lambda: outputDriver.close())
625*67e74705SXin Li
626*67e74705SXin Li    info = ''
627*67e74705SXin Li    info += '// %s\n'%(' '.join(sys.argv),)
628*67e74705SXin Li    info += '// Generated: %s\n'%(time.strftime('%Y-%m-%d %H:%M'),)
629*67e74705SXin Li    info += '// Cardinality of function generator: %s\n'%(ftg.cardinality,)
630*67e74705SXin Li    info += '// Cardinality of type generator: %s\n'%(atg.cardinality,)
631*67e74705SXin Li
632*67e74705SXin Li    if opts.testLayout:
633*67e74705SXin Li        info += '\n#include <stdio.h>'
634*67e74705SXin Li
635*67e74705SXin Li    P = TypePrinter(output,
636*67e74705SXin Li                    outputHeader=outputHeader,
637*67e74705SXin Li                    outputTests=outputTests,
638*67e74705SXin Li                    outputDriver=outputDriver,
639*67e74705SXin Li                    headerName=opts.outputHeader,
640*67e74705SXin Li                    info=info)
641*67e74705SXin Li
642*67e74705SXin Li    def write(N):
643*67e74705SXin Li        try:
644*67e74705SXin Li            FT = ftg.get(N)
645*67e74705SXin Li        except RuntimeError,e:
646*67e74705SXin Li            if e.args[0]=='maximum recursion depth exceeded':
647*67e74705SXin Li                print >>sys.stderr,'WARNING: Skipped %d, recursion limit exceeded (bad arguments?)'%(N,)
648*67e74705SXin Li                return
649*67e74705SXin Li            raise
650*67e74705SXin Li        if opts.testLayout:
651*67e74705SXin Li            P.writeLayoutTest(N, FT)
652*67e74705SXin Li        else:
653*67e74705SXin Li            P.writeFunction(N, FT)
654*67e74705SXin Li
655*67e74705SXin Li    if args:
656*67e74705SXin Li        [write(int(a)) for a in args]
657*67e74705SXin Li
658*67e74705SXin Li    skipTests = set(opts.skipTests)
659*67e74705SXin Li    for i in range(opts.count):
660*67e74705SXin Li        if opts.mode=='linear':
661*67e74705SXin Li            index = opts.minIndex + i
662*67e74705SXin Li        else:
663*67e74705SXin Li            index = opts.minIndex + int((opts.maxIndex-opts.minIndex) * random.random())
664*67e74705SXin Li        if index in skipTests:
665*67e74705SXin Li            continue
666*67e74705SXin Li        write(index)
667*67e74705SXin Li
668*67e74705SXin Li    P.finish()
669*67e74705SXin Li
670*67e74705SXin Liif __name__=='__main__':
671*67e74705SXin Li    main()
672*67e74705SXin Li
673