/* * Copyright © 2012 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Author: Benjamin Segovia */ /** * \file program.cpp * \author Benjamin Segovia */ #ifdef GBE_COMPILER_AVAILABLE #include "llvm/Config/llvm-config.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/DataLayout.h" #include "llvm-c/Linker.h" #include "llvm-c/BitReader.h" #include "llvm-c/BitWriter.h" #include "llvm/Transforms/Utils/Cloning.h" #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 40 #include "llvm/Bitcode/BitcodeWriter.h" #else #include "llvm/Bitcode/ReaderWriter.h" #endif /* LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 40 */ #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/IRReader/IRReader.h" #endif #include "backend/program.h" #include "backend/gen_program.h" #include "backend/gen_program.hpp" #include "backend/gen_context.hpp" #include "backend/gen75_context.hpp" #include "backend/gen8_context.hpp" #include "backend/gen9_context.hpp" #include "backend/gen_defs.hpp" #include "backend/gen/gen_mesa_disasm.h" #include "backend/gen_reg_allocation.hpp" #include "ir/unit.hpp" #ifdef GBE_COMPILER_AVAILABLE #include "llvm/llvm_to_gen.hpp" #include "llvm/llvm_gen_backend.hpp" #include #endif #include "sys/cvar.hpp" #include #include #include #include #include #include #include namespace gbe { GenKernel::GenKernel(const std::string &name, uint32_t deviceID) : Kernel(name), deviceID(deviceID), insns(NULL), insnNum(0) {} GenKernel::~GenKernel(void) { GBE_SAFE_DELETE_ARRAY(insns); } const char *GenKernel::getCode(void) const { return (const char*) insns; } void GenKernel::setCode(const char * ins, size_t size) { insns = (GenInstruction *)ins; insnNum = size / sizeof(GenInstruction); } uint32_t GenKernel::getCodeSize(void) const { return insnNum * sizeof(GenInstruction); } void GenKernel::printStatus(int indent, std::ostream& outs) { #ifdef GBE_COMPILER_AVAILABLE Kernel::printStatus(indent, outs); FILE *f = fopen("/dev/null", "w"); if(!f) { outs << "could not open /dev/null !"; return; } char *buf = new char[4096]; setbuffer(f, buf, 4096); GenCompactInstruction * pCom = NULL; GenInstruction insn[2]; uint32_t insn_version = 0; if (IS_GEN7(deviceID) || IS_GEN75(deviceID)) insn_version = 7; else if (IS_GEN8(deviceID) || IS_GEN9(deviceID)) insn_version = 8; for (uint32_t i = 0; i < insnNum;) { pCom = (GenCompactInstruction*)(insns+i); if(pCom->bits1.cmpt_control == 1) { decompactInstruction(pCom, &insn, insn_version); gen_disasm(f, &insn, deviceID, 1); i++; } else { gen_disasm(f, insns+i, deviceID, 0); i = i + 2; } outs << buf; fflush(f); setbuffer(f, NULL, 0); setbuffer(f, buf, 4096); } setbuffer(f, NULL, 0); delete [] buf; fclose(f); #endif } void GenProgram::CleanLlvmResource(void){ #ifdef GBE_COMPILER_AVAILABLE llvm::LLVMContext* ctx = NULL; if(module){ ctx = &((llvm::Module*)module)->getContext(); (void)ctx; delete (llvm::Module*)module; module = NULL; } //llvm's version < 3.9, ctx is global ctx, can't be deleted. #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39 //each module's context is individual, just delete it, ignaor llvm_ctx. if (ctx != NULL) delete ctx; #else if(llvm_ctx){ delete (llvm::LLVMContext*)llvm_ctx; llvm_ctx = NULL; } #endif #endif } /*! We must avoid spilling at all cost with Gen */ struct CodeGenStrategy { uint32_t simdWidth; uint32_t reservedSpillRegs; bool limitRegisterPressure; }; static const struct CodeGenStrategy codeGenStrategyDefault[] = { {16, 0, false}, {8, 0, false}, {8, 8, false}, {8, 16, false}, }; static const struct CodeGenStrategy codeGenStrategySimd16[] = { {16, 0, false}, {16, 8, false}, {16, 16, false}, }; IVAR(OCL_SIMD_WIDTH, 8, 15, 16); Kernel *GenProgram::compileKernel(const ir::Unit &unit, const std::string &name, bool relaxMath, int profiling) { #ifdef GBE_COMPILER_AVAILABLE // Be careful when the simdWidth is forced by the programmer. We can see it // when the function already provides the simd width we need to use (i.e. // non zero) const ir::Function *fn = unit.getFunction(name); const struct CodeGenStrategy* codeGenStrategy = codeGenStrategyDefault; if(fn == NULL) GBE_ASSERT(0); uint32_t codeGenNum = sizeof(codeGenStrategyDefault) / sizeof(codeGenStrategyDefault[0]); uint32_t codeGen = 0; GenContext *ctx = NULL; if ( fn->getSimdWidth() != 0 && OCL_SIMD_WIDTH != 15) { GBE_ASSERTM(0, "unsupported SIMD width!"); }else if (fn->getSimdWidth() == 8 || OCL_SIMD_WIDTH == 8) { codeGen = 1; } else if (fn->getSimdWidth() == 16 || OCL_SIMD_WIDTH == 16){ codeGenStrategy = codeGenStrategySimd16; codeGenNum = sizeof(codeGenStrategySimd16) / sizeof(codeGenStrategySimd16[0]); } else if (fn->getSimdWidth() == 0 && OCL_SIMD_WIDTH == 15) { codeGen = 0; } else GBE_ASSERTM(0, "unsupported SIMD width!"); Kernel *kernel = NULL; // Stop when compilation is successful if (IS_IVYBRIDGE(deviceID)) { ctx = GBE_NEW(GenContext, unit, name, deviceID, relaxMath); } else if (IS_HASWELL(deviceID)) { ctx = GBE_NEW(Gen75Context, unit, name, deviceID, relaxMath); } else if (IS_BROADWELL(deviceID)) { ctx = GBE_NEW(Gen8Context, unit, name, deviceID, relaxMath); } else if (IS_CHERRYVIEW(deviceID)) { ctx = GBE_NEW(ChvContext, unit, name, deviceID, relaxMath); } else if (IS_SKYLAKE(deviceID)) { ctx = GBE_NEW(Gen9Context, unit, name, deviceID, relaxMath); } else if (IS_BROXTON(deviceID)) { ctx = GBE_NEW(BxtContext, unit, name, deviceID, relaxMath); } else if (IS_KABYLAKE(deviceID)) { ctx = GBE_NEW(KblContext, unit, name, deviceID, relaxMath); } else if (IS_COFFEELAKE(deviceID)) { ctx = GBE_NEW(KblContext, unit, name, deviceID, relaxMath); } else if (IS_GEMINILAKE(deviceID)) { ctx = GBE_NEW(GlkContext, unit, name, deviceID, relaxMath); } GBE_ASSERTM(ctx != NULL, "Fail to create the gen context\n"); if (profiling) { ctx->setProfilingMode(true); unit.getProfilingInfo()->setDeviceID(deviceID); } ctx->setASMFileName(this->asm_file_name); for (; codeGen < codeGenNum; ++codeGen) { const uint32_t simdWidth = codeGenStrategy[codeGen].simdWidth; const bool limitRegisterPressure = codeGenStrategy[codeGen].limitRegisterPressure; const uint32_t reservedSpillRegs = codeGenStrategy[codeGen].reservedSpillRegs; // Force the SIMD width now and try to compile ir::Function *simdFn = unit.getFunction(name); if(simdFn == NULL) GBE_ASSERT(0); simdFn->setSimdWidth(simdWidth); ctx->startNewCG(simdWidth, reservedSpillRegs, limitRegisterPressure); kernel = ctx->compileKernel(); if (kernel != NULL) { GBE_ASSERT(ctx->getErrCode() == NO_ERROR); kernel->setOclVersion(unit.getOclVersion()); break; } simdFn->getImageSet()->clearInfo(); // If we get a out of range if/endif error. // We need to set the context to if endif fix mode and restart the previous compile. if ( ctx->getErrCode() == OUT_OF_RANGE_IF_ENDIF && !ctx->getIFENDIFFix() ) { ctx->setIFENDIFFix(true); codeGen--; } else GBE_ASSERT(!(ctx->getErrCode() == OUT_OF_RANGE_IF_ENDIF && ctx->getIFENDIFFix())); } //GBE_ASSERTM(kernel != NULL, "Fail to compile kernel, may need to increase reserved registers for spilling."); return kernel; #else return NULL; #endif } #define GEN_BINARY_HEADER_LENGTH 8 enum GEN_BINARY_HEADER_INDEX { GBHI_BYT = 0, GBHI_IVB = 1, GBHI_HSW = 2, GBHI_CHV = 3, GBHI_BDW = 4, GBHI_SKL = 5, GBHI_BXT = 6, GBHI_KBL = 7, GBHI_GLK = 8, GBHI_MAX, }; #define GEN_BINARY_VERSION 1 static const unsigned char gen_binary_header[GBHI_MAX][GEN_BINARY_HEADER_LENGTH]= \ {{GEN_BINARY_VERSION, 'G','E', 'N', 'C', 'B', 'Y', 'T'}, {GEN_BINARY_VERSION, 'G','E', 'N', 'C', 'I', 'V', 'B'}, {GEN_BINARY_VERSION, 'G','E', 'N', 'C', 'H', 'S', 'W'}, {GEN_BINARY_VERSION, 'G','E', 'N', 'C', 'C', 'H', 'V'}, {GEN_BINARY_VERSION, 'G','E', 'N', 'C', 'B', 'D', 'W'}, {GEN_BINARY_VERSION, 'G','E', 'N', 'C', 'S', 'K', 'L'}, {GEN_BINARY_VERSION, 'G','E', 'N', 'C', 'B', 'X', 'T'}, {GEN_BINARY_VERSION, 'G','E', 'N', 'C', 'K', 'B', 'T'}, {GEN_BINARY_VERSION, 'G','E', 'N', 'C', 'G', 'L', 'K'} }; #define FILL_GEN_HEADER(binary, index) do {int i = 0; do {*(binary+i) = gen_binary_header[index][i]; i++; }while(i < GEN_BINARY_HEADER_LENGTH);}while(0) #define FILL_BYT_HEADER(binary) FILL_GEN_HEADER(binary, GBHI_BYT) #define FILL_IVB_HEADER(binary) FILL_GEN_HEADER(binary, GBHI_IVB) #define FILL_HSW_HEADER(binary) FILL_GEN_HEADER(binary, GBHI_HSW) #define FILL_CHV_HEADER(binary) FILL_GEN_HEADER(binary, GBHI_CHV) #define FILL_BDW_HEADER(binary) FILL_GEN_HEADER(binary, GBHI_BDW) #define FILL_SKL_HEADER(binary) FILL_GEN_HEADER(binary, GBHI_SKL) #define FILL_BXT_HEADER(binary) FILL_GEN_HEADER(binary, GBHI_BXT) #define FILL_KBL_HEADER(binary) FILL_GEN_HEADER(binary, GBHI_KBL) #define FILL_GLK_HEADER(binary) FILL_GEN_HEADER(binary, GBHI_GLK) static bool genHeaderCompare(const unsigned char *BufPtr, GEN_BINARY_HEADER_INDEX index) { bool matched = true; for (int i = 1; i < GEN_BINARY_HEADER_LENGTH; ++i) { matched = matched && (BufPtr[i] == gen_binary_header[index][i]); } if(matched) { if(BufPtr[0] != gen_binary_header[index][0]) { std::cout << "Beignet binary format have been changed, please generate binary again.\n"; matched = false; } } return matched; } #define MATCH_BYT_HEADER(binary) genHeaderCompare(binary, GBHI_BYT) #define MATCH_IVB_HEADER(binary) genHeaderCompare(binary, GBHI_IVB) #define MATCH_HSW_HEADER(binary) genHeaderCompare(binary, GBHI_HSW) #define MATCH_CHV_HEADER(binary) genHeaderCompare(binary, GBHI_CHV) #define MATCH_BDW_HEADER(binary) genHeaderCompare(binary, GBHI_BDW) #define MATCH_SKL_HEADER(binary) genHeaderCompare(binary, GBHI_SKL) #define MATCH_BXT_HEADER(binary) genHeaderCompare(binary, GBHI_BXT) #define MATCH_KBL_HEADER(binary) genHeaderCompare(binary, GBHI_KBL) #define MATCH_GLK_HEADER(binary) genHeaderCompare(binary, GBHI_GLK) #define MATCH_DEVICE(deviceID, binary) ((IS_IVYBRIDGE(deviceID) && MATCH_IVB_HEADER(binary)) || \ (IS_IVYBRIDGE(deviceID) && MATCH_IVB_HEADER(binary)) || \ (IS_BAYTRAIL_T(deviceID) && MATCH_BYT_HEADER(binary)) || \ (IS_HASWELL(deviceID) && MATCH_HSW_HEADER(binary)) || \ (IS_BROADWELL(deviceID) && MATCH_BDW_HEADER(binary)) || \ (IS_CHERRYVIEW(deviceID) && MATCH_CHV_HEADER(binary)) || \ (IS_SKYLAKE(deviceID) && MATCH_SKL_HEADER(binary)) || \ (IS_BROXTON(deviceID) && MATCH_BXT_HEADER(binary)) || \ (IS_KABYLAKE(deviceID) && MATCH_KBL_HEADER(binary)) || \ (IS_COFFEELAKE(deviceID) && MATCH_KBL_HEADER(binary)) || \ (IS_GEMINILAKE(deviceID) && MATCH_GLK_HEADER(binary)) \ ) static gbe_program genProgramNewFromBinary(uint32_t deviceID, const char *binary, size_t size) { using namespace gbe; std::string binary_content; if(size < GEN_BINARY_HEADER_LENGTH) return NULL; //the header length is 8 bytes: 1 byte is binary type, 4 bytes are bitcode header, 3 bytes are hw info. if(!MATCH_DEVICE(deviceID, (unsigned char*)binary)){ return NULL; } binary_content.assign(binary+GEN_BINARY_HEADER_LENGTH, size-GEN_BINARY_HEADER_LENGTH); GenProgram *program = GBE_NEW(GenProgram, deviceID); std::istringstream ifs(binary_content, std::ostringstream::binary); if (!program->deserializeFromBin(ifs)) { delete program; return NULL; } //program->printStatus(0, std::cout); return reinterpret_cast(program); } static gbe_program genProgramNewFromLLVMBinary(uint32_t deviceID, const char *binary, size_t size) { #ifdef GBE_COMPILER_AVAILABLE using namespace gbe; std::string binary_content; //the first byte stands for binary_type. binary_content.assign(binary+1, size-1); llvm::StringRef llvm_bin_str(binary_content); #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39 llvm::LLVMContext *c = new llvm::LLVMContext; #else llvm::LLVMContext *c = &llvm::getGlobalContext(); #endif llvm::SMDiagnostic Err; #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 36 std::unique_ptr memory_buffer = llvm::MemoryBuffer::getMemBuffer(llvm_bin_str, "llvm_bin_str"); acquireLLVMContextLock(); llvm::Module* module = llvm::parseIR(memory_buffer->getMemBufferRef(), Err, *c).release(); #else llvm::MemoryBuffer* memory_buffer = llvm::MemoryBuffer::getMemBuffer(llvm_bin_str, "llvm_bin_str"); acquireLLVMContextLock(); llvm::Module* module = llvm::ParseIR(memory_buffer, Err, *c); #endif // if load 32 bit spir binary, the triple should be spir-unknown-unknown. llvm::Triple triple(module->getTargetTriple()); if (triple.getArchName() == "spir" && triple.getVendorName() == "unknown" && triple.getOSName() == "unknown"){ module->setTargetTriple("spir"); } else if (triple.getArchName() == "spir64" && triple.getVendorName() == "unknown" && triple.getOSName() == "unknown"){ module->setTargetTriple("spir64"); } releaseLLVMContextLock(); if(module == NULL){ GBE_ASSERT(0); } GenProgram *program = GBE_NEW(GenProgram, deviceID, module); //program->printStatus(0, std::cout); return reinterpret_cast(program); #else return NULL; #endif } static size_t genProgramSerializeToBinary(gbe_program program, char **binary, int binary_type) { using namespace gbe; size_t sz; std::ostringstream oss; GenProgram *prog = (GenProgram*)program; //0 means GEN binary, 1 means LLVM bitcode compiled object, 2 means LLVM bitcode library if(binary_type == 0){ if ((sz = prog->serializeToBin(oss)) == 0) { *binary = NULL; return 0; } //add header to differetiate from llvm bitcode binary. //the header length is 8 bytes: 1 byte is binary type, 4 bytes are bitcode header, 3 bytes are hw info. *binary = (char *)malloc(sizeof(char) * (sz+GEN_BINARY_HEADER_LENGTH) ); if(*binary == NULL) return 0; memset(*binary, 0, sizeof(char) * (sz+GEN_BINARY_HEADER_LENGTH) ); if(IS_IVYBRIDGE(prog->deviceID)){ FILL_IVB_HEADER(*binary); if(IS_BAYTRAIL_T(prog->deviceID)){ FILL_BYT_HEADER(*binary); } }else if(IS_HASWELL(prog->deviceID)){ FILL_HSW_HEADER(*binary); }else if(IS_BROADWELL(prog->deviceID)){ FILL_BDW_HEADER(*binary); }else if(IS_CHERRYVIEW(prog->deviceID)){ FILL_CHV_HEADER(*binary); }else if(IS_SKYLAKE(prog->deviceID)){ FILL_SKL_HEADER(*binary); }else if(IS_BROXTON(prog->deviceID)){ FILL_BXT_HEADER(*binary); }else if(IS_KABYLAKE(prog->deviceID)){ FILL_KBL_HEADER(*binary); }else if(IS_COFFEELAKE(prog->deviceID)){ FILL_KBL_HEADER(*binary); }else if(IS_GEMINILAKE(prog->deviceID)){ FILL_GLK_HEADER(*binary); }else { free(*binary); *binary = NULL; return 0; } memcpy(*binary+GEN_BINARY_HEADER_LENGTH, oss.str().c_str(), sz*sizeof(char)); return sz+GEN_BINARY_HEADER_LENGTH; }else{ #ifdef GBE_COMPILER_AVAILABLE std::string str; llvm::raw_string_ostream OS(str); llvm::WriteBitcodeToFile((llvm::Module*)prog->module, OS); std::string& bin_str = OS.str(); int llsz = bin_str.size(); *binary = (char *)malloc(sizeof(char) * (llsz+1) ); if(*binary == NULL) return 0; *(*binary) = binary_type; memcpy(*binary+1, bin_str.c_str(), llsz); return llsz+1; #else return 0; #endif } } static gbe_program genProgramNewFromLLVM(uint32_t deviceID, const void* module, const void* llvm_ctx, const char* asm_file_name, size_t stringSize, char *err, size_t *errSize, int optLevel, const char* options) { using namespace gbe; uint32_t fast_relaxed_math = 0; if (options != NULL) if (strstr(options, "-cl-fast-relaxed-math") != NULL) fast_relaxed_math = 1; GenProgram *program = GBE_NEW(GenProgram, deviceID, module, llvm_ctx, asm_file_name, fast_relaxed_math); #ifdef GBE_COMPILER_AVAILABLE std::string error; // Try to compile the program if (program->buildFromLLVMModule(module, error, optLevel) == false) { if (err != NULL && errSize != NULL && stringSize > 0u) { const size_t msgSize = std::min(error.size(), stringSize-1u); std::memcpy(err, error.c_str(), msgSize); *errSize = error.size(); } GBE_DELETE(program); return NULL; } #endif // Everything run fine return (gbe_program) program; } static gbe_program genProgramNewGenProgram(uint32_t deviceID, const void* module, const void* llvm_ctx,const char* asm_file_name) { using namespace gbe; GenProgram *program = GBE_NEW(GenProgram, deviceID, module, llvm_ctx, asm_file_name); // Everything run fine return (gbe_program) program; } static bool genProgramLinkFromLLVM(gbe_program dst_program, gbe_program src_program, size_t stringSize, char * err, size_t * errSize) { #ifdef GBE_COMPILER_AVAILABLE using namespace gbe; char* errMsg = NULL; if(((GenProgram*)dst_program)->module == NULL){ #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39 LLVMModuleRef modRef; LLVMParseBitcodeInContext2(wrap(new llvm::LLVMContext()), LLVMWriteBitcodeToMemoryBuffer(wrap((llvm::Module*)((GenProgram*)src_program)->module)), &modRef); ((GenProgram*)dst_program)->module = llvm::unwrap(modRef); #elif LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 38 ((GenProgram*)dst_program)->module = llvm::CloneModule((llvm::Module*)((GenProgram*)src_program)->module).release(); #else ((GenProgram*)dst_program)->module = llvm::CloneModule((llvm::Module*)((GenProgram*)src_program)->module); #endif errSize = 0; } else { llvm::Module* src = (llvm::Module*)((GenProgram*)src_program)->module; llvm::Module* dst = (llvm::Module*)((GenProgram*)dst_program)->module; #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39 if (&src->getContext() != &dst->getContext()) { LLVMModuleRef modRef; LLVMParseBitcodeInContext2(wrap(&dst->getContext()), LLVMWriteBitcodeToMemoryBuffer(wrap(src)), &modRef); src = llvm::unwrap(modRef); } llvm::Module* clone = llvm::CloneModule(src).release(); if (LLVMLinkModules2(wrap(dst), wrap(clone))) { #elif LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 37 if (LLVMLinkModules(wrap(dst), wrap(src), LLVMLinkerPreserveSource_Removed, &errMsg)) { #else if (LLVMLinkModules(wrap(dst), wrap(src), LLVMLinkerPreserveSource, &errMsg)) { #endif if (err != NULL && errSize != NULL && stringSize > 0u && errMsg) { strncpy(err, errMsg, stringSize-1); err[stringSize-1] = '\0'; *errSize = strlen(err); } return true; } } #endif return false; } static void genProgramBuildFromLLVM(gbe_program program, size_t stringSize, char *err, size_t *errSize, const char * options) { #ifdef GBE_COMPILER_AVAILABLE using namespace gbe; std::string error; int optLevel = 1; std::string dumpASMFileName; size_t start = 0, end = 0; uint32_t fast_relaxed_math = 0; if(options) { char *p; p = strstr(const_cast(options), "-cl-opt-disable"); if (p) optLevel = 0; if (options != NULL) if (strstr(options, "-cl-fast-relaxed-math") != NULL) fast_relaxed_math = 1; char *options_str = (char *)malloc(sizeof(char) * (strlen(options) + 1)); if (options_str == NULL) return; memcpy(options_str, options, strlen(options) + 1); std::string optionStr(options_str); while (end != std::string::npos) { end = optionStr.find(' ', start); std::string str = optionStr.substr(start, end - start); start = end + 1; if(str.size() == 0) continue; if(str.find("-dump-opt-asm=") != std::string::npos) { dumpASMFileName = str.substr(str.find("=") + 1); continue; // Don't push this str back; ignore it. } } free(options_str); } GenProgram* p = (GenProgram*) program; p->fast_relaxed_math = fast_relaxed_math; if (!dumpASMFileName.empty()) { p->asm_file_name = dumpASMFileName.c_str(); FILE *asmDumpStream = fopen(dumpASMFileName.c_str(), "w"); if (asmDumpStream) fclose(asmDumpStream); } // Try to compile the program acquireLLVMContextLock(); llvm::Module* module = (llvm::Module*)p->module; if (p->buildFromLLVMModule(module, error, optLevel) == false) { if (err != NULL && errSize != NULL && stringSize > 0u) { const size_t msgSize = std::min(error.size(), stringSize-1u); std::memcpy(err, error.c_str(), msgSize); *errSize = error.size(); } } releaseLLVMContextLock(); #endif } } /* namespace gbe */ void genSetupCallBacks(void) { gbe_program_new_from_binary = gbe::genProgramNewFromBinary; gbe_program_new_from_llvm_binary = gbe::genProgramNewFromLLVMBinary; gbe_program_serialize_to_binary = gbe::genProgramSerializeToBinary; gbe_program_new_from_llvm = gbe::genProgramNewFromLLVM; gbe_program_new_gen_program = gbe::genProgramNewGenProgram; gbe_program_link_from_llvm = gbe::genProgramLinkFromLLVM; gbe_program_build_from_llvm = gbe::genProgramBuildFromLLVM; }