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