<p dir="ltr">Push it!</p>
<div class="gmail_quote">On Mar 9, 2015 7:03 PM, "Connor Abbott" <<a href="mailto:cwabbott0@gmail.com">cwabbott0@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Reviewed-by: Connor Abbott <<a href="mailto:cwabbott0@gmail.com">cwabbott0@gmail.com</a>><br>
<br>
I was in the middle of rewriting this pass for making derefs<br>
instructions, which hasn't been going nearly as nicely as I would like<br>
(ugh...), so if it pans out then I'll have to think about it a little<br>
more to make sure the new version is deterministic too.<br>
<br>
On Mon, Mar 9, 2015 at 9:36 PM, Kenneth Graunke <<a href="mailto:kenneth@whitecape.org">kenneth@whitecape.org</a>> wrote:<br>
> Previously, we stored derefs in a hash table, using the malloc'd pointer<br>
> as the key.  Then, we walked through the hash table and generated code,<br>
> based on the order of the hash table's elements.<br>
><br>
> Memory addresses returned by malloc are pretty much random, which meant<br>
> that the hash was random, and the hash table's elements would be walked<br>
> in some random order.  This led to successive compiles of the same<br>
> shader using different variable names and slightly different orderings<br>
> of phi-nodes.  Code could not be diff'd, and the final assembly would<br>
> sometimes change slightly too.<br>
><br>
> It turns out the only point of the hash table was to avoid inserting<br>
> the same node multiple times for different dereferences.  We never<br>
> actually searched the hash table!  This patch uses an intrusive<br>
> linked list instead.  Since exec_list uses head and tail sentinels,<br>
> checking prev or next against NULL will tell us whether the node is<br>
> already in the list.<br>
><br>
> Pair programming with Jason Ekstrand.<br>
><br>
> Signed-off-by: Jason Ekstrand <<a href="mailto:jason.ekstrand@intel.com">jason.ekstrand@intel.com</a>><br>
> Signed-off-by: Kenneth Graunke <<a href="mailto:kenneth@whitecape.org">kenneth@whitecape.org</a>><br>
> ---<br>
>  src/glsl/nir/nir_lower_vars_to_ssa.c | 123 ++++++++---------------------------<br>
>  1 file changed, 26 insertions(+), 97 deletions(-)<br>
><br>
> diff --git a/src/glsl/nir/nir_lower_vars_to_ssa.c b/src/glsl/nir/nir_lower_vars_to_ssa.c<br>
> index 9e9a418..86e6ab4 100644<br>
> --- a/src/glsl/nir/nir_lower_vars_to_ssa.c<br>
> +++ b/src/glsl/nir/nir_lower_vars_to_ssa.c<br>
> @@ -35,6 +35,13 @@ struct deref_node {<br>
><br>
>     bool lower_to_ssa;<br>
><br>
> +   /* Only valid for things that end up in the direct list.<br>
> +    * Note that multiple nir_deref_vars may correspond to this node, but they<br>
> +    * will all be equivalent, so any is as good as the other.<br>
> +    */<br>
> +   nir_deref_var *deref;<br>
> +   struct exec_node direct_derefs_link;<br>
> +<br>
>     struct set *loads;<br>
>     struct set *stores;<br>
>     struct set *copies;<br>
> @@ -69,7 +76,7 @@ struct lower_variables_state {<br>
>      * wildcards and no indirects, these are precisely the derefs that we<br>
>      * can actually consider lowering.<br>
>      */<br>
> -   struct hash_table *direct_deref_nodes;<br>
> +   struct exec_list direct_deref_nodes;<br>
><br>
>     /* Controls whether get_deref_node will add variables to the<br>
>      * direct_deref_nodes table.  This is turned on when we are initially<br>
> @@ -83,88 +90,6 @@ struct lower_variables_state {<br>
>     struct hash_table *phi_table;<br>
>  };<br>
><br>
> -/* The following two functions implement a hash and equality check for<br>
> - * variable dreferences.  When the hash or equality function encounters an<br>
> - * array, all indirects are treated as equal and are never equal to a<br>
> - * direct dereference or a wildcard.<br>
> - */<br>
> -static uint32_t<br>
> -hash_deref(const void *void_deref)<br>
> -{<br>
> -   uint32_t hash = _mesa_fnv32_1a_offset_bias;<br>
> -<br>
> -   const nir_deref_var *deref_var = void_deref;<br>
> -   hash = _mesa_fnv32_1a_accumulate(hash, deref_var->var);<br>
> -<br>
> -   for (const nir_deref *deref = deref_var->deref.child;<br>
> -        deref; deref = deref->child) {<br>
> -      switch (deref->deref_type) {<br>
> -      case nir_deref_type_array: {<br>
> -         nir_deref_array *deref_array = nir_deref_as_array(deref);<br>
> -<br>
> -         hash = _mesa_fnv32_1a_accumulate(hash, deref_array->deref_array_type);<br>
> -<br>
> -         if (deref_array->deref_array_type == nir_deref_array_type_direct)<br>
> -            hash = _mesa_fnv32_1a_accumulate(hash, deref_array->base_offset);<br>
> -         break;<br>
> -      }<br>
> -      case nir_deref_type_struct: {<br>
> -         nir_deref_struct *deref_struct = nir_deref_as_struct(deref);<br>
> -         hash = _mesa_fnv32_1a_accumulate(hash, deref_struct->index);<br>
> -         break;<br>
> -      }<br>
> -      default:<br>
> -         assert("Invalid deref chain");<br>
> -      }<br>
> -   }<br>
> -<br>
> -   return hash;<br>
> -}<br>
> -<br>
> -static bool<br>
> -derefs_equal(const void *void_a, const void *void_b)<br>
> -{<br>
> -   const nir_deref_var *a_var = void_a;<br>
> -   const nir_deref_var *b_var = void_b;<br>
> -<br>
> -   if (a_var->var != b_var->var)<br>
> -      return false;<br>
> -<br>
> -   for (const nir_deref *a = a_var->deref.child, *b = b_var->deref.child;<br>
> -        a != NULL; a = a->child, b = b->child) {<br>
> -      if (a->deref_type != b->deref_type)<br>
> -         return false;<br>
> -<br>
> -      switch (a->deref_type) {<br>
> -      case nir_deref_type_array: {<br>
> -         nir_deref_array *a_arr = nir_deref_as_array(a);<br>
> -         nir_deref_array *b_arr = nir_deref_as_array(b);<br>
> -<br>
> -         if (a_arr->deref_array_type != b_arr->deref_array_type)<br>
> -            return false;<br>
> -<br>
> -         if (a_arr->deref_array_type == nir_deref_array_type_direct &&<br>
> -             a_arr->base_offset != b_arr->base_offset)<br>
> -            return false;<br>
> -         break;<br>
> -      }<br>
> -      case nir_deref_type_struct:<br>
> -         if (nir_deref_as_struct(a)->index != nir_deref_as_struct(b)->index)<br>
> -            return false;<br>
> -         break;<br>
> -      default:<br>
> -         assert("Invalid deref chain");<br>
> -         return false;<br>
> -      }<br>
> -<br>
> -      assert((a->child == NULL) == (b->child == NULL));<br>
> -      if((a->child == NULL) != (b->child == NULL))<br>
> -         return false;<br>
> -   }<br>
> -<br>
> -   return true;<br>
> -}<br>
> -<br>
>  static int<br>
>  type_get_length(const struct glsl_type *type)<br>
>  {<br>
> @@ -195,6 +120,8 @@ deref_node_create(struct deref_node *parent,<br>
>     struct deref_node *node = rzalloc_size(mem_ctx, size);<br>
>     node->type = type;<br>
>     node->parent = parent;<br>
> +   node->deref = NULL;<br>
> +   exec_node_init(&node->direct_derefs_link);<br>
><br>
>     return node;<br>
>  }<br>
> @@ -297,8 +224,14 @@ get_deref_node(nir_deref_var *deref, struct lower_variables_state *state)<br>
><br>
>     assert(node);<br>
><br>
> -   if (is_direct && state->add_to_direct_deref_nodes)<br>
> -      _mesa_hash_table_insert(state->direct_deref_nodes, deref, node);<br>
> +   /* Only insert if it isn't already in the list. */<br>
> +   if (is_direct && state->add_to_direct_deref_nodes &&<br>
> +       node->direct_derefs_link.next == NULL) {<br>
> +      node->deref = deref;<br>
> +      assert(deref->var != NULL);<br>
> +      exec_list_push_tail(&state->direct_deref_nodes,<br>
> +                          &node->direct_derefs_link);<br>
> +   }<br>
><br>
>     return node;<br>
>  }<br>
> @@ -917,10 +850,8 @@ insert_phi_nodes(struct lower_variables_state *state)<br>
>     unsigned w_start, w_end;<br>
>     unsigned iter_count = 0;<br>
><br>
> -   struct hash_entry *deref_entry;<br>
> -   hash_table_foreach(state->direct_deref_nodes, deref_entry) {<br>
> -      struct deref_node *node = deref_entry->data;<br>
> -<br>
> +   foreach_list_typed(struct deref_node, node, direct_derefs_link,<br>
> +                      &state->direct_deref_nodes) {<br>
>        if (node->stores == NULL)<br>
>           continue;<br>
><br>
> @@ -1014,8 +945,7 @@ nir_lower_vars_to_ssa_impl(nir_function_impl *impl)<br>
>     state.deref_var_nodes = _mesa_hash_table_create(state.dead_ctx,<br>
>                                                     _mesa_hash_pointer,<br>
>                                                     _mesa_key_pointer_equal);<br>
> -   state.direct_deref_nodes = _mesa_hash_table_create(state.dead_ctx,<br>
> -                                                      hash_deref, derefs_equal);<br>
> +   exec_list_make_empty(&state.direct_deref_nodes);<br>
>     state.phi_table = _mesa_hash_table_create(state.dead_ctx,<br>
>                                               _mesa_hash_pointer,<br>
>                                               _mesa_key_pointer_equal);<br>
> @@ -1035,18 +965,17 @@ nir_lower_vars_to_ssa_impl(nir_function_impl *impl)<br>
>     /* We're about to iterate through direct_deref_nodes.  Don't modify it. */<br>
>     state.add_to_direct_deref_nodes = false;<br>
><br>
> -   struct hash_entry *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>
> +   foreach_list_typed_safe(struct deref_node, node, direct_derefs_link,<br>
> +                           &state.direct_deref_nodes) {<br>
> +      nir_deref_var *deref = node->deref;<br>
><br>
>        if (deref->var->data.mode != nir_var_local) {<br>
> -         _mesa_hash_table_remove(state.direct_deref_nodes, entry);<br>
> +         exec_node_remove(&node->direct_derefs_link);<br>
>           continue;<br>
>        }<br>
><br>
>        if (deref_may_be_aliased(deref, &state)) {<br>
> -         _mesa_hash_table_remove(state.direct_deref_nodes, entry);<br>
> +         exec_node_remove(&node->direct_derefs_link);<br>
>           continue;<br>
>        }<br>
><br>
> --<br>
> 2.2.2<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>
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>
</blockquote></div>