slang.cpp revision 6de89272b00a31f2a73e2f56edf9cc511df46265
1#include "slang.hpp"
2#include "libslang.h"
3
4#include "llvm/ADT/Twine.h"     /* for class llvm::Twine */
5
6#include "llvm/Target/TargetSelect.h"       /* for function LLVMInitialize[ARM|X86][TargetInfo|Target|AsmPrinter]() */
7
8#include "llvm/Support/MemoryBuffer.h"      /* for class llvm::MemoryBuffer */
9#include "llvm/Support/ErrorHandling.h"     /* for function llvm::install_fatal_error_handler() */
10#include "llvm/Support/ManagedStatic.h"     /* for class llvm::llvm_shutdown */
11
12#include "clang/Basic/TargetInfo.h"     /* for class clang::TargetInfo */
13#include "clang/Basic/LangOptions.h"    /* for class clang::LangOptions */
14#include "clang/Basic/TargetOptions.h"  /* for class clang::TargetOptions */
15
16#include "clang/Frontend/FrontendDiagnostic.h"      /* for clang::diag::* */
17
18#include "clang/Sema/ParseAST.h"        /* for function clang::ParseAST() */
19
20#if defined(__arm__)
21#   define DEFAULT_TARGET_TRIPLE_STRING "armv7-none-linux-gnueabi"
22#elif defined(__x86_64__)
23#   define DEFAULT_TARGET_TRIPLE_STRING "x86_64-unknown-linux"
24#else
25#   define DEFAULT_TARGET_TRIPLE_STRING "i686-unknown-linux"    // let's use x86 as default target
26#endif
27
28namespace slang {
29
30bool Slang::GlobalInitialized = false;
31
32/* Language option (define the language feature for compiler such as C99) */
33LangOptions Slang::LangOpts;
34
35/* Code generation option for the compiler */
36CodeGenOptions Slang::CodeGenOpts;
37
38const 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";
39
40/* The named of metadata node that pragma resides (should be synced with bcc.cpp) */
41const llvm::Twine Slang::PragmaMetadataName = "#pragma";
42
43void Slang::GlobalInitialization() {
44    if(!GlobalInitialized) {
45        /* We only support x86, x64 and ARM target */
46
47        /* For ARM */
48        LLVMInitializeARMTargetInfo();
49        LLVMInitializeARMTarget();
50        LLVMInitializeARMAsmPrinter();
51
52        /* For x86 and x64 */
53        LLVMInitializeX86TargetInfo();
54        LLVMInitializeX86Target();
55        LLVMInitializeX86AsmPrinter();
56
57        /* Please refer to clang/include/clang/Basic/LangOptions.h for setting up the options */
58        LangOpts.RTTI = 0;  /* turn off the RTTI information support */
59        LangOpts.NeXTRuntime = 0;   /* turn off the NeXT runtime uses */
60        LangOpts.Bool = 1;  /* turn on 'bool', 'true', 'false' keywords. */
61
62        CodeGenOpts.OptimizationLevel = 3;  /* -O3 */
63
64        GlobalInitialized = true;
65    }
66
67    return;
68}
69
70void Slang::LLVMErrorHandler(void *UserData, const std::string &Message) {
71    Diagnostic* Diags = static_cast<Diagnostic*>(UserData);
72    Diags->Report(clang::diag::err_fe_error_backend) << Message;
73    exit(1);
74}
75
76void Slang::createTarget(const char* Triple, const char* CPU, const char** Features) {
77    if(Triple != NULL)
78        mTargetOpts.Triple = Triple;
79    else
80        mTargetOpts.Triple = DEFAULT_TARGET_TRIPLE_STRING;
81
82    if(CPU != NULL)
83        mTargetOpts.CPU = CPU;
84
85    mTarget.reset(TargetInfo::CreateTargetInfo(*mDiagnostics, mTargetOpts));
86
87    if(Features != NULL)
88        for(int i=0;Features[i]!=NULL;i++)
89            mTargetOpts.Features.push_back(Features[i]);
90
91    return;
92}
93
94Slang::Slang(const char* Triple, const char* CPU, const char** Features) :
95    mOutputType(SlangCompilerOutput_Default),
96    mAllowRSPrefix(false)
97{
98    GlobalInitialization();
99
100    createDiagnostic();
101    llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagnostics.get());
102
103    createTarget(Triple, CPU, Features);
104    createFileManager();
105    createSourceManager();
106
107    return;
108}
109
110bool Slang::setInputSource(llvm::StringRef inputFile, const char* text, size_t textLength) {
111    mInputFileName = inputFile.str();
112
113    /* Reset the ID tables if we are reusing the SourceManager */
114    mSourceMgr->clearIDTables();
115
116    /* Load the source */
117    llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getMemBuffer(text, text + textLength);
118    mSourceMgr->createMainFileIDForMemBuffer(SB);
119
120    if(mSourceMgr->getMainFileID().isInvalid()) {
121        mDiagnostics->Report(clang::diag::err_fe_error_reading) << inputFile;
122        return false;
123    }
124
125    return true;
126}
127
128bool Slang::setInputSource(llvm::StringRef inputFile) {
129    mInputFileName = inputFile.str();
130
131    mSourceMgr->clearIDTables();
132
133    const FileEntry* File = mFileMgr->getFile(inputFile);
134    if(File)
135        mSourceMgr->createMainFileID(File, SourceLocation());
136
137    if(mSourceMgr->getMainFileID().isInvalid()) {
138        mDiagnostics->Report(clang::diag::err_fe_error_reading) << inputFile;
139        return false;
140    }
141
142    return true;
143}
144
145void Slang::setOutputType(SlangCompilerOutputTy outputType) {
146    mOutputType = outputType;
147    if( mOutputType != SlangCompilerOutput_Assembly &&
148        mOutputType != SlangCompilerOutput_LL &&
149        mOutputType != SlangCompilerOutput_Bitcode &&
150        mOutputType != SlangCompilerOutput_Nothing &&
151        mOutputType != SlangCompilerOutput_Obj)
152        mOutputType = SlangCompilerOutput_Default;
153    return;
154}
155
156bool Slang::setOutput(const char* outputFile) {
157    std::string Error;
158
159    switch(mOutputType) {
160        case SlangCompilerOutput_Assembly:
161        case SlangCompilerOutput_LL:
162            mOS.reset( new llvm::raw_fd_ostream(outputFile, Error, 0) );
163        break;
164
165        case SlangCompilerOutput_Nothing:
166            mOS.reset();
167        break;
168
169        case SlangCompilerOutput_Obj:
170        case SlangCompilerOutput_Bitcode:
171        default:
172            mOS.reset( new llvm::raw_fd_ostream(outputFile, Error, llvm::raw_fd_ostream::F_Binary) );
173        break;
174    }
175
176    if(!Error.empty()) {
177        mOS.reset();
178        mDiagnostics->Report(clang::diag::err_fe_error_opening) << outputFile << Error;
179        return false;
180    }
181
182    mOutputFileName = outputFile;
183
184    return true;
185}
186
187int Slang::compile() {
188    if((mDiagnostics->getNumErrors() > 0) || (mOS.get() == NULL))
189        return mDiagnostics->getNumErrors();
190
191    /* Here is per-compilation needed initialization */
192    createPreprocessor();
193    createASTContext();
194    createRSContext();
195    //createBackend();
196    createRSBackend();
197
198    /* Inform the diagnostic client we are processing a source file */
199    mDiagClient->BeginSourceFile(LangOpts, mPP.get());
200
201    /* The core of the slang compiler */
202    ParseAST(*mPP, mBackend.get(), *mASTContext);
203
204    /* The compilation ended, clear up */
205    mBackend.reset();
206    mASTContext.reset();
207    mPP.reset();
208
209    /* Inform the diagnostic client we are done with previous source file */
210    mDiagClient->EndSourceFile();
211
212    return mDiagnostics->getNumErrors();
213}
214
215bool Slang::reflectToJava(const char* outputPackageName) {
216    if(mRSContext.get())
217        return mRSContext->reflectToJava(outputPackageName, mInputFileName, mOutputFileName);
218    else
219        return false;
220}
221
222bool Slang::reflectToJavaPath(const char* outputPathName) {
223    if(mRSContext.get())
224        return mRSContext->reflectToJavaPath(outputPathName);
225    else
226        return false;
227}
228
229void Slang::getPragmas(size_t* actualStringCount, size_t maxStringCount, char** strings) {
230    int stringCount = mPragmas.size() * 2;
231
232    if(actualStringCount)
233        *actualStringCount = stringCount;
234    if(stringCount > maxStringCount)
235        stringCount = maxStringCount;
236    if(strings)
237        for(PragmaList::const_iterator it = mPragmas.begin();
238            stringCount > 0;
239            stringCount-=2, it++)
240        {
241            *strings++ = const_cast<char*>(it->first.c_str());
242            *strings++ = const_cast<char*>(it->second.c_str());
243        }
244
245    return;
246}
247
248Slang::~Slang() {
249    llvm::llvm_shutdown();
250    return;
251}
252
253}   /* namespace slang */
254