<div dir="auto"><div><div class="gmail_extra"><div class="gmail_quote">On Dec 21, 2016 8:11 PM, "Timothy Arceri" <<a href="mailto:timothy.arceri@collabora.com">timothy.arceri@collabora.com</a>> wrote:<br type="attribution"><blockquote class="quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="elided-text">On Mon, 2016-12-19 at 20:11 -0800, Jason Ekstrand wrote:<br>
> ---<br>
> src/compiler/Makefile.<wbr>sources | 1 +<br>
> src/compiler/nir/nir.h <wbr> | 2 +<br>
> src/compiler/nir/nir_opt_<wbr>trivial_continues.c | 141<br>
> +++++++++++++++++++++++++++<br>
> 3 files changed, 144 insertions(+)<br>
> create mode 100644 src/compiler/nir/nir_opt_<wbr>trivial_continues.c<br>
><br>
> diff --git a/src/compiler/Makefile.<wbr>sources<br>
> b/src/compiler/Makefile.<wbr>sources<br>
> index ae3e5f0..a0abede 100644<br>
> --- a/src/compiler/Makefile.<wbr>sources<br>
> +++ b/src/compiler/Makefile.<wbr>sources<br>
> @@ -242,6 +242,7 @@ NIR_FILES = \<br>
> nir/nir_opt_loop_unroll.c \<br>
> nir/nir_opt_peephole_select.c \<br>
> nir/nir_opt_remove_phis.c \<br>
> + nir/nir_opt_trivial_continues.<wbr>c \<br>
> nir/nir_opt_undef.c \<br>
> nir/nir_phi_builder.c \<br>
> nir/nir_phi_builder.h \<br>
> diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h<br>
> index 89b0c70..a6c8956 100644<br>
> --- a/src/compiler/nir/nir.h<br>
> +++ b/src/compiler/nir/nir.h<br>
> @@ -2563,6 +2563,8 @@ bool nir_opt_peephole_select(nir_<wbr>shader<br>
> *shader, unsigned limit);<br>
> <br>
> bool nir_opt_remove_phis(nir_shader *shader);<br>
> <br>
> +bool nir_opt_trivial_continues(nir_<wbr>shader *shader);<br>
> +<br>
> bool nir_opt_undef(nir_shader *shader);<br>
> <br>
> bool nir_opt_conditional_discard(<wbr>nir_shader *shader);<br>
> diff --git a/src/compiler/nir/nir_opt_<wbr>trivial_continues.c<br>
> b/src/compiler/nir/nir_opt_<wbr>trivial_continues.c<br>
> new file mode 100644<br>
> index 0000000..ff3205d<br>
> --- /dev/null<br>
> +++ b/src/compiler/nir/nir_opt_<wbr>trivial_continues.c<br>
> @@ -0,0 +1,141 @@<br>
> +/*<br>
> + * Copyright © 2016 Intel Corporation<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 whom<br>
> the<br>
> + * Software is furnished to do so, subject to the following<br>
> conditions:<br>
> + *<br>
> + * The above copyright notice and this permission notice (including<br>
> 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, DAMAGES<br>
> 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>
> +#include "nir.h"<br>
> +<br>
> +static bool<br>
> +instr_is_continue(nir_instr *instr)<br>
> +{<br>
> + if (instr->type != nir_instr_type_jump)<br>
> + return false;<br>
> +<br>
> + return nir_instr_as_jump(instr)->type == nir_jump_continue;<br>
> +}<br>
> +<br>
> +static bool<br>
> +lower_trivial_continues_<wbr>block(nir_block *block, nir_loop *loop)<br>
> +{<br>
> + bool progress = false;<br>
> + nir_instr *first_instr = nir_block_first_instr(block);<br>
> + if (!first_instr || instr_is_continue(first_instr)<wbr>) {<br>
> + /* The block contains only a continue if anything */<br>
> + nir_cf_node *prev_node = nir_cf_node_prev(&block->cf_<wbr>node);<br>
> + if (prev_node && prev_node->type == nir_cf_node_if) {<br>
> + nir_if *prev_if = nir_cf_node_as_if(prev_node);<br>
> + progress |= lower_trivial_continues_block(<br>
> + nir_if_last_then_<wbr>block(prev_if), loop);<br>
> + progress |= lower_trivial_continues_block(<br>
> + nir_if_last_else_<wbr>block(prev_if), loop);<br>
> + }<br>
> +<br>
> + /* The lower_phis_to_regs helper is smart enough to push phi<br>
> sources as<br>
> + * far up if-ladders as it possibly can. In other words, the<br>
> recursive<br>
> + * calls above shouldn't be adding instructions to this block<br>
> since it<br>
> + * follows an if statement.<br>
> + */<br>
> + first_instr = nir_block_first_instr(block);<br>
> + assert(!first_instr || instr_is_continue(first_instr)<wbr>);<br>
> + }<br>
> +<br>
> + nir_instr *last_instr = nir_block_last_instr(block);<br>
> + if (!last_instr || !instr_is_continue(last_instr)<wbr>)<br>
> + return progress;<br>
> +<br>
> + /* We're at the end of a block that goes straight through to the<br>
> end of the<br>
> + * loop and continues to the top. We can exit normally instead<br>
> of jump.<br>
> + */<br>
> + nir_lower_phis_to_regs_<wbr>block(nir_loop_first_block(<wbr>loop));<br>
> + nir_instr_remove(last_<wbr>instr);<br>
> + return true;<br>
> +}<br>
> +<br>
> +static bool<br>
> +lower_trivial_continues_list(<wbr>struct exec_list *cf_list,<br>
> + <wbr>bool list_ends_at_loop_tail,<br>
> + <wbr>nir_loop *loop)<br>
> +{<br>
> + bool progress = false;<br>
> + foreach_list_typed(nir_cf_<wbr>node, cf_node, node, cf_list) {<br>
> + bool at_loop_tail = list_ends_at_loop_tail &&<br>
> + &<wbr>cf_node->node ==<br>
> exec_list_get_tail(cf_list);<br>
> + switch (cf_node->type) {<br>
> + case nir_cf_node_block:<br>
> + break;<br>
> +<br>
> + case nir_cf_node_if: {<br>
> + nir_if *nif = nir_cf_node_as_if(cf_node);<br>
> + if (lower_trivial_continues_list(<wbr>&nif->then_list,<br>
> at_loop_tail, loop))<br>
> + progress = true;<br>
> + if (lower_trivial_continues_list(<wbr>&nif->else_list,<br>
> at_loop_tail, loop))<br>
> + progress = true;<br>
> + break;<br>
> + }<br>
> +<br>
> + case nir_cf_node_loop: {<br>
> + nir_loop *loop = nir_cf_node_as_loop(cf_node);<br>
> + if (lower_trivial_continues_list(<wbr>&loop->body, true, loop))<br>
> + progress = true;<br>
> + if<br>
> (lower_trivial_continues_<wbr>block(nir_loop_last_block(<wbr>loop), loop))<br>
> + progress = true;<br>
> + break;<br>
> + }<br>
> +<br>
> + case nir_cf_node_function:<br>
> + unreachable("Invalid cf type");<br>
> + }<br>
> + }<br>
> +<br>
> + return progress;<br>
> +}<br>
> +<br>
> +/**<br>
> + * This simple pass gets rid of any "trivial" continues, i.e. those<br>
> that are<br>
> + * at the tail of a loop where we can just delete the continue<br>
> instruction and<br>
> + * control-flow will naturally and harmlessly take us back to the<br>
> top of the<br>
> + * loop.<br>
> + */<br>
> +bool<br>
> +nir_opt_trivial_continues(<wbr>nir_shader *shader)<br>
> +{<br>
> + bool progress = false;<br>
> +<br>
> + nir_foreach_function(<wbr>function, shader) {<br>
> + if (function->impl == NULL)<br>
> + continue;<br>
> +<br>
> + /* First we run the simple pass to get rid of pesky continues<br>
> */<br>
> + if (lower_trivial_continues_list(<wbr>&function->impl->body, false,<br>
> NULL)) {<br>
> + nir_metadata_<wbr>preserve(function->impl, nir_metadata_none);<br>
> +<br>
> + /* If that made progress, we're no longer really in SSA<br>
> form. Go<br>
> + * back into SSA form and clean up.<br>
> + */<br>
> + nir_convert_to_ssa_<wbr>impl(function->impl);<br>
> + nir_copy_prop_impl(<wbr>function->impl);<br>
> + nir_opt_dce_impl(<wbr>function->impl);<br>
<br>
</div>Just curious why you explicitly call these rather than just let them<br>
get cleaned up normally? Does it cut compile times to get rid of them<br>
straight away?<br></blockquote></div></div></div><div dir="auto"><br></div><div dir="auto">The nir_opt_if pass I wrote relies on this pass. Of this pass is run, it also needs copy_prop and dce. This potentially allows is to drop an iteration of the optimization loop. Another option would be to do this in brw_nir.c:</div><div dir="auto"><br></div><div dir="auto">if (OPT(nir_opt_trivial_continues)) {</div><div dir="auto"> OPT(nir_opt_copy_prop);</div><div dir="auto"> OPT(nir_opt_dce);</div><div dir="auto">}</div><div dir="auto"><br></div><div dir="auto">I don't have a strong preference either way.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Anyway this looks good to me and very easy to follow:<br>
<br>
Reviewed-by: Timothy Arceri <<a href="mailto:timothy.arceri@collabora.com">timothy.arceri@collabora.com</a>><br>
<div class="elided-text"><br>
> + progress = true;<br>
> + }<br>
> + }<br>
> +<br>
> + return progress;<br>
> +}</div></blockquote></div></div></div></div>