[Beignet] [PATCH] [opencl-1.2 add binary type support for compiled object and library.
xionghu.luo at intel.com
xionghu.luo at intel.com
Thu Jun 12 14:47:17 PDT 2014
From: Luo <xionghu.luo at intel.com>
save the llvm bitecode to program->binary: insert a bite 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.
Signed-off-by: Luo <xionghu.luo at intel.com>
---
backend/src/backend/gen_program.cpp | 77 +++++++++++++++++++++++++++++++++----
backend/src/backend/program.cpp | 1 +
backend/src/backend/program.h | 8 +++-
src/cl_api.c | 25 ++++++++++--
src/cl_gbe_loader.cpp | 4 ++
src/cl_khr_icd.c | 4 +-
src/cl_program.c | 67 ++++++++++++++++++++++++++++++--
src/cl_program.h | 1 +
8 files changed, 170 insertions(+), 17 deletions(-)
diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp
index ad9043b..5324b8c 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 {
@@ -193,20 +200,75 @@ 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 bit 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);
+
+ 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 = 0;
+ return 0;
+ }
+
+ *binary = (char *)malloc(sizeof(char) * sz);
+ memcpy(*binary, oss.str().c_str(), sz*sizeof(char));
+ return sz;
+ }else{
+#ifdef GBE_COMPILER_AVAILABLE
+ char llStr[] = "/tmp/XXXXXX.ll";
+ int llFd = mkstemps(llStr, 3);
+ close(llFd);
+ const std::string llName = std::string(llStr);
+ std::string errorInfo;
+#if (LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR > 3)
+ auto mode = llvm::sys::fs::F_Binary;
+#else
+ auto mode = llvm::raw_fd_ostream::F_Binary;
+#endif
+ llvm::raw_fd_ostream OS(llName.c_str(), errorInfo, mode);
+ llvm::WriteBitcodeToFile((llvm::Module*)prog->module, OS);
+ OS.close();
+ FILE* pfile = fopen(llName.c_str(), "rb");
+ fseek(pfile, 0, SEEK_END);
+ int llsz = ftell(pfile);
+ rewind(pfile);
+ *binary = (char *)malloc(sizeof(char) * (llsz+1) );
+ int result = fread(*binary+1, 1, llsz, pfile);
+ if(result != llsz){
+ GBE_ASSERT(0);
+ }
+ *(*binary) = binary_type;
+ fclose(pfile);
+ remove(llName.c_str());
+ 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,
@@ -327,6 +389,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 b4c56b7..ebaf3d3 100644
--- a/backend/src/backend/program.cpp
+++ b/backend/src/backend/program.cpp
@@ -1099,6 +1099,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 8fb7fd1..c9668f5 100644
--- a/backend/src/backend/program.h
+++ b/backend/src/backend/program.h
@@ -148,8 +148,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 b529a0a..caeef35 100644
--- a/src/cl_api.c
+++ b/src/cl_api.c
@@ -1043,8 +1043,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 = gbe_program_serialize_to_binary(program->opaque, &program->binary);
+ if (program->binary == NULL){
+ if( program->binary_type == CL_PROGRAM_BINARY_TYPE_EXECUTABLE) {
+ program->binary_sz = gbe_program_serialize_to_binary(program->opaque, &program->binary, 0);
+ }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT) {
+ program->binary_sz = gbe_program_serialize_to_binary(program->opaque, &program->binary, 1);
+ }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_LIBRARY) {
+ program->binary_sz = gbe_program_serialize_to_binary(program->opaque, &program->binary, 2);
+ }else{
+ assert(0);
+ }
}
if (program->binary == NULL || program->binary_sz == 0) {
@@ -1060,7 +1068,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 = gbe_program_serialize_to_binary(program->opaque, &program->binary);
+ if( program->binary_type == CL_PROGRAM_BINARY_TYPE_EXECUTABLE) {
+ program->binary_sz = gbe_program_serialize_to_binary(program->opaque, &program->binary, 0);
+ }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT) {
+ program->binary_sz = gbe_program_serialize_to_binary(program->opaque, &program->binary, 1);
+ }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_LIBRARY) {
+ program->binary_sz = gbe_program_serialize_to_binary(program->opaque, &program->binary, 2);
+ }else{
+ assert(0);
+ }
}
if (program->binary == NULL || program->binary_sz == 0) {
@@ -1112,6 +1128,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 cb9e397..de9f170 100644
--- a/src/cl_gbe_loader.cpp
+++ b/src/cl_gbe_loader.cpp
@@ -61,6 +61,10 @@ struct GbeLoaderInitializer
if (gbe_program_serialize_to_binary == NULL)
return;
+ gbe_program_new_from_llvm_binary = *(gbe_program_new_from_llvm_binary_cb **)dlsym(dlh, "gbe_program_new_from_llvm_binary");
+ if (gbe_program_new_from_llvm_binary == NULL)
+ return;
+
gbe_program_new_from_llvm = *(gbe_program_new_from_llvm_cb **)dlsym(dlh, "gbe_program_new_from_llvm");
if (gbe_program_new_from_llvm == NULL)
return;
diff --git a/src/cl_khr_icd.c b/src/cl_khr_icd.c
index d601134..8c544f6 100644
--- a/src/cl_khr_icd.c
+++ b/src/cl_khr_icd.c
@@ -146,8 +146,8 @@ struct _cl_icd_dispatch const cl_khr_icd_dispatch = {
CL_1_2_NOTYET(clReleaseDevice),
CL_1_2_NOTYET(clCreateImage),
CL_1_2_NOTYET(clCreateProgramWithBuiltInKernels),
- CL_1_2_NOTYET(clCompileProgram),
- CL_1_2_NOTYET(clLinkProgram),
+ (clCompileProgram),
+ (clLinkProgram),
CL_1_2_NOTYET(clUnloadPlatformCompiler),
CL_1_2_NOTYET(clGetKernelArgInfo),
CL_1_2_NOTYET(clEnqueueFillBuffer),
diff --git a/src/cl_program.c b/src/cl_program.c
index 08ce489..0f268ae 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,22 @@ 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{
+ assert(0);
+ }
+ program->opaque = gbe_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 +400,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 +473,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 = gbe_program_get_kernel(p->opaque, i);
@@ -468,6 +510,7 @@ cl_program_link(cl_context context,
p->opaque = gbe_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])
gbe_program_link_program(p->opaque, input_programs[i]->opaque,
p->build_log_max_sz, p->build_log, &p->build_log_sz);
@@ -477,6 +520,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;
+ }
+
gbe_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 +584,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,13 +594,14 @@ 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, "/");
strcat(temp_path, header_include_names[i]);
char* dirc = strdup(temp_path);
char* dir = dirname(dirc);
@@ -572,7 +625,14 @@ cl_program_compile(cl_program p,
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");
+ char rm_path[255]="rm ";
+ strcat(rm_path, temp_header_path);
+ strcat(rm_path, " -rf");
+ int temp = system(rm_path);
+
+ if(temp){
+ assert(0);
+ }
if (UNLIKELY(p->opaque == NULL)) {
if (p->build_log_sz > 0 && strstr(p->build_log, "error: error reading 'options'"))
@@ -584,6 +644,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