1 /* 2 * Copyright 2010-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_context.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/DeclBase.h" 25 #include "clang/AST/Mangle.h" 26 #include "clang/AST/Type.h" 27 28 #include "clang/Basic/Linkage.h" 29 #include "clang/Basic/TargetInfo.h" 30 31 #include "llvm/IR/LLVMContext.h" 32 #include "llvm/IR/DataLayout.h" 33 34 #include "slang.h" 35 #include "slang_assert.h" 36 #include "slang_backend.h" 37 #include "slang_rs_export_foreach.h" 38 #include "slang_rs_export_func.h" 39 #include "slang_rs_export_reduce.h" 40 #include "slang_rs_export_type.h" 41 #include "slang_rs_export_var.h" 42 #include "slang_rs_exportable.h" 43 #include "slang_rs_pragma_handler.h" 44 #include "slang_rs_reflection.h" 45 #include "slang_rs_special_func.h" 46 47 namespace slang { 48 49 RSContext::RSContext(clang::Preprocessor &PP, 50 clang::ASTContext &Ctx, 51 const clang::TargetInfo &Target, 52 PragmaList *Pragmas, 53 unsigned int TargetAPI, 54 bool Verbose) 55 : mPP(PP), 56 mCtx(Ctx), 57 mPragmas(Pragmas), 58 mTargetAPI(TargetAPI), 59 mVerbose(Verbose), 60 mDataLayout(Target.getDataLayout()), 61 mLLVMContext(slang::getGlobalLLVMContext()), 62 mLicenseNote(nullptr), 63 mRSPackageName("android.renderscript"), 64 version(0), 65 mMangleCtx(Ctx.createMangleContext()), 66 mIs64Bit(Target.getPointerWidth(0) == 64), 67 mNextSlot(1), 68 mNextForEachOrdinal(0) { 69 70 AddPragmaHandlers(PP, this); 71 72 // Prepare target data 73 // mDataLayout = Target.getDataLayout(); 74 75 // Reserve slot 0 for the root kernel. 76 mExportForEach.push_back(nullptr); 77 mFirstOldStyleKernel = mExportForEach.end(); 78 } 79 80 bool RSContext::processExportVar(const clang::VarDecl *VD) { 81 slangAssert(!VD->getName().empty() && "Variable name should not be empty"); 82 83 RSExportType *ET = RSExportType::CreateFromDecl(this, VD); 84 if (!ET) 85 return false; 86 87 RSExportVar *EV = new RSExportVar(this, VD, ET); 88 if (EV == nullptr) 89 return false; 90 else 91 mExportVars.push_back(EV); 92 93 return true; 94 } 95 96 int RSContext::getForEachSlotNumber(const clang::FunctionDecl* FD) { 97 const clang::StringRef& funcName = FD->getName(); 98 return getForEachSlotNumber(funcName); 99 } 100 101 int RSContext::getForEachSlotNumber(const clang::StringRef& funcName) { 102 auto it = mExportForEachMap.find(funcName); 103 if (it == mExportForEachMap.end()) { 104 return -1; 105 } 106 return it->second; 107 } 108 109 bool RSContext::processExportFunc(const clang::FunctionDecl *FD) { 110 slangAssert(!FD->getName().empty() && "Function name should not be empty"); 111 112 if (!FD->isThisDeclarationADefinition()) { 113 return true; 114 } 115 116 slangAssert(FD->getStorageClass() == clang::SC_None); 117 118 // Specialized function 119 if (RSSpecialFunc::isSpecialRSFunc(mTargetAPI, FD)) { 120 // Do not reflect specialized functions like init, dtor, or graphics root. 121 return RSSpecialFunc::validateSpecialFuncDecl(mTargetAPI, this, FD); 122 } 123 124 // Foreach kernel 125 if (RSExportForEach::isRSForEachFunc(mTargetAPI, FD)) { 126 RSExportForEach *EFE = RSExportForEach::Create(this, FD); 127 if (EFE == nullptr) { 128 return false; 129 } 130 131 // The root function should be at index 0 in the list 132 if (FD->getName().equals("root")) { 133 mExportForEach[0] = EFE; 134 return true; 135 } 136 137 // New-style kernels with attribute "kernel" should come first in the list 138 if (FD->hasAttr<clang::RenderScriptKernelAttr>()) { 139 mFirstOldStyleKernel = mExportForEach.insert(mFirstOldStyleKernel, EFE) + 1; 140 slangAssert((mTargetAPI < SLANG_FEATURE_SINGLE_SOURCE_API || 141 getForEachSlotNumber(FD->getName()) == 142 mFirstOldStyleKernel - mExportForEach.begin() - 1) && 143 "Inconsistent slot number assignment"); 144 return true; 145 } 146 147 // Old-style kernels should appear in the end of the list 148 mFirstOldStyleKernel = mExportForEach.insert(mFirstOldStyleKernel, EFE); 149 return true; 150 } 151 152 // Invokable 153 if (auto *EF = RSExportFunc::Create(this, FD)) { 154 mExportFuncs.push_back(EF); 155 return true; 156 } 157 158 return false; 159 } 160 161 bool RSContext::addForEach(const clang::FunctionDecl* FD) { 162 const llvm::StringRef& funcName = FD->getName(); 163 164 if (funcName.equals("root")) { 165 // The root kernel should always be in slot 0. 166 mExportForEachMap.insert(std::make_pair(funcName, 0)); 167 } else { 168 mExportForEachMap.insert(std::make_pair(funcName, mNextSlot++)); 169 } 170 171 return true; 172 } 173 174 bool RSContext::processExportType(const llvm::StringRef &Name) { 175 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl(); 176 177 slangAssert(TUDecl != nullptr && "Translation unit declaration (top-level " 178 "declaration) is null object"); 179 180 const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name); 181 if (II == nullptr) 182 // TODO(zonr): alert identifier @Name mark as an exportable type cannot be 183 // found 184 return false; 185 186 clang::DeclContext::lookup_result R = TUDecl->lookup(II); 187 RSExportType *ET = nullptr; 188 189 for (clang::DeclContext::lookup_iterator I = R.begin(), E = R.end(); 190 I != E; 191 I++) { 192 clang::NamedDecl *const ND = *I; 193 const clang::Type *T = nullptr; 194 195 switch (ND->getKind()) { 196 case clang::Decl::Typedef: { 197 T = static_cast<const clang::TypedefDecl*>( 198 ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr(); 199 break; 200 } 201 case clang::Decl::Record: { 202 T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl(); 203 break; 204 } 205 default: { 206 // unsupported, skip 207 break; 208 } 209 } 210 211 if (T != nullptr) 212 ET = RSExportType::Create(this, T, NotLegacyKernelArgument); 213 } 214 215 return (ET != nullptr); 216 } 217 218 void RSContext::setAllocationType(const clang::TypeDecl* TD) { 219 mAllocationType = mCtx.getTypeDeclType(TD); 220 } 221 222 void RSContext::setScriptCallType(const clang::TypeDecl* TD) { 223 mScriptCallType = mCtx.getTypeDeclType(TD); 224 } 225 226 bool RSContext::processExports() { 227 bool valid = true; 228 229 if (getDiagnostics()->hasErrorOccurred()) { 230 return false; 231 } 232 233 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl(); 234 for (auto I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; I++) { 235 clang::Decl* D = *I; 236 switch (D->getKind()) { 237 case clang::Decl::Var: { 238 clang::VarDecl* VD = llvm::dyn_cast<clang::VarDecl>(D); 239 bool ShouldExportVariable = true; 240 if (VD->getFormalLinkage() == clang::ExternalLinkage) { 241 clang::QualType QT = VD->getTypeSourceInfo()->getType(); 242 if (QT.isConstQualified() && !VD->hasInit()) { 243 if (Slang::IsLocInRSHeaderFile(VD->getLocation(), 244 *getSourceManager())) { 245 // We don't export variables internal to the runtime's 246 // implementation. 247 ShouldExportVariable = false; 248 } else { 249 clang::DiagnosticsEngine *DiagEngine = getDiagnostics(); 250 DiagEngine->Report(VD->getLocation(), DiagEngine->getCustomDiagID( 251 clang::DiagnosticsEngine::Error, 252 "invalid declaration of uninitialized constant variable '%0'")) 253 << VD->getName(); 254 valid = false; 255 } 256 } 257 if (valid && ShouldExportVariable && isSyntheticName(VD->getName())) 258 ShouldExportVariable = false; 259 if (valid && ShouldExportVariable && !processExportVar(VD)) { 260 valid = false; 261 } 262 } 263 break; 264 } 265 case clang::Decl::Function: { 266 clang::FunctionDecl* FD = llvm::dyn_cast<clang::FunctionDecl>(D); 267 if (FD->getFormalLinkage() == clang::ExternalLinkage) { 268 if (!processExportFunc(FD)) { 269 valid = false; 270 } 271 } 272 break; 273 } 274 default: 275 break; 276 } 277 } 278 279 // Create a dummy root in slot 0 if a root kernel is not seen 280 // and there exists a non-root kernel. 281 if (valid && mExportForEach[0] == nullptr) { 282 const size_t numExportedForEach = mExportForEach.size(); 283 if (numExportedForEach > 1) { 284 mExportForEach[0] = RSExportForEach::CreateDummyRoot(this); 285 } else { 286 slangAssert(numExportedForEach == 1); 287 mExportForEach.pop_back(); 288 } 289 } 290 291 // Finally, export type forcely set to be exported by user 292 for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(), 293 EE = mNeedExportTypes.end(); 294 EI != EE; 295 EI++) { 296 if (!processExportType(EI->getKey())) { 297 valid = false; 298 } 299 } 300 301 return valid; 302 } 303 304 bool RSContext::processReducePragmas(Backend *BE) { 305 // This is needed to ensure that the dummy variable is emitted into 306 // the bitcode -- which in turn forces the function to be emitted 307 // into the bitcode. We couldn't do this at 308 // markUsedByReducePragma() time because we had to wait until the 309 // Backend is available. 310 for (auto DummyVar : mUsedByReducePragmaDummyVars) 311 BE->HandleTopLevelDecl(clang::DeclGroupRef(DummyVar)); 312 313 bool valid = true; 314 for (auto I = export_reduce_begin(), E = export_reduce_end(); I != E; ++I) { 315 if (! (*I)->analyzeTranslationUnit()) 316 valid = false; 317 } 318 return valid; 319 } 320 321 void RSContext::markUsedByReducePragma(clang::FunctionDecl *FD, CheckName Check) { 322 if (mUsedByReducePragmaFns.find(FD) != mUsedByReducePragmaFns.end()) 323 return; // already marked used 324 325 if (Check == CheckNameYes) { 326 // This is an inefficient linear search. If this turns out to be a 327 // problem in practice, then processReducePragmas() could build a 328 // set or hash table or something similar containing all function 329 // names mentioned in a reduce pragma and searchable in O(c) or 330 // O(log(n)) time rather than the currently-implemented O(n) search. 331 auto NameMatches = [this, FD]() { 332 for (auto I = export_reduce_begin(), E = export_reduce_end(); I != E; ++I) { 333 if ((*I)->matchName(FD->getName())) 334 return true; 335 } 336 return false; 337 }; 338 if (!NameMatches()) 339 return; 340 } 341 342 mUsedByReducePragmaFns.insert(FD); 343 344 // This is needed to prevent clang from warning that the function is 345 // unused (in the case where it is only referenced by #pragma rs 346 // reduce). 347 FD->setIsUsed(); 348 349 // Each constituent function "f" of a reduction kernel gets a dummy variable generated for it: 350 // void *.rs.reduce_fn.f = (void*)&f; 351 // This is a trick to ensure that clang will not delete "f" as unused. 352 353 // `-VarDecl 0x87cb558 <line:3:1, col:30> col:7 var 'void *' cinit 354 // `-CStyleCastExpr 0x87cb630 <col:19, col:26> 'void *' <BitCast> 355 // `-ImplicitCastExpr 0x87cb618 <col:26> 'void (*)(int *, float, double)' <FunctionToPointerDecay> 356 // `-DeclRefExpr 0x87cb5b8 <col:26> 'void (int *, float, double)' Function 0x8784e10 'foo' 'void (int *, float, double) 357 358 const clang::QualType VoidPtrType = mCtx.getPointerType(mCtx.VoidTy); 359 360 clang::DeclContext *const DC = FD->getDeclContext(); 361 const clang::SourceLocation Loc = FD->getLocation(); 362 363 clang::VarDecl *const VD = clang::VarDecl::Create( 364 mCtx, DC, Loc, Loc, 365 &mCtx.Idents.get(std::string(".rs.reduce_fn.") + FD->getNameAsString()), 366 VoidPtrType, 367 mCtx.getTrivialTypeSourceInfo(VoidPtrType), 368 clang::SC_None); 369 VD->setLexicalDeclContext(DC); 370 DC->addDecl(VD); 371 372 clang::DeclRefExpr *const DRE = clang::DeclRefExpr::Create(mCtx, 373 clang::NestedNameSpecifierLoc(), 374 Loc, 375 FD, false, Loc, FD->getType(), 376 clang::VK_RValue); 377 clang::ImplicitCastExpr *const ICE = clang::ImplicitCastExpr::Create(mCtx, mCtx.getPointerType(FD->getType()), 378 clang::CK_FunctionToPointerDecay, DRE, 379 nullptr, clang::VK_RValue); 380 clang::CStyleCastExpr *const CSCE = clang::CStyleCastExpr::Create(mCtx, VoidPtrType, clang::VK_RValue, clang::CK_BitCast, 381 ICE, nullptr, nullptr, 382 Loc, Loc); 383 VD->setInit(CSCE); 384 385 mUsedByReducePragmaDummyVars.push_back(VD); 386 } 387 388 bool RSContext::insertExportType(const llvm::StringRef &TypeName, 389 RSExportType *ET) { 390 ExportTypeMap::value_type *NewItem = 391 ExportTypeMap::value_type::Create(TypeName, 392 mExportTypes.getAllocator(), 393 ET); 394 395 if (mExportTypes.insert(NewItem)) { 396 return true; 397 } else { 398 NewItem->Destroy(mExportTypes.getAllocator()); 399 return false; 400 } 401 } 402 403 RSContext::~RSContext() { 404 delete mLicenseNote; 405 for (ExportableList::iterator I = mExportables.begin(), 406 E = mExportables.end(); 407 I != E; 408 I++) { 409 if (!(*I)->isKeep()) 410 delete *I; 411 } 412 } 413 414 } // namespace slang 415