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:

committed by
Marge Bot

parent
7be8d0f7f4
commit
e379b9ad8c
@@ -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. */
|
||||
|
Reference in New Issue
Block a user