From daa38c1972efe1ca26f9fdc94806fd7f0be5f3fa Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Fri, 15 May 2026 16:00:51 -0700 Subject: [PATCH] nir/opt_if: Merge if-statements with inverted conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cases like if (x) { ... } else { ... } if (!x) { ... } else { ... } should be merged. I don't know why Ice Lake is affected differetly by this commit. v2: Add implementation of srcs_equal_or_logical_inverse after bad rebase. That's what I get for rushing out an MR right before lunch. Noticed by Georg. shader-db: Lunar Lake No changes. All other Iris platforms had simlar results. (Meteor Lake shown) total cycles in shared programs: 882310108 -> 882311504 (<.01%) cycles in affected programs: 74306 -> 75702 (1.88%) helped: 4 HURT: 2 helped stats (abs) min: 2.0 max: 38.0 x̄: 11.00 x̃: 2 helped stats (rel) min: 0.02% max: 0.29% x̄: 0.09% x̃: 0.02% HURT stats (abs) min: 720.0 max: 720.0 x̄: 720.00 x̃: 720 HURT stats (rel) min: 5.27% max: 5.27% x̄: 5.27% x̃: 5.27% 95% mean confidence interval for cycles value: -163.75 629.08 95% mean confidence interval for cycles %-change: -1.21% 4.61% Inconclusive result (value mean confidence interval includes 0). fossil-db: All Intel platforms except Ice Lake had similar results. (Lunar Lake shown) Totals: Instrs: 914554534 -> 914546744 (-0.00%); split: -0.00%, +0.00% CodeSize: 12887129264 -> 12886823808 (-0.00%); split: -0.00%, +0.00% Send messages: 40220826 -> 40219429 (-0.00%); split: -0.00%, +0.00% Cycle count: 100101810976 -> 100101804762 (-0.00%); split: -0.00%, +0.00% Spill count: 3459811 -> 3459786 (-0.00%); split: -0.00%, +0.00% Fill count: 4909877 -> 4909835 (-0.00%); split: -0.00%, +0.00% Max live registers: 191837229 -> 191838000 (+0.00%); split: -0.00%, +0.00% Max dispatch width: 48514400 -> 48514336 (-0.00%) Non SSA regs after NIR: 136346777 -> 136343948 (-0.00%); split: -0.00%, +0.00% Totals from 1937 (0.10% of 2003486) affected shaders: Instrs: 3013550 -> 3005760 (-0.26%); split: -0.39%, +0.13% CodeSize: 43169072 -> 42863616 (-0.71%); split: -0.81%, +0.10% Send messages: 183171 -> 181774 (-0.76%); split: -0.82%, +0.06% Cycle count: 126864798 -> 126858584 (-0.00%); split: -0.67%, +0.67% Spill count: 7354 -> 7329 (-0.34%); split: -0.45%, +0.11% Fill count: 5547 -> 5505 (-0.76%); split: -0.88%, +0.13% Max live registers: 296895 -> 297666 (+0.26%); split: -0.04%, +0.30% Max dispatch width: 41856 -> 41792 (-0.15%) Non SSA regs after NIR: 545672 -> 542843 (-0.52%); split: -1.15%, +0.63% Ice Lake Totals: Instrs: 996341606 -> 996312120 (-0.00%); split: -0.00%, +0.00% CodeSize: 12563695936 -> 12563195200 (-0.00%); split: -0.00%, +0.00% Send messages: 45911343 -> 45909063 (-0.00%); split: -0.00%, +0.00% Cycle count: 82819362995 -> 82818778468 (-0.00%); split: -0.00%, +0.00% Spill count: 2935451 -> 2935452 (+0.00%); split: -0.00%, +0.00% Fill count: 5034267 -> 5034281 (+0.00%); split: -0.00%, +0.00% Max live registers: 124672355 -> 124672961 (+0.00%); split: -0.00%, +0.00% Max dispatch width: 41330808 -> 41330672 (-0.00%) Non SSA regs after NIR: 160790466 -> 160785863 (-0.00%); split: -0.01%, +0.00% Totals from 2163 (0.09% of 2327905) affected shaders: Instrs: 4164788 -> 4135302 (-0.71%); split: -0.80%, +0.09% CodeSize: 53351344 -> 52850608 (-0.94%); split: -0.95%, +0.01% Send messages: 271164 -> 268884 (-0.84%); split: -0.84%, +0.00% Cycle count: 145818114 -> 145233587 (-0.40%); split: -0.66%, +0.26% Spill count: 7819 -> 7820 (+0.01%); split: -0.32%, +0.33% Fill count: 7191 -> 7205 (+0.19%); split: -0.57%, +0.76% Max live registers: 192403 -> 193009 (+0.31%); split: -0.08%, +0.40% Max dispatch width: 34728 -> 34592 (-0.39%) Non SSA regs after NIR: 570874 -> 566271 (-0.81%); split: -1.49%, +0.68% Reviewed-by: Georg Lehmann Part-of: --- src/compiler/nir/nir_opt_if.c | 43 +++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c index f44ce7149ce..15427fbddb8 100644 --- a/src/compiler/nir/nir_opt_if.c +++ b/src/compiler/nir/nir_opt_if.c @@ -1279,13 +1279,17 @@ opt_if_phi_src_unused(nir_builder *b, nir_if *nif) } static void -rewrite_phi_uses(nir_phi_instr *phi, nir_if *prev_if, nir_if *next_if) +rewrite_phi_uses(nir_phi_instr *phi, nir_if *prev_if, nir_if *next_if, + bool inverse) { nir_def *then_src = nir_phi_get_src_from_block(phi, nir_if_last_then_block(prev_if))->src.ssa; nir_def *else_src = nir_phi_get_src_from_block(phi, nir_if_last_else_block(prev_if))->src.ssa; + if (inverse) + SWAP(then_src, else_src); + /* Rewrite all uses inside the next IF with either then_src or else_src. */ nir_foreach_use_including_if_safe(use, &phi->def) { nir_cf_node *node = &nir_src_get_block(use)->cf_node; @@ -1313,6 +1317,30 @@ rewrite_phi_uses(nir_phi_instr *phi, nir_if *prev_if, nir_if *next_if) } } +static bool +srcs_equal_or_logical_inverse(nir_src src1, nir_src src2, bool *inverse) +{ + *inverse = false; + if (nir_srcs_equal(src1, src2)) + return true; + + nir_alu_instr *alu; + + alu = nir_src_as_alu(src1); + if (alu != NULL && alu->op == nir_op_inot) { + *inverse = nir_srcs_equal(alu->src[0].src, src2); + return *inverse; + } + + alu = nir_src_as_alu(src2); + if (alu != NULL && alu->op == nir_op_inot) { + *inverse = nir_srcs_equal(alu->src[0].src, src1); + return *inverse; + } + + return false; +} + static bool opt_if_merge(nir_if *nif) { @@ -1321,7 +1349,9 @@ opt_if_merge(nir_if *nif) return false; nir_if *next_if = nir_block_get_following_if(next_blk); - if (!next_if || !nir_srcs_equal(nif->condition, next_if->condition)) + bool inverse = false; + if (!next_if || !srcs_equal_or_logical_inverse(nif->condition, + next_if->condition, &inverse)) return false; /* This optimization isn't made to work in this case and @@ -1355,7 +1385,7 @@ opt_if_merge(nir_if *nif) * with the phi source from the respective branch leg of the * previous IF. */ - rewrite_phi_uses(phi, nif, next_if); + rewrite_phi_uses(phi, nif, next_if, inverse); } /* Here we merge two consecutive ifs that have the same condition e.g: @@ -1374,8 +1404,8 @@ opt_if_merge(nir_if *nif) * Note: This only merges if-statements when the block between them is * empty except for phis. */ - simple_merge_if(nif, next_if, true, true); - simple_merge_if(nif, next_if, false, false); + simple_merge_if(nif, next_if, true, !inverse); + simple_merge_if(nif, next_if, false, inverse); nir_block *new_then_block = nir_if_last_then_block(nif); nir_block *new_else_block = nir_if_last_else_block(nif); @@ -1383,6 +1413,9 @@ opt_if_merge(nir_if *nif) nir_block *old_then_block = nir_if_last_then_block(next_if); nir_block *old_else_block = nir_if_last_else_block(next_if); + if (inverse) + SWAP(new_then_block, new_else_block); + /* Rewrite the predecessor block for any phis following the second * if-statement. */