mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-22 19:20:22 +01:00
broadcom: lower null pointers
We only support the variablePointersStorageBuffer feature of variable pointers,
which basically ensures that pointers may only target one buffer. This means
that a particular pointer may change where it points within a given buffer but
it cannot change its value to point to some other buffer. This is a requirement
from us since we expect buffer indices on buffer loads and stores to be
constant, so we can't have a buffer load come through a pointer that may
be assigned to different buffers, since in that case the buffer index
would need to come from bcsel.
There is, however, a small complication: the spec still allows pointers to
be null, and NIR defines null pointers to use 0xffffffff for both the buffer
index and the offset, which will cause a problem in a scenario like this:
int *b = ...
if (cond) {
b = null;
discard;
}
ubo_load(b);
Here the buffer index for the ubo load may come from a bcsel choosing between
the null pointer (0xffffffff) and the valid address (let's say 0), so we don't
have a constant and we assert fail.
This change detects this scenario and upon finding it will rewrite the buffer
index on the null pointer branch of the bcsel to match that of the valid
branch so that later optimizations passes can remove the bcsel and we end up
with a constant index. This is fine because a null pointer dereference is
undefined behavior and it is not something we should see in valid applications.
Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26683>
This commit is contained in:
parent
716847a77d
commit
d0f75fdeab
1 changed files with 76 additions and 0 deletions
|
|
@ -605,6 +605,81 @@ lower_tex_packing_cb(const nir_tex_instr *tex, const void *data)
|
|||
nir_lower_tex_packing_16 : nir_lower_tex_packing_none;
|
||||
}
|
||||
|
||||
static bool
|
||||
v3d_nir_lower_null_pointers_cb(nir_builder *b,
|
||||
nir_intrinsic_instr *intr,
|
||||
void *_state)
|
||||
{
|
||||
uint32_t buffer_src_idx;
|
||||
|
||||
switch (intr->intrinsic) {
|
||||
case nir_intrinsic_load_ubo:
|
||||
case nir_intrinsic_load_ssbo:
|
||||
buffer_src_idx = 0;
|
||||
break;
|
||||
case nir_intrinsic_store_ssbo:
|
||||
buffer_src_idx = 1;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If index if constant we are good */
|
||||
nir_src *src = &intr->src[buffer_src_idx];
|
||||
if (nir_src_is_const(*src))
|
||||
return false;
|
||||
|
||||
/* Otherwise, see if it comes from a bcsel including a null pointer */
|
||||
if (src->ssa->parent_instr->type != nir_instr_type_alu)
|
||||
return false;
|
||||
|
||||
nir_alu_instr *alu = nir_instr_as_alu(src->ssa->parent_instr);
|
||||
if (alu->op != nir_op_bcsel)
|
||||
return false;
|
||||
|
||||
/* A null pointer is specified using block index 0xffffffff */
|
||||
int32_t null_src_idx = -1;
|
||||
for (int i = 1; i < 3; i++) {
|
||||
/* FIXME: since we are running this before optimization maybe
|
||||
* we need to also handle the case where we may have bcsel
|
||||
* chain that we need to recurse?
|
||||
*/
|
||||
if (!nir_src_is_const(alu->src[i].src))
|
||||
continue;
|
||||
if (nir_src_comp_as_uint(alu->src[i].src, 0) != 0xffffffff)
|
||||
continue;
|
||||
|
||||
/* One of the bcsel srcs is a null pointer reference */
|
||||
null_src_idx = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (null_src_idx < 0)
|
||||
return false;
|
||||
|
||||
assert(null_src_idx == 1 || null_src_idx == 2);
|
||||
int32_t copy_src_idx = null_src_idx == 1 ? 2 : 1;
|
||||
|
||||
/* Rewrite the null pointer reference so we use the same buffer index
|
||||
* as the other bcsel branch. This will allow optimization to remove
|
||||
* the bcsel and we should then end up with a constant buffer index
|
||||
* like we need.
|
||||
*/
|
||||
b->cursor = nir_before_instr(&alu->instr);
|
||||
nir_def *copy = nir_mov(b, alu->src[copy_src_idx].src.ssa);
|
||||
nir_src_rewrite(&alu->src[null_src_idx].src, copy);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
v3d_nir_lower_null_pointers(nir_shader *s)
|
||||
{
|
||||
return nir_shader_intrinsics_pass(s, v3d_nir_lower_null_pointers_cb,
|
||||
nir_metadata_block_index |
|
||||
nir_metadata_dominance, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
v3d_lower_nir(struct v3d_compile *c)
|
||||
{
|
||||
|
|
@ -656,6 +731,7 @@ v3d_lower_nir(struct v3d_compile *c)
|
|||
0,
|
||||
glsl_get_natural_size_align_bytes);
|
||||
NIR_PASS(_, c->s, v3d_nir_lower_scratch);
|
||||
NIR_PASS(_, c->s, v3d_nir_lower_null_pointers);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue