[Beignet] [PATCH v4 1/3] add [opencl-1.2] API clCompileProgram.

xionghu.luo at intel.com xionghu.luo at intel.com
Thu Jun 5 23:18:47 PDT 2014


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

This API compiles a program's source for all the devices or a specific
device in the OpenCL context associated with program.
The pre-processor runs before the program sources are compiled.

Signed-off-by: Luo <xionghu.luo at intel.com>
---
 backend/src/backend/gen_program.cpp |  9 ++++
 backend/src/backend/program.cpp     | 60 +++++++++++++++++++++++
 backend/src/backend/program.h       | 20 ++++++++
 src/cl_api.c                        | 41 ++++++++++++++++
 src/cl_gbe_loader.cpp               |  4 ++
 src/cl_program.c                    | 96 +++++++++++++++++++++++++++++++++++++
 src/cl_program.h                    |  8 +++-
 7 files changed, 237 insertions(+), 1 deletion(-)

diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp
index 33f2ed6..1d19289 100644
--- a/backend/src/backend/gen_program.cpp
+++ b/backend/src/backend/gen_program.cpp
@@ -232,6 +232,14 @@ 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;
+  }
 } /* namespace gbe */
 
 void genSetupCallBacks(void)
@@ -239,4 +247,5 @@ 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;
 }
diff --git a/backend/src/backend/program.cpp b/backend/src/backend/program.cpp
index d23529a..121153d 100644
--- a/backend/src/backend/program.cpp
+++ b/backend/src/backend/program.cpp
@@ -861,6 +861,52 @@ namespace gbe {
   }
 #endif
 
+#ifdef GBE_COMPILER_AVAILABLE
+
+  static gbe_program programCompileFromSource(uint32_t deviceID,
+                                          const char *source,
+                                          const char *temp_header_path,
+                                          size_t stringSize,
+                                          const char *options,
+                                          char *err,
+                                          size_t *errSize)
+  {
+    int optLevel = 1;
+    std::string clOpt;
+    std::string clName;
+    processSourceAndOption(source, options, temp_header_path, clOpt, clName, optLevel);
+
+    gbe_program p;
+    acquireLLVMContextLock();
+    //FIXME: if use new allocated context to link two modules there would be context mismatch
+    //for some functions, so we use global context now, need switch to new context later.
+    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
+      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;
+      if (OCL_OUTPUT_BUILD_LOG && options)
+        llvm::errs() << options;
+    } else
+      p = NULL;
+    remove(clName.c_str());
+    releaseLLVMContextLock();
+    return p;
+  }
+#endif
+
   static size_t programGetGlobalConstantSize(gbe_program gbeProgram) {
     if (gbeProgram == NULL) return 0;
     const gbe::Program *program = (const gbe::Program*) gbeProgram;
@@ -1024,10 +1070,23 @@ namespace gbe {
   }
 } /* namespace gbe */
 
+std::mutex llvm_ctx_mutex;
+void acquireLLVMContextLock()
+{
+  llvm_ctx_mutex.lock();
+}
+
+void releaseLLVMContextLock()
+{
+  llvm_ctx_mutex.unlock();
+}
+
 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_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_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;
@@ -1067,6 +1126,7 @@ namespace gbe
   {
     CallBackInitializer(void) {
       gbe_program_new_from_source = gbe::programNewFromSource;
+      gbe_program_compile_from_source = gbe::programCompileFromSource;
       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 077d0d3..5639e27 100644
--- a/backend/src/backend/program.h
+++ b/backend/src/backend/program.h
@@ -121,6 +121,22 @@ typedef gbe_program (gbe_program_new_from_source_cb)(uint32_t deviceID,
                                                      char *err,
                                                      size_t *err_size);
 extern gbe_program_new_from_source_cb *gbe_program_new_from_source;
+/*! Create a new program from the given source code and compile it (zero terminated string) */
+typedef gbe_program (gbe_program_compile_from_source_cb)(uint32_t deviceID,
+                                                         const char *source,
+                                                         const char *temp_header_path,
+                                                         size_t stringSize,
+                                                         const char *options,
+                                                         char *err,
+                                                         size_t *err_size);
+extern gbe_program_compile_from_source_cb *gbe_program_compile_from_source;
+
+/*! 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;
+
 /*! 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);
 extern gbe_program_new_from_binary_cb *gbe_program_new_from_binary;
@@ -241,6 +257,10 @@ extern gbe_kernel_use_slm_cb *gbe_kernel_use_slm;
 typedef int32_t (gbe_kernel_get_slm_size_cb)(gbe_kernel);
 extern gbe_kernel_get_slm_size_cb *gbe_kernel_get_slm_size;
 
+/*mutex to lock global llvmcontext access.*/
+extern void acquireLLVMContextLock();
+extern void releaseLLVMContextLock();
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/src/cl_api.c b/src/cl_api.c
index 8598088..790fbff 100644
--- a/src/cl_api.c
+++ b/src/cl_api.c
@@ -933,6 +933,47 @@ error:
 }
 
 cl_int
+clCompileProgram(cl_program            program ,
+                 cl_uint               num_devices ,
+                 const cl_device_id *  device_list ,
+                 const char *          options ,
+                 cl_uint               num_input_headers ,
+                 const cl_program *    input_headers ,
+                 const char **         header_include_names ,
+                 void (CL_CALLBACK *   pfn_notify )(cl_program, void *),
+                 void *                user_data )
+{
+  cl_int err = CL_SUCCESS;
+  CHECK_PROGRAM(program);
+  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_headers == 0 && input_headers != NULL);
+  INVALID_VALUE_IF (num_input_headers != 0 && input_headers == NULL);
+
+  /* Everything is easy. We only support one device anyway */
+  if (num_devices != 0) {
+    assert(program->ctx);
+    INVALID_DEVICE_IF (device_list[0] != program->ctx->device);
+  }
+
+  /* TODO support create program from binary */
+  assert(program->source_type == FROM_LLVM ||
+      program->source_type == FROM_SOURCE ||
+      program->source_type == FROM_BINARY);
+  if((err = cl_program_compile(program, num_input_headers, input_headers, header_include_names, options)) != CL_SUCCESS) {
+    goto error;
+  }
+  program->is_built = CL_TRUE;
+
+  if (pfn_notify) pfn_notify(program, user_data);
+
+error:
+  return err;
+}
+
+cl_int
 clUnloadCompiler(void)
 {
   return CL_SUCCESS;
diff --git a/src/cl_gbe_loader.cpp b/src/cl_gbe_loader.cpp
index da83c9a..71c1492 100644
--- a/src/cl_gbe_loader.cpp
+++ b/src/cl_gbe_loader.cpp
@@ -41,6 +41,10 @@ struct GbeLoaderInitializer
       if (gbe_program_new_from_source == NULL)
         return;
 
+      gbe_program_compile_from_source = *(gbe_program_compile_from_source_cb **)dlsym(dlh, "gbe_program_compile_from_source");
+      if (gbe_program_compile_from_source == 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 6910330..88b165f 100644
--- a/src/cl_program.c
+++ b/src/cl_program.c
@@ -33,6 +33,9 @@
 #include <stdint.h>
 #include <string.h>
 #include <assert.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libgen.h>
 
 static void
 cl_program_release_sources(cl_program p)
@@ -449,6 +452,99 @@ error:
   return err;
 }
 
+LOCAL cl_int
+cl_program_compile(cl_program            p,
+                   cl_uint               num_input_headers,
+                   const cl_program *    input_headers,
+                   const char **         header_include_names,
+                   const char*           options)
+{
+  cl_int err = CL_SUCCESS;
+  int i = 0;
+
+  if (p->ref_n > 1)
+    return CL_INVALID_OPERATION;
+
+  if (options) {
+    if(p->build_opts == NULL || strcmp(options, p->build_opts) != 0) {
+      if(p->build_opts) {
+        cl_free(p->build_opts);
+        p->build_opts = NULL;
+      }
+      TRY_ALLOC (p->build_opts, cl_calloc(strlen(options) + 1, sizeof(char)));
+      memcpy(p->build_opts, options, strlen(options));
+
+      p->source_type = p->source ? FROM_SOURCE : p->binary ? FROM_BINARY : FROM_LLVM;
+    }
+  }
+
+  if (options == NULL && p->build_opts) {
+    p->source_type = p->source ? FROM_SOURCE : p->binary ? FROM_BINARY : FROM_LLVM;
+
+    cl_free(p->build_opts);
+    p->build_opts = NULL;
+  }
+
+  const char* temp_header_path = "/tmp/beignet_header/";
+  if (p->source_type == FROM_SOURCE) {
+
+    if (!CompilerSupported()) {
+      err = CL_COMPILER_NOT_AVAILABLE;
+      goto error;
+    }
+
+    //write the headers to /tmp/beignet_header 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* dirc = strdup(temp_path);
+      char* dir = dirname(dirc);
+      mkdir(dir, 0755);
+      if(access(dir, R_OK|W_OK) != 0){
+        err = CL_COMPILE_PROGRAM_FAILURE;
+        goto error;
+      }
+      free(dirc);
+
+      FILE* pfile = fopen(temp_path, "wb");
+      if(pfile){
+        fwrite(input_headers[i]->source, strlen(input_headers[i]->source), 1, pfile);
+        fclose(pfile);
+      }else{
+        err = CL_COMPILE_PROGRAM_FAILURE;
+        goto error;
+      }
+    }
+
+    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");
+
+    if (UNLIKELY(p->opaque == NULL)) {
+      if (p->build_log_sz > 0 && strstr(p->build_log, "error: error reading 'options'"))
+        err = CL_INVALID_BUILD_OPTIONS;
+      else
+        err = CL_BUILD_PROGRAM_FAILURE;
+      goto error;
+    }
+
+    /* Create all the kernels */
+    p->source_type = FROM_LLVM;
+  }
+  p->is_built = 1;
+  return CL_SUCCESS;
+
+error:
+  cl_program_delete(p);
+  p = NULL;
+  return err;
+}
+
 LOCAL cl_kernel
 cl_program_create_kernel(cl_program p, const char *name, cl_int *errcode_ret)
 {
diff --git a/src/cl_program.h b/src/cl_program.h
index b9bf395..a576d37 100644
--- a/src/cl_program.h
+++ b/src/cl_program.h
@@ -110,6 +110,12 @@ cl_program_create_from_llvm(cl_context             context,
 /* Build the program as specified by OCL */
 extern cl_int
 cl_program_build(cl_program p, const char* options);
-
+/* Compile the program as specified by OCL */
+extern cl_int
+cl_program_compile(cl_program            p,
+                   cl_uint               num_input_headers,
+                   const cl_program *    input_headers,
+                   const char **         header_include_names,
+                   const char*           options);
 #endif /* __CL_PROGRAM_H__ */
 
-- 
1.8.1.2



More information about the Beignet mailing list