blob: 812a75532b30191c08ea4a1308dfa419c165f8d9 [file] [log] [blame]
Jason Sams135c4b72013-12-11 18:24:45 -08001/*
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
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -080017/* 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
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -080043#include <math.h>
44#include <stdio.h>
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -080045#include <cctype>
46#include <cstdlib>
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -080047#include <fstream>
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -080048#include <functional>
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -080049#include <iomanip>
Jason Sams135c4b72013-12-11 18:24:45 -080050#include <list>
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -080051#include <map>
52#include <set>
Jean-Luc Brouillet46341432014-02-21 22:49:22 -080053#include <sstream>
Jason Sams135c4b72013-12-11 18:24:45 -080054#include <string>
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -080055#include <vector>
Jason Sams135c4b72013-12-11 18:24:45 -080056
57using namespace std;
58
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -080059namespace {
Jason Sams135c4b72013-12-11 18:24:45 -080060
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -080061const 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";
Jean-Luc Brouillet462e62c2014-12-12 13:42:24 -080080const char* DOX_HEADER =
81 "/** @file\n"
82 " *\n"
83 " */\n\n";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -080084
85class Function;
86class Specification;
87class Permutation;
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -080088struct Type;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -080089
90/* Information about a parameter to a function. The values of all the fields should only be set by
91 * parseParameterDefinition.
92 */
93struct ParameterDefinition {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -080094 string rsType; // The Renderscript type, e.g. "uint3"
95 string rsBaseType; // As above but without the number, e.g. "uint"
96 string javaBaseType; // The type we need to declare in Java, e.g. "unsigned int"
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -070097 string specType; // The type found in the spec, e.g. "f16"
98 bool isFloatType; // True if it's a floating point value
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -080099
100 /* The number of entries in the vector. It should be either "1", "2", "3", or "4". It's also
101 * "1" for scalars.
102 */
103 string mVectorSize;
104 /* The space the vector takes in an array. It's the same as the vector size, except for size
105 * "3", where the width is "4".
106 */
107 string vectorWidth;
108
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800109 string specName; // e.g. x, as found in the spec file
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800110 string variableName; // e.g. inX, used both in .rs and .java
111 string rsAllocName; // e.g. gAllocInX
112 string javaAllocName; // e.g. inX
113 string javaArrayName; // e.g. arrayInX
114
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800115 // If non empty, the mininum and maximum values to be used when generating the test data.
116 string minValue;
117 string maxValue;
118 /* If non empty, contains the name of another parameter that should be smaller or equal to this
119 * parameter, i.e. value(smallerParameter) <= value(this). This is used when testing clamp.
120 */
121 string smallerParameter;
122
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800123 bool isOutParameter; // True if this parameter returns data from the script.
124 bool undefinedIfOutIsNan; // If true, we don't validate if 'out' is NaN.
125
126 int typeIndex; // Index in the TYPES array.
127 int compatibleTypeIndex; // Index in TYPES for which the test data must also fit.
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800128
129 /* Parse the parameter definition found in the spec file. It will generate a name if none
130 * are present in the file. One of the two counts will be incremented, and potentially
131 * used to generate unique names. isReturn is true if we're processing the "return:"
132 * definition.
133 */
134 void parseParameterDefinition(string s, bool isReturn, int* inputCount, int* outputCount);
135};
136
137// An entire spec file and the methods to process it.
138class SpecFile {
Jason Sams135c4b72013-12-11 18:24:45 -0800139public:
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800140 explicit SpecFile(const string& specFileName) : mSpecFileName(specFileName) {}
141 bool process(int versionOfTestFiles);
Jason Sams135c4b72013-12-11 18:24:45 -0800142
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800143private:
144 const string mSpecFileName;
145 // The largest version number that we have found in all the specifications.
146 int mLargestVersionNumber;
147
148 map<string, Function*> mFunctionsMap; // All the known functions.
149 typedef map<string, Function*>::iterator FunctionsIterator;
150
151 bool readSpecFile();
152 Function* getFunction(const string& name);
153 bool generateFiles(int versionOfTestFiles);
154 bool writeAllFunctions(ofstream& headerFile, int versionOfTestFiles);
155};
156
157/* Represents a function, like "clamp". Even though the spec file contains many entries for clamp,
158 * we'll only have one clamp instance.
159 */
160class Function {
161private:
162 string mName; // The lower case name, e.g. native_log
163 string mCapitalizedName; // The capitalized name, e.g. NativeLog
Jean-Luc Brouillet225bdc52015-03-16 14:31:57 -0700164 string mTestName; // e.g. GeneratedTestNativeLog
165 string mRelaxedTestName; // e.g. GeneratedTestNativeLogRelaxed
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800166
167 vector<Specification*> mSpecifications;
168 typedef vector<Specification*>::iterator SpecificationIterator;
169
170 /* We keep track of the allocations generated in the .rs file and the argument classes defined
171 * in the Java file, as we share these between the functions created for each specification.
172 */
173 set<string> mRsAllocationsGenerated;
174 set<string> mJavaGeneratedArgumentClasses;
175
176 string mJavaCallAllCheckMethods; // Lines of Java code to invoke the check methods.
177
178 ofstream mRsFile; // The Renderscript test file we're generating.
179 ofstream mJavaFile; // The Jave test file we're generating.
180
181 bool startRsFile(); // Open the mRsFile and writes its header.
182 bool writeRelaxedRsFile(); // Write the entire relaxed rs test file (an include essentially)
183 bool startJavaFile(); // Open the mJavaFile and writes the header.
184 void finishJavaFile(); // Write the test method and closes the file.
185
186public:
187 explicit Function(const string& name);
188 void addSpecification(Specification* spec) { mSpecifications.push_back(spec); }
189 /* Write the .java and the two .rs test files. versionOfTestFiles is used to restrict which API
190 * to test. Also writes the section of the header file.
191 */
192 bool writeFiles(ofstream& headerFile, int versionOfTestFiles);
193 // Write an allocation and keep track of having it written, so it can be shared.
194 void writeRsAllocationDefinition(const ParameterDefinition& param);
195 // Write an argument class definiton and keep track of having it written, so it can be shared.
196 void writeJavaArgumentClassDefinition(const string& className, const string& definition);
197 // Add a call to mJavaCallAllCheckMethods to be used at the end of the file generation.
198 void addJavaCheckCall(const string& call);
199};
200
201/* Defines one of the many variations of the function. There's a one to one correspondance between
202 * Specification objects and entries in the spec file. Some of the strings that are parts of a
203 * Specification can include placeholders, which are "#1", "#2", "#3", and "#4". We'll replace
204 * these by values before generating the files.
205 */
206class Specification {
207private:
208 /* The range of versions this specification applies to. 0 if there's no restriction, so an API
209 * that became available at 9 and is still valid would have min:9 max:0.
210 */
Jason Sams135c4b72013-12-11 18:24:45 -0800211 int mMinVersion;
212 int mMaxVersion;
213
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800214 /* The name of the function without #n, e.g. convert. As of this writing, it only differs for
215 * convert.
216 */
217 string mCleanName;
Jean-Luc Brouillet93906642014-07-23 21:25:45 -0700218 /* How to test. One of:
219 * "scalar": Generate test code that checks entries of each vector indepently. E.g. for
220 * sin(float3), the test code will call the CoreMathVerfier.computeSin 3 times.
221 * "vector": Generate test code that calls the CoreMathVerifier only once for each vector.
222 * This is useful for APIs like dot() or length().
223 * "noverify": Generate test code that calls the API but don't verify the returned value.
224 * "limited": Like "scalar" but tests a limited range of input values.
225 * "custom": Like "scalar" but instead of calling CoreMathVerifier.computeXXX() to compute
226 * the expected value, we call instead CoreMathVerifier.verifyXXX(). This method
227 * returns a string that contains the error message, null if there's no error.
228 */
229 string mTest;
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800230 string mPrecisionLimit; // Maximum precision required when checking output of this function.
Jason Sams135c4b72013-12-11 18:24:45 -0800231
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800232 vector<vector<string> > mReplaceables;
233
234 // The following fields may contain placeholders that will be replaced using the mReplaceables.
235
236 // The name of this function, can include #, e.g. convert_#1_#2
237 string mName;
238
239 string mReturn; // The return type
240 vector<string> mComment; // The comments to be included in the header
241 vector<string> mInline; // The inline code to be included in the header
242 vector<string> mParam; // One entry per parameter defined
243
244 // Substitute the placeholders in the strings by the corresponding entries in mReplaceables.
245 string expandString(string s, int i1, int i2, int i3, int i4) const;
246 void expandStringVector(const vector<string>& in, int i1, int i2, int i3, int i4,
247 vector<string>* out) const;
248
249public:
250 Specification() {
251 mMinVersion = 0;
252 mMaxVersion = 0;
253 }
254 int getMinVersion() const { return mMinVersion; }
255 int getMaxVersion() const { return mMaxVersion; }
256
257 string getName(int i1, int i2, int i3, int i4) const {
258 return expandString(mName, i1, i2, i3, i4);
259 }
260 string getReturn(int i1, int i2, int i3, int i4) const {
261 return expandString(mReturn, i1, i2, i3, i4);
262 }
263 void getComments(int i1, int i2, int i3, int i4, vector<string>* comments) const {
264 return expandStringVector(mComment, i1, i2, i3, i4, comments);
265 }
266 void getInlines(int i1, int i2, int i3, int i4, vector<string>* inlines) const {
267 return expandStringVector(mInline, i1, i2, i3, i4, inlines);
268 }
269 void getParams(int i1, int i2, int i3, int i4, vector<string>* params) const {
270 return expandStringVector(mParam, i1, i2, i3, i4, params);
271 }
272 string getTest() const { return mTest; }
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800273 string getPrecisionLimit() const { return mPrecisionLimit; }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800274 string getCleanName() const { return mCleanName; }
275
276 void writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile, Function* function,
277 int versionOfTestFiles);
278 bool writeRelaxedRsFile() const;
279 // Return true if this specification should be generated for this version.
280 bool relevantForVersion(int versionOfTestFiles) const;
281
282 static Specification* scanSpecification(FILE* in);
Jason Sams135c4b72013-12-11 18:24:45 -0800283};
284
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800285// A concrete version of a specification, where all placeholders have been replaced by actual
286// values.
287class Permutation {
288private:
289 Function* mFunction;
290 Specification* mSpecification;
Jason Sams135c4b72013-12-11 18:24:45 -0800291
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800292 // These are the expanded version of those found on Specification
293 string mName;
294 string mCleanName;
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800295 string mTest; // How to test. One of "scalar", "vector", "noverify", "limited", and "none".
296 string mPrecisionLimit; // Maximum precision required when checking output of this function.
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800297 vector<string> mInline;
298 vector<string> mComment;
299
300 // The inputs and outputs of the function. This include the return type, if present.
301 vector<ParameterDefinition*> mParams;
302 // The index of the return value in mParams, -1 if the function is void.
303 int mReturnIndex;
304 // The index of the first input value in mParams, -1 if there's no input.
305 int mFirstInputIndex;
306 // The number of input and output parameters.
307 int mInputCount;
308 int mOutputCount;
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -0700309 // Whether one of the output parameters is a float.
310 bool mHasFloatAnswers;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800311
312 string mRsKernelName;
313 string mJavaArgumentsClassName;
314 string mJavaArgumentsNClassName;
315 string mJavaVerifierComputeMethodName;
Jean-Luc Brouillet93906642014-07-23 21:25:45 -0700316 string mJavaVerifierVerifyMethodName;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800317 string mJavaCheckMethodName;
318 string mJavaVerifyMethodName;
319
320 void writeHeaderSection(ofstream& file) const;
321
322 void writeRsSection(ofstream& rs) const;
323
324 void writeJavaSection(ofstream& file) const;
325 void writeJavaArgumentClass(ofstream& file, bool scalar) const;
Jean-Luc Brouillet93906642014-07-23 21:25:45 -0700326 void writeJavaCheckMethod(ofstream& file, bool generateCallToVerifier) const;
327 void writeJavaVerifyScalarMethod(ofstream& file, bool verifierValidates) const;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800328 void writeJavaVerifyVectorMethod(ofstream& file) const;
329 void writeJavaVerifyFunctionHeader(ofstream& file) const;
330 void writeJavaInputAllocationDefinition(ofstream& file, const string& indent,
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800331 const ParameterDefinition& param) const;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800332 void writeJavaOutputAllocationDefinition(ofstream& file, const string& indent,
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800333 const ParameterDefinition& param) const;
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800334 // Write code to create a random allocation for which the data must be compatible for two types.
335 void writeJavaRandomCompatibleFloatAllocation(ofstream& file, const string& dataType,
336 const string& seed, char vectorSize,
337 const Type& compatibleType,
338 const Type& generatedType) const;
339 void writeJavaRandomCompatibleIntegerAllocation(ofstream& file, const string& dataType,
340 const string& seed, char vectorSize,
341 const Type& compatibleType,
342 const Type& generatedType) const;
Jean-Luc Brouillet93906642014-07-23 21:25:45 -0700343 void writeJavaCallToRs(ofstream& file, bool relaxed, bool generateCallToVerifier) const;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800344
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800345 void writeJavaTestAndSetValid(ofstream& file, int indent, const ParameterDefinition& p,
346 const string& argsIndex, const string& actualIndex) const;
347 void writeJavaTestOneValue(ofstream& file, int indent, const ParameterDefinition& p,
348 const string& argsIndex, const string& actualIndex) const;
349 void writeJavaAppendOutputToMessage(ofstream& file, int indent, const ParameterDefinition& p,
Jean-Luc Brouillet93906642014-07-23 21:25:45 -0700350 const string& argsIndex, const string& actualIndex,
351 bool verifierValidates) const;
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -0700352 void writeJavaAppendInputToMessage(ofstream& file, int indent, const ParameterDefinition& p,
353 const string& actual) const;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800354 void writeJavaAppendNewLineToMessage(ofstream& file, int indent) const;
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -0700355 void writeJavaAppendVariableToMessage(ofstream& file, int indent, const ParameterDefinition& p,
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800356 const string& value) const;
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -0700357 void writeJavaAppendFloatVariableToMessage(ofstream& file, int indent, const string& value,
358 bool regularFloat) const;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800359 void writeJavaVectorComparison(ofstream& file, int indent, const ParameterDefinition& p) const;
360 void writeJavaAppendVectorInputToMessage(ofstream& file, int indent,
361 const ParameterDefinition& p) const;
362 void writeJavaAppendVectorOutputToMessage(ofstream& file, int indent,
363 const ParameterDefinition& p) const;
364 bool passByAddressToSet(const string& name) const;
365 void convertToRsType(const string& name, string* dataType, char* vectorSize) const;
366
367public:
368 Permutation(Function* function, Specification* specification, int i1, int i2, int i3, int i4);
369 void writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile,
370 int versionOfTestFiles);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800371};
372
373// Table of type equivalences
374// TODO: We should just be pulling this from a shared header. Slang does exactly the same thing.
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800375
376enum NumberKind { SIGNED_INTEGER, UNSIGNED_INTEGER, FLOATING_POINT };
377
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800378struct Type {
379 const char* specType; // Name found in the .spec file
380 string rsDataType; // RS data type
381 string cType; // Type in a C file
382 const char* javaType; // Type in a Java file
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800383 NumberKind kind;
384 /* For integers, number of bits of the number, excluding the sign bit.
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -0700385 * For floats, number of implied bits of the mantissa.
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800386 */
387 int significantBits;
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -0700388 // For floats, number of bits of the exponent. 0 for integer types.
389 int exponentBits;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800390};
391
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -0700392const Type TYPES[] = {{"f16", "FLOAT_16", "half", "half", FLOATING_POINT, 11, 5},
393 {"f32", "FLOAT_32", "float", "float", FLOATING_POINT, 24, 8},
394 {"f64", "FLOAT_64", "double", "double", FLOATING_POINT, 53, 11},
395 {"i8", "SIGNED_8", "char", "byte", SIGNED_INTEGER, 7, 0},
396 {"u8", "UNSIGNED_8", "uchar", "byte", UNSIGNED_INTEGER, 8, 0},
397 {"i16", "SIGNED_16", "short", "short", SIGNED_INTEGER, 15, 0},
398 {"u16", "UNSIGNED_16", "ushort", "short", UNSIGNED_INTEGER, 16, 0},
399 {"i32", "SIGNED_32", "int", "int", SIGNED_INTEGER, 31, 0},
400 {"u32", "UNSIGNED_32", "uint", "int", UNSIGNED_INTEGER, 32, 0},
401 {"i64", "SIGNED_64", "long", "long", SIGNED_INTEGER, 63, 0},
402 {"u64", "UNSIGNED_64", "ulong", "long", UNSIGNED_INTEGER, 64, 0}};
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800403
404const int NUM_TYPES = sizeof(TYPES) / sizeof(TYPES[0]);
405
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800406// Returns the index in TYPES for the provided cType
407int FindCType(const string& cType) {
408 for (int i = 0; i < NUM_TYPES; i++) {
409 if (cType == TYPES[i].cType) {
410 return i;
411 }
412 }
413 return -1;
414}
415
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800416// Capitalizes and removes underscores. E.g. converts "native_log" to NativeLog.
417string capitalize(const string& source) {
418 int length = source.length();
419 string result;
420 bool capitalize = true;
421 for (int s = 0; s < length; s++) {
422 if (source[s] == '_') {
423 capitalize = true;
424 } else if (capitalize) {
425 result += toupper(source[s]);
426 capitalize = false;
427 } else {
428 result += source[s];
429 }
430 }
431 return result;
432}
433
434string tab(int n) { return string(n * 4, ' '); }
435
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800436// Returns a string that's an hexadecimal constant fo the hash of the string.
437string hashString(const string& s) {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800438 long hash = 0;
439 for (size_t i = 0; i < s.length(); i++) {
440 hash = hash * 43 + s[i];
441 }
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800442 stringstream stream;
443 stream << "0x" << std::hex << hash << "l";
444 return stream.str();
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800445}
446
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800447// Removes the character from present. Returns true if the string contained the character.
448static bool charRemoved(char c, string* s) {
449 size_t p = s->find(c);
450 if (p != string::npos) {
451 s->erase(p, 1);
452 return true;
453 }
454 return false;
455}
456
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800457// Return true if the string is already in the set. Inserts it if not.
458bool testAndSet(const string& flag, set<string>* set) {
459 if (set->find(flag) == set->end()) {
460 set->insert(flag);
461 return false;
Jason Sams135c4b72013-12-11 18:24:45 -0800462 }
463 return true;
464}
465
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800466// Convert an int into a string.
467string toString(int n) {
468 char buf[100];
469 snprintf(buf, sizeof(buf), "%d", n);
470 return string(buf);
471}
472
473void trim(string* s, size_t start) {
Jason Sams135c4b72013-12-11 18:24:45 -0800474 if (start > 0) {
475 s->erase(0, start);
476 }
477
478 while (s->size() && (s->at(0) == ' ')) {
479 s->erase(0, 1);
480 }
481
482 size_t p = s->find_first_of("\n\r");
483 if (p != string::npos) {
484 s->erase(p);
485 }
486
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800487 while ((s->size() > 0) && (s->at(s->size() - 1) == ' ')) {
488 s->erase(s->size() - 1);
Jason Sams135c4b72013-12-11 18:24:45 -0800489 }
490}
491
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800492string stringReplace(string s, string match, string rep) {
493 while (1) {
494 size_t p = s.find(match);
495 if (p == string::npos) break;
496
497 s.erase(p, match.size());
498 s.insert(p, rep);
499 }
500 return s;
501}
502
503// Return the next line from the input file.
504bool getNextLine(FILE* in, string* s) {
505 s->clear();
506 while (1) {
507 int c = fgetc(in);
508 if (c == EOF) return s->size() != 0;
509 if (c == '\n') break;
510 s->push_back((char)c);
511 }
512 return true;
513}
514
515void writeIfdef(ofstream& file, string filename, bool isStart) {
516 string t = "__";
517 t += filename;
518 t += "__";
519
520 for (size_t i = 2; i < t.size(); i++) {
521 if (t[i] == '.') {
522 t[i] = '_';
523 }
524 }
525
526 if (isStart) {
527 file << "#ifndef " << t << "\n";
528 file << "#define " << t << "\n";
529 } else {
530 file << "#endif // " << t << "\n";
531 }
532}
533
534void writeJavaArrayInitialization(ofstream& file, const ParameterDefinition& p) {
535 file << tab(2) << p.javaBaseType << "[] " << p.javaArrayName << " = new " << p.javaBaseType
536 << "[INPUTSIZE * " << p.vectorWidth << "];\n";
537 file << tab(2) << p.javaAllocName << ".copyTo(" << p.javaArrayName << ");\n";
538}
539
540bool parseCommandLine(int argc, char* argv[], int* versionOfTestFiles,
541 vector<string>* specFileNames) {
542 for (int i = 1; i < argc; i++) {
543 if (argv[i][0] == '-') {
544 if (argv[i][1] == 'v') {
545 i++;
546 if (i < argc) {
547 char* end;
548 *versionOfTestFiles = strtol(argv[i], &end, 10);
549 if (*end != '\0') {
550 printf("Can't parse the version number %s\n", argv[i]);
551 return false;
552 }
553 } else {
554 printf("Missing version number after -v\n");
555 return false;
556 }
557 } else {
558 printf("Unrecognized flag %s\n", argv[i]);
559 return false;
560 }
561 } else {
562 specFileNames->push_back(argv[i]);
563 }
564 }
565 if (specFileNames->size() == 0) {
566 printf("No spec file specified\n");
567 return false;
568 }
569 return true;
570}
571
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -0700572/* Returns a double that should be able to be converted to an integer of size
573 * numberOfIntegerBits.
574 */
575static double MaxDoubleForInteger(int numberOfIntegerBits, int mantissaSize) {
576 /* Double has only 52 bits of precision (53 implied). So for longs, we want
577 * to create smaller values to avoid a round up. Same for floats and halfs.
578 */
579 int lowZeroBits = max(0, numberOfIntegerBits - mantissaSize);
580 unsigned long l = (0xffffffffffffffff >> (64 - numberOfIntegerBits + lowZeroBits))
581 << lowZeroBits;
582 return (double)l;
583}
584
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800585/* Parse a parameter definition. It's of the form "type [*][name]". The type
586 * is required. The name is optional. The * indicates it's an output
587 * parameter. We also pass the indexed of this parameter in the definition, so
588 * we can create names like in2, in3, etc. */
589void ParameterDefinition::parseParameterDefinition(string s, bool isReturn, int* inputCount,
590 int* outputCount) {
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800591 istringstream stream(s);
592 string name, type, option;
593 stream >> rsType;
594 stream >> specName;
595 stream >> option;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800596
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800597 // Determine if this is an output.
598 isOutParameter = charRemoved('*', &rsType) || charRemoved('*', &specName) || isReturn;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800599
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800600 // Extract the vector size out of the type.
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800601 int last = rsType.size() - 1;
602 char lastChar = rsType[last];
603 if (lastChar >= '0' && lastChar <= '9') {
604 rsBaseType = rsType.substr(0, last);
605 mVectorSize = lastChar;
606 } else {
607 rsBaseType = rsType;
608 mVectorSize = "1";
609 }
610 if (mVectorSize == "3") {
611 vectorWidth = "4";
612 } else {
613 vectorWidth = mVectorSize;
614 }
615
616 /* Create variable names to be used in the java and .rs files. Because x and
617 * y are reserved in .rs files, we prefix variable names with "in" or "out".
618 */
619 if (isOutParameter) {
620 variableName = "out";
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800621 if (!specName.empty()) {
622 variableName += capitalize(specName);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800623 } else if (!isReturn) {
624 variableName += toString(*outputCount);
625 }
626 (*outputCount)++;
627 } else {
628 variableName = "in";
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800629 if (!specName.empty()) {
630 variableName += capitalize(specName);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800631 } else if (*inputCount > 0) {
632 variableName += toString(*inputCount);
633 }
634 (*inputCount)++;
635 }
636 rsAllocName = "gAlloc" + capitalize(variableName);
637 javaAllocName = variableName;
638 javaArrayName = "array" + capitalize(javaAllocName);
639
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800640 // Process the option.
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800641 undefinedIfOutIsNan = false;
642 compatibleTypeIndex = -1;
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800643 if (!option.empty()) {
644 if (option.compare(0, 6, "range(") == 0) {
645 size_t pComma = option.find(',');
646 size_t pParen = option.find(')');
647 if (pComma == string::npos || pParen == string::npos) {
648 printf("Incorrect range %s\n", option.c_str());
649 } else {
650 minValue = option.substr(6, pComma - 6);
651 maxValue = option.substr(pComma + 1, pParen - pComma - 1);
652 }
653 } else if (option.compare(0, 6, "above(") == 0) {
654 size_t pParen = option.find(')');
655 if (pParen == string::npos) {
656 printf("Incorrect option %s\n", option.c_str());
657 } else {
658 smallerParameter = option.substr(6, pParen - 6);
659 }
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800660 } else if (option.compare(0, 11, "compatible(") == 0) {
661 size_t pParen = option.find(')');
662 if (pParen == string::npos) {
663 printf("Incorrect option %s\n", option.c_str());
664 } else {
665 compatibleTypeIndex = FindCType(option.substr(11, pParen - 11));
666 }
667 } else if (option.compare(0, 11, "conditional") == 0) {
668 undefinedIfOutIsNan = true;
Jean-Luc Brouillet46341432014-02-21 22:49:22 -0800669 } else {
670 printf("Unrecognized option %s\n", option.c_str());
671 }
672 }
673
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800674 typeIndex = FindCType(rsBaseType);
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -0700675 isFloatType = false;
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800676 if (typeIndex < 0) {
677 // TODO set a global flag when we encounter an error & abort
678 printf("Error, could not find %s\n", rsBaseType.c_str());
679 } else {
680 javaBaseType = TYPES[typeIndex].javaType;
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -0700681 specType = TYPES[typeIndex].specType;
682 isFloatType = TYPES[typeIndex].exponentBits > 0;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800683 }
684}
685
686bool SpecFile::process(int versionOfTestFiles) {
687 if (!readSpecFile()) {
688 return false;
689 }
690 if (versionOfTestFiles == 0) {
691 versionOfTestFiles = mLargestVersionNumber;
692 }
693 if (!generateFiles(versionOfTestFiles)) {
694 return false;
695 }
696 printf("%s: %ld functions processed.\n", mSpecFileName.c_str(), mFunctionsMap.size());
697 return true;
698}
699
700// Read the specification, adding the definitions to the global functions map.
701bool SpecFile::readSpecFile() {
702 FILE* specFile = fopen(mSpecFileName.c_str(), "rt");
703 if (!specFile) {
704 printf("Error opening input file: %s\n", mSpecFileName.c_str());
705 return false;
706 }
707
708 mLargestVersionNumber = 0;
709 while (1) {
710 Specification* spec = Specification::scanSpecification(specFile);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700711 if (spec == nullptr) {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800712 break;
713 }
714 getFunction(spec->getCleanName())->addSpecification(spec);
715 int specMin = spec->getMinVersion();
716 int specMax = spec->getMaxVersion();
717 if (specMin && specMin > mLargestVersionNumber) {
718 mLargestVersionNumber = specMin;
719 }
720 if (specMax && specMax > mLargestVersionNumber) {
721 mLargestVersionNumber = specMax;
722 }
723 }
724
725 fclose(specFile);
726 return true;
727}
728
729bool SpecFile::generateFiles(int versionOfTestFiles) {
730 printf("%s: Generating test files for version %d\n", mSpecFileName.c_str(), versionOfTestFiles);
731
732 // The header file name should have the same base but with a ".rsh" extension.
733 string headerFileName = mSpecFileName;
734 size_t l = headerFileName.length();
735 const char SPEC[] = ".spec";
736 const int SPEC_SIZE = sizeof(SPEC) - 1;
737 const int start = l - SPEC_SIZE;
738 if (start >= 0 && headerFileName.compare(start, SPEC_SIZE, SPEC) == 0) {
739 headerFileName.erase(start);
740 }
741 headerFileName += ".rsh";
742
743 // Write the start of the header file.
744 ofstream headerFile;
745 headerFile.open(headerFileName.c_str(), ios::out | ios::trunc);
746 if (!headerFile.is_open()) {
747 printf("Error opening output file: %s\n", headerFileName.c_str());
748 return false;
749 }
750 headerFile << LEGAL_NOTICE;
751 headerFile << AUTO_GENERATED_WARNING;
Jean-Luc Brouillet462e62c2014-12-12 13:42:24 -0800752 headerFile << DOX_HEADER;
753
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800754 writeIfdef(headerFile, headerFileName, true);
755
756 // Write the functions to the header and test files.
757 bool success = writeAllFunctions(headerFile, versionOfTestFiles);
758
759 // Finish the header file.
760 writeIfdef(headerFile, headerFileName, false);
761 headerFile.close();
762
763 return success;
764}
765
766// Return the named function from the map. Creates it if it's not there.
767Function* SpecFile::getFunction(const string& name) {
768 FunctionsIterator iter = mFunctionsMap.find(name);
769 if (iter != mFunctionsMap.end()) {
770 return iter->second;
771 }
772 Function* f = new Function(name);
773 mFunctionsMap[name] = f;
774 return f;
775}
776
777bool SpecFile::writeAllFunctions(ofstream& headerFile, int versionOfTestFiles) {
778 bool success = true;
779 for (FunctionsIterator iter = mFunctionsMap.begin(); iter != mFunctionsMap.end(); iter++) {
780 Function* func = iter->second;
781 if (!func->writeFiles(headerFile, versionOfTestFiles)) {
782 success = false;
783 }
784 }
785 return success;
786}
787
788Function::Function(const string& name) {
789 mName = name;
790 mCapitalizedName = capitalize(mName);
Jean-Luc Brouillet225bdc52015-03-16 14:31:57 -0700791 mTestName = "GeneratedTest" + mCapitalizedName;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800792 mRelaxedTestName = mTestName + "Relaxed";
793}
794
795bool Function::writeFiles(ofstream& headerFile, int versionOfTestFiles) {
796 if (!startRsFile() || !startJavaFile() || !writeRelaxedRsFile()) {
797 return false;
798 }
799
800 for (SpecificationIterator i = mSpecifications.begin(); i < mSpecifications.end(); i++) {
801 (*i)->writeFiles(headerFile, mRsFile, mJavaFile, this, versionOfTestFiles);
802 }
803
804 finishJavaFile();
805 // There's no work to wrap-up in the .rs file.
806
807 mRsFile.close();
808 mJavaFile.close();
809 return true;
810}
811
812bool Function::startRsFile() {
813 string fileName = mTestName + ".rs";
814 mRsFile.open(fileName.c_str(), ios::out | ios::trunc);
815 if (!mRsFile.is_open()) {
816 printf("Error opening file: %s\n", fileName.c_str());
817 return false;
818 }
819 mRsFile << LEGAL_NOTICE;
820 mRsFile << "#pragma version(1)\n";
821 mRsFile << "#pragma rs java_package_name(android.renderscript.cts)\n\n";
822 mRsFile << AUTO_GENERATED_WARNING;
823 return true;
824}
825
826// Write an allocation definition if not already emitted in the .rs file.
827void Function::writeRsAllocationDefinition(const ParameterDefinition& param) {
828 if (!testAndSet(param.rsAllocName, &mRsAllocationsGenerated)) {
829 mRsFile << "rs_allocation " << param.rsAllocName << ";\n";
830 }
831}
832
833// Write the entire *Relaxed.rs test file, as it only depends on the name.
834bool Function::writeRelaxedRsFile() {
835 string name = mRelaxedTestName + ".rs";
836 FILE* file = fopen(name.c_str(), "wt");
837 if (!file) {
838 printf("Error opening file: %s\n", name.c_str());
839 return false;
840 }
841 fputs(LEGAL_NOTICE, file);
842 string s;
843 s += "#include \"" + mTestName + ".rs\"\n";
844 s += "#pragma rs_fp_relaxed\n";
845 s += AUTO_GENERATED_WARNING;
846 fputs(s.c_str(), file);
847 fclose(file);
848 return true;
849}
850
851bool Function::startJavaFile() {
852 string fileName = mTestName + ".java";
853 mJavaFile.open(fileName.c_str(), ios::out | ios::trunc);
854 if (!mJavaFile.is_open()) {
855 printf("Error opening file: %s\n", fileName.c_str());
856 return false;
857 }
858 mJavaFile << LEGAL_NOTICE;
859 mJavaFile << AUTO_GENERATED_WARNING;
860 mJavaFile << "package android.renderscript.cts;\n\n";
861
862 mJavaFile << "import android.renderscript.Allocation;\n";
863 mJavaFile << "import android.renderscript.RSRuntimeException;\n";
864 mJavaFile << "import android.renderscript.Element;\n\n";
865
866 mJavaFile << "public class " << mTestName << " extends RSBaseCompute {\n\n";
867
868 mJavaFile << tab(1) << "private ScriptC_" << mTestName << " script;\n";
869 mJavaFile << tab(1) << "private ScriptC_" << mRelaxedTestName << " scriptRelaxed;\n\n";
870
871 mJavaFile << tab(1) << "@Override\n";
872 mJavaFile << tab(1) << "protected void setUp() throws Exception {\n";
873 mJavaFile << tab(2) << "super.setUp();\n";
874 mJavaFile << tab(2) << "script = new ScriptC_" << mTestName << "(mRS);\n";
875 mJavaFile << tab(2) << "scriptRelaxed = new ScriptC_" << mRelaxedTestName << "(mRS);\n";
876 mJavaFile << tab(1) << "}\n\n";
877 return true;
878}
879
880void Function::writeJavaArgumentClassDefinition(const string& className, const string& definition) {
881 if (!testAndSet(className, &mJavaGeneratedArgumentClasses)) {
882 mJavaFile << definition;
883 }
884}
885
886void Function::addJavaCheckCall(const string& call) {
887 mJavaCallAllCheckMethods += tab(2) + call + "\n";
888}
889
890void Function::finishJavaFile() {
891 mJavaFile << tab(1) << "public void test" << mCapitalizedName << "() {\n";
892 mJavaFile << mJavaCallAllCheckMethods;
893 mJavaFile << tab(1) << "}\n";
894 mJavaFile << "}\n";
895}
896
897void Specification::expandStringVector(const vector<string>& in, int i1, int i2, int i3, int i4,
898 vector<string>* out) const {
899 out->clear();
900 for (vector<string>::const_iterator iter = in.begin(); iter != in.end(); iter++) {
901 out->push_back(expandString(*iter, i1, i2, i3, i4));
902 }
903}
904
905Specification* Specification::scanSpecification(FILE* in) {
906 Specification* spec = new Specification();
907 spec->mTest = "scalar"; // default
Jason Sams135c4b72013-12-11 18:24:45 -0800908 bool modeComment = false;
909 bool modeInline = false;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800910 bool success = true;
Jason Sams135c4b72013-12-11 18:24:45 -0800911
912 while (1) {
913 string s;
914 bool ret = getNextLine(in, &s);
915 if (!ret) break;
916
917 if (modeComment) {
918 if (!s.size() || (s[0] == ' ')) {
919 trim(&s, 0);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800920 spec->mComment.push_back(s);
Jason Sams135c4b72013-12-11 18:24:45 -0800921 continue;
922 } else {
923 modeComment = false;
924 }
925 }
926
927 if (modeInline) {
928 if (!s.size() || (s[0] == ' ')) {
929 trim(&s, 0);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800930 spec->mInline.push_back(s);
Jason Sams135c4b72013-12-11 18:24:45 -0800931 continue;
932 } else {
933 modeInline = false;
934 }
935 }
936
937 if (s[0] == '#') {
938 continue;
939 }
940
941 if (s.compare(0, 5, "name:") == 0) {
942 trim(&s, 5);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800943 spec->mName = s;
944 // Some functions like convert have # part of the name. Truncate at that point.
945 size_t p = s.find('#');
946 if (p != string::npos) {
947 if (p > 0 && s[p - 1] == '_') {
948 p--;
949 }
950 s.erase(p);
951 }
952 spec->mCleanName = s;
Jason Sams135c4b72013-12-11 18:24:45 -0800953 continue;
954 }
955
956 if (s.compare(0, 4, "arg:") == 0) {
957 trim(&s, 4);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800958 spec->mParam.push_back(s);
Jason Sams135c4b72013-12-11 18:24:45 -0800959 continue;
960 }
961
962 if (s.compare(0, 4, "ret:") == 0) {
963 trim(&s, 4);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800964 spec->mReturn = s;
965 continue;
966 }
967
968 if (s.compare(0, 5, "test:") == 0) {
969 trim(&s, 5);
Jean-Luc Brouillet93906642014-07-23 21:25:45 -0700970 if (s == "scalar" || s == "vector" || s == "noverify" || s == "custom" || s == "none") {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800971 spec->mTest = s;
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800972 } else if (s.compare(0, 7, "limited") == 0) {
973 spec->mTest = "limited";
974 if (s.compare(7, 1, "(") == 0) {
975 size_t pParen = s.find(')');
976 if (pParen == string::npos) {
977 printf("Incorrect test %s\n", s.c_str());
978 } else {
979 spec->mPrecisionLimit = s.substr(8, pParen - 8);
980 }
981 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800982 } else {
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -0800983 printf("Error: Unrecognized test option: %s\n", s.c_str());
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800984 success = false;
985 }
Jason Sams135c4b72013-12-11 18:24:45 -0800986 continue;
987 }
988
989 if (s.compare(0, 4, "end:") == 0) {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800990 if (success) {
991 return spec;
992 } else {
993 delete spec;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700994 return nullptr;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -0800995 }
Jason Sams135c4b72013-12-11 18:24:45 -0800996 }
997
998 if (s.compare(0, 8, "comment:") == 0) {
999 modeComment = true;
1000 continue;
1001 }
1002
1003 if (s.compare(0, 7, "inline:") == 0) {
1004 modeInline = true;
1005 continue;
1006 }
1007
1008 if (s.compare(0, 8, "version:") == 0) {
1009 trim(&s, 8);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001010 sscanf(s.c_str(), "%i %i", &spec->mMinVersion, &spec->mMaxVersion);
Jason Sams135c4b72013-12-11 18:24:45 -08001011 continue;
1012 }
1013
1014 if (s.compare(0, 8, "start:") == 0) {
1015 continue;
1016 }
1017
1018 if (s.compare(0, 2, "w:") == 0) {
1019 vector<string> t;
1020 if (s.find("1") != string::npos) {
1021 t.push_back("");
1022 }
1023 if (s.find("2") != string::npos) {
1024 t.push_back("2");
1025 }
1026 if (s.find("3") != string::npos) {
1027 t.push_back("3");
1028 }
1029 if (s.find("4") != string::npos) {
1030 t.push_back("4");
1031 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001032 spec->mReplaceables.push_back(t);
Jason Sams135c4b72013-12-11 18:24:45 -08001033 continue;
1034 }
1035
1036 if (s.compare(0, 2, "t:") == 0) {
1037 vector<string> t;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001038 for (int i = 0; i < NUM_TYPES; i++) {
1039 if (s.find(TYPES[i].specType) != string::npos) {
1040 t.push_back(TYPES[i].cType);
1041 }
Jason Sams135c4b72013-12-11 18:24:45 -08001042 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001043 spec->mReplaceables.push_back(t);
Jason Sams135c4b72013-12-11 18:24:45 -08001044 continue;
1045 }
1046
1047 if (s.size() == 0) {
1048 // eat empty line
1049 continue;
1050 }
1051
1052 printf("Error, line:\n");
1053 printf(" %s\n", s.c_str());
1054 }
1055
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001056 delete spec;
Chris Wailes44bef6f2014-08-12 13:51:10 -07001057 return nullptr;
Jason Sams135c4b72013-12-11 18:24:45 -08001058}
1059
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001060void Specification::writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile,
1061 Function* function, int versionOfTestFiles) {
1062 int start[4];
1063 int end[4];
1064 for (int i = 0; i < 4; i++) {
1065 if (i < (int)mReplaceables.size()) {
1066 start[i] = 0;
1067 end[i] = mReplaceables[i].size();
1068 } else {
1069 start[i] = -1;
1070 end[i] = 0;
1071 }
1072 }
1073 for (int i4 = start[3]; i4 < end[3]; i4++) {
1074 for (int i3 = start[2]; i3 < end[2]; i3++) {
1075 for (int i2 = start[1]; i2 < end[1]; i2++) {
1076 for (int i1 = start[0]; i1 < end[0]; i1++) {
1077 Permutation p(function, this, i1, i2, i3, i4);
1078 p.writeFiles(headerFile, rsFile, javaFile, versionOfTestFiles);
1079 }
1080 }
1081 }
1082 }
1083}
Jason Sams135c4b72013-12-11 18:24:45 -08001084
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001085bool Specification::relevantForVersion(int versionOfTestFiles) const {
1086 if (mMinVersion != 0 && mMinVersion > versionOfTestFiles) {
1087 return false;
1088 }
1089 if (mMaxVersion != 0 && mMaxVersion < versionOfTestFiles) {
1090 return false;
1091 }
1092 return true;
1093}
1094
1095string Specification::expandString(string s, int i1, int i2, int i3, int i4) const {
1096 if (mReplaceables.size() > 0) {
1097 s = stringReplace(s, "#1", mReplaceables[0][i1]);
1098 }
1099 if (mReplaceables.size() > 1) {
1100 s = stringReplace(s, "#2", mReplaceables[1][i2]);
1101 }
1102 if (mReplaceables.size() > 2) {
1103 s = stringReplace(s, "#3", mReplaceables[2][i3]);
1104 }
1105 if (mReplaceables.size() > 3) {
1106 s = stringReplace(s, "#4", mReplaceables[3][i4]);
Jason Sams135c4b72013-12-11 18:24:45 -08001107 }
1108 return s;
1109}
1110
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001111Permutation::Permutation(Function* func, Specification* spec, int i1, int i2, int i3, int i4)
1112 : mFunction(func),
1113 mSpecification(spec),
1114 mReturnIndex(-1),
1115 mFirstInputIndex(-1),
1116 mInputCount(0),
1117 mOutputCount(0) {
1118 // We expand the strings now to make capitalization easier. The previous code preserved the #n
1119 // markers just before emitting, which made capitalization difficult.
1120 mName = spec->getName(i1, i2, i3, i4);
1121 mCleanName = spec->getCleanName();
1122 mTest = spec->getTest();
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001123 mPrecisionLimit = spec->getPrecisionLimit();
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001124 spec->getInlines(i1, i2, i3, i4, &mInline);
1125 spec->getComments(i1, i2, i3, i4, &mComment);
1126
1127 vector<string> paramDefinitions;
1128 spec->getParams(i1, i2, i3, i4, &paramDefinitions);
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001129 mHasFloatAnswers = false;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001130 for (size_t i = 0; i < paramDefinitions.size(); i++) {
1131 ParameterDefinition* def = new ParameterDefinition();
1132 def->parseParameterDefinition(paramDefinitions[i], false, &mInputCount, &mOutputCount);
1133 if (!def->isOutParameter && mFirstInputIndex < 0) {
1134 mFirstInputIndex = mParams.size();
1135 }
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001136 if (def->isOutParameter && def->isFloatType) {
1137 mHasFloatAnswers = true;
1138 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001139 mParams.push_back(def);
Jason Sams135c4b72013-12-11 18:24:45 -08001140 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001141
1142 const string s = spec->getReturn(i1, i2, i3, i4);
1143 if (!s.empty() && s != "void") {
1144 ParameterDefinition* def = new ParameterDefinition();
1145 // Adding "*" tells the parse method it's an output.
1146 def->parseParameterDefinition(s, true, &mInputCount, &mOutputCount);
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001147 if (def->isOutParameter && def->isFloatType) {
1148 mHasFloatAnswers = true;
1149 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001150 mReturnIndex = mParams.size();
1151 mParams.push_back(def);
Jason Sams135c4b72013-12-11 18:24:45 -08001152 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001153
1154 mRsKernelName = "test" + capitalize(mName);
1155 mJavaArgumentsClassName = "Arguments";
1156 mJavaArgumentsNClassName = "Arguments";
1157 mJavaCheckMethodName = "check" + capitalize(mCleanName);
1158 mJavaVerifyMethodName = "verifyResults" + capitalize(mCleanName);
1159 for (int i = 0; i < (int)mParams.size(); i++) {
1160 const ParameterDefinition& p = *mParams[i];
1161 mRsKernelName += capitalize(p.rsType);
1162 mJavaArgumentsClassName += capitalize(p.rsBaseType);
1163 mJavaArgumentsNClassName += capitalize(p.rsBaseType);
1164 if (p.mVectorSize != "1") {
1165 mJavaArgumentsNClassName += "N";
1166 }
1167 mJavaCheckMethodName += capitalize(p.rsType);
1168 mJavaVerifyMethodName += capitalize(p.rsType);
Jason Sams135c4b72013-12-11 18:24:45 -08001169 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001170 mJavaVerifierComputeMethodName = "compute" + capitalize(mCleanName);
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001171 mJavaVerifierVerifyMethodName = "verify" + capitalize(mCleanName);
Jason Sams135c4b72013-12-11 18:24:45 -08001172}
1173
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001174void Permutation::writeFiles(ofstream& headerFile, ofstream& rsFile, ofstream& javaFile,
1175 int versionOfTestFiles) {
1176 writeHeaderSection(headerFile);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001177 if (mSpecification->relevantForVersion(versionOfTestFiles) && mTest != "none") {
1178 writeRsSection(rsFile);
1179 writeJavaSection(javaFile);
1180 }
1181}
1182
1183void Permutation::writeHeaderSection(ofstream& file) const {
1184 int minVersion = mSpecification->getMinVersion();
1185 int maxVersion = mSpecification->getMaxVersion();
1186 bool hasVersion = minVersion || maxVersion;
1187
1188 if (hasVersion) {
1189 if (maxVersion) {
1190 file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << minVersion
1191 << ") && (RS_VERSION <= " << maxVersion << "))\n";
1192 } else {
1193 file << "#if (defined(RS_VERSION) && (RS_VERSION >= " << minVersion << "))\n";
Jason Samsea877ed2014-01-09 15:48:32 -08001194 }
1195 }
1196
Jean-Luc Brouillet462e62c2014-12-12 13:42:24 -08001197 file << "/**\n";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001198 for (size_t ct = 0; ct < mComment.size(); ct++) {
1199 if (!mComment[ct].empty()) {
1200 file << " * " << mComment[ct] << "\n";
1201 } else {
1202 file << " *\n";
1203 }
Jason Samsea877ed2014-01-09 15:48:32 -08001204 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001205 file << " *\n";
1206 if (minVersion || maxVersion) {
1207 if (maxVersion) {
1208 file << " * Suppored by API versions " << minVersion << " - " << maxVersion << "\n";
1209 } else {
1210 file << " * Supported by API versions " << minVersion << " and newer.\n";
1211 }
1212 }
1213 file << " */\n";
1214 if (mInline.size() > 0) {
1215 file << "static ";
1216 } else {
1217 file << "extern ";
1218 }
1219 if (mReturnIndex >= 0) {
1220 file << mParams[mReturnIndex]->rsType;
1221 } else {
1222 file << "void";
1223 }
1224 file << " __attribute__((";
1225 if (mOutputCount <= 1) {
1226 file << "const, ";
1227 }
1228 file << "overloadable))";
1229 file << mName;
1230 file << "(";
1231 bool needComma = false;
1232 for (int i = 0; i < (int)mParams.size(); i++) {
1233 if (i != mReturnIndex) {
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001234 const ParameterDefinition& p = *mParams[i];
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001235 if (needComma) {
1236 file << ", ";
1237 }
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001238 file << p.rsType;
1239 if (p.isOutParameter) {
1240 file << "*";
1241 }
1242 if (!p.specName.empty()) {
1243 file << " " << p.specName;
1244 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001245 needComma = true;
1246 }
1247 }
1248 if (mInline.size() > 0) {
1249 file << ") {\n";
1250 for (size_t ct = 0; ct < mInline.size(); ct++) {
1251 file << " " << mInline[ct].c_str() << "\n";
1252 }
1253 file << "}\n";
1254 } else {
1255 file << ");\n";
1256 }
1257 if (hasVersion) {
1258 file << "#endif\n";
1259 }
1260 file << "\n";
Jason Samsea877ed2014-01-09 15:48:32 -08001261}
1262
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001263/* Write the section of the .rs file for this permutation.
1264 *
1265 * We communicate the extra input and output parameters via global allocations.
1266 * For example, if we have a function that takes three arguments, two for input
1267 * and one for output:
1268 *
1269 * start:
1270 * name: gamn
1271 * ret: float3
1272 * arg: float3 a
1273 * arg: int b
1274 * arg: float3 *c
1275 * end:
1276 *
1277 * We'll produce:
1278 *
1279 * rs_allocation gAllocInB;
1280 * rs_allocation gAllocOutC;
1281 *
1282 * float3 __attribute__((kernel)) test_gamn_float3_int_float3(float3 inA, unsigned int x) {
1283 * int inB;
1284 * float3 outC;
1285 * float2 out;
1286 * inB = rsGetElementAt_int(gAllocInB, x);
1287 * out = gamn(a, in_b, &outC);
1288 * rsSetElementAt_float4(gAllocOutC, &outC, x);
1289 * return out;
1290 * }
1291 *
1292 * We avoid re-using x and y from the definition because these have reserved
1293 * meanings in a .rs file.
1294 */
1295void Permutation::writeRsSection(ofstream& rs) const {
1296 // Write the allocation declarations we'll need.
1297 for (int i = 0; i < (int)mParams.size(); i++) {
1298 const ParameterDefinition& p = *mParams[i];
1299 // Don't need allocation for one input and one return value.
1300 if (i != mReturnIndex && i != mFirstInputIndex) {
1301 mFunction->writeRsAllocationDefinition(p);
1302 }
1303 }
1304 rs << "\n";
Jason Samsea877ed2014-01-09 15:48:32 -08001305
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001306 // Write the function header.
1307 if (mReturnIndex >= 0) {
1308 rs << mParams[mReturnIndex]->rsType;
1309 } else {
1310 rs << "void";
1311 }
1312 rs << " __attribute__((kernel)) " << mRsKernelName;
1313 rs << "(";
1314 bool needComma = false;
1315 if (mFirstInputIndex >= 0) {
1316 rs << mParams[mFirstInputIndex]->rsType << " " << mParams[mFirstInputIndex]->variableName;
1317 needComma = true;
1318 }
1319 if (mOutputCount > 1 || mInputCount > 1) {
1320 if (needComma) {
1321 rs << ", ";
1322 }
1323 rs << "unsigned int x";
1324 }
1325 rs << ") {\n";
Jason Samsea877ed2014-01-09 15:48:32 -08001326
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001327 // Write the local variable declarations and initializations.
1328 for (int i = 0; i < (int)mParams.size(); i++) {
1329 if (i == mFirstInputIndex || i == mReturnIndex) {
1330 continue;
1331 }
1332 const ParameterDefinition& p = *mParams[i];
1333 rs << tab(1) << p.rsType << " " << p.variableName;
1334 if (p.isOutParameter) {
1335 rs << " = 0;\n";
1336 } else {
1337 rs << " = rsGetElementAt_" << p.rsType << "(" << p.rsAllocName << ", x);\n";
1338 }
1339 }
1340
1341 // Write the function call.
1342 if (mReturnIndex >= 0) {
1343 if (mOutputCount > 1) {
1344 rs << tab(1) << mParams[mReturnIndex]->rsType << " "
1345 << mParams[mReturnIndex]->variableName << " = ";
1346 } else {
1347 rs << tab(1) << "return ";
1348 }
1349 }
1350 rs << mName << "(";
1351 needComma = false;
1352 for (int i = 0; i < (int)mParams.size(); i++) {
1353 const ParameterDefinition& p = *mParams[i];
1354 if (i == mReturnIndex) {
1355 continue;
1356 }
1357 if (needComma) {
1358 rs << ", ";
1359 }
1360 if (p.isOutParameter) {
1361 rs << "&";
1362 }
1363 rs << p.variableName;
1364 needComma = true;
1365 }
1366 rs << ");\n";
1367
1368 if (mOutputCount > 1) {
1369 // Write setting the extra out parameters into the allocations.
1370 for (int i = 0; i < (int)mParams.size(); i++) {
1371 const ParameterDefinition& p = *mParams[i];
1372 if (p.isOutParameter && i != mReturnIndex) {
1373 rs << tab(1) << "rsSetElementAt_" << p.rsType << "(" << p.rsAllocName << ", ";
1374 if (passByAddressToSet(p.variableName)) {
1375 rs << "&";
1376 }
1377 rs << p.variableName << ", x);\n";
1378 }
1379 }
1380 if (mReturnIndex >= 0) {
1381 rs << tab(1) << "return " << mParams[mReturnIndex]->variableName << ";\n";
1382 }
1383 }
1384 rs << "}\n";
1385}
1386
1387bool Permutation::passByAddressToSet(const string& name) const {
1388 string s = name;
1389 int last = s.size() - 1;
1390 char lastChar = s[last];
1391 return lastChar >= '0' && lastChar <= '9';
1392}
1393
1394void Permutation::writeJavaSection(ofstream& file) const {
1395 // By default, we test the results using item by item comparison.
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001396 if (mTest == "scalar" || mTest == "limited") {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001397 writeJavaArgumentClass(file, true);
1398 writeJavaCheckMethod(file, true);
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001399 writeJavaVerifyScalarMethod(file, false);
1400 } else if (mTest == "custom") {
1401 writeJavaArgumentClass(file, true);
1402 writeJavaCheckMethod(file, true);
1403 writeJavaVerifyScalarMethod(file, true);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001404 } else if (mTest == "vector") {
1405 writeJavaArgumentClass(file, false);
1406 writeJavaCheckMethod(file, true);
1407 writeJavaVerifyVectorMethod(file);
1408 } else if (mTest == "noverify") {
1409 writeJavaCheckMethod(file, false);
1410 }
1411
1412 // Register the check method to be called. This code will be written at the end.
1413 mFunction->addJavaCheckCall(mJavaCheckMethodName + "();");
1414}
1415
1416void Permutation::writeJavaArgumentClass(ofstream& file, bool scalar) const {
1417 string name;
1418 if (scalar) {
1419 name = mJavaArgumentsClassName;
1420 } else {
1421 name = mJavaArgumentsNClassName;
1422 }
Jason Sams135c4b72013-12-11 18:24:45 -08001423 string s;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001424 s += tab(1) + "public class " + name + " {\n";
1425 for (size_t i = 0; i < mParams.size(); i++) {
1426 const ParameterDefinition& p = *mParams[i];
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001427 s += tab(2) + "public ";
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001428 if (p.isOutParameter && p.isFloatType && mTest != "custom") {
1429 s += "Target.Floaty";
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001430 } else {
1431 s += p.javaBaseType;
1432 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001433 if (!scalar && p.mVectorSize != "1") {
1434 s += "[]";
Jason Sams135c4b72013-12-11 18:24:45 -08001435 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001436 s += " " + p.variableName + ";\n";
Jason Sams135c4b72013-12-11 18:24:45 -08001437 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001438 s += tab(1) + "}\n\n";
Jason Sams135c4b72013-12-11 18:24:45 -08001439
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001440 mFunction->writeJavaArgumentClassDefinition(name, s);
Jason Sams135c4b72013-12-11 18:24:45 -08001441}
1442
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001443void Permutation::writeJavaCheckMethod(ofstream& file, bool generateCallToVerifier) const {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001444 file << tab(1) << "private void " << mJavaCheckMethodName << "() {\n";
1445 // Generate the input allocations and initialization.
1446 for (size_t i = 0; i < mParams.size(); i++) {
1447 const ParameterDefinition& p = *mParams[i];
1448 if (!p.isOutParameter) {
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001449 writeJavaInputAllocationDefinition(file, tab(2), p);
1450 }
1451 }
1452 // Enforce ordering if needed.
1453 for (size_t i = 0; i < mParams.size(); i++) {
1454 const ParameterDefinition& p = *mParams[i];
1455 if (!p.isOutParameter && !p.smallerParameter.empty()) {
1456 string smallerAlloc = "in" + capitalize(p.smallerParameter);
1457 file << tab(2) << "enforceOrdering(" << smallerAlloc << ", " << p.javaAllocName
1458 << ");\n";
Jason Sams135c4b72013-12-11 18:24:45 -08001459 }
Jason Sams135c4b72013-12-11 18:24:45 -08001460 }
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001461 writeJavaCallToRs(file, false, generateCallToVerifier);
1462 writeJavaCallToRs(file, true, generateCallToVerifier);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001463 file << tab(1) << "}\n\n";
Jason Sams135c4b72013-12-11 18:24:45 -08001464}
1465
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001466void Permutation::writeJavaInputAllocationDefinition(ofstream& file, const string& indent,
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001467 const ParameterDefinition& param) const {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001468 string dataType;
1469 char vectorSize;
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001470 convertToRsType(param.rsType, &dataType, &vectorSize);
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001471
1472 string seed = hashString(mJavaCheckMethodName + param.javaAllocName);
1473 file << indent << "Allocation " << param.javaAllocName << " = ";
1474 if (param.compatibleTypeIndex >= 0) {
1475 if (TYPES[param.typeIndex].kind == FLOATING_POINT) {
1476 writeJavaRandomCompatibleFloatAllocation(file, dataType, seed, vectorSize,
1477 TYPES[param.compatibleTypeIndex],
1478 TYPES[param.typeIndex]);
1479 } else {
1480 writeJavaRandomCompatibleIntegerAllocation(file, dataType, seed, vectorSize,
1481 TYPES[param.compatibleTypeIndex],
1482 TYPES[param.typeIndex]);
1483 }
1484 } else if (!param.minValue.empty()) {
1485 if (TYPES[param.typeIndex].kind != FLOATING_POINT) {
1486 printf("range(,) is only supported for floating point\n");
1487 } else {
1488 file << "createRandomFloatAllocation(mRS, Element.DataType." << dataType << ", "
1489 << vectorSize << ", " << seed << ", " << param.minValue << ", " << param.maxValue
1490 << ")";
1491 }
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001492 } else {
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001493 file << "createRandomAllocation(mRS, Element.DataType." << dataType << ", " << vectorSize
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001494 // TODO set to false only for native, i.e.
1495 // << ", " << seed << ", " << (mTest == "limited" ? "false" : "true") << ")";
1496 << ", " << seed << ", false)";
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001497 }
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001498 file << ";\n";
1499}
1500
1501void Permutation::writeJavaRandomCompatibleFloatAllocation(ofstream& file, const string& dataType,
1502 const string& seed, char vectorSize,
1503 const Type& compatibleType,
1504 const Type& generatedType) const {
1505 file << "createRandomFloatAllocation"
1506 << "(mRS, Element.DataType." << dataType << ", " << vectorSize << ", " << seed << ", ";
Jean-Luc Brouillet2f281cf2014-03-12 18:25:33 -07001507 double minValue = 0.0;
1508 double maxValue = 0.0;
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001509 switch (compatibleType.kind) {
1510 case FLOATING_POINT: {
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001511 // We're generating floating point values. We just worry about the exponent.
1512 // Subtract 1 for the exponent sign.
1513 int bits = min(compatibleType.exponentBits, generatedType.exponentBits) - 1;
Jean-Luc Brouillet2f281cf2014-03-12 18:25:33 -07001514 maxValue = ldexp(0.95, (1 << bits) - 1);
1515 minValue = -maxValue;
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001516 break;
1517 }
1518 case UNSIGNED_INTEGER:
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001519 maxValue = MaxDoubleForInteger(compatibleType.significantBits,
1520 generatedType.significantBits);
Jean-Luc Brouillet2f281cf2014-03-12 18:25:33 -07001521 minValue = 0.0;
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001522 break;
Jean-Luc Brouillet2f281cf2014-03-12 18:25:33 -07001523 case SIGNED_INTEGER:
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001524 maxValue = MaxDoubleForInteger(compatibleType.significantBits,
1525 generatedType.significantBits);
1526 minValue = -maxValue - 1.0;
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001527 break;
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001528 }
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001529 file << scientific << std::setprecision(19);
Jean-Luc Brouillet2f281cf2014-03-12 18:25:33 -07001530 file << minValue << ", " << maxValue << ")";
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001531 file.unsetf(ios_base::floatfield);
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001532}
1533
1534void Permutation::writeJavaRandomCompatibleIntegerAllocation(ofstream& file, const string& dataType,
1535 const string& seed, char vectorSize,
1536 const Type& compatibleType,
1537 const Type& generatedType) const {
1538 file << "createRandomIntegerAllocation"
1539 << "(mRS, Element.DataType." << dataType << ", " << vectorSize << ", " << seed << ", ";
1540
1541 if (compatibleType.kind == FLOATING_POINT) {
1542 // Currently, all floating points can take any number we generate.
1543 bool isSigned = generatedType.kind == SIGNED_INTEGER;
1544 file << (isSigned ? "true" : "false") << ", " << generatedType.significantBits;
1545 } else {
1546 bool isSigned =
1547 compatibleType.kind == SIGNED_INTEGER && generatedType.kind == SIGNED_INTEGER;
1548 file << (isSigned ? "true" : "false") << ", "
1549 << min(compatibleType.significantBits, generatedType.significantBits);
1550 }
1551 file << ")";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001552}
Jason Sams135c4b72013-12-11 18:24:45 -08001553
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001554void Permutation::writeJavaOutputAllocationDefinition(ofstream& file, const string& indent,
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001555 const ParameterDefinition& param) const {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001556 string dataType;
1557 char vectorSize;
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001558 convertToRsType(param.rsType, &dataType, &vectorSize);
1559 file << indent << "Allocation " << param.javaAllocName << " = Allocation.createSized(mRS, "
1560 << "getElement(mRS, Element.DataType." << dataType << ", " << vectorSize
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001561 << "), INPUTSIZE);\n";
1562}
Jason Sams135c4b72013-12-11 18:24:45 -08001563
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001564// Converts float2 to FLOAT_32 and 2, etc.
1565void Permutation::convertToRsType(const string& name, string* dataType, char* vectorSize) const {
1566 string s = name;
1567 int last = s.size() - 1;
1568 char lastChar = s[last];
1569 if (lastChar >= '1' && lastChar <= '4') {
1570 s.erase(last);
1571 *vectorSize = lastChar;
1572 } else {
1573 *vectorSize = '1';
Jason Sams135c4b72013-12-11 18:24:45 -08001574 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001575 dataType->clear();
1576 for (int i = 0; i < NUM_TYPES; i++) {
1577 if (s == TYPES[i].cType) {
1578 *dataType = TYPES[i].rsDataType;
Jason Sams135c4b72013-12-11 18:24:45 -08001579 break;
1580 }
1581 }
Jason Sams135c4b72013-12-11 18:24:45 -08001582}
1583
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001584void Permutation::writeJavaVerifyScalarMethod(ofstream& file, bool verifierValidates) const {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001585 writeJavaVerifyFunctionHeader(file);
1586 string vectorSize = "1";
1587 for (size_t i = 0; i < mParams.size(); i++) {
1588 const ParameterDefinition& p = *mParams[i];
1589 writeJavaArrayInitialization(file, p);
1590 if (p.mVectorSize != "1" && p.mVectorSize != vectorSize) {
1591 if (vectorSize == "1") {
1592 vectorSize = p.mVectorSize;
1593 } else {
1594 printf("Yikes, had vector %s and %s\n", vectorSize.c_str(), p.mVectorSize.c_str());
1595 }
1596 }
1597 }
Jason Sams135c4b72013-12-11 18:24:45 -08001598
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001599 file << tab(2) << "for (int i = 0; i < INPUTSIZE; i++) {\n";
1600 file << tab(3) << "for (int j = 0; j < " << vectorSize << " ; j++) {\n";
1601
1602 file << tab(4) << "// Extract the inputs.\n";
1603 file << tab(4) << mJavaArgumentsClassName << " args = new " << mJavaArgumentsClassName
1604 << "();\n";
1605 for (size_t i = 0; i < mParams.size(); i++) {
1606 const ParameterDefinition& p = *mParams[i];
1607 if (!p.isOutParameter) {
1608 file << tab(4) << "args." << p.variableName << " = " << p.javaArrayName << "[i";
1609 if (p.vectorWidth != "1") {
1610 file << " * " << p.vectorWidth << " + j";
1611 }
1612 file << "];\n";
1613 }
1614 }
1615
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001616 if (verifierValidates) {
1617 file << tab(4) << "// Extract the outputs.\n";
1618 for (size_t i = 0; i < mParams.size(); i++) {
1619 const ParameterDefinition& p = *mParams[i];
1620 if (p.isOutParameter) {
1621 file << tab(4) << "args." << p.variableName << " = " << p.javaArrayName
1622 << "[i * " + p.vectorWidth + " + j];\n";
1623 }
1624 }
1625 file << tab(4) << "// Ask the CoreMathVerifier to validate.\n";
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001626 if (mHasFloatAnswers) {
1627 file << tab(4) << "Target target = new Target(relaxed);\n";
1628 }
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001629 file << tab(4) << "String errorMessage = CoreMathVerifier." << mJavaVerifierVerifyMethodName
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001630 << "(args";
1631 if (mHasFloatAnswers) {
1632 file << ", target";
1633 }
1634 file << ");\n";
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001635 file << tab(4) << "boolean valid = errorMessage == null;\n";
1636 } else {
1637 file << tab(4) << "// Figure out what the outputs should have been.\n";
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001638 if (mHasFloatAnswers) {
1639 file << tab(4) << "Target target = new Target(relaxed);\n";
1640 }
1641 file << tab(4) << "CoreMathVerifier." << mJavaVerifierComputeMethodName << "(args";
1642 if (mHasFloatAnswers) {
1643 file << ", target";
1644 }
1645 file << ");\n";
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001646 file << tab(4) << "// Validate the outputs.\n";
1647 file << tab(4) << "boolean valid = true;\n";
1648 for (size_t i = 0; i < mParams.size(); i++) {
1649 const ParameterDefinition& p = *mParams[i];
1650 if (p.isOutParameter) {
1651 writeJavaTestAndSetValid(file, 4, p, "", "[i * " + p.vectorWidth + " + j]");
1652 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001653 }
1654 }
1655
1656 file << tab(4) << "if (!valid) {\n";
1657 file << tab(5) << "StringBuilder message = new StringBuilder();\n";
1658 for (size_t i = 0; i < mParams.size(); i++) {
1659 const ParameterDefinition& p = *mParams[i];
1660 if (p.isOutParameter) {
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001661 writeJavaAppendOutputToMessage(file, 5, p, "", "[i * " + p.vectorWidth + " + j]",
1662 verifierValidates);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001663 } else {
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001664 writeJavaAppendInputToMessage(file, 5, p, "args." + p.variableName);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001665 }
1666 }
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001667 if (verifierValidates) {
1668 file << tab(5) << "message.append(errorMessage);\n";
1669 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001670
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001671 file << tab(5) << "assertTrue(\"Incorrect output for " << mJavaCheckMethodName << "\" +\n";
1672 file << tab(7) << "(relaxed ? \"_relaxed\" : \"\") + \":\\n\" + message.toString(), valid);\n";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001673 file << tab(4) << "}\n";
1674 file << tab(3) << "}\n";
1675 file << tab(2) << "}\n";
1676 file << tab(1) << "}\n\n";
1677}
1678
1679void Permutation::writeJavaVerifyFunctionHeader(ofstream& file) const {
1680 file << tab(1) << "private void " << mJavaVerifyMethodName << "(";
1681 for (size_t i = 0; i < mParams.size(); i++) {
1682 const ParameterDefinition& p = *mParams[i];
1683 file << "Allocation " << p.javaAllocName << ", ";
1684 }
1685 file << "boolean relaxed) {\n";
1686}
1687
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001688void Permutation::writeJavaTestAndSetValid(ofstream& file, int indent, const ParameterDefinition& p,
1689 const string& argsIndex,
1690 const string& actualIndex) const {
1691 writeJavaTestOneValue(file, indent, p, argsIndex, actualIndex);
1692 file << tab(indent + 1) << "valid = false;\n";
1693 file << tab(indent) << "}\n";
1694}
1695
1696void Permutation::writeJavaTestOneValue(ofstream& file, int indent, const ParameterDefinition& p,
1697 const string& argsIndex, const string& actualIndex) const {
1698 file << tab(indent) << "if (";
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001699 if (p.isFloatType) {
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001700 file << "!args." << p.variableName << argsIndex << ".couldBe(" << p.javaArrayName
1701 << actualIndex;
1702 if (!mPrecisionLimit.empty()) {
1703 file << ", " << mPrecisionLimit;
1704 }
1705 file << ")";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001706 } else {
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001707 file << "args." << p.variableName << argsIndex << " != " << p.javaArrayName << actualIndex;
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001708 }
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001709 if (p.undefinedIfOutIsNan && mReturnIndex >= 0) {
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001710 file << " && !args." << mParams[mReturnIndex]->variableName << argsIndex << ".isNaN()";
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001711 }
1712 file << ") {\n";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001713}
1714
1715void Permutation::writeJavaAppendOutputToMessage(ofstream& file, int indent,
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001716 const ParameterDefinition& p,
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001717 const string& argsIndex, const string& actualIndex,
1718 bool verifierValidates) const {
1719 if (verifierValidates) {
1720 const string actual = "args." + p.variableName + argsIndex;
1721 file << tab(indent) << "message.append(\"Output " + p.variableName + ": \");\n";
1722 if (p.isFloatType) {
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001723 writeJavaAppendFloatVariableToMessage(file, indent, actual, true);
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001724 } else {
1725 writeJavaAppendVariableToMessage(file, indent, p, actual);
1726 }
1727 writeJavaAppendNewLineToMessage(file, indent);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001728 } else {
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001729 const string expected = "args." + p.variableName + argsIndex;
1730 const string actual = p.javaArrayName + actualIndex;
1731 file << tab(indent) << "message.append(\"Expected output " + p.variableName + ": \");\n";
1732 if (p.isFloatType) {
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001733 writeJavaAppendFloatVariableToMessage(file, indent, expected, false);
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001734 } else {
1735 writeJavaAppendVariableToMessage(file, indent, p, expected);
1736 }
1737 writeJavaAppendNewLineToMessage(file, indent);
1738 file << tab(indent) << "message.append(\"Actual output " + p.variableName + ": \");\n";
1739 writeJavaAppendVariableToMessage(file, indent, p, actual);
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001740
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001741 writeJavaTestOneValue(file, indent, p, argsIndex, actualIndex);
1742 file << tab(indent + 1) << "message.append(\" FAIL\");\n";
1743 file << tab(indent) << "}\n";
1744 writeJavaAppendNewLineToMessage(file, indent);
1745 }
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001746}
1747
1748void Permutation::writeJavaAppendInputToMessage(ofstream& file, int indent,
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001749 const ParameterDefinition& p,
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001750 const string& actual) const {
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001751 file << tab(indent) << "message.append(\"Input " + p.variableName + ": \");\n";
1752 writeJavaAppendVariableToMessage(file, indent, p, actual);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001753 writeJavaAppendNewLineToMessage(file, indent);
1754}
1755
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001756void Permutation::writeJavaAppendNewLineToMessage(ofstream& file, int indent) const {
1757 file << tab(indent) << "message.append(\"\\n\");\n";
1758}
1759
1760void Permutation::writeJavaAppendVariableToMessage(ofstream& file, int indent,
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001761 const ParameterDefinition& p,
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001762 const string& value) const {
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001763 if (p.specType == "f16" || p.specType == "f32") {
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001764 file << tab(indent) << "message.append(String.format(\"%14.8g {%8x} %15a\",\n";
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001765 file << tab(indent + 2) << value << ", "
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001766 << "Float.floatToRawIntBits(" << value << "), " << value << "));\n";
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001767 } else if (p.specType == "f64") {
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001768 file << tab(indent) << "message.append(String.format(\"%24.8g {%16x} %31a\",\n";
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001769 file << tab(indent + 2) << value << ", "
1770 << "Double.doubleToRawLongBits(" << value << "), " << value << "));\n";
1771 } else if (p.specType[0] == 'u') {
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001772 file << tab(indent) << "message.append(String.format(\"0x%x\", " << value << "));\n";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001773 } else {
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001774 file << tab(indent) << "message.append(String.format(\"%d\", " << value << "));\n";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001775 }
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001776}
1777
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001778void Permutation::writeJavaAppendFloatVariableToMessage(ofstream& file, int indent,
1779 const string& value,
1780 bool regularFloat) const {
1781 file << tab(indent) << "message.append(";
1782 if (regularFloat) {
1783 file << "Float.toString(" << value << ")";
1784 } else {
1785 file << value << ".toString()";
1786 }
1787 file << ");\n";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001788}
1789
1790void Permutation::writeJavaVectorComparison(ofstream& file, int indent,
1791 const ParameterDefinition& p) const {
1792 if (p.mVectorSize == "1") {
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001793 writeJavaTestAndSetValid(file, indent, p, "", "[i]");
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001794
1795 } else {
1796 file << tab(indent) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n";
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001797 writeJavaTestAndSetValid(file, indent + 1, p, "[j]", "[i * " + p.vectorWidth + " + j]");
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001798 file << tab(indent) << "}\n";
1799 }
1800}
1801
1802void Permutation::writeJavaAppendVectorInputToMessage(ofstream& file, int indent,
1803 const ParameterDefinition& p) const {
1804 if (p.mVectorSize == "1") {
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001805 writeJavaAppendInputToMessage(file, indent, p, p.javaArrayName + "[i]");
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001806 } else {
1807 file << tab(indent) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n";
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001808 writeJavaAppendInputToMessage(file, indent + 1, p,
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001809 p.javaArrayName + "[i * " + p.vectorWidth + " + j]");
1810 file << tab(indent) << "}\n";
1811 }
1812}
1813
1814void Permutation::writeJavaAppendVectorOutputToMessage(ofstream& file, int indent,
1815 const ParameterDefinition& p) const {
1816 if (p.mVectorSize == "1") {
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001817 writeJavaAppendOutputToMessage(file, indent, p, "", "[i]", false);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001818
1819 } else {
1820 file << tab(indent) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n";
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001821 writeJavaAppendOutputToMessage(file, indent + 1, p, "[j]",
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001822 "[i * " + p.vectorWidth + " + j]", false);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001823 file << tab(indent) << "}\n";
1824 }
1825}
1826
1827void Permutation::writeJavaVerifyVectorMethod(ofstream& file) const {
1828 writeJavaVerifyFunctionHeader(file);
1829 for (size_t i = 0; i < mParams.size(); i++) {
1830 const ParameterDefinition& p = *mParams[i];
1831 writeJavaArrayInitialization(file, p);
1832 }
1833 file << tab(2) + "for (int i = 0; i < INPUTSIZE; i++) {\n";
1834 file << tab(3) << mJavaArgumentsNClassName << " args = new " << mJavaArgumentsNClassName
1835 << "();\n";
1836
1837 file << tab(3) << "// Create the appropriate sized arrays in args\n";
1838 for (size_t i = 0; i < mParams.size(); i++) {
1839 const ParameterDefinition& p = *mParams[i];
1840 if (p.mVectorSize != "1") {
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001841 string type = p.javaBaseType;
Jean-Luc Brouillet46ebc972014-05-05 20:33:25 -07001842 if (p.isOutParameter && p.isFloatType) {
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001843 type = "Target.Floaty";
Jean-Luc Brouilletbcd5b9a2014-03-07 18:00:57 -08001844 }
1845 file << tab(3) << "args." << p.variableName << " = new " << type << "[" << p.mVectorSize
1846 << "];\n";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001847 }
1848 }
1849
1850 file << tab(3) << "// Fill args with the input values\n";
1851 for (size_t i = 0; i < mParams.size(); i++) {
1852 const ParameterDefinition& p = *mParams[i];
1853 if (!p.isOutParameter) {
1854 if (p.mVectorSize == "1") {
1855 file << tab(3) << "args." << p.variableName << " = " << p.javaArrayName + "[i]"
1856 << ";\n";
1857 } else {
1858 file << tab(3) << "for (int j = 0; j < " << p.mVectorSize << " ; j++) {\n";
1859 file << tab(4) << "args." << p.variableName + "[j] = "
1860 << p.javaArrayName + "[i * " + p.vectorWidth + " + j]"
1861 << ";\n";
1862 file << tab(3) << "}\n";
1863 }
1864 }
1865 }
Jean-Luc Brouillet32c18182014-07-29 13:52:45 -07001866 file << tab(3) << "Target target = new Target(relaxed);\n";
1867 file << tab(3) << "CoreMathVerifier." << mJavaVerifierComputeMethodName
1868 << "(args, target);\n\n";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001869
1870 file << tab(3) << "// Compare the expected outputs to the actual values returned by RS.\n";
1871 file << tab(3) << "boolean valid = true;\n";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001872 for (size_t i = 0; i < mParams.size(); i++) {
1873 const ParameterDefinition& p = *mParams[i];
1874 if (p.isOutParameter) {
1875 writeJavaVectorComparison(file, 3, p);
1876 }
1877 }
1878
1879 file << tab(3) << "if (!valid) {\n";
1880 file << tab(4) << "StringBuilder message = new StringBuilder();\n";
1881 for (size_t i = 0; i < mParams.size(); i++) {
1882 const ParameterDefinition& p = *mParams[i];
1883 if (p.isOutParameter) {
1884 writeJavaAppendVectorOutputToMessage(file, 4, p);
1885 } else {
1886 writeJavaAppendVectorInputToMessage(file, 4, p);
1887 }
1888 }
1889
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001890 file << tab(4) << "assertTrue(\"Incorrect output for " << mJavaCheckMethodName << "\" +\n";
1891 file << tab(6) << "(relaxed ? \"_relaxed\" : \"\") + \":\\n\" + message.toString(), valid);\n";
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001892 file << tab(3) << "}\n";
1893 file << tab(2) << "}\n";
1894 file << tab(1) << "}\n\n";
1895}
1896
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001897void Permutation::writeJavaCallToRs(ofstream& file, bool relaxed, bool generateCallToVerifier) const {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001898 string script = "script";
1899 if (relaxed) {
1900 script += "Relaxed";
1901 }
1902
1903 file << tab(2) << "try {\n";
1904 for (size_t i = 0; i < mParams.size(); i++) {
1905 const ParameterDefinition& p = *mParams[i];
1906 if (p.isOutParameter) {
Jean-Luc Brouillet46341432014-02-21 22:49:22 -08001907 writeJavaOutputAllocationDefinition(file, tab(3), p);
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001908 }
1909 }
1910
1911 for (int i = 0; i < (int)mParams.size(); i++) {
1912 const ParameterDefinition& p = *mParams[i];
1913 if (i != mReturnIndex && i != mFirstInputIndex) {
1914 file << tab(3) << script << ".set_" << p.rsAllocName << "(" << p.javaAllocName
1915 << ");\n";
1916 }
1917 }
1918
1919 file << tab(3) << script << ".forEach_" << mRsKernelName << "(";
1920 bool needComma = false;
1921 if (mFirstInputIndex >= 0) {
1922 file << mParams[mFirstInputIndex]->javaAllocName;
1923 needComma = true;
1924 }
1925 if (mReturnIndex >= 0) {
1926 if (needComma) {
1927 file << ", ";
1928 }
1929 file << mParams[mReturnIndex]->variableName << ");\n";
1930 }
1931
Jean-Luc Brouillet93906642014-07-23 21:25:45 -07001932 if (generateCallToVerifier) {
Jean-Luc Brouillet963c3672014-02-12 20:58:47 -08001933 file << tab(3) << mJavaVerifyMethodName << "(";
1934 for (size_t i = 0; i < mParams.size(); i++) {
1935 const ParameterDefinition& p = *mParams[i];
1936 file << p.variableName << ", ";
1937 }
1938
1939 if (relaxed) {
1940 file << "true";
1941 } else {
1942 file << "false";
1943 }
1944 file << ");\n";
1945 }
1946 file << tab(2) << "} catch (Exception e) {\n";
1947 file << tab(3) << "throw new RSRuntimeException(\"RenderScript. Can't invoke forEach_"
1948 << mRsKernelName << ": \" + e.toString());\n";
1949 file << tab(2) << "}\n";
1950}
1951
1952} // namespace
1953
1954int main(int argc, char* argv[]) {
1955 int versionOfTestFiles = 0;
1956 vector<string> specFileNames;
1957 if (!parseCommandLine(argc, argv, &versionOfTestFiles, &specFileNames)) {
1958 printf("Usage: gen_runtime spec_file [spec_file...] [-v version_of_test_files]\n");
1959 return -1;
1960 }
1961 int result = 0;
1962 for (size_t i = 0; i < specFileNames.size(); i++) {
1963 SpecFile specFile(specFileNames[i]);
1964 if (!specFile.process(versionOfTestFiles)) {
1965 result = -1;
1966 }
1967 }
1968 return result;
1969}