Mesa (glsl2): glsl2: Make sure functions end with a return before doing ir_if_return.

Eric Anholt anholt at kemper.freedesktop.org
Thu Jul 29 23:18:11 UTC 2010


Module: Mesa
Branch: glsl2
Commit: a62ef12ef242ecd48887df2aa2052d2ecb0979f7
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=a62ef12ef242ecd48887df2aa2052d2ecb0979f7

Author: Eric Anholt <eric at anholt.net>
Date:   Thu Jul 29 13:29:17 2010 -0700

glsl2: Make sure functions end with a return before doing ir_if_return.

This catches a few remaining functions that weren't getting inlined,
generally operating on global or out variables and using an early
return to skip work when possible.

Fixes for i965:
glsl1-function with early return (3)

---

 src/glsl/ir_if_return.cpp |   62 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 61 insertions(+), 1 deletions(-)

diff --git a/src/glsl/ir_if_return.cpp b/src/glsl/ir_if_return.cpp
index 4d59e70..293f7aa 100644
--- a/src/glsl/ir_if_return.cpp
+++ b/src/glsl/ir_if_return.cpp
@@ -24,13 +24,16 @@
 /**
  * \file ir_if_return.cpp
  *
- * This pass tries to normalize functions to always return from one place.
+ * This pass tries to normalize functions to always return from one
+ * place by moving around blocks of code in if statements.
  *
  * This helps on hardware with no branching support, and may even be a
  * useful transform on hardware supporting control flow by turning
  * masked returns into normal returns.
  */
 
+#include <string.h>
+#include "glsl_types.h"
 #include "ir.h"
 
 class ir_if_return_visitor : public ir_hierarchical_visitor {
@@ -40,6 +43,7 @@ public:
       this->progress = false;
    }
 
+   ir_visitor_status visit_enter(ir_function_signature *);
    ir_visitor_status visit_enter(ir_if *);
 
    void move_outer_block_inside(ir_instruction *ir,
@@ -138,6 +142,62 @@ ir_if_return_visitor::move_outer_block_inside(ir_instruction *ir,
    }
 }
 
+/* Normalize a function to always have a return statement at the end.
+ *
+ * This avoids the ir_if handler needing to know whether it is at the
+ * top level of the function to know if there's an implicit return at
+ * the end of the outer block.
+ */
+ir_visitor_status
+ir_if_return_visitor::visit_enter(ir_function_signature *ir)
+{
+   ir_return *ret;
+
+   if (!ir->is_defined)
+      return visit_continue_with_parent;
+   if (strcmp(ir->function_name(), "main") == 0)
+      return visit_continue_with_parent;
+
+   ret = find_return_in_block(&ir->body);
+
+   if (ret) {
+      truncate_after_instruction(ret);
+   } else {
+      if (ir->return_type->is_void()) {
+	 ir->body.push_tail(new(ir) ir_return(NULL));
+      } else {
+	 /* Probably, if we've got a function with a return value
+	  * hitting this point, it's something like:
+	  *
+	  * float reduce_below_half(float val)
+	  * {
+	  *         while () {
+	  *                 if (val >= 0.5)
+	  *                         val /= 2.0;
+	  *                 else
+	  *                         return val;
+	  *         }
+	  * }
+	  *
+	  * So we gain a junk return statement of an undefined value
+	  * at the end that never gets executed.  However, a backend
+	  * using this pass is probably desperate to get rid of
+	  * function calls, so go ahead and do it for their sake in
+	  * case it fixes apps.
+	  */
+	 ir_variable *undef = new(ir) ir_variable(ir->return_type,
+						  "if_return_undef",
+						  ir_var_temporary);
+	 ir->body.push_tail(undef);
+
+	 ir_dereference_variable *deref = new(ir) ir_dereference_variable(undef);
+	 ir->body.push_tail(new(ir) ir_return(deref));
+      }
+   }
+
+   return visit_continue;
+}
+
 ir_visitor_status
 ir_if_return_visitor::visit_enter(ir_if *ir)
 {




More information about the mesa-commit mailing list