Home | History | Annotate | Download | only in slang
      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 
     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 
     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 
    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 
    130 RSReflectionCpp::~RSReflectionCpp() {}
    131 
    132 bool RSReflectionCpp::reflect() {
    133   writeHeaderFile();
    134   writeImplementationFile();
    135 
    136   return true;
    137 }
    138 
    139 #define RS_TYPE_CLASS_NAME_PREFIX "ScriptField_"
    140 
    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 
    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 
    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 
    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 
    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 
    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
    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
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    699 void RSReflectionCpp::genGetterAndSetter(const RSExportRecordType *ERT,
    700                                          const RSExportVar *EV) {
    701   slangAssert(false);
    702 }
    703 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
   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 
   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 
   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