• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
49 namespace ndkpc {
50 
openOutputFile(const char * OutputFile,unsigned Flags,std::string * Error,clang::DiagnosticsEngine * Diag)51 static 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 
LLVMErrorHandler(void * UserData,const std::string & Message)69 void 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 
createDiagnostic()75 void 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 
createTarget(const std::string & Triple,const std::string & CPU,const std::vector<std::string> & Features)84 void 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 
createFileManager()103 void Compiler::createFileManager() {
104   mFileSysOpt.reset(new clang::FileSystemOptions());
105   mFileMgr.reset(new clang::FileManager(*mFileSysOpt));
106 }
107 
createSourceManager()108 void Compiler::createSourceManager() {
109   mSourceMgr.reset(new clang::SourceManager(*mDiagnostics, *mFileMgr));
110   return;
111 }
112 
createPreprocessor()113 void 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 
createASTContext()148 void 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 
161 clang::ASTConsumer
createBackend(const clang::CodeGenOptions & CodeGenOpts,llvm::raw_ostream * OS,OutputType OT)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 
Compiler()172 Compiler::Compiler() : mInitialized(false), mpDiagClient(NULL), mOT(OT_Default) {
173 }
174 
injectPreDefined()175 void 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 
init(const std::string & Triple,const std::string & CPU,const std::vector<std::string> & Features,bool isCXX)185 void 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 
setInputSource(llvm::StringRef InputFile,const char * Text,size_t TextLength)207 bool 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 
setInputSource(llvm::StringRef InputFile)227 bool 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 
setOutput(const char * OutputFile)244 bool 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 
compile()282 int 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 
reset()322 void Compiler::reset() {
323   mDiagnostics->Reset();
324   return;
325 }
326 
~Compiler()327 Compiler::~Compiler() {
328   llvm::llvm_shutdown();
329   return;
330 }
331 
332 }
333