<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jan 14, 2015 at 1:05 PM, Connor Abbott <span dir="ltr"><<a href="mailto:cwabbott0@gmail.com" target="_blank">cwabbott0@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Wed, Jan 14, 2015 at 3:36 PM, Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> wrote:<br>
><br>
><br>
> On Fri, Jan 9, 2015 at 11:31 AM, Connor Abbott <<a href="mailto:cwabbott0@gmail.com">cwabbott0@gmail.com</a>> wrote:<br>
>><br>
>> On Tue, Jan 6, 2015 at 7:34 PM, Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br>
>> wrote:<br>
>> > Additional description was added to a variety of places.  Also, we no<br>
>> > longer use the term "leaf" to describe fully-qualified direct derefs.<br>
>> > Instead, we simply use the term "direct" or spell it out completely.<br>
>> > ---<br>
>> >  src/glsl/nir/nir_lower_variables.c | 103<br>
>> > +++++++++++++++++++++++++++----------<br>
>> >  1 file changed, 76 insertions(+), 27 deletions(-)<br>
>> ><br>
>> > diff --git a/src/glsl/nir/nir_lower_variables.c<br>
>> > b/src/glsl/nir/nir_lower_variables.c<br>
>> > index 6c3e6cc..085c6fe 100644<br>
>> > --- a/src/glsl/nir/nir_lower_variables.c<br>
>> > +++ b/src/glsl/nir/nir_lower_variables.c<br>
>> > @@ -53,12 +53,18 @@ struct lower_variables_state {<br>
>> >     /* A hash table mapping variables to deref_node data */<br>
>> >     struct hash_table *deref_var_nodes;<br>
>> ><br>
>> > -   /* A hash table mapping dereference leaves to deref_node data.  A<br>
>> > deref<br>
>> > -    * is considered a leaf if it is fully-qualified (no wildcards) and<br>
>> > -    * direct.  In short, these are the derefs we can actually consider<br>
>> > -    * lowering to SSA values.<br>
>> > +   /* A hash table mapping fully-qualified direct dereferences to<br>
>> > +    * deref_node data.<br>
>><br>
>> Since this is the first time you mention "fully-qualified direct<br>
>> dereferences" in the comments, I'd add a little explanation here e.g.<br>
>> "A hash table mapping fully-qualified direct dereferences, i.e.<br>
>> dereferences with no indirect or wildcard array dereferences, to<br>
>> deref_node data."<br>
>><br>
>> > +    *<br>
>> > +    * At the moment, we don't do anything interesting with variable<br>
>> > copy<br>
>> > +    * instructions other than splitting up wildcards and lowering them<br>
>> > to<br>
>> > +    * load/store instructions.  We only really care about lowering a<br>
>> > +    * particular deref to SSA values if it is used in a load or store<br>
>> > +    * operation.  Since wildcards can only occur in load/store<br>
>> > operations,<br>
>><br>
>> Copy operations?<br>
>><br>
>> > +    * the leaves are precicly the derefs we can actually consider<br>
>> > lowering<br>
>><br>
>> leaves?<br>
>><br>
>> > +    * to SSA values.<br>
>> >      */<br>
>><br>
>> Here's what I would say:<br>
>><br>
>> At the moment, we don't try and lower most variable copy instructions.<br>
>> We only lower loads, stores, and copies that can be trivially lowered<br>
>> to loads and stores, i.e. copies with no indirects and no wildcards.<br>
>> If a part of a variable that is being loaded from and/or stored into<br>
>> is also involved in a copy operation with wildcards, then we lower<br>
>> that copy operation to loads and stores, but otherwise we leave copies<br>
>> with wildcards alone. Since the only derefs used in these loads,<br>
>> stores, and trivial copies are ones with no wildcards and no<br>
>> indirects, these are precisely the derefs that we can actually<br>
>> consider lowering.<br>
><br>
><br>
> I fixed the minor things and more-or-less copied the above.  Anything else<br>
> that needs to be done?<br>
<br>
</div></div>There are a few things:<br>
<br>
- Remove the leftover comment above hash_deref() ("Some of the magic<br>
numbers here...")<br></blockquote><div><br></div><div>Consider it done<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
- Address my comment on the original lower_variables patch about<br>
directly looking up stuff in the hash table instead of calling<br>
get_deref_node().<br></blockquote><div><br></div><div>Just sent a cleanup patch<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
- Rename the entire thing.<br></blockquote><div><br></div><div>Did that in it's own patch.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
The middle one is the only one I'm not sure you'd agree to, but it<br>
seems pretty obvious to me. Anyways, once all that's done, then all<br>
the lower_variables patches are:<br>
<br>
Reviewed-by: Connor Abbott <<a href="mailto:cwabbott0@gmail.com">cwabbott0@gmail.com</a>><br>
<div class="HOEnZb"><div class="h5"><br>
><br>
>><br>
>><br>
>> > -   struct hash_table *deref_leaves;<br>
>> > +   struct hash_table *direct_deref_nodes;<br>
>> ><br>
>> >     /* A hash table mapping phi nodes to deref_state data */<br>
>> >     struct hash_table *phi_table;<br>
>> > @@ -184,14 +190,15 @@ deref_node_create(struct deref_node *parent,<br>
>> >  }<br>
>> ><br>
>> >  /* Gets the deref_node for the given deref chain and creates it if it<br>
>> > - * doesn't yet exist.  If the deref is a leaf (fully-qualified and<br>
>> > direct)<br>
>> > - * and add_to_leaves is true, it will be added to the hash table of<br>
>> > leaves.<br>
>> > + * doesn't yet exist.  If the deref is fully-qualified and direct and<br>
>> > + * add_to_direct_deref_nodes is true, it will be added to the hash<br>
>> > table of<br>
>> > + * of fully-qualified direct derefs.<br>
>> >   */<br>
>> >  static struct deref_node *<br>
>> > -get_deref_node(nir_deref_var *deref, bool add_to_leaves,<br>
>> > +get_deref_node(nir_deref_var *deref, bool add_to_direct_deref_nodes,<br>
>> >                 struct lower_variables_state *state)<br>
>> >  {<br>
>> > -   bool is_leaf = true;<br>
>> > +   bool is_direct = true;<br>
>> ><br>
>> >     struct deref_node *node;<br>
>> ><br>
>> > @@ -247,7 +254,7 @@ get_deref_node(nir_deref_var *deref, bool<br>
>> > add_to_leaves,<br>
>> >                                                    state->dead_ctx);<br>
>> ><br>
>> >              node = node->indirect;<br>
>> > -            is_leaf = false;<br>
>> > +            is_direct = false;<br>
>> >              break;<br>
>> ><br>
>> >           case nir_deref_array_type_wildcard:<br>
>> > @@ -256,7 +263,7 @@ get_deref_node(nir_deref_var *deref, bool<br>
>> > add_to_leaves,<br>
>> >                                                    state->dead_ctx);<br>
>> ><br>
>> >              node = node->wildcard;<br>
>> > -            is_leaf = false;<br>
>> > +            is_direct = false;<br>
>> >              break;<br>
>> ><br>
>> >           default:<br>
>> > @@ -271,8 +278,8 @@ get_deref_node(nir_deref_var *deref, bool<br>
>> > add_to_leaves,<br>
>> ><br>
>> >     assert(node);<br>
>> ><br>
>> > -   if (is_leaf && add_to_leaves)<br>
>> > -      _mesa_hash_table_insert(state->deref_leaves,<br>
>> > +   if (is_direct && add_to_direct_deref_nodes)<br>
>> > +      _mesa_hash_table_insert(state->direct_deref_nodes,<br>
>> >                                hash_deref(deref), deref, node);<br>
>> ><br>
>> >     return node;<br>
>> > @@ -327,7 +334,7 @@ foreach_deref_node_worker(struct deref_node *node,<br>
>> > nir_deref *deref,<br>
>> >   * a[*].foo[*].bar<br>
>> >   *<br>
>> >   * The given deref must be a full-length and fully qualified (no<br>
>> > wildcards<br>
>> > - * or indirexcts) deref chain.<br>
>> > + * or indirects) deref chain.<br>
>> >   */<br>
>> >  static bool<br>
>> >  foreach_deref_node_match(nir_deref_var *deref,<br>
>> > @@ -390,13 +397,18 @@ deref_may_be_aliased_node(struct deref_node *node,<br>
>> > nir_deref *deref,<br>
>> >  }<br>
>> ><br>
>> >  /* Returns true if there are no indirects that can ever touch this<br>
>> > deref.<br>
>> > - * This question can only be asked about fully-qualified derefs.<br>
>> > + *<br>
>> > + * For example, if the given deref is a[6].foo, then any uses of<br>
>> > a[i].foo<br>
>> > + * would cause this to return false, but a[i].bar would not affect it<br>
>> > + * because it's a different structure member.  A var_copy involving of<br>
>> > + * a[*].bar also doesn't affect it because that can be lowered to<br>
>> > entirely<br>
>> > + * direct load/stores.<br>
>> > + *<br>
>> > + * We only support asking this question about fully-qualified derefs.<br>
>> >   * Obviously, it's pointless to ask this about indirects, but we also<br>
>> > - * rule-out wildcards.  For example, if the given deref is a[6].foo,<br>
>> > then<br>
>> > - * any uses of a[i].foo would case this to return false, but a[i].bar<br>
>> > would<br>
>> > - * not affect it because it's a different structure member.  A var_copy<br>
>> > - * involving of a[*].bar also doesn't affect it because that can be<br>
>> > lowered<br>
>> > - * to entirely direct load/stores.<br>
>> > + * rule-out wildcards.  Handling Wildcard dereferences would involve<br>
>> > + * checking each array index to make sure that there aren't any<br>
>> > indirect<br>
>> > + * references.<br>
>> >   */<br>
>> >  static bool<br>
>> >  deref_may_be_aliased(nir_deref_var *deref,<br>
>> > @@ -948,7 +960,7 @@ rename_variables_block(nir_block *block, struct<br>
>> > lower_variables_state *state)<br>
>> ><br>
>> >              def_stack_push(node, &mov->dest.dest.ssa, state);<br>
>> ><br>
>> > -            /* We'll wait to remove the unstruction until the next pass<br>
>> > +            /* We'll wait to remove the instruction until the next pass<br>
>> >               * where we pop the node we just pushed back off the stack.<br>
>> >               */<br>
>> >              break;<br>
>> > @@ -1021,6 +1033,15 @@ insert_phi_nodes(struct lower_variables_state<br>
>> > *state)<br>
>> >  {<br>
>> >     unsigned work[state->impl->num_blocks];<br>
>> >     unsigned has_already[state->impl->num_blocks];<br>
>> > +<br>
>> > +   /*<br>
>> > +    * Since the work flags already prevent us from inserting a node<br>
>> > that has<br>
>> > +    * ever been inserted into W, we don't need to use a set to<br>
>> > represent W.<br>
>> > +    * Also, since no block can ever be inserted into W more than once,<br>
>> > we know<br>
>> > +    * that the maximum size of W is the number of basic blocks in the<br>
>> > +    * function. So all we need to handle W is an array and a pointer to<br>
>> > the<br>
>> > +    * next element to be inserted and the next element to be removed.<br>
>> > +    */<br>
>> >     nir_block *W[state->impl->num_blocks];<br>
>> ><br>
>> >     memset(work, 0, sizeof work);<br>
>> > @@ -1030,7 +1051,7 @@ insert_phi_nodes(struct lower_variables_state<br>
>> > *state)<br>
>> >     unsigned iter_count = 0;<br>
>> ><br>
>> >     struct hash_entry *deref_entry;<br>
>> > -   hash_table_foreach(state->deref_leaves, deref_entry) {<br>
>> > +   hash_table_foreach(state->direct_deref_nodes, deref_entry) {<br>
>> >        struct deref_node *node = deref_entry->data;<br>
>> ><br>
>> >        if (node->stores == NULL)<br>
>> > @@ -1088,6 +1109,34 @@ insert_phi_nodes(struct lower_variables_state<br>
>> > *state)<br>
>> >     }<br>
>> >  }<br>
>> ><br>
>> > +<br>
>> > +/** Implements a pass to lower variable uses to SSA values<br>
>> > + *<br>
>> > + * This path walks the list of instructions and tries to lower as many<br>
>> > + * local variable load/store operations to SSA defs and uses as it can.<br>
>> > + * The process involves four passes:<br>
>> > + *<br>
>> > + *  1) Iterate over all of the instructions and mark where each local<br>
>> > + *     variable deref is used in a load, store, or copy.  While we're<br>
>> > at<br>
>> > + *     it, we keep track of all of the fully-qualified (no wildcards)<br>
>> > and<br>
>> > + *     fully-direct references we see and store them in the<br>
>> > + *     direct_deref_nodes hash table.<br>
>> > + *<br>
>> > + *  2) Walk over the the list of fully-qualified direct derefs<br>
>> > generated in<br>
>> > + *     the previous pass.  For each deref, we determine if it can ever<br>
>> > be<br>
>> > + *     aliased, i.e. if there is an indirect reference anywhere that<br>
>> > may<br>
>> > + *     refer to it.  If it cannot be aliased, we mark it for lowering<br>
>> > to an<br>
>> > + *     SSA value.  At this point, we lower any var_copy instructions<br>
>> > that<br>
>> > + *     use the given deref to load/store operations and, if the deref<br>
>> > has a<br>
>> > + *     constant initializer, we go ahead and add a load_const value at<br>
>> > the<br>
>> > + *     beginning of the function with the initialized value.<br>
>> > + *<br>
>> > + *  3) Walk over the list of derefss we plan to lower to SSA values and<br>
>><br>
>> derefs<br>
>><br>
>> > + *     insert phi nodes as needed.<br>
>> > + *<br>
>> > + *  4) Perform "variable renaming" by replacing the load/store<br>
>> > instructions<br>
>> > + *     with SSA definitions and SSA uses.<br>
>> > + */<br>
>> >  static bool<br>
>> >  nir_lower_variables_impl(nir_function_impl *impl)<br>
>> >  {<br>
>> > @@ -1099,8 +1148,8 @@ nir_lower_variables_impl(nir_function_impl *impl)<br>
>> ><br>
>> >     state.deref_var_nodes = _mesa_hash_table_create(state.dead_ctx,<br>
>> ><br>
>> > _mesa_key_pointer_equal);<br>
>> > -   state.deref_leaves = _mesa_hash_table_create(state.dead_ctx,<br>
>> > -                                                derefs_equal);<br>
>> > +   state.direct_deref_nodes = _mesa_hash_table_create(state.dead_ctx,<br>
>> > +                                                      derefs_equal);<br>
>> >     state.phi_table = _mesa_hash_table_create(state.dead_ctx,<br>
>> >                                               _mesa_key_pointer_equal);<br>
>> ><br>
>> > @@ -1114,17 +1163,17 @@ nir_lower_variables_impl(nir_function_impl<br>
>> > *impl)<br>
>> >     nir_metadata_require(impl, nir_metadata_block_index);<br>
>> ><br>
>> >     struct hash_entry *entry;<br>
>> > -   hash_table_foreach(state.deref_leaves, entry) {<br>
>> > +   hash_table_foreach(state.direct_deref_nodes, entry) {<br>
>> >        nir_deref_var *deref = (void *)entry->key;<br>
>> >        struct deref_node *node = entry->data;<br>
>> ><br>
>> >        if (deref->var->data.mode != nir_var_local) {<br>
>> > -         _mesa_hash_table_remove(state.deref_leaves, entry);<br>
>> > +         _mesa_hash_table_remove(state.direct_deref_nodes, entry);<br>
>> >           continue;<br>
>> >        }<br>
>> ><br>
>> >        if (deref_may_be_aliased(deref, &state)) {<br>
>> > -         _mesa_hash_table_remove(state.deref_leaves, entry);<br>
>> > +         _mesa_hash_table_remove(state.direct_deref_nodes, entry);<br>
>> >           continue;<br>
>> >        }<br>
>> ><br>
>> > --<br>
>> > 2.2.0<br>
>> ><br>
>> > _______________________________________________<br>
>> > mesa-dev mailing list<br>
>> > <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
>> > <a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev" target="_blank">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
><br>
><br>
</div></div></blockquote></div><br></div></div>