From: Luo <xionghu....@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....@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 _______________________________________________ Beignet mailing list Beignet@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/beignet