diff options
author | Jason Ekstrand <[email protected]> | 2016-08-10 14:34:49 -0700 |
---|---|---|
committer | Jason Ekstrand <[email protected]> | 2016-09-08 20:53:01 -0700 |
commit | 88a2a2e05302179c59e257533ed77d2d0a6a5021 (patch) | |
tree | 7b552b25b277a2ee80e2aafdbd34477946610b96 /src/compiler/nir/nir_opt_gcm.c | |
parent | 99ff4b3eb21ccc5df670e4dc62073cee96d07f23 (diff) |
nir/gcm: Add global value numbering support
Unlike the current CSE pass, global value numbering is capable of detecting
common values even if one does not dominate the other. For instance, in
you have
if (...) {
ssa_1 = ssa_0 + 7;
/* use ssa_1 */
} else {
ssa_2 = ssa_0 + 7;
/* use ssa_2 */
}
Global value numbering doesn't care about dominance relationships so it
figures out that ssa_1 and ssa_2 are the same and converts this to
if (...) {
ssa_1 = ssa_0 + 7;
/* use ssa_1 */
} else {
/* use ssa_1 */
}
Obviously, we just broke SSA form which is bad. Global code motion,
however, will repair this for us by turning this into
ssa_1 = ssa_0 + 7;
if (...) {
/* use ssa_1 */
} else {
/* use ssa_1 */
}
This intended to eventually mostly replace CSE. However, conventional CSE
may still be useful because it's less of a scorched-earth approach and
doesn't require GCM. This makes it a bit more appropriate for use as a
clean-up in a late optimization run.
Signed-off-by: Jason Ekstrand <[email protected]>
Reviewed-by: Kenneth Graunke <[email protected]>
Diffstat (limited to 'src/compiler/nir/nir_opt_gcm.c')
-rw-r--r-- | src/compiler/nir/nir_opt_gcm.c | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/src/compiler/nir/nir_opt_gcm.c b/src/compiler/nir/nir_opt_gcm.c index 02a93489eba..77eb8e6da5a 100644 --- a/src/compiler/nir/nir_opt_gcm.c +++ b/src/compiler/nir/nir_opt_gcm.c @@ -26,6 +26,7 @@ */ #include "nir.h" +#include "nir_instr_set.h" /* * Implements Global Code Motion. A description of GCM can be found in @@ -451,8 +452,8 @@ gcm_place_instr(nir_instr *instr, struct gcm_state *state) block_info->last_instr = instr; } -static void -opt_gcm_impl(nir_function_impl *impl) +static bool +opt_gcm_impl(nir_function_impl *impl, bool value_number) { struct gcm_state state; @@ -470,6 +471,18 @@ opt_gcm_impl(nir_function_impl *impl) gcm_pin_instructions_block(block, &state); } + bool progress = false; + if (value_number) { + struct set *gvn_set = nir_instr_set_create(NULL); + foreach_list_typed_safe(nir_instr, instr, node, &state.instrs) { + if (nir_instr_set_add_or_rewrite(gvn_set, instr)) { + nir_instr_remove(instr); + progress = true; + } + } + nir_instr_set_destroy(gvn_set); + } + foreach_list_typed(nir_instr, instr, node, &state.instrs) gcm_schedule_early_instr(instr, &state); @@ -486,13 +499,19 @@ opt_gcm_impl(nir_function_impl *impl) nir_metadata_preserve(impl, nir_metadata_block_index | nir_metadata_dominance); + + return progress; } -void -nir_opt_gcm(nir_shader *shader) +bool +nir_opt_gcm(nir_shader *shader, bool value_number) { + bool progress = false; + nir_foreach_function(function, shader) { if (function->impl) - opt_gcm_impl(function->impl); + progress |= opt_gcm_impl(function->impl, value_number); } + + return progress; } |