nir/deref: Elide loads/stores from deref cast of undef

These can never be meaningful. DOOM: The Dark Ages also relies on this.

Cc: mesa-stable
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40799>
This commit is contained in:
Natalie Vock 2026-04-14 12:33:45 +02:00 committed by Marge Bot
parent 118b975ce7
commit 57f796752d

View file

@ -922,6 +922,30 @@ nir_deref_instr_fixup_child_types(nir_deref_instr *parent)
}
}
static bool
opt_propagate_undef_cast(nir_builder *b, nir_deref_instr *deref)
{
if (deref->deref_type != nir_deref_type_struct &&
deref->deref_type != nir_deref_type_array &&
deref->deref_type != nir_deref_type_cast &&
deref->deref_type != nir_deref_type_ptr_as_array)
return false;
/* If we chase an deref originating from an undef pointer, propagate the undef through
* the chain.
*/
nir_deref_instr *parent = nir_def_as_deref_or_null(deref->parent.ssa);
if (!parent || parent->deref_type != nir_deref_type_cast ||
!nir_src_is_undef(parent->parent))
return false;
b->cursor = nir_before_instr(&deref->instr);
nir_deref_instr *new_deref = nir_build_deref_cast(b, parent->parent.ssa, deref->modes,
deref->type, 0);
nir_def_replace(&deref->def, &new_deref->def);
return true;
}
static bool
opt_alu_of_cast(nir_alu_instr *alu)
{
@ -1406,6 +1430,34 @@ opt_store_vec_deref(nir_builder *b, nir_intrinsic_instr *store)
return false;
}
static bool
opt_load_undef_deref(nir_builder *b, nir_intrinsic_instr *load)
{
nir_deref_instr *parent = nir_def_as_deref_or_null(load->src[0].ssa);
if (!parent || parent->deref_type != nir_deref_type_cast ||
!nir_src_is_undef(parent->parent))
return false;
b->cursor = nir_before_instr(&load->instr);
nir_def *undef = nir_undef(b, load->def.num_components, load->def.bit_size);
nir_def_replace(&load->def, undef);
return true;
}
static bool
opt_store_undef_deref(nir_builder *b, nir_intrinsic_instr *store)
{
nir_deref_instr *parent = nir_def_as_deref_or_null(store->src[0].ssa);
if (!parent || parent->deref_type != nir_deref_type_cast ||
!nir_src_is_undef(parent->parent))
return false;
nir_instr_remove(&store->instr);
return true;
}
static bool
opt_known_deref_mode_is(nir_builder *b, nir_intrinsic_instr *intrin)
{
@ -1454,6 +1506,11 @@ nir_opt_deref_impl(nir_function_impl *impl)
if (opt_restrict_deref_modes(deref))
progress = true;
if (opt_propagate_undef_cast(&b, deref)) {
progress = true;
break;
}
switch (deref->deref_type) {
case nir_deref_type_ptr_as_array:
if (opt_deref_ptr_as_array(&b, deref))
@ -1478,11 +1535,15 @@ nir_opt_deref_impl(nir_function_impl *impl)
case nir_intrinsic_load_deref:
if (opt_load_vec_deref(&b, intrin))
progress = true;
if (opt_load_undef_deref(&b, intrin))
progress = true;
break;
case nir_intrinsic_store_deref:
if (opt_store_vec_deref(&b, intrin))
progress = true;
if (opt_store_undef_deref(&b, intrin))
progress = true;
break;
case nir_intrinsic_deref_mode_is: