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