microsoft/clc: When possible, compute a part-constant "pointer" value for kernel inputs

When a kernel input is a pointer to global or constant memory, it's expected
that the invoker provides the pointer value in the form of
(buffer_index << 32) | offset. The buffer index, however, is statically
knowable in the compiler, as long as a buffer is bound. Since it's
undefined behavior to dereference the pointer with no buffer bound,
we can replace any deref chain that terminates in an access with one
that uses a constant buffer index.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26803>
This commit is contained in:
Jesse Natalie
2023-12-08 14:02:35 -08:00
committed by Marge Bot
parent 6fc8d0147e
commit 1649a4d92b
3 changed files with 85 additions and 1 deletions
+3 -1
View File
@@ -804,7 +804,7 @@ clc_spirv_to_dxil(struct clc_libclc *lib,
var->data.driver_location + size);
if (out_dxil->kernel->args[i].address_qualifier == CLC_KERNEL_ARG_ADDRESS_GLOBAL ||
out_dxil->kernel->args[i].address_qualifier == CLC_KERNEL_ARG_ADDRESS_CONSTANT) {
metadata->args[i].globconstptr.buf_id = uav_id++;
metadata->args[i].globconstptr.buf_id = var->data.binding = uav_id++;
} else if (glsl_type_is_sampler(var->type)) {
unsigned address_mode = conf ? conf->args[i].sampler.addressing_mode : 0u;
int_sampler_states[sampler_id].wrap[0] =
@@ -906,6 +906,8 @@ clc_spirv_to_dxil(struct clc_libclc *lib,
}
NIR_PASS_V(nir, nir_lower_memcpy);
NIR_PASS_V(nir, clc_nir_lower_global_pointers_to_constants);
// Attempt to preserve derefs to constants by moving them to shader_temp
NIR_PASS_V(nir, dxil_nir_lower_constant_to_temp);
// While inserting new var derefs for our "logical" addressing mode, temporarily
+81
View File
@@ -25,6 +25,7 @@
#include "nir.h"
#include "glsl_types.h"
#include "nir_builder.h"
#include "nir_deref.h"
#include "clc_nir.h"
#include "clc_compiler.h"
@@ -261,3 +262,83 @@ clc_lower_printf_base(nir_shader *nir, unsigned uav_id)
return printf_var != NULL;
}
/* Find patterns of:
* - deref_var for one of the kernel inputs
* - load_deref to get a pointer to global/constant memory
* - cast the pointer into a deref
* - use a basic deref chain that terminates in a load/store/atomic
*
* When this pattern is found, replace the load_deref with a constant value,
* based on which kernel argument is being loaded from. This can only be done
* for chains that terminate in a pointer access, since the presence of null
* pointers should be detected by actually performing the load and inspecting
* the resulting pointer value.
*/
static bool
lower_deref_base_to_constant(nir_builder *b, nir_intrinsic_instr *intr, void *context)
{
switch (intr->intrinsic) {
case nir_intrinsic_load_deref:
case nir_intrinsic_store_deref:
case nir_intrinsic_deref_atomic:
case nir_intrinsic_deref_atomic_swap:
break;
default:
return false;
}
nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
if (!nir_deref_mode_must_be(deref, nir_var_mem_global | nir_var_mem_constant))
return false;
nir_deref_path path;
nir_deref_path_init(&path, deref, NULL);
bool ret = false;
if (path.path[0]->deref_type != nir_deref_type_cast)
goto done;
if (!nir_deref_mode_must_be(path.path[0], nir_var_mem_global | nir_var_mem_constant))
goto done;
nir_instr *cast_src = path.path[0]->parent.ssa->parent_instr;
if (cast_src->type != nir_instr_type_intrinsic)
goto done;
nir_intrinsic_instr *cast_src_intr = nir_instr_as_intrinsic(cast_src);
if (cast_src_intr->intrinsic != nir_intrinsic_load_deref)
goto done;
nir_deref_instr *load_deref_src = nir_src_as_deref(cast_src_intr->src[0]);
if (load_deref_src->deref_type != nir_deref_type_var ||
load_deref_src->modes != nir_var_uniform)
goto done;
nir_variable *var = load_deref_src->var;
ret = true;
b->cursor = nir_before_instr(&path.path[0]->instr);
nir_def *original_offset = nir_unpack_64_2x32_split_x(b, &cast_src_intr->def);
nir_def *constant_ptr = nir_pack_64_2x32_split(b, original_offset, nir_imm_int(b, var->data.binding));
nir_deref_instr *new_path = nir_build_deref_cast_with_alignment(b, constant_ptr, path.path[0]->modes, path.path[0]->type, path.path[0]->cast.ptr_stride,
path.path[0]->cast.align_mul, path.path[0]->cast.align_offset);
for (unsigned i = 1; path.path[i]; ++i) {
b->cursor = nir_after_instr(&path.path[i]->instr);
new_path = nir_build_deref_follower(b, new_path, path.path[i]);
}
nir_src_rewrite(&intr->src[0], &new_path->def);
done:
nir_deref_path_finish(&path);
return ret;
}
bool
clc_nir_lower_global_pointers_to_constants(nir_shader *nir)
{
return nir_shader_intrinsics_pass(nir, lower_deref_base_to_constant,
nir_metadata_block_index |
nir_metadata_dominance |
nir_metadata_loop_analysis, NULL);
}
+1
View File
@@ -32,4 +32,5 @@ clc_nir_lower_system_values(nir_shader *nir, nir_variable *var);
bool clc_nir_lower_kernel_input_loads(nir_shader *nir, nir_variable *var);
bool clc_lower_printf_base(nir_shader *nir, unsigned uav_id);
bool clc_nir_lower_global_pointers_to_constants(nir_shader *nir);
#endif