From: Luo <xionghu....@intel.com> save the llvm bitcode to program->binary: insert a byte in front of the bitcode stands for binary type(1 means COMPILED_OBJECT, 2 means LIBRARY); load the binary to module by ParseIR.
create random directory to save compile header files. use strncpy and strncat to replace strcpy and strcat. Signed-off-by: Luo <xionghu....@intel.com> --- backend/src/backend/gen_program.cpp | 68 ++++++++++++++++++++++++++++++----- backend/src/backend/program.cpp | 1 + backend/src/backend/program.h | 8 +++-- src/cl_api.c | 25 +++++++++++-- src/cl_gbe_loader.cpp | 11 ++++-- src/cl_gbe_loader.h | 10 +++--- src/cl_program.c | 72 +++++++++++++++++++++++++++++++++---- src/cl_program.h | 1 + 8 files changed, 169 insertions(+), 27 deletions(-) diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp index 300741e..b999931 100644 --- a/backend/src/backend/gen_program.cpp +++ b/backend/src/backend/gen_program.cpp @@ -35,6 +35,12 @@ #include "llvm/Linker.h" #include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/IRReader/IRReader.h" #include "backend/program.h" #include "backend/gen_program.h" @@ -55,6 +61,7 @@ #include <iostream> #include <fstream> #include <mutex> +#include <unistd.h> namespace gbe { @@ -188,7 +195,7 @@ namespace gbe { static gbe_program genProgramNewFromBinary(uint32_t deviceID, const char *binary, size_t size) { using namespace gbe; std::string binary_content; - binary_content.assign(binary, size); + binary_content.assign(binary+5, size-5); GenProgram *program = GBE_NEW(GenProgram, deviceID); std::istringstream ifs(binary_content, std::ostringstream::binary); // FIXME we need to check the whether the current device ID match the binary file's. @@ -203,20 +210,64 @@ namespace gbe { return reinterpret_cast<gbe_program>(program); } - static size_t genProgramSerializeToBinary(gbe_program program, char **binary) { + static gbe_program genProgramNewFromLLVMBinary(uint32_t deviceID, const char *binary, size_t size) { +#ifdef GBE_COMPILER_AVAILABLE + using namespace gbe; + std::string binary_content; + //the first byte stands for binary_type. + binary_content.assign(binary+1, size-1); + llvm::StringRef llvm_bin_str(binary_content); + llvm::LLVMContext& c = llvm::getGlobalContext(); + llvm::SMDiagnostic Err; + llvm::MemoryBuffer* memory_buffer = llvm::MemoryBuffer::getMemBuffer(llvm_bin_str, "llvm_bin_str"); + llvm::Module* module = llvm::ParseIR(memory_buffer, Err, c); + if(module == NULL){ + GBE_ASSERT(0); + } + + GenProgram *program = GBE_NEW(GenProgram, deviceID, module); + + //program->printStatus(0, std::cout); + return reinterpret_cast<gbe_program>(program); +#else + return NULL; +#endif + } + + static size_t genProgramSerializeToBinary(gbe_program program, char **binary, int binary_type) { using namespace gbe; size_t sz; std::ostringstream oss; GenProgram *prog = (GenProgram*)program; - if ((sz = prog->serializeToBin(oss)) == 0) { - *binary = 0; + //0 means GEN binary, 1 means LLVM bitcode compiled object, 2 means LLVM bitcode library + if(binary_type == 0){ + if ((sz = prog->serializeToBin(oss)) == 0) { + *binary = NULL; + return 0; + } + + //add header to differetiate from llvm bitcode binary. + //the header length is 5 bytes: 1 binary type, 4 bitcode header. + *binary = (char *)malloc(sizeof(char) * (sz+5) ); + memset(*binary, 0, sizeof(char) * (sz+5) ); + memcpy(*binary+5, oss.str().c_str(), sz*sizeof(char)); + return sz+5; + }else{ +#ifdef GBE_COMPILER_AVAILABLE + std::string str; + llvm::raw_string_ostream OS(str); + llvm::WriteBitcodeToFile((llvm::Module*)prog->module, OS); + std::string& bin_str = OS.str(); + int llsz = bin_str.size(); + *binary = (char *)malloc(sizeof(char) * (llsz+1) ); + *(*binary) = binary_type; + memcpy(*binary+1, bin_str.c_str(), llsz); + return llsz+1; +#else return 0; +#endif } - - *binary = (char *)malloc(sizeof(char) * sz); - memcpy(*binary, oss.str().c_str(), sz*sizeof(char)); - return sz; } static gbe_program genProgramNewFromLLVM(uint32_t deviceID, @@ -337,6 +388,7 @@ namespace gbe { void genSetupCallBacks(void) { gbe_program_new_from_binary = gbe::genProgramNewFromBinary; + gbe_program_new_from_llvm_binary = gbe::genProgramNewFromLLVMBinary; 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 45983fd..98e7ab7 100644 --- a/backend/src/backend/program.cpp +++ b/backend/src/backend/program.cpp @@ -1158,6 +1158,7 @@ GBE_EXPORT_SYMBOL gbe_program_new_from_source_cb *gbe_program_new_from_source = 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_new_from_llvm_binary_cb *gbe_program_new_from_llvm_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; diff --git a/backend/src/backend/program.h b/backend/src/backend/program.h index 508fe64..c56b94a 100644 --- a/backend/src/backend/program.h +++ b/backend/src/backend/program.h @@ -179,8 +179,12 @@ extern gbe_program_new_gen_program_cb *gbe_program_new_gen_program; 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; -/*! Serialize a program to a bin */ -typedef size_t (gbe_program_serialize_to_binary_cb)(gbe_program program, char **binary); +/*! Create a new program from the llvm bitcode*/ +typedef gbe_program (gbe_program_new_from_llvm_binary_cb)(uint32_t deviceID, const char *binary, size_t size); +extern gbe_program_new_from_llvm_binary_cb *gbe_program_new_from_llvm_binary; + +/*! Serialize a program to a bin, 0 means executable, 1 means llvm bitcode*/ +typedef size_t (gbe_program_serialize_to_binary_cb)(gbe_program program, char **binary, int binary_type); extern gbe_program_serialize_to_binary_cb *gbe_program_serialize_to_binary; /*! Create a new program from the given LLVM file */ diff --git a/src/cl_api.c b/src/cl_api.c index 73447c4..2f287e3 100644 --- a/src/cl_api.c +++ b/src/cl_api.c @@ -1065,8 +1065,16 @@ clGetProgramInfo(cl_program program, FILL_GETINFO_RET (char, (strlen(program->source) + 1), program->source, CL_SUCCESS); } else if (param_name == CL_PROGRAM_BINARY_SIZES) { - if (program->binary == NULL) { - program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary); + if (program->binary == NULL){ + if( program->binary_type == CL_PROGRAM_BINARY_TYPE_EXECUTABLE) { + program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 0); + }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT) { + program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 1); + }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_LIBRARY) { + program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 2); + }else{ + return CL_INVALID_BINARY; + } } if (program->binary == NULL || program->binary_sz == 0) { @@ -1082,7 +1090,15 @@ clGetProgramInfo(cl_program program, /* param_value points to an array of n pointers allocated by the caller */ if (program->binary == NULL) { - program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary); + if( program->binary_type == CL_PROGRAM_BINARY_TYPE_EXECUTABLE) { + program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 0); + }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT) { + program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 1); + }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_LIBRARY) { + program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 2); + }else{ + return CL_INVALID_BINARY; + } } if (program->binary == NULL || program->binary_sz == 0) { @@ -1134,6 +1150,9 @@ clGetProgramBuildInfo(cl_program program, FILL_GETINFO_RET (char, program->build_log_sz + 1, program->build_log, CL_SUCCESS); if (param_value_size_ret) *param_value_size_ret = program->build_log_sz + 1; + }else if (param_name == CL_PROGRAM_BINARY_TYPE){ + + FILL_GETINFO_RET (cl_uint, 1, &program->binary_type, CL_SUCCESS); } else { return CL_INVALID_VALUE; } diff --git a/src/cl_gbe_loader.cpp b/src/cl_gbe_loader.cpp index 470299b..2fda50c 100644 --- a/src/cl_gbe_loader.cpp +++ b/src/cl_gbe_loader.cpp @@ -24,13 +24,14 @@ //function pointer from libgbe.so gbe_program_new_from_source_cb *compiler_program_new_from_source = NULL; -gbe_program_serialize_to_binary_cb *compiler_program_serialize_to_binary = NULL; -gbe_program_new_from_llvm_cb *compiler_program_new_from_llvm = NULL; -gbe_set_image_base_index_cb *compiler_set_image_base_index = NULL; gbe_program_compile_from_source_cb *compiler_program_compile_from_source = NULL; gbe_program_new_gen_program_cb *compiler_program_new_gen_program = NULL; gbe_program_link_program_cb *compiler_program_link_program = NULL; gbe_program_build_from_llvm_cb *compiler_program_build_from_llvm = NULL; +gbe_program_new_from_llvm_binary_cb *compiler_program_new_from_llvm_binary = NULL; +gbe_program_serialize_to_binary_cb *compiler_program_serialize_to_binary = NULL; +gbe_program_new_from_llvm_cb *compiler_program_new_from_llvm = NULL; +gbe_set_image_base_index_cb *compiler_set_image_base_index = NULL; //function pointer from libgbeinterp.so gbe_program_new_from_binary_cb *interp_program_new_from_binary = NULL; @@ -272,6 +273,10 @@ struct GbeLoaderInitializer if (compiler_program_build_from_llvm == NULL) return; + compiler_program_new_from_llvm_binary = *(gbe_program_new_from_llvm_binary_cb **)dlsym(dlhCompiler, "gbe_program_new_from_llvm_binary"); + if (compiler_program_new_from_llvm_binary == NULL) + return; + compiler_program_serialize_to_binary = *(gbe_program_serialize_to_binary_cb **)dlsym(dlhCompiler, "gbe_program_serialize_to_binary"); if (compiler_program_serialize_to_binary == NULL) return; diff --git a/src/cl_gbe_loader.h b/src/cl_gbe_loader.h index bd6afe6..632163b 100644 --- a/src/cl_gbe_loader.h +++ b/src/cl_gbe_loader.h @@ -25,9 +25,15 @@ extern "C" { #endif extern gbe_program_new_from_source_cb *compiler_program_new_from_source; +extern gbe_program_compile_from_source_cb *compiler_program_compile_from_source; +extern gbe_program_new_gen_program_cb *compiler_program_new_gen_program; +extern gbe_program_link_program_cb *compiler_program_link_program; +extern gbe_program_build_from_llvm_cb *compiler_program_build_from_llvm; +extern gbe_program_new_from_llvm_binary_cb *compiler_program_new_from_llvm_binary; extern gbe_program_serialize_to_binary_cb *compiler_program_serialize_to_binary; extern gbe_program_new_from_llvm_cb *compiler_program_new_from_llvm; extern gbe_set_image_base_index_cb *compiler_set_image_base_index; + extern gbe_program_new_from_binary_cb *interp_program_new_from_binary; extern gbe_program_get_global_constant_size_cb *interp_program_get_global_constant_size; extern gbe_program_get_global_constant_data_cb *interp_program_get_global_constant_data; @@ -63,10 +69,6 @@ extern gbe_get_printf_sizeof_size_cb* interp_get_printf_sizeof_size; extern gbe_release_printf_info_cb* interp_release_printf_info; extern gbe_output_printf_cb* interp_output_printf; //extern gbe_set_image_base_index_cb *gbe_set_image_base_index_interp; -extern gbe_program_compile_from_source_cb *compiler_program_compile_from_source; -extern gbe_program_new_gen_program_cb *compiler_program_new_gen_program; -extern gbe_program_link_program_cb *compiler_program_link_program; -extern gbe_program_build_from_llvm_cb *compiler_program_build_from_llvm; extern gbe_kernel_get_arg_info_cb *interp_kernel_get_arg_info; int CompilerSupported(); diff --git a/src/cl_program.c b/src/cl_program.c index 240453c..0dcc59a 100644 --- a/src/cl_program.c +++ b/src/cl_program.c @@ -156,6 +156,30 @@ error: return err; } +inline cl_bool isBitcodeWrapper(const unsigned char *BufPtr, const unsigned char *BufEnd) +{ + // See if you can find the hidden message in the magic bytes :-). + // (Hint: it's a little-endian encoding.) + return BufPtr != BufEnd && + BufPtr[0] == 0xDE && + BufPtr[1] == 0xC0 && + BufPtr[2] == 0x17 && + BufPtr[3] == 0x0B; +} + +inline cl_bool isRawBitcode(const unsigned char *BufPtr, const unsigned char *BufEnd) +{ + // These bytes sort of have a hidden message, but it's not in + // little-endian this time, and it's a little redundant. + return BufPtr != BufEnd && + BufPtr[0] == 'B' && + BufPtr[1] == 'C' && + BufPtr[2] == 0xc0 && + BufPtr[3] == 0xde; +} + +#define isBitcode(BufPtr,BufEnd) (isBitcodeWrapper(BufPtr, BufEnd) || isRawBitcode(BufPtr, BufEnd)) + LOCAL cl_program cl_program_create_from_binary(cl_context ctx, cl_uint num_devices, @@ -197,6 +221,23 @@ cl_program_create_from_binary(cl_context ctx, program->binary_sz = lengths[0]; program->source_type = FROM_BINARY; + if(isBitcode((unsigned char*)program->binary+1, (unsigned char*)program->binary+program->binary_sz)) { + if(*program->binary == 1){ + program->binary_type = CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT; + }else if(*program->binary == 2){ + program->binary_type = CL_PROGRAM_BINARY_TYPE_LIBRARY; + }else{ + err= CL_INVALID_BINARY; + goto error; + } + program->opaque = compiler_program_new_from_llvm_binary(program->ctx->device->vendor_id, program->binary, program->binary_sz); + + if (UNLIKELY(program->opaque == NULL)) { + err = CL_INVALID_PROGRAM; + goto error; + } + } + if (binary_status) binary_status[0] = CL_SUCCESS; @@ -360,6 +401,7 @@ cl_program_create_from_source(cl_context ctx, *p = '\0'; program->source_type = FROM_SOURCE; + program->binary_type = CL_PROGRAM_BINARY_TYPE_NONE; exit: cl_free(lens); @@ -432,6 +474,7 @@ cl_program_build(cl_program p, const char *options) TRY (cl_program_load_gen_program, p); p->source_type = FROM_LLVM; } + p->binary_type = CL_PROGRAM_BINARY_TYPE_EXECUTABLE; for (i = 0; i < p->ker_n; i ++) { const gbe_kernel opaque = interp_program_get_kernel(p->opaque, i); @@ -468,6 +511,7 @@ cl_program_link(cl_context context, p->opaque = compiler_program_new_gen_program(context->device->vendor_id, NULL, NULL); for(i = 0; i < num_input_programs; i++) { + // if program create with llvm binary, need deserilize first to get module. if(input_programs[i]) compiler_program_link_program(p->opaque, input_programs[i]->opaque, p->build_log_max_sz, p->build_log, &p->build_log_sz); @@ -477,6 +521,13 @@ cl_program_link(cl_context context, } } + if(options && strstr(options, "-create-library")){ + p->binary_type = CL_PROGRAM_BINARY_TYPE_LIBRARY; + return p; + }else{ + p->binary_type = CL_PROGRAM_BINARY_TYPE_EXECUTABLE; + } + compiler_program_build_from_llvm(p->opaque, p->build_log_max_sz, p->build_log, &p->build_log_sz, options); /* Create all the kernels */ @@ -534,7 +585,9 @@ cl_program_compile(cl_program p, p->build_opts = NULL; } - const char* temp_header_path = "/tmp/beignet_header/"; + char temp_header_template[]= "/tmp/beignet.XXXXXX"; + char* temp_header_path = mkdtemp(temp_header_template); + if (p->source_type == FROM_SOURCE) { if (!CompilerSupported()) { @@ -542,14 +595,15 @@ cl_program_compile(cl_program p, goto error; } - //write the headers to /tmp/beignet_header for include. + //write the headers to /tmp/beignet.XXXXXX 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 temp_path[255]=""; + strncpy(temp_path, temp_header_path, strlen(temp_header_path)); + strncat(temp_path, "/", 1); + strncat(temp_path, header_include_names[i], strlen(header_include_names[i])); char* dirc = strdup(temp_path); char* dir = dirname(dirc); mkdir(dir, 0755); @@ -572,9 +626,12 @@ cl_program_compile(cl_program p, p->opaque = compiler_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); - int rm_ret = system("rm /tmp/beignet_header/* -rf"); + char rm_path[255]="rm "; + strncat(rm_path, temp_header_path, strlen(temp_header_path)); + strncat(rm_path, " -rf", 4); + int temp = system(rm_path); - if(rm_ret){ + if(temp){ assert(0); } @@ -588,6 +645,7 @@ cl_program_compile(cl_program p, /* Create all the kernels */ p->source_type = FROM_LLVM; + p->binary_type = CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT; } p->is_built = 1; return CL_SUCCESS; diff --git a/src/cl_program.h b/src/cl_program.h index 49a4f48..52d1ac1 100644 --- a/src/cl_program.h +++ b/src/cl_program.h @@ -50,6 +50,7 @@ struct _cl_program { char *source; /* Program sources */ char *binary; /* Program binary. */ size_t binary_sz; /* The binary size. */ + uint32_t binary_type; /* binary type: COMPILED_OBJECT(LLVM IR), LIBRARY(LLVM IR with option "-create-library"), or EXECUTABLE(GEN binary). */ uint32_t ker_n; /* Number of declared kernels */ uint32_t source_type:2; /* Built from binary, source or LLVM */ uint32_t is_built:1; /* Did we call clBuildProgram on it? */ -- 1.8.1.2 _______________________________________________ Beignet mailing list Beignet@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/beignet