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