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