slang_rs_context.cpp revision fc4f78b9c7941132fb048a83f0e4ba528c3b4fd0
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/Decl.h" 23#include "clang/AST/DeclBase.h" 24#include "clang/AST/Mangle.h" 25#include "clang/AST/Type.h" 26 27#include "clang/Basic/Linkage.h" 28#include "clang/Basic/TargetInfo.h" 29 30#include "llvm/IR/LLVMContext.h" 31#include "llvm/IR/DataLayout.h" 32 33#include "slang.h" 34#include "slang_assert.h" 35#include "slang_rs_export_foreach.h" 36#include "slang_rs_export_func.h" 37#include "slang_rs_export_type.h" 38#include "slang_rs_export_var.h" 39#include "slang_rs_exportable.h" 40#include "slang_rs_pragma_handler.h" 41#include "slang_rs_reflection.h" 42 43namespace slang { 44 45RSContext::RSContext(clang::Preprocessor &PP, 46 clang::ASTContext &Ctx, 47 const clang::TargetInfo &Target, 48 PragmaList *Pragmas, 49 unsigned int TargetAPI, 50 bool Verbose) 51 : mPP(PP), 52 mCtx(Ctx), 53 mPragmas(Pragmas), 54 mTargetAPI(TargetAPI), 55 mVerbose(Verbose), 56 mDataLayout(NULL), 57 mLLVMContext(llvm::getGlobalContext()), 58 mLicenseNote(NULL), 59 mRSPackageName("android.renderscript"), 60 version(0), 61 mMangleCtx(Ctx.createMangleContext()) { 62 63 // For #pragma rs export_type 64 PP.AddPragmaHandler( 65 "rs", RSPragmaHandler::CreatePragmaExportTypeHandler(this)); 66 67 // For #pragma rs java_package_name 68 PP.AddPragmaHandler( 69 "rs", RSPragmaHandler::CreatePragmaJavaPackageNameHandler(this)); 70 71 // For #pragma rs set_reflect_license 72 PP.AddPragmaHandler( 73 "rs", RSPragmaHandler::CreatePragmaReflectLicenseHandler(this)); 74 75 // For #pragma version 76 PP.AddPragmaHandler(RSPragmaHandler::CreatePragmaVersionHandler(this)); 77 78 // Prepare target data 79 mDataLayout = new llvm::DataLayout(Target.getTargetDescription()); 80} 81 82bool RSContext::processExportVar(const clang::VarDecl *VD) { 83 slangAssert(!VD->getName().empty() && "Variable name should not be empty"); 84 85 // TODO(zonr): some check on variable 86 87 RSExportType *ET = RSExportType::CreateFromDecl(this, VD); 88 if (!ET) 89 return false; 90 91 RSExportVar *EV = new RSExportVar(this, VD, ET); 92 if (EV == NULL) 93 return false; 94 else 95 mExportVars.push_back(EV); 96 97 return true; 98} 99 100bool RSContext::processExportFunc(const clang::FunctionDecl *FD) { 101 slangAssert(!FD->getName().empty() && "Function name should not be empty"); 102 103 if (!FD->isThisDeclarationADefinition()) { 104 return true; 105 } 106 107 if (FD->getStorageClass() != clang::SC_None) { 108 fprintf(stderr, "RSContext::processExportFunc : cannot export extern or " 109 "static function '%s'\n", FD->getName().str().c_str()); 110 return false; 111 } 112 113 if (RSExportForEach::isSpecialRSFunc(mTargetAPI, FD)) { 114 // Do not reflect specialized functions like init, dtor, or graphics root. 115 return RSExportForEach::validateSpecialFuncDecl(mTargetAPI, this, FD); 116 } else if (RSExportForEach::isRSForEachFunc(mTargetAPI, this, FD)) { 117 RSExportForEach *EFE = RSExportForEach::Create(this, FD); 118 if (EFE == NULL) 119 return false; 120 else 121 mExportForEach.push_back(EFE); 122 return true; 123 } 124 125 RSExportFunc *EF = RSExportFunc::Create(this, FD); 126 if (EF == NULL) 127 return false; 128 else 129 mExportFuncs.push_back(EF); 130 131 return true; 132} 133 134 135bool RSContext::processExportType(const llvm::StringRef &Name) { 136 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl(); 137 138 slangAssert(TUDecl != NULL && "Translation unit declaration (top-level " 139 "declaration) is null object"); 140 141 const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name); 142 if (II == NULL) 143 // TODO(zonr): alert identifier @Name mark as an exportable type cannot be 144 // found 145 return false; 146 147 clang::DeclContext::lookup_const_result R = TUDecl->lookup(II); 148 RSExportType *ET = NULL; 149 150 for (clang::DeclContext::lookup_const_iterator I = R.begin(), E = R.end(); 151 I != E; 152 I++) { 153 clang::NamedDecl *const ND = *I; 154 const clang::Type *T = NULL; 155 156 switch (ND->getKind()) { 157 case clang::Decl::Typedef: { 158 T = static_cast<const clang::TypedefDecl*>( 159 ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr(); 160 break; 161 } 162 case clang::Decl::Record: { 163 T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl(); 164 break; 165 } 166 default: { 167 // unsupported, skip 168 break; 169 } 170 } 171 172 if (T != NULL) 173 ET = RSExportType::Create(this, T); 174 } 175 176 return (ET != NULL); 177} 178 179 180// Possibly re-order ForEach exports (maybe generating a dummy "root" function). 181// We require "root" to be listed as slot 0 of our exported compute kernels, 182// so this only needs to be created if we have other non-root kernels. 183void RSContext::cleanupForEach() { 184 bool foundNonRoot = false; 185 ExportForEachList::iterator begin = mExportForEach.begin(); 186 187 for (ExportForEachList::iterator I = begin, E = mExportForEach.end(); 188 I != E; 189 I++) { 190 RSExportForEach *EFE = *I; 191 if (!EFE->getName().compare("root")) { 192 if (I == begin) { 193 // Nothing to do, since it is the first function 194 return; 195 } 196 197 mExportForEach.erase(I); 198 mExportForEach.push_front(EFE); 199 return; 200 } else { 201 foundNonRoot = true; 202 } 203 } 204 205 // If we found a non-root kernel, but no root() function, we need to add a 206 // dummy version (so that script->script calls of rsForEach don't behave 207 // erratically). 208 if (foundNonRoot) { 209 RSExportForEach *DummyRoot = RSExportForEach::CreateDummyRoot(this); 210 mExportForEach.push_front(DummyRoot); 211 } 212} 213 214 215bool RSContext::processExport() { 216 bool valid = true; 217 218 if (getDiagnostics()->hasErrorOccurred()) { 219 return false; 220 } 221 222 // Export variable 223 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl(); 224 for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(), 225 DE = TUDecl->decls_end(); 226 DI != DE; 227 DI++) { 228 if (DI->getKind() == clang::Decl::Var) { 229 clang::VarDecl *VD = (clang::VarDecl*) (*DI); 230 if (VD->getFormalLinkage() == clang::ExternalLinkage) { 231 if (!processExportVar(VD)) { 232 valid = false; 233 } 234 } 235 } else if (DI->getKind() == clang::Decl::Function) { 236 // Export functions 237 clang::FunctionDecl *FD = (clang::FunctionDecl*) (*DI); 238 if (FD->getFormalLinkage() == clang::ExternalLinkage) { 239 if (!processExportFunc(FD)) { 240 valid = false; 241 } 242 } 243 } 244 } 245 246 if (valid) { 247 cleanupForEach(); 248 } 249 250 // Finally, export type forcely set to be exported by user 251 for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(), 252 EE = mNeedExportTypes.end(); 253 EI != EE; 254 EI++) { 255 if (!processExportType(EI->getKey())) { 256 valid = false; 257 } 258 } 259 260 return valid; 261} 262 263bool RSContext::insertExportType(const llvm::StringRef &TypeName, 264 RSExportType *ET) { 265 ExportTypeMap::value_type *NewItem = 266 ExportTypeMap::value_type::Create(TypeName.begin(), 267 TypeName.end(), 268 mExportTypes.getAllocator(), 269 ET); 270 271 if (mExportTypes.insert(NewItem)) { 272 return true; 273 } else { 274 free(NewItem); 275 return false; 276 } 277} 278 279RSContext::~RSContext() { 280 delete mLicenseNote; 281 delete mDataLayout; 282 for (ExportableList::iterator I = mExportables.begin(), 283 E = mExportables.end(); 284 I != E; 285 I++) { 286 if (!(*I)->isKeep()) 287 delete *I; 288 } 289} 290 291} // namespace slang 292