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