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