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