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