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