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