Module: Mesa
Branch: shader-work
Commit: fa93dadda31decb7869fc856f58b5eaade284923
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=fa93dadda31decb7869fc856f58b5eaade284923

Author: Luca Barbieri <l...@luca-barbieri.com>
Date:   Tue Sep 14 04:56:34 2010 +0200

glsl/loop_unroll: unroll loops with cond breaks anywhere, not just the end

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

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

---

 src/glsl/loop_unroll.cpp |  130 +++++++++++++++++++++++++++-------------------
 1 files changed, 76 insertions(+), 54 deletions(-)

diff --git a/src/glsl/loop_unroll.cpp b/src/glsl/loop_unroll.cpp
index 90797bd..6308907 100644
--- a/src/glsl/loop_unroll.cpp
+++ b/src/glsl/loop_unroll.cpp
@@ -73,44 +73,77 @@ 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());
-
-      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 (last && last->ir_type == ir_type_loop_jump
-            && ((ir_loop_jump*) last)->is_break()) {
-           continue_from_then_branch = false;
-        } else {
-           last = (ir_instruction *) last_if->then_instructions.get_tail();
-
-           if (last && last->ir_type == ir_type_loop_jump
-               && ((ir_loop_jump*) last)->is_break())
-              continue_from_then_branch = true;
-           else
-              /* Bail out if neither if-statement branch ends with a break.
-               */
-              return visit_continue;
-        }
-
-        /* Remove the break from the if-statement.
-         */
-        last->remove();
+      ir_instruction *last_ir = 
((ir_instruction*)ir->body_instructions.get_tail());
+
+      if (last_ir->ir_type == ir_type_loop_jump
+            && ((ir_loop_jump*)last_ir)->is_break()) {
+         /* 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 = 0;
+         ir_instruction *break_ir = 0;
+         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;
+
+            assert(last_ir != NULL);
+
+            ir_if = cur_ir->as_if();
+            if (ir_if) {
+               /* 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 *ir_if_last =
+                  (ir_instruction *) ir_if->then_instructions.get_tail();
+
+               if (ir_if_last && ir_if_last->ir_type == ir_type_loop_jump
+                   && ((ir_loop_jump*) ir_if_last)->is_break()) {
+                  continue_from_then_branch = false;
+                  break_ir = ir_if_last;
+                  break;
+               } else {
+                  ir_if_last = (ir_instruction *) 
ir_if->then_instructions.get_tail();
+
+                  if (ir_if_last && ir_if_last->ir_type == ir_type_loop_jump
+                      && ((ir_loop_jump*) ir_if_last)->is_break())
+                  {
+                     break_ir = ir_if_last;
+                     continue_from_then_branch = true;
+                     break;
+                  }
+               }
+            }
+         }
+
+         if(!break_ir)
+            return visit_continue;
+
+         /* 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;
@@ -121,18 +154,18 @@ 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);
 
             ir_to_replace->insert_before(&copy_list);
             ir_to_replace->remove();
 
             /* placeholder that will be removed in the next iteration */
             ir_to_replace =
-              new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_continue);
+               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);
          }
@@ -141,18 +174,7 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
 
          this->progress = true;
          return visit_continue;
-      } else if (last_ir->ir_type == ir_type_loop_jump
-                && ((ir_loop_jump *)last_ir)->is_break()) {
-        /* 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);

_______________________________________________
mesa-commit mailing list
mesa-commit@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-commit

Reply via email to