Commit a92afdea authored by Pierre Moreau's avatar Pierre Moreau

clover: Implement clCreateProgramWithILKHR

v2: Use the same storage for OpenCL C sources and ILs representations
    (Karol Herbst, Francisco Jerez)
v3:
* Remove `program::has_source` and instead add a value to
  `program::il_type` for sources. (Francisco Jerez)
* Use `std::move()` on sources.
* Replace `CL_MAKE_VERSION(99999999u, 0u, 0u)` with
  `std::numeric_limits<uint32_t>::max()` (Francisco Jerez)
Reviewed-by: Francisco Jerez's avatarFrancisco Jerez <currojerez@riseup.net>
Signed-off-by: Pierre Moreau's avatarPierre Moreau <dev@pmoreau.org>
Part-of: <mesa/mesa!2078>
parent 7b165917
......@@ -100,6 +100,10 @@ namespace clover {
const cl_event *event_wait_list,
cl_event *event,
cl_int cmd);
cl_program
CreateProgramWithILKHR(cl_context d_ctx, const void *il,
size_t length, cl_int *r_errcode);
}
#endif
......@@ -22,8 +22,10 @@
#include "api/util.hpp"
#include "core/program.hpp"
#include "spirv/invocation.hpp"
#include "util/u_debug.h"
#include <limits>
#include <sstream>
using namespace clover;
......@@ -71,6 +73,29 @@ namespace {
}, objs<allow_empty_tag>(d_devs, num_devs)))
throw error(CL_INVALID_DEVICE);
}
enum program::il_type
identify_and_validate_il(const std::string &il,
const cl_version opencl_version,
const context::notify_action &notify) {
enum program::il_type il_type = program::il_type::none;
#ifdef HAVE_CLOVER_SPIRV
if (spirv::is_binary_spirv(il)) {
std::string log;
if (!spirv::is_valid_spirv(il, opencl_version, log)) {
if (notify) {
notify(log.c_str());
}
throw error(CL_INVALID_VALUE);
}
il_type = program::il_type::spirv;
}
#endif
return il_type;
}
}
CLOVER_API cl_program
......@@ -92,7 +117,7 @@ clCreateProgramWithSource(cl_context d_ctx, cl_uint count,
// ...and create a program object for them.
ret_error(r_errcode, CL_SUCCESS);
return new program(ctx, source);
return new program(ctx, std::move(source), program::il_type::source);
} catch (error &e) {
ret_error(r_errcode, e);
......@@ -154,6 +179,40 @@ clCreateProgramWithBinary(cl_context d_ctx, cl_uint n,
return NULL;
}
cl_program
clover::CreateProgramWithILKHR(cl_context d_ctx, const void *il,
size_t length, cl_int *r_errcode) try {
auto &ctx = obj(d_ctx);
if (!il || !length)
throw error(CL_INVALID_VALUE);
// Compute the highest OpenCL version supported by all devices associated to
// the context. That is the version used for validating the SPIR-V binary.
cl_version min_opencl_version = std::numeric_limits<uint32_t>::max();
for (const device &dev : ctx.devices()) {
const cl_version opencl_version = dev.device_version();
min_opencl_version = std::min(opencl_version, min_opencl_version);
}
const char *stream = reinterpret_cast<const char *>(il);
std::string binary(stream, stream + length);
const enum program::il_type il_type = identify_and_validate_il(binary,
min_opencl_version,
ctx.notify);
if (il_type == program::il_type::none)
throw error(CL_INVALID_VALUE);
// Initialize a program object with it.
ret_error(r_errcode, CL_SUCCESS);
return new program(ctx, std::move(binary), il_type);
} catch (error &e) {
ret_error(r_errcode, e);
return NULL;
}
CLOVER_API cl_program
clCreateProgramWithBuiltInKernels(cl_context d_ctx, cl_uint n,
const cl_device_id *d_devs,
......@@ -210,7 +269,7 @@ clBuildProgram(cl_program d_prog, cl_uint num_devs,
auto notifier = build_notifier(d_prog, pfn_notify, user_data);
if (prog.has_source) {
if (prog.il_type() != program::il_type::none) {
prog.compile(devs, opts);
prog.link(devs, opts, { prog });
} else if (any_of([&](const device &dev){
......@@ -248,11 +307,11 @@ clCompileProgram(cl_program d_prog, cl_uint num_devs,
if (bool(num_headers) != bool(header_names))
throw error(CL_INVALID_VALUE);
if (!prog.has_source)
if (prog.il_type() == program::il_type::none)
throw error(CL_INVALID_OPERATION);
for_each([&](const char *name, const program &header) {
if (!header.has_source)
if (header.il_type() == program::il_type::none)
throw error(CL_INVALID_OPERATION);
if (!any_of(key_equals(name), headers))
......
......@@ -32,16 +32,27 @@
namespace clover {
namespace compiler {
static inline module
compile_program(const std::string &source, const header_map &headers,
compile_program(const program &prog, const header_map &headers,
const device &dev, const std::string &opts,
std::string &log) {
switch (dev.ir_format()) {
#ifdef HAVE_CLOVER_SPIRV
case PIPE_SHADER_IR_NIR_SERIALIZED:
return llvm::compile_to_spirv(source, headers, dev, opts, log);
switch (prog.il_type()) {
case program::il_type::source:
return llvm::compile_to_spirv(prog.source(), headers, dev, opts, log);
case program::il_type::spirv:
return spirv::compile_program(prog.source(), dev, log);
default:
unreachable("device with unsupported IL");
throw error(CL_INVALID_VALUE);
}
#endif
case PIPE_SHADER_IR_NATIVE:
return llvm::compile_program(source, headers, dev, opts, log);
if (prog.il_type() == program::il_type::source)
return llvm::compile_program(prog.source(), headers, dev, opts, log);
else
throw error(CL_INVALID_VALUE);
default:
unreachable("device with unsupported IR");
throw error(CL_INVALID_VALUE);
......
......@@ -25,16 +25,17 @@
using namespace clover;
program::program(clover::context &ctx, const std::string &source) :
has_source(true), context(ctx), _devices(ctx.devices()), _source(source),
_kernel_ref_counter(0) {
program::program(clover::context &ctx, std::string &&source,
enum il_type il_type) :
context(ctx), _devices(ctx.devices()), _source(std::move(source)),
_kernel_ref_counter(0), _il_type(il_type) {
}
program::program(clover::context &ctx,
const ref_vector<device> &devs,
const std::vector<module> &binaries) :
has_source(false), context(ctx),
_devices(devs), _kernel_ref_counter(0) {
context(ctx), _devices(devs), _kernel_ref_counter(0),
_il_type(il_type::none) {
for_each([&](device &dev, const module &bin) {
_builds[&dev] = { bin };
},
......@@ -44,7 +45,7 @@ program::program(clover::context &ctx,
void
program::compile(const ref_vector<device> &devs, const std::string &opts,
const header_map &headers) {
if (has_source) {
if (_il_type != il_type::none) {
_devices = devs;
for (auto &dev : devs) {
......@@ -52,7 +53,7 @@ program::compile(const ref_vector<device> &devs, const std::string &opts,
try {
const module m =
compiler::compile_program(_source, headers, dev, opts, log);
compiler::compile_program(*this, headers, dev, opts, log);
_builds[&dev] = { m, opts, log };
} catch (...) {
_builds[&dev] = { module(), opts, log };
......@@ -83,6 +84,11 @@ program::link(const ref_vector<device> &devs, const std::string &opts,
}
}
enum program::il_type
program::il_type() const {
return _il_type;
}
const std::string &
program::source() const {
return _source;
......
......@@ -38,8 +38,11 @@ namespace clover {
evals, const std::vector<intrusive_ref<device>> &> device_range;
public:
enum class il_type { none, source, spirv };
program(clover::context &ctx,
const std::string &source);
std::string &&il,
enum il_type il_type);
program(clover::context &ctx,
const ref_vector<device> &devs = {},
const std::vector<module> &binaries = {});
......@@ -53,8 +56,8 @@ namespace clover {
void link(const ref_vector<device> &devs, const std::string &opts,
const ref_vector<program> &progs);
const bool has_source;
const std::string &source() const;
enum il_type il_type() const;
device_range devices() const;
......@@ -85,6 +88,7 @@ namespace clover {
std::map<const device *, struct build> _builds;
std::string _source;
ref_counter _kernel_ref_counter;
enum il_type _il_type;
};
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment