For simple loop terminators we can evaluate all further uses of the
condition in the loop because we know we must have either exited
the loop or we have a known value.
shader-db results IVB (all changes from dolphin uber shaders):
total instructions in shared programs: 10022822 -> 10018187 (-0.05%)
instructions in affected programs: 115380 -> 110745 (-4.02%)
helped: 54
HURT: 0
total cycles in shared programs: 232376154 -> 220065064 (-5.30%)
cycles in affected programs: 143176202 -> 130865112 (-8.60%)
helped: 54
HURT: 0
total spills in shared programs: 4383 -> 4370 (-0.30%)
spills in affected programs: 1656 -> 1643 (-0.79%)
helped: 9
HURT: 18
total fills in shared programs: 4610 -> 4581 (-0.63%)
fills in affected programs: 374 -> 345 (-7.75%)
helped: 6
HURT: 0
---
src/compiler/nir/nir_opt_if.c | 115 ++++++++++++++++++++++++++++++++--
1 file changed, 109 insertions(+), 6 deletions(-)
diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c
index 8863c42d9e7..83f2141dff6 100644
--- a/src/compiler/nir/nir_opt_if.c
+++ b/src/compiler/nir/nir_opt_if.c
@@ -430,6 +430,98 @@ opt_if_evaluate_condition_use(nir_if *nif, void *mem_ctx)
return progress;
}
+static bool
+evaluate_term_condition_use(unsigned prev_blk_idx,
+ unsigned after_loop_blk_idx,
+ unsigned nir_boolean,
+ nir_src *use_src, void *mem_ctx,
+ bool if_condition)
+{
+ bool progress = false;
+
+ if (if_condition) {
+ unsigned blk_idx_before_if =
+
nir_cf_node_as_block(nir_cf_node_prev(&use_src->parent_if->cf_node))->index;
+ if (prev_blk_idx <= blk_idx_before_if &&
+ after_loop_blk_idx > blk_idx_before_if) {
+ replace_if_condition_use_with_const(use_src, nir_boolean, mem_ctx,
+ if_condition);
+ progress = true;
+ }
+
+ } else {
+ unsigned use_blk_idx = use_src->parent_instr->block->index;
+ if (prev_blk_idx < use_blk_idx && after_loop_blk_idx > use_blk_idx) {
+ replace_if_condition_use_with_const(use_src, nir_boolean, mem_ctx,
+ if_condition);
+ progress = true;
+ }
+ }
+
+ return progress;
+}
+
+/**
+ * Since we know loop terminators either exit the loop or continue we can
+ * evaluate any further uses of the if-statements condition in the continue
+ * path.
+ */
+static bool
+opt_if_evaluate_condition_use_loop_terminator(nir_if *nif, nir_loop *loop,
+ void *mem_ctx)
+{
+ if (!loop)
+ return false;
+
+ nir_block *break_blk = NULL;
+ bool continue_from_then = true;
+
+ nir_block *last_then = nir_if_last_then_block(nif);
+ nir_block *last_else = nir_if_last_else_block(nif);
+
+ if (nir_block_ends_in_break(last_then)) {
+ break_blk = last_then;
+ continue_from_then = false;
+ } else if (nir_block_ends_in_break(last_else)) {
+ break_blk = last_else;
+ }
+
+ /* Continue if the if-statement contained no jumps at all */
+ if (!break_blk)
+ return false;
+
+ if (!nir_is_trivial_loop_if(nif, break_blk))
+ return false;
+
+ const unsigned nir_boolean = continue_from_then ? NIR_TRUE : NIR_FALSE;
+ bool progress = false;
+
+ nir_block *prev_block =
+ nir_cursor_current_block(nir_before_cf_node(&nif->cf_node));
+
+ nir_block *after_loop =
+ nir_cursor_current_block(nir_after_cf_node(&loop->cf_node));
+
+ /* Evaluate any uses of the loop terminator condition */
+ assert(nif->condition.is_ssa);
+ nir_foreach_use_safe(use_src, nif->condition.ssa) {
+ progress =
+ evaluate_term_condition_use(prev_block->index, after_loop->index,
+ nir_boolean, use_src, mem_ctx, false);
+ }
+
+ nir_foreach_if_use_safe(use_src, nif->condition.ssa) {
+ if (use_src->parent_if != nif) {
+ progress =
+ evaluate_term_condition_use(prev_block->index, after_loop->index,
+ nir_boolean, use_src, mem_ctx, true);
+ }
+ }
+
+
+ return progress;
+}
+
static bool
opt_if_cf_list(nir_builder *b, struct exec_list *cf_list)
{
@@ -468,9 +560,11 @@ opt_if_cf_list(nir_builder *b, struct exec_list *cf_list)
* not do anything to cause the metadata to become invalid.
*/
static bool
-opt_if_safe_cf_list(nir_builder *b, struct exec_list *cf_list, void *mem_ctx)
+opt_if_safe_cf_list(nir_builder *b, struct exec_list *cf_list,
+ nir_loop *curr_loop, void *mem_ctx)
{
bool progress = false;
+
foreach_list_typed(nir_cf_node, cf_node, node, cf_list) {
switch (cf_node->type) {
case nir_cf_node_block:
@@ -478,15 +572,23 @@ opt_if_safe_cf_list(nir_builder *b, struct exec_list
*cf_list, void *mem_ctx)
case nir_cf_node_if: {
nir_if *nif = nir_cf_node_as_if(cf_node);
- progress |= opt_if_safe_cf_list(b, &nif->then_list, mem_ctx);
- progress |= opt_if_safe_cf_list(b, &nif->else_list, mem_ctx);
+ progress |= opt_if_safe_cf_list(b, &nif->then_list, curr_loop,
+ mem_ctx);
+ progress |= opt_if_safe_cf_list(b, &nif->else_list, curr_loop,
+ mem_ctx);
progress |= opt_if_evaluate_condition_use(nif, mem_ctx);
+ progress |= opt_if_evaluate_condition_use_loop_terminator(nif,
+ curr_loop,
+ mem_ctx);
break;
}
case nir_cf_node_loop: {
- nir_loop *loop = nir_cf_node_as_loop(cf_node);
- progress |= opt_if_safe_cf_list(b, &loop->body, mem_ctx);
+ nir_loop *prev_loop = curr_loop;
+ nir_loop *curr_loop = nir_cf_node_as_loop(cf_node);
+ progress |= opt_if_safe_cf_list(b, &curr_loop->body, curr_loop,
+ mem_ctx);
+ curr_loop = prev_loop;
break;
}
@@ -513,7 +615,8 @@ nir_opt_if(nir_shader *shader)
void *mem_ctx = ralloc_parent(function->impl);
nir_metadata_require(function->impl, nir_metadata_block_index);
- progress = opt_if_safe_cf_list(&b, &function->impl->body, mem_ctx);
+ progress = opt_if_safe_cf_list(&b, &function->impl->body, NULL,
+ mem_ctx);
nir_metadata_preserve(function->impl, nir_metadata_block_index);
if (opt_if_cf_list(&b, &function->impl->body)) {
--
2.17.1
_______________________________________________
mesa-dev mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/mesa-dev