Added first support for compilation from source
authorBenjamin Segovia <segovia.benjamin@gmail.com>
Mon, 16 Apr 2012 08:09:58 +0000 (01:09 -0700)
committerKeith Packard <keithp@keithp.com>
Fri, 10 Aug 2012 23:16:26 +0000 (16:16 -0700)
src/cl_api.c
src/cl_program.c
src/cl_program.h

index aa7b664..b3971b8 100644 (file)
@@ -418,8 +418,19 @@ clCreateProgramWithSource(cl_context     context,
                           const size_t * lengths,
                           cl_int *       errcode_ret)
 {
-  NOT_IMPLEMENTED;
-  return NULL;
+  cl_program program = NULL;
+  cl_int err = CL_SUCCESS;
+
+  CHECK_CONTEXT (context);
+  program = cl_program_create_from_source(context,
+                                          count,
+                                          strings,
+                                          lengths,
+                                          &err);
+error:
+  if (errcode_ret)
+    *errcode_ret = err;
+  return program;
 }
 
 cl_program
@@ -447,7 +458,6 @@ error:
     *errcode_ret = err;
   return program;
 }
-
 cl_int
 clRetainProgram(cl_program program)
 {
@@ -476,9 +486,6 @@ clBuildProgram(cl_program            program,
                void (CL_CALLBACK *pfn_notify) (cl_program, void*),
                void *                user_data)
 {
-  /* It does nothing today since we only support creation from binary. We just
-   * try to follow OCL specification
-   */
   cl_int err = CL_SUCCESS;
   CHECK_PROGRAM(program);
   INVALID_VALUE_IF (num_devices > 1);
@@ -494,14 +501,14 @@ clBuildProgram(cl_program            program,
     }
   }
 
-  /* XXX */
-  FATAL_IF (pfn_notify != NULL || user_data != NULL,
-            "No call back is supported now");
-
-  /* TODO support create program from source */
-  assert(program->from_source == CL_FALSE);
+  /* TODO support create program from binary */
+  assert(program->source_type == FROM_LLVM ||
+         program->source_type == FROM_SOURCE);
+  cl_program_build(program);
   program->is_built = CL_TRUE;
 
+  if (pfn_notify) pfn_notify(program, user_data);
+
 error:
   return err;
 }
index 5eec661..074a343 100644 (file)
 #include <string.h>
 #include <assert.h>
 
+static void
+cl_program_release_sources(cl_program p)
+{
+  int i;
+  if (p->sources == NULL) return;
+  for (i = 0; i < p->src_n; ++i)
+    if (p->sources[i]) cl_free(p->sources[i]);
+  cl_free(p->sources);
+  p->sources = NULL;
+  p->src_n = 0;
+}
+
 LOCAL void
 cl_program_delete(cl_program p)
 {
@@ -41,8 +53,10 @@ cl_program_delete(cl_program p)
     return;
 
   /* We are not done with it yet */
-  if ((ref = atomic_dec(&p->ref_n)) > 1)
-    return;
+  if ((ref = atomic_dec(&p->ref_n)) > 1) return;
+
+  /* Destroy the sources if still allocated */
+  cl_program_release_sources(p);
 
   /* Remove it from the list */
   assert(p->ctx);
@@ -187,15 +201,58 @@ cl_program_create_from_llvm(cl_context ctx,
   INVALID_VALUE_IF (file_name == NULL);
 
   program = cl_program_new(ctx);
-
   program->opaque = gbe_program_new_from_llvm(file_name, 0, NULL, NULL);
-  if (program->opaque == NULL) {
+  if (UNLIKELY(program->opaque == NULL)) {
     err = CL_INVALID_PROGRAM;
     goto error;
   }
 
   /* Create all the kernels */
   TRY (cl_program_load_gen_program, program);
+  program->source_type = FROM_LLVM;
+
+exit:
+  if (errcode_ret)
+    *errcode_ret = err;
+  return program;
+error:
+  cl_program_delete(program);
+  program = NULL;
+  goto exit;
+}
+
+LOCAL cl_program
+cl_program_create_from_source(cl_context ctx,
+                              cl_uint count,
+                              const char **strings,
+                              const size_t *lengths,
+                              cl_int *errcode_ret)
+
+{
+  cl_program program = NULL;
+  cl_int err = CL_SUCCESS;
+  cl_int i;
+
+  assert(ctx);
+  INVALID_VALUE_IF (count == 0);
+  INVALID_VALUE_IF (strings == NULL);
+
+  // the real compilation step will be done at build time since we do not have
+  // yet the compilation options
+  program = cl_program_new(ctx);
+  TRY_ALLOC (program->sources, cl_calloc(count, sizeof(char*)));
+  for (i = 0; i < count; ++i) {
+    size_t len;
+    if (lengths == NULL || lengths[i] == 0)
+      len = strlen(strings[i]);
+    else
+      len = lengths[i];
+    TRY_ALLOC (program->sources[i], cl_calloc(len+1, sizeof(char)));
+    memcpy(program->sources[i], strings[i], len);
+    program->sources[i][len] = 0;
+  }
+  program->src_n = count;
+  program->source_type = FROM_SOURCE;
 
 exit:
   if (errcode_ret)
@@ -207,6 +264,30 @@ error:
   goto exit;
 }
 
+LOCAL cl_int
+cl_program_build(cl_program p)
+{
+  cl_int err = CL_SUCCESS;
+
+  if (p->source_type == FROM_SOURCE) {
+    /* XXX support multiple sources later */
+    FATAL_IF (p->src_n != 1, "Only ONE source supported");
+    p->opaque = gbe_program_new_from_source(p->sources[0], 0, NULL, NULL);
+    if (UNLIKELY(p->opaque == NULL)) {
+      err = CL_INVALID_PROGRAM;
+      goto error;
+    }
+
+    /* Create all the kernels */
+    TRY (cl_program_load_gen_program, p);
+    p->source_type = FROM_LLVM;
+  }
+
+  p->is_built = 1;
+error:
+  return err;
+}
+
 LOCAL cl_kernel
 cl_program_create_kernel(cl_program p, const char *name, cl_int *errcode_ret)
 {
index 03ade0f..fc33c79 100644 (file)
 // This is the structure ouput by the compiler
 struct _gbe_program;
 
+enum {
+  FROM_SOURCE = 0,
+  FROM_LLVM = 1,
+  FROM_BINARY = 2
+};
+
 /* This maps an OCL file containing some kernels */
 struct _cl_program {
   uint64_t magic;         /* To identify it as a program */
@@ -40,8 +46,10 @@ struct _cl_program {
   cl_context ctx;         /* Its parent context */
   char *bin;              /* The program copied verbatim */
   size_t bin_sz;          /* Its size in memory */
+  char **sources;         /* Program sources */
+  size_t src_n;           /* Number of sources */
   uint32_t ker_n;         /* Number of declared kernels */
-  uint32_t from_source:1; /* Built from binary or source? */
+  uint32_t source_type:2; /* Built from binary, source or LLVM */
   uint32_t is_built:1;    /* Did we call clBuildProgram on it? */
 };
 
@@ -57,6 +65,14 @@ extern void cl_program_add_ref(cl_program);
 /* Create a kernel for the OCL user */
 extern cl_kernel cl_program_create_kernel(cl_program, const char*, cl_int*);
 
+/* Create a program from OCL source */
+extern cl_program
+cl_program_create_from_source(cl_context ctx,
+                              cl_uint count,
+                              const char **strings,
+                              const size_t *lengths,
+                              cl_int *errcode_ret);
+
 /* Directly create a program from a blob */
 extern cl_program
 cl_program_create_from_binary(cl_context             context,
@@ -75,5 +91,9 @@ cl_program_create_from_llvm(cl_context             context,
                             const char *           fileName,
                             cl_int *               errcode_ret);
 
+/* Build the program as specified by OCL */
+extern cl_int
+cl_program_build(cl_program p);
+
 #endif /* __CL_PROGRAM_H__ */