Mesa (glsl2): glsl2: Add a new pass at the IR level to break down matrix ops to vector ops.

Eric Anholt anholt at kemper.freedesktop.org
Mon Jul 12 20:34:57 UTC 2010


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

Author: Eric Anholt <eric at anholt.net>
Date:   Mon Jul 12 11:04:07 2010 -0700

glsl2: Add a new pass at the IR level to break down matrix ops to vector ops.

This will be used by the Mesa IR and likely most HW backends, as it
allows other optimizations to occur that might not otherwise.

Fixes glsl-vs-mat-sub-1, glsl-vs-mat-div-1.

---

 src/glsl/Makefile              |    1 +
 src/glsl/ir.h                  |    6 ++
 src/glsl/ir_mat_op_to_vec.cpp  |  188 ++++++++++++++++++++++++++++++++++++++++
 src/glsl/ir_optimization.h     |    1 +
 src/mesa/shader/ir_to_mesa.cpp |    1 +
 5 files changed, 197 insertions(+), 0 deletions(-)

diff --git a/src/glsl/Makefile b/src/glsl/Makefile
index ddc9d82..a36ff28 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_mat_op_to_vec.cpp \
 	ir_mod_to_fract.cpp \
 	ir_print_visitor.cpp \
 	ir_reader.cpp \
diff --git a/src/glsl/ir.h b/src/glsl/ir.h
index 500a8c7..0d5bbc2 100644
--- a/src/glsl/ir.h
+++ b/src/glsl/ir.h
@@ -74,6 +74,7 @@ public:
    virtual class ir_dereference *       as_dereference()      { return NULL; }
    virtual class ir_dereference_array *	as_dereference_array() { return NULL; }
    virtual class ir_dereference_variable *as_dereference_variable() { return NULL; }
+   virtual class ir_expression *        as_expression()       { return NULL; }
    virtual class ir_rvalue *            as_rvalue()           { return NULL; }
    virtual class ir_loop *              as_loop()             { return NULL; }
    virtual class ir_assignment *        as_assignment()       { return NULL; }
@@ -603,6 +604,11 @@ public:
    ir_expression(int op, const struct glsl_type *type,
 		 ir_rvalue *, ir_rvalue *);
 
+   virtual ir_expression *as_expression()
+   {
+      return this;
+   }
+
    virtual ir_expression *clone(struct hash_table *ht) const;
 
    static unsigned int get_num_operands(ir_expression_operation);
diff --git a/src/glsl/ir_mat_op_to_vec.cpp b/src/glsl/ir_mat_op_to_vec.cpp
new file mode 100644
index 0000000..828c63c
--- /dev/null
+++ b/src/glsl/ir_mat_op_to_vec.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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_mat_op_to_vec.cpp
+ *
+ * Breaks matrix operation expressions down to a series of vector operations.
+ *
+ * Generally this is how we have to codegen matrix operations for a
+ * GPU, so this gives us the chance to constant fold operations on a
+ * column or row.
+ */
+
+#include "ir.h"
+#include "ir_expression_flattening.h"
+#include "glsl_types.h"
+
+class ir_mat_op_to_vec_visitor : public ir_hierarchical_visitor {
+public:
+   ir_mat_op_to_vec_visitor()
+   {
+      this->made_progress = false;
+   }
+
+   ir_visitor_status visit_leave(ir_assignment *);
+
+   ir_rvalue *get_column(ir_variable *var, int i);
+
+   bool made_progress;
+};
+
+static bool
+mat_op_to_vec_predicate(ir_instruction *ir)
+{
+   ir_expression *expr = ir->as_expression();
+   unsigned int i;
+
+   if (!expr)
+      return false;
+
+   for (i = 0; i < expr->get_num_operands(); i++) {
+      if (expr->operands[i]->type->is_matrix())
+	 return true;
+   }
+
+   return false;
+}
+
+bool
+do_mat_op_to_vec(exec_list *instructions)
+{
+   ir_mat_op_to_vec_visitor v;
+
+   /* Pull out any matrix expression to a separate assignment to a
+    * temp.  This will make our handling of the breakdown to
+    * operations on the matrix's vector components much easier.
+    */
+   do_expression_flattening(instructions, mat_op_to_vec_predicate);
+
+   visit_list_elements(&v, instructions);
+
+   return v.made_progress;
+}
+
+ir_rvalue *
+ir_mat_op_to_vec_visitor::get_column(ir_variable *var, int i)
+{
+   ir_dereference *deref;
+
+   if (!var->type->is_matrix()) {
+      deref = new(base_ir) ir_dereference_variable(var);
+   } else {
+      deref = new(base_ir) ir_dereference_variable(var);
+      deref = new(base_ir) ir_dereference_array(deref,
+						new(base_ir) ir_constant(i));
+   }
+
+   return deref;
+}
+
+ir_visitor_status
+ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *assign)
+{
+   ir_expression *expr = assign->rhs->as_expression();
+   bool found_matrix = false;
+   unsigned int i, matrix_columns = 1;
+   ir_variable *op_var[2];
+
+   if (!expr)
+      return visit_continue;
+
+   for (i = 0; i < expr->get_num_operands(); i++) {
+      if (expr->operands[i]->type->is_matrix()) {
+	 found_matrix = true;
+	 matrix_columns = expr->operands[i]->type->matrix_columns;
+	 break;
+      }
+   }
+   if (!found_matrix)
+      return visit_continue;
+
+   /* FINISHME: see below */
+   if (expr->operation == ir_binop_mul)
+      return visit_continue;
+
+   ir_dereference_variable *lhs_deref = assign->lhs->as_dereference_variable();
+   assert(lhs_deref);
+
+   ir_variable *result_var = lhs_deref->var;
+
+   /* Store the expression operands in temps so we can use them
+    * multiple times.
+    */
+   for (i = 0; i < expr->get_num_operands(); i++) {
+      ir_assignment *assign;
+
+      op_var[i] = new(base_ir) ir_variable(expr->operands[i]->type,
+					   "mat_op_to_vec");
+      base_ir->insert_before(op_var[i]);
+
+      lhs_deref = new(base_ir) ir_dereference_variable(op_var[i]);
+      assign = new(base_ir) ir_assignment(lhs_deref,
+					  expr->operands[i],
+					  NULL);
+      base_ir->insert_before(assign);
+   }
+
+   /* OK, time to break down this matrix operation. */
+   switch (expr->operation) {
+   case ir_binop_add:
+   case ir_binop_sub:
+   case ir_binop_div:
+   case ir_binop_mod:
+      /* For most operations, the matrix version is just going
+       * column-wise through and applying the operation to each column
+       * if available.
+       */
+      for (i = 0; i < matrix_columns; i++) {
+	 ir_rvalue *op0 = get_column(op_var[0], i);
+	 ir_rvalue *op1 = get_column(op_var[1], i);
+	 ir_rvalue *result = get_column(result_var, i);
+	 ir_expression *column_expr;
+	 ir_assignment *column_assign;
+
+	 column_expr = new(base_ir) ir_expression(expr->operation,
+						  result->type,
+						  op0,
+						  op1);
+
+	 column_assign = new(base_ir) ir_assignment(result,
+						    column_expr,
+						    NULL);
+	 base_ir->insert_before(column_assign);
+      }
+      break;
+   case ir_binop_mul:
+      /* FINISHME */
+      return visit_continue;
+      break;
+   default:
+      printf("FINISHME: Handle matrix operation for %s\n", expr->operator_string());
+      abort();
+   }
+   assign->remove();
+   this->made_progress = true;
+
+   return visit_continue;
+}
diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h
index b03c064..fae583d 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_mat_op_to_vec(exec_list *instructions);
 bool do_mod_to_fract(exec_list *instructions);
 bool do_swizzle_swizzle(exec_list *instructions);
 bool do_vec_index_to_cond_assign(exec_list *instructions);
diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp
index 708c6fe..81b9191 100644
--- a/src/mesa/shader/ir_to_mesa.cpp
+++ b/src/mesa/shader/ir_to_mesa.cpp
@@ -1960,6 +1960,7 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader)
       _mesa_ast_to_hir(shader->ir, state);
 
    /* Lowering */
+   do_mat_op_to_vec(shader->ir);
    do_mod_to_fract(shader->ir);
    do_div_to_mul_rcp(shader->ir);
 




More information about the mesa-commit mailing list