[Beignet] [PATCH v4 1/3] add [opencl-1.2] API clCompileProgram.
xionghu.luo at intel.com
xionghu.luo at intel.com
Thu Jun 5 23:18:47 PDT 2014
From: Luo <xionghu.luo at intel.com>
This API compiles a program's source for all the devices or a specific
device in the OpenCL context associated with program.
The pre-processor runs before the program sources are compiled.
Signed-off-by: Luo <xionghu.luo at intel.com>
---
backend/src/backend/gen_program.cpp | 9 ++++
backend/src/backend/program.cpp | 60 +++++++++++++++++++++++
backend/src/backend/program.h | 20 ++++++++
src/cl_api.c | 41 ++++++++++++++++
src/cl_gbe_loader.cpp | 4 ++
src/cl_program.c | 96 +++++++++++++++++++++++++++++++++++++
src/cl_program.h | 8 +++-
7 files changed, 237 insertions(+), 1 deletion(-)
diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp
index 33f2ed6..1d19289 100644
--- a/backend/src/backend/gen_program.cpp
+++ b/backend/src/backend/gen_program.cpp
@@ -232,6 +232,14 @@ 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;
+ }
} /* namespace gbe */
void genSetupCallBacks(void)
@@ -239,4 +247,5 @@ 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;
}
diff --git a/backend/src/backend/program.cpp b/backend/src/backend/program.cpp
index d23529a..121153d 100644
--- a/backend/src/backend/program.cpp
+++ b/backend/src/backend/program.cpp
@@ -861,6 +861,52 @@ namespace gbe {
}
#endif
+#ifdef GBE_COMPILER_AVAILABLE
+
+ static gbe_program programCompileFromSource(uint32_t deviceID,
+ const char *source,
+ const char *temp_header_path,
+ size_t stringSize,
+ const char *options,
+ char *err,
+ size_t *errSize)
+ {
+ int optLevel = 1;
+ std::string clOpt;
+ std::string clName;
+ processSourceAndOption(source, options, temp_header_path, clOpt, clName, optLevel);
+
+ gbe_program p;
+ acquireLLVMContextLock();
+ //FIXME: if use new allocated context to link two modules there would be context mismatch
+ //for some functions, so we use global context now, need switch to new context later.
+ 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
+ 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;
+ if (OCL_OUTPUT_BUILD_LOG && options)
+ llvm::errs() << options;
+ } else
+ p = NULL;
+ remove(clName.c_str());
+ releaseLLVMContextLock();
+ return p;
+ }
+#endif
+
static size_t programGetGlobalConstantSize(gbe_program gbeProgram) {
if (gbeProgram == NULL) return 0;
const gbe::Program *program = (const gbe::Program*) gbeProgram;
@@ -1024,10 +1070,23 @@ namespace gbe {
}
} /* namespace gbe */
+std::mutex llvm_ctx_mutex;
+void acquireLLVMContextLock()
+{
+ llvm_ctx_mutex.lock();
+}
+
+void releaseLLVMContextLock()
+{
+ llvm_ctx_mutex.unlock();
+}
+
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_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_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;
@@ -1067,6 +1126,7 @@ namespace gbe
{
CallBackInitializer(void) {
gbe_program_new_from_source = gbe::programNewFromSource;
+ gbe_program_compile_from_source = gbe::programCompileFromSource;
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 077d0d3..5639e27 100644
--- a/backend/src/backend/program.h
+++ b/backend/src/backend/program.h
@@ -121,6 +121,22 @@ typedef gbe_program (gbe_program_new_from_source_cb)(uint32_t deviceID,
char *err,
size_t *err_size);
extern gbe_program_new_from_source_cb *gbe_program_new_from_source;
+/*! Create a new program from the given source code and compile it (zero terminated string) */
+typedef gbe_program (gbe_program_compile_from_source_cb)(uint32_t deviceID,
+ const char *source,
+ const char *temp_header_path,
+ size_t stringSize,
+ const char *options,
+ char *err,
+ size_t *err_size);
+extern gbe_program_compile_from_source_cb *gbe_program_compile_from_source;
+
+/*! 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;
+
/*! 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);
extern gbe_program_new_from_binary_cb *gbe_program_new_from_binary;
@@ -241,6 +257,10 @@ extern gbe_kernel_use_slm_cb *gbe_kernel_use_slm;
typedef int32_t (gbe_kernel_get_slm_size_cb)(gbe_kernel);
extern gbe_kernel_get_slm_size_cb *gbe_kernel_get_slm_size;
+/*mutex to lock global llvmcontext access.*/
+extern void acquireLLVMContextLock();
+extern void releaseLLVMContextLock();
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/src/cl_api.c b/src/cl_api.c
index 8598088..790fbff 100644
--- a/src/cl_api.c
+++ b/src/cl_api.c
@@ -933,6 +933,47 @@ error:
}
cl_int
+clCompileProgram(cl_program program ,
+ cl_uint num_devices ,
+ const cl_device_id * device_list ,
+ const char * options ,
+ cl_uint num_input_headers ,
+ const cl_program * input_headers ,
+ const char ** header_include_names ,
+ void (CL_CALLBACK * pfn_notify )(cl_program, void *),
+ void * user_data )
+{
+ cl_int err = CL_SUCCESS;
+ CHECK_PROGRAM(program);
+ 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_headers == 0 && input_headers != NULL);
+ INVALID_VALUE_IF (num_input_headers != 0 && input_headers == NULL);
+
+ /* Everything is easy. We only support one device anyway */
+ if (num_devices != 0) {
+ assert(program->ctx);
+ INVALID_DEVICE_IF (device_list[0] != program->ctx->device);
+ }
+
+ /* TODO support create program from binary */
+ assert(program->source_type == FROM_LLVM ||
+ program->source_type == FROM_SOURCE ||
+ program->source_type == FROM_BINARY);
+ if((err = cl_program_compile(program, num_input_headers, input_headers, header_include_names, options)) != CL_SUCCESS) {
+ goto error;
+ }
+ program->is_built = CL_TRUE;
+
+ if (pfn_notify) pfn_notify(program, user_data);
+
+error:
+ return err;
+}
+
+cl_int
clUnloadCompiler(void)
{
return CL_SUCCESS;
diff --git a/src/cl_gbe_loader.cpp b/src/cl_gbe_loader.cpp
index da83c9a..71c1492 100644
--- a/src/cl_gbe_loader.cpp
+++ b/src/cl_gbe_loader.cpp
@@ -41,6 +41,10 @@ struct GbeLoaderInitializer
if (gbe_program_new_from_source == NULL)
return;
+ gbe_program_compile_from_source = *(gbe_program_compile_from_source_cb **)dlsym(dlh, "gbe_program_compile_from_source");
+ if (gbe_program_compile_from_source == 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 6910330..88b165f 100644
--- a/src/cl_program.c
+++ b/src/cl_program.c
@@ -33,6 +33,9 @@
#include <stdint.h>
#include <string.h>
#include <assert.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libgen.h>
static void
cl_program_release_sources(cl_program p)
@@ -449,6 +452,99 @@ error:
return err;
}
+LOCAL cl_int
+cl_program_compile(cl_program p,
+ cl_uint num_input_headers,
+ const cl_program * input_headers,
+ const char ** header_include_names,
+ const char* options)
+{
+ cl_int err = CL_SUCCESS;
+ int i = 0;
+
+ if (p->ref_n > 1)
+ return CL_INVALID_OPERATION;
+
+ if (options) {
+ if(p->build_opts == NULL || strcmp(options, p->build_opts) != 0) {
+ if(p->build_opts) {
+ cl_free(p->build_opts);
+ p->build_opts = NULL;
+ }
+ TRY_ALLOC (p->build_opts, cl_calloc(strlen(options) + 1, sizeof(char)));
+ memcpy(p->build_opts, options, strlen(options));
+
+ p->source_type = p->source ? FROM_SOURCE : p->binary ? FROM_BINARY : FROM_LLVM;
+ }
+ }
+
+ if (options == NULL && p->build_opts) {
+ p->source_type = p->source ? FROM_SOURCE : p->binary ? FROM_BINARY : FROM_LLVM;
+
+ cl_free(p->build_opts);
+ p->build_opts = NULL;
+ }
+
+ const char* temp_header_path = "/tmp/beignet_header/";
+ if (p->source_type == FROM_SOURCE) {
+
+ if (!CompilerSupported()) {
+ err = CL_COMPILER_NOT_AVAILABLE;
+ goto error;
+ }
+
+ //write the headers to /tmp/beignet_header for include.
+ for (i = 0; i < num_input_headers; i++) {
+ if(header_include_names[i] == NULL || input_headers[i] == NULL)
+ continue;
+
+ char temp_path[255];
+ strcpy(temp_path, temp_header_path);
+ strcat(temp_path, header_include_names[i]);
+ char* dirc = strdup(temp_path);
+ char* dir = dirname(dirc);
+ mkdir(dir, 0755);
+ if(access(dir, R_OK|W_OK) != 0){
+ err = CL_COMPILE_PROGRAM_FAILURE;
+ goto error;
+ }
+ free(dirc);
+
+ FILE* pfile = fopen(temp_path, "wb");
+ if(pfile){
+ fwrite(input_headers[i]->source, strlen(input_headers[i]->source), 1, pfile);
+ fclose(pfile);
+ }else{
+ err = CL_COMPILE_PROGRAM_FAILURE;
+ goto error;
+ }
+ }
+
+ p->opaque = gbe_program_compile_from_source(p->ctx->device->vendor_id, p->source, temp_header_path,
+ p->build_log_max_sz, options, p->build_log, &p->build_log_sz);
+
+ system("rm /tmp/beignet_header/* -rf");
+
+ if (UNLIKELY(p->opaque == NULL)) {
+ if (p->build_log_sz > 0 && strstr(p->build_log, "error: error reading 'options'"))
+ err = CL_INVALID_BUILD_OPTIONS;
+ else
+ err = CL_BUILD_PROGRAM_FAILURE;
+ goto error;
+ }
+
+ /* Create all the kernels */
+ p->source_type = FROM_LLVM;
+ }
+ p->is_built = 1;
+ return CL_SUCCESS;
+
+error:
+ cl_program_delete(p);
+ p = NULL;
+ return err;
+}
+
LOCAL cl_kernel
cl_program_create_kernel(cl_program p, const char *name, cl_int *errcode_ret)
{
diff --git a/src/cl_program.h b/src/cl_program.h
index b9bf395..a576d37 100644
--- a/src/cl_program.h
+++ b/src/cl_program.h
@@ -110,6 +110,12 @@ cl_program_create_from_llvm(cl_context context,
/* Build the program as specified by OCL */
extern cl_int
cl_program_build(cl_program p, const char* options);
-
+/* Compile the program as specified by OCL */
+extern cl_int
+cl_program_compile(cl_program p,
+ cl_uint num_input_headers,
+ const cl_program * input_headers,
+ const char ** header_include_names,
+ const char* options);
#endif /* __CL_PROGRAM_H__ */
--
1.8.1.2
More information about the Beignet
mailing list