<html><head></head><body><div>On Tue, 2018-09-18 at 07:27 -0500, Jason Ekstrand wrote:</div><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Tue, Sep 18, 2018 at 4:11 AM Iago Toral <<a href="mailto:itoral@igalia.com">itoral@igalia.com</a>> wrote:<br></div><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex">Hi Jason,<br>
<br>
I left a few comments in patches 1 and 4, feel free to ignore them if<br>
you think they are not relevant. Either way the series is:<br></blockquote><div><br></div><div>I would like to back-port this to 18.2 if you don't mind.  I think it's far more accurate than what we were doing before to try and avoid derefs in phis.</div></div></div></blockquote><div><br></div><div>Sure, sounds good to me.</div><div><br></div><div>Iago</div><div><br></div><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>--Jason<br></div><div> </div><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex">
Reviewed-by: Iago Toral Quiroga <<a href="mailto:itoral@igalia.com" target="_blank">itoral@igalia.com</a>><br>
<br>
On Mon, 2018-09-17 at 09:43 -0500, Jason Ekstrand wrote:<br>
> This pass re-materializes deref instructions on a per-block basis to<br>
> ensure that every use of a deref occurs in the same block as the<br>
> instruction which uses it.<br>
> ---<br>
>  src/compiler/nir/nir.h       |   1 +<br>
>  src/compiler/nir/nir_deref.c | 132<br>
> +++++++++++++++++++++++++++++++++++<br>
>  2 files changed, 133 insertions(+)<br>
> <br>
> diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h<br>
> index 599f469a714..e0df95c391c 100644<br>
> --- a/src/compiler/nir/nir.h<br>
> +++ b/src/compiler/nir/nir.h<br>
> @@ -3012,6 +3012,7 @@ bool nir_convert_from_ssa(nir_shader *shader,<br>
> bool phi_webs_only);<br>
>  <br>
>  bool nir_lower_phis_to_regs_block(nir_block *block);<br>
>  bool nir_lower_ssa_defs_to_regs_block(nir_block *block);<br>
> +bool nir_rematerialize_derefs_in_use_blocks_impl(nir_function_impl<br>
> *impl);<br>
>  <br>
>  bool nir_opt_algebraic(nir_shader *shader);<br>
>  bool nir_opt_algebraic_before_ffma(nir_shader *shader);<br>
> diff --git a/src/compiler/nir/nir_deref.c<br>
> b/src/compiler/nir/nir_deref.c<br>
> index 097ea8f1046..87a54790c95 100644<br>
> --- a/src/compiler/nir/nir_deref.c<br>
> +++ b/src/compiler/nir/nir_deref.c<br>
> @@ -24,6 +24,7 @@<br>
>  #include "nir.h"<br>
>  #include "nir_builder.h"<br>
>  #include "nir_deref.h"<br>
> +#include "util/hash_table.h"<br>
>  <br>
>  void<br>
>  nir_deref_path_init(nir_deref_path *path,<br>
> @@ -379,3 +380,134 @@ nir_compare_derefs(nir_deref_instr *a,<br>
> nir_deref_instr *b)<br>
>  <br>
>     return result;<br>
>  }<br>
> +<br>
> +struct rematerialize_deref_state {<br>
> +   bool progress;<br>
> +   nir_builder builder;<br>
> +   nir_block *block;<br>
> +   struct hash_table *cache;<br>
> +};<br>
> +<br>
> +static nir_deref_instr *<br>
> +rematerialize_deref_in_block(nir_deref_instr *deref,<br>
> +                             struct rematerialize_deref_state<br>
> *state)<br>
> +{<br>
> +   if (deref->instr.block == state->block)<br>
> +      return deref;<br>
> +<br>
> +   if (!state->cache) {<br>
> +      state->cache= _mesa_hash_table_create(NULL,<br>
> _mesa_hash_pointer,<br>
> +                                            _mesa_key_pointer_equal)<br>
> ;<br>
> +   }<br>
> +<br>
> +   struct hash_entry *cached = _mesa_hash_table_search(state->cache, <br>
> deref);<br>
> +   if (cached)<br>
> +      return cached->data;<br>
> +<br>
> +   nir_builder *b = &state->builder;<br>
> +   nir_deref_instr *new_deref =<br>
> +      nir_deref_instr_create(b->shader, deref->deref_type);<br>
> +   new_deref->mode = deref->mode;<br>
> +   new_deref->type = deref->type;<br>
> +<br>
> +   if (deref->deref_type == nir_deref_type_var) {<br>
> +      new_deref->var = deref->var;<br>
> +   } else {<br>
> +      nir_deref_instr *parent = nir_src_as_deref(deref->parent);<br>
> +      if (parent) {<br>
> +         parent = rematerialize_deref_in_block(parent, state);<br>
> +         new_deref->parent = nir_src_for_ssa(&parent->dest.ssa);<br>
> +      } else {<br>
> +         nir_src_copy(&new_deref->parent, &deref->parent,<br>
> new_deref);<br>
> +      }<br>
> +   }<br>
> +<br>
> +   switch (deref->deref_type) {<br>
> +   case nir_deref_type_var:<br>
> +   case nir_deref_type_array_wildcard:<br>
> +   case nir_deref_type_cast:<br>
> +      /* Nothing more to do */<br>
> +      break;<br>
> +<br>
> +   case nir_deref_type_array:<br>
> +      assert(!nir_src_as_deref(deref->arr.index));<br>
> +      nir_src_copy(&new_deref->arr.index, &deref->arr.index,<br>
> new_deref);<br>
> +      break;<br>
> +<br>
> +   case nir_deref_type_struct:<br>
> +      new_deref->strct.index = deref->strct.index;<br>
> +      break;<br>
> +<br>
> +   default:<br>
> +      unreachable("Invalid deref instruction type");<br>
> +   }<br>
> +<br>
> +   nir_ssa_dest_init(&new_deref->instr, &new_deref->dest,<br>
> +                     deref->dest.ssa.num_components,<br>
> +                     deref->dest.ssa.bit_size,<br>
> +                     deref-><a href="http://dest.ssa.name" rel="noreferrer" target="_blank">dest.ssa.name</a>);<br>
> +   nir_builder_instr_insert(b, &new_deref->instr);<br>
> +<br>
> +   return new_deref;<br>
> +}<br>
> +<br>
> +static bool<br>
> +rematerialize_deref_src(nir_src *src, void *_state)<br>
> +{<br>
> +   struct rematerialize_deref_state *state = _state;<br>
> +<br>
> +   nir_deref_instr *deref = nir_src_as_deref(*src);<br>
> +   if (!deref)<br>
> +      return true;<br>
> +<br>
> +   nir_deref_instr *block_deref =<br>
> rematerialize_deref_in_block(deref, state);<br>
> +<br>
> +   nir_instr_rewrite_src(src->parent_instr, src,<br>
> +                         nir_src_for_ssa(&block_deref->dest.ssa));<br>
> +   nir_deref_instr_remove_if_unused(deref);<br>
> +   state->progress = true;<br>
> +<br>
> +   return true;<br>
> +}<br>
> +<br>
> +/** Re-materialize derefs in every block<br>
> + *<br>
> + * This pass re-materializes deref instructions in every block in<br>
> which it is<br>
> + * used.  After this pass has been run, every use of a deref will be<br>
> of a<br>
> + * deref in the same block as the use.  Also, all unused derefs will<br>
> be<br>
> + * deleted as a side-effect.<br>
> + */<br>
> +bool<br>
> +nir_rematerialize_derefs_in_use_blocks_impl(nir_function_impl *impl)<br>
> +{<br>
> +   struct rematerialize_deref_state state = { };<br>
> +   nir_builder_init(&state.builder, impl);<br>
> +<br>
> +   nir_foreach_block(block, impl) {<br>
> +      state.block = block;<br>
> +<br>
> +      /* Start each block with a fresh cache */<br>
> +      if (state.cache)<br>
> +         _mesa_hash_table_clear(state.cache, NULL);<br>
> +<br>
> +      nir_foreach_instr_safe(instr, block) {<br>
> +         if (instr->type == nir_instr_type_deref) {<br>
> +            nir_deref_instr_remove_if_unused(nir_instr_as_deref(inst<br>
> r));<br>
> +            continue;<br>
> +         }<br>
> +<br>
> +         state.builder.cursor = nir_before_instr(instr);<br>
> +         nir_foreach_src(instr, rematerialize_deref_src, &state);<br>
> +      }<br>
> +<br>
> +#ifndef NDEBUG<br>
> +      nir_if *following_if = nir_block_get_following_if(block);<br>
> +      if (following_if)<br>
> +         assert(!nir_src_as_deref(following_if->condition));<br>
> +#endif<br>
> +   }<br>
> +<br>
> +   _mesa_hash_table_destroy(state.cache, NULL);<br>
> +<br>
> +   return state.progress;<br>
> +}<br>
</blockquote></div></div>
</blockquote></body></html>