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