From: Ian Romanick <ian.d.roman...@intel.com> Some shaders end up with code that looks something like:
if (some_condition) result = 1.0; else result = 0.0; This pass converts those if-statements to result = float(some_condition); total instructions in shared programs: 5934568 -> 5921818 (-0.21%) instructions in affected programs: 723433 -> 710683 (-1.76%) GAINED: 26 LOST: 7 12 vertex shaders contain loops that we were now able to unroll. Since their instruction count deltas are not representative of this change, I've removed them from the stats. Reviewed-by: Matt Turner <matts...@gmail.com> --- idr: Want to put an S-o-b on this? src/glsl/Makefile.sources | 1 + src/glsl/glsl_parser_extras.cpp | 1 + src/glsl/ir_optimization.h | 1 + src/glsl/opt_if_to_bool_cast.cpp | 178 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 181 insertions(+) create mode 100644 src/glsl/opt_if_to_bool_cast.cpp diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources index 006e947..61de09b 100644 --- a/src/glsl/Makefile.sources +++ b/src/glsl/Makefile.sources @@ -162,6 +162,7 @@ LIBGLSL_FILES = \ $(GLSL_SRCDIR)/opt_flip_matrices.cpp \ $(GLSL_SRCDIR)/opt_function_inlining.cpp \ $(GLSL_SRCDIR)/opt_if_simplification.cpp \ + $(GLSL_SRCDIR)/opt_if_to_bool_cast.cpp \ $(GLSL_SRCDIR)/opt_minmax.cpp \ $(GLSL_SRCDIR)/opt_noop_swizzle.cpp \ $(GLSL_SRCDIR)/opt_rebalance_tree.cpp \ diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp index 6d18cd4..c96b6c9 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -1603,6 +1603,7 @@ do_common_optimization(exec_list *ir, bool linked, progress = do_structure_splitting(ir) || progress; } progress = do_if_simplification(ir) || progress; + progress = optimize_if_to_bool_cast(ir) || progress; progress = opt_flatten_nested_if_blocks(ir) || progress; progress = do_copy_propagation(ir) || progress; progress = do_copy_propagation_elements(ir) || progress; diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h index 34e0b4b..4dbbd7c 100644 --- a/src/glsl/ir_optimization.h +++ b/src/glsl/ir_optimization.h @@ -131,6 +131,7 @@ void optimize_dead_builtin_variables(exec_list *instructions, enum ir_variable_mode other); bool lower_vertex_id(gl_shader *shader); +bool optimize_if_to_bool_cast(exec_list *instructions); ir_rvalue * compare_index_block(exec_list *instructions, ir_variable *index, diff --git a/src/glsl/opt_if_to_bool_cast.cpp b/src/glsl/opt_if_to_bool_cast.cpp new file mode 100644 index 0000000..32c1f99 --- /dev/null +++ b/src/glsl/opt_if_to_bool_cast.cpp @@ -0,0 +1,178 @@ +/* + * Copyright © 2014 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 opt_if_to_bool_cast.cpp + * Optimize certain if-statements to just casts from the condition + * + * Some shaders end up with code that looks something like: + * + * if (some_condition) + * result = 1.0; + * else + * result = 0.0; + * + * This pass converts those if-statements to + * + * result = float(some_condition); + */ + +#include "main/imports.h" +#include "ir.h" +#include "ir_builder.h" +#include "program/prog_instruction.h" + +using namespace ir_builder; + +namespace { + +class ir_if_to_bool_cast_visitor : public ir_hierarchical_visitor { +public: + ir_if_to_bool_cast_visitor() + : progress(false) + { + /* empty */ + } + + ir_visitor_status visit_leave(ir_if *); + + bool progress; +}; + +} /* unnamed namespace */ + +bool +optimize_if_to_bool_cast(exec_list *instructions) +{ + ir_if_to_bool_cast_visitor v; + + v.run(instructions); + return v.progress; +} + +ir_visitor_status +ir_if_to_bool_cast_visitor::visit_leave(ir_if *ir) +{ + /* Both the then-block and the else-block must contain a single instruction + * that is an assignment. + */ + ir_instruction *const then_inst = + (ir_instruction *) ir->then_instructions.get_head(); + if (then_inst == NULL + || !then_inst->next->is_tail_sentinel() + || then_inst->ir_type != ir_type_assignment) + return visit_continue; + + ir_instruction *const else_inst = + (ir_instruction *) ir->else_instructions.get_head(); + if (else_inst == NULL + || !else_inst->next->is_tail_sentinel() + || else_inst->ir_type != ir_type_assignment) + return visit_continue; + + /* That assignment must have the same write-mask and have the same LHS. + */ + ir_assignment *const then_assign = then_inst->as_assignment(); + ir_assignment *const else_assign = else_inst->as_assignment(); + + assert(then_assign != NULL); + assert(else_assign != NULL); + + if (then_assign->write_mask != else_assign->write_mask + || then_assign->condition != NULL + || else_assign->condition != NULL) + return visit_continue; + + if (!then_assign->lhs->equals(else_assign->lhs)) + return visit_continue; + + /* The RHS of the then-assignment must be 1, and the RHS of the + * else-assignment must be 0. Or vice-versa. + */ + ir_constant *const then_rhs = then_assign->rhs->as_constant(); + ir_constant *const else_rhs = else_assign->rhs->as_constant(); + + if (then_rhs == NULL || else_rhs == NULL) + return visit_continue; + + if (then_rhs->is_zero()) { + if (!else_rhs->is_one() && !else_rhs->is_negative_one()) + return visit_continue; + } else if (else_rhs->is_zero()) { + if (!then_rhs->is_one() && !then_rhs->is_negative_one()) + return visit_continue; + } else { + return visit_continue; + } + + /* Generate the RHS of the new assignment. Note that if the old code + * looked like + * + * x = (cond) ? 0.0 : 1.0; + * + * we have to generate + * + * x = float(!cond); + */ + ir_rvalue *const cond = then_rhs->is_zero() + ? logic_not(ir->condition) : ir->condition; + + ir_rvalue *rhs = NULL; + + switch (then_rhs->type->base_type) { + case GLSL_TYPE_UINT: + rhs = i2u(b2i(cond)); + break; + case GLSL_TYPE_INT: + rhs = b2i(cond); + break; + case GLSL_TYPE_FLOAT: + rhs = b2f(cond); + break; + case GLSL_TYPE_BOOL: + rhs = cond; + break; + default: + unreachable("invalid base type"); + } + + /* If the non-zero value was -1, negate the result of the b2[uif] + * operation. + */ + if (then_rhs->is_negative_one() || else_rhs->is_negative_one()) + rhs = neg(rhs); + + const unsigned size = _mesa_bitcount(then_assign->write_mask); + + assert(size >= 1 && size <= 4); + + ir_assignment *const a = assign(then_assign->lhs, + swizzle(rhs, SWIZZLE_XXXX, size), + then_assign->write_mask); + + ir->insert_before(a); + ir->remove(); + progress = true; + + return visit_continue; + } -- 2.0.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev