[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