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