slang_rs_context.cpp revision 15410146cdc2a354ade80ceb3cd134f8a792d92a
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); 210 } 211 212 return (ET != nullptr); 213} 214 215bool RSContext::processExports() { 216 bool valid = true; 217 218 if (getDiagnostics()->hasErrorOccurred()) { 219 return false; 220 } 221 222 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl(); 223 for (auto I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; I++) { 224 clang::Decl* D = *I; 225 switch (D->getKind()) { 226 case clang::Decl::Var: { 227 clang::VarDecl* VD = llvm::dyn_cast<clang::VarDecl>(D); 228 bool ShouldExportVariable = true; 229 if (VD->getFormalLinkage() == clang::ExternalLinkage) { 230 clang::QualType QT = VD->getTypeSourceInfo()->getType(); 231 if (QT.isConstQualified() && !VD->hasInit()) { 232 if (Slang::IsLocInRSHeaderFile(VD->getLocation(), 233 *getSourceManager())) { 234 // We don't export variables internal to the runtime's 235 // implementation. 236 ShouldExportVariable = false; 237 } else { 238 clang::DiagnosticsEngine *DiagEngine = getDiagnostics(); 239 DiagEngine->Report(VD->getLocation(), DiagEngine->getCustomDiagID( 240 clang::DiagnosticsEngine::Error, 241 "invalid declaration of uninitialized constant variable '%0'")) 242 << VD->getName(); 243 valid = false; 244 } 245 } 246 if (valid && ShouldExportVariable && !processExportVar(VD)) { 247 valid = false; 248 } 249 } 250 break; 251 } 252 case clang::Decl::Function: { 253 clang::FunctionDecl* FD = llvm::dyn_cast<clang::FunctionDecl>(D); 254 if (FD->getFormalLinkage() == clang::ExternalLinkage) { 255 if (!processExportFunc(FD)) { 256 valid = false; 257 } 258 } 259 break; 260 } 261 default: 262 break; 263 } 264 } 265 266 // Create a dummy root in slot 0 if a root kernel is not seen 267 // and there exists a non-root kernel. 268 if (valid && mExportForEach[0] == nullptr) { 269 const size_t numExportedForEach = mExportForEach.size(); 270 if (numExportedForEach > 1) { 271 mExportForEach[0] = RSExportForEach::CreateDummyRoot(this); 272 } else { 273 slangAssert(numExportedForEach == 1); 274 mExportForEach.pop_back(); 275 } 276 } 277 278 // Finally, export type forcely set to be exported by user 279 for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(), 280 EE = mNeedExportTypes.end(); 281 EI != EE; 282 EI++) { 283 if (!processExportType(EI->getKey())) { 284 valid = false; 285 } 286 } 287 288 return valid; 289} 290 291bool RSContext::insertExportType(const llvm::StringRef &TypeName, 292 RSExportType *ET) { 293 ExportTypeMap::value_type *NewItem = 294 ExportTypeMap::value_type::Create(TypeName, 295 mExportTypes.getAllocator(), 296 ET); 297 298 if (mExportTypes.insert(NewItem)) { 299 return true; 300 } else { 301 NewItem->Destroy(mExportTypes.getAllocator()); 302 return false; 303 } 304} 305 306RSContext::~RSContext() { 307 delete mLicenseNote; 308 delete mDataLayout; 309 for (ExportableList::iterator I = mExportables.begin(), 310 E = mExportables.end(); 311 I != E; 312 I++) { 313 if (!(*I)->isKeep()) 314 delete *I; 315 } 316} 317 318} // namespace slang 319