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