From 32aaf89823de11e98cb59d5ec78c66cd3e74bcd4 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Mon, 15 Nov 2010 14:35:46 -0800 Subject: glsl: Rename various ir_* files to lower_* and opt_*. This helps distinguish between lowering passes, optimization passes, and other compiler code. --- src/glsl/opt_algebraic.cpp | 474 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 474 insertions(+) create mode 100644 src/glsl/opt_algebraic.cpp (limited to 'src/glsl/opt_algebraic.cpp') diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp new file mode 100644 index 0000000000..2ed66db476 --- /dev/null +++ b/src/glsl/opt_algebraic.cpp @@ -0,0 +1,474 @@ +/* + * 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_algebraic.cpp + * + * Takes advantage of association, commutivity, and other algebraic + * properties to simplify expressions. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_rvalue_visitor.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +/** + * Visitor class for replacing expressions with ir_constant values. + */ + +class ir_algebraic_visitor : public ir_rvalue_visitor { +public: + ir_algebraic_visitor() + { + this->progress = false; + this->mem_ctx = NULL; + } + + virtual ~ir_algebraic_visitor() + { + } + + ir_rvalue *handle_expression(ir_expression *ir); + void handle_rvalue(ir_rvalue **rvalue); + bool reassociate_constant(ir_expression *ir1, + int const_index, + ir_constant *constant, + ir_expression *ir2); + void reassociate_operands(ir_expression *ir1, + int op1, + ir_expression *ir2, + int op2); + ir_rvalue *swizzle_if_required(ir_expression *expr, + ir_rvalue *operand); + + void *mem_ctx; + + bool progress; +}; + +static bool +is_vec_zero(ir_constant *ir) +{ + int c; + + if (!ir) + return false; + if (!ir->type->is_scalar() && + !ir->type->is_vector()) + return false; + + for (c = 0; c < ir->type->vector_elements; c++) { + switch (ir->type->base_type) { + case GLSL_TYPE_FLOAT: + if (ir->value.f[c] != 0.0) + return false; + break; + case GLSL_TYPE_INT: + if (ir->value.i[c] != 0) + return false; + break; + case GLSL_TYPE_UINT: + if (ir->value.u[c] != 0) + return false; + break; + case GLSL_TYPE_BOOL: + if (ir->value.b[c] != false) + return false; + break; + default: + assert(!"bad base type"); + return false; + } + } + + return true; +} + +static bool +is_vec_one(ir_constant *ir) +{ + int c; + + if (!ir) + return false; + if (!ir->type->is_scalar() && + !ir->type->is_vector()) + return false; + + for (c = 0; c < ir->type->vector_elements; c++) { + switch (ir->type->base_type) { + case GLSL_TYPE_FLOAT: + if (ir->value.f[c] != 1.0) + return false; + break; + case GLSL_TYPE_INT: + if (ir->value.i[c] != 1) + return false; + break; + case GLSL_TYPE_UINT: + if (ir->value.u[c] != 1) + return false; + break; + case GLSL_TYPE_BOOL: + if (ir->value.b[c] != true) + return false; + break; + default: + assert(!"bad base type"); + return false; + } + } + + return true; +} + +static void +update_type(ir_expression *ir) +{ + if (ir->operands[0]->type->is_vector()) + ir->type = ir->operands[0]->type; + else + ir->type = ir->operands[1]->type; +} + +void +ir_algebraic_visitor::reassociate_operands(ir_expression *ir1, + int op1, + ir_expression *ir2, + int op2) +{ + ir_rvalue *temp = ir2->operands[op2]; + ir2->operands[op2] = ir1->operands[op1]; + ir1->operands[op1] = temp; + + /* Update the type of ir2. The type of ir1 won't have changed -- + * base types matched, and at least one of the operands of the 2 + * binops is still a vector if any of them were. + */ + update_type(ir2); + + this->progress = true; +} + +/** + * Reassociates a constant down a tree of adds or multiplies. + * + * Consider (2 * (a * (b * 0.5))). We want to send up with a * b. + */ +bool +ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index, + ir_constant *constant, + ir_expression *ir2) +{ + if (!ir2 || ir1->operation != ir2->operation) + return false; + + /* Don't want to even think about matrices. */ + if (ir1->operands[0]->type->is_matrix() || + ir1->operands[0]->type->is_matrix() || + ir2->operands[1]->type->is_matrix() || + ir2->operands[1]->type->is_matrix()) + return false; + + ir_constant *ir2_const[2]; + ir2_const[0] = ir2->operands[0]->constant_expression_value(); + ir2_const[1] = ir2->operands[1]->constant_expression_value(); + + if (ir2_const[0] && ir2_const[1]) + return false; + + if (ir2_const[0]) { + reassociate_operands(ir1, const_index, ir2, 1); + return true; + } else if (ir2_const[1]) { + reassociate_operands(ir1, const_index, ir2, 0); + return true; + } + + if (reassociate_constant(ir1, const_index, constant, + ir2->operands[0]->as_expression())) { + update_type(ir2); + return true; + } + + if (reassociate_constant(ir1, const_index, constant, + ir2->operands[1]->as_expression())) { + update_type(ir2); + return true; + } + + return false; +} + +/* When eliminating an expression and just returning one of its operands, + * we may need to swizzle that operand out to a vector if the expression was + * vector type. + */ +ir_rvalue * +ir_algebraic_visitor::swizzle_if_required(ir_expression *expr, + ir_rvalue *operand) +{ + if (expr->type->is_vector() && operand->type->is_scalar()) { + return new(mem_ctx) ir_swizzle(operand, 0, 0, 0, 0, + expr->type->vector_elements); + } else + return operand; +} + +ir_rvalue * +ir_algebraic_visitor::handle_expression(ir_expression *ir) +{ + ir_constant *op_const[2] = {NULL, NULL}; + ir_expression *op_expr[2] = {NULL, NULL}; + ir_expression *temp; + unsigned int i; + + for (i = 0; i < ir->get_num_operands(); i++) { + if (ir->operands[i]->type->is_matrix()) + return ir; + + op_const[i] = ir->operands[i]->constant_expression_value(); + op_expr[i] = ir->operands[i]->as_expression(); + } + + if (this->mem_ctx == NULL) + this->mem_ctx = talloc_parent(ir); + + switch (ir->operation) { + case ir_unop_logic_not: { + enum ir_expression_operation new_op = ir_unop_logic_not; + + if (op_expr[0] == NULL) + break; + + switch (op_expr[0]->operation) { + case ir_binop_less: new_op = ir_binop_gequal; break; + case ir_binop_greater: new_op = ir_binop_lequal; break; + case ir_binop_lequal: new_op = ir_binop_greater; break; + case ir_binop_gequal: new_op = ir_binop_less; break; + case ir_binop_equal: new_op = ir_binop_nequal; break; + case ir_binop_nequal: new_op = ir_binop_equal; break; + case ir_binop_all_equal: new_op = ir_binop_any_nequal; break; + case ir_binop_any_nequal: new_op = ir_binop_all_equal; break; + + default: + /* The default case handler is here to silence a warning from GCC. + */ + break; + } + + if (new_op != ir_unop_logic_not) { + this->progress = true; + return new(mem_ctx) ir_expression(new_op, + ir->type, + op_expr[0]->operands[0], + op_expr[0]->operands[1]); + } + + break; + } + + case ir_binop_add: + if (is_vec_zero(op_const[0])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[1]); + } + if (is_vec_zero(op_const[1])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[0]); + } + + /* Reassociate addition of constants so that we can do constant + * folding. + */ + if (op_const[0] && !op_const[1]) + reassociate_constant(ir, 0, op_const[0], + ir->operands[1]->as_expression()); + if (op_const[1] && !op_const[0]) + reassociate_constant(ir, 1, op_const[1], + ir->operands[0]->as_expression()); + break; + + case ir_binop_sub: + if (is_vec_zero(op_const[0])) { + this->progress = true; + temp = new(mem_ctx) ir_expression(ir_unop_neg, + ir->operands[1]->type, + ir->operands[1], + NULL); + return swizzle_if_required(ir, temp); + } + if (is_vec_zero(op_const[1])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[0]); + } + break; + + case ir_binop_mul: + if (is_vec_one(op_const[0])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[1]); + } + if (is_vec_one(op_const[1])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[0]); + } + + if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) { + this->progress = true; + return ir_constant::zero(ir, ir->type); + } + + /* Reassociate multiplication of constants so that we can do + * constant folding. + */ + if (op_const[0] && !op_const[1]) + reassociate_constant(ir, 0, op_const[0], + ir->operands[1]->as_expression()); + if (op_const[1] && !op_const[0]) + reassociate_constant(ir, 1, op_const[1], + ir->operands[0]->as_expression()); + + break; + + case ir_binop_div: + if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) { + this->progress = true; + temp = new(mem_ctx) ir_expression(ir_unop_rcp, + ir->operands[1]->type, + ir->operands[1], + NULL); + return swizzle_if_required(ir, temp); + } + if (is_vec_one(op_const[1])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[0]); + } + break; + + case ir_binop_logic_and: + /* FINISHME: Also simplify (a && a) to (a). */ + if (is_vec_one(op_const[0])) { + this->progress = true; + return ir->operands[1]; + } else if (is_vec_one(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } else if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) { + this->progress = true; + return ir_constant::zero(mem_ctx, ir->type); + } + break; + + case ir_binop_logic_xor: + /* FINISHME: Also simplify (a ^^ a) to (false). */ + if (is_vec_zero(op_const[0])) { + this->progress = true; + return ir->operands[1]; + } else if (is_vec_zero(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } else if (is_vec_one(op_const[0])) { + this->progress = true; + return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type, + ir->operands[1], NULL); + } else if (is_vec_one(op_const[1])) { + this->progress = true; + return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type, + ir->operands[0], NULL); + } + break; + + case ir_binop_logic_or: + /* FINISHME: Also simplify (a || a) to (a). */ + if (is_vec_zero(op_const[0])) { + this->progress = true; + return ir->operands[1]; + } else if (is_vec_zero(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } else if (is_vec_one(op_const[0]) || is_vec_one(op_const[1])) { + ir_constant_data data; + + for (unsigned i = 0; i < 16; i++) + data.b[i] = true; + + this->progress = true; + return new(mem_ctx) ir_constant(ir->type, &data); + } + break; + + case ir_unop_rcp: + if (op_expr[0] && op_expr[0]->operation == ir_unop_rcp) { + this->progress = true; + return op_expr[0]->operands[0]; + } + + /* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some + * backends, except that some backends will have done sqrt -> + * rcp(rsq(x)) and we don't want to undo it for them. + */ + + /* As far as we know, all backends are OK with rsq. */ + if (op_expr[0] && op_expr[0]->operation == ir_unop_sqrt) { + this->progress = true; + temp = new(mem_ctx) ir_expression(ir_unop_rsq, + op_expr[0]->operands[0]->type, + op_expr[0]->operands[0], + NULL); + return swizzle_if_required(ir, temp); + } + + break; + + default: + break; + } + + return ir; +} + +void +ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + if (!*rvalue) + return; + + ir_expression *expr = (*rvalue)->as_expression(); + if (!expr) + return; + + *rvalue = handle_expression(expr); +} + +bool +do_algebraic(exec_list *instructions) +{ + ir_algebraic_visitor v; + + visit_list_elements(&v, instructions); + + return v.progress; +} -- cgit v1.2.3 From 38e55153af031e48125b1cd0a5d939bb92379ddc Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Fri, 12 Nov 2010 10:19:08 -0800 Subject: glsl: Refactor is_vec_{zero,one} to be methods of ir_constant These predicates will be used in other places soon. --- src/glsl/ir.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++ src/glsl/ir.h | 24 +++++++++++++++ src/glsl/opt_algebraic.cpp | 72 +++------------------------------------------ 3 files changed, 101 insertions(+), 68 deletions(-) (limited to 'src/glsl/opt_algebraic.cpp') diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index 87e78eee05..4b886018dc 100644 --- a/src/glsl/ir.cpp +++ b/src/glsl/ir.cpp @@ -742,6 +742,79 @@ ir_constant::has_value(const ir_constant *c) const return true; } +bool +ir_constant::is_zero() const +{ + if (!this->type->is_scalar() && !this->type->is_vector()) + return false; + + for (unsigned c = 0; c < this->type->vector_elements; c++) { + switch (this->type->base_type) { + case GLSL_TYPE_FLOAT: + if (this->value.f[c] != 0.0) + return false; + break; + case GLSL_TYPE_INT: + if (this->value.i[c] != 0) + return false; + break; + case GLSL_TYPE_UINT: + if (this->value.u[c] != 0) + return false; + break; + case GLSL_TYPE_BOOL: + if (this->value.b[c] != false) + return false; + break; + default: + /* The only other base types are structures, arrays, and samplers. + * Samplers cannot be constants, and the others should have been + * filtered out above. + */ + assert(!"Should not get here."); + return false; + } + } + + return true; +} + +bool +ir_constant::is_one() const +{ + if (!this->type->is_scalar() && !this->type->is_vector()) + return false; + + for (unsigned c = 0; c < this->type->vector_elements; c++) { + switch (this->type->base_type) { + case GLSL_TYPE_FLOAT: + if (this->value.f[c] != 1.0) + return false; + break; + case GLSL_TYPE_INT: + if (this->value.i[c] != 1) + return false; + break; + case GLSL_TYPE_UINT: + if (this->value.u[c] != 1) + return false; + break; + case GLSL_TYPE_BOOL: + if (this->value.b[c] != true) + return false; + break; + default: + /* The only other base types are structures, arrays, and samplers. + * Samplers cannot be constants, and the others should have been + * filtered out above. + */ + assert(!"Should not get here."); + return false; + } + } + + return true; +} ir_loop::ir_loop() { diff --git a/src/glsl/ir.h b/src/glsl/ir.h index 80e0f67d6d..6a70dede9b 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -1441,9 +1441,33 @@ public: /** * Determine whether a constant has the same value as another constant + * + * \sa ir_constant::is_zero, ir_constant::is_one */ bool has_value(const ir_constant *) const; + /** + * Determine if a constant has the value zero + * + * \note + * This function always returns \c false for constants that are not + * scalars or vectors. + * + * \sa ir_constant::has_value, ir_constant::is_one + */ + bool is_zero() const; + + /** + * Determine if a constant has the value one + * + * \note + * This function always returns \c false for constants that are not + * scalars or vectors. + * + * \sa ir_constant::has_value, ir_constant::is_zero + */ + bool is_one() const; + /** * Value of the constant. * diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp index 2ed66db476..c7f5c3b4d6 100644 --- a/src/glsl/opt_algebraic.cpp +++ b/src/glsl/opt_algebraic.cpp @@ -68,80 +68,16 @@ public: bool progress; }; -static bool +static inline bool is_vec_zero(ir_constant *ir) { - int c; - - if (!ir) - return false; - if (!ir->type->is_scalar() && - !ir->type->is_vector()) - return false; - - for (c = 0; c < ir->type->vector_elements; c++) { - switch (ir->type->base_type) { - case GLSL_TYPE_FLOAT: - if (ir->value.f[c] != 0.0) - return false; - break; - case GLSL_TYPE_INT: - if (ir->value.i[c] != 0) - return false; - break; - case GLSL_TYPE_UINT: - if (ir->value.u[c] != 0) - return false; - break; - case GLSL_TYPE_BOOL: - if (ir->value.b[c] != false) - return false; - break; - default: - assert(!"bad base type"); - return false; - } - } - - return true; + return (ir == NULL) ? false : ir->is_zero(); } -static bool +static inline bool is_vec_one(ir_constant *ir) { - int c; - - if (!ir) - return false; - if (!ir->type->is_scalar() && - !ir->type->is_vector()) - return false; - - for (c = 0; c < ir->type->vector_elements; c++) { - switch (ir->type->base_type) { - case GLSL_TYPE_FLOAT: - if (ir->value.f[c] != 1.0) - return false; - break; - case GLSL_TYPE_INT: - if (ir->value.i[c] != 1) - return false; - break; - case GLSL_TYPE_UINT: - if (ir->value.u[c] != 1) - return false; - break; - case GLSL_TYPE_BOOL: - if (ir->value.b[c] != true) - return false; - break; - default: - assert(!"bad base type"); - return false; - } - } - - return true; + return (ir == NULL) ? false : ir->is_one(); } static void -- cgit v1.2.3 From df883eb1575a740bf91e01cbe2eaa4dbc1f9f154 Mon Sep 17 00:00:00 2001 From: Chad Versace Date: Wed, 17 Nov 2010 10:43:10 -0800 Subject: glsl: Fix Doxygen tag \file in recently renamed files --- src/glsl/lower_div_to_mul_rcp.cpp | 2 +- src/glsl/lower_explog_to_explog2.cpp | 2 +- src/glsl/lower_if_to_cond_assign.cpp | 2 +- src/glsl/lower_jumps.cpp | 2 +- src/glsl/lower_mat_op_to_vec.cpp | 2 +- src/glsl/lower_mod_to_fract.cpp | 2 +- src/glsl/lower_sub_to_add_neg.cpp | 2 +- src/glsl/lower_vec_index_to_cond_assign.cpp | 2 +- src/glsl/lower_vec_index_to_swizzle.cpp | 2 +- src/glsl/opt_algebraic.cpp | 2 +- src/glsl/opt_constant_folding.cpp | 2 +- src/glsl/opt_constant_propagation.cpp | 2 +- src/glsl/opt_constant_variable.cpp | 2 +- src/glsl/opt_copy_propagation.cpp | 2 +- src/glsl/opt_dead_code.cpp | 2 +- src/glsl/opt_dead_code_local.cpp | 2 +- src/glsl/opt_dead_functions.cpp | 2 +- src/glsl/opt_function_inlining.cpp | 2 +- src/glsl/opt_if_simplification.cpp | 2 +- src/glsl/opt_noop_swizzle.cpp | 2 +- src/glsl/opt_structure_splitting.cpp | 2 +- src/glsl/opt_swizzle_swizzle.cpp | 2 +- src/glsl/opt_tree_grafting.cpp | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) (limited to 'src/glsl/opt_algebraic.cpp') diff --git a/src/glsl/lower_div_to_mul_rcp.cpp b/src/glsl/lower_div_to_mul_rcp.cpp index 640d5d64f9..d34c4bc46d 100644 --- a/src/glsl/lower_div_to_mul_rcp.cpp +++ b/src/glsl/lower_div_to_mul_rcp.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_div_to_mul_rcp.cpp + * \file lower_div_to_mul_rcp.cpp * * Breaks an ir_unop_div expression down to op0 * (rcp(op1)). * diff --git a/src/glsl/lower_explog_to_explog2.cpp b/src/glsl/lower_explog_to_explog2.cpp index 78694a2029..8ad0262544 100644 --- a/src/glsl/lower_explog_to_explog2.cpp +++ b/src/glsl/lower_explog_to_explog2.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_explog_to_explog2.cpp + * \file lower_explog_to_explog2.cpp * * Many GPUs don't have a base e log or exponent instruction, but they * do have base 2 versions, so this pass converts exp and log to exp2 diff --git a/src/glsl/lower_if_to_cond_assign.cpp b/src/glsl/lower_if_to_cond_assign.cpp index 0b87413941..cf48cfb8d6 100644 --- a/src/glsl/lower_if_to_cond_assign.cpp +++ b/src/glsl/lower_if_to_cond_assign.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_if_to_cond_assign.cpp + * \file lower_if_to_cond_assign.cpp * * This attempts to flatten all if statements to conditional * assignments for GPUs that don't do control flow. diff --git a/src/glsl/lower_jumps.cpp b/src/glsl/lower_jumps.cpp index b69cc1ec31..e1e7a5b007 100644 --- a/src/glsl/lower_jumps.cpp +++ b/src/glsl/lower_jumps.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_lower_jumps.cpp + * \file lower_jumps.cpp */ #include "glsl_types.h" diff --git a/src/glsl/lower_mat_op_to_vec.cpp b/src/glsl/lower_mat_op_to_vec.cpp index 244fe48928..4965df8976 100644 --- a/src/glsl/lower_mat_op_to_vec.cpp +++ b/src/glsl/lower_mat_op_to_vec.cpp @@ -22,7 +22,7 @@ */ /** - * \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. * diff --git a/src/glsl/lower_mod_to_fract.cpp b/src/glsl/lower_mod_to_fract.cpp index c82a1f64fd..ff907ae97c 100644 --- a/src/glsl/lower_mod_to_fract.cpp +++ b/src/glsl/lower_mod_to_fract.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_mod_to_fract.cpp + * \file lower_mod_to_fract.cpp * * Breaks an ir_unop_mod expression down to (op1 * fract(op0 / op1)) * diff --git a/src/glsl/lower_sub_to_add_neg.cpp b/src/glsl/lower_sub_to_add_neg.cpp index 7ed8c1495e..9e4019709b 100644 --- a/src/glsl/lower_sub_to_add_neg.cpp +++ b/src/glsl/lower_sub_to_add_neg.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_sub_to_add_neg.cpp + * \file lower_sub_to_add_neg.cpp * * Breaks an ir_binop_sub expression down to add(op0, neg(op1)) * diff --git a/src/glsl/lower_vec_index_to_cond_assign.cpp b/src/glsl/lower_vec_index_to_cond_assign.cpp index cd8dedf2fe..f8011a16e5 100644 --- a/src/glsl/lower_vec_index_to_cond_assign.cpp +++ b/src/glsl/lower_vec_index_to_cond_assign.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_vec_index_to_cond_assign.cpp + * \file lower_vec_index_to_cond_assign.cpp * * Turns indexing into vector types to a series of conditional moves * of each channel's swizzle into a temporary. diff --git a/src/glsl/lower_vec_index_to_swizzle.cpp b/src/glsl/lower_vec_index_to_swizzle.cpp index 969dc8f94a..9ae43c0db1 100644 --- a/src/glsl/lower_vec_index_to_swizzle.cpp +++ b/src/glsl/lower_vec_index_to_swizzle.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_vec_index_to_swizzle.cpp + * \file lower_vec_index_to_swizzle.cpp * * Turns constant indexing into vector types to swizzles. This will * let other swizzle-aware optimization passes catch these constructs, diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp index c7f5c3b4d6..88b6c485d3 100644 --- a/src/glsl/opt_algebraic.cpp +++ b/src/glsl/opt_algebraic.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_algebraic.cpp + * \file opt_algebraic.cpp * * Takes advantage of association, commutivity, and other algebraic * properties to simplify expressions. diff --git a/src/glsl/opt_constant_folding.cpp b/src/glsl/opt_constant_folding.cpp index 554c54fae3..d69ca75fe0 100644 --- a/src/glsl/opt_constant_folding.cpp +++ b/src/glsl/opt_constant_folding.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_constant_folding.cpp + * \file opt_constant_folding.cpp * Replace constant-valued expressions with references to constant values. */ diff --git a/src/glsl/opt_constant_propagation.cpp b/src/glsl/opt_constant_propagation.cpp index 5d875b7be0..6719fc8186 100644 --- a/src/glsl/opt_constant_propagation.cpp +++ b/src/glsl/opt_constant_propagation.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_constant_propagation.cpp + * \file opt_constant_propagation.cpp * * Tracks assignments of constants to channels of variables, and * usage of those constant channels with direct usage of the constants. diff --git a/src/glsl/opt_constant_variable.cpp b/src/glsl/opt_constant_variable.cpp index 1fb73e765e..8068d0c143 100644 --- a/src/glsl/opt_constant_variable.cpp +++ b/src/glsl/opt_constant_variable.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_constant_variable.cpp + * \file opt_constant_variable.cpp * * Marks variables assigned a single constant value over the course * of the program as constant. diff --git a/src/glsl/opt_copy_propagation.cpp b/src/glsl/opt_copy_propagation.cpp index 0fe8fa6c41..8d07fefbfd 100644 --- a/src/glsl/opt_copy_propagation.cpp +++ b/src/glsl/opt_copy_propagation.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_copy_propagation.cpp + * \file opt_copy_propagation.cpp * * Moves usage of recently-copied variables to the previous copy of * the variable. diff --git a/src/glsl/opt_dead_code.cpp b/src/glsl/opt_dead_code.cpp index 5cf5e99add..cb500d2d10 100644 --- a/src/glsl/opt_dead_code.cpp +++ b/src/glsl/opt_dead_code.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_dead_code.cpp + * \file opt_dead_code.cpp * * Eliminates dead assignments and variable declarations from the code. */ diff --git a/src/glsl/opt_dead_code_local.cpp b/src/glsl/opt_dead_code_local.cpp index 4bbedf0ff9..5689e7d20d 100644 --- a/src/glsl/opt_dead_code_local.cpp +++ b/src/glsl/opt_dead_code_local.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_dead_code_local.cpp + * \file opt_dead_code_local.cpp * * Eliminates local dead assignments from the code. * diff --git a/src/glsl/opt_dead_functions.cpp b/src/glsl/opt_dead_functions.cpp index 16037a2632..cf91cb6d36 100644 --- a/src/glsl/opt_dead_functions.cpp +++ b/src/glsl/opt_dead_functions.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_dead_functions.cpp + * \file opt_dead_functions.cpp * * Eliminates unused functions from the linked program. */ diff --git a/src/glsl/opt_function_inlining.cpp b/src/glsl/opt_function_inlining.cpp index 147c1824c1..169fd82688 100644 --- a/src/glsl/opt_function_inlining.cpp +++ b/src/glsl/opt_function_inlining.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_function_inlining.cpp + * \file opt_function_inlining.cpp * * Replaces calls to functions with the body of the function. */ diff --git a/src/glsl/opt_if_simplification.cpp b/src/glsl/opt_if_simplification.cpp index 021615ebd1..618bacfecf 100644 --- a/src/glsl/opt_if_simplification.cpp +++ b/src/glsl/opt_if_simplification.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_if_simplification.cpp + * \file opt_if_simplification.cpp * * Moves constant branches of if statements out to the surrounding * instruction stream. diff --git a/src/glsl/opt_noop_swizzle.cpp b/src/glsl/opt_noop_swizzle.cpp index 0403dfa4e9..0a906aaf1d 100644 --- a/src/glsl/opt_noop_swizzle.cpp +++ b/src/glsl/opt_noop_swizzle.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_noop_swizzle.cpp + * \file opt_noop_swizzle.cpp * * If a swizzle doesn't change the order or count of components, then * remove the swizzle so that other optimization passes see the value diff --git a/src/glsl/opt_structure_splitting.cpp b/src/glsl/opt_structure_splitting.cpp index ff3ec936eb..d6191002c2 100644 --- a/src/glsl/opt_structure_splitting.cpp +++ b/src/glsl/opt_structure_splitting.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_structure_splitting.cpp + * \file opt_structure_splitting.cpp * * If a structure is only ever referenced by its components, then * split those components out to individual variables so they can be diff --git a/src/glsl/opt_swizzle_swizzle.cpp b/src/glsl/opt_swizzle_swizzle.cpp index 0ffb4fa313..bc442fa869 100644 --- a/src/glsl/opt_swizzle_swizzle.cpp +++ b/src/glsl/opt_swizzle_swizzle.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_swizzle_swizzle.cpp + * \file opt_swizzle_swizzle.cpp * * Eliminates the second swizzle in a swizzle chain. */ diff --git a/src/glsl/opt_tree_grafting.cpp b/src/glsl/opt_tree_grafting.cpp index 9b569b8284..9917c045b1 100644 --- a/src/glsl/opt_tree_grafting.cpp +++ b/src/glsl/opt_tree_grafting.cpp @@ -22,7 +22,7 @@ */ /** - * \file ir_tree_grafting.cpp + * \file opt_tree_grafting.cpp * * Takes assignments to variables that are dereferenced only once and * pastes the RHS expression into where the variable is dereferenced. -- cgit v1.2.3 From fc92e87b9757eda01caf0bb3e2c31b1dbbd73aa0 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Wed, 10 Nov 2010 16:33:10 -0800 Subject: glsl: Eliminate assumptions about size of ir_expression::operands This may grow in the near future. --- src/glsl/ir_clone.cpp | 3 ++- src/glsl/ir_constant_expression.cpp | 2 +- src/glsl/ir_print_visitor.cpp | 7 +++---- src/glsl/lower_mat_op_to_vec.cpp | 2 ++ src/glsl/opt_algebraic.cpp | 1 + src/mesa/drivers/dri/i965/brw_fs.cpp | 3 +++ src/mesa/program/ir_to_mesa.cpp | 2 +- 7 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src/glsl/opt_algebraic.cpp') diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp index a3cc8dbc97..4032647c3a 100644 --- a/src/glsl/ir_clone.cpp +++ b/src/glsl/ir_clone.cpp @@ -22,6 +22,7 @@ */ #include +#include "main/compiler.h" #include "ir.h" #include "glsl_types.h" extern "C" { @@ -160,7 +161,7 @@ ir_call::clone(void *mem_ctx, struct hash_table *ht) const ir_expression * ir_expression::clone(void *mem_ctx, struct hash_table *ht) const { - ir_rvalue *op[2] = {NULL, NULL}; + ir_rvalue *op[Elements(this->operands)] = { NULL, }; unsigned int i; for (i = 0; i < get_num_operands(); i++) { diff --git a/src/glsl/ir_constant_expression.cpp b/src/glsl/ir_constant_expression.cpp index 45860b279f..1fe1505047 100644 --- a/src/glsl/ir_constant_expression.cpp +++ b/src/glsl/ir_constant_expression.cpp @@ -57,7 +57,7 @@ ir_expression::constant_expression_value() if (this->type->is_error()) return NULL; - ir_constant *op[2] = { NULL, NULL }; + ir_constant *op[Elements(this->operands)] = { NULL, }; ir_constant_data data; memset(&data, 0, sizeof(data)); diff --git a/src/glsl/ir_print_visitor.cpp b/src/glsl/ir_print_visitor.cpp index 5c19db1326..e5067bfdad 100644 --- a/src/glsl/ir_print_visitor.cpp +++ b/src/glsl/ir_print_visitor.cpp @@ -182,11 +182,10 @@ void ir_print_visitor::visit(ir_expression *ir) printf(" %s ", ir->operator_string()); - if (ir->operands[0]) - ir->operands[0]->accept(this); + for (unsigned i = 0; i < ir->get_num_operands(); i++) { + ir->operands[i]->accept(this); + } - if (ir->operands[1]) - ir->operands[1]->accept(this); printf(") "); } diff --git a/src/glsl/lower_mat_op_to_vec.cpp b/src/glsl/lower_mat_op_to_vec.cpp index 4965df8976..7065fdec35 100644 --- a/src/glsl/lower_mat_op_to_vec.cpp +++ b/src/glsl/lower_mat_op_to_vec.cpp @@ -366,6 +366,8 @@ ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign) if (!has_matrix_operand(orig_expr, matrix_columns)) return visit_continue; + assert(orig_expr->get_num_operands() <= 2); + mem_ctx = talloc_parent(orig_assign); ir_dereference_variable *lhs_deref = diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp index 88b6c485d3..9a8080bff3 100644 --- a/src/glsl/opt_algebraic.cpp +++ b/src/glsl/opt_algebraic.cpp @@ -181,6 +181,7 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) ir_expression *temp; unsigned int i; + assert(ir->get_num_operands() <= 2); for (i = 0; i < ir->get_num_operands(); i++) { if (ir->operands[i]->type->is_matrix()) return ir; diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp index 164f89eace..105327c7fe 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp @@ -708,6 +708,7 @@ fs_visitor::visit(ir_expression *ir) fs_reg op[2], temp; fs_inst *inst; + assert(ir->get_num_operands() <= 2); for (operand = 0; operand < ir->get_num_operands(); operand++) { ir->operands[operand]->accept(this); if (this->result.file == BAD_FILE) { @@ -1387,6 +1388,7 @@ fs_visitor::emit_bool_to_cond_code(ir_rvalue *ir) fs_reg op[2]; fs_inst *inst; + assert(expr->get_num_operands() <= 2); for (unsigned int i = 0; i < expr->get_num_operands(); i++) { assert(expr->operands[i]->type->is_scalar()); @@ -1494,6 +1496,7 @@ fs_visitor::emit_if_gen6(ir_if *ir) fs_inst *inst; fs_reg temp; + assert(expr->get_num_operands() <= 2); for (unsigned int i = 0; i < expr->get_num_operands(); i++) { assert(expr->operands[i]->type->is_scalar()); diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index ef9f692f94..1b5337e92e 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -961,7 +961,7 @@ void ir_to_mesa_visitor::visit(ir_expression *ir) { unsigned int operand; - struct ir_to_mesa_src_reg op[2]; + struct ir_to_mesa_src_reg op[Elements(ir->operands)]; struct ir_to_mesa_src_reg result_src; struct ir_to_mesa_dst_reg result_dst; -- cgit v1.2.3 From 11d6f1c69871d0b7edc28f639256460839fccd2d Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 16 Nov 2010 12:01:42 -0800 Subject: glsl: Add ir_quadop_vector expression The vector operator collects 2, 3, or 4 scalar components into a vector. Doing this has several advantages. First, it will make ud-chain tracking for components of vectors much easier. Second, a later optimization pass could collect scalars into vectors to allow generation of SWZ instructions (or similar as operands to other instructions on R200 and i915). It also enables an easy way to generate IR for SWZ instructions in the ARB_vertex_program assembler. --- src/glsl/Makefile | 1 + src/glsl/ir.cpp | 25 +++- src/glsl/ir.h | 14 ++- src/glsl/ir_clone.cpp | 3 +- src/glsl/ir_constant_expression.cpp | 18 +++ src/glsl/ir_optimization.h | 1 + src/glsl/ir_validate.cpp | 45 +++++++ src/glsl/lower_vector.cpp | 224 +++++++++++++++++++++++++++++++++++ src/glsl/opt_algebraic.cpp | 2 +- src/mesa/drivers/dri/i965/brw_fs.cpp | 1 + src/mesa/program/ir_to_mesa.cpp | 132 +++++++++++++++++++++ 11 files changed, 460 insertions(+), 6 deletions(-) create mode 100644 src/glsl/lower_vector.cpp (limited to 'src/glsl/opt_algebraic.cpp') diff --git a/src/glsl/Makefile b/src/glsl/Makefile index 62984f81c0..ea4d6be5a4 100644 --- a/src/glsl/Makefile +++ b/src/glsl/Makefile @@ -64,6 +64,7 @@ CXX_SOURCES = \ lower_variable_index_to_cond_assign.cpp \ lower_vec_index_to_cond_assign.cpp \ lower_vec_index_to_swizzle.cpp \ + lower_vector.cpp \ opt_algebraic.cpp \ opt_constant_folding.cpp \ opt_constant_propagation.cpp \ diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index 1f5e2ebdcb..741e3cb177 100644 --- a/src/glsl/ir.cpp +++ b/src/glsl/ir.cpp @@ -200,18 +200,35 @@ ir_expression::ir_expression(int op, const struct glsl_type *type, this->operation = ir_expression_operation(op); this->operands[0] = op0; this->operands[1] = NULL; + this->operands[2] = NULL; + this->operands[3] = NULL; } ir_expression::ir_expression(int op, const struct glsl_type *type, ir_rvalue *op0, ir_rvalue *op1) { - assert((op1 == NULL) && (get_num_operands(ir_expression_operation(op)) == 1) + assert(((op1 == NULL) && (get_num_operands(ir_expression_operation(op)) == 1)) || (get_num_operands(ir_expression_operation(op)) == 2)); this->ir_type = ir_type_expression; this->type = type; this->operation = ir_expression_operation(op); this->operands[0] = op0; this->operands[1] = op1; + this->operands[2] = NULL; + this->operands[3] = NULL; +} + +ir_expression::ir_expression(int op, const struct glsl_type *type, + ir_rvalue *op0, ir_rvalue *op1, + ir_rvalue *op2, ir_rvalue *op3) +{ + this->ir_type = ir_type_expression; + this->type = type; + this->operation = ir_expression_operation(op); + this->operands[0] = op0; + this->operands[1] = op1; + this->operands[2] = op2; + this->operands[3] = op3; } unsigned int @@ -225,6 +242,9 @@ ir_expression::get_num_operands(ir_expression_operation op) if (op <= ir_last_binop) return 2; + if (op == ir_quadop_vector) + return 4; + assert(false); return 0; } @@ -287,12 +307,13 @@ static const char *const operator_strs[] = { "min", "max", "pow", + "vector", }; const char *ir_expression::operator_string(ir_expression_operation op) { assert((unsigned int) op < Elements(operator_strs)); - assert(Elements(operator_strs) == (ir_binop_pow + 1)); + assert(Elements(operator_strs) == (ir_quadop_vector + 1)); return operator_strs[op]; } diff --git a/src/glsl/ir.h b/src/glsl/ir.h index 99fdaa3b09..be0da07b3b 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -33,6 +33,7 @@ extern "C" { #include } +#include "glsl_types.h" #include "list.h" #include "ir_visitor.h" #include "ir_hierarchical_visitor.h" @@ -824,6 +825,8 @@ enum ir_expression_operation { */ ir_last_binop = ir_binop_pow, + ir_quadop_vector, + /** * A sentinel marking the last of all operations. */ @@ -843,6 +846,12 @@ public: ir_expression(int op, const struct glsl_type *type, ir_rvalue *, ir_rvalue *); + /** + * Constructor for quad operator expressions + */ + ir_expression(int op, const struct glsl_type *type, + ir_rvalue *, ir_rvalue *, ir_rvalue *, ir_rvalue *); + virtual ir_expression *as_expression() { return this; @@ -868,7 +877,8 @@ public: */ unsigned int get_num_operands() const { - return get_num_operands(operation); + return (this->operation == ir_quadop_vector) + ? this->type->vector_elements : get_num_operands(operation); } /** @@ -895,7 +905,7 @@ public: virtual ir_visitor_status accept(ir_hierarchical_visitor *); ir_expression_operation operation; - ir_rvalue *operands[2]; + ir_rvalue *operands[4]; }; diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp index 4032647c3a..325f606615 100644 --- a/src/glsl/ir_clone.cpp +++ b/src/glsl/ir_clone.cpp @@ -168,7 +168,8 @@ ir_expression::clone(void *mem_ctx, struct hash_table *ht) const op[i] = this->operands[i]->clone(mem_ctx, ht); } - return new(mem_ctx) ir_expression(this->operation, this->type, op[0], op[1]); + return new(mem_ctx) ir_expression(this->operation, this->type, + op[0], op[1], op[2], op[3]); } ir_dereference_variable * diff --git a/src/glsl/ir_constant_expression.cpp b/src/glsl/ir_constant_expression.cpp index 1fe1505047..4fd6d09a3a 100644 --- a/src/glsl/ir_constant_expression.cpp +++ b/src/glsl/ir_constant_expression.cpp @@ -788,6 +788,24 @@ ir_expression::constant_expression_value() } break; + case ir_quadop_vector: + for (unsigned c = 0; c < this->type->vector_elements; c++) { + switch (this->type->base_type) { + case GLSL_TYPE_INT: + data.i[c] = op[c]->value.i[0]; + break; + case GLSL_TYPE_UINT: + data.u[c] = op[c]->value.u[0]; + break; + case GLSL_TYPE_FLOAT: + data.f[c] = op[c]->value.f[0]; + break; + default: + assert(0); + } + } + break; + default: /* FINISHME: Should handle all expression types. */ return NULL; diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h index ffdc66b9f7..1f8da16bcb 100644 --- a/src/glsl/ir_optimization.h +++ b/src/glsl/ir_optimization.h @@ -59,4 +59,5 @@ bool do_vec_index_to_swizzle(exec_list *instructions); bool lower_noise(exec_list *instructions); bool lower_variable_index_to_cond_assign(exec_list *instructions, bool lower_input, bool lower_output, bool lower_temp, bool lower_uniform); +bool lower_quadop_vector(exec_list *instructions, bool dont_lower_swz); bool optimize_redundant_jumps(exec_list *instructions); diff --git a/src/glsl/ir_validate.cpp b/src/glsl/ir_validate.cpp index 2a066c1a27..5b055f64d3 100644 --- a/src/glsl/ir_validate.cpp +++ b/src/glsl/ir_validate.cpp @@ -374,6 +374,51 @@ ir_validate::visit_leave(ir_expression *ir) assert(ir->operands[0]->type->is_vector()); assert(ir->operands[0]->type == ir->operands[1]->type); break; + + case ir_quadop_vector: + /* The vector operator collects some number of scalars and generates a + * vector from them. + * + * - All of the operands must be scalar. + * - Number of operands must matche the size of the resulting vector. + * - Base type of the operands must match the base type of the result. + */ + assert(ir->type->is_vector()); + switch (ir->type->vector_elements) { + case 2: + assert(ir->operands[0]->type->is_scalar()); + assert(ir->operands[0]->type->base_type == ir->type->base_type); + assert(ir->operands[1]->type->is_scalar()); + assert(ir->operands[1]->type->base_type == ir->type->base_type); + assert(ir->operands[2] == NULL); + assert(ir->operands[3] == NULL); + break; + case 3: + assert(ir->operands[0]->type->is_scalar()); + assert(ir->operands[0]->type->base_type == ir->type->base_type); + assert(ir->operands[1]->type->is_scalar()); + assert(ir->operands[1]->type->base_type == ir->type->base_type); + assert(ir->operands[2]->type->is_scalar()); + assert(ir->operands[2]->type->base_type == ir->type->base_type); + assert(ir->operands[3] == NULL); + break; + case 4: + assert(ir->operands[0]->type->is_scalar()); + assert(ir->operands[0]->type->base_type == ir->type->base_type); + assert(ir->operands[1]->type->is_scalar()); + assert(ir->operands[1]->type->base_type == ir->type->base_type); + assert(ir->operands[2]->type->is_scalar()); + assert(ir->operands[2]->type->base_type == ir->type->base_type); + assert(ir->operands[3]->type->is_scalar()); + assert(ir->operands[3]->type->base_type == ir->type->base_type); + break; + default: + /* The is_vector assertion above should prevent execution from ever + * getting here. + */ + assert(!"Should not get here."); + break; + } } return visit_continue; diff --git a/src/glsl/lower_vector.cpp b/src/glsl/lower_vector.cpp new file mode 100644 index 0000000000..ae50120100 --- /dev/null +++ b/src/glsl/lower_vector.cpp @@ -0,0 +1,224 @@ +/* + * 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 lower_vector.cpp + * IR lowering pass to remove some types of ir_quadop_vector + * + * \author Ian Romanick + */ + +#include "ir.h" +#include "ir_rvalue_visitor.h" + +class lower_vector_visitor : public ir_rvalue_visitor { +public: + lower_vector_visitor() : progress(false) + { + /* empty */ + } + + void handle_rvalue(ir_rvalue **rvalue); + + /** + * Should SWZ-like expressions be lowered? + */ + bool dont_lower_swz; + + bool progress; +}; + +/** + * Determine if an IR expression tree looks like an extended swizzle + * + * Extended swizzles consist of access of a single vector source (with possible + * per component negation) and the constants -1, 0, or 1. + */ +bool +is_extended_swizzle(ir_expression *ir) +{ + /* Track any variables that are accessed by this expression. + */ + ir_variable *var = NULL; + + assert(ir->operation == ir_quadop_vector); + + for (unsigned i = 0; i < ir->type->vector_elements; i++) { + ir_rvalue *op = ir->operands[i]; + + while (op != NULL) { + switch (op->ir_type) { + case ir_type_constant: { + const ir_constant *const c = op->as_constant(); + + if (!c->is_one() && !c->is_zero() && !c->is_negative_one()) + return false; + + op = NULL; + break; + } + + case ir_type_dereference_variable: { + ir_dereference_variable *const d = (ir_dereference_variable *) op; + + if ((var != NULL) && (var != d->var)) + return false; + + var = d->var; + op = NULL; + break; + } + + case ir_type_expression: { + ir_expression *const ex = (ir_expression *) op; + + if (ex->operation != ir_unop_neg) + return false; + + op = ex->operands[0]; + break; + } + + case ir_type_swizzle: + op = ((ir_swizzle *) op)->val; + break; + + default: + return false; + } + } + } + + return true; +} + +void +lower_vector_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + if (!*rvalue) + return; + + ir_expression *expr = (*rvalue)->as_expression(); + if ((expr == NULL) || (expr->operation != ir_quadop_vector)) + return; + + if (this->dont_lower_swz && is_extended_swizzle(expr)) + return; + + /* FINISHME: Is this the right thing to use for the talloc context? + */ + void *const mem_ctx = expr; + + assert(expr->type->vector_elements == expr->get_num_operands()); + + /* Generate a temporary with the same type as the ir_quadop_operation. + */ + ir_variable *const temp = + new(mem_ctx) ir_variable(expr->type, "vecop_tmp", ir_var_temporary); + + this->base_ir->insert_before(temp); + + /* Counter of the number of components collected so far. + */ + unsigned assigned; + + /* Write-mask in the destination that receives counted by 'assigned'. + */ + unsigned write_mask; + + + /* Generate upto four assignments to that variable. Try to group component + * assignments together: + * + * - All constant components can be assigned at once. + * - All assigments of components from a single variable with the same + * unary operator can be assigned at once. + */ + ir_constant_data d = { { 0 } }; + + assigned = 0; + write_mask = 0; + for (unsigned i = 0; i < expr->type->vector_elements; i++) { + const ir_constant *const c = expr->operands[i]->as_constant(); + + if (c == NULL) + continue; + + switch (expr->type->base_type) { + case GLSL_TYPE_UINT: d.u[assigned] = c->value.u[0]; break; + case GLSL_TYPE_INT: d.i[assigned] = c->value.i[0]; break; + case GLSL_TYPE_FLOAT: d.f[assigned] = c->value.f[0]; break; + case GLSL_TYPE_BOOL: d.b[assigned] = c->value.b[0]; break; + defatul: assert(!"Should not get here."); break; + } + + write_mask |= (1U << i); + assigned++; + } + + assert((write_mask == 0) == (assigned == 0)); + + /* If there were constant values, generate an assignment. + */ + if (assigned > 0) { + ir_constant *const c = + new(mem_ctx) ir_constant(glsl_type::get_instance(expr->type->base_type, + assigned, 0), + &d); + ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp); + ir_assignment *const assign = + new(mem_ctx) ir_assignment(lhs, c, NULL, write_mask); + + this->base_ir->insert_before(assign); + } + + /* FINISHME: This should try to coalesce assignments. + */ + for (unsigned i = 0; i < expr->type->vector_elements; i++) { + if (expr->operands[i]->ir_type == ir_type_constant) + continue; + + ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp); + ir_assignment *const assign = + new(mem_ctx) ir_assignment(lhs, expr->operands[i], NULL, (1U << i)); + + this->base_ir->insert_before(assign); + assigned++; + } + + assert(assigned == expr->type->vector_elements); + + *rvalue = new(mem_ctx) ir_dereference_variable(temp); + this->progress = true; +} + +bool +lower_quadop_vector(exec_list *instructions, bool dont_lower_swz) +{ + lower_vector_visitor v; + + v.dont_lower_swz = dont_lower_swz; + visit_list_elements(&v, instructions); + + return v.progress; +} diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp index 9a8080bff3..3c9af85f31 100644 --- a/src/glsl/opt_algebraic.cpp +++ b/src/glsl/opt_algebraic.cpp @@ -394,7 +394,7 @@ ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue) return; ir_expression *expr = (*rvalue)->as_expression(); - if (!expr) + if (!expr || expr->operation == ir_quadop_vector) return; *rvalue = handle_expression(expr); diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp index 105327c7fe..e1cb94452d 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp @@ -130,6 +130,7 @@ brw_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) GL_TRUE, /* temp */ GL_TRUE /* uniform */ ) || progress; + progress = lower_quadop_vector(shader->ir, false) || progress; } while (progress); validate_ir_tree(shader->ir); diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index 1b5337e92e..1cb8183042 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -289,6 +289,8 @@ public: GLboolean try_emit_mad(ir_expression *ir, int mul_operand); + void emit_swz(ir_expression *ir); + bool process_move_condition(ir_rvalue *ir); void *mem_ctx; @@ -957,6 +959,123 @@ ir_to_mesa_visitor::reladdr_to_temp(ir_instruction *ir, (*num_reladdr)--; } +void +ir_to_mesa_visitor::emit_swz(ir_expression *ir) +{ + /* Assume that the vector operator is in a form compatible with OPCODE_SWZ. + * This means that each of the operands is either an immediate value of -1, + * 0, or 1, or is a component from one source register (possibly with + * negation). + */ + uint8_t components[4] = { 0 }; + bool negate[4] = { false }; + ir_variable *var = NULL; + + for (unsigned i = 0; i < ir->type->vector_elements; i++) { + ir_rvalue *op = ir->operands[i]; + + assert(op->type->is_scalar()); + + while (op != NULL) { + switch (op->ir_type) { + case ir_type_constant: { + + assert(op->type->is_scalar()); + + const ir_constant *const c = op->as_constant(); + if (c->is_one()) { + components[i] = SWIZZLE_ONE; + } else if (c->is_zero()) { + components[i] = SWIZZLE_ZERO; + } else if (c->is_negative_one()) { + components[i] = SWIZZLE_ONE; + negate[i] = true; + } else { + assert(!"SWZ constant must be 0.0 or 1.0."); + } + + op = NULL; + break; + } + + case ir_type_dereference_variable: { + ir_dereference_variable *const deref = + (ir_dereference_variable *) op; + + assert((var == NULL) || (deref->var == var)); + components[i] = SWIZZLE_X; + var = deref->var; + op = NULL; + break; + } + + case ir_type_expression: { + ir_expression *const expr = (ir_expression *) op; + + assert(expr->operation == ir_unop_neg); + negate[i] = true; + + op = expr->operands[0]; + break; + } + + case ir_type_swizzle: { + ir_swizzle *const swiz = (ir_swizzle *) op; + + components[i] = swiz->mask.x; + op = swiz->val; + break; + } + + default: + assert(!"Should not get here."); + return; + } + } + } + + assert(var != NULL); + + ir_dereference_variable *const deref = + new(mem_ctx) ir_dereference_variable(var); + + this->result.file = PROGRAM_UNDEFINED; + deref->accept(this); + if (this->result.file == PROGRAM_UNDEFINED) { + ir_print_visitor v; + printf("Failed to get tree for expression operand:\n"); + deref->accept(&v); + exit(1); + } + + ir_to_mesa_src_reg src; + + src = this->result; + src.swizzle = MAKE_SWIZZLE4(components[0], + components[1], + components[2], + components[3]); + src.negate = ((unsigned(negate[0]) << 0) + | (unsigned(negate[1]) << 1) + | (unsigned(negate[2]) << 2) + | (unsigned(negate[3]) << 3)); + + /* Storage for our result. Ideally for an assignment we'd be using the + * actual storage for the result here, instead. + */ + const ir_to_mesa_src_reg result_src = get_temp(ir->type); + ir_to_mesa_dst_reg result_dst = ir_to_mesa_dst_reg_from_src(result_src); + + /* Limit writes to the channels that will be used by result_src later. + * This does limit this temp's use as a temporary for multi-instruction + * sequences. + */ + result_dst.writemask = (1 << ir->type->vector_elements) - 1; + + ir_to_mesa_emit_op1(ir, OPCODE_SWZ, result_dst, src); + this->result = result_src; +} + void ir_to_mesa_visitor::visit(ir_expression *ir) { @@ -974,6 +1093,11 @@ ir_to_mesa_visitor::visit(ir_expression *ir) return; } + if (ir->operation == ir_quadop_vector) { + this->emit_swz(ir); + return; + } + for (operand = 0; operand < ir->get_num_operands(); operand++) { this->result.file = PROGRAM_UNDEFINED; ir->operands[operand]->accept(this); @@ -1231,6 +1355,12 @@ ir_to_mesa_visitor::visit(ir_expression *ir) case ir_unop_round_even: assert(!"GLSL 1.30 features unsupported"); break; + + case ir_quadop_vector: + /* This operation should have already been handled. + */ + assert(!"Should not get here."); + break; } this->result = result_src; @@ -2676,6 +2806,8 @@ _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) progress = do_common_optimization(ir, true, options->MaxUnrollIterations) || progress; + progress = lower_quadop_vector(ir, true) || progress; + if (options->EmitNoIfs) progress = do_if_to_cond_assign(ir) || progress; -- cgit v1.2.3 From 4ce084c7072931732fba7ae1d73a4e4e20269f9d Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Tue, 30 Nov 2010 13:24:44 -0800 Subject: glsl: fix matrix type check in ir_algebraic Fixes glsl-mat-mul-1. --- src/glsl/opt_algebraic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/glsl/opt_algebraic.cpp') diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp index 3c9af85f31..20f6159f0e 100644 --- a/src/glsl/opt_algebraic.cpp +++ b/src/glsl/opt_algebraic.cpp @@ -123,8 +123,8 @@ ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index, /* Don't want to even think about matrices. */ if (ir1->operands[0]->type->is_matrix() || - ir1->operands[0]->type->is_matrix() || - ir2->operands[1]->type->is_matrix() || + ir1->operands[1]->type->is_matrix() || + ir2->operands[0]->type->is_matrix() || ir2->operands[1]->type->is_matrix()) return false; -- cgit v1.2.3