gen_runtime.cpp revision 46ebc97e1ba04766f23296574ebde52102fbd4be
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* This program processes Renderscript function definitions described in spec files. 18 * For each spec file provided on the command line, it generates a corresponding 19 * Renderscript header (*.rsh) which is meant for inclusion in client scripts. 20 * 21 * This program also generates Junit test files to automatically test each of the 22 * functions using randomly generated data. We create two files for each function: 23 * - a Renderscript file named Test{Function}.rs, 24 * - a Junit file named Test{function}.java, which calls the above RS file. 25 * 26 * This program takes an optional -v parameter, the RS version to target the 27 * test files for. The header file will always contain all the functions. 28 * 29 * This program contains five main classes: 30 * - SpecFile: Represents on spec file. 31 * - Function: Each instance represents a function, like clamp. Even though the 32 * spec file contains many entries for clamp, we'll only have one clamp instance. 33 * - Specification: Defines one of the many variations of the function. There's 34 * a one to one correspondance between Specification objects and entries in the 35 * spec file. Strings that are parts of a Specification can include placeholders, 36 * which are "#1", "#2", "#3", and "#4". We'll replace these by values before 37 * generating the files. 38 * - Permutation: A concrete version of a specification, where all placeholders have 39 * been replaced by actual values. 40 * - ParameterDefinition: A definition of a parameter of a concrete function. 41 */ 42 43#include <math.h> 44#include <stdio.h> 45#include <cctype> 46#include <cstdlib> 47#include <fstream> 48#include <functional> 49#include <iomanip> 50#include <list> 51#include <map> 52#include <set> 53#include <sstream> 54#include <string> 55#include <vector> 56 57using namespace std; 58 59namespace { 60 61const char* AUTO_GENERATED_WARNING = 62 "// Don't edit this file! It is auto-generated by " 63 "frameworks/rs/api/gen_runtime.\n\n"; 64const char* LEGAL_NOTICE = 65 "/*\n" 66 " * Copyright (C) 2014 The Android Open Source Project\n" 67 " *\n" 68 " * Licensed under the Apache License, Version 2.0 (the \"License\");\n" 69 " * you may not use this file except in compliance with the License.\n" 70 " * You may obtain a copy of the License at\n" 71 " *\n" 72 " * http://www.apache.org/licenses/LICENSE-2.0\n" 73 " *\n" 74 " * Unless required by applicable law or agreed to in writing, software\n" 75 " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" 76 " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" 77 " * See the License for the specific language governing permissions and\n" 78 " * limitations under the License.\n" 79 " */\n\n"; 80 81class Function; 82class Specification; 83class Permutation; 84struct Type; 85 86/* Information about a parameter to a function. The values of all the fields should only be set by 87 * parseParameterDefinition. 88 */ 89struct ParameterDefinition { 90 string rsType; // The Renderscript type, e.g. "uint3" 91 string rsBaseType; // As above but without the number, e.g. "uint" 92 string javaBaseType; // The type we need to declare in Java, e.g. "unsigned int" 93 string specType; // The type found in the spec, e.g. "f16" 94 bool isFloatType; // True if it's a floating point value 95 96 /* The number of entries in the vector. It should be either "1", "2", "3", or "4". It's also 97 * "1" for scalars. 98 */ 99 string mVectorSize; 100 /* The space the vector takes in an array. It's the same as the vector size, except for size 101 * "3", where the width is "4". 102 */ 103 string vectorWidth; 104 105 string specName; // e.g. x, as found in the spec file 106 string variableName; // e.g. inX, used both in .rs and .java 107 string rsAllocName; // e.g. gAllocInX 108 string javaAllocName; // e.g. inX 109 string javaArrayName; // e.g. arrayInX 110 111 // If non empty, the mininum and maximum values to be used when generating the test data. 112 string minValue; 113 string maxValue; 114 /* If non empty, contains the name of another parameter that should be smaller or equal to this 115 * parameter, i.e. value(smallerParameter) <= value(this). This is used when testing clamp. 116 */ 117 string smallerParameter; 118 119 bool isOutParameter; // True if this parameter returns data from the script. 120 bool undefinedIfOutIsNan; // If true, we don't validate if 'out' is NaN. 121 122 int typeIndex; // Index in the TYPES array. 123 int compatibleTypeIndex; // Index in TYPES for which the test data must also fit. 124 125 /* Parse the parameter definition found in the spec file. It will generate a name if none 126 * are present in the file. One of the two counts will be incremented, and potentially 127 * used to generate unique names. isReturn is true if we're processing the "return:" 128 * definition. 129 */ 130 void parseParameterDefinition(string s, bool isReturn, int* inputCount, int* outputCount); 131}; 132 133// An entire spec file and the methods to process it. 134class SpecFile { 135public: 136 explicit SpecFile(const string& specFileName) : mSpecFileName(specFileName) {} 137 bool process(int versionOfTestFiles); 138 139private: 140 const string mSpecFileName; 141 // The largest version number that we have found in all the specifications. 142 int mLargestVersionNumber; 143 144 map<string, Function*> mFunctionsMap; // All the known functions. 145 typedef map<string, Function*>::iterator FunctionsIterator; 146 147 bool readSpecFile(); 148 Function* getFunction(const string& name); 149 bool generateFiles(int versionOfTestFiles); 150 bool writeAllFunctions(ofstream& headerFile, int versionOfTestFiles); 151}; 152 153/* Represents a function, like "clamp". Even though the spec file contains many entries for clamp, 154 * we'll only have one clamp instance. 155 */ 156class Function { 157private: 158 string mName; // The lower case name, e.g. native_log 159 string mCapitalizedName; // The capitalized name, e.g. NativeLog 160 string mTestName; // e.g. TestNativeLog 161 string mRelaxedTestName; // e.g. TestNativeLogRelaxed 162 163 vector<Specification*> mSpecifications; 164 typedef vector<Specification*>::iterator SpecificationIterator; 165 166 /* We keep track of the allocations generated in the .rs file and the argument classes defined 167 * in the Java file, as we share these between the functions created for each specification. 168 */ 169 set<string> mRsAllocationsGenerated; 170 set<string> mJavaGeneratedArgumentClasses; 171 172 string mJavaCallAllCheckMethods; // Lines of Java code to invoke the check methods. 173 174 ofstream mRsFile; // The Renderscript test file we're generating. 175 ofstream mJavaFile; // The Jave test file we're generating. 176 177 bool startRsFile(); // Open the mRsFile and writes its header. 178 bool writeRelaxedRsFile(); // Write the entire relaxed rs test file (an include essentially) 179 bool startJavaFile(); // Open the mJavaFile and writes the header. 180 void finishJavaFile(); // Write the test method and closes the file. 181 182public: 183 explicit Function(const string& name); 184 void addSpecification(Specification* spec) { mSpecifications.push_back(spec); } 185 /* Write the .java and the two .rs test files. versionOfTestFiles is used to restrict which API 186 * to test. Also writes the section of the header file. 187 */ 188 bool writeFiles(ofstream& headerFile, int versionOfTestFiles); 189 // Write an allocation and keep track of having it written, so it can be shared. 190 void writeRsAllocationDefinition(const ParameterDefinition& param); 191 // Write an argument class definiton and keep track of having it written, so it can be shared. 192 void writeJavaArgumentClassDefinition(const string& className, const string& definition); 193 // Add a call to mJavaCallAllCheckMethods to be used at the end of the file generation. 194 void addJavaCheckCall(const string& call); 195}; 196 197/* Defines one of the many variations of the function. There's a one to one correspondance between 198 * Specification objects and entries in the spec file. Some of the strings that are parts of a 199 * Specification can include placeholders, which are "#1", "#2", "#3", and "#4". We'll replace 200 * these by values before generating the files. 201 */ 202class Specification { 203private: 204 /* The range of versions this specification applies to. 0 if there's no restriction, so an API 205 * that became available at 9 and is still valid would have min:9 max:0. 206 */ 207 int mMinVersion; 208 int mMaxVersion; 209 210 /* The name of the function without #n, e.g. convert. As of this writing, it only differs for 211 * convert. 212 */ 213 string mCleanName; 214 string mTest; // How to test. One of "scalar", "vector", "noverify", "limited", and "none". 215 string mPrecisionLimit; // Maximum precision required when checking output of this function. 216 217 vector<vector<string> > mReplaceables; 218 219 // The following fields may contain placeholders that will be replaced using the mReplaceables. 220 221 // The name of this function, can include #, e.g. convert_#1_#2 222 string mName; 223 224 string mReturn; // The return type 225 vector<string> mComment; // The comments to be included in the header 226 vector<string> mInline; // The inline code to be included in the header 227 vector<string> mParam; // One entry per parameter defined 228 229 // Substitute the placeholders in the strings by the corresponding entries in mReplaceables. 230 string expandString(string s, int i1, int i2, int i3, int i4) const; 231 void expandStringVector(const vector<string>& in, int i1, int i2, int i3, int i4, 232 vector<string>* out) const; 233 234public: 235 Specification() { 236 mMinVersion = 0; 237 mMaxVersion = 0; 238 } 239 int getMinVersion() const { return mMinVersion; } 240 int getMaxVersion() const { return mMaxVersion; } 241 242 string getName(int i1, int i2, int i3, int i4) const { 243 return expandString(mName, i1, i2, i3, i4); 244 } 245 string getReturn(int i1, int i2, int i3, int i4) const { 246 return expandString(mReturn, i1, i2, i3, i4); 247 } 248 void getComments(int i1, int i2, int i3, int i4, vector<string>* comments) const { 249 return expandStringVector(mComment, i1, i2, i3, i4, comments); 250 } 251 void getInlines(int i1, int i2, int i3, int i4, vector<string>* inlines) const { 252 return expandStringVector(mInline, i1, i2, i3, i4, inlines); 253 } 254 void getParams(int i1, int i2, int i3, int i4, vector<string>* params) const { 255 return expandStringVector(mParam, i1, i2, i3, i4, params); 256 } 257 string getTest() const { return mTest; } 258 string getPrecisionLimit() const { return mPrecisionLimit; } 259 string getCleanName() const { return mCleanName; } 260 261 void writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile, Function* function, 262 int versionOfTestFiles); 263 bool writeRelaxedRsFile() const; 264 // Return true if this specification should be generated for this version. 265 bool relevantForVersion(int versionOfTestFiles) const; 266 267 static Specification* scanSpecification(FILE* in); 268}; 269 270// A concrete version of a specification, where all placeholders have been replaced by actual 271// values. 272class Permutation { 273private: 274 Function* mFunction; 275 Specification* mSpecification; 276 277 // These are the expanded version of those found on Specification 278 string mName; 279 string mCleanName; 280 string mTest; // How to test. One of "scalar", "vector", "noverify", "limited", and "none". 281 string mPrecisionLimit; // Maximum precision required when checking output of this function. 282 vector<string> mInline; 283 vector<string> mComment; 284 285 // The inputs and outputs of the function. This include the return type, if present. 286 vector<ParameterDefinition*> mParams; 287 // The index of the return value in mParams, -1 if the function is void. 288 int mReturnIndex; 289 // The index of the first input value in mParams, -1 if there's no input. 290 int mFirstInputIndex; 291 // The number of input and output parameters. 292 int mInputCount; 293 int mOutputCount; 294 295 string mRsKernelName; 296 string mJavaArgumentsClassName; 297 string mJavaArgumentsNClassName; 298 string mJavaVerifierComputeMethodName; 299 string mJavaCheckMethodName; 300 string mJavaVerifyMethodName; 301 302 void writeHeaderSection(ofstream& file) const; 303 304 void writeRsSection(ofstream& rs) const; 305 306 void writeJavaSection(ofstream& file) const; 307 void writeJavaArgumentClass(ofstream& file, bool scalar) const; 308 void writeJavaCheckMethod(ofstream& file, bool generateCallToVerify) const; 309 void writeJavaVerifyScalarMethod(ofstream& file) const; 310 void writeJavaVerifyVectorMethod(ofstream& file) const; 311 void writeJavaVerifyFunctionHeader(ofstream& file) const; 312 void writeJavaInputAllocationDefinition(ofstream& file, const string& indent, 313 const ParameterDefinition& param) const; 314 void writeJavaOutputAllocationDefinition(ofstream& file, const string& indent, 315 const ParameterDefinition& param) const; 316 // Write code to create a random allocation for which the data must be compatible for two types. 317 void writeJavaRandomCompatibleFloatAllocation(ofstream& file, const string& dataType, 318 const string& seed, char vectorSize, 319 const Type& compatibleType, 320 const Type& generatedType) const; 321 void writeJavaRandomCompatibleIntegerAllocation(ofstream& file, const string& dataType, 322 const string& seed, char vectorSize, 323 const Type& compatibleType, 324 const Type& generatedType) const; 325 void writeJavaCallToRs(ofstream& file, bool relaxed, bool generateCallToVerify) const; 326 327 void writeJavaTestAndSetValid(ofstream& file, int indent, const ParameterDefinition& p, 328 const string& argsIndex, const string& actualIndex) const; 329 void writeJavaTestOneValue(ofstream& file, int indent, const ParameterDefinition& p, 330 const string& argsIndex, const string& actualIndex) const; 331 void writeJavaAppendOutputToMessage(ofstream& file, int indent, const ParameterDefinition& p, 332 const string& argsIndex, const string& actualIndex) const; 333 void writeJavaAppendInputToMessage(ofstream& file, int indent, const ParameterDefinition& p, 334 const string& actual) const; 335 void writeJavaAppendNewLineToMessage(ofstream& file, int indent) const; 336 void writeJavaAppendVariableToMessage(ofstream& file, int indent, const ParameterDefinition& p, 337 const string& value) const; 338 void writeJavaAppendFloatyVariableToMessage(ofstream& file, int indent, 339 const string& value) const; 340 void writeJavaVectorComparison(ofstream& file, int indent, const ParameterDefinition& p) const; 341 void writeJavaAppendVectorInputToMessage(ofstream& file, int indent, 342 const ParameterDefinition& p) const; 343 void writeJavaAppendVectorOutputToMessage(ofstream& file, int indent, 344 const ParameterDefinition& p) const; 345 bool passByAddressToSet(const string& name) const; 346 void convertToRsType(const string& name, string* dataType, char* vectorSize) const; 347 348public: 349 Permutation(Function* function, Specification* specification, int i1, int i2, int i3, int i4); 350 void writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile, 351 int versionOfTestFiles); 352#define DISABLE_LONG_AND_DOUBLE_TESTS 353#ifdef DISABLE_LONG_AND_DOUBLE_TESTS 354 bool hasLongOrDoubleParameter() const; 355#endif 356}; 357 358// Table of type equivalences 359// TODO: We should just be pulling this from a shared header. Slang does exactly the same thing. 360 361enum NumberKind { SIGNED_INTEGER, UNSIGNED_INTEGER, FLOATING_POINT }; 362 363struct Type { 364 const char* specType; // Name found in the .spec file 365 string rsDataType; // RS data type 366 string cType; // Type in a C file 367 const char* javaType; // Type in a Java file 368 NumberKind kind; 369 /* For integers, number of bits of the number, excluding the sign bit. 370 * For floats, number of implied bits of the mantissa. 371 */ 372 int significantBits; 373 // For floats, number of bits of the exponent. 0 for integer types. 374 int exponentBits; 375}; 376 377const Type TYPES[] = {{"f16", "FLOAT_16", "half", "half", FLOATING_POINT, 11, 5}, 378 {"f32", "FLOAT_32", "float", "float", FLOATING_POINT, 24, 8}, 379 {"f64", "FLOAT_64", "double", "double", FLOATING_POINT, 53, 11}, 380 {"i8", "SIGNED_8", "char", "byte", SIGNED_INTEGER, 7, 0}, 381 {"u8", "UNSIGNED_8", "uchar", "byte", UNSIGNED_INTEGER, 8, 0}, 382 {"i16", "SIGNED_16", "short", "short", SIGNED_INTEGER, 15, 0}, 383 {"u16", "UNSIGNED_16", "ushort", "short", UNSIGNED_INTEGER, 16, 0}, 384 {"i32", "SIGNED_32", "int", "int", SIGNED_INTEGER, 31, 0}, 385 {"u32", "UNSIGNED_32", "uint", "int", UNSIGNED_INTEGER, 32, 0}, 386 {"i64", "SIGNED_64", "long", "long", SIGNED_INTEGER, 63, 0}, 387 {"u64", "UNSIGNED_64", "ulong", "long", UNSIGNED_INTEGER, 64, 0}}; 388 389const int NUM_TYPES = sizeof(TYPES) / sizeof(TYPES[0]); 390 391// Returns the index in TYPES for the provided cType 392int FindCType(const string& cType) { 393 for (int i = 0; i < NUM_TYPES; i++) { 394 if (cType == TYPES[i].cType) { 395 return i; 396 } 397 } 398 return -1; 399} 400 401// Capitalizes and removes underscores. E.g. converts "native_log" to NativeLog. 402string capitalize(const string& source) { 403 int length = source.length(); 404 string result; 405 bool capitalize = true; 406 for (int s = 0; s < length; s++) { 407 if (source[s] == '_') { 408 capitalize = true; 409 } else if (capitalize) { 410 result += toupper(source[s]); 411 capitalize = false; 412 } else { 413 result += source[s]; 414 } 415 } 416 return result; 417} 418 419string tab(int n) { return string(n * 4, ' '); } 420 421// Returns a string that's an hexadecimal constant fo the hash of the string. 422string hashString(const string& s) { 423 long hash = 0; 424 for (size_t i = 0; i < s.length(); i++) { 425 hash = hash * 43 + s[i]; 426 } 427 stringstream stream; 428 stream << "0x" << std::hex << hash << "l"; 429 return stream.str(); 430} 431 432// Removes the character from present. Returns true if the string contained the character. 433static bool charRemoved(char c, string* s) { 434 size_t p = s->find(c); 435 if (p != string::npos) { 436 s->erase(p, 1); 437 return true; 438 } 439 return false; 440} 441 442// Return true if the string is already in the set. Inserts it if not. 443bool testAndSet(const string& flag, set<string>* set) { 444 if (set->find(flag) == set->end()) { 445 set->insert(flag); 446 return false; 447 } 448 return true; 449} 450 451// Convert an int into a string. 452string toString(int n) { 453 char buf[100]; 454 snprintf(buf, sizeof(buf), "%d", n); 455 return string(buf); 456} 457 458void trim(string* s, size_t start) { 459 if (start > 0) { 460 s->erase(0, start); 461 } 462 463 while (s->size() && (s->at(0) == ' ')) { 464 s->erase(0, 1); 465 } 466 467 size_t p = s->find_first_of("\n\r"); 468 if (p != string::npos) { 469 s->erase(p); 470 } 471 472 while ((s->size() > 0) && (s->at(s->size() - 1) == ' ')) { 473 s->erase(s->size() - 1); 474 } 475} 476 477string stringReplace(string s, string match, string rep) { 478 while (1) { 479 size_t p = s.find(match); 480 if (p == string::npos) break; 481 482 s.erase(p, match.size()); 483 s.insert(p, rep); 484 } 485 return s; 486} 487 488// Return the next line from the input file. 489bool getNextLine(FILE* in, string* s) { 490 s->clear(); 491 while (1) { 492 int c = fgetc(in); 493 if (c == EOF) return s->size() != 0; 494 if (c == '\n') break; 495 s->push_back((char)c); 496 } 497 return true; 498} 499 500void writeIfdef(ofstream& file, string filename, bool isStart) { 501 string t = "__"; 502 t += filename; 503 t += "__"; 504 505 for (size_t i = 2; i < t.size(); i++) { 506 if (t[i] == '.') { 507 t[i] = '_'; 508 } 509 } 510 511 if (isStart) { 512 file << "#ifndef " << t << "\n"; 513 file << "#define " << t << "\n"; 514 } else { 515 file << "#endif // " << t << "\n"; 516 } 517} 518 519void writeJavaArrayInitialization(ofstream& file, const ParameterDefinition& p) { 520 file << tab(2) << p.javaBaseType << "[] " << p.javaArrayName << " = new " << p.javaBaseType 521 << "[INPUTSIZE * " << p.vectorWidth << "];\n"; 522 file << tab(2) << p.javaAllocName << ".copyTo(" << p.javaArrayName << ");\n"; 523} 524 525bool parseCommandLine(int argc, char* argv[], int* versionOfTestFiles, 526 vector<string>* specFileNames) { 527 for (int i = 1; i < argc; i++) { 528 if (argv[i][0] == '-') { 529 if (argv[i][1] == 'v') { 530 i++; 531 if (i < argc) { 532 char* end; 533 *versionOfTestFiles = strtol(argv[i], &end, 10); 534 if (*end != '\0') { 535 printf("Can't parse the version number %s\n", argv[i]); 536 return false; 537 } 538 } else { 539 printf("Missing version number after -v\n"); 540 return false; 541 } 542 } else { 543 printf("Unrecognized flag %s\n", argv[i]); 544 return false; 545 } 546 } else { 547 specFileNames->push_back(argv[i]); 548 } 549 } 550 if (specFileNames->size() == 0) { 551 printf("No spec file specified\n"); 552 return false; 553 } 554 return true; 555} 556 557/* Returns a double that should be able to be converted to an integer of size 558 * numberOfIntegerBits. 559 */ 560static double MaxDoubleForInteger(int numberOfIntegerBits, int mantissaSize) { 561 /* Double has only 52 bits of precision (53 implied). So for longs, we want 562 * to create smaller values to avoid a round up. Same for floats and halfs. 563 */ 564 int lowZeroBits = max(0, numberOfIntegerBits - mantissaSize); 565 unsigned long l = (0xffffffffffffffff >> (64 - numberOfIntegerBits + lowZeroBits)) 566 << lowZeroBits; 567 return (double)l; 568} 569 570/* Parse a parameter definition. It's of the form "type [*][name]". The type 571 * is required. The name is optional. The * indicates it's an output 572 * parameter. We also pass the indexed of this parameter in the definition, so 573 * we can create names like in2, in3, etc. */ 574void ParameterDefinition::parseParameterDefinition(string s, bool isReturn, int* inputCount, 575 int* outputCount) { 576 istringstream stream(s); 577 string name, type, option; 578 stream >> rsType; 579 stream >> specName; 580 stream >> option; 581 582 // Determine if this is an output. 583 isOutParameter = charRemoved('*', &rsType) || charRemoved('*', &specName) || isReturn; 584 585 // Extract the vector size out of the type. 586 int last = rsType.size() - 1; 587 char lastChar = rsType[last]; 588 if (lastChar >= '0' && lastChar <= '9') { 589 rsBaseType = rsType.substr(0, last); 590 mVectorSize = lastChar; 591 } else { 592 rsBaseType = rsType; 593 mVectorSize = "1"; 594 } 595 if (mVectorSize == "3") { 596 vectorWidth = "4"; 597 } else { 598 vectorWidth = mVectorSize; 599 } 600 601 /* Create variable names to be used in the java and .rs files. Because x and 602 * y are reserved in .rs files, we prefix variable names with "in" or "out". 603 */ 604 if (isOutParameter) { 605 variableName = "out"; 606 if (!specName.empty()) { 607 variableName += capitalize(specName); 608 } else if (!isReturn) { 609 variableName += toString(*outputCount); 610 } 611 (*outputCount)++; 612 } else { 613 variableName = "in"; 614 if (!specName.empty()) { 615 variableName += capitalize(specName); 616 } else if (*inputCount > 0) { 617 variableName += toString(*inputCount); 618 } 619 (*inputCount)++; 620 } 621 rsAllocName = "gAlloc" + capitalize(variableName); 622 javaAllocName = variableName; 623 javaArrayName = "array" + capitalize(javaAllocName); 624 625 // Process the option. 626 undefinedIfOutIsNan = false; 627 compatibleTypeIndex = -1; 628 if (!option.empty()) { 629 if (option.compare(0, 6, "range(") == 0) { 630 size_t pComma = option.find(','); 631 size_t pParen = option.find(')'); 632 if (pComma == string::npos || pParen == string::npos) { 633 printf("Incorrect range %s\n", option.c_str()); 634 } else { 635 minValue = option.substr(6, pComma - 6); 636 maxValue = option.substr(pComma + 1, pParen - pComma - 1); 637 } 638 } else if (option.compare(0, 6, "above(") == 0) { 639 size_t pParen = option.find(')'); 640 if (pParen == string::npos) { 641 printf("Incorrect option %s\n", option.c_str()); 642 } else { 643 smallerParameter = option.substr(6, pParen - 6); 644 } 645 } else if (option.compare(0, 11, "compatible(") == 0) { 646 size_t pParen = option.find(')'); 647 if (pParen == string::npos) { 648 printf("Incorrect option %s\n", option.c_str()); 649 } else { 650 compatibleTypeIndex = FindCType(option.substr(11, pParen - 11)); 651 } 652 } else if (option.compare(0, 11, "conditional") == 0) { 653 undefinedIfOutIsNan = true; 654 } else { 655 printf("Unrecognized option %s\n", option.c_str()); 656 } 657 } 658 659 typeIndex = FindCType(rsBaseType); 660 isFloatType = false; 661 if (typeIndex < 0) { 662 // TODO set a global flag when we encounter an error & abort 663 printf("Error, could not find %s\n", rsBaseType.c_str()); 664 } else { 665 javaBaseType = TYPES[typeIndex].javaType; 666 specType = TYPES[typeIndex].specType; 667 isFloatType = TYPES[typeIndex].exponentBits > 0; 668 } 669} 670 671bool SpecFile::process(int versionOfTestFiles) { 672 if (!readSpecFile()) { 673 return false; 674 } 675 if (versionOfTestFiles == 0) { 676 versionOfTestFiles = mLargestVersionNumber; 677 } 678 if (!generateFiles(versionOfTestFiles)) { 679 return false; 680 } 681 printf("%s: %ld functions processed.\n", mSpecFileName.c_str(), mFunctionsMap.size()); 682 return true; 683} 684 685// Read the specification, adding the definitions to the global functions map. 686bool SpecFile::readSpecFile() { 687 FILE* specFile = fopen(mSpecFileName.c_str(), "rt"); 688 if (!specFile) { 689 printf("Error opening input file: %s\n", mSpecFileName.c_str()); 690 return false; 691 } 692 693 mLargestVersionNumber = 0; 694 while (1) { 695 Specification* spec = Specification::scanSpecification(specFile); 696 if (spec == NULL) { 697 break; 698 } 699 getFunction(spec->getCleanName())->addSpecification(spec); 700 int specMin = spec->getMinVersion(); 701 int specMax = spec->getMaxVersion(); 702 if (specMin && specMin > mLargestVersionNumber) { 703 mLargestVersionNumber = specMin; 704 } 705 if (specMax && specMax > mLargestVersionNumber) { 706 mLargestVersionNumber = specMax; 707 } 708 } 709 710 fclose(specFile); 711 return true; 712} 713 714bool SpecFile::generateFiles(int versionOfTestFiles) { 715 printf("%s: Generating test files for version %d\n", mSpecFileName.c_str(), versionOfTestFiles); 716 717 // The header file name should have the same base but with a ".rsh" extension. 718 string headerFileName = mSpecFileName; 719 size_t l = headerFileName.length(); 720 const char SPEC[] = ".spec"; 721 const int SPEC_SIZE = sizeof(SPEC) - 1; 722 const int start = l - SPEC_SIZE; 723 if (start >= 0 && headerFileName.compare(start, SPEC_SIZE, SPEC) == 0) { 724 headerFileName.erase(start); 725 } 726 headerFileName += ".rsh"; 727 728 // Write the start of the header file. 729 ofstream headerFile; 730 headerFile.open(headerFileName.c_str(), ios::out | ios::trunc); 731 if (!headerFile.is_open()) { 732 printf("Error opening output file: %s\n", headerFileName.c_str()); 733 return false; 734 } 735 headerFile << LEGAL_NOTICE; 736 headerFile << AUTO_GENERATED_WARNING; 737 writeIfdef(headerFile, headerFileName, true); 738 739 // Write the functions to the header and test files. 740 bool success = writeAllFunctions(headerFile, versionOfTestFiles); 741 742 // Finish the header file. 743 writeIfdef(headerFile, headerFileName, false); 744 headerFile.close(); 745 746 return success; 747} 748 749// Return the named function from the map. Creates it if it's not there. 750Function* SpecFile::getFunction(const string& name) { 751 FunctionsIterator iter = mFunctionsMap.find(name); 752 if (iter != mFunctionsMap.end()) { 753 return iter->second; 754 } 755 Function* f = new Function(name); 756 mFunctionsMap[name] = f; 757 return f; 758} 759 760bool SpecFile::writeAllFunctions(ofstream& headerFile, int versionOfTestFiles) { 761 bool success = true; 762 for (FunctionsIterator iter = mFunctionsMap.begin(); iter != mFunctionsMap.end(); iter++) { 763 Function* func = iter->second; 764 if (!func->writeFiles(headerFile, versionOfTestFiles)) { 765 success = false; 766 } 767 } 768 return success; 769} 770 771Function::Function(const string& name) { 772 mName = name; 773 mCapitalizedName = capitalize(mName); 774 mTestName = "Test" + mCapitalizedName; 775 mRelaxedTestName = mTestName + "Relaxed"; 776} 777 778bool Function::writeFiles(ofstream& headerFile, int versionOfTestFiles) { 779 if (!startRsFile() || !startJavaFile() || !writeRelaxedRsFile()) { 780 return false; 781 } 782 783 for (SpecificationIterator i = mSpecifications.begin(); i < mSpecifications.end(); i++) { 784 (*i)->writeFiles(headerFile, mRsFile, mJavaFile, this, versionOfTestFiles); 785 } 786 787 finishJavaFile(); 788 // There's no work to wrap-up in the .rs file. 789 790 mRsFile.close(); 791 mJavaFile.close(); 792 return true; 793} 794 795bool Function::startRsFile() { 796 string fileName = mTestName + ".rs"; 797 mRsFile.open(fileName.c_str(), ios::out | ios::trunc); 798 if (!mRsFile.is_open()) { 799 printf("Error opening file: %s\n", fileName.c_str()); 800 return false; 801 } 802 mRsFile << LEGAL_NOTICE; 803 mRsFile << "#pragma version(1)\n"; 804 mRsFile << "#pragma rs java_package_name(android.renderscript.cts)\n\n"; 805 mRsFile << AUTO_GENERATED_WARNING; 806 return true; 807} 808 809// Write an allocation definition if not already emitted in the .rs file. 810void Function::writeRsAllocationDefinition(const ParameterDefinition& param) { 811 if (!testAndSet(param.rsAllocName, &mRsAllocationsGenerated)) { 812 mRsFile << "rs_allocation " << param.rsAllocName << ";\n"; 813 } 814} 815 816// Write the entire *Relaxed.rs test file, as it only depends on the name. 817bool Function::writeRelaxedRsFile() { 818 string name = mRelaxedTestName + ".rs"; 819 FILE* file = fopen(name.c_str(), "wt"); 820 if (!file) { 821 printf("Error opening file: %s\n", name.c_str()); 822 return false; 823 } 824 fputs(LEGAL_NOTICE, file); 825 string s; 826 s += "#include \"" + mTestName + ".rs\"\n"; 827 s += "#pragma rs_fp_relaxed\n"; 828 s += AUTO_GENERATED_WARNING; 829 fputs(s.c_str(), file); 830 fclose(file); 831 return true; 832} 833 834bool Function::startJavaFile() { 835 string fileName = mTestName + ".java"; 836 mJavaFile.open(fileName.c_str(), ios::out | ios::trunc); 837 if (!mJavaFile.is_open()) { 838 printf("Error opening file: %s\n", fileName.c_str()); 839 return false; 840 } 841 mJavaFile << LEGAL_NOTICE; 842 mJavaFile << AUTO_GENERATED_WARNING; 843 mJavaFile << "package android.renderscript.cts;\n\n"; 844 845 mJavaFile << "import android.renderscript.Allocation;\n"; 846 mJavaFile << "import android.renderscript.RSRuntimeException;\n"; 847 mJavaFile << "import android.renderscript.Element;\n\n"; 848 849 mJavaFile << "public class " << mTestName << " extends RSBaseCompute {\n\n"; 850 851 mJavaFile << tab(1) << "private ScriptC_" << mTestName << " script;\n"; 852 mJavaFile << tab(1) << "private ScriptC_" << mRelaxedTestName << " scriptRelaxed;\n\n"; 853 854 mJavaFile << tab(1) << "@Override\n"; 855 mJavaFile << tab(1) << "protected void setUp() throws Exception {\n"; 856 mJavaFile << tab(2) << "super.setUp();\n"; 857 mJavaFile << tab(2) << "script = new ScriptC_" << mTestName << "(mRS);\n"; 858 mJavaFile << tab(2) << "scriptRelaxed = new ScriptC_" << mRelaxedTestName << "(mRS);\n"; 859 mJavaFile << tab(1) << "}\n\n"; 860 return true; 861} 862 863void Function::writeJavaArgumentClassDefinition(const string& className, const string& definition) { 864 if (!testAndSet(className, &mJavaGeneratedArgumentClasses)) { 865 mJavaFile << definition; 866 } 867} 868 869void Function::addJavaCheckCall(const string& call) { 870 mJavaCallAllCheckMethods += tab(2) + call + "\n"; 871} 872 873void Function::finishJavaFile() { 874 mJavaFile << tab(1) << "public void test" << mCapitalizedName << "() {\n"; 875 mJavaFile << mJavaCallAllCheckMethods; 876 mJavaFile << tab(1) << "}\n"; 877 mJavaFile << "}\n"; 878} 879 880void Specification::expandStringVector(const vector<string>& in, int i1, int i2, int i3, int i4, 881 vector<string>* out) const { 882 out->clear(); 883 for (vector<string>::const_iterator iter = in.begin(); iter != in.end(); iter++) { 884 out->push_back(expandString(*iter, i1, i2, i3, i4)); 885 } 886} 887 888Specification* Specification::scanSpecification(FILE* in) { 889 Specification* spec = new Specification(); 890 spec->mTest = "scalar"; // default 891 bool modeComment = false; 892 bool modeInline = false; 893 bool success = true; 894 895 while (1) { 896 string s; 897 bool ret = getNextLine(in, &s); 898 if (!ret) break; 899 900 if (modeComment) { 901 if (!s.size() || (s[0] == ' ')) { 902 trim(&s, 0); 903 spec->mComment.push_back(s); 904 continue; 905 } else { 906 modeComment = false; 907 } 908 } 909 910 if (modeInline) { 911 if (!s.size() || (s[0] == ' ')) { 912 trim(&s, 0); 913 spec->mInline.push_back(s); 914 continue; 915 } else { 916 modeInline = false; 917 } 918 } 919 920 if (s[0] == '#') { 921 continue; 922 } 923 924 if (s.compare(0, 5, "name:") == 0) { 925 trim(&s, 5); 926 spec->mName = s; 927 // Some functions like convert have # part of the name. Truncate at that point. 928 size_t p = s.find('#'); 929 if (p != string::npos) { 930 if (p > 0 && s[p - 1] == '_') { 931 p--; 932 } 933 s.erase(p); 934 } 935 spec->mCleanName = s; 936 continue; 937 } 938 939 if (s.compare(0, 4, "arg:") == 0) { 940 trim(&s, 4); 941 spec->mParam.push_back(s); 942 continue; 943 } 944 945 if (s.compare(0, 4, "ret:") == 0) { 946 trim(&s, 4); 947 spec->mReturn = s; 948 continue; 949 } 950 951 if (s.compare(0, 5, "test:") == 0) { 952 trim(&s, 5); 953 if (s == "scalar" || s == "vector" || s == "noverify" || s == "none") { 954 spec->mTest = s; 955 } else if (s.compare(0, 7, "limited") == 0) { 956 spec->mTest = "limited"; 957 if (s.compare(7, 1, "(") == 0) { 958 size_t pParen = s.find(')'); 959 if (pParen == string::npos) { 960 printf("Incorrect test %s\n", s.c_str()); 961 } else { 962 spec->mPrecisionLimit = s.substr(8, pParen - 8); 963 } 964 } 965 } else { 966 printf("Error: Unrecognized test option: %s\n", s.c_str()); 967 success = false; 968 } 969 continue; 970 } 971 972 if (s.compare(0, 4, "end:") == 0) { 973 if (success) { 974 return spec; 975 } else { 976 delete spec; 977 return NULL; 978 } 979 } 980 981 if (s.compare(0, 8, "comment:") == 0) { 982 modeComment = true; 983 continue; 984 } 985 986 if (s.compare(0, 7, "inline:") == 0) { 987 modeInline = true; 988 continue; 989 } 990 991 if (s.compare(0, 8, "version:") == 0) { 992 trim(&s, 8); 993 sscanf(s.c_str(), "%i %i", &spec->mMinVersion, &spec->mMaxVersion); 994 continue; 995 } 996 997 if (s.compare(0, 8, "start:") == 0) { 998 continue; 999 } 1000 1001 if (s.compare(0, 2, "w:") == 0) { 1002 vector<string> t; 1003 if (s.find("1") != string::npos) { 1004 t.push_back(""); 1005 } 1006 if (s.find("2") != string::npos) { 1007 t.push_back("2"); 1008 } 1009 if (s.find("3") != string::npos) { 1010 t.push_back("3"); 1011 } 1012 if (s.find("4") != string::npos) { 1013 t.push_back("4"); 1014 } 1015 spec->mReplaceables.push_back(t); 1016 continue; 1017 } 1018 1019 if (s.compare(0, 2, "t:") == 0) { 1020 vector<string> t; 1021 for (int i = 0; i < NUM_TYPES; i++) { 1022 if (s.find(TYPES[i].specType) != string::npos) { 1023 t.push_back(TYPES[i].cType); 1024 } 1025 } 1026 spec->mReplaceables.push_back(t); 1027 continue; 1028 } 1029 1030 if (s.size() == 0) { 1031 // eat empty line 1032 continue; 1033 } 1034 1035 printf("Error, line:\n"); 1036 printf(" %s\n", s.c_str()); 1037 } 1038 1039 delete spec; 1040 return NULL; 1041} 1042 1043void Specification::writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile, 1044 Function* function, int versionOfTestFiles) { 1045 int start[4]; 1046 int end[4]; 1047 for (int i = 0; i < 4; i++) { 1048 if (i < (int)mReplaceables.size()) { 1049 start[i] = 0; 1050 end[i] = mReplaceables[i].size(); 1051 } else { 1052 start[i] = -1; 1053 end[i] = 0; 1054 } 1055 } 1056 for (int i4 = start[3]; i4 < end[3]; i4++) { 1057 for (int i3 = start[2]; i3 < end[2]; i3++) { 1058 for (int i2 = start[1]; i2 < end[1]; i2++) { 1059 for (int i1 = start[0]; i1 < end[0]; i1++) { 1060 Permutation p(function, this, i1, i2, i3, i4); 1061 p.writeFiles(headerFile, rsFile, javaFile, versionOfTestFiles); 1062 } 1063 } 1064 } 1065 } 1066} 1067 1068bool Specification::relevantForVersion(int versionOfTestFiles) const { 1069 if (mMinVersion != 0 && mMinVersion > versionOfTestFiles) { 1070 return false; 1071 } 1072 if (mMaxVersion != 0 && mMaxVersion < versionOfTestFiles) { 1073 return false; 1074 } 1075 return true; 1076} 1077 1078string Specification::expandString(string s, int i1, int i2, int i3, int i4) const { 1079 if (mReplaceables.size() > 0) { 1080 s = stringReplace(s, "#1", mReplaceables[0][i1]); 1081 } 1082 if (mReplaceables.size() > 1) { 1083 s = stringReplace(s, "#2", mReplaceables[1][i2]); 1084 } 1085 if (mReplaceables.size() > 2) { 1086 s = stringReplace(s, "#3", mReplaceables[2][i3]); 1087 } 1088 if (mReplaceables.size() > 3) { 1089 s = stringReplace(s, "#4", mReplaceables[3][i4]); 1090 } 1091 return s; 1092} 1093 1094Permutation::Permutation(Function* func, Specification* spec, int i1, int i2, int i3, int i4) 1095 : mFunction(func), 1096 mSpecification(spec), 1097 mReturnIndex(-1), 1098 mFirstInputIndex(-1), 1099 mInputCount(0), 1100 mOutputCount(0) { 1101 // We expand the strings now to make capitalization easier. The previous code preserved the #n 1102 // markers just before emitting, which made capitalization difficult. 1103 mName = spec->getName(i1, i2, i3, i4); 1104 mCleanName = spec->getCleanName(); 1105 mTest = spec->getTest(); 1106 mPrecisionLimit = spec->getPrecisionLimit(); 1107 spec->getInlines(i1, i2, i3, i4, &mInline); 1108 spec->getComments(i1, i2, i3, i4, &mComment); 1109 1110 vector<string> paramDefinitions; 1111 spec->getParams(i1, i2, i3, i4, ¶mDefinitions); 1112 for (size_t i = 0; i < paramDefinitions.size(); i++) { 1113 ParameterDefinition* def = new ParameterDefinition(); 1114 def->parseParameterDefinition(paramDefinitions[i], false, &mInputCount, &mOutputCount); 1115 if (!def->isOutParameter && mFirstInputIndex < 0) { 1116 mFirstInputIndex = mParams.size(); 1117 } 1118 mParams.push_back(def); 1119 } 1120 1121 const string s = spec->getReturn(i1, i2, i3, i4); 1122 if (!s.empty() && s != "void") { 1123 ParameterDefinition* def = new ParameterDefinition(); 1124 // Adding "*" tells the parse method it's an output. 1125 def->parseParameterDefinition(s, true, &mInputCount, &mOutputCount); 1126 mReturnIndex = mParams.size(); 1127 mParams.push_back(def); 1128 } 1129 1130 mRsKernelName = "test" + capitalize(mName); 1131 mJavaArgumentsClassName = "Arguments"; 1132 mJavaArgumentsNClassName = "Arguments"; 1133 mJavaCheckMethodName = "check" + capitalize(mCleanName); 1134 mJavaVerifyMethodName = "verifyResults" + capitalize(mCleanName); 1135 for (int i = 0; i < (int)mParams.size(); i++) { 1136 const ParameterDefinition& p = *mParams[i]; 1137 mRsKernelName += capitalize(p.rsType); 1138 mJavaArgumentsClassName += capitalize(p.rsBaseType); 1139 mJavaArgumentsNClassName += capitalize(p.rsBaseType); 1140 if (p.mVectorSize != "1") { 1141 mJavaArgumentsNClassName += "N"; 1142 } 1143 mJavaCheckMethodName += capitalize(p.rsType); 1144 mJavaVerifyMethodName += capitalize(p.rsType); 1145 } 1146 mJavaVerifierComputeMethodName = "compute" + capitalize(mCleanName); 1147} 1148 1149#ifdef DISABLE_LONG_AND_DOUBLE_TESTS 1150// TODO Remove once we have long/double copyTo/copyFrom 1151bool Permutation::hasLongOrDoubleParameter() const { 1152 for (size_t i = 0; i < mParams.size(); i++) { 1153 const ParameterDefinition& p = *mParams[i]; 1154 if (p.javaBaseType == "long" || p.javaBaseType == "double") { 1155 return true; 1156 } 1157 } 1158 return false; 1159} 1160#endif 1161 1162void Permutation::writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile, 1163 int versionOfTestFiles) { 1164 writeHeaderSection(headerFile); 1165#ifdef DISABLE_LONG_AND_DOUBLE_TESTS 1166 if (hasLongOrDoubleParameter()) { 1167 printf("Warning: skipping a test for %s as we don't support long or double arguments (due " 1168 "to Allocation not supporting them).\n", 1169 mName.c_str()); 1170 return; 1171 } 1172#endif 1173 if (mSpecification->relevantForVersion(versionOfTestFiles) && mTest != "none") { 1174 writeRsSection(rsFile); 1175 writeJavaSection(javaFile); 1176 } 1177} 1178 1179void Permutation::writeHeaderSection(ofstream& file) const { 1180 int minVersion = mSpecification->getMinVersion(); 1181 int maxVersion = mSpecification->getMaxVersion(); 1182 bool hasVersion = minVersion || maxVersion; 1183 1184 if (hasVersion) { 1185 if (maxVersion) { 1186 file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << minVersion 1187 << ") && (RS_VERSION <= " << maxVersion << "))\n"; 1188 } else { 1189 file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << minVersion << "))\n"; 1190 } 1191 } 1192 1193 file << "/*\n"; 1194 for (size_t ct = 0; ct < mComment.size(); ct++) { 1195 if (!mComment[ct].empty()) { 1196 file << " * " << mComment[ct] << "\n"; 1197 } else { 1198 file << " *\n"; 1199 } 1200 } 1201 file << " *\n"; 1202 if (minVersion || maxVersion) { 1203 if (maxVersion) { 1204 file << " * Suppored by API versions " << minVersion << " - " << maxVersion << "\n"; 1205 } else { 1206 file << " * Supported by API versions " << minVersion << " and newer.\n"; 1207 } 1208 } 1209 file << " */\n"; 1210 if (mInline.size() > 0) { 1211 file << "static "; 1212 } else { 1213 file << "extern "; 1214 } 1215 if (mReturnIndex >= 0) { 1216 file << mParams[mReturnIndex]->rsType; 1217 } else { 1218 file << "void"; 1219 } 1220 file << " __attribute__(("; 1221 if (mOutputCount <= 1) { 1222 file << "const, "; 1223 } 1224 file << "overloadable))"; 1225 file << mName; 1226 file << "("; 1227 bool needComma = false; 1228 for (int i = 0; i < (int)mParams.size(); i++) { 1229 if (i != mReturnIndex) { 1230 const ParameterDefinition& p = *mParams[i]; 1231 if (needComma) { 1232 file << ", "; 1233 } 1234 file << p.rsType; 1235 if (p.isOutParameter) { 1236 file << "*"; 1237 } 1238 if (!p.specName.empty()) { 1239 file << " " << p.specName; 1240 } 1241 needComma = true; 1242 } 1243 } 1244 if (mInline.size() > 0) { 1245 file << ") {\n"; 1246 for (size_t ct = 0; ct < mInline.size(); ct++) { 1247 file << " " << mInline[ct].c_str() << "\n"; 1248 } 1249 file << "}\n"; 1250 } else { 1251 file << ");\n"; 1252 } 1253 if (hasVersion) { 1254 file << "#endif\n"; 1255 } 1256 file << "\n"; 1257} 1258 1259/* Write the section of the .rs file for this permutation. 1260 * 1261 * We communicate the extra input and output parameters via global allocations. 1262 * For example, if we have a function that takes three arguments, two for input 1263 * and one for output: 1264 * 1265 * start: 1266 * name: gamn 1267 * ret: float3 1268 * arg: float3 a 1269 * arg: int b 1270 * arg: float3 *c 1271 * end: 1272 * 1273 * We'll produce: 1274 * 1275 * rs_allocation gAllocInB; 1276 * rs_allocation gAllocOutC; 1277 * 1278 * float3 __attribute__((kernel)) test_gamn_float3_int_float3(float3 inA, unsigned int x) { 1279 * int inB; 1280 * float3 outC; 1281 * float2 out; 1282 * inB = rsGetElementAt_int(gAllocInB, x); 1283 * out = gamn(a, in_b, &outC); 1284 * rsSetElementAt_float4(gAllocOutC, &outC, x); 1285 * return out; 1286 * } 1287 * 1288 * We avoid re-using x and y from the definition because these have reserved 1289 * meanings in a .rs file. 1290 */ 1291void Permutation::writeRsSection(ofstream& rs) const { 1292 // Write the allocation declarations we'll need. 1293 for (int i = 0; i < (int)mParams.size(); i++) { 1294 const ParameterDefinition& p = *mParams[i]; 1295 // Don't need allocation for one input and one return value. 1296 if (i != mReturnIndex && i != mFirstInputIndex) { 1297 mFunction->writeRsAllocationDefinition(p); 1298 } 1299 } 1300 rs << "\n"; 1301 1302 // Write the function header. 1303 if (mReturnIndex >= 0) { 1304 rs << mParams[mReturnIndex]->rsType; 1305 } else { 1306 rs << "void"; 1307 } 1308 rs << " __attribute__((kernel)) " << mRsKernelName; 1309 rs << "("; 1310 bool needComma = false; 1311 if (mFirstInputIndex >= 0) { 1312 rs << mParams[mFirstInputIndex]->rsType << " " << mParams[mFirstInputIndex]->variableName; 1313 needComma = true; 1314 } 1315 if (mOutputCount > 1 || mInputCount > 1) { 1316 if (needComma) { 1317 rs << ", "; 1318 } 1319 rs << "unsigned int x"; 1320 } 1321 rs << ") {\n"; 1322 1323 // Write the local variable declarations and initializations. 1324 for (int i = 0; i < (int)mParams.size(); i++) { 1325 if (i == mFirstInputIndex || i == mReturnIndex) { 1326 continue; 1327 } 1328 const ParameterDefinition& p = *mParams[i]; 1329 rs << tab(1) << p.rsType << " " << p.variableName; 1330 if (p.isOutParameter) { 1331 rs << " = 0;\n"; 1332 } else { 1333 rs << " = rsGetElementAt_" << p.rsType << "(" << p.rsAllocName << ", x);\n"; 1334 } 1335 } 1336 1337 // Write the function call. 1338 if (mReturnIndex >= 0) { 1339 if (mOutputCount > 1) { 1340 rs << tab(1) << mParams[mReturnIndex]->rsType << " " 1341 << mParams[mReturnIndex]->variableName << " = "; 1342 } else { 1343 rs << tab(1) << "return "; 1344 } 1345 } 1346 rs << mName << "("; 1347 needComma = false; 1348 for (int i = 0; i < (int)mParams.size(); i++) { 1349 const ParameterDefinition& p = *mParams[i]; 1350 if (i == mReturnIndex) { 1351 continue; 1352 } 1353 if (needComma) { 1354 rs << ", "; 1355 } 1356 if (p.isOutParameter) { 1357 rs << "&"; 1358 } 1359 rs << p.variableName; 1360 needComma = true; 1361 } 1362 rs << ");\n"; 1363 1364 if (mOutputCount > 1) { 1365 // Write setting the extra out parameters into the allocations. 1366 for (int i = 0; i < (int)mParams.size(); i++) { 1367 const ParameterDefinition& p = *mParams[i]; 1368 if (p.isOutParameter && i != mReturnIndex) { 1369 rs << tab(1) << "rsSetElementAt_" << p.rsType << "(" << p.rsAllocName << ", "; 1370 if (passByAddressToSet(p.variableName)) { 1371 rs << "&"; 1372 } 1373 rs << p.variableName << ", x);\n"; 1374 } 1375 } 1376 if (mReturnIndex >= 0) { 1377 rs << tab(1) << "return " << mParams[mReturnIndex]->variableName << ";\n"; 1378 } 1379 } 1380 rs << "}\n"; 1381} 1382 1383bool Permutation::passByAddressToSet(const string& name) const { 1384 string s = name; 1385 int last = s.size() - 1; 1386 char lastChar = s[last]; 1387 return lastChar >= '0' && lastChar <= '9'; 1388} 1389 1390void Permutation::writeJavaSection(ofstream& file) const { 1391 // By default, we test the results using item by item comparison. 1392 if (mTest == "scalar" || mTest == "limited") { 1393 writeJavaArgumentClass(file, true); 1394 writeJavaCheckMethod(file, true); 1395 writeJavaVerifyScalarMethod(file); 1396 } else if (mTest == "vector") { 1397 writeJavaArgumentClass(file, false); 1398 writeJavaCheckMethod(file, true); 1399 writeJavaVerifyVectorMethod(file); 1400 } else if (mTest == "noverify") { 1401 writeJavaCheckMethod(file, false); 1402 } 1403 1404 // Register the check method to be called. This code will be written at the end. 1405 mFunction->addJavaCheckCall(mJavaCheckMethodName + "();"); 1406} 1407 1408void Permutation::writeJavaArgumentClass(ofstream& file, bool scalar) const { 1409 string name; 1410 if (scalar) { 1411 name = mJavaArgumentsClassName; 1412 } else { 1413 name = mJavaArgumentsNClassName; 1414 } 1415 string s; 1416 s += tab(1) + "public class " + name + " {\n"; 1417 for (size_t i = 0; i < mParams.size(); i++) { 1418 const ParameterDefinition& p = *mParams[i]; 1419 s += tab(2) + "public "; 1420 if (p.isOutParameter && p.isFloatType) { 1421 s += "Floaty"; 1422 } else { 1423 s += p.javaBaseType; 1424 } 1425 if (!scalar && p.mVectorSize != "1") { 1426 s += "[]"; 1427 } 1428 s += " " + p.variableName + ";\n"; 1429 } 1430 s += tab(1) + "}\n\n"; 1431 1432 mFunction->writeJavaArgumentClassDefinition(name, s); 1433} 1434 1435void Permutation::writeJavaCheckMethod(ofstream& file, bool generateCallToVerify) const { 1436 file << tab(1) << "private void " << mJavaCheckMethodName << "() {\n"; 1437 // Generate the input allocations and initialization. 1438 for (size_t i = 0; i < mParams.size(); i++) { 1439 const ParameterDefinition& p = *mParams[i]; 1440 if (!p.isOutParameter) { 1441 writeJavaInputAllocationDefinition(file, tab(2), p); 1442 } 1443 } 1444 // Enforce ordering if needed. 1445 for (size_t i = 0; i < mParams.size(); i++) { 1446 const ParameterDefinition& p = *mParams[i]; 1447 if (!p.isOutParameter && !p.smallerParameter.empty()) { 1448 string smallerAlloc = "in" + capitalize(p.smallerParameter); 1449 file << tab(2) << "enforceOrdering(" << smallerAlloc << ", " << p.javaAllocName 1450 << ");\n"; 1451 } 1452 } 1453 writeJavaCallToRs(file, false, generateCallToVerify); 1454 writeJavaCallToRs(file, true, generateCallToVerify); 1455 file << tab(1) << "}\n\n"; 1456} 1457 1458void Permutation::writeJavaInputAllocationDefinition(ofstream& file, const string& indent, 1459 const ParameterDefinition& param) const { 1460 string dataType; 1461 char vectorSize; 1462 convertToRsType(param.rsType, &dataType, &vectorSize); 1463 1464 string seed = hashString(mJavaCheckMethodName + param.javaAllocName); 1465 file << indent << "Allocation " << param.javaAllocName << " = "; 1466 if (param.compatibleTypeIndex >= 0) { 1467 if (TYPES[param.typeIndex].kind == FLOATING_POINT) { 1468 writeJavaRandomCompatibleFloatAllocation(file, dataType, seed, vectorSize, 1469 TYPES[param.compatibleTypeIndex], 1470 TYPES[param.typeIndex]); 1471 } else { 1472 writeJavaRandomCompatibleIntegerAllocation(file, dataType, seed, vectorSize, 1473 TYPES[param.compatibleTypeIndex], 1474 TYPES[param.typeIndex]); 1475 } 1476 } else if (!param.minValue.empty()) { 1477 if (TYPES[param.typeIndex].kind != FLOATING_POINT) { 1478 printf("range(,) is only supported for floating point\n"); 1479 } else { 1480 file << "createRandomFloatAllocation(mRS, Element.DataType." << dataType << ", " 1481 << vectorSize << ", " << seed << ", " << param.minValue << ", " << param.maxValue 1482 << ")"; 1483 } 1484 } else { 1485 file << "createRandomAllocation(mRS, Element.DataType." << dataType << ", " << vectorSize 1486 << ", " << seed << ", false)"; // TODO set to false only for native 1487 } 1488 file << ";\n"; 1489} 1490 1491void Permutation::writeJavaRandomCompatibleFloatAllocation(ofstream& file, const string& dataType, 1492 const string& seed, char vectorSize, 1493 const Type& compatibleType, 1494 const Type& generatedType) const { 1495 file << "createRandomFloatAllocation" 1496 << "(mRS, Element.DataType." << dataType << ", " << vectorSize << ", " << seed << ", "; 1497 double minValue = 0.0; 1498 double maxValue = 0.0; 1499 switch (compatibleType.kind) { 1500 case FLOATING_POINT: { 1501 // We're generating floating point values. We just worry about the exponent. 1502 // Subtract 1 for the exponent sign. 1503 int bits = min(compatibleType.exponentBits, generatedType.exponentBits) - 1; 1504 maxValue = ldexp(0.95, (1 << bits) - 1); 1505 minValue = -maxValue; 1506 break; 1507 } 1508 case UNSIGNED_INTEGER: 1509 maxValue = MaxDoubleForInteger(compatibleType.significantBits, 1510 generatedType.significantBits); 1511 minValue = 0.0; 1512 break; 1513 case SIGNED_INTEGER: 1514 maxValue = MaxDoubleForInteger(compatibleType.significantBits, 1515 generatedType.significantBits); 1516 minValue = -maxValue - 1.0; 1517 break; 1518 } 1519 file << scientific << std::setprecision(19); 1520 file << minValue << ", " << maxValue << ")"; 1521 file.unsetf(ios_base::floatfield); 1522} 1523 1524void Permutation::writeJavaRandomCompatibleIntegerAllocation(ofstream& file, const string& dataType, 1525 const string& seed, char vectorSize, 1526 const Type& compatibleType, 1527 const Type& generatedType) const { 1528 file << "createRandomIntegerAllocation" 1529 << "(mRS, Element.DataType." << dataType << ", " << vectorSize << ", " << seed << ", "; 1530 1531 if (compatibleType.kind == FLOATING_POINT) { 1532 // Currently, all floating points can take any number we generate. 1533 bool isSigned = generatedType.kind == SIGNED_INTEGER; 1534 file << (isSigned ? "true" : "false") << ", " << generatedType.significantBits; 1535 } else { 1536 bool isSigned = 1537 compatibleType.kind == SIGNED_INTEGER && generatedType.kind == SIGNED_INTEGER; 1538 file << (isSigned ? "true" : "false") << ", " 1539 << min(compatibleType.significantBits, generatedType.significantBits); 1540 } 1541 file << ")"; 1542} 1543 1544void Permutation::writeJavaOutputAllocationDefinition(ofstream& file, const string& indent, 1545 const ParameterDefinition& param) const { 1546 string dataType; 1547 char vectorSize; 1548 convertToRsType(param.rsType, &dataType, &vectorSize); 1549 file << indent << "Allocation " << param.javaAllocName << " = Allocation.createSized(mRS, " 1550 << "getElement(mRS, Element.DataType." << dataType << ", " << vectorSize 1551 << "), INPUTSIZE);\n"; 1552} 1553 1554// Converts float2 to FLOAT_32 and 2, etc. 1555void Permutation::convertToRsType(const string& name, string* dataType, char* vectorSize) const { 1556 string s = name; 1557 int last = s.size() - 1; 1558 char lastChar = s[last]; 1559 if (lastChar >= '1' && lastChar <= '4') { 1560 s.erase(last); 1561 *vectorSize = lastChar; 1562 } else { 1563 *vectorSize = '1'; 1564 } 1565 dataType->clear(); 1566 for (int i = 0; i < NUM_TYPES; i++) { 1567 if (s == TYPES[i].cType) { 1568 *dataType = TYPES[i].rsDataType; 1569 break; 1570 } 1571 } 1572} 1573 1574void Permutation::writeJavaVerifyScalarMethod(ofstream& file) const { 1575 writeJavaVerifyFunctionHeader(file); 1576 string vectorSize = "1"; 1577 for (size_t i = 0; i < mParams.size(); i++) { 1578 const ParameterDefinition& p = *mParams[i]; 1579 writeJavaArrayInitialization(file, p); 1580 if (p.mVectorSize != "1" && p.mVectorSize != vectorSize) { 1581 if (vectorSize == "1") { 1582 vectorSize = p.mVectorSize; 1583 } else { 1584 printf("Yikes, had vector %s and %s\n", vectorSize.c_str(), p.mVectorSize.c_str()); 1585 } 1586 } 1587 } 1588 1589 file << tab(2) << "for (int i = 0; i < INPUTSIZE; i++) {\n"; 1590 file << tab(3) << "for (int j = 0; j < " << vectorSize << " ; j++) {\n"; 1591 1592 file << tab(4) << "// Extract the inputs.\n"; 1593 file << tab(4) << mJavaArgumentsClassName << " args = new " << mJavaArgumentsClassName 1594 << "();\n"; 1595 for (size_t i = 0; i < mParams.size(); i++) { 1596 const ParameterDefinition& p = *mParams[i]; 1597 if (!p.isOutParameter) { 1598 file << tab(4) << "args." << p.variableName << " = " << p.javaArrayName << "[i"; 1599 if (p.vectorWidth != "1") { 1600 file << " * " << p.vectorWidth << " + j"; 1601 } 1602 file << "];\n"; 1603 } 1604 } 1605 1606 file << tab(4) << "// Figure out what the outputs should have been.\n"; 1607 file << tab(4) << "Floaty.setRelaxed(relaxed);\n"; 1608 file << tab(4) << "CoreMathVerifier." << mJavaVerifierComputeMethodName << "(args);\n"; 1609 1610 file << tab(4) << "// Figure out what the outputs should have been.\n"; 1611 file << tab(4) << "boolean valid = true;\n"; 1612 for (size_t i = 0; i < mParams.size(); i++) { 1613 const ParameterDefinition& p = *mParams[i]; 1614 if (p.isOutParameter) { 1615 writeJavaTestAndSetValid(file, 4, p, "", "[i * " + p.vectorWidth + " + j]"); 1616 } 1617 } 1618 1619 file << tab(4) << "if (!valid) {\n"; 1620 file << tab(5) << "StringBuilder message = new StringBuilder();\n"; 1621 for (size_t i = 0; i < mParams.size(); i++) { 1622 const ParameterDefinition& p = *mParams[i]; 1623 if (p.isOutParameter) { 1624 writeJavaAppendOutputToMessage(file, 5, p, "", "[i * " + p.vectorWidth + " + j]"); 1625 } else { 1626 writeJavaAppendInputToMessage(file, 5, p, "args." + p.variableName); 1627 } 1628 } 1629 1630 file << tab(5) << "assertTrue(\"Incorrect output for " << mJavaCheckMethodName << "\" +\n"; 1631 file << tab(7) << "(relaxed ? \"_relaxed\" : \"\") + \":\\n\" + message.toString(), valid);\n"; 1632 file << tab(4) << "}\n"; 1633 file << tab(3) << "}\n"; 1634 file << tab(2) << "}\n"; 1635 file << tab(1) << "}\n\n"; 1636} 1637 1638void Permutation::writeJavaVerifyFunctionHeader(ofstream& file) const { 1639 file << tab(1) << "private void " << mJavaVerifyMethodName << "("; 1640 for (size_t i = 0; i < mParams.size(); i++) { 1641 const ParameterDefinition& p = *mParams[i]; 1642 file << "Allocation " << p.javaAllocName << ", "; 1643 } 1644 file << "boolean relaxed) {\n"; 1645} 1646 1647void Permutation::writeJavaTestAndSetValid(ofstream& file, int indent, const ParameterDefinition& p, 1648 const string& argsIndex, 1649 const string& actualIndex) const { 1650 writeJavaTestOneValue(file, indent, p, argsIndex, actualIndex); 1651 file << tab(indent + 1) << "valid = false;\n"; 1652 file << tab(indent) << "}\n"; 1653} 1654 1655void Permutation::writeJavaTestOneValue(ofstream& file, int indent, const ParameterDefinition& p, 1656 const string& argsIndex, const string& actualIndex) const { 1657 file << tab(indent) << "if ("; 1658 if (p.isFloatType) { 1659 file << "!args." << p.variableName << argsIndex << ".couldBe(" << p.javaArrayName 1660 << actualIndex; 1661 if (!mPrecisionLimit.empty()) { 1662 file << ", " << mPrecisionLimit; 1663 } 1664 file << ")"; 1665 } else { 1666 file << "args." << p.variableName << argsIndex << " != " << p.javaArrayName << actualIndex; 1667 } 1668 if (p.undefinedIfOutIsNan && mReturnIndex >= 0) { 1669 file << " && args." << mParams[mReturnIndex]->variableName << argsIndex << ".isNaN()"; 1670 } 1671 file << ") {\n"; 1672} 1673 1674void Permutation::writeJavaAppendOutputToMessage(ofstream& file, int indent, 1675 const ParameterDefinition& p, 1676 const string& argsIndex, 1677 const string& actualIndex) const { 1678 const string expected = "args." + p.variableName + argsIndex; 1679 const string actual = p.javaArrayName + actualIndex; 1680 file << tab(indent) << "message.append(\"Expected output " + p.variableName + ": \");\n"; 1681 if (p.isFloatType) { 1682 writeJavaAppendFloatyVariableToMessage(file, indent, expected); 1683 } else { 1684 writeJavaAppendVariableToMessage(file, indent, p, expected); 1685 } 1686 writeJavaAppendNewLineToMessage(file, indent); 1687 file << tab(indent) << "message.append(\"Actual output " + p.variableName + ": \");\n"; 1688 writeJavaAppendVariableToMessage(file, indent, p, actual); 1689 1690 writeJavaTestOneValue(file, indent, p, argsIndex, actualIndex); 1691 file << tab(indent + 1) << "message.append(\" FAIL\");\n"; 1692 file << tab(indent) << "}\n"; 1693 writeJavaAppendNewLineToMessage(file, indent); 1694} 1695 1696void Permutation::writeJavaAppendInputToMessage(ofstream& file, int indent, 1697 const ParameterDefinition& p, 1698 const string& actual) const { 1699 file << tab(indent) << "message.append(\"Input " + p.variableName + ": \");\n"; 1700 writeJavaAppendVariableToMessage(file, indent, p, actual); 1701 writeJavaAppendNewLineToMessage(file, indent); 1702} 1703 1704void Permutation::writeJavaAppendNewLineToMessage(ofstream& file, int indent) const { 1705 file << tab(indent) << "message.append(\"\\n\");\n"; 1706} 1707 1708void Permutation::writeJavaAppendVariableToMessage(ofstream& file, int indent, 1709 const ParameterDefinition& p, 1710 const string& value) const { 1711 if (p.specType == "f16" || p.specType == "f32") { 1712 file << tab(indent) << "message.append(String.format(\"%14.8g %8x %15a\",\n"; 1713 file << tab(indent + 2) << value << ", " 1714 << "Float.floatToRawIntBits(" << value << "), " << value << "));\n"; 1715 } else if (p.specType == "f64") { 1716 file << tab(indent) << "message.append(String.format(\"%24.8g %16x %31a\",\n"; 1717 file << tab(indent + 2) << value << ", " 1718 << "Double.doubleToRawLongBits(" << value << "), " << value << "));\n"; 1719 } else if (p.specType[0] == 'u') { 1720 file << tab(indent) << "message.append(String.format(\"0x%x\", " << value << "));\n"; 1721 } else { 1722 file << tab(indent) << "message.append(String.format(\"%d\", " << value << "));\n"; 1723 } 1724} 1725 1726void Permutation::writeJavaAppendFloatyVariableToMessage(ofstream& file, int indent, 1727 const string& value) const { 1728 file << tab(indent) << "message.append(" << value << ".toString());\n"; 1729} 1730 1731void Permutation::writeJavaVectorComparison(ofstream& file, int indent, 1732 const ParameterDefinition& p) const { 1733 if (p.mVectorSize == "1") { 1734 writeJavaTestAndSetValid(file, indent, p, "", "[i]"); 1735 1736 } else { 1737 file << tab(indent) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n"; 1738 writeJavaTestAndSetValid(file, indent + 1, p, "[j]", "[i * " + p.vectorWidth + " + j]"); 1739 file << tab(indent) << "}\n"; 1740 } 1741} 1742 1743void Permutation::writeJavaAppendVectorInputToMessage(ofstream& file, int indent, 1744 const ParameterDefinition& p) const { 1745 if (p.mVectorSize == "1") { 1746 writeJavaAppendInputToMessage(file, indent, p, p.javaArrayName + "[i]"); 1747 } else { 1748 file << tab(indent) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n"; 1749 writeJavaAppendInputToMessage(file, indent + 1, p, 1750 p.javaArrayName + "[i * " + p.vectorWidth + " + j]"); 1751 file << tab(indent) << "}\n"; 1752 } 1753} 1754 1755void Permutation::writeJavaAppendVectorOutputToMessage(ofstream& file, int indent, 1756 const ParameterDefinition& p) const { 1757 if (p.mVectorSize == "1") { 1758 writeJavaAppendOutputToMessage(file, indent, p, "", "[i]"); 1759 1760 } else { 1761 file << tab(indent) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n"; 1762 writeJavaAppendOutputToMessage(file, indent + 1, p, "[j]", 1763 "[i * " + p.vectorWidth + " + j]"); 1764 file << tab(indent) << "}\n"; 1765 } 1766} 1767 1768void Permutation::writeJavaVerifyVectorMethod(ofstream& file) const { 1769 writeJavaVerifyFunctionHeader(file); 1770 for (size_t i = 0; i < mParams.size(); i++) { 1771 const ParameterDefinition& p = *mParams[i]; 1772 writeJavaArrayInitialization(file, p); 1773 } 1774 file << tab(2) + "for (int i = 0; i < INPUTSIZE; i++) {\n"; 1775 file << tab(3) << mJavaArgumentsNClassName << " args = new " << mJavaArgumentsNClassName 1776 << "();\n"; 1777 1778 file << tab(3) << "// Create the appropriate sized arrays in args\n"; 1779 for (size_t i = 0; i < mParams.size(); i++) { 1780 const ParameterDefinition& p = *mParams[i]; 1781 if (p.mVectorSize != "1") { 1782 string type = p.javaBaseType; 1783 if (p.isOutParameter && p.isFloatType) { 1784 type = "Floaty"; 1785 } 1786 file << tab(3) << "args." << p.variableName << " = new " << type << "[" << p.mVectorSize 1787 << "];\n"; 1788 } 1789 } 1790 1791 file << tab(3) << "// Fill args with the input values\n"; 1792 for (size_t i = 0; i < mParams.size(); i++) { 1793 const ParameterDefinition& p = *mParams[i]; 1794 if (!p.isOutParameter) { 1795 if (p.mVectorSize == "1") { 1796 file << tab(3) << "args." << p.variableName << " = " << p.javaArrayName + "[i]" 1797 << ";\n"; 1798 } else { 1799 file << tab(3) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n"; 1800 file << tab(4) << "args." << p.variableName + "[j] = " 1801 << p.javaArrayName + "[i * " + p.vectorWidth + " + j]" 1802 << ";\n"; 1803 file << tab(3) << "}\n"; 1804 } 1805 } 1806 } 1807 file << tab(3) << "Floaty.setRelaxed(relaxed);\n"; 1808 file << tab(3) << "CoreMathVerifier." << mJavaVerifierComputeMethodName << "(args);\n\n"; 1809 1810 file << tab(3) << "// Compare the expected outputs to the actual values returned by RS.\n"; 1811 file << tab(3) << "boolean valid = true;\n"; 1812 for (size_t i = 0; i < mParams.size(); i++) { 1813 const ParameterDefinition& p = *mParams[i]; 1814 if (p.isOutParameter) { 1815 writeJavaVectorComparison(file, 3, p); 1816 } 1817 } 1818 1819 file << tab(3) << "if (!valid) {\n"; 1820 file << tab(4) << "StringBuilder message = new StringBuilder();\n"; 1821 for (size_t i = 0; i < mParams.size(); i++) { 1822 const ParameterDefinition& p = *mParams[i]; 1823 if (p.isOutParameter) { 1824 writeJavaAppendVectorOutputToMessage(file, 4, p); 1825 } else { 1826 writeJavaAppendVectorInputToMessage(file, 4, p); 1827 } 1828 } 1829 1830 file << tab(4) << "assertTrue(\"Incorrect output for " << mJavaCheckMethodName << "\" +\n"; 1831 file << tab(6) << "(relaxed ? \"_relaxed\" : \"\") + \":\\n\" + message.toString(), valid);\n"; 1832 file << tab(3) << "}\n"; 1833 file << tab(2) << "}\n"; 1834 file << tab(1) << "}\n\n"; 1835} 1836 1837void Permutation::writeJavaCallToRs(ofstream& file, bool relaxed, bool generateCallToVerify) const { 1838 string script = "script"; 1839 if (relaxed) { 1840 script += "Relaxed"; 1841 } 1842 1843 file << tab(2) << "try {\n"; 1844 for (size_t i = 0; i < mParams.size(); i++) { 1845 const ParameterDefinition& p = *mParams[i]; 1846 if (p.isOutParameter) { 1847 writeJavaOutputAllocationDefinition(file, tab(3), p); 1848 } 1849 } 1850 1851 for (int i = 0; i < (int)mParams.size(); i++) { 1852 const ParameterDefinition& p = *mParams[i]; 1853 if (i != mReturnIndex && i != mFirstInputIndex) { 1854 file << tab(3) << script << ".set_" << p.rsAllocName << "(" << p.javaAllocName 1855 << ");\n"; 1856 } 1857 } 1858 1859 file << tab(3) << script << ".forEach_" << mRsKernelName << "("; 1860 bool needComma = false; 1861 if (mFirstInputIndex >= 0) { 1862 file << mParams[mFirstInputIndex]->javaAllocName; 1863 needComma = true; 1864 } 1865 if (mReturnIndex >= 0) { 1866 if (needComma) { 1867 file << ", "; 1868 } 1869 file << mParams[mReturnIndex]->variableName << ");\n"; 1870 } 1871 1872 if (generateCallToVerify) { 1873 file << tab(3) << mJavaVerifyMethodName << "("; 1874 for (size_t i = 0; i < mParams.size(); i++) { 1875 const ParameterDefinition& p = *mParams[i]; 1876 file << p.variableName << ", "; 1877 } 1878 1879 if (relaxed) { 1880 file << "true"; 1881 } else { 1882 file << "false"; 1883 } 1884 file << ");\n"; 1885 } 1886 file << tab(2) << "} catch (Exception e) {\n"; 1887 file << tab(3) << "throw new RSRuntimeException(\"RenderScript. Can't invoke forEach_" 1888 << mRsKernelName << ": \" + e.toString());\n"; 1889 file << tab(2) << "}\n"; 1890} 1891 1892} // namespace 1893 1894int main(int argc, char* argv[]) { 1895 int versionOfTestFiles = 0; 1896 vector<string> specFileNames; 1897 if (!parseCommandLine(argc, argv, &versionOfTestFiles, &specFileNames)) { 1898 printf("Usage: gen_runtime spec_file [spec_file...] [-v version_of_test_files]\n"); 1899 return -1; 1900 } 1901 int result = 0; 1902 for (size_t i = 0; i < specFileNames.size(); i++) { 1903 SpecFile specFile(specFileNames[i]); 1904 if (!specFile.process(versionOfTestFiles)) { 1905 result = -1; 1906 } 1907 } 1908 return result; 1909} 1910