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 | 120 ++++++++++++++++++++++++++++++++++++ backend/src/backend/program.cpp | 33 +++++++--- backend/src/backend/program.h | 28 +++++++++ src/cl_api.c | 33 ++++++++++ src/cl_gbe_loader.cpp | 12 ++++ src/cl_program.c | 69 ++++++++++++++++----- src/cl_program.h | 7 +++ 7 files changed, 277 insertions(+), 25 deletions(-) diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp index 33f2ed6..d7cb898 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" @@ -232,6 +235,120 @@ 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) + { +#ifdef GBE_COMPILER_AVAILABLE + 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 +#endif + } + + 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; + + 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); + } +#endif + } + } /* namespace gbe */ void genSetupCallBacks(void) @@ -239,4 +356,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 5af66fb..0014b6d 100644 --- a/backend/src/backend/program.cpp +++ b/backend/src/backend/program.cpp @@ -971,27 +971,20 @@ namespace gbe { fclose(clFile); gbe_program p; - // will delete the module and llvm_ctx in the destructor of GenProgram. + // will delete the module in the destructor of GenProgram. llvm::Module * out_module; llvm::LLVMContext* llvm_ctx = &llvm::getGlobalContext(); if (buildModuleFromSource(clName.c_str(), &out_module, llvm_ctx, clOpt.c_str(), stringSize, err, errSize)) { // Now build the program from llvm - static std::mutex gbe_mutex; - gbe_mutex.lock(); - size_t clangErrSize = 0; if (err != NULL) { GBE_ASSERT(errSize != NULL); stringSize -= *errSize; err += *errSize; - clangErrSize = *errSize; } p = gbe_program_new_gen_program(deviceID, out_module, NULL); - if (err != NULL) - *errSize += clangErrSize; - gbe_mutex.unlock(); if (OCL_OUTPUT_BUILD_LOG && options) llvm::errs() << options; } else @@ -1001,6 +994,25 @@ namespace gbe { } #endif +#ifdef GBE_COMPILER_AVAILABLE + static void programLinkProgram(gbe_program dst_program, + gbe_program src_program, + size_t stringSize, + char * err, + size_t * errSize) + { + static std::mutex gbe_mutex; + gbe_mutex.lock(); + + gbe_program_link_from_llvm(dst_program, src_program, stringSize, err, errSize); + + gbe_mutex.unlock(); + + if (OCL_OUTPUT_BUILD_LOG && err) + llvm::errs() << err; + } +#endif + static size_t programGetGlobalConstantSize(gbe_program gbeProgram) { if (gbeProgram == NULL) return 0; const gbe::Program *program = (const gbe::Program*) gbeProgram; @@ -1166,9 +1178,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; @@ -1209,6 +1225,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 45754c4..856e04d 100644 --- a/backend/src/backend/program.h +++ b/backend/src/backend/program.h @@ -130,6 +130,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); @@ -150,6 +157,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 790fbff..b529a0a 100644 --- a/src/cl_api.c +++ b/src/cl_api.c @@ -973,6 +973,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_gbe_loader.cpp b/src/cl_gbe_loader.cpp index 71c1492..cb9e397 100644 --- a/src/cl_gbe_loader.cpp +++ b/src/cl_gbe_loader.cpp @@ -45,6 +45,18 @@ struct GbeLoaderInitializer if (gbe_program_compile_from_source == NULL) return; + gbe_program_new_gen_program = *(gbe_program_new_gen_program_cb **)dlsym(dlh, "gbe_program_new_gen_program"); + if (gbe_program_new_gen_program == NULL) + return; + + gbe_program_link_program = *(gbe_program_link_program_cb **)dlsym(dlh, "gbe_program_link_program"); + if (gbe_program_link_program == NULL) + return; + + gbe_program_build_from_llvm = *(gbe_program_build_from_llvm_cb **)dlsym(dlh, "gbe_program_build_from_llvm"); + if (gbe_program_build_from_llvm == NULL) + return; + gbe_program_serialize_to_binary = *(gbe_program_serialize_to_binary_cb **)dlsym(dlh, "gbe_program_serialize_to_binary"); if (gbe_program_serialize_to_binary == NULL) return; diff --git a/src/cl_program.c b/src/cl_program.c index 9fd202a..59c0e83 100644 --- a/src/cl_program.c +++ b/src/cl_program.c @@ -452,6 +452,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, @@ -461,7 +510,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; @@ -529,26 +577,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 a576d37..49a4f48 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
