summaryrefslogtreecommitdiffstats
path: root/src/broadcom
diff options
context:
space:
mode:
Diffstat (limited to 'src/broadcom')
-rw-r--r--src/broadcom/compiler/v3d_compiler.h2
-rw-r--r--src/broadcom/compiler/vir_live_variables.c45
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;