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