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