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