From: Luo <xionghu....@intel.com> save the llvm bitcode to program->binary: insert a byte in front of the bitcode stands for binary type(0 means GEN binary, 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. v6: fix enqueue_copy_fill bug, use '\0' instead of 0 in the header. v7 binary header format issue: fix test_load_program_from_bin bug of standalone kernel generated by gbe_bin_generater. Signed-off-by: Luo <xionghu....@intel.com> --- backend/src/backend/gen_program.cpp | 71 +++++++++++++++++++++++++++++++----- backend/src/backend/program.cpp | 1 + backend/src/backend/program.h | 8 +++-- backend/src/gbe_bin_generater.cpp | 58 ++++++++++++++++++++---------- 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 + 9 files changed, 211 insertions(+), 46 deletions(-) diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp index 300741e..8897dbb 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,8 @@ 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); + //the first 5 bytes are header to differentiate from llvm bitcode binary. + 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 +211,66 @@ 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"); + acquireLLVMContextLock(); + llvm::Module* module = llvm::ParseIR(memory_buffer, Err, c); + releaseLLVMContextLock(); + 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 +391,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/backend/src/gbe_bin_generater.cpp b/backend/src/gbe_bin_generater.cpp index dce0792..2627673 100644 --- a/backend/src/gbe_bin_generater.cpp +++ b/backend/src/gbe_bin_generater.cpp @@ -38,6 +38,7 @@ #include "backend/program.h" #include "backend/program.hpp" +#include "backend/src/sys/platform.hpp" using namespace std; @@ -148,40 +149,59 @@ public: string program_build_instance::bin_path; bool program_build_instance::str_fmt_out = false; +#define OUTS_UPDATE_SZ(elt) SERIALIZE_OUT(elt, oss, header_sz) +#define OUTF_UPDATE_SZ(elt) SERIALIZE_OUT(elt, ofs, header_sz) void program_build_instance::serialize_program(void) throw(int) { ofstream ofs; ostringstream oss; - size_t sz; + size_t sz, header_sz = 0; ofs.open(bin_path, ofstream::out | ofstream::trunc | ofstream::binary); + //add header to differeciate from llvm bitcode binary. + // (5 bytes: 1 byte for binary type, 4 byte for bc code.) + char header = '\0'; + if (str_fmt_out) { - string array_name = "Unkown_name_array"; - unsigned long last_slash = bin_path.rfind("/"); - unsigned long last_dot = bin_path.rfind("."); + OUTS_UPDATE_SZ(header); + OUTS_UPDATE_SZ(header); + OUTS_UPDATE_SZ(header); + OUTS_UPDATE_SZ(header); + OUTS_UPDATE_SZ(header); - if (last_slash != string::npos && last_dot != string::npos) - array_name = bin_path.substr(last_slash + 1, last_dot - 1 - last_slash); + string array_name = "Unkown_name_array"; + unsigned long last_slash = bin_path.rfind("/"); + unsigned long last_dot = bin_path.rfind("."); - ofs << "char " << array_name << "[] = {" << "\n"; + if (last_slash != string::npos && last_dot != string::npos) + array_name = bin_path.substr(last_slash + 1, last_dot - 1 - last_slash); - sz = gbe_prog->serializeToBin(oss); + ofs << "char " << array_name << "[] = {" << "\n"; - for (size_t i = 0; i < sz; i++) { - unsigned char c = oss.str().c_str()[i]; - char asic_str[9]; - sprintf(asic_str, "%2.2x", c); - ofs << "0x"; - ofs << asic_str << ((i == sz - 1) ? "" : ", "); - } + sz = gbe_prog->serializeToBin(oss); + + sz+=5; + + for (size_t i = 0; i < sz; i++) { + unsigned char c = oss.str().c_str()[i]; + char asic_str[9]; + sprintf(asic_str, "%2.2x", c); + ofs << "0x"; + ofs << asic_str << ((i == sz - 1) ? "" : ", "); + } - ofs << "};\n"; + ofs << "};\n"; - string array_size = array_name + "_size"; - ofs << "int " << array_size << " = " << sz << ";" << "\n"; + string array_size = array_name + "_size"; + ofs << "int " << array_size << " = " << sz << ";" << "\n"; } else { - sz = gbe_prog->serializeToBin(ofs); + OUTF_UPDATE_SZ(header); + OUTF_UPDATE_SZ(header); + OUTF_UPDATE_SZ(header); + OUTF_UPDATE_SZ(header); + OUTF_UPDATE_SZ(header); + sz = gbe_prog->serializeToBin(ofs); } ofs.close(); diff --git a/src/cl_api.c b/src/cl_api.c index 327f02b..c4a8730 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