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