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