blob: a09c21f807b0369d868b2f5769205dcdae0cebbf [file] [log] [blame]
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001/*
2 * Copyright (C) 2015 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#include <iomanip>
18#include <iostream>
19#include <cmath>
20#include <sstream>
21
22#include "Generator.h"
23#include "Specification.h"
24#include "Utilities.h"
25
26using namespace std;
27
28// Converts float2 to FLOAT_32 and 2, etc.
29static void convertToRsType(const string& name, string* dataType, char* vectorSize) {
30 string s = name;
31 int last = s.size() - 1;
32 char lastChar = s[last];
33 if (lastChar >= '1' && lastChar <= '4') {
34 s.erase(last);
35 *vectorSize = lastChar;
36 } else {
37 *vectorSize = '1';
38 }
39 dataType->clear();
40 for (int i = 0; i < NUM_TYPES; i++) {
41 if (s == TYPES[i].cType) {
42 *dataType = TYPES[i].rsDataType;
43 break;
44 }
45 }
46}
47
48// Returns true if any permutation of the function have tests to b
Yang Ni12398d82015-09-18 14:57:07 -070049static bool needTestFiles(const Function& function, unsigned int versionOfTestFiles) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -070050 for (auto spec : function.getSpecifications()) {
51 if (spec->hasTests(versionOfTestFiles)) {
52 return true;
53 }
54 }
55 return false;
56}
57
58/* One instance of this class is generated for each permutation of a function for which
59 * we are generating test code. This instance will generate both the script and the Java
60 * section of the test files for this permutation. The class is mostly used to keep track
61 * of the various names shared between script and Java files.
62 * WARNING: Because the constructor keeps a reference to the FunctionPermutation, PermutationWriter
63 * should not exceed the lifetime of FunctionPermutation.
64 */
65class PermutationWriter {
66private:
67 FunctionPermutation& mPermutation;
68
69 string mRsKernelName;
70 string mJavaArgumentsClassName;
71 string mJavaArgumentsNClassName;
72 string mJavaVerifierComputeMethodName;
73 string mJavaVerifierVerifyMethodName;
74 string mJavaCheckMethodName;
75 string mJavaVerifyMethodName;
76
77 // Pointer to the files we are generating. Handy to avoid always passing them in the calls.
78 GeneratedFile* mRs;
79 GeneratedFile* mJava;
80
81 /* Shortcuts to the return parameter and the first input parameter of the function
82 * specification.
83 */
84 const ParameterDefinition* mReturnParam; // Can be nullptr. NOT OWNED.
85 const ParameterDefinition* mFirstInputParam; // Can be nullptr. NOT OWNED.
86
87 /* All the parameters plus the return param, if present. Collecting them together
88 * simplifies code generation. NOT OWNED.
89 */
90 vector<const ParameterDefinition*> mAllInputsAndOutputs;
91
92 /* We use a class to pass the arguments between the generated code and the CoreVerifier. This
93 * method generates this class. The set keeps track if we've generated this class already
94 * for this test file, as more than one permutation may use the same argument class.
95 */
96 void writeJavaArgumentClass(bool scalar, set<string>* javaGeneratedArgumentClasses) const;
97
98 // Generate the Check* method that invokes the script and calls the verifier.
99 void writeJavaCheckMethod(bool generateCallToVerifier) const;
100
101 // Generate code to define and randomly initialize the input allocation.
102 void writeJavaInputAllocationDefinition(const ParameterDefinition& param) const;
103
104 /* Generate code that instantiate an allocation of floats or integers and fills it with
105 * random data. This random data must be compatible with the specified type. This is
106 * used for the convert_* tests, as converting values that don't fit yield undefined results.
107 */
108 void writeJavaRandomCompatibleFloatAllocation(const string& dataType, const string& seed,
109 char vectorSize,
110 const NumericalType& compatibleType,
111 const NumericalType& generatedType) const;
112 void writeJavaRandomCompatibleIntegerAllocation(const string& dataType, const string& seed,
113 char vectorSize,
114 const NumericalType& compatibleType,
115 const NumericalType& generatedType) const;
116
117 // Generate code that defines an output allocation.
118 void writeJavaOutputAllocationDefinition(const ParameterDefinition& param) const;
119
120 /* Generate the code that verifies the results for RenderScript functions where each entry
121 * of a vector is evaluated independently. If verifierValidates is true, CoreMathVerifier
122 * does the actual validation instead of more commonly returning the range of acceptable values.
123 */
124 void writeJavaVerifyScalarMethod(bool verifierValidates) const;
125
126 /* Generate the code that verify the results for a RenderScript function where a vector
127 * is a point in n-dimensional space.
128 */
129 void writeJavaVerifyVectorMethod() const;
130
Pirama Arumuga Nainar93abc2d2016-02-16 15:11:29 -0800131 // Generate the line that creates the Target.
132 void writeJavaCreateTarget() const;
133
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700134 // Generate the method header of the verify function.
135 void writeJavaVerifyMethodHeader() const;
136
137 // Generate codes that copies the content of an allocation to an array.
138 void writeJavaArrayInitialization(const ParameterDefinition& p) const;
139
140 // Generate code that tests one value returned from the script.
141 void writeJavaTestAndSetValid(const ParameterDefinition& p, const string& argsIndex,
142 const string& actualIndex) const;
143 void writeJavaTestOneValue(const ParameterDefinition& p, const string& argsIndex,
144 const string& actualIndex) const;
145 // For test:vector cases, generate code that compares returned vector vs. expected value.
146 void writeJavaVectorComparison(const ParameterDefinition& p) const;
147
148 // Muliple functions that generates code to build the error message if an error is found.
149 void writeJavaAppendOutputToMessage(const ParameterDefinition& p, const string& argsIndex,
150 const string& actualIndex, bool verifierValidates) const;
151 void writeJavaAppendInputToMessage(const ParameterDefinition& p, const string& actual) const;
152 void writeJavaAppendNewLineToMessage() const;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700153 void writeJavaAppendVectorInputToMessage(const ParameterDefinition& p) const;
154 void writeJavaAppendVectorOutputToMessage(const ParameterDefinition& p) const;
155
156 // Generate the set of instructions to call the script.
157 void writeJavaCallToRs(bool relaxed, bool generateCallToVerifier) const;
158
159 // Write an allocation definition if not already emitted in the .rs file.
160 void writeRsAllocationDefinition(const ParameterDefinition& param,
161 set<string>* rsAllocationsGenerated) const;
162
163public:
164 /* NOTE: We keep pointers to the permutation and the files. This object should not
165 * outlive the arguments.
166 */
167 PermutationWriter(FunctionPermutation& permutation, GeneratedFile* rsFile,
168 GeneratedFile* javaFile);
169 string getJavaCheckMethodName() const { return mJavaCheckMethodName; }
170
171 // Write the script test function for this permutation.
172 void writeRsSection(set<string>* rsAllocationsGenerated) const;
173 // Write the section of the Java code that calls the script and validates the results
174 void writeJavaSection(set<string>* javaGeneratedArgumentClasses) const;
175};
176
177PermutationWriter::PermutationWriter(FunctionPermutation& permutation, GeneratedFile* rsFile,
178 GeneratedFile* javaFile)
179 : mPermutation(permutation),
180 mRs(rsFile),
181 mJava(javaFile),
182 mReturnParam(nullptr),
183 mFirstInputParam(nullptr) {
184 mRsKernelName = "test" + capitalize(permutation.getName());
185
186 mJavaArgumentsClassName = "Arguments";
187 mJavaArgumentsNClassName = "Arguments";
188 const string trunk = capitalize(permutation.getNameTrunk());
189 mJavaCheckMethodName = "check" + trunk;
190 mJavaVerifyMethodName = "verifyResults" + trunk;
191
192 for (auto p : permutation.getParams()) {
193 mAllInputsAndOutputs.push_back(p);
194 if (mFirstInputParam == nullptr && !p->isOutParameter) {
195 mFirstInputParam = p;
196 }
197 }
198 mReturnParam = permutation.getReturn();
199 if (mReturnParam) {
200 mAllInputsAndOutputs.push_back(mReturnParam);
201 }
202
203 for (auto p : mAllInputsAndOutputs) {
204 const string capitalizedRsType = capitalize(p->rsType);
205 const string capitalizedBaseType = capitalize(p->rsBaseType);
206 mRsKernelName += capitalizedRsType;
207 mJavaArgumentsClassName += capitalizedBaseType;
208 mJavaArgumentsNClassName += capitalizedBaseType;
209 if (p->mVectorSize != "1") {
210 mJavaArgumentsNClassName += "N";
211 }
212 mJavaCheckMethodName += capitalizedRsType;
213 mJavaVerifyMethodName += capitalizedRsType;
214 }
215 mJavaVerifierComputeMethodName = "compute" + trunk;
216 mJavaVerifierVerifyMethodName = "verify" + trunk;
217}
218
219void PermutationWriter::writeJavaSection(set<string>* javaGeneratedArgumentClasses) const {
220 // By default, we test the results using item by item comparison.
221 const string test = mPermutation.getTest();
222 if (test == "scalar" || test == "limited") {
223 writeJavaArgumentClass(true, javaGeneratedArgumentClasses);
224 writeJavaCheckMethod(true);
225 writeJavaVerifyScalarMethod(false);
226 } else if (test == "custom") {
227 writeJavaArgumentClass(true, javaGeneratedArgumentClasses);
228 writeJavaCheckMethod(true);
229 writeJavaVerifyScalarMethod(true);
230 } else if (test == "vector") {
231 writeJavaArgumentClass(false, javaGeneratedArgumentClasses);
232 writeJavaCheckMethod(true);
233 writeJavaVerifyVectorMethod();
234 } else if (test == "noverify") {
235 writeJavaCheckMethod(false);
236 }
237}
238
239void PermutationWriter::writeJavaArgumentClass(bool scalar,
240 set<string>* javaGeneratedArgumentClasses) const {
241 string name;
242 if (scalar) {
243 name = mJavaArgumentsClassName;
244 } else {
245 name = mJavaArgumentsNClassName;
246 }
247
248 // Make sure we have not generated the argument class already.
249 if (!testAndSet(name, javaGeneratedArgumentClasses)) {
250 mJava->indent() << "public class " << name;
251 mJava->startBlock();
252
253 for (auto p : mAllInputsAndOutputs) {
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -0800254 bool isFieldArray = !scalar && p->mVectorSize != "1";
255 bool isFloatyField = p->isOutParameter && p->isFloatType && mPermutation.getTest() != "custom";
256
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700257 mJava->indent() << "public ";
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -0800258 if (isFloatyField) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700259 *mJava << "Target.Floaty";
260 } else {
261 *mJava << p->javaBaseType;
262 }
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -0800263 if (isFieldArray) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700264 *mJava << "[]";
265 }
266 *mJava << " " << p->variableName << ";\n";
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -0800267
268 // For Float16 parameters, add an extra 'double' field in the class
269 // to hold the Double value converted from the input.
270 if (p->isFloat16Parameter() && !isFloatyField) {
271 mJava->indent() << "public double";
272 if (isFieldArray) {
273 *mJava << "[]";
274 }
275 *mJava << " " + p->variableName << "Double;\n";
276 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700277 }
278 mJava->endBlock();
279 *mJava << "\n";
280 }
281}
282
283void PermutationWriter::writeJavaCheckMethod(bool generateCallToVerifier) const {
284 mJava->indent() << "private void " << mJavaCheckMethodName << "()";
285 mJava->startBlock();
286
287 // Generate the input allocations and initialization.
288 for (auto p : mAllInputsAndOutputs) {
289 if (!p->isOutParameter) {
290 writeJavaInputAllocationDefinition(*p);
291 }
292 }
293 // Generate code to enforce ordering between two allocations if needed.
294 for (auto p : mAllInputsAndOutputs) {
295 if (!p->isOutParameter && !p->smallerParameter.empty()) {
296 string smallerAlloc = "in" + capitalize(p->smallerParameter);
297 mJava->indent() << "enforceOrdering(" << smallerAlloc << ", " << p->javaAllocName
298 << ");\n";
299 }
300 }
301
302 // Generate code to check the full and relaxed scripts.
303 writeJavaCallToRs(false, generateCallToVerifier);
304 writeJavaCallToRs(true, generateCallToVerifier);
305
306 mJava->endBlock();
307 *mJava << "\n";
308}
309
310void PermutationWriter::writeJavaInputAllocationDefinition(const ParameterDefinition& param) const {
311 string dataType;
312 char vectorSize;
313 convertToRsType(param.rsType, &dataType, &vectorSize);
314
315 const string seed = hashString(mJavaCheckMethodName + param.javaAllocName);
316 mJava->indent() << "Allocation " << param.javaAllocName << " = ";
317 if (param.compatibleTypeIndex >= 0) {
318 if (TYPES[param.typeIndex].kind == FLOATING_POINT) {
319 writeJavaRandomCompatibleFloatAllocation(dataType, seed, vectorSize,
320 TYPES[param.compatibleTypeIndex],
321 TYPES[param.typeIndex]);
322 } else {
323 writeJavaRandomCompatibleIntegerAllocation(dataType, seed, vectorSize,
324 TYPES[param.compatibleTypeIndex],
325 TYPES[param.typeIndex]);
326 }
327 } else if (!param.minValue.empty()) {
328 *mJava << "createRandomFloatAllocation(mRS, Element.DataType." << dataType << ", "
329 << vectorSize << ", " << seed << ", " << param.minValue << ", " << param.maxValue
330 << ")";
331 } else {
332 /* TODO Instead of passing always false, check whether we are doing a limited test.
333 * Use instead: (mPermutation.getTest() == "limited" ? "false" : "true")
334 */
335 *mJava << "createRandomAllocation(mRS, Element.DataType." << dataType << ", " << vectorSize
336 << ", " << seed << ", false)";
337 }
338 *mJava << ";\n";
339}
340
341void PermutationWriter::writeJavaRandomCompatibleFloatAllocation(
342 const string& dataType, const string& seed, char vectorSize,
343 const NumericalType& compatibleType, const NumericalType& generatedType) const {
344 *mJava << "createRandomFloatAllocation"
345 << "(mRS, Element.DataType." << dataType << ", " << vectorSize << ", " << seed << ", ";
346 double minValue = 0.0;
347 double maxValue = 0.0;
348 switch (compatibleType.kind) {
349 case FLOATING_POINT: {
350 // We're generating floating point values. We just worry about the exponent.
351 // Subtract 1 for the exponent sign.
352 int bits = min(compatibleType.exponentBits, generatedType.exponentBits) - 1;
353 maxValue = ldexp(0.95, (1 << bits) - 1);
354 minValue = -maxValue;
355 break;
356 }
357 case UNSIGNED_INTEGER:
358 maxValue = maxDoubleForInteger(compatibleType.significantBits,
359 generatedType.significantBits);
360 minValue = 0.0;
361 break;
362 case SIGNED_INTEGER:
363 maxValue = maxDoubleForInteger(compatibleType.significantBits,
364 generatedType.significantBits);
365 minValue = -maxValue - 1.0;
366 break;
367 }
368 *mJava << scientific << std::setprecision(19);
369 *mJava << minValue << ", " << maxValue << ")";
370 mJava->unsetf(ios_base::floatfield);
371}
372
373void PermutationWriter::writeJavaRandomCompatibleIntegerAllocation(
374 const string& dataType, const string& seed, char vectorSize,
375 const NumericalType& compatibleType, const NumericalType& generatedType) const {
376 *mJava << "createRandomIntegerAllocation"
377 << "(mRS, Element.DataType." << dataType << ", " << vectorSize << ", " << seed << ", ";
378
379 if (compatibleType.kind == FLOATING_POINT) {
380 // Currently, all floating points can take any number we generate.
381 bool isSigned = generatedType.kind == SIGNED_INTEGER;
382 *mJava << (isSigned ? "true" : "false") << ", " << generatedType.significantBits;
383 } else {
384 bool isSigned =
385 compatibleType.kind == SIGNED_INTEGER && generatedType.kind == SIGNED_INTEGER;
386 *mJava << (isSigned ? "true" : "false") << ", "
387 << min(compatibleType.significantBits, generatedType.significantBits);
388 }
389 *mJava << ")";
390}
391
392void PermutationWriter::writeJavaOutputAllocationDefinition(
393 const ParameterDefinition& param) const {
394 string dataType;
395 char vectorSize;
396 convertToRsType(param.rsType, &dataType, &vectorSize);
397 mJava->indent() << "Allocation " << param.javaAllocName << " = Allocation.createSized(mRS, "
398 << "getElement(mRS, Element.DataType." << dataType << ", " << vectorSize
399 << "), INPUTSIZE);\n";
400}
401
402void PermutationWriter::writeJavaVerifyScalarMethod(bool verifierValidates) const {
403 writeJavaVerifyMethodHeader();
404 mJava->startBlock();
405
406 string vectorSize = "1";
407 for (auto p : mAllInputsAndOutputs) {
408 writeJavaArrayInitialization(*p);
409 if (p->mVectorSize != "1" && p->mVectorSize != vectorSize) {
410 if (vectorSize == "1") {
411 vectorSize = p->mVectorSize;
412 } else {
413 cerr << "Error. Had vector " << vectorSize << " and " << p->mVectorSize << "\n";
414 }
415 }
416 }
417
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700418 mJava->indent() << "StringBuilder message = new StringBuilder();\n";
419 mJava->indent() << "boolean errorFound = false;\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700420 mJava->indent() << "for (int i = 0; i < INPUTSIZE; i++)";
421 mJava->startBlock();
422
423 mJava->indent() << "for (int j = 0; j < " << vectorSize << " ; j++)";
424 mJava->startBlock();
425
426 mJava->indent() << "// Extract the inputs.\n";
427 mJava->indent() << mJavaArgumentsClassName << " args = new " << mJavaArgumentsClassName
428 << "();\n";
429 for (auto p : mAllInputsAndOutputs) {
430 if (!p->isOutParameter) {
431 mJava->indent() << "args." << p->variableName << " = " << p->javaArrayName << "[i";
432 if (p->vectorWidth != "1") {
433 *mJava << " * " << p->vectorWidth << " + j";
434 }
435 *mJava << "];\n";
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -0800436
437 // Convert the Float16 parameter to double and store it in the appropriate field in the
438 // Arguments class.
439 if (p->isFloat16Parameter()) {
440 mJava->indent() << "args." << p->doubleVariableName
441 << " = Float16Utils.convertFloat16ToDouble(args."
442 << p->variableName << ");\n";
443 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700444 }
445 }
446 const bool hasFloat = mPermutation.hasFloatAnswers();
447 if (verifierValidates) {
448 mJava->indent() << "// Extract the outputs.\n";
449 for (auto p : mAllInputsAndOutputs) {
450 if (p->isOutParameter) {
451 mJava->indent() << "args." << p->variableName << " = " << p->javaArrayName
Jean-Luc Brouillet49736b32015-04-14 14:23:48 -0700452 << "[i * " << p->vectorWidth << " + j];\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700453 }
454 }
455 mJava->indent() << "// Ask the CoreMathVerifier to validate.\n";
456 if (hasFloat) {
Pirama Arumuga Nainar93abc2d2016-02-16 15:11:29 -0800457 writeJavaCreateTarget();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700458 }
459 mJava->indent() << "String errorMessage = CoreMathVerifier."
460 << mJavaVerifierVerifyMethodName << "(args";
461 if (hasFloat) {
462 *mJava << ", target";
463 }
464 *mJava << ");\n";
465 mJava->indent() << "boolean valid = errorMessage == null;\n";
466 } else {
467 mJava->indent() << "// Figure out what the outputs should have been.\n";
468 if (hasFloat) {
Pirama Arumuga Nainar93abc2d2016-02-16 15:11:29 -0800469 writeJavaCreateTarget();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700470 }
471 mJava->indent() << "CoreMathVerifier." << mJavaVerifierComputeMethodName << "(args";
472 if (hasFloat) {
473 *mJava << ", target";
474 }
475 *mJava << ");\n";
476 mJava->indent() << "// Validate the outputs.\n";
477 mJava->indent() << "boolean valid = true;\n";
478 for (auto p : mAllInputsAndOutputs) {
479 if (p->isOutParameter) {
480 writeJavaTestAndSetValid(*p, "", "[i * " + p->vectorWidth + " + j]");
481 }
482 }
483 }
484
485 mJava->indent() << "if (!valid)";
486 mJava->startBlock();
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700487 mJava->indent() << "if (!errorFound)";
488 mJava->startBlock();
489 mJava->indent() << "errorFound = true;\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700490
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700491 for (auto p : mAllInputsAndOutputs) {
492 if (p->isOutParameter) {
493 writeJavaAppendOutputToMessage(*p, "", "[i * " + p->vectorWidth + " + j]",
494 verifierValidates);
495 } else {
496 writeJavaAppendInputToMessage(*p, "args." + p->variableName);
497 }
498 }
499 if (verifierValidates) {
500 mJava->indent() << "message.append(errorMessage);\n";
501 }
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700502 mJava->indent() << "message.append(\"Errors at\");\n";
503 mJava->endBlock();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700504
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700505 mJava->indent() << "message.append(\" [\");\n";
506 mJava->indent() << "message.append(Integer.toString(i));\n";
507 mJava->indent() << "message.append(\", \");\n";
508 mJava->indent() << "message.append(Integer.toString(j));\n";
509 mJava->indent() << "message.append(\"]\");\n";
510
511 mJava->endBlock();
512 mJava->endBlock();
513 mJava->endBlock();
514
515 mJava->indent() << "assertFalse(\"Incorrect output for " << mJavaCheckMethodName << "\" +\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700516 mJava->indentPlus()
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700517 << "(relaxed ? \"_relaxed\" : \"\") + \":\\n\" + message.toString(), errorFound);\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700518
519 mJava->endBlock();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700520 *mJava << "\n";
521}
522
523void PermutationWriter::writeJavaVerifyVectorMethod() const {
524 writeJavaVerifyMethodHeader();
525 mJava->startBlock();
526
527 for (auto p : mAllInputsAndOutputs) {
528 writeJavaArrayInitialization(*p);
529 }
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700530 mJava->indent() << "StringBuilder message = new StringBuilder();\n";
531 mJava->indent() << "boolean errorFound = false;\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700532 mJava->indent() << "for (int i = 0; i < INPUTSIZE; i++)";
533 mJava->startBlock();
534
535 mJava->indent() << mJavaArgumentsNClassName << " args = new " << mJavaArgumentsNClassName
536 << "();\n";
537
538 mJava->indent() << "// Create the appropriate sized arrays in args\n";
539 for (auto p : mAllInputsAndOutputs) {
540 if (p->mVectorSize != "1") {
541 string type = p->javaBaseType;
542 if (p->isOutParameter && p->isFloatType) {
543 type = "Target.Floaty";
544 }
545 mJava->indent() << "args." << p->variableName << " = new " << type << "["
546 << p->mVectorSize << "];\n";
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -0800547 if (p->isFloat16Parameter() && !p->isOutParameter) {
548 mJava->indent() << "args." << p->variableName << "Double = new double["
549 << p->mVectorSize << "];\n";
550 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700551 }
552 }
553
554 mJava->indent() << "// Fill args with the input values\n";
555 for (auto p : mAllInputsAndOutputs) {
556 if (!p->isOutParameter) {
557 if (p->mVectorSize == "1") {
Jean-Luc Brouillet49736b32015-04-14 14:23:48 -0700558 mJava->indent() << "args." << p->variableName << " = " << p->javaArrayName << "[i]"
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700559 << ";\n";
Pirama Arumuga Nainarb7841c42016-03-22 11:50:43 -0700560 // Convert the Float16 parameter to double and store it in the appropriate field in
561 // the Arguments class.
562 if (p->isFloat16Parameter()) {
563 mJava->indent() << "args." << p->doubleVariableName << " = "
564 << "Float16Utils.convertFloat16ToDouble(args."
565 << p->variableName << ");\n";
566 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700567 } else {
568 mJava->indent() << "for (int j = 0; j < " << p->mVectorSize << " ; j++)";
569 mJava->startBlock();
Jean-Luc Brouillet49736b32015-04-14 14:23:48 -0700570 mJava->indent() << "args." << p->variableName << "[j] = "
571 << p->javaArrayName << "[i * " << p->vectorWidth << " + j]"
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700572 << ";\n";
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -0800573
574 // Convert the Float16 parameter to double and store it in the appropriate field in
575 // the Arguments class.
576 if (p->isFloat16Parameter()) {
577 mJava->indent() << "args." << p->doubleVariableName << "[j] = "
578 << "Float16Utils.convertFloat16ToDouble(args."
579 << p->variableName << "[j]);\n";
580 }
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700581 mJava->endBlock();
582 }
583 }
584 }
Pirama Arumuga Nainar93abc2d2016-02-16 15:11:29 -0800585 writeJavaCreateTarget();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700586 mJava->indent() << "CoreMathVerifier." << mJavaVerifierComputeMethodName
587 << "(args, target);\n\n";
588
589 mJava->indent() << "// Compare the expected outputs to the actual values returned by RS.\n";
590 mJava->indent() << "boolean valid = true;\n";
591 for (auto p : mAllInputsAndOutputs) {
592 if (p->isOutParameter) {
593 writeJavaVectorComparison(*p);
594 }
595 }
596
597 mJava->indent() << "if (!valid)";
598 mJava->startBlock();
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700599 mJava->indent() << "if (!errorFound)";
600 mJava->startBlock();
601 mJava->indent() << "errorFound = true;\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700602
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700603 for (auto p : mAllInputsAndOutputs) {
604 if (p->isOutParameter) {
605 writeJavaAppendVectorOutputToMessage(*p);
606 } else {
607 writeJavaAppendVectorInputToMessage(*p);
608 }
609 }
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700610 mJava->indent() << "message.append(\"Errors at\");\n";
611 mJava->endBlock();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700612
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700613 mJava->indent() << "message.append(\" [\");\n";
614 mJava->indent() << "message.append(Integer.toString(i));\n";
615 mJava->indent() << "message.append(\"]\");\n";
616
617 mJava->endBlock();
618 mJava->endBlock();
619
620 mJava->indent() << "assertFalse(\"Incorrect output for " << mJavaCheckMethodName << "\" +\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700621 mJava->indentPlus()
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700622 << "(relaxed ? \"_relaxed\" : \"\") + \":\\n\" + message.toString(), errorFound);\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700623
624 mJava->endBlock();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700625 *mJava << "\n";
626}
627
Pirama Arumuga Nainar93abc2d2016-02-16 15:11:29 -0800628
629void PermutationWriter::writeJavaCreateTarget() const {
630 string name = mPermutation.getName();
631
632 const char* functionType = "NORMAL";
633 size_t end = name.find('_');
634 if (end != string::npos) {
635 if (name.compare(0, end, "native") == 0) {
636 functionType = "NATIVE";
637 } else if (name.compare(0, end, "half") == 0) {
638 functionType = "HALF";
639 } else if (name.compare(0, end, "fast") == 0) {
640 functionType = "FAST";
641 }
642 }
643
644 string floatType = mReturnParam->specType;
645 const char* precisionStr = "";
646 if (floatType.compare("f16") == 0) {
647 precisionStr = "HALF";
648 } else if (floatType.compare("f32") == 0) {
649 precisionStr = "FLOAT";
650 } else if (floatType.compare("f64") == 0) {
651 precisionStr = "DOUBLE";
652 } else {
653 cerr << "Error. Unreachable. Return type is not floating point\n";
654 }
655
656 mJava->indent() << "Target target = new Target(Target.FunctionType." <<
657 functionType << ", Target.ReturnType." << precisionStr <<
658 ", relaxed);\n";
659}
660
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700661void PermutationWriter::writeJavaVerifyMethodHeader() const {
662 mJava->indent() << "private void " << mJavaVerifyMethodName << "(";
663 for (auto p : mAllInputsAndOutputs) {
664 *mJava << "Allocation " << p->javaAllocName << ", ";
665 }
666 *mJava << "boolean relaxed)";
667}
668
669void PermutationWriter::writeJavaArrayInitialization(const ParameterDefinition& p) const {
670 mJava->indent() << p.javaBaseType << "[] " << p.javaArrayName << " = new " << p.javaBaseType
671 << "[INPUTSIZE * " << p.vectorWidth << "];\n";
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700672
673 /* For basic types, populate the array with values, to help understand failures. We have had
674 * bugs where the output buffer was all 0. We were not sure if there was a failed copy or
675 * the GPU driver was copying zeroes.
676 */
677 if (p.typeIndex >= 0) {
678 mJava->indent() << "Arrays.fill(" << p.javaArrayName << ", (" << TYPES[p.typeIndex].javaType
679 << ") 42);\n";
680 }
681
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700682 mJava->indent() << p.javaAllocName << ".copyTo(" << p.javaArrayName << ");\n";
683}
684
685void PermutationWriter::writeJavaTestAndSetValid(const ParameterDefinition& p,
686 const string& argsIndex,
687 const string& actualIndex) const {
688 writeJavaTestOneValue(p, argsIndex, actualIndex);
689 mJava->startBlock();
690 mJava->indent() << "valid = false;\n";
691 mJava->endBlock();
692}
693
694void PermutationWriter::writeJavaTestOneValue(const ParameterDefinition& p, const string& argsIndex,
695 const string& actualIndex) const {
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -0800696 string actualOut;
697 if (p.isFloat16Parameter()) {
698 // For Float16 values, the output needs to be converted to Double.
699 actualOut = "Float16Utils.convertFloat16ToDouble(" + p.javaArrayName + actualIndex + ")";
700 } else {
701 actualOut = p.javaArrayName + actualIndex;
702 }
703
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700704 mJava->indent() << "if (";
705 if (p.isFloatType) {
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -0800706 *mJava << "!args." << p.variableName << argsIndex << ".couldBe(" << actualOut;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700707 const string s = mPermutation.getPrecisionLimit();
708 if (!s.empty()) {
709 *mJava << ", " << s;
710 }
711 *mJava << ")";
712 } else {
713 *mJava << "args." << p.variableName << argsIndex << " != " << p.javaArrayName
714 << actualIndex;
715 }
716
717 if (p.undefinedIfOutIsNan && mReturnParam) {
718 *mJava << " && !args." << mReturnParam->variableName << argsIndex << ".isNaN()";
719 }
720 *mJava << ")";
721}
722
723void PermutationWriter::writeJavaVectorComparison(const ParameterDefinition& p) const {
724 if (p.mVectorSize == "1") {
725 writeJavaTestAndSetValid(p, "", "[i]");
726 } else {
727 mJava->indent() << "for (int j = 0; j < " << p.mVectorSize << " ; j++)";
728 mJava->startBlock();
729 writeJavaTestAndSetValid(p, "[j]", "[i * " + p.vectorWidth + " + j]");
730 mJava->endBlock();
731 }
732}
733
734void PermutationWriter::writeJavaAppendOutputToMessage(const ParameterDefinition& p,
735 const string& argsIndex,
736 const string& actualIndex,
737 bool verifierValidates) const {
738 if (verifierValidates) {
Jean-Luc Brouillet49736b32015-04-14 14:23:48 -0700739 mJava->indent() << "message.append(\"Output " << p.variableName << ": \");\n";
740 mJava->indent() << "appendVariableToMessage(message, args." << p.variableName << argsIndex
741 << ");\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700742 writeJavaAppendNewLineToMessage();
743 } else {
Jean-Luc Brouillet49736b32015-04-14 14:23:48 -0700744 mJava->indent() << "message.append(\"Expected output " << p.variableName << ": \");\n";
745 mJava->indent() << "appendVariableToMessage(message, args." << p.variableName << argsIndex
746 << ");\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700747 writeJavaAppendNewLineToMessage();
Jean-Luc Brouillet49736b32015-04-14 14:23:48 -0700748
749 mJava->indent() << "message.append(\"Actual output " << p.variableName << ": \");\n";
750 mJava->indent() << "appendVariableToMessage(message, " << p.javaArrayName << actualIndex
751 << ");\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700752
Pirama Arumuga Nainar3b2be142016-02-29 13:35:18 -0800753 if (p.isFloat16Parameter()) {
754 writeJavaAppendNewLineToMessage();
755 mJava->indent() << "message.append(\"Actual output " << p.variableName
756 << " (in double): \");\n";
757 mJava->indent() << "appendVariableToMessage(message, Float16Utils.convertFloat16ToDouble("
758 << p.javaArrayName << actualIndex << "));\n";
759 }
760
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700761 writeJavaTestOneValue(p, argsIndex, actualIndex);
762 mJava->startBlock();
763 mJava->indent() << "message.append(\" FAIL\");\n";
764 mJava->endBlock();
765 writeJavaAppendNewLineToMessage();
766 }
767}
768
769void PermutationWriter::writeJavaAppendInputToMessage(const ParameterDefinition& p,
770 const string& actual) const {
Jean-Luc Brouillet49736b32015-04-14 14:23:48 -0700771 mJava->indent() << "message.append(\"Input " << p.variableName << ": \");\n";
772 mJava->indent() << "appendVariableToMessage(message, " << actual << ");\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700773 writeJavaAppendNewLineToMessage();
774}
775
776void PermutationWriter::writeJavaAppendNewLineToMessage() const {
777 mJava->indent() << "message.append(\"\\n\");\n";
778}
779
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700780void PermutationWriter::writeJavaAppendVectorInputToMessage(const ParameterDefinition& p) const {
781 if (p.mVectorSize == "1") {
782 writeJavaAppendInputToMessage(p, p.javaArrayName + "[i]");
783 } else {
784 mJava->indent() << "for (int j = 0; j < " << p.mVectorSize << " ; j++)";
785 mJava->startBlock();
786 writeJavaAppendInputToMessage(p, p.javaArrayName + "[i * " + p.vectorWidth + " + j]");
787 mJava->endBlock();
788 }
789}
790
791void PermutationWriter::writeJavaAppendVectorOutputToMessage(const ParameterDefinition& p) const {
792 if (p.mVectorSize == "1") {
793 writeJavaAppendOutputToMessage(p, "", "[i]", false);
794 } else {
795 mJava->indent() << "for (int j = 0; j < " << p.mVectorSize << " ; j++)";
796 mJava->startBlock();
797 writeJavaAppendOutputToMessage(p, "[j]", "[i * " + p.vectorWidth + " + j]", false);
798 mJava->endBlock();
799 }
800}
801
802void PermutationWriter::writeJavaCallToRs(bool relaxed, bool generateCallToVerifier) const {
803 string script = "script";
804 if (relaxed) {
805 script += "Relaxed";
806 }
807
808 mJava->indent() << "try";
809 mJava->startBlock();
810
811 for (auto p : mAllInputsAndOutputs) {
812 if (p->isOutParameter) {
813 writeJavaOutputAllocationDefinition(*p);
814 }
815 }
816
817 for (auto p : mPermutation.getParams()) {
818 if (p != mFirstInputParam) {
819 mJava->indent() << script << ".set_" << p->rsAllocName << "(" << p->javaAllocName
820 << ");\n";
821 }
822 }
823
824 mJava->indent() << script << ".forEach_" << mRsKernelName << "(";
825 bool needComma = false;
826 if (mFirstInputParam) {
827 *mJava << mFirstInputParam->javaAllocName;
828 needComma = true;
829 }
830 if (mReturnParam) {
831 if (needComma) {
832 *mJava << ", ";
833 }
834 *mJava << mReturnParam->variableName << ");\n";
835 }
836
837 if (generateCallToVerifier) {
838 mJava->indent() << mJavaVerifyMethodName << "(";
839 for (auto p : mAllInputsAndOutputs) {
840 *mJava << p->variableName << ", ";
841 }
842
843 if (relaxed) {
844 *mJava << "true";
845 } else {
846 *mJava << "false";
847 }
848 *mJava << ");\n";
849 }
850 mJava->decreaseIndent();
851 mJava->indent() << "} catch (Exception e) {\n";
852 mJava->increaseIndent();
853 mJava->indent() << "throw new RSRuntimeException(\"RenderScript. Can't invoke forEach_"
854 << mRsKernelName << ": \" + e.toString());\n";
855 mJava->endBlock();
856}
857
858/* Write the section of the .rs file for this permutation.
859 *
860 * We communicate the extra input and output parameters via global allocations.
861 * For example, if we have a function that takes three arguments, two for input
862 * and one for output:
863 *
864 * start:
865 * name: gamn
866 * ret: float3
867 * arg: float3 a
868 * arg: int b
869 * arg: float3 *c
870 * end:
871 *
872 * We'll produce:
873 *
874 * rs_allocation gAllocInB;
875 * rs_allocation gAllocOutC;
876 *
877 * float3 __attribute__((kernel)) test_gamn_float3_int_float3(float3 inA, unsigned int x) {
878 * int inB;
879 * float3 outC;
880 * float2 out;
881 * inB = rsGetElementAt_int(gAllocInB, x);
882 * out = gamn(a, in_b, &outC);
883 * rsSetElementAt_float4(gAllocOutC, &outC, x);
884 * return out;
885 * }
886 *
887 * We avoid re-using x and y from the definition because these have reserved
888 * meanings in a .rs file.
889 */
890void PermutationWriter::writeRsSection(set<string>* rsAllocationsGenerated) const {
891 // Write the allocation declarations we'll need.
892 for (auto p : mPermutation.getParams()) {
893 // Don't need allocation for one input and one return value.
894 if (p != mFirstInputParam) {
895 writeRsAllocationDefinition(*p, rsAllocationsGenerated);
896 }
897 }
898 *mRs << "\n";
899
900 // Write the function header.
901 if (mReturnParam) {
902 *mRs << mReturnParam->rsType;
903 } else {
904 *mRs << "void";
905 }
906 *mRs << " __attribute__((kernel)) " << mRsKernelName;
907 *mRs << "(";
908 bool needComma = false;
909 if (mFirstInputParam) {
910 *mRs << mFirstInputParam->rsType << " " << mFirstInputParam->variableName;
911 needComma = true;
912 }
913 if (mPermutation.getOutputCount() > 1 || mPermutation.getInputCount() > 1) {
914 if (needComma) {
915 *mRs << ", ";
916 }
917 *mRs << "unsigned int x";
918 }
919 *mRs << ")";
920 mRs->startBlock();
921
922 // Write the local variable declarations and initializations.
923 for (auto p : mPermutation.getParams()) {
924 if (p == mFirstInputParam) {
925 continue;
926 }
927 mRs->indent() << p->rsType << " " << p->variableName;
928 if (p->isOutParameter) {
929 *mRs << " = 0;\n";
930 } else {
931 *mRs << " = rsGetElementAt_" << p->rsType << "(" << p->rsAllocName << ", x);\n";
932 }
933 }
934
935 // Write the function call.
936 if (mReturnParam) {
937 if (mPermutation.getOutputCount() > 1) {
938 mRs->indent() << mReturnParam->rsType << " " << mReturnParam->variableName << " = ";
939 } else {
940 mRs->indent() << "return ";
941 }
942 }
943 *mRs << mPermutation.getName() << "(";
944 needComma = false;
945 for (auto p : mPermutation.getParams()) {
946 if (needComma) {
947 *mRs << ", ";
948 }
949 if (p->isOutParameter) {
950 *mRs << "&";
951 }
952 *mRs << p->variableName;
953 needComma = true;
954 }
955 *mRs << ");\n";
956
957 if (mPermutation.getOutputCount() > 1) {
958 // Write setting the extra out parameters into the allocations.
959 for (auto p : mPermutation.getParams()) {
960 if (p->isOutParameter) {
961 mRs->indent() << "rsSetElementAt_" << p->rsType << "(" << p->rsAllocName << ", ";
962 // Check if we need to use '&' for this type of argument.
963 char lastChar = p->variableName.back();
964 if (lastChar >= '0' && lastChar <= '9') {
965 *mRs << "&";
966 }
967 *mRs << p->variableName << ", x);\n";
968 }
969 }
970 if (mReturnParam) {
971 mRs->indent() << "return " << mReturnParam->variableName << ";\n";
972 }
973 }
974 mRs->endBlock();
975}
976
977void PermutationWriter::writeRsAllocationDefinition(const ParameterDefinition& param,
978 set<string>* rsAllocationsGenerated) const {
979 if (!testAndSet(param.rsAllocName, rsAllocationsGenerated)) {
980 *mRs << "rs_allocation " << param.rsAllocName << ";\n";
981 }
982}
983
984// Open the mJavaFile and writes the header.
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700985static bool startJavaFile(GeneratedFile* file, const Function& function, const string& directory,
986 const string& testName, const string& relaxedTestName) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700987 const string fileName = testName + ".java";
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -0700988 if (!file->start(directory, fileName)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -0700989 return false;
990 }
991 file->writeNotices();
992
993 *file << "package android.renderscript.cts;\n\n";
994
995 *file << "import android.renderscript.Allocation;\n";
996 *file << "import android.renderscript.RSRuntimeException;\n";
Pirama Arumuga Nainar93abc2d2016-02-16 15:11:29 -0800997 *file << "import android.renderscript.Element;\n";
998 *file << "import android.renderscript.cts.Target;\n\n";
Jean-Luc Brouillet0c905c82015-07-23 14:03:19 -0700999 *file << "import java.util.Arrays;\n\n";
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001000
1001 *file << "public class " << testName << " extends RSBaseCompute";
1002 file->startBlock(); // The corresponding endBlock() is in finishJavaFile()
1003 *file << "\n";
1004
1005 file->indent() << "private ScriptC_" << testName << " script;\n";
1006 file->indent() << "private ScriptC_" << relaxedTestName << " scriptRelaxed;\n\n";
1007
1008 file->indent() << "@Override\n";
1009 file->indent() << "protected void setUp() throws Exception";
1010 file->startBlock();
1011
1012 file->indent() << "super.setUp();\n";
1013 file->indent() << "script = new ScriptC_" << testName << "(mRS);\n";
1014 file->indent() << "scriptRelaxed = new ScriptC_" << relaxedTestName << "(mRS);\n";
1015
1016 file->endBlock();
1017 *file << "\n";
1018 return true;
1019}
1020
1021// Write the test method that calls all the generated Check methods.
1022static void finishJavaFile(GeneratedFile* file, const Function& function,
1023 const vector<string>& javaCheckMethods) {
1024 file->indent() << "public void test" << function.getCapitalizedName() << "()";
1025 file->startBlock();
1026 for (auto m : javaCheckMethods) {
1027 file->indent() << m << "();\n";
1028 }
1029 file->endBlock();
1030
1031 file->endBlock();
1032}
1033
1034// Open the script file and write its header.
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -07001035static bool startRsFile(GeneratedFile* file, const Function& function, const string& directory,
1036 const string& testName) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001037 string fileName = testName + ".rs";
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -07001038 if (!file->start(directory, fileName)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001039 return false;
1040 }
1041 file->writeNotices();
1042
1043 *file << "#pragma version(1)\n";
1044 *file << "#pragma rs java_package_name(android.renderscript.cts)\n\n";
1045 return true;
1046}
1047
1048// Write the entire *Relaxed.rs test file, as it only depends on the name.
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -07001049static bool writeRelaxedRsFile(const Function& function, const string& directory,
1050 const string& testName, const string& relaxedTestName) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001051 string name = relaxedTestName + ".rs";
1052
1053 GeneratedFile file;
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -07001054 if (!file.start(directory, name)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001055 return false;
1056 }
1057 file.writeNotices();
1058
1059 file << "#include \"" << testName << ".rs\"\n";
1060 file << "#pragma rs_fp_relaxed\n";
1061 file.close();
1062 return true;
1063}
1064
1065/* Write the .java and the two .rs test files. versionOfTestFiles is used to restrict which API
1066 * to test.
1067 */
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -07001068static bool writeTestFilesForFunction(const Function& function, const string& directory,
Yang Ni12398d82015-09-18 14:57:07 -07001069 unsigned int versionOfTestFiles) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001070 // Avoid creating empty files if we're not testing this function.
1071 if (!needTestFiles(function, versionOfTestFiles)) {
1072 return true;
1073 }
1074
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -07001075 const string testName = "Test" + function.getCapitalizedName();
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001076 const string relaxedTestName = testName + "Relaxed";
1077
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -07001078 if (!writeRelaxedRsFile(function, directory, testName, relaxedTestName)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001079 return false;
1080 }
1081
1082 GeneratedFile rsFile; // The Renderscript test file we're generating.
1083 GeneratedFile javaFile; // The Jave test file we're generating.
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -07001084 if (!startRsFile(&rsFile, function, directory, testName)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001085 return false;
1086 }
1087
Jean-Luc Brouillet62e09932015-03-22 11:14:07 -07001088 if (!startJavaFile(&javaFile, function, directory, testName, relaxedTestName)) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001089 return false;
1090 }
1091
1092 /* We keep track of the allocations generated in the .rs file and the argument classes defined
1093 * in the Java file, as we share these between the functions created for each specification.
1094 */
1095 set<string> rsAllocationsGenerated;
1096 set<string> javaGeneratedArgumentClasses;
1097 // Lines of Java code to invoke the check methods.
1098 vector<string> javaCheckMethods;
1099
1100 for (auto spec : function.getSpecifications()) {
1101 if (spec->hasTests(versionOfTestFiles)) {
1102 for (auto permutation : spec->getPermutations()) {
1103 PermutationWriter w(*permutation, &rsFile, &javaFile);
1104 w.writeRsSection(&rsAllocationsGenerated);
1105 w.writeJavaSection(&javaGeneratedArgumentClasses);
1106
1107 // Store the check method to be called.
1108 javaCheckMethods.push_back(w.getJavaCheckMethodName());
1109 }
1110 }
1111 }
1112
1113 finishJavaFile(&javaFile, function, javaCheckMethods);
1114 // There's no work to wrap-up in the .rs file.
1115
1116 rsFile.close();
1117 javaFile.close();
1118 return true;
1119}
1120
Yang Ni12398d82015-09-18 14:57:07 -07001121bool generateTestFiles(const string& directory, unsigned int versionOfTestFiles) {
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001122 bool success = true;
Jean-Luc Brouillet7c078542015-03-23 16:16:08 -07001123 for (auto f : systemSpecification.getFunctions()) {
1124 if (!writeTestFilesForFunction(*f.second, directory, versionOfTestFiles)) {
1125 success = false;
Jean-Luc Brouilletc5184e22015-03-13 13:51:24 -07001126 }
1127 }
1128 return success;
1129}