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