Shih-wei Liao | 462aefd | 2010-06-04 15:32:04 -0700 | [diff] [blame] | 1 | #include "slang.hpp" |
Shih-wei Liao | 4c9f742 | 2010-08-05 04:30:02 -0700 | [diff] [blame] | 2 | #include "slang_rs_export_func.hpp" |
Shih-wei Liao | 68e8e9f | 2010-07-18 18:46:49 -0700 | [diff] [blame] | 3 | |
| 4 | #include <stdlib.h> /* for getenv */ |
| 5 | |
Shih-wei Liao | 462aefd | 2010-06-04 15:32:04 -0700 | [diff] [blame] | 6 | #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 | |
| 32 | namespace slang { |
| 33 | |
| 34 | bool Slang::GlobalInitialized = false; |
| 35 | |
| 36 | /* Language option (define the language feature for compiler such as C99) */ |
| 37 | LangOptions Slang::LangOpts; |
| 38 | |
| 39 | /* Code generation option for the compiler */ |
| 40 | CodeGenOptions Slang::CodeGenOpts; |
| 41 | |
| 42 | const 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) */ |
| 45 | const llvm::Twine Slang::PragmaMetadataName = "#pragma"; |
| 46 | |
| 47 | void 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 | |
| 74 | void 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 | |
| 80 | void 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 Liao | 68e8e9f | 2010-07-18 18:46:49 -0700 | [diff] [blame] | 98 | void 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 Liao | 60de5bd | 2010-07-21 12:43:30 -0700 | [diff] [blame] | 112 | std::string inclFiles("#include \"rs_types.rsh\""); |
| 113 | mPP->setPredefines(inclFiles + "\n" + "#include \"rs_math.rsh\"" + "\n"); |
| 114 | |
Shih-wei Liao | 68e8e9f | 2010-07-18 18:46:49 -0700 | [diff] [blame] | 115 | /* Like ApplyHeaderSearchOptions in InitHeaderSearch.cpp */ |
Shih-wei Liao | 9089828 | 2010-07-19 18:38:57 -0700 | [diff] [blame] | 116 | const char *inclDir = getenv("ANDROID_BUILD_TOP"); |
| 117 | std::vector<DirectoryLookup> SearchList; |
Shih-wei Liao | 68e8e9f | 2010-07-18 18:46:49 -0700 | [diff] [blame] | 118 | if (inclDir) { |
Shih-wei Liao | 8eac094 | 2010-07-19 14:19:51 -0700 | [diff] [blame] | 119 | char *dirPath = new char[strlen(inclDir) + 33]; |
| 120 | strcpy(dirPath, inclDir); |
| 121 | strcpy(dirPath + strlen(inclDir), "/frameworks/base/libs/rs/scriptc"); |
| 122 | |
Shih-wei Liao | 8eac094 | 2010-07-19 14:19:51 -0700 | [diff] [blame] | 123 | if (const DirectoryEntry *DE = mFileMgr->getDirectory(dirPath, dirPath + strlen(dirPath))) { |
Shih-wei Liao | 68e8e9f | 2010-07-18 18:46:49 -0700 | [diff] [blame] | 124 | SearchList.push_back(DirectoryLookup(DE, SrcMgr::C_System, false, false)); |
Shih-wei Liao | 68e8e9f | 2010-07-18 18:46:49 -0700 | [diff] [blame] | 125 | } |
| 126 | } |
| 127 | |
Shih-wei Liao | 9089828 | 2010-07-19 18:38:57 -0700 | [diff] [blame] | 128 | int siz = 256; |
| 129 | char *currDir = new char[siz]; |
| 130 | while (!getcwd(currDir, siz)) { |
| 131 | siz *= 2; |
Shih-wei Liao | 4c9f742 | 2010-08-05 04:30:02 -0700 | [diff] [blame] | 132 | currDir = new char[siz]; |
Shih-wei Liao | 9089828 | 2010-07-19 18:38:57 -0700 | [diff] [blame] | 133 | } |
| 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 Liao | 68e8e9f | 2010-07-18 18:46:49 -0700 | [diff] [blame] | 150 | return; |
| 151 | } |
| 152 | |
Shih-wei Liao | 462aefd | 2010-06-04 15:32:04 -0700 | [diff] [blame] | 153 | Slang::Slang(const char* Triple, const char* CPU, const char** Features) : |
Kirk Stewart | 1fd8579 | 2010-07-07 09:51:23 -0700 | [diff] [blame] | 154 | mOutputType(SlangCompilerOutput_Default), |
| 155 | mAllowRSPrefix(false) |
Shih-wei Liao | 462aefd | 2010-06-04 15:32:04 -0700 | [diff] [blame] | 156 | { |
| 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 | |
| 169 | bool 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 | |
| 187 | bool 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 | |
| 204 | void 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 Liao | b55d7ef | 2010-07-16 00:19:38 -0700 | [diff] [blame] | 215 | static void _mkdir_given_a_file(const char *file) { |
Che-Liang Chiou | 807a0ea | 2010-07-16 17:53:52 -0700 | [diff] [blame] | 216 | char buf[256]; |
| 217 | char *tmp, *p = NULL; |
| 218 | size_t len = strlen(file); |
Shih-wei Liao | b55d7ef | 2010-07-16 00:19:38 -0700 | [diff] [blame] | 219 | |
Che-Liang Chiou | 807a0ea | 2010-07-16 17:53:52 -0700 | [diff] [blame] | 220 | if (len + 1 <= sizeof(buf)) |
| 221 | tmp = buf; |
| 222 | else |
| 223 | tmp = new char [len + 1]; |
| 224 | |
| 225 | strcpy(tmp, file); |
Shih-wei Liao | b55d7ef | 2010-07-16 00:19:38 -0700 | [diff] [blame] | 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 | } |
Che-Liang Chiou | 807a0ea | 2010-07-16 17:53:52 -0700 | [diff] [blame] | 237 | |
| 238 | if (tmp != buf) |
| 239 | delete[] tmp; |
Shih-wei Liao | b55d7ef | 2010-07-16 00:19:38 -0700 | [diff] [blame] | 240 | } |
| 241 | |
Shih-wei Liao | 462aefd | 2010-06-04 15:32:04 -0700 | [diff] [blame] | 242 | bool Slang::setOutput(const char* outputFile) { |
| 243 | std::string Error; |
| 244 | |
Shih-wei Liao | b55d7ef | 2010-07-16 00:19:38 -0700 | [diff] [blame] | 245 | _mkdir_given_a_file(outputFile); |
| 246 | |
Shih-wei Liao | 462aefd | 2010-06-04 15:32:04 -0700 | [diff] [blame] | 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, 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 | |
| 275 | int 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 Liao | 462aefd | 2010-06-04 15:32:04 -0700 | [diff] [blame] | 281 | createASTContext(); |
Shih-wei Liao | 001fb6d | 2010-06-21 11:17:11 -0700 | [diff] [blame] | 282 | createRSContext(); |
Shih-wei Liao | 462aefd | 2010-06-04 15:32:04 -0700 | [diff] [blame] | 283 | //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 Liao | f83d3c3 | 2010-07-30 22:22:49 -0700 | [diff] [blame] | 294 | // Can't reset yet because the reflection later on still needs mRSContext |
| 295 | // mRSContext.reset(); |
Shih-wei Liao | 462aefd | 2010-06-04 15:32:04 -0700 | [diff] [blame] | 296 | 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 | |
| 305 | bool 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 Liao | 6de8927 | 2010-07-15 15:26:20 -0700 | [diff] [blame] | 312 | bool Slang::reflectToJavaPath(const char* outputPathName) { |
| 313 | if(mRSContext.get()) |
| 314 | return mRSContext->reflectToJavaPath(outputPathName); |
| 315 | else |
| 316 | return false; |
| 317 | } |
| 318 | |
Shih-wei Liao | 462aefd | 2010-06-04 15:32:04 -0700 | [diff] [blame] | 319 | void 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 Liao | 4c9f742 | 2010-08-05 04:30:02 -0700 | [diff] [blame] | 338 | typedef std::list<RSExportFunc*> ExportFuncList; |
| 339 | |
| 340 | const 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 Liao | 462aefd | 2010-06-04 15:32:04 -0700 | [diff] [blame] | 352 | Slang::~Slang() { |
| 353 | llvm::llvm_shutdown(); |
| 354 | return; |
| 355 | } |
| 356 | |
| 357 | } /* namespace slang */ |