slang_rs_reflection_cpp.cpp revision 1c6b927b4c59fabf44db846855ff5c4cfd48aa53
1/* 2 * Copyright 2013, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <sys/stat.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <iostream> 21 22#include <cstdarg> 23#include <cctype> 24 25#include <algorithm> 26#include <sstream> 27#include <string> 28 29#include "os_sep.h" 30#include "slang_rs_context.h" 31#include "slang_rs_export_var.h" 32#include "slang_rs_export_foreach.h" 33#include "slang_rs_export_func.h" 34#include "slang_rs_export_reduce.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 44const char kRsTypeItemClassName[] = "Item"; 45const char kRsElemPrefix[] = "__rs_elem_"; 46// The name of the Allocation type that is reflected in C++ 47const char kAllocationSp[] = "android::RSC::sp<android::RSC::Allocation>"; 48const char kConstRsScriptCall[] = "const RsScriptCall"; 49 50static const char *GetMatrixTypeName(const RSExportMatrixType *EMT) { 51 static const char *MatrixTypeCNameMap[] = { 52 "rs_matrix2x2", "rs_matrix3x3", "rs_matrix4x4", 53 }; 54 unsigned Dim = EMT->getDim(); 55 56 if ((Dim - 2) < (sizeof(MatrixTypeCNameMap) / sizeof(const char *))) 57 return MatrixTypeCNameMap[EMT->getDim() - 2]; 58 59 slangAssert(false && "GetMatrixTypeName : Unsupported matrix dimension"); 60 return nullptr; 61} 62 63static std::string GetTypeName(const RSExportType *ET, bool Brackets = true) { 64 switch (ET->getClass()) { 65 case RSExportType::ExportClassPrimitive: { 66 const RSExportPrimitiveType *EPT = 67 static_cast<const RSExportPrimitiveType *>(ET); 68 if (EPT->isRSObjectType()) { 69 return std::string("android::RSC::sp<const android::RSC::") + 70 RSExportPrimitiveType::getRSReflectionType(EPT)->c_name + ">"; 71 } else { 72 return RSExportPrimitiveType::getRSReflectionType(EPT)->c_name; 73 } 74 } 75 case RSExportType::ExportClassPointer: { 76 const RSExportType *PointeeType = 77 static_cast<const RSExportPointerType *>(ET)->getPointeeType(); 78 79 if (PointeeType->getClass() != RSExportType::ExportClassRecord) 80 return kAllocationSp; 81 else 82 return PointeeType->getElementName(); 83 } 84 case RSExportType::ExportClassVector: { 85 const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET); 86 std::stringstream VecName; 87 VecName << EVT->getRSReflectionType(EVT)->rs_c_vector_prefix 88 << EVT->getNumElement(); 89 return VecName.str(); 90 } 91 case RSExportType::ExportClassMatrix: { 92 return GetMatrixTypeName(static_cast<const RSExportMatrixType *>(ET)); 93 } 94 case RSExportType::ExportClassConstantArray: { 95 // TODO: Fix this for C arrays! 96 const RSExportConstantArrayType *CAT = 97 static_cast<const RSExportConstantArrayType *>(ET); 98 std::string ElementTypeName = GetTypeName(CAT->getElementType()); 99 if (Brackets) { 100 ElementTypeName.append("[]"); 101 } 102 return ElementTypeName; 103 } 104 case RSExportType::ExportClassRecord: { 105 // TODO: Fix for C structs! 106 return ET->getElementName() + "." + kRsTypeItemClassName; 107 } 108 default: { slangAssert(false && "Unknown class of type"); } 109 } 110 111 return ""; 112} 113 114static bool canExportReduceArrayVariant(const RSExportType *Type) { 115 // FIXME: No half types available for C++ reflection yet 116 if (Type->getElementName().find("F16") == 0) { 117 return false; 118 } 119 return Type->getClass() == RSExportType::ExportClassPrimitive || 120 Type->getClass() == RSExportType::ExportClassVector; 121} 122 123RSReflectionCpp::RSReflectionCpp(const RSContext *Context, 124 const string &OutputDirectory, 125 const string &RSSourceFileName, 126 const string &BitCodeFileName) 127 : mRSContext(Context), mRSSourceFilePath(RSSourceFileName), 128 mBitCodeFilePath(BitCodeFileName), mOutputDirectory(OutputDirectory), 129 mNextExportVarSlot(0), mNextExportFuncSlot(0), mNextExportForEachSlot(0), 130 mNextExportReduceSlot(0) { 131 mCleanedRSFileName = RootNameFromRSFileName(mRSSourceFilePath); 132 mClassName = "ScriptC_" + mCleanedRSFileName; 133} 134 135RSReflectionCpp::~RSReflectionCpp() {} 136 137bool RSReflectionCpp::reflect() { 138 writeHeaderFile(); 139 writeImplementationFile(); 140 141 return true; 142} 143 144#define RS_TYPE_CLASS_NAME_PREFIX "ScriptField_" 145 146bool RSReflectionCpp::writeHeaderFile() { 147 // Create the file and write the license note. 148 if (!mOut.startFile(mOutputDirectory, mClassName + ".h", mRSSourceFilePath, 149 mRSContext->getLicenseNote(), false, 150 mRSContext->getVerbose())) { 151 return false; 152 } 153 154 mOut.indent() << "#include \"RenderScript.h\"\n\n"; 155 mOut.indent() << "using namespace android::RSC;\n\n"; 156 157 mOut.comment("This class encapsulates access to the exported elements of the script. " 158 "Typically, you would instantiate this class once, call the set_* methods " 159 "for each of the exported global variables you want to change, then call " 160 "one of the forEach_ methods to invoke a kernel."); 161 mOut.indent() << "class " << mClassName << " : public android::RSC::ScriptC"; 162 mOut.startBlock(); 163 164 mOut.decreaseIndent(); 165 mOut.indent() << "private:\n"; 166 mOut.increaseIndent(); 167 168 genFieldsToStoreExportVariableValues(); 169 genTypeInstancesUsedInForEach(); 170 genTypeInstancesUsedInReduce(); 171 genFieldsForAllocationTypeVerification(); 172 173 mOut.decreaseIndent(); 174 mOut.indent() << "public:\n"; 175 mOut.increaseIndent(); 176 177 // Generate the constructor and destructor declarations. 178 mOut.indent() << mClassName << "(android::RSC::sp<android::RSC::RS> rs);\n"; 179 mOut.indent() << "virtual ~" << mClassName << "();\n\n"; 180 181 genExportVariablesGetterAndSetter(); 182 genForEachDeclarations(); 183 genReduceDeclarations(); 184 genExportFunctionDeclarations(); 185 186 mOut.endBlock(true); 187 mOut.closeFile(); 188 return true; 189} 190 191void RSReflectionCpp::genTypeInstancesUsedInForEach() { 192 for (auto I = mRSContext->export_foreach_begin(), 193 E = mRSContext->export_foreach_end(); 194 I != E; I++) { 195 const RSExportForEach *EF = *I; 196 const RSExportType *OET = EF->getOutType(); 197 198 if (OET) { 199 genTypeInstanceFromPointer(OET); 200 } 201 202 const RSExportForEach::InTypeVec &InTypes = EF->getInTypes(); 203 204 for (RSExportForEach::InTypeIter BI = InTypes.begin(), 205 EI = InTypes.end(); BI != EI; BI++) { 206 207 genTypeInstanceFromPointer(*BI); 208 } 209 } 210} 211 212// Ensure that the type of the reduce kernel is reflected. 213void RSReflectionCpp::genTypeInstancesUsedInReduce() { 214 for (auto I = mRSContext->export_reduce_begin(), 215 E = mRSContext->export_reduce_end(); 216 I != E; ++I) { 217 genTypeInstance((*I)->getType()); 218 } 219} 220 221void RSReflectionCpp::genFieldsForAllocationTypeVerification() { 222 bool CommentAdded = false; 223 for (std::set<std::string>::iterator I = mTypesToCheck.begin(), 224 E = mTypesToCheck.end(); 225 I != E; I++) { 226 if (!CommentAdded) { 227 mOut.comment("The following elements are used to verify the types of " 228 "allocations passed to kernels."); 229 CommentAdded = true; 230 } 231 mOut.indent() << "android::RSC::sp<const android::RSC::Element> " 232 << kRsElemPrefix << *I << ";\n"; 233 } 234} 235 236void RSReflectionCpp::genFieldsToStoreExportVariableValues() { 237 bool CommentAdded = false; 238 for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(), 239 E = mRSContext->export_vars_end(); 240 I != E; I++) { 241 const RSExportVar *ev = *I; 242 if (ev->isConst()) { 243 continue; 244 } 245 if (!CommentAdded) { 246 mOut.comment("For each non-const variable exported by the script, we " 247 "have an equivalent field. This field contains the last " 248 "value this variable was set to using the set_ method. " 249 "This may not be current value of the variable in the " 250 "script, as the script is free to modify its internal " 251 "variable without changing this field. If the script " 252 "initializes the exported variable, the constructor will " 253 "initialize this field to the same value."); 254 CommentAdded = true; 255 } 256 mOut.indent() << GetTypeName(ev->getType()) << " " RS_EXPORT_VAR_PREFIX 257 << ev->getName() << ";\n"; 258 } 259} 260 261void RSReflectionCpp::genForEachDeclarations() { 262 bool CommentAdded = false; 263 for (RSContext::const_export_foreach_iterator 264 I = mRSContext->export_foreach_begin(), 265 E = mRSContext->export_foreach_end(); 266 I != E; I++) { 267 const RSExportForEach *ForEach = *I; 268 269 if (ForEach->isDummyRoot()) { 270 mOut.indent() << "// No forEach_root(...)\n"; 271 continue; 272 } 273 274 if (!CommentAdded) { 275 mOut.comment("For each kernel of the script corresponds one method. " 276 "That method queues the kernel for execution. The kernel " 277 "may not have completed nor even started by the time this " 278 "function returns. Calls that extract the data out of the " 279 "output allocation will wait for the kernels to complete."); 280 CommentAdded = true; 281 } 282 283 std::string FunctionStart = "void forEach_" + ForEach->getName() + "("; 284 mOut.indent() << FunctionStart; 285 286 ArgumentList Arguments; 287 const RSExportForEach::InVec &Ins = ForEach->getIns(); 288 for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end(); 289 BI != EI; BI++) { 290 291 Arguments.push_back(Argument(kAllocationSp, (*BI)->getName())); 292 } 293 294 if (ForEach->hasOut() || ForEach->hasReturn()) { 295 Arguments.push_back(Argument(kAllocationSp, "aout")); 296 } 297 298 const RSExportRecordType *ERT = ForEach->getParamPacketType(); 299 if (ERT) { 300 for (RSExportForEach::const_param_iterator i = ForEach->params_begin(), 301 e = ForEach->params_end(); 302 i != e; i++) { 303 RSReflectionTypeData rtd; 304 (*i)->getType()->convertToRTD(&rtd); 305 Arguments.push_back(Argument(rtd.type->c_name, (*i)->getName())); 306 } 307 } 308 genArguments(Arguments, FunctionStart.length()); 309 mOut << ");\n"; 310 } 311} 312 313void RSReflectionCpp::genReduceDeclarations() { 314 bool CommentAdded = false; 315 for (auto I = mRSContext->export_reduce_begin(), 316 E = mRSContext->export_reduce_end(); I != E; I++) { 317 if (!CommentAdded) { 318 mOut.comment("For each reduce kernel of the script, there is an entry " 319 "point to call the reduce kernel."); 320 CommentAdded = true; 321 } 322 323 makeReduceSignatureAllocationVariant(false, *I); 324 makeReduceSignatureArrayVariant(false, *I); 325 } 326} 327 328void RSReflectionCpp::genExportFunctionDeclarations() { 329 for (RSContext::const_export_func_iterator 330 I = mRSContext->export_funcs_begin(), 331 E = mRSContext->export_funcs_end(); 332 I != E; I++) { 333 const RSExportFunc *ef = *I; 334 335 makeFunctionSignature(false, ef); 336 } 337} 338 339// forEach_* implementation 340void RSReflectionCpp::genExportForEachBodies() { 341 uint32_t slot = 0; 342 for (auto I = mRSContext->export_foreach_begin(), 343 E = mRSContext->export_foreach_end(); 344 I != E; I++, slot++) { 345 const RSExportForEach *ef = *I; 346 if (ef->isDummyRoot()) { 347 mOut.indent() << "// No forEach_root(...)\n"; 348 continue; 349 } 350 351 ArgumentList Arguments; 352 std::string FunctionStart = 353 "void " + mClassName + "::forEach_" + ef->getName() + "("; 354 mOut.indent() << FunctionStart; 355 356 if (ef->hasIns()) { 357 // FIXME: Add support for kernels with multiple inputs. 358 slangAssert(ef->getIns().size() == 1); 359 Arguments.push_back(Argument(kAllocationSp, "ain")); 360 } 361 362 if (ef->hasOut() || ef->hasReturn()) { 363 Arguments.push_back(Argument(kAllocationSp, "aout")); 364 } 365 366 const RSExportRecordType *ERT = ef->getParamPacketType(); 367 if (ERT) { 368 for (RSExportForEach::const_param_iterator i = ef->params_begin(), 369 e = ef->params_end(); 370 i != e; i++) { 371 RSReflectionTypeData rtd; 372 (*i)->getType()->convertToRTD(&rtd); 373 Arguments.push_back(Argument(rtd.type->c_name, (*i)->getName())); 374 } 375 } 376 genArguments(Arguments, FunctionStart.length()); 377 mOut << ")"; 378 mOut.startBlock(); 379 380 const RSExportType *OET = ef->getOutType(); 381 const RSExportForEach::InTypeVec &InTypes = ef->getInTypes(); 382 if (ef->hasIns()) { 383 // FIXME: Add support for kernels with multiple inputs. 384 slangAssert(ef->getIns().size() == 1); 385 genTypeCheck(InTypes[0], "ain"); 386 } 387 if (OET) { 388 genTypeCheck(OET, "aout"); 389 } 390 391 // TODO Add the appropriate dimension checking code, as seen in 392 // slang_rs_reflection.cpp. 393 394 std::string FieldPackerName = ef->getName() + "_fp"; 395 if (ERT) { 396 if (genCreateFieldPacker(ERT, FieldPackerName.c_str())) { 397 genPackVarOfType(ERT, nullptr, FieldPackerName.c_str()); 398 } 399 } 400 mOut.indent() << "forEach(" << slot << ", "; 401 402 if (ef->hasIns()) { 403 // FIXME: Add support for kernels with multiple inputs. 404 slangAssert(ef->getIns().size() == 1); 405 mOut << "ain, "; 406 } else { 407 mOut << "NULL, "; 408 } 409 410 if (ef->hasOut() || ef->hasReturn()) { 411 mOut << "aout, "; 412 } else { 413 mOut << "NULL, "; 414 } 415 416 // FIXME (no support for usrData with C++ kernels) 417 mOut << "NULL, 0);\n"; 418 mOut.endBlock(); 419 } 420} 421 422// reduce_* implementation 423void RSReflectionCpp::genExportReduceBodies() { 424 for (auto I = mRSContext->export_reduce_begin(), 425 E = mRSContext->export_reduce_end(); 426 I != E; ++I) { 427 const RSExportReduce &Reduce = **I; 428 const RSExportType *Type = Reduce.getType(); 429 430 // Allocation variant 431 // 432 // void reduce_foo(sp<Allocation> ain, sp<Allocation> aout, 433 // const RsScriptCall *sc); 434 makeReduceSignatureAllocationVariant(true, &Reduce); 435 mOut.startBlock(); 436 437 // Type check 438 genTypeCheck(Type, "ain"); 439 genTypeCheck(Type, "aout"); 440 441 // Dimension check 442 gen1DCheck("ain"); 443 444 const uint32_t Slot = getNextExportReduceSlot(); 445 446 // Call into RenderScript. 447 mOut.indent() << "reduce(" << Slot << ", " 448 << "ain, aout, sc);\n"; 449 mOut.endBlock(); 450 451 if (!canExportReduceArrayVariant(Type)) { 452 continue; 453 } 454 455 // Array variant 456 // 457 // Ty reduce_foo(const ElemTy[] in, uint32_t x1, uint32_t x2, uint32_t inLen); 458 // "Ty" could be different from "ElemTy" in the case of vectors. 459 makeReduceSignatureArrayVariant(true, &Reduce); 460 mOut.startBlock(); 461 462 const std::string ReturnType = GetTypeName(Type); 463 const std::string DefaultReturnValue = ReturnType + "()"; 464 465 genNullOrEmptyArrayCheck("in", "inLen", DefaultReturnValue); 466 467 RSReflectionTypeData TypeData; 468 Type->convertToRTD(&TypeData); 469 const uint32_t VecSize = TypeData.vecSize; 470 std::string InLength = "inLen"; 471 // Adjust the length so that it corresponds to the number of elements in the allocation. 472 if (VecSize > 1) { 473 InLength += " / " + std::to_string(VecSize); 474 } 475 genVectorLengthCompatibilityCheck("inLen", VecSize, DefaultReturnValue); 476 477 mOut.indent() << "if (x1 >= x2 || x2 > " << InLength << ")"; 478 mOut.startBlock(); 479 mOut.indent() << "mRS->throwError(RS_ERROR_RUNTIME_ERROR, " 480 << "\"Input bounds are invalid\");\n"; 481 mOut.indent() << "return " << DefaultReturnValue << ";\n"; 482 mOut.endBlock(); 483 484 mOut.indent() << kAllocationSp 485 << " ain = android::RSC::Allocation::createSized(mRS, " 486 << kRsElemPrefix << Type->getElementName() << ", " 487 << "x2 - x1);\n"; 488 489 mOut.indent() << "ain->setAutoPadding(true);\n"; 490 491 mOut.indent() << kAllocationSp 492 << " aout = android::RSC::Allocation::createSized(mRS, " 493 << kRsElemPrefix << Type->getElementName() << ", 1);\n"; 494 495 mOut.indent() << "aout->setAutoPadding(true);\n"; 496 497 const std::string ArrayElementType = TypeData.type->c_name; 498 499 std::string StartOffset = "x1"; 500 if (VecSize > 1) { 501 StartOffset += " * " + std::to_string(VecSize); 502 } 503 mOut.indent() << "ain->copy1DRangeFrom(0, x2 - x1, &in[" << StartOffset << "]);\n"; 504 mOut.indent() << "reduce_" << Reduce.getName() << "(ain, aout);\n"; 505 mOut.indent() << ArrayElementType << " outArray[" << VecSize << "];\n"; 506 507 mOut.indent() << "aout->copy1DRangeTo(0, 1, &outArray[0]);\n"; 508 509 mOut.indent() << "return " << ReturnType << "("; 510 for (uint32_t VecElem = 0; VecElem < VecSize; ++VecElem) { 511 if (VecElem > 0) mOut << ", "; 512 mOut << "outArray[" << VecElem << "]"; 513 } 514 mOut << ");\n"; 515 mOut.endBlock(); 516 } 517} 518 519// invoke_* implementation 520void RSReflectionCpp::genExportFunctionBodies() { 521 uint32_t slot = 0; 522 // Reflect export function 523 for (auto I = mRSContext->export_funcs_begin(), 524 E = mRSContext->export_funcs_end(); 525 I != E; I++) { 526 const RSExportFunc *ef = *I; 527 528 makeFunctionSignature(true, ef); 529 mOut.startBlock(); 530 const RSExportRecordType *params = ef->getParamPacketType(); 531 size_t param_len = 0; 532 if (params) { 533 param_len = params->getAllocSize(); 534 if (genCreateFieldPacker(params, "__fp")) { 535 genPackVarOfType(params, nullptr, "__fp"); 536 } 537 } 538 539 mOut.indent() << "invoke(" << slot; 540 if (params) { 541 mOut << ", __fp.getData(), " << param_len << ");\n"; 542 } else { 543 mOut << ", NULL, 0);\n"; 544 } 545 mOut.endBlock(); 546 547 slot++; 548 } 549} 550 551bool RSReflectionCpp::genEncodedBitCode() { 552 FILE *pfin = fopen(mBitCodeFilePath.c_str(), "rb"); 553 if (pfin == nullptr) { 554 fprintf(stderr, "Error: could not read file %s\n", 555 mBitCodeFilePath.c_str()); 556 return false; 557 } 558 559 unsigned char buf[16]; 560 int read_length; 561 mOut.indent() << "static const unsigned char __txt[] ="; 562 mOut.startBlock(); 563 while ((read_length = fread(buf, 1, sizeof(buf), pfin)) > 0) { 564 mOut.indent(); 565 for (int i = 0; i < read_length; i++) { 566 char buf2[16]; 567 snprintf(buf2, sizeof(buf2), "0x%02x,", buf[i]); 568 mOut << buf2; 569 } 570 mOut << "\n"; 571 } 572 mOut.endBlock(true); 573 mOut << "\n"; 574 return true; 575} 576 577bool RSReflectionCpp::writeImplementationFile() { 578 if (!mOut.startFile(mOutputDirectory, mClassName + ".cpp", mRSSourceFilePath, 579 mRSContext->getLicenseNote(), false, 580 mRSContext->getVerbose())) { 581 return false; 582 } 583 584 // Front matter 585 mOut.indent() << "#include \"" << mClassName << ".h\"\n\n"; 586 587 genEncodedBitCode(); 588 mOut.indent() << "\n\n"; 589 590 // Constructor 591 const std::string &packageName = mRSContext->getReflectJavaPackageName(); 592 mOut.indent() << mClassName << "::" << mClassName 593 << "(android::RSC::sp<android::RSC::RS> rs):\n" 594 " ScriptC(rs, __txt, sizeof(__txt), \"" 595 << mCleanedRSFileName << "\", " << mCleanedRSFileName.length() 596 << ", \"/data/data/" << packageName << "/app\", sizeof(\"" 597 << packageName << "\"))"; 598 mOut.startBlock(); 599 for (std::set<std::string>::iterator I = mTypesToCheck.begin(), 600 E = mTypesToCheck.end(); 601 I != E; I++) { 602 mOut.indent() << kRsElemPrefix << *I << " = android::RSC::Element::" << *I 603 << "(mRS);\n"; 604 } 605 606 for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(), 607 E = mRSContext->export_vars_end(); 608 I != E; I++) { 609 const RSExportVar *EV = *I; 610 if (!EV->getInit().isUninit()) { 611 genInitExportVariable(EV->getType(), EV->getName(), EV->getInit()); 612 } else { 613 genZeroInitExportVariable(EV->getName()); 614 } 615 } 616 mOut.endBlock(); 617 618 // Destructor 619 mOut.indent() << mClassName << "::~" << mClassName << "()"; 620 mOut.startBlock(); 621 mOut.endBlock(); 622 623 // Function bodies 624 genExportForEachBodies(); 625 genExportReduceBodies(); 626 genExportFunctionBodies(); 627 628 mOut.closeFile(); 629 return true; 630} 631 632void RSReflectionCpp::genExportVariablesGetterAndSetter() { 633 mOut.comment("Methods to set and get the variables exported by the script. " 634 "Const variables will not have a setter.\n\n" 635 "Note that the value returned by the getter may not be the " 636 "current value of the variable in the script. The getter will " 637 "return the initial value of the variable (as defined in the " 638 "script) or the the last value set by using the setter method. " 639 "The script is free to modify its value independently."); 640 for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(), 641 E = mRSContext->export_vars_end(); 642 I != E; I++) { 643 const RSExportVar *EV = *I; 644 const RSExportType *ET = EV->getType(); 645 646 switch (ET->getClass()) { 647 case RSExportType::ExportClassPrimitive: { 648 genGetterAndSetter(static_cast<const RSExportPrimitiveType *>(ET), EV); 649 break; 650 } 651 case RSExportType::ExportClassPointer: { 652 // TODO Deprecate this. 653 genPointerTypeExportVariable(EV); 654 break; 655 } 656 case RSExportType::ExportClassVector: { 657 genGetterAndSetter(static_cast<const RSExportVectorType *>(ET), EV); 658 break; 659 } 660 case RSExportType::ExportClassMatrix: { 661 genMatrixTypeExportVariable(EV); 662 break; 663 } 664 case RSExportType::ExportClassConstantArray: { 665 genGetterAndSetter(static_cast<const RSExportConstantArrayType *>(ET), 666 EV); 667 break; 668 } 669 case RSExportType::ExportClassRecord: { 670 genGetterAndSetter(static_cast<const RSExportRecordType *>(ET), EV); 671 break; 672 } 673 default: { slangAssert(false && "Unknown class of type"); } 674 } 675 } 676} 677 678void RSReflectionCpp::genGetterAndSetter(const RSExportPrimitiveType *EPT, 679 const RSExportVar *EV) { 680 RSReflectionTypeData rtd; 681 EPT->convertToRTD(&rtd); 682 std::string TypeName = GetTypeName(EPT, false); 683 684 if (!EV->isConst()) { 685 mOut.indent() << "void set_" << EV->getName() << "(" << TypeName << " v)"; 686 mOut.startBlock(); 687 mOut.indent() << "setVar(" << getNextExportVarSlot() << ", "; 688 if (EPT->isRSObjectType()) { 689 mOut << "v"; 690 } else { 691 mOut << "&v, sizeof(v)"; 692 } 693 mOut << ");\n"; 694 mOut.indent() << RS_EXPORT_VAR_PREFIX << EV->getName() << " = v;\n"; 695 mOut.endBlock(); 696 } 697 mOut.indent() << TypeName << " get_" << EV->getName() << "() const"; 698 mOut.startBlock(); 699 if (EV->isConst()) { 700 const clang::APValue &val = EV->getInit(); 701 bool isBool = !strcmp(TypeName.c_str(), "bool"); 702 mOut.indent() << "return "; 703 genInitValue(val, isBool); 704 mOut << ";\n"; 705 } else { 706 mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << EV->getName() 707 << ";\n"; 708 } 709 mOut.endBlock(); 710} 711 712void RSReflectionCpp::genPointerTypeExportVariable(const RSExportVar *EV) { 713 const RSExportType *ET = EV->getType(); 714 715 slangAssert((ET->getClass() == RSExportType::ExportClassPointer) && 716 "Variable should be type of pointer here"); 717 718 std::string TypeName = GetTypeName(ET); 719 std::string VarName = EV->getName(); 720 721 RSReflectionTypeData rtd; 722 EV->getType()->convertToRTD(&rtd); 723 uint32_t slot = getNextExportVarSlot(); 724 725 if (!EV->isConst()) { 726 mOut.indent() << "void bind_" << VarName << "(" << TypeName << " v)"; 727 mOut.startBlock(); 728 mOut.indent() << "bindAllocation(v, " << slot << ");\n"; 729 mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = v;\n"; 730 mOut.endBlock(); 731 } 732 mOut.indent() << TypeName << " get_" << VarName << "() const"; 733 mOut.startBlock(); 734 if (EV->isConst()) { 735 const clang::APValue &val = EV->getInit(); 736 bool isBool = !strcmp(TypeName.c_str(), "bool"); 737 mOut.indent() << "return "; 738 genInitValue(val, isBool); 739 mOut << ";\n"; 740 } else { 741 mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << VarName << ";\n"; 742 } 743 mOut.endBlock(); 744} 745 746void RSReflectionCpp::genGetterAndSetter(const RSExportVectorType *EVT, 747 const RSExportVar *EV) { 748 slangAssert(EVT != nullptr); 749 750 RSReflectionTypeData rtd; 751 EVT->convertToRTD(&rtd); 752 753 if (!EV->isConst()) { 754 mOut.indent() << "void set_" << EV->getName() << "(" 755 << rtd.type->rs_c_vector_prefix << EVT->getNumElement() 756 << " v)"; 757 mOut.startBlock(); 758 mOut.indent() << "setVar(" << getNextExportVarSlot() 759 << ", &v, sizeof(v));\n"; 760 mOut.indent() << RS_EXPORT_VAR_PREFIX << EV->getName() << " = v;\n"; 761 mOut.endBlock(); 762 } 763 mOut.indent() << rtd.type->rs_c_vector_prefix << EVT->getNumElement() 764 << " get_" << EV->getName() << "() const"; 765 mOut.startBlock(); 766 if (EV->isConst()) { 767 const clang::APValue &val = EV->getInit(); 768 mOut.indent() << "return "; 769 genInitValue(val, false); 770 mOut << ";\n"; 771 } else { 772 mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << EV->getName() 773 << ";\n"; 774 } 775 mOut.endBlock(); 776} 777 778void RSReflectionCpp::genMatrixTypeExportVariable(const RSExportVar *EV) { 779 slangAssert(false); 780} 781 782void RSReflectionCpp::genGetterAndSetter(const RSExportConstantArrayType *AT, 783 const RSExportVar *EV) { 784 slangAssert(false); 785} 786 787void RSReflectionCpp::genGetterAndSetter(const RSExportRecordType *ERT, 788 const RSExportVar *EV) { 789 slangAssert(false); 790} 791 792void RSReflectionCpp::makeFunctionSignature(bool isDefinition, 793 const RSExportFunc *ef) { 794 mOut.indent() << "void "; 795 if (isDefinition) { 796 mOut << mClassName << "::"; 797 } 798 mOut << "invoke_" << ef->getName() << "("; 799 800 if (ef->getParamPacketType()) { 801 bool FirstArg = true; 802 for (RSExportFunc::const_param_iterator i = ef->params_begin(), 803 e = ef->params_end(); 804 i != e; i++) { 805 if (!FirstArg) { 806 mOut << ", "; 807 } else { 808 FirstArg = false; 809 } 810 mOut << GetTypeName((*i)->getType(), false) << " " << (*i)->getName(); 811 } 812 } 813 814 if (isDefinition) { 815 mOut << ")"; 816 } else { 817 mOut << ");\n"; 818 } 819} 820 821void RSReflectionCpp::makeReduceSignatureAllocationVariant(bool IsDefinition, 822 const RSExportReduce *ER) { 823 // void reduce_foo(sp<Allocation> ain, sp<Allocation> aout, 824 // const RsScriptCall *sc = nullptr); 825 std::string FunctionStart = "void "; 826 if (IsDefinition) { 827 FunctionStart += mClassName + "::"; 828 } 829 FunctionStart += "reduce_" + ER->getName() + "("; 830 831 ArgumentList Arguments{ 832 Argument(kAllocationSp, "ain"), 833 Argument(kAllocationSp, "aout"), 834 Argument(kConstRsScriptCall, "*sc", IsDefinition ? "" : "nullptr") 835 }; 836 837 mOut.indent() << FunctionStart; 838 839 genArguments(Arguments, FunctionStart.length()); 840 841 if (IsDefinition) { 842 mOut << ")"; 843 } else { 844 mOut << ");\n\n"; 845 } 846} 847 848void RSReflectionCpp::makeReduceSignatureArrayVariant(bool IsDefinition, 849 const RSExportReduce *ER) { 850 // Ty reduce_foo(const ElemTy[] in, uint32_t x1, uint32_t x2, size_t inLen); 851 // "Ty" could be different from "ElemTy" in the case of vectors. 852 853 const RSExportType *Type = ER->getType(); 854 if (!canExportReduceArrayVariant(Type)) { 855 return; 856 } 857 858 RSReflectionTypeData TypeData; 859 Type->convertToRTD(&TypeData); 860 861 const std::string ReturnType = GetTypeName(Type); 862 std::string FunctionStart = ReturnType + " "; 863 if (IsDefinition) { 864 FunctionStart += mClassName + "::"; 865 } 866 FunctionStart += "reduce_" + ER->getName() + "("; 867 868 const std::string ArrayElementType = TypeData.type->c_name; 869 870 ArgumentList Arguments{ 871 Argument("const " + ArrayElementType, "in[]"), 872 Argument("uint32_t", "x1"), 873 Argument("uint32_t", "x2"), 874 Argument("size_t", "inLen") 875 }; 876 877 mOut.indent() << FunctionStart; 878 genArguments(Arguments, FunctionStart.size()); 879 880 if (IsDefinition) { 881 mOut << ")"; 882 } else { 883 mOut << ");\n\n"; 884 } 885 886 if (!IsDefinition) { 887 // We reflect three more variants in the header. First, there is 888 // 889 // Ty reduce_foo(const ElemTy[] in, size_t inLen); 890 // 891 // Note the inLen is the number of primitive elements in the array, as opposed to the 892 // bounds whose units are allocation elements. The other variants use templates to infer 893 // the array length statically: 894 // 895 // template<size_t inLen> Ty reduce_foo(const ElemTy (&in)[inLen]); 896 // template<size_t inLen> Ty reduce_foo(const ElemTy (&in)[inLen], uint32_t x1, uint32_t x2); 897 898 // Generate inLen variant 899 const uint32_t VecSize = TypeData.vecSize; 900 std::string X2 = "inLen"; 901 902 const std::string FunctionName = ER->getName(); 903 904 auto ForwardReduce = [this, &FunctionName](const std::string &x1, 905 const std::string &x2, 906 const std::string &inLen) { 907 this->mOut.indent() << " return reduce_" << FunctionName << "(in, " 908 << x1 << ", " << x2 << ", " << inLen << ");\n"; 909 this->mOut.indent() << "}\n\n"; 910 }; 911 912 const std::string DefaultValue = ReturnType + "()"; 913 914 ArgumentList InLenVariantArguments{ 915 Argument("const " + ArrayElementType, "in[]"), Argument("size_t", "inLen") 916 }; 917 mOut.indent() << FunctionStart; 918 genArguments(InLenVariantArguments, FunctionStart.size()); 919 mOut << ") {\n"; 920 if (VecSize > 1) { 921 genVectorLengthCompatibilityCheck("inLen", VecSize, DefaultValue, 2); 922 X2 += " / " + std::to_string(VecSize); 923 } 924 ForwardReduce("0", X2, "inLen"); 925 926 // Generate template variants 927 ArgumentList TemplateVariantArguments{ 928 Argument("const " + ArrayElementType, "(&in)[inLen]") 929 }; 930 931 mOut.indent() << "template<size_t inLen>\n"; 932 mOut.indent() << FunctionStart; 933 genArguments(TemplateVariantArguments, FunctionStart.size()); 934 mOut << ") {\n return reduce_" << FunctionName << "(in, inLen);\n }\n\n"; 935 936 TemplateVariantArguments.push_back(Argument("uint32_t", "x1")); 937 TemplateVariantArguments.push_back(Argument("uint32_t", "x2")); 938 mOut.indent() << "template<size_t inLen>\n"; 939 mOut.indent() << FunctionStart; 940 genArguments(TemplateVariantArguments, FunctionStart.size()); 941 mOut << ") {\n"; 942 ForwardReduce("x1", "x2", "inLen"); 943 } 944} 945 946void RSReflectionCpp::genArguments(const ArgumentList &Arguments, int Offset) { 947 bool FirstArg = true; 948 949 for (ArgumentList::const_iterator I = Arguments.begin(), E = Arguments.end(); 950 I != E; I++) { 951 if (!FirstArg) { 952 mOut << ",\n"; 953 mOut.indent() << string(Offset, ' '); 954 } else { 955 FirstArg = false; 956 } 957 958 mOut << I->Type << " " << I->Name; 959 if (!I->DefaultValue.empty()) { 960 mOut << " = " << I->DefaultValue; 961 } 962 } 963} 964 965bool RSReflectionCpp::genCreateFieldPacker(const RSExportType *ET, 966 const char *FieldPackerName) { 967 size_t AllocSize = ET->getAllocSize(); 968 969 if (AllocSize > 0) { 970 mOut.indent() << "android::RSC::FieldPacker " << FieldPackerName << "(" 971 << AllocSize << ");\n"; 972 return true; 973 } 974 975 return false; 976} 977 978void RSReflectionCpp::genPackVarOfType(const RSExportType *ET, 979 const char *VarName, 980 const char *FieldPackerName) { 981 switch (ET->getClass()) { 982 case RSExportType::ExportClassPrimitive: 983 case RSExportType::ExportClassVector: 984 case RSExportType::ExportClassPointer: 985 case RSExportType::ExportClassMatrix: { 986 mOut.indent() << FieldPackerName << ".add(" << VarName << ");\n"; 987 break; 988 } 989 case RSExportType::ExportClassConstantArray: { 990 /*const RSExportConstantArrayType *ECAT = 991 static_cast<const RSExportConstantArrayType *>(ET); 992 993 // TODO(zonr): more elegant way. Currently, we obtain the unique index 994 // variable (this method involves recursive call which means 995 // we may have more than one level loop, therefore we can't 996 // always use the same index variable name here) name given 997 // in the for-loop from counting the '.' in @VarName. 998 unsigned Level = 0; 999 size_t LastDotPos = 0; 1000 std::string ElementVarName(VarName); 1001 1002 while (LastDotPos != std::string::npos) { 1003 LastDotPos = ElementVarName.find_first_of('.', LastDotPos + 1); 1004 Level++; 1005 } 1006 std::string IndexVarName("ct"); 1007 IndexVarName.append(llvm::utostr_32(Level)); 1008 1009 C.indent() << "for (int " << IndexVarName << " = 0; " << 1010 IndexVarName << " < " << ECAT->getSize() << "; " << 1011 IndexVarName << "++)"; 1012 C.startBlock(); 1013 1014 ElementVarName.append("[" + IndexVarName + "]"); 1015 genPackVarOfType(C, ECAT->getElementType(), ElementVarName.c_str(), 1016 FieldPackerName); 1017 1018 C.endBlock();*/ 1019 break; 1020 } 1021 case RSExportType::ExportClassRecord: { 1022 const RSExportRecordType *ERT = static_cast<const RSExportRecordType *>(ET); 1023 // Relative pos from now on in field packer 1024 unsigned Pos = 0; 1025 1026 for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(), 1027 E = ERT->fields_end(); 1028 I != E; I++) { 1029 const RSExportRecordType::Field *F = *I; 1030 std::string FieldName; 1031 size_t FieldOffset = F->getOffsetInParent(); 1032 const RSExportType *T = F->getType(); 1033 size_t FieldStoreSize = T->getStoreSize(); 1034 size_t FieldAllocSize = T->getAllocSize(); 1035 1036 if (VarName != nullptr) 1037 FieldName = VarName + ("." + F->getName()); 1038 else 1039 FieldName = F->getName(); 1040 1041 if (FieldOffset > Pos) { 1042 mOut.indent() << FieldPackerName << ".skip(" << (FieldOffset - Pos) 1043 << ");\n"; 1044 } 1045 1046 genPackVarOfType(F->getType(), FieldName.c_str(), FieldPackerName); 1047 1048 // There is padding in the field type 1049 if (FieldAllocSize > FieldStoreSize) { 1050 mOut.indent() << FieldPackerName << ".skip(" 1051 << (FieldAllocSize - FieldStoreSize) << ");\n"; 1052 } 1053 1054 Pos = FieldOffset + FieldAllocSize; 1055 } 1056 1057 // There maybe some padding after the struct 1058 if (ERT->getAllocSize() > Pos) { 1059 mOut.indent() << FieldPackerName << ".skip(" << ERT->getAllocSize() - Pos 1060 << ");\n"; 1061 } 1062 break; 1063 } 1064 default: { slangAssert(false && "Unknown class of type"); } 1065 } 1066} 1067 1068void RSReflectionCpp::genTypeCheck(const RSExportType *ET, 1069 const char *VarName) { 1070 mOut.indent() << "// Type check for " << VarName << "\n"; 1071 1072 if (ET->getClass() == RSExportType::ExportClassPointer) { 1073 const RSExportPointerType *EPT = 1074 static_cast<const RSExportPointerType *>(ET); 1075 ET = EPT->getPointeeType(); 1076 } 1077 1078 std::string TypeName; 1079 switch (ET->getClass()) { 1080 case RSExportType::ExportClassPrimitive: 1081 case RSExportType::ExportClassVector: 1082 case RSExportType::ExportClassRecord: { 1083 TypeName = ET->getElementName(); 1084 break; 1085 } 1086 1087 default: 1088 break; 1089 } 1090 1091 if (!TypeName.empty()) { 1092 mOut.indent() << "if (!" << VarName 1093 << "->getType()->getElement()->isCompatible(" 1094 << kRsElemPrefix << TypeName << "))"; 1095 mOut.startBlock(); 1096 mOut.indent() << "mRS->throwError(RS_ERROR_RUNTIME_ERROR, " 1097 "\"Incompatible type\");\n"; 1098 mOut.indent() << "return;\n"; 1099 mOut.endBlock(); 1100 } 1101} 1102 1103// Ensure that the input is 1 dimensional. 1104void RSReflectionCpp::gen1DCheck(const std::string &VarName) { 1105 mOut.indent() << "// check that " << VarName << " is 1d\n"; 1106 mOut.indent() << "sp<const Type> t0 = " << VarName << "->getType();\n"; 1107 mOut.indent() << "if (t0->getY() != 0 ||\n"; 1108 mOut.indent() << " t0->hasFaces() ||\n"; 1109 mOut.indent() << " t0->hasMipmaps())"; 1110 mOut.startBlock(); 1111 mOut.indent() << "mRS->throwError(RS_ERROR_INVALID_PARAMETER, " 1112 << "\"" << VarName << " is not 1D!\");\n"; 1113 mOut.indent() << "return;\n"; 1114 mOut.endBlock(); 1115} 1116 1117// Generates code to ensure that the supplied array length is a multiple of the vector size. 1118void RSReflectionCpp::genVectorLengthCompatibilityCheck(const std::string &Length, 1119 unsigned VecSize, 1120 const std::string &ValueToReturn, 1121 unsigned IndentLevels) { 1122 auto Indenter = [this, IndentLevels]() -> std::ofstream& { 1123 GeneratedFile &Out = this->mOut; 1124 for (unsigned Level = 0; Level < IndentLevels; ++Level) { 1125 Out.indent(); 1126 } 1127 return Out; 1128 }; 1129 1130 Indenter() << "// Verify that the array length is a multiple of the vector size.\n"; 1131 Indenter() << "if (" << Length << " % " << std::to_string(VecSize) << " != 0) {\n"; 1132 Indenter() << " mRS->throwError(RS_ERROR_INVALID_PARAMETER, " 1133 << "\"Input array length is not a multiple of " 1134 << std::to_string(VecSize) << "\");\n"; 1135 Indenter() << " return " << ValueToReturn << ";\n"; 1136 Indenter() << "}\n\n"; 1137} 1138 1139// Generates code to ensure that the supplied array is non-null and nonzero in length. 1140void RSReflectionCpp::genNullOrEmptyArrayCheck(const std::string &ArrayName, 1141 const std::string &Length, 1142 const std::string &ValueToReturn) { 1143 mOut.indent() << "// Verify that the array is non-null and non-empty.\n"; 1144 mOut.indent() << "if (" << ArrayName << " == nullptr) {\n"; 1145 mOut.indent() << " mRS->throwError(RS_ERROR_INVALID_PARAMETER, " 1146 << "\"Input array is null\");\n"; 1147 mOut.indent() << " return " << ValueToReturn << ";\n"; 1148 mOut.indent() << "}\n\n"; 1149 1150 mOut.indent() << "if (" << Length << " == 0) {\n"; 1151 mOut.indent() << " mRS->throwError(RS_ERROR_INVALID_PARAMETER, " 1152 << "\"Input array is zero-length\");\n"; 1153 mOut.indent() << " return " << ValueToReturn << ";\n"; 1154 mOut.indent() << "}\n\n"; 1155} 1156 1157void RSReflectionCpp::genTypeInstanceFromPointer(const RSExportType *ET) { 1158 if (ET->getClass() == RSExportType::ExportClassPointer) { 1159 // For pointer parameters to original forEach kernels. 1160 const RSExportPointerType *EPT = 1161 static_cast<const RSExportPointerType *>(ET); 1162 genTypeInstance(EPT->getPointeeType()); 1163 } else { 1164 // For handling pass-by-value kernel parameters. 1165 genTypeInstance(ET); 1166 } 1167} 1168 1169void RSReflectionCpp::genTypeInstance(const RSExportType *ET) { 1170 switch (ET->getClass()) { 1171 case RSExportType::ExportClassPrimitive: 1172 case RSExportType::ExportClassVector: 1173 case RSExportType::ExportClassConstantArray: 1174 case RSExportType::ExportClassRecord: { 1175 std::string TypeName = ET->getElementName(); 1176 mTypesToCheck.insert(TypeName); 1177 break; 1178 } 1179 1180 default: 1181 break; 1182 } 1183} 1184 1185void RSReflectionCpp::genInitExportVariable(const RSExportType *ET, 1186 const std::string &VarName, 1187 const clang::APValue &Val) { 1188 slangAssert(!Val.isUninit() && "Not a valid initializer"); 1189 1190 switch (ET->getClass()) { 1191 case RSExportType::ExportClassPrimitive: { 1192 const RSExportPrimitiveType *EPT = 1193 static_cast<const RSExportPrimitiveType *>(ET); 1194 if (EPT->getType() == DataTypeBoolean) { 1195 genInitBoolExportVariable(VarName, Val); 1196 } else { 1197 genInitPrimitiveExportVariable(VarName, Val); 1198 } 1199 break; 1200 } 1201 case RSExportType::ExportClassPointer: { 1202 if (!Val.isInt() || Val.getInt().getSExtValue() != 0) 1203 std::cerr << "Initializer which is non-NULL to pointer type variable " 1204 "will be ignored" << std::endl; 1205 break; 1206 } 1207 case RSExportType::ExportClassVector: { 1208 const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET); 1209 switch (Val.getKind()) { 1210 case clang::APValue::Int: 1211 case clang::APValue::Float: { 1212 for (unsigned i = 0; i < EVT->getNumElement(); i++) { 1213 std::string Name = VarName + "." + getVectorAccessor(i); 1214 genInitPrimitiveExportVariable(Name, Val); 1215 } 1216 break; 1217 } 1218 case clang::APValue::Vector: { 1219 unsigned NumElements = std::min( 1220 static_cast<unsigned>(EVT->getNumElement()), Val.getVectorLength()); 1221 for (unsigned i = 0; i < NumElements; i++) { 1222 const clang::APValue &ElementVal = Val.getVectorElt(i); 1223 std::string Name = VarName + "." + getVectorAccessor(i); 1224 genInitPrimitiveExportVariable(Name, ElementVal); 1225 } 1226 break; 1227 } 1228 case clang::APValue::MemberPointer: 1229 case clang::APValue::Uninitialized: 1230 case clang::APValue::ComplexInt: 1231 case clang::APValue::ComplexFloat: 1232 case clang::APValue::LValue: 1233 case clang::APValue::Array: 1234 case clang::APValue::Struct: 1235 case clang::APValue::Union: 1236 case clang::APValue::AddrLabelDiff: { 1237 slangAssert(false && "Unexpected type of value of initializer."); 1238 } 1239 } 1240 break; 1241 } 1242 case RSExportType::ExportClassMatrix: 1243 case RSExportType::ExportClassConstantArray: 1244 case RSExportType::ExportClassRecord: { 1245 slangAssert(false && "Unsupported initializer for record/matrix/constant " 1246 "array type variable currently"); 1247 break; 1248 } 1249 default: { slangAssert(false && "Unknown class of type"); } 1250 } 1251} 1252 1253const char *RSReflectionCpp::getVectorAccessor(unsigned Index) { 1254 static const char *VectorAccessorMap[] = {/* 0 */ "x", 1255 /* 1 */ "y", 1256 /* 2 */ "z", 1257 /* 3 */ "w", 1258 }; 1259 1260 slangAssert((Index < (sizeof(VectorAccessorMap) / sizeof(const char *))) && 1261 "Out-of-bound index to access vector member"); 1262 1263 return VectorAccessorMap[Index]; 1264} 1265 1266void RSReflectionCpp::genZeroInitExportVariable(const std::string &VarName) { 1267 mOut.indent() << "memset(&" << RS_EXPORT_VAR_PREFIX << VarName 1268 << ", 0, sizeof(" << RS_EXPORT_VAR_PREFIX << VarName << "));\n"; 1269} 1270 1271void 1272RSReflectionCpp::genInitPrimitiveExportVariable(const std::string &VarName, 1273 const clang::APValue &Val) { 1274 slangAssert(!Val.isUninit() && "Not a valid initializer"); 1275 1276 mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = "; 1277 genInitValue(Val); 1278 mOut << ";\n"; 1279} 1280 1281void RSReflectionCpp::genInitValue(const clang::APValue &Val, bool asBool) { 1282 switch (Val.getKind()) { 1283 case clang::APValue::Int: { 1284 llvm::APInt api = Val.getInt(); 1285 if (asBool) { 1286 mOut << ((api.getSExtValue() == 0) ? "false" : "true"); 1287 } else { 1288 // TODO: Handle unsigned correctly for C++ 1289 mOut << api.getSExtValue(); 1290 if (api.getBitWidth() > 32) { 1291 mOut << "L"; 1292 } 1293 } 1294 break; 1295 } 1296 1297 case clang::APValue::Float: { 1298 llvm::APFloat apf = Val.getFloat(); 1299 llvm::SmallString<30> s; 1300 apf.toString(s); 1301 mOut << s.c_str(); 1302 if (&apf.getSemantics() == &llvm::APFloat::IEEEsingle) { 1303 if (s.count('.') == 0) { 1304 mOut << ".f"; 1305 } else { 1306 mOut << "f"; 1307 } 1308 } 1309 break; 1310 } 1311 1312 case clang::APValue::ComplexInt: 1313 case clang::APValue::ComplexFloat: 1314 case clang::APValue::LValue: 1315 case clang::APValue::Vector: { 1316 slangAssert(false && "Primitive type cannot have such kind of initializer"); 1317 break; 1318 } 1319 1320 default: { slangAssert(false && "Unknown kind of initializer"); } 1321 } 1322} 1323 1324void RSReflectionCpp::genInitBoolExportVariable(const std::string &VarName, 1325 const clang::APValue &Val) { 1326 slangAssert(!Val.isUninit() && "Not a valid initializer"); 1327 slangAssert((Val.getKind() == clang::APValue::Int) && 1328 "Bool type has wrong initial APValue"); 1329 1330 mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = " 1331 << ((Val.getInt().getSExtValue() == 0) ? "false" : "true") 1332 << ";"; 1333} 1334 1335} // namespace slang 1336