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