<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Sep 16, 2016 at 6:24 AM, Timothy Arceri <span dir="ltr"><<a href="mailto:timothy.arceri@collabora.com" target="_blank">timothy.arceri@collabora.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Thomas Helland <<a href="mailto:thomashelland90@gmail.com">thomashelland90@gmail.com</a>><br>
<br>
V2: Do a "depth first search" to convert to LCSSA<br>
<br>
V3: Small comment fixup<br>
<br>
V4: Rebase, adapt to removal of function overloads<br>
<br>
V5: Rebase, adapt to relocation of nir to compiler/nir<br>
    Still need to adapt to potential if-uses<br>
    Work around nir_validate issue<br>
<br>
V6 (Timothy):<br>
 - tidy lcssa and stop leaking memory<br>
 - dont rewrite the src for the lcssa phi node<br>
 - validate lcssa phi srcs to avoid postvalidate assert<br>
 - don't add new phi if one already exists<br>
 - more lcssa phi validation fixes<br>
 - Rather than marking ssa defs inside a loop just mark blocks inside<br>
   a loop. This is simpler and fixes lcssa for intrinsics which do<br>
   not have a destination.<br>
 - don't create LCSSA phis for loops we won't unroll<br>
 - require loop metadata for lcssa pass<br>
 - handle case were the ssa defs use outside the loop is already a phi<br>
<br>
V7: (Timothy)<br>
- pass indirect mask to metadata call<br>
---<br>
 src/compiler/Makefile.sources   |   1 +<br>
 src/compiler/nir/nir.h          |   6 ++<br>
 src/compiler/nir/nir_to_lcssa.<wbr>c | 227 ++++++++++++++++++++++++++++++<wbr>++++++++++<br>
 src/compiler/nir/nir_validate.<wbr>c |  11 +-<br>
 4 files changed, 242 insertions(+), 3 deletions(-)<br>
 create mode 100644 src/compiler/nir/nir_to_lcssa.<wbr>c<br>
<br>
diff --git a/src/compiler/Makefile.<wbr>sources b/src/compiler/Makefile.<wbr>sources<br>
index 7ed26a9..8ef6080 100644<br>
--- a/src/compiler/Makefile.<wbr>sources<br>
+++ b/src/compiler/Makefile.<wbr>sources<br>
@@ -247,6 +247,7 @@ NIR_FILES = \<br>
        nir/nir_search_helpers.h \<br>
        nir/nir_split_var_copies.c \<br>
        nir/nir_sweep.c \<br>
+       nir/nir_to_lcssa.c \<br>
        nir/nir_to_ssa.c \<br>
        nir/nir_validate.c \<br>
        nir/nir_vla.h \<br>
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h<br>
index cc8f4b6..29a6f45 100644<br>
--- a/src/compiler/nir/nir.h<br>
+++ b/src/compiler/nir/nir.h<br>
@@ -1387,6 +1387,8 @@ typedef struct {<br>
    struct exec_list srcs; /** < list of nir_phi_src */<br>
<br>
    nir_dest dest;<br>
+<br>
+   bool is_lcssa_phi;<br>
 } nir_phi_instr;<br>
<br>
 typedef struct {<br>
@@ -2643,6 +2645,10 @@ void nir_convert_to_ssa(nir_shader *shader);<br>
 bool nir_repair_ssa_impl(nir_<wbr>function_impl *impl);<br>
 bool nir_repair_ssa(nir_shader *shader);<br>
<br>
+void nir_to_lcssa_impl(nir_<wbr>function_impl *impl,<br>
+                       nir_variable_mode indirect_mask);<br>
+void nir_to_lcssa(nir_shader *shader, nir_variable_mode indirect_mask);<br>
+<br>
 /* If phi_webs_only is true, only convert SSA values involved in phi nodes to<br>
  * registers.  If false, convert all values (even those not involved in a phi<br>
  * node) to registers.<br>
diff --git a/src/compiler/nir/nir_to_<wbr>lcssa.c b/src/compiler/nir/nir_to_<wbr>lcssa.c<br>
new file mode 100644<br>
index 0000000..25d0bdb<br>
--- /dev/null<br>
+++ b/src/compiler/nir/nir_to_<wbr>lcssa.c<br>
@@ -0,0 +1,227 @@<br>
+/*<br>
+ * Copyright © 2015 Thomas Helland<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS<br>
+ * IN THE SOFTWARE.<br>
+ */<br>
+<br>
+/*<br>
+ * This pass converts the ssa-graph into "Loop Closed SSA form". This is<br>
+ * done by placing phi nodes at the exits of the loop for all values<br>
+ * that are used outside the loop. The result is it transforms:<br>
+ *<br>
+ * loop {                    ->      loop {<br>
+ *    ssa2 = ....            ->          ssa2 = ...<br>
+ *    if (cond)              ->          if (cond) {<br>
+ *       break;              ->             break;<br>
+ *    ssa3 = ssa2 * ssa4     ->          }<br>
+ * }                         ->          ssa3 = ssa2 * ssa4<br>
+ * ssa6 = ssa2 + 4           ->       }<br>
+ *                                    ssa5 = lcssa_phi(ssa2)<br>
+ *                                    ssa6 = ssa5 + 4<br>
+ */<br></blockquote><div><br></div><div>Let me make sure I understand this correctly.  The point here seems to be to ensure that SSA defs can never escape a loop without going through a phi.  Correct?  This can happen if the ssa def, for whatever reason, dominates all of the breaks in the loop.  In that case, it will dominate the block after the loop and can go through without a phi.  This raises a question: Is there any real difference between an LCSSA phi and a regular phi?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+#include "nir.h"<br>
+<br>
+typedef struct {<br>
+   /* The nir_shader we are transforming */<br>
+   nir_shader *shader;<br>
+<br>
+   /* The loop we store information for */<br>
+   nir_loop *loop;<br>
+<br>
+   /* Keep track of which defs are in the loop */<br>
+   BITSET_WORD *is_in_loop;<br>
+<br>
+   /* General purpose bool */<br>
+   bool flag;<br>
+} lcssa_state;<br>
+<br>
+static void<br>
+mark_block_as_in_loop(nir_<wbr>block *blk, void *state)<br>
+{<br>
+   lcssa_state *state_cast = (lcssa_state *) state;<br>
+   BITSET_SET(state_cast->is_in_<wbr>loop, blk->index);<br>
+}<br>
+<br>
+static void<br>
+is_block_outside_loop(nir_<wbr>block *blk, void *void_state)<br>
+{<br>
+   lcssa_state *state = void_state;<br>
+   if (!BITSET_TEST(state->is_in_<wbr>loop, blk->index)) {<br>
+      state->flag = true;<br>
+   }<br>
+}<br></blockquote><div><br></div><div>These helpers aren't really needed anymore (they probably were prior to better block iteration) and I think they're just confusing.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+static bool<br>
+convert_loop_exit_for_ssa(<wbr>nir_ssa_def *def, void *void_state)<br>
+{<br>
+   lcssa_state *state = void_state;<br>
+<br>
+   state->flag = false;<br>
+<br>
+   nir_block *block_after_loop =<br>
+      nir_cf_node_as_block(nir_cf_<wbr>node_next(&state->loop->cf_<wbr>node));<br>
+<br>
+   nir_foreach_use_safe(src, def) {<br>
+      if (src->parent_instr->type == nir_instr_type_phi &&<br>
+          (block_after_loop->index == src->parent_instr->block-><wbr>index ||<br></blockquote><div><br></div><div>You should be able to just compare the block pointers.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+           nir_instr_as_phi(src->parent_<wbr>instr)->is_lcssa_phi))<br></blockquote><div><br></div><div>I don't think you need this check.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+         continue;<br>
+<br>
+      is_block_outside_loop(src-><wbr>parent_instr->block, void_state);<br>
+   }<br>
+<br>
+   /* There where no sources that had defs outside the loop */<br>
+   if (!state->flag)<br>
+      return true;<br>
+<br>
+   /* Initialize a phi-instruction */<br>
+   nir_phi_instr *phi = nir_phi_instr_create(state-><wbr>shader);<br>
+   phi->instr.block = block_after_loop;<br>
+   nir_ssa_dest_init(&phi->instr, &phi->dest,<br>
+                     def->num_components, def->bit_size, "LCSSA-phi");<br>
+   phi->is_lcssa_phi = true;<br>
+<br>
+   /* Connect the ssa-def and the phi instruction */<br>
+   nir_phi_src *phi_src = ralloc(phi, nir_phi_src);<br>
+   phi_src->pred = def->parent_instr->block;<br></blockquote><div><br></div><div>Uh... I don't think this is what you want.  I think you want to place the phi in block_after_loop.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+   phi_src->src = nir_src_for_ssa(def);<br></blockquote><div><br></div><div>Is there any particular reason why we have this is_lcssa_phi flag?  Why don't we just create a regular phi node with as many sources as the block has predecessors and make them all point to the same ssa def?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+   exec_list_push_tail(&phi-><wbr>srcs, &phi_src->node);<br>
+<br>
+   nir_instr_insert_before_block(<wbr>phi->instr.block, &phi->instr);<br>
+<br>
+   /* Run through all uses and rewrite those outside the loop to point to<br>
+    * the phi instead of pointing to the ssa-def.<br>
+    */<br>
+   nir_foreach_use_safe(src, def) {<br>
+      state->flag = false;<br>
+<br>
+      if (src->parent_instr->type == nir_instr_type_phi &&<br>
+          (block_after_loop->index == src->parent_instr->block-><wbr>index ||<br>
+           nir_instr_as_phi(src->parent_<wbr>instr)->is_lcssa_phi))<br>
+         continue;<br></blockquote><div><br></div><div>How is this different from "src->parent_instr == &phi->instr"?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+      is_block_outside_loop(src-><wbr>parent_instr->block, state);<br>
+<br>
+      if (!state->flag)<br>
+         continue;<br></blockquote><div><br></div><div>Yeah, those helpers need to go.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+      nir_instr_rewrite_src(src-><wbr>parent_instr, src,<br>
+                            nir_src_for_ssa(&phi->dest.<wbr>ssa));<br>
+   }<br>
+<br>
+   return true;<br>
+}<br>
+<br>
+static void<br>
+convert_to_lcssa(nir_cf_node *cf_node, lcssa_state *state)<br>
+{<br>
+   switch (cf_node->type) {<br>
+   case nir_cf_node_block:<br>
+      nir_foreach_instr(instr, nir_cf_node_as_block(cf_node))<br>
+         nir_foreach_ssa_def(instr, convert_loop_exit_for_ssa, state);<br>
+      return;<br>
+   case nir_cf_node_if: {<br>
+      nir_if *if_stmt = nir_cf_node_as_if(cf_node);<br>
+      foreach_list_typed(nir_cf_<wbr>node, nested_node, node, &if_stmt->then_list)<br>
+         convert_to_lcssa(nested_node, state);<br>
+      foreach_list_typed(nir_cf_<wbr>node, nested_node, node, &if_stmt->else_list)<br>
+         convert_to_lcssa(nested_node, state);<br>
+      return;<br>
+   }<br>
+   case nir_cf_node_loop:<br>
+      /* Since we are going depth first the innermost loop will already have<br>
+       * been rewritten, and so there should be no defs inside the inner loop<br>
+       * that are not already rewritten with LCSSA-phis in our current loop.<br>
+       */<br></blockquote><div><br></div><div>I have a feeling your recursion here could be a bit simpler.  I'm not 100% sure how off-hand.  I'll think about it a bit.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      return;<br>
+   default:<br>
+      unreachable("unknown cf node type");<br>
+   }<br>
+}<br>
+<br>
+static void<br>
+compute_lcssa(nir_cf_node *cf_node, nir_function_impl *impl)<br>
+{<br>
+   nir_loop *loop;<br>
+<br>
+   switch (cf_node->type) {<br>
+   case nir_cf_node_block:<br>
+      return;<br>
+   case nir_cf_node_if: {<br>
+      nir_if *if_stmt = nir_cf_node_as_if(cf_node);<br>
+      foreach_list_typed(nir_cf_<wbr>node, nested_node, node, &if_stmt->then_list)<br>
+         compute_lcssa(nested_node, impl);<br>
+      foreach_list_typed(nir_cf_<wbr>node, nested_node, node, &if_stmt->else_list)<br>
+         compute_lcssa(nested_node, impl);<br>
+      return;<br>
+   }<br>
+   case nir_cf_node_loop:<br>
+      loop = nir_cf_node_as_loop(cf_node);<br>
+      foreach_list_typed(nir_cf_<wbr>node, nested_node, node, &loop->body)<br>
+         compute_lcssa(nested_node, impl);<br>
+      break;<br>
+   default:<br>
+      unreachable("unknown cf node type");<br>
+   }<br>
+<br>
+   if (loop->info->limiting_<wbr>terminator == NULL)<br>
+      return;<br>
+<br>
+   nir_function *fn = nir_cf_node_get_function(&<wbr>loop->cf_node)->function;<br>
+   if (!is_simple_loop(fn->shader, loop->info) &&<br>
+       !is_complex_loop(fn->shader, loop->info)) {<br>
+      return;<br>
+   }<br></blockquote><div><br></div><div>Why are the above two checks needed?  I don't really see why we need loop analysis for lcssa.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+   lcssa_state *state = rzalloc(NULL, lcssa_state);<br>
+   state->is_in_loop = rzalloc_array(state, BITSET_WORD,<br>
+                                     BITSET_WORDS(impl->ssa_alloc))<wbr>;<br>
+   state->loop = loop;<br>
+<br>
+   nir_foreach_block_in_cf_node(<wbr>block, cf_node) {<br>
+      mark_block_as_in_loop(block, state);<br>
+   }<br>
+<br>
+   foreach_list_typed(nir_cf_<wbr>node, node, node, &loop->body)<br>
+      convert_to_lcssa(node, state);<br>
+<br>
+   ralloc_free(state);<br>
+}<br>
+<br>
+void<br>
+nir_to_lcssa_impl(nir_<wbr>function_impl *impl, nir_variable_mode indirect_mask)<br>
+{<br>
+   nir_metadata_require(impl, nir_metadata_loop_analysis, indirect_mask);<br></blockquote><div><br></div><div>You need to also require block indices.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+   foreach_list_typed(nir_cf_<wbr>node, node, node, &impl->body)<br>
+      compute_lcssa(node, impl);<br>
+}<br>
+<br>
+void<br>
+nir_to_lcssa(nir_shader *shader, nir_variable_mode indirect_mask)<br>
+{<br>
+   nir_foreach_function(func, shader) {<br>
+      if (func->impl) {<br>
+         nir_to_lcssa_impl(func->impl, indirect_mask);<br>
+      }<br>
+   }<br>
+}<br>
diff --git a/src/compiler/nir/nir_<wbr>validate.c b/src/compiler/nir/nir_<wbr>validate.c<br>
index 60af715..9d1566c 100644<br>
--- a/src/compiler/nir/nir_<wbr>validate.c<br>
+++ b/src/compiler/nir/nir_<wbr>validate.c<br>
@@ -564,8 +564,13 @@ validate_phi_instr(nir_phi_<wbr>instr *instr, validate_state *state)<br>
    validate_dest(&instr->dest, state);<br>
<br>
    exec_list_validate(&instr-><wbr>srcs);<br>
-   validate_assert(state, exec_list_length(&instr->srcs) ==<br>
-          state->block->predecessors-><wbr>entries);<br>
+<br>
+   if (!instr->is_lcssa_phi) {<br>
+      validate_assert(state, exec_list_length(&instr->srcs) ==<br>
+             state->block->predecessors-><wbr>entries);<br>
+   } else {<br>
+      validate_assert(state, exec_list_length(&instr->srcs) == 1);<br>
+   }<br>
 }<br>
<br>
 static void<br>
@@ -624,7 +629,7 @@ validate_phi_src(nir_phi_instr *instr, nir_block *pred, validate_state *state)<br>
<br>
    exec_list_validate(&instr-><wbr>srcs);<br>
    nir_foreach_phi_src(src, instr) {<br>
-      if (src->pred == pred) {<br>
+      if (src->pred == pred || instr->is_lcssa_phi) {<br>
          validate_assert(state, src->src.is_ssa);<br>
          validate_assert(state, src->src.ssa->num_components ==<br>
                 instr->dest.ssa.num_<wbr>components);<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.7.4<br>
<br>
______________________________<wbr>_________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org">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/<wbr>mailman/listinfo/mesa-dev</a><br>
</font></span></blockquote></div><br></div></div>