3 from __future__
import absolute_import
, division
, print_function
4 from pprint
import pprint
5 import random
, atexit
, time
6 from random
import randrange
9 from Enumeration
import *
15 class TypePrinter(object):
26 self
.outputHeader
= outputHeader
27 self
.outputTests
= outputTests
28 self
.outputDriver
= outputDriver
29 self
.writeBody
= outputHeader
or outputTests
or outputDriver
32 self
.testReturnValues
= {}
34 self
.declarations
= set()
47 print("#include <stdio.h>\n", file=self
.output
)
49 print("#include <stdio.h>", file=self
.outputTests
)
50 print("#include <string.h>", file=self
.outputTests
)
51 print("#include <assert.h>\n", file=self
.outputTests
)
54 for f
in (self
.output
, self
.outputTests
, self
.outputDriver
):
56 print('#include "%s"\n' % (headerName
,), file=f
)
59 print("#include <stdio.h>", file=self
.outputDriver
)
60 print("#include <stdlib.h>\n", file=self
.outputDriver
)
61 print("int main(int argc, char **argv) {", file=self
.outputDriver
)
62 print(" int index = -1;", file=self
.outputDriver
)
63 print(" if (argc > 1) index = atoi(argv[1]);", file=self
.outputDriver
)
67 print("int main(int argc, char **argv) {", file=self
.output
)
68 print(" int index = -1;", file=self
.output
)
69 print(" if (argc > 1) index = atoi(argv[1]);", file=self
.output
)
70 for i
, f
in self
.layoutTests
:
71 print(" if (index == -1 || index == %d)" % i
, file=self
.output
)
72 print(" %s();" % f
, file=self
.output
)
73 print(" return 0;", file=self
.output
)
74 print("}", file=self
.output
)
77 print(' printf("DONE\\n");', file=self
.outputDriver
)
78 print(" return 0;", file=self
.outputDriver
)
79 print("}", file=self
.outputDriver
)
81 def addDeclaration(self
, decl
):
82 if decl
in self
.declarations
:
85 self
.declarations
.add(decl
)
87 print(decl
, file=self
.outputHeader
)
89 print(decl
, file=self
.output
)
91 print(decl
, file=self
.outputTests
)
94 def getTypeName(self
, T
):
95 name
= self
.types
.get(T
)
99 self
.types
[T
] = name
= T
.getTypeName(self
)
102 def writeLayoutTest(self
, i
, ty
):
103 tyName
= self
.getTypeName(ty
)
104 tyNameClean
= tyName
.replace(" ", "_").replace("*", "star")
105 fnName
= "test_%s" % tyNameClean
107 print("void %s(void) {" % fnName
, file=self
.output
)
108 self
.printSizeOfType(" %s" % fnName
, tyName
, ty
, self
.output
)
109 self
.printAlignOfType(" %s" % fnName
, tyName
, ty
, self
.output
)
110 self
.printOffsetsOfType(" %s" % fnName
, tyName
, ty
, self
.output
)
111 print("}", file=self
.output
)
112 print(file=self
.output
)
114 self
.layoutTests
.append((i
, fnName
))
116 def writeFunction(self
, i
, FT
):
118 ["%s arg%d" % (self
.getTypeName(t
), i
) for i
, t
in enumerate(FT
.argTypes
)]
123 if FT
.returnType
is None:
125 retvalTypeName
= "void"
127 retvalTypeName
= self
.getTypeName(FT
.returnType
)
128 if self
.writeBody
or self
.outputTests
:
129 retvalName
= self
.getTestReturnValue(FT
.returnType
)
131 fnName
= "fn%d" % (FT
.index
,)
132 if self
.outputHeader
:
133 print("%s %s(%s);" % (retvalTypeName
, fnName
, args
), file=self
.outputHeader
)
134 elif self
.outputTests
:
135 print("%s %s(%s);" % (retvalTypeName
, fnName
, args
), file=self
.outputTests
)
137 print("%s %s(%s)" % (retvalTypeName
, fnName
, args
), end
=" ", file=self
.output
)
139 print("{", file=self
.output
)
141 for i
, t
in enumerate(FT
.argTypes
):
142 self
.printValueOfType(" %s" % fnName
, "arg%d" % i
, t
)
144 if retvalName
is not None:
145 print(" return %s;" % (retvalName
,), file=self
.output
)
146 print("}", file=self
.output
)
148 print("{}", file=self
.output
)
149 print(file=self
.output
)
151 if self
.outputDriver
:
152 print(" if (index == -1 || index == %d) {" % i
, file=self
.outputDriver
)
153 print(" extern void test_%s(void);" % fnName
, file=self
.outputDriver
)
154 print(" test_%s();" % fnName
, file=self
.outputDriver
)
155 print(" }", file=self
.outputDriver
)
158 if self
.outputHeader
:
159 print("void test_%s(void);" % (fnName
,), file=self
.outputHeader
)
161 if retvalName
is None:
164 retvalTests
= self
.getTestValuesArray(FT
.returnType
)
165 tests
= [self
.getTestValuesArray(ty
) for ty
in FT
.argTypes
]
166 print("void test_%s(void) {" % (fnName
,), file=self
.outputTests
)
168 if retvalTests
is not None:
170 ' printf("%s: testing return.\\n");' % (fnName
,),
171 file=self
.outputTests
,
174 " for (int i=0; i<%d; ++i) {" % (retvalTests
[1],),
175 file=self
.outputTests
,
177 args
= ", ".join(["%s[%d]" % (t
, randrange(l
)) for t
, l
in tests
])
178 print(" %s RV;" % (retvalTypeName
,), file=self
.outputTests
)
180 " %s = %s[i];" % (retvalName
, retvalTests
[0]),
181 file=self
.outputTests
,
183 print(" RV = %s(%s);" % (fnName
, args
), file=self
.outputTests
)
184 self
.printValueOfType(
188 output
=self
.outputTests
,
191 self
.checkTypeValues(
193 "%s[i]" % retvalTests
[0],
195 output
=self
.outputTests
,
198 print(" }", file=self
.outputTests
)
202 ' printf("%s: testing arguments.\\n");' % (fnName
,),
203 file=self
.outputTests
,
205 for i
, (array
, length
) in enumerate(tests
):
206 for j
in range(length
):
207 args
= ["%s[%d]" % (t
, randrange(l
)) for t
, l
in tests
]
208 args
[i
] = "%s[%d]" % (array
, j
)
215 file=self
.outputTests
,
217 print("}", file=self
.outputTests
)
219 def getTestReturnValue(self
, type):
220 typeName
= self
.getTypeName(type)
221 info
= self
.testReturnValues
.get(typeName
)
223 name
= "%s_retval" % (typeName
.replace(" ", "_").replace("*", "star"),)
224 print("%s %s;" % (typeName
, name
), file=self
.output
)
225 if self
.outputHeader
:
226 print("extern %s %s;" % (typeName
, name
), file=self
.outputHeader
)
227 elif self
.outputTests
:
228 print("extern %s %s;" % (typeName
, name
), file=self
.outputTests
)
229 info
= self
.testReturnValues
[typeName
] = name
232 def getTestValuesArray(self
, type):
233 typeName
= self
.getTypeName(type)
234 info
= self
.testValues
.get(typeName
)
236 name
= "%s_values" % (typeName
.replace(" ", "_").replace("*", "star"),)
237 print("static %s %s[] = {" % (typeName
, name
), file=self
.outputTests
)
239 for item
in self
.getTestValues(type):
240 print("\t%s," % (item
,), file=self
.outputTests
)
242 print("};", file=self
.outputTests
)
243 info
= self
.testValues
[typeName
] = (name
, length
)
246 def getTestValues(self
, t
):
247 if isinstance(t
, BuiltinType
):
248 if t
.name
== "float":
249 for i
in ["0.0", "-1.0", "1.0"]:
251 elif t
.name
== "double":
252 for i
in ["0.0", "-1.0", "1.0"]:
254 elif t
.name
in ("void *"):
258 yield "(%s) 0" % (t
.name
,)
259 yield "(%s) -1" % (t
.name
,)
260 yield "(%s) 1" % (t
.name
,)
261 elif isinstance(t
, EnumType
):
262 for i
in range(0, len(t
.enumerators
)):
263 yield "enum%dval%d_%d" % (t
.index
, i
, t
.unique_id
)
264 elif isinstance(t
, RecordType
):
265 nonPadding
= [f
for f
in t
.fields
if not f
.isPaddingBitField()]
271 # FIXME: Use designated initializers to access non-first
274 for v
in self
.getTestValues(nonPadding
[0]):
278 fieldValues
= [list(v
) for v
in map(self
.getTestValues
, nonPadding
)]
279 for i
, values
in enumerate(fieldValues
):
281 elements
= [random
.choice(fv
) for fv
in fieldValues
]
283 yield "{ %s }" % (", ".join(elements
))
285 elif isinstance(t
, ComplexType
):
286 for t
in self
.getTestValues(t
.elementType
):
287 yield "%s + %s * 1i" % (t
, t
)
288 elif isinstance(t
, ArrayType
):
289 values
= list(self
.getTestValues(t
.elementType
))
292 for i
in range(t
.numElements
):
294 elements
= [random
.choice(values
) for i
in range(t
.numElements
)]
296 yield "{ %s }" % (", ".join(elements
))
298 raise NotImplementedError('Cannot make tests values of type: "%s"' % (t
,))
300 def printSizeOfType(self
, prefix
, name
, t
, output
=None, indent
=2):
302 '%*sprintf("%s: sizeof(%s) = %%ld\\n", (long)sizeof(%s));'
303 % (indent
, "", prefix
, name
, name
),
307 def printAlignOfType(self
, prefix
, name
, t
, output
=None, indent
=2):
309 '%*sprintf("%s: __alignof__(%s) = %%ld\\n", (long)__alignof__(%s));'
310 % (indent
, "", prefix
, name
, name
),
314 def printOffsetsOfType(self
, prefix
, name
, t
, output
=None, indent
=2):
315 if isinstance(t
, RecordType
):
316 for i
, f
in enumerate(t
.fields
):
319 fname
= "field%d" % i
321 '%*sprintf("%s: __builtin_offsetof(%s, %s) = %%ld\\n", (long)__builtin_offsetof(%s, %s));'
322 % (indent
, "", prefix
, name
, fname
, name
, fname
),
326 def printValueOfType(self
, prefix
, name
, t
, output
=None, indent
=2):
329 if isinstance(t
, BuiltinType
):
331 if t
.name
.split(" ")[-1] == "_Bool":
332 # Hack to work around PR5579.
333 value_expr
= "%s ? 2 : 0" % name
335 if t
.name
.endswith("long long"):
337 elif t
.name
.endswith("long"):
339 elif t
.name
.split(" ")[-1] in ("_Bool", "char", "short", "int", "unsigned"):
341 elif t
.name
in ("float", "double"):
343 elif t
.name
== "long double":
348 '%*sprintf("%s: %s = %%%s\\n", %s);'
349 % (indent
, "", prefix
, name
, code
, value_expr
),
352 elif isinstance(t
, EnumType
):
354 '%*sprintf("%s: %s = %%d\\n", %s);' % (indent
, "", prefix
, name
, name
),
357 elif isinstance(t
, RecordType
):
360 '%*sprintf("%s: %s (empty)\\n");' % (indent
, "", prefix
, name
),
363 for i
, f
in enumerate(t
.fields
):
364 if f
.isPaddingBitField():
366 fname
= "%s.field%d" % (name
, i
)
367 self
.printValueOfType(prefix
, fname
, f
, output
=output
, indent
=indent
)
368 elif isinstance(t
, ComplexType
):
369 self
.printValueOfType(
371 "(__real %s)" % name
,
376 self
.printValueOfType(
378 "(__imag %s)" % name
,
383 elif isinstance(t
, ArrayType
):
384 for i
in range(t
.numElements
):
385 # Access in this fashion as a hackish way to portably
388 self
.printValueOfType(
390 "((%s*) &%s)[%d]" % (t
.elementType
, name
, i
),
396 self
.printValueOfType(
398 "%s[%d]" % (name
, i
),
404 raise NotImplementedError('Cannot print value of type: "%s"' % (t
,))
406 def checkTypeValues(self
, nameLHS
, nameRHS
, t
, output
=None, indent
=2):
410 if isinstance(t
, BuiltinType
):
411 print("%*sassert(%s == %s);" % (indent
, "", nameLHS
, nameRHS
), file=output
)
412 elif isinstance(t
, EnumType
):
413 print("%*sassert(%s == %s);" % (indent
, "", nameLHS
, nameRHS
), file=output
)
414 elif isinstance(t
, RecordType
):
415 for i
, f
in enumerate(t
.fields
):
416 if f
.isPaddingBitField():
418 self
.checkTypeValues(
419 "%s.field%d" % (nameLHS
, i
),
420 "%s.field%d" % (nameRHS
, i
),
427 elif isinstance(t
, ComplexType
):
428 self
.checkTypeValues(
429 "(__real %s)" % nameLHS
,
430 "(__real %s)" % nameRHS
,
435 self
.checkTypeValues(
436 "(__imag %s)" % nameLHS
,
437 "(__imag %s)" % nameRHS
,
442 elif isinstance(t
, ArrayType
):
443 for i
in range(t
.numElements
):
444 # Access in this fashion as a hackish way to portably
447 self
.checkTypeValues(
448 "((%s*) &%s)[%d]" % (t
.elementType
, nameLHS
, i
),
449 "((%s*) &%s)[%d]" % (t
.elementType
, nameRHS
, i
),
455 self
.checkTypeValues(
456 "%s[%d]" % (nameLHS
, i
),
457 "%s[%d]" % (nameRHS
, i
),
463 raise NotImplementedError('Cannot print value of type: "%s"' % (t
,))
470 from optparse
import OptionParser
, OptionGroup
472 parser
= OptionParser("%prog [options] {indices}")
477 help="autogeneration mode (random or linear) [default %default]",
479 choices
=("random", "linear"),
486 help="autogenerate COUNT functions according to MODE",
495 help="start autogeneration with the Nth function type [default %default]",
504 help="maximum index for random autogeneration [default %default]",
512 help="random number generator seed [default %default]",
519 dest
="useRandomSeed",
520 help="use random value for initial random number generator seed",
528 help="add a test index to skip",
538 help="write output to FILE [default %default]",
547 help="write header file for output to FILE [default %default]",
556 help="write function tests to FILE [default %default]",
565 help="write test driver to FILE [default %default]",
574 help="test structure layout",
579 group
= OptionGroup(parser
, "Type Enumeration Options")
585 help="do not generate char types",
586 action
="store_false",
593 help="do not generate short types",
594 action
="store_false",
601 help="do not generate int types",
602 action
="store_false",
609 help="do not generate long types",
610 action
="store_false",
617 help="do not generate long long types",
618 action
="store_false",
625 help="do not generate unsigned integer types",
626 action
="store_false",
635 help="do not generate bool types",
636 action
="store_false",
643 help="do not generate float types",
644 action
="store_false",
651 help="do not generate double types",
652 action
="store_false",
658 dest
="useLongDouble",
659 help="do not generate long double types",
660 action
="store_false",
666 dest
="useVoidPointer",
667 help="do not generate void* types",
668 action
="store_false",
677 help="do not generate enum types",
678 action
="store_false",
687 help="do not generate record types",
688 action
="store_false",
695 help="do not generate complex types",
696 action
="store_false",
703 help="do not generate record types",
704 action
="store_false",
710 dest
="recordUseUnion",
711 help="do not generate union types",
712 action
="store_false",
719 help="do not generate vector types",
720 action
="store_false",
727 help="do not generate bit-field record members",
728 action
="store_false",
735 help="do not use any types",
736 action
="store_false",
743 "--no-function-return",
744 dest
="functionUseReturn",
745 help="do not generate return types for functions",
746 action
="store_false",
753 help="comma separated list of vector types (e.g., v2i32) [default %default]",
756 default
="v2i16, v1i64, v2i32, v4i16, v8i8, v2f32, v2i64, v4i32, v8i16, v16i8, v2f64, v4f32, v16f32",
763 help="comma separated list 'type:width' bit-field specifiers [default %default]",
766 default
=("char:0,char:4,int:0,unsigned:1,int:1,int:4,int:13,int:24"),
771 dest
="functionMaxArgs",
772 help="maximum number of arguments per function [default %default]",
782 help="maximum array size [default %default]",
791 dest
="recordMaxSize",
792 help="maximum number of fields per record [default %default]",
800 "--max-record-depth",
801 dest
="recordMaxDepth",
802 help="maximum nested structure depth [default %default]",
808 parser
.add_option_group(group
)
809 (opts
, args
) = parser
.parse_args()
811 if not opts
.useRandomSeed
:
812 random
.seed(opts
.seed
)
814 # Construct type generator
819 ints
.append(("char", 1))
821 ints
.append(("short", 2))
823 ints
.append(("int", 4))
826 ints
.append(("long", 4))
828 ints
.append(("long long", 8))
830 ints
= [("unsigned %s" % i
, s
) for i
, s
in ints
] + [
831 ("signed %s" % i
, s
) for i
, s
in ints
833 builtins
.extend(ints
)
836 builtins
.append(("_Bool", 1))
838 builtins
.append(("float", 4))
840 builtins
.append(("double", 8))
841 if opts
.useLongDouble
:
842 builtins
.append(("long double", 16))
844 if opts
.useVoidPointer
:
845 builtins
.append(("void*", 4))
847 btg
= FixedTypeGenerator([BuiltinType(n
, s
) for n
, s
in builtins
])
850 for specifier
in opts
.bitFields
.split(","):
851 if not specifier
.strip():
853 name
, width
= specifier
.strip().split(":", 1)
854 bitfields
.append(BuiltinType(name
, None, int(width
)))
855 bftg
= FixedTypeGenerator(bitfields
)
857 charType
= BuiltinType("char", 1)
858 shortType
= BuiltinType("short", 2)
859 intType
= BuiltinType("int", 4)
860 longlongType
= BuiltinType("long long", 8)
861 floatType
= BuiltinType("float", 4)
862 doubleType
= BuiltinType("double", 8)
863 sbtg
= FixedTypeGenerator([charType
, intType
, floatType
, doubleType
])
865 atg
= AnyTypeGenerator()
866 artg
= AnyTypeGenerator()
868 def makeGenerator(atg
, subgen
, subfieldgen
, useRecord
, useArray
, useBitField
):
869 atg
.addGenerator(btg
)
870 if useBitField
and opts
.useBitField
:
871 atg
.addGenerator(bftg
)
872 if useRecord
and opts
.useRecord
:
876 subfieldgen
, opts
.recordUseUnion
, opts
.recordMaxSize
880 # FIXME: Allow overriding builtins here
881 atg
.addGenerator(ComplexTypeGenerator(sbtg
))
882 if useArray
and opts
.useArray
:
884 atg
.addGenerator(ArrayTypeGenerator(subgen
, opts
.arrayMaxSize
))
887 for i
, t
in enumerate(opts
.vectorTypes
.split(",")):
888 m
= re
.match("v([1-9][0-9]*)([if][1-9][0-9]*)", t
.strip())
890 parser
.error("Invalid vector type: %r" % t
)
891 count
, kind
= m
.groups()
902 parser
.error("Invalid vector type: %r" % t
)
903 vTypes
.append(ArrayType(i
, True, type, count
* type.size
))
905 atg
.addGenerator(FixedTypeGenerator(vTypes
))
907 atg
.addGenerator(EnumTypeGenerator([None, "-1", "1", "1u"], 1, 4))
909 if opts
.recordMaxDepth
is None:
910 # Fully recursive, just avoid top-level arrays.
911 subFTG
= AnyTypeGenerator()
912 subTG
= AnyTypeGenerator()
913 atg
= AnyTypeGenerator()
914 makeGenerator(subFTG
, atg
, atg
, True, True, True)
915 makeGenerator(subTG
, atg
, subFTG
, True, True, False)
916 makeGenerator(atg
, subTG
, subFTG
, True, False, False)
918 # Make a chain of type generators, each builds smaller
920 base
= AnyTypeGenerator()
921 fbase
= AnyTypeGenerator()
922 makeGenerator(base
, None, None, False, False, False)
923 makeGenerator(fbase
, None, None, False, False, True)
924 for i
in range(opts
.recordMaxDepth
):
925 n
= AnyTypeGenerator()
926 fn
= AnyTypeGenerator()
927 makeGenerator(n
, base
, fbase
, True, True, False)
928 makeGenerator(fn
, base
, fbase
, True, True, True)
931 atg
= AnyTypeGenerator()
932 makeGenerator(atg
, base
, fbase
, True, False, False)
937 ftg
= FunctionTypeGenerator(atg
, opts
.functionUseReturn
, opts
.functionMaxArgs
)
939 # Override max,min,count if finite
940 if opts
.maxIndex
is None:
941 if ftg
.cardinality
is aleph0
:
942 opts
.maxIndex
= 10000000
944 opts
.maxIndex
= ftg
.cardinality
945 opts
.maxIndex
= min(opts
.maxIndex
, ftg
.cardinality
)
946 opts
.minIndex
= max(0, min(opts
.maxIndex
- 1, opts
.minIndex
))
947 if not opts
.mode
== "random":
948 opts
.count
= min(opts
.count
, opts
.maxIndex
- opts
.minIndex
)
950 if opts
.output
== "-":
953 output
= open(opts
.output
, "w")
954 atexit
.register(lambda: output
.close())
957 if opts
.outputHeader
:
958 outputHeader
= open(opts
.outputHeader
, "w")
959 atexit
.register(lambda: outputHeader
.close())
963 outputTests
= open(opts
.outputTests
, "w")
964 atexit
.register(lambda: outputTests
.close())
967 if opts
.outputDriver
:
968 outputDriver
= open(opts
.outputDriver
, "w")
969 atexit
.register(lambda: outputDriver
.close())
972 info
+= "// %s\n" % (" ".join(sys
.argv
),)
973 info
+= "// Generated: %s\n" % (time
.strftime("%Y-%m-%d %H:%M"),)
974 info
+= "// Cardinality of function generator: %s\n" % (ftg
.cardinality
,)
975 info
+= "// Cardinality of type generator: %s\n" % (atg
.cardinality
,)
978 info
+= "\n#include <stdio.h>"
982 outputHeader
=outputHeader
,
983 outputTests
=outputTests
,
984 outputDriver
=outputDriver
,
985 headerName
=opts
.outputHeader
,
992 except RuntimeError as e
:
993 if e
.args
[0] == "maximum recursion depth exceeded":
995 "WARNING: Skipped %d, recursion limit exceeded (bad arguments?)"
1002 P
.writeLayoutTest(N
, FT
)
1004 P
.writeFunction(N
, FT
)
1007 [write(int(a
)) for a
in args
]
1009 skipTests
= set(opts
.skipTests
)
1010 for i
in range(opts
.count
):
1011 if opts
.mode
== "linear":
1012 index
= opts
.minIndex
+ i
1014 index
= opts
.minIndex
+ int(
1015 (opts
.maxIndex
- opts
.minIndex
) * random
.random()
1017 if index
in skipTests
:
1024 if __name__
== "__main__":