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