Commit e4a5db47 authored by Timothy Arceri's avatar Timothy Arceri

nir: add loop unroll support for wrapper loops

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
parent 1546b99e
......@@ -516,6 +516,69 @@ process_loops(nir_shader *sh, nir_cf_node *cf_node, bool *has_nested_loop)
*/
if (!progress) {
/* Check for the 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) {
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;
}
goto exit;
}
if (*has_nested_loop || loop->info->limiting_terminator == NULL)
goto exit;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment