From: Luo <[email protected]> this API links a set of compiled program objects and libraries for all the devices or a specific device(s) in the OpenCL context and creates an executable. the llvm bitcode in the compiled program objects are linked together and built to Gen binary.
Signed-off-by: Luo <[email protected]> --- backend/src/backend/gen_program.cpp | 116 ++++++++++++++++++++++++++++++++++++ backend/src/backend/program.cpp | 23 ++++++- backend/src/backend/program.h | 28 +++++++++ src/cl_api.c | 33 ++++++++++ src/cl_program.c | 69 +++++++++++++++------ src/cl_program.h | 7 +++ 6 files changed, 257 insertions(+), 19 deletions(-) diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp index 7019060..dc885d5 100644 --- a/backend/src/backend/gen_program.cpp +++ b/backend/src/backend/gen_program.cpp @@ -33,6 +33,9 @@ #include "llvm/IR/DataLayout.h" #endif /* LLVM_VERSION_MINOR <= 2 */ +#include "llvm/Linker.h" +#include "llvm/Transforms/Utils/Cloning.h" + #include "backend/program.h" #include "backend/gen_program.h" #include "backend/gen_program.hpp" @@ -222,6 +225,116 @@ namespace gbe { // Everything run fine return (gbe_program) program; } + + static gbe_program genProgramNewGenProgram(uint32_t deviceID, const void* module, const void* llvm_ctx) + { + using namespace gbe; + GenProgram *program = GBE_NEW(GenProgram, deviceID, module, llvm_ctx); + // Everything run fine + return (gbe_program) program; + } + + static void genProgramLinkFromLLVM(gbe_program dst_program, + gbe_program src_program, + size_t stringSize, + char * err, + size_t * errSize) + { + using namespace gbe; + std::string errMsg; + if(((GenProgram*)dst_program)->module == NULL){ + ((GenProgram*)dst_program)->module = llvm::CloneModule((llvm::Module*)((GenProgram*)src_program)->module); + errSize = 0; + }else{ + llvm::Module* src = (llvm::Module*)((GenProgram*)src_program)->module; + llvm::GlobalVariable* gv = src->getNamedGlobal("PIo2"); + gv->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + gv = src->getNamedGlobal("npio2_hw"); + gv->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + gv = src->getNamedGlobal("two_over_pi"); + gv->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + gv = src->getNamedGlobal("atanhi"); + gv->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + gv = src->getNamedGlobal("atanlo"); + gv->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + + llvm::Function* fc = src->getFunction("barrier"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memset_p"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memset_g"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memset_l"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memcpy_gg"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memcpy_gp"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memcpy_gl"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memcpy_pg"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memcpy_pp"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memcpy_pl"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memcpy_lg"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memcpy_lp"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + fc = src->getFunction("__gen_memcpy_ll"); + fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + + llvm::Module* dst = (llvm::Module*)((GenProgram*)dst_program)->module; + llvm::Linker::LinkModules( dst, + src, + llvm::Linker::PreserveSource, + &errMsg); + if (errMsg.c_str() != NULL) { + if (err != NULL && errSize != NULL && stringSize > 0u) { + if(errMsg.length() < stringSize ) + stringSize = errMsg.length(); + strcpy(err, errMsg.c_str()); + err[stringSize+1] = '\0'; + } + } + printf("%s\n", err); + } + // Everything run fine + } + + static void genProgramBuildFromLLVM(gbe_program program, + size_t stringSize, + char *err, + size_t *errSize, + const char * options) + { + using namespace gbe; + std::string error; + + int optLevel = 1; + + if(options) { + char *p; + p = strstr(const_cast<char *>(options), "-cl-opt-disable"); + if (p) + optLevel = 0; + } + + GenProgram* p = (GenProgram*) program; + // Try to compile the program + llvm::Module* module = (llvm::Module*)p->module; + + if (p->buildFromLLVMFile(NULL, 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(p); + } + } + } /* namespace gbe */ void genSetupCallBacks(void) @@ -229,4 +342,7 @@ void genSetupCallBacks(void) gbe_program_new_from_binary = gbe::genProgramNewFromBinary; 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; } diff --git a/backend/src/backend/program.cpp b/backend/src/backend/program.cpp index 18895cd..83b97ce 100644 --- a/backend/src/backend/program.cpp +++ b/backend/src/backend/program.cpp @@ -968,8 +968,9 @@ namespace gbe { err += *errSize; clangErrSize = *errSize; } - p = gbe_program_new_from_llvm(deviceID, NULL, out_module, llvm_ctx, stringSize, - err, errSize, optLevel); + + p = gbe_program_new_gen_program(deviceID, out_module, llvm_ctx); + if (err != NULL) *errSize += clangErrSize; gbe_mutex.unlock(); @@ -981,6 +982,19 @@ namespace gbe { return p; } + static void programLinkProgram(gbe_program dst_program, + gbe_program src_program, + size_t stringSize, + char * err, + size_t * errSize) + { + + gbe_program_link_from_llvm(dst_program, src_program, stringSize, err, errSize); + + if (OCL_OUTPUT_BUILD_LOG && err) + llvm::errs() << err; + } + static size_t programGetGlobalConstantSize(gbe_program gbeProgram) { if (gbeProgram == NULL) return 0; const gbe::Program *program = (const gbe::Program*) gbeProgram; @@ -1146,9 +1160,13 @@ namespace gbe { GBE_EXPORT_SYMBOL gbe_program_new_from_source_cb *gbe_program_new_from_source = NULL; GBE_EXPORT_SYMBOL gbe_program_compile_from_source_cb *gbe_program_compile_from_source = NULL; +GBE_EXPORT_SYMBOL gbe_program_link_program_cb *gbe_program_link_program = NULL; GBE_EXPORT_SYMBOL gbe_program_new_from_binary_cb *gbe_program_new_from_binary = NULL; GBE_EXPORT_SYMBOL gbe_program_serialize_to_binary_cb *gbe_program_serialize_to_binary = NULL; GBE_EXPORT_SYMBOL gbe_program_new_from_llvm_cb *gbe_program_new_from_llvm = NULL; +GBE_EXPORT_SYMBOL gbe_program_new_gen_program_cb *gbe_program_new_gen_program = NULL; +GBE_EXPORT_SYMBOL gbe_program_link_from_llvm_cb *gbe_program_link_from_llvm = NULL; +GBE_EXPORT_SYMBOL gbe_program_build_from_llvm_cb *gbe_program_build_from_llvm = NULL; GBE_EXPORT_SYMBOL gbe_program_get_global_constant_size_cb *gbe_program_get_global_constant_size = NULL; GBE_EXPORT_SYMBOL gbe_program_get_global_constant_data_cb *gbe_program_get_global_constant_data = NULL; GBE_EXPORT_SYMBOL gbe_program_delete_cb *gbe_program_delete = NULL; @@ -1187,6 +1205,7 @@ namespace gbe CallBackInitializer(void) { gbe_program_new_from_source = gbe::programNewFromSource; gbe_program_compile_from_source = gbe::programCompileFromSource; + gbe_program_link_program = gbe::programLinkProgram; gbe_program_get_global_constant_size = gbe::programGetGlobalConstantSize; gbe_program_get_global_constant_data = gbe::programGetGlobalConstantData; gbe_program_delete = gbe::programDelete; diff --git a/backend/src/backend/program.h b/backend/src/backend/program.h index 8d434ba..31b6299 100644 --- a/backend/src/backend/program.h +++ b/backend/src/backend/program.h @@ -129,6 +129,13 @@ typedef gbe_program (gbe_program_compile_from_source_cb)(uint32_t deviceID, char *err, size_t *err_size); extern gbe_program_compile_from_source_cb *gbe_program_compile_from_source; +/*! link the programs. */ +typedef void (gbe_program_link_program_cb)(gbe_program dst_program, + gbe_program src_program, + size_t stringSize, + char * err, + size_t * errSize); +extern gbe_program_link_program_cb *gbe_program_link_program; /*! Create a new program from the given blob */ typedef gbe_program (gbe_program_new_from_binary_cb)(uint32_t deviceID, const char *binary, size_t size); @@ -149,6 +156,27 @@ typedef gbe_program (gbe_program_new_from_llvm_cb)(uint32_t deviceID, int optLevel); extern gbe_program_new_from_llvm_cb *gbe_program_new_from_llvm; +/*! create s new genprogram for link. */ +typedef gbe_program (gbe_program_new_gen_program_cb)(uint32_t deviceID, + const void *module, + const void *act); +extern gbe_program_new_gen_program_cb *gbe_program_new_gen_program; + +/*! link the programs from llvm level. */ +typedef void (gbe_program_link_from_llvm_cb)(gbe_program dst_program, + gbe_program src_program, + size_t stringSize, + char * err, + size_t * errSize); +extern gbe_program_link_from_llvm_cb *gbe_program_link_from_llvm; +/* build the program to gen binary */ +typedef void gbe_program_build_from_llvm_cb(gbe_program program, + size_t stringSize, + char *err, + size_t *errSize, + const char * options); +extern gbe_program_build_from_llvm_cb *gbe_program_build_from_llvm; + /*! Get the size of global constants */ typedef size_t (gbe_program_get_global_constant_size_cb)(gbe_program gbeProgram); extern gbe_program_get_global_constant_size_cb *gbe_program_get_global_constant_size; diff --git a/src/cl_api.c b/src/cl_api.c index 36b523a..9a3f5ea 100644 --- a/src/cl_api.c +++ b/src/cl_api.c @@ -937,6 +937,39 @@ error: return err; } +cl_program +clLinkProgram(cl_context context, + cl_uint num_devices, + const cl_device_id * device_list, + const char * options, + cl_uint num_input_programs, + const cl_program * input_programs, + void (CL_CALLBACK * pfn_notify)(cl_program program, void * user_data), + void * user_data, + cl_int * errcode_ret) +{ + cl_int err = CL_SUCCESS; + cl_program program; + CHECK_CONTEXT (context); + INVALID_VALUE_IF (num_devices > 1); + INVALID_VALUE_IF (num_devices == 0 && device_list != NULL); + INVALID_VALUE_IF (num_devices != 0 && device_list == NULL); + INVALID_VALUE_IF (pfn_notify == 0 && user_data != NULL); + INVALID_VALUE_IF (num_input_programs == 0 && input_programs != NULL); + INVALID_VALUE_IF (num_input_programs != 0 && input_programs == NULL); + + program = cl_program_link(context, num_input_programs, input_programs, options, &err); + + program->is_built = CL_TRUE; + + if (pfn_notify) pfn_notify(program, user_data); + +error: + if (errcode_ret) + *errcode_ret = err; + return program; +} + cl_int clUnloadCompiler(void) { diff --git a/src/cl_program.c b/src/cl_program.c index ed486d0..95ab68d 100644 --- a/src/cl_program.c +++ b/src/cl_program.c @@ -446,6 +446,55 @@ error: return err; } +cl_program +cl_program_link(cl_context context, + cl_uint num_input_programs, + const cl_program * input_programs, + const char * options, + cl_int* errcode_ret) +{ + cl_program p = NULL; + cl_int err=CL_SUCCESS; + cl_int i = 0; + int copyed = 0; + p = cl_program_new(context); + + p->opaque = gbe_program_new_gen_program(context->device->vendor_id, NULL, NULL); + + for(i = 0; i < num_input_programs; i++) { + if(input_programs[i]) + gbe_program_link_program(p->opaque, input_programs[i]->opaque, + p->build_log_max_sz, p->build_log, &p->build_log_sz); + if (UNLIKELY(p->opaque == NULL)) { + err = CL_LINK_PROGRAM_FAILURE; + goto error; + } + } + + gbe_program_build_from_llvm(p->opaque, p->build_log_max_sz, p->build_log, &p->build_log_sz, options); + + /* Create all the kernels */ + TRY (cl_program_load_gen_program, p); + + for (i = 0; i < p->ker_n; i ++) { + const gbe_kernel opaque = gbe_program_get_kernel(p->opaque, i); + p->bin_sz += gbe_kernel_get_code_size(opaque); + } + + TRY_ALLOC (p->bin, cl_calloc(p->bin_sz, sizeof(char))); + for (i = 0; i < p->ker_n; i ++) { + const gbe_kernel opaque = gbe_program_get_kernel(p->opaque, i); + size_t sz = gbe_kernel_get_code_size(opaque); + + memcpy(p->bin + copyed, gbe_kernel_get_code(opaque), sz); + copyed += sz; + } + +error: + p->is_built = 1; + return p; +} + LOCAL cl_int cl_program_compile(cl_program p, cl_uint num_input_headers, @@ -455,7 +504,6 @@ cl_program_compile(cl_program p, { cl_int err = CL_SUCCESS; int i = 0; - int copyed = 0; if (p->ref_n > 1) return CL_INVALID_OPERATION; @@ -523,26 +571,13 @@ cl_program_compile(cl_program p, } /* Create all the kernels */ - TRY (cl_program_load_gen_program, p); p->source_type = FROM_LLVM; } - - for (i = 0; i < p->ker_n; i ++) { - const gbe_kernel opaque = gbe_program_get_kernel(p->opaque, i); - p->bin_sz += gbe_kernel_get_code_size(opaque); - } - - TRY_ALLOC (p->bin, cl_calloc(p->bin_sz, sizeof(char))); - for (i = 0; i < p->ker_n; i ++) { - const gbe_kernel opaque = gbe_program_get_kernel(p->opaque, i); - size_t sz = gbe_kernel_get_code_size(opaque); - - memcpy(p->bin + copyed, gbe_kernel_get_code(opaque), sz); - copyed += sz; - } + return CL_SUCCESS; error: - p->is_built = 1; + cl_program_delete(p); + p = NULL; return err; } diff --git a/src/cl_program.h b/src/cl_program.h index 1e156c7..f54532a 100644 --- a/src/cl_program.h +++ b/src/cl_program.h @@ -117,5 +117,12 @@ cl_program_compile(cl_program p, const cl_program * input_headers, const char ** header_include_names, const char* options); +/* link the program as specified by OCL */ +extern cl_program +cl_program_link(cl_context context, + cl_uint num_input_programs, + const cl_program * input_programs, + const char * options, + cl_int* errcode_ret); #endif /* __CL_PROGRAM_H__ */ -- 1.8.1.2 _______________________________________________ Beignet mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/beignet
