diff --git a/src/compiler/nir/nir_opt_licm.c b/src/compiler/nir/nir_opt_licm.c index b2b67823cb3..a563c74bebf 100644 --- a/src/compiler/nir/nir_opt_licm.c +++ b/src/compiler/nir/nir_opt_licm.c @@ -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,