• 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/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 
openOutputFile(const char * OutputFile,unsigned Flags,std::string * Error,clang::Diagnostic * Diag)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 
LLVMErrorHandler(void * UserData,const std::string & Message)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 
createDiagnostic()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 
createTarget(const std::string & Triple,const std::string & CPU,const std::vector<std::string> & Features)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 
createFileManager()102 void Compiler::createFileManager() {
103   mFileSysOpt.reset(new clang::FileSystemOptions());
104   mFileMgr.reset(new clang::FileManager(*mFileSysOpt));
105 }
106 
createSourceManager()107 void Compiler::createSourceManager() {
108   mSourceMgr.reset(new clang::SourceManager(*mDiagnostics, *mFileMgr));
109   return;
110 }
111 
createPreprocessor()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 
createASTContext()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
createBackend(const clang::CodeGenOptions & CodeGenOpts,llvm::raw_ostream * OS,OutputType OT)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 
Compiler()163 Compiler::Compiler() : mInitialized(false), mpDiagClient(NULL), mOT(OT_Default) {
164 }
165 
injectPreDefined()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 
init(const std::string & Triple,const std::string & CPU,const std::vector<std::string> & Features,bool isCXX)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 
setInputSource(llvm::StringRef InputFile,const char * Text,size_t TextLength)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 
setInputSource(llvm::StringRef InputFile)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 
setOutput(const char * OutputFile)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 
compile()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 
reset()314 void Compiler::reset() {
315   mDiagnostics->Reset();
316   return;
317 }
318 
~Compiler()319 Compiler::~Compiler() {
320   llvm::llvm_shutdown();
321   return;
322 }
323 
324 }
325