slang_rs_context.cpp revision 65f23ed862e1a1e16477ba740f295ff4a83ac822
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_rs_export_foreach.h" 37#include "slang_rs_export_func.h" 38#include "slang_rs_export_reduce.h" 39#include "slang_rs_export_type.h" 40#include "slang_rs_export_var.h" 41#include "slang_rs_exportable.h" 42#include "slang_rs_pragma_handler.h" 43#include "slang_rs_reflection.h" 44#include "slang_rs_special_func.h" 45 46namespace slang { 47 48RSContext::RSContext(clang::Preprocessor &PP, 49 clang::ASTContext &Ctx, 50 const clang::TargetInfo &Target, 51 PragmaList *Pragmas, 52 unsigned int TargetAPI, 53 bool Verbose) 54 : mPP(PP), 55 mCtx(Ctx), 56 mPragmas(Pragmas), 57 mTargetAPI(TargetAPI), 58 mVerbose(Verbose), 59 mDataLayout(nullptr), 60 mLLVMContext(llvm::getGlobalContext()), 61 mLicenseNote(nullptr), 62 mRSPackageName("android.renderscript"), 63 version(0), 64 mMangleCtx(Ctx.createMangleContext()), 65 mIs64Bit(Target.getPointerWidth(0) == 64), 66 mNextSlot(1) { 67 68 AddPragmaHandlers(PP, this); 69 70 // Prepare target data 71 mDataLayout = new llvm::DataLayout(Target.getTargetDescription()); 72 73 // Reserve slot 0 for the root kernel. 74 mExportForEach.push_back(nullptr); 75} 76 77bool RSContext::processExportVar(const clang::VarDecl *VD) { 78 slangAssert(!VD->getName().empty() && "Variable name should not be empty"); 79 80 RSExportType *ET = RSExportType::CreateFromDecl(this, VD); 81 if (!ET) 82 return false; 83 84 RSExportVar *EV = new RSExportVar(this, VD, ET); 85 if (EV == nullptr) 86 return false; 87 else 88 mExportVars.push_back(EV); 89 90 return true; 91} 92 93int RSContext::getForEachSlotNumber(const clang::FunctionDecl* FD) { 94 const clang::StringRef& funcName = FD->getName(); 95 return getForEachSlotNumber(funcName); 96} 97 98int RSContext::getForEachSlotNumber(const clang::StringRef& funcName) { 99 auto it = mExportForEachMap.find(funcName); 100 if (it == mExportForEachMap.end()) { 101 return -1; 102 } 103 return it->second; 104} 105 106bool RSContext::processExportFunc(const clang::FunctionDecl *FD) { 107 slangAssert(!FD->getName().empty() && "Function name should not be empty"); 108 109 if (!FD->isThisDeclarationADefinition()) { 110 return true; 111 } 112 113 slangAssert(FD->getStorageClass() == clang::SC_None); 114 115 // Specialized function 116 if (RSSpecialFunc::isSpecialRSFunc(mTargetAPI, FD)) { 117 // Do not reflect specialized functions like init, dtor, or graphics root. 118 return RSSpecialFunc::validateSpecialFuncDecl(mTargetAPI, this, FD); 119 } 120 121 // Foreach kernel 122 if (RSExportForEach::isRSForEachFunc(mTargetAPI, FD)) { 123 RSExportForEach *EFE = RSExportForEach::Create(this, FD); 124 if (EFE == nullptr) { 125 return false; 126 } 127 const llvm::StringRef& funcName = FD->getName(); 128 if (funcName.equals("root")) { 129 mExportForEach[0] = EFE; 130 } else { 131 mExportForEach.push_back(EFE); 132 } 133 return true; 134 } 135 136 // Reduce kernel 137 if (RSExportReduce::isRSReduceFunc(mTargetAPI, FD)) { 138 if (auto *ER = RSExportReduce::Create(this, FD)) { 139 mExportReduce.push_back(ER); 140 return true; 141 } 142 return false; 143 } 144 145 // Invokable 146 if (auto *EF = RSExportFunc::Create(this, FD)) { 147 mExportFuncs.push_back(EF); 148 return true; 149 } 150 151 return false; 152} 153 154bool RSContext::addForEach(const clang::FunctionDecl* FD) { 155 const llvm::StringRef& funcName = FD->getName(); 156 157 if (funcName.equals("root")) { 158 // The root kernel should always be in slot 0. 159 mExportForEachMap.insert(std::make_pair(funcName, 0)); 160 } else { 161 mExportForEachMap.insert(std::make_pair(funcName, mNextSlot++)); 162 } 163 164 return true; 165} 166 167bool RSContext::processExportType(const llvm::StringRef &Name) { 168 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl(); 169 170 slangAssert(TUDecl != nullptr && "Translation unit declaration (top-level " 171 "declaration) is null object"); 172 173 const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name); 174 if (II == nullptr) 175 // TODO(zonr): alert identifier @Name mark as an exportable type cannot be 176 // found 177 return false; 178 179 clang::DeclContext::lookup_result R = TUDecl->lookup(II); 180 RSExportType *ET = nullptr; 181 182 for (clang::DeclContext::lookup_iterator I = R.begin(), E = R.end(); 183 I != E; 184 I++) { 185 clang::NamedDecl *const ND = *I; 186 const clang::Type *T = nullptr; 187 188 switch (ND->getKind()) { 189 case clang::Decl::Typedef: { 190 T = static_cast<const clang::TypedefDecl*>( 191 ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr(); 192 break; 193 } 194 case clang::Decl::Record: { 195 T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl(); 196 break; 197 } 198 default: { 199 // unsupported, skip 200 break; 201 } 202 } 203 204 if (T != nullptr) 205 ET = RSExportType::Create(this, T, NotLegacyKernelArgument); 206 } 207 208 return (ET != nullptr); 209} 210 211void RSContext::setAllocationType(const clang::TypeDecl* TD) { 212 mAllocationType = mCtx.getTypeDeclType(TD); 213} 214 215void RSContext::setScriptCallType(const clang::TypeDecl* TD) { 216 mScriptCallType = mCtx.getTypeDeclType(TD); 217} 218 219bool RSContext::processExports() { 220 bool valid = true; 221 222 if (getDiagnostics()->hasErrorOccurred()) { 223 return false; 224 } 225 226 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl(); 227 for (auto I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; I++) { 228 clang::Decl* D = *I; 229 switch (D->getKind()) { 230 case clang::Decl::Var: { 231 clang::VarDecl* VD = llvm::dyn_cast<clang::VarDecl>(D); 232 bool ShouldExportVariable = true; 233 if (VD->getFormalLinkage() == clang::ExternalLinkage) { 234 clang::QualType QT = VD->getTypeSourceInfo()->getType(); 235 if (QT.isConstQualified() && !VD->hasInit()) { 236 if (Slang::IsLocInRSHeaderFile(VD->getLocation(), 237 *getSourceManager())) { 238 // We don't export variables internal to the runtime's 239 // implementation. 240 ShouldExportVariable = false; 241 } else { 242 clang::DiagnosticsEngine *DiagEngine = getDiagnostics(); 243 DiagEngine->Report(VD->getLocation(), DiagEngine->getCustomDiagID( 244 clang::DiagnosticsEngine::Error, 245 "invalid declaration of uninitialized constant variable '%0'")) 246 << VD->getName(); 247 valid = false; 248 } 249 } 250 if (valid && ShouldExportVariable && !processExportVar(VD)) { 251 valid = false; 252 } 253 } 254 break; 255 } 256 case clang::Decl::Function: { 257 clang::FunctionDecl* FD = llvm::dyn_cast<clang::FunctionDecl>(D); 258 if (FD->getFormalLinkage() == clang::ExternalLinkage) { 259 if (!processExportFunc(FD)) { 260 valid = false; 261 } 262 } 263 break; 264 } 265 default: 266 break; 267 } 268 } 269 270 // Create a dummy root in slot 0 if a root kernel is not seen 271 // and there exists a non-root kernel. 272 if (valid && mExportForEach[0] == nullptr) { 273 const size_t numExportedForEach = mExportForEach.size(); 274 if (numExportedForEach > 1) { 275 mExportForEach[0] = RSExportForEach::CreateDummyRoot(this); 276 } else { 277 slangAssert(numExportedForEach == 1); 278 mExportForEach.pop_back(); 279 } 280 } 281 282 // Finally, export type forcely set to be exported by user 283 for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(), 284 EE = mNeedExportTypes.end(); 285 EI != EE; 286 EI++) { 287 if (!processExportType(EI->getKey())) { 288 valid = false; 289 } 290 } 291 292 return valid; 293} 294 295bool RSContext::processReducePragmas() { 296 bool valid = true; 297 for (auto I = export_reduce_new_begin(), E = export_reduce_new_end(); I != E; ++I) { 298 if (! (*I)->analyzeTranslationUnit()) 299 valid = false; 300 } 301 return valid; 302} 303 304bool RSContext::isReferencedByReducePragma(const clang::FunctionDecl *FD) const { 305 // This is an inefficient linear search. If this turns out to be a 306 // problem in practice, then processReducePragmas() could build a 307 // set or hash table or something similar containing all function 308 // names mentioned in a reduce pragma and searchable in O(c) or 309 // O(log(n)) time rather than the currently-implemented O(n) search. 310 for (auto I = export_reduce_new_begin(), E = export_reduce_new_end(); I != E; ++I) { 311 if ((*I)->matchName(FD->getName())) 312 return true; 313 } 314 return false; 315} 316 317bool RSContext::insertExportType(const llvm::StringRef &TypeName, 318 RSExportType *ET) { 319 ExportTypeMap::value_type *NewItem = 320 ExportTypeMap::value_type::Create(TypeName, 321 mExportTypes.getAllocator(), 322 ET); 323 324 if (mExportTypes.insert(NewItem)) { 325 return true; 326 } else { 327 NewItem->Destroy(mExportTypes.getAllocator()); 328 return false; 329 } 330} 331 332RSContext::~RSContext() { 333 delete mLicenseNote; 334 delete mDataLayout; 335 for (ExportableList::iterator I = mExportables.begin(), 336 E = mExportables.end(); 337 I != E; 338 I++) { 339 if (!(*I)->isKeep()) 340 delete *I; 341 } 342} 343 344} // namespace slang 345