diff options
author | Timothy Arceri <[email protected]> | 2018-06-01 15:37:28 +1000 |
---|---|---|
committer | Timothy Arceri <[email protected]> | 2018-06-07 11:33:04 +1000 |
commit | 2a74296f24ba15b14602286a680ca5f344a71059 (patch) | |
tree | a4c7e47f0692eeab574dca96d797debe1e5d4ff9 /src/compiler | |
parent | 1098bc5e854a1253e050fa30d16eda6ca676d4b3 (diff) |
nir: add opt_if_loop_terminator()
This pass detects potential loop terminators and moves intructions
from the non breaking branch after the if-statement.
This enables both the new opt_if_simplification() pass and loop
unrolling to potentially progress further.
Unexpectedly this change speed up shader-db run times by ~3%
Ivy Bridge shader-db results (all changes in dolphin/ubershaders):
total instructions in shared programs: 9995662 -> 9995338 (-0.00%)
instructions in affected programs: 87845 -> 87521 (-0.37%)
helped: 27
HURT: 0
total cycles in shared programs: 230931495 -> 230925015 (-0.00%)
cycles in affected programs: 56391385 -> 56384905 (-0.01%)
helped: 27
HURT: 0
Reviewed-by: Ian Romanick <[email protected]>
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/nir/nir_opt_if.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/src/compiler/nir/nir_opt_if.c b/src/compiler/nir/nir_opt_if.c index b03657a4244..863ca630fbd 100644 --- a/src/compiler/nir/nir_opt_if.c +++ b/src/compiler/nir/nir_opt_if.c @@ -24,6 +24,7 @@ #include "nir.h" #include "nir/nir_builder.h" #include "nir_control_flow.h" +#include "nir_loop_analyze.h" /** * This optimization detects if statements at the tops of loops where the @@ -283,6 +284,72 @@ opt_if_simplification(nir_builder *b, nir_if *nif) return true; } +/** + * This optimization simplifies potential loop terminators which then allows + * other passes such as opt_if_simplification() and loop unrolling to progress + * further: + * + * if (cond) { + * ... then block instructions ... + * } else { + * ... + * break; + * } + * + * into: + * + * if (cond) { + * } else { + * ... + * break; + * } + * ... then block instructions ... + */ +static bool +opt_if_loop_terminator(nir_if *nif) +{ + nir_block *break_blk = NULL; + nir_block *continue_from_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_blk = last_else; + continue_from_then = false; + } else if (nir_block_ends_in_break(last_else)) { + break_blk = last_else; + continue_from_blk = last_then; + } + + /* Continue if the if-statement contained no jumps at all */ + if (!break_blk) + return false; + + /* If the continue from block is empty then return as there is nothing to + * move. + */ + nir_block *first_continue_from_blk = continue_from_then ? + nir_if_first_then_block(nif) : + nir_if_first_else_block(nif); + if (is_block_empty(first_continue_from_blk)) + return false; + + if (!nir_is_trivial_loop_if(nif, break_blk)) + return false; + + /* Finally, move the continue from branch after the if-statement. */ + nir_cf_list tmp; + nir_cf_extract(&tmp, nir_before_block(first_continue_from_blk), + nir_after_block(continue_from_blk)); + nir_cf_reinsert(&tmp, nir_after_cf_node(&nif->cf_node)); + nir_cf_delete(&tmp); + + return true; +} + static bool opt_if_cf_list(nir_builder *b, struct exec_list *cf_list) { @@ -296,6 +363,7 @@ opt_if_cf_list(nir_builder *b, struct exec_list *cf_list) nir_if *nif = nir_cf_node_as_if(cf_node); progress |= opt_if_cf_list(b, &nif->then_list); progress |= opt_if_cf_list(b, &nif->else_list); + progress |= opt_if_loop_terminator(nif); progress |= opt_if_simplification(b, nif); break; } |