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