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