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 <pendingchaos02@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23150>
This commit is contained in:
Konstantin Seurer
2023-05-20 21:57:57 +02:00
committed by Marge Bot
parent 7be8d0f7f4
commit e379b9ad8c

View File

@@ -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. */