[Mesa-dev] [PATCH 2/2] nir: merge some basic consecutive ifs
Ian Romanick
idr at freedesktop.org
Tue Nov 27 18:27:12 UTC 2018
On 11/26/2018 09:31 PM, Timothy Arceri wrote:
> After trying multiple times to merge if-statements with phis
> between them I've come to the conclusion that it cannot be done
> without regressions. The problem is for some shaders we end up
> with a whole bunch of phis for the merged ifs resulting in
> increased register pressure.
>
> So this patch just merges ifs that have no phis between them.
> This seems to be consistent with what LLVM does so for radeonsi
> we only see a change (although its a large change) in a single
> shader.
>
> Shader-db results i965 (SKL):
>
> total instructions in shared programs: 13098176 -> 13098152 (<.01%)
> instructions in affected programs: 1326 -> 1302 (-1.81%)
> helped: 4
> HURT: 0
>
> total cycles in shared programs: 332032989 -> 332037583 (<.01%)
> cycles in affected programs: 60665 -> 65259 (7.57%)
> helped: 0
> HURT: 4
>
> The cycles estimates reported by shader-db for i965 seem inaccurate
> as the only difference in the final code is the removal of the
> redundent condition evaluations and jumps.
The scheduling doesn't even change? Whenever I've encountered things
like this, the scheduler has been to blame. It seems surprising that
only 4 shaders are affected. Are these all different instances of the
same shader? :)
> Also the biggest code reduction (~7%) for radeonsi was in a tomb
> raider tressfx shader but for some reason this does not get merged
> for i965.
>
> Shader-db results radeonsi (VEGA):
>
> Totals from affected shaders:
> SGPRS: 232 -> 232 (0.00 %)
> VGPRS: 164 -> 164 (0.00 %)
> Spilled SGPRs: 59 -> 59 (0.00 %)
> Spilled VGPRs: 0 -> 0 (0.00 %)
> Private memory VGPRs: 0 -> 0 (0.00 %)
> Scratch size: 0 -> 0 (0.00 %) dwords per thread
> Code Size: 14584 -> 13520 (-7.30 %) bytes
> LDS: 0 -> 0 (0.00 %) blocks
> Max Waves: 13 -> 13 (0.00 %)
> Wait states: 0 -> 0 (0.00 %)
> ---
> src/compiler/nir/nir_opt_if.c | 93 +++++++++++++++++++++++++++++++++++
> 1 file changed, 93 insertions(+)
>
> diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c
> index 62566eb403..dd488b1787 100644
> --- a/src/compiler/nir/nir_opt_if.c
> +++ b/src/compiler/nir/nir_opt_if.c
> @@ -585,6 +585,98 @@ opt_if_evaluate_condition_use(nir_builder *b, nir_if *nif)
> return progress;
> }
>
> +static void
> +simple_merge_if(nir_if *dest_if, nir_if *src_if, bool dest_if_then,
> + bool src_if_then)
> +{
> + /* Now merge the if branch */
> + nir_block *dest_blk = dest_if_then ? nir_if_last_then_block(dest_if)
> + : nir_if_last_else_block(dest_if);
> +
> + struct exec_list *list = src_if_then ? &src_if->then_list
> + : &src_if->else_list;
> +
> + nir_cf_list if_cf_list;
> + nir_cf_extract(&if_cf_list, nir_before_cf_list(list),
> + nir_after_cf_list(list));
> + nir_cf_reinsert(&if_cf_list, nir_after_block(dest_blk));
> +}
> +
> +static bool
> +opt_if_merge(nir_if *nif)
> +{
> + bool progress = false;
> +
> + nir_block *next_blk = nir_cf_node_cf_tree_next(&nif->cf_node);
> + if (next_blk && nif->condition.is_ssa) {
> + nir_if *next_if = nir_block_get_following_if(next_blk);
> + if (next_if && next_if->condition.is_ssa) {
> +
> + /* Here we merge two consecutive ifs that have the same
> + * condition e.g:
> + *
> + * if ssa_12 {
> + * ...
> + * } else {
> + * ...
> + * }
> + * if ssa_12 {
> + * ...
> + * } else {
> + * ...
> + * }
> + *
> + * Note: This only merges if-statements when the block between them
> + * is empty. The reason we don't try to merge ifs that just have phis
> + * between them is because this can results in increased register
> + * pressure. For example when merging if ladders created by indirect
> + * indexing.
> + */
> + if (nif->condition.ssa == next_if->condition.ssa &&
> + exec_list_is_empty(&next_blk->instr_list)) {
> +
> + simple_merge_if(nif, next_if, true, true);
> + simple_merge_if(nif, next_if, false, false);
> +
> + nir_block *new_then_block = nir_if_last_then_block(nif);
> + nir_block *new_else_block = nir_if_last_else_block(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);
> +
> + /* Rewrite the predecessor block for any phis following the second
> + * if-statement.
> + */
> + rewrite_phi_predecessor_blocks(next_if, old_then_block,
> + old_else_block,
> + new_then_block,
> + new_else_block);
> +
> + /* Move phis after merged if to avoid them being deleted when we
> + * remove the merged if-statement.
> + */
> + nir_block *after_next_if_block =
> + nir_cf_node_as_block(nir_cf_node_next(&next_if->cf_node));
> +
> + nir_foreach_instr_safe(instr, after_next_if_block) {
> + if (instr->type != nir_instr_type_phi)
> + break;
> +
> + exec_node_remove(&instr->node);
> + exec_list_push_tail(&next_blk->instr_list, &instr->node);
> + instr->block = next_blk;
> + }
> +
> + nir_cf_node_remove(&next_if->cf_node);
> +
> + progress = true;
> + }
> + }
> + }
> +
> + return progress;
> +}
> +
> static bool
> opt_if_cf_list(nir_builder *b, struct exec_list *cf_list)
> {
> @@ -599,6 +691,7 @@ opt_if_cf_list(nir_builder *b, struct exec_list *cf_list)
> progress |= opt_if_cf_list(b, &nif->then_list);
> progress |= opt_if_cf_list(b, &nif->else_list);
> progress |= opt_if_loop_terminator(nif);
> + progress |= opt_if_merge(nif);
> progress |= opt_if_simplification(b, nif);
> break;
> }
>
More information about the mesa-dev
mailing list