Mesa (glsl2): glsl2: Add a pass for converting if statements to conditional assignment.

Eric Anholt anholt at kemper.freedesktop.org
Mon Jul 19 17:48:42 UTC 2010


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

Author: Eric Anholt <eric at anholt.net>
Date:   Mon Jul 19 09:36:43 2010 -0700

glsl2: Add a pass for converting if statements to conditional assignment.

This will be used on 915 and similar hardware of that generation.

---

 src/glsl/Makefile                 |    1 +
 src/glsl/ir_if_to_cond_assign.cpp |  167 +++++++++++++++++++++++++++++++++++++
 src/glsl/ir_optimization.h        |    1 +
 3 files changed, 169 insertions(+), 0 deletions(-)

diff --git a/src/glsl/Makefile b/src/glsl/Makefile
index a36ff28..c09735d 100644
--- a/src/glsl/Makefile
+++ b/src/glsl/Makefile
@@ -42,6 +42,7 @@ CXX_SOURCES = \
 	ir_hv_accept.cpp \
 	ir_if_return.cpp \
 	ir_if_simplification.cpp \
+	ir_if_to_cond_assign.cpp \
 	ir_mat_op_to_vec.cpp \
 	ir_mod_to_fract.cpp \
 	ir_print_visitor.cpp \
diff --git a/src/glsl/ir_if_to_cond_assign.cpp b/src/glsl/ir_if_to_cond_assign.cpp
new file mode 100644
index 0000000..274874b
--- /dev/null
+++ b/src/glsl/ir_if_to_cond_assign.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_if_to_cond_assign.cpp
+ *
+ * This attempts to flatten all if statements to conditional
+ * assignments for GPUs that don't do control flow.
+ *
+ * It can't handle other control flow being inside of its block, such
+ * as calls or loops.  Hopefully loop unrolling and inlining will take
+ * care of those.
+ */
+
+#include "glsl_types.h"
+#include "ir.h"
+
+class ir_if_to_cond_assign_visitor : public ir_hierarchical_visitor {
+public:
+   ir_if_to_cond_assign_visitor()
+   {
+      this->progress = false;
+   }
+
+   ir_visitor_status visit_leave(ir_if *);
+
+   bool progress;
+};
+
+bool
+do_if_to_cond_assign(exec_list *instructions)
+{
+   ir_if_to_cond_assign_visitor v;
+
+   visit_list_elements(&v, instructions);
+
+   return v.progress;
+}
+
+void
+check_control_flow(ir_instruction *ir, void *data)
+{
+   bool *found_control_flow = (bool *)data;
+   switch (ir->ir_type) {
+   case ir_type_call:
+   case ir_type_discard:
+   case ir_type_loop:
+   case ir_type_loop_jump:
+   case ir_type_return:
+      *found_control_flow = true;
+      break;
+   default:
+      break;
+   }
+}
+
+void
+move_block_to_cond_assign(void *mem_ctx,
+			  ir_if *if_ir, ir_variable *cond_var, bool then)
+{
+   exec_list *instructions;
+
+   if (then) {
+      instructions = &if_ir->then_instructions;
+   } else {
+      instructions = &if_ir->else_instructions;
+   }
+
+   foreach_iter(exec_list_iterator, iter, *instructions) {
+      ir_instruction *ir = (ir_instruction *)iter.get();
+
+      if (ir->ir_type == ir_type_assignment) {
+	 ir_assignment *assign = (ir_assignment *)ir;
+	 ir_rvalue *cond_expr;
+	 ir_dereference *deref = new(mem_ctx) ir_dereference_variable(cond_var);
+
+	 if (then) {
+	    cond_expr = deref;
+	 } else {
+	    cond_expr = new(mem_ctx) ir_expression(ir_unop_logic_not,
+						   glsl_type::bool_type,
+						   deref,
+						   NULL);
+	 }
+
+	 if (!assign->condition) {
+	    assign->condition = cond_expr;
+	 } else {
+	    assign->condition = new(mem_ctx) ir_expression(ir_binop_logic_and,
+							   glsl_type::bool_type,
+							   cond_expr,
+							   assign->condition);
+	 }
+      }
+
+      /* Now, move from the if block to the block surrounding it. */
+      ir->remove();
+      if_ir->insert_before(ir);
+   }
+}
+
+ir_visitor_status
+ir_if_to_cond_assign_visitor::visit_leave(ir_if *ir)
+{
+   bool found_control_flow = false;
+   ir_variable *cond_var;
+   ir_assignment *assign;
+   ir_dereference_variable *deref;
+
+   /* Check that both blocks don't contain anything we can't support. */
+   foreach_iter(exec_list_iterator, then_iter, ir->then_instructions) {
+      ir_instruction *then_ir = (ir_instruction *)then_iter.get();
+      visit_tree(then_ir, check_control_flow, &found_control_flow);
+   }
+   foreach_iter(exec_list_iterator, else_iter, ir->else_instructions) {
+      ir_instruction *else_ir = (ir_instruction *)else_iter.get();
+      visit_tree(else_ir, check_control_flow, &found_control_flow);
+   }
+   if (found_control_flow)
+      return visit_continue;
+
+   void *mem_ctx = talloc_parent(ir);
+
+   /* Store the condition to a variable so the assignment conditions are
+    * simpler.
+    */
+   cond_var = new(mem_ctx) ir_variable(glsl_type::bool_type,
+				       "if_to_cond_assign_condition");
+   ir->insert_before(cond_var);
+
+   deref = new(mem_ctx) ir_dereference_variable(cond_var);
+   assign = new(mem_ctx) ir_assignment(deref,
+				       ir->condition, NULL);
+   ir->insert_before(assign);
+
+   /* Now, move all of the instructions out of the if blocks, putting
+    * conditions on assignments.
+    */
+   move_block_to_cond_assign(mem_ctx, ir, cond_var, true);
+   move_block_to_cond_assign(mem_ctx, ir, cond_var, false);
+
+   ir->remove();
+
+   this->progress = true;
+
+   return visit_continue;
+}
diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h
index fae583d..06cb4d2 100644
--- a/src/glsl/ir_optimization.h
+++ b/src/glsl/ir_optimization.h
@@ -41,6 +41,7 @@ bool do_div_to_mul_rcp(exec_list *instructions);
 bool do_function_inlining(exec_list *instructions);
 bool do_if_return(exec_list *instructions);
 bool do_if_simplification(exec_list *instructions);
+bool do_if_to_cond_assign(exec_list *instructions);
 bool do_mat_op_to_vec(exec_list *instructions);
 bool do_mod_to_fract(exec_list *instructions);
 bool do_swizzle_swizzle(exec_list *instructions);




More information about the mesa-commit mailing list