[Mesa-dev] [PATCH 10/10] nir: evaluate loop terminator ior use when false

Timothy Arceri tarceri at itsqueeze.com
Wed Jul 11 06:48:17 UTC 2018


This allows some loops to unroll were they are guaranteed to
exit after the first iteration. For example:

	loop {
		block block_1:
		/* preds: block_0 block_13 */
		vec1 32 ssa_85 = load_const (0x00000002 /* 0.000000 */)
		vec1 32 ssa_86 = ieq ssa_48, ssa_85
		vec1 32 ssa_87 = load_const (0x00000001 /* 0.000000 */)
		vec1 32 ssa_88 = ieq ssa_48, ssa_87
		vec1 32 ssa_89 = ior ssa_86, ssa_88
		vec1 32 ssa_90 = ieq ssa_48, ssa_0
		vec1 32 ssa_91 = ior ssa_89, ssa_90

		/* succs: block_2 block_3 */
		if ssa_86 {
			block block_2:
			/* preds: block_1 */
			 ...
			break
			/* succs: block_14 */
		} else {
			block block_3:
			/* preds: block_1 */
			/* succs: block_4 */
		}
		block block_4:
		/* preds: block_3 */
		/* succs: block_5 block_6 */
		if ssa_88 {
			block block_5:
			/* preds: block_4 */
			 ...
			break
			/* succs: block_14 */
		} else {
			block block_6:
			/* preds: block_4 */
			/* succs: block_7 */
		}
		block block_7:
		/* preds: block_6 */
		/* succs: block_8 block_9 */
		if ssa_90 {
			block block_8:
			/* preds: block_7 */
			 ...
			break
			/* succs: block_14 */
		} else {
			block block_9:
			/* preds: block_7 */
			/* succs: block_10 */
		}
		block block_10:
		/* preds: block_9 */
		vec1 32 ssa_107 = inot ssa_91
		/* succs: block_11 block_12 */
		if ssa_107 {
			block block_11:
			/* preds: block_10 */
			break
			/* succs: block_14 */
		} else {
			block block_12:
			/* preds: block_10 */
			/* succs: block_13 */
		}
	}

These loops have been seen in Bethesda games running over
DXVK. There is a slight increase in VGPR use but removing
the loops allows us to further optimise the code in
future. For example many of the unrolled if-statements
could now be merged as they apear in the shaders multiple
times.

vkpipeline results RADV (from a db of only 3 games):

Totals from affected shaders:
SGPRS: 10920 -> 10440 (-4.40 %)
VGPRS: 6120 -> 6264 (2.35 %)
Spilled SGPRs: 0 -> 0 (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: 369952 -> 356608 (-3.61 %) bytes
LDS: 0 -> 0 (0.00 %) blocks
Max Waves: 2040 -> 2040 (0.00 %)
Wait states: 0 -> 0 (0.00 %)
---
 src/compiler/nir/nir_opt_if.c | 38 +++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c
index 7b8085452ce..b3403f70a4e 100644
--- a/src/compiler/nir/nir_opt_if.c
+++ b/src/compiler/nir/nir_opt_if.c
@@ -525,6 +525,44 @@ opt_if_evaluate_condition_use_loop_terminator(nir_if *nif, nir_loop *loop,
                                            after_loop->index, NIR_TRUE,
                                            or_use, mem_ctx, true);
          }
+      } else if (nir_boolean == NIR_FALSE &&
+                 parent_instr->type == nir_instr_type_alu &&
+                 nir_instr_as_alu(parent_instr)->op == nir_op_ior) {
+
+         nir_alu_instr *alu = nir_instr_as_alu(parent_instr);
+
+         nir_src *other_or_src = NULL;
+         for (unsigned i = 0; i < 2; i++) {
+            if (alu->src[i].src.ssa != use_src->ssa) {
+               other_or_src = &alu->src[i].src;
+               break;
+            }
+         }
+         assert(other_or_src);
+
+         nir_foreach_use_safe(or_use, &alu->dest.dest.ssa) {
+            if (prev_block->index < or_use->parent_instr->block->index &&
+               after_loop->index > or_use->parent_instr->block->index) {
+
+               nir_instr_rewrite_src(or_use->parent_instr, or_use,
+                                     *other_or_src);
+               progress = true;
+            }
+         }
+
+         nir_foreach_if_use_safe(or_use, &alu->dest.dest.ssa) {
+            if (or_use->parent_if != nif) {
+               unsigned blk_idx_before_if =
+                  nir_cf_node_as_block(nir_cf_node_prev(
+                     &or_use->parent_if->cf_node))->index;
+
+               if (prev_block->index <= blk_idx_before_if &&
+                   after_loop->index > blk_idx_before_if) {
+                  nir_if_rewrite_condition(or_use->parent_if, *other_or_src);
+                  progress = true;
+               }
+            }
+         }
       } else {
          progress =
             evaluate_term_condition_use(prev_block->index, after_loop->index,
-- 
2.17.1



More information about the mesa-dev mailing list