<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Mon, Aug 27, 2018 at 4:09 AM Timothy Arceri <<a href="mailto:tarceri@itsqueeze.com" target="_blank">tarceri@itsqueeze.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Since we know what side of the branch we ended up on we can just<br>
replace the use with a constant.<br>
<br>
All the spill changes in shader-db are from Dolphin uber shaders,<br>
despite some small regressions the change is clearly positive.<br>
<br>
V2: insert new constant after any phis in the<br>
    use->parent_instr->type == nir_instr_type_phi path.<br>
<br>
v3:<br>
 - use nir_after_block_before_jump() for inserting const<br>
 - check dominance of phi uses correctly<br>
<br>
v4:<br>
 - create some helpers as suggested by Jason.<br>
<br>
shader-db results IVB:<br>
<br>
total instructions in shared programs: 9999201 -> 9993483 (-0.06%)<br>
instructions in affected programs: 163235 -> 157517 (-3.50%)<br>
helped: 132<br>
HURT: 2<br>
<br>
total cycles in shared programs: 231670754 -> 219476091 (-5.26%)<br>
cycles in affected programs: 143424120 -> 131229457 (-8.50%)<br>
helped: 115<br>
HURT: 24<br>
<br>
total spills in shared programs: 4383 -> 4370 (-0.30%)<br>
spills in affected programs: 1656 -> 1643 (-0.79%)<br>
helped: 9<br>
HURT: 18<br>
<br>
total fills in shared programs: 4610 -> 4581 (-0.63%)<br>
fills in affected programs: 374 -> 345 (-7.75%)<br>
helped: 6<br>
HURT: 0<br>
---<br>
 src/compiler/nir/nir.h        |  22 +++++++<br>
 src/compiler/nir/nir_opt_if.c | 113 ++++++++++++++++++++++++++++++++++<br>
 2 files changed, 135 insertions(+)<br>
<br>
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h<br>
index 009a6d60371..0caacd30173 100644<br>
--- a/src/compiler/nir/nir.h<br>
+++ b/src/compiler/nir/nir.h<br>
@@ -2331,6 +2331,28 @@ nir_after_block_before_jump(nir_block *block)<br>
    }<br>
 }<br>
<br>
+static inline nir_cursor<br>
+nir_before_src(nir_src *src, bool is_if_condition)<br>
+{<br>
+   if (is_if_condition) {<br>
+      nir_block *prev_block =<br>
+         nir_cf_node_as_block(nir_cf_node_prev(&src->parent_if->cf_node));<br>
+      assert(!nir_block_ends_in_jump(prev_block));<br>
+      return nir_after_block(prev_block);<br>
+   } else if (src->parent_instr->type == nir_instr_type_phi) {<br>
+      nir_phi_instr *cond_phi = nir_instr_as_phi(src->parent_instr);<br>
+      nir_foreach_phi_src(phi_src, cond_phi) {<br>
+         if (phi_src->src.ssa == src->ssa) {<br>
+            return nir_after_block_before_jump(phi_src->pred);<br>
+         }<br>
+      }<br></blockquote><div><br></div><div>This works.  Some sort of container_of would be more efficient.  I guess that wouldn't work if the source was a register indirect on a phi src but I don't think that's valid.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+      unreachable("failed to find phi src");<br></blockquote><div><br></div><div>If the source isn't a phi src (and container_of would fail) hitting an unreachable is really nasty.  I don't think we will hit this case but I also think that if we do, container_of is actually the safer option as weird as that sounds.  That said, we should do something to ensure that we get an assertion failure if it ever isn't the source of a phi.  What you did above works.  If we did container_of, we should add an assert loop somehow.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+   } else {<br>
+      return nir_before_instr(src->parent_instr);<br>
+   }<br>
+}<br>
+<br>
 static inline nir_cursor<br>
 nir_before_cf_node(nir_cf_node *node)<br>
 {<br>
diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c<br>
index dacf2d6c667..11c6693d302 100644<br>
--- a/src/compiler/nir/nir_opt_if.c<br>
+++ b/src/compiler/nir/nir_opt_if.c<br>
@@ -369,6 +369,76 @@ opt_if_loop_terminator(nir_if *nif)<br>
    return true;<br>
 }<br>
<br>
+static void<br>
+replace_if_condition_use_with_const(nir_src *use, void *mem_ctx,<br>
+                                    nir_cursor cursor, unsigned nir_boolean,<br></blockquote><div><br></div><div>Mind making nir_boolean a uint32_t?</div><div><br></div><div>With that (and regardless of what way we go with container_of above), this patch is</div><div><br></div><div>Reviewed-by: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+                                    bool if_condition)<br>
+{<br>
+   /* Create const */<br>
+   nir_load_const_instr *load = nir_load_const_instr_create(mem_ctx, 1, 32);<br>
+   load->value.u32[0] = nir_boolean;<br>
+   nir_instr_insert(cursor, &load->instr);<br>
+<br>
+   /* Rewrite use to use const */<br>
+   nir_src new_src = nir_src_for_ssa(&load->def);<br>
+<br>
+   if (if_condition)<br>
+      nir_if_rewrite_condition(use->parent_if, new_src);<br>
+   else<br>
+      nir_instr_rewrite_src(use->parent_instr, use, new_src);<br>
+}<br>
+<br>
+static bool<br>
+evaluate_if_condition(nir_if *nif, nir_cursor cursor, uint32_t *value)<br>
+{<br>
+   nir_block *use_block = nir_cursor_current_block(cursor);<br>
+   if (nir_block_dominates(nir_if_first_then_block(nif), use_block)) {<br>
+      *value = NIR_TRUE;<br>
+      return true;<br>
+   } else if (nir_block_dominates(nir_if_first_else_block(nif), use_block)) {<br>
+      *value = NIR_FALSE;<br>
+      return true;<br>
+   } else {<br>
+      return false;<br>
+   }<br>
+}<br>
+<br>
+static bool<br>
+evaluate_condition_use(nir_if *nif, nir_src *use_src, void *mem_ctx,<br>
+                       bool is_if_condition)<br>
+{<br>
+   bool progress = false;<br>
+<br>
+   uint32_t value;<br>
+   nir_cursor cursor = nir_before_src(use_src, is_if_condition);<br>
+   if (evaluate_if_condition(nif, cursor, &value)) {<br>
+      replace_if_condition_use_with_const(use_src, mem_ctx, cursor, value,<br>
+                                          is_if_condition);<br>
+      progress = true;<br>
+   }<br>
+<br>
+   return progress;<br>
+}<br>
+<br>
+static bool<br>
+opt_if_evaluate_condition_use(nir_if *nif, void *mem_ctx)<br>
+{<br>
+   bool progress = false;<br>
+<br>
+   /* Evaluate any uses of the if condition inside the if branches */<br>
+   assert(nif->condition.is_ssa);<br>
+   nir_foreach_use_safe(use_src, nif->condition.ssa) {<br>
+      progress |= evaluate_condition_use(nif, use_src, mem_ctx, false);<br>
+   }<br>
+<br>
+   nir_foreach_if_use_safe(use_src, nif->condition.ssa) {<br>
+      if (use_src->parent_if != nif)<br>
+         progress |= evaluate_condition_use(nif, use_src, mem_ctx, true);<br>
+   }<br>
+<br>
+   return progress;<br>
+}<br>
+<br>
 static bool<br>
 opt_if_cf_list(nir_builder *b, struct exec_list *cf_list)<br>
 {<br>
@@ -402,6 +472,41 @@ opt_if_cf_list(nir_builder *b, struct exec_list *cf_list)<br>
    return progress;<br>
 }<br>
<br>
+/**<br>
+ * These optimisations depend on nir_metadata_block_index and therefore must<br>
+ * not do anything to cause the metadata to become invalid.<br>
+ */<br>
+static bool<br>
+opt_if_safe_cf_list(nir_builder *b, struct exec_list *cf_list, void *mem_ctx)<br>
+{<br>
+   bool progress = false;<br>
+   foreach_list_typed(nir_cf_node, cf_node, node, cf_list) {<br>
+      switch (cf_node->type) {<br>
+      case nir_cf_node_block:<br>
+         break;<br>
+<br>
+      case nir_cf_node_if: {<br>
+         nir_if *nif = nir_cf_node_as_if(cf_node);<br>
+         progress |= opt_if_safe_cf_list(b, &nif->then_list, mem_ctx);<br>
+         progress |= opt_if_safe_cf_list(b, &nif->else_list, mem_ctx);<br>
+         progress |= opt_if_evaluate_condition_use(nif, mem_ctx);<br>
+         break;<br>
+      }<br>
+<br>
+      case nir_cf_node_loop: {<br>
+         nir_loop *loop = nir_cf_node_as_loop(cf_node);<br>
+         progress |= opt_if_safe_cf_list(b, &loop->body, mem_ctx);<br>
+         break;<br>
+      }<br>
+<br>
+      case nir_cf_node_function:<br>
+         unreachable("Invalid cf type");<br>
+      }<br>
+   }<br>
+<br>
+   return progress;<br>
+}<br>
+<br>
 bool<br>
 nir_opt_if(nir_shader *shader)<br>
 {<br>
@@ -414,6 +519,14 @@ nir_opt_if(nir_shader *shader)<br>
       nir_builder b;<br>
       nir_builder_init(&b, function->impl);<br>
<br>
+      void *mem_ctx = ralloc_parent(function->impl);<br>
+<br>
+      nir_metadata_require(function->impl, nir_metadata_block_index |<br>
+                           nir_metadata_dominance);<br>
+      progress = opt_if_safe_cf_list(&b, &function->impl->body, mem_ctx);<br>
+      nir_metadata_preserve(function->impl, nir_metadata_block_index |<br>
+                            nir_metadata_dominance);<br>
+<br>
       if (opt_if_cf_list(&b, &function->impl->body)) {<br>
          nir_metadata_preserve(function->impl, nir_metadata_none);<br>
<br>
-- <br>
2.17.1<br>
<br>
_______________________________________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org" target="_blank">mesa-dev@lists.freedesktop.org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev" rel="noreferrer" target="_blank">https://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</blockquote></div></div>