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