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