Mesa (7.10): glsl: Unroll loops with conditional breaks anywhere ( not just the end)

Ian Romanick idr at kemper.freedesktop.org
Fri Dec 10 00:45:31 UTC 2010


Module: Mesa
Branch: 7.10
Commit: 0e50c21e247b6d4246fcc2b583563a8f44bc4249
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=0e50c21e247b6d4246fcc2b583563a8f44bc4249

Author: Luca Barbieri <luca at luca-barbieri.com>
Date:   Wed Dec  1 15:12:07 2010 -0800

glsl: Unroll loops with conditional breaks anywhere (not just the end)

Currently we only unroll loops with conditional breaks at the end, which is
the form that lower_jumps generates.

However, if breaks are not lowered, they tend to appear at the beginning, so
add support for a conditional break anywhere.

Signed-off-by: Luca Barbieri <luca at luca-barbieri.com>
Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>

---

 src/glsl/loop_unroll.cpp |  114 +++++++++++++++++++++++++++------------------
 1 files changed, 68 insertions(+), 46 deletions(-)

diff --git a/src/glsl/loop_unroll.cpp b/src/glsl/loop_unroll.cpp
index c5001ba..4600052 100644
--- a/src/glsl/loop_unroll.cpp
+++ b/src/glsl/loop_unroll.cpp
@@ -81,42 +81,74 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
    if (ls->num_loop_jumps > 1)
       return visit_continue;
    else if (ls->num_loop_jumps) {
-      /* recognize loops in the form produced by ir_lower_jumps */
-      ir_instruction *last_ir =
-	 ((ir_instruction*)ir->body_instructions.get_tail());
-
+      ir_instruction *last_ir = (ir_instruction *) ir->body_instructions.get_tail();
       assert(last_ir != NULL);
 
-      ir_if *last_if = last_ir->as_if();
-      if (last_if) {
-	 bool continue_from_then_branch;
-
-	 /* Determine which if-statement branch, if any, ends with a break.
-	  * The branch that did *not* have the break will get a temporary
-	  * continue inserted in each iteration of the loop unroll.
-	  *
-	  * Note that since ls->num_loop_jumps is <= 1, it is impossible for
-	  * both branches to end with a break.
-	  */
-	 ir_instruction *last =
-	    (ir_instruction *) last_if->then_instructions.get_tail();
-
-	 if (is_break(last)) {
-	    continue_from_then_branch = false;
-	 } else {
-	    last = (ir_instruction *) last_if->else_instructions.get_tail();
-
-	    if (is_break(last))
-	       continue_from_then_branch = true;
-	    else
-	       /* Bail out if neither if-statement branch ends with a break.
+      if (is_break(last_ir)) {
+         /* If the only loop-jump is a break at the end of the loop, the loop
+          * will execute exactly once.  Remove the break, set the iteration
+          * count, and fall through to the normal unroller.
+          */
+         last_ir->remove();
+         iterations = 1;
+
+         this->progress = true;
+      } else {
+         ir_if *ir_if = NULL;
+         ir_instruction *break_ir = NULL;
+         bool continue_from_then_branch = false;
+
+         foreach_list(node, &ir->body_instructions) {
+            /* recognize loops in the form produced by ir_lower_jumps */
+            ir_instruction *cur_ir = (ir_instruction *) node;
+
+            ir_if = cur_ir->as_if();
+            if (ir_if != NULL) {
+	       /* Determine which if-statement branch, if any, ends with a
+		* break.  The branch that did *not* have the break will get a
+		* temporary continue inserted in each iteration of the loop
+		* unroll.
+		*
+		* Note that since ls->num_loop_jumps is <= 1, it is impossible
+		* for both branches to end with a break.
 		*/
-	       return visit_continue;
-	 }
+               ir_instruction *ir_if_last =
+                  (ir_instruction *) ir_if->then_instructions.get_tail();
+
+               if (is_break(ir_if_last)) {
+                  continue_from_then_branch = false;
+                  break_ir = ir_if_last;
+                  break;
+               } else {
+                  ir_if_last =
+		     (ir_instruction *) ir_if->else_instructions.get_tail();
+
+                  if (is_break(ir_if_last)) {
+                     break_ir = ir_if_last;
+                     continue_from_then_branch = true;
+                     break;
+                  }
+               }
+            }
+         }
+
+         if (break_ir == NULL)
+            return visit_continue;
 
-	 /* Remove the break from the if-statement.
-	  */
-	 last->remove();
+         /* move instructions after then if in the continue branch */
+         while (!ir_if->get_next()->is_tail_sentinel()) {
+            ir_instruction *move_ir = (ir_instruction *) ir_if->get_next();
+
+            move_ir->remove();
+            if (continue_from_then_branch)
+               ir_if->then_instructions.push_tail(move_ir);
+            else
+               ir_if->else_instructions.push_tail(move_ir);
+         }
+
+         /* Remove the break from the if-statement.
+          */
+         break_ir->remove();
 
          void *const mem_ctx = talloc_parent(ir);
          ir_instruction *ir_to_replace = ir;
@@ -127,8 +159,8 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
             copy_list.make_empty();
             clone_ir_list(mem_ctx, &copy_list, &ir->body_instructions);
 
-            last_if = ((ir_instruction*)copy_list.get_tail())->as_if();
-            assert(last_if);
+            ir_if = ((ir_instruction *) copy_list.get_tail())->as_if();
+            assert(ir_if != NULL);
 
             ir_to_replace->insert_before(&copy_list);
             ir_to_replace->remove();
@@ -138,7 +170,7 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
 	       new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_continue);
 
             exec_list *const list = (continue_from_then_branch)
-	       ? &last_if->then_instructions : &last_if->else_instructions;
+               ? &ir_if->then_instructions : &ir_if->else_instructions;
 
             list->push_tail(ir_to_replace);
          }
@@ -147,17 +179,7 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
 
          this->progress = true;
          return visit_continue;
-      } else if (is_break(last_ir)) {
-	 /* If the only loop-jump is a break at the end of the loop, the loop
-	  * will execute exactly once.  Remove the break, set the iteration
-	  * count, and fall through to the normal unroller.
-	  */
-         last_ir->remove();
-	 iterations = 1;
-
-	 this->progress = true;
-      } else
-         return visit_continue;
+      }
    }
 
    void *const mem_ctx = talloc_parent(ir);




More information about the mesa-commit mailing list