slang.cpp revision f83d3c396d5d7eacd97cf0a5d3b6a01d75535b67
1#include "slang.hpp" 2 3#include <stdlib.h> /* for getenv */ 4 5#include "libslang.h" 6 7#include "llvm/ADT/Twine.h" /* for class llvm::Twine */ 8 9#include "llvm/Target/TargetSelect.h" /* for function LLVMInitialize[ARM|X86][TargetInfo|Target|AsmPrinter]() */ 10 11#include "llvm/Support/MemoryBuffer.h" /* for class llvm::MemoryBuffer */ 12#include "llvm/Support/ErrorHandling.h" /* for function llvm::install_fatal_error_handler() */ 13#include "llvm/Support/ManagedStatic.h" /* for class llvm::llvm_shutdown */ 14 15#include "clang/Basic/TargetInfo.h" /* for class clang::TargetInfo */ 16#include "clang/Basic/LangOptions.h" /* for class clang::LangOptions */ 17#include "clang/Basic/TargetOptions.h" /* for class clang::TargetOptions */ 18 19#include "clang/Frontend/FrontendDiagnostic.h" /* for clang::diag::* */ 20 21#include "clang/Sema/ParseAST.h" /* for function clang::ParseAST() */ 22 23#if defined(__arm__) 24# define DEFAULT_TARGET_TRIPLE_STRING "armv7-none-linux-gnueabi" 25#elif defined(__x86_64__) 26# define DEFAULT_TARGET_TRIPLE_STRING "x86_64-unknown-linux" 27#else 28# define DEFAULT_TARGET_TRIPLE_STRING "i686-unknown-linux" // let's use x86 as default target 29#endif 30 31namespace slang { 32 33bool Slang::GlobalInitialized = false; 34 35/* Language option (define the language feature for compiler such as C99) */ 36LangOptions Slang::LangOpts; 37 38/* Code generation option for the compiler */ 39CodeGenOptions Slang::CodeGenOpts; 40 41const 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"; 42 43/* The named of metadata node that pragma resides (should be synced with bcc.cpp) */ 44const llvm::Twine Slang::PragmaMetadataName = "#pragma"; 45 46void Slang::GlobalInitialization() { 47 if(!GlobalInitialized) { 48 /* We only support x86, x64 and ARM target */ 49 50 /* For ARM */ 51 LLVMInitializeARMTargetInfo(); 52 LLVMInitializeARMTarget(); 53 LLVMInitializeARMAsmPrinter(); 54 55 /* For x86 and x64 */ 56 LLVMInitializeX86TargetInfo(); 57 LLVMInitializeX86Target(); 58 LLVMInitializeX86AsmPrinter(); 59 60 /* Please refer to clang/include/clang/Basic/LangOptions.h for setting up the options */ 61 LangOpts.RTTI = 0; /* turn off the RTTI information support */ 62 LangOpts.NeXTRuntime = 0; /* turn off the NeXT runtime uses */ 63 LangOpts.Bool = 1; /* turn on 'bool', 'true', 'false' keywords. */ 64 65 CodeGenOpts.OptimizationLevel = 3; /* -O3 */ 66 67 GlobalInitialized = true; 68 } 69 70 return; 71} 72 73void Slang::LLVMErrorHandler(void *UserData, const std::string &Message) { 74 Diagnostic* Diags = static_cast<Diagnostic*>(UserData); 75 Diags->Report(clang::diag::err_fe_error_backend) << Message; 76 exit(1); 77} 78 79void Slang::createTarget(const char* Triple, const char* CPU, const char** Features) { 80 if(Triple != NULL) 81 mTargetOpts.Triple = Triple; 82 else 83 mTargetOpts.Triple = DEFAULT_TARGET_TRIPLE_STRING; 84 85 if(CPU != NULL) 86 mTargetOpts.CPU = CPU; 87 88 mTarget.reset(TargetInfo::CreateTargetInfo(*mDiagnostics, mTargetOpts)); 89 90 if(Features != NULL) 91 for(int i=0;Features[i]!=NULL;i++) 92 mTargetOpts.Features.push_back(Features[i]); 93 94 return; 95} 96 97void Slang::createPreprocessor() { 98 HeaderSearch* HS = new HeaderSearch(*mFileMgr); /* Default only search header file in current dir */ 99 100 mPP.reset(new Preprocessor( *mDiagnostics, 101 LangOpts, 102 *mTarget, 103 *mSourceMgr, 104 *HS, 105 NULL, 106 true /* OwnsHeaderSearch */)); 107 /* Initialize the prepocessor */ 108 mPragmas.clear(); 109 mPP->AddPragmaHandler(NULL, new PragmaRecorder(mPragmas)); 110 111 std::string inclFiles("#include \"rs_types.rsh\""); 112 mPP->setPredefines(inclFiles + "\n" + "#include \"rs_math.rsh\"" + "\n"); 113 114 /* Like ApplyHeaderSearchOptions in InitHeaderSearch.cpp */ 115 const char *inclDir = getenv("ANDROID_BUILD_TOP"); 116 std::vector<DirectoryLookup> SearchList; 117 if (inclDir) { 118 char *dirPath = new char[strlen(inclDir) + 33]; 119 strcpy(dirPath, inclDir); 120 strcpy(dirPath + strlen(inclDir), "/frameworks/base/libs/rs/scriptc"); 121 122 if (const DirectoryEntry *DE = mFileMgr->getDirectory(dirPath, dirPath + strlen(dirPath))) { 123 SearchList.push_back(DirectoryLookup(DE, SrcMgr::C_System, false, false)); 124 } 125 } 126 127 int siz = 256; 128 char *currDir = new char[siz]; 129 while (!getcwd(currDir, siz)) { 130 siz *= 2; 131 } 132 133 if (siz - strlen(currDir) >= 33) { 134 strcpy(currDir + strlen(currDir), "/frameworks/base/libs/rs/scriptc"); 135 } else { 136 char *tmp = new char[strlen(currDir) + 33]; 137 strcpy(tmp, currDir); 138 strcpy(tmp + strlen(currDir), "/frameworks/base/libs/rs/scriptc"); 139 currDir = tmp; 140 } 141 142 if (const DirectoryEntry *DE = mFileMgr->getDirectory(currDir, currDir + strlen(currDir))) { 143 SearchList.push_back(DirectoryLookup(DE, SrcMgr::C_System, false, false)); 144 } 145 146 HS->SetSearchPaths(SearchList, 1, false); 147 148 return; 149} 150 151Slang::Slang(const char* Triple, const char* CPU, const char** Features) : 152 mOutputType(SlangCompilerOutput_Default), 153 mAllowRSPrefix(false) 154{ 155 GlobalInitialization(); 156 157 createDiagnostic(); 158 llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagnostics.get()); 159 160 createTarget(Triple, CPU, Features); 161 createFileManager(); 162 createSourceManager(); 163 164 return; 165} 166 167bool Slang::setInputSource(llvm::StringRef inputFile, const char* text, size_t textLength) { 168 mInputFileName = inputFile.str(); 169 170 /* Reset the ID tables if we are reusing the SourceManager */ 171 mSourceMgr->clearIDTables(); 172 173 /* Load the source */ 174 llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getMemBuffer(text, text + textLength); 175 mSourceMgr->createMainFileIDForMemBuffer(SB); 176 177 if(mSourceMgr->getMainFileID().isInvalid()) { 178 mDiagnostics->Report(clang::diag::err_fe_error_reading) << inputFile; 179 return false; 180 } 181 182 return true; 183} 184 185bool Slang::setInputSource(llvm::StringRef inputFile) { 186 mInputFileName = inputFile.str(); 187 188 mSourceMgr->clearIDTables(); 189 190 const FileEntry* File = mFileMgr->getFile(inputFile); 191 if(File) 192 mSourceMgr->createMainFileID(File, SourceLocation()); 193 194 if(mSourceMgr->getMainFileID().isInvalid()) { 195 mDiagnostics->Report(clang::diag::err_fe_error_reading) << inputFile; 196 return false; 197 } 198 199 return true; 200} 201 202void Slang::setOutputType(SlangCompilerOutputTy outputType) { 203 mOutputType = outputType; 204 if( mOutputType != SlangCompilerOutput_Assembly && 205 mOutputType != SlangCompilerOutput_LL && 206 mOutputType != SlangCompilerOutput_Bitcode && 207 mOutputType != SlangCompilerOutput_Nothing && 208 mOutputType != SlangCompilerOutput_Obj) 209 mOutputType = SlangCompilerOutput_Default; 210 return; 211} 212 213static void _mkdir_given_a_file(const char *file) { 214 char buf[256]; 215 char *tmp, *p = NULL; 216 size_t len = strlen(file); 217 218 if (len + 1 <= sizeof(buf)) 219 tmp = buf; 220 else 221 tmp = new char [len + 1]; 222 223 strcpy(tmp, file); 224 225 if (tmp[len - 1] == '/') 226 tmp[len - 1] = 0; 227 228 for (p = tmp + 1; *p; p++) { 229 if (*p == '/') { 230 *p = 0; 231 mkdir(tmp, S_IRWXU); 232 *p = '/'; 233 } 234 } 235 236 if (tmp != buf) 237 delete[] tmp; 238} 239 240bool Slang::setOutput(const char* outputFile) { 241 std::string Error; 242 243 _mkdir_given_a_file(outputFile); 244 245 switch(mOutputType) { 246 case SlangCompilerOutput_Assembly: 247 case SlangCompilerOutput_LL: 248 mOS.reset( new llvm::raw_fd_ostream(outputFile, Error, 0) ); 249 break; 250 251 case SlangCompilerOutput_Nothing: 252 mOS.reset(); 253 break; 254 255 case SlangCompilerOutput_Obj: 256 case SlangCompilerOutput_Bitcode: 257 default: 258 mOS.reset( new llvm::raw_fd_ostream(outputFile, Error, llvm::raw_fd_ostream::F_Binary) ); 259 break; 260 } 261 262 if(!Error.empty()) { 263 mOS.reset(); 264 mDiagnostics->Report(clang::diag::err_fe_error_opening) << outputFile << Error; 265 return false; 266 } 267 268 mOutputFileName = outputFile; 269 270 return true; 271} 272 273int Slang::compile() { 274 if((mDiagnostics->getNumErrors() > 0) || (mOS.get() == NULL)) 275 return mDiagnostics->getNumErrors(); 276 277 /* Here is per-compilation needed initialization */ 278 createPreprocessor(); 279 createASTContext(); 280 createRSContext(); 281 //createBackend(); 282 createRSBackend(); 283 284 /* Inform the diagnostic client we are processing a source file */ 285 mDiagClient->BeginSourceFile(LangOpts, mPP.get()); 286 287 /* The core of the slang compiler */ 288 ParseAST(*mPP, mBackend.get(), *mASTContext); 289 290 /* The compilation ended, clear up */ 291 mBackend.reset(); 292 // Can't reset yet because the reflection later on still needs mRSContext 293 // mRSContext.reset(); 294 mASTContext.reset(); 295 mPP.reset(); 296 297 /* Inform the diagnostic client we are done with previous source file */ 298 mDiagClient->EndSourceFile(); 299 300 return mDiagnostics->getNumErrors(); 301} 302 303bool Slang::reflectToJava(const char* outputPackageName) { 304 if(mRSContext.get()) 305 return mRSContext->reflectToJava(outputPackageName, mInputFileName, mOutputFileName); 306 else 307 return false; 308} 309 310bool Slang::reflectToJavaPath(const char* outputPathName) { 311 if(mRSContext.get()) 312 return mRSContext->reflectToJavaPath(outputPathName); 313 else 314 return false; 315} 316 317void Slang::getPragmas(size_t* actualStringCount, size_t maxStringCount, char** strings) { 318 int stringCount = mPragmas.size() * 2; 319 320 if(actualStringCount) 321 *actualStringCount = stringCount; 322 if(stringCount > maxStringCount) 323 stringCount = maxStringCount; 324 if(strings) 325 for(PragmaList::const_iterator it = mPragmas.begin(); 326 stringCount > 0; 327 stringCount-=2, it++) 328 { 329 *strings++ = const_cast<char*>(it->first.c_str()); 330 *strings++ = const_cast<char*>(it->second.c_str()); 331 } 332 333 return; 334} 335 336Slang::~Slang() { 337 llvm::llvm_shutdown(); 338 return; 339} 340 341} /* namespace slang */ 342