1 /*
2  * Copyright 2013, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <sys/stat.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <iostream>
21 
22 #include <cstdarg>
23 #include <cctype>
24 
25 #include <algorithm>
26 #include <sstream>
27 #include <string>
28 
29 #include "os_sep.h"
30 #include "slang_rs_context.h"
31 #include "slang_rs_export_var.h"
32 #include "slang_rs_export_foreach.h"
33 #include "slang_rs_export_func.h"
34 #include "slang_rs_reflect_utils.h"
35 #include "slang_version.h"
36 
37 #include "slang_rs_reflection_cpp.h"
38 
39 using namespace std;
40 
41 namespace slang {
42 
43 const char kRsTypeItemClassName[] = "Item";
44 const char kRsElemPrefix[] = "__rs_elem_";
45 // The name of the Allocation type that is reflected in C++
46 const char kAllocationSp[] = "android::RSC::sp<android::RSC::Allocation>";
47 
GetMatrixTypeName(const RSExportMatrixType * EMT)48 static const char *GetMatrixTypeName(const RSExportMatrixType *EMT) {
49   static const char *MatrixTypeCNameMap[] = {
50       "rs_matrix2x2", "rs_matrix3x3", "rs_matrix4x4",
51   };
52   unsigned Dim = EMT->getDim();
53 
54   if ((Dim - 2) < (sizeof(MatrixTypeCNameMap) / sizeof(const char *)))
55     return MatrixTypeCNameMap[EMT->getDim() - 2];
56 
57   slangAssert(false && "GetMatrixTypeName : Unsupported matrix dimension");
58   return nullptr;
59 }
60 
GetTypeName(const RSExportType * ET,bool PreIdentifier=true)61 static std::string GetTypeName(const RSExportType *ET, bool PreIdentifier = true) {
62   if((!PreIdentifier) && (ET->getClass() != RSExportType::ExportClassConstantArray)) {
63     slangAssert(false && "Non-array type post identifier?");
64     return "";
65   }
66   switch (ET->getClass()) {
67   case RSExportType::ExportClassPrimitive: {
68     const RSExportPrimitiveType *EPT =
69         static_cast<const RSExportPrimitiveType *>(ET);
70     if (EPT->isRSObjectType()) {
71       return std::string("android::RSC::sp<const android::RSC::") +
72              RSExportPrimitiveType::getRSReflectionType(EPT)->c_name + ">";
73     } else {
74       return RSExportPrimitiveType::getRSReflectionType(EPT)->c_name;
75     }
76   }
77   case RSExportType::ExportClassPointer: {
78     const RSExportType *PointeeType =
79         static_cast<const RSExportPointerType *>(ET)->getPointeeType();
80 
81     if (PointeeType->getClass() != RSExportType::ExportClassRecord)
82       return kAllocationSp;
83     else
84       return PointeeType->getElementName();
85   }
86   case RSExportType::ExportClassVector: {
87     const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET);
88     std::stringstream VecName;
89     VecName << EVT->getRSReflectionType(EVT)->rs_c_vector_prefix
90             << EVT->getNumElement();
91     return VecName.str();
92   }
93   case RSExportType::ExportClassMatrix: {
94     return GetMatrixTypeName(static_cast<const RSExportMatrixType *>(ET));
95   }
96   case RSExportType::ExportClassConstantArray: {
97     const RSExportConstantArrayType *CAT =
98         static_cast<const RSExportConstantArrayType *>(ET);
99     if (PreIdentifier) {
100       std::string ElementTypeName = GetTypeName(CAT->getElementType());
101       return ElementTypeName;
102     }
103     else {
104       std::stringstream ArraySpec;
105       ArraySpec << "[" << CAT->getNumElement() << "]";
106       return ArraySpec.str();
107     }
108   }
109   case RSExportType::ExportClassRecord: {
110     // TODO: Fix for C structs!
111     return ET->getElementName() + "." + kRsTypeItemClassName;
112   }
113   default: { slangAssert(false && "Unknown class of type"); }
114   }
115 
116   return "";
117 }
118 
RSReflectionCpp(const RSContext * Context,const string & OutputDirectory,const string & RSSourceFileName,const string & BitCodeFileName)119 RSReflectionCpp::RSReflectionCpp(const RSContext *Context,
120                                  const string &OutputDirectory,
121                                  const string &RSSourceFileName,
122                                  const string &BitCodeFileName)
123     : mRSContext(Context), mRSSourceFilePath(RSSourceFileName),
124       mBitCodeFilePath(BitCodeFileName), mOutputDirectory(OutputDirectory),
125       mNextExportVarSlot(0), mNextExportFuncSlot(0), mNextExportForEachSlot(0) {
126   mCleanedRSFileName = RootNameFromRSFileName(mRSSourceFilePath);
127   mClassName = "ScriptC_" + mCleanedRSFileName;
128 }
129 
~RSReflectionCpp()130 RSReflectionCpp::~RSReflectionCpp() {}
131 
reflect()132 bool RSReflectionCpp::reflect() {
133   writeHeaderFile();
134   writeImplementationFile();
135 
136   return true;
137 }
138 
139 #define RS_TYPE_CLASS_NAME_PREFIX "ScriptField_"
140 
writeHeaderFile()141 bool RSReflectionCpp::writeHeaderFile() {
142   // Create the file and write the license note.
143   if (!mOut.startFile(mOutputDirectory, mClassName + ".h", mRSSourceFilePath,
144                       mRSContext->getLicenseNote(), false,
145                       mRSContext->getVerbose())) {
146     return false;
147   }
148 
149   mOut.indent() << "#include \"RenderScript.h\"\n\n";
150   // Add NOLINT to suppress clang-tidy warnings of "using namespace".
151   // Keep "using namespace" to compile existing code.
152   mOut.indent() << "using namespace android::RSC;  // NOLINT\n\n";
153 
154   mOut.comment("This class encapsulates access to the exported elements of the script.  "
155                "Typically, you would instantiate this class once, call the set_* methods "
156                "for each of the exported global variables you want to change, then call "
157                "one of the forEach_ methods to invoke a kernel.");
158   mOut.indent() << "class " << mClassName << " : public android::RSC::ScriptC";
159   mOut.startBlock();
160 
161   mOut.decreaseIndent();
162   mOut.indent() << "private:\n";
163   mOut.increaseIndent();
164 
165   genFieldsToStoreExportVariableValues();
166   genTypeInstancesUsedInForEach();
167   genFieldsForAllocationTypeVerification();
168 
169   mOut.decreaseIndent();
170   mOut.indent() << "public:\n";
171   mOut.increaseIndent();
172 
173   // Generate the constructor and destructor declarations.
174   mOut.indent() << mClassName << "(android::RSC::sp<android::RSC::RS> rs);\n";
175   mOut.indent() << "virtual ~" << mClassName << "();\n\n";
176 
177   genExportVariablesGetterAndSetter();
178   genForEachDeclarations();
179   genExportFunctionDeclarations();
180 
181   mOut.endBlock(true);
182   mOut.closeFile();
183   return true;
184 }
185 
genTypeInstancesUsedInForEach()186 void RSReflectionCpp::genTypeInstancesUsedInForEach() {
187   for (auto I = mRSContext->export_foreach_begin(),
188             E = mRSContext->export_foreach_end();
189        I != E; I++) {
190     const RSExportForEach *EF = *I;
191     const RSExportType *OET = EF->getOutType();
192 
193     if (OET) {
194       genTypeInstanceFromPointer(OET);
195     }
196 
197     const RSExportForEach::InTypeVec &InTypes = EF->getInTypes();
198 
199     for (RSExportForEach::InTypeIter BI = InTypes.begin(),
200          EI = InTypes.end(); BI != EI; BI++) {
201 
202       genTypeInstanceFromPointer(*BI);
203     }
204   }
205 }
206 
genFieldsForAllocationTypeVerification()207 void RSReflectionCpp::genFieldsForAllocationTypeVerification() {
208   bool CommentAdded = false;
209   for (std::set<std::string>::iterator I = mTypesToCheck.begin(),
210                                        E = mTypesToCheck.end();
211        I != E; I++) {
212     if (!CommentAdded) {
213       mOut.comment("The following elements are used to verify the types of "
214                    "allocations passed to kernels.");
215       CommentAdded = true;
216     }
217     mOut.indent() << "android::RSC::sp<const android::RSC::Element> "
218                   << kRsElemPrefix << *I << ";\n";
219   }
220 }
221 
genFieldsToStoreExportVariableValues()222 void RSReflectionCpp::genFieldsToStoreExportVariableValues() {
223   bool CommentAdded = false;
224   for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
225                                             E = mRSContext->export_vars_end();
226        I != E; I++) {
227     const RSExportVar *ev = *I;
228     if (ev->isConst()) {
229       continue;
230     }
231     if (!CommentAdded) {
232       mOut.comment("For each non-const variable exported by the script, we "
233                    "have an equivalent field.  This field contains the last "
234                    "value this variable was set to using the set_ method.  "
235                    "This may not be current value of the variable in the "
236                    "script, as the script is free to modify its internal "
237                    "variable without changing this field.  If the script "
238                    "initializes the exported variable, the constructor will "
239                    "initialize this field to the same value.");
240       CommentAdded = true;
241     }
242     mOut.indent() << GetTypeName(ev->getType()) << " " RS_EXPORT_VAR_PREFIX
243                   << ev->getName() << ";\n";
244   }
245 }
246 
genForEachDeclarations()247 void RSReflectionCpp::genForEachDeclarations() {
248   bool CommentAdded = false;
249   for (RSContext::const_export_foreach_iterator
250            I = mRSContext->export_foreach_begin(),
251            E = mRSContext->export_foreach_end();
252        I != E; I++) {
253     const RSExportForEach *ForEach = *I;
254 
255     if (ForEach->isDummyRoot()) {
256       mOut.indent() << "// No forEach_root(...)\n";
257       continue;
258     }
259 
260     if (!CommentAdded) {
261       mOut.comment("For each kernel of the script corresponds one method.  "
262                    "That method queues the kernel for execution.  The kernel "
263                    "may not have completed nor even started by the time this "
264                    "function returns.  Calls that extract the data out of the "
265                    "output allocation will wait for the kernels to complete.");
266       CommentAdded = true;
267     }
268 
269     std::string FunctionStart = "void forEach_" + ForEach->getName() + "(";
270     mOut.indent() << FunctionStart;
271 
272     ArgumentList Arguments;
273     const RSExportForEach::InVec &Ins = ForEach->getIns();
274     for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end();
275          BI != EI; BI++) {
276 
277       Arguments.push_back(Argument(kAllocationSp, (*BI)->getName()));
278     }
279 
280     if (ForEach->hasOut() || ForEach->hasReturn()) {
281       Arguments.push_back(Argument(kAllocationSp, "aout"));
282     }
283 
284     const RSExportRecordType *ERT = ForEach->getParamPacketType();
285     if (ERT) {
286       for (RSExportForEach::const_param_iterator i = ForEach->params_begin(),
287                                                  e = ForEach->params_end();
288            i != e; i++) {
289         RSReflectionTypeData rtd;
290         (*i)->getType()->convertToRTD(&rtd);
291         Arguments.push_back(Argument(rtd.type->c_name, (*i)->getName()));
292       }
293     }
294     genArguments(Arguments, FunctionStart.length());
295     mOut << ");\n";
296   }
297 }
298 
genExportFunctionDeclarations()299 void RSReflectionCpp::genExportFunctionDeclarations() {
300   for (RSContext::const_export_func_iterator
301            I = mRSContext->export_funcs_begin(),
302            E = mRSContext->export_funcs_end();
303        I != E; I++) {
304     const RSExportFunc *ef = *I;
305 
306     makeFunctionSignature(false, ef);
307   }
308 }
309 
310 // forEach_* implementation
genExportForEachBodies()311 void RSReflectionCpp::genExportForEachBodies() {
312   uint32_t slot = 0;
313   for (auto I = mRSContext->export_foreach_begin(),
314             E = mRSContext->export_foreach_end();
315        I != E; I++, slot++) {
316     const RSExportForEach *ef = *I;
317     if (ef->isDummyRoot()) {
318       mOut.indent() << "// No forEach_root(...)\n";
319       continue;
320     }
321 
322     ArgumentList Arguments;
323     std::string FunctionStart =
324         "void " + mClassName + "::forEach_" + ef->getName() + "(";
325     mOut.indent() << FunctionStart;
326 
327     if (ef->hasIns()) {
328       // FIXME: Add support for kernels with multiple inputs.
329       slangAssert(ef->getIns().size() == 1);
330       Arguments.push_back(Argument(kAllocationSp, "ain"));
331     }
332 
333     if (ef->hasOut() || ef->hasReturn()) {
334       Arguments.push_back(Argument(kAllocationSp, "aout"));
335     }
336 
337     const RSExportRecordType *ERT = ef->getParamPacketType();
338     if (ERT) {
339       for (RSExportForEach::const_param_iterator i = ef->params_begin(),
340                                                  e = ef->params_end();
341            i != e; i++) {
342         RSReflectionTypeData rtd;
343         (*i)->getType()->convertToRTD(&rtd);
344         Arguments.push_back(Argument(rtd.type->c_name, (*i)->getName()));
345       }
346     }
347     genArguments(Arguments, FunctionStart.length());
348     mOut << ")";
349     mOut.startBlock();
350 
351     const RSExportType *OET = ef->getOutType();
352     const RSExportForEach::InTypeVec &InTypes = ef->getInTypes();
353     if (ef->hasIns()) {
354       // FIXME: Add support for kernels with multiple inputs.
355       slangAssert(ef->getIns().size() == 1);
356       genTypeCheck(InTypes[0], "ain");
357     }
358     if (OET) {
359       genTypeCheck(OET, "aout");
360     }
361 
362     // TODO Add the appropriate dimension checking code, as seen in
363     // slang_rs_reflection.cpp.
364 
365     std::string FieldPackerName = ef->getName() + "_fp";
366     if (ERT) {
367       if (genCreateFieldPacker(ERT, FieldPackerName.c_str())) {
368         genPackVarOfType(ERT, nullptr, FieldPackerName.c_str());
369       }
370     }
371     mOut.indent() << "forEach(" << slot << ", ";
372 
373     if (ef->hasIns()) {
374       // FIXME: Add support for kernels with multiple inputs.
375       slangAssert(ef->getIns().size() == 1);
376       mOut << "ain, ";
377     } else {
378       mOut << "NULL, ";
379     }
380 
381     if (ef->hasOut() || ef->hasReturn()) {
382       mOut << "aout, ";
383     } else {
384       mOut << "NULL, ";
385     }
386 
387     // FIXME (no support for usrData with C++ kernels)
388     mOut << "NULL, 0);\n";
389     mOut.endBlock();
390   }
391 }
392 
393 // invoke_* implementation
genExportFunctionBodies()394 void RSReflectionCpp::genExportFunctionBodies() {
395   uint32_t slot = 0;
396   // Reflect export function
397   for (auto I = mRSContext->export_funcs_begin(),
398             E = mRSContext->export_funcs_end();
399        I != E; I++) {
400     const RSExportFunc *ef = *I;
401 
402     makeFunctionSignature(true, ef);
403     mOut.startBlock();
404     const RSExportRecordType *params = ef->getParamPacketType();
405     size_t param_len = 0;
406     if (params) {
407       param_len = params->getAllocSize();
408       if (genCreateFieldPacker(params, "__fp")) {
409         genPackVarOfType(params, nullptr, "__fp");
410       }
411     }
412 
413     mOut.indent() << "invoke(" << slot;
414     if (params) {
415       mOut << ", __fp.getData(), " << param_len << ");\n";
416     } else {
417       mOut << ", NULL, 0);\n";
418     }
419     mOut.endBlock();
420 
421     slot++;
422   }
423 }
424 
genEncodedBitCode()425 bool RSReflectionCpp::genEncodedBitCode() {
426   FILE *pfin = fopen(mBitCodeFilePath.c_str(), "rb");
427   if (pfin == nullptr) {
428     fprintf(stderr, "Error: could not read file %s\n",
429             mBitCodeFilePath.c_str());
430     return false;
431   }
432 
433   unsigned char buf[16];
434   int read_length;
435   mOut.indent() << "static const unsigned char __txt[] =";
436   mOut.startBlock();
437   while ((read_length = fread(buf, 1, sizeof(buf), pfin)) > 0) {
438     mOut.indent();
439     for (int i = 0; i < read_length; i++) {
440       char buf2[16];
441       snprintf(buf2, sizeof(buf2), "0x%02x,", buf[i]);
442       mOut << buf2;
443     }
444     mOut << "\n";
445   }
446   mOut.endBlock(true);
447   mOut << "\n";
448   return true;
449 }
450 
writeImplementationFile()451 bool RSReflectionCpp::writeImplementationFile() {
452   if (!mOut.startFile(mOutputDirectory, mClassName + ".cpp", mRSSourceFilePath,
453                       mRSContext->getLicenseNote(), false,
454                       mRSContext->getVerbose())) {
455     return false;
456   }
457 
458   // Front matter
459   mOut.indent() << "#include \"" << mClassName << ".h\"\n\n";
460 
461   genEncodedBitCode();
462   mOut.indent() << "\n\n";
463 
464   // Constructor
465   const std::string &packageName = mRSContext->getReflectJavaPackageName();
466   mOut.indent() << mClassName << "::" << mClassName
467                 << "(android::RSC::sp<android::RSC::RS> rs):\n"
468                    "        ScriptC(rs, __txt, sizeof(__txt), \""
469                 << mCleanedRSFileName << "\", " << mCleanedRSFileName.length()
470                 << ", \"/data/data/" << packageName << "/app\", sizeof(\""
471                 << packageName << "\"))";
472   mOut.startBlock();
473   for (std::set<std::string>::iterator I = mTypesToCheck.begin(),
474                                        E = mTypesToCheck.end();
475        I != E; I++) {
476     mOut.indent() << kRsElemPrefix << *I << " = android::RSC::Element::" << *I
477                   << "(mRS);\n";
478   }
479 
480   for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
481                                             E = mRSContext->export_vars_end();
482        I != E; I++) {
483     const RSExportVar *EV = *I;
484     if (!EV->getInit().isUninit()) {
485       genInitExportVariable(EV->getType(), EV->getName(), EV->getInit());
486     } else {
487       genZeroInitExportVariable(EV->getName());
488     }
489   }
490   mOut.endBlock();
491 
492   // Destructor
493   mOut.indent() << mClassName << "::~" << mClassName << "()";
494   mOut.startBlock();
495   mOut.endBlock();
496 
497   // Function bodies
498   genExportForEachBodies();
499   genExportFunctionBodies();
500 
501   mOut.closeFile();
502   return true;
503 }
504 
genExportVariablesGetterAndSetter()505 void RSReflectionCpp::genExportVariablesGetterAndSetter() {
506   mOut.comment("Methods to set and get the variables exported by the script. "
507                "Const variables will not have a setter.\n\n"
508                "Note that the value returned by the getter may not be the "
509                "current value of the variable in the script.  The getter will "
510                "return the initial value of the variable (as defined in the "
511                "script) or the the last value set by using the setter method.  "
512                "The script is free to modify its value independently.");
513   for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
514                                             E = mRSContext->export_vars_end();
515        I != E; I++) {
516     const RSExportVar *EV = *I;
517     const RSExportType *ET = EV->getType();
518 
519     switch (ET->getClass()) {
520     case RSExportType::ExportClassPrimitive: {
521       genGetterAndSetter(static_cast<const RSExportPrimitiveType *>(ET), EV);
522       break;
523     }
524     case RSExportType::ExportClassPointer: {
525       // TODO Deprecate this.
526       genPointerTypeExportVariable(EV);
527       break;
528     }
529     case RSExportType::ExportClassVector: {
530       genGetterAndSetter(static_cast<const RSExportVectorType *>(ET), EV);
531       break;
532     }
533     case RSExportType::ExportClassMatrix: {
534       genMatrixTypeExportVariable(EV);
535       break;
536     }
537     case RSExportType::ExportClassConstantArray: {
538       genGetterAndSetter(static_cast<const RSExportConstantArrayType *>(ET),
539                          EV);
540       break;
541     }
542     case RSExportType::ExportClassRecord: {
543       genGetterAndSetter(static_cast<const RSExportRecordType *>(ET), EV);
544       break;
545     }
546     default: { slangAssert(false && "Unknown class of type"); }
547     }
548   }
549 }
550 
genGetterAndSetter(const RSExportPrimitiveType * EPT,const RSExportVar * EV)551 void RSReflectionCpp::genGetterAndSetter(const RSExportPrimitiveType *EPT,
552                                          const RSExportVar *EV) {
553   RSReflectionTypeData rtd;
554   EPT->convertToRTD(&rtd);
555   std::string TypeName = GetTypeName(EPT);
556 
557   if (!EV->isConst()) {
558     mOut.indent() << "void set_" << EV->getName() << "(" << TypeName << " v)";
559     mOut.startBlock();
560     mOut.indent() << "setVar(" << getNextExportVarSlot() << ", ";
561     if (EPT->isRSObjectType()) {
562       mOut << "v";
563    } else {
564       mOut << "&v, sizeof(v)";
565     }
566     mOut << ");\n";
567     mOut.indent() << RS_EXPORT_VAR_PREFIX << EV->getName() << " = v;\n";
568     mOut.endBlock();
569   }
570   mOut.indent() << TypeName << " get_" << EV->getName() << "() const";
571   mOut.startBlock();
572   if (EV->isConst()) {
573     const clang::APValue &val = EV->getInit();
574     bool isBool = !strcmp(TypeName.c_str(), "bool");
575     mOut.indent() << "return ";
576     genInitValue(val, isBool);
577     mOut << ";\n";
578   } else {
579     mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << EV->getName()
580                   << ";\n";
581   }
582   mOut.endBlock();
583 }
584 
genPointerTypeExportVariable(const RSExportVar * EV)585 void RSReflectionCpp::genPointerTypeExportVariable(const RSExportVar *EV) {
586   const RSExportType *ET = EV->getType();
587 
588   slangAssert((ET->getClass() == RSExportType::ExportClassPointer) &&
589               "Variable should be type of pointer here");
590 
591   std::string TypeName = GetTypeName(ET);
592   const std::string &VarName = EV->getName();
593 
594   RSReflectionTypeData rtd;
595   EV->getType()->convertToRTD(&rtd);
596   uint32_t slot = getNextExportVarSlot();
597 
598   if (!EV->isConst()) {
599     mOut.indent() << "void bind_" << VarName << "(" << TypeName << " v)";
600     mOut.startBlock();
601     mOut.indent() << "bindAllocation(v, " << slot << ");\n";
602     mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = v;\n";
603     mOut.endBlock();
604   }
605   mOut.indent() << TypeName << " get_" << VarName << "() const";
606   mOut.startBlock();
607   if (EV->isConst()) {
608     const clang::APValue &val = EV->getInit();
609     bool isBool = !strcmp(TypeName.c_str(), "bool");
610     mOut.indent() << "return ";
611     genInitValue(val, isBool);
612     mOut << ";\n";
613   } else {
614     mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << VarName << ";\n";
615   }
616   mOut.endBlock();
617 }
618 
genGetterAndSetter(const RSExportVectorType * EVT,const RSExportVar * EV)619 void RSReflectionCpp::genGetterAndSetter(const RSExportVectorType *EVT,
620                                          const RSExportVar *EV) {
621   slangAssert(EVT != nullptr);
622 
623   RSReflectionTypeData rtd;
624   EVT->convertToRTD(&rtd);
625 
626   if (!EV->isConst()) {
627     mOut.indent() << "void set_" << EV->getName() << "("
628                   << rtd.type->rs_c_vector_prefix << EVT->getNumElement()
629                   << " v)";
630     mOut.startBlock();
631     mOut.indent() << "setVar(" << getNextExportVarSlot()
632                   << ", &v, sizeof(v));\n";
633     mOut.indent() << RS_EXPORT_VAR_PREFIX << EV->getName() << " = v;\n";
634     mOut.endBlock();
635   }
636   mOut.indent() << rtd.type->rs_c_vector_prefix << EVT->getNumElement()
637                 << " get_" << EV->getName() << "() const";
638   mOut.startBlock();
639   if (EV->isConst()) {
640     const clang::APValue &val = EV->getInit();
641     mOut.indent() << "return ";
642     genInitValue(val, false);
643     mOut << ";\n";
644   } else {
645     mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << EV->getName()
646                   << ";\n";
647   }
648   mOut.endBlock();
649 }
650 
genMatrixTypeExportVariable(const RSExportVar * EV)651 void RSReflectionCpp::genMatrixTypeExportVariable(const RSExportVar *EV) {
652   uint32_t slot = getNextExportVarSlot();
653   stringstream tmp;
654   tmp << slot;
655 
656   const RSExportType *ET = EV->getType();
657   if (ET->getName() == "rs_matrix4x4") {
658     mOut.indent() << "void set_" << EV->getName() << "(float v[16])";
659     mOut.startBlock();
660     mOut.indent() << "setVar(" << tmp.str() << ", v, sizeof(float)*16);\n";
661     mOut.endBlock();
662   } else if (ET->getName() == "rs_matrix3x3") {
663     mOut.indent() << "void set_" << EV->getName() << "(float v[9])";
664     mOut.startBlock();
665     mOut.indent() << "setVar(" << tmp.str() << ", v, sizeof(float)*9);";
666     mOut.endBlock();
667   } else if (ET->getName() == "rs_matrix2x2") {
668     mOut.indent() << "void set_" << EV->getName() << "(float v[4])";
669     mOut.startBlock();
670     mOut.indent() << "setVar(" << tmp.str() << ", v, sizeof(float)*4);";
671     mOut.endBlock();
672   } else {
673     mOut.indent() << "#error: TODO: " << ET->getName();
674     slangAssert(false);
675   }
676 }
677 
genGetterAndSetter(const RSExportConstantArrayType * AT,const RSExportVar * EV)678 void RSReflectionCpp::genGetterAndSetter(const RSExportConstantArrayType *AT,
679                                          const RSExportVar *EV) {
680   std::stringstream ArraySpec;
681   const RSExportType *ET = EV->getType();
682 
683   const RSExportConstantArrayType *CAT =
684       static_cast<const RSExportConstantArrayType *>(ET);
685 
686   uint32_t slot = getNextExportVarSlot();
687   stringstream tmp;
688   tmp << slot;
689 
690   ArraySpec << CAT->getNumElement();
691   mOut.indent() << "void set_" << EV->getName() << "(" << GetTypeName(EV->getType()) << " v "
692       << GetTypeName(EV->getType(), false) << ")";
693   mOut.startBlock();
694   mOut.indent() << "setVar(" << tmp.str() << ", v, sizeof(" << GetTypeName(EV->getType()) + ") *"
695       << ArraySpec.str() << ");";
696   mOut.endBlock();
697 }
698 
genGetterAndSetter(const RSExportRecordType * ERT,const RSExportVar * EV)699 void RSReflectionCpp::genGetterAndSetter(const RSExportRecordType *ERT,
700                                          const RSExportVar *EV) {
701   slangAssert(false);
702 }
703 
makeFunctionSignature(bool isDefinition,const RSExportFunc * ef)704 void RSReflectionCpp::makeFunctionSignature(bool isDefinition,
705                                             const RSExportFunc *ef) {
706   mOut.indent() << "void ";
707   if (isDefinition) {
708     mOut << mClassName << "::";
709   }
710   mOut << "invoke_" << ef->getName() << "(";
711 
712   if (ef->getParamPacketType()) {
713     bool FirstArg = true;
714     for (RSExportFunc::const_param_iterator i = ef->params_begin(),
715                                             e = ef->params_end();
716          i != e; i++) {
717       if (!FirstArg) {
718         mOut << ", ";
719       } else {
720         FirstArg = false;
721       }
722       mOut << GetTypeName((*i)->getType()) << " " << (*i)->getName();
723     }
724   }
725 
726   if (isDefinition) {
727     mOut << ")";
728   } else {
729     mOut << ");\n";
730   }
731 }
732 
genArguments(const ArgumentList & Arguments,int Offset)733 void RSReflectionCpp::genArguments(const ArgumentList &Arguments, int Offset) {
734   bool FirstArg = true;
735 
736   for (ArgumentList::const_iterator I = Arguments.begin(), E = Arguments.end();
737        I != E; I++) {
738     if (!FirstArg) {
739       mOut << ",\n";
740       mOut.indent() << string(Offset, ' ');
741     } else {
742       FirstArg = false;
743     }
744 
745     mOut << I->Type << " " << I->Name;
746     if (!I->DefaultValue.empty()) {
747       mOut << " = " << I->DefaultValue;
748     }
749   }
750 }
751 
genCreateFieldPacker(const RSExportType * ET,const char * FieldPackerName)752 bool RSReflectionCpp::genCreateFieldPacker(const RSExportType *ET,
753                                            const char *FieldPackerName) {
754   size_t AllocSize = ET->getAllocSize();
755 
756   if (AllocSize > 0) {
757     mOut.indent() << "android::RSC::FieldPacker " << FieldPackerName << "("
758                   << AllocSize << ");\n";
759     return true;
760   }
761 
762   return false;
763 }
764 
genPackVarOfType(const RSExportType * ET,const char * VarName,const char * FieldPackerName)765 void RSReflectionCpp::genPackVarOfType(const RSExportType *ET,
766                                        const char *VarName,
767                                        const char *FieldPackerName) {
768   switch (ET->getClass()) {
769   case RSExportType::ExportClassPrimitive:
770   case RSExportType::ExportClassVector:
771   case RSExportType::ExportClassPointer:
772   case RSExportType::ExportClassMatrix: {
773     mOut.indent() << FieldPackerName << ".add(" << VarName << ");\n";
774     break;
775   }
776   case RSExportType::ExportClassConstantArray: {
777     /*const RSExportConstantArrayType *ECAT =
778         static_cast<const RSExportConstantArrayType *>(ET);
779 
780     // TODO(zonr): more elegant way. Currently, we obtain the unique index
781     //             variable (this method involves recursive call which means
782     //             we may have more than one level loop, therefore we can't
783     //             always use the same index variable name here) name given
784     //             in the for-loop from counting the '.' in @VarName.
785     unsigned Level = 0;
786     size_t LastDotPos = 0;
787     std::string ElementVarName(VarName);
788 
789   while (LastDotPos != std::string::npos) {
790     LastDotPos = ElementVarName.find_first_of('.', LastDotPos + 1);
791     Level++;
792   }
793   std::string IndexVarName("ct");
794   IndexVarName.append(llvm::utostr(Level));
795 
796   C.indent() << "for (int " << IndexVarName << " = 0; " <<
797                       IndexVarName << " < " << ECAT->getSize() << "; " <<
798                       IndexVarName << "++)";
799   C.startBlock();
800 
801   ElementVarName.append("[" + IndexVarName + "]");
802   genPackVarOfType(C, ECAT->getElementType(), ElementVarName.c_str(),
803                    FieldPackerName);
804 
805   C.endBlock();*/
806     break;
807   }
808   case RSExportType::ExportClassRecord: {
809     const RSExportRecordType *ERT = static_cast<const RSExportRecordType *>(ET);
810     // Relative pos from now on in field packer
811     unsigned Pos = 0;
812 
813     for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(),
814                                                   E = ERT->fields_end();
815          I != E; I++) {
816       const RSExportRecordType::Field *F = *I;
817       std::string FieldName;
818       size_t FieldOffset = F->getOffsetInParent();
819       const RSExportType *T = F->getType();
820       size_t FieldStoreSize = T->getStoreSize();
821       size_t FieldAllocSize = T->getAllocSize();
822 
823       if (VarName != nullptr)
824         FieldName = VarName + ("." + F->getName());
825       else
826         FieldName = F->getName();
827 
828       if (FieldOffset > Pos) {
829         mOut.indent() << FieldPackerName << ".skip(" << (FieldOffset - Pos)
830                       << ");\n";
831       }
832 
833       genPackVarOfType(F->getType(), FieldName.c_str(), FieldPackerName);
834 
835       // There is padding in the field type
836       if (FieldAllocSize > FieldStoreSize) {
837         mOut.indent() << FieldPackerName << ".skip("
838                       << (FieldAllocSize - FieldStoreSize) << ");\n";
839       }
840 
841       Pos = FieldOffset + FieldAllocSize;
842     }
843 
844     // There maybe some padding after the struct
845     if (ERT->getAllocSize() > Pos) {
846       mOut.indent() << FieldPackerName << ".skip(" << ERT->getAllocSize() - Pos
847                     << ");\n";
848     }
849     break;
850   }
851   default: { slangAssert(false && "Unknown class of type"); }
852   }
853 }
854 
genTypeCheck(const RSExportType * ET,const char * VarName)855 void RSReflectionCpp::genTypeCheck(const RSExportType *ET,
856                                    const char *VarName) {
857   mOut.indent() << "// Type check for " << VarName << "\n";
858 
859   if (ET->getClass() == RSExportType::ExportClassPointer) {
860     const RSExportPointerType *EPT =
861         static_cast<const RSExportPointerType *>(ET);
862     ET = EPT->getPointeeType();
863   }
864 
865   std::string TypeName;
866   switch (ET->getClass()) {
867   case RSExportType::ExportClassPrimitive:
868   case RSExportType::ExportClassVector:
869   case RSExportType::ExportClassRecord: {
870     TypeName = ET->getElementName();
871     break;
872   }
873 
874   default:
875     break;
876   }
877 
878   if (!TypeName.empty()) {
879     mOut.indent() << "if (!" << VarName
880                   << "->getType()->getElement()->isCompatible("
881                   << kRsElemPrefix << TypeName << "))";
882     mOut.startBlock();
883     mOut.indent() << "mRS->throwError(RS_ERROR_RUNTIME_ERROR, "
884                      "\"Incompatible type\");\n";
885     mOut.indent() << "return;\n";
886     mOut.endBlock();
887   }
888 }
889 
genTypeInstanceFromPointer(const RSExportType * ET)890 void RSReflectionCpp::genTypeInstanceFromPointer(const RSExportType *ET) {
891   if (ET->getClass() == RSExportType::ExportClassPointer) {
892     // For pointer parameters to original forEach kernels.
893     const RSExportPointerType *EPT =
894         static_cast<const RSExportPointerType *>(ET);
895     genTypeInstance(EPT->getPointeeType());
896   } else {
897     // For handling pass-by-value kernel parameters.
898     genTypeInstance(ET);
899   }
900 }
901 
genTypeInstance(const RSExportType * ET)902 void RSReflectionCpp::genTypeInstance(const RSExportType *ET) {
903   switch (ET->getClass()) {
904   case RSExportType::ExportClassPrimitive:
905   case RSExportType::ExportClassVector:
906   case RSExportType::ExportClassConstantArray:
907   case RSExportType::ExportClassRecord: {
908     std::string TypeName = ET->getElementName();
909     mTypesToCheck.insert(TypeName);
910     break;
911   }
912 
913   default:
914     break;
915   }
916 }
917 
genInitExportVariable(const RSExportType * ET,const std::string & VarName,const clang::APValue & Val)918 void RSReflectionCpp::genInitExportVariable(const RSExportType *ET,
919                                             const std::string &VarName,
920                                             const clang::APValue &Val) {
921   slangAssert(!Val.isUninit() && "Not a valid initializer");
922 
923   switch (ET->getClass()) {
924   case RSExportType::ExportClassPrimitive: {
925     const RSExportPrimitiveType *EPT =
926         static_cast<const RSExportPrimitiveType *>(ET);
927     if (EPT->getType() == DataTypeBoolean) {
928       genInitBoolExportVariable(VarName, Val);
929     } else {
930       genInitPrimitiveExportVariable(VarName, Val);
931     }
932     break;
933   }
934   case RSExportType::ExportClassPointer: {
935     if (!Val.isInt() || Val.getInt().getSExtValue() != 0)
936       std::cerr << "Initializer which is non-NULL to pointer type variable "
937                    "will be ignored" << std::endl;
938     break;
939   }
940   case RSExportType::ExportClassVector: {
941     const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET);
942     switch (Val.getKind()) {
943     case clang::APValue::Int:
944     case clang::APValue::Float: {
945       for (unsigned i = 0; i < EVT->getNumElement(); i++) {
946         std::string Name = VarName + "." + getVectorAccessor(i);
947         genInitPrimitiveExportVariable(Name, Val);
948       }
949       break;
950     }
951     case clang::APValue::Vector: {
952       unsigned NumElements = std::min(
953           static_cast<unsigned>(EVT->getNumElement()), Val.getVectorLength());
954       for (unsigned i = 0; i < NumElements; i++) {
955         const clang::APValue &ElementVal = Val.getVectorElt(i);
956         std::string Name = VarName + "." + getVectorAccessor(i);
957         genInitPrimitiveExportVariable(Name, ElementVal);
958       }
959       break;
960     }
961     case clang::APValue::MemberPointer:
962     case clang::APValue::Uninitialized:
963     case clang::APValue::ComplexInt:
964     case clang::APValue::ComplexFloat:
965     case clang::APValue::LValue:
966     case clang::APValue::Array:
967     case clang::APValue::Struct:
968     case clang::APValue::Union:
969     case clang::APValue::AddrLabelDiff: {
970       slangAssert(false && "Unexpected type of value of initializer.");
971     }
972     }
973     break;
974   }
975   case RSExportType::ExportClassMatrix:
976   case RSExportType::ExportClassConstantArray:
977   case RSExportType::ExportClassRecord: {
978     slangAssert(false && "Unsupported initializer for record/matrix/constant "
979                          "array type variable currently");
980     break;
981   }
982   default: { slangAssert(false && "Unknown class of type"); }
983   }
984 }
985 
getVectorAccessor(unsigned Index)986 const char *RSReflectionCpp::getVectorAccessor(unsigned Index) {
987   static const char *VectorAccessorMap[] = {/* 0 */ "x",
988                                             /* 1 */ "y",
989                                             /* 2 */ "z",
990                                             /* 3 */ "w",
991   };
992 
993   slangAssert((Index < (sizeof(VectorAccessorMap) / sizeof(const char *))) &&
994               "Out-of-bound index to access vector member");
995 
996   return VectorAccessorMap[Index];
997 }
998 
genZeroInitExportVariable(const std::string & VarName)999 void RSReflectionCpp::genZeroInitExportVariable(const std::string &VarName) {
1000   mOut.indent() << "memset(&" << RS_EXPORT_VAR_PREFIX << VarName
1001                 << ", 0, sizeof(" << RS_EXPORT_VAR_PREFIX << VarName << "));\n";
1002 }
1003 
1004 void
genInitPrimitiveExportVariable(const std::string & VarName,const clang::APValue & Val)1005 RSReflectionCpp::genInitPrimitiveExportVariable(const std::string &VarName,
1006                                                 const clang::APValue &Val) {
1007   slangAssert(!Val.isUninit() && "Not a valid initializer");
1008 
1009   mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = ";
1010   genInitValue(Val);
1011   mOut << ";\n";
1012 }
1013 
genInitValue(const clang::APValue & Val,bool asBool)1014 void RSReflectionCpp::genInitValue(const clang::APValue &Val, bool asBool) {
1015   switch (Val.getKind()) {
1016   case clang::APValue::Int: {
1017     const llvm::APInt &api = Val.getInt();
1018     if (asBool) {
1019       mOut << ((api.getSExtValue() == 0) ? "false" : "true");
1020     } else {
1021       // TODO: Handle unsigned correctly for C++
1022       mOut << api.getSExtValue();
1023       if (api.getBitWidth() > 32) {
1024         mOut << "L";
1025       }
1026     }
1027     break;
1028   }
1029 
1030   case clang::APValue::Float: {
1031     const llvm::APFloat &apf = Val.getFloat();
1032     llvm::SmallString<30> s;
1033     apf.toString(s);
1034     mOut << s.c_str();
1035     if (&apf.getSemantics() == &llvm::APFloat::IEEEsingle) {
1036       if (s.count('.') == 0) {
1037         mOut << ".f";
1038       } else {
1039         mOut << "f";
1040       }
1041     }
1042     break;
1043   }
1044 
1045   case clang::APValue::ComplexInt:
1046   case clang::APValue::ComplexFloat:
1047   case clang::APValue::LValue:
1048   case clang::APValue::Vector: {
1049     slangAssert(false && "Primitive type cannot have such kind of initializer");
1050     break;
1051   }
1052 
1053   default: { slangAssert(false && "Unknown kind of initializer"); }
1054   }
1055 }
1056 
genInitBoolExportVariable(const std::string & VarName,const clang::APValue & Val)1057 void RSReflectionCpp::genInitBoolExportVariable(const std::string &VarName,
1058                                                 const clang::APValue &Val) {
1059   slangAssert(!Val.isUninit() && "Not a valid initializer");
1060   slangAssert((Val.getKind() == clang::APValue::Int) &&
1061               "Bool type has wrong initial APValue");
1062 
1063   mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = "
1064                 << ((Val.getInt().getSExtValue() == 0) ? "false" : "true")
1065                 << ";";
1066 }
1067 
1068 } // namespace slang
1069