blob: 46b65781e3602c63fb664951a444d13718f175c3 [file] [log] [blame]
Shih-wei Liao462aefd2010-06-04 15:32:04 -07001#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) :
Kirk Stewart1fd85792010-07-07 09:51:23 -070095 mOutputType(SlangCompilerOutput_Default),
96 mAllowRSPrefix(false)
Shih-wei Liao462aefd2010-06-04 15:32:04 -070097{
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
Shih-wei Liaob55d7ef2010-07-16 00:19:38 -0700156static void _mkdir_given_a_file(const char *file) {
Che-Liang Chiou807a0ea2010-07-16 17:53:52 -0700157 char buf[256];
158 char *tmp, *p = NULL;
159 size_t len = strlen(file);
Shih-wei Liaob55d7ef2010-07-16 00:19:38 -0700160
Che-Liang Chiou807a0ea2010-07-16 17:53:52 -0700161 if (len + 1 <= sizeof(buf))
162 tmp = buf;
163 else
164 tmp = new char [len + 1];
165
166 strcpy(tmp, file);
Shih-wei Liaob55d7ef2010-07-16 00:19:38 -0700167
168 if (tmp[len - 1] == '/')
169 tmp[len - 1] = 0;
170
171 for (p = tmp + 1; *p; p++) {
172 if (*p == '/') {
173 *p = 0;
174 mkdir(tmp, S_IRWXU);
175 *p = '/';
176 }
177 }
Che-Liang Chiou807a0ea2010-07-16 17:53:52 -0700178
179 if (tmp != buf)
180 delete[] tmp;
Shih-wei Liaob55d7ef2010-07-16 00:19:38 -0700181}
182
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700183bool Slang::setOutput(const char* outputFile) {
184 std::string Error;
185
Shih-wei Liaob55d7ef2010-07-16 00:19:38 -0700186 _mkdir_given_a_file(outputFile);
187
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700188 switch(mOutputType) {
189 case SlangCompilerOutput_Assembly:
190 case SlangCompilerOutput_LL:
191 mOS.reset( new llvm::raw_fd_ostream(outputFile, Error, 0) );
192 break;
193
194 case SlangCompilerOutput_Nothing:
195 mOS.reset();
196 break;
197
198 case SlangCompilerOutput_Obj:
199 case SlangCompilerOutput_Bitcode:
200 default:
201 mOS.reset( new llvm::raw_fd_ostream(outputFile, Error, llvm::raw_fd_ostream::F_Binary) );
202 break;
203 }
204
205 if(!Error.empty()) {
206 mOS.reset();
207 mDiagnostics->Report(clang::diag::err_fe_error_opening) << outputFile << Error;
208 return false;
209 }
210
211 mOutputFileName = outputFile;
212
213 return true;
214}
215
216int Slang::compile() {
217 if((mDiagnostics->getNumErrors() > 0) || (mOS.get() == NULL))
218 return mDiagnostics->getNumErrors();
219
220 /* Here is per-compilation needed initialization */
221 createPreprocessor();
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700222 createASTContext();
Shih-wei Liao001fb6d2010-06-21 11:17:11 -0700223 createRSContext();
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700224 //createBackend();
225 createRSBackend();
226
227 /* Inform the diagnostic client we are processing a source file */
228 mDiagClient->BeginSourceFile(LangOpts, mPP.get());
229
230 /* The core of the slang compiler */
231 ParseAST(*mPP, mBackend.get(), *mASTContext);
232
233 /* The compilation ended, clear up */
234 mBackend.reset();
235 mASTContext.reset();
236 mPP.reset();
237
238 /* Inform the diagnostic client we are done with previous source file */
239 mDiagClient->EndSourceFile();
240
241 return mDiagnostics->getNumErrors();
242}
243
244bool Slang::reflectToJava(const char* outputPackageName) {
245 if(mRSContext.get())
246 return mRSContext->reflectToJava(outputPackageName, mInputFileName, mOutputFileName);
247 else
248 return false;
249}
250
Shih-wei Liao6de89272010-07-15 15:26:20 -0700251bool Slang::reflectToJavaPath(const char* outputPathName) {
252 if(mRSContext.get())
253 return mRSContext->reflectToJavaPath(outputPathName);
254 else
255 return false;
256}
257
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700258void Slang::getPragmas(size_t* actualStringCount, size_t maxStringCount, char** strings) {
259 int stringCount = mPragmas.size() * 2;
260
261 if(actualStringCount)
262 *actualStringCount = stringCount;
263 if(stringCount > maxStringCount)
264 stringCount = maxStringCount;
265 if(strings)
266 for(PragmaList::const_iterator it = mPragmas.begin();
267 stringCount > 0;
268 stringCount-=2, it++)
269 {
270 *strings++ = const_cast<char*>(it->first.c_str());
271 *strings++ = const_cast<char*>(it->second.c_str());
272 }
273
274 return;
275}
276
277Slang::~Slang() {
278 llvm::llvm_shutdown();
279 return;
280}
281
282} /* namespace slang */