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