slang_rs_export_foreach.cpp revision b3e022a62c7017f7853a6149a63bd00b13091a6c
1/* 2 * Copyright 2011-2012, 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 "slang_rs_export_foreach.h" 18 19#include <string> 20 21#include "clang/AST/ASTContext.h" 22#include "clang/AST/Attr.h" 23#include "clang/AST/Decl.h" 24#include "clang/AST/TypeLoc.h" 25 26#include "llvm/IR/DerivedTypes.h" 27 28#include "bcinfo/MetadataExtractor.h" 29 30#include "slang_assert.h" 31#include "slang_rs_context.h" 32#include "slang_rs_export_type.h" 33#include "slang_version.h" 34 35namespace { 36 37const size_t RS_KERNEL_INPUT_LIMIT = 8; // see frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h 38 39enum SpecialParameterKind { 40 SPK_INT, // 'int' or 'unsigned int' 41 SPK_CTXT, // rs_kernel_context 42}; 43 44struct SpecialParameter { 45 const char *name; 46 bcinfo::MetadataSignatureBitval bitval; 47 SpecialParameterKind kind; 48 SlangTargetAPI minAPI; 49}; 50 51// Table entries are in the order parameters must occur in a kernel parameter list. 52const SpecialParameter specialParameterTable[] = { 53 { "ctxt", bcinfo::MD_SIG_Ctxt, SPK_CTXT, SLANG_M_TARGET_API }, 54 { "x", bcinfo::MD_SIG_X, SPK_INT, SLANG_MINIMUM_TARGET_API }, 55 { "y", bcinfo::MD_SIG_Y, SPK_INT, SLANG_MINIMUM_TARGET_API }, 56 { "z", bcinfo::MD_SIG_Z, SPK_INT, SLANG_M_TARGET_API }, 57 { nullptr, bcinfo::MD_SIG_None, SPK_INT, SLANG_MINIMUM_TARGET_API }, // marks end of table 58}; 59 60// If the specified name matches the name of an entry in 61// specialParameterTable, return the corresponding table index; 62// otherwise return -1. 63int lookupSpecialParameter(const llvm::StringRef name) { 64 for (int i = 0; specialParameterTable[i].name != nullptr; ++i) 65 if (name.equals(specialParameterTable[i].name)) 66 return i; 67 return -1; 68} 69 70// Return a comma-separated list of names in specialParameterTable 71// that are available at the specified API level. 72std::string listSpecialParameters(unsigned int api) { 73 std::string ret; 74 bool first = true; 75 for (int i = 0; specialParameterTable[i].name != nullptr; ++i) { 76 if (specialParameterTable[i].minAPI > api) 77 continue; 78 if (first) 79 first = false; 80 else 81 ret += ", "; 82 ret += "'"; 83 ret += specialParameterTable[i].name; 84 ret += "'"; 85 } 86 return ret; 87} 88 89} 90 91namespace slang { 92 93// This function takes care of additional validation and construction of 94// parameters related to forEach_* reflection. 95bool RSExportForEach::validateAndConstructParams( 96 RSContext *Context, const clang::FunctionDecl *FD) { 97 slangAssert(Context && FD); 98 bool valid = true; 99 100 numParams = FD->getNumParams(); 101 102 if (Context->getTargetAPI() < SLANG_JB_TARGET_API) { 103 // Before JellyBean, we allowed only one kernel per file. It must be called "root". 104 if (!isRootRSFunc(FD)) { 105 Context->ReportError(FD->getLocation(), 106 "Non-root compute kernel %0() is " 107 "not supported in SDK levels %1-%2") 108 << FD->getName() << SLANG_MINIMUM_TARGET_API 109 << (SLANG_JB_TARGET_API - 1); 110 return false; 111 } 112 } 113 114 mResultType = FD->getReturnType().getCanonicalType(); 115 // Compute kernel functions are defined differently when the 116 // "__attribute__((kernel))" is set. 117 if (FD->hasAttr<clang::KernelAttr>()) { 118 valid |= validateAndConstructKernelParams(Context, FD); 119 } else { 120 valid |= validateAndConstructOldStyleParams(Context, FD); 121 } 122 123 valid |= setSignatureMetadata(Context, FD); 124 return valid; 125} 126 127bool RSExportForEach::validateAndConstructOldStyleParams( 128 RSContext *Context, const clang::FunctionDecl *FD) { 129 slangAssert(Context && FD); 130 // If numParams is 0, we already marked this as a graphics root(). 131 slangAssert(numParams > 0); 132 133 bool valid = true; 134 135 // Compute kernel functions of this style are required to return a void type. 136 clang::ASTContext &C = Context->getASTContext(); 137 if (mResultType != C.VoidTy) { 138 Context->ReportError(FD->getLocation(), 139 "Compute kernel %0() is required to return a " 140 "void type") 141 << FD->getName(); 142 valid = false; 143 } 144 145 // Validate remaining parameter types 146 147 size_t IndexOfFirstSpecialParameter = numParams; 148 valid |= validateSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter); 149 150 // Validate the non-special parameters, which should all be found before the 151 // first special parameter. 152 for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) { 153 const clang::ParmVarDecl *PVD = FD->getParamDecl(i); 154 clang::QualType QT = PVD->getType().getCanonicalType(); 155 156 if (!QT->isPointerType()) { 157 Context->ReportError(PVD->getLocation(), 158 "Compute kernel %0() cannot have non-pointer " 159 "parameters besides (%1). Parameter '%2' is " 160 "of type: '%3'") 161 << FD->getName() << listSpecialParameters(Context->getTargetAPI()) 162 << PVD->getName() << PVD->getType().getAsString(); 163 valid = false; 164 continue; 165 } 166 167 // The only non-const pointer should be out. 168 if (!QT->getPointeeType().isConstQualified()) { 169 if (mOut == nullptr) { 170 mOut = PVD; 171 } else { 172 Context->ReportError(PVD->getLocation(), 173 "Compute kernel %0() can only have one non-const " 174 "pointer parameter. Parameters '%1' and '%2' are " 175 "both non-const.") 176 << FD->getName() << mOut->getName() << PVD->getName(); 177 valid = false; 178 } 179 } else { 180 if (mIns.empty() && mOut == nullptr) { 181 mIns.push_back(PVD); 182 } else if (mUsrData == nullptr) { 183 mUsrData = PVD; 184 } else { 185 Context->ReportError( 186 PVD->getLocation(), 187 "Unexpected parameter '%0' for compute kernel %1()") 188 << PVD->getName() << FD->getName(); 189 valid = false; 190 } 191 } 192 } 193 194 if (mIns.empty() && !mOut) { 195 Context->ReportError(FD->getLocation(), 196 "Compute kernel %0() must have at least one " 197 "parameter for in or out") 198 << FD->getName(); 199 valid = false; 200 } 201 202 return valid; 203} 204 205bool RSExportForEach::validateAndConstructKernelParams( 206 RSContext *Context, const clang::FunctionDecl *FD) { 207 slangAssert(Context && FD); 208 bool valid = true; 209 clang::ASTContext &C = Context->getASTContext(); 210 211 if (Context->getTargetAPI() < SLANG_JB_MR1_TARGET_API) { 212 Context->ReportError(FD->getLocation(), 213 "Compute kernel %0() targeting SDK levels " 214 "%1-%2 may not use pass-by-value with " 215 "__attribute__((kernel))") 216 << FD->getName() << SLANG_MINIMUM_TARGET_API 217 << (SLANG_JB_MR1_TARGET_API - 1); 218 return false; 219 } 220 221 // Denote that we are indeed a pass-by-value kernel. 222 mIsKernelStyle = true; 223 mHasReturnType = (mResultType != C.VoidTy); 224 225 if (mResultType->isPointerType()) { 226 Context->ReportError( 227 FD->getTypeSpecStartLoc(), 228 "Compute kernel %0() cannot return a pointer type: '%1'") 229 << FD->getName() << mResultType.getAsString(); 230 valid = false; 231 } 232 233 // Validate remaining parameter types 234 235 size_t IndexOfFirstSpecialParameter = numParams; 236 valid |= validateSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter); 237 238 // Validate the non-special parameters, which should all be found before the 239 // first special. 240 for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) { 241 const clang::ParmVarDecl *PVD = FD->getParamDecl(i); 242 243 if (Context->getTargetAPI() >= SLANG_M_TARGET_API || i == 0) { 244 if (i >= RS_KERNEL_INPUT_LIMIT) { 245 Context->ReportError(PVD->getLocation(), 246 "Invalid parameter '%0' for compute kernel %1(). " 247 "Kernels targeting SDK levels %2+ may not use " 248 "more than %3 input parameters.") << PVD->getName() << 249 FD->getName() << SLANG_M_TARGET_API << 250 int(RS_KERNEL_INPUT_LIMIT); 251 252 } else { 253 mIns.push_back(PVD); 254 } 255 } else { 256 Context->ReportError(PVD->getLocation(), 257 "Invalid parameter '%0' for compute kernel %1(). " 258 "Kernels targeting SDK levels %2-%3 may not use " 259 "multiple input parameters.") << PVD->getName() << 260 FD->getName() << SLANG_MINIMUM_TARGET_API << 261 (SLANG_M_TARGET_API - 1); 262 valid = false; 263 } 264 clang::QualType QT = PVD->getType().getCanonicalType(); 265 if (QT->isPointerType()) { 266 Context->ReportError(PVD->getLocation(), 267 "Compute kernel %0() cannot have " 268 "parameter '%1' of pointer type: '%2'") 269 << FD->getName() << PVD->getName() << PVD->getType().getAsString(); 270 valid = false; 271 } 272 } 273 274 // Check that we have at least one allocation to use for dimensions. 275 if (valid && mIns.empty() && !mHasReturnType && Context->getTargetAPI() < SLANG_M_TARGET_API) { 276 Context->ReportError(FD->getLocation(), 277 "Compute kernel %0() targeting SDK levels " 278 "%1-%2 must have at least one " 279 "input parameter or a non-void return " 280 "type") 281 << FD->getName() << SLANG_MINIMUM_TARGET_API 282 << (SLANG_M_TARGET_API - 1); 283 valid = false; 284 } 285 286 return valid; 287} 288 289// Search for the optional special parameters. Returns true if valid. Also 290// sets *IndexOfFirstSpecialParameter to the index of the first special parameter, or 291// FD->getNumParams() if none are found. 292bool RSExportForEach::validateSpecialParameters( 293 RSContext *Context, const clang::FunctionDecl *FD, 294 size_t *IndexOfFirstSpecialParameter) { 295 slangAssert(IndexOfFirstSpecialParameter != nullptr); 296 slangAssert(mSpecialParameterSignatureMetadata == 0); 297 clang::ASTContext &C = Context->getASTContext(); 298 299 // Find all special parameters if present. 300 int LastSpecialParameterIdx = -1; // index into specialParameterTable 301 int FirstIntSpecialParameterIdx = -1; // index into specialParameterTable 302 clang::QualType FirstIntSpecialParameterType; 303 size_t NumParams = FD->getNumParams(); 304 *IndexOfFirstSpecialParameter = NumParams; 305 bool valid = true; 306 for (size_t i = 0; i < NumParams; i++) { 307 const clang::ParmVarDecl *PVD = FD->getParamDecl(i); 308 llvm::StringRef ParamName = PVD->getName(); 309 int SpecialParameterIdx = lookupSpecialParameter(ParamName); 310 if (SpecialParameterIdx >= 0) { 311 const SpecialParameter &SP = specialParameterTable[SpecialParameterIdx]; 312 // We won't be invoked if two parameters of the same name are present. 313 slangAssert(!(mSpecialParameterSignatureMetadata & SP.bitval)); 314 315 if (Context->getTargetAPI() < SP.minAPI) { 316 Context->ReportError(PVD->getLocation(), 317 "Compute kernel %0() targeting SDK levels " 318 "%1-%2 may not use parameter '%3'.") 319 << FD->getName() 320 << SLANG_MINIMUM_TARGET_API 321 << (SP.minAPI - 1) 322 << SP.name; 323 valid = false; 324 } 325 326 mSpecialParameterSignatureMetadata |= SP.bitval; 327 if (SpecialParameterIdx < LastSpecialParameterIdx) { 328 Context->ReportError(PVD->getLocation(), 329 "In compute kernel %0(), parameter '%1' must " 330 "be defined before parameter '%2'.") 331 << FD->getName() 332 << SP.name 333 << specialParameterTable[LastSpecialParameterIdx].name; 334 valid = false; 335 } 336 LastSpecialParameterIdx = SpecialParameterIdx; 337 338 // Ensure that all SPK_INT special parameters have the same type. 339 if (SP.kind == SPK_INT) { 340 clang::QualType SpecialParameterType = PVD->getType(); 341 if (FirstIntSpecialParameterIdx >= 0) { 342 if (SpecialParameterType != FirstIntSpecialParameterType) { 343 Context->ReportError(PVD->getLocation(), 344 "Parameters '%0' and '%1' must be of the same type. " 345 "'%0' is of type '%2' while '%1' is of type '%3'.") 346 << specialParameterTable[FirstIntSpecialParameterIdx].name 347 << SP.name 348 << FirstIntSpecialParameterType.getAsString() 349 << SpecialParameterType.getAsString(); 350 valid = false; 351 } 352 } else { 353 FirstIntSpecialParameterIdx = SpecialParameterIdx; 354 FirstIntSpecialParameterType = SpecialParameterType; 355 } 356 } 357 } else { 358 // It's not a special parameter. 359 if (*IndexOfFirstSpecialParameter < NumParams) { 360 Context->ReportError(PVD->getLocation(), 361 "In compute kernel %0(), parameter '%1' cannot " 362 "appear after any of the (%2) parameters.") 363 << FD->getName() << ParamName << listSpecialParameters(Context->getTargetAPI()); 364 valid = false; 365 } 366 continue; 367 } 368 // Validate the data type of the special parameter. 369 switch (specialParameterTable[SpecialParameterIdx].kind) { 370 case SPK_INT: { 371 clang::QualType QT = PVD->getType().getCanonicalType(); 372 clang::QualType UT = QT.getUnqualifiedType(); 373 if (UT != C.UnsignedIntTy && UT != C.IntTy) { 374 Context->ReportError(PVD->getLocation(), 375 "Parameter '%0' must be of type 'int' or " 376 "'unsigned int'. It is of type '%1'.") 377 << ParamName << PVD->getType().getAsString(); 378 valid = false; 379 } 380 break; 381 } 382 case SPK_CTXT: { 383 static const char ExpectedTypeNameMatch[] = "const struct rs_kernel_context_t *"; 384 static const char ExpectedTypeNamePrint[] = "rs_kernel_context"; 385 clang::QualType QT = PVD->getType().getCanonicalType(); 386 clang::QualType UT = QT.getUnqualifiedType(); 387 if (UT.getAsString() != ExpectedTypeNameMatch) { 388 Context->ReportError(PVD->getLocation(), 389 "Parameter '%0' must be of type '%1'. " 390 "It is of type '%2'.") 391 << ParamName << ExpectedTypeNamePrint << PVD->getType().getAsString(); 392 valid = false; 393 } 394 break; 395 } 396 default: 397 slangAssert(!"Unexpected special parameter type"); 398 } 399 // If this is the first time we find a special parameter, save it. 400 if (*IndexOfFirstSpecialParameter >= NumParams) { 401 *IndexOfFirstSpecialParameter = i; 402 } 403 } 404 return valid; 405} 406 407bool RSExportForEach::setSignatureMetadata(RSContext *Context, 408 const clang::FunctionDecl *FD) { 409 mSignatureMetadata = 0; 410 bool valid = true; 411 412 if (mIsKernelStyle) { 413 slangAssert(mOut == nullptr); 414 slangAssert(mUsrData == nullptr); 415 } else { 416 slangAssert(!mHasReturnType); 417 } 418 419 // Set up the bitwise metadata encoding for runtime argument passing. 420 const bool HasOut = mOut || mHasReturnType; 421 mSignatureMetadata |= (hasIns() ? bcinfo::MD_SIG_In : 0); 422 mSignatureMetadata |= (HasOut ? bcinfo::MD_SIG_Out : 0); 423 mSignatureMetadata |= (mUsrData ? bcinfo::MD_SIG_Usr : 0); 424 mSignatureMetadata |= (mIsKernelStyle ? bcinfo::MD_SIG_Kernel : 0); // pass-by-value 425 mSignatureMetadata |= mSpecialParameterSignatureMetadata; 426 427 if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) { 428 // APIs before ICS cannot skip between parameters. It is ok, however, for 429 // them to omit further parameters (i.e. skipping X is ok if you skip Y). 430 if (mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr | 431 bcinfo::MD_SIG_X | bcinfo::MD_SIG_Y) && 432 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr | 433 bcinfo::MD_SIG_X) && 434 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr) && 435 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out) && 436 mSignatureMetadata != (bcinfo::MD_SIG_In)) { 437 Context->ReportError(FD->getLocation(), 438 "Compute kernel %0() targeting SDK levels " 439 "%1-%2 may not skip parameters") 440 << FD->getName() << SLANG_MINIMUM_TARGET_API 441 << (SLANG_ICS_TARGET_API - 1); 442 valid = false; 443 } 444 } 445 return valid; 446} 447 448RSExportForEach *RSExportForEach::Create(RSContext *Context, 449 const clang::FunctionDecl *FD) { 450 slangAssert(Context && FD); 451 llvm::StringRef Name = FD->getName(); 452 RSExportForEach *FE; 453 454 slangAssert(!Name.empty() && "Function must have a name"); 455 456 FE = new RSExportForEach(Context, Name); 457 458 if (!FE->validateAndConstructParams(Context, FD)) { 459 return nullptr; 460 } 461 462 clang::ASTContext &Ctx = Context->getASTContext(); 463 464 std::string Id = CreateDummyName("helper_foreach_param", FE->getName()); 465 466 // Extract the usrData parameter (if we have one) 467 if (FE->mUsrData) { 468 const clang::ParmVarDecl *PVD = FE->mUsrData; 469 clang::QualType QT = PVD->getType().getCanonicalType(); 470 slangAssert(QT->isPointerType() && 471 QT->getPointeeType().isConstQualified()); 472 473 const clang::ASTContext &C = Context->getASTContext(); 474 if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() == 475 C.VoidTy) { 476 // In the case of using const void*, we can't reflect an appopriate 477 // Java type, so we fall back to just reflecting the ain/aout parameters 478 FE->mUsrData = nullptr; 479 } else { 480 clang::RecordDecl *RD = 481 clang::RecordDecl::Create(Ctx, clang::TTK_Struct, 482 Ctx.getTranslationUnitDecl(), 483 clang::SourceLocation(), 484 clang::SourceLocation(), 485 &Ctx.Idents.get(Id)); 486 487 clang::FieldDecl *FD = 488 clang::FieldDecl::Create(Ctx, 489 RD, 490 clang::SourceLocation(), 491 clang::SourceLocation(), 492 PVD->getIdentifier(), 493 QT->getPointeeType(), 494 nullptr, 495 /* BitWidth = */ nullptr, 496 /* Mutable = */ false, 497 /* HasInit = */ clang::ICIS_NoInit); 498 RD->addDecl(FD); 499 RD->completeDefinition(); 500 501 // Create an export type iff we have a valid usrData type 502 clang::QualType T = Ctx.getTagDeclType(RD); 503 slangAssert(!T.isNull()); 504 505 RSExportType *ET = RSExportType::Create(Context, T.getTypePtr()); 506 507 slangAssert(ET && "Failed to export a kernel"); 508 509 slangAssert((ET->getClass() == RSExportType::ExportClassRecord) && 510 "Parameter packet must be a record"); 511 512 FE->mParamPacketType = static_cast<RSExportRecordType *>(ET); 513 } 514 } 515 516 if (FE->hasIns()) { 517 518 for (InIter BI = FE->mIns.begin(), EI = FE->mIns.end(); BI != EI; BI++) { 519 const clang::Type *T = (*BI)->getType().getCanonicalType().getTypePtr(); 520 RSExportType *InExportType = RSExportType::Create(Context, T); 521 522 if (FE->mIsKernelStyle) { 523 slangAssert(InExportType != nullptr); 524 } 525 526 FE->mInTypes.push_back(InExportType); 527 } 528 } 529 530 if (FE->mIsKernelStyle && FE->mHasReturnType) { 531 const clang::Type *T = FE->mResultType.getTypePtr(); 532 FE->mOutType = RSExportType::Create(Context, T); 533 slangAssert(FE->mOutType); 534 } else if (FE->mOut) { 535 const clang::Type *T = FE->mOut->getType().getCanonicalType().getTypePtr(); 536 FE->mOutType = RSExportType::Create(Context, T); 537 } 538 539 return FE; 540} 541 542RSExportForEach *RSExportForEach::CreateDummyRoot(RSContext *Context) { 543 slangAssert(Context); 544 llvm::StringRef Name = "root"; 545 RSExportForEach *FE = new RSExportForEach(Context, Name); 546 FE->mDummyRoot = true; 547 return FE; 548} 549 550bool RSExportForEach::isGraphicsRootRSFunc(unsigned int targetAPI, 551 const clang::FunctionDecl *FD) { 552 if (FD->hasAttr<clang::KernelAttr>()) { 553 return false; 554 } 555 556 if (!isRootRSFunc(FD)) { 557 return false; 558 } 559 560 if (FD->getNumParams() == 0) { 561 // Graphics root function 562 return true; 563 } 564 565 // Check for legacy graphics root function (with single parameter). 566 if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) { 567 const clang::QualType &IntType = FD->getASTContext().IntTy; 568 if (FD->getReturnType().getCanonicalType() == IntType) { 569 return true; 570 } 571 } 572 573 return false; 574} 575 576bool RSExportForEach::isRSForEachFunc(unsigned int targetAPI, 577 slang::RSContext* Context, 578 const clang::FunctionDecl *FD) { 579 slangAssert(Context && FD); 580 bool hasKernelAttr = FD->hasAttr<clang::KernelAttr>(); 581 582 if (FD->getStorageClass() == clang::SC_Static) { 583 if (hasKernelAttr) { 584 Context->ReportError(FD->getLocation(), 585 "Invalid use of attribute kernel with " 586 "static function declaration: %0") 587 << FD->getName(); 588 } 589 return false; 590 } 591 592 // Anything tagged as a kernel is definitely used with ForEach. 593 if (hasKernelAttr) { 594 return true; 595 } 596 597 if (isGraphicsRootRSFunc(targetAPI, FD)) { 598 return false; 599 } 600 601 // Check if first parameter is a pointer (which is required for ForEach). 602 unsigned int numParams = FD->getNumParams(); 603 604 if (numParams > 0) { 605 const clang::ParmVarDecl *PVD = FD->getParamDecl(0); 606 clang::QualType QT = PVD->getType().getCanonicalType(); 607 608 if (QT->isPointerType()) { 609 return true; 610 } 611 612 // Any non-graphics root() is automatically a ForEach candidate. 613 // At this point, however, we know that it is not going to be a valid 614 // compute root() function (due to not having a pointer parameter). We 615 // still want to return true here, so that we can issue appropriate 616 // diagnostics. 617 if (isRootRSFunc(FD)) { 618 return true; 619 } 620 } 621 622 return false; 623} 624 625bool 626RSExportForEach::validateSpecialFuncDecl(unsigned int targetAPI, 627 slang::RSContext *Context, 628 clang::FunctionDecl const *FD) { 629 slangAssert(Context && FD); 630 bool valid = true; 631 const clang::ASTContext &C = FD->getASTContext(); 632 const clang::QualType &IntType = FD->getASTContext().IntTy; 633 634 if (isGraphicsRootRSFunc(targetAPI, FD)) { 635 if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) { 636 // Legacy graphics root function 637 const clang::ParmVarDecl *PVD = FD->getParamDecl(0); 638 clang::QualType QT = PVD->getType().getCanonicalType(); 639 if (QT != IntType) { 640 Context->ReportError(PVD->getLocation(), 641 "invalid parameter type for legacy " 642 "graphics root() function: %0") 643 << PVD->getType(); 644 valid = false; 645 } 646 } 647 648 // Graphics root function, so verify that it returns an int 649 if (FD->getReturnType().getCanonicalType() != IntType) { 650 Context->ReportError(FD->getLocation(), 651 "root() is required to return " 652 "an int for graphics usage"); 653 valid = false; 654 } 655 } else if (isInitRSFunc(FD) || isDtorRSFunc(FD)) { 656 if (FD->getNumParams() != 0) { 657 Context->ReportError(FD->getLocation(), 658 "%0(void) is required to have no " 659 "parameters") 660 << FD->getName(); 661 valid = false; 662 } 663 664 if (FD->getReturnType().getCanonicalType() != C.VoidTy) { 665 Context->ReportError(FD->getLocation(), 666 "%0(void) is required to have a void " 667 "return type") 668 << FD->getName(); 669 valid = false; 670 } 671 } else { 672 slangAssert(false && "must be called on root, init or .rs.dtor function!"); 673 } 674 675 return valid; 676} 677 678} // namespace slang 679