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