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