1 /* 2 * Copyright 2010, 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.h" 18 19 #include <stdlib.h> 20 21 #include <string> 22 #include <vector> 23 24 #include "clang/AST/ASTConsumer.h" 25 #include "clang/AST/ASTContext.h" 26 27 #include "clang/Basic/DiagnosticIDs.h" 28 #include "clang/Basic/DiagnosticOptions.h" 29 #include "clang/Basic/FileManager.h" 30 #include "clang/Basic/FileSystemOptions.h" 31 #include "clang/Basic/LangOptions.h" 32 #include "clang/Basic/SourceManager.h" 33 #include "clang/Basic/TargetInfo.h" 34 #include "clang/Basic/TargetOptions.h" 35 36 #include "clang/Frontend/CodeGenOptions.h" 37 #include "clang/Frontend/DependencyOutputOptions.h" 38 #include "clang/Frontend/FrontendDiagnostic.h" 39 #include "clang/Frontend/FrontendOptions.h" 40 #include "clang/Frontend/TextDiagnosticPrinter.h" 41 #include "clang/Frontend/Utils.h" 42 43 #include "clang/Lex/Preprocessor.h" 44 #include "clang/Lex/PreprocessorOptions.h" 45 #include "clang/Lex/HeaderSearch.h" 46 #include "clang/Lex/HeaderSearchOptions.h" 47 48 #include "clang/Parse/ParseAST.h" 49 50 #include "llvm/ADT/IntrusiveRefCntPtr.h" 51 52 #include "llvm/Bitcode/ReaderWriter.h" 53 54 // More force linking 55 #include "llvm/Linker/Linker.h" 56 57 // Force linking all passes/vmcore stuffs to libslang.so 58 #include "llvm/LinkAllIR.h" 59 #include "llvm/LinkAllPasses.h" 60 61 #include "llvm/Support/raw_ostream.h" 62 #include "llvm/Support/MemoryBuffer.h" 63 #include "llvm/Support/ErrorHandling.h" 64 #include "llvm/Support/ManagedStatic.h" 65 #include "llvm/Support/Path.h" 66 #include "llvm/Support/TargetSelect.h" 67 #include "llvm/Support/ToolOutputFile.h" 68 69 #include "slang_assert.h" 70 #include "slang_backend.h" 71 #include "slang_utils.h" 72 73 namespace { 74 75 static const char *kRSTriple32 = "armv7-none-linux-gnueabi"; 76 static const char *kRSTriple64 = "aarch64-none-linux-gnueabi"; 77 78 struct ForceSlangLinking { 79 ForceSlangLinking() { 80 // We must reference the functions in such a way that compilers will not 81 // delete it all as dead code, even with whole program optimization, 82 // yet is effectively a NO-OP. As the compiler isn't smart enough 83 // to know that getenv() never returns -1, this will do the job. 84 if (std::getenv("bar") != reinterpret_cast<char*>(-1)) 85 return; 86 87 // llvm-rs-link needs following functions existing in libslang. 88 llvm::parseBitcodeFile(NULL, llvm::getGlobalContext()); 89 llvm::Linker::LinkModules(NULL, NULL, 0, NULL); 90 91 // llvm-rs-cc need this. 92 new clang::TextDiagnosticPrinter(llvm::errs(), 93 new clang::DiagnosticOptions()); 94 } 95 } ForceSlangLinking; 96 97 } // namespace 98 99 namespace slang { 100 101 bool Slang::GlobalInitialized = false; 102 103 // Language option (define the language feature for compiler such as C99) 104 clang::LangOptions Slang::LangOpts; 105 106 // Code generation option for the compiler 107 clang::CodeGenOptions Slang::CodeGenOpts; 108 109 // The named of metadata node that pragma resides (should be synced with 110 // bcc.cpp) 111 const llvm::StringRef Slang::PragmaMetadataName = "#pragma"; 112 113 static inline llvm::tool_output_file * 114 OpenOutputFile(const char *OutputFile, 115 llvm::sys::fs::OpenFlags Flags, 116 std::string* Error, 117 clang::DiagnosticsEngine *DiagEngine) { 118 slangAssert((OutputFile != NULL) && (Error != NULL) && 119 (DiagEngine != NULL) && "Invalid parameter!"); 120 121 if (SlangUtils::CreateDirectoryWithParents( 122 llvm::sys::path::parent_path(OutputFile), Error)) { 123 llvm::tool_output_file *F = 124 new llvm::tool_output_file(OutputFile, *Error, Flags); 125 if (F != NULL) 126 return F; 127 } 128 129 // Report error here. 130 DiagEngine->Report(clang::diag::err_fe_error_opening) 131 << OutputFile << *Error; 132 133 return NULL; 134 } 135 136 void Slang::GlobalInitialization() { 137 if (!GlobalInitialized) { 138 // We only support x86, x64 and ARM target 139 140 // For ARM 141 LLVMInitializeARMTargetInfo(); 142 LLVMInitializeARMTarget(); 143 LLVMInitializeARMAsmPrinter(); 144 145 // For x86 and x64 146 LLVMInitializeX86TargetInfo(); 147 LLVMInitializeX86Target(); 148 LLVMInitializeX86AsmPrinter(); 149 150 // Please refer to include/clang/Basic/LangOptions.h to setup 151 // the options. 152 LangOpts.RTTI = 0; // Turn off the RTTI information support 153 LangOpts.C99 = 1; 154 LangOpts.Renderscript = 1; 155 LangOpts.LaxVectorConversions = 0; // Do not bitcast vectors! 156 LangOpts.CharIsSigned = 1; // Signed char is our default. 157 158 CodeGenOpts.OptimizationLevel = 3; 159 160 GlobalInitialized = true; 161 } 162 } 163 164 void Slang::LLVMErrorHandler(void *UserData, const std::string &Message, 165 bool GenCrashDialog) { 166 clang::DiagnosticsEngine* DiagEngine = 167 static_cast<clang::DiagnosticsEngine *>(UserData); 168 169 DiagEngine->Report(clang::diag::err_fe_error_backend) << Message; 170 exit(1); 171 } 172 173 void Slang::createTarget(uint32_t BitWidth) { 174 std::vector<std::string> features; 175 176 if (BitWidth == 64) { 177 mTargetOpts->Triple = kRSTriple64; 178 } else { 179 mTargetOpts->Triple = kRSTriple32; 180 // Treat long as a 64-bit type for our 32-bit RS code. 181 features.push_back("+long64"); 182 mTargetOpts->FeaturesAsWritten = features; 183 } 184 185 mTarget.reset(clang::TargetInfo::CreateTargetInfo(*mDiagEngine, 186 mTargetOpts)); 187 } 188 189 void Slang::createFileManager() { 190 mFileSysOpt.reset(new clang::FileSystemOptions()); 191 mFileMgr.reset(new clang::FileManager(*mFileSysOpt)); 192 } 193 194 void Slang::createSourceManager() { 195 mSourceMgr.reset(new clang::SourceManager(*mDiagEngine, *mFileMgr)); 196 } 197 198 void Slang::createPreprocessor() { 199 // Default only search header file in current dir 200 llvm::IntrusiveRefCntPtr<clang::HeaderSearchOptions> HSOpts = 201 new clang::HeaderSearchOptions(); 202 clang::HeaderSearch *HeaderInfo = new clang::HeaderSearch(HSOpts, 203 *mSourceMgr, 204 *mDiagEngine, 205 LangOpts, 206 mTarget.get()); 207 208 llvm::IntrusiveRefCntPtr<clang::PreprocessorOptions> PPOpts = 209 new clang::PreprocessorOptions(); 210 mPP.reset(new clang::Preprocessor(PPOpts, 211 *mDiagEngine, 212 LangOpts, 213 *mSourceMgr, 214 *HeaderInfo, 215 *this, 216 NULL, 217 /* OwnsHeaderSearch = */true)); 218 // Initialize the preprocessor 219 mPP->Initialize(getTargetInfo()); 220 clang::FrontendOptions FEOpts; 221 clang::InitializePreprocessor(*mPP, *PPOpts, FEOpts); 222 223 mPragmas.clear(); 224 mPP->AddPragmaHandler(new PragmaRecorder(&mPragmas)); 225 226 std::vector<clang::DirectoryLookup> SearchList; 227 for (unsigned i = 0, e = mIncludePaths.size(); i != e; i++) { 228 if (const clang::DirectoryEntry *DE = 229 mFileMgr->getDirectory(mIncludePaths[i])) { 230 SearchList.push_back(clang::DirectoryLookup(DE, 231 clang::SrcMgr::C_System, 232 false)); 233 } 234 } 235 236 HeaderInfo->SetSearchPaths(SearchList, 237 /* angledDirIdx = */1, 238 /* systemDixIdx = */1, 239 /* noCurDirSearch = */false); 240 241 initPreprocessor(); 242 } 243 244 void Slang::createASTContext() { 245 mASTContext.reset(new clang::ASTContext(LangOpts, 246 *mSourceMgr, 247 mPP->getIdentifierTable(), 248 mPP->getSelectorTable(), 249 mPP->getBuiltinInfo())); 250 mASTContext->InitBuiltinTypes(getTargetInfo()); 251 initASTContext(); 252 } 253 254 clang::ASTConsumer * 255 Slang::createBackend(const clang::CodeGenOptions& CodeGenOpts, 256 llvm::raw_ostream *OS, OutputType OT) { 257 return new Backend(mDiagEngine, CodeGenOpts, getTargetOptions(), 258 &mPragmas, OS, OT); 259 } 260 261 Slang::Slang() : mInitialized(false), mDiagClient(NULL), 262 mTargetOpts(new clang::TargetOptions()), mOT(OT_Default) { 263 GlobalInitialization(); 264 } 265 266 void Slang::init(uint32_t BitWidth, clang::DiagnosticsEngine *DiagEngine, 267 DiagnosticBuffer *DiagClient) { 268 if (mInitialized) 269 return; 270 271 mDiagEngine = DiagEngine; 272 mDiagClient = DiagClient; 273 mDiag.reset(new clang::Diagnostic(mDiagEngine)); 274 initDiagnostic(); 275 llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagEngine); 276 277 createTarget(BitWidth); 278 createFileManager(); 279 createSourceManager(); 280 281 mInitialized = true; 282 } 283 284 clang::ModuleLoadResult Slang::loadModule( 285 clang::SourceLocation ImportLoc, 286 clang::ModuleIdPath Path, 287 clang::Module::NameVisibilityKind Visibility, 288 bool IsInclusionDirective) { 289 slangAssert(0 && "Not implemented"); 290 return clang::ModuleLoadResult(); 291 } 292 293 bool Slang::setInputSource(llvm::StringRef InputFile, 294 const char *Text, 295 size_t TextLength) { 296 mInputFileName = InputFile.str(); 297 298 // Reset the ID tables if we are reusing the SourceManager 299 mSourceMgr->clearIDTables(); 300 301 // Load the source 302 llvm::MemoryBuffer *SB = 303 llvm::MemoryBuffer::getMemBuffer(Text, Text + TextLength); 304 mSourceMgr->setMainFileID(mSourceMgr->createFileID(SB)); 305 306 if (mSourceMgr->getMainFileID().isInvalid()) { 307 mDiagEngine->Report(clang::diag::err_fe_error_reading) << InputFile; 308 return false; 309 } 310 return true; 311 } 312 313 bool Slang::setInputSource(llvm::StringRef InputFile) { 314 mInputFileName = InputFile.str(); 315 316 mSourceMgr->clearIDTables(); 317 318 const clang::FileEntry *File = mFileMgr->getFile(InputFile); 319 if (File) { 320 mSourceMgr->setMainFileID(mSourceMgr->createFileID(File, 321 clang::SourceLocation(), clang::SrcMgr::C_User)); 322 } 323 324 if (mSourceMgr->getMainFileID().isInvalid()) { 325 mDiagEngine->Report(clang::diag::err_fe_error_reading) << InputFile; 326 return false; 327 } 328 329 return true; 330 } 331 332 bool Slang::setOutput(const char *OutputFile) { 333 std::string Error; 334 llvm::tool_output_file *OS = NULL; 335 336 switch (mOT) { 337 case OT_Dependency: 338 case OT_Assembly: 339 case OT_LLVMAssembly: { 340 OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_Text, &Error, 341 mDiagEngine); 342 break; 343 } 344 case OT_Nothing: { 345 break; 346 } 347 case OT_Object: 348 case OT_Bitcode: { 349 OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_None, 350 &Error, mDiagEngine); 351 break; 352 } 353 default: { 354 llvm_unreachable("Unknown compiler output type"); 355 } 356 } 357 358 if (!Error.empty()) 359 return false; 360 361 mOS.reset(OS); 362 363 mOutputFileName = OutputFile; 364 365 return true; 366 } 367 368 bool Slang::setDepOutput(const char *OutputFile) { 369 std::string Error; 370 371 mDOS.reset( 372 OpenOutputFile(OutputFile, llvm::sys::fs::F_Text, &Error, mDiagEngine)); 373 if (!Error.empty() || (mDOS.get() == NULL)) 374 return false; 375 376 mDepOutputFileName = OutputFile; 377 378 return true; 379 } 380 381 int Slang::generateDepFile() { 382 if (mDiagEngine->hasErrorOccurred()) 383 return 1; 384 if (mDOS.get() == NULL) 385 return 1; 386 387 // Initialize options for generating dependency file 388 clang::DependencyOutputOptions DepOpts; 389 DepOpts.IncludeSystemHeaders = 1; 390 DepOpts.OutputFile = mDepOutputFileName; 391 DepOpts.Targets = mAdditionalDepTargets; 392 DepOpts.Targets.push_back(mDepTargetBCFileName); 393 for (std::vector<std::string>::const_iterator 394 I = mGeneratedFileNames.begin(), E = mGeneratedFileNames.end(); 395 I != E; 396 I++) { 397 DepOpts.Targets.push_back(*I); 398 } 399 mGeneratedFileNames.clear(); 400 401 // Per-compilation needed initialization 402 createPreprocessor(); 403 clang::DependencyFileGenerator::CreateAndAttachToPreprocessor(*mPP.get(), DepOpts); 404 405 // Inform the diagnostic client we are processing a source file 406 mDiagClient->BeginSourceFile(LangOpts, mPP.get()); 407 408 // Go through the source file (no operations necessary) 409 clang::Token Tok; 410 mPP->EnterMainSourceFile(); 411 do { 412 mPP->Lex(Tok); 413 } while (Tok.isNot(clang::tok::eof)); 414 415 mPP->EndSourceFile(); 416 417 // Declare success if no error 418 if (!mDiagEngine->hasErrorOccurred()) 419 mDOS->keep(); 420 421 // Clean up after compilation 422 mPP.reset(); 423 mDOS.reset(); 424 425 return mDiagEngine->hasErrorOccurred() ? 1 : 0; 426 } 427 428 int Slang::compile() { 429 if (mDiagEngine->hasErrorOccurred()) 430 return 1; 431 if (mOS.get() == NULL) 432 return 1; 433 434 // Here is per-compilation needed initialization 435 createPreprocessor(); 436 createASTContext(); 437 438 mBackend.reset(createBackend(CodeGenOpts, &mOS->os(), mOT)); 439 440 // Inform the diagnostic client we are processing a source file 441 mDiagClient->BeginSourceFile(LangOpts, mPP.get()); 442 443 // The core of the slang compiler 444 ParseAST(*mPP, mBackend.get(), *mASTContext); 445 446 // Inform the diagnostic client we are done with previous source file 447 mDiagClient->EndSourceFile(); 448 449 // Declare success if no error 450 if (!mDiagEngine->hasErrorOccurred()) 451 mOS->keep(); 452 453 // The compilation ended, clear 454 mBackend.reset(); 455 mASTContext.reset(); 456 mPP.reset(); 457 mOS.reset(); 458 459 return mDiagEngine->hasErrorOccurred() ? 1 : 0; 460 } 461 462 void Slang::setDebugMetadataEmission(bool EmitDebug) { 463 if (EmitDebug) 464 CodeGenOpts.setDebugInfo(clang::CodeGenOptions::FullDebugInfo); 465 else 466 CodeGenOpts.setDebugInfo(clang::CodeGenOptions::NoDebugInfo); 467 } 468 469 void Slang::setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel) { 470 CodeGenOpts.OptimizationLevel = OptimizationLevel; 471 } 472 473 void Slang::reset(bool SuppressWarnings) { 474 // Always print diagnostics if we had an error occur, but don't print 475 // warnings if we suppressed them (i.e. we are doing the 64-bit compile after 476 // an existing 32-bit compile). 477 // 478 // TODO: This should really be removing duplicate identical warnings between 479 // the 32-bit and 64-bit compiles, but that is a more substantial feature. 480 // Bug: 17052573 481 if (!SuppressWarnings || mDiagEngine->hasErrorOccurred()) { 482 llvm::errs() << mDiagClient->str(); 483 } 484 mDiagEngine->Reset(); 485 mDiagClient->reset(); 486 } 487 488 Slang::~Slang() { 489 } 490 491 } // namespace slang 492