From 832aad989e3d319a8aaac046aa49df25da134d82 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 26 Jul 2010 22:50:29 -0700 Subject: glsl2: Add optimization pass for algebraic simplifications. This cleans up the assembly output of almost all the non-logic tests glsl-algebraic-*. glsl-algebraic-pow-two needs love (basically, flattening to a temporary and squaring it). --- src/glsl/ir_algebraic.cpp | 366 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 src/glsl/ir_algebraic.cpp (limited to 'src/glsl/ir_algebraic.cpp') diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp new file mode 100644 index 0000000000..5b065b086e --- /dev/null +++ b/src/glsl/ir_algebraic.cpp @@ -0,0 +1,366 @@ +/* + * 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_optimization.h" +#include "glsl_types.h" + +/** + * Visitor class for replacing expressions with ir_constant values. + */ + +class ir_algebraic_visitor : public ir_hierarchical_visitor { +public: + ir_algebraic_visitor() + { + this->progress = false; + } + + virtual ~ir_algebraic_visitor() + { + } + + virtual ir_visitor_status visit_leave(ir_assignment *); + virtual ir_visitor_status visit_leave(ir_call *); + virtual ir_visitor_status visit_leave(ir_dereference_array *); + virtual ir_visitor_status visit_leave(ir_expression *); + virtual ir_visitor_status visit_leave(ir_if *); + virtual ir_visitor_status visit_leave(ir_return *); + virtual ir_visitor_status visit_leave(ir_swizzle *); + virtual ir_visitor_status visit_leave(ir_texture *); + + ir_rvalue *handle_expression(ir_rvalue *in_ir); + + 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; +} + +ir_rvalue * +ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir) +{ + ir_expression *ir = (ir_expression *)in_ir; + ir_constant *op_const[2] = {NULL, NULL}; + ir_expression *op_expr[2] = {NULL, NULL}; + unsigned int i; + + if (!in_ir) + return NULL; + + if (in_ir->ir_type != ir_type_expression) + return in_ir; + + for (i = 0; i < ir->get_num_operands(); i++) { + if (ir->operands[i]->type->is_matrix()) + return in_ir; + + op_const[i] = ir->operands[i]->constant_expression_value(); + op_expr[i] = ir->operands[i]->as_expression(); + } + + switch (ir->operation) { + case ir_unop_logic_not: + if (op_expr[0] && op_expr[0]->operation == ir_binop_equal) { + this->progress = true; + return new(ir) ir_expression(ir_binop_nequal, + ir->type, + op_expr[0]->operands[0], + op_expr[0]->operands[1]); + } + if (op_expr[0] && op_expr[0]->operation == ir_binop_nequal) { + this->progress = true; + return new(ir) ir_expression(ir_binop_equal, + 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 ir->operands[1]; + } + if (is_vec_zero(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } + break; + + case ir_binop_sub: + if (is_vec_zero(op_const[0])) { + this->progress = true; + return new(ir) ir_expression(ir_unop_neg, + ir->type, + ir->operands[1], + NULL); + } + if (is_vec_zero(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } + break; + + case ir_binop_mul: + if (is_vec_one(op_const[0])) { + this->progress = true; + return ir->operands[1]; + } + if (is_vec_one(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } + + if (is_vec_zero(op_const[0]) || + is_vec_zero(op_const[1])) { + ir_constant_data zero_data; + memset(&zero_data, 0, sizeof(zero_data)); + + this->progress = true; + return new(ir) ir_constant(ir->type, &zero_data); + } + break; + + case ir_binop_div: + if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) { + this->progress = true; + return new(ir) ir_expression(ir_unop_rcp, + ir->type, + ir->operands[1], + NULL); + } + if (is_vec_one(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } + 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; + return new(ir) ir_expression(ir_unop_rsq, + ir->type, + op_expr[0]->operands[0], + NULL); + } + + break; + + default: + break; + } + + return in_ir; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_expression *ir) +{ + unsigned int operand; + + for (operand = 0; operand < ir->get_num_operands(); operand++) { + ir->operands[operand] = handle_expression(ir->operands[operand]); + } + + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_texture *ir) +{ + ir->coordinate = handle_expression(ir->coordinate); + ir->projector = handle_expression(ir->projector); + ir->shadow_comparitor = handle_expression(ir->shadow_comparitor); + + switch (ir->op) { + case ir_tex: + break; + case ir_txb: + ir->lod_info.bias = handle_expression(ir->lod_info.bias); + break; + case ir_txf: + case ir_txl: + ir->lod_info.lod = handle_expression(ir->lod_info.lod); + break; + case ir_txd: + ir->lod_info.grad.dPdx = handle_expression(ir->lod_info.grad.dPdx); + ir->lod_info.grad.dPdy = handle_expression(ir->lod_info.grad.dPdy); + break; + } + + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_swizzle *ir) +{ + ir->val = handle_expression(ir->val); + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_dereference_array *ir) +{ + ir->array_index = handle_expression(ir->array_index); + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_assignment *ir) +{ + ir->rhs = handle_expression(ir->rhs); + ir->condition = handle_expression(ir->condition); + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_call *ir) +{ + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param = (ir_rvalue *)iter.get(); + ir_rvalue *new_param = handle_expression(param); + + if (new_param != param) { + param->replace_with(new_param); + } + } + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_return *ir) +{ + ir->value = handle_expression(ir->value);; + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_if *ir) +{ + ir->condition = handle_expression(ir->condition); + return visit_continue; +} + + +bool +do_algebraic(exec_list *instructions) +{ + ir_algebraic_visitor v; + + visit_list_elements(&v, instructions); + + return v.progress; +} -- cgit v1.2.3 From f7b94f32a22a769fc71065ca6515186e5a8e3a96 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Wed, 28 Jul 2010 12:20:38 -0700 Subject: ir_algebraic: Use ir_constant::zero. --- src/glsl/ir_algebraic.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src/glsl/ir_algebraic.cpp') diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp index 5b065b086e..a6ecad7b65 100644 --- a/src/glsl/ir_algebraic.cpp +++ b/src/glsl/ir_algebraic.cpp @@ -213,13 +213,9 @@ ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir) return ir->operands[0]; } - if (is_vec_zero(op_const[0]) || - is_vec_zero(op_const[1])) { - ir_constant_data zero_data; - memset(&zero_data, 0, sizeof(zero_data)); - + if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) { this->progress = true; - return new(ir) ir_constant(ir->type, &zero_data); + return ir_constant::zero(ir, ir->type); } break; -- cgit v1.2.3 From fe277089c7a9bb402ef40d89f641b69fb508f2dc Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 9 Aug 2010 09:54:47 -0700 Subject: ir_algebraic: Convert ir_unop_logic_not handler to use a switch statement Currently only ir_binop_equal and ir_binop_nequal are supported, but soon all of the relational operators will be added. Making this change now will simplify those commits. --- src/glsl/ir_algebraic.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'src/glsl/ir_algebraic.cpp') diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp index a6ecad7b65..d9e7b680f7 100644 --- a/src/glsl/ir_algebraic.cpp +++ b/src/glsl/ir_algebraic.cpp @@ -161,22 +161,32 @@ ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir) } switch (ir->operation) { - case ir_unop_logic_not: - if (op_expr[0] && op_expr[0]->operation == ir_binop_equal) { - this->progress = true; - return new(ir) ir_expression(ir_binop_nequal, - ir->type, - op_expr[0]->operands[0], - op_expr[0]->operands[1]); + 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_equal: new_op = ir_binop_nequal; break; + case ir_binop_nequal: new_op = ir_binop_equal; break; + + default: + /* The default case handler is here to silence a warning from GCC. + */ + break; } - if (op_expr[0] && op_expr[0]->operation == ir_binop_nequal) { + + if (new_op != ir_unop_logic_not) { this->progress = true; - return new(ir) ir_expression(ir_binop_equal, + return new(ir) 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])) { -- cgit v1.2.3 From c88e60a27b8d5675cbf488e754537739c2c40bfd Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 9 Aug 2010 10:46:38 -0700 Subject: ir_algebraic: Support other comparisons in ir_unop_logic_not --- src/glsl/ir_algebraic.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/glsl/ir_algebraic.cpp') diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp index d9e7b680f7..43d8f9e699 100644 --- a/src/glsl/ir_algebraic.cpp +++ b/src/glsl/ir_algebraic.cpp @@ -168,6 +168,10 @@ ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir) 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; -- cgit v1.2.3 From 0ff3b2b344b21ae4a7b62ebba22d7358755c8dfe Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 26 Jul 2010 23:56:19 -0700 Subject: glsl2: Make ir_algebraic reassociate add/mul operands for constant folding. It's rather easy to produce two constant multiplies separated by other multiplies while writing a BRDF shader, and non-obvious enough in the resulting codegen that I didn't catch it in my demo code until just recently. Cuts 3 965 instructions from my demo (<1%), and 20 from glsl-fs-raytrace (1.3%). --- src/glsl/ir_algebraic.cpp | 108 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) (limited to 'src/glsl/ir_algebraic.cpp') diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp index 43d8f9e699..86fb7e49c0 100644 --- a/src/glsl/ir_algebraic.cpp +++ b/src/glsl/ir_algebraic.cpp @@ -58,7 +58,14 @@ public: virtual ir_visitor_status visit_leave(ir_texture *); ir_rvalue *handle_expression(ir_rvalue *in_ir); - + 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); bool progress; }; @@ -138,6 +145,84 @@ is_vec_one(ir_constant *ir) 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; +} + ir_rvalue * ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir) { @@ -201,6 +286,16 @@ ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir) this->progress = true; return 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: @@ -231,6 +326,17 @@ ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir) 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: -- cgit v1.2.3 From b3b0cf6a4c6b23e0ebe7e5f5ab1b7cacf27268b1 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 13 Aug 2010 20:39:24 -0700 Subject: glsl2: Add a generic visitor class to call back with pointers to each rvalue. I keep copy and pasting this code all over, so consolidate it in one place. --- src/glsl/Makefile | 1 + src/glsl/ir_algebraic.cpp | 120 ++++---------------------------- src/glsl/ir_rvalue_visitor.cpp | 134 ++++++++++++++++++++++++++++++++++++ src/glsl/ir_rvalue_visitor.h | 47 +++++++++++++ src/glsl/ir_structure_splitting.cpp | 109 ++--------------------------- 5 files changed, 203 insertions(+), 208 deletions(-) create mode 100644 src/glsl/ir_rvalue_visitor.cpp create mode 100644 src/glsl/ir_rvalue_visitor.h (limited to 'src/glsl/ir_algebraic.cpp') diff --git a/src/glsl/Makefile b/src/glsl/Makefile index 2f62517e95..48b7c8f66b 100644 --- a/src/glsl/Makefile +++ b/src/glsl/Makefile @@ -57,6 +57,7 @@ CXX_SOURCES = \ ir_mod_to_fract.cpp \ ir_print_visitor.cpp \ ir_reader.cpp \ + ir_rvalue_visitor.cpp \ ir_set_program_inouts.cpp \ ir_structure_splitting.cpp \ ir_sub_to_add_neg.cpp \ diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp index 86fb7e49c0..a66c820a27 100644 --- a/src/glsl/ir_algebraic.cpp +++ b/src/glsl/ir_algebraic.cpp @@ -30,6 +30,7 @@ #include "ir.h" #include "ir_visitor.h" +#include "ir_rvalue_visitor.h" #include "ir_optimization.h" #include "glsl_types.h" @@ -37,7 +38,7 @@ * Visitor class for replacing expressions with ir_constant values. */ -class ir_algebraic_visitor : public ir_hierarchical_visitor { +class ir_algebraic_visitor : public ir_rvalue_visitor { public: ir_algebraic_visitor() { @@ -48,16 +49,8 @@ public: { } - virtual ir_visitor_status visit_leave(ir_assignment *); - virtual ir_visitor_status visit_leave(ir_call *); - virtual ir_visitor_status visit_leave(ir_dereference_array *); - virtual ir_visitor_status visit_leave(ir_expression *); - virtual ir_visitor_status visit_leave(ir_if *); - virtual ir_visitor_status visit_leave(ir_return *); - virtual ir_visitor_status visit_leave(ir_swizzle *); - virtual ir_visitor_status visit_leave(ir_texture *); - - ir_rvalue *handle_expression(ir_rvalue *in_ir); + 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, @@ -224,22 +217,15 @@ ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index, } ir_rvalue * -ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir) +ir_algebraic_visitor::handle_expression(ir_expression *ir) { - ir_expression *ir = (ir_expression *)in_ir; ir_constant *op_const[2] = {NULL, NULL}; ir_expression *op_expr[2] = {NULL, NULL}; unsigned int i; - if (!in_ir) - return NULL; - - if (in_ir->ir_type != ir_type_expression) - return in_ir; - for (i = 0; i < ir->get_num_operands(); i++) { if (ir->operands[i]->type->is_matrix()) - return in_ir; + return ir; op_const[i] = ir->operands[i]->constant_expression_value(); op_expr[i] = ir->operands[i]->as_expression(); @@ -379,98 +365,22 @@ ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir) break; } - return in_ir; -} - -ir_visitor_status -ir_algebraic_visitor::visit_leave(ir_expression *ir) -{ - unsigned int operand; - - for (operand = 0; operand < ir->get_num_operands(); operand++) { - ir->operands[operand] = handle_expression(ir->operands[operand]); - } - - return visit_continue; -} - -ir_visitor_status -ir_algebraic_visitor::visit_leave(ir_texture *ir) -{ - ir->coordinate = handle_expression(ir->coordinate); - ir->projector = handle_expression(ir->projector); - ir->shadow_comparitor = handle_expression(ir->shadow_comparitor); - - switch (ir->op) { - case ir_tex: - break; - case ir_txb: - ir->lod_info.bias = handle_expression(ir->lod_info.bias); - break; - case ir_txf: - case ir_txl: - ir->lod_info.lod = handle_expression(ir->lod_info.lod); - break; - case ir_txd: - ir->lod_info.grad.dPdx = handle_expression(ir->lod_info.grad.dPdx); - ir->lod_info.grad.dPdy = handle_expression(ir->lod_info.grad.dPdy); - break; - } - - return visit_continue; + return ir; } -ir_visitor_status -ir_algebraic_visitor::visit_leave(ir_swizzle *ir) -{ - ir->val = handle_expression(ir->val); - return visit_continue; -} - -ir_visitor_status -ir_algebraic_visitor::visit_leave(ir_dereference_array *ir) -{ - ir->array_index = handle_expression(ir->array_index); - return visit_continue; -} - -ir_visitor_status -ir_algebraic_visitor::visit_leave(ir_assignment *ir) -{ - ir->rhs = handle_expression(ir->rhs); - ir->condition = handle_expression(ir->condition); - return visit_continue; -} - -ir_visitor_status -ir_algebraic_visitor::visit_leave(ir_call *ir) +void +ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue) { - foreach_iter(exec_list_iterator, iter, *ir) { - ir_rvalue *param = (ir_rvalue *)iter.get(); - ir_rvalue *new_param = handle_expression(param); + if (!*rvalue) + return; - if (new_param != param) { - param->replace_with(new_param); - } - } - return visit_continue; -} + ir_expression *expr = (*rvalue)->as_expression(); + if (!expr) + return; -ir_visitor_status -ir_algebraic_visitor::visit_leave(ir_return *ir) -{ - ir->value = handle_expression(ir->value);; - return visit_continue; + *rvalue = handle_expression(expr); } -ir_visitor_status -ir_algebraic_visitor::visit_leave(ir_if *ir) -{ - ir->condition = handle_expression(ir->condition); - return visit_continue; -} - - bool do_algebraic(exec_list *instructions) { diff --git a/src/glsl/ir_rvalue_visitor.cpp b/src/glsl/ir_rvalue_visitor.cpp new file mode 100644 index 0000000000..613b07c302 --- /dev/null +++ b/src/glsl/ir_rvalue_visitor.cpp @@ -0,0 +1,134 @@ +/* + * 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_rvalue_visitor.cpp + * + * Generic class to implement the common pattern we have of wanting to + * visit each ir_rvalue * and possibly change that node to a different + * class. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_rvalue_visitor.h" +#include "ir_print_visitor.h" +#include "glsl_types.h" + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_expression *ir) +{ + unsigned int operand; + + for (operand = 0; operand < ir->get_num_operands(); operand++) { + handle_rvalue(&ir->operands[operand]); + } + + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_texture *ir) +{ + handle_rvalue(&ir->coordinate); + handle_rvalue(&ir->projector); + handle_rvalue(&ir->shadow_comparitor); + + switch (ir->op) { + case ir_tex: + break; + case ir_txb: + handle_rvalue(&ir->lod_info.bias); + break; + case ir_txf: + case ir_txl: + handle_rvalue(&ir->lod_info.lod); + break; + case ir_txd: + handle_rvalue(&ir->lod_info.grad.dPdx); + handle_rvalue(&ir->lod_info.grad.dPdy); + break; + } + + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_swizzle *ir) +{ + handle_rvalue(&ir->val); + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_dereference_array *ir) +{ + handle_rvalue(&ir->array_index); + handle_rvalue(&ir->array); + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_dereference_record *ir) +{ + handle_rvalue(&ir->record); + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_assignment *ir) +{ + handle_rvalue(&ir->rhs); + handle_rvalue(&ir->condition); + + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_call *ir) +{ + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param = (ir_rvalue *)iter.get(); + ir_rvalue *new_param = param; + handle_rvalue(&new_param); + + if (new_param != param) { + param->replace_with(new_param); + } + } + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_return *ir) +{ + handle_rvalue(&ir->value);; + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_if *ir) +{ + handle_rvalue(&ir->condition); + return visit_continue; +} diff --git a/src/glsl/ir_rvalue_visitor.h b/src/glsl/ir_rvalue_visitor.h new file mode 100644 index 0000000000..31a56beb9b --- /dev/null +++ b/src/glsl/ir_rvalue_visitor.h @@ -0,0 +1,47 @@ +/* + * 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_rvalue_visitor.h + * + * Generic class to implement the common pattern we have of wanting to + * visit each ir_rvalue * and possibly change that node to a different + * class. Just implement handle_rvalue() and you will be called with + * a pointer to each rvalue in the tree. + */ + +class ir_rvalue_visitor : public ir_hierarchical_visitor { +public: + + virtual ir_visitor_status visit_leave(ir_assignment *); + virtual ir_visitor_status visit_leave(ir_call *); + virtual ir_visitor_status visit_leave(ir_dereference_array *); + virtual ir_visitor_status visit_leave(ir_dereference_record *); + virtual ir_visitor_status visit_leave(ir_expression *); + virtual ir_visitor_status visit_leave(ir_if *); + virtual ir_visitor_status visit_leave(ir_return *); + virtual ir_visitor_status visit_leave(ir_swizzle *); + virtual ir_visitor_status visit_leave(ir_texture *); + + virtual void handle_rvalue(ir_rvalue **rvalue) = 0; +}; diff --git a/src/glsl/ir_structure_splitting.cpp b/src/glsl/ir_structure_splitting.cpp index 2f83896263..e257defb1a 100644 --- a/src/glsl/ir_structure_splitting.cpp +++ b/src/glsl/ir_structure_splitting.cpp @@ -35,6 +35,7 @@ #include "ir.h" #include "ir_visitor.h" #include "ir_print_visitor.h" +#include "ir_rvalue_visitor.h" #include "glsl_types.h" static bool debug = false; @@ -165,7 +166,7 @@ ir_structure_reference_visitor::visit_enter(ir_function_signature *ir) return visit_continue_with_parent; } -class ir_structure_splitting_visitor : public ir_hierarchical_visitor { +class ir_structure_splitting_visitor : public ir_rvalue_visitor { public: ir_structure_splitting_visitor(exec_list *vars) { @@ -177,17 +178,9 @@ public: } virtual ir_visitor_status visit_leave(ir_assignment *); - virtual ir_visitor_status visit_leave(ir_call *); - virtual ir_visitor_status visit_leave(ir_dereference_array *); - virtual ir_visitor_status visit_leave(ir_dereference_record *); - virtual ir_visitor_status visit_leave(ir_expression *); - virtual ir_visitor_status visit_leave(ir_if *); - virtual ir_visitor_status visit_leave(ir_return *); - virtual ir_visitor_status visit_leave(ir_swizzle *); - virtual ir_visitor_status visit_leave(ir_texture *); void split_deref(ir_dereference **deref); - void split_rvalue(ir_rvalue **rvalue); + void handle_rvalue(ir_rvalue **rvalue); struct variable_entry *get_splitting_entry(ir_variable *var); exec_list *variable_list; @@ -239,7 +232,7 @@ ir_structure_splitting_visitor::split_deref(ir_dereference **deref) } void -ir_structure_splitting_visitor::split_rvalue(ir_rvalue **rvalue) +ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue) { if (!*rvalue) return; @@ -253,66 +246,6 @@ ir_structure_splitting_visitor::split_rvalue(ir_rvalue **rvalue) *rvalue = deref; } -ir_visitor_status -ir_structure_splitting_visitor::visit_leave(ir_expression *ir) -{ - unsigned int operand; - - for (operand = 0; operand < ir->get_num_operands(); operand++) { - split_rvalue(&ir->operands[operand]); - } - - return visit_continue; -} - -ir_visitor_status -ir_structure_splitting_visitor::visit_leave(ir_texture *ir) -{ - split_rvalue(&ir->coordinate); - split_rvalue(&ir->projector); - split_rvalue(&ir->shadow_comparitor); - - switch (ir->op) { - case ir_tex: - break; - case ir_txb: - split_rvalue(&ir->lod_info.bias); - break; - case ir_txf: - case ir_txl: - split_rvalue(&ir->lod_info.lod); - break; - case ir_txd: - split_rvalue(&ir->lod_info.grad.dPdx); - split_rvalue(&ir->lod_info.grad.dPdy); - break; - } - - return visit_continue; -} - -ir_visitor_status -ir_structure_splitting_visitor::visit_leave(ir_swizzle *ir) -{ - split_rvalue(&ir->val); - return visit_continue; -} - -ir_visitor_status -ir_structure_splitting_visitor::visit_leave(ir_dereference_array *ir) -{ - split_rvalue(&ir->array_index); - split_rvalue(&ir->array); - return visit_continue; -} - -ir_visitor_status -ir_structure_splitting_visitor::visit_leave(ir_dereference_record *ir) -{ - split_rvalue(&ir->record); - return visit_continue; -} - ir_visitor_status ir_structure_splitting_visitor::visit_leave(ir_assignment *ir) { @@ -349,45 +282,15 @@ ir_structure_splitting_visitor::visit_leave(ir_assignment *ir) } ir->remove(); } else { - split_rvalue(&ir->rhs); + handle_rvalue(&ir->rhs); split_deref(&ir->lhs); } - split_rvalue(&ir->condition); - - return visit_continue; -} - -ir_visitor_status -ir_structure_splitting_visitor::visit_leave(ir_call *ir) -{ - foreach_iter(exec_list_iterator, iter, *ir) { - ir_rvalue *param = (ir_rvalue *)iter.get(); - ir_rvalue *new_param = param; - split_rvalue(&new_param); - - if (new_param != param) { - param->replace_with(new_param); - } - } - return visit_continue; -} - -ir_visitor_status -ir_structure_splitting_visitor::visit_leave(ir_return *ir) -{ - split_rvalue(&ir->value);; - return visit_continue; -} + handle_rvalue(&ir->condition); -ir_visitor_status -ir_structure_splitting_visitor::visit_leave(ir_if *ir) -{ - split_rvalue(&ir->condition); return visit_continue; } - bool do_structure_splitting(exec_list *instructions) { -- cgit v1.2.3 From f166d94fac8383b4c56f899ead0b7c06151e16d9 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 17 Aug 2010 13:27:44 -0700 Subject: glsl: Make ir_algebraic new expressions allocate out of the parent. This could reduce the amount of memory used by a shader tree after optimization, and increases consistency with other passes. --- src/glsl/ir_algebraic.cpp | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'src/glsl/ir_algebraic.cpp') diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp index a66c820a27..0092eea036 100644 --- a/src/glsl/ir_algebraic.cpp +++ b/src/glsl/ir_algebraic.cpp @@ -43,6 +43,7 @@ public: ir_algebraic_visitor() { this->progress = false; + this->mem_ctx = NULL; } virtual ~ir_algebraic_visitor() @@ -59,6 +60,8 @@ public: int op1, ir_expression *ir2, int op2); + + void *mem_ctx; bool progress; }; @@ -231,6 +234,9 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) 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; @@ -254,10 +260,10 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) if (new_op != ir_unop_logic_not) { this->progress = true; - return new(ir) ir_expression(new_op, - ir->type, - op_expr[0]->operands[0], - op_expr[0]->operands[1]); + return new(mem_ctx) ir_expression(new_op, + ir->type, + op_expr[0]->operands[0], + op_expr[0]->operands[1]); } break; @@ -287,10 +293,10 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) case ir_binop_sub: if (is_vec_zero(op_const[0])) { this->progress = true; - return new(ir) ir_expression(ir_unop_neg, - ir->type, - ir->operands[1], - NULL); + return new(mem_ctx) ir_expression(ir_unop_neg, + ir->type, + ir->operands[1], + NULL); } if (is_vec_zero(op_const[1])) { this->progress = true; @@ -328,10 +334,10 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) case ir_binop_div: if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) { this->progress = true; - return new(ir) ir_expression(ir_unop_rcp, - ir->type, - ir->operands[1], - NULL); + return new(mem_ctx) ir_expression(ir_unop_rcp, + ir->type, + ir->operands[1], + NULL); } if (is_vec_one(op_const[1])) { this->progress = true; @@ -353,10 +359,10 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) /* 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; - return new(ir) ir_expression(ir_unop_rsq, - ir->type, - op_expr[0]->operands[0], - NULL); + return new(mem_ctx) ir_expression(ir_unop_rsq, + ir->type, + op_expr[0]->operands[0], + NULL); } break; -- cgit v1.2.3 From 0e6066df633f4594fd6fb8ceeb12b15561c57a48 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 17 Aug 2010 13:24:50 -0700 Subject: glsl: When doing algebraic simplification, make sure the type still matches. When simplifying (vec4(1.0) / (float(x))) to rcp(float(x)), we forgot to produce a vec4, angering ir_validate when starting alien-arena. Fixes: glsl-algebraic-add-zero-2 glsl-algebraic-div-one-2 glsl-algebraic-mul-one-2 glsl-algebraic-sub-zero-3 glsl-algebraic-rcp-sqrt-2 --- src/glsl/ir_algebraic.cpp | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) (limited to 'src/glsl/ir_algebraic.cpp') diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp index 0092eea036..b731ba05be 100644 --- a/src/glsl/ir_algebraic.cpp +++ b/src/glsl/ir_algebraic.cpp @@ -60,8 +60,11 @@ public: int op1, ir_expression *ir2, int op2); + ir_rvalue *swizzle_if_required(ir_expression *expr, + ir_rvalue *operand); void *mem_ctx; + bool progress; }; @@ -219,11 +222,27 @@ ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index, 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++) { @@ -272,11 +291,11 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) case ir_binop_add: if (is_vec_zero(op_const[0])) { this->progress = true; - return ir->operands[1]; + return swizzle_if_required(ir, ir->operands[1]); } if (is_vec_zero(op_const[1])) { this->progress = true; - return ir->operands[0]; + return swizzle_if_required(ir, ir->operands[0]); } /* Reassociate addition of constants so that we can do constant @@ -293,25 +312,26 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) case ir_binop_sub: if (is_vec_zero(op_const[0])) { this->progress = true; - return new(mem_ctx) ir_expression(ir_unop_neg, - ir->type, + 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 ir->operands[0]; + return swizzle_if_required(ir, ir->operands[0]); } break; case ir_binop_mul: if (is_vec_one(op_const[0])) { this->progress = true; - return ir->operands[1]; + return swizzle_if_required(ir, ir->operands[1]); } if (is_vec_one(op_const[1])) { this->progress = true; - return ir->operands[0]; + return swizzle_if_required(ir, ir->operands[0]); } if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) { @@ -334,14 +354,15 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) case ir_binop_div: if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) { this->progress = true; - return new(mem_ctx) ir_expression(ir_unop_rcp, - ir->type, + 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 ir->operands[0]; + return swizzle_if_required(ir, ir->operands[0]); } break; @@ -359,10 +380,11 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) /* 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; - return new(mem_ctx) ir_expression(ir_unop_rsq, - ir->type, + 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; -- cgit v1.2.3 From a35faa6a41eb8a240f8e6086853653e9a21e75bd Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Wed, 1 Sep 2010 10:13:21 -0700 Subject: glsl2: Perform algebraic simplifications on logical binary operators Reduces glsl-vs-all-01 from 42 Mesa IR instructions (including the END) to 17. --- src/glsl/ir_algebraic.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'src/glsl/ir_algebraic.cpp') diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp index b731ba05be..ff81563f19 100644 --- a/src/glsl/ir_algebraic.cpp +++ b/src/glsl/ir_algebraic.cpp @@ -366,6 +366,58 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) } 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; -- cgit v1.2.3