mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 11:16:09 +00:00

This is an ongoing series of commits that are reformatting our Python code. Reformatting is done with `black`. If you end up having problems merging this commit because you have made changes to a python file, the best way to handle that is to run git checkout --ours <yourfile> and then reformat it with black. If you run into any problems, post to discourse about it and we will try to help. RFC Thread below: https://discourse.llvm.org/t/rfc-document-and-standardize-python-code-style Reviewed By: MatzeB Differential Revision: https://reviews.llvm.org/D150761
1026 lines
32 KiB
Python
Executable File
1026 lines
32 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
from pprint import pprint
|
|
import random, atexit, time
|
|
from random import randrange
|
|
import re
|
|
|
|
from Enumeration import *
|
|
from TypeGen import *
|
|
|
|
####
|
|
|
|
|
|
class TypePrinter(object):
|
|
def __init__(
|
|
self,
|
|
output,
|
|
outputHeader=None,
|
|
outputTests=None,
|
|
outputDriver=None,
|
|
headerName=None,
|
|
info=None,
|
|
):
|
|
self.output = output
|
|
self.outputHeader = outputHeader
|
|
self.outputTests = outputTests
|
|
self.outputDriver = outputDriver
|
|
self.writeBody = outputHeader or outputTests or outputDriver
|
|
self.types = {}
|
|
self.testValues = {}
|
|
self.testReturnValues = {}
|
|
self.layoutTests = []
|
|
self.declarations = set()
|
|
|
|
if info:
|
|
for f in (
|
|
self.output,
|
|
self.outputHeader,
|
|
self.outputTests,
|
|
self.outputDriver,
|
|
):
|
|
if f:
|
|
print(info, file=f)
|
|
|
|
if self.writeBody:
|
|
print("#include <stdio.h>\n", file=self.output)
|
|
if self.outputTests:
|
|
print("#include <stdio.h>", file=self.outputTests)
|
|
print("#include <string.h>", file=self.outputTests)
|
|
print("#include <assert.h>\n", file=self.outputTests)
|
|
|
|
if headerName:
|
|
for f in (self.output, self.outputTests, self.outputDriver):
|
|
if f is not None:
|
|
print('#include "%s"\n' % (headerName,), file=f)
|
|
|
|
if self.outputDriver:
|
|
print("#include <stdio.h>", file=self.outputDriver)
|
|
print("#include <stdlib.h>\n", file=self.outputDriver)
|
|
print("int main(int argc, char **argv) {", file=self.outputDriver)
|
|
print(" int index = -1;", file=self.outputDriver)
|
|
print(" if (argc > 1) index = atoi(argv[1]);", file=self.outputDriver)
|
|
|
|
def finish(self):
|
|
if self.layoutTests:
|
|
print("int main(int argc, char **argv) {", file=self.output)
|
|
print(" int index = -1;", file=self.output)
|
|
print(" if (argc > 1) index = atoi(argv[1]);", file=self.output)
|
|
for i, f in self.layoutTests:
|
|
print(" if (index == -1 || index == %d)" % i, file=self.output)
|
|
print(" %s();" % f, file=self.output)
|
|
print(" return 0;", file=self.output)
|
|
print("}", file=self.output)
|
|
|
|
if self.outputDriver:
|
|
print(' printf("DONE\\n");', file=self.outputDriver)
|
|
print(" return 0;", file=self.outputDriver)
|
|
print("}", file=self.outputDriver)
|
|
|
|
def addDeclaration(self, decl):
|
|
if decl in self.declarations:
|
|
return False
|
|
|
|
self.declarations.add(decl)
|
|
if self.outputHeader:
|
|
print(decl, file=self.outputHeader)
|
|
else:
|
|
print(decl, file=self.output)
|
|
if self.outputTests:
|
|
print(decl, file=self.outputTests)
|
|
return True
|
|
|
|
def getTypeName(self, T):
|
|
name = self.types.get(T)
|
|
if name is None:
|
|
# Reserve slot
|
|
self.types[T] = None
|
|
self.types[T] = name = T.getTypeName(self)
|
|
return name
|
|
|
|
def writeLayoutTest(self, i, ty):
|
|
tyName = self.getTypeName(ty)
|
|
tyNameClean = tyName.replace(" ", "_").replace("*", "star")
|
|
fnName = "test_%s" % tyNameClean
|
|
|
|
print("void %s(void) {" % fnName, file=self.output)
|
|
self.printSizeOfType(" %s" % fnName, tyName, ty, self.output)
|
|
self.printAlignOfType(" %s" % fnName, tyName, ty, self.output)
|
|
self.printOffsetsOfType(" %s" % fnName, tyName, ty, self.output)
|
|
print("}", file=self.output)
|
|
print(file=self.output)
|
|
|
|
self.layoutTests.append((i, fnName))
|
|
|
|
def writeFunction(self, i, FT):
|
|
args = ", ".join(
|
|
["%s arg%d" % (self.getTypeName(t), i) for i, t in enumerate(FT.argTypes)]
|
|
)
|
|
if not args:
|
|
args = "void"
|
|
|
|
if FT.returnType is None:
|
|
retvalName = None
|
|
retvalTypeName = "void"
|
|
else:
|
|
retvalTypeName = self.getTypeName(FT.returnType)
|
|
if self.writeBody or self.outputTests:
|
|
retvalName = self.getTestReturnValue(FT.returnType)
|
|
|
|
fnName = "fn%d" % (FT.index,)
|
|
if self.outputHeader:
|
|
print("%s %s(%s);" % (retvalTypeName, fnName, args), file=self.outputHeader)
|
|
elif self.outputTests:
|
|
print("%s %s(%s);" % (retvalTypeName, fnName, args), file=self.outputTests)
|
|
|
|
print("%s %s(%s)" % (retvalTypeName, fnName, args), end=" ", file=self.output)
|
|
if self.writeBody:
|
|
print("{", file=self.output)
|
|
|
|
for i, t in enumerate(FT.argTypes):
|
|
self.printValueOfType(" %s" % fnName, "arg%d" % i, t)
|
|
|
|
if retvalName is not None:
|
|
print(" return %s;" % (retvalName,), file=self.output)
|
|
print("}", file=self.output)
|
|
else:
|
|
print("{}", file=self.output)
|
|
print(file=self.output)
|
|
|
|
if self.outputDriver:
|
|
print(" if (index == -1 || index == %d) {" % i, file=self.outputDriver)
|
|
print(" extern void test_%s(void);" % fnName, file=self.outputDriver)
|
|
print(" test_%s();" % fnName, file=self.outputDriver)
|
|
print(" }", file=self.outputDriver)
|
|
|
|
if self.outputTests:
|
|
if self.outputHeader:
|
|
print("void test_%s(void);" % (fnName,), file=self.outputHeader)
|
|
|
|
if retvalName is None:
|
|
retvalTests = None
|
|
else:
|
|
retvalTests = self.getTestValuesArray(FT.returnType)
|
|
tests = [self.getTestValuesArray(ty) for ty in FT.argTypes]
|
|
print("void test_%s(void) {" % (fnName,), file=self.outputTests)
|
|
|
|
if retvalTests is not None:
|
|
print(
|
|
' printf("%s: testing return.\\n");' % (fnName,),
|
|
file=self.outputTests,
|
|
)
|
|
print(
|
|
" for (int i=0; i<%d; ++i) {" % (retvalTests[1],),
|
|
file=self.outputTests,
|
|
)
|
|
args = ", ".join(["%s[%d]" % (t, randrange(l)) for t, l in tests])
|
|
print(" %s RV;" % (retvalTypeName,), file=self.outputTests)
|
|
print(
|
|
" %s = %s[i];" % (retvalName, retvalTests[0]),
|
|
file=self.outputTests,
|
|
)
|
|
print(" RV = %s(%s);" % (fnName, args), file=self.outputTests)
|
|
self.printValueOfType(
|
|
" %s_RV" % fnName,
|
|
"RV",
|
|
FT.returnType,
|
|
output=self.outputTests,
|
|
indent=4,
|
|
)
|
|
self.checkTypeValues(
|
|
"RV",
|
|
"%s[i]" % retvalTests[0],
|
|
FT.returnType,
|
|
output=self.outputTests,
|
|
indent=4,
|
|
)
|
|
print(" }", file=self.outputTests)
|
|
|
|
if tests:
|
|
print(
|
|
' printf("%s: testing arguments.\\n");' % (fnName,),
|
|
file=self.outputTests,
|
|
)
|
|
for i, (array, length) in enumerate(tests):
|
|
for j in range(length):
|
|
args = ["%s[%d]" % (t, randrange(l)) for t, l in tests]
|
|
args[i] = "%s[%d]" % (array, j)
|
|
print(
|
|
" %s(%s);"
|
|
% (
|
|
fnName,
|
|
", ".join(args),
|
|
),
|
|
file=self.outputTests,
|
|
)
|
|
print("}", file=self.outputTests)
|
|
|
|
def getTestReturnValue(self, type):
|
|
typeName = self.getTypeName(type)
|
|
info = self.testReturnValues.get(typeName)
|
|
if info is None:
|
|
name = "%s_retval" % (typeName.replace(" ", "_").replace("*", "star"),)
|
|
print("%s %s;" % (typeName, name), file=self.output)
|
|
if self.outputHeader:
|
|
print("extern %s %s;" % (typeName, name), file=self.outputHeader)
|
|
elif self.outputTests:
|
|
print("extern %s %s;" % (typeName, name), file=self.outputTests)
|
|
info = self.testReturnValues[typeName] = name
|
|
return info
|
|
|
|
def getTestValuesArray(self, type):
|
|
typeName = self.getTypeName(type)
|
|
info = self.testValues.get(typeName)
|
|
if info is None:
|
|
name = "%s_values" % (typeName.replace(" ", "_").replace("*", "star"),)
|
|
print("static %s %s[] = {" % (typeName, name), file=self.outputTests)
|
|
length = 0
|
|
for item in self.getTestValues(type):
|
|
print("\t%s," % (item,), file=self.outputTests)
|
|
length += 1
|
|
print("};", file=self.outputTests)
|
|
info = self.testValues[typeName] = (name, length)
|
|
return info
|
|
|
|
def getTestValues(self, t):
|
|
if isinstance(t, BuiltinType):
|
|
if t.name == "float":
|
|
for i in ["0.0", "-1.0", "1.0"]:
|
|
yield i + "f"
|
|
elif t.name == "double":
|
|
for i in ["0.0", "-1.0", "1.0"]:
|
|
yield i
|
|
elif t.name in ("void *"):
|
|
yield "(void*) 0"
|
|
yield "(void*) -1"
|
|
else:
|
|
yield "(%s) 0" % (t.name,)
|
|
yield "(%s) -1" % (t.name,)
|
|
yield "(%s) 1" % (t.name,)
|
|
elif isinstance(t, EnumType):
|
|
for i in range(0, len(t.enumerators)):
|
|
yield "enum%dval%d_%d" % (t.index, i, t.unique_id)
|
|
elif isinstance(t, RecordType):
|
|
nonPadding = [f for f in t.fields if not f.isPaddingBitField()]
|
|
|
|
if not nonPadding:
|
|
yield "{ }"
|
|
return
|
|
|
|
# FIXME: Use designated initializers to access non-first
|
|
# fields of unions.
|
|
if t.isUnion:
|
|
for v in self.getTestValues(nonPadding[0]):
|
|
yield "{ %s }" % v
|
|
return
|
|
|
|
fieldValues = [list(v) for v in map(self.getTestValues, nonPadding)]
|
|
for i, values in enumerate(fieldValues):
|
|
for v in values:
|
|
elements = [random.choice(fv) for fv in fieldValues]
|
|
elements[i] = v
|
|
yield "{ %s }" % (", ".join(elements))
|
|
|
|
elif isinstance(t, ComplexType):
|
|
for t in self.getTestValues(t.elementType):
|
|
yield "%s + %s * 1i" % (t, t)
|
|
elif isinstance(t, ArrayType):
|
|
values = list(self.getTestValues(t.elementType))
|
|
if not values:
|
|
yield "{ }"
|
|
for i in range(t.numElements):
|
|
for v in values:
|
|
elements = [random.choice(values) for i in range(t.numElements)]
|
|
elements[i] = v
|
|
yield "{ %s }" % (", ".join(elements))
|
|
else:
|
|
raise NotImplementedError('Cannot make tests values of type: "%s"' % (t,))
|
|
|
|
def printSizeOfType(self, prefix, name, t, output=None, indent=2):
|
|
print(
|
|
'%*sprintf("%s: sizeof(%s) = %%ld\\n", (long)sizeof(%s));'
|
|
% (indent, "", prefix, name, name),
|
|
file=output,
|
|
)
|
|
|
|
def printAlignOfType(self, prefix, name, t, output=None, indent=2):
|
|
print(
|
|
'%*sprintf("%s: __alignof__(%s) = %%ld\\n", (long)__alignof__(%s));'
|
|
% (indent, "", prefix, name, name),
|
|
file=output,
|
|
)
|
|
|
|
def printOffsetsOfType(self, prefix, name, t, output=None, indent=2):
|
|
if isinstance(t, RecordType):
|
|
for i, f in enumerate(t.fields):
|
|
if f.isBitField():
|
|
continue
|
|
fname = "field%d" % i
|
|
print(
|
|
'%*sprintf("%s: __builtin_offsetof(%s, %s) = %%ld\\n", (long)__builtin_offsetof(%s, %s));'
|
|
% (indent, "", prefix, name, fname, name, fname),
|
|
file=output,
|
|
)
|
|
|
|
def printValueOfType(self, prefix, name, t, output=None, indent=2):
|
|
if output is None:
|
|
output = self.output
|
|
if isinstance(t, BuiltinType):
|
|
value_expr = name
|
|
if t.name.split(" ")[-1] == "_Bool":
|
|
# Hack to work around PR5579.
|
|
value_expr = "%s ? 2 : 0" % name
|
|
|
|
if t.name.endswith("long long"):
|
|
code = "lld"
|
|
elif t.name.endswith("long"):
|
|
code = "ld"
|
|
elif t.name.split(" ")[-1] in ("_Bool", "char", "short", "int", "unsigned"):
|
|
code = "d"
|
|
elif t.name in ("float", "double"):
|
|
code = "f"
|
|
elif t.name == "long double":
|
|
code = "Lf"
|
|
else:
|
|
code = "p"
|
|
print(
|
|
'%*sprintf("%s: %s = %%%s\\n", %s);'
|
|
% (indent, "", prefix, name, code, value_expr),
|
|
file=output,
|
|
)
|
|
elif isinstance(t, EnumType):
|
|
print(
|
|
'%*sprintf("%s: %s = %%d\\n", %s);' % (indent, "", prefix, name, name),
|
|
file=output,
|
|
)
|
|
elif isinstance(t, RecordType):
|
|
if not t.fields:
|
|
print(
|
|
'%*sprintf("%s: %s (empty)\\n");' % (indent, "", prefix, name),
|
|
file=output,
|
|
)
|
|
for i, f in enumerate(t.fields):
|
|
if f.isPaddingBitField():
|
|
continue
|
|
fname = "%s.field%d" % (name, i)
|
|
self.printValueOfType(prefix, fname, f, output=output, indent=indent)
|
|
elif isinstance(t, ComplexType):
|
|
self.printValueOfType(
|
|
prefix,
|
|
"(__real %s)" % name,
|
|
t.elementType,
|
|
output=output,
|
|
indent=indent,
|
|
)
|
|
self.printValueOfType(
|
|
prefix,
|
|
"(__imag %s)" % name,
|
|
t.elementType,
|
|
output=output,
|
|
indent=indent,
|
|
)
|
|
elif isinstance(t, ArrayType):
|
|
for i in range(t.numElements):
|
|
# Access in this fashion as a hackish way to portably
|
|
# access vectors.
|
|
if t.isVector:
|
|
self.printValueOfType(
|
|
prefix,
|
|
"((%s*) &%s)[%d]" % (t.elementType, name, i),
|
|
t.elementType,
|
|
output=output,
|
|
indent=indent,
|
|
)
|
|
else:
|
|
self.printValueOfType(
|
|
prefix,
|
|
"%s[%d]" % (name, i),
|
|
t.elementType,
|
|
output=output,
|
|
indent=indent,
|
|
)
|
|
else:
|
|
raise NotImplementedError('Cannot print value of type: "%s"' % (t,))
|
|
|
|
def checkTypeValues(self, nameLHS, nameRHS, t, output=None, indent=2):
|
|
prefix = "foo"
|
|
if output is None:
|
|
output = self.output
|
|
if isinstance(t, BuiltinType):
|
|
print("%*sassert(%s == %s);" % (indent, "", nameLHS, nameRHS), file=output)
|
|
elif isinstance(t, EnumType):
|
|
print("%*sassert(%s == %s);" % (indent, "", nameLHS, nameRHS), file=output)
|
|
elif isinstance(t, RecordType):
|
|
for i, f in enumerate(t.fields):
|
|
if f.isPaddingBitField():
|
|
continue
|
|
self.checkTypeValues(
|
|
"%s.field%d" % (nameLHS, i),
|
|
"%s.field%d" % (nameRHS, i),
|
|
f,
|
|
output=output,
|
|
indent=indent,
|
|
)
|
|
if t.isUnion:
|
|
break
|
|
elif isinstance(t, ComplexType):
|
|
self.checkTypeValues(
|
|
"(__real %s)" % nameLHS,
|
|
"(__real %s)" % nameRHS,
|
|
t.elementType,
|
|
output=output,
|
|
indent=indent,
|
|
)
|
|
self.checkTypeValues(
|
|
"(__imag %s)" % nameLHS,
|
|
"(__imag %s)" % nameRHS,
|
|
t.elementType,
|
|
output=output,
|
|
indent=indent,
|
|
)
|
|
elif isinstance(t, ArrayType):
|
|
for i in range(t.numElements):
|
|
# Access in this fashion as a hackish way to portably
|
|
# access vectors.
|
|
if t.isVector:
|
|
self.checkTypeValues(
|
|
"((%s*) &%s)[%d]" % (t.elementType, nameLHS, i),
|
|
"((%s*) &%s)[%d]" % (t.elementType, nameRHS, i),
|
|
t.elementType,
|
|
output=output,
|
|
indent=indent,
|
|
)
|
|
else:
|
|
self.checkTypeValues(
|
|
"%s[%d]" % (nameLHS, i),
|
|
"%s[%d]" % (nameRHS, i),
|
|
t.elementType,
|
|
output=output,
|
|
indent=indent,
|
|
)
|
|
else:
|
|
raise NotImplementedError('Cannot print value of type: "%s"' % (t,))
|
|
|
|
|
|
import sys
|
|
|
|
|
|
def main():
|
|
from optparse import OptionParser, OptionGroup
|
|
|
|
parser = OptionParser("%prog [options] {indices}")
|
|
parser.add_option(
|
|
"",
|
|
"--mode",
|
|
dest="mode",
|
|
help="autogeneration mode (random or linear) [default %default]",
|
|
type="choice",
|
|
choices=("random", "linear"),
|
|
default="linear",
|
|
)
|
|
parser.add_option(
|
|
"",
|
|
"--count",
|
|
dest="count",
|
|
help="autogenerate COUNT functions according to MODE",
|
|
type=int,
|
|
default=0,
|
|
)
|
|
parser.add_option(
|
|
"",
|
|
"--min",
|
|
dest="minIndex",
|
|
metavar="N",
|
|
help="start autogeneration with the Nth function type [default %default]",
|
|
type=int,
|
|
default=0,
|
|
)
|
|
parser.add_option(
|
|
"",
|
|
"--max",
|
|
dest="maxIndex",
|
|
metavar="N",
|
|
help="maximum index for random autogeneration [default %default]",
|
|
type=int,
|
|
default=10000000,
|
|
)
|
|
parser.add_option(
|
|
"",
|
|
"--seed",
|
|
dest="seed",
|
|
help="random number generator seed [default %default]",
|
|
type=int,
|
|
default=1,
|
|
)
|
|
parser.add_option(
|
|
"",
|
|
"--use-random-seed",
|
|
dest="useRandomSeed",
|
|
help="use random value for initial random number generator seed",
|
|
action="store_true",
|
|
default=False,
|
|
)
|
|
parser.add_option(
|
|
"",
|
|
"--skip",
|
|
dest="skipTests",
|
|
help="add a test index to skip",
|
|
type=int,
|
|
action="append",
|
|
default=[],
|
|
)
|
|
parser.add_option(
|
|
"-o",
|
|
"--output",
|
|
dest="output",
|
|
metavar="FILE",
|
|
help="write output to FILE [default %default]",
|
|
type=str,
|
|
default="-",
|
|
)
|
|
parser.add_option(
|
|
"-O",
|
|
"--output-header",
|
|
dest="outputHeader",
|
|
metavar="FILE",
|
|
help="write header file for output to FILE [default %default]",
|
|
type=str,
|
|
default=None,
|
|
)
|
|
parser.add_option(
|
|
"-T",
|
|
"--output-tests",
|
|
dest="outputTests",
|
|
metavar="FILE",
|
|
help="write function tests to FILE [default %default]",
|
|
type=str,
|
|
default=None,
|
|
)
|
|
parser.add_option(
|
|
"-D",
|
|
"--output-driver",
|
|
dest="outputDriver",
|
|
metavar="FILE",
|
|
help="write test driver to FILE [default %default]",
|
|
type=str,
|
|
default=None,
|
|
)
|
|
parser.add_option(
|
|
"",
|
|
"--test-layout",
|
|
dest="testLayout",
|
|
metavar="FILE",
|
|
help="test structure layout",
|
|
action="store_true",
|
|
default=False,
|
|
)
|
|
|
|
group = OptionGroup(parser, "Type Enumeration Options")
|
|
# Builtins - Ints
|
|
group.add_option(
|
|
"",
|
|
"--no-char",
|
|
dest="useChar",
|
|
help="do not generate char types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-short",
|
|
dest="useShort",
|
|
help="do not generate short types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-int",
|
|
dest="useInt",
|
|
help="do not generate int types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-long",
|
|
dest="useLong",
|
|
help="do not generate long types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-long-long",
|
|
dest="useLongLong",
|
|
help="do not generate long long types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-unsigned",
|
|
dest="useUnsigned",
|
|
help="do not generate unsigned integer types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
|
|
# Other builtins
|
|
group.add_option(
|
|
"",
|
|
"--no-bool",
|
|
dest="useBool",
|
|
help="do not generate bool types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-float",
|
|
dest="useFloat",
|
|
help="do not generate float types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-double",
|
|
dest="useDouble",
|
|
help="do not generate double types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-long-double",
|
|
dest="useLongDouble",
|
|
help="do not generate long double types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-void-pointer",
|
|
dest="useVoidPointer",
|
|
help="do not generate void* types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
|
|
# Enumerations
|
|
group.add_option(
|
|
"",
|
|
"--no-enums",
|
|
dest="useEnum",
|
|
help="do not generate enum types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
|
|
# Derived types
|
|
group.add_option(
|
|
"",
|
|
"--no-array",
|
|
dest="useArray",
|
|
help="do not generate record types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-complex",
|
|
dest="useComplex",
|
|
help="do not generate complex types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-record",
|
|
dest="useRecord",
|
|
help="do not generate record types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-union",
|
|
dest="recordUseUnion",
|
|
help="do not generate union types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-vector",
|
|
dest="useVector",
|
|
help="do not generate vector types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-bit-field",
|
|
dest="useBitField",
|
|
help="do not generate bit-field record members",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--no-builtins",
|
|
dest="useBuiltins",
|
|
help="do not use any types",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
|
|
# Tuning
|
|
group.add_option(
|
|
"",
|
|
"--no-function-return",
|
|
dest="functionUseReturn",
|
|
help="do not generate return types for functions",
|
|
action="store_false",
|
|
default=True,
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--vector-types",
|
|
dest="vectorTypes",
|
|
help="comma separated list of vector types (e.g., v2i32) [default %default]",
|
|
action="store",
|
|
type=str,
|
|
default="v2i16, v1i64, v2i32, v4i16, v8i8, v2f32, v2i64, v4i32, v8i16, v16i8, v2f64, v4f32, v16f32",
|
|
metavar="N",
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--bit-fields",
|
|
dest="bitFields",
|
|
help="comma separated list 'type:width' bit-field specifiers [default %default]",
|
|
action="store",
|
|
type=str,
|
|
default=("char:0,char:4,int:0,unsigned:1,int:1,int:4,int:13,int:24"),
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--max-args",
|
|
dest="functionMaxArgs",
|
|
help="maximum number of arguments per function [default %default]",
|
|
action="store",
|
|
type=int,
|
|
default=4,
|
|
metavar="N",
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--max-array",
|
|
dest="arrayMaxSize",
|
|
help="maximum array size [default %default]",
|
|
action="store",
|
|
type=int,
|
|
default=4,
|
|
metavar="N",
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--max-record",
|
|
dest="recordMaxSize",
|
|
help="maximum number of fields per record [default %default]",
|
|
action="store",
|
|
type=int,
|
|
default=4,
|
|
metavar="N",
|
|
)
|
|
group.add_option(
|
|
"",
|
|
"--max-record-depth",
|
|
dest="recordMaxDepth",
|
|
help="maximum nested structure depth [default %default]",
|
|
action="store",
|
|
type=int,
|
|
default=None,
|
|
metavar="N",
|
|
)
|
|
parser.add_option_group(group)
|
|
(opts, args) = parser.parse_args()
|
|
|
|
if not opts.useRandomSeed:
|
|
random.seed(opts.seed)
|
|
|
|
# Construct type generator
|
|
builtins = []
|
|
if opts.useBuiltins:
|
|
ints = []
|
|
if opts.useChar:
|
|
ints.append(("char", 1))
|
|
if opts.useShort:
|
|
ints.append(("short", 2))
|
|
if opts.useInt:
|
|
ints.append(("int", 4))
|
|
# FIXME: Wrong size.
|
|
if opts.useLong:
|
|
ints.append(("long", 4))
|
|
if opts.useLongLong:
|
|
ints.append(("long long", 8))
|
|
if opts.useUnsigned:
|
|
ints = [("unsigned %s" % i, s) for i, s in ints] + [
|
|
("signed %s" % i, s) for i, s in ints
|
|
]
|
|
builtins.extend(ints)
|
|
|
|
if opts.useBool:
|
|
builtins.append(("_Bool", 1))
|
|
if opts.useFloat:
|
|
builtins.append(("float", 4))
|
|
if opts.useDouble:
|
|
builtins.append(("double", 8))
|
|
if opts.useLongDouble:
|
|
builtins.append(("long double", 16))
|
|
# FIXME: Wrong size.
|
|
if opts.useVoidPointer:
|
|
builtins.append(("void*", 4))
|
|
|
|
btg = FixedTypeGenerator([BuiltinType(n, s) for n, s in builtins])
|
|
|
|
bitfields = []
|
|
for specifier in opts.bitFields.split(","):
|
|
if not specifier.strip():
|
|
continue
|
|
name, width = specifier.strip().split(":", 1)
|
|
bitfields.append(BuiltinType(name, None, int(width)))
|
|
bftg = FixedTypeGenerator(bitfields)
|
|
|
|
charType = BuiltinType("char", 1)
|
|
shortType = BuiltinType("short", 2)
|
|
intType = BuiltinType("int", 4)
|
|
longlongType = BuiltinType("long long", 8)
|
|
floatType = BuiltinType("float", 4)
|
|
doubleType = BuiltinType("double", 8)
|
|
sbtg = FixedTypeGenerator([charType, intType, floatType, doubleType])
|
|
|
|
atg = AnyTypeGenerator()
|
|
artg = AnyTypeGenerator()
|
|
|
|
def makeGenerator(atg, subgen, subfieldgen, useRecord, useArray, useBitField):
|
|
atg.addGenerator(btg)
|
|
if useBitField and opts.useBitField:
|
|
atg.addGenerator(bftg)
|
|
if useRecord and opts.useRecord:
|
|
assert subgen
|
|
atg.addGenerator(
|
|
RecordTypeGenerator(
|
|
subfieldgen, opts.recordUseUnion, opts.recordMaxSize
|
|
)
|
|
)
|
|
if opts.useComplex:
|
|
# FIXME: Allow overriding builtins here
|
|
atg.addGenerator(ComplexTypeGenerator(sbtg))
|
|
if useArray and opts.useArray:
|
|
assert subgen
|
|
atg.addGenerator(ArrayTypeGenerator(subgen, opts.arrayMaxSize))
|
|
if opts.useVector:
|
|
vTypes = []
|
|
for i, t in enumerate(opts.vectorTypes.split(",")):
|
|
m = re.match("v([1-9][0-9]*)([if][1-9][0-9]*)", t.strip())
|
|
if not m:
|
|
parser.error("Invalid vector type: %r" % t)
|
|
count, kind = m.groups()
|
|
count = int(count)
|
|
type = {
|
|
"i8": charType,
|
|
"i16": shortType,
|
|
"i32": intType,
|
|
"i64": longlongType,
|
|
"f32": floatType,
|
|
"f64": doubleType,
|
|
}.get(kind)
|
|
if not type:
|
|
parser.error("Invalid vector type: %r" % t)
|
|
vTypes.append(ArrayType(i, True, type, count * type.size))
|
|
|
|
atg.addGenerator(FixedTypeGenerator(vTypes))
|
|
if opts.useEnum:
|
|
atg.addGenerator(EnumTypeGenerator([None, "-1", "1", "1u"], 1, 4))
|
|
|
|
if opts.recordMaxDepth is None:
|
|
# Fully recursive, just avoid top-level arrays.
|
|
subFTG = AnyTypeGenerator()
|
|
subTG = AnyTypeGenerator()
|
|
atg = AnyTypeGenerator()
|
|
makeGenerator(subFTG, atg, atg, True, True, True)
|
|
makeGenerator(subTG, atg, subFTG, True, True, False)
|
|
makeGenerator(atg, subTG, subFTG, True, False, False)
|
|
else:
|
|
# Make a chain of type generators, each builds smaller
|
|
# structures.
|
|
base = AnyTypeGenerator()
|
|
fbase = AnyTypeGenerator()
|
|
makeGenerator(base, None, None, False, False, False)
|
|
makeGenerator(fbase, None, None, False, False, True)
|
|
for i in range(opts.recordMaxDepth):
|
|
n = AnyTypeGenerator()
|
|
fn = AnyTypeGenerator()
|
|
makeGenerator(n, base, fbase, True, True, False)
|
|
makeGenerator(fn, base, fbase, True, True, True)
|
|
base = n
|
|
fbase = fn
|
|
atg = AnyTypeGenerator()
|
|
makeGenerator(atg, base, fbase, True, False, False)
|
|
|
|
if opts.testLayout:
|
|
ftg = atg
|
|
else:
|
|
ftg = FunctionTypeGenerator(atg, opts.functionUseReturn, opts.functionMaxArgs)
|
|
|
|
# Override max,min,count if finite
|
|
if opts.maxIndex is None:
|
|
if ftg.cardinality is aleph0:
|
|
opts.maxIndex = 10000000
|
|
else:
|
|
opts.maxIndex = ftg.cardinality
|
|
opts.maxIndex = min(opts.maxIndex, ftg.cardinality)
|
|
opts.minIndex = max(0, min(opts.maxIndex - 1, opts.minIndex))
|
|
if not opts.mode == "random":
|
|
opts.count = min(opts.count, opts.maxIndex - opts.minIndex)
|
|
|
|
if opts.output == "-":
|
|
output = sys.stdout
|
|
else:
|
|
output = open(opts.output, "w")
|
|
atexit.register(lambda: output.close())
|
|
|
|
outputHeader = None
|
|
if opts.outputHeader:
|
|
outputHeader = open(opts.outputHeader, "w")
|
|
atexit.register(lambda: outputHeader.close())
|
|
|
|
outputTests = None
|
|
if opts.outputTests:
|
|
outputTests = open(opts.outputTests, "w")
|
|
atexit.register(lambda: outputTests.close())
|
|
|
|
outputDriver = None
|
|
if opts.outputDriver:
|
|
outputDriver = open(opts.outputDriver, "w")
|
|
atexit.register(lambda: outputDriver.close())
|
|
|
|
info = ""
|
|
info += "// %s\n" % (" ".join(sys.argv),)
|
|
info += "// Generated: %s\n" % (time.strftime("%Y-%m-%d %H:%M"),)
|
|
info += "// Cardinality of function generator: %s\n" % (ftg.cardinality,)
|
|
info += "// Cardinality of type generator: %s\n" % (atg.cardinality,)
|
|
|
|
if opts.testLayout:
|
|
info += "\n#include <stdio.h>"
|
|
|
|
P = TypePrinter(
|
|
output,
|
|
outputHeader=outputHeader,
|
|
outputTests=outputTests,
|
|
outputDriver=outputDriver,
|
|
headerName=opts.outputHeader,
|
|
info=info,
|
|
)
|
|
|
|
def write(N):
|
|
try:
|
|
FT = ftg.get(N)
|
|
except RuntimeError as e:
|
|
if e.args[0] == "maximum recursion depth exceeded":
|
|
print(
|
|
"WARNING: Skipped %d, recursion limit exceeded (bad arguments?)"
|
|
% (N,),
|
|
file=sys.stderr,
|
|
)
|
|
return
|
|
raise
|
|
if opts.testLayout:
|
|
P.writeLayoutTest(N, FT)
|
|
else:
|
|
P.writeFunction(N, FT)
|
|
|
|
if args:
|
|
[write(int(a)) for a in args]
|
|
|
|
skipTests = set(opts.skipTests)
|
|
for i in range(opts.count):
|
|
if opts.mode == "linear":
|
|
index = opts.minIndex + i
|
|
else:
|
|
index = opts.minIndex + int(
|
|
(opts.maxIndex - opts.minIndex) * random.random()
|
|
)
|
|
if index in skipTests:
|
|
continue
|
|
write(index)
|
|
|
|
P.finish()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|