mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 09:38:07 +02:00
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>
(cherry picked from commit e379b9ad8c)
This commit is contained in:
parent
44b0a656b4
commit
e4dd65fc4f
2 changed files with 27 additions and 29 deletions
|
|
@ -4729,7 +4729,7 @@
|
|||
"description": "nir/opt_dead_cf: Handle if statements ending in a jump correctly",
|
||||
"nominated": true,
|
||||
"nomination_type": 0,
|
||||
"resolution": 0,
|
||||
"resolution": 1,
|
||||
"main_sha": null,
|
||||
"because_sha": null
|
||||
},
|
||||
|
|
|
|||
|
|
@ -83,43 +83,41 @@ 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_instr_safe(instr, after) {
|
||||
if (instr->type != nir_instr_type_phi)
|
||||
break;
|
||||
|
||||
nir_phi_instr *phi = nir_instr_as_phi(instr);
|
||||
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(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_instr_safe(instr, after) {
|
||||
if (instr->type != nir_instr_type_phi)
|
||||
break;
|
||||
|
||||
nir_phi_instr *phi = nir_instr_as_phi(instr);
|
||||
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. */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue