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