1bf215546Sopenharmony_ci// 2bf215546Sopenharmony_ci// Copyright 2012 Francisco Jerez 3bf215546Sopenharmony_ci// 4bf215546Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci// copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci// to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci// the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci// and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci// Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci// 11bf215546Sopenharmony_ci// The above copyright notice and this permission notice shall be included in 12bf215546Sopenharmony_ci// all copies or substantial portions of the Software. 13bf215546Sopenharmony_ci// 14bf215546Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15bf215546Sopenharmony_ci// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16bf215546Sopenharmony_ci// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17bf215546Sopenharmony_ci// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18bf215546Sopenharmony_ci// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19bf215546Sopenharmony_ci// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20bf215546Sopenharmony_ci// OTHER DEALINGS IN THE SOFTWARE. 21bf215546Sopenharmony_ci// 22bf215546Sopenharmony_ci 23bf215546Sopenharmony_ci#include "api/util.hpp" 24bf215546Sopenharmony_ci#include "core/program.hpp" 25bf215546Sopenharmony_ci#include "core/platform.hpp" 26bf215546Sopenharmony_ci#include "spirv/invocation.hpp" 27bf215546Sopenharmony_ci#include "util/u_debug.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include <limits> 30bf215546Sopenharmony_ci#include <sstream> 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ciusing namespace clover; 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_cinamespace { 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci std::string 37bf215546Sopenharmony_ci build_options(const char *p_opts, const char *p_debug) { 38bf215546Sopenharmony_ci auto opts = std::string(p_opts ? p_opts : ""); 39bf215546Sopenharmony_ci std::string extra_opts = debug_get_option(p_debug, ""); 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_ci return detokenize(std::vector<std::string>{opts, extra_opts}, " "); 42bf215546Sopenharmony_ci } 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci class build_notifier { 45bf215546Sopenharmony_ci public: 46bf215546Sopenharmony_ci build_notifier(cl_program prog, 47bf215546Sopenharmony_ci void (*notifer)(cl_program, void *), void *data) : 48bf215546Sopenharmony_ci prog_(prog), notifer(notifer), data_(data) { } 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci ~build_notifier() { 51bf215546Sopenharmony_ci if (notifer) 52bf215546Sopenharmony_ci notifer(prog_, data_); 53bf215546Sopenharmony_ci } 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci private: 56bf215546Sopenharmony_ci cl_program prog_; 57bf215546Sopenharmony_ci void (*notifer)(cl_program, void *); 58bf215546Sopenharmony_ci void *data_; 59bf215546Sopenharmony_ci }; 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci void 62bf215546Sopenharmony_ci validate_build_common(const program &prog, cl_uint num_devs, 63bf215546Sopenharmony_ci const cl_device_id *d_devs, 64bf215546Sopenharmony_ci void (*pfn_notify)(cl_program, void *), 65bf215546Sopenharmony_ci void *user_data) { 66bf215546Sopenharmony_ci if (!pfn_notify && user_data) 67bf215546Sopenharmony_ci throw error(CL_INVALID_VALUE); 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci if (prog.kernel_ref_count()) 70bf215546Sopenharmony_ci throw error(CL_INVALID_OPERATION); 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci if (any_of([&](const device &dev) { 73bf215546Sopenharmony_ci return !count(dev, prog.devices()); 74bf215546Sopenharmony_ci }, objs<allow_empty_tag>(d_devs, num_devs))) 75bf215546Sopenharmony_ci throw error(CL_INVALID_DEVICE); 76bf215546Sopenharmony_ci } 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci enum program::il_type 79bf215546Sopenharmony_ci identify_and_validate_il(const std::string &il, 80bf215546Sopenharmony_ci const cl_version opencl_version, 81bf215546Sopenharmony_ci const context::notify_action ¬ify) { 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci enum program::il_type il_type = program::il_type::none; 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci#ifdef HAVE_CLOVER_SPIRV 86bf215546Sopenharmony_ci if (spirv::is_binary_spirv(il)) { 87bf215546Sopenharmony_ci std::string log; 88bf215546Sopenharmony_ci if (!spirv::is_valid_spirv(il, opencl_version, log)) { 89bf215546Sopenharmony_ci if (notify) { 90bf215546Sopenharmony_ci notify(log.c_str()); 91bf215546Sopenharmony_ci } 92bf215546Sopenharmony_ci throw error(CL_INVALID_VALUE); 93bf215546Sopenharmony_ci } 94bf215546Sopenharmony_ci il_type = program::il_type::spirv; 95bf215546Sopenharmony_ci } 96bf215546Sopenharmony_ci#endif 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci return il_type; 99bf215546Sopenharmony_ci } 100bf215546Sopenharmony_ci} 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ciCLOVER_API cl_program 103bf215546Sopenharmony_ciclCreateProgramWithSource(cl_context d_ctx, cl_uint count, 104bf215546Sopenharmony_ci const char **strings, const size_t *lengths, 105bf215546Sopenharmony_ci cl_int *r_errcode) try { 106bf215546Sopenharmony_ci auto &ctx = obj(d_ctx); 107bf215546Sopenharmony_ci std::string source; 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_ci if (!count || !strings || 110bf215546Sopenharmony_ci any_of(is_zero(), range(strings, count))) 111bf215546Sopenharmony_ci throw error(CL_INVALID_VALUE); 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci // Concatenate all the provided fragments together 114bf215546Sopenharmony_ci for (unsigned i = 0; i < count; ++i) 115bf215546Sopenharmony_ci source += (lengths && lengths[i] ? 116bf215546Sopenharmony_ci std::string(strings[i], strings[i] + lengths[i]) : 117bf215546Sopenharmony_ci std::string(strings[i])); 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci // ...and create a program object for them. 120bf215546Sopenharmony_ci ret_error(r_errcode, CL_SUCCESS); 121bf215546Sopenharmony_ci return new program(ctx, std::move(source), program::il_type::source); 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci} catch (error &e) { 124bf215546Sopenharmony_ci ret_error(r_errcode, e); 125bf215546Sopenharmony_ci return NULL; 126bf215546Sopenharmony_ci} 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ciCLOVER_API cl_program 129bf215546Sopenharmony_ciclCreateProgramWithBinary(cl_context d_ctx, cl_uint n, 130bf215546Sopenharmony_ci const cl_device_id *d_devs, 131bf215546Sopenharmony_ci const size_t *lengths, 132bf215546Sopenharmony_ci const unsigned char **binaries, 133bf215546Sopenharmony_ci cl_int *r_status, cl_int *r_errcode) try { 134bf215546Sopenharmony_ci auto &ctx = obj(d_ctx); 135bf215546Sopenharmony_ci auto devs = objs(d_devs, n); 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci if (!lengths || !binaries) 138bf215546Sopenharmony_ci throw error(CL_INVALID_VALUE); 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci if (any_of([&](const device &dev) { 141bf215546Sopenharmony_ci return !count(dev, ctx.devices()); 142bf215546Sopenharmony_ci }, devs)) 143bf215546Sopenharmony_ci throw error(CL_INVALID_DEVICE); 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci // Deserialize the provided binaries, 146bf215546Sopenharmony_ci std::vector<std::pair<cl_int, binary>> result = map( 147bf215546Sopenharmony_ci [](const unsigned char *p, size_t l) -> std::pair<cl_int, binary> { 148bf215546Sopenharmony_ci if (!p || !l) 149bf215546Sopenharmony_ci return { CL_INVALID_VALUE, {} }; 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci try { 152bf215546Sopenharmony_ci std::stringbuf bin( std::string{ (char*)p, l } ); 153bf215546Sopenharmony_ci std::istream s(&bin); 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci return { CL_SUCCESS, binary::deserialize(s) }; 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci } catch (std::istream::failure &) { 158bf215546Sopenharmony_ci return { CL_INVALID_BINARY, {} }; 159bf215546Sopenharmony_ci } 160bf215546Sopenharmony_ci }, 161bf215546Sopenharmony_ci range(binaries, n), 162bf215546Sopenharmony_ci range(lengths, n)); 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ci // update the status array, 165bf215546Sopenharmony_ci if (r_status) 166bf215546Sopenharmony_ci copy(map(keys(), result), r_status); 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci if (any_of(key_equals(CL_INVALID_VALUE), result)) 169bf215546Sopenharmony_ci throw error(CL_INVALID_VALUE); 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci if (any_of(key_equals(CL_INVALID_BINARY), result)) 172bf215546Sopenharmony_ci throw error(CL_INVALID_BINARY); 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci // initialize a program object with them. 175bf215546Sopenharmony_ci ret_error(r_errcode, CL_SUCCESS); 176bf215546Sopenharmony_ci return new program(ctx, devs, map(values(), result)); 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci} catch (error &e) { 179bf215546Sopenharmony_ci ret_error(r_errcode, e); 180bf215546Sopenharmony_ci return NULL; 181bf215546Sopenharmony_ci} 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_cicl_program 184bf215546Sopenharmony_ciclover::CreateProgramWithILKHR(cl_context d_ctx, const void *il, 185bf215546Sopenharmony_ci size_t length, cl_int *r_errcode) try { 186bf215546Sopenharmony_ci auto &ctx = obj(d_ctx); 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci if (!il || !length) 189bf215546Sopenharmony_ci throw error(CL_INVALID_VALUE); 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci // Compute the highest OpenCL version supported by all devices associated to 192bf215546Sopenharmony_ci // the context. That is the version used for validating the SPIR-V binary. 193bf215546Sopenharmony_ci cl_version min_opencl_version = std::numeric_limits<uint32_t>::max(); 194bf215546Sopenharmony_ci for (const device &dev : ctx.devices()) { 195bf215546Sopenharmony_ci const cl_version opencl_version = dev.device_version(); 196bf215546Sopenharmony_ci min_opencl_version = std::min(opencl_version, min_opencl_version); 197bf215546Sopenharmony_ci } 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci const char *stream = reinterpret_cast<const char *>(il); 200bf215546Sopenharmony_ci std::string binary(stream, stream + length); 201bf215546Sopenharmony_ci const enum program::il_type il_type = identify_and_validate_il(binary, 202bf215546Sopenharmony_ci min_opencl_version, 203bf215546Sopenharmony_ci ctx.notify); 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci if (il_type == program::il_type::none) 206bf215546Sopenharmony_ci throw error(CL_INVALID_VALUE); 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci // Initialize a program object with it. 209bf215546Sopenharmony_ci ret_error(r_errcode, CL_SUCCESS); 210bf215546Sopenharmony_ci return new program(ctx, std::move(binary), il_type); 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci} catch (error &e) { 213bf215546Sopenharmony_ci ret_error(r_errcode, e); 214bf215546Sopenharmony_ci return NULL; 215bf215546Sopenharmony_ci} 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ciCLOVER_API cl_program 218bf215546Sopenharmony_ciclCreateProgramWithIL(cl_context d_ctx, 219bf215546Sopenharmony_ci const void *il, 220bf215546Sopenharmony_ci size_t length, 221bf215546Sopenharmony_ci cl_int *r_errcode) { 222bf215546Sopenharmony_ci return CreateProgramWithILKHR(d_ctx, il, length, r_errcode); 223bf215546Sopenharmony_ci} 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ciCLOVER_API cl_program 226bf215546Sopenharmony_ciclCreateProgramWithBuiltInKernels(cl_context d_ctx, cl_uint n, 227bf215546Sopenharmony_ci const cl_device_id *d_devs, 228bf215546Sopenharmony_ci const char *kernel_names, 229bf215546Sopenharmony_ci cl_int *r_errcode) try { 230bf215546Sopenharmony_ci auto &ctx = obj(d_ctx); 231bf215546Sopenharmony_ci auto devs = objs(d_devs, n); 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci if (any_of([&](const device &dev) { 234bf215546Sopenharmony_ci return !count(dev, ctx.devices()); 235bf215546Sopenharmony_ci }, devs)) 236bf215546Sopenharmony_ci throw error(CL_INVALID_DEVICE); 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci // No currently supported built-in kernels. 239bf215546Sopenharmony_ci throw error(CL_INVALID_VALUE); 240bf215546Sopenharmony_ci 241bf215546Sopenharmony_ci} catch (error &e) { 242bf215546Sopenharmony_ci ret_error(r_errcode, e); 243bf215546Sopenharmony_ci return NULL; 244bf215546Sopenharmony_ci} 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ciCLOVER_API cl_int 248bf215546Sopenharmony_ciclRetainProgram(cl_program d_prog) try { 249bf215546Sopenharmony_ci obj(d_prog).retain(); 250bf215546Sopenharmony_ci return CL_SUCCESS; 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci} catch (error &e) { 253bf215546Sopenharmony_ci return e.get(); 254bf215546Sopenharmony_ci} 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ciCLOVER_API cl_int 257bf215546Sopenharmony_ciclReleaseProgram(cl_program d_prog) try { 258bf215546Sopenharmony_ci if (obj(d_prog).release()) 259bf215546Sopenharmony_ci delete pobj(d_prog); 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci return CL_SUCCESS; 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci} catch (error &e) { 264bf215546Sopenharmony_ci return e.get(); 265bf215546Sopenharmony_ci} 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ciCLOVER_API cl_int 268bf215546Sopenharmony_ciclBuildProgram(cl_program d_prog, cl_uint num_devs, 269bf215546Sopenharmony_ci const cl_device_id *d_devs, const char *p_opts, 270bf215546Sopenharmony_ci void (*pfn_notify)(cl_program, void *), 271bf215546Sopenharmony_ci void *user_data) try { 272bf215546Sopenharmony_ci auto &prog = obj(d_prog); 273bf215546Sopenharmony_ci auto devs = 274bf215546Sopenharmony_ci (d_devs ? objs(d_devs, num_devs) : ref_vector<device>(prog.devices())); 275bf215546Sopenharmony_ci const auto opts = build_options(p_opts, "CLOVER_EXTRA_BUILD_OPTIONS"); 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci validate_build_common(prog, num_devs, d_devs, pfn_notify, user_data); 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci auto notifier = build_notifier(d_prog, pfn_notify, user_data); 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci if (prog.il_type() != program::il_type::none) { 282bf215546Sopenharmony_ci prog.compile(devs, opts); 283bf215546Sopenharmony_ci prog.link(devs, opts, { prog }); 284bf215546Sopenharmony_ci } else if (any_of([&](const device &dev){ 285bf215546Sopenharmony_ci return prog.build(dev).binary_type() != CL_PROGRAM_BINARY_TYPE_EXECUTABLE; 286bf215546Sopenharmony_ci }, devs)) { 287bf215546Sopenharmony_ci // According to the OpenCL 1.2 specification, “if program is created 288bf215546Sopenharmony_ci // with clCreateProgramWithBinary, then the program binary must be an 289bf215546Sopenharmony_ci // executable binary (not a compiled binary or library).” 290bf215546Sopenharmony_ci throw error(CL_INVALID_BINARY); 291bf215546Sopenharmony_ci } 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci return CL_SUCCESS; 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci} catch (error &e) { 296bf215546Sopenharmony_ci return e.get(); 297bf215546Sopenharmony_ci} 298bf215546Sopenharmony_ci 299bf215546Sopenharmony_ciCLOVER_API cl_int 300bf215546Sopenharmony_ciclCompileProgram(cl_program d_prog, cl_uint num_devs, 301bf215546Sopenharmony_ci const cl_device_id *d_devs, const char *p_opts, 302bf215546Sopenharmony_ci cl_uint num_headers, const cl_program *d_header_progs, 303bf215546Sopenharmony_ci const char **header_names, 304bf215546Sopenharmony_ci void (*pfn_notify)(cl_program, void *), 305bf215546Sopenharmony_ci void *user_data) try { 306bf215546Sopenharmony_ci auto &prog = obj(d_prog); 307bf215546Sopenharmony_ci auto devs = 308bf215546Sopenharmony_ci (d_devs ? objs(d_devs, num_devs) : ref_vector<device>(prog.devices())); 309bf215546Sopenharmony_ci const auto opts = build_options(p_opts, "CLOVER_EXTRA_COMPILE_OPTIONS"); 310bf215546Sopenharmony_ci header_map headers; 311bf215546Sopenharmony_ci 312bf215546Sopenharmony_ci validate_build_common(prog, num_devs, d_devs, pfn_notify, user_data); 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci auto notifier = build_notifier(d_prog, pfn_notify, user_data); 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ci if (bool(num_headers) != bool(header_names)) 317bf215546Sopenharmony_ci throw error(CL_INVALID_VALUE); 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_ci if (prog.il_type() == program::il_type::none) 320bf215546Sopenharmony_ci throw error(CL_INVALID_OPERATION); 321bf215546Sopenharmony_ci 322bf215546Sopenharmony_ci for_each([&](const char *name, const program &header) { 323bf215546Sopenharmony_ci if (header.il_type() == program::il_type::none) 324bf215546Sopenharmony_ci throw error(CL_INVALID_OPERATION); 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci if (!any_of(key_equals(name), headers)) 327bf215546Sopenharmony_ci headers.push_back(std::pair<std::string, std::string>( 328bf215546Sopenharmony_ci name, header.source())); 329bf215546Sopenharmony_ci }, 330bf215546Sopenharmony_ci range(header_names, num_headers), 331bf215546Sopenharmony_ci objs<allow_empty_tag>(d_header_progs, num_headers)); 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci prog.compile(devs, opts, headers); 334bf215546Sopenharmony_ci return CL_SUCCESS; 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci} catch (invalid_build_options_error &) { 337bf215546Sopenharmony_ci return CL_INVALID_COMPILER_OPTIONS; 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_ci} catch (build_error &) { 340bf215546Sopenharmony_ci return CL_COMPILE_PROGRAM_FAILURE; 341bf215546Sopenharmony_ci 342bf215546Sopenharmony_ci} catch (error &e) { 343bf215546Sopenharmony_ci return e.get(); 344bf215546Sopenharmony_ci} 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_cinamespace { 347bf215546Sopenharmony_ci ref_vector<device> 348bf215546Sopenharmony_ci validate_link_devices(const ref_vector<program> &progs, 349bf215546Sopenharmony_ci const ref_vector<device> &all_devs, 350bf215546Sopenharmony_ci const std::string &opts) { 351bf215546Sopenharmony_ci std::vector<device *> devs; 352bf215546Sopenharmony_ci const bool create_library = 353bf215546Sopenharmony_ci opts.find("-create-library") != std::string::npos; 354bf215546Sopenharmony_ci const bool enable_link_options = 355bf215546Sopenharmony_ci opts.find("-enable-link-options") != std::string::npos; 356bf215546Sopenharmony_ci const bool has_link_options = 357bf215546Sopenharmony_ci opts.find("-cl-denorms-are-zero") != std::string::npos || 358bf215546Sopenharmony_ci opts.find("-cl-no-signed-zeroes") != std::string::npos || 359bf215546Sopenharmony_ci opts.find("-cl-unsafe-math-optimizations") != std::string::npos || 360bf215546Sopenharmony_ci opts.find("-cl-finite-math-only") != std::string::npos || 361bf215546Sopenharmony_ci opts.find("-cl-fast-relaxed-math") != std::string::npos || 362bf215546Sopenharmony_ci opts.find("-cl-no-subgroup-ifp") != std::string::npos; 363bf215546Sopenharmony_ci 364bf215546Sopenharmony_ci // According to the OpenCL 1.2 specification, "[the 365bf215546Sopenharmony_ci // -enable-link-options] option must be specified with the 366bf215546Sopenharmony_ci // create-library option". 367bf215546Sopenharmony_ci if (enable_link_options && !create_library) 368bf215546Sopenharmony_ci throw error(CL_INVALID_LINKER_OPTIONS); 369bf215546Sopenharmony_ci 370bf215546Sopenharmony_ci // According to the OpenCL 1.2 specification, "the 371bf215546Sopenharmony_ci // [program linking options] can be specified when linking a program 372bf215546Sopenharmony_ci // executable". 373bf215546Sopenharmony_ci if (has_link_options && create_library) 374bf215546Sopenharmony_ci throw error(CL_INVALID_LINKER_OPTIONS); 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci for (auto &dev : all_devs) { 377bf215546Sopenharmony_ci const auto has_binary = [&](const program &prog) { 378bf215546Sopenharmony_ci const auto t = prog.build(dev).binary_type(); 379bf215546Sopenharmony_ci return t == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT || 380bf215546Sopenharmony_ci t == CL_PROGRAM_BINARY_TYPE_LIBRARY; 381bf215546Sopenharmony_ci }; 382bf215546Sopenharmony_ci 383bf215546Sopenharmony_ci // According to the OpenCL 1.2 specification, a library is made of 384bf215546Sopenharmony_ci // “compiled binaries specified in input_programs argument to 385bf215546Sopenharmony_ci // clLinkProgram“; compiled binaries does not refer to libraries: 386bf215546Sopenharmony_ci // “input_programs is an array of program objects that are compiled 387bf215546Sopenharmony_ci // binaries or libraries that are to be linked to create the program 388bf215546Sopenharmony_ci // executable”. 389bf215546Sopenharmony_ci if (create_library && any_of([&](const program &prog) { 390bf215546Sopenharmony_ci const auto t = prog.build(dev).binary_type(); 391bf215546Sopenharmony_ci return t != CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT; 392bf215546Sopenharmony_ci }, progs)) 393bf215546Sopenharmony_ci throw error(CL_INVALID_OPERATION); 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci // According to the CL 1.2 spec, when "all programs specified [..] 396bf215546Sopenharmony_ci // contain a compiled binary or library for the device [..] a link is 397bf215546Sopenharmony_ci // performed", 398bf215546Sopenharmony_ci else if (all_of(has_binary, progs)) 399bf215546Sopenharmony_ci devs.push_back(&dev); 400bf215546Sopenharmony_ci 401bf215546Sopenharmony_ci // otherwise if "none of the programs contain a compiled binary or 402bf215546Sopenharmony_ci // library for that device [..] no link is performed. All other 403bf215546Sopenharmony_ci // cases will return a CL_INVALID_OPERATION error." 404bf215546Sopenharmony_ci else if (any_of(has_binary, progs)) 405bf215546Sopenharmony_ci throw error(CL_INVALID_OPERATION); 406bf215546Sopenharmony_ci 407bf215546Sopenharmony_ci // According to the OpenCL 1.2 specification, "[t]he linker may apply 408bf215546Sopenharmony_ci // [program linking options] to all compiled program objects 409bf215546Sopenharmony_ci // specified to clLinkProgram. The linker may apply these options 410bf215546Sopenharmony_ci // only to libraries which were created with the 411bf215546Sopenharmony_ci // -enable-link-option." 412bf215546Sopenharmony_ci else if (has_link_options && any_of([&](const program &prog) { 413bf215546Sopenharmony_ci const auto t = prog.build(dev).binary_type(); 414bf215546Sopenharmony_ci return !(t == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT || 415bf215546Sopenharmony_ci (t == CL_PROGRAM_BINARY_TYPE_LIBRARY && 416bf215546Sopenharmony_ci prog.build(dev).opts.find("-enable-link-options") != 417bf215546Sopenharmony_ci std::string::npos)); 418bf215546Sopenharmony_ci }, progs)) 419bf215546Sopenharmony_ci throw error(CL_INVALID_LINKER_OPTIONS); 420bf215546Sopenharmony_ci } 421bf215546Sopenharmony_ci 422bf215546Sopenharmony_ci return map(derefs(), devs); 423bf215546Sopenharmony_ci } 424bf215546Sopenharmony_ci} 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ciCLOVER_API cl_program 427bf215546Sopenharmony_ciclLinkProgram(cl_context d_ctx, cl_uint num_devs, const cl_device_id *d_devs, 428bf215546Sopenharmony_ci const char *p_opts, cl_uint num_progs, const cl_program *d_progs, 429bf215546Sopenharmony_ci void (*pfn_notify) (cl_program, void *), void *user_data, 430bf215546Sopenharmony_ci cl_int *r_errcode) try { 431bf215546Sopenharmony_ci auto &ctx = obj(d_ctx); 432bf215546Sopenharmony_ci const auto opts = build_options(p_opts, "CLOVER_EXTRA_LINK_OPTIONS"); 433bf215546Sopenharmony_ci auto progs = objs(d_progs, num_progs); 434bf215546Sopenharmony_ci auto all_devs = 435bf215546Sopenharmony_ci (d_devs ? objs(d_devs, num_devs) : ref_vector<device>(ctx.devices())); 436bf215546Sopenharmony_ci auto prog = create<program>(ctx, all_devs); 437bf215546Sopenharmony_ci auto r_prog = ret_object(prog); 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci auto notifier = build_notifier(r_prog, pfn_notify, user_data); 440bf215546Sopenharmony_ci 441bf215546Sopenharmony_ci auto devs = validate_link_devices(progs, all_devs, opts); 442bf215546Sopenharmony_ci 443bf215546Sopenharmony_ci validate_build_common(prog, num_devs, d_devs, pfn_notify, user_data); 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci try { 446bf215546Sopenharmony_ci prog().link(devs, opts, progs); 447bf215546Sopenharmony_ci ret_error(r_errcode, CL_SUCCESS); 448bf215546Sopenharmony_ci 449bf215546Sopenharmony_ci } catch (build_error &) { 450bf215546Sopenharmony_ci ret_error(r_errcode, CL_LINK_PROGRAM_FAILURE); 451bf215546Sopenharmony_ci } 452bf215546Sopenharmony_ci 453bf215546Sopenharmony_ci return r_prog; 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ci} catch (invalid_build_options_error &) { 456bf215546Sopenharmony_ci ret_error(r_errcode, CL_INVALID_LINKER_OPTIONS); 457bf215546Sopenharmony_ci return NULL; 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_ci} catch (error &e) { 460bf215546Sopenharmony_ci ret_error(r_errcode, e); 461bf215546Sopenharmony_ci return NULL; 462bf215546Sopenharmony_ci} 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ciCLOVER_API cl_int 465bf215546Sopenharmony_ciclUnloadCompiler() { 466bf215546Sopenharmony_ci return CL_SUCCESS; 467bf215546Sopenharmony_ci} 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_ciCLOVER_API cl_int 470bf215546Sopenharmony_ciclUnloadPlatformCompiler(cl_platform_id d_platform) try { 471bf215546Sopenharmony_ci find_platform(d_platform); 472bf215546Sopenharmony_ci return CL_SUCCESS; 473bf215546Sopenharmony_ci} catch (error &e) { 474bf215546Sopenharmony_ci return e.get(); 475bf215546Sopenharmony_ci} 476bf215546Sopenharmony_ci 477bf215546Sopenharmony_ciCLOVER_API cl_int 478bf215546Sopenharmony_ciclGetProgramInfo(cl_program d_prog, cl_program_info param, 479bf215546Sopenharmony_ci size_t size, void *r_buf, size_t *r_size) try { 480bf215546Sopenharmony_ci property_buffer buf { r_buf, size, r_size }; 481bf215546Sopenharmony_ci auto &prog = obj(d_prog); 482bf215546Sopenharmony_ci 483bf215546Sopenharmony_ci switch (param) { 484bf215546Sopenharmony_ci case CL_PROGRAM_REFERENCE_COUNT: 485bf215546Sopenharmony_ci buf.as_scalar<cl_uint>() = prog.ref_count(); 486bf215546Sopenharmony_ci break; 487bf215546Sopenharmony_ci 488bf215546Sopenharmony_ci case CL_PROGRAM_CONTEXT: 489bf215546Sopenharmony_ci buf.as_scalar<cl_context>() = desc(prog.context()); 490bf215546Sopenharmony_ci break; 491bf215546Sopenharmony_ci 492bf215546Sopenharmony_ci case CL_PROGRAM_NUM_DEVICES: 493bf215546Sopenharmony_ci buf.as_scalar<cl_uint>() = (prog.devices().size() ? 494bf215546Sopenharmony_ci prog.devices().size() : 495bf215546Sopenharmony_ci prog.context().devices().size()); 496bf215546Sopenharmony_ci break; 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_ci case CL_PROGRAM_DEVICES: 499bf215546Sopenharmony_ci buf.as_vector<cl_device_id>() = (prog.devices().size() ? 500bf215546Sopenharmony_ci descs(prog.devices()) : 501bf215546Sopenharmony_ci descs(prog.context().devices())); 502bf215546Sopenharmony_ci break; 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_ci case CL_PROGRAM_SOURCE: 505bf215546Sopenharmony_ci buf.as_string() = prog.source(); 506bf215546Sopenharmony_ci break; 507bf215546Sopenharmony_ci 508bf215546Sopenharmony_ci case CL_PROGRAM_BINARY_SIZES: 509bf215546Sopenharmony_ci buf.as_vector<size_t>() = map([&](const device &dev) { 510bf215546Sopenharmony_ci return prog.build(dev).bin.size(); 511bf215546Sopenharmony_ci }, 512bf215546Sopenharmony_ci prog.devices()); 513bf215546Sopenharmony_ci break; 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_ci case CL_PROGRAM_BINARIES: 516bf215546Sopenharmony_ci buf.as_matrix<unsigned char>() = map([&](const device &dev) { 517bf215546Sopenharmony_ci std::stringbuf bin; 518bf215546Sopenharmony_ci std::ostream s(&bin); 519bf215546Sopenharmony_ci prog.build(dev).bin.serialize(s); 520bf215546Sopenharmony_ci return bin.str(); 521bf215546Sopenharmony_ci }, 522bf215546Sopenharmony_ci prog.devices()); 523bf215546Sopenharmony_ci break; 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_ci case CL_PROGRAM_NUM_KERNELS: 526bf215546Sopenharmony_ci buf.as_scalar<cl_uint>() = prog.symbols().size(); 527bf215546Sopenharmony_ci break; 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_ci case CL_PROGRAM_KERNEL_NAMES: 530bf215546Sopenharmony_ci buf.as_string() = fold([](const std::string &a, const binary::symbol &s) { 531bf215546Sopenharmony_ci return ((a.empty() ? "" : a + ";") + s.name); 532bf215546Sopenharmony_ci }, std::string(), prog.symbols()); 533bf215546Sopenharmony_ci break; 534bf215546Sopenharmony_ci 535bf215546Sopenharmony_ci case CL_PROGRAM_SCOPE_GLOBAL_CTORS_PRESENT: 536bf215546Sopenharmony_ci case CL_PROGRAM_SCOPE_GLOBAL_DTORS_PRESENT: 537bf215546Sopenharmony_ci buf.as_scalar<cl_bool>() = CL_FALSE; 538bf215546Sopenharmony_ci break; 539bf215546Sopenharmony_ci 540bf215546Sopenharmony_ci case CL_PROGRAM_IL: 541bf215546Sopenharmony_ci if (prog.il_type() == program::il_type::spirv) 542bf215546Sopenharmony_ci buf.as_vector<char>() = prog.source(); 543bf215546Sopenharmony_ci else if (r_size) 544bf215546Sopenharmony_ci *r_size = 0u; 545bf215546Sopenharmony_ci break; 546bf215546Sopenharmony_ci default: 547bf215546Sopenharmony_ci throw error(CL_INVALID_VALUE); 548bf215546Sopenharmony_ci } 549bf215546Sopenharmony_ci 550bf215546Sopenharmony_ci return CL_SUCCESS; 551bf215546Sopenharmony_ci 552bf215546Sopenharmony_ci} catch (error &e) { 553bf215546Sopenharmony_ci return e.get(); 554bf215546Sopenharmony_ci} 555bf215546Sopenharmony_ci 556bf215546Sopenharmony_ciCLOVER_API cl_int 557bf215546Sopenharmony_ciclGetProgramBuildInfo(cl_program d_prog, cl_device_id d_dev, 558bf215546Sopenharmony_ci cl_program_build_info param, 559bf215546Sopenharmony_ci size_t size, void *r_buf, size_t *r_size) try { 560bf215546Sopenharmony_ci property_buffer buf { r_buf, size, r_size }; 561bf215546Sopenharmony_ci auto &prog = obj(d_prog); 562bf215546Sopenharmony_ci auto &dev = obj(d_dev); 563bf215546Sopenharmony_ci 564bf215546Sopenharmony_ci if (!count(dev, prog.context().devices())) 565bf215546Sopenharmony_ci return CL_INVALID_DEVICE; 566bf215546Sopenharmony_ci 567bf215546Sopenharmony_ci switch (param) { 568bf215546Sopenharmony_ci case CL_PROGRAM_BUILD_STATUS: 569bf215546Sopenharmony_ci buf.as_scalar<cl_build_status>() = prog.build(dev).status(); 570bf215546Sopenharmony_ci break; 571bf215546Sopenharmony_ci 572bf215546Sopenharmony_ci case CL_PROGRAM_BUILD_OPTIONS: 573bf215546Sopenharmony_ci buf.as_string() = prog.build(dev).opts; 574bf215546Sopenharmony_ci break; 575bf215546Sopenharmony_ci 576bf215546Sopenharmony_ci case CL_PROGRAM_BUILD_LOG: 577bf215546Sopenharmony_ci buf.as_string() = prog.build(dev).log; 578bf215546Sopenharmony_ci break; 579bf215546Sopenharmony_ci 580bf215546Sopenharmony_ci case CL_PROGRAM_BINARY_TYPE: 581bf215546Sopenharmony_ci buf.as_scalar<cl_program_binary_type>() = prog.build(dev).binary_type(); 582bf215546Sopenharmony_ci break; 583bf215546Sopenharmony_ci 584bf215546Sopenharmony_ci case CL_PROGRAM_BUILD_GLOBAL_VARIABLE_TOTAL_SIZE: 585bf215546Sopenharmony_ci buf.as_scalar<size_t>() = 0; 586bf215546Sopenharmony_ci break; 587bf215546Sopenharmony_ci 588bf215546Sopenharmony_ci default: 589bf215546Sopenharmony_ci throw error(CL_INVALID_VALUE); 590bf215546Sopenharmony_ci } 591bf215546Sopenharmony_ci 592bf215546Sopenharmony_ci return CL_SUCCESS; 593bf215546Sopenharmony_ci 594bf215546Sopenharmony_ci} catch (error &e) { 595bf215546Sopenharmony_ci return e.get(); 596bf215546Sopenharmony_ci} 597