*/
/**
- * \file ir_mat_op_to_vec.cpp
+ * \file lower_mat_op_to_vec.cpp
*
* Breaks matrix operation expressions down to a series of vector operations.
*
#include "ir_expression_flattening.h"
#include "glsl_types.h"
+namespace {
+
class ir_mat_op_to_vec_visitor : public ir_hierarchical_visitor {
public:
ir_mat_op_to_vec_visitor()
ir_visitor_status visit_leave(ir_assignment *);
- ir_dereference *get_column(ir_variable *var, int col);
- ir_rvalue *get_element(ir_variable *var, int col, int row);
+ ir_dereference *get_column(ir_dereference *val, int col);
+ ir_rvalue *get_element(ir_dereference *val, int col, int row);
- void do_mul_mat_mat(ir_variable *result_var,
- ir_variable *a_var, ir_variable *b_var);
- void do_mul_mat_vec(ir_variable *result_var,
- ir_variable *a_var, ir_variable *b_var);
- void do_mul_vec_mat(ir_variable *result_var,
- ir_variable *a_var, ir_variable *b_var);
- void do_mul_mat_scalar(ir_variable *result_var,
- ir_variable *a_var, ir_variable *b_var);
- void do_equal_mat_mat(ir_variable *result_var, ir_variable *a_var,
- ir_variable *b_var, bool test_equal);
+ void do_mul_mat_mat(ir_dereference *result,
+ ir_dereference *a, ir_dereference *b);
+ void do_mul_mat_vec(ir_dereference *result,
+ ir_dereference *a, ir_dereference *b);
+ void do_mul_vec_mat(ir_dereference *result,
+ ir_dereference *a, ir_dereference *b);
+ void do_mul_mat_scalar(ir_dereference *result,
+ ir_dereference *a, ir_dereference *b);
+ void do_equal_mat_mat(ir_dereference *result, ir_dereference *a,
+ ir_dereference *b, bool test_equal);
void *mem_ctx;
bool made_progress;
};
+} /* anonymous namespace */
+
static bool
mat_op_to_vec_predicate(ir_instruction *ir)
{
}
ir_rvalue *
-ir_mat_op_to_vec_visitor::get_element(ir_variable *var, int col, int row)
+ir_mat_op_to_vec_visitor::get_element(ir_dereference *val, int col, int row)
{
- ir_dereference *deref;
-
- deref = new(mem_ctx) ir_dereference_variable(var);
+ val = get_column(val, col);
- if (var->type->is_matrix()) {
- deref = new(mem_ctx) ir_dereference_array(var,
- new(mem_ctx) ir_constant(col));
- } else {
- assert(col == 0);
- }
-
- return new(mem_ctx) ir_swizzle(deref, row, 0, 0, 0, 1);
+ return new(mem_ctx) ir_swizzle(val, row, 0, 0, 0, 1);
}
ir_dereference *
-ir_mat_op_to_vec_visitor::get_column(ir_variable *var, int row)
+ir_mat_op_to_vec_visitor::get_column(ir_dereference *val, int row)
{
- ir_dereference *deref;
-
- if (!var->type->is_matrix()) {
- deref = new(mem_ctx) ir_dereference_variable(var);
- } else {
- deref = new(mem_ctx) ir_dereference_variable(var);
- deref = new(mem_ctx) ir_dereference_array(deref,
- new(mem_ctx) ir_constant(row));
+ val = val->clone(mem_ctx, NULL);
+
+ if (val->type->is_matrix()) {
+ val = new(mem_ctx) ir_dereference_array(val,
+ new(mem_ctx) ir_constant(row));
}
- return deref;
+ return val;
}
void
-ir_mat_op_to_vec_visitor::do_mul_mat_mat(ir_variable *result_var,
- ir_variable *a_var,
- ir_variable *b_var)
+ir_mat_op_to_vec_visitor::do_mul_mat_mat(ir_dereference *result,
+ ir_dereference *a,
+ ir_dereference *b)
{
- int b_col, i;
+ unsigned b_col, i;
ir_assignment *assign;
ir_expression *expr;
- for (b_col = 0; b_col < b_var->type->matrix_columns; b_col++) {
- ir_rvalue *a = get_column(a_var, 0);
- ir_rvalue *b = get_element(b_var, b_col, 0);
-
+ for (b_col = 0; b_col < b->type->matrix_columns; b_col++) {
/* first column */
expr = new(mem_ctx) ir_expression(ir_binop_mul,
- a->type,
- a,
- b);
+ get_column(a, 0),
+ get_element(b, b_col, 0));
/* following columns */
- for (i = 1; i < a_var->type->matrix_columns; i++) {
+ for (i = 1; i < a->type->matrix_columns; i++) {
ir_expression *mul_expr;
- a = get_column(a_var, i);
- b = get_element(b_var, b_col, i);
-
mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
- a->type,
- a,
- b);
+ get_column(a, i),
+ get_element(b, b_col, i));
expr = new(mem_ctx) ir_expression(ir_binop_add,
- a->type,
expr,
mul_expr);
}
- ir_rvalue *result = get_column(result_var, b_col);
- assign = new(mem_ctx) ir_assignment(result,
- expr,
- NULL);
+ assign = new(mem_ctx) ir_assignment(get_column(result, b_col), expr);
base_ir->insert_before(assign);
}
}
void
-ir_mat_op_to_vec_visitor::do_mul_mat_vec(ir_variable *result_var,
- ir_variable *a_var,
- ir_variable *b_var)
+ir_mat_op_to_vec_visitor::do_mul_mat_vec(ir_dereference *result,
+ ir_dereference *a,
+ ir_dereference *b)
{
- int i;
- ir_rvalue *a = get_column(a_var, 0);
- ir_rvalue *b = get_element(b_var, 0, 0);
+ unsigned i;
ir_assignment *assign;
ir_expression *expr;
/* first column */
expr = new(mem_ctx) ir_expression(ir_binop_mul,
- result_var->type,
- a,
- b);
+ get_column(a, 0),
+ get_element(b, 0, 0));
/* following columns */
- for (i = 1; i < a_var->type->matrix_columns; i++) {
+ for (i = 1; i < a->type->matrix_columns; i++) {
ir_expression *mul_expr;
- a = get_column(a_var, i);
- b = get_element(b_var, 0, i);
-
mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
- result_var->type,
- a,
- b);
- expr = new(mem_ctx) ir_expression(ir_binop_add,
- result_var->type,
- expr,
- mul_expr);
+ get_column(a, i),
+ get_element(b, 0, i));
+ expr = new(mem_ctx) ir_expression(ir_binop_add, expr, mul_expr);
}
- ir_rvalue *result = new(mem_ctx) ir_dereference_variable(result_var);
- assign = new(mem_ctx) ir_assignment(result,
- expr,
- NULL);
+ result = result->clone(mem_ctx, NULL);
+ assign = new(mem_ctx) ir_assignment(result, expr);
base_ir->insert_before(assign);
}
void
-ir_mat_op_to_vec_visitor::do_mul_vec_mat(ir_variable *result_var,
- ir_variable *a_var,
- ir_variable *b_var)
+ir_mat_op_to_vec_visitor::do_mul_vec_mat(ir_dereference *result,
+ ir_dereference *a,
+ ir_dereference *b)
{
- int i;
+ unsigned i;
- for (i = 0; i < b_var->type->matrix_columns; i++) {
- ir_rvalue *a = new(mem_ctx) ir_dereference_variable(a_var);
- ir_rvalue *b = get_column(b_var, i);
- ir_rvalue *result;
+ for (i = 0; i < b->type->matrix_columns; i++) {
+ ir_rvalue *column_result;
ir_expression *column_expr;
ir_assignment *column_assign;
- result = new(mem_ctx) ir_dereference_variable(result_var);
- result = new(mem_ctx) ir_swizzle(result, i, 0, 0, 0, 1);
+ column_result = result->clone(mem_ctx, NULL);
+ column_result = new(mem_ctx) ir_swizzle(column_result, i, 0, 0, 0, 1);
column_expr = new(mem_ctx) ir_expression(ir_binop_dot,
- result->type,
- a,
- b);
+ a->clone(mem_ctx, NULL),
+ get_column(b, i));
- column_assign = new(mem_ctx) ir_assignment(result,
- column_expr,
- NULL);
+ column_assign = new(mem_ctx) ir_assignment(column_result,
+ column_expr);
base_ir->insert_before(column_assign);
}
}
void
-ir_mat_op_to_vec_visitor::do_mul_mat_scalar(ir_variable *result_var,
- ir_variable *a_var,
- ir_variable *b_var)
+ir_mat_op_to_vec_visitor::do_mul_mat_scalar(ir_dereference *result,
+ ir_dereference *a,
+ ir_dereference *b)
{
- int i;
+ unsigned i;
- for (i = 0; i < a_var->type->matrix_columns; i++) {
- ir_rvalue *a = get_column(a_var, i);
- ir_rvalue *b = new(mem_ctx) ir_dereference_variable(b_var);
- ir_rvalue *result = get_column(result_var, i);
+ for (i = 0; i < a->type->matrix_columns; i++) {
ir_expression *column_expr;
ir_assignment *column_assign;
column_expr = new(mem_ctx) ir_expression(ir_binop_mul,
- result->type,
- a,
- b);
+ get_column(a, i),
+ b->clone(mem_ctx, NULL));
- column_assign = new(mem_ctx) ir_assignment(result,
- column_expr,
- NULL);
+ column_assign = new(mem_ctx) ir_assignment(get_column(result, i),
+ column_expr);
base_ir->insert_before(column_assign);
}
}
void
-ir_mat_op_to_vec_visitor::do_equal_mat_mat(ir_variable *result_var,
- ir_variable *a_var,
- ir_variable *b_var,
+ir_mat_op_to_vec_visitor::do_equal_mat_mat(ir_dereference *result,
+ ir_dereference *a,
+ ir_dereference *b,
bool test_equal)
{
/* This essentially implements the following GLSL:
* a[3] != b[3]);
* }
*/
- const unsigned columns = a_var->type->matrix_columns;
+ const unsigned columns = a->type->matrix_columns;
const glsl_type *const bvec_type =
glsl_type::get_instance(GLSL_TYPE_BOOL, columns, 1);
this->base_ir->insert_before(tmp_bvec);
for (unsigned i = 0; i < columns; i++) {
- ir_dereference *const op0 = get_column(a_var, i);
- ir_dereference *const op1 = get_column(b_var, i);
-
ir_expression *const cmp =
new(this->mem_ctx) ir_expression(ir_binop_any_nequal,
- glsl_type::bool_type, op0, op1);
+ get_column(a, i),
+ get_column(b, i));
ir_dereference *const lhs =
new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
this->base_ir->insert_before(assign);
}
- ir_rvalue *const val =
- new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
-
- ir_expression *any =
- new(this->mem_ctx) ir_expression(ir_unop_any, glsl_type::bool_type,
- val, NULL);
+ ir_rvalue *const val = new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
+ ir_expression *any = new(this->mem_ctx) ir_expression(ir_unop_any, val);
if (test_equal)
- any = new(this->mem_ctx) ir_expression(ir_unop_logic_not,
- glsl_type::bool_type,
- any, NULL);
-
- ir_rvalue *const result =
- new(this->mem_ctx) ir_dereference_variable(result_var);
+ any = new(this->mem_ctx) ir_expression(ir_unop_logic_not, any);
ir_assignment *const assign =
- new(mem_ctx) ir_assignment(result, any, NULL);
+ new(mem_ctx) ir_assignment(result->clone(mem_ctx, NULL), any);
base_ir->insert_before(assign);
}
{
ir_expression *orig_expr = orig_assign->rhs->as_expression();
unsigned int i, matrix_columns = 1;
- ir_variable *op_var[2];
+ ir_dereference *op[2];
if (!orig_expr)
return visit_continue;
if (!has_matrix_operand(orig_expr, matrix_columns))
return visit_continue;
- mem_ctx = talloc_parent(orig_assign);
+ assert(orig_expr->get_num_operands() <= 2);
- ir_dereference_variable *lhs_deref =
- orig_assign->lhs->as_dereference_variable();
- assert(lhs_deref);
+ mem_ctx = ralloc_parent(orig_assign);
- ir_variable *result_var = lhs_deref->var;
+ ir_dereference_variable *result =
+ orig_assign->lhs->as_dereference_variable();
+ assert(result);
/* Store the expression operands in temps so we can use them
* multiple times.
*/
for (i = 0; i < orig_expr->get_num_operands(); i++) {
ir_assignment *assign;
+ ir_dereference *deref = orig_expr->operands[i]->as_dereference();
- op_var[i] = new(mem_ctx) ir_variable(orig_expr->operands[i]->type,
- "mat_op_to_vec",
- ir_var_temporary);
- base_ir->insert_before(op_var[i]);
+ /* Avoid making a temporary if we don't need to to avoid aliasing. */
+ if (deref &&
+ deref->variable_referenced() != result->variable_referenced()) {
+ op[i] = deref;
+ continue;
+ }
+
+ /* Otherwise, store the operand in a temporary generally if it's
+ * not a dereference.
+ */
+ ir_variable *var = new(mem_ctx) ir_variable(orig_expr->operands[i]->type,
+ "mat_op_to_vec",
+ ir_var_temporary);
+ base_ir->insert_before(var);
- lhs_deref = new(mem_ctx) ir_dereference_variable(op_var[i]);
- assign = new(mem_ctx) ir_assignment(lhs_deref,
- orig_expr->operands[i],
- NULL);
+ /* Note that we use this dereference for the assignment. That means
+ * that others that want to use op[i] have to clone the deref.
+ */
+ op[i] = new(mem_ctx) ir_dereference_variable(var);
+ assign = new(mem_ctx) ir_assignment(op[i], orig_expr->operands[i]);
base_ir->insert_before(assign);
}
/* OK, time to break down this matrix operation. */
switch (orig_expr->operation) {
+ case ir_unop_d2f:
+ case ir_unop_f2d:
case ir_unop_neg: {
- const unsigned mask = (1U << result_var->type->vector_elements) - 1;
-
/* Apply the operation to each column.*/
for (i = 0; i < matrix_columns; i++) {
- ir_rvalue *op0 = get_column(op_var[0], i);
- ir_dereference *result = get_column(result_var, i);
ir_expression *column_expr;
ir_assignment *column_assign;
column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
- result->type,
- op0,
- NULL);
-
- column_assign = new(mem_ctx) ir_assignment(result,
- column_expr,
- NULL,
- mask);
+ get_column(op[0], i));
+
+ column_assign = new(mem_ctx) ir_assignment(get_column(result, i),
+ column_expr);
assert(column_assign->write_mask != 0);
base_ir->insert_before(column_assign);
}
case ir_binop_sub:
case ir_binop_div:
case ir_binop_mod: {
- const unsigned mask = (1U << result_var->type->vector_elements) - 1;
-
/* 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_dereference *result = get_column(result_var, i);
ir_expression *column_expr;
ir_assignment *column_assign;
column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
- result->type,
- op0,
- op1);
-
- column_assign = new(mem_ctx) ir_assignment(result,
- column_expr,
- NULL,
- mask);
+ get_column(op[0], i),
+ get_column(op[1], i));
+
+ column_assign = new(mem_ctx) ir_assignment(get_column(result, i),
+ column_expr);
assert(column_assign->write_mask != 0);
base_ir->insert_before(column_assign);
}
break;
}
case ir_binop_mul:
- if (op_var[0]->type->is_matrix()) {
- if (op_var[1]->type->is_matrix()) {
- do_mul_mat_mat(result_var, op_var[0], op_var[1]);
- } else if (op_var[1]->type->is_vector()) {
- do_mul_mat_vec(result_var, op_var[0], op_var[1]);
+ if (op[0]->type->is_matrix()) {
+ if (op[1]->type->is_matrix()) {
+ do_mul_mat_mat(result, op[0], op[1]);
+ } else if (op[1]->type->is_vector()) {
+ do_mul_mat_vec(result, op[0], op[1]);
} else {
- assert(op_var[1]->type->is_scalar());
- do_mul_mat_scalar(result_var, op_var[0], op_var[1]);
+ assert(op[1]->type->is_scalar());
+ do_mul_mat_scalar(result, op[0], op[1]);
}
} else {
- assert(op_var[1]->type->is_matrix());
- if (op_var[0]->type->is_vector()) {
- do_mul_vec_mat(result_var, op_var[0], op_var[1]);
+ assert(op[1]->type->is_matrix());
+ if (op[0]->type->is_vector()) {
+ do_mul_vec_mat(result, op[0], op[1]);
} else {
- assert(op_var[0]->type->is_scalar());
- do_mul_mat_scalar(result_var, op_var[1], op_var[0]);
+ assert(op[0]->type->is_scalar());
+ do_mul_mat_scalar(result, op[1], op[0]);
}
}
break;
case ir_binop_all_equal:
case ir_binop_any_nequal:
- do_equal_mat_mat(result_var, op_var[1], op_var[0],
+ do_equal_mat_mat(result, op[1], op[0],
(orig_expr->operation == ir_binop_all_equal));
break;