[Mesa-dev] [PATCH 02/10] nir: evaluate loop terminator condition uses

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


For simple loop terminators we can evaluate all further uses of the
condition in the loop because we know we must have either exited
the loop or we have a known value.

shader-db results IVB (all changes from dolphin uber shaders):

total instructions in shared programs: 10022822 -> 10018187 (-0.05%)
instructions in affected programs: 115380 -> 110745 (-4.02%)
helped: 54
HURT: 0

total cycles in shared programs: 232376154 -> 220065064 (-5.30%)
cycles in affected programs: 143176202 -> 130865112 (-8.60%)
helped: 54
HURT: 0

total spills in shared programs: 4383 -> 4370 (-0.30%)
spills in affected programs: 1656 -> 1643 (-0.79%)
helped: 9
HURT: 18

total fills in shared programs: 4610 -> 4581 (-0.63%)
fills in affected programs: 374 -> 345 (-7.75%)
helped: 6
HURT: 0
---
 src/compiler/nir/nir_opt_if.c | 115 ++++++++++++++++++++++++++++++++--
 1 file changed, 109 insertions(+), 6 deletions(-)

diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c
index 8863c42d9e7..83f2141dff6 100644
--- a/src/compiler/nir/nir_opt_if.c
+++ b/src/compiler/nir/nir_opt_if.c
@@ -430,6 +430,98 @@ opt_if_evaluate_condition_use(nir_if *nif, void *mem_ctx)
    return progress;
 }
 
+static bool
+evaluate_term_condition_use(unsigned prev_blk_idx,
+                            unsigned after_loop_blk_idx,
+                            unsigned nir_boolean,
+                            nir_src *use_src, void *mem_ctx,
+                            bool if_condition)
+{
+   bool progress = false;
+
+   if (if_condition) {
+      unsigned blk_idx_before_if =
+         nir_cf_node_as_block(nir_cf_node_prev(&use_src->parent_if->cf_node))->index;
+      if (prev_blk_idx <= blk_idx_before_if &&
+          after_loop_blk_idx > blk_idx_before_if) {
+         replace_if_condition_use_with_const(use_src, nir_boolean, mem_ctx,
+                                             if_condition);
+         progress = true;
+      }
+
+   } else {
+      unsigned use_blk_idx = use_src->parent_instr->block->index;
+      if (prev_blk_idx < use_blk_idx && after_loop_blk_idx > use_blk_idx) {
+         replace_if_condition_use_with_const(use_src, nir_boolean, mem_ctx,
+                                             if_condition);
+         progress = true;
+      }
+   }
+
+   return progress;
+}
+
+/**
+ * Since we know loop terminators either exit the loop or continue we can
+ * evaluate any further uses of the if-statements condition in the continue
+ * path.
+ */
+static bool
+opt_if_evaluate_condition_use_loop_terminator(nir_if *nif, nir_loop *loop,
+                                              void *mem_ctx)
+{
+   if (!loop)
+      return false;
+
+   nir_block *break_blk = NULL;
+   bool continue_from_then = true;
+
+   nir_block *last_then = nir_if_last_then_block(nif);
+   nir_block *last_else = nir_if_last_else_block(nif);
+
+   if (nir_block_ends_in_break(last_then)) {
+      break_blk = last_then;
+      continue_from_then = false;
+   } else if (nir_block_ends_in_break(last_else)) {
+      break_blk = last_else;
+   }
+
+   /* Continue if the if-statement contained no jumps at all */
+   if (!break_blk)
+      return false;
+
+   if (!nir_is_trivial_loop_if(nif, break_blk))
+      return false;
+
+   const unsigned nir_boolean = continue_from_then ? NIR_TRUE : NIR_FALSE;
+   bool progress = false;
+
+   nir_block *prev_block =
+      nir_cursor_current_block(nir_before_cf_node(&nif->cf_node));
+
+   nir_block *after_loop =
+      nir_cursor_current_block(nir_after_cf_node(&loop->cf_node));
+
+   /* Evaluate any uses of the loop terminator condition */
+   assert(nif->condition.is_ssa);
+   nir_foreach_use_safe(use_src, nif->condition.ssa) {
+      progress =
+         evaluate_term_condition_use(prev_block->index, after_loop->index,
+                                     nir_boolean, use_src, mem_ctx, false);
+   }
+
+   nir_foreach_if_use_safe(use_src, nif->condition.ssa) {
+      if (use_src->parent_if != nif) {
+         progress =
+            evaluate_term_condition_use(prev_block->index, after_loop->index,
+                                        nir_boolean, use_src, mem_ctx, true);
+      }
+   }
+
+
+   return progress;
+}
+
 static bool
 opt_if_cf_list(nir_builder *b, struct exec_list *cf_list)
 {
@@ -468,9 +560,11 @@ opt_if_cf_list(nir_builder *b, struct exec_list *cf_list)
  * not do anything to cause the metadata to become invalid.
  */
 static bool
-opt_if_safe_cf_list(nir_builder *b, struct exec_list *cf_list, void *mem_ctx)
+opt_if_safe_cf_list(nir_builder *b, struct exec_list *cf_list,
+                    nir_loop *curr_loop, void *mem_ctx)
 {
    bool progress = false;
+
    foreach_list_typed(nir_cf_node, cf_node, node, cf_list) {
       switch (cf_node->type) {
       case nir_cf_node_block:
@@ -478,15 +572,23 @@ opt_if_safe_cf_list(nir_builder *b, struct exec_list *cf_list, void *mem_ctx)
 
       case nir_cf_node_if: {
          nir_if *nif = nir_cf_node_as_if(cf_node);
-         progress |= opt_if_safe_cf_list(b, &nif->then_list, mem_ctx);
-         progress |= opt_if_safe_cf_list(b, &nif->else_list, mem_ctx);
+         progress |= opt_if_safe_cf_list(b, &nif->then_list, curr_loop,
+                                         mem_ctx);
+         progress |= opt_if_safe_cf_list(b, &nif->else_list, curr_loop,
+                                         mem_ctx);
          progress |= opt_if_evaluate_condition_use(nif, mem_ctx);
+         progress |= opt_if_evaluate_condition_use_loop_terminator(nif,
+                                                                   curr_loop,
+                                                                   mem_ctx);
          break;
       }
 
       case nir_cf_node_loop: {
-         nir_loop *loop = nir_cf_node_as_loop(cf_node);
-         progress |= opt_if_safe_cf_list(b, &loop->body, mem_ctx);
+         nir_loop *prev_loop = curr_loop;
+         nir_loop *curr_loop = nir_cf_node_as_loop(cf_node);
+         progress |= opt_if_safe_cf_list(b, &curr_loop->body, curr_loop,
+                                         mem_ctx);
+         curr_loop = prev_loop;
          break;
       }
 
@@ -513,7 +615,8 @@ nir_opt_if(nir_shader *shader)
       void *mem_ctx = ralloc_parent(function->impl);
 
       nir_metadata_require(function->impl, nir_metadata_block_index);
-      progress = opt_if_safe_cf_list(&b, &function->impl->body, mem_ctx);
+      progress = opt_if_safe_cf_list(&b, &function->impl->body, NULL,
+                                     mem_ctx);
       nir_metadata_preserve(function->impl, nir_metadata_block_index);
 
       if (opt_if_cf_list(&b, &function->impl->body)) {
-- 
2.17.1



More information about the mesa-dev mailing list