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