17ec681f3Smrg// 27ec681f3Smrg// Copyright 2012 Francisco Jerez 37ec681f3Smrg// 47ec681f3Smrg// Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg// copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg// to deal in the Software without restriction, including without limitation 77ec681f3Smrg// the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg// and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg// Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg// 117ec681f3Smrg// The above copyright notice and this permission notice shall be included in 127ec681f3Smrg// all copies or substantial portions of the Software. 137ec681f3Smrg// 147ec681f3Smrg// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 157ec681f3Smrg// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 167ec681f3Smrg// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 177ec681f3Smrg// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 187ec681f3Smrg// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 197ec681f3Smrg// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 207ec681f3Smrg// OTHER DEALINGS IN THE SOFTWARE. 217ec681f3Smrg// 227ec681f3Smrg 237ec681f3Smrg#include "api/util.hpp" 247ec681f3Smrg#include "core/program.hpp" 257ec681f3Smrg#include "core/platform.hpp" 267ec681f3Smrg#include "spirv/invocation.hpp" 277ec681f3Smrg#include "util/u_debug.h" 287ec681f3Smrg 297ec681f3Smrg#include <limits> 307ec681f3Smrg#include <sstream> 317ec681f3Smrg 327ec681f3Smrgusing namespace clover; 337ec681f3Smrg 347ec681f3Smrgnamespace { 357ec681f3Smrg 367ec681f3Smrg std::string 377ec681f3Smrg build_options(const char *p_opts, const char *p_debug) { 387ec681f3Smrg auto opts = std::string(p_opts ? p_opts : ""); 397ec681f3Smrg std::string extra_opts = debug_get_option(p_debug, ""); 407ec681f3Smrg 417ec681f3Smrg return detokenize(std::vector<std::string>{opts, extra_opts}, " "); 427ec681f3Smrg } 437ec681f3Smrg 447ec681f3Smrg class build_notifier { 457ec681f3Smrg public: 467ec681f3Smrg build_notifier(cl_program prog, 477ec681f3Smrg void (*notifer)(cl_program, void *), void *data) : 487ec681f3Smrg prog_(prog), notifer(notifer), data_(data) { } 497ec681f3Smrg 507ec681f3Smrg ~build_notifier() { 517ec681f3Smrg if (notifer) 527ec681f3Smrg notifer(prog_, data_); 537ec681f3Smrg } 547ec681f3Smrg 557ec681f3Smrg private: 567ec681f3Smrg cl_program prog_; 577ec681f3Smrg void (*notifer)(cl_program, void *); 587ec681f3Smrg void *data_; 597ec681f3Smrg }; 607ec681f3Smrg 617ec681f3Smrg void 627ec681f3Smrg validate_build_common(const program &prog, cl_uint num_devs, 637ec681f3Smrg const cl_device_id *d_devs, 647ec681f3Smrg void (*pfn_notify)(cl_program, void *), 657ec681f3Smrg void *user_data) { 667ec681f3Smrg if (!pfn_notify && user_data) 677ec681f3Smrg throw error(CL_INVALID_VALUE); 687ec681f3Smrg 697ec681f3Smrg if (prog.kernel_ref_count()) 707ec681f3Smrg throw error(CL_INVALID_OPERATION); 717ec681f3Smrg 727ec681f3Smrg if (any_of([&](const device &dev) { 737ec681f3Smrg return !count(dev, prog.devices()); 747ec681f3Smrg }, objs<allow_empty_tag>(d_devs, num_devs))) 757ec681f3Smrg throw error(CL_INVALID_DEVICE); 767ec681f3Smrg } 777ec681f3Smrg 787ec681f3Smrg enum program::il_type 797ec681f3Smrg identify_and_validate_il(const std::string &il, 807ec681f3Smrg const cl_version opencl_version, 817ec681f3Smrg const context::notify_action ¬ify) { 827ec681f3Smrg 837ec681f3Smrg enum program::il_type il_type = program::il_type::none; 847ec681f3Smrg 857ec681f3Smrg#ifdef HAVE_CLOVER_SPIRV 867ec681f3Smrg if (spirv::is_binary_spirv(il)) { 877ec681f3Smrg std::string log; 887ec681f3Smrg if (!spirv::is_valid_spirv(il, opencl_version, log)) { 897ec681f3Smrg if (notify) { 907ec681f3Smrg notify(log.c_str()); 917ec681f3Smrg } 927ec681f3Smrg throw error(CL_INVALID_VALUE); 937ec681f3Smrg } 947ec681f3Smrg il_type = program::il_type::spirv; 957ec681f3Smrg } 967ec681f3Smrg#endif 977ec681f3Smrg 987ec681f3Smrg return il_type; 997ec681f3Smrg } 1007ec681f3Smrg} 1017ec681f3Smrg 1027ec681f3SmrgCLOVER_API cl_program 1037ec681f3SmrgclCreateProgramWithSource(cl_context d_ctx, cl_uint count, 1047ec681f3Smrg const char **strings, const size_t *lengths, 1057ec681f3Smrg cl_int *r_errcode) try { 1067ec681f3Smrg auto &ctx = obj(d_ctx); 1077ec681f3Smrg std::string source; 1087ec681f3Smrg 1097ec681f3Smrg if (!count || !strings || 1107ec681f3Smrg any_of(is_zero(), range(strings, count))) 1117ec681f3Smrg throw error(CL_INVALID_VALUE); 1127ec681f3Smrg 1137ec681f3Smrg // Concatenate all the provided fragments together 1147ec681f3Smrg for (unsigned i = 0; i < count; ++i) 1157ec681f3Smrg source += (lengths && lengths[i] ? 1167ec681f3Smrg std::string(strings[i], strings[i] + lengths[i]) : 1177ec681f3Smrg std::string(strings[i])); 1187ec681f3Smrg 1197ec681f3Smrg // ...and create a program object for them. 1207ec681f3Smrg ret_error(r_errcode, CL_SUCCESS); 1217ec681f3Smrg return new program(ctx, std::move(source), program::il_type::source); 1227ec681f3Smrg 1237ec681f3Smrg} catch (error &e) { 1247ec681f3Smrg ret_error(r_errcode, e); 1257ec681f3Smrg return NULL; 1267ec681f3Smrg} 1277ec681f3Smrg 1287ec681f3SmrgCLOVER_API cl_program 1297ec681f3SmrgclCreateProgramWithBinary(cl_context d_ctx, cl_uint n, 1307ec681f3Smrg const cl_device_id *d_devs, 1317ec681f3Smrg const size_t *lengths, 1327ec681f3Smrg const unsigned char **binaries, 1337ec681f3Smrg cl_int *r_status, cl_int *r_errcode) try { 1347ec681f3Smrg auto &ctx = obj(d_ctx); 1357ec681f3Smrg auto devs = objs(d_devs, n); 1367ec681f3Smrg 1377ec681f3Smrg if (!lengths || !binaries) 1387ec681f3Smrg throw error(CL_INVALID_VALUE); 1397ec681f3Smrg 1407ec681f3Smrg if (any_of([&](const device &dev) { 1417ec681f3Smrg return !count(dev, ctx.devices()); 1427ec681f3Smrg }, devs)) 1437ec681f3Smrg throw error(CL_INVALID_DEVICE); 1447ec681f3Smrg 1457ec681f3Smrg // Deserialize the provided binaries, 1467ec681f3Smrg std::vector<std::pair<cl_int, binary>> result = map( 1477ec681f3Smrg [](const unsigned char *p, size_t l) -> std::pair<cl_int, binary> { 1487ec681f3Smrg if (!p || !l) 1497ec681f3Smrg return { CL_INVALID_VALUE, {} }; 1507ec681f3Smrg 1517ec681f3Smrg try { 1527ec681f3Smrg std::stringbuf bin( std::string{ (char*)p, l } ); 1537ec681f3Smrg std::istream s(&bin); 1547ec681f3Smrg 1557ec681f3Smrg return { CL_SUCCESS, binary::deserialize(s) }; 1567ec681f3Smrg 1577ec681f3Smrg } catch (std::istream::failure &) { 1587ec681f3Smrg return { CL_INVALID_BINARY, {} }; 1597ec681f3Smrg } 1607ec681f3Smrg }, 1617ec681f3Smrg range(binaries, n), 1627ec681f3Smrg range(lengths, n)); 1637ec681f3Smrg 1647ec681f3Smrg // update the status array, 1657ec681f3Smrg if (r_status) 1667ec681f3Smrg copy(map(keys(), result), r_status); 1677ec681f3Smrg 1687ec681f3Smrg if (any_of(key_equals(CL_INVALID_VALUE), result)) 1697ec681f3Smrg throw error(CL_INVALID_VALUE); 1707ec681f3Smrg 1717ec681f3Smrg if (any_of(key_equals(CL_INVALID_BINARY), result)) 1727ec681f3Smrg throw error(CL_INVALID_BINARY); 1737ec681f3Smrg 1747ec681f3Smrg // initialize a program object with them. 1757ec681f3Smrg ret_error(r_errcode, CL_SUCCESS); 1767ec681f3Smrg return new program(ctx, devs, map(values(), result)); 1777ec681f3Smrg 1787ec681f3Smrg} catch (error &e) { 1797ec681f3Smrg ret_error(r_errcode, e); 1807ec681f3Smrg return NULL; 1817ec681f3Smrg} 1827ec681f3Smrg 1837ec681f3Smrgcl_program 1847ec681f3Smrgclover::CreateProgramWithILKHR(cl_context d_ctx, const void *il, 1857ec681f3Smrg size_t length, cl_int *r_errcode) try { 1867ec681f3Smrg auto &ctx = obj(d_ctx); 1877ec681f3Smrg 1887ec681f3Smrg if (!il || !length) 1897ec681f3Smrg throw error(CL_INVALID_VALUE); 1907ec681f3Smrg 1917ec681f3Smrg // Compute the highest OpenCL version supported by all devices associated to 1927ec681f3Smrg // the context. That is the version used for validating the SPIR-V binary. 1937ec681f3Smrg cl_version min_opencl_version = std::numeric_limits<uint32_t>::max(); 1947ec681f3Smrg for (const device &dev : ctx.devices()) { 1957ec681f3Smrg const cl_version opencl_version = dev.device_version(); 1967ec681f3Smrg min_opencl_version = std::min(opencl_version, min_opencl_version); 1977ec681f3Smrg } 1987ec681f3Smrg 1997ec681f3Smrg const char *stream = reinterpret_cast<const char *>(il); 2007ec681f3Smrg std::string binary(stream, stream + length); 2017ec681f3Smrg const enum program::il_type il_type = identify_and_validate_il(binary, 2027ec681f3Smrg min_opencl_version, 2037ec681f3Smrg ctx.notify); 2047ec681f3Smrg 2057ec681f3Smrg if (il_type == program::il_type::none) 2067ec681f3Smrg throw error(CL_INVALID_VALUE); 2077ec681f3Smrg 2087ec681f3Smrg // Initialize a program object with it. 2097ec681f3Smrg ret_error(r_errcode, CL_SUCCESS); 2107ec681f3Smrg return new program(ctx, std::move(binary), il_type); 2117ec681f3Smrg 2127ec681f3Smrg} catch (error &e) { 2137ec681f3Smrg ret_error(r_errcode, e); 2147ec681f3Smrg return NULL; 2157ec681f3Smrg} 2167ec681f3Smrg 2177ec681f3SmrgCLOVER_API cl_program 2187ec681f3SmrgclCreateProgramWithIL(cl_context d_ctx, 2197ec681f3Smrg const void *il, 2207ec681f3Smrg size_t length, 2217ec681f3Smrg cl_int *r_errcode) { 2227ec681f3Smrg return CreateProgramWithILKHR(d_ctx, il, length, r_errcode); 2237ec681f3Smrg} 2247ec681f3Smrg 2257ec681f3SmrgCLOVER_API cl_program 2267ec681f3SmrgclCreateProgramWithBuiltInKernels(cl_context d_ctx, cl_uint n, 2277ec681f3Smrg const cl_device_id *d_devs, 2287ec681f3Smrg const char *kernel_names, 2297ec681f3Smrg cl_int *r_errcode) try { 2307ec681f3Smrg auto &ctx = obj(d_ctx); 2317ec681f3Smrg auto devs = objs(d_devs, n); 2327ec681f3Smrg 2337ec681f3Smrg if (any_of([&](const device &dev) { 2347ec681f3Smrg return !count(dev, ctx.devices()); 2357ec681f3Smrg }, devs)) 2367ec681f3Smrg throw error(CL_INVALID_DEVICE); 2377ec681f3Smrg 2387ec681f3Smrg // No currently supported built-in kernels. 2397ec681f3Smrg throw error(CL_INVALID_VALUE); 2407ec681f3Smrg 2417ec681f3Smrg} catch (error &e) { 2427ec681f3Smrg ret_error(r_errcode, e); 2437ec681f3Smrg return NULL; 2447ec681f3Smrg} 2457ec681f3Smrg 2467ec681f3Smrg 2477ec681f3SmrgCLOVER_API cl_int 2487ec681f3SmrgclRetainProgram(cl_program d_prog) try { 2497ec681f3Smrg obj(d_prog).retain(); 2507ec681f3Smrg return CL_SUCCESS; 2517ec681f3Smrg 2527ec681f3Smrg} catch (error &e) { 2537ec681f3Smrg return e.get(); 2547ec681f3Smrg} 2557ec681f3Smrg 2567ec681f3SmrgCLOVER_API cl_int 2577ec681f3SmrgclReleaseProgram(cl_program d_prog) try { 2587ec681f3Smrg if (obj(d_prog).release()) 2597ec681f3Smrg delete pobj(d_prog); 2607ec681f3Smrg 2617ec681f3Smrg return CL_SUCCESS; 2627ec681f3Smrg 2637ec681f3Smrg} catch (error &e) { 2647ec681f3Smrg return e.get(); 2657ec681f3Smrg} 2667ec681f3Smrg 2677ec681f3SmrgCLOVER_API cl_int 2687ec681f3SmrgclBuildProgram(cl_program d_prog, cl_uint num_devs, 2697ec681f3Smrg const cl_device_id *d_devs, const char *p_opts, 2707ec681f3Smrg void (*pfn_notify)(cl_program, void *), 2717ec681f3Smrg void *user_data) try { 2727ec681f3Smrg auto &prog = obj(d_prog); 2737ec681f3Smrg auto devs = 2747ec681f3Smrg (d_devs ? objs(d_devs, num_devs) : ref_vector<device>(prog.devices())); 2757ec681f3Smrg const auto opts = build_options(p_opts, "CLOVER_EXTRA_BUILD_OPTIONS"); 2767ec681f3Smrg 2777ec681f3Smrg validate_build_common(prog, num_devs, d_devs, pfn_notify, user_data); 2787ec681f3Smrg 2797ec681f3Smrg auto notifier = build_notifier(d_prog, pfn_notify, user_data); 2807ec681f3Smrg 2817ec681f3Smrg if (prog.il_type() != program::il_type::none) { 2827ec681f3Smrg prog.compile(devs, opts); 2837ec681f3Smrg prog.link(devs, opts, { prog }); 2847ec681f3Smrg } else if (any_of([&](const device &dev){ 2857ec681f3Smrg return prog.build(dev).binary_type() != CL_PROGRAM_BINARY_TYPE_EXECUTABLE; 2867ec681f3Smrg }, devs)) { 2877ec681f3Smrg // According to the OpenCL 1.2 specification, “if program is created 2887ec681f3Smrg // with clCreateProgramWithBinary, then the program binary must be an 2897ec681f3Smrg // executable binary (not a compiled binary or library).” 2907ec681f3Smrg throw error(CL_INVALID_BINARY); 2917ec681f3Smrg } 2927ec681f3Smrg 2937ec681f3Smrg return CL_SUCCESS; 2947ec681f3Smrg 2957ec681f3Smrg} catch (error &e) { 2967ec681f3Smrg return e.get(); 2977ec681f3Smrg} 2987ec681f3Smrg 2997ec681f3SmrgCLOVER_API cl_int 3007ec681f3SmrgclCompileProgram(cl_program d_prog, cl_uint num_devs, 3017ec681f3Smrg const cl_device_id *d_devs, const char *p_opts, 3027ec681f3Smrg cl_uint num_headers, const cl_program *d_header_progs, 3037ec681f3Smrg const char **header_names, 3047ec681f3Smrg void (*pfn_notify)(cl_program, void *), 3057ec681f3Smrg void *user_data) try { 3067ec681f3Smrg auto &prog = obj(d_prog); 3077ec681f3Smrg auto devs = 3087ec681f3Smrg (d_devs ? objs(d_devs, num_devs) : ref_vector<device>(prog.devices())); 3097ec681f3Smrg const auto opts = build_options(p_opts, "CLOVER_EXTRA_COMPILE_OPTIONS"); 3107ec681f3Smrg header_map headers; 3117ec681f3Smrg 3127ec681f3Smrg validate_build_common(prog, num_devs, d_devs, pfn_notify, user_data); 3137ec681f3Smrg 3147ec681f3Smrg auto notifier = build_notifier(d_prog, pfn_notify, user_data); 3157ec681f3Smrg 3167ec681f3Smrg if (bool(num_headers) != bool(header_names)) 3177ec681f3Smrg throw error(CL_INVALID_VALUE); 3187ec681f3Smrg 3197ec681f3Smrg if (prog.il_type() == program::il_type::none) 3207ec681f3Smrg throw error(CL_INVALID_OPERATION); 3217ec681f3Smrg 3227ec681f3Smrg for_each([&](const char *name, const program &header) { 3237ec681f3Smrg if (header.il_type() == program::il_type::none) 3247ec681f3Smrg throw error(CL_INVALID_OPERATION); 3257ec681f3Smrg 3267ec681f3Smrg if (!any_of(key_equals(name), headers)) 3277ec681f3Smrg headers.push_back(std::pair<std::string, std::string>( 3287ec681f3Smrg name, header.source())); 3297ec681f3Smrg }, 3307ec681f3Smrg range(header_names, num_headers), 3317ec681f3Smrg objs<allow_empty_tag>(d_header_progs, num_headers)); 3327ec681f3Smrg 3337ec681f3Smrg prog.compile(devs, opts, headers); 3347ec681f3Smrg return CL_SUCCESS; 3357ec681f3Smrg 3367ec681f3Smrg} catch (invalid_build_options_error &) { 3377ec681f3Smrg return CL_INVALID_COMPILER_OPTIONS; 3387ec681f3Smrg 3397ec681f3Smrg} catch (build_error &) { 3407ec681f3Smrg return CL_COMPILE_PROGRAM_FAILURE; 3417ec681f3Smrg 3427ec681f3Smrg} catch (error &e) { 3437ec681f3Smrg return e.get(); 3447ec681f3Smrg} 3457ec681f3Smrg 3467ec681f3Smrgnamespace { 3477ec681f3Smrg ref_vector<device> 3487ec681f3Smrg validate_link_devices(const ref_vector<program> &progs, 3497ec681f3Smrg const ref_vector<device> &all_devs, 3507ec681f3Smrg const std::string &opts) { 3517ec681f3Smrg std::vector<device *> devs; 3527ec681f3Smrg const bool create_library = 3537ec681f3Smrg opts.find("-create-library") != std::string::npos; 3547ec681f3Smrg const bool enable_link_options = 3557ec681f3Smrg opts.find("-enable-link-options") != std::string::npos; 3567ec681f3Smrg const bool has_link_options = 3577ec681f3Smrg opts.find("-cl-denorms-are-zero") != std::string::npos || 3587ec681f3Smrg opts.find("-cl-no-signed-zeroes") != std::string::npos || 3597ec681f3Smrg opts.find("-cl-unsafe-math-optimizations") != std::string::npos || 3607ec681f3Smrg opts.find("-cl-finite-math-only") != std::string::npos || 3617ec681f3Smrg opts.find("-cl-fast-relaxed-math") != std::string::npos || 3627ec681f3Smrg opts.find("-cl-no-subgroup-ifp") != std::string::npos; 3637ec681f3Smrg 3647ec681f3Smrg // According to the OpenCL 1.2 specification, "[the 3657ec681f3Smrg // -enable-link-options] option must be specified with the 3667ec681f3Smrg // create-library option". 3677ec681f3Smrg if (enable_link_options && !create_library) 3687ec681f3Smrg throw error(CL_INVALID_LINKER_OPTIONS); 3697ec681f3Smrg 3707ec681f3Smrg // According to the OpenCL 1.2 specification, "the 3717ec681f3Smrg // [program linking options] can be specified when linking a program 3727ec681f3Smrg // executable". 3737ec681f3Smrg if (has_link_options && create_library) 3747ec681f3Smrg throw error(CL_INVALID_LINKER_OPTIONS); 3757ec681f3Smrg 3767ec681f3Smrg for (auto &dev : all_devs) { 3777ec681f3Smrg const auto has_binary = [&](const program &prog) { 3787ec681f3Smrg const auto t = prog.build(dev).binary_type(); 3797ec681f3Smrg return t == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT || 3807ec681f3Smrg t == CL_PROGRAM_BINARY_TYPE_LIBRARY; 3817ec681f3Smrg }; 3827ec681f3Smrg 3837ec681f3Smrg // According to the OpenCL 1.2 specification, a library is made of 3847ec681f3Smrg // “compiled binaries specified in input_programs argument to 3857ec681f3Smrg // clLinkProgram“; compiled binaries does not refer to libraries: 3867ec681f3Smrg // “input_programs is an array of program objects that are compiled 3877ec681f3Smrg // binaries or libraries that are to be linked to create the program 3887ec681f3Smrg // executable”. 3897ec681f3Smrg if (create_library && any_of([&](const program &prog) { 3907ec681f3Smrg const auto t = prog.build(dev).binary_type(); 3917ec681f3Smrg return t != CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT; 3927ec681f3Smrg }, progs)) 3937ec681f3Smrg throw error(CL_INVALID_OPERATION); 3947ec681f3Smrg 3957ec681f3Smrg // According to the CL 1.2 spec, when "all programs specified [..] 3967ec681f3Smrg // contain a compiled binary or library for the device [..] a link is 3977ec681f3Smrg // performed", 3987ec681f3Smrg else if (all_of(has_binary, progs)) 3997ec681f3Smrg devs.push_back(&dev); 4007ec681f3Smrg 4017ec681f3Smrg // otherwise if "none of the programs contain a compiled binary or 4027ec681f3Smrg // library for that device [..] no link is performed. All other 4037ec681f3Smrg // cases will return a CL_INVALID_OPERATION error." 4047ec681f3Smrg else if (any_of(has_binary, progs)) 4057ec681f3Smrg throw error(CL_INVALID_OPERATION); 4067ec681f3Smrg 4077ec681f3Smrg // According to the OpenCL 1.2 specification, "[t]he linker may apply 4087ec681f3Smrg // [program linking options] to all compiled program objects 4097ec681f3Smrg // specified to clLinkProgram. The linker may apply these options 4107ec681f3Smrg // only to libraries which were created with the 4117ec681f3Smrg // -enable-link-option." 4127ec681f3Smrg else if (has_link_options && any_of([&](const program &prog) { 4137ec681f3Smrg const auto t = prog.build(dev).binary_type(); 4147ec681f3Smrg return !(t == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT || 4157ec681f3Smrg (t == CL_PROGRAM_BINARY_TYPE_LIBRARY && 4167ec681f3Smrg prog.build(dev).opts.find("-enable-link-options") != 4177ec681f3Smrg std::string::npos)); 4187ec681f3Smrg }, progs)) 4197ec681f3Smrg throw error(CL_INVALID_LINKER_OPTIONS); 4207ec681f3Smrg } 4217ec681f3Smrg 4227ec681f3Smrg return map(derefs(), devs); 4237ec681f3Smrg } 4247ec681f3Smrg} 4257ec681f3Smrg 4267ec681f3SmrgCLOVER_API cl_program 4277ec681f3SmrgclLinkProgram(cl_context d_ctx, cl_uint num_devs, const cl_device_id *d_devs, 4287ec681f3Smrg const char *p_opts, cl_uint num_progs, const cl_program *d_progs, 4297ec681f3Smrg void (*pfn_notify) (cl_program, void *), void *user_data, 4307ec681f3Smrg cl_int *r_errcode) try { 4317ec681f3Smrg auto &ctx = obj(d_ctx); 4327ec681f3Smrg const auto opts = build_options(p_opts, "CLOVER_EXTRA_LINK_OPTIONS"); 4337ec681f3Smrg auto progs = objs(d_progs, num_progs); 4347ec681f3Smrg auto all_devs = 4357ec681f3Smrg (d_devs ? objs(d_devs, num_devs) : ref_vector<device>(ctx.devices())); 4367ec681f3Smrg auto prog = create<program>(ctx, all_devs); 4377ec681f3Smrg auto r_prog = ret_object(prog); 4387ec681f3Smrg 4397ec681f3Smrg auto notifier = build_notifier(r_prog, pfn_notify, user_data); 4407ec681f3Smrg 4417ec681f3Smrg auto devs = validate_link_devices(progs, all_devs, opts); 4427ec681f3Smrg 4437ec681f3Smrg validate_build_common(prog, num_devs, d_devs, pfn_notify, user_data); 4447ec681f3Smrg 4457ec681f3Smrg try { 4467ec681f3Smrg prog().link(devs, opts, progs); 4477ec681f3Smrg ret_error(r_errcode, CL_SUCCESS); 4487ec681f3Smrg 4497ec681f3Smrg } catch (build_error &) { 4507ec681f3Smrg ret_error(r_errcode, CL_LINK_PROGRAM_FAILURE); 4517ec681f3Smrg } 4527ec681f3Smrg 4537ec681f3Smrg return r_prog; 4547ec681f3Smrg 4557ec681f3Smrg} catch (invalid_build_options_error &) { 4567ec681f3Smrg ret_error(r_errcode, CL_INVALID_LINKER_OPTIONS); 4577ec681f3Smrg return NULL; 4587ec681f3Smrg 4597ec681f3Smrg} catch (error &e) { 4607ec681f3Smrg ret_error(r_errcode, e); 4617ec681f3Smrg return NULL; 4627ec681f3Smrg} 4637ec681f3Smrg 4647ec681f3SmrgCLOVER_API cl_int 4657ec681f3SmrgclUnloadCompiler() { 4667ec681f3Smrg return CL_SUCCESS; 4677ec681f3Smrg} 4687ec681f3Smrg 4697ec681f3SmrgCLOVER_API cl_int 4707ec681f3SmrgclUnloadPlatformCompiler(cl_platform_id d_platform) try { 4717ec681f3Smrg find_platform(d_platform); 4727ec681f3Smrg return CL_SUCCESS; 4737ec681f3Smrg} catch (error &e) { 4747ec681f3Smrg return e.get(); 4757ec681f3Smrg} 4767ec681f3Smrg 4777ec681f3SmrgCLOVER_API cl_int 4787ec681f3SmrgclGetProgramInfo(cl_program d_prog, cl_program_info param, 4797ec681f3Smrg size_t size, void *r_buf, size_t *r_size) try { 4807ec681f3Smrg property_buffer buf { r_buf, size, r_size }; 4817ec681f3Smrg auto &prog = obj(d_prog); 4827ec681f3Smrg 4837ec681f3Smrg switch (param) { 4847ec681f3Smrg case CL_PROGRAM_REFERENCE_COUNT: 4857ec681f3Smrg buf.as_scalar<cl_uint>() = prog.ref_count(); 4867ec681f3Smrg break; 4877ec681f3Smrg 4887ec681f3Smrg case CL_PROGRAM_CONTEXT: 4897ec681f3Smrg buf.as_scalar<cl_context>() = desc(prog.context()); 4907ec681f3Smrg break; 4917ec681f3Smrg 4927ec681f3Smrg case CL_PROGRAM_NUM_DEVICES: 4937ec681f3Smrg buf.as_scalar<cl_uint>() = (prog.devices().size() ? 4947ec681f3Smrg prog.devices().size() : 4957ec681f3Smrg prog.context().devices().size()); 4967ec681f3Smrg break; 4977ec681f3Smrg 4987ec681f3Smrg case CL_PROGRAM_DEVICES: 4997ec681f3Smrg buf.as_vector<cl_device_id>() = (prog.devices().size() ? 5007ec681f3Smrg descs(prog.devices()) : 5017ec681f3Smrg descs(prog.context().devices())); 5027ec681f3Smrg break; 5037ec681f3Smrg 5047ec681f3Smrg case CL_PROGRAM_SOURCE: 5057ec681f3Smrg buf.as_string() = prog.source(); 5067ec681f3Smrg break; 5077ec681f3Smrg 5087ec681f3Smrg case CL_PROGRAM_BINARY_SIZES: 5097ec681f3Smrg buf.as_vector<size_t>() = map([&](const device &dev) { 5107ec681f3Smrg return prog.build(dev).bin.size(); 5117ec681f3Smrg }, 5127ec681f3Smrg prog.devices()); 5137ec681f3Smrg break; 5147ec681f3Smrg 5157ec681f3Smrg case CL_PROGRAM_BINARIES: 5167ec681f3Smrg buf.as_matrix<unsigned char>() = map([&](const device &dev) { 5177ec681f3Smrg std::stringbuf bin; 5187ec681f3Smrg std::ostream s(&bin); 5197ec681f3Smrg prog.build(dev).bin.serialize(s); 5207ec681f3Smrg return bin.str(); 5217ec681f3Smrg }, 5227ec681f3Smrg prog.devices()); 5237ec681f3Smrg break; 5247ec681f3Smrg 5257ec681f3Smrg case CL_PROGRAM_NUM_KERNELS: 5267ec681f3Smrg buf.as_scalar<cl_uint>() = prog.symbols().size(); 5277ec681f3Smrg break; 5287ec681f3Smrg 5297ec681f3Smrg case CL_PROGRAM_KERNEL_NAMES: 5307ec681f3Smrg buf.as_string() = fold([](const std::string &a, const binary::symbol &s) { 5317ec681f3Smrg return ((a.empty() ? "" : a + ";") + s.name); 5327ec681f3Smrg }, std::string(), prog.symbols()); 5337ec681f3Smrg break; 5347ec681f3Smrg 5357ec681f3Smrg case CL_PROGRAM_SCOPE_GLOBAL_CTORS_PRESENT: 5367ec681f3Smrg case CL_PROGRAM_SCOPE_GLOBAL_DTORS_PRESENT: 5377ec681f3Smrg buf.as_scalar<cl_bool>() = CL_FALSE; 5387ec681f3Smrg break; 5397ec681f3Smrg 5407ec681f3Smrg case CL_PROGRAM_IL: 5417ec681f3Smrg if (prog.il_type() == program::il_type::spirv) 5427ec681f3Smrg buf.as_vector<char>() = prog.source(); 5437ec681f3Smrg else if (r_size) 5447ec681f3Smrg *r_size = 0u; 5457ec681f3Smrg break; 5467ec681f3Smrg default: 5477ec681f3Smrg throw error(CL_INVALID_VALUE); 5487ec681f3Smrg } 5497ec681f3Smrg 5507ec681f3Smrg return CL_SUCCESS; 5517ec681f3Smrg 5527ec681f3Smrg} catch (error &e) { 5537ec681f3Smrg return e.get(); 5547ec681f3Smrg} 5557ec681f3Smrg 5567ec681f3SmrgCLOVER_API cl_int 5577ec681f3SmrgclGetProgramBuildInfo(cl_program d_prog, cl_device_id d_dev, 5587ec681f3Smrg cl_program_build_info param, 5597ec681f3Smrg size_t size, void *r_buf, size_t *r_size) try { 5607ec681f3Smrg property_buffer buf { r_buf, size, r_size }; 5617ec681f3Smrg auto &prog = obj(d_prog); 5627ec681f3Smrg auto &dev = obj(d_dev); 5637ec681f3Smrg 5647ec681f3Smrg if (!count(dev, prog.context().devices())) 5657ec681f3Smrg return CL_INVALID_DEVICE; 5667ec681f3Smrg 5677ec681f3Smrg switch (param) { 5687ec681f3Smrg case CL_PROGRAM_BUILD_STATUS: 5697ec681f3Smrg buf.as_scalar<cl_build_status>() = prog.build(dev).status(); 5707ec681f3Smrg break; 5717ec681f3Smrg 5727ec681f3Smrg case CL_PROGRAM_BUILD_OPTIONS: 5737ec681f3Smrg buf.as_string() = prog.build(dev).opts; 5747ec681f3Smrg break; 5757ec681f3Smrg 5767ec681f3Smrg case CL_PROGRAM_BUILD_LOG: 5777ec681f3Smrg buf.as_string() = prog.build(dev).log; 5787ec681f3Smrg break; 5797ec681f3Smrg 5807ec681f3Smrg case CL_PROGRAM_BINARY_TYPE: 5817ec681f3Smrg buf.as_scalar<cl_program_binary_type>() = prog.build(dev).binary_type(); 5827ec681f3Smrg break; 5837ec681f3Smrg 5847ec681f3Smrg case CL_PROGRAM_BUILD_GLOBAL_VARIABLE_TOTAL_SIZE: 5857ec681f3Smrg buf.as_scalar<size_t>() = 0; 5867ec681f3Smrg break; 5877ec681f3Smrg 5887ec681f3Smrg default: 5897ec681f3Smrg throw error(CL_INVALID_VALUE); 5907ec681f3Smrg } 5917ec681f3Smrg 5927ec681f3Smrg return CL_SUCCESS; 5937ec681f3Smrg 5947ec681f3Smrg} catch (error &e) { 5957ec681f3Smrg return e.get(); 5967ec681f3Smrg} 597