<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Oct 4, 2016 at 6:46 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"><div class="gmail-HOEnZb"><div class="gmail-h5">On Tue, 2016-10-04 at 16:47 -0700, Jason Ekstrand wrote:<br>
> On Fri, Sep 16, 2016 at 6:24 AM, 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>
> >  src/compiler/Makefile.<wbr>sources   |   1 +<br>
> >  src/compiler/nir/nir.h          |   6 ++<br>
> >  src/compiler/nir/nir_to_<wbr>lcssa.c | 227<br>
> > ++++++++++++++++++++++++++++++<wbr>++++++++++<br>
> >  src/compiler/nir/nir_<wbr>validate.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<br>
> > 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<br>
> > indirect_mask);<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..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<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     ->          }<br>
> > + * }                         ->          ssa3 = ssa2 * ssa4<br>
> > + * ssa6 = ssa2 + 4           ->       }<br>
> > + *                                    ssa5 = lcssa_phi(ssa2)<br>
> > + *                                    ssa6 = ssa5 + 4<br>
> > + */<br>
><br>
> Let me make sure I understand this correctly.  The point here seems<br>
> to be to ensure that SSA defs can never escape a loop without going<br>
> through a phi.  Correct?  This can happen if the ssa def, for<br>
> whatever reason, dominates all of the breaks in the loop.  In that<br>
> case, it will dominate the block after the loop and can go through<br>
> without a phi.  This raises a question: Is there any real difference<br>
> between an LCSSA phi and a regular phi?<br>
<br>
</div></div>There shouldn't be any real difference besides only having a single src<br>
which validation doesn't like. I guess I'll try the suggestion you make<br>
below, but I'm concerned I'll hit more validation problems.<br><div><div class="gmail-h5"></div></div></blockquote><div><br></div><div>Honestly, I'm surprised what you have now passes validation. :/  We really should be validating that a phi has a set of predecessors exactly equal to the predecessors of the block in which it lives.<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"><div><div class="gmail-h5">
>  <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>
> > +   /* 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>
><br>
> These helpers aren't really needed anymore (they probably were prior<br>
> to better block iteration) and I think they're just confusing.<br>
<br>
</div></div>Hmm. Your probably right. Thomas was originally checking inividual<br>
definitions rather than just using the blocks.</blockquote><div><br>What I meant is that the is_block_outside_loop 
helper made sense because it could be passed to nir_foreach_block.  Now 
that we have better block iteration, the helpers that set a flag in a 
struct passed in as a void * are just piles of wrapping that's just 
confusing.<br> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> Are you thinking<br>
something like:<br>
<br>
if (block_after_loop->index <= src->parent_instr->block-><wbr>index)<br>
  ... we are outside the loop ..<span class="gmail-"><br></span></blockquote><div><br></div><div>Actually, that would probably work and would save us some iteration.  I hadn't thought of that.<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"><span class="gmail-">
>  <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>
> > +<br>
> > +   state->flag = false;<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>
> > +   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-<br>
> > >index ||<br>
><br>
> You should be able to just compare the block pointers.<br>
>  <br>
> > +           nir_instr_as_phi(src->parent_<wbr>instr)->is_lcssa_phi))<br>
><br>
</span>> I don't think you need this check.expand<br>
<br>
As I say below I don't recall how this could already be an lcssa_phi<br>
but I recall removing it once before and it caused issues. Maybe nested<br>
loops although we shouldn't be touching those. I need to run some tests<br>
(and add comments this time around).<br>
<span class="gmail-"><br>
>  <br>
> > +         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-><wbr>instr, &phi->dest,<br>
> > +                     def->num_components, def->bit_size, "LCSSA-<br>
> > 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>
><br>
> Uh... I don't think this is what you want.  I think you want to place<br>
> the phi in block_after_loop.<br>
<br>
</span>??<br>
<br>
It is in the code below, this is setting the src pred to the block from<br>
the loop.<br>
<br>
   nir_instr_insert_before_<wbr>block(phi->instr.block, &phi->instr);<br>
<br>
Here phi->instr.block == block_after_loop.<span class="gmail-"><br></span></blockquote><div><br></div><div>Drp... I can't read.  Your code is fine. :-)<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"><span class="gmail-">
>  <br>
> > +   phi_src->src = nir_src_for_ssa(def);<br>
><br>
> Is there any particular reason why we have this is_lcssa_phi flag? <br>
> Why don't we just create a regular phi node with as many sources as<br>
> the block has predecessors and make them all point to the same ssa<br>
> def?<br>
<br>
</span>I guess that could work I'll give it a try. Although will that not<br>
cause some kind of validation problems? For example the ssa_def belongs<br>
to only one of the predecessors.<span class="gmail-"><br></span></blockquote><div><br></div><div>The only time you can get into a case where you're adding this phi is if you have the same ssa_def for all predecessors.  If that's not the case, then the ssa_def does not dominate the use and we'll have a phi in between anyway.  I don't think we have an issue there.<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"><span class="gmail-">
>  <br>
> > +<br>
> > +   exec_list_push_tail(&phi-><wbr>srcs, &phi_src->node);<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(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-<br>
> > >index ||<br>
> > +           nir_instr_as_phi(src->parent_<wbr>instr)->is_lcssa_phi))<br>
> > +         continue;<br>
><br>
> How is this different from "src->parent_instr == &phi->instr"?<br>
<br>
</span>That would check that the we are not trying to rewrite the use of the<br>
phi we just added as opposed to avoiding rewriting a use if it is an<br>
existing phi.<br></blockquote><div><br></div><div>Right.  However, I don't think you want the is_lcssa_phi.  You may have some other phi in block_after_loop that uses the ssa_def and you don't want to overwrite that.<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">
Although I'm starting to wonder how this could already be an lcssa_phi<br>
at this point. I'll need double check a few things, my mind has purged<br>
this from memory.<br></blockquote><div><br></div>I'm not sure if it could either...<br></div><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div class="gmail-h5">
>  <br>
> > +<br>
> > +      is_block_outside_loop(src-><wbr>parent_instr->block, state);<br>
> > +<br>
> > +      if (!state->flag)<br>
> > +         continue;<br>
><br>
> Yeah, those helpers need to go.<br>
>  <br>
> > +<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,<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>
> > +      /* Since we are going depth first the innermost loop will<br>
> > already have<br>
> > +       * been rewritten, and so there should be no defs inside the<br>
> > inner loop<br>
> > +       * that are not already rewritten with LCSSA-phis in our<br>
> > current loop.<br>
> > +       */<br>
><br>
> I have a feeling your recursion here could be a bit simpler.  I'm not<br>
> 100% sure how off-hand.  I'll think about it a bit.<br>
<br>
</div></div>Yeah I've had the same thoughts but this is what the original code did<br>
and I couldn't think of anything obvious so I just left it.<br>
<div><div class="gmail-h5"><br>
>  <br>
> > +      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-<br>
> > >then_list)<br>
> > +         compute_lcssa(nested_node, impl);<br>
> > +      foreach_list_typed(nir_cf_<wbr>node, nested_node, node, &if_stmt-<br>
> > >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-<br>
> > >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)-<br>
> > >function;<br>
> > +   if (!is_simple_loop(fn->shader, loop->info) &&<br>
> > +       !is_complex_loop(fn->shader, loop->info)) {<br>
> > +      return;<br>
> > +   }<br>
><br>
> Why are the above two checks needed?  I don't really see why we need<br>
> loop analysis for lcssa.<br>
<br>
</div></div>Well we need lcssa and loop analysis to do loop unrolling so why not<br>
skip lcssa is we can't unroll the loop?<br></blockquote><div><br></div><div>As I've been reviewing your series, I've been thinking about how we can decouple things.  Ideally, I'd like to have:<br><br></div><div> 1) A loop analysis pass that's pure analysis and doesn't make any real decisions<br></div><div> 2) A dumb LCSSA pass that just converts to LCSSA<br></div><div> 3) A "smart" loop unrolling pass that makes all of the decisions about what gets unrolled and does the unrolling<br><br></div><div>I'm not really happy with having all three be as tightly coupled as they are.  Maybe they need to be?  But I don't think so.<br><br></div><div>Another thought I had this morning was that maybe we would just want to convert to LCSSA on-demand one loop at a time as we unroll.  Looking at the algorithm, I don't think that would be terribly difficult and it would certainly solve both the progress problem and the "don't do unnecessary work" problem.  I'm not convinced it's a good idea, but it's a thought.<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">
Also if we remove the is_lcssa phi flag we would end up in an infinite<br>
loop of adding lcssa phis and removing them (see patch 6 which come to<br>
think of it might not be needed any longer since we already do this).<span class="gmail-"><br></span></blockquote><div><br></div><div>Right.  I'm ok with keeping the is_lcssa_phi flag for the sole purpose of proper progress reporting.  However, I'd like us to avoid making "special" phi nodes with different rules.<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"><span class="gmail-">
>  <br>
> > +<br>
> > +   lcssa_state *state = rzalloc(NULL, lcssa_state);<br>
> > +   state->is_in_loop = rzalloc_array(state, BITSET_WORD,<br>
> > +                                     BITSET_WORDS(impl-<br>
> > >ssa_alloc));<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<br>
> > indirect_mask)<br>
> > +{<br>
> > +   nir_metadata_require(impl, nir_metadata_loop_analysis,<br>
> > indirect_mask);<br>
><br>
> You need to also require block indices.<br>
<br>
</span>Will add.<br>
<div class="gmail-HOEnZb"><div class="gmail-h5"><br>
>  <br>
> > +<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<br>
> > 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,<br>
> > 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,<br>
> > 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>
> > --<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>
> ><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>