diff options
author | Ian Romanick <ian.d.romanick@intel.com> | 2014-07-01 17:19:57 -0700 |
---|---|---|
committer | Ian Romanick <ian.d.romanick@intel.com> | 2015-01-21 20:47:44 -0800 |
commit | 21e5af5f1fd9db76a81b8d58e9e71665deeda638 (patch) | |
tree | 3c178bba2760a79ca7fca06afa88b70e02fcee82 | |
parent | e4e82ba83e3356690b95d664b00c83db425ac636 (diff) |
glsl: Optimize certain if-statements to just casts from the conditioncmod-bar
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);
-rw-r--r-- | src/glsl/Makefile.sources | 1 | ||||
-rw-r--r-- | src/glsl/glsl_parser_extras.cpp | 1 | ||||
-rw-r--r-- | src/glsl/ir_optimization.h | 1 | ||||
-rw-r--r-- | src/glsl/opt_if_to_bool_cast.cpp | 184 |
4 files changed, 187 insertions, 0 deletions
diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources index 6237627ac60..f9fa1f7d417 100644 --- a/src/glsl/Makefile.sources +++ b/src/glsl/Makefile.sources @@ -166,6 +166,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 ccdf03198a2..3b8be47f796 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -1604,6 +1604,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 34e0b4b947d..4dbbd7c7e9e 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 00000000000..20a27e3e2c3 --- /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; + } |