[Beignet] [PATCH 3/4] add [opencl-1.2] API clLinkProgram.
xionghu.luo at intel.com
xionghu.luo at intel.com
Tue May 27 19:52:37 PDT 2014
From: Luo <xionghu.luo at intel.com>
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 <xionghu.luo at intel.com>
---
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
More information about the Beignet
mailing list