From 96cde7784624de4a376bebe8f030681d302aa85b Mon Sep 17 00:00:00 2001 From: Danylo Piliaiev Date: Thu, 16 Jul 2020 21:09:08 +0300 Subject: [PATCH] nir/opt_if: Fix opt_if_simplification when else branch has jump Consider the following case: if ssa_1 { block block_2: /* succs: block_4 */ } else { block block_3: ... break /* succs: block_5 */ } block block_4: vec1 32 ssa_100 = phi block_2: ssa_2 After block_3 extraction and reinsertion, phi->pred becomes invalid and isn't updated by reinsertion since it is unreachable from block_3. Call nir_opt_remove_phis_block before moving block to eliminate single source phis after the if. Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/3282 Fixes: e3e929f8c342b32dc8f5296adf8fb337866fa40a Signed-off-by: Danylo Piliaiev Reviewed-by: Matt Turner Reviewed-by: Timothy Arceri Part-of: (cherry picked from commit 6f94b3da111f65a46126fdb3652474dc4d9cbda5) --- .pick_status.json | 2 +- src/compiler/nir/nir_opt_if.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.pick_status.json b/.pick_status.json index edd8863022e..9d56b2caefd 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -67,7 +67,7 @@ "description": "nir/opt_if: Fix opt_if_simplification when else branch has jump", "nominated": true, "nomination_type": 1, - "resolution": 0, + "resolution": 1, "master_sha": null, "because_sha": "e3e929f8c342b32dc8f5296adf8fb337866fa40a" }, diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c index 4ba63de9275..d1be3518877 100644 --- a/src/compiler/nir/nir_opt_if.c +++ b/src/compiler/nir/nir_opt_if.c @@ -933,6 +933,17 @@ opt_if_simplification(nir_builder *b, nir_if *nif) nir_block *then_block = nir_if_last_then_block(nif); nir_block *else_block = nir_if_last_else_block(nif); + if (nir_block_ends_in_jump(else_block)) { + /* Even though this if statement has a jump on one side, we may still have + * phis afterwards. Single-source phis can be produced by loop unrolling + * or dead control-flow passes and are perfectly legal. Run a quick phi + * removal on the block after the if to clean up any such phis. + */ + nir_block *const next_block = + nir_cf_node_as_block(nir_cf_node_next(&nif->cf_node)); + nir_opt_remove_phis_block(next_block); + } + rewrite_phi_predecessor_blocks(nif, then_block, else_block, else_block, then_block);