<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Wed, Aug 29, 2018 at 6:48 PM Timothy Arceri <<a href="mailto:tarceri@itsqueeze.com">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">v2:<br>
 - only allow nir_op_inot or nir_op_b2i when alu input is 1.<br>
 - use some helpers as suggested by Jason.<br>
<br>
v3:<br>
 - evaluate alu op for single input alu ops<br>
 - add helper function to decide if to propagate through alu<br>
 - make use of nir_before_src in another spot<br>
<br>
shader-db IVB results:<br>
<br>
total instructions in shared programs: 9993483 -> 9993472 (-0.00%)<br>
instructions in affected programs: 1300 -> 1289 (-0.85%)<br>
helped: 11<br>
HURT: 0<br>
<br>
total cycles in shared programs: 219476091 -> 219476059 (-0.00%)<br>
cycles in affected programs: 7675 -> 7643 (-0.42%)<br>
helped: 10<br>
HURT: 1<br>
---<br>
 src/compiler/nir/nir_opt_if.c | 145 ++++++++++++++++++++++++++++++++--<br>
 1 file changed, 139 insertions(+), 6 deletions(-)<br>
<br>
diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c<br>
index 11c6693d302..9e9d8edda21 100644<br>
--- a/src/compiler/nir/nir_opt_if.c<br>
+++ b/src/compiler/nir/nir_opt_if.c<br>
@@ -23,6 +23,7 @@<br>
<br>
 #include "nir.h"<br>
 #include "nir/nir_builder.h"<br>
+#include "nir_constant_expressions.h"<br>
 #include "nir_control_flow.h"<br>
 #include "nir_loop_analyze.h"<br>
<br>
@@ -403,9 +404,127 @@ evaluate_if_condition(nir_if *nif, nir_cursor cursor, uint32_t *value)<br>
    }<br>
 }<br>
<br>
+/*<br>
+ * This propagates if condition evaluation down the chain of some alu<br>
+ * instructions. For example by checking the use of some of the following alu<br>
+ * instruction we can eventually replace ssa_107 with NIR_TRUE.<br>
+ *<br>
+ *   loop {<br>
+ *      block block_1:<br>
+ *      vec1 32 ssa_85 = load_const (0x00000002)<br>
+ *      vec1 32 ssa_86 = ieq ssa_48, ssa_85<br>
+ *      vec1 32 ssa_87 = load_const (0x00000001)<br>
+ *      vec1 32 ssa_88 = ieq ssa_48, ssa_87<br>
+ *      vec1 32 ssa_89 = ior ssa_86, ssa_88<br>
+ *      vec1 32 ssa_90 = ieq ssa_48, ssa_0<br>
+ *      vec1 32 ssa_91 = ior ssa_89, ssa_90<br>
+ *      if ssa_86 {<br>
+ *         block block_2:<br>
+ *             ...<br>
+ *            break<br>
+ *      } else {<br>
+ *            block block_3:<br>
+ *      }<br>
+ *      block block_4:<br>
+ *      if ssa_88 {<br>
+ *            block block_5:<br>
+ *             ...<br>
+ *            break<br>
+ *      } else {<br>
+ *            block block_6:<br>
+ *      }<br>
+ *      block block_7:<br>
+ *      if ssa_90 {<br>
+ *            block block_8:<br>
+ *             ...<br>
+ *            break<br>
+ *      } else {<br>
+ *            block block_9:<br>
+ *      }<br>
+ *      block block_10:<br>
+ *      vec1 32 ssa_107 = inot ssa_91<br>
+ *      if ssa_107 {<br>
+ *            block block_11:<br>
+ *            break<br>
+ *      } else {<br>
+ *            block block_12:<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>
+propagate_condition_eval(nir_builder *b, nir_if *nif, nir_src *use_src,<br>
+                         nir_src *alu_use, nir_alu_instr *alu, void *mem_ctx,<br>
+                         bool is_if_condition)<br>
+{<br>
+   bool progress = false;<br>
+<br>
+   uint32_t bool_value;<br>
+   b->cursor = nir_before_src(alu_use, is_if_condition);<br>
+   if (nir_op_infos[alu->op].num_inputs == 1) {<br>
+      assert(alu->op == nir_op_inot || alu->op == nir_op_b2i);<br>
+<br>
+      if (evaluate_if_condition(nif, b->cursor, &bool_value)) {<br>
+         nir_const_value bool_src;<br>
+         bool_src.u32[0] = bool_value;<br></blockquote><div><br></div><div>Since you're just going to put bool_value in bool_src and const_value below, why not just have bool_value be a nir_const_value and do evaluate_if_condition(nif, b->cursor, &bool_value.u32[0]) and be done with it?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+         unsigned bit_size = nir_src_bit_size(alu->src[0].src);<br></blockquote><div><br></div><div>This had better be 32 or we're toast because we're assuming a uint32_t the whole time.  Maybe make this an assert instead?<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+         nir_const_value result =<br>
+            nir_eval_const_opcode(alu->op, 1, bit_size, &bool_src);<br>
+<br>
+         replace_if_condition_use_with_const(alu_use, mem_ctx, b->cursor,<br>
+                                             result.u32[0], is_if_condition);<br>
+         progress = true;<br>
+      }<br>
+   } else {<br>
+      assert(alu->op == nir_op_ior || alu->op == nir_op_iand);<br>
+<br>
+      if (evaluate_if_condition(nif, b->cursor, &bool_value)) {<br>
+         nir_ssa_def *def[2];<br>
+         for (unsigned i = 0; i < 2; i++) {<br>
+            if (alu->src[i].src.ssa == use_src->ssa) {<br>
+               nir_const_value const_value;<br>
+               const_value.u32[0] = bool_value;<br>
+<br>
+               def[i] = nir_build_imm(b, 1, 32, const_value);<br></blockquote><div><br></div><div>We assume 32 here, for instance.</div><div><br></div><div>With the above two clean-ups,</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">
+            } else {<br>
+               def[i] = alu->src[i].src.ssa;<br>
+            }<br>
+         }<br>
+<br>
+         nir_ssa_def *nalu =<br>
+            nir_build_alu(b, alu->op, def[0], def[1], NULL, NULL);<br>
+<br>
+         /* Rewrite use to use new alu instruction */<br>
+         nir_src new_src = nir_src_for_ssa(nalu);<br>
+<br>
+         if (is_if_condition)<br>
+            nir_if_rewrite_condition(alu_use->parent_if, new_src);<br>
+         else<br>
+            nir_instr_rewrite_src(alu_use->parent_instr, alu_use, new_src);<br>
+<br>
+         progress = true;<br>
+      }<br>
+   }<br>
+<br>
+   return progress;<br>
+}<br>
+<br>
+static bool<br>
+can_propagate_through_alu(nir_src *src)<br>
+{<br>
+   if (src->parent_instr->type == nir_instr_type_alu &&<br>
+       (nir_instr_as_alu(src->parent_instr)->op == nir_op_ior ||<br>
+        nir_instr_as_alu(src->parent_instr)->op == nir_op_iand ||<br>
+        nir_instr_as_alu(src->parent_instr)->op == nir_op_inot ||<br>
+        nir_instr_as_alu(src->parent_instr)->op == nir_op_b2i))<br>
+      return true;<br>
+<br>
+   return false;<br>
+}<br>
+<br>
+static bool<br>
+evaluate_condition_use(nir_builder *b, nir_if *nif, nir_src *use_src,<br>
+                       void *mem_ctx, bool is_if_condition)<br>
 {<br>
    bool progress = false;<br>
<br>
@@ -417,23 +536,37 @@ evaluate_condition_use(nir_if *nif, nir_src *use_src, void *mem_ctx,<br>
       progress = true;<br>
    }<br>
<br>
+   if (!is_if_condition && can_propagate_through_alu(use_src)) {<br>
+      nir_alu_instr *alu = nir_instr_as_alu(use_src->parent_instr);<br>
+<br>
+      nir_foreach_use_safe(alu_use, &alu->dest.dest.ssa) {<br>
+         progress |= propagate_condition_eval(b, nif, use_src, alu_use, alu,<br>
+                                              mem_ctx, false);<br>
+      }<br>
+<br>
+      nir_foreach_if_use_safe(alu_use, &alu->dest.dest.ssa) {<br>
+         progress |= propagate_condition_eval(b, nif, use_src, alu_use, alu,<br>
+                                              mem_ctx, true);<br>
+      }<br>
+   }<br>
+<br>
    return progress;<br>
 }<br>
<br>
 static bool<br>
-opt_if_evaluate_condition_use(nir_if *nif, void *mem_ctx)<br>
+opt_if_evaluate_condition_use(nir_builder *b, 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>
+      progress |= evaluate_condition_use(b, 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>
+         progress |= evaluate_condition_use(b, nif, use_src, mem_ctx, true);<br>
    }<br>
<br>
    return progress;<br>
@@ -489,7 +622,7 @@ opt_if_safe_cf_list(nir_builder *b, struct exec_list *cf_list, void *mem_ctx)<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>
+         progress |= opt_if_evaluate_condition_use(b, nif, mem_ctx);<br>
          break;<br>
       }<br>
<br>
-- <br>
2.17.1<br>
<br>
</blockquote></div></div>