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;