Commit 18119e2f authored by Timothy Arceri's avatar Timothy Arceri

nir: evaluate loop terminator condition uses

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
parent f1638178
......@@ -449,6 +449,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)
{
......@@ -487,9 +579,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:
......@@ -497,15 +591,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;
}
......@@ -532,7 +634,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)) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment