2019-08-06 20:35:48 +02:00
|
|
|
//
|
|
|
|
|
// Copyright 2019 Karol Herbst
|
|
|
|
|
//
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
//
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
|
//
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
|
|
|
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
|
|
|
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
|
|
|
// OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include "invocation.hpp"
|
|
|
|
|
|
|
|
|
|
#include <tuple>
|
|
|
|
|
|
|
|
|
|
#include "core/device.hpp"
|
|
|
|
|
#include "core/error.hpp"
|
2020-08-19 16:02:55 +02:00
|
|
|
#include "core/module.hpp"
|
2019-08-06 20:35:48 +02:00
|
|
|
#include "pipe/p_state.h"
|
|
|
|
|
#include "util/algorithm.hpp"
|
|
|
|
|
#include "util/functional.hpp"
|
|
|
|
|
|
|
|
|
|
#include <compiler/glsl_types.h>
|
2020-08-19 16:02:55 +02:00
|
|
|
#include <compiler/nir/nir_builder.h>
|
2019-08-06 20:35:48 +02:00
|
|
|
#include <compiler/nir/nir_serialize.h>
|
|
|
|
|
#include <compiler/spirv/nir_spirv.h>
|
|
|
|
|
#include <util/u_math.h>
|
|
|
|
|
|
|
|
|
|
using namespace clover;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CLOVER_SPIRV
|
|
|
|
|
|
|
|
|
|
// Refs and unrefs the glsl_type_singleton.
|
|
|
|
|
static class glsl_type_ref {
|
|
|
|
|
public:
|
|
|
|
|
glsl_type_ref() {
|
|
|
|
|
glsl_type_singleton_init_or_ref();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~glsl_type_ref() {
|
|
|
|
|
glsl_type_singleton_decref();
|
|
|
|
|
}
|
|
|
|
|
} glsl_type_ref;
|
|
|
|
|
|
|
|
|
|
static const nir_shader_compiler_options *
|
|
|
|
|
dev_get_nir_compiler_options(const device &dev)
|
|
|
|
|
{
|
|
|
|
|
const void *co = dev.get_compiler_options(PIPE_SHADER_IR_NIR);
|
|
|
|
|
return static_cast<const nir_shader_compiler_options*>(co);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-10 23:21:56 +02:00
|
|
|
static void debug_function(void *private_data,
|
|
|
|
|
enum nir_spirv_debug_level level, size_t spirv_offset,
|
|
|
|
|
const char *message)
|
|
|
|
|
{
|
|
|
|
|
assert(private_data);
|
|
|
|
|
auto r_log = reinterpret_cast<std::string *>(private_data);
|
|
|
|
|
*r_log += message;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-19 16:02:55 +02:00
|
|
|
struct clover_lower_nir_state {
|
|
|
|
|
std::vector<module::argument> &args;
|
|
|
|
|
uint32_t global_dims;
|
|
|
|
|
nir_variable *offset_vars[3];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
clover_lower_nir_filter(const nir_instr *instr, const void *)
|
|
|
|
|
{
|
|
|
|
|
return instr->type == nir_instr_type_intrinsic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static nir_ssa_def *
|
|
|
|
|
clover_lower_nir_instr(nir_builder *b, nir_instr *instr, void *_state)
|
|
|
|
|
{
|
|
|
|
|
clover_lower_nir_state *state = reinterpret_cast<clover_lower_nir_state*>(_state);
|
|
|
|
|
nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(instr);
|
|
|
|
|
|
|
|
|
|
switch (intrinsic->intrinsic) {
|
|
|
|
|
case nir_intrinsic_load_base_global_invocation_id: {
|
|
|
|
|
nir_ssa_def *loads[3];
|
|
|
|
|
|
|
|
|
|
/* create variables if we didn't do so alrady */
|
|
|
|
|
if (!state->offset_vars[0]) {
|
|
|
|
|
/* TODO: fix for 64 bit */
|
|
|
|
|
/* Even though we only place one scalar argument, clover will bind up to
|
|
|
|
|
* three 32 bit values
|
|
|
|
|
*/
|
|
|
|
|
state->args.emplace_back(module::argument::scalar, 4, 4, 4,
|
|
|
|
|
module::argument::zero_ext,
|
|
|
|
|
module::argument::grid_offset);
|
|
|
|
|
|
|
|
|
|
const glsl_type *type = glsl_uint_type();
|
|
|
|
|
for (uint32_t i = 0; i < 3; i++) {
|
|
|
|
|
state->offset_vars[i] =
|
2020-08-28 12:52:20 -07:00
|
|
|
nir_variable_create(b->shader, nir_var_uniform, type,
|
2020-08-19 16:02:55 +02:00
|
|
|
"global_invocation_id_offsets");
|
2020-08-28 12:52:20 -07:00
|
|
|
state->offset_vars[i]->data.location = b->shader->num_uniforms++;
|
2020-08-19 16:02:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
|
nir_variable *var = state->offset_vars[i];
|
|
|
|
|
loads[i] = var ? nir_load_var(b, var) : nir_imm_int(b, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nir_u2u(b, nir_vec(b, loads, state->global_dims),
|
|
|
|
|
nir_dest_bit_size(intrinsic->dest));
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
clover_lower_nir(nir_shader *nir, std::vector<module::argument> &args, uint32_t dims)
|
|
|
|
|
{
|
|
|
|
|
clover_lower_nir_state state = { args, dims };
|
|
|
|
|
return nir_shader_lower_instructions(nir,
|
|
|
|
|
clover_lower_nir_filter, clover_lower_nir_instr, &state);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-06 20:35:48 +02:00
|
|
|
module clover::nir::spirv_to_nir(const module &mod, const device &dev,
|
|
|
|
|
std::string &r_log)
|
|
|
|
|
{
|
2019-09-22 15:27:33 +02:00
|
|
|
struct spirv_to_nir_options spirv_options = {};
|
2019-12-05 11:30:11 +01:00
|
|
|
spirv_options.environment = NIR_SPIRV_OPENCL;
|
2020-05-21 15:12:15 -07:00
|
|
|
if (dev.address_bits() == 32u) {
|
2020-08-19 12:15:23 -05:00
|
|
|
spirv_options.shared_addr_format = nir_address_format_32bit_offset;
|
2020-05-21 15:12:15 -07:00
|
|
|
spirv_options.global_addr_format = nir_address_format_32bit_global;
|
2020-08-19 21:14:46 +02:00
|
|
|
spirv_options.temp_addr_format = nir_address_format_32bit_offset;
|
2020-08-19 11:34:21 -05:00
|
|
|
spirv_options.constant_addr_format = nir_address_format_32bit_global;
|
2020-05-21 15:12:15 -07:00
|
|
|
} else {
|
2020-08-19 12:15:23 -05:00
|
|
|
spirv_options.shared_addr_format = nir_address_format_32bit_offset_as_64bit;
|
2020-05-21 15:12:15 -07:00
|
|
|
spirv_options.global_addr_format = nir_address_format_64bit_global;
|
2020-08-19 21:14:46 +02:00
|
|
|
spirv_options.temp_addr_format = nir_address_format_32bit_offset_as_64bit;
|
2020-08-19 11:34:21 -05:00
|
|
|
spirv_options.constant_addr_format = nir_address_format_64bit_global;
|
2020-05-21 15:12:15 -07:00
|
|
|
}
|
2019-09-22 15:27:33 +02:00
|
|
|
spirv_options.caps.address = true;
|
|
|
|
|
spirv_options.caps.float64 = true;
|
|
|
|
|
spirv_options.caps.int8 = true;
|
|
|
|
|
spirv_options.caps.int16 = true;
|
|
|
|
|
spirv_options.caps.int64 = true;
|
|
|
|
|
spirv_options.caps.kernel = true;
|
2020-03-05 23:00:27 +01:00
|
|
|
spirv_options.caps.int64_atomics = dev.has_int64_atomics();
|
2020-05-10 23:21:56 +02:00
|
|
|
spirv_options.debug.func = &debug_function;
|
|
|
|
|
spirv_options.debug.private_data = &r_log;
|
2019-08-06 20:35:48 +02:00
|
|
|
|
|
|
|
|
module m;
|
|
|
|
|
// We only insert one section.
|
|
|
|
|
assert(mod.secs.size() == 1);
|
|
|
|
|
auto §ion = mod.secs[0];
|
|
|
|
|
|
|
|
|
|
module::resource_id section_id = 0;
|
|
|
|
|
for (const auto &sym : mod.syms) {
|
|
|
|
|
assert(sym.section == 0);
|
|
|
|
|
|
|
|
|
|
const auto *binary =
|
|
|
|
|
reinterpret_cast<const pipe_binary_program_header *>(section.data.data());
|
|
|
|
|
const uint32_t *data = reinterpret_cast<const uint32_t *>(binary->blob);
|
|
|
|
|
const size_t num_words = binary->num_bytes / 4;
|
|
|
|
|
const char *name = sym.name.c_str();
|
|
|
|
|
auto *compiler_options = dev_get_nir_compiler_options(dev);
|
|
|
|
|
|
|
|
|
|
nir_shader *nir = spirv_to_nir(data, num_words, nullptr, 0,
|
|
|
|
|
MESA_SHADER_KERNEL, name,
|
|
|
|
|
&spirv_options, compiler_options);
|
2020-05-05 13:13:19 +02:00
|
|
|
if (!nir) {
|
|
|
|
|
r_log += "Translation from SPIR-V to NIR for kernel \"" + sym.name +
|
|
|
|
|
"\" failed.\n";
|
|
|
|
|
throw build_error();
|
|
|
|
|
}
|
2019-08-06 20:35:48 +02:00
|
|
|
|
|
|
|
|
nir->info.cs.local_size_variable = true;
|
|
|
|
|
nir_validate_shader(nir, "clover");
|
|
|
|
|
|
|
|
|
|
// Inline all functions first.
|
|
|
|
|
// according to the comment on nir_inline_functions
|
2020-02-07 14:18:49 -06:00
|
|
|
NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp);
|
2019-08-06 20:35:48 +02:00
|
|
|
NIR_PASS_V(nir, nir_lower_returns);
|
|
|
|
|
NIR_PASS_V(nir, nir_inline_functions);
|
2020-06-11 13:29:02 -05:00
|
|
|
NIR_PASS_V(nir, nir_copy_prop);
|
2019-08-06 20:35:48 +02:00
|
|
|
NIR_PASS_V(nir, nir_opt_deref);
|
|
|
|
|
|
|
|
|
|
// Pick off the single entrypoint that we want.
|
|
|
|
|
foreach_list_typed_safe(nir_function, func, node, &nir->functions) {
|
|
|
|
|
if (!func->is_entrypoint)
|
|
|
|
|
exec_node_remove(&func->node);
|
|
|
|
|
}
|
|
|
|
|
assert(exec_list_length(&nir->functions) == 1);
|
|
|
|
|
|
|
|
|
|
nir_validate_shader(nir, "clover after function inlining");
|
|
|
|
|
|
2020-08-31 18:08:49 +02:00
|
|
|
NIR_PASS_V(nir, nir_lower_variable_initializers, ~nir_var_function_temp);
|
2019-08-06 20:35:48 +02:00
|
|
|
|
|
|
|
|
// copy propagate to prepare for lower_explicit_io
|
|
|
|
|
NIR_PASS_V(nir, nir_split_var_copies);
|
|
|
|
|
NIR_PASS_V(nir, nir_opt_copy_prop_vars);
|
|
|
|
|
NIR_PASS_V(nir, nir_lower_var_copies);
|
|
|
|
|
NIR_PASS_V(nir, nir_lower_vars_to_ssa);
|
|
|
|
|
NIR_PASS_V(nir, nir_opt_dce);
|
|
|
|
|
|
2020-08-19 16:02:55 +02:00
|
|
|
NIR_PASS_V(nir, nir_lower_system_values);
|
|
|
|
|
nir_lower_compute_system_values_options sysval_options = { 0 };
|
|
|
|
|
sysval_options.has_base_global_invocation_id = true;
|
|
|
|
|
NIR_PASS_V(nir, nir_lower_compute_system_values, &sysval_options);
|
|
|
|
|
|
|
|
|
|
auto args = sym.args;
|
|
|
|
|
NIR_PASS_V(nir, clover_lower_nir, args, dev.max_block_size().size());
|
|
|
|
|
|
|
|
|
|
// Calculate input offsets.
|
|
|
|
|
unsigned offset = 0;
|
2020-08-28 12:52:20 -07:00
|
|
|
nir_foreach_uniform_variable(var, nir) {
|
2020-08-19 16:02:55 +02:00
|
|
|
offset = align(offset, glsl_get_cl_alignment(var->type));
|
|
|
|
|
var->data.driver_location = offset;
|
|
|
|
|
offset += glsl_get_cl_size(var->type);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-02 17:43:07 -05:00
|
|
|
NIR_PASS_V(nir, nir_lower_mem_constant_vars,
|
|
|
|
|
glsl_get_cl_type_size_align);
|
2020-08-16 17:43:18 +02:00
|
|
|
NIR_PASS_V(nir, nir_lower_vars_to_explicit_types,
|
|
|
|
|
nir_var_mem_shared | nir_var_function_temp,
|
2020-08-15 13:33:29 +02:00
|
|
|
glsl_get_cl_type_size_align);
|
|
|
|
|
|
2020-08-21 17:23:59 -05:00
|
|
|
/* use offsets for kernel inputs (uniform) */
|
2020-08-28 12:52:20 -07:00
|
|
|
NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_uniform,
|
2020-08-21 17:23:59 -05:00
|
|
|
nir->info.cs.ptr_size == 64 ?
|
|
|
|
|
nir_address_format_32bit_offset_as_64bit :
|
2020-08-19 12:15:23 -05:00
|
|
|
nir_address_format_32bit_offset);
|
|
|
|
|
|
2020-08-19 11:34:21 -05:00
|
|
|
NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_constant,
|
|
|
|
|
spirv_options.constant_addr_format);
|
2020-08-19 12:15:23 -05:00
|
|
|
NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_shared,
|
|
|
|
|
spirv_options.shared_addr_format);
|
2020-08-14 21:56:00 +02:00
|
|
|
|
2020-08-16 17:43:18 +02:00
|
|
|
NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_function_temp,
|
|
|
|
|
spirv_options.temp_addr_format);
|
|
|
|
|
|
2020-08-19 11:32:32 -05:00
|
|
|
NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_global,
|
|
|
|
|
spirv_options.global_addr_format);
|
2019-08-06 20:35:48 +02:00
|
|
|
|
2020-08-16 17:43:18 +02:00
|
|
|
NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_all, NULL);
|
|
|
|
|
|
2019-08-06 20:35:48 +02:00
|
|
|
if (compiler_options->lower_int64_options)
|
2020-07-13 20:28:16 +02:00
|
|
|
NIR_PASS_V(nir, nir_lower_int64);
|
2019-08-06 20:35:48 +02:00
|
|
|
|
|
|
|
|
NIR_PASS_V(nir, nir_opt_dce);
|
|
|
|
|
|
|
|
|
|
struct blob blob;
|
|
|
|
|
blob_init(&blob);
|
2019-10-10 18:43:47 -04:00
|
|
|
nir_serialize(&blob, nir, false);
|
2019-08-06 20:35:48 +02:00
|
|
|
|
|
|
|
|
const pipe_binary_program_header header { uint32_t(blob.size) };
|
|
|
|
|
module::section text { section_id, module::section::text_executable, header.num_bytes, {} };
|
|
|
|
|
text.data.insert(text.data.end(), reinterpret_cast<const char *>(&header),
|
|
|
|
|
reinterpret_cast<const char *>(&header) + sizeof(header));
|
|
|
|
|
text.data.insert(text.data.end(), blob.data, blob.data + blob.size);
|
|
|
|
|
|
2020-08-19 16:02:55 +02:00
|
|
|
m.syms.emplace_back(sym.name, section_id, 0, args);
|
2019-08-06 20:35:48 +02:00
|
|
|
m.secs.push_back(text);
|
|
|
|
|
section_id++;
|
|
|
|
|
}
|
|
|
|
|
return m;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
module clover::nir::spirv_to_nir(const module &mod, const device &dev, std::string &r_log)
|
|
|
|
|
{
|
|
|
|
|
r_log += "SPIR-V support in clover is not enabled.\n";
|
|
|
|
|
throw error(CL_LINKER_NOT_AVAILABLE);
|
|
|
|
|
}
|
|
|
|
|
#endif
|