nir: fix O(N^2) behaviour in nir_remove_dead_variables

..where N = # of functions in the shader. We were accidentally reprocessing the
whole shader for every function impl. Noticed when reading a vtn_bindgen2
profile.

We elect to port the relevant part of the pass to instrctions_pass which fixes
the perf problem while deleting a pile of code.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Reviewed-by: Georg Lehmann <dadschoorse@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33245>
This commit is contained in:
Alyssa Rosenzweig 2025-01-27 12:22:26 -05:00 committed by Marge Bot
parent 8357ef588f
commit 54879582b4

View file

@ -26,6 +26,7 @@
*/
#include "nir.h"
#include "nir_builder.h"
static bool
deref_used_for_not_store(nir_deref_instr *deref)
@ -105,52 +106,40 @@ add_var_use_shader(nir_shader *shader, struct set *live, nir_variable_mode modes
}
}
static void
remove_dead_var_writes(nir_shader *shader)
static bool
remove_dead_var_writes(nir_builder *b, nir_instr *instr, void *_)
{
nir_foreach_function_impl(impl, shader) {
nir_foreach_block(block, impl) {
nir_foreach_instr_safe(instr, block) {
switch (instr->type) {
case nir_instr_type_deref: {
nir_deref_instr *deref = nir_instr_as_deref(instr);
if (deref->deref_type == nir_deref_type_cast &&
!nir_deref_instr_parent(deref))
continue;
if (instr->type == nir_instr_type_deref) {
nir_deref_instr *deref = nir_instr_as_deref(instr);
if (deref->deref_type == nir_deref_type_cast &&
!nir_deref_instr_parent(deref))
return false;
nir_variable_mode parent_modes;
if (deref->deref_type == nir_deref_type_var)
parent_modes = deref->var->data.mode;
else
parent_modes = nir_deref_instr_parent(deref)->modes;
nir_variable_mode parent_modes;
if (deref->deref_type == nir_deref_type_var)
parent_modes = deref->var->data.mode;
else
parent_modes = nir_deref_instr_parent(deref)->modes;
/* If the parent mode is 0, then it references a dead variable.
* Flag this deref as dead and remove it.
*/
if (parent_modes == 0) {
deref->modes = 0;
nir_instr_remove(&deref->instr);
}
break;
}
/* If the parent mode is 0, then it references a dead variable.
* Flag this deref as dead and remove it.
*/
if (parent_modes != 0)
return false;
case nir_instr_type_intrinsic: {
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
if (intrin->intrinsic != nir_intrinsic_copy_deref &&
intrin->intrinsic != nir_intrinsic_store_deref)
break;
if (nir_src_as_deref(intrin->src[0])->modes == 0)
nir_instr_remove(instr);
break;
}
default:
break; /* Nothing to do */
}
}
}
deref->modes = 0;
} else if (instr->type == nir_instr_type_intrinsic) {
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
if (!(intrin->intrinsic == nir_intrinsic_copy_deref ||
intrin->intrinsic == nir_intrinsic_store_deref) ||
nir_src_as_deref(intrin->src[0])->modes != 0)
return false;
} else {
return false;
}
nir_instr_remove(instr);
return true;
}
static bool
@ -205,13 +194,11 @@ nir_remove_dead_variables(nir_shader *shader, nir_variable_mode modes,
_mesa_set_destroy(live, NULL);
nir_foreach_function_impl(impl, shader) {
if (progress) {
remove_dead_var_writes(shader);
nir_metadata_preserve(impl, nir_metadata_control_flow);
} else {
nir_metadata_preserve(impl, nir_metadata_all);
}
if (progress) {
nir_shader_instructions_pass(shader, remove_dead_var_writes,
nir_metadata_control_flow, NULL);
} else {
nir_shader_preserve_all_metadata(shader);
}
return progress;