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;

Reply via email to