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