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