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