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(Target.getDataLayout()),
     61       mLLVMContext(slang::getGlobalLLVMContext()),
     62       mLicenseNote(nullptr),
     63       mRSPackageName("android.renderscript"),
     64       version(0),
     65       mMangleCtx(Ctx.createMangleContext()),
     66       mIs64Bit(Target.getPointerWidth(0) == 64),
     67       mNextSlot(1),
     68       mNextForEachOrdinal(0) {
     69 
     70   AddPragmaHandlers(PP, this);
     71 
     72   // Prepare target data
     73   // mDataLayout = Target.getDataLayout();
     74 
     75   // Reserve slot 0 for the root kernel.
     76   mExportForEach.push_back(nullptr);
     77   mFirstOldStyleKernel = mExportForEach.end();
     78 }
     79 
     80 bool RSContext::processExportVar(const clang::VarDecl *VD) {
     81   slangAssert(!VD->getName().empty() && "Variable name should not be empty");
     82 
     83   RSExportType *ET = RSExportType::CreateFromDecl(this, VD);
     84   if (!ET)
     85     return false;
     86 
     87   RSExportVar *EV = new RSExportVar(this, VD, ET);
     88   if (EV == nullptr)
     89     return false;
     90   else
     91     mExportVars.push_back(EV);
     92 
     93   return true;
     94 }
     95 
     96 int RSContext::getForEachSlotNumber(const clang::FunctionDecl* FD) {
     97   const clang::StringRef& funcName = FD->getName();
     98   return getForEachSlotNumber(funcName);
     99 }
    100 
    101 int RSContext::getForEachSlotNumber(const clang::StringRef& funcName) {
    102   auto it = mExportForEachMap.find(funcName);
    103   if (it == mExportForEachMap.end()) {
    104     return -1;
    105   }
    106   return it->second;
    107 }
    108 
    109 bool RSContext::processExportFunc(const clang::FunctionDecl *FD) {
    110   slangAssert(!FD->getName().empty() && "Function name should not be empty");
    111 
    112   if (!FD->isThisDeclarationADefinition()) {
    113     return true;
    114   }
    115 
    116   slangAssert(FD->getStorageClass() == clang::SC_None);
    117 
    118   // Specialized function
    119   if (RSSpecialFunc::isSpecialRSFunc(mTargetAPI, FD)) {
    120     // Do not reflect specialized functions like init, dtor, or graphics root.
    121     return RSSpecialFunc::validateSpecialFuncDecl(mTargetAPI, this, FD);
    122   }
    123 
    124   // Foreach kernel
    125   if (RSExportForEach::isRSForEachFunc(mTargetAPI, FD)) {
    126     RSExportForEach *EFE = RSExportForEach::Create(this, FD);
    127     if (EFE == nullptr) {
    128       return false;
    129     }
    130 
    131     // The root function should be at index 0 in the list
    132     if (FD->getName().equals("root")) {
    133       mExportForEach[0] = EFE;
    134       return true;
    135     }
    136 
    137     // New-style kernels with attribute "kernel" should come first in the list
    138     if (FD->hasAttr<clang::RenderScriptKernelAttr>()) {
    139       mFirstOldStyleKernel = mExportForEach.insert(mFirstOldStyleKernel, EFE) + 1;
    140       slangAssert((mTargetAPI < SLANG_FEATURE_SINGLE_SOURCE_API ||
    141                    getForEachSlotNumber(FD->getName()) ==
    142                    mFirstOldStyleKernel - mExportForEach.begin() - 1) &&
    143                   "Inconsistent slot number assignment");
    144       return true;
    145     }
    146 
    147     // Old-style kernels should appear in the end of the list
    148     mFirstOldStyleKernel = mExportForEach.insert(mFirstOldStyleKernel, EFE);
    149     return true;
    150   }
    151 
    152   // Invokable
    153   if (auto *EF = RSExportFunc::Create(this, FD)) {
    154     mExportFuncs.push_back(EF);
    155     return true;
    156   }
    157 
    158   return false;
    159 }
    160 
    161 bool RSContext::addForEach(const clang::FunctionDecl* FD) {
    162   const llvm::StringRef& funcName = FD->getName();
    163 
    164   if (funcName.equals("root")) {
    165     // The root kernel should always be in slot 0.
    166     mExportForEachMap.insert(std::make_pair(funcName, 0));
    167   } else {
    168     mExportForEachMap.insert(std::make_pair(funcName, mNextSlot++));
    169   }
    170 
    171   return true;
    172 }
    173 
    174 bool RSContext::processExportType(const llvm::StringRef &Name) {
    175   clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
    176 
    177   slangAssert(TUDecl != nullptr && "Translation unit declaration (top-level "
    178                                    "declaration) is null object");
    179 
    180   const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name);
    181   if (II == nullptr)
    182     // TODO(zonr): alert identifier @Name mark as an exportable type cannot be
    183     //             found
    184     return false;
    185 
    186   clang::DeclContext::lookup_result R = TUDecl->lookup(II);
    187   RSExportType *ET = nullptr;
    188 
    189   for (clang::DeclContext::lookup_iterator I = R.begin(), E = R.end();
    190        I != E;
    191        I++) {
    192     clang::NamedDecl *const ND = *I;
    193     const clang::Type *T = nullptr;
    194 
    195     switch (ND->getKind()) {
    196       case clang::Decl::Typedef: {
    197         T = static_cast<const clang::TypedefDecl*>(
    198             ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr();
    199         break;
    200       }
    201       case clang::Decl::Record: {
    202         T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl();
    203         break;
    204       }
    205       default: {
    206         // unsupported, skip
    207         break;
    208       }
    209     }
    210 
    211     if (T != nullptr)
    212       ET = RSExportType::Create(this, T, NotLegacyKernelArgument);
    213   }
    214 
    215   return (ET != nullptr);
    216 }
    217 
    218 void RSContext::setAllocationType(const clang::TypeDecl* TD) {
    219   mAllocationType = mCtx.getTypeDeclType(TD);
    220 }
    221 
    222 void RSContext::setScriptCallType(const clang::TypeDecl* TD) {
    223   mScriptCallType = mCtx.getTypeDeclType(TD);
    224 }
    225 
    226 bool RSContext::processExports() {
    227   bool valid = true;
    228 
    229   if (getDiagnostics()->hasErrorOccurred()) {
    230     return false;
    231   }
    232 
    233   clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
    234   for (auto I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; I++) {
    235     clang::Decl* D = *I;
    236     switch (D->getKind()) {
    237     case clang::Decl::Var: {
    238       clang::VarDecl* VD = llvm::dyn_cast<clang::VarDecl>(D);
    239       bool ShouldExportVariable = true;
    240       if (VD->getFormalLinkage() == clang::ExternalLinkage) {
    241         clang::QualType QT = VD->getTypeSourceInfo()->getType();
    242         if (QT.isConstQualified() && !VD->hasInit()) {
    243           if (Slang::IsLocInRSHeaderFile(VD->getLocation(),
    244                                          *getSourceManager())) {
    245             // We don't export variables internal to the runtime's
    246             // implementation.
    247             ShouldExportVariable = false;
    248           } else {
    249             clang::DiagnosticsEngine *DiagEngine = getDiagnostics();
    250             DiagEngine->Report(VD->getLocation(), DiagEngine->getCustomDiagID(
    251                 clang::DiagnosticsEngine::Error,
    252                 "invalid declaration of uninitialized constant variable '%0'"))
    253               << VD->getName();
    254             valid = false;
    255           }
    256         }
    257         if (valid && ShouldExportVariable && isSyntheticName(VD->getName()))
    258           ShouldExportVariable = false;
    259         if (valid && ShouldExportVariable && !processExportVar(VD)) {
    260           valid = false;
    261         }
    262       }
    263       break;
    264     }
    265     case clang::Decl::Function: {
    266       clang::FunctionDecl* FD = llvm::dyn_cast<clang::FunctionDecl>(D);
    267       if (FD->getFormalLinkage() == clang::ExternalLinkage) {
    268         if (!processExportFunc(FD)) {
    269           valid = false;
    270         }
    271       }
    272       break;
    273     }
    274     default:
    275       break;
    276     }
    277   }
    278 
    279   // Create a dummy root in slot 0 if a root kernel is not seen
    280   // and there exists a non-root kernel.
    281   if (valid && mExportForEach[0] == nullptr) {
    282     const size_t numExportedForEach = mExportForEach.size();
    283     if (numExportedForEach > 1) {
    284       mExportForEach[0] = RSExportForEach::CreateDummyRoot(this);
    285     } else {
    286       slangAssert(numExportedForEach == 1);
    287       mExportForEach.pop_back();
    288     }
    289   }
    290 
    291   // Finally, export type forcely set to be exported by user
    292   for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(),
    293            EE = mNeedExportTypes.end();
    294        EI != EE;
    295        EI++) {
    296     if (!processExportType(EI->getKey())) {
    297       valid = false;
    298     }
    299   }
    300 
    301   return valid;
    302 }
    303 
    304 bool RSContext::processReducePragmas(Backend *BE) {
    305   // This is needed to ensure that the dummy variable is emitted into
    306   // the bitcode -- which in turn forces the function to be emitted
    307   // into the bitcode.  We couldn't do this at
    308   // markUsedByReducePragma() time because we had to wait until the
    309   // Backend is available.
    310   for (auto DummyVar : mUsedByReducePragmaDummyVars)
    311     BE->HandleTopLevelDecl(clang::DeclGroupRef(DummyVar));
    312 
    313   bool valid = true;
    314   for (auto I = export_reduce_begin(), E = export_reduce_end(); I != E; ++I) {
    315     if (! (*I)->analyzeTranslationUnit())
    316       valid = false;
    317   }
    318   return valid;
    319 }
    320 
    321 void RSContext::markUsedByReducePragma(clang::FunctionDecl *FD, CheckName Check) {
    322   if (mUsedByReducePragmaFns.find(FD) != mUsedByReducePragmaFns.end())
    323     return;  // already marked used
    324 
    325   if (Check == CheckNameYes) {
    326     // This is an inefficient linear search.  If this turns out to be a
    327     // problem in practice, then processReducePragmas() could build a
    328     // set or hash table or something similar containing all function
    329     // names mentioned in a reduce pragma and searchable in O(c) or
    330     // O(log(n)) time rather than the currently-implemented O(n) search.
    331     auto NameMatches = [this, FD]() {
    332       for (auto I = export_reduce_begin(), E = export_reduce_end(); I != E; ++I) {
    333         if ((*I)->matchName(FD->getName()))
    334           return true;
    335       }
    336       return false;
    337     };
    338     if (!NameMatches())
    339       return;
    340   }
    341 
    342   mUsedByReducePragmaFns.insert(FD);
    343 
    344   // This is needed to prevent clang from warning that the function is
    345   // unused (in the case where it is only referenced by #pragma rs
    346   // reduce).
    347   FD->setIsUsed();
    348 
    349   // Each constituent function "f" of a reduction kernel gets a dummy variable generated for it:
    350   //   void *.rs.reduce_fn.f = (void*)&f;
    351   // This is a trick to ensure that clang will not delete "f" as unused.
    352 
    353   // `-VarDecl 0x87cb558 <line:3:1, col:30> col:7 var 'void *' cinit
    354   //     `-CStyleCastExpr 0x87cb630 <col:19, col:26> 'void *' <BitCast>
    355   //       `-ImplicitCastExpr 0x87cb618 <col:26> 'void (*)(int *, float, double)' <FunctionToPointerDecay>
    356   //         `-DeclRefExpr 0x87cb5b8 <col:26> 'void (int *, float, double)' Function 0x8784e10 'foo' 'void (int *, float, double)
    357 
    358   const clang::QualType VoidPtrType = mCtx.getPointerType(mCtx.VoidTy);
    359 
    360   clang::DeclContext *const DC = FD->getDeclContext();
    361   const clang::SourceLocation Loc = FD->getLocation();
    362 
    363   clang::VarDecl *const VD = clang::VarDecl::Create(
    364       mCtx, DC, Loc, Loc,
    365       &mCtx.Idents.get(std::string(".rs.reduce_fn.") + FD->getNameAsString()),
    366       VoidPtrType,
    367       mCtx.getTrivialTypeSourceInfo(VoidPtrType),
    368       clang::SC_None);
    369   VD->setLexicalDeclContext(DC);
    370   DC->addDecl(VD);
    371 
    372   clang::DeclRefExpr *const DRE = clang::DeclRefExpr::Create(mCtx,
    373                                                              clang::NestedNameSpecifierLoc(),
    374                                                              Loc,
    375                                                              FD, false, Loc, FD->getType(),
    376                                                              clang::VK_RValue);
    377   clang::ImplicitCastExpr *const ICE = clang::ImplicitCastExpr::Create(mCtx, mCtx.getPointerType(FD->getType()),
    378                                                                        clang::CK_FunctionToPointerDecay, DRE,
    379                                                                        nullptr, clang::VK_RValue);
    380   clang::CStyleCastExpr *const CSCE = clang::CStyleCastExpr::Create(mCtx, VoidPtrType, clang::VK_RValue, clang::CK_BitCast,
    381                                                                     ICE, nullptr, nullptr,
    382                                                                     Loc, Loc);
    383   VD->setInit(CSCE);
    384 
    385   mUsedByReducePragmaDummyVars.push_back(VD);
    386 }
    387 
    388 bool RSContext::insertExportType(const llvm::StringRef &TypeName,
    389                                  RSExportType *ET) {
    390   ExportTypeMap::value_type *NewItem =
    391       ExportTypeMap::value_type::Create(TypeName,
    392                                         mExportTypes.getAllocator(),
    393                                         ET);
    394 
    395   if (mExportTypes.insert(NewItem)) {
    396     return true;
    397   } else {
    398     NewItem->Destroy(mExportTypes.getAllocator());
    399     return false;
    400   }
    401 }
    402 
    403 RSContext::~RSContext() {
    404   delete mLicenseNote;
    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