1 #include "Compiler.h" 2 3 #include <cassert> 4 #include <cstdlib> 5 #include <string> 6 #include <vector> 7 8 #include "clang/AST/ASTConsumer.h" 9 #include "clang/AST/ASTContext.h" 10 11 #include "clang/Basic/DiagnosticIDs.h" 12 #include "clang/Basic/FileManager.h" 13 #include "clang/Basic/FileSystemOptions.h" 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/CodeGenOptions.h" 20 #include "clang/Frontend/DiagnosticOptions.h" 21 #include "clang/Frontend/DependencyOutputOptions.h" 22 #include "clang/Frontend/FrontendDiagnostic.h" 23 #include "clang/Frontend/TextDiagnosticPrinter.h" 24 #include "clang/Frontend/Utils.h" 25 26 #include "clang/Lex/Preprocessor.h" 27 #include "clang/Lex/HeaderSearch.h" 28 29 #include "clang/Parse/ParseAST.h" 30 31 #include "llvm/LLVMContext.h" 32 33 #include "llvm/ADT/IntrusiveRefCntPtr.h" 34 35 #include "llvm/Bitcode/ReaderWriter.h" 36 37 #include "llvm/Support/raw_ostream.h" 38 #include "llvm/Support/MemoryBuffer.h" 39 #include "llvm/Support/ErrorHandling.h" 40 #include "llvm/Support/ManagedStatic.h" 41 #include "llvm/Support/ToolOutputFile.h" 42 #include "llvm/Support/Path.h" 43 44 #include "llvm/Target/TargetSelect.h" 45 46 #include "Backend.h" 47 48 namespace ndkpc { 49 50 static inline llvm::tool_output_file *openOutputFile(const char *OutputFile, 51 unsigned Flags, 52 std::string* Error, 53 clang::Diagnostic* Diag) { 54 assert((OutputFile != NULL) && (Error != NULL) && (Diag != NULL) && 55 "Invalid parameter!"); 56 57 llvm::tool_output_file *F = 58 new llvm::tool_output_file(OutputFile, *Error, Flags); 59 if (F != NULL) 60 return F; 61 62 // Report error here. 63 Diag->Report(clang::diag::err_fe_error_opening) << OutputFile << *Error; 64 65 return NULL; 66 } 67 68 void Compiler::LLVMErrorHandler(void *UserData, const std::string &Message) { 69 clang::Diagnostic* Diags = static_cast<clang::Diagnostic*>(UserData); 70 Diags->Report(clang::diag::err_fe_error_backend) << Message; 71 exit(1); 72 } 73 74 void Compiler::createDiagnostic() { 75 mpDiagClient = new clang::TextDiagnosticPrinter(llvm::errs(), 76 clang::DiagnosticOptions()); 77 mDiagIDs = new clang::DiagnosticIDs(); 78 mDiagnostics = new clang::Diagnostic(mDiagIDs, mpDiagClient, true); 79 initDiagnostic(); 80 return; 81 } 82 83 void Compiler::createTarget(const std::string &Triple, const std::string &CPU, 84 const std::vector<std::string> &Features) { 85 if (!Triple.empty()) 86 mTargetOpts.Triple = Triple; 87 else 88 mTargetOpts.Triple = llvm::Triple::normalize(DEFAULT_TARGET_TRIPLE_STRING); 89 90 if (!CPU.empty()) 91 mTargetOpts.CPU = CPU; 92 93 if (!Features.empty()) 94 mTargetOpts.Features = Features; 95 96 mTarget.reset(clang::TargetInfo::CreateTargetInfo(*mDiagnostics, 97 mTargetOpts)); 98 99 return; 100 } 101 102 void Compiler::createFileManager() { 103 mFileSysOpt.reset(new clang::FileSystemOptions()); 104 mFileMgr.reset(new clang::FileManager(*mFileSysOpt)); 105 } 106 107 void Compiler::createSourceManager() { 108 mSourceMgr.reset(new clang::SourceManager(*mDiagnostics, *mFileMgr)); 109 return; 110 } 111 112 void Compiler::createPreprocessor() { 113 clang::HeaderSearch *HS = new clang::HeaderSearch(*mFileMgr); 114 115 mPP.reset(new clang::Preprocessor(*mDiagnostics, 116 mLangOpts, 117 *mTarget, 118 *mSourceMgr, 119 *HS, 120 NULL, /* IILookup */ 121 /* OwnsHeaderSearch = */true)); 122 123 std::vector<clang::DirectoryLookup> SearchList; 124 for (unsigned i = 0, e = mIncludePaths.size(); i != e; i++) { 125 if (const clang::DirectoryEntry *DE = 126 mFileMgr->getDirectory(mIncludePaths[i])) { 127 SearchList.push_back(clang::DirectoryLookup(DE, 128 clang::SrcMgr::C_System, 129 false, /* isUser */ 130 false /* isFramework */)); 131 } 132 } 133 134 HS->SetSearchPaths(SearchList, 0/* angledDirIdx FIXME CHECK */, 0/* systemDirIdx */, false/* noCurDirSearch */); 135 136 initPreprocessor(); 137 return; 138 } 139 140 void Compiler::createASTContext() { 141 mASTContext.reset(new clang::ASTContext(mLangOpts, 142 *mSourceMgr, 143 *mTarget, 144 mPP->getIdentifierTable(), 145 mPP->getSelectorTable(), 146 mPP->getBuiltinInfo(), 147 /* size_reserve = */0)); 148 initASTContext(); 149 return; 150 } 151 152 clang::ASTConsumer 153 *Compiler::createBackend(const clang::CodeGenOptions& CodeGenOpts, 154 llvm::raw_ostream *OS, 155 OutputType OT) { 156 return new Backend(CodeGenOpts, 157 mTargetOpts, 158 mDiagnostics.getPtr(), 159 OS, 160 OT); 161 } 162 163 Compiler::Compiler() : mInitialized(false), mpDiagClient(NULL), mOT(OT_Default) { 164 } 165 166 void Compiler::injectPreDefined() { 167 typedef std::map<std::string, std::string> SymbolMapTy; 168 for (SymbolMapTy::iterator 169 it = mPreDefinedSymbolMap.begin(), et = mPreDefinedSymbolMap.end(); 170 it != et; ++it) { 171 std::string Str = "#define "+it->first+" "+it->second+"\n"; 172 mPP->setPredefines(Str); 173 } 174 } 175 176 void Compiler::init(const std::string &Triple, const std::string &CPU, 177 const std::vector<std::string> &Features, bool isCXX) { 178 mLangOpts.RTTI = 0; // Turn off the RTTI information support 179 mLangOpts.NeXTRuntime = 0; // Turn off the NeXT runtime uses 180 mLangOpts.C99 = 1; 181 if (isCXX) { 182 mLangOpts.CPlusPlus = 1; 183 } 184 185 mCodeGenOpts.OptimizationLevel = 3; /* -O3 */ 186 187 createDiagnostic(); 188 llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagnostics.getPtr()); 189 190 createTarget(Triple, CPU, Features); 191 createFileManager(); 192 createSourceManager(); 193 194 mInitialized = true; 195 196 return; 197 } 198 199 bool Compiler::setInputSource(llvm::StringRef InputFile, 200 const char *Text, 201 size_t TextLength) { 202 mInputFileName = InputFile.str(); 203 204 // Reset the ID tables if we are reusing the SourceManager 205 mSourceMgr->clearIDTables(); 206 207 // Load the source 208 llvm::MemoryBuffer *SB = 209 llvm::MemoryBuffer::getMemBuffer(Text, Text + TextLength); 210 mSourceMgr->createMainFileIDForMemBuffer(SB); 211 212 if (mSourceMgr->getMainFileID().isInvalid()) { 213 mDiagnostics->Report(clang::diag::err_fe_error_reading) << InputFile; 214 return false; 215 } 216 return true; 217 } 218 219 bool Compiler::setInputSource(llvm::StringRef InputFile) { 220 mInputFileName = InputFile.str(); 221 222 mSourceMgr->clearIDTables(); 223 224 const clang::FileEntry *File = mFileMgr->getFile(InputFile); 225 if (File) 226 mSourceMgr->createMainFileID(File); 227 228 if (mSourceMgr->getMainFileID().isInvalid()) { 229 mDiagnostics->Report(clang::diag::err_fe_error_reading) << InputFile; 230 return false; 231 } 232 233 return true; 234 } 235 236 bool Compiler::setOutput(const char *OutputFile) { 237 llvm::sys::Path OutputFilePath(OutputFile); 238 std::string Error; 239 llvm::tool_output_file *OS = NULL; 240 241 switch (mOT) { 242 case OT_Dependency: 243 case OT_Assembly: 244 case OT_LLVMAssembly: { 245 OS = openOutputFile(OutputFile, 0, &Error, mDiagnostics.getPtr()); 246 break; 247 } 248 case OT_Nothing: { 249 break; 250 } 251 case OT_Object: 252 case OT_Bitcode: { 253 OS = openOutputFile(OutputFile, 254 llvm::raw_fd_ostream::F_Binary, 255 &Error, 256 mDiagnostics.getPtr()); 257 break; 258 } 259 default: { 260 llvm_unreachable("Unknown compiler output type"); 261 } 262 } 263 264 if (!Error.empty()) 265 return false; 266 267 mOS.reset(OS); 268 269 mOutputFileName = OutputFile; 270 271 return true; 272 } 273 274 int Compiler::compile() { 275 if (mDiagnostics->hasErrorOccurred()) 276 return 1; 277 if (mOS.get() == NULL) 278 return 1; 279 280 // Here is per-compilation needed initialization 281 createPreprocessor(); 282 createASTContext(); 283 284 mBackend.reset(createBackend(mCodeGenOpts, &mOS->os(), mOT)); 285 286 // Inform the diagnostic client we are processing a source file 287 mpDiagClient->BeginSourceFile(mLangOpts, mPP.get()); 288 289 if (mLangOpts.CPlusPlus == 1) { 290 mPP->setPredefines("#define __cplusplus\n"); 291 } 292 293 this->injectPreDefined(); 294 295 // The core of the slang compiler 296 ParseAST(*mPP, mBackend.get(), *mASTContext); 297 298 // Inform the diagnostic client we are done with previous source file 299 mpDiagClient->EndSourceFile(); 300 301 // Declare success if no error 302 if (!mDiagnostics->hasErrorOccurred()) 303 mOS->keep(); 304 305 // The compilation ended, clear 306 mBackend.reset(); 307 mASTContext.reset(); 308 mPP.reset(); 309 mOS.reset(); 310 311 return mDiagnostics->hasErrorOccurred() ? 1 : 0; 312 } 313 314 void Compiler::reset() { 315 mDiagnostics->Reset(); 316 return; 317 } 318 319 Compiler::~Compiler() { 320 llvm::llvm_shutdown(); 321 return; 322 } 323 324 } 325