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