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