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