Home | History | Annotate | Download | only in slang
      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_backend.h"
     37 #include "slang_rs_export_foreach.h"
     38 #include "slang_rs_export_func.h"
     39 #include "slang_rs_export_reduce.h"
     40 #include "slang_rs_export_type.h"
     41 #include "slang_rs_export_var.h"
     42 #include "slang_rs_exportable.h"
     43 #include "slang_rs_pragma_handler.h"
     44 #include "slang_rs_reflection.h"
     45 #include "slang_rs_special_func.h"
     46 
     47 namespace slang {
     48 
     49 RSContext::RSContext(clang::Preprocessor &PP,
     50                      clang::ASTContext &Ctx,
     51                      const clang::TargetInfo &Target,
     52                      PragmaList *Pragmas,
     53                      unsigned int TargetAPI,
     54                      bool Verbose)
     55     : mPP(PP),
     56       mCtx(Ctx),
     57       mPragmas(Pragmas),
     58       mTargetAPI(TargetAPI),
     59       mVerbose(Verbose),
     60       mDataLayout(nullptr),
     61       mLLVMContext(llvm::getGlobalContext()),
     62       mLicenseNote(nullptr),
     63       mRSPackageName("android.renderscript"),
     64       version(0),
     65       mMangleCtx(Ctx.createMangleContext()),
     66       mIs64Bit(Target.getPointerWidth(0) == 64),
     67       mNextSlot(1) {
     68 
     69   AddPragmaHandlers(PP, this);
     70 
     71   // Prepare target data
     72   mDataLayout = new llvm::DataLayout(Target.getDataLayoutString());
     73 
     74   // Reserve slot 0 for the root kernel.
     75   mExportForEach.push_back(nullptr);
     76   mFirstOldStyleKernel = mExportForEach.end();
     77 }
     78 
     79 bool RSContext::processExportVar(const clang::VarDecl *VD) {
     80   slangAssert(!VD->getName().empty() && "Variable name should not be empty");
     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 
     95 int RSContext::getForEachSlotNumber(const clang::FunctionDecl* FD) {
     96   const clang::StringRef& funcName = FD->getName();
     97   return getForEachSlotNumber(funcName);
     98 }
     99 
    100 int 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 
    108 bool 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   slangAssert(FD->getStorageClass() == clang::SC_None);
    116 
    117   // Specialized function
    118   if (RSSpecialFunc::isSpecialRSFunc(mTargetAPI, FD)) {
    119     // Do not reflect specialized functions like init, dtor, or graphics root.
    120     return RSSpecialFunc::validateSpecialFuncDecl(mTargetAPI, this, FD);
    121   }
    122 
    123   // Foreach kernel
    124   if (RSExportForEach::isRSForEachFunc(mTargetAPI, FD)) {
    125     RSExportForEach *EFE = RSExportForEach::Create(this, FD);
    126     if (EFE == nullptr) {
    127       return false;
    128     }
    129 
    130     // The root function should be at index 0 in the list
    131     if (FD->getName().equals("root")) {
    132       mExportForEach[0] = EFE;
    133       return true;
    134     }
    135 
    136     // New-style kernels with attribute "kernel" should come first in the list
    137     if (FD->hasAttr<clang::KernelAttr>()) {
    138       mFirstOldStyleKernel = mExportForEach.insert(mFirstOldStyleKernel, EFE) + 1;
    139       slangAssert((mTargetAPI < SLANG_FEATURE_SINGLE_SOURCE_API ||
    140                    getForEachSlotNumber(FD->getName()) ==
    141                    mFirstOldStyleKernel - mExportForEach.begin() - 1) &&
    142                   "Inconsistent slot number assignment");
    143       return true;
    144     }
    145 
    146     // Old-style kernels should appear in the end of the list
    147     mFirstOldStyleKernel = mExportForEach.insert(mFirstOldStyleKernel, EFE);
    148     return true;
    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 
    160 bool 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 
    173 bool 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, NotLegacyKernelArgument);
    212   }
    213 
    214   return (ET != nullptr);
    215 }
    216 
    217 void RSContext::setAllocationType(const clang::TypeDecl* TD) {
    218   mAllocationType = mCtx.getTypeDeclType(TD);
    219 }
    220 
    221 void RSContext::setScriptCallType(const clang::TypeDecl* TD) {
    222   mScriptCallType = mCtx.getTypeDeclType(TD);
    223 }
    224 
    225 bool RSContext::processExports() {
    226   bool valid = true;
    227 
    228   if (getDiagnostics()->hasErrorOccurred()) {
    229     return false;
    230   }
    231 
    232   clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
    233   for (auto I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; I++) {
    234     clang::Decl* D = *I;
    235     switch (D->getKind()) {
    236     case clang::Decl::Var: {
    237       clang::VarDecl* VD = llvm::dyn_cast<clang::VarDecl>(D);
    238       bool ShouldExportVariable = true;
    239       if (VD->getFormalLinkage() == clang::ExternalLinkage) {
    240         clang::QualType QT = VD->getTypeSourceInfo()->getType();
    241         if (QT.isConstQualified() && !VD->hasInit()) {
    242           if (Slang::IsLocInRSHeaderFile(VD->getLocation(),
    243                                          *getSourceManager())) {
    244             // We don't export variables internal to the runtime's
    245             // implementation.
    246             ShouldExportVariable = false;
    247           } else {
    248             clang::DiagnosticsEngine *DiagEngine = getDiagnostics();
    249             DiagEngine->Report(VD->getLocation(), DiagEngine->getCustomDiagID(
    250                 clang::DiagnosticsEngine::Error,
    251                 "invalid declaration of uninitialized constant variable '%0'"))
    252               << VD->getName();
    253             valid = false;
    254           }
    255         }
    256         if (valid && ShouldExportVariable && isSyntheticName(VD->getName()))
    257           ShouldExportVariable = false;
    258         if (valid && ShouldExportVariable && !processExportVar(VD)) {
    259           valid = false;
    260         }
    261       }
    262       break;
    263     }
    264     case clang::Decl::Function: {
    265       clang::FunctionDecl* FD = llvm::dyn_cast<clang::FunctionDecl>(D);
    266       if (FD->getFormalLinkage() == clang::ExternalLinkage) {
    267         if (!processExportFunc(FD)) {
    268           valid = false;
    269         }
    270       }
    271       break;
    272     }
    273     default:
    274       break;
    275     }
    276   }
    277 
    278   // Create a dummy root in slot 0 if a root kernel is not seen
    279   // and there exists a non-root kernel.
    280   if (valid && mExportForEach[0] == nullptr) {
    281     const size_t numExportedForEach = mExportForEach.size();
    282     if (numExportedForEach > 1) {
    283       mExportForEach[0] = RSExportForEach::CreateDummyRoot(this);
    284     } else {
    285       slangAssert(numExportedForEach == 1);
    286       mExportForEach.pop_back();
    287     }
    288   }
    289 
    290   // Finally, export type forcely set to be exported by user
    291   for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(),
    292            EE = mNeedExportTypes.end();
    293        EI != EE;
    294        EI++) {
    295     if (!processExportType(EI->getKey())) {
    296       valid = false;
    297     }
    298   }
    299 
    300   return valid;
    301 }
    302 
    303 bool RSContext::processReducePragmas(Backend *BE) {
    304   // This is needed to ensure that the dummy variable is emitted into
    305   // the bitcode -- which in turn forces the function to be emitted
    306   // into the bitcode.  We couldn't do this at
    307   // markUsedByReducePragma() time because we had to wait until the
    308   // Backend is available.
    309   for (auto DummyVar : mUsedByReducePragmaDummyVars)
    310     BE->HandleTopLevelDecl(clang::DeclGroupRef(DummyVar));
    311 
    312   bool valid = true;
    313   for (auto I = export_reduce_begin(), E = export_reduce_end(); I != E; ++I) {
    314     if (! (*I)->analyzeTranslationUnit())
    315       valid = false;
    316   }
    317   return valid;
    318 }
    319 
    320 void RSContext::markUsedByReducePragma(clang::FunctionDecl *FD, CheckName Check) {
    321   if (mUsedByReducePragmaFns.find(FD) != mUsedByReducePragmaFns.end())
    322     return;  // already marked used
    323 
    324   if (Check == CheckNameYes) {
    325     // This is an inefficient linear search.  If this turns out to be a
    326     // problem in practice, then processReducePragmas() could build a
    327     // set or hash table or something similar containing all function
    328     // names mentioned in a reduce pragma and searchable in O(c) or
    329     // O(log(n)) time rather than the currently-implemented O(n) search.
    330     auto NameMatches = [this, FD]() {
    331       for (auto I = export_reduce_begin(), E = export_reduce_end(); I != E; ++I) {
    332         if ((*I)->matchName(FD->getName()))
    333           return true;
    334       }
    335       return false;
    336     };
    337     if (!NameMatches())
    338       return;
    339   }
    340 
    341   mUsedByReducePragmaFns.insert(FD);
    342 
    343   // This is needed to prevent clang from warning that the function is
    344   // unused (in the case where it is only referenced by #pragma rs
    345   // reduce).
    346   FD->setIsUsed();
    347 
    348   // Each constituent function "f" of a reduction kernel gets a dummy variable generated for it:
    349   //   void *.rs.reduce_fn.f = (void*)&f;
    350   // This is a trick to ensure that clang will not delete "f" as unused.
    351 
    352   // `-VarDecl 0x87cb558 <line:3:1, col:30> col:7 var 'void *' cinit
    353   //     `-CStyleCastExpr 0x87cb630 <col:19, col:26> 'void *' <BitCast>
    354   //       `-ImplicitCastExpr 0x87cb618 <col:26> 'void (*)(int *, float, double)' <FunctionToPointerDecay>
    355   //         `-DeclRefExpr 0x87cb5b8 <col:26> 'void (int *, float, double)' Function 0x8784e10 'foo' 'void (int *, float, double)
    356 
    357   const clang::QualType VoidPtrType = mCtx.getPointerType(mCtx.VoidTy);
    358 
    359   clang::DeclContext *const DC = FD->getDeclContext();
    360   const clang::SourceLocation Loc = FD->getLocation();
    361 
    362   clang::VarDecl *const VD = clang::VarDecl::Create(
    363       mCtx, DC, Loc, Loc,
    364       &mCtx.Idents.get(std::string(".rs.reduce_fn.") + FD->getNameAsString()),
    365       VoidPtrType,
    366       mCtx.getTrivialTypeSourceInfo(VoidPtrType),
    367       clang::SC_None);
    368   VD->setLexicalDeclContext(DC);
    369   DC->addDecl(VD);
    370 
    371   clang::DeclRefExpr *const DRE = clang::DeclRefExpr::Create(mCtx,
    372                                                              clang::NestedNameSpecifierLoc(),
    373                                                              Loc,
    374                                                              FD, false, Loc, FD->getType(),
    375                                                              clang::VK_RValue);
    376   clang::ImplicitCastExpr *const ICE = clang::ImplicitCastExpr::Create(mCtx, mCtx.getPointerType(FD->getType()),
    377                                                                        clang::CK_FunctionToPointerDecay, DRE,
    378                                                                        nullptr, clang::VK_RValue);
    379   clang::CStyleCastExpr *const CSCE = clang::CStyleCastExpr::Create(mCtx, VoidPtrType, clang::VK_RValue, clang::CK_BitCast,
    380                                                                     ICE, nullptr, nullptr,
    381                                                                     Loc, Loc);
    382   VD->setInit(CSCE);
    383 
    384   mUsedByReducePragmaDummyVars.push_back(VD);
    385 }
    386 
    387 bool RSContext::insertExportType(const llvm::StringRef &TypeName,
    388                                  RSExportType *ET) {
    389   ExportTypeMap::value_type *NewItem =
    390       ExportTypeMap::value_type::Create(TypeName,
    391                                         mExportTypes.getAllocator(),
    392                                         ET);
    393 
    394   if (mExportTypes.insert(NewItem)) {
    395     return true;
    396   } else {
    397     NewItem->Destroy(mExportTypes.getAllocator());
    398     return false;
    399   }
    400 }
    401 
    402 RSContext::~RSContext() {
    403   delete mLicenseNote;
    404   delete mDataLayout;
    405   for (ExportableList::iterator I = mExportables.begin(),
    406           E = mExportables.end();
    407        I != E;
    408        I++) {
    409     if (!(*I)->isKeep())
    410       delete *I;
    411   }
    412 }
    413 
    414 }  // namespace slang
    415