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