Module: Mesa Branch: main Commit: 7fba5abfd7f749c2d0ec73d77e6e7119c262341e URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=7fba5abfd7f749c2d0ec73d77e6e7119c262341e
Author: Daniel Schürmann <[email protected]> Date: Thu Dec 2 11:08:31 2021 +0100 nir/lower_continue_constructs: special-case Continue Constructs with zero or one predecessors If a loop has only a single continue, the control flow is already converged and we can inline the continue construct. If a loop has no continue statement at all, the Continue Construct is unreachable and can simply be deleted. Reviewed-by: Faith Ekstrand <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13962> --- src/compiler/nir/nir_lower_continue_constructs.c | 81 ++++++++++++++++-------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/src/compiler/nir/nir_lower_continue_constructs.c b/src/compiler/nir/nir_lower_continue_constructs.c index 96114b06a86..f9ead9a7d7f 100644 --- a/src/compiler/nir/nir_lower_continue_constructs.c +++ b/src/compiler/nir/nir_lower_continue_constructs.c @@ -36,35 +36,66 @@ lower_loop_continue_block(nir_builder *b, nir_loop *loop) nir_block *header = nir_loop_first_block(loop); nir_block *cont = nir_loop_first_continue_block(loop); + /* count continue statements excluding unreachable ones */ + unsigned num_continue = 0; + nir_block *single_predecessor = NULL; + set_foreach(cont->predecessors, entry) { + nir_block *pred = (nir_block*) entry->key; + /* If the continue block has no predecessors, it is unreachable. */ + if (pred->predecessors->entries == 0) + continue; + + single_predecessor = pred; + if (num_continue++) + break; + } + nir_lower_phis_to_regs_block(header); - nir_lower_phis_to_regs_block(cont); - - /* As control flow has to re-converge before executing the continue - * construct, we insert it at the beginning of the loop with a flag - * to ensure that it doesn't get executed in the first iteration: - * - * loop { - * if (i != 0) { - * continue construct - * } - * loop body - * } - */ - - nir_variable *do_cont = - nir_local_variable_create(b->impl, glsl_bool_type(), "cont"); - - b->cursor = nir_before_cf_node(&loop->cf_node); - nir_store_var(b, do_cont, nir_imm_false(b), 1); - b->cursor = nir_before_block(header); - nir_if *cont_if = nir_push_if(b, nir_load_var(b, do_cont)); - { + + if (num_continue == 0) { + /* this loop doesn't continue at all. delete the continue construct */ nir_cf_list extracted; nir_cf_list_extract(&extracted, &loop->continue_list); - nir_cf_reinsert(&extracted, nir_before_cf_list(&cont_if->then_list)); + nir_cf_delete(&extracted); + } else if (num_continue == 1) { + /* inline the continue construct */ + assert(single_predecessor->successors[0] == cont); + assert(single_predecessor->successors[1] == NULL); + + nir_cf_list extracted; + nir_cf_list_extract(&extracted, &loop->continue_list); + nir_cf_reinsert(&extracted, + nir_after_block_before_jump(single_predecessor)); + } else { + nir_lower_phis_to_regs_block(cont); + + /* As control flow has to re-converge before executing the continue + * construct, we insert it at the beginning of the loop with a flag + * to ensure that it doesn't get executed in the first iteration: + * + * loop { + * if (i != 0) { + * continue construct + * } + * loop body + * } + */ + + nir_variable *do_cont = + nir_local_variable_create(b->impl, glsl_bool_type(), "cont"); + + b->cursor = nir_before_cf_node(&loop->cf_node); + nir_store_var(b, do_cont, nir_imm_false(b), 1); + b->cursor = nir_before_block(header); + nir_if *cont_if = nir_push_if(b, nir_load_var(b, do_cont)); + { + nir_cf_list extracted; + nir_cf_list_extract(&extracted, &loop->continue_list); + nir_cf_reinsert(&extracted, nir_before_cf_list(&cont_if->then_list)); + } + nir_pop_if(b, cont_if); + nir_store_var(b, do_cont, nir_imm_true(b), 1); } - nir_pop_if(b, cont_if); - nir_store_var(b, do_cont, nir_imm_true(b), 1); nir_loop_remove_continue_construct(loop); return true;
