slang.cpp revision 3a9ca1f0d6bd8f12c2bb2adea51f95c255996180
1#include "slang.h"
2
3#include <stdlib.h>
4
5#include "llvm/Target/TargetSelect.h"
6
7#include "llvm/Support/raw_ostream.h"
8#include "llvm/Support/MemoryBuffer.h"
9#include "llvm/Support/ErrorHandling.h"
10#include "llvm/Support/ManagedStatic.h"
11
12#include "clang/Basic/LangOptions.h"
13#include "clang/Basic/SourceManager.h"
14#include "clang/Basic/TargetInfo.h"
15#include "clang/Basic/TargetOptions.h"
16
17#include "clang/Lex/Preprocessor.h"
18#include "clang/Lex/HeaderSearch.h"
19
20#include "clang/AST/ASTConsumer.h"
21#include "clang/AST/ASTContext.h"
22
23#include "clang/Basic/FileManager.h"
24
25#include "clang/Frontend/CodeGenOptions.h"
26#include "clang/Frontend/FrontendDiagnostic.h"
27
28#include "clang/Parse/ParseAST.h"
29
30#include "slang_backend.h"
31
32using namespace slang;
33
34#if defined(__arm__)
35#   define DEFAULT_TARGET_TRIPLE_STRING "armv7-none-linux-gnueabi"
36#elif defined(__x86_64__)
37#   define DEFAULT_TARGET_TRIPLE_STRING "x86_64-unknown-linux"
38#else
39// let's use x86 as default target
40#   define DEFAULT_TARGET_TRIPLE_STRING "i686-unknown-linux"
41#endif
42
43bool Slang::GlobalInitialized = false;
44
45// Language option (define the language feature for compiler such as C99)
46clang::LangOptions Slang::LangOpts;
47
48// Code generation option for the compiler
49clang::CodeGenOptions Slang::CodeGenOpts;
50
51const std::string Slang::TargetDescription =
52  "e-"  // little-endian
53  "p:32:32:32-"   // 32-bit pointer
54  "i1:8:8-"
55  "i8:8:8-"
56  "i16:16:16-"
57  "i32:32:32-"
58  "i64:64:64-"
59  "f32:32:32-"
60  "f64:64:64-"
61  "v64:64:64-"  // 64-bit vector (e.g. float2, int2, short4)
62  "v128:128:128-"
63  "a0:0:64-"
64  "n32";  // native CPU only support 32-bit integer width.
65
66// The named of metadata node that pragma resides (should be synced with
67// bcc.cpp)
68const llvm::StringRef Slang::PragmaMetadataName = "#pragma";
69
70void Slang::GlobalInitialization() {
71  if (!GlobalInitialized) {
72    // We only support x86, x64 and ARM target
73
74    // For ARM
75    LLVMInitializeARMTargetInfo();
76    LLVMInitializeARMTarget();
77    LLVMInitializeARMAsmPrinter();
78
79    // For x86 and x64
80    LLVMInitializeX86TargetInfo();
81    LLVMInitializeX86Target();
82    LLVMInitializeX86AsmPrinter();
83
84    // Please refer to include/clang/Basic/LangOptions.h to setup
85    // the options.
86    LangOpts.RTTI = 0;  // Turn off the RTTI information support
87    LangOpts.NeXTRuntime = 0;   // Turn off the NeXT runtime uses
88    LangOpts.Bool = 1;  // Turn on 'bool', 'true', 'false' keywords
89
90    CodeGenOpts.OptimizationLevel = 3;  /* -O3 */
91
92    GlobalInitialized = true;
93  }
94
95  return;
96}
97
98void Slang::LLVMErrorHandler(void *UserData, const std::string &Message) {
99  clang::Diagnostic* Diags = static_cast<clang::Diagnostic*>(UserData);
100  Diags->Report(clang::diag::err_fe_error_backend) << Message;
101  exit(1);
102}
103
104void Slang::createDiagnostic() {
105  mDiagnostics =
106      llvm::IntrusiveRefCntPtr<clang::Diagnostic>(new clang::Diagnostic());
107  mDiagClient = new DiagnosticBuffer();
108  // This takes the ownership of mDiagClient.
109  mDiagnostics->setClient(mDiagClient);
110  return;
111}
112
113void Slang::createTarget(const char* Triple, const char* CPU,
114                         const char** Features) {
115  if (Triple != NULL)
116    mTargetOpts.Triple = Triple;
117  else
118    mTargetOpts.Triple = DEFAULT_TARGET_TRIPLE_STRING;
119
120  if (CPU != NULL)
121    mTargetOpts.CPU = CPU;
122
123  mTarget.reset(clang::TargetInfo::CreateTargetInfo(*mDiagnostics,
124                                                    mTargetOpts));
125
126  if (Features != NULL)
127    for (int i = 0; Features[i] != NULL; i++)
128      mTargetOpts.Features.push_back(Features[i]);
129
130    return;
131}
132
133void Slang::createFileManager() {
134  mFileMgr.reset(new clang::FileManager());
135}
136
137void Slang::createSourceManager() {
138  mSourceMgr.reset(new clang::SourceManager(*mDiagnostics));
139  return;
140}
141
142void Slang::createPreprocessor() {
143  // Default only search header file in current dir
144  clang::HeaderSearch *HS = new clang::HeaderSearch(*mFileMgr);
145
146  mPP.reset(new clang::Preprocessor(*mDiagnostics,
147                                    LangOpts,
148                                    *mTarget,
149                                    *mSourceMgr,
150                                    *HS,
151                                    NULL,
152                                    /* OwnsHeaderSearch = */true));
153  // Initialize the prepocessor
154  mPragmas.clear();
155  mPP->AddPragmaHandler(new PragmaRecorder(mPragmas));
156
157  std::vector<clang::DirectoryLookup> SearchList;
158  for (unsigned i = 0, e = mIncludePaths.size(); i != e; i++) {
159    if (const clang::DirectoryEntry *DE =
160            mFileMgr->getDirectory(mIncludePaths[i])) {
161      SearchList.push_back(clang::DirectoryLookup(DE,
162                                                  clang::SrcMgr::C_System,
163                                                  false,
164                                                  false));
165    }
166  }
167
168  HS->SetSearchPaths(SearchList, 1, false);
169
170  initPreprocessor();
171  return;
172}
173
174void Slang::createASTContext() {
175  mASTContext.reset(new clang::ASTContext(LangOpts,
176                                          *mSourceMgr,
177                                          *mTarget,
178                                          mPP->getIdentifierTable(),
179                                          mPP->getSelectorTable(),
180                                          mPP->getBuiltinInfo(),
181                                          /* size_reserve = */0));
182  initASTContext();
183  return;
184}
185
186clang::ASTConsumer
187*Slang::createBackend(const clang::CodeGenOptions& CodeGenOpts,
188                      llvm::raw_ostream *OS,
189                      OutputType OT) {
190  return new Backend(*mDiagnostics,
191                     CodeGenOpts,
192                     mTargetOpts,
193                     mPragmas,
194                     OS,
195                     OT);
196}
197
198Slang::Slang(const char *Triple, const char *CPU, const char **Features)
199    : mDiagClient(NULL),
200      mOT(OT_Default) {
201  GlobalInitialization();
202
203  createDiagnostic();
204  llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagnostics.getPtr());
205
206  createTarget(Triple, CPU, Features);
207  createFileManager();
208  createSourceManager();
209
210  return;
211}
212
213bool Slang::setInputSource(llvm::StringRef InputFile,
214                           const char *Text,
215                           size_t TextLength) {
216  mInputFileName = InputFile.str();
217
218  // Reset the ID tables if we are reusing the SourceManager
219  mSourceMgr->clearIDTables();
220
221  // Load the source
222  llvm::MemoryBuffer *SB =
223      llvm::MemoryBuffer::getMemBuffer(Text, Text + TextLength);
224  mSourceMgr->createMainFileIDForMemBuffer(SB);
225
226  if (mSourceMgr->getMainFileID().isInvalid()) {
227    mDiagnostics->Report(clang::diag::err_fe_error_reading) << InputFile;
228    return false;
229  }
230  return true;
231}
232
233bool Slang::setInputSource(llvm::StringRef InputFile) {
234  mInputFileName = InputFile.str();
235
236  mSourceMgr->clearIDTables();
237
238  const clang::FileEntry *File = mFileMgr->getFile(InputFile);
239  if (File)
240    mSourceMgr->createMainFileID(File);
241
242  if (mSourceMgr->getMainFileID().isInvalid()) {
243    mDiagnostics->Report(clang::diag::err_fe_error_reading) << InputFile;
244    return false;
245  }
246
247  return true;
248}
249
250static void _mkdir_given_a_file(const char *file) {
251  char buf[256];
252  char *tmp, *p = NULL;
253  size_t len = strlen(file);
254
255  if (len + 1 <= sizeof(buf))
256    tmp = buf;
257  else
258    tmp = new char[len + 1];
259
260  strcpy(tmp, file);
261
262  if (tmp[len - 1] == '/')
263    tmp[len - 1] = 0;
264
265  for (p = tmp + 1; *p; p++) {
266    if (*p == '/') {
267      *p = 0;
268      mkdir(tmp, S_IRWXU);
269      *p = '/';
270    }
271  }
272
273  if (tmp != buf)
274    delete[] tmp;
275}
276
277bool Slang::setOutput(const char *OutputFile) {
278  std::string Error;
279
280  _mkdir_given_a_file(OutputFile);
281
282  switch (mOT) {
283    case OT_Assembly:
284    case OT_LLVMAssembly: {
285      mOS.reset(new llvm::raw_fd_ostream(OutputFile, Error, 0));
286      break;
287    }
288    case OT_Nothing: {
289      mOS.reset();
290      break;
291    }
292    case OT_Object:
293    case OT_Bitcode:
294    default: {
295      mOS.reset(new llvm::raw_fd_ostream(OutputFile,
296                                         Error,
297                                         llvm::raw_fd_ostream::F_Binary));
298      break;
299    }
300  }
301
302  if (!Error.empty()) {
303    mOS.reset();
304    mDiagnostics->Report(clang::diag::err_fe_error_opening) << OutputFile
305                                                            << Error;
306    return false;
307  }
308
309  mOutputFileName = OutputFile;
310
311  return true;
312}
313
314int Slang::compile() {
315  if ((mDiagnostics->getNumErrors() > 0) || (mOS.get() == NULL))
316    return mDiagnostics->getNumErrors();
317
318  // Here is per-compilation needed initialization
319  createPreprocessor();
320  createASTContext();
321
322  mBackend.reset(createBackend(CodeGenOpts, mOS.take(), mOT));
323
324  // Inform the diagnostic client we are processing a source file
325  mDiagClient->BeginSourceFile(LangOpts, mPP.get());
326
327  // The core of the slang compiler
328  ParseAST(*mPP, mBackend.get(), *mASTContext);
329
330  // The compilation ended, clear
331  mBackend.reset();
332  mASTContext.reset();
333  mPP.reset();
334
335  // Inform the diagnostic client we are done with previous source file
336  mDiagClient->EndSourceFile();
337
338  return mDiagnostics->getNumErrors();
339}
340
341void Slang::reset() {
342  mDiagnostics->Reset();
343  mDiagClient->reset();
344  return;
345}
346
347Slang::~Slang() {
348  llvm::llvm_shutdown();
349  return;
350}
351