<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">I did have a couple of "real" comments on this one that I'd like to at least see a reply to.  Does look pretty good though.<br></div><div class="gmail_quote"><br>On Sun, Dec 18, 2016 at 9:47 PM, 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:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);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>
v8: (Timothy)<br>
- make convert to lcssa a helper function rather than a nir pass<br>
- replace inside loop bitset with on the fly block index logic.<br>
- remove lcssa phi validation special cases<br>
- inline code from useless helpers, suggested by Jason.<br>
- always do lcssa on loops, suggested by Jason.<br>
- stop making lcssa phis special. Add as many source as the block<br>
  has predecessors, suggested by Jason.<br>
<br>
V9: (Timothy)<br>
- fix regression with the is_lcssa_phi field not being initialised<br>
  to false now that ralloc() doesn't zero out memory.<br>
<br>
V10: (Timothy)<br>
- remove extra braces in SSA example, pointed out by Topi<br>
<br>
V11: (Timothy)<br>
- add missing support for LCSSA phis in if conditions.<br>
---<br>
 src/compiler/Makefile.sources   |   1 +<br>
 src/compiler/nir/nir.c          |   1 +<br>
 src/compiler/nir/nir.h          |   4 +<br>
 src/compiler/nir/nir_to_lcssa.<wbr>c | 215 ++++++++++++++++++++++++++++++<wbr>++++++++++<br>
 4 files changed, 221 insertions(+)<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 ca8a056..e8f7b02 100644<br>
--- a/src/compiler/Makefile.<wbr>sources<br>
+++ b/src/compiler/Makefile.<wbr>sources<br>
@@ -254,6 +254,7 @@ NIR_FILES = \<br>
        nir/nir_split_var_copies.c \<br>
        nir/nir_sweep.c \<br>
        nir/nir_to_ssa.c \<br>
+       nir/nir_to_lcssa.c \<br>
        nir/nir_validate.c \<br>
        nir/nir_vla.h \<br>
        nir/nir_worklist.c \<br>
diff --git a/src/compiler/nir/nir.c b/src/compiler/nir/nir.c<br>
index 2c3531c..e522a67 100644<br>
--- a/src/compiler/nir/nir.c<br>
+++ b/src/compiler/nir/nir.c<br>
@@ -561,6 +561,7 @@ nir_phi_instr_create(nir_<wbr>shader *shader)<br>
 {<br>
    nir_phi_instr *instr = ralloc(shader, nir_phi_instr);<br>
    instr_init(&instr->instr, nir_instr_type_phi);<br>
+   instr->is_lcssa_phi = false;<br>
<br>
    dest_init(&instr->dest);<br>
    exec_list_make_empty(&instr-><wbr>srcs);<br>
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h<br>
index 28010aa..75a91ea 100644<br>
--- a/src/compiler/nir/nir.h<br>
+++ b/src/compiler/nir/nir.h<br>
@@ -1360,6 +1360,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>
@@ -2526,6 +2528,8 @@ 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_convert_loop_to_lcssa(nir_<wbr>loop *loop);<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..8afdc54<br>
--- /dev/null<br>
+++ b/src/compiler/nir/nir_to_<wbr>lcssa.c<br>
@@ -0,0 +1,215 @@<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     ->          ssa3 = ssa2 * ssa4<br>
+ * }                         ->       }<br>
+ * ssa6 = ssa2 + 4           ->       ssa5 = lcssa_phi(ssa2)<br>
+ *                                    ssa6 = ssa5 + 4<br>
+ */<br>
+<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>
+} lcssa_state;<br>
+<br>
+static bool<br>
+is_if_use_inside_loop(nir_src *use, nir_loop* loop)<br>
+{<br>
+   nir_block *block_before_loop =<br>
+      nir_cf_node_as_block(nir_cf_<wbr>node_prev(&loop->cf_node));<br>
+   nir_block *block_after_loop =<br>
+      nir_cf_node_as_block(nir_cf_<wbr>node_next(&loop->cf_node));<br>
+<br>
+   nir_block *prev_block =<br>
+      nir_cf_node_as_block(nir_cf_<wbr>node_prev(&use->parent_if->cf_<wbr>node));<br>
+   if (prev_block->index <= block_before_loop->index ||<br>
+       prev_block->index >= block_after_loop->index) {<br></blockquote><div><br></div><div>I'm not sure you want "<=" and ">=" here.  It seems like you either want <= and nir_loop_first_block above or keep what you have above and use <.  As currently written, this will return true if it's used in the block before or after the loop not just inside the loop.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+      return false;<br>
+   }<br>
+<br>
+   return true;<br>
+}<br>
+<br>
+static bool<br>
+is_use_inside_loop(nir_src *use, nir_loop* loop)<br>
+{<br>
+   nir_block *block_before_loop =<br>
+      nir_cf_node_as_block(nir_cf_<wbr>node_prev(&loop->cf_node));<br>
+   nir_block *block_after_loop =<br>
+      nir_cf_node_as_block(nir_cf_<wbr>node_next(&loop->cf_node));<br>
+<br>
+   if (use->parent_instr->block-><wbr>index <= block_before_loop->index ||<br>
+       use->parent_instr->block-><wbr>index >= block_after_loop->index) {<br></blockquote><div><br></div><div>Same here<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+      return false;<br>
+   }<br>
+<br>
+   return true;<br>
+}<br>
+<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>
+   bool all_uses_inside_loop = true;<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>
+   /* If a LCSSA-phi from a nested loop is use outside the parent loop there<br>
+    * is no reason to create another LCSSA-phi for the parent loop.<br>
+    */<br></blockquote><div><br></div><div>I don't think this is true.  The whole point of LCSSA is that no SSA def declared inside a loop is able to escape the loop except through a phi in the block after the loop.  If it's an LCSSA phi from an inner loop, I think you very much want it to have another phi for the outer loop.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+   if (def->parent_instr->type == nir_instr_type_phi &&<br>
+       nir_instr_as_phi(def->parent_<wbr>instr)->is_lcssa_phi) {<br>
+      return true;<br>
+   }<br>
+<br>
+   nir_foreach_use(use, def) {<br>
+      if (use->parent_instr->type == nir_instr_type_phi &&<br>
+          block_after_loop == use->parent_instr->block) {<br></blockquote><div><br></div><div>I'm silly but would you mind flipping this equality around?  That way the LHS is use->parent_instr->something for both clauses.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+         continue;<br>
+      }<br>
+<br>
+      if (!is_use_inside_loop(use, state->loop)) {<br>
+         all_uses_inside_loop = false;<br>
+      }<br>
+   }<br>
+<br>
+   nir_foreach_if_use(use, def) {<br>
+      if (!is_if_use_inside_loop(use, state->loop)) {<br>
+         all_uses_inside_loop = false;<br>
+      }<br>
+   }<br>
+<br>
+   /* There where no sources that had defs outside the loop */<br>
+   if (all_uses_inside_loop)<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></blockquote><div><br></div><div>You don't need this.  nir_instr_insert will set it for you.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+   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>
+   /* Create a phi node with as many sources pointing to the same ssa_def as<br>
+    * the block has predecessors.<br>
+    */<br>
+   struct set_entry *entry;<br>
+   set_foreach(block_after_loop-><wbr>predecessors, entry) {<br>
+      nir_phi_src *phi_src = ralloc(phi, nir_phi_src);<br>
+      phi_src->src = nir_src_for_ssa(def);<br>
+<br>
+      /* This is a lie to pass validation */<br>
+      phi_src->pred = (nir_block *) entry->key;<br></blockquote><div><br></div><div>This is not a lie.  It really is the value we get coming in from that predecessor.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+      exec_list_push_tail(&phi-><wbr>srcs, &phi_src->node);<br>
+   }<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(use, def) {<br>
+      if (use->parent_instr->type == nir_instr_type_phi &&<br>
+          block_after_loop == use->parent_instr->block) {<br>
+         continue;<br>
+      }<br>
+<br>
+      if (!is_use_inside_loop(use, state->loop)) {<br>
+         nir_instr_rewrite_src(use-><wbr>parent_instr, use,<br>
+                               nir_src_for_ssa(&phi->dest.<wbr>ssa));<br>
+      }<br>
+   }<br>
+<br>
+   nir_foreach_if_use_safe(use, def) {<br>
+      if (!is_if_use_inside_loop(use, state->loop)) {<br>
+         nir_if_rewrite_condition(use-><wbr>parent_if,<br>
+                                  nir_src_for_ssa(&phi->dest.<wbr>ssa));<br>
+      }<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>
+      nir_loop *parent_loop = state->loop;<br>
+      state->loop = nir_cf_node_as_loop(cf_node);<br>
+<br>
+      foreach_list_typed(nir_cf_<wbr>node, nested_node, node, &state->loop->body)<br>
+         convert_to_lcssa(nested_node, state);<br>
+<br>
+      state->loop = parent_loop;<br>
+      return;<br>
+   }<br>
+   default:<br>
+      unreachable("unknown cf node type");<br>
+   } <br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+}<br>
+<br>
+void<br>
+nir_convert_loop_to_lcssa(<wbr>nir_loop *loop) {<br>
+   nir_function_impl *impl = nir_cf_node_get_function(&<wbr>loop->cf_node);<br>
+<br>
+   nir_metadata_require(impl, nir_metadata_block_index);<br>
+<br>
+   lcssa_state *state = rzalloc(NULL, lcssa_state);<br>
+   state->loop = loop;<br>
+   state->shader = impl->function->shader;<br>
+<br>
+   foreach_list_typed(nir_cf_<wbr>node, node, node, &state->loop->body)<br>
+      convert_to_lcssa(node, state);<br></blockquote><div><br><div>We have better iterators now!  This and the whole convert_to_lcssa function can be replaced with<br></div><div><br></div><div>nir_foreach_block_in_cf_node(block, &loop->cf_node) {<br></div><div>   nir_foreach_instr(instr, block)<br></div><div>      nir_foreach_ssa_def(instr, convert_loop_exit_for_ssa, state);<br></div>}<br><br></div><div>Much simpler!<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+   ralloc_free(state);<br>
+}<br>
<span class="gmail-HOEnZb"><font color="#888888">--<br>
2.9.3<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>