diff options
author | Eric Anholt <[email protected]> | 2019-03-04 22:10:33 -0800 |
---|---|---|
committer | Eric Anholt <[email protected]> | 2019-03-05 07:36:24 -0800 |
commit | c6ae666cf5a731118147bb6e88eb520140445e7a (patch) | |
tree | 91f16ef05332132cc838768db531cb4cc0d9016e | |
parent | cf79d62f90a857c92e45f3ab6ba363b0688ce0f0 (diff) |
v3d: Restrict live intervals to the blocks reachable from any def.
In the backend, we often have condition codes on writes to variables, such
that there's no screening def anywhere and the previous live ranges
algorithm would conclude that the start of the range extends to the start
of the program. However, we do know that the live range can only extend
as early as you can reach from all blocks writing to the variable.
The motivation was that, while we have a couple of hacks to try to promote
conditional writes up to being a def within the block, the exec_mask one
was broken and needed a replacement.
Based on c3c1aa5aeb92 ("intel/fs: Restrict live intervals to the subset
possibly reachable from any definition.").
-rw-r--r-- | src/broadcom/compiler/v3d_compiler.h | 2 | ||||
-rw-r--r-- | src/broadcom/compiler/vir_live_variables.c | 45 |
2 files changed, 43 insertions, 4 deletions
diff --git a/src/broadcom/compiler/v3d_compiler.h b/src/broadcom/compiler/v3d_compiler.h index 5984d3ef5fe..75dff07404e 100644 --- a/src/broadcom/compiler/v3d_compiler.h +++ b/src/broadcom/compiler/v3d_compiler.h @@ -419,6 +419,8 @@ struct qblock { /** @{ used by v3d_vir_live_variables.c */ BITSET_WORD *def; + BITSET_WORD *defin; + BITSET_WORD *defout; BITSET_WORD *use; BITSET_WORD *live_in; BITSET_WORD *live_out; diff --git a/src/broadcom/compiler/vir_live_variables.c b/src/broadcom/compiler/vir_live_variables.c index 2879e23b43c..cba4000fd1d 100644 --- a/src/broadcom/compiler/vir_live_variables.c +++ b/src/broadcom/compiler/vir_live_variables.c @@ -109,8 +109,11 @@ vir_setup_def(struct v3d_compile *c, struct qblock *block, int ip, c->temp_start[var] = MIN2(c->temp_start[var], ip); c->temp_end[var] = MAX2(c->temp_end[var], ip); - /* If we've already tracked this as a def, or already used it within - * the block, there's nothing to do. + /* Mark the block as having a (partial) def of the var. */ + BITSET_SET(block->defout, var); + + /* If we've already tracked this as a def that screens off previous + * uses, or already used it within the block, there's nothing to do. */ if (BITSET_TEST(block->use, var) || BITSET_TEST(block->def, var)) return; @@ -278,6 +281,33 @@ vir_live_variables_dataflow(struct v3d_compile *c, int bitset_words) return cont; } +static bool +vir_live_variables_defin_defout_dataflow(struct v3d_compile *c, int bitset_words) +{ + bool cont = false; + + vir_for_each_block_rev(block, c) { + /* Propagate defin/defout down the successors to produce the + * union of blocks with a reachable (partial) definition of + * the var. + * + * This keeps a conditional first write to a reg from + * extending its lifetime back to the start of the program. + */ + vir_for_each_successor(succ, block) { + for (int i = 0; i < bitset_words; i++) { + BITSET_WORD new_def = (block->defout[i] & + ~succ->defin[i]); + succ->defin[i] |= new_def; + succ->defout[i] |= new_def; + cont |= new_def; + } + } + } + + return cont; +} + /** * Extend the start/end ranges for each variable to account for the * new information calculated from control flow. @@ -287,14 +317,16 @@ vir_compute_start_end(struct v3d_compile *c, int num_vars) { vir_for_each_block(block, c) { for (int i = 0; i < num_vars; i++) { - if (BITSET_TEST(block->live_in, i)) { + if (BITSET_TEST(block->live_in, i) && + BITSET_TEST(block->defin, i)) { c->temp_start[i] = MIN2(c->temp_start[i], block->start_ip); c->temp_end[i] = MAX2(c->temp_end[i], block->start_ip); } - if (BITSET_TEST(block->live_out, i)) { + if (BITSET_TEST(block->live_out, i) && + BITSET_TEST(block->defout, i)) { c->temp_start[i] = MIN2(c->temp_start[i], block->end_ip); c->temp_end[i] = MAX2(c->temp_end[i], @@ -334,6 +366,8 @@ vir_calculate_live_intervals(struct v3d_compile *c) vir_for_each_block(block, c) { block->def = rzalloc_array(c, BITSET_WORD, bitset_words); + block->defin = rzalloc_array(c, BITSET_WORD, bitset_words); + block->defout = rzalloc_array(c, BITSET_WORD, bitset_words); block->use = rzalloc_array(c, BITSET_WORD, bitset_words); block->live_in = rzalloc_array(c, BITSET_WORD, bitset_words); block->live_out = rzalloc_array(c, BITSET_WORD, bitset_words); @@ -344,6 +378,9 @@ vir_calculate_live_intervals(struct v3d_compile *c) while (vir_live_variables_dataflow(c, bitset_words)) ; + while (vir_live_variables_defin_defout_dataflow(c, bitset_words)) + ; + vir_compute_start_end(c, c->num_temps); c->live_intervals_valid = true; |