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