slang_rs_reflection_cpp.cpp revision 1c6b927b4c59fabf44db846855ff5c4cfd48aa53
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
29#include "os_sep.h"
30#include "slang_rs_context.h"
31#include "slang_rs_export_var.h"
32#include "slang_rs_export_foreach.h"
33#include "slang_rs_export_func.h"
34#include "slang_rs_export_reduce.h"
35#include "slang_rs_reflect_utils.h"
36#include "slang_version.h"
37
38#include "slang_rs_reflection_cpp.h"
39
40using namespace std;
41
42namespace slang {
43
44const char kRsTypeItemClassName[] = "Item";
45const char kRsElemPrefix[] = "__rs_elem_";
46// The name of the Allocation type that is reflected in C++
47const char kAllocationSp[] = "android::RSC::sp<android::RSC::Allocation>";
48const char kConstRsScriptCall[] = "const RsScriptCall";
49
50static const char *GetMatrixTypeName(const RSExportMatrixType *EMT) {
51  static const char *MatrixTypeCNameMap[] = {
52      "rs_matrix2x2", "rs_matrix3x3", "rs_matrix4x4",
53  };
54  unsigned Dim = EMT->getDim();
55
56  if ((Dim - 2) < (sizeof(MatrixTypeCNameMap) / sizeof(const char *)))
57    return MatrixTypeCNameMap[EMT->getDim() - 2];
58
59  slangAssert(false && "GetMatrixTypeName : Unsupported matrix dimension");
60  return nullptr;
61}
62
63static std::string GetTypeName(const RSExportType *ET, bool Brackets = true) {
64  switch (ET->getClass()) {
65  case RSExportType::ExportClassPrimitive: {
66    const RSExportPrimitiveType *EPT =
67        static_cast<const RSExportPrimitiveType *>(ET);
68    if (EPT->isRSObjectType()) {
69      return std::string("android::RSC::sp<const android::RSC::") +
70             RSExportPrimitiveType::getRSReflectionType(EPT)->c_name + ">";
71    } else {
72      return RSExportPrimitiveType::getRSReflectionType(EPT)->c_name;
73    }
74  }
75  case RSExportType::ExportClassPointer: {
76    const RSExportType *PointeeType =
77        static_cast<const RSExportPointerType *>(ET)->getPointeeType();
78
79    if (PointeeType->getClass() != RSExportType::ExportClassRecord)
80      return kAllocationSp;
81    else
82      return PointeeType->getElementName();
83  }
84  case RSExportType::ExportClassVector: {
85    const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET);
86    std::stringstream VecName;
87    VecName << EVT->getRSReflectionType(EVT)->rs_c_vector_prefix
88            << EVT->getNumElement();
89    return VecName.str();
90  }
91  case RSExportType::ExportClassMatrix: {
92    return GetMatrixTypeName(static_cast<const RSExportMatrixType *>(ET));
93  }
94  case RSExportType::ExportClassConstantArray: {
95    // TODO: Fix this for C arrays!
96    const RSExportConstantArrayType *CAT =
97        static_cast<const RSExportConstantArrayType *>(ET);
98    std::string ElementTypeName = GetTypeName(CAT->getElementType());
99    if (Brackets) {
100      ElementTypeName.append("[]");
101    }
102    return ElementTypeName;
103  }
104  case RSExportType::ExportClassRecord: {
105    // TODO: Fix for C structs!
106    return ET->getElementName() + "." + kRsTypeItemClassName;
107  }
108  default: { slangAssert(false && "Unknown class of type"); }
109  }
110
111  return "";
112}
113
114static bool canExportReduceArrayVariant(const RSExportType *Type) {
115  // FIXME: No half types available for C++ reflection yet
116  if (Type->getElementName().find("F16") == 0) {
117    return false;
118  }
119  return Type->getClass() == RSExportType::ExportClassPrimitive ||
120    Type->getClass() == RSExportType::ExportClassVector;
121}
122
123RSReflectionCpp::RSReflectionCpp(const RSContext *Context,
124                                 const string &OutputDirectory,
125                                 const string &RSSourceFileName,
126                                 const string &BitCodeFileName)
127    : mRSContext(Context), mRSSourceFilePath(RSSourceFileName),
128      mBitCodeFilePath(BitCodeFileName), mOutputDirectory(OutputDirectory),
129      mNextExportVarSlot(0), mNextExportFuncSlot(0), mNextExportForEachSlot(0),
130      mNextExportReduceSlot(0) {
131  mCleanedRSFileName = RootNameFromRSFileName(mRSSourceFilePath);
132  mClassName = "ScriptC_" + mCleanedRSFileName;
133}
134
135RSReflectionCpp::~RSReflectionCpp() {}
136
137bool RSReflectionCpp::reflect() {
138  writeHeaderFile();
139  writeImplementationFile();
140
141  return true;
142}
143
144#define RS_TYPE_CLASS_NAME_PREFIX "ScriptField_"
145
146bool RSReflectionCpp::writeHeaderFile() {
147  // Create the file and write the license note.
148  if (!mOut.startFile(mOutputDirectory, mClassName + ".h", mRSSourceFilePath,
149                      mRSContext->getLicenseNote(), false,
150                      mRSContext->getVerbose())) {
151    return false;
152  }
153
154  mOut.indent() << "#include \"RenderScript.h\"\n\n";
155  mOut.indent() << "using namespace android::RSC;\n\n";
156
157  mOut.comment("This class encapsulates access to the exported elements of the script.  "
158               "Typically, you would instantiate this class once, call the set_* methods "
159               "for each of the exported global variables you want to change, then call "
160               "one of the forEach_ methods to invoke a kernel.");
161  mOut.indent() << "class " << mClassName << " : public android::RSC::ScriptC";
162  mOut.startBlock();
163
164  mOut.decreaseIndent();
165  mOut.indent() << "private:\n";
166  mOut.increaseIndent();
167
168  genFieldsToStoreExportVariableValues();
169  genTypeInstancesUsedInForEach();
170  genTypeInstancesUsedInReduce();
171  genFieldsForAllocationTypeVerification();
172
173  mOut.decreaseIndent();
174  mOut.indent() << "public:\n";
175  mOut.increaseIndent();
176
177  // Generate the constructor and destructor declarations.
178  mOut.indent() << mClassName << "(android::RSC::sp<android::RSC::RS> rs);\n";
179  mOut.indent() << "virtual ~" << mClassName << "();\n\n";
180
181  genExportVariablesGetterAndSetter();
182  genForEachDeclarations();
183  genReduceDeclarations();
184  genExportFunctionDeclarations();
185
186  mOut.endBlock(true);
187  mOut.closeFile();
188  return true;
189}
190
191void RSReflectionCpp::genTypeInstancesUsedInForEach() {
192  for (auto I = mRSContext->export_foreach_begin(),
193            E = mRSContext->export_foreach_end();
194       I != E; I++) {
195    const RSExportForEach *EF = *I;
196    const RSExportType *OET = EF->getOutType();
197
198    if (OET) {
199      genTypeInstanceFromPointer(OET);
200    }
201
202    const RSExportForEach::InTypeVec &InTypes = EF->getInTypes();
203
204    for (RSExportForEach::InTypeIter BI = InTypes.begin(),
205         EI = InTypes.end(); BI != EI; BI++) {
206
207      genTypeInstanceFromPointer(*BI);
208    }
209  }
210}
211
212// Ensure that the type of the reduce kernel is reflected.
213void RSReflectionCpp::genTypeInstancesUsedInReduce() {
214  for (auto I = mRSContext->export_reduce_begin(),
215            E = mRSContext->export_reduce_end();
216       I != E; ++I) {
217    genTypeInstance((*I)->getType());
218  }
219}
220
221void RSReflectionCpp::genFieldsForAllocationTypeVerification() {
222  bool CommentAdded = false;
223  for (std::set<std::string>::iterator I = mTypesToCheck.begin(),
224                                       E = mTypesToCheck.end();
225       I != E; I++) {
226    if (!CommentAdded) {
227      mOut.comment("The following elements are used to verify the types of "
228                   "allocations passed to kernels.");
229      CommentAdded = true;
230    }
231    mOut.indent() << "android::RSC::sp<const android::RSC::Element> "
232                  << kRsElemPrefix << *I << ";\n";
233  }
234}
235
236void RSReflectionCpp::genFieldsToStoreExportVariableValues() {
237  bool CommentAdded = false;
238  for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
239                                            E = mRSContext->export_vars_end();
240       I != E; I++) {
241    const RSExportVar *ev = *I;
242    if (ev->isConst()) {
243      continue;
244    }
245    if (!CommentAdded) {
246      mOut.comment("For each non-const variable exported by the script, we "
247                   "have an equivalent field.  This field contains the last "
248                   "value this variable was set to using the set_ method.  "
249                   "This may not be current value of the variable in the "
250                   "script, as the script is free to modify its internal "
251                   "variable without changing this field.  If the script "
252                   "initializes the exported variable, the constructor will "
253                   "initialize this field to the same value.");
254      CommentAdded = true;
255    }
256    mOut.indent() << GetTypeName(ev->getType()) << " " RS_EXPORT_VAR_PREFIX
257                  << ev->getName() << ";\n";
258  }
259}
260
261void RSReflectionCpp::genForEachDeclarations() {
262  bool CommentAdded = false;
263  for (RSContext::const_export_foreach_iterator
264           I = mRSContext->export_foreach_begin(),
265           E = mRSContext->export_foreach_end();
266       I != E; I++) {
267    const RSExportForEach *ForEach = *I;
268
269    if (ForEach->isDummyRoot()) {
270      mOut.indent() << "// No forEach_root(...)\n";
271      continue;
272    }
273
274    if (!CommentAdded) {
275      mOut.comment("For each kernel of the script corresponds one method.  "
276                   "That method queues the kernel for execution.  The kernel "
277                   "may not have completed nor even started by the time this "
278                   "function returns.  Calls that extract the data out of the "
279                   "output allocation will wait for the kernels to complete.");
280      CommentAdded = true;
281    }
282
283    std::string FunctionStart = "void forEach_" + ForEach->getName() + "(";
284    mOut.indent() << FunctionStart;
285
286    ArgumentList Arguments;
287    const RSExportForEach::InVec &Ins = ForEach->getIns();
288    for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end();
289         BI != EI; BI++) {
290
291      Arguments.push_back(Argument(kAllocationSp, (*BI)->getName()));
292    }
293
294    if (ForEach->hasOut() || ForEach->hasReturn()) {
295      Arguments.push_back(Argument(kAllocationSp, "aout"));
296    }
297
298    const RSExportRecordType *ERT = ForEach->getParamPacketType();
299    if (ERT) {
300      for (RSExportForEach::const_param_iterator i = ForEach->params_begin(),
301                                                 e = ForEach->params_end();
302           i != e; i++) {
303        RSReflectionTypeData rtd;
304        (*i)->getType()->convertToRTD(&rtd);
305        Arguments.push_back(Argument(rtd.type->c_name, (*i)->getName()));
306      }
307    }
308    genArguments(Arguments, FunctionStart.length());
309    mOut << ");\n";
310  }
311}
312
313void RSReflectionCpp::genReduceDeclarations() {
314  bool CommentAdded = false;
315  for (auto I = mRSContext->export_reduce_begin(),
316            E = mRSContext->export_reduce_end(); I != E; I++) {
317    if (!CommentAdded) {
318      mOut.comment("For each reduce kernel of the script, there is an entry "
319                   "point to call the reduce kernel.");
320      CommentAdded = true;
321    }
322
323    makeReduceSignatureAllocationVariant(false, *I);
324    makeReduceSignatureArrayVariant(false, *I);
325  }
326}
327
328void RSReflectionCpp::genExportFunctionDeclarations() {
329  for (RSContext::const_export_func_iterator
330           I = mRSContext->export_funcs_begin(),
331           E = mRSContext->export_funcs_end();
332       I != E; I++) {
333    const RSExportFunc *ef = *I;
334
335    makeFunctionSignature(false, ef);
336  }
337}
338
339// forEach_* implementation
340void RSReflectionCpp::genExportForEachBodies() {
341  uint32_t slot = 0;
342  for (auto I = mRSContext->export_foreach_begin(),
343            E = mRSContext->export_foreach_end();
344       I != E; I++, slot++) {
345    const RSExportForEach *ef = *I;
346    if (ef->isDummyRoot()) {
347      mOut.indent() << "// No forEach_root(...)\n";
348      continue;
349    }
350
351    ArgumentList Arguments;
352    std::string FunctionStart =
353        "void " + mClassName + "::forEach_" + ef->getName() + "(";
354    mOut.indent() << FunctionStart;
355
356    if (ef->hasIns()) {
357      // FIXME: Add support for kernels with multiple inputs.
358      slangAssert(ef->getIns().size() == 1);
359      Arguments.push_back(Argument(kAllocationSp, "ain"));
360    }
361
362    if (ef->hasOut() || ef->hasReturn()) {
363      Arguments.push_back(Argument(kAllocationSp, "aout"));
364    }
365
366    const RSExportRecordType *ERT = ef->getParamPacketType();
367    if (ERT) {
368      for (RSExportForEach::const_param_iterator i = ef->params_begin(),
369                                                 e = ef->params_end();
370           i != e; i++) {
371        RSReflectionTypeData rtd;
372        (*i)->getType()->convertToRTD(&rtd);
373        Arguments.push_back(Argument(rtd.type->c_name, (*i)->getName()));
374      }
375    }
376    genArguments(Arguments, FunctionStart.length());
377    mOut << ")";
378    mOut.startBlock();
379
380    const RSExportType *OET = ef->getOutType();
381    const RSExportForEach::InTypeVec &InTypes = ef->getInTypes();
382    if (ef->hasIns()) {
383      // FIXME: Add support for kernels with multiple inputs.
384      slangAssert(ef->getIns().size() == 1);
385      genTypeCheck(InTypes[0], "ain");
386    }
387    if (OET) {
388      genTypeCheck(OET, "aout");
389    }
390
391    // TODO Add the appropriate dimension checking code, as seen in
392    // slang_rs_reflection.cpp.
393
394    std::string FieldPackerName = ef->getName() + "_fp";
395    if (ERT) {
396      if (genCreateFieldPacker(ERT, FieldPackerName.c_str())) {
397        genPackVarOfType(ERT, nullptr, FieldPackerName.c_str());
398      }
399    }
400    mOut.indent() << "forEach(" << slot << ", ";
401
402    if (ef->hasIns()) {
403      // FIXME: Add support for kernels with multiple inputs.
404      slangAssert(ef->getIns().size() == 1);
405      mOut << "ain, ";
406    } else {
407      mOut << "NULL, ";
408    }
409
410    if (ef->hasOut() || ef->hasReturn()) {
411      mOut << "aout, ";
412    } else {
413      mOut << "NULL, ";
414    }
415
416    // FIXME (no support for usrData with C++ kernels)
417    mOut << "NULL, 0);\n";
418    mOut.endBlock();
419  }
420}
421
422// reduce_* implementation
423void RSReflectionCpp::genExportReduceBodies() {
424  for (auto I = mRSContext->export_reduce_begin(),
425            E = mRSContext->export_reduce_end();
426       I != E; ++I) {
427    const RSExportReduce &Reduce = **I;
428    const RSExportType *Type = Reduce.getType();
429
430    // Allocation variant
431    //
432    // void reduce_foo(sp<Allocation> ain, sp<Allocation> aout,
433    //                 const RsScriptCall *sc);
434    makeReduceSignatureAllocationVariant(true, &Reduce);
435    mOut.startBlock();
436
437    // Type check
438    genTypeCheck(Type, "ain");
439    genTypeCheck(Type, "aout");
440
441    // Dimension check
442    gen1DCheck("ain");
443
444    const uint32_t Slot = getNextExportReduceSlot();
445
446    // Call into RenderScript.
447    mOut.indent() << "reduce(" << Slot << ", "
448                  << "ain, aout, sc);\n";
449    mOut.endBlock();
450
451    if (!canExportReduceArrayVariant(Type)) {
452      continue;
453    }
454
455    // Array variant
456    //
457    // Ty reduce_foo(const ElemTy[] in, uint32_t x1, uint32_t x2, uint32_t inLen);
458    // "Ty" could be different from "ElemTy" in the case of vectors.
459    makeReduceSignatureArrayVariant(true, &Reduce);
460    mOut.startBlock();
461
462    const std::string ReturnType = GetTypeName(Type);
463    const std::string DefaultReturnValue = ReturnType + "()";
464
465    genNullOrEmptyArrayCheck("in", "inLen", DefaultReturnValue);
466
467    RSReflectionTypeData TypeData;
468    Type->convertToRTD(&TypeData);
469    const uint32_t VecSize = TypeData.vecSize;
470    std::string InLength = "inLen";
471    // Adjust the length so that it corresponds to the number of elements in the allocation.
472    if (VecSize > 1) {
473      InLength += " / " + std::to_string(VecSize);
474    }
475    genVectorLengthCompatibilityCheck("inLen", VecSize, DefaultReturnValue);
476
477    mOut.indent() << "if (x1 >= x2 || x2 > " << InLength << ")";
478    mOut.startBlock();
479    mOut.indent() << "mRS->throwError(RS_ERROR_RUNTIME_ERROR, "
480                  << "\"Input bounds are invalid\");\n";
481    mOut.indent() << "return " << DefaultReturnValue << ";\n";
482    mOut.endBlock();
483
484    mOut.indent() << kAllocationSp
485                  << " ain = android::RSC::Allocation::createSized(mRS, "
486                  << kRsElemPrefix << Type->getElementName() << ", "
487                  << "x2 - x1);\n";
488
489    mOut.indent() << "ain->setAutoPadding(true);\n";
490
491    mOut.indent() << kAllocationSp
492                  << " aout = android::RSC::Allocation::createSized(mRS, "
493                  << kRsElemPrefix << Type->getElementName() << ", 1);\n";
494
495    mOut.indent() << "aout->setAutoPadding(true);\n";
496
497    const std::string ArrayElementType = TypeData.type->c_name;
498
499    std::string StartOffset = "x1";
500    if (VecSize > 1) {
501      StartOffset += " * " + std::to_string(VecSize);
502    }
503    mOut.indent() << "ain->copy1DRangeFrom(0, x2 - x1, &in[" << StartOffset << "]);\n";
504    mOut.indent() << "reduce_" << Reduce.getName() << "(ain, aout);\n";
505    mOut.indent() << ArrayElementType << " outArray[" << VecSize << "];\n";
506
507    mOut.indent() << "aout->copy1DRangeTo(0, 1, &outArray[0]);\n";
508
509    mOut.indent() << "return " << ReturnType << "(";
510    for (uint32_t VecElem = 0; VecElem < VecSize; ++VecElem) {
511      if (VecElem > 0) mOut << ", ";
512      mOut << "outArray[" << VecElem << "]";
513    }
514    mOut << ");\n";
515    mOut.endBlock();
516  }
517}
518
519// invoke_* implementation
520void RSReflectionCpp::genExportFunctionBodies() {
521  uint32_t slot = 0;
522  // Reflect export function
523  for (auto I = mRSContext->export_funcs_begin(),
524            E = mRSContext->export_funcs_end();
525       I != E; I++) {
526    const RSExportFunc *ef = *I;
527
528    makeFunctionSignature(true, ef);
529    mOut.startBlock();
530    const RSExportRecordType *params = ef->getParamPacketType();
531    size_t param_len = 0;
532    if (params) {
533      param_len = params->getAllocSize();
534      if (genCreateFieldPacker(params, "__fp")) {
535        genPackVarOfType(params, nullptr, "__fp");
536      }
537    }
538
539    mOut.indent() << "invoke(" << slot;
540    if (params) {
541      mOut << ", __fp.getData(), " << param_len << ");\n";
542    } else {
543      mOut << ", NULL, 0);\n";
544    }
545    mOut.endBlock();
546
547    slot++;
548  }
549}
550
551bool RSReflectionCpp::genEncodedBitCode() {
552  FILE *pfin = fopen(mBitCodeFilePath.c_str(), "rb");
553  if (pfin == nullptr) {
554    fprintf(stderr, "Error: could not read file %s\n",
555            mBitCodeFilePath.c_str());
556    return false;
557  }
558
559  unsigned char buf[16];
560  int read_length;
561  mOut.indent() << "static const unsigned char __txt[] =";
562  mOut.startBlock();
563  while ((read_length = fread(buf, 1, sizeof(buf), pfin)) > 0) {
564    mOut.indent();
565    for (int i = 0; i < read_length; i++) {
566      char buf2[16];
567      snprintf(buf2, sizeof(buf2), "0x%02x,", buf[i]);
568      mOut << buf2;
569    }
570    mOut << "\n";
571  }
572  mOut.endBlock(true);
573  mOut << "\n";
574  return true;
575}
576
577bool RSReflectionCpp::writeImplementationFile() {
578  if (!mOut.startFile(mOutputDirectory, mClassName + ".cpp", mRSSourceFilePath,
579                      mRSContext->getLicenseNote(), false,
580                      mRSContext->getVerbose())) {
581    return false;
582  }
583
584  // Front matter
585  mOut.indent() << "#include \"" << mClassName << ".h\"\n\n";
586
587  genEncodedBitCode();
588  mOut.indent() << "\n\n";
589
590  // Constructor
591  const std::string &packageName = mRSContext->getReflectJavaPackageName();
592  mOut.indent() << mClassName << "::" << mClassName
593                << "(android::RSC::sp<android::RSC::RS> rs):\n"
594                   "        ScriptC(rs, __txt, sizeof(__txt), \""
595                << mCleanedRSFileName << "\", " << mCleanedRSFileName.length()
596                << ", \"/data/data/" << packageName << "/app\", sizeof(\""
597                << packageName << "\"))";
598  mOut.startBlock();
599  for (std::set<std::string>::iterator I = mTypesToCheck.begin(),
600                                       E = mTypesToCheck.end();
601       I != E; I++) {
602    mOut.indent() << kRsElemPrefix << *I << " = android::RSC::Element::" << *I
603                  << "(mRS);\n";
604  }
605
606  for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
607                                            E = mRSContext->export_vars_end();
608       I != E; I++) {
609    const RSExportVar *EV = *I;
610    if (!EV->getInit().isUninit()) {
611      genInitExportVariable(EV->getType(), EV->getName(), EV->getInit());
612    } else {
613      genZeroInitExportVariable(EV->getName());
614    }
615  }
616  mOut.endBlock();
617
618  // Destructor
619  mOut.indent() << mClassName << "::~" << mClassName << "()";
620  mOut.startBlock();
621  mOut.endBlock();
622
623  // Function bodies
624  genExportForEachBodies();
625  genExportReduceBodies();
626  genExportFunctionBodies();
627
628  mOut.closeFile();
629  return true;
630}
631
632void RSReflectionCpp::genExportVariablesGetterAndSetter() {
633  mOut.comment("Methods to set and get the variables exported by the script. "
634               "Const variables will not have a setter.\n\n"
635               "Note that the value returned by the getter may not be the "
636               "current value of the variable in the script.  The getter will "
637               "return the initial value of the variable (as defined in the "
638               "script) or the the last value set by using the setter method.  "
639               "The script is free to modify its value independently.");
640  for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
641                                            E = mRSContext->export_vars_end();
642       I != E; I++) {
643    const RSExportVar *EV = *I;
644    const RSExportType *ET = EV->getType();
645
646    switch (ET->getClass()) {
647    case RSExportType::ExportClassPrimitive: {
648      genGetterAndSetter(static_cast<const RSExportPrimitiveType *>(ET), EV);
649      break;
650    }
651    case RSExportType::ExportClassPointer: {
652      // TODO Deprecate this.
653      genPointerTypeExportVariable(EV);
654      break;
655    }
656    case RSExportType::ExportClassVector: {
657      genGetterAndSetter(static_cast<const RSExportVectorType *>(ET), EV);
658      break;
659    }
660    case RSExportType::ExportClassMatrix: {
661      genMatrixTypeExportVariable(EV);
662      break;
663    }
664    case RSExportType::ExportClassConstantArray: {
665      genGetterAndSetter(static_cast<const RSExportConstantArrayType *>(ET),
666                         EV);
667      break;
668    }
669    case RSExportType::ExportClassRecord: {
670      genGetterAndSetter(static_cast<const RSExportRecordType *>(ET), EV);
671      break;
672    }
673    default: { slangAssert(false && "Unknown class of type"); }
674    }
675  }
676}
677
678void RSReflectionCpp::genGetterAndSetter(const RSExportPrimitiveType *EPT,
679                                         const RSExportVar *EV) {
680  RSReflectionTypeData rtd;
681  EPT->convertToRTD(&rtd);
682  std::string TypeName = GetTypeName(EPT, false);
683
684  if (!EV->isConst()) {
685    mOut.indent() << "void set_" << EV->getName() << "(" << TypeName << " v)";
686    mOut.startBlock();
687    mOut.indent() << "setVar(" << getNextExportVarSlot() << ", ";
688    if (EPT->isRSObjectType()) {
689      mOut << "v";
690   } else {
691      mOut << "&v, sizeof(v)";
692    }
693    mOut << ");\n";
694    mOut.indent() << RS_EXPORT_VAR_PREFIX << EV->getName() << " = v;\n";
695    mOut.endBlock();
696  }
697  mOut.indent() << TypeName << " get_" << EV->getName() << "() const";
698  mOut.startBlock();
699  if (EV->isConst()) {
700    const clang::APValue &val = EV->getInit();
701    bool isBool = !strcmp(TypeName.c_str(), "bool");
702    mOut.indent() << "return ";
703    genInitValue(val, isBool);
704    mOut << ";\n";
705  } else {
706    mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << EV->getName()
707                  << ";\n";
708  }
709  mOut.endBlock();
710}
711
712void RSReflectionCpp::genPointerTypeExportVariable(const RSExportVar *EV) {
713  const RSExportType *ET = EV->getType();
714
715  slangAssert((ET->getClass() == RSExportType::ExportClassPointer) &&
716              "Variable should be type of pointer here");
717
718  std::string TypeName = GetTypeName(ET);
719  std::string VarName = EV->getName();
720
721  RSReflectionTypeData rtd;
722  EV->getType()->convertToRTD(&rtd);
723  uint32_t slot = getNextExportVarSlot();
724
725  if (!EV->isConst()) {
726    mOut.indent() << "void bind_" << VarName << "(" << TypeName << " v)";
727    mOut.startBlock();
728    mOut.indent() << "bindAllocation(v, " << slot << ");\n";
729    mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = v;\n";
730    mOut.endBlock();
731  }
732  mOut.indent() << TypeName << " get_" << VarName << "() const";
733  mOut.startBlock();
734  if (EV->isConst()) {
735    const clang::APValue &val = EV->getInit();
736    bool isBool = !strcmp(TypeName.c_str(), "bool");
737    mOut.indent() << "return ";
738    genInitValue(val, isBool);
739    mOut << ";\n";
740  } else {
741    mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << VarName << ";\n";
742  }
743  mOut.endBlock();
744}
745
746void RSReflectionCpp::genGetterAndSetter(const RSExportVectorType *EVT,
747                                         const RSExportVar *EV) {
748  slangAssert(EVT != nullptr);
749
750  RSReflectionTypeData rtd;
751  EVT->convertToRTD(&rtd);
752
753  if (!EV->isConst()) {
754    mOut.indent() << "void set_" << EV->getName() << "("
755                  << rtd.type->rs_c_vector_prefix << EVT->getNumElement()
756                  << " v)";
757    mOut.startBlock();
758    mOut.indent() << "setVar(" << getNextExportVarSlot()
759                  << ", &v, sizeof(v));\n";
760    mOut.indent() << RS_EXPORT_VAR_PREFIX << EV->getName() << " = v;\n";
761    mOut.endBlock();
762  }
763  mOut.indent() << rtd.type->rs_c_vector_prefix << EVT->getNumElement()
764                << " get_" << EV->getName() << "() const";
765  mOut.startBlock();
766  if (EV->isConst()) {
767    const clang::APValue &val = EV->getInit();
768    mOut.indent() << "return ";
769    genInitValue(val, false);
770    mOut << ";\n";
771  } else {
772    mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << EV->getName()
773                  << ";\n";
774  }
775  mOut.endBlock();
776}
777
778void RSReflectionCpp::genMatrixTypeExportVariable(const RSExportVar *EV) {
779  slangAssert(false);
780}
781
782void RSReflectionCpp::genGetterAndSetter(const RSExportConstantArrayType *AT,
783                                         const RSExportVar *EV) {
784  slangAssert(false);
785}
786
787void RSReflectionCpp::genGetterAndSetter(const RSExportRecordType *ERT,
788                                         const RSExportVar *EV) {
789  slangAssert(false);
790}
791
792void RSReflectionCpp::makeFunctionSignature(bool isDefinition,
793                                            const RSExportFunc *ef) {
794  mOut.indent() << "void ";
795  if (isDefinition) {
796    mOut << mClassName << "::";
797  }
798  mOut << "invoke_" << ef->getName() << "(";
799
800  if (ef->getParamPacketType()) {
801    bool FirstArg = true;
802    for (RSExportFunc::const_param_iterator i = ef->params_begin(),
803                                            e = ef->params_end();
804         i != e; i++) {
805      if (!FirstArg) {
806        mOut << ", ";
807      } else {
808        FirstArg = false;
809      }
810      mOut << GetTypeName((*i)->getType(), false) << " " << (*i)->getName();
811    }
812  }
813
814  if (isDefinition) {
815    mOut << ")";
816  } else {
817    mOut << ");\n";
818  }
819}
820
821void RSReflectionCpp::makeReduceSignatureAllocationVariant(bool IsDefinition,
822                                                           const RSExportReduce *ER) {
823  // void reduce_foo(sp<Allocation> ain, sp<Allocation> aout,
824  //                 const RsScriptCall *sc = nullptr);
825  std::string FunctionStart = "void ";
826  if (IsDefinition) {
827    FunctionStart += mClassName +  "::";
828  }
829  FunctionStart += "reduce_" + ER->getName() + "(";
830
831  ArgumentList Arguments{
832    Argument(kAllocationSp, "ain"),
833    Argument(kAllocationSp, "aout"),
834    Argument(kConstRsScriptCall, "*sc", IsDefinition ? "" : "nullptr")
835  };
836
837  mOut.indent() << FunctionStart;
838
839  genArguments(Arguments, FunctionStart.length());
840
841  if (IsDefinition) {
842    mOut << ")";
843  } else {
844    mOut << ");\n\n";
845  }
846}
847
848void RSReflectionCpp::makeReduceSignatureArrayVariant(bool IsDefinition,
849                                                      const RSExportReduce *ER) {
850  // Ty reduce_foo(const ElemTy[] in, uint32_t x1, uint32_t x2, size_t inLen);
851  // "Ty" could be different from "ElemTy" in the case of vectors.
852
853  const RSExportType *Type = ER->getType();
854  if (!canExportReduceArrayVariant(Type)) {
855      return;
856  }
857
858  RSReflectionTypeData TypeData;
859  Type->convertToRTD(&TypeData);
860
861  const std::string ReturnType = GetTypeName(Type);
862  std::string FunctionStart = ReturnType + " ";
863  if (IsDefinition) {
864    FunctionStart += mClassName +  "::";
865  }
866  FunctionStart += "reduce_" + ER->getName() + "(";
867
868  const std::string ArrayElementType = TypeData.type->c_name;
869
870  ArgumentList Arguments{
871    Argument("const " + ArrayElementType, "in[]"),
872    Argument("uint32_t", "x1"),
873    Argument("uint32_t", "x2"),
874    Argument("size_t", "inLen")
875  };
876
877  mOut.indent() << FunctionStart;
878  genArguments(Arguments, FunctionStart.size());
879
880  if (IsDefinition) {
881    mOut << ")";
882  } else {
883    mOut << ");\n\n";
884  }
885
886  if (!IsDefinition) {
887    // We reflect three more variants in the header. First, there is
888    //
889    //   Ty reduce_foo(const ElemTy[] in, size_t inLen);
890    //
891    // Note the inLen is the number of primitive elements in the array, as opposed to the
892    // bounds whose units are allocation elements. The other variants use templates to infer
893    // the array length statically:
894    //
895    //   template<size_t inLen> Ty reduce_foo(const ElemTy (&in)[inLen]);
896    //   template<size_t inLen> Ty reduce_foo(const ElemTy (&in)[inLen], uint32_t x1, uint32_t x2);
897
898    // Generate inLen variant
899    const uint32_t VecSize = TypeData.vecSize;
900    std::string X2 = "inLen";
901
902    const std::string FunctionName = ER->getName();
903
904    auto ForwardReduce = [this, &FunctionName](const std::string &x1,
905                                               const std::string &x2,
906                                               const std::string &inLen) {
907      this->mOut.indent() << "    return reduce_" << FunctionName << "(in, "
908                          << x1 << ", " << x2 << ", " << inLen << ");\n";
909      this->mOut.indent() << "}\n\n";
910    };
911
912    const std::string DefaultValue = ReturnType + "()";
913
914    ArgumentList InLenVariantArguments{
915      Argument("const " + ArrayElementType, "in[]"), Argument("size_t", "inLen")
916    };
917    mOut.indent() << FunctionStart;
918    genArguments(InLenVariantArguments, FunctionStart.size());
919    mOut << ") {\n";
920    if (VecSize > 1) {
921      genVectorLengthCompatibilityCheck("inLen", VecSize, DefaultValue, 2);
922      X2 += " / " + std::to_string(VecSize);
923    }
924    ForwardReduce("0", X2, "inLen");
925
926    // Generate template variants
927    ArgumentList TemplateVariantArguments{
928      Argument("const " + ArrayElementType, "(&in)[inLen]")
929    };
930
931    mOut.indent() << "template<size_t inLen>\n";
932    mOut.indent() << FunctionStart;
933    genArguments(TemplateVariantArguments, FunctionStart.size());
934    mOut << ") {\n        return reduce_" << FunctionName << "(in, inLen);\n    }\n\n";
935
936    TemplateVariantArguments.push_back(Argument("uint32_t", "x1"));
937    TemplateVariantArguments.push_back(Argument("uint32_t", "x2"));
938    mOut.indent() << "template<size_t inLen>\n";
939    mOut.indent() << FunctionStart;
940    genArguments(TemplateVariantArguments, FunctionStart.size());
941    mOut << ") {\n";
942    ForwardReduce("x1", "x2", "inLen");
943  }
944}
945
946void RSReflectionCpp::genArguments(const ArgumentList &Arguments, int Offset) {
947  bool FirstArg = true;
948
949  for (ArgumentList::const_iterator I = Arguments.begin(), E = Arguments.end();
950       I != E; I++) {
951    if (!FirstArg) {
952      mOut << ",\n";
953      mOut.indent() << string(Offset, ' ');
954    } else {
955      FirstArg = false;
956    }
957
958    mOut << I->Type << " " << I->Name;
959    if (!I->DefaultValue.empty()) {
960      mOut << " = " << I->DefaultValue;
961    }
962  }
963}
964
965bool RSReflectionCpp::genCreateFieldPacker(const RSExportType *ET,
966                                           const char *FieldPackerName) {
967  size_t AllocSize = ET->getAllocSize();
968
969  if (AllocSize > 0) {
970    mOut.indent() << "android::RSC::FieldPacker " << FieldPackerName << "("
971                  << AllocSize << ");\n";
972    return true;
973  }
974
975  return false;
976}
977
978void RSReflectionCpp::genPackVarOfType(const RSExportType *ET,
979                                       const char *VarName,
980                                       const char *FieldPackerName) {
981  switch (ET->getClass()) {
982  case RSExportType::ExportClassPrimitive:
983  case RSExportType::ExportClassVector:
984  case RSExportType::ExportClassPointer:
985  case RSExportType::ExportClassMatrix: {
986    mOut.indent() << FieldPackerName << ".add(" << VarName << ");\n";
987    break;
988  }
989  case RSExportType::ExportClassConstantArray: {
990    /*const RSExportConstantArrayType *ECAT =
991        static_cast<const RSExportConstantArrayType *>(ET);
992
993    // TODO(zonr): more elegant way. Currently, we obtain the unique index
994    //             variable (this method involves recursive call which means
995    //             we may have more than one level loop, therefore we can't
996    //             always use the same index variable name here) name given
997    //             in the for-loop from counting the '.' in @VarName.
998    unsigned Level = 0;
999    size_t LastDotPos = 0;
1000    std::string ElementVarName(VarName);
1001
1002  while (LastDotPos != std::string::npos) {
1003    LastDotPos = ElementVarName.find_first_of('.', LastDotPos + 1);
1004    Level++;
1005  }
1006  std::string IndexVarName("ct");
1007  IndexVarName.append(llvm::utostr_32(Level));
1008
1009  C.indent() << "for (int " << IndexVarName << " = 0; " <<
1010                      IndexVarName << " < " << ECAT->getSize() << "; " <<
1011                      IndexVarName << "++)";
1012  C.startBlock();
1013
1014  ElementVarName.append("[" + IndexVarName + "]");
1015  genPackVarOfType(C, ECAT->getElementType(), ElementVarName.c_str(),
1016                   FieldPackerName);
1017
1018  C.endBlock();*/
1019    break;
1020  }
1021  case RSExportType::ExportClassRecord: {
1022    const RSExportRecordType *ERT = static_cast<const RSExportRecordType *>(ET);
1023    // Relative pos from now on in field packer
1024    unsigned Pos = 0;
1025
1026    for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(),
1027                                                  E = ERT->fields_end();
1028         I != E; I++) {
1029      const RSExportRecordType::Field *F = *I;
1030      std::string FieldName;
1031      size_t FieldOffset = F->getOffsetInParent();
1032      const RSExportType *T = F->getType();
1033      size_t FieldStoreSize = T->getStoreSize();
1034      size_t FieldAllocSize = T->getAllocSize();
1035
1036      if (VarName != nullptr)
1037        FieldName = VarName + ("." + F->getName());
1038      else
1039        FieldName = F->getName();
1040
1041      if (FieldOffset > Pos) {
1042        mOut.indent() << FieldPackerName << ".skip(" << (FieldOffset - Pos)
1043                      << ");\n";
1044      }
1045
1046      genPackVarOfType(F->getType(), FieldName.c_str(), FieldPackerName);
1047
1048      // There is padding in the field type
1049      if (FieldAllocSize > FieldStoreSize) {
1050        mOut.indent() << FieldPackerName << ".skip("
1051                      << (FieldAllocSize - FieldStoreSize) << ");\n";
1052      }
1053
1054      Pos = FieldOffset + FieldAllocSize;
1055    }
1056
1057    // There maybe some padding after the struct
1058    if (ERT->getAllocSize() > Pos) {
1059      mOut.indent() << FieldPackerName << ".skip(" << ERT->getAllocSize() - Pos
1060                    << ");\n";
1061    }
1062    break;
1063  }
1064  default: { slangAssert(false && "Unknown class of type"); }
1065  }
1066}
1067
1068void RSReflectionCpp::genTypeCheck(const RSExportType *ET,
1069                                   const char *VarName) {
1070  mOut.indent() << "// Type check for " << VarName << "\n";
1071
1072  if (ET->getClass() == RSExportType::ExportClassPointer) {
1073    const RSExportPointerType *EPT =
1074        static_cast<const RSExportPointerType *>(ET);
1075    ET = EPT->getPointeeType();
1076  }
1077
1078  std::string TypeName;
1079  switch (ET->getClass()) {
1080  case RSExportType::ExportClassPrimitive:
1081  case RSExportType::ExportClassVector:
1082  case RSExportType::ExportClassRecord: {
1083    TypeName = ET->getElementName();
1084    break;
1085  }
1086
1087  default:
1088    break;
1089  }
1090
1091  if (!TypeName.empty()) {
1092    mOut.indent() << "if (!" << VarName
1093                  << "->getType()->getElement()->isCompatible("
1094                  << kRsElemPrefix << TypeName << "))";
1095    mOut.startBlock();
1096    mOut.indent() << "mRS->throwError(RS_ERROR_RUNTIME_ERROR, "
1097                     "\"Incompatible type\");\n";
1098    mOut.indent() << "return;\n";
1099    mOut.endBlock();
1100  }
1101}
1102
1103// Ensure that the input is 1 dimensional.
1104void RSReflectionCpp::gen1DCheck(const std::string &VarName) {
1105  mOut.indent() << "// check that " << VarName << " is 1d\n";
1106  mOut.indent() << "sp<const Type> t0 = " << VarName << "->getType();\n";
1107  mOut.indent() << "if (t0->getY() != 0 ||\n";
1108  mOut.indent() << "    t0->hasFaces()  ||\n";
1109  mOut.indent() << "    t0->hasMipmaps())";
1110  mOut.startBlock();
1111  mOut.indent() << "mRS->throwError(RS_ERROR_INVALID_PARAMETER, "
1112                << "\"" << VarName << " is not 1D!\");\n";
1113  mOut.indent() << "return;\n";
1114  mOut.endBlock();
1115}
1116
1117// Generates code to ensure that the supplied array length is a multiple of the vector size.
1118void RSReflectionCpp::genVectorLengthCompatibilityCheck(const std::string &Length,
1119                                                        unsigned VecSize,
1120                                                        const std::string &ValueToReturn,
1121                                                        unsigned IndentLevels) {
1122  auto Indenter = [this, IndentLevels]() -> std::ofstream& {
1123    GeneratedFile &Out = this->mOut;
1124    for (unsigned Level = 0; Level < IndentLevels; ++Level) {
1125      Out.indent();
1126    }
1127    return Out;
1128  };
1129
1130  Indenter() << "// Verify that the array length is a multiple of the vector size.\n";
1131  Indenter() << "if (" << Length << " % " << std::to_string(VecSize) << " != 0) {\n";
1132  Indenter() << "    mRS->throwError(RS_ERROR_INVALID_PARAMETER, "
1133             << "\"Input array length is not a multiple of "
1134             << std::to_string(VecSize) << "\");\n";
1135  Indenter() << "    return " << ValueToReturn << ";\n";
1136  Indenter() << "}\n\n";
1137}
1138
1139// Generates code to ensure that the supplied array is non-null and nonzero in length.
1140void RSReflectionCpp::genNullOrEmptyArrayCheck(const std::string &ArrayName,
1141                                               const std::string &Length,
1142                                               const std::string &ValueToReturn) {
1143  mOut.indent() << "// Verify that the array is non-null and non-empty.\n";
1144  mOut.indent() << "if (" << ArrayName << " == nullptr) {\n";
1145  mOut.indent() << "    mRS->throwError(RS_ERROR_INVALID_PARAMETER, "
1146                << "\"Input array is null\");\n";
1147  mOut.indent() << "    return " << ValueToReturn << ";\n";
1148  mOut.indent() << "}\n\n";
1149
1150  mOut.indent() << "if (" << Length << " == 0) {\n";
1151  mOut.indent() << "    mRS->throwError(RS_ERROR_INVALID_PARAMETER, "
1152                << "\"Input array is zero-length\");\n";
1153  mOut.indent() << "    return " << ValueToReturn << ";\n";
1154  mOut.indent() << "}\n\n";
1155}
1156
1157void RSReflectionCpp::genTypeInstanceFromPointer(const RSExportType *ET) {
1158  if (ET->getClass() == RSExportType::ExportClassPointer) {
1159    // For pointer parameters to original forEach kernels.
1160    const RSExportPointerType *EPT =
1161        static_cast<const RSExportPointerType *>(ET);
1162    genTypeInstance(EPT->getPointeeType());
1163  } else {
1164    // For handling pass-by-value kernel parameters.
1165    genTypeInstance(ET);
1166  }
1167}
1168
1169void RSReflectionCpp::genTypeInstance(const RSExportType *ET) {
1170  switch (ET->getClass()) {
1171  case RSExportType::ExportClassPrimitive:
1172  case RSExportType::ExportClassVector:
1173  case RSExportType::ExportClassConstantArray:
1174  case RSExportType::ExportClassRecord: {
1175    std::string TypeName = ET->getElementName();
1176    mTypesToCheck.insert(TypeName);
1177    break;
1178  }
1179
1180  default:
1181    break;
1182  }
1183}
1184
1185void RSReflectionCpp::genInitExportVariable(const RSExportType *ET,
1186                                            const std::string &VarName,
1187                                            const clang::APValue &Val) {
1188  slangAssert(!Val.isUninit() && "Not a valid initializer");
1189
1190  switch (ET->getClass()) {
1191  case RSExportType::ExportClassPrimitive: {
1192    const RSExportPrimitiveType *EPT =
1193        static_cast<const RSExportPrimitiveType *>(ET);
1194    if (EPT->getType() == DataTypeBoolean) {
1195      genInitBoolExportVariable(VarName, Val);
1196    } else {
1197      genInitPrimitiveExportVariable(VarName, Val);
1198    }
1199    break;
1200  }
1201  case RSExportType::ExportClassPointer: {
1202    if (!Val.isInt() || Val.getInt().getSExtValue() != 0)
1203      std::cerr << "Initializer which is non-NULL to pointer type variable "
1204                   "will be ignored" << std::endl;
1205    break;
1206  }
1207  case RSExportType::ExportClassVector: {
1208    const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET);
1209    switch (Val.getKind()) {
1210    case clang::APValue::Int:
1211    case clang::APValue::Float: {
1212      for (unsigned i = 0; i < EVT->getNumElement(); i++) {
1213        std::string Name = VarName + "." + getVectorAccessor(i);
1214        genInitPrimitiveExportVariable(Name, Val);
1215      }
1216      break;
1217    }
1218    case clang::APValue::Vector: {
1219      unsigned NumElements = std::min(
1220          static_cast<unsigned>(EVT->getNumElement()), Val.getVectorLength());
1221      for (unsigned i = 0; i < NumElements; i++) {
1222        const clang::APValue &ElementVal = Val.getVectorElt(i);
1223        std::string Name = VarName + "." + getVectorAccessor(i);
1224        genInitPrimitiveExportVariable(Name, ElementVal);
1225      }
1226      break;
1227    }
1228    case clang::APValue::MemberPointer:
1229    case clang::APValue::Uninitialized:
1230    case clang::APValue::ComplexInt:
1231    case clang::APValue::ComplexFloat:
1232    case clang::APValue::LValue:
1233    case clang::APValue::Array:
1234    case clang::APValue::Struct:
1235    case clang::APValue::Union:
1236    case clang::APValue::AddrLabelDiff: {
1237      slangAssert(false && "Unexpected type of value of initializer.");
1238    }
1239    }
1240    break;
1241  }
1242  case RSExportType::ExportClassMatrix:
1243  case RSExportType::ExportClassConstantArray:
1244  case RSExportType::ExportClassRecord: {
1245    slangAssert(false && "Unsupported initializer for record/matrix/constant "
1246                         "array type variable currently");
1247    break;
1248  }
1249  default: { slangAssert(false && "Unknown class of type"); }
1250  }
1251}
1252
1253const char *RSReflectionCpp::getVectorAccessor(unsigned Index) {
1254  static const char *VectorAccessorMap[] = {/* 0 */ "x",
1255                                            /* 1 */ "y",
1256                                            /* 2 */ "z",
1257                                            /* 3 */ "w",
1258  };
1259
1260  slangAssert((Index < (sizeof(VectorAccessorMap) / sizeof(const char *))) &&
1261              "Out-of-bound index to access vector member");
1262
1263  return VectorAccessorMap[Index];
1264}
1265
1266void RSReflectionCpp::genZeroInitExportVariable(const std::string &VarName) {
1267  mOut.indent() << "memset(&" << RS_EXPORT_VAR_PREFIX << VarName
1268                << ", 0, sizeof(" << RS_EXPORT_VAR_PREFIX << VarName << "));\n";
1269}
1270
1271void
1272RSReflectionCpp::genInitPrimitiveExportVariable(const std::string &VarName,
1273                                                const clang::APValue &Val) {
1274  slangAssert(!Val.isUninit() && "Not a valid initializer");
1275
1276  mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = ";
1277  genInitValue(Val);
1278  mOut << ";\n";
1279}
1280
1281void RSReflectionCpp::genInitValue(const clang::APValue &Val, bool asBool) {
1282  switch (Val.getKind()) {
1283  case clang::APValue::Int: {
1284    llvm::APInt api = Val.getInt();
1285    if (asBool) {
1286      mOut << ((api.getSExtValue() == 0) ? "false" : "true");
1287    } else {
1288      // TODO: Handle unsigned correctly for C++
1289      mOut << api.getSExtValue();
1290      if (api.getBitWidth() > 32) {
1291        mOut << "L";
1292      }
1293    }
1294    break;
1295  }
1296
1297  case clang::APValue::Float: {
1298    llvm::APFloat apf = Val.getFloat();
1299    llvm::SmallString<30> s;
1300    apf.toString(s);
1301    mOut << s.c_str();
1302    if (&apf.getSemantics() == &llvm::APFloat::IEEEsingle) {
1303      if (s.count('.') == 0) {
1304        mOut << ".f";
1305      } else {
1306        mOut << "f";
1307      }
1308    }
1309    break;
1310  }
1311
1312  case clang::APValue::ComplexInt:
1313  case clang::APValue::ComplexFloat:
1314  case clang::APValue::LValue:
1315  case clang::APValue::Vector: {
1316    slangAssert(false && "Primitive type cannot have such kind of initializer");
1317    break;
1318  }
1319
1320  default: { slangAssert(false && "Unknown kind of initializer"); }
1321  }
1322}
1323
1324void RSReflectionCpp::genInitBoolExportVariable(const std::string &VarName,
1325                                                const clang::APValue &Val) {
1326  slangAssert(!Val.isUninit() && "Not a valid initializer");
1327  slangAssert((Val.getKind() == clang::APValue::Int) &&
1328              "Bool type has wrong initial APValue");
1329
1330  mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = "
1331                << ((Val.getInt().getSExtValue() == 0) ? "false" : "true")
1332                << ";";
1333}
1334
1335} // namespace slang
1336