[Beignet] [PATCH V3] add binary type support for compiled object and library.
xionghu.luo at intel.com
xionghu.luo at intel.com
Mon Jun 16 14:28:09 PDT 2014
From: Luo <xionghu.luo at 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.
Signed-off-by: Luo <xionghu.luo at intel.com>
---
backend/src/backend/gen_program.cpp | 71 +++++++++++++++++++++++++++++++-----
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, 172 insertions(+), 27 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/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
More information about the Beignet
mailing list