1//
2// Copyright 2012 Francisco Jerez
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17// THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20// SOFTWARE.
21//
22
23#include "api/util.hpp"
24#include "core/program.hpp"
25
26using namespace clover;
27
28PUBLIC cl_program
29clCreateProgramWithSource(cl_context ctx, cl_uint count,
30                          const char **strings, const size_t *lengths,
31                          cl_int *errcode_ret) try {
32   std::string source;
33
34   if (!ctx)
35      throw error(CL_INVALID_CONTEXT);
36
37   if (!count || !strings ||
38       any_of(is_zero<const char *>(), strings, strings + count))
39      throw error(CL_INVALID_VALUE);
40
41   // Concatenate all the provided fragments together
42   for (unsigned i = 0; i < count; ++i)
43         source += (lengths && lengths[i] ?
44                    std::string(strings[i], strings[i] + lengths[i]) :
45                    std::string(strings[i]));
46
47   // ...and create a program object for them.
48   ret_error(errcode_ret, CL_SUCCESS);
49   return new program(*ctx, source);
50
51} catch (error &e) {
52   ret_error(errcode_ret, e);
53   return NULL;
54}
55
56PUBLIC cl_program
57clCreateProgramWithBinary(cl_context ctx, cl_uint count,
58                          const cl_device_id *devs, const size_t *lengths,
59                          const unsigned char **binaries, cl_int *status_ret,
60                          cl_int *errcode_ret) try {
61   if (!ctx)
62      throw error(CL_INVALID_CONTEXT);
63
64   if (!count || !devs || !lengths || !binaries)
65      throw error(CL_INVALID_VALUE);
66
67   if (any_of([&](const cl_device_id dev) {
68            return !ctx->has_device(dev);
69         }, devs, devs + count))
70      throw error(CL_INVALID_DEVICE);
71
72   // Deserialize the provided binaries,
73   auto modules = map(
74      [](const unsigned char *p, size_t l) -> std::pair<cl_int, module> {
75         if (!p || !l)
76            return { CL_INVALID_VALUE, {} };
77
78         try {
79            compat::istream::buffer_t bin(p, l);
80            compat::istream s(bin);
81
82            return { CL_SUCCESS, module::deserialize(s) };
83
84         } catch (compat::istream::error &e) {
85            return { CL_INVALID_BINARY, {} };
86         }
87      },
88      binaries, binaries + count, lengths);
89
90   // update the status array,
91   if (status_ret)
92      std::transform(modules.begin(), modules.end(), status_ret,
93                     keys<cl_int, module>);
94
95   if (any_of(key_equals<cl_int, module>(CL_INVALID_VALUE),
96              modules.begin(), modules.end()))
97      throw error(CL_INVALID_VALUE);
98
99   if (any_of(key_equals<cl_int, module>(CL_INVALID_BINARY),
100              modules.begin(), modules.end()))
101      throw error(CL_INVALID_BINARY);
102
103   // initialize a program object with them.
104   ret_error(errcode_ret, CL_SUCCESS);
105   return new program(*ctx, { devs, devs + count },
106                      map(values<cl_int, module>,
107                          modules.begin(), modules.end()));
108
109} catch (error &e) {
110   ret_error(errcode_ret, e);
111   return NULL;
112}
113
114PUBLIC cl_int
115clRetainProgram(cl_program prog) {
116   if (!prog)
117      return CL_INVALID_PROGRAM;
118
119   prog->retain();
120   return CL_SUCCESS;
121}
122
123PUBLIC cl_int
124clReleaseProgram(cl_program prog) {
125   if (!prog)
126      return CL_INVALID_PROGRAM;
127
128   if (prog->release())
129      delete prog;
130
131   return CL_SUCCESS;
132}
133
134PUBLIC cl_int
135clBuildProgram(cl_program prog, cl_uint count, const cl_device_id *devs,
136               const char *opts, void (*pfn_notify)(cl_program, void *),
137               void *user_data) try {
138   if (!prog)
139      throw error(CL_INVALID_PROGRAM);
140
141   if (bool(count) != bool(devs) ||
142       (!pfn_notify && user_data))
143      throw error(CL_INVALID_VALUE);
144
145   if (devs) {
146      if (any_of([&](const cl_device_id dev) {
147               return !prog->ctx.has_device(dev);
148            }, devs, devs + count))
149         throw error(CL_INVALID_DEVICE);
150
151      prog->build({ devs, devs + count });
152   } else {
153      prog->build(prog->ctx.devs);
154   }
155
156   return CL_SUCCESS;
157
158} catch (error &e) {
159   return e.get();
160}
161
162PUBLIC cl_int
163clUnloadCompiler() {
164   return CL_SUCCESS;
165}
166
167PUBLIC cl_int
168clGetProgramInfo(cl_program prog, cl_program_info param,
169                 size_t size, void *buf, size_t *size_ret) {
170   if (!prog)
171      return CL_INVALID_PROGRAM;
172
173   switch (param) {
174   case CL_PROGRAM_REFERENCE_COUNT:
175      return scalar_property<cl_uint>(buf, size, size_ret,
176                                      prog->ref_count());
177
178   case CL_PROGRAM_CONTEXT:
179      return scalar_property<cl_context>(buf, size, size_ret,
180                                         &prog->ctx);
181
182   case CL_PROGRAM_NUM_DEVICES:
183      return scalar_property<cl_uint>(buf, size, size_ret,
184                                      prog->binaries().size());
185
186   case CL_PROGRAM_DEVICES:
187      return vector_property<cl_device_id>(
188         buf, size, size_ret,
189         map(keys<device *, module>,
190             prog->binaries().begin(), prog->binaries().end()));
191
192   case CL_PROGRAM_SOURCE:
193      return string_property(buf, size, size_ret, prog->source());
194
195   case CL_PROGRAM_BINARY_SIZES:
196      return vector_property<size_t>(
197         buf, size, size_ret,
198         map([](const std::pair<device *, module> &ent) {
199               compat::ostream::buffer_t bin;
200               compat::ostream s(bin);
201               ent.second.serialize(s);
202               return bin.size();
203            },
204            prog->binaries().begin(), prog->binaries().end()));
205
206   case CL_PROGRAM_BINARIES:
207      return matrix_property<unsigned char>(
208         buf, size, size_ret,
209         map([](const std::pair<device *, module> &ent) {
210               compat::ostream::buffer_t bin;
211               compat::ostream s(bin);
212               ent.second.serialize(s);
213               return bin;
214            },
215            prog->binaries().begin(), prog->binaries().end()));
216
217   default:
218      return CL_INVALID_VALUE;
219   }
220}
221
222PUBLIC cl_int
223clGetProgramBuildInfo(cl_program prog, cl_device_id dev,
224                      cl_program_build_info param,
225                      size_t size, void *buf, size_t *size_ret) {
226   if (!prog)
227      return CL_INVALID_PROGRAM;
228
229   if (!prog->ctx.has_device(dev))
230      return CL_INVALID_DEVICE;
231
232   switch (param) {
233   case CL_PROGRAM_BUILD_STATUS:
234      return scalar_property<cl_build_status>(buf, size, size_ret,
235                                              prog->build_status(dev));
236
237   case CL_PROGRAM_BUILD_OPTIONS:
238      return string_property(buf, size, size_ret, prog->build_opts(dev));
239
240   case CL_PROGRAM_BUILD_LOG:
241      return string_property(buf, size, size_ret, prog->build_log(dev));
242
243   default:
244      return CL_INVALID_VALUE;
245   }
246}
247