2 // Copyright 2012 Francisco Jerez
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:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
23 #include "api/util.hpp"
24 #include "core/program.hpp"
25 #include "util/u_debug.h"
29 using namespace clover
;
33 validate_build_common(const program
&prog
, cl_uint num_devs
,
34 const cl_device_id
*d_devs
,
35 void (*pfn_notify
)(cl_program
, void *),
37 if (!pfn_notify
&& user_data
)
38 throw error(CL_INVALID_VALUE
);
40 if (prog
.kernel_ref_count())
41 throw error(CL_INVALID_OPERATION
);
43 if (any_of([&](const device
&dev
) {
44 return !count(dev
, prog
.devices());
45 }, objs
<allow_empty_tag
>(d_devs
, num_devs
)))
46 throw error(CL_INVALID_DEVICE
);
51 clCreateProgramWithSource(cl_context d_ctx
, cl_uint count
,
52 const char **strings
, const size_t *lengths
,
53 cl_int
*r_errcode
) try {
54 auto &ctx
= obj(d_ctx
);
57 if (!count
|| !strings
||
58 any_of(is_zero(), range(strings
, count
)))
59 throw error(CL_INVALID_VALUE
);
61 // Concatenate all the provided fragments together
62 for (unsigned i
= 0; i
< count
; ++i
)
63 source
+= (lengths
&& lengths
[i
] ?
64 std::string(strings
[i
], strings
[i
] + lengths
[i
]) :
65 std::string(strings
[i
]));
67 // ...and create a program object for them.
68 ret_error(r_errcode
, CL_SUCCESS
);
69 return new program(ctx
, source
);
72 ret_error(r_errcode
, e
);
77 clCreateProgramWithBinary(cl_context d_ctx
, cl_uint n
,
78 const cl_device_id
*d_devs
,
79 const size_t *lengths
,
80 const unsigned char **binaries
,
81 cl_int
*r_status
, cl_int
*r_errcode
) try {
82 auto &ctx
= obj(d_ctx
);
83 auto devs
= objs(d_devs
, n
);
85 if (!lengths
|| !binaries
)
86 throw error(CL_INVALID_VALUE
);
88 if (any_of([&](const device
&dev
) {
89 return !count(dev
, ctx
.devices());
91 throw error(CL_INVALID_DEVICE
);
93 // Deserialize the provided binaries,
94 std::vector
<std::pair
<cl_int
, module
>> result
= map(
95 [](const unsigned char *p
, size_t l
) -> std::pair
<cl_int
, module
> {
97 return { CL_INVALID_VALUE
, {} };
100 std::stringbuf
bin( { (char*)p
, l
} );
101 std::istream
s(&bin
);
103 return { CL_SUCCESS
, module::deserialize(s
) };
105 } catch (std::istream::failure
&e
) {
106 return { CL_INVALID_BINARY
, {} };
112 // update the status array,
114 copy(map(keys(), result
), r_status
);
116 if (any_of(key_equals(CL_INVALID_VALUE
), result
))
117 throw error(CL_INVALID_VALUE
);
119 if (any_of(key_equals(CL_INVALID_BINARY
), result
))
120 throw error(CL_INVALID_BINARY
);
122 // initialize a program object with them.
123 ret_error(r_errcode
, CL_SUCCESS
);
124 return new program(ctx
, devs
, map(values(), result
));
127 ret_error(r_errcode
, e
);
131 CLOVER_API cl_program
132 clCreateProgramWithBuiltInKernels(cl_context d_ctx
, cl_uint n
,
133 const cl_device_id
*d_devs
,
134 const char *kernel_names
,
135 cl_int
*r_errcode
) try {
136 auto &ctx
= obj(d_ctx
);
137 auto devs
= objs(d_devs
, n
);
139 if (any_of([&](const device
&dev
) {
140 return !count(dev
, ctx
.devices());
142 throw error(CL_INVALID_DEVICE
);
144 // No currently supported built-in kernels.
145 throw error(CL_INVALID_VALUE
);
148 ret_error(r_errcode
, e
);
154 clRetainProgram(cl_program d_prog
) try {
155 obj(d_prog
).retain();
163 clReleaseProgram(cl_program d_prog
) try {
164 if (obj(d_prog
).release())
174 clBuildProgram(cl_program d_prog
, cl_uint num_devs
,
175 const cl_device_id
*d_devs
, const char *p_opts
,
176 void (*pfn_notify
)(cl_program
, void *),
177 void *user_data
) try {
178 auto &prog
= obj(d_prog
);
180 (d_devs
? objs(d_devs
, num_devs
) : ref_vector
<device
>(prog
.devices()));
181 const auto opts
= std::string(p_opts
? p_opts
: "") + " " +
182 debug_get_option("CLOVER_EXTRA_BUILD_OPTIONS", "");
184 validate_build_common(prog
, num_devs
, d_devs
, pfn_notify
, user_data
);
186 if (prog
.has_source
) {
187 prog
.compile(devs
, opts
);
188 prog
.link(devs
, opts
, { prog
});
189 } else if (any_of([&](const device
&dev
){
190 return prog
.build(dev
).binary_type() != CL_PROGRAM_BINARY_TYPE_EXECUTABLE
;
192 // According to the OpenCL 1.2 specification, “if program is created
193 // with clCreateProgramWithBinary, then the program binary must be an
194 // executable binary (not a compiled binary or library).”
195 throw error(CL_INVALID_BINARY
);
205 clCompileProgram(cl_program d_prog
, cl_uint num_devs
,
206 const cl_device_id
*d_devs
, const char *p_opts
,
207 cl_uint num_headers
, const cl_program
*d_header_progs
,
208 const char **header_names
,
209 void (*pfn_notify
)(cl_program
, void *),
210 void *user_data
) try {
211 auto &prog
= obj(d_prog
);
213 (d_devs
? objs(d_devs
, num_devs
) : ref_vector
<device
>(prog
.devices()));
214 const auto opts
= std::string(p_opts
? p_opts
: "") + " " +
215 debug_get_option("CLOVER_EXTRA_COMPILE_OPTIONS", "");
218 validate_build_common(prog
, num_devs
, d_devs
, pfn_notify
, user_data
);
220 if (bool(num_headers
) != bool(header_names
))
221 throw error(CL_INVALID_VALUE
);
223 if (!prog
.has_source
)
224 throw error(CL_INVALID_OPERATION
);
226 for_each([&](const char *name
, const program
&header
) {
227 if (!header
.has_source
)
228 throw error(CL_INVALID_OPERATION
);
230 if (!any_of(key_equals(name
), headers
))
231 headers
.push_back(std::pair
<std::string
, std::string
>(
232 name
, header
.source()));
234 range(header_names
, num_headers
),
235 objs
<allow_empty_tag
>(d_header_progs
, num_headers
));
237 prog
.compile(devs
, opts
, headers
);
240 } catch (invalid_build_options_error
&e
) {
241 return CL_INVALID_COMPILER_OPTIONS
;
243 } catch (build_error
&e
) {
244 return CL_COMPILE_PROGRAM_FAILURE
;
252 validate_link_devices(const ref_vector
<program
> &progs
,
253 const ref_vector
<device
> &all_devs
,
254 const std::string
&opts
) {
255 std::vector
<device
*> devs
;
256 const bool create_library
=
257 opts
.find("-create-library") != std::string::npos
;
258 const bool enable_link_options
=
259 opts
.find("-enable-link-options") != std::string::npos
;
260 const bool has_link_options
=
261 opts
.find("-cl-denorms-are-zero") != std::string::npos
||
262 opts
.find("-cl-no-signed-zeroes") != std::string::npos
||
263 opts
.find("-cl-unsafe-math-optimizations") != std::string::npos
||
264 opts
.find("-cl-finite-math-only") != std::string::npos
||
265 opts
.find("-cl-fast-relaxed-math") != std::string::npos
||
266 opts
.find("-cl-no-subgroup-ifp") != std::string::npos
;
268 // According to the OpenCL 1.2 specification, "[the
269 // -enable-link-options] option must be specified with the
270 // create-library option".
271 if (enable_link_options
&& !create_library
)
272 throw error(CL_INVALID_LINKER_OPTIONS
);
274 // According to the OpenCL 1.2 specification, "the
275 // [program linking options] can be specified when linking a program
277 if (has_link_options
&& create_library
)
278 throw error(CL_INVALID_LINKER_OPTIONS
);
280 for (auto &dev
: all_devs
) {
281 const auto has_binary
= [&](const program
&prog
) {
282 const auto t
= prog
.build(dev
).binary_type();
283 return t
== CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT
||
284 t
== CL_PROGRAM_BINARY_TYPE_LIBRARY
;
287 // According to the OpenCL 1.2 specification, a library is made of
288 // “compiled binaries specified in input_programs argument to
289 // clLinkProgram“; compiled binaries does not refer to libraries:
290 // “input_programs is an array of program objects that are compiled
291 // binaries or libraries that are to be linked to create the program
293 if (create_library
&& any_of([&](const program
&prog
) {
294 const auto t
= prog
.build(dev
).binary_type();
295 return t
!= CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT
;
297 throw error(CL_INVALID_OPERATION
);
299 // According to the CL 1.2 spec, when "all programs specified [..]
300 // contain a compiled binary or library for the device [..] a link is
302 else if (all_of(has_binary
, progs
))
303 devs
.push_back(&dev
);
305 // otherwise if "none of the programs contain a compiled binary or
306 // library for that device [..] no link is performed. All other
307 // cases will return a CL_INVALID_OPERATION error."
308 else if (any_of(has_binary
, progs
))
309 throw error(CL_INVALID_OPERATION
);
311 // According to the OpenCL 1.2 specification, "[t]he linker may apply
312 // [program linking options] to all compiled program objects
313 // specified to clLinkProgram. The linker may apply these options
314 // only to libraries which were created with the
315 // -enable-link-option."
316 else if (has_link_options
&& any_of([&](const program
&prog
) {
317 const auto t
= prog
.build(dev
).binary_type();
318 return !(t
== CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT
||
319 (t
== CL_PROGRAM_BINARY_TYPE_LIBRARY
&&
320 prog
.build(dev
).opts
.find("-enable-link-options") !=
323 throw error(CL_INVALID_LINKER_OPTIONS
);
326 return map(derefs(), devs
);
330 CLOVER_API cl_program
331 clLinkProgram(cl_context d_ctx
, cl_uint num_devs
, const cl_device_id
*d_devs
,
332 const char *p_opts
, cl_uint num_progs
, const cl_program
*d_progs
,
333 void (*pfn_notify
) (cl_program
, void *), void *user_data
,
334 cl_int
*r_errcode
) try {
335 auto &ctx
= obj(d_ctx
);
336 const auto opts
= std::string(p_opts
? p_opts
: "") + " " +
337 debug_get_option("CLOVER_EXTRA_LINK_OPTIONS", "");
338 auto progs
= objs(d_progs
, num_progs
);
340 (d_devs
? objs(d_devs
, num_devs
) : ref_vector
<device
>(ctx
.devices()));
341 auto prog
= create
<program
>(ctx
, all_devs
);
342 auto devs
= validate_link_devices(progs
, all_devs
, opts
);
344 validate_build_common(prog
, num_devs
, d_devs
, pfn_notify
, user_data
);
347 prog().link(devs
, opts
, progs
);
348 ret_error(r_errcode
, CL_SUCCESS
);
350 } catch (build_error
&e
) {
351 ret_error(r_errcode
, CL_LINK_PROGRAM_FAILURE
);
354 return ret_object(prog
);
356 } catch (invalid_build_options_error
&e
) {
357 ret_error(r_errcode
, CL_INVALID_LINKER_OPTIONS
);
361 ret_error(r_errcode
, e
);
371 clUnloadPlatformCompiler(cl_platform_id d_platform
) {
376 clGetProgramInfo(cl_program d_prog
, cl_program_info param
,
377 size_t size
, void *r_buf
, size_t *r_size
) try {
378 property_buffer buf
{ r_buf
, size
, r_size
};
379 auto &prog
= obj(d_prog
);
382 case CL_PROGRAM_REFERENCE_COUNT
:
383 buf
.as_scalar
<cl_uint
>() = prog
.ref_count();
386 case CL_PROGRAM_CONTEXT
:
387 buf
.as_scalar
<cl_context
>() = desc(prog
.context());
390 case CL_PROGRAM_NUM_DEVICES
:
391 buf
.as_scalar
<cl_uint
>() = (prog
.devices().size() ?
392 prog
.devices().size() :
393 prog
.context().devices().size());
396 case CL_PROGRAM_DEVICES
:
397 buf
.as_vector
<cl_device_id
>() = (prog
.devices().size() ?
398 descs(prog
.devices()) :
399 descs(prog
.context().devices()));
402 case CL_PROGRAM_SOURCE
:
403 buf
.as_string() = prog
.source();
406 case CL_PROGRAM_BINARY_SIZES
:
407 buf
.as_vector
<size_t>() = map([&](const device
&dev
) {
408 return prog
.build(dev
).binary
.size();
413 case CL_PROGRAM_BINARIES
:
414 buf
.as_matrix
<unsigned char>() = map([&](const device
&dev
) {
416 std::ostream
s(&bin
);
417 prog
.build(dev
).binary
.serialize(s
);
423 case CL_PROGRAM_NUM_KERNELS
:
424 buf
.as_scalar
<cl_uint
>() = prog
.symbols().size();
427 case CL_PROGRAM_KERNEL_NAMES
:
428 buf
.as_string() = fold([](const std::string
&a
, const module::symbol
&s
) {
429 return ((a
.empty() ? "" : a
+ ";") + s
.name
);
430 }, std::string(), prog
.symbols());
434 throw error(CL_INVALID_VALUE
);
444 clGetProgramBuildInfo(cl_program d_prog
, cl_device_id d_dev
,
445 cl_program_build_info param
,
446 size_t size
, void *r_buf
, size_t *r_size
) try {
447 property_buffer buf
{ r_buf
, size
, r_size
};
448 auto &prog
= obj(d_prog
);
449 auto &dev
= obj(d_dev
);
451 if (!count(dev
, prog
.context().devices()))
452 return CL_INVALID_DEVICE
;
455 case CL_PROGRAM_BUILD_STATUS
:
456 buf
.as_scalar
<cl_build_status
>() = prog
.build(dev
).status();
459 case CL_PROGRAM_BUILD_OPTIONS
:
460 buf
.as_string() = prog
.build(dev
).opts
;
463 case CL_PROGRAM_BUILD_LOG
:
464 buf
.as_string() = prog
.build(dev
).log
;
467 case CL_PROGRAM_BINARY_TYPE
:
468 buf
.as_scalar
<cl_program_binary_type
>() = prog
.build(dev
).binary_type();
472 throw error(CL_INVALID_VALUE
);