slang.cpp revision 4c9f742efa36b1037acc640184681d421aa0f6ba
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/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 98void 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 112 std::string inclFiles("#include \"rs_types.rsh\""); 113 mPP->setPredefines(inclFiles + "\n" + "#include \"rs_math.rsh\"" + "\n"); 114 115 /* Like ApplyHeaderSearchOptions in InitHeaderSearch.cpp */ 116 const char *inclDir = getenv("ANDROID_BUILD_TOP"); 117 std::vector<DirectoryLookup> SearchList; 118 if (inclDir) { 119 char *dirPath = new char[strlen(inclDir) + 33]; 120 strcpy(dirPath, inclDir); 121 strcpy(dirPath + strlen(inclDir), "/frameworks/base/libs/rs/scriptc"); 122 123 if (const DirectoryEntry *DE = mFileMgr->getDirectory(dirPath, dirPath + strlen(dirPath))) { 124 SearchList.push_back(DirectoryLookup(DE, SrcMgr::C_System, false, false)); 125 } 126 } 127 128 int siz = 256; 129 char *currDir = new char[siz]; 130 while (!getcwd(currDir, siz)) { 131 siz *= 2; 132 currDir = new char[siz]; 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 150 return; 151} 152 153Slang::Slang(const char* Triple, const char* CPU, const char** Features) : 154 mOutputType(SlangCompilerOutput_Default), 155 mAllowRSPrefix(false) 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 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 215static void _mkdir_given_a_file(const char *file) { 216 char buf[256]; 217 char *tmp, *p = NULL; 218 size_t len = strlen(file); 219 220 if (len + 1 <= sizeof(buf)) 221 tmp = buf; 222 else 223 tmp = new char [len + 1]; 224 225 strcpy(tmp, file); 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 } 237 238 if (tmp != buf) 239 delete[] tmp; 240} 241 242bool Slang::setOutput(const char* outputFile) { 243 std::string Error; 244 245 _mkdir_given_a_file(outputFile); 246 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 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(); 281 createASTContext(); 282 createRSContext(); 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(); 294 // Can't reset yet because the reflection later on still needs mRSContext 295 // mRSContext.reset(); 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 305bool Slang::reflectToJava(const char* outputPackageName) { 306 if(mRSContext.get()) 307 return mRSContext->reflectToJava(outputPackageName, mInputFileName, mOutputFileName); 308 else 309 return false; 310} 311 312bool Slang::reflectToJavaPath(const char* outputPathName) { 313 if(mRSContext.get()) 314 return mRSContext->reflectToJavaPath(outputPathName); 315 else 316 return false; 317} 318 319void 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 338typedef 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 352Slang::~Slang() { 353 llvm::llvm_shutdown(); 354 return; 355} 356 357} /* namespace slang */ 358