From: Ian Romanick <ian.d.roman...@intel.com> Some shaders end up with code that looks something like:
if (condition) result = 1.0; else result = 0.0; This pass converts those if-statements to result = float(condition); Of the shaders hurt, 12 of them are vertex shaders "hurt" by virtue of having a loop unrolled. Shader-db results: GM45 (0x2A42): total instructions in shared programs: 3550788 -> 3548093 (-0.08%) instructions in affected programs: 231205 -> 228510 (-1.17%) helped: 712 HURT: 43 Iron Lake (0x0046): total instructions in shared programs: 4980593 -> 4977700 (-0.06%) instructions in affected programs: 267985 -> 265092 (-1.08%) helped: 852 HURT: 56 GAINED: 3 LOST: 24 Sandy Bridge (0x0116): total instructions in shared programs: 6817050 -> 6806224 (-0.16%) instructions in affected programs: 696386 -> 685560 (-1.55%) helped: 2510 HURT: 34 GAINED: 1 LOST: 11 Sandy Bridge (0x0116) NIR: total instructions in shared programs: 6823377 -> 6813527 (-0.14%) instructions in affected programs: 703053 -> 693203 (-1.40%) helped: 2555 HURT: 52 LOST: 23 Ivy Bridge (0x0166): total instructions in shared programs: 6289987 -> 6282273 (-0.12%) instructions in affected programs: 542999 -> 535285 (-1.42%) helped: 1751 HURT: 603 GAINED: 1 LOST: 3 Ivy Bridge (0x0166) NIR: total instructions in shared programs: 6310434 -> 6303918 (-0.10%) instructions in affected programs: 592493 -> 585977 (-1.10%) helped: 1874 HURT: 665 GAINED: 21 Haswell (0x0426): total instructions in shared programs: 5777713 -> 5766346 (-0.20%) instructions in affected programs: 545464 -> 534097 (-2.08%) helped: 2314 HURT: 32 GAINED: 1 LOST: 3 Haswell (0x0426) NIR: total instructions in shared programs: 5791071 -> 5780761 (-0.18%) instructions in affected programs: 565597 -> 555287 (-1.82%) helped: 2399 HURT: 52 GAINED: 21 Broadwell (0x162E): total instructions in shared programs: 6821371 -> 6813617 (-0.11%) instructions in affected programs: 572656 -> 564902 (-1.35%) helped: 2316 HURT: 28 GAINED: 2 LOST: 3 Broadwell (0x162E) NIR: total instructions in shared programs: 7013739 -> 7006622 (-0.10%) instructions in affected programs: 594449 -> 587332 (-1.20%) helped: 2396 HURT: 46 Signed-off-by: Ian Romanick <ian.d.roman...@intel.com> --- 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 | 184 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 187 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 b876642..f49fc86 100644 --- a/src/glsl/Makefile.sources +++ b/src/glsl/Makefile.sources @@ -173,6 +173,7 @@ LIBGLSL_FILES = \ opt_flip_matrices.cpp \ opt_function_inlining.cpp \ opt_if_simplification.cpp \ + opt_if_to_bool_cast.cpp \ opt_minmax.cpp \ opt_noop_swizzle.cpp \ opt_rebalance_tree.cpp \ diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp index 79624bc..cb7ec2b 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -1626,6 +1626,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 = opt_conditional_discard(ir) || progress; progress = do_copy_propagation(ir) || progress; diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h index e6939f3..4892a1d3 100644 --- a/src/glsl/ir_optimization.h +++ b/src/glsl/ir_optimization.h @@ -134,6 +134,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..20a27e3 --- /dev/null +++ b/src/glsl/opt_if_to_bool_cast.cpp @@ -0,0 +1,184 @@ +/* + * 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; +} + +static ir_assignment * +emit_0_or_1_assigment(ir_dereference *lhs, unsigned write_mask, + ir_rvalue *condition, + ir_rvalue *then_rhs, ir_rvalue *else_rhs) +{ + /* 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); + */ + if (then_rhs->is_zero()) + condition = logic_not(condition); + + ir_rvalue *rhs = NULL; + + switch (then_rhs->type->base_type) { + case GLSL_TYPE_UINT: + rhs = i2u(b2i(condition)); + break; + case GLSL_TYPE_INT: + rhs = b2i(condition); + break; + case GLSL_TYPE_FLOAT: + rhs = b2f(condition); + break; + case GLSL_TYPE_BOOL: + rhs = condition; + 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(write_mask); + + assert(size >= 1 && size <= 4); + + return assign(lhs, swizzle(rhs, SWIZZLE_XXXX, size), write_mask); +} + +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; + + ir_assignment *a = NULL; + if ((then_rhs->is_zero() + && (else_rhs->is_one() || else_rhs->is_negative_one())) + || (else_rhs->is_zero() + && (then_rhs->is_one() || then_rhs->is_negative_one()))) { + a = emit_0_or_1_assigment(then_assign->lhs, then_assign->write_mask, + ir->condition, + then_rhs, else_rhs); + } + + if (a != NULL) { + ir->insert_before(a); + ir->remove(); + progress = true; + } + + return visit_continue; + } -- 2.1.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev