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