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