Mesa (master): glsl: lower unconditional returns and continues in loops.

Paul Berry stereotype441 at kemper.freedesktop.org
Fri Jul 8 17:03:40 UTC 2011


Module: Mesa
Branch: master
Commit: 03145ba655ad9173a74b853843eccaae78ff392f
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=03145ba655ad9173a74b853843eccaae78ff392f

Author: Paul Berry <stereotype441 at gmail.com>
Date:   Fri Jul  1 18:26:05 2011 -0700

glsl: lower unconditional returns and continues in loops.

Previously, lower_jumps.cpp would only lower return and continue
statements that appeared inside conditionals.  This patch makes it
lower unconditional returns and continue statements that occur inside
a loop.

Such unconditional flow control statements would be unlikely to be
explicitly coded by a reasonable user, however they might arise as a
result of other optimizations.

Without this patch, lower_jumps.cpp might not lower certain return and
continue statements, causing some backends to fail.

Fixes unit tests test_lower_return_void_at_end_of_loop and
test_remove_continue_at_end_of_loop.

---

 src/glsl/lower_jumps.cpp |   62 ++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/src/glsl/lower_jumps.cpp b/src/glsl/lower_jumps.cpp
index eceba09..cbdd8ea 100644
--- a/src/glsl/lower_jumps.cpp
+++ b/src/glsl/lower_jumps.cpp
@@ -304,6 +304,43 @@ struct ir_lower_jumps_visitor : public ir_control_flow_visitor {
       }
    }
 
+   /**
+    * Insert the instructions necessary to lower a return statement,
+    * before the given return instruction.
+    */
+   void insert_lowered_return(ir_return *ir)
+   {
+      ir_variable* return_flag = this->function.get_return_flag();
+      if(!this->function.signature->return_type->is_void()) {
+         ir_variable* return_value = this->function.get_return_value();
+         ir->insert_before(
+            new(ir) ir_assignment(
+               new (ir) ir_dereference_variable(return_value),
+               ir->value));
+      }
+      ir->insert_before(
+         new(ir) ir_assignment(
+            new (ir) ir_dereference_variable(return_flag),
+            new (ir) ir_constant(true)));
+      this->loop.may_set_return_flag = true;
+   }
+
+   /**
+    * If the given instruction is a return, lower it to instructions
+    * that store the return value (if there is one), set the return
+    * flag, and then break.
+    *
+    * It is safe to pass NULL to this function.
+    */
+   void lower_return_unconditionally(ir_instruction *ir)
+   {
+      if (get_jump_strength(ir) != strength_return) {
+         return;
+      }
+      insert_lowered_return((ir_return*)ir);
+      ir->replace_with(new(ir) ir_loop_jump(ir_loop_jump::jump_break));
+   }
+
    virtual void visit(class ir_loop_jump * ir)
    {
       /* Eliminate all instructions after each one, since they are
@@ -532,13 +569,7 @@ retry: /* we get here if we put code after the if inside a branch */
              * that: 1. store the return value (if this function has a
              * non-void return) and 2. set the return flag
              */
-            ir_variable* return_flag = this->function.get_return_flag();
-            if(!this->function.signature->return_type->is_void()) {
-               ir_variable* return_value = this->function.get_return_value();
-               jumps[lower]->insert_before(new(ir) ir_assignment(new (ir) ir_dereference_variable(return_value), ((ir_return*)jumps[lower])->value, NULL));
-            }
-            jumps[lower]->insert_before(new(ir) ir_assignment(new (ir) ir_dereference_variable(return_flag), new (ir) ir_constant(true), NULL));
-            this->loop.may_set_return_flag = true;
+            insert_lowered_return((ir_return*)jumps[lower]);
             if(this->loop.loop) {
                /* If we are in a loop, replace the return instruction
                 * with a break instruction, and then loop so that the
@@ -761,10 +792,25 @@ lower_continue:
       /* Recursively lower nested jumps.  This satisfies the
        * CONTAINED_JUMPS_LOWERED postcondition, except in the case of
        * an unconditional continue or return at the bottom of the
-       * loop.
+       * loop, which are handled below.
        */
       block_record body = visit_block(&ir->body_instructions);
 
+      /* If the loop ends in an unconditional continue, eliminate it
+       * because it is redundant.
+       */
+      ir_instruction *ir_last
+         = (ir_instruction *) ir->body_instructions.get_tail();
+      if (get_jump_strength(ir_last) == strength_continue) {
+         ir_last->remove();
+      }
+
+      /* If the loop ends in an unconditional return, and we are
+       * lowering returns, lower it.
+       */
+      if (this->function.lower_return)
+         lower_return_unconditionally(ir_last);
+
       if(body.min_strength >= strength_break) {
          /* FINISHME: If the min_strength of the loop body is
           * strength_break or strength_return, that means that it




More information about the mesa-commit mailing list