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.h"
     18 
     19 #include <cstring>
     20 #include <list>
     21 #include <sstream>
     22 #include <string>
     23 #include <utility>
     24 #include <vector>
     25 
     26 #include "clang/Basic/SourceLocation.h"
     27 
     28 #include "clang/Frontend/FrontendDiagnostic.h"
     29 
     30 #include "clang/Sema/SemaDiagnostic.h"
     31 
     32 #include "llvm/Support/Path.h"
     33 
     34 #include "os_sep.h"
     35 #include "slang_rs_backend.h"
     36 #include "slang_rs_context.h"
     37 #include "slang_rs_export_type.h"
     38 
     39 #include "slang_rs_reflection_cpp.h"
     40 
     41 namespace slang {
     42 
     43 #define FS_SUFFIX  "fs"
     44 
     45 #define RS_HEADER_SUFFIX  "rsh"
     46 
     47 /* RS_HEADER_ENTRY(name) */
     48 #define ENUM_RS_HEADER()  \
     49   RS_HEADER_ENTRY(rs_allocation) \
     50   RS_HEADER_ENTRY(rs_atomic) \
     51   RS_HEADER_ENTRY(rs_cl) \
     52   RS_HEADER_ENTRY(rs_core) \
     53   RS_HEADER_ENTRY(rs_debug) \
     54   RS_HEADER_ENTRY(rs_element) \
     55   RS_HEADER_ENTRY(rs_graphics) \
     56   RS_HEADER_ENTRY(rs_math) \
     57   RS_HEADER_ENTRY(rs_mesh) \
     58   RS_HEADER_ENTRY(rs_matrix) \
     59   RS_HEADER_ENTRY(rs_object) \
     60   RS_HEADER_ENTRY(rs_program) \
     61   RS_HEADER_ENTRY(rs_quaternion) \
     62   RS_HEADER_ENTRY(rs_sampler) \
     63   RS_HEADER_ENTRY(rs_time) \
     64   RS_HEADER_ENTRY(rs_types) \
     65 
     66 // Returns true if \p Filename ends in ".fs".
     67 bool SlangRS::isFilterscript(const char *Filename) {
     68   const char *c = strrchr(Filename, '.');
     69   if (c && !strncmp(FS_SUFFIX, c + 1, strlen(FS_SUFFIX) + 1)) {
     70     return true;
     71   } else {
     72     return false;
     73   }
     74 }
     75 
     76 bool SlangRS::reflectToJava(const std::string &OutputPathBase,
     77                             const std::string &OutputPackageName,
     78                             const std::string &RSPackageName,
     79                             std::string *RealPackageName) {
     80   return mRSContext->reflectToJava(OutputPathBase,
     81                                    OutputPackageName,
     82                                    RSPackageName,
     83                                    getInputFileName(),
     84                                    getOutputFileName(),
     85                                    RealPackageName);
     86 }
     87 
     88 bool SlangRS::generateBitcodeAccessor(const std::string &OutputPathBase,
     89                                       const std::string &PackageName) {
     90   RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext;
     91 
     92   BCAccessorContext.rsFileName = getInputFileName().c_str();
     93   BCAccessorContext.bcFileName = getOutputFileName().c_str();
     94   BCAccessorContext.reflectPath = OutputPathBase.c_str();
     95   BCAccessorContext.packageName = PackageName.c_str();
     96   BCAccessorContext.bcStorage = BCST_JAVA_CODE;   // Must be BCST_JAVA_CODE
     97 
     98   return RSSlangReflectUtils::GenerateBitCodeAccessor(BCAccessorContext);
     99 }
    100 
    101 bool SlangRS::checkODR(const char *CurInputFile) {
    102   for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(),
    103           E = mRSContext->exportable_end();
    104        I != E;
    105        I++) {
    106     RSExportable *RSE = *I;
    107     if (RSE->getKind() != RSExportable::EX_TYPE)
    108       continue;
    109 
    110     RSExportType *ET = static_cast<RSExportType *>(RSE);
    111     if (ET->getClass() != RSExportType::ExportClassRecord)
    112       continue;
    113 
    114     RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET);
    115 
    116     // Artificial record types (create by us not by user in the source) always
    117     // conforms the ODR.
    118     if (ERT->isArtificial())
    119       continue;
    120 
    121     // Key to lookup ERT in ReflectedDefinitions
    122     llvm::StringRef RDKey(ERT->getName());
    123     ReflectedDefinitionListTy::const_iterator RD =
    124         ReflectedDefinitions.find(RDKey);
    125 
    126     if (RD != ReflectedDefinitions.end()) {
    127       const RSExportRecordType *Reflected = RD->getValue().first;
    128       // There's a record (struct) with the same name reflected before. Enforce
    129       // ODR checking - the Reflected must hold *exactly* the same "definition"
    130       // as the one defined previously. We say two record types A and B have the
    131       // same definition iff:
    132       //
    133       //  struct A {              struct B {
    134       //    Type(a1) a1,            Type(b1) b1,
    135       //    Type(a2) a2,            Type(b1) b2,
    136       //    ...                     ...
    137       //    Type(aN) aN             Type(b3) b3,
    138       //  };                      }
    139       //  Cond. #1. They have same number of fields, i.e., N = M;
    140       //  Cond. #2. for (i := 1 to N)
    141       //              Type(ai) = Type(bi) must hold;
    142       //  Cond. #3. for (i := 1 to N)
    143       //              Name(ai) = Name(bi) must hold;
    144       //
    145       // where,
    146       //  Type(F) = the type of field F and
    147       //  Name(F) = the field name.
    148 
    149       bool PassODR = false;
    150       // Cond. #1 and Cond. #2
    151       if (Reflected->equals(ERT)) {
    152         // Cond #3.
    153         RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(),
    154                                                  BI = ERT->fields_begin();
    155 
    156         for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) {
    157           if ((*AI)->getName() != (*BI)->getName())
    158             break;
    159           AI++;
    160           BI++;
    161         }
    162         PassODR = (AI == (Reflected->fields_end()));
    163       }
    164 
    165       if (!PassODR) {
    166         getDiagnostics().Report(mDiagErrorODR) << Reflected->getName()
    167                                                << getInputFileName()
    168                                                << RD->getValue().second;
    169         return false;
    170       }
    171     } else {
    172       llvm::StringMapEntry<ReflectedDefinitionTy> *ME =
    173           llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(),
    174                                                               RDKey.end());
    175       ME->setValue(std::make_pair(ERT, CurInputFile));
    176 
    177       if (!ReflectedDefinitions.insert(ME))
    178         delete ME;
    179 
    180       // Take the ownership of ERT such that it won't be freed in ~RSContext().
    181       ERT->keep();
    182     }
    183   }
    184   return true;
    185 }
    186 
    187 void SlangRS::initDiagnostic() {
    188   clang::DiagnosticsEngine &DiagEngine = getDiagnostics();
    189 
    190   if (DiagEngine.setDiagnosticGroupMapping("implicit-function-declaration",
    191                                            clang::diag::MAP_ERROR))
    192     DiagEngine.Report(clang::diag::warn_unknown_warning_option)
    193       << "implicit-function-declaration";
    194 
    195   DiagEngine.setDiagnosticMapping(
    196     clang::diag::ext_typecheck_convert_discards_qualifiers,
    197     clang::diag::MAP_ERROR,
    198     clang::SourceLocation());
    199 
    200   mDiagErrorInvalidOutputDepParameter =
    201     DiagEngine.getCustomDiagID(
    202       clang::DiagnosticsEngine::Error,
    203       "invalid parameter for output dependencies files.");
    204 
    205   mDiagErrorODR =
    206     DiagEngine.getCustomDiagID(
    207       clang::DiagnosticsEngine::Error,
    208       "type '%0' in different translation unit (%1 v.s. %2) "
    209       "has incompatible type definition");
    210 
    211   mDiagErrorTargetAPIRange =
    212     DiagEngine.getCustomDiagID(
    213       clang::DiagnosticsEngine::Error,
    214       "target API level '%0' is out of range ('%1' - '%2')");
    215 }
    216 
    217 void SlangRS::initPreprocessor() {
    218   clang::Preprocessor &PP = getPreprocessor();
    219 
    220   std::stringstream RSH;
    221   RSH << "#define RS_VERSION " << mTargetAPI << std::endl;
    222   RSH << "#include \"rs_core." RS_HEADER_SUFFIX "\"" << std::endl;
    223   PP.setPredefines(RSH.str());
    224 }
    225 
    226 void SlangRS::initASTContext() {
    227   mRSContext = new RSContext(getPreprocessor(),
    228                              getASTContext(),
    229                              getTargetInfo(),
    230                              &mPragmas,
    231                              mTargetAPI,
    232                              &mGeneratedFileNames);
    233 }
    234 
    235 clang::ASTConsumer
    236 *SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts,
    237                         llvm::raw_ostream *OS,
    238                         Slang::OutputType OT) {
    239     return new RSBackend(mRSContext,
    240                          &getDiagnostics(),
    241                          CodeGenOpts,
    242                          getTargetOptions(),
    243                          &mPragmas,
    244                          OS,
    245                          OT,
    246                          getSourceManager(),
    247                          mAllowRSPrefix,
    248                          mIsFilterscript);
    249 }
    250 
    251 bool SlangRS::IsRSHeaderFile(const char *File) {
    252 #define RS_HEADER_ENTRY(name)  \
    253   if (::strcmp(File, #name "."RS_HEADER_SUFFIX) == 0)  \
    254     return true;
    255 ENUM_RS_HEADER()
    256 #undef RS_HEADER_ENTRY
    257   return false;
    258 }
    259 
    260 bool SlangRS::IsLocInRSHeaderFile(const clang::SourceLocation &Loc,
    261                                   const clang::SourceManager &SourceMgr) {
    262   clang::FullSourceLoc FSL(Loc, SourceMgr);
    263   clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL);
    264 
    265   const char *Filename = PLoc.getFilename();
    266   if (!Filename) {
    267     return false;
    268   } else {
    269     return IsRSHeaderFile(llvm::sys::path::filename(Filename).data());
    270   }
    271 }
    272 
    273 SlangRS::SlangRS()
    274   : Slang(), mRSContext(NULL), mAllowRSPrefix(false), mTargetAPI(0),
    275     mIsFilterscript(false) {
    276 }
    277 
    278 bool SlangRS::compile(
    279     const std::list<std::pair<const char*, const char*> > &IOFiles,
    280     const std::list<std::pair<const char*, const char*> > &DepFiles,
    281     const std::vector<std::string> &IncludePaths,
    282     const std::vector<std::string> &AdditionalDepTargets,
    283     Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage,
    284     bool AllowRSPrefix, bool OutputDep,
    285     unsigned int TargetAPI, bool EmitDebug,
    286     llvm::CodeGenOpt::Level OptimizationLevel,
    287     const std::string &JavaReflectionPathBase,
    288     const std::string &JavaReflectionPackageName,
    289     const std::string &RSPackageName) {
    290   if (IOFiles.empty())
    291     return true;
    292 
    293   if (OutputDep && (DepFiles.size() != IOFiles.size())) {
    294     getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter);
    295     return false;
    296   }
    297 
    298   std::string RealPackageName;
    299 
    300   const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile;
    301   std::list<std::pair<const char*, const char*> >::const_iterator
    302       IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin();
    303 
    304   setIncludePaths(IncludePaths);
    305   setOutputType(OutputType);
    306   if (OutputDep) {
    307     setAdditionalDepTargets(AdditionalDepTargets);
    308   }
    309 
    310   setDebugMetadataEmission(EmitDebug);
    311 
    312   setOptimizationLevel(OptimizationLevel);
    313 
    314   mAllowRSPrefix = AllowRSPrefix;
    315 
    316   mTargetAPI = TargetAPI;
    317   if (mTargetAPI < SLANG_MINIMUM_TARGET_API ||
    318       mTargetAPI > SLANG_MAXIMUM_TARGET_API) {
    319     getDiagnostics().Report(mDiagErrorTargetAPIRange) << mTargetAPI
    320         << SLANG_MINIMUM_TARGET_API << SLANG_MAXIMUM_TARGET_API;
    321     return false;
    322   }
    323 
    324   // Skip generation of warnings a second time if we are doing more than just
    325   // a single pass over the input file.
    326   bool SuppressAllWarnings = (OutputType != Slang::OT_Dependency);
    327 
    328   for (unsigned i = 0, e = IOFiles.size(); i != e; i++) {
    329     InputFile = IOFileIter->first;
    330     OutputFile = IOFileIter->second;
    331 
    332     reset();
    333 
    334     if (!setInputSource(InputFile))
    335       return false;
    336 
    337     if (!setOutput(OutputFile))
    338       return false;
    339 
    340     if (!JavaReflectionPackageName.empty()) {
    341       mRSContext->setReflectJavaPackageName(
    342           JavaReflectionPackageName);
    343     }
    344 
    345     mIsFilterscript = isFilterscript(InputFile);
    346 
    347     if (Slang::compile() > 0)
    348       return false;
    349 
    350     if (OutputType != Slang::OT_Dependency) {
    351 
    352       if (BitcodeStorage == BCST_CPP_CODE) {
    353           RSReflectionCpp R(mRSContext);
    354           bool ret = R.reflect(JavaReflectionPathBase, getInputFileName(), getOutputFileName());
    355           if (!ret) {
    356             return false;
    357           }
    358       } else {
    359 
    360         if (!reflectToJava(JavaReflectionPathBase,
    361                            JavaReflectionPackageName,
    362                            RSPackageName,
    363                            &RealPackageName)) {
    364           return false;
    365         }
    366 
    367         for (std::vector<std::string>::const_iterator
    368                  I = mGeneratedFileNames.begin(), E = mGeneratedFileNames.end();
    369              I != E;
    370              I++) {
    371           std::string ReflectedName = RSSlangReflectUtils::ComputePackagedPath(
    372               JavaReflectionPathBase.c_str(),
    373               (RealPackageName + OS_PATH_SEPARATOR_STR + *I).c_str());
    374           appendGeneratedFileName(ReflectedName + ".java");
    375         }
    376 
    377         if ((OutputType == Slang::OT_Bitcode) &&
    378             (BitcodeStorage == BCST_JAVA_CODE) &&
    379             !generateBitcodeAccessor(JavaReflectionPathBase,
    380                                      RealPackageName.c_str())) {
    381           return false;
    382         }
    383       }
    384     }
    385 
    386     if (OutputDep) {
    387       BCOutputFile = DepFileIter->first;
    388       DepOutputFile = DepFileIter->second;
    389 
    390       setDepTargetBC(BCOutputFile);
    391 
    392       if (!setDepOutput(DepOutputFile))
    393         return false;
    394 
    395       if (SuppressAllWarnings) {
    396         getDiagnostics().setSuppressAllDiagnostics(true);
    397       }
    398       if (generateDepFile() > 0)
    399         return false;
    400       if (SuppressAllWarnings) {
    401         getDiagnostics().setSuppressAllDiagnostics(false);
    402       }
    403 
    404       DepFileIter++;
    405     }
    406 
    407     if (!checkODR(InputFile))
    408       return false;
    409 
    410     IOFileIter++;
    411   }
    412 
    413   return true;
    414 }
    415 
    416 void SlangRS::reset() {
    417   delete mRSContext;
    418   mRSContext = NULL;
    419   mGeneratedFileNames.clear();
    420   Slang::reset();
    421   return;
    422 }
    423 
    424 SlangRS::~SlangRS() {
    425   delete mRSContext;
    426   for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(),
    427           E = ReflectedDefinitions.end();
    428        I != E;
    429        I++) {
    430     delete I->getValue().first;
    431   }
    432   return;
    433 }
    434 
    435 }  // namespace slang
    436