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