[Beignet] [PATCH V2 2/3] add [opencl-1.2] API clLinkProgram.

xionghu.luo at intel.com xionghu.luo at intel.com
Wed Jun 4 19:44:16 PDT 2014


From: Luo <xionghu.luo at intel.com>

this API links a set of compiled program objects and libraries for all
the devices or a specific device(s) in the OpenCL context and creates
an executable.
the llvm bitcode in the compiled program objects are linked together and
built to Gen binary.

Signed-off-by: Luo <xionghu.luo at intel.com>
---
 backend/src/backend/gen_program.cpp | 120 ++++++++++++++++++++++++++++++++++++
 backend/src/backend/program.cpp     |  33 +++++++---
 backend/src/backend/program.h       |  28 +++++++++
 src/cl_api.c                        |  33 ++++++++++
 src/cl_gbe_loader.cpp               |  12 ++++
 src/cl_program.c                    |  69 ++++++++++++++++-----
 src/cl_program.h                    |   7 +++
 7 files changed, 277 insertions(+), 25 deletions(-)

diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp
index 33f2ed6..d7cb898 100644
--- a/backend/src/backend/gen_program.cpp
+++ b/backend/src/backend/gen_program.cpp
@@ -33,6 +33,9 @@
 #include "llvm/IR/DataLayout.h"
 #endif  /* LLVM_VERSION_MINOR <= 2 */
 
+#include "llvm/Linker.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
 #include "backend/program.h"
 #include "backend/gen_program.h"
 #include "backend/gen_program.hpp"
@@ -232,6 +235,120 @@ namespace gbe {
     // Everything run fine
     return (gbe_program) program;
   }
+
+  static gbe_program genProgramNewGenProgram(uint32_t deviceID, const void* module, const void* llvm_ctx)
+  {
+    using namespace gbe;
+    GenProgram *program = GBE_NEW(GenProgram, deviceID, module, llvm_ctx);
+    // Everything run fine
+    return (gbe_program) program;
+  }
+
+  static void genProgramLinkFromLLVM(gbe_program           dst_program,
+                                     gbe_program           src_program,
+                                     size_t                stringSize,
+                                     char *                err,
+                                     size_t *              errSize)
+  {
+#ifdef GBE_COMPILER_AVAILABLE
+    using namespace gbe;
+    std::string errMsg;
+    if(((GenProgram*)dst_program)->module == NULL){
+      ((GenProgram*)dst_program)->module = llvm::CloneModule((llvm::Module*)((GenProgram*)src_program)->module);
+      errSize = 0;
+    }else{
+      llvm::Module* src = (llvm::Module*)((GenProgram*)src_program)->module;
+      llvm::GlobalVariable* gv = src->getNamedGlobal("PIo2");
+      gv->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      gv = src->getNamedGlobal("npio2_hw");
+      gv->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      gv = src->getNamedGlobal("two_over_pi");
+      gv->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      gv = src->getNamedGlobal("atanhi");
+      gv->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      gv = src->getNamedGlobal("atanlo");
+      gv->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+
+      llvm::Function* fc = src->getFunction("barrier");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memset_p");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memset_g");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memset_l");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memcpy_gg");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memcpy_gp");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memcpy_gl");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memcpy_pg");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memcpy_pp");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memcpy_pl");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memcpy_lg");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memcpy_lp");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+      fc = src->getFunction("__gen_memcpy_ll");
+      fc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+
+      llvm::Module* dst = (llvm::Module*)((GenProgram*)dst_program)->module;
+      llvm::Linker::LinkModules( dst,
+                                 src,
+                                 llvm::Linker::PreserveSource,
+                                 &errMsg);
+      if (errMsg.c_str() != NULL) {
+        if (err != NULL && errSize != NULL && stringSize > 0u) {
+          if(errMsg.length() < stringSize )
+            stringSize = errMsg.length();
+          strcpy(err, errMsg.c_str());
+          err[stringSize+1] = '\0';
+        }
+      }
+      printf("%s\n", err);
+    }
+    // Everything run fine
+#endif
+  }
+
+  static void genProgramBuildFromLLVM(gbe_program program,
+                                      size_t stringSize,
+                                      char *err,
+                                      size_t *errSize,
+                                      const char *          options)
+  {
+#ifdef GBE_COMPILER_AVAILABLE
+    using namespace gbe;
+    std::string error;
+
+    int optLevel = 1;
+
+    if(options) {
+      char *p;
+      p = strstr(const_cast<char *>(options), "-cl-opt-disable");
+      if (p)
+        optLevel = 0;
+    }
+
+    GenProgram* p = (GenProgram*) program;
+    // Try to compile the program
+    llvm::Module* module = (llvm::Module*)p->module;
+
+    if (p->buildFromLLVMFile(NULL, module, error, optLevel) == false) {
+      if (err != NULL && errSize != NULL && stringSize > 0u) {
+        const size_t msgSize = std::min(error.size(), stringSize-1u);
+        std::memcpy(err, error.c_str(), msgSize);
+        *errSize = error.size();
+      }
+      GBE_DELETE(p);
+    }
+#endif
+  }
+
 } /* namespace gbe */
 
 void genSetupCallBacks(void)
@@ -239,4 +356,7 @@ void genSetupCallBacks(void)
   gbe_program_new_from_binary = gbe::genProgramNewFromBinary;
   gbe_program_serialize_to_binary = gbe::genProgramSerializeToBinary;
   gbe_program_new_from_llvm = gbe::genProgramNewFromLLVM;
+  gbe_program_new_gen_program = gbe::genProgramNewGenProgram;
+  gbe_program_link_from_llvm = gbe::genProgramLinkFromLLVM;
+  gbe_program_build_from_llvm = gbe::genProgramBuildFromLLVM;
 }
diff --git a/backend/src/backend/program.cpp b/backend/src/backend/program.cpp
index 5af66fb..0014b6d 100644
--- a/backend/src/backend/program.cpp
+++ b/backend/src/backend/program.cpp
@@ -971,27 +971,20 @@ namespace gbe {
     fclose(clFile);
 
     gbe_program p;
-    // will delete the module and llvm_ctx in the destructor of GenProgram.
+    // will delete the module in the destructor of GenProgram.
     llvm::Module * out_module;
     llvm::LLVMContext* llvm_ctx = &llvm::getGlobalContext();
     if (buildModuleFromSource(clName.c_str(), &out_module, llvm_ctx, clOpt.c_str(),
                               stringSize, err, errSize)) {
     // Now build the program from llvm
-      static std::mutex gbe_mutex;
-      gbe_mutex.lock();
-      size_t clangErrSize = 0;
       if (err != NULL) {
         GBE_ASSERT(errSize != NULL);
         stringSize -= *errSize;
         err += *errSize;
-        clangErrSize = *errSize;
       }
 
       p = gbe_program_new_gen_program(deviceID, out_module, NULL);
 
-      if (err != NULL)
-        *errSize += clangErrSize;
-      gbe_mutex.unlock();
       if (OCL_OUTPUT_BUILD_LOG && options)
         llvm::errs() << options;
     } else
@@ -1001,6 +994,25 @@ namespace gbe {
   }
 #endif
 
+#ifdef GBE_COMPILER_AVAILABLE
+  static void programLinkProgram(gbe_program           dst_program,
+                                 gbe_program           src_program,
+                                 size_t                stringSize,
+                                 char *                err,
+                                 size_t *              errSize)
+  {
+    static std::mutex gbe_mutex;
+    gbe_mutex.lock();
+
+    gbe_program_link_from_llvm(dst_program, src_program, stringSize, err, errSize);
+
+    gbe_mutex.unlock();
+
+    if (OCL_OUTPUT_BUILD_LOG && err)
+      llvm::errs() << err;
+  }
+#endif
+
   static size_t programGetGlobalConstantSize(gbe_program gbeProgram) {
     if (gbeProgram == NULL) return 0;
     const gbe::Program *program = (const gbe::Program*) gbeProgram;
@@ -1166,9 +1178,13 @@ namespace gbe {
 
 GBE_EXPORT_SYMBOL gbe_program_new_from_source_cb *gbe_program_new_from_source = NULL;
 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_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;
+GBE_EXPORT_SYMBOL gbe_program_link_from_llvm_cb *gbe_program_link_from_llvm = NULL;
+GBE_EXPORT_SYMBOL gbe_program_build_from_llvm_cb *gbe_program_build_from_llvm = NULL;
 GBE_EXPORT_SYMBOL gbe_program_get_global_constant_size_cb *gbe_program_get_global_constant_size = NULL;
 GBE_EXPORT_SYMBOL gbe_program_get_global_constant_data_cb *gbe_program_get_global_constant_data = NULL;
 GBE_EXPORT_SYMBOL gbe_program_delete_cb *gbe_program_delete = NULL;
@@ -1209,6 +1225,7 @@ namespace gbe
     CallBackInitializer(void) {
       gbe_program_new_from_source = gbe::programNewFromSource;
       gbe_program_compile_from_source = gbe::programCompileFromSource;
+      gbe_program_link_program = gbe::programLinkProgram;
       gbe_program_get_global_constant_size = gbe::programGetGlobalConstantSize;
       gbe_program_get_global_constant_data = gbe::programGetGlobalConstantData;
       gbe_program_delete = gbe::programDelete;
diff --git a/backend/src/backend/program.h b/backend/src/backend/program.h
index 45754c4..856e04d 100644
--- a/backend/src/backend/program.h
+++ b/backend/src/backend/program.h
@@ -130,6 +130,13 @@ typedef gbe_program (gbe_program_compile_from_source_cb)(uint32_t deviceID,
                                                          char *err,
                                                          size_t *err_size);
 extern gbe_program_compile_from_source_cb *gbe_program_compile_from_source;
+/*! link the programs. */
+typedef void (gbe_program_link_program_cb)(gbe_program           dst_program,
+                                           gbe_program           src_program,
+                                           size_t                stringSize,
+                                           char *                err,
+                                           size_t *              errSize);
+extern gbe_program_link_program_cb *gbe_program_link_program;
 
 /*! Create a new program from the given blob */
 typedef gbe_program (gbe_program_new_from_binary_cb)(uint32_t deviceID, const char *binary, size_t size);
@@ -150,6 +157,27 @@ typedef gbe_program (gbe_program_new_from_llvm_cb)(uint32_t deviceID,
                                                    int optLevel);
 extern gbe_program_new_from_llvm_cb *gbe_program_new_from_llvm;
 
+/*! create s new genprogram for link. */
+typedef gbe_program (gbe_program_new_gen_program_cb)(uint32_t deviceID,
+                                                   const void *module,
+                                                   const void *act);
+extern gbe_program_new_gen_program_cb *gbe_program_new_gen_program;
+
+/*! link the programs from llvm level. */
+typedef void (gbe_program_link_from_llvm_cb)(gbe_program dst_program,
+                                             gbe_program src_program,
+                                             size_t      stringSize,
+                                             char *      err,
+                                             size_t *    errSize);
+extern gbe_program_link_from_llvm_cb *gbe_program_link_from_llvm;
+/* build the program to gen binary */
+typedef void gbe_program_build_from_llvm_cb(gbe_program program,
+                                      size_t stringSize,
+                                      char *err,
+                                      size_t *errSize,
+                                      const char *          options);
+extern gbe_program_build_from_llvm_cb *gbe_program_build_from_llvm;
+
 /*! Get the size of global constants */
 typedef size_t (gbe_program_get_global_constant_size_cb)(gbe_program gbeProgram);
 extern gbe_program_get_global_constant_size_cb *gbe_program_get_global_constant_size;
diff --git a/src/cl_api.c b/src/cl_api.c
index 790fbff..b529a0a 100644
--- a/src/cl_api.c
+++ b/src/cl_api.c
@@ -973,6 +973,39 @@ error:
   return err;
 }
 
+cl_program
+clLinkProgram(cl_context            context,
+              cl_uint               num_devices,
+              const cl_device_id *  device_list,
+              const char *          options,
+              cl_uint               num_input_programs,
+              const cl_program *    input_programs,
+              void (CL_CALLBACK *   pfn_notify)(cl_program  program, void * user_data),
+              void *                user_data,
+              cl_int *              errcode_ret)
+{
+  cl_int err = CL_SUCCESS;
+  cl_program program;
+  CHECK_CONTEXT (context);
+  INVALID_VALUE_IF (num_devices > 1);
+  INVALID_VALUE_IF (num_devices == 0 && device_list != NULL);
+  INVALID_VALUE_IF (num_devices != 0 && device_list == NULL);
+  INVALID_VALUE_IF (pfn_notify  == 0 && user_data   != NULL);
+  INVALID_VALUE_IF (num_input_programs == 0 && input_programs != NULL);
+  INVALID_VALUE_IF (num_input_programs != 0 && input_programs == NULL);
+
+  program = cl_program_link(context, num_input_programs, input_programs, options, &err);
+
+  program->is_built = CL_TRUE;
+
+  if (pfn_notify) pfn_notify(program, user_data);
+
+error:
+  if (errcode_ret)
+    *errcode_ret = err;
+  return program;
+}
+
 cl_int
 clUnloadCompiler(void)
 {
diff --git a/src/cl_gbe_loader.cpp b/src/cl_gbe_loader.cpp
index 71c1492..cb9e397 100644
--- a/src/cl_gbe_loader.cpp
+++ b/src/cl_gbe_loader.cpp
@@ -45,6 +45,18 @@ struct GbeLoaderInitializer
       if (gbe_program_compile_from_source == NULL)
         return;
 
+      gbe_program_new_gen_program = *(gbe_program_new_gen_program_cb **)dlsym(dlh, "gbe_program_new_gen_program");
+      if (gbe_program_new_gen_program == NULL)
+        return;
+
+      gbe_program_link_program = *(gbe_program_link_program_cb **)dlsym(dlh, "gbe_program_link_program");
+      if (gbe_program_link_program == NULL)
+        return;
+
+      gbe_program_build_from_llvm = *(gbe_program_build_from_llvm_cb **)dlsym(dlh, "gbe_program_build_from_llvm");
+      if (gbe_program_build_from_llvm == NULL)
+        return;
+
       gbe_program_serialize_to_binary = *(gbe_program_serialize_to_binary_cb **)dlsym(dlh, "gbe_program_serialize_to_binary");
       if (gbe_program_serialize_to_binary == NULL)
         return;
diff --git a/src/cl_program.c b/src/cl_program.c
index 9fd202a..59c0e83 100644
--- a/src/cl_program.c
+++ b/src/cl_program.c
@@ -452,6 +452,55 @@ error:
   return err;
 }
 
+cl_program
+cl_program_link(cl_context            context,
+                cl_uint               num_input_programs,
+                const cl_program *    input_programs,
+                const char *          options,
+                cl_int*               errcode_ret)
+{
+  cl_program p = NULL;
+  cl_int err=CL_SUCCESS;
+  cl_int i = 0;
+  int copyed = 0;
+  p = cl_program_new(context);
+
+  p->opaque = gbe_program_new_gen_program(context->device->vendor_id, NULL, NULL);
+
+  for(i = 0; i < num_input_programs; i++) {
+    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);
+    if (UNLIKELY(p->opaque == NULL)) {
+      err = CL_LINK_PROGRAM_FAILURE;
+      goto error;
+    }
+  }
+
+  gbe_program_build_from_llvm(p->opaque, p->build_log_max_sz, p->build_log, &p->build_log_sz, options);
+
+  /* Create all the kernels */
+  TRY (cl_program_load_gen_program, p);
+
+  for (i = 0; i < p->ker_n; i ++) {
+    const gbe_kernel opaque = gbe_program_get_kernel(p->opaque, i);
+    p->bin_sz += gbe_kernel_get_code_size(opaque);
+  }
+
+  TRY_ALLOC (p->bin, cl_calloc(p->bin_sz, sizeof(char)));
+  for (i = 0; i < p->ker_n; i ++) {
+    const gbe_kernel opaque = gbe_program_get_kernel(p->opaque, i);
+    size_t sz = gbe_kernel_get_code_size(opaque);
+
+    memcpy(p->bin + copyed, gbe_kernel_get_code(opaque), sz);
+    copyed += sz;
+  }
+
+error:
+  p->is_built = 1;
+  return p;
+}
+
 LOCAL cl_int
 cl_program_compile(cl_program            p,
                    cl_uint               num_input_headers,
@@ -461,7 +510,6 @@ cl_program_compile(cl_program            p,
 {
   cl_int err = CL_SUCCESS;
   int i = 0;
-  int copyed = 0;
 
   if (p->ref_n > 1)
     return CL_INVALID_OPERATION;
@@ -529,26 +577,13 @@ cl_program_compile(cl_program            p,
     }
 
     /* Create all the kernels */
-    TRY (cl_program_load_gen_program, p);
     p->source_type = FROM_LLVM;
   }
-
-  for (i = 0; i < p->ker_n; i ++) {
-    const gbe_kernel opaque = gbe_program_get_kernel(p->opaque, i);
-    p->bin_sz += gbe_kernel_get_code_size(opaque);
-  }
-
-  TRY_ALLOC (p->bin, cl_calloc(p->bin_sz, sizeof(char)));
-  for (i = 0; i < p->ker_n; i ++) {
-    const gbe_kernel opaque = gbe_program_get_kernel(p->opaque, i);
-    size_t sz = gbe_kernel_get_code_size(opaque);
-
-    memcpy(p->bin + copyed, gbe_kernel_get_code(opaque), sz);
-    copyed += sz;
-  }
+  return CL_SUCCESS;
 
 error:
-  p->is_built = 1;
+  cl_program_delete(p);
+  p = NULL;
   return err;
 }
 
diff --git a/src/cl_program.h b/src/cl_program.h
index a576d37..49a4f48 100644
--- a/src/cl_program.h
+++ b/src/cl_program.h
@@ -117,5 +117,12 @@ cl_program_compile(cl_program            p,
                    const cl_program *    input_headers,
                    const char **         header_include_names,
                    const char*           options);
+/* link the program as specified by OCL */
+extern cl_program
+cl_program_link(cl_context            context,
+                cl_uint               num_input_programs,
+                const cl_program *    input_programs,
+                const char *          options,
+                cl_int*               errcode_ret);
 #endif /* __CL_PROGRAM_H__ */
 
-- 
1.8.1.2



More information about the Beignet mailing list