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