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