On Mon, Jul 23, 2018 at 3:02 AM Timothy Arceri <tarc...@itsqueeze.com> wrote:
> This adds support for unrolling the classic > > do { > // ... > } while (false) > > that is used to wrap multi-line macros. GLSL IR also wraps switch > statements in a loop like this. > > shader-db results IVB: > > total loops in shared programs: 2515 -> 2512 (-0.12%) > loops in affected programs: 33 -> 30 (-9.09%) > helped: 3 > HURT: 0 > --- > src/compiler/nir/nir_opt_loop_unroll.c | 77 ++++++++++++++++++++++++++ > 1 file changed, 77 insertions(+) > > diff --git a/src/compiler/nir/nir_opt_loop_unroll.c > b/src/compiler/nir/nir_opt_loop_unroll.c > index e0e0b754716..9c33267cb72 100644 > --- a/src/compiler/nir/nir_opt_loop_unroll.c > +++ b/src/compiler/nir/nir_opt_loop_unroll.c > @@ -465,6 +465,65 @@ complex_unroll(nir_loop *loop, nir_loop_terminator > *unlimit_term, > _mesa_hash_table_destroy(remap_table, NULL); > } > > +/* Unrolls the classic wrapper loops e.g > + * > + * do { > + * // ... > + * } while (false) > + */ > +static bool > +wrapper_unroll(nir_loop *loop) > +{ > + bool progress = false; > + > + nir_block *blk_after_loop = > + nir_cursor_current_block(nir_after_cf_node(&loop->cf_node)); > + > + /* There may still be some single src phis following the loop that > + * have not yet been cleaned up by another pass. Tidy those up before > + * unrolling the loop. > + */ > + nir_foreach_instr_safe(instr, blk_after_loop) { > + if (instr->type != nir_instr_type_phi) > + break; > + > + nir_phi_instr *phi = nir_instr_as_phi(instr); > + assert(exec_list_length(&phi->srcs) == 1); > + > + nir_phi_src *phi_src = exec_node_data(nir_phi_src, > + > exec_list_get_head(&phi->srcs), > + node); > + > + nir_ssa_def_rewrite_uses(&phi->dest.ssa, phi_src->src); > + nir_instr_remove(instr); > + > + progress = true; > + } > + > + nir_block *last_loop_blk = nir_loop_last_block(loop); > + if (nir_block_ends_in_break(last_loop_blk)) { > + > + /* Remove break at end of the loop */ > + nir_instr *break_instr = nir_block_last_instr(last_loop_blk); > + nir_instr_remove(break_instr); > + > + /* Pluck out the loop body. */ > + nir_cf_list loop_body; > + nir_cf_extract(&loop_body, > nir_before_block(nir_loop_first_block(loop)), > + nir_after_block(nir_loop_last_block(loop))); > + > + /* Reinsert loop body after the loop */ > + nir_cf_reinsert(&loop_body, nir_after_cf_node(&loop->cf_node)); > + > + /* The loop has been unrolled so remove it. */ > + nir_cf_node_remove(&loop->cf_node); > + > + progress = true; > + } > + > + return progress; > +} > + > static bool > is_loop_small_enough_to_unroll(nir_shader *shader, nir_loop_info *li) > { > @@ -516,6 +575,24 @@ process_loops(nir_shader *sh, nir_cf_node *cf_node, > bool *has_nested_loop_out) > */ > if (!progress) { > > + /* Check for the classic > + * > + * do { > + * // ... > + * } while (false) > + * > + * that is used to wrap multi-line macros. GLSL IR also wraps switch > + * statements in a loop like this. > + */ > + if (loop->info->limiting_terminator == NULL && > + list_empty(&loop->info->loop_terminator_list) && > + !loop->info->complex_loop) { > What does this do with "do { } while (true)"? Would those also hit this path? If they do, unrolling them is probably ok since it's a GPU hang if we don't but I thought it was worth asking. > + > + progress = wrapper_unroll(loop); > + > + goto exit; > + } > + > if (has_nested_loop || loop->info->limiting_terminator == NULL) > goto exit; > > -- > 2.17.1 > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/mesa-dev >
_______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev