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