slang.cpp revision 6315f76e3cc6ff2d012d1183a0b030d4ff0dc808
1#include "slang.h" 2 3#include <stdlib.h> 4 5#include "llvm/Target/TargetSelect.h" 6 7#include "llvm/Support/MemoryBuffer.h" 8#include "llvm/Support/ErrorHandling.h" 9#include "llvm/Support/ManagedStatic.h" 10 11#include "clang/Basic/TargetInfo.h" 12#include "clang/Basic/LangOptions.h" 13#include "clang/Basic/TargetOptions.h" 14 15#include "clang/Frontend/FrontendDiagnostic.h" 16 17#include "clang/Parse/ParseAST.h" 18 19#include "libslang.h" 20#include "slang_rs_export_func.h" 21 22using namespace slang; 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// let's use x86 as default target 30# define DEFAULT_TARGET_TRIPLE_STRING "i686-unknown-linux" 31#endif 32 33bool Slang::GlobalInitialized = false; 34 35// Language option (define the language feature for compiler such as C99) 36clang::LangOptions Slang::LangOpts; 37 38// Code generation option for the compiler 39clang::CodeGenOptions Slang::CodeGenOpts; 40 41const std::string Slang::TargetDescription = 42 "e-" // little-endian 43 "p:32:32:32-" // 32-bit pointer 44 "i1:8:8-" 45 "i8:8:8-" 46 "i16:16:16-" 47 "i32:32:32-" 48 "i64:64:64-" 49 "f32:32:32-" 50 "f64:64:64-" 51 "v64:64:64-" // 64-bit vector (e.g. float2, int2, short4) 52 "v128:128:128-" 53 "a0:0:64-" 54 "n32"; // native CPU only support 32-bit integer width. 55 56// The named of metadata node that pragma resides (should be synced with 57// bcc.cpp) 58const llvm::StringRef Slang::PragmaMetadataName = "#pragma"; 59 60void Slang::GlobalInitialization() { 61 if (!GlobalInitialized) { 62 // We only support x86, x64 and ARM target 63 64 // For ARM 65 LLVMInitializeARMTargetInfo(); 66 LLVMInitializeARMTarget(); 67 LLVMInitializeARMAsmPrinter(); 68 69 // For x86 and x64 70 LLVMInitializeX86TargetInfo(); 71 LLVMInitializeX86Target(); 72 LLVMInitializeX86AsmPrinter(); 73 74 // Please refer to clang/include/clang/Basic/LangOptions.h to set up 75 // the options. 76 LangOpts.RTTI = 0; // Turn off the RTTI information support 77 LangOpts.NeXTRuntime = 0; // Turn off the NeXT runtime uses 78 LangOpts.Bool = 1; // Turn on 'bool', 'true', 'false' keywords 79 80 CodeGenOpts.OptimizationLevel = 3; /* -O3 */ 81 82 GlobalInitialized = true; 83 } 84 85 return; 86} 87 88void Slang::LLVMErrorHandler(void *UserData, const std::string &Message) { 89 clang::Diagnostic* Diags = static_cast<clang::Diagnostic*>(UserData); 90 Diags->Report(clang::diag::err_fe_error_backend) << Message; 91 exit(1); 92} 93 94void Slang::createTarget(const char* Triple, const char* CPU, 95 const char** Features) { 96 if (Triple != NULL) 97 mTargetOpts.Triple = Triple; 98 else 99 mTargetOpts.Triple = DEFAULT_TARGET_TRIPLE_STRING; 100 101 if (CPU != NULL) 102 mTargetOpts.CPU = CPU; 103 104 mTarget.reset(clang::TargetInfo::CreateTargetInfo(*mDiagnostics, 105 mTargetOpts)); 106 107 if (Features != NULL) 108 for (int i = 0; Features[i] != NULL; i++) 109 mTargetOpts.Features.push_back(Features[i]); 110 111 return; 112} 113 114void Slang::createPreprocessor() { 115 // Default only search header file in current dir 116 clang::HeaderSearch *HS = new clang::HeaderSearch(*mFileMgr); 117 118 mPP.reset(new clang::Preprocessor(*mDiagnostics, 119 LangOpts, 120 *mTarget, 121 *mSourceMgr, 122 *HS, 123 NULL, 124 /* OwnsHeaderSearch */true)); 125 // Initialize the prepocessor 126 mPragmas.clear(); 127 mPP->AddPragmaHandler(new PragmaRecorder(mPragmas)); 128 129 std::string inclFiles("#include \"rs_types.rsh\""); 130 mPP->setPredefines(inclFiles + "\n" + "#include \"rs_math.rsh\"" + "\n"); 131 132 std::vector<clang::DirectoryLookup> SearchList; 133 for (unsigned i = 0; i < mIncludePaths.size(); ++i) { 134 if (const clang::DirectoryEntry *DE = 135 mFileMgr->getDirectory(mIncludePaths[i])) { 136 SearchList.push_back(clang::DirectoryLookup(DE, 137 clang::SrcMgr::C_System, 138 false, 139 false)); 140 } 141 } 142 143 HS->SetSearchPaths(SearchList, 1, false); 144 145 return; 146} 147 148Slang::Slang(const char *Triple, const char *CPU, const char **Features) 149 : mOutputType(SlangCompilerOutput_Default), 150 mAllowRSPrefix(false) { 151 GlobalInitialization(); 152 153 createDiagnostic(); 154 llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagnostics.get()); 155 156 createTarget(Triple, CPU, Features); 157 createFileManager(); 158 createSourceManager(); 159 160 return; 161} 162 163bool Slang::setInputSource(llvm::StringRef inputFile, 164 const char *text, 165 size_t textLength) { 166 mInputFileName = inputFile.str(); 167 168 // Reset the ID tables if we are reusing the SourceManager 169 mSourceMgr->clearIDTables(); 170 171 // Load the source 172 llvm::MemoryBuffer *SB = 173 llvm::MemoryBuffer::getMemBuffer(text, text + textLength); 174 mSourceMgr->createMainFileIDForMemBuffer(SB); 175 176 if (mSourceMgr->getMainFileID().isInvalid()) { 177 mDiagnostics->Report(clang::diag::err_fe_error_reading) << inputFile; 178 return false; 179 } 180 return true; 181} 182 183bool Slang::setInputSource(llvm::StringRef inputFile) { 184 mInputFileName = inputFile.str(); 185 186 mSourceMgr->clearIDTables(); 187 188 const clang::FileEntry *File = mFileMgr->getFile(inputFile); 189 if (File) 190 mSourceMgr->createMainFileID(File); 191 192 if (mSourceMgr->getMainFileID().isInvalid()) { 193 mDiagnostics->Report(clang::diag::err_fe_error_reading) << inputFile; 194 return false; 195 } 196 197 return true; 198} 199 200void Slang::addIncludePath(const char *path) { 201 mIncludePaths.push_back(path); 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, 261 Error, 262 llvm::raw_fd_ostream::F_Binary)); 263 break; 264 } 265 } 266 267 if (!Error.empty()) { 268 mOS.reset(); 269 mDiagnostics->Report(clang::diag::err_fe_error_opening) << outputFile 270 << Error; 271 return false; 272 } 273 274 mOutputFileName = outputFile; 275 276 return true; 277} 278 279int Slang::compile() { 280 if ((mDiagnostics->getNumErrors() > 0) || (mOS.get() == NULL)) 281 return mDiagnostics->getNumErrors(); 282 283 // Here is per-compilation needed initialization 284 createPreprocessor(); 285 createASTContext(); 286 createRSContext(); 287 //createBackend(); 288 createRSBackend(); 289 290 // Inform the diagnostic client we are processing a source file 291 mDiagClient->BeginSourceFile(LangOpts, mPP.get()); 292 293 // The core of the slang compiler 294 ParseAST(*mPP, mBackend.get(), *mASTContext); 295 296 // The compilation ended, clear up 297 mBackend.reset(); 298 // Can't reset yet because the reflection later on still needs mRSContext 299 //mRSContext.reset(); 300 mASTContext.reset(); 301 mPP.reset(); 302 303 // Inform the diagnostic client we are done with previous source file 304 mDiagClient->EndSourceFile(); 305 306 return mDiagnostics->getNumErrors(); 307} 308 309bool Slang::reflectToJava(const char *outputPackageName, 310 char *realPackageName, 311 int bSize) { 312 if (mRSContext.get()) 313 return mRSContext->reflectToJava(outputPackageName, 314 mInputFileName, 315 mOutputFileName, 316 realPackageName, 317 bSize); 318 else 319 return false; 320} 321 322bool Slang::reflectToJavaPath(const char *outputPathName) { 323 if (mRSContext.get()) 324 return mRSContext->reflectToJavaPath(outputPathName); 325 else 326 return false; 327} 328 329void Slang::getPragmas(size_t *actualStringCount, 330 size_t maxStringCount, 331 char **strings) { 332 unsigned stringCount = mPragmas.size() * 2; 333 334 if (actualStringCount) 335 *actualStringCount = stringCount; 336 if (stringCount > maxStringCount) 337 stringCount = maxStringCount; 338 if (strings) 339 for (PragmaList::const_iterator it = mPragmas.begin(); 340 stringCount > 0; 341 stringCount -= 2, it++) { 342 *strings++ = const_cast<char*>(it->first.c_str()); 343 *strings++ = const_cast<char*>(it->second.c_str()); 344 } 345 346 return; 347} 348 349typedef std::list<RSExportFunc*> ExportFuncList; 350 351const char* Slang::exportFuncs() { 352 std::string fNames; 353 for (RSContext::const_export_func_iterator 354 I = mRSContext->export_funcs_begin(), 355 E = mRSContext->export_funcs_end(); 356 I != E; 357 I++) { 358 RSExportFunc* func = *I; 359 fNames.push_back(','); 360 fNames.append(func->getName()); 361 } 362 return fNames.c_str(); 363} 364 365Slang::~Slang() { 366 llvm::llvm_shutdown(); 367 return; 368} 369