From e379b9ad8c37edb4a583aefa876ab5f11a36b572 Mon Sep 17 00:00:00 2001 From: Konstantin Seurer Date: Sat, 20 May 2023 21:57:57 +0200 Subject: [PATCH] nir/opt_dead_cf: Handle if statements ending in a jump correctly If a then/else block ends in a jump, the phi nodes do not necessarily have to reference the always taken branch because they are dead code. Avoid crashing in this case by only rewriting phis, if the block does not end in a jump. cc: mesa-stable Reviewed-by: Rhys Perry Part-of: --- src/compiler/nir/nir_opt_dead_cf.c | 46 ++++++++++++++---------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/compiler/nir/nir_opt_dead_cf.c b/src/compiler/nir/nir_opt_dead_cf.c index 4d7c3337332..8458b84c28b 100644 --- a/src/compiler/nir/nir_opt_dead_cf.c +++ b/src/compiler/nir/nir_opt_dead_cf.c @@ -83,39 +83,37 @@ remove_after_cf_node(nir_cf_node *node) static void opt_constant_if(nir_if *if_stmt, bool condition) { - /* First, we need to remove any phi nodes after the if by rewriting uses to - * point to the correct source. - */ - nir_block *after = nir_cf_node_as_block(nir_cf_node_next(&if_stmt->cf_node)); nir_block *last_block = condition ? nir_if_last_then_block(if_stmt) : nir_if_last_else_block(if_stmt); - nir_foreach_phi_safe(phi, after) { - nir_ssa_def *def = NULL; - nir_foreach_phi_src(phi_src, phi) { - if (phi_src->pred != last_block) - continue; - - assert(phi_src->src.is_ssa); - def = phi_src->src.ssa; - } - - assert(def); - assert(phi->dest.is_ssa); - nir_ssa_def_rewrite_uses(&phi->dest.ssa, def); - nir_instr_remove(&phi->instr); - } - /* The control flow list we're about to paste in may include a jump at the * end, and in that case we have to delete the rest of the control flow * list after the if since it's unreachable and the validator will balk if * we don't. */ - if (!exec_list_is_empty(&last_block->instr_list)) { - nir_instr *last_instr = nir_block_last_instr(last_block); - if (last_instr->type == nir_instr_type_jump) - remove_after_cf_node(&if_stmt->cf_node); + if (nir_block_ends_in_jump(last_block)) { + remove_after_cf_node(&if_stmt->cf_node); + } else { + /* Remove any phi nodes after the if by rewriting uses to point to the + * correct source. + */ + nir_block *after = nir_cf_node_as_block(nir_cf_node_next(&if_stmt->cf_node)); + nir_foreach_phi_safe(phi, after) { + nir_ssa_def *def = NULL; + nir_foreach_phi_src(phi_src, phi) { + if (phi_src->pred != last_block) + continue; + + assert(phi_src->src.is_ssa); + def = phi_src->src.ssa; + } + + assert(def); + assert(phi->dest.is_ssa); + nir_ssa_def_rewrite_uses(&phi->dest.ssa, def); + nir_instr_remove(&phi->instr); + } } /* Finally, actually paste in the then or else branch and delete the if. */