slang.cpp revision 3f8b44dba57685b437cecc208f2a20a4ed93ed36
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 std::vector<DirectoryLookup> SearchList; 116 for (int i = 0; i < mIncludePaths.size(); ++i) { 117 if (const DirectoryEntry *DE = mFileMgr->getDirectory(mIncludePaths[i])) { 118 SearchList.push_back(DirectoryLookup(DE, SrcMgr::C_System, false, false)); 119 } 120 } 121 122 HS->SetSearchPaths(SearchList, 1, false); 123 124 return; 125} 126 127Slang::Slang(const char* Triple, const char* CPU, const char** Features) : 128 mOutputType(SlangCompilerOutput_Default), 129 mAllowRSPrefix(false) 130{ 131 GlobalInitialization(); 132 133 createDiagnostic(); 134 llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagnostics.get()); 135 136 createTarget(Triple, CPU, Features); 137 createFileManager(); 138 createSourceManager(); 139 140 return; 141} 142 143bool Slang::setInputSource(llvm::StringRef inputFile, const char* text, size_t textLength) { 144 mInputFileName = inputFile.str(); 145 146 /* Reset the ID tables if we are reusing the SourceManager */ 147 mSourceMgr->clearIDTables(); 148 149 /* Load the source */ 150 llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getMemBuffer(text, text + textLength); 151 mSourceMgr->createMainFileIDForMemBuffer(SB); 152 153 if(mSourceMgr->getMainFileID().isInvalid()) { 154 mDiagnostics->Report(clang::diag::err_fe_error_reading) << inputFile; 155 return false; 156 } 157 158 return true; 159} 160 161bool Slang::setInputSource(llvm::StringRef inputFile) { 162 mInputFileName = inputFile.str(); 163 164 mSourceMgr->clearIDTables(); 165 166 const FileEntry* File = mFileMgr->getFile(inputFile); 167 if(File) 168 mSourceMgr->createMainFileID(File, SourceLocation()); 169 170 if(mSourceMgr->getMainFileID().isInvalid()) { 171 mDiagnostics->Report(clang::diag::err_fe_error_reading) << inputFile; 172 return false; 173 } 174 175 return true; 176} 177 178void Slang::addIncludePath(const char* path) { 179 mIncludePaths.push_back(path); 180} 181 182void Slang::setOutputType(SlangCompilerOutputTy outputType) { 183 mOutputType = outputType; 184 if( mOutputType != SlangCompilerOutput_Assembly && 185 mOutputType != SlangCompilerOutput_LL && 186 mOutputType != SlangCompilerOutput_Bitcode && 187 mOutputType != SlangCompilerOutput_Nothing && 188 mOutputType != SlangCompilerOutput_Obj) 189 mOutputType = SlangCompilerOutput_Default; 190 return; 191} 192 193static void _mkdir_given_a_file(const char *file) { 194 char buf[256]; 195 char *tmp, *p = NULL; 196 size_t len = strlen(file); 197 198 if (len + 1 <= sizeof(buf)) 199 tmp = buf; 200 else 201 tmp = new char [len + 1]; 202 203 strcpy(tmp, file); 204 205 if (tmp[len - 1] == '/') 206 tmp[len - 1] = 0; 207 208 for (p = tmp + 1; *p; p++) { 209 if (*p == '/') { 210 *p = 0; 211 mkdir(tmp, S_IRWXU); 212 *p = '/'; 213 } 214 } 215 216 if (tmp != buf) 217 delete[] tmp; 218} 219 220bool Slang::setOutput(const char* outputFile) { 221 std::string Error; 222 223 _mkdir_given_a_file(outputFile); 224 225 switch(mOutputType) { 226 case SlangCompilerOutput_Assembly: 227 case SlangCompilerOutput_LL: 228 mOS.reset( new llvm::raw_fd_ostream(outputFile, Error, 0) ); 229 break; 230 231 case SlangCompilerOutput_Nothing: 232 mOS.reset(); 233 break; 234 235 case SlangCompilerOutput_Obj: 236 case SlangCompilerOutput_Bitcode: 237 default: 238 mOS.reset( new llvm::raw_fd_ostream(outputFile, Error, llvm::raw_fd_ostream::F_Binary) ); 239 break; 240 } 241 242 if(!Error.empty()) { 243 mOS.reset(); 244 mDiagnostics->Report(clang::diag::err_fe_error_opening) << outputFile << Error; 245 return false; 246 } 247 248 mOutputFileName = outputFile; 249 250 return true; 251} 252 253int Slang::compile() { 254 if((mDiagnostics->getNumErrors() > 0) || (mOS.get() == NULL)) 255 return mDiagnostics->getNumErrors(); 256 257 /* Here is per-compilation needed initialization */ 258 createPreprocessor(); 259 createASTContext(); 260 createRSContext(); 261 //createBackend(); 262 createRSBackend(); 263 264 /* Inform the diagnostic client we are processing a source file */ 265 mDiagClient->BeginSourceFile(LangOpts, mPP.get()); 266 267 /* The core of the slang compiler */ 268 ParseAST(*mPP, mBackend.get(), *mASTContext); 269 270 /* The compilation ended, clear up */ 271 mBackend.reset(); 272 // Can't reset yet because the reflection later on still needs mRSContext 273 // mRSContext.reset(); 274 mASTContext.reset(); 275 mPP.reset(); 276 277 /* Inform the diagnostic client we are done with previous source file */ 278 mDiagClient->EndSourceFile(); 279 280 return mDiagnostics->getNumErrors(); 281} 282 283bool Slang::reflectToJava(const char* outputPackageName, char* realPackageName, int bSize) { 284 if(mRSContext.get()) 285 return mRSContext->reflectToJava(outputPackageName, mInputFileName, mOutputFileName, 286 realPackageName, bSize); 287 else 288 return false; 289} 290 291bool Slang::reflectToJavaPath(const char* outputPathName) { 292 if(mRSContext.get()) 293 return mRSContext->reflectToJavaPath(outputPathName); 294 else 295 return false; 296} 297 298void Slang::getPragmas(size_t* actualStringCount, size_t maxStringCount, char** strings) { 299 int stringCount = mPragmas.size() * 2; 300 301 if(actualStringCount) 302 *actualStringCount = stringCount; 303 if(stringCount > maxStringCount) 304 stringCount = maxStringCount; 305 if(strings) 306 for(PragmaList::const_iterator it = mPragmas.begin(); 307 stringCount > 0; 308 stringCount-=2, it++) 309 { 310 *strings++ = const_cast<char*>(it->first.c_str()); 311 *strings++ = const_cast<char*>(it->second.c_str()); 312 } 313 314 return; 315} 316 317typedef std::list<RSExportFunc*> ExportFuncList; 318 319const char* Slang::exportFuncs() { 320 std::string fNames; 321 for (RSContext::const_export_func_iterator I = mRSContext->export_funcs_begin(); 322 I != mRSContext->export_funcs_end(); 323 ++I) { 324 RSExportFunc* func = *I; 325 fNames.push_back(','); 326 fNames.append(func->getName()); 327 } 328 return fNames.c_str(); 329} 330 331Slang::~Slang() { 332 llvm::llvm_shutdown(); 333 return; 334} 335 336} /* namespace slang */ 337