diff --git a/ispc.cpp b/ispc.cpp index 4293b21b..6729da92 100644 --- a/ispc.cpp +++ b/ispc.cpp @@ -515,8 +515,10 @@ Globals::Globals() { emitPerfWarnings = true; emitInstrumentation = false; generateDebuggingSymbols = false; + enableFuzzTest = false; + fuzzTestSeed = -1; mangleFunctionsWithTarget = false; - + ctx = new llvm::LLVMContext; #ifdef ISPC_IS_WINDOWS diff --git a/ispc.h b/ispc.h index 856b988e..5f25ebe4 100644 --- a/ispc.h +++ b/ispc.h @@ -405,6 +405,14 @@ struct Globals { vector width to them. */ bool mangleFunctionsWithTarget; + /** If enabled, the lexer will randomly replace some tokens returned + with other tokens, in order to test error condition handling in the + compiler. */ + bool enableFuzzTest; + + /** Seed for random number generator used for fuzz testing. */ + int fuzzTestSeed; + /** Global LLVMContext object */ llvm::LLVMContext *ctx; diff --git a/lex.ll b/lex.ll index e5e395c3..9ba21f2a 100644 --- a/lex.ll +++ b/lex.ll @@ -58,6 +58,178 @@ static double lParseHexFloat(const char *ptr); inline int isatty(int) { return 0; } #endif // ISPC_IS_WINDOWS +static int allTokens[] = { + TOKEN_ASSERT, TOKEN_BOOL, TOKEN_BREAK, TOKEN_CASE, TOKEN_CBREAK, + TOKEN_CCONTINUE, TOKEN_CDO, TOKEN_CFOR, TOKEN_CIF, TOKEN_CWHILE, + TOKEN_CONST, TOKEN_CONTINUE, TOKEN_CRETURN, TOKEN_DEFAULT, TOKEN_DO, + TOKEN_DELETE, TOKEN_DELETE, TOKEN_DOUBLE, TOKEN_ELSE, TOKEN_ENUM, + TOKEN_EXPORT, TOKEN_EXTERN, TOKEN_FALSE, TOKEN_FLOAT, TOKEN_FOR, + TOKEN_FOREACH, TOKEN_FOREACH_TILED, TOKEN_GOTO, TOKEN_IF, TOKEN_INLINE, + TOKEN_INT, TOKEN_INT8, TOKEN_INT16, TOKEN_INT, TOKEN_INT64, TOKEN_LAUNCH, + TOKEN_NEW, TOKEN_NULL, TOKEN_PRINT, TOKEN_RETURN, TOKEN_SOA, TOKEN_SIGNED, + TOKEN_SIZEOF, TOKEN_STATIC, TOKEN_STRUCT, TOKEN_SWITCH, TOKEN_SYNC, + TOKEN_TASK, TOKEN_TRUE, TOKEN_TYPEDEF, TOKEN_UNIFORM, TOKEN_UNSIGNED, + TOKEN_VARYING, TOKEN_VOID, TOKEN_WHILE, TOKEN_STRING_C_LITERAL, + TOKEN_DOTDOTDOT, + TOKEN_FLOAT_CONSTANT, + TOKEN_INT32_CONSTANT, TOKEN_UINT32_CONSTANT, + TOKEN_INT64_CONSTANT, TOKEN_UINT64_CONSTANT, + TOKEN_INC_OP, TOKEN_DEC_OP, TOKEN_LEFT_OP, TOKEN_RIGHT_OP, TOKEN_LE_OP, + TOKEN_GE_OP, TOKEN_EQ_OP, TOKEN_NE_OP, TOKEN_AND_OP, TOKEN_OR_OP, + TOKEN_MUL_ASSIGN, TOKEN_DIV_ASSIGN, TOKEN_MOD_ASSIGN, TOKEN_ADD_ASSIGN, + TOKEN_SUB_ASSIGN, TOKEN_LEFT_ASSIGN, TOKEN_RIGHT_ASSIGN, TOKEN_AND_ASSIGN, + TOKEN_XOR_ASSIGN, TOKEN_OR_ASSIGN, TOKEN_PTR_OP, + ';', '{', '}', ',', ':', '=', '(', ')', '[', ']', '.', '&', '!', '~', '-', + '+', '*', '/', '%', '<', '>', '^', '|', '?', +}; + +static std::map tokenToName; + +static void lInitTokenToName() { + tokenToName[TOKEN_ASSERT] = "assert"; + tokenToName[TOKEN_BOOL] = "bool"; + tokenToName[TOKEN_BREAK] = "break"; + tokenToName[TOKEN_CASE] = "case"; + tokenToName[TOKEN_CBREAK] = "cbreak"; + tokenToName[TOKEN_CCONTINUE] = "ccontinue"; + tokenToName[TOKEN_CDO] = "cdo"; + tokenToName[TOKEN_CFOR] = "cfor"; + tokenToName[TOKEN_CIF] = "cif"; + tokenToName[TOKEN_CWHILE] = "cwhile"; + tokenToName[TOKEN_CONST] = "const"; + tokenToName[TOKEN_CONTINUE] = "continue"; + tokenToName[TOKEN_CRETURN] = "creturn"; + tokenToName[TOKEN_DEFAULT] = "default"; + tokenToName[TOKEN_DO] = "do"; + tokenToName[TOKEN_DELETE] = "delete"; + tokenToName[TOKEN_DELETE] = "delete"; + tokenToName[TOKEN_DOUBLE] = "double"; + tokenToName[TOKEN_ELSE] = "else"; + tokenToName[TOKEN_ENUM] = "enum"; + tokenToName[TOKEN_EXPORT] = "export"; + tokenToName[TOKEN_EXTERN] = "extern"; + tokenToName[TOKEN_FALSE] = "false"; + tokenToName[TOKEN_FLOAT] = "float"; + tokenToName[TOKEN_FOR] = "for"; + tokenToName[TOKEN_FOREACH] = "foreach"; + tokenToName[TOKEN_FOREACH_TILED] = "foreach_tiled"; + tokenToName[TOKEN_GOTO] = "goto"; + tokenToName[TOKEN_IF] = "if"; + tokenToName[TOKEN_INLINE] = "inline"; + tokenToName[TOKEN_INT] = "int"; + tokenToName[TOKEN_INT8] = "int8"; + tokenToName[TOKEN_INT16] = "int16"; + tokenToName[TOKEN_INT] = "int"; + tokenToName[TOKEN_INT64] = "int64"; + tokenToName[TOKEN_LAUNCH] = "launch"; + tokenToName[TOKEN_NEW] = "new"; + tokenToName[TOKEN_NULL] = "NULL"; + tokenToName[TOKEN_PRINT] = "print"; + tokenToName[TOKEN_RETURN] = "return"; + tokenToName[TOKEN_SOA] = "soa"; + tokenToName[TOKEN_SIGNED] = "signed"; + tokenToName[TOKEN_SIZEOF] = "sizeof"; + tokenToName[TOKEN_STATIC] = "static"; + tokenToName[TOKEN_STRUCT] = "struct"; + tokenToName[TOKEN_SWITCH] = "switch"; + tokenToName[TOKEN_SYNC] = "sync"; + tokenToName[TOKEN_TASK] = "task"; + tokenToName[TOKEN_TRUE] = "true"; + tokenToName[TOKEN_TYPEDEF] = "typedef"; + tokenToName[TOKEN_UNIFORM] = "uniform"; + tokenToName[TOKEN_UNSIGNED] = "unsigned"; + tokenToName[TOKEN_VARYING] = "varying"; + tokenToName[TOKEN_VOID] = "void"; + tokenToName[TOKEN_WHILE] = "while"; + tokenToName[TOKEN_STRING_C_LITERAL] = "\"C\""; + tokenToName[TOKEN_DOTDOTDOT] = "..."; + tokenToName[TOKEN_FLOAT_CONSTANT] = "TOKEN_FLOAT_CONSTANT"; + tokenToName[TOKEN_INT32_CONSTANT] = "TOKEN_INT32_CONSTANT"; + tokenToName[TOKEN_UINT32_CONSTANT] = "TOKEN_UINT32_CONSTANT"; + tokenToName[TOKEN_INT64_CONSTANT] = "TOKEN_INT64_CONSTANT"; + tokenToName[TOKEN_UINT64_CONSTANT] = "TOKEN_UINT64_CONSTANT"; + tokenToName[TOKEN_INC_OP] = "++"; + tokenToName[TOKEN_DEC_OP] = "--"; + tokenToName[TOKEN_LEFT_OP] = "<<"; + tokenToName[TOKEN_RIGHT_OP] = ">>"; + tokenToName[TOKEN_LE_OP] = "<="; + tokenToName[TOKEN_GE_OP] = ">="; + tokenToName[TOKEN_EQ_OP] = "=="; + tokenToName[TOKEN_NE_OP] = "!="; + tokenToName[TOKEN_AND_OP] = "&&"; + tokenToName[TOKEN_OR_OP] = "||"; + tokenToName[TOKEN_MUL_ASSIGN] = "*="; + tokenToName[TOKEN_DIV_ASSIGN] = "/="; + tokenToName[TOKEN_MOD_ASSIGN] = "%="; + tokenToName[TOKEN_ADD_ASSIGN] = "+="; + tokenToName[TOKEN_SUB_ASSIGN] = "-="; + tokenToName[TOKEN_LEFT_ASSIGN] = "<<="; + tokenToName[TOKEN_RIGHT_ASSIGN] = ">>="; + tokenToName[TOKEN_AND_ASSIGN] = "&="; + tokenToName[TOKEN_XOR_ASSIGN] = "^="; + tokenToName[TOKEN_OR_ASSIGN] = "|="; + tokenToName[TOKEN_PTR_OP] = "->"; + tokenToName[';'] = ";"; + tokenToName['{'] = "{"; + tokenToName['}'] = "}"; + tokenToName[','] = ","; + tokenToName[':'] = ":"; + tokenToName['='] = "="; + tokenToName['('] = "("; + tokenToName[')'] = ")"; + tokenToName['['] = "["; + tokenToName[']'] = "]"; + tokenToName['.'] = "."; + tokenToName['&'] = "&"; + tokenToName['!'] = "!"; + tokenToName['~'] = "~"; + tokenToName['-'] = "-"; + tokenToName['+'] = "+"; + tokenToName['*'] = "*"; + tokenToName['/'] = "/"; + tokenToName['%'] = "%"; + tokenToName['<'] = "<"; + tokenToName['>'] = ">"; + tokenToName['^'] = "^"; + tokenToName['|'] = "|"; + tokenToName['?'] = "?"; + tokenToName[';'] = ";"; +} + + +inline int ispcRand() { +#ifdef ISPC_IS_WINDOWS + return rand(); +#else + return lrand48(); +#endif +} + +#define RT \ + if (g->enableFuzzTest) { \ + int r = ispcRand() % 40; \ + if (r == 0) { \ + Warning(*yylloc, "Dropping token"); \ + } \ + else if (r == 1) { \ + if (tokenToName.size() == 0) lInitTokenToName(); \ + int nt = sizeof(allTokens) / sizeof(allTokens[0]); \ + int tn = ispcRand() % nt; \ + yylval->stringVal = new std::string(yytext); /* just in case */\ + Warning(*yylloc, "Replaced with \"%s\"", tokenToName[allTokens[tn]].c_str()); \ + return allTokens[tn]; \ + } \ + else if (r == 2) { \ + Symbol *sym = m->symbolTable->RandomSymbol(); \ + if (sym != NULL) { \ + yylval->stringVal = new std::string(sym->name); \ + Warning(*yylloc, "Replaced with identifier \"%s\".", sym->name.c_str()); \ + return TOKEN_IDENTIFIER; \ + } \ + } \ + /* TOKEN_TYPE_NAME */ \ + } else /* swallow semicolon */ + %} %option nounput @@ -78,70 +250,71 @@ ZO_SWIZZLE ([01]+[w-z]+)+|([01]+[rgba]+)+|([01]+[uv]+)+ "/*" { lCComment(yylloc); } "//" { lCppComment(yylloc); } -__assert { return TOKEN_ASSERT; } -bool { return TOKEN_BOOL; } -break { return TOKEN_BREAK; } -case { return TOKEN_CASE; } -cbreak { return TOKEN_CBREAK; } -ccontinue { return TOKEN_CCONTINUE; } -cdo { return TOKEN_CDO; } -cfor { return TOKEN_CFOR; } -cif { return TOKEN_CIF; } -cwhile { return TOKEN_CWHILE; } -const { return TOKEN_CONST; } -continue { return TOKEN_CONTINUE; } -creturn { return TOKEN_CRETURN; } -default { return TOKEN_DEFAULT; } -do { return TOKEN_DO; } -delete { return TOKEN_DELETE; } -delete\[\] { return TOKEN_DELETE; } -double { return TOKEN_DOUBLE; } -else { return TOKEN_ELSE; } -enum { return TOKEN_ENUM; } -export { return TOKEN_EXPORT; } -extern { return TOKEN_EXTERN; } -false { return TOKEN_FALSE; } -float { return TOKEN_FLOAT; } -for { return TOKEN_FOR; } -foreach { return TOKEN_FOREACH; } -foreach_tiled { return TOKEN_FOREACH_TILED; } -goto { return TOKEN_GOTO; } -if { return TOKEN_IF; } -inline { return TOKEN_INLINE; } -int { return TOKEN_INT; } -int8 { return TOKEN_INT8; } -int16 { return TOKEN_INT16; } -int32 { return TOKEN_INT; } -int64 { return TOKEN_INT64; } -launch { return TOKEN_LAUNCH; } -new { return TOKEN_NEW; } -NULL { return TOKEN_NULL; } -print { return TOKEN_PRINT; } +__assert { RT; return TOKEN_ASSERT; } +bool { RT; return TOKEN_BOOL; } +break { RT; return TOKEN_BREAK; } +case { RT; return TOKEN_CASE; } +cbreak { RT; return TOKEN_CBREAK; } +ccontinue { RT; return TOKEN_CCONTINUE; } +cdo { RT; return TOKEN_CDO; } +cfor { RT; return TOKEN_CFOR; } +cif { RT; return TOKEN_CIF; } +cwhile { RT; return TOKEN_CWHILE; } +const { RT; return TOKEN_CONST; } +continue { RT; return TOKEN_CONTINUE; } +creturn { RT; return TOKEN_CRETURN; } +default { RT; return TOKEN_DEFAULT; } +do { RT; return TOKEN_DO; } +delete { RT; return TOKEN_DELETE; } +delete\[\] { RT; return TOKEN_DELETE; } +double { RT; return TOKEN_DOUBLE; } +else { RT; return TOKEN_ELSE; } +enum { RT; return TOKEN_ENUM; } +export { RT; return TOKEN_EXPORT; } +extern { RT; return TOKEN_EXTERN; } +false { RT; return TOKEN_FALSE; } +float { RT; return TOKEN_FLOAT; } +for { RT; return TOKEN_FOR; } +foreach { RT; return TOKEN_FOREACH; } +foreach_tiled { RT; return TOKEN_FOREACH_TILED; } +goto { RT; return TOKEN_GOTO; } +if { RT; return TOKEN_IF; } +inline { RT; return TOKEN_INLINE; } +int { RT; return TOKEN_INT; } +int8 { RT; return TOKEN_INT8; } +int16 { RT; return TOKEN_INT16; } +int32 { RT; return TOKEN_INT; } +int64 { RT; return TOKEN_INT64; } +launch { RT; return TOKEN_LAUNCH; } +new { RT; return TOKEN_NEW; } +NULL { RT; return TOKEN_NULL; } +print { RT; return TOKEN_PRINT; } reference { Error(*yylloc, "\"reference\" qualifier is no longer supported; " "please use C++-style '&' syntax for references " "instead."); } -return { return TOKEN_RETURN; } -soa { return TOKEN_SOA; } -signed { return TOKEN_SIGNED; } -sizeof { return TOKEN_SIZEOF; } -static { return TOKEN_STATIC; } -struct { return TOKEN_STRUCT; } -switch { return TOKEN_SWITCH; } -sync { return TOKEN_SYNC; } -task { return TOKEN_TASK; } -true { return TOKEN_TRUE; } -typedef { return TOKEN_TYPEDEF; } -uniform { return TOKEN_UNIFORM; } -unsigned { return TOKEN_UNSIGNED; } -varying { return TOKEN_VARYING; } -void { return TOKEN_VOID; } -while { return TOKEN_WHILE; } -\"C\" { return TOKEN_STRING_C_LITERAL; } -\.\.\. { return TOKEN_DOTDOTDOT; } +return { RT; return TOKEN_RETURN; } +soa { RT; return TOKEN_SOA; } +signed { RT; return TOKEN_SIGNED; } +sizeof { RT; return TOKEN_SIZEOF; } +static { RT; return TOKEN_STATIC; } +struct { RT; return TOKEN_STRUCT; } +switch { RT; return TOKEN_SWITCH; } +sync { RT; return TOKEN_SYNC; } +task { RT; return TOKEN_TASK; } +true { RT; return TOKEN_TRUE; } +typedef { RT; return TOKEN_TYPEDEF; } +uniform { RT; return TOKEN_UNIFORM; } +unsigned { RT; return TOKEN_UNSIGNED; } +varying { RT; return TOKEN_VARYING; } +void { RT; return TOKEN_VOID; } +while { RT; return TOKEN_WHILE; } +\"C\" { RT; return TOKEN_STRING_C_LITERAL; } +\.\.\. { RT; return TOKEN_DOTDOTDOT; } L?\"(\\.|[^\\"])*\" { lStringConst(yylval, yylloc); return TOKEN_STRING_LITERAL; } {IDENT} { + RT; /* We have an identifier--is it a type name or an identifier? The symbol table will straighten us out... */ yylval->stringVal = new std::string(yytext); @@ -152,6 +325,7 @@ L?\"(\\.|[^\\"])*\" { lStringConst(yylval, yylloc); return TOKEN_STRING_LITERAL; } {INT_NUMBER}+(u|U|l|L)*? { + RT; int ls = 0, us = 0; char *endPtr = NULL; @@ -201,60 +375,62 @@ L?\"(\\.|[^\\"])*\" { lStringConst(yylval, yylloc); return TOKEN_STRING_LITERAL; {FLOAT_NUMBER} { - yylval->floatVal = (float)atof(yytext); + RT; + yylval->floatVal = (float)atof(yytext); return TOKEN_FLOAT_CONSTANT; } {HEX_FLOAT_NUMBER} { + RT; yylval->floatVal = (float)lParseHexFloat(yytext); return TOKEN_FLOAT_CONSTANT; } -"++" { return TOKEN_INC_OP; } -"--" { return TOKEN_DEC_OP; } -"<<" { return TOKEN_LEFT_OP; } -">>" { return TOKEN_RIGHT_OP; } -"<=" { return TOKEN_LE_OP; } -">=" { return TOKEN_GE_OP; } -"==" { return TOKEN_EQ_OP; } -"!=" { return TOKEN_NE_OP; } -"&&" { return TOKEN_AND_OP; } -"||" { return TOKEN_OR_OP; } -"*=" { return TOKEN_MUL_ASSIGN; } -"/=" { return TOKEN_DIV_ASSIGN; } -"%=" { return TOKEN_MOD_ASSIGN; } -"+=" { return TOKEN_ADD_ASSIGN; } -"-=" { return TOKEN_SUB_ASSIGN; } -"<<=" { return TOKEN_LEFT_ASSIGN; } -">>=" { return TOKEN_RIGHT_ASSIGN; } -"&=" { return TOKEN_AND_ASSIGN; } -"^=" { return TOKEN_XOR_ASSIGN; } -"|=" { return TOKEN_OR_ASSIGN; } -"->" { return TOKEN_PTR_OP; } -";" { return ';'; } -("{"|"<%") { return '{'; } -("}"|"%>") { return '}'; } -"," { return ','; } -":" { return ':'; } -"=" { return '='; } -"(" { return '('; } -")" { return ')'; } -("["|"<:") { return '['; } -("]"|":>") { return ']'; } -"." { return '.'; } -"&" { return '&'; } -"!" { return '!'; } -"~" { return '~'; } -"-" { return '-'; } -"+" { return '+'; } -"*" { return '*'; } -"/" { return '/'; } -"%" { return '%'; } -"<" { return '<'; } -">" { return '>'; } -"^" { return '^'; } -"|" { return '|'; } -"?" { return '?'; } +"++" { RT; return TOKEN_INC_OP; } +"--" { RT; return TOKEN_DEC_OP; } +"<<" { RT; return TOKEN_LEFT_OP; } +">>" { RT; return TOKEN_RIGHT_OP; } +"<=" { RT; return TOKEN_LE_OP; } +">=" { RT; return TOKEN_GE_OP; } +"==" { RT; return TOKEN_EQ_OP; } +"!=" { RT; return TOKEN_NE_OP; } +"&&" { RT; return TOKEN_AND_OP; } +"||" { RT; return TOKEN_OR_OP; } +"*=" { RT; return TOKEN_MUL_ASSIGN; } +"/=" { RT; return TOKEN_DIV_ASSIGN; } +"%=" { RT; return TOKEN_MOD_ASSIGN; } +"+=" { RT; return TOKEN_ADD_ASSIGN; } +"-=" { RT; return TOKEN_SUB_ASSIGN; } +"<<=" { RT; return TOKEN_LEFT_ASSIGN; } +">>=" { RT; return TOKEN_RIGHT_ASSIGN; } +"&=" { RT; return TOKEN_AND_ASSIGN; } +"^=" { RT; return TOKEN_XOR_ASSIGN; } +"|=" { RT; return TOKEN_OR_ASSIGN; } +"->" { RT; return TOKEN_PTR_OP; } +";" { RT; return ';'; } +("{"|"<%") { RT; return '{'; } +("}"|"%>") { RT; return '}'; } +"," { RT; return ','; } +":" { RT; return ':'; } +"=" { RT; return '='; } +"(" { RT; return '('; } +")" { RT; return ')'; } +("["|"<:") { RT; return '['; } +("]"|":>") { RT; return ']'; } +"." { RT; return '.'; } +"&" { RT; return '&'; } +"!" { RT; return '!'; } +"~" { RT; return '~'; } +"-" { RT; return '-'; } +"+" { RT; return '+'; } +"*" { RT; return '*'; } +"/" { RT; return '/'; } +"%" { RT; return '%'; } +"<" { RT; return '<'; } +">" { RT; return '>'; } +"^" { RT; return '^'; } +"|" { RT; return '|'; } +"?" { RT; return '?'; } {WHITESPACE} { } diff --git a/main.cpp b/main.cpp index 4c05d044..45f76658 100644 --- a/main.cpp +++ b/main.cpp @@ -41,6 +41,9 @@ #include "type.h" #include #include +#ifdef ISPC_IS_WINDOWS + #include +#endif // ISPC_IS_WINDOWS #include #include #if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn) @@ -97,6 +100,10 @@ usage(int ret) { #endif // !LLVM_2_9 printf(" [--emit-llvm]\t\t\tEmit LLVM bitode file as output\n"); printf(" [--emit-obj]\t\t\tGenerate object file file as output (default)\n"); +#if 0 + printf(" [--fuzz-test]\t\t\tRandomly perturb program input to test error conditions\n"); + printf(" [--fuzz-seed=]\t\tSeed value for RNG for fuzz testing\n"); +#endif printf(" [-g]\t\t\t\tGenerate debugging information\n"); printf(" [--help]\t\t\t\tPrint help\n"); printf(" [-h /--header-outfile=]\tOutput filename for header\n"); @@ -144,7 +151,7 @@ usage(int ret) { /** We take arguments from both the command line as well as from the ISPC_ARGS environment variable. This function returns a new set of arguments representing the ones from those two sources merged together. - */ +*/ static void lGetAllArgs(int Argc, char *Argv[], int &argc, char *argv[128]) { // Copy over the command line arguments (passed in) for (int i = 0; i < Argc; ++i) @@ -272,6 +279,10 @@ int main(int Argc, char *Argv[]) { ot = Module::Bitcode; else if (!strcmp(argv[i], "--emit-obj")) ot = Module::Object; + else if (!strcmp(argv[i], "--fuzz-test")) + g->enableFuzzTest = true; + else if (!strncmp(argv[i], "--fuzz-seed=", 12)) + g->fuzzTestSeed = atoi(argv[i] + 12); else if (!strcmp(argv[i], "--target")) { // FIXME: should remove this way of specifying the target... if (++i == argc) { @@ -411,6 +422,24 @@ int main(int Argc, char *Argv[]) { if (debugSet && !optSet) g->opt.level = 0; + if (g->enableFuzzTest) { + if (g->fuzzTestSeed == -1) { +#ifdef ISPC_IS_WINDOWS + int seed = (unsigned)time(NULL); +#else + int seed = getpid(); +#endif + g->fuzzTestSeed = seed; + Warning(SourcePos(), "Using seed %d for fuzz testing", + g->fuzzTestSeed); + } +#ifdef ISPC_IS_WINDOWS + srand(g->fuzzTestSeed); +#else + srand48(g->fuzzTestSeed); +#endif + } + if (outFileName == NULL && headerFileName == NULL) Warning(SourcePos(), "No output file or header file name specified. " "Program will be compiled and warnings/errors will " diff --git a/sym.cpp b/sym.cpp index 0647a5b4..f60dc1aa 100644 --- a/sym.cpp +++ b/sym.cpp @@ -354,3 +354,42 @@ SymbolTable::Print() { depth += 4; } } + + +inline int ispcRand() { +#ifdef ISPC_IS_WINDOWS + return rand(); +#else + return lrand48(); +#endif +} + + +Symbol * +SymbolTable::RandomSymbol() { + int v = ispcRand() % variables.size(); + if (variables[v]->size() == 0) + return NULL; + int count = ispcRand() % variables[v]->size(); + SymbolMapType::iterator iter = variables[v]->begin(); + while (count-- > 0) { + ++iter; + Assert(iter != variables[v]->end()); + } + return iter->second; +} + + +const Type * +SymbolTable::RandomType() { + int v = ispcRand() % types.size(); + if (types[v]->size() == 0) + return NULL; + int count = ispcRand() % types[v]->size(); + TypeMapType::iterator iter = types[v]->begin(); + while (count-- > 0) { + ++iter; + Assert(iter != types[v]->end()); + } + return iter->second; +} diff --git a/sym.h b/sym.h index aff0553c..fa452326 100644 --- a/sym.h +++ b/sym.h @@ -244,6 +244,13 @@ public: (Debugging method). */ void Print(); + /** Returns a random symbol from the symbol table. (It is not + guaranteed that it is equally likely to return all symbols). */ + Symbol *RandomSymbol(); + + /** Returns a random type from the symbol table. */ + const Type *RandomType(); + private: std::vector closestTypeMatch(const char *str, bool structsVsEnums) const;