blob: fd5abf6da6b36b4b57f81b6c8c37745059ab4c73 [file] [log] [blame]
Shih-wei Liao462aefd2010-06-04 15:32:04 -07001#include "slang.hpp"
Shih-wei Liao4c9f7422010-08-05 04:30:02 -07002#include "slang_rs_export_func.hpp"
Shih-wei Liao68e8e9f2010-07-18 18:46:49 -07003
4#include <stdlib.h> /* for getenv */
5
Shih-wei Liao462aefd2010-06-04 15:32:04 -07006#include "libslang.h"
7
8#include "llvm/ADT/Twine.h" /* for class llvm::Twine */
9
10#include "llvm/Target/TargetSelect.h" /* for function LLVMInitialize[ARM|X86][TargetInfo|Target|AsmPrinter]() */
11
12#include "llvm/Support/MemoryBuffer.h" /* for class llvm::MemoryBuffer */
13#include "llvm/Support/ErrorHandling.h" /* for function llvm::install_fatal_error_handler() */
14#include "llvm/Support/ManagedStatic.h" /* for class llvm::llvm_shutdown */
15
16#include "clang/Basic/TargetInfo.h" /* for class clang::TargetInfo */
17#include "clang/Basic/LangOptions.h" /* for class clang::LangOptions */
18#include "clang/Basic/TargetOptions.h" /* for class clang::TargetOptions */
19
20#include "clang/Frontend/FrontendDiagnostic.h" /* for clang::diag::* */
21
22#include "clang/Sema/ParseAST.h" /* for function clang::ParseAST() */
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# define DEFAULT_TARGET_TRIPLE_STRING "i686-unknown-linux" // let's use x86 as default target
30#endif
31
32namespace slang {
33
34bool Slang::GlobalInitialized = false;
35
36/* Language option (define the language feature for compiler such as C99) */
37LangOptions Slang::LangOpts;
38
39/* Code generation option for the compiler */
40CodeGenOptions Slang::CodeGenOpts;
41
42const 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";
43
44/* The named of metadata node that pragma resides (should be synced with bcc.cpp) */
45const llvm::Twine Slang::PragmaMetadataName = "#pragma";
46
47void Slang::GlobalInitialization() {
48 if(!GlobalInitialized) {
49 /* We only support x86, x64 and ARM target */
50
51 /* For ARM */
52 LLVMInitializeARMTargetInfo();
53 LLVMInitializeARMTarget();
54 LLVMInitializeARMAsmPrinter();
55
56 /* For x86 and x64 */
57 LLVMInitializeX86TargetInfo();
58 LLVMInitializeX86Target();
59 LLVMInitializeX86AsmPrinter();
60
61 /* Please refer to clang/include/clang/Basic/LangOptions.h for setting up 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 Diagnostic* Diags = static_cast<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, const char** Features) {
81 if(Triple != NULL)
82 mTargetOpts.Triple = Triple;
83 else
84 mTargetOpts.Triple = DEFAULT_TARGET_TRIPLE_STRING;
85
86 if(CPU != NULL)
87 mTargetOpts.CPU = CPU;
88
89 mTarget.reset(TargetInfo::CreateTargetInfo(*mDiagnostics, mTargetOpts));
90
91 if(Features != NULL)
92 for(int i=0;Features[i]!=NULL;i++)
93 mTargetOpts.Features.push_back(Features[i]);
94
95 return;
96}
97
Shih-wei Liao68e8e9f2010-07-18 18:46:49 -070098void Slang::createPreprocessor() {
99 HeaderSearch* HS = new HeaderSearch(*mFileMgr); /* Default only search header file in current dir */
100
101 mPP.reset(new Preprocessor( *mDiagnostics,
102 LangOpts,
103 *mTarget,
104 *mSourceMgr,
105 *HS,
106 NULL,
107 true /* OwnsHeaderSearch */));
108 /* Initialize the prepocessor */
109 mPragmas.clear();
110 mPP->AddPragmaHandler(NULL, new PragmaRecorder(mPragmas));
111
Shih-wei Liao60de5bd2010-07-21 12:43:30 -0700112 std::string inclFiles("#include \"rs_types.rsh\"");
113 mPP->setPredefines(inclFiles + "\n" + "#include \"rs_math.rsh\"" + "\n");
114
Shih-wei Liao68e8e9f2010-07-18 18:46:49 -0700115 /* Like ApplyHeaderSearchOptions in InitHeaderSearch.cpp */
Shih-wei Liao90898282010-07-19 18:38:57 -0700116 const char *inclDir = getenv("ANDROID_BUILD_TOP");
117 std::vector<DirectoryLookup> SearchList;
Shih-wei Liao68e8e9f2010-07-18 18:46:49 -0700118 if (inclDir) {
Shih-wei Liao8eac0942010-07-19 14:19:51 -0700119 char *dirPath = new char[strlen(inclDir) + 33];
120 strcpy(dirPath, inclDir);
121 strcpy(dirPath + strlen(inclDir), "/frameworks/base/libs/rs/scriptc");
122
Shih-wei Liao8eac0942010-07-19 14:19:51 -0700123 if (const DirectoryEntry *DE = mFileMgr->getDirectory(dirPath, dirPath + strlen(dirPath))) {
Shih-wei Liao68e8e9f2010-07-18 18:46:49 -0700124 SearchList.push_back(DirectoryLookup(DE, SrcMgr::C_System, false, false));
Shih-wei Liao68e8e9f2010-07-18 18:46:49 -0700125 }
126 }
127
Shih-wei Liao90898282010-07-19 18:38:57 -0700128 int siz = 256;
129 char *currDir = new char[siz];
130 while (!getcwd(currDir, siz)) {
131 siz *= 2;
Shih-wei Liao4c9f7422010-08-05 04:30:02 -0700132 currDir = new char[siz];
Shih-wei Liao90898282010-07-19 18:38:57 -0700133 }
134
135 if (siz - strlen(currDir) >= 33) {
136 strcpy(currDir + strlen(currDir), "/frameworks/base/libs/rs/scriptc");
137 } else {
138 char *tmp = new char[strlen(currDir) + 33];
139 strcpy(tmp, currDir);
140 strcpy(tmp + strlen(currDir), "/frameworks/base/libs/rs/scriptc");
141 currDir = tmp;
142 }
143
144 if (const DirectoryEntry *DE = mFileMgr->getDirectory(currDir, currDir + strlen(currDir))) {
145 SearchList.push_back(DirectoryLookup(DE, SrcMgr::C_System, false, false));
146 }
147
148 HS->SetSearchPaths(SearchList, 1, false);
149
Shih-wei Liao68e8e9f2010-07-18 18:46:49 -0700150 return;
151}
152
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700153Slang::Slang(const char* Triple, const char* CPU, const char** Features) :
Kirk Stewart1fd85792010-07-07 09:51:23 -0700154 mOutputType(SlangCompilerOutput_Default),
155 mAllowRSPrefix(false)
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700156{
157 GlobalInitialization();
158
159 createDiagnostic();
160 llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagnostics.get());
161
162 createTarget(Triple, CPU, Features);
163 createFileManager();
164 createSourceManager();
165
166 return;
167}
168
169bool Slang::setInputSource(llvm::StringRef inputFile, const char* text, size_t textLength) {
170 mInputFileName = inputFile.str();
171
172 /* Reset the ID tables if we are reusing the SourceManager */
173 mSourceMgr->clearIDTables();
174
175 /* Load the source */
176 llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getMemBuffer(text, text + textLength);
177 mSourceMgr->createMainFileIDForMemBuffer(SB);
178
179 if(mSourceMgr->getMainFileID().isInvalid()) {
180 mDiagnostics->Report(clang::diag::err_fe_error_reading) << inputFile;
181 return false;
182 }
183
184 return true;
185}
186
187bool Slang::setInputSource(llvm::StringRef inputFile) {
188 mInputFileName = inputFile.str();
189
190 mSourceMgr->clearIDTables();
191
192 const FileEntry* File = mFileMgr->getFile(inputFile);
193 if(File)
194 mSourceMgr->createMainFileID(File, SourceLocation());
195
196 if(mSourceMgr->getMainFileID().isInvalid()) {
197 mDiagnostics->Report(clang::diag::err_fe_error_reading) << inputFile;
198 return false;
199 }
200
201 return true;
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
Shih-wei Liaob55d7ef2010-07-16 00:19:38 -0700215static void _mkdir_given_a_file(const char *file) {
Che-Liang Chiou807a0ea2010-07-16 17:53:52 -0700216 char buf[256];
217 char *tmp, *p = NULL;
218 size_t len = strlen(file);
Shih-wei Liaob55d7ef2010-07-16 00:19:38 -0700219
Che-Liang Chiou807a0ea2010-07-16 17:53:52 -0700220 if (len + 1 <= sizeof(buf))
221 tmp = buf;
222 else
223 tmp = new char [len + 1];
224
225 strcpy(tmp, file);
Shih-wei Liaob55d7ef2010-07-16 00:19:38 -0700226
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 }
Che-Liang Chiou807a0ea2010-07-16 17:53:52 -0700237
238 if (tmp != buf)
239 delete[] tmp;
Shih-wei Liaob55d7ef2010-07-16 00:19:38 -0700240}
241
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700242bool Slang::setOutput(const char* outputFile) {
243 std::string Error;
244
Shih-wei Liaob55d7ef2010-07-16 00:19:38 -0700245 _mkdir_given_a_file(outputFile);
246
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700247 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, Error, llvm::raw_fd_ostream::F_Binary) );
261 break;
262 }
263
264 if(!Error.empty()) {
265 mOS.reset();
266 mDiagnostics->Report(clang::diag::err_fe_error_opening) << outputFile << Error;
267 return false;
268 }
269
270 mOutputFileName = outputFile;
271
272 return true;
273}
274
275int Slang::compile() {
276 if((mDiagnostics->getNumErrors() > 0) || (mOS.get() == NULL))
277 return mDiagnostics->getNumErrors();
278
279 /* Here is per-compilation needed initialization */
280 createPreprocessor();
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700281 createASTContext();
Shih-wei Liao001fb6d2010-06-21 11:17:11 -0700282 createRSContext();
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700283 //createBackend();
284 createRSBackend();
285
286 /* Inform the diagnostic client we are processing a source file */
287 mDiagClient->BeginSourceFile(LangOpts, mPP.get());
288
289 /* The core of the slang compiler */
290 ParseAST(*mPP, mBackend.get(), *mASTContext);
291
292 /* The compilation ended, clear up */
293 mBackend.reset();
Shih-wei Liaof83d3c32010-07-30 22:22:49 -0700294 // Can't reset yet because the reflection later on still needs mRSContext
295 // mRSContext.reset();
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700296 mASTContext.reset();
297 mPP.reset();
298
299 /* Inform the diagnostic client we are done with previous source file */
300 mDiagClient->EndSourceFile();
301
302 return mDiagnostics->getNumErrors();
303}
304
305bool Slang::reflectToJava(const char* outputPackageName) {
306 if(mRSContext.get())
307 return mRSContext->reflectToJava(outputPackageName, mInputFileName, mOutputFileName);
308 else
309 return false;
310}
311
Shih-wei Liao6de89272010-07-15 15:26:20 -0700312bool Slang::reflectToJavaPath(const char* outputPathName) {
313 if(mRSContext.get())
314 return mRSContext->reflectToJavaPath(outputPathName);
315 else
316 return false;
317}
318
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700319void Slang::getPragmas(size_t* actualStringCount, size_t maxStringCount, char** strings) {
320 int stringCount = mPragmas.size() * 2;
321
322 if(actualStringCount)
323 *actualStringCount = stringCount;
324 if(stringCount > maxStringCount)
325 stringCount = maxStringCount;
326 if(strings)
327 for(PragmaList::const_iterator it = mPragmas.begin();
328 stringCount > 0;
329 stringCount-=2, it++)
330 {
331 *strings++ = const_cast<char*>(it->first.c_str());
332 *strings++ = const_cast<char*>(it->second.c_str());
333 }
334
335 return;
336}
337
Shih-wei Liao4c9f7422010-08-05 04:30:02 -0700338typedef std::list<RSExportFunc*> ExportFuncList;
339
340const char* Slang::exportFuncs() {
341 std::string fNames;
342 for (RSContext::const_export_func_iterator I = mRSContext->export_funcs_begin();
343 I != mRSContext->export_funcs_end();
344 ++I) {
345 RSExportFunc* func = *I;
346 fNames.push_back(',');
347 fNames.append(func->getName());
348 }
349 return fNames.c_str();
350}
351
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700352Slang::~Slang() {
353 llvm::llvm_shutdown();
354 return;
355}
356
357} /* namespace slang */