slang_rs_context.cpp revision 13fad85b3c99a37c17d8acfec72f46b8ee64e912
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 if (FD->getStorageClass() != clang::SC_None) { 114 fprintf(stderr, "RSContext::processExportFunc : cannot export extern or " 115 "static function '%s'\n", FD->getName().str().c_str()); 116 return false; 117 } 118 119 // Specialized function 120 if (RSSpecialFunc::isSpecialRSFunc(mTargetAPI, FD)) { 121 // Do not reflect specialized functions like init, dtor, or graphics root. 122 return RSSpecialFunc::validateSpecialFuncDecl(mTargetAPI, this, FD); 123 } 124 125 // Foreach kernel 126 if (RSExportForEach::isRSForEachFunc(mTargetAPI, FD)) { 127 RSExportForEach *EFE = RSExportForEach::Create(this, FD); 128 if (EFE == nullptr) { 129 return false; 130 } 131 const llvm::StringRef& funcName = FD->getName(); 132 if (funcName.equals("root")) { 133 mExportForEach[0] = EFE; 134 } else { 135 mExportForEach.push_back(EFE); 136 } 137 return true; 138 } 139 140 // Reduce kernel 141 if (RSExportReduce::isRSReduceFunc(mTargetAPI, FD)) { 142 if (auto *ER = RSExportReduce::Create(this, FD)) { 143 mExportReduce.push_back(ER); 144 return true; 145 } 146 return false; 147 } 148 149 // Invokable 150 if (auto *EF = RSExportFunc::Create(this, FD)) { 151 mExportFuncs.push_back(EF); 152 return true; 153 } 154 155 return false; 156} 157 158bool RSContext::addForEach(const clang::FunctionDecl* FD) { 159 const llvm::StringRef& funcName = FD->getName(); 160 161 if (funcName.equals("root")) { 162 // The root kernel should always be in slot 0. 163 mExportForEachMap.insert(std::make_pair(funcName, 0)); 164 } else { 165 mExportForEachMap.insert(std::make_pair(funcName, mNextSlot++)); 166 } 167 168 return true; 169} 170 171bool RSContext::processExportType(const llvm::StringRef &Name) { 172 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl(); 173 174 slangAssert(TUDecl != nullptr && "Translation unit declaration (top-level " 175 "declaration) is null object"); 176 177 const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name); 178 if (II == nullptr) 179 // TODO(zonr): alert identifier @Name mark as an exportable type cannot be 180 // found 181 return false; 182 183 clang::DeclContext::lookup_result R = TUDecl->lookup(II); 184 RSExportType *ET = nullptr; 185 186 for (clang::DeclContext::lookup_iterator I = R.begin(), E = R.end(); 187 I != E; 188 I++) { 189 clang::NamedDecl *const ND = *I; 190 const clang::Type *T = nullptr; 191 192 switch (ND->getKind()) { 193 case clang::Decl::Typedef: { 194 T = static_cast<const clang::TypedefDecl*>( 195 ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr(); 196 break; 197 } 198 case clang::Decl::Record: { 199 T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl(); 200 break; 201 } 202 default: { 203 // unsupported, skip 204 break; 205 } 206 } 207 208 if (T != nullptr) 209 ET = RSExportType::Create(this, T, NotLegacyKernelArgument); 210 } 211 212 return (ET != nullptr); 213} 214 215void RSContext::setAllocationType(const clang::TypeDecl* TD) { 216 mAllocationType = 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::insertExportType(const llvm::StringRef &TypeName, 296 RSExportType *ET) { 297 ExportTypeMap::value_type *NewItem = 298 ExportTypeMap::value_type::Create(TypeName, 299 mExportTypes.getAllocator(), 300 ET); 301 302 if (mExportTypes.insert(NewItem)) { 303 return true; 304 } else { 305 NewItem->Destroy(mExportTypes.getAllocator()); 306 return false; 307 } 308} 309 310RSContext::~RSContext() { 311 delete mLicenseNote; 312 delete mDataLayout; 313 for (ExportableList::iterator I = mExportables.begin(), 314 E = mExportables.end(); 315 I != E; 316 I++) { 317 if (!(*I)->isKeep()) 318 delete *I; 319 } 320} 321 322} // namespace slang 323