nir: remove unreachable loop terminators

Remove the conditional break statements associated with all
terminators that are associated with a fixed iteration count,
except for the one associated with the limiting terminator.

This logic matches similiar functionality that exists in the
old GLSL IR unrolling code.

This change helps a piglit test pass on the r300 driver once
we switch off the old GLSL IR unrolling code.

Shader-db results IRIS (BDW):

total instructions in shared programs: 17538619 -> 17538595 (<.01%)
instructions in affected programs: 216 -> 192 (-11.11%)
helped: 3
HURT: 0
helped stats (abs) min: 7 max: 10 x̄: 8.00 x̃: 7
helped stats (rel) min: 10.00% max: 12.07% x̄: 11.38% x̃: 12.07%

total cycles in shared programs: 858674910 -> 858672810 (<.01%)
cycles in affected programs: 79540 -> 77440 (-2.64%)
helped: 3
HURT: 0
helped stats (abs) min: 620 max: 800 x̄: 700.00 x̃: 680
helped stats (rel) min: 2.45% max: 2.83% x̄: 2.63% x̃: 2.62%

Reviewed-by: Emma Anholt <emma@anholt.net>
Reviewed-by: Jason Ekstrand <jason.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16399>
This commit is contained in:
Timothy Arceri 2022-05-09 20:20:26 +10:00 committed by Marge Bot
parent 4c3d138e5d
commit 0f98ed4afe

View file

@ -946,6 +946,43 @@ process_loops(nir_shader *sh, nir_cf_node *cf_node, bool *has_nested_loop_out,
*/
if (!progress && loop->control != nir_loop_control_dont_unroll) {
/* Remove the conditional break statements associated with all terminators
* that are associated with a fixed iteration count, except for the one
* associated with the limiting terminator--that one needs to stay, since
* it terminates the loop.
*/
if (loop->info->limiting_terminator) {
list_for_each_entry_safe(nir_loop_terminator, t,
&loop->info->loop_terminator_list,
loop_terminator_link) {
if (t->exact_trip_count_unknown)
continue;
if (t != loop->info->limiting_terminator) {
/* Only delete the if-statement if the continue block is empty.
* We trust that nir_opt_if() does its job well enough to
* remove all instructions from the continue block when possible.
*/
nir_block *first_continue_from_blk = t->continue_from_then ?
nir_if_first_then_block(t->nif) :
nir_if_first_else_block(t->nif);
if (!(nir_cf_node_is_last(&first_continue_from_blk->cf_node) &&
exec_list_is_empty(&first_continue_from_blk->instr_list)))
continue;
/* Now delete the if */
nir_cf_node_remove(&t->nif->cf_node);
/* Also remove it from the terminator list */
list_del(&t->loop_terminator_link);
progress = true;
}
}
}
/* Check for the classic
*
* do {