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

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to