<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Dec 17, 2014 at 1:10 PM, Jason Ekstrand <span dir="ltr"><<a href="mailto:jason@jlekstrand.net" target="_blank">jason@jlekstrand.net</a>></span> wrote:<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote"><div><div class="h5">On Wed, Dec 17, 2014 at 12:07 PM, Connor Abbott <span dir="ltr"><<a href="mailto:cwabbott0@gmail.com" target="_blank">cwabbott0@gmail.com</a>></span> wrote:<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div>On Tue, Dec 16, 2014 at 1:04 AM, Jason Ekstrand <<a href="mailto:jason@jlekstrand.net" target="_blank">jason@jlekstrand.net</a>> wrote:<br>
> From: Connor Abbott <<a href="mailto:connor.abbott@intel.com" target="_blank">connor.abbott@intel.com</a>><br>
><br>
> ---<br>
>  src/glsl/Makefile.sources             |   1 +<br>
>  src/glsl/nir/nir.h                    |   3 +<br>
>  src/glsl/nir/nir_opt_copy_propagate.c | 313 ++++++++++++++++++++++++++++++++++<br>
>  3 files changed, 317 insertions(+)<br>
>  create mode 100644 src/glsl/nir/nir_opt_copy_propagate.c<br>
><br>
> diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources<br>
> index 0aaea58..556648b 100644<br>
> --- a/src/glsl/Makefile.sources<br>
> +++ b/src/glsl/Makefile.sources<br>
> @@ -25,6 +25,7 @@ NIR_FILES = \<br>
>         $(GLSL_SRCDIR)/nir/nir_lower_variables_scalar.c \<br>
>         $(GLSL_SRCDIR)/nir/nir_opcodes.c \<br>
>         $(GLSL_SRCDIR)/nir/nir_opcodes.h \<br>
> +       $(GLSL_SRCDIR)/nir/nir_opt_copy_propagate.c \<br>
>         $(GLSL_SRCDIR)/nir/nir_opt_global_to_local.c \<br>
>         $(GLSL_SRCDIR)/nir/nir_print.c \<br>
>         $(GLSL_SRCDIR)/nir/nir_remove_dead_variables.c \<br>
> diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h<br>
> index c2b4724..a5cb5ed 100644<br>
> --- a/src/glsl/nir/nir.h<br>
> +++ b/src/glsl/nir/nir.h<br>
> @@ -1293,6 +1293,9 @@ void nir_convert_to_ssa(nir_shader *shader);<br>
><br>
>  bool nir_opt_global_to_local(nir_shader *shader);<br>
><br>
> +bool nir_copy_prop_impl(nir_function_impl *impl);<br>
> +bool nir_copy_prop(nir_shader *shader);<br>
> +<br>
>  #ifdef __cplusplus<br>
>  } /* extern "C" */<br>
>  #endif<br>
> diff --git a/src/glsl/nir/nir_opt_copy_propagate.c b/src/glsl/nir/nir_opt_copy_propagate.c<br>
> new file mode 100644<br>
> index 0000000..a2be047<br>
> --- /dev/null<br>
> +++ b/src/glsl/nir/nir_opt_copy_propagate.c<br>
> @@ -0,0 +1,313 @@<br>
> +/*<br>
> + * Copyright © 2014 Intel Corporation<br>
> + *<br>
> + * Permission is hereby granted, free of charge, to any person obtaining a<br>
> + * copy of this software and associated documentation files (the "Software"),<br>
> + * to deal in the Software without restriction, including without limitation<br>
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
> + * and/or sell copies of the Software, and to permit persons to whom the<br>
> + * Software is furnished to do so, subject to the following conditions:<br>
> + *<br>
> + * The above copyright notice and this permission notice (including the next<br>
> + * paragraph) shall be included in all copies or substantial portions of the<br>
> + * Software.<br>
> + *<br>
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS<br>
> + * IN THE SOFTWARE.<br>
> + *<br>
> + * Authors:<br>
> + *    Connor Abbott (<a href="mailto:cwabbott0@gmail.com" target="_blank">cwabbott0@gmail.com</a>)<br>
> + *<br>
> + */<br>
> +<br>
> +#include "nir.h"<br>
> +#include <main/imports.h><br>
> +<br>
> +/**<br>
> + * SSA-based copy propagation<br>
> + */<br>
> +<br>
> +static bool is_move(nir_alu_instr *instr)<br>
> +{<br>
> +   if (instr->op != nir_op_fmov &&<br>
> +       instr->op != nir_op_imov)<br>
> +      return false;<br>
> +<br>
> +   if (instr->dest.saturate)<br>
> +      return false;<br>
> +<br>
> +   /* we handle modifiers in a separate pass */<br>
<br>
</div></div>This comment is stale now, since this pass should never see<br>
modifiers... maybe we should replace those if's with asserts to make<br>
that clear.<br></blockquote><div><br></div></div></div><div>Easy enough to do.<br></div></div></div></div></blockquote><div><br></div><div>Wait, I just remembered that I left them in intentionally.  We may want to run copy prop after lowering to source mods.  In fact, when I wrote lower_to_source_mods, I was lazy and just changed sat instructions to mov and trusted in copy prop to clan up the swizzles for me.  If anything, we may want to make copy prop simply handle them correctly.<br></div><div>--Jason<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div> <br></div><div><div class="h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div><br>
> +<br>
> +   if (instr->src[0].abs || instr->src[0].negate)<br>
> +      return false;<br>
> +<br>
> +   if (!instr->src[0].src.is_ssa)<br>
> +      return false;<br>
> +<br>
> +   return true;<br>
> +<br>
> +}<br>
> +<br>
> +static bool<br>
> +is_swizzleless_move(nir_alu_instr *instr)<br>
> +{<br>
> +   if (!is_move(instr))<br>
> +      return false;<br>
> +<br>
> +   for (unsigned i = 0; i < 4; i++) {<br>
> +      if (!((instr->dest.write_mask >> i) & 1))<br>
> +         break;<br>
> +      if (instr->src[0].swizzle[i] != i)<br>
> +         return false;<br>
> +   }<br>
> +<br>
> +   return true;<br>
> +}<br>
> +<br>
> +static bool is_vec(nir_alu_instr *instr)<br>
> +{<br>
> +   for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++)<br>
> +      if (!instr->src[i].src.is_ssa)<br>
> +         return false;<br>
> +<br>
> +   return instr->op == nir_op_vec2 ||<br>
> +          instr->op == nir_op_vec3 ||<br>
> +          instr->op == nir_op_vec4;<br>
> +}<br>
> +<br>
> +typedef struct {<br>
> +   nir_ssa_def *def;<br>
> +   bool found;<br>
> +} search_def_state;<br>
> +<br>
> +static bool<br>
> +search_def(nir_src *src, void *_state)<br>
> +{<br>
> +   search_def_state *state = (search_def_state *) _state;<br>
> +<br>
> +   if (src->is_ssa && src->ssa == state->def)<br>
> +      state->found = true;<br>
> +<br>
> +   return true;<br>
> +}<br>
> +<br>
> +static void<br>
> +rewrite_src_instr(nir_src *src, nir_ssa_def *new_def, nir_instr *parent_instr)<br>
> +{<br>
> +   nir_ssa_def *old_def = src->ssa;<br>
> +<br>
> +   src->ssa = new_def;<br>
> +<br>
> +   /*<br>
> +    * The instruction could still use the old definition in one of its other<br>
> +    * sources, so only remove the instruction from the uses if there are no<br>
> +    * more uses left.<br>
> +    */<br>
> +<br>
> +   search_def_state search_state;<br>
> +   search_state.def = old_def;<br>
> +   search_state.found = false;<br>
> +   nir_foreach_src(parent_instr, search_def, &search_state);<br>
> +   if (!search_state.found) {<br>
> +      struct set_entry *entry =<br>
> +         _mesa_set_search(old_def->uses, _mesa_hash_pointer(parent_instr),<br>
> +                          parent_instr);<br>
> +      assert(entry);<br>
> +      _mesa_set_remove(old_def->uses, entry);<br>
> +   }<br>
> +<br>
> +   _mesa_set_add(new_def->uses, _mesa_hash_pointer(parent_instr),<br>
> +                 parent_instr);<br>
> +}<br>
> +<br>
> +static void<br>
> +rewrite_src_if(nir_if *if_stmt, nir_ssa_def *new_def)<br>
> +{<br>
> +   nir_ssa_def *old_def = if_stmt->condition.ssa;<br>
> +<br>
> +   if_stmt->condition.ssa = new_def;<br>
> +<br>
> +   struct set_entry *entry =<br>
> +      _mesa_set_search(old_def->if_uses, _mesa_hash_pointer(if_stmt), if_stmt);<br>
> +   assert(entry);<br>
> +   _mesa_set_remove(old_def->if_uses, entry);<br>
> +<br>
> +   _mesa_set_add(new_def->if_uses, _mesa_hash_pointer(if_stmt), if_stmt);<br>
> +}<br>
> +<br>
> +static bool<br>
> +copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if)<br>
> +{<br>
> +   if (!src->is_ssa) {<br>
> +      if (src->reg.indirect)<br>
> +         return copy_prop_src(src, parent_instr, parent_if);<br>
> +      return false;<br>
> +   }<br>
> +<br>
> +   nir_instr *src_instr = src->ssa->parent_instr;<br>
> +   if (src_instr->type != nir_instr_type_alu)<br>
> +      return false;<br>
> +<br>
> +   nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr);<br>
> +   if (!is_swizzleless_move(alu_instr))<br>
> +      return false;<br>
> +<br>
> +   if (parent_instr)<br>
> +      rewrite_src_instr(src, alu_instr->src[0].src.ssa, parent_instr);<br>
> +   else<br>
> +      rewrite_src_if(parent_if, alu_instr->src[0].src.ssa);<br>
> +<br>
> +   return true;<br>
> +}<br>
> +<br>
> +static bool<br>
> +copy_prop_alu_src(nir_alu_instr *parent_alu_instr, unsigned index)<br>
> +{<br>
> +   nir_alu_src *src = &parent_alu_instr->src[index];<br>
> +   if (!src->src.is_ssa) {<br>
> +      if (src->src.reg.indirect)<br>
> +         return copy_prop_src(src->src.reg.indirect, &parent_alu_instr->instr,<br>
> +                              NULL);<br>
> +      return false;<br>
> +   }<br>
> +<br>
> +   nir_instr *src_instr =  src->src.ssa->parent_instr;<br>
> +   if (src_instr->type != nir_instr_type_alu)<br>
> +      return false;<br>
> +<br>
> +   nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr);<br>
> +   if (!is_move(alu_instr) && !is_vec(alu_instr))<br>
> +      return false;<br>
> +<br>
> +   nir_ssa_def *def;<br>
> +   unsigned new_swizzle[4] = {0, 0, 0, 0};<br>
> +<br>
> +   if (alu_instr->op == nir_op_fmov ||<br>
> +       alu_instr->op == nir_op_imov) {<br>
> +      for (unsigned i = 0; i < 4; i++)<br>
> +         new_swizzle[i] = alu_instr->src[0].swizzle[src->swizzle[i]];<br>
> +      def = alu_instr->src[0].src.ssa;<br>
> +   } else {<br>
> +      def = NULL;<br>
> +<br>
> +      for (unsigned i = 0; i < 4; i++) {<br>
> +         if (!nir_alu_instr_channel_used(parent_alu_instr, index, i))<br>
> +            continue;<br>
> +<br>
> +         nir_ssa_def *new_def = alu_instr->src[src->swizzle[i]].src.ssa;<br>
> +         if (def == NULL)<br>
> +            def = new_def;<br>
> +         else {<br>
> +            if (def != new_def)<br>
> +               return false;<br>
> +         }<br>
> +         new_swizzle[i] = alu_instr->src[src->swizzle[i]].swizzle[0];<br>
> +      }<br>
> +   }<br>
> +<br>
> +   for (unsigned i = 0; i < 4; i++)<br>
> +      src->swizzle[i] = new_swizzle[i];<br>
> +<br>
> +   rewrite_src_instr(&src->src, def, &parent_alu_instr->instr);<br>
> +<br>
> +   return true;<br>
> +}<br>
> +<br>
> +typedef struct {<br>
> +   nir_instr *parent_instr;<br>
> +   bool progress;<br>
> +} copy_prop_state;<br>
> +<br>
> +static bool<br>
> +copy_prop_src_cb(nir_src *src, void *_state)<br>
> +{<br>
> +   copy_prop_state *state = (copy_prop_state *) _state;<br>
> +   while (copy_prop_src(src, state->parent_instr, NULL))<br>
> +      state->progress = true;<br>
> +<br>
> +   return true;<br>
> +}<br>
> +<br>
> +static bool<br>
> +copy_prop_instr(nir_instr *instr)<br>
> +{<br>
> +   if (instr->type == nir_instr_type_alu) {<br>
> +      nir_alu_instr *alu_instr = nir_instr_as_alu(instr);<br>
> +      bool progress = false;<br>
> +<br>
> +      for (unsigned i = 0; i < nir_op_infos[alu_instr->op].num_inputs; i++)<br>
> +         while (copy_prop_alu_src(alu_instr, i))<br>
> +            progress = true;<br>
> +<br>
> +      if (alu_instr->has_predicate)<br>
> +         while (copy_prop_src(&alu_instr->predicate, instr, NULL))<br>
> +            progress = true;<br>
> +<br>
> +      if (!alu_instr->dest.dest.is_ssa && alu_instr->dest.dest.reg.indirect)<br>
> +         while (copy_prop_src(alu_instr->dest.dest.reg.indirect, instr, NULL))<br>
> +            progress = true;<br>
> +<br>
> +      return progress;<br>
> +   }<br>
> +<br>
> +   copy_prop_state state;<br>
> +   state.parent_instr = instr;<br>
> +   state.progress = false;<br>
> +   nir_foreach_src(instr, copy_prop_src_cb, &state);<br>
> +<br>
> +   return state.progress;<br>
> +}<br>
> +<br>
> +static bool<br>
> +copy_prop_if(nir_if *if_stmt)<br>
> +{<br>
> +   return copy_prop_src(&if_stmt->condition, NULL, if_stmt);<br>
> +}<br>
> +<br>
> +static bool<br>
> +copy_prop_block(nir_block *block, void *_state)<br>
> +{<br>
> +   bool *progress = (bool *) _state;<br>
> +<br>
> +   nir_foreach_instr(block, instr) {<br>
> +      if (copy_prop_instr(instr))<br>
> +         *progress = true;<br>
> +   }<br>
> +<br>
> +   if (block->cf_node.node.next != NULL && /* check that we aren't the end node */<br>
> +       !nir_cf_node_is_last(&block->cf_node) &&<br>
> +       nir_cf_node_next(&block->cf_node)->type == nir_cf_node_if) {<br>
> +      nir_if *if_stmt = nir_cf_node_as_if(nir_cf_node_next(&block->cf_node));<br>
> +      if (copy_prop_if(if_stmt))<br>
> +         *progress = true;<br>
> +   }<br>
> +<br>
> +   return true;<br>
> +}<br>
> +<br>
> +bool<br>
> +nir_copy_prop_impl(nir_function_impl *impl)<br>
> +{<br>
> +   bool progress = false;<br>
> +<br>
> +   nir_foreach_block(impl, copy_prop_block, &progress);<br>
> +   return progress;<br>
> +}<br>
> +<br>
> +bool<br>
> +nir_copy_prop(nir_shader *shader)<br>
> +{<br>
> +   bool progress = false;<br>
> +<br>
> +   nir_foreach_overload(shader, overload) {<br>
> +      if (overload->impl && nir_copy_prop_impl(overload->impl))<br>
> +         progress = true;<br>
> +   }<br>
> +<br>
> +   return progress;<br>
> +}<br>
> --<br>
> 2.2.0<br>
><br>
</div></div>> _______________________________________________<br>
> mesa-dev mailing list<br>
> <a href="mailto:mesa-dev@lists.freedesktop.org" target="_blank">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></div></div></div></div>
</blockquote></div></div></div>