From 598928d7e75577832056826b205a34aeeffcc363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 25 Nov 2025 11:35:25 +0100 Subject: [PATCH] nir/loop_analyze: determine whether all control flow gets eliminated upon loop unrolling Totals from 17 (0.02% of 79839) affected shaders: (Navi48) MaxWaves: 241 -> 243 (+0.83%); split: +5.81%, -4.98% Instrs: 44198 -> 43786 (-0.93%); split: -8.19%, +7.26% CodeSize: 230284 -> 226900 (-1.47%); split: -10.55%, +9.08% VGPRs: 2152 -> 2524 (+17.29%); split: -3.90%, +21.19% Scratch: 718848 -> 0 (-inf%) Latency: 128977 -> 145720 (+12.98%); split: -2.12%, +15.10% InvThroughput: 206804 -> 254250 (+22.94%); split: -0.32%, +23.27% VClause: 1296 -> 1309 (+1.00%); split: -28.09%, +29.09% SClause: 835 -> 833 (-0.24%) Copies: 6284 -> 3630 (-42.23%); split: -44.51%, +2.28% Branches: 1003 -> 961 (-4.19%) PreSGPRs: 1003 -> 996 (-0.70%); split: -1.20%, +0.50% PreVGPRs: 1510 -> 2130 (+41.06%) VALU: 23577 -> 24309 (+3.10%); split: -6.26%, +9.37% SALU: 5875 -> 5688 (-3.18%); split: -6.26%, +3.08% VMEM: 3679 -> 3001 (-18.43%); split: -33.27%, +14.84% SMEM: 1632 -> 1631 (-0.06%) VOPD: 23 -> 24 (+4.35%) Part-of: --- src/compiler/nir/nir.h | 3 +++ src/compiler/nir/nir_loop_analyze.c | 11 +++++++++++ src/compiler/nir/nir_opt_loop_unroll.c | 3 +++ 3 files changed, 17 insertions(+) diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 90e1ab95ce1..b72f3c6e1fd 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -3444,6 +3444,9 @@ typedef struct nir_loop_info { /* Unroll the loop regardless of its size */ bool force_unroll; + /* Whether all control flow gets eliminated upon unrolling. */ + bool flattens_all_control_flow; + /* Does the loop contain complex loop terminators, continues or other * complex behaviours? If this is true we can't rely on * loop_terminator_list to be complete or accurate. diff --git a/src/compiler/nir/nir_loop_analyze.c b/src/compiler/nir/nir_loop_analyze.c index 641a798f242..65737f8f9f3 100644 --- a/src/compiler/nir/nir_loop_analyze.c +++ b/src/compiler/nir/nir_loop_analyze.c @@ -1405,6 +1405,8 @@ gather_constant_fold_info(loop_info_state *state, nir_instr *instr) static void gather_unroll_heuristic_info(loop_info_state *state, const nir_shader_compiler_options *options) { + state->loop->info->flattens_all_control_flow = state->loop->info->exact_trip_count_known; + nir_foreach_block_in_cf_node(block, &state->loop->cf_node) { /* Calculate instruction cost. */ nir_foreach_instr(instr, block) { @@ -1412,6 +1414,15 @@ gather_unroll_heuristic_info(loop_info_state *state, const nir_shader_compiler_o state->loop->info->instr_cost += instr_cost(state, instr, options); } + nir_if *nif = nir_block_get_following_if(block); + if (nif) { + /* If all IF statements can be constant-folded after unrolling, + * the loop becomes a single large basic block. + */ + state->loop->info->flattens_all_control_flow &= + is_const_after_unrolling(state, nif->condition.ssa); + } + if (state->loop->info->force_unroll) continue; diff --git a/src/compiler/nir/nir_opt_loop_unroll.c b/src/compiler/nir/nir_opt_loop_unroll.c index 8c193721b1c..84103f66e32 100644 --- a/src/compiler/nir/nir_opt_loop_unroll.c +++ b/src/compiler/nir/nir_opt_loop_unroll.c @@ -905,6 +905,9 @@ check_unrolling_restrictions(nir_shader *shader, nir_loop *loop) /* Unroll much more aggressively if it can hide load latency. */ if (shader->options->max_unroll_iterations_aggressive && can_pipeline_loads(loop)) max_iter = shader->options->max_unroll_iterations_aggressive; + /* Unroll much more aggressively if all control flow gets eliminated. */ + if (shader->options->max_unroll_iterations_aggressive && li->flattens_all_control_flow) + max_iter = shader->options->max_unroll_iterations_aggressive; /* Tune differently if the loop has double ops and soft fp64 is in use */ else if (shader->options->max_unroll_iterations_fp64 && loop->info->has_soft_fp64) max_iter = shader->options->max_unroll_iterations_fp64;