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