xref: /llvm-project/clang/utils/ABITest/ABITestGen.py (revision dd3c26a045c081620375a878159f536758baba6e)
1#!/usr/bin/env python
2
3from __future__ import absolute_import, division, print_function
4from pprint import pprint
5import random, atexit, time
6from random import randrange
7import re
8
9from Enumeration import *
10from TypeGen import *
11
12####
13
14
15class TypePrinter(object):
16    def __init__(
17        self,
18        output,
19        outputHeader=None,
20        outputTests=None,
21        outputDriver=None,
22        headerName=None,
23        info=None,
24    ):
25        self.output = output
26        self.outputHeader = outputHeader
27        self.outputTests = outputTests
28        self.outputDriver = outputDriver
29        self.writeBody = outputHeader or outputTests or outputDriver
30        self.types = {}
31        self.testValues = {}
32        self.testReturnValues = {}
33        self.layoutTests = []
34        self.declarations = set()
35
36        if info:
37            for f in (
38                self.output,
39                self.outputHeader,
40                self.outputTests,
41                self.outputDriver,
42            ):
43                if f:
44                    print(info, file=f)
45
46        if self.writeBody:
47            print("#include <stdio.h>\n", file=self.output)
48            if self.outputTests:
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)
52
53        if headerName:
54            for f in (self.output, self.outputTests, self.outputDriver):
55                if f is not None:
56                    print('#include "%s"\n' % (headerName,), file=f)
57
58        if self.outputDriver:
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)
64
65    def finish(self):
66        if self.layoutTests:
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)
75
76        if self.outputDriver:
77            print('  printf("DONE\\n");', file=self.outputDriver)
78            print("  return 0;", file=self.outputDriver)
79            print("}", file=self.outputDriver)
80
81    def addDeclaration(self, decl):
82        if decl in self.declarations:
83            return False
84
85        self.declarations.add(decl)
86        if self.outputHeader:
87            print(decl, file=self.outputHeader)
88        else:
89            print(decl, file=self.output)
90            if self.outputTests:
91                print(decl, file=self.outputTests)
92        return True
93
94    def getTypeName(self, T):
95        name = self.types.get(T)
96        if name is None:
97            # Reserve slot
98            self.types[T] = None
99            self.types[T] = name = T.getTypeName(self)
100        return name
101
102    def writeLayoutTest(self, i, ty):
103        tyName = self.getTypeName(ty)
104        tyNameClean = tyName.replace(" ", "_").replace("*", "star")
105        fnName = "test_%s" % tyNameClean
106
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)
113
114        self.layoutTests.append((i, fnName))
115
116    def writeFunction(self, i, FT):
117        args = ", ".join(
118            ["%s arg%d" % (self.getTypeName(t), i) for i, t in enumerate(FT.argTypes)]
119        )
120        if not args:
121            args = "void"
122
123        if FT.returnType is None:
124            retvalName = None
125            retvalTypeName = "void"
126        else:
127            retvalTypeName = self.getTypeName(FT.returnType)
128            if self.writeBody or self.outputTests:
129                retvalName = self.getTestReturnValue(FT.returnType)
130
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)
136
137        print("%s %s(%s)" % (retvalTypeName, fnName, args), end=" ", file=self.output)
138        if self.writeBody:
139            print("{", file=self.output)
140
141            for i, t in enumerate(FT.argTypes):
142                self.printValueOfType("    %s" % fnName, "arg%d" % i, t)
143
144            if retvalName is not None:
145                print("  return %s;" % (retvalName,), file=self.output)
146            print("}", file=self.output)
147        else:
148            print("{}", file=self.output)
149        print(file=self.output)
150
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)
156
157        if self.outputTests:
158            if self.outputHeader:
159                print("void test_%s(void);" % (fnName,), file=self.outputHeader)
160
161            if retvalName is None:
162                retvalTests = None
163            else:
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)
167
168            if retvalTests is not None:
169                print(
170                    '  printf("%s: testing return.\\n");' % (fnName,),
171                    file=self.outputTests,
172                )
173                print(
174                    "  for (int i=0; i<%d; ++i) {" % (retvalTests[1],),
175                    file=self.outputTests,
176                )
177                args = ", ".join(["%s[%d]" % (t, randrange(l)) for t, l in tests])
178                print("    %s RV;" % (retvalTypeName,), file=self.outputTests)
179                print(
180                    "    %s = %s[i];" % (retvalName, retvalTests[0]),
181                    file=self.outputTests,
182                )
183                print("    RV = %s(%s);" % (fnName, args), file=self.outputTests)
184                self.printValueOfType(
185                    "  %s_RV" % fnName,
186                    "RV",
187                    FT.returnType,
188                    output=self.outputTests,
189                    indent=4,
190                )
191                self.checkTypeValues(
192                    "RV",
193                    "%s[i]" % retvalTests[0],
194                    FT.returnType,
195                    output=self.outputTests,
196                    indent=4,
197                )
198                print("  }", file=self.outputTests)
199
200            if tests:
201                print(
202                    '  printf("%s: testing arguments.\\n");' % (fnName,),
203                    file=self.outputTests,
204                )
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)
209                    print(
210                        "  %s(%s);"
211                        % (
212                            fnName,
213                            ", ".join(args),
214                        ),
215                        file=self.outputTests,
216                    )
217            print("}", file=self.outputTests)
218
219    def getTestReturnValue(self, type):
220        typeName = self.getTypeName(type)
221        info = self.testReturnValues.get(typeName)
222        if info is None:
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
230        return info
231
232    def getTestValuesArray(self, type):
233        typeName = self.getTypeName(type)
234        info = self.testValues.get(typeName)
235        if info is None:
236            name = "%s_values" % (typeName.replace(" ", "_").replace("*", "star"),)
237            print("static %s %s[] = {" % (typeName, name), file=self.outputTests)
238            length = 0
239            for item in self.getTestValues(type):
240                print("\t%s," % (item,), file=self.outputTests)
241                length += 1
242            print("};", file=self.outputTests)
243            info = self.testValues[typeName] = (name, length)
244        return info
245
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"]:
250                    yield i + "f"
251            elif t.name == "double":
252                for i in ["0.0", "-1.0", "1.0"]:
253                    yield i
254            elif t.name in ("void *"):
255                yield "(void*) 0"
256                yield "(void*) -1"
257            else:
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()]
266
267            if not nonPadding:
268                yield "{ }"
269                return
270
271            # FIXME: Use designated initializers to access non-first
272            # fields of unions.
273            if t.isUnion:
274                for v in self.getTestValues(nonPadding[0]):
275                    yield "{ %s }" % v
276                return
277
278            fieldValues = [list(v) for v in map(self.getTestValues, nonPadding)]
279            for i, values in enumerate(fieldValues):
280                for v in values:
281                    elements = [random.choice(fv) for fv in fieldValues]
282                    elements[i] = v
283                    yield "{ %s }" % (", ".join(elements))
284
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))
290            if not values:
291                yield "{ }"
292            for i in range(t.numElements):
293                for v in values:
294                    elements = [random.choice(values) for i in range(t.numElements)]
295                    elements[i] = v
296                    yield "{ %s }" % (", ".join(elements))
297        else:
298            raise NotImplementedError('Cannot make tests values of type: "%s"' % (t,))
299
300    def printSizeOfType(self, prefix, name, t, output=None, indent=2):
301        print(
302            '%*sprintf("%s: sizeof(%s) = %%ld\\n", (long)sizeof(%s));'
303            % (indent, "", prefix, name, name),
304            file=output,
305        )
306
307    def printAlignOfType(self, prefix, name, t, output=None, indent=2):
308        print(
309            '%*sprintf("%s: __alignof__(%s) = %%ld\\n", (long)__alignof__(%s));'
310            % (indent, "", prefix, name, name),
311            file=output,
312        )
313
314    def printOffsetsOfType(self, prefix, name, t, output=None, indent=2):
315        if isinstance(t, RecordType):
316            for i, f in enumerate(t.fields):
317                if f.isBitField():
318                    continue
319                fname = "field%d" % i
320                print(
321                    '%*sprintf("%s: __builtin_offsetof(%s, %s) = %%ld\\n", (long)__builtin_offsetof(%s, %s));'
322                    % (indent, "", prefix, name, fname, name, fname),
323                    file=output,
324                )
325
326    def printValueOfType(self, prefix, name, t, output=None, indent=2):
327        if output is None:
328            output = self.output
329        if isinstance(t, BuiltinType):
330            value_expr = name
331            if t.name.split(" ")[-1] == "_Bool":
332                # Hack to work around PR5579.
333                value_expr = "%s ? 2 : 0" % name
334
335            if t.name.endswith("long long"):
336                code = "lld"
337            elif t.name.endswith("long"):
338                code = "ld"
339            elif t.name.split(" ")[-1] in ("_Bool", "char", "short", "int", "unsigned"):
340                code = "d"
341            elif t.name in ("float", "double"):
342                code = "f"
343            elif t.name == "long double":
344                code = "Lf"
345            else:
346                code = "p"
347            print(
348                '%*sprintf("%s: %s = %%%s\\n", %s);'
349                % (indent, "", prefix, name, code, value_expr),
350                file=output,
351            )
352        elif isinstance(t, EnumType):
353            print(
354                '%*sprintf("%s: %s = %%d\\n", %s);' % (indent, "", prefix, name, name),
355                file=output,
356            )
357        elif isinstance(t, RecordType):
358            if not t.fields:
359                print(
360                    '%*sprintf("%s: %s (empty)\\n");' % (indent, "", prefix, name),
361                    file=output,
362                )
363            for i, f in enumerate(t.fields):
364                if f.isPaddingBitField():
365                    continue
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(
370                prefix,
371                "(__real %s)" % name,
372                t.elementType,
373                output=output,
374                indent=indent,
375            )
376            self.printValueOfType(
377                prefix,
378                "(__imag %s)" % name,
379                t.elementType,
380                output=output,
381                indent=indent,
382            )
383        elif isinstance(t, ArrayType):
384            for i in range(t.numElements):
385                # Access in this fashion as a hackish way to portably
386                # access vectors.
387                if t.isVector:
388                    self.printValueOfType(
389                        prefix,
390                        "((%s*) &%s)[%d]" % (t.elementType, name, i),
391                        t.elementType,
392                        output=output,
393                        indent=indent,
394                    )
395                else:
396                    self.printValueOfType(
397                        prefix,
398                        "%s[%d]" % (name, i),
399                        t.elementType,
400                        output=output,
401                        indent=indent,
402                    )
403        else:
404            raise NotImplementedError('Cannot print value of type: "%s"' % (t,))
405
406    def checkTypeValues(self, nameLHS, nameRHS, t, output=None, indent=2):
407        prefix = "foo"
408        if output is None:
409            output = self.output
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():
417                    continue
418                self.checkTypeValues(
419                    "%s.field%d" % (nameLHS, i),
420                    "%s.field%d" % (nameRHS, i),
421                    f,
422                    output=output,
423                    indent=indent,
424                )
425                if t.isUnion:
426                    break
427        elif isinstance(t, ComplexType):
428            self.checkTypeValues(
429                "(__real %s)" % nameLHS,
430                "(__real %s)" % nameRHS,
431                t.elementType,
432                output=output,
433                indent=indent,
434            )
435            self.checkTypeValues(
436                "(__imag %s)" % nameLHS,
437                "(__imag %s)" % nameRHS,
438                t.elementType,
439                output=output,
440                indent=indent,
441            )
442        elif isinstance(t, ArrayType):
443            for i in range(t.numElements):
444                # Access in this fashion as a hackish way to portably
445                # access vectors.
446                if t.isVector:
447                    self.checkTypeValues(
448                        "((%s*) &%s)[%d]" % (t.elementType, nameLHS, i),
449                        "((%s*) &%s)[%d]" % (t.elementType, nameRHS, i),
450                        t.elementType,
451                        output=output,
452                        indent=indent,
453                    )
454                else:
455                    self.checkTypeValues(
456                        "%s[%d]" % (nameLHS, i),
457                        "%s[%d]" % (nameRHS, i),
458                        t.elementType,
459                        output=output,
460                        indent=indent,
461                    )
462        else:
463            raise NotImplementedError('Cannot print value of type: "%s"' % (t,))
464
465
466import sys
467
468
469def main():
470    from optparse import OptionParser, OptionGroup
471
472    parser = OptionParser("%prog [options] {indices}")
473    parser.add_option(
474        "",
475        "--mode",
476        dest="mode",
477        help="autogeneration mode (random or linear) [default %default]",
478        type="choice",
479        choices=("random", "linear"),
480        default="linear",
481    )
482    parser.add_option(
483        "",
484        "--count",
485        dest="count",
486        help="autogenerate COUNT functions according to MODE",
487        type=int,
488        default=0,
489    )
490    parser.add_option(
491        "",
492        "--min",
493        dest="minIndex",
494        metavar="N",
495        help="start autogeneration with the Nth function type  [default %default]",
496        type=int,
497        default=0,
498    )
499    parser.add_option(
500        "",
501        "--max",
502        dest="maxIndex",
503        metavar="N",
504        help="maximum index for random autogeneration  [default %default]",
505        type=int,
506        default=10000000,
507    )
508    parser.add_option(
509        "",
510        "--seed",
511        dest="seed",
512        help="random number generator seed [default %default]",
513        type=int,
514        default=1,
515    )
516    parser.add_option(
517        "",
518        "--use-random-seed",
519        dest="useRandomSeed",
520        help="use random value for initial random number generator seed",
521        action="store_true",
522        default=False,
523    )
524    parser.add_option(
525        "",
526        "--skip",
527        dest="skipTests",
528        help="add a test index to skip",
529        type=int,
530        action="append",
531        default=[],
532    )
533    parser.add_option(
534        "-o",
535        "--output",
536        dest="output",
537        metavar="FILE",
538        help="write output to FILE  [default %default]",
539        type=str,
540        default="-",
541    )
542    parser.add_option(
543        "-O",
544        "--output-header",
545        dest="outputHeader",
546        metavar="FILE",
547        help="write header file for output to FILE  [default %default]",
548        type=str,
549        default=None,
550    )
551    parser.add_option(
552        "-T",
553        "--output-tests",
554        dest="outputTests",
555        metavar="FILE",
556        help="write function tests to FILE  [default %default]",
557        type=str,
558        default=None,
559    )
560    parser.add_option(
561        "-D",
562        "--output-driver",
563        dest="outputDriver",
564        metavar="FILE",
565        help="write test driver to FILE  [default %default]",
566        type=str,
567        default=None,
568    )
569    parser.add_option(
570        "",
571        "--test-layout",
572        dest="testLayout",
573        metavar="FILE",
574        help="test structure layout",
575        action="store_true",
576        default=False,
577    )
578
579    group = OptionGroup(parser, "Type Enumeration Options")
580    # Builtins - Ints
581    group.add_option(
582        "",
583        "--no-char",
584        dest="useChar",
585        help="do not generate char types",
586        action="store_false",
587        default=True,
588    )
589    group.add_option(
590        "",
591        "--no-short",
592        dest="useShort",
593        help="do not generate short types",
594        action="store_false",
595        default=True,
596    )
597    group.add_option(
598        "",
599        "--no-int",
600        dest="useInt",
601        help="do not generate int types",
602        action="store_false",
603        default=True,
604    )
605    group.add_option(
606        "",
607        "--no-long",
608        dest="useLong",
609        help="do not generate long types",
610        action="store_false",
611        default=True,
612    )
613    group.add_option(
614        "",
615        "--no-long-long",
616        dest="useLongLong",
617        help="do not generate long long types",
618        action="store_false",
619        default=True,
620    )
621    group.add_option(
622        "",
623        "--no-unsigned",
624        dest="useUnsigned",
625        help="do not generate unsigned integer types",
626        action="store_false",
627        default=True,
628    )
629
630    # Other builtins
631    group.add_option(
632        "",
633        "--no-bool",
634        dest="useBool",
635        help="do not generate bool types",
636        action="store_false",
637        default=True,
638    )
639    group.add_option(
640        "",
641        "--no-float",
642        dest="useFloat",
643        help="do not generate float types",
644        action="store_false",
645        default=True,
646    )
647    group.add_option(
648        "",
649        "--no-double",
650        dest="useDouble",
651        help="do not generate double types",
652        action="store_false",
653        default=True,
654    )
655    group.add_option(
656        "",
657        "--no-long-double",
658        dest="useLongDouble",
659        help="do not generate long double types",
660        action="store_false",
661        default=True,
662    )
663    group.add_option(
664        "",
665        "--no-void-pointer",
666        dest="useVoidPointer",
667        help="do not generate void* types",
668        action="store_false",
669        default=True,
670    )
671
672    # Enumerations
673    group.add_option(
674        "",
675        "--no-enums",
676        dest="useEnum",
677        help="do not generate enum types",
678        action="store_false",
679        default=True,
680    )
681
682    # Derived types
683    group.add_option(
684        "",
685        "--no-array",
686        dest="useArray",
687        help="do not generate record types",
688        action="store_false",
689        default=True,
690    )
691    group.add_option(
692        "",
693        "--no-complex",
694        dest="useComplex",
695        help="do not generate complex types",
696        action="store_false",
697        default=True,
698    )
699    group.add_option(
700        "",
701        "--no-record",
702        dest="useRecord",
703        help="do not generate record types",
704        action="store_false",
705        default=True,
706    )
707    group.add_option(
708        "",
709        "--no-union",
710        dest="recordUseUnion",
711        help="do not generate union types",
712        action="store_false",
713        default=True,
714    )
715    group.add_option(
716        "",
717        "--no-vector",
718        dest="useVector",
719        help="do not generate vector types",
720        action="store_false",
721        default=True,
722    )
723    group.add_option(
724        "",
725        "--no-bit-field",
726        dest="useBitField",
727        help="do not generate bit-field record members",
728        action="store_false",
729        default=True,
730    )
731    group.add_option(
732        "",
733        "--no-builtins",
734        dest="useBuiltins",
735        help="do not use any types",
736        action="store_false",
737        default=True,
738    )
739
740    # Tuning
741    group.add_option(
742        "",
743        "--no-function-return",
744        dest="functionUseReturn",
745        help="do not generate return types for functions",
746        action="store_false",
747        default=True,
748    )
749    group.add_option(
750        "",
751        "--vector-types",
752        dest="vectorTypes",
753        help="comma separated list of vector types (e.g., v2i32) [default %default]",
754        action="store",
755        type=str,
756        default="v2i16, v1i64, v2i32, v4i16, v8i8, v2f32, v2i64, v4i32, v8i16, v16i8, v2f64, v4f32, v16f32",
757        metavar="N",
758    )
759    group.add_option(
760        "",
761        "--bit-fields",
762        dest="bitFields",
763        help="comma separated list 'type:width' bit-field specifiers [default %default]",
764        action="store",
765        type=str,
766        default=("char:0,char:4,int:0,unsigned:1,int:1,int:4,int:13,int:24"),
767    )
768    group.add_option(
769        "",
770        "--max-args",
771        dest="functionMaxArgs",
772        help="maximum number of arguments per function [default %default]",
773        action="store",
774        type=int,
775        default=4,
776        metavar="N",
777    )
778    group.add_option(
779        "",
780        "--max-array",
781        dest="arrayMaxSize",
782        help="maximum array size [default %default]",
783        action="store",
784        type=int,
785        default=4,
786        metavar="N",
787    )
788    group.add_option(
789        "",
790        "--max-record",
791        dest="recordMaxSize",
792        help="maximum number of fields per record [default %default]",
793        action="store",
794        type=int,
795        default=4,
796        metavar="N",
797    )
798    group.add_option(
799        "",
800        "--max-record-depth",
801        dest="recordMaxDepth",
802        help="maximum nested structure depth [default %default]",
803        action="store",
804        type=int,
805        default=None,
806        metavar="N",
807    )
808    parser.add_option_group(group)
809    (opts, args) = parser.parse_args()
810
811    if not opts.useRandomSeed:
812        random.seed(opts.seed)
813
814    # Construct type generator
815    builtins = []
816    if opts.useBuiltins:
817        ints = []
818        if opts.useChar:
819            ints.append(("char", 1))
820        if opts.useShort:
821            ints.append(("short", 2))
822        if opts.useInt:
823            ints.append(("int", 4))
824        # FIXME: Wrong size.
825        if opts.useLong:
826            ints.append(("long", 4))
827        if opts.useLongLong:
828            ints.append(("long long", 8))
829        if opts.useUnsigned:
830            ints = [("unsigned %s" % i, s) for i, s in ints] + [
831                ("signed %s" % i, s) for i, s in ints
832            ]
833        builtins.extend(ints)
834
835        if opts.useBool:
836            builtins.append(("_Bool", 1))
837        if opts.useFloat:
838            builtins.append(("float", 4))
839        if opts.useDouble:
840            builtins.append(("double", 8))
841        if opts.useLongDouble:
842            builtins.append(("long double", 16))
843        # FIXME: Wrong size.
844        if opts.useVoidPointer:
845            builtins.append(("void*", 4))
846
847    btg = FixedTypeGenerator([BuiltinType(n, s) for n, s in builtins])
848
849    bitfields = []
850    for specifier in opts.bitFields.split(","):
851        if not specifier.strip():
852            continue
853        name, width = specifier.strip().split(":", 1)
854        bitfields.append(BuiltinType(name, None, int(width)))
855    bftg = FixedTypeGenerator(bitfields)
856
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])
864
865    atg = AnyTypeGenerator()
866    artg = AnyTypeGenerator()
867
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:
873            assert subgen
874            atg.addGenerator(
875                RecordTypeGenerator(
876                    subfieldgen, opts.recordUseUnion, opts.recordMaxSize
877                )
878            )
879        if opts.useComplex:
880            # FIXME: Allow overriding builtins here
881            atg.addGenerator(ComplexTypeGenerator(sbtg))
882        if useArray and opts.useArray:
883            assert subgen
884            atg.addGenerator(ArrayTypeGenerator(subgen, opts.arrayMaxSize))
885        if opts.useVector:
886            vTypes = []
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())
889                if not m:
890                    parser.error("Invalid vector type: %r" % t)
891                count, kind = m.groups()
892                count = int(count)
893                type = {
894                    "i8": charType,
895                    "i16": shortType,
896                    "i32": intType,
897                    "i64": longlongType,
898                    "f32": floatType,
899                    "f64": doubleType,
900                }.get(kind)
901                if not type:
902                    parser.error("Invalid vector type: %r" % t)
903                vTypes.append(ArrayType(i, True, type, count * type.size))
904
905            atg.addGenerator(FixedTypeGenerator(vTypes))
906        if opts.useEnum:
907            atg.addGenerator(EnumTypeGenerator([None, "-1", "1", "1u"], 1, 4))
908
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)
917    else:
918        # Make a chain of type generators, each builds smaller
919        # structures.
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)
929            base = n
930            fbase = fn
931        atg = AnyTypeGenerator()
932        makeGenerator(atg, base, fbase, True, False, False)
933
934    if opts.testLayout:
935        ftg = atg
936    else:
937        ftg = FunctionTypeGenerator(atg, opts.functionUseReturn, opts.functionMaxArgs)
938
939    # Override max,min,count if finite
940    if opts.maxIndex is None:
941        if ftg.cardinality is aleph0:
942            opts.maxIndex = 10000000
943        else:
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)
949
950    if opts.output == "-":
951        output = sys.stdout
952    else:
953        output = open(opts.output, "w")
954        atexit.register(lambda: output.close())
955
956    outputHeader = None
957    if opts.outputHeader:
958        outputHeader = open(opts.outputHeader, "w")
959        atexit.register(lambda: outputHeader.close())
960
961    outputTests = None
962    if opts.outputTests:
963        outputTests = open(opts.outputTests, "w")
964        atexit.register(lambda: outputTests.close())
965
966    outputDriver = None
967    if opts.outputDriver:
968        outputDriver = open(opts.outputDriver, "w")
969        atexit.register(lambda: outputDriver.close())
970
971    info = ""
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,)
976
977    if opts.testLayout:
978        info += "\n#include <stdio.h>"
979
980    P = TypePrinter(
981        output,
982        outputHeader=outputHeader,
983        outputTests=outputTests,
984        outputDriver=outputDriver,
985        headerName=opts.outputHeader,
986        info=info,
987    )
988
989    def write(N):
990        try:
991            FT = ftg.get(N)
992        except RuntimeError as e:
993            if e.args[0] == "maximum recursion depth exceeded":
994                print(
995                    "WARNING: Skipped %d, recursion limit exceeded (bad arguments?)"
996                    % (N,),
997                    file=sys.stderr,
998                )
999                return
1000            raise
1001        if opts.testLayout:
1002            P.writeLayoutTest(N, FT)
1003        else:
1004            P.writeFunction(N, FT)
1005
1006    if args:
1007        [write(int(a)) for a in args]
1008
1009    skipTests = set(opts.skipTests)
1010    for i in range(opts.count):
1011        if opts.mode == "linear":
1012            index = opts.minIndex + i
1013        else:
1014            index = opts.minIndex + int(
1015                (opts.maxIndex - opts.minIndex) * random.random()
1016            )
1017        if index in skipTests:
1018            continue
1019        write(index)
1020
1021    P.finish()
1022
1023
1024if __name__ == "__main__":
1025    main()
1026