<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Dec 20, 2016 at 8:03 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:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Tue, 2016-12-20 at 15:14 -0800, Jason Ekstrand wrote:<br>
</span><div><div class="h5">> I did have a couple of "real" comments on this one that I'd like to<br>
> at least see a reply to. Does look pretty good though.<br>
><br>
> On Sun, Dec 18, 2016 at 9:47 PM, Timothy Arceri <timothy.arceri@colla<br>
> <a href="http://bora.com" rel="noreferrer" target="_blank">bora.com</a>> wrote:<br>
> > 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<br>
> > 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<br>
> > 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.<wbr>sources | 1 +<br>
> > src/compiler/nir/nir.c | 1 +<br>
> > src/compiler/nir/nir.h | 4 +<br>
> > src/compiler/nir/nir_to_<wbr>lcssa.c | 215<br>
> > ++++++++++++++++++++++++++++++<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<br>
> > 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<br>
> > phi nodes to<br>
> > * registers. If false, convert all values (even those not<br>
> > involved in a phi<br>
> > * node) to registers.<br>
> > diff --git a/src/compiler/nir/nir_to_<wbr>lcssa.c<br>
> > 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<br>
> > obtaining a<br>
> > + * copy of this software and associated documentation files (the<br>
> > "Software"),<br>
> > + * to deal in the Software without restriction, including without<br>
> > limitation<br>
> > + * the rights to use, copy, modify, merge, publish, distribute,<br>
> > sublicense,<br>
> > + * and/or sell copies of the Software, and to permit persons to<br>
> > whom the<br>
> > + * Software is furnished to do so, subject to the following<br>
> > conditions:<br>
> > + *<br>
> > + * The above copyright notice and this permission notice<br>
> > (including the next<br>
> > + * paragraph) shall be included in all copies or substantial<br>
> > portions of the<br>
> > + * Software.<br>
> > + *<br>
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,<br>
> > EXPRESS OR<br>
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF<br>
> > MERCHANTABILITY,<br>
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO<br>
> > EVENT SHALL<br>
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,<br>
> > DAMAGES OR OTHER<br>
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,<br>
> > ARISING<br>
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR<br>
> > OTHER DEALINGS<br>
> > + * IN THE SOFTWARE.<br>
> > + */<br>
> > +<br>
> > +/*<br>
> > + * This pass converts the ssa-graph into "Loop Closed SSA form".<br>
> > This is<br>
> > + * done by placing phi nodes at the exits of the loop for all<br>
> > 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-<br>
> > >cf_node));<br>
> > + if (prev_block->index <= block_before_loop->index ||<br>
> > + prev_block->index >= block_after_loop->index) {<br>
><br>
> I'm not sure you want "<=" and ">=" here. It seems like you either<br>
> want <= and nir_loop_first_block above or keep what you have above<br>
> and use <. As currently written, this will return true if it's used<br>
> in the block before or after the loop not just inside the loop.<br>
> <br>
> > + 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>
> > ||<br>
> > + use->parent_instr->block-><wbr>index >= block_after_loop->index)<br>
> > {<br>
><br>
> Same here<br>
> <br>
> > + 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-<br>
> > >cf_node));<br>
> > +<br>
> > + /* If a LCSSA-phi from a nested loop is use outside the parent<br>
> > loop there<br>
> > + * is no reason to create another LCSSA-phi for the parent<br>
> > loop.<br>
> > + */<br>
><br>
> I don't think this is true. The whole point of LCSSA is that no SSA<br>
> def declared inside a loop is able to escape the loop except through<br>
> a phi in the block after the loop. If it's an LCSSA phi from an<br>
> inner loop, I think you very much want it to have another phi for the<br>
> outer loop.<br>
> <br>
> > + 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>
><br>
> I'm silly but would you mind flipping this equality around? That way<br>
> the LHS is use->parent_instr->something for both clauses.<br>
> <br>
> > + 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>
><br>
> You don't need this. nir_instr_insert will set it for you.<br>
> <br>
> > + nir_ssa_dest_init(&phi-><wbr>instr, &phi->dest,<br>
> > + def->num_components, def->bit_size, "LCSSA-<br>
> > phi");<br>
> > + phi->is_lcssa_phi = true;<br>
> > +<br>
> > + /* Create a phi node with as many sources pointing to the same<br>
> > 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>
><br>
> This is not a lie. It really is the value we get coming in from that<br>
> predecessor.<br>
> <br>
> > +<br>
> > + exec_list_push_tail(&phi-><wbr>srcs, &phi_src->node);<br>
> > + }<br>
> > +<br>
> > + nir_instr_insert_before_<wbr>block(phi->instr.block, &phi->instr);<br>
> > +<br>
> > + /* Run through all uses and rewrite those outside the loop to<br>
> > 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-<br>
> > >dest.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,<br>
> > 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-<br>
> > >then_list)<br>
> > + convert_to_lcssa(nested_node, state);<br>
> > + foreach_list_typed(nir_cf_<wbr>node, nested_node, node, &if_stmt-<br>
> > >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-<br>
> > >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>
> > +}<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-<br>
> > >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>
><br>
> We have better iterators now! This and the whole convert_to_lcssa<br>
> function can be replaced with<br>
><br>
> nir_foreach_block_in_cf_node(<wbr>block, &loop->cf_node) {<br>
> nir_foreach_instr(instr, block)<br>
> nir_foreach_ssa_def(instr, convert_loop_exit_for_ssa, state);<br>
> }<br>
><br>
> Much simpler!<br>
<br>
</div></div>I don't think I can use that or we won't be setting state->loop<br></blockquote><div><br></div><div>Bummer. :(<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">
> <br>
> > +<br>
> > + ralloc_free(state);<br>
> > +}<br>
> > --<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>
> ><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>
</div></div></blockquote></div><br></div></div>