nir/licm: allow speculative hoisting across terminate if the filter is set

Reviewed-by: Daniel Schürmann <daniel@schuermann.dev>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41453>
This commit is contained in:
Marek Olšák 2026-05-11 09:22:13 -04:00 committed by Marge Bot
parent 3c2786b76a
commit feeaae1c28

View file

@ -9,6 +9,7 @@ typedef struct {
nir_opt_licm_filter_cb filter;
nir_loop *loop;
bool loop_has_terminate;
bool current_block_dominates_exit;
} licm_state;
@ -71,8 +72,10 @@ visit_block(nir_block *block, licm_state *state)
}
static bool
should_optimize_loop(nir_loop *loop)
should_optimize_loop(nir_loop *loop, licm_state *state)
{
state->loop_has_terminate = false;
/* Ignore loops without back-edge */
if (!nir_loop_has_back_edge(loop))
return false;
@ -83,8 +86,13 @@ should_optimize_loop(nir_loop *loop)
if (instr->type == nir_instr_type_intrinsic) {
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
if (intrin->intrinsic == nir_intrinsic_terminate ||
intrin->intrinsic == nir_intrinsic_terminate_if)
return false;
intrin->intrinsic == nir_intrinsic_terminate_if) {
state->loop_has_terminate = true;
/* The filter allows speculative hoisting across terminate. */
if (!state->filter)
return false;
}
}
}
@ -115,7 +123,8 @@ visit_cf_list(struct exec_list *list, licm_state *state)
*/
if (next && next->type == nir_cf_node_loop) {
nir_loop *inner_loop = nir_cf_node_as_loop(next);
optimize_loop = should_optimize_loop(inner_loop);
bool prev_loop_has_terminate = state->loop_has_terminate;
optimize_loop = should_optimize_loop(inner_loop, state);
if (optimize_loop) {
nir_loop *outer_loop = state->loop;
@ -125,11 +134,13 @@ visit_cf_list(struct exec_list *list, licm_state *state)
progress |= visit_cf_list(&inner_loop->continue_list, state);
state->loop = outer_loop;
}
state->loop_has_terminate = prev_loop_has_terminate;
}
nir_block *block = nir_cf_node_as_block(node);
if (state->loop) {
state->current_block_dominates_exit =
!state->loop_has_terminate &&
nir_block_dominates(block, nir_loop_successor_block(state->loop));
/* By only visiting blocks which dominate the block after the loop,