slang_rs_context.cpp revision fb40ee2a90f37967bf4a40a18dec7f60e5c580d8
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 // TODO(zonr): some check on variable 81 82 RSExportType *ET = RSExportType::CreateFromDecl(this, VD); 83 if (!ET) 84 return false; 85 86 RSExportVar *EV = new RSExportVar(this, VD, ET); 87 if (EV == nullptr) 88 return false; 89 else 90 mExportVars.push_back(EV); 91 92 return true; 93} 94 95int RSContext::getForEachSlotNumber(const clang::FunctionDecl* FD) { 96 const clang::StringRef& funcName = FD->getName(); 97 return getForEachSlotNumber(funcName); 98} 99 100int RSContext::getForEachSlotNumber(const clang::StringRef& funcName) { 101 auto it = mExportForEachMap.find(funcName); 102 if (it == mExportForEachMap.end()) { 103 return -1; 104 } 105 return it->second; 106} 107 108bool RSContext::processExportFunc(const clang::FunctionDecl *FD) { 109 slangAssert(!FD->getName().empty() && "Function name should not be empty"); 110 111 if (!FD->isThisDeclarationADefinition()) { 112 return true; 113 } 114 115 if (FD->getStorageClass() != clang::SC_None) { 116 fprintf(stderr, "RSContext::processExportFunc : cannot export extern or " 117 "static function '%s'\n", FD->getName().str().c_str()); 118 return false; 119 } 120 121 // Specialized function 122 if (RSSpecialFunc::isSpecialRSFunc(mTargetAPI, FD)) { 123 // Do not reflect specialized functions like init, dtor, or graphics root. 124 return RSSpecialFunc::validateSpecialFuncDecl(mTargetAPI, this, FD); 125 } 126 127 // Foreach kernel 128 if (RSExportForEach::isRSForEachFunc(mTargetAPI, FD)) { 129 RSExportForEach *EFE = RSExportForEach::Create(this, FD); 130 if (EFE == nullptr) { 131 return false; 132 } 133 const llvm::StringRef& funcName = FD->getName(); 134 if (funcName.equals("root")) { 135 mExportForEach[0] = EFE; 136 } else { 137 mExportForEach.push_back(EFE); 138 } 139 return true; 140 } 141 142 // Reduce kernel 143 if (RSExportReduce::isRSReduceFunc(mTargetAPI, FD)) { 144 if (auto *ER = RSExportReduce::Create(this, FD)) { 145 mExportReduce.push_back(ER); 146 return true; 147 } 148 return false; 149 } 150 151 // Invokable 152 if (auto *EF = RSExportFunc::Create(this, FD)) { 153 mExportFuncs.push_back(EF); 154 return true; 155 } 156 157 return false; 158} 159 160bool RSContext::addForEach(const clang::FunctionDecl* FD) { 161 const llvm::StringRef& funcName = FD->getName(); 162 163 if (funcName.equals("root")) { 164 // The root kernel should always be in slot 0. 165 mExportForEachMap.insert(std::make_pair(funcName, 0)); 166 } else { 167 mExportForEachMap.insert(std::make_pair(funcName, mNextSlot++)); 168 } 169 170 return true; 171} 172 173bool RSContext::processExportType(const llvm::StringRef &Name) { 174 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl(); 175 176 slangAssert(TUDecl != nullptr && "Translation unit declaration (top-level " 177 "declaration) is null object"); 178 179 const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name); 180 if (II == nullptr) 181 // TODO(zonr): alert identifier @Name mark as an exportable type cannot be 182 // found 183 return false; 184 185 clang::DeclContext::lookup_result R = TUDecl->lookup(II); 186 RSExportType *ET = nullptr; 187 188 for (clang::DeclContext::lookup_iterator I = R.begin(), E = R.end(); 189 I != E; 190 I++) { 191 clang::NamedDecl *const ND = *I; 192 const clang::Type *T = nullptr; 193 194 switch (ND->getKind()) { 195 case clang::Decl::Typedef: { 196 T = static_cast<const clang::TypedefDecl*>( 197 ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr(); 198 break; 199 } 200 case clang::Decl::Record: { 201 T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl(); 202 break; 203 } 204 default: { 205 // unsupported, skip 206 break; 207 } 208 } 209 210 if (T != nullptr) 211 ET = RSExportType::Create(this, T); 212 } 213 214 return (ET != nullptr); 215} 216 217void RSContext::addAllocationType(const clang::TypeDecl* TD) { 218 mAllocationType = mCtx.getTypeDeclType(TD); 219} 220 221bool RSContext::processExports() { 222 bool valid = true; 223 224 if (getDiagnostics()->hasErrorOccurred()) { 225 return false; 226 } 227 228 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl(); 229 for (auto I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; I++) { 230 clang::Decl* D = *I; 231 switch (D->getKind()) { 232 case clang::Decl::Var: { 233 clang::VarDecl* VD = llvm::dyn_cast<clang::VarDecl>(D); 234 if (VD->getFormalLinkage() == clang::ExternalLinkage) { 235 if (!processExportVar(VD)) { 236 valid = false; 237 } 238 } 239 break; 240 } 241 case clang::Decl::Function: { 242 clang::FunctionDecl* FD = llvm::dyn_cast<clang::FunctionDecl>(D); 243 if (FD->getFormalLinkage() == clang::ExternalLinkage) { 244 if (!processExportFunc(FD)) { 245 valid = false; 246 } 247 } 248 break; 249 } 250 default: 251 break; 252 } 253 } 254 255 // Create a dummy root in slot 0 if a root kernel is not seen. 256 if (valid && mExportForEach[0] == nullptr) { 257 mExportForEach[0] = RSExportForEach::CreateDummyRoot(this); 258 } 259 260 // Finally, export type forcely set to be exported by user 261 for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(), 262 EE = mNeedExportTypes.end(); 263 EI != EE; 264 EI++) { 265 if (!processExportType(EI->getKey())) { 266 valid = false; 267 } 268 } 269 270 return valid; 271} 272 273bool RSContext::insertExportType(const llvm::StringRef &TypeName, 274 RSExportType *ET) { 275 ExportTypeMap::value_type *NewItem = 276 ExportTypeMap::value_type::Create(TypeName, 277 mExportTypes.getAllocator(), 278 ET); 279 280 if (mExportTypes.insert(NewItem)) { 281 return true; 282 } else { 283 NewItem->Destroy(mExportTypes.getAllocator()); 284 return false; 285 } 286} 287 288RSContext::~RSContext() { 289 delete mLicenseNote; 290 delete mDataLayout; 291 for (ExportableList::iterator I = mExportables.begin(), 292 E = mExportables.end(); 293 I != E; 294 I++) { 295 if (!(*I)->isKeep()) 296 delete *I; 297 } 298} 299 300} // namespace slang 301