summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2010-09-29 15:20:12 -0700
committerEric Anholt <eric@anholt.net>2010-09-29 16:40:31 -0700
commitb90c7d1713c5a52fd85cb9dacad5828ae2fdbf6c (patch)
tree2eacae57071ee381475de490342dbf6bb175556b
parente1261d3c493ff48348483a0084f3017c7e663dc0 (diff)
i965: Add live interval analysis and hook it up to the register allocator.
Fixes 13 piglit cases that failed at register allocation before.
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs.cpp85
1 files changed, 83 insertions, 2 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp
index 4de64f0927..b00930d5cf 100644
--- a/src/mesa/drivers/dri/i965/brw_fs.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs.cpp
@@ -417,6 +417,8 @@ public:
this->virtual_grf_sizes = NULL;
this->virtual_grf_next = 1;
this->virtual_grf_array_size = 0;
+ this->virtual_grf_def = NULL;
+ this->virtual_grf_use = NULL;
}
~fs_visitor()
{
@@ -450,6 +452,8 @@ public:
void assign_urb_setup();
void assign_regs();
void assign_regs_trivial();
+ void calculate_live_intervals();
+ bool virtual_grf_interferes(int a, int b);
void generate_code();
void generate_fb_write(fs_inst *inst);
void generate_linterp(fs_inst *inst, struct brw_reg dst,
@@ -483,6 +487,8 @@ public:
int *virtual_grf_sizes;
int virtual_grf_next;
int virtual_grf_array_size;
+ int *virtual_grf_def;
+ int *virtual_grf_use;
struct hash_table *variable_ht;
ir_variable *frag_color, *frag_data, *frag_depth;
@@ -2042,6 +2048,8 @@ fs_visitor::assign_regs()
int class_sizes[base_reg_count];
int class_count = 0;
+ calculate_live_intervals();
+
/* Set up the register classes.
*
* The base registers store a scalar value. For texture samples,
@@ -2115,7 +2123,6 @@ fs_visitor::assign_regs()
*/
ra_set_node_class(g, 0, classes[0]);
- /* FINISHME: Proper interference (live interval analysis) */
for (int i = 1; i < this->virtual_grf_next; i++) {
for (int c = 0; c < class_count; c++) {
if (class_sizes[c] == this->virtual_grf_sizes[i]) {
@@ -2125,7 +2132,9 @@ fs_visitor::assign_regs()
}
for (int j = 1; j < i; j++) {
- ra_add_node_interference(g, i, j);
+ if (virtual_grf_interferes(i, j)) {
+ ra_add_node_interference(g, i, j);
+ }
}
}
@@ -2173,6 +2182,78 @@ fs_visitor::assign_regs()
talloc_free(regs);
}
+void
+fs_visitor::calculate_live_intervals()
+{
+ int num_vars = this->virtual_grf_next;
+ int *def = talloc_array(mem_ctx, int, num_vars);
+ int *use = talloc_array(mem_ctx, int, num_vars);
+ int loop_depth = 0;
+ int loop_start = 0;
+
+ for (int i = 0; i < num_vars; i++) {
+ def[i] = 1 << 30;
+ use[i] = 0;
+ }
+
+ int ip = 0;
+ foreach_iter(exec_list_iterator, iter, this->instructions) {
+ fs_inst *inst = (fs_inst *)iter.get();
+
+ if (inst->opcode == BRW_OPCODE_DO) {
+ if (loop_depth++ == 0)
+ loop_start = ip;
+ } else if (inst->opcode == BRW_OPCODE_WHILE) {
+ loop_depth--;
+
+ if (loop_depth == 0) {
+ /* FINISHME:
+ *
+ * Patches up any vars marked for use within the loop as
+ * live until the end. This is conservative, as there
+ * will often be variables defined and used inside the
+ * loop but dead at the end of the loop body.
+ */
+ for (int i = 0; i < num_vars; i++) {
+ if (use[i] == loop_start) {
+ use[i] = ip;
+ }
+ }
+ }
+ } else {
+ int eip = ip;
+
+ if (loop_depth)
+ eip = loop_start;
+
+ for (unsigned int i = 0; i < 3; i++) {
+ if (inst->src[i].file == GRF && inst->src[i].reg != 0) {
+ def[inst->src[i].reg] = MIN2(def[inst->src[i].reg], eip);
+ use[inst->src[i].reg] = MAX2(use[inst->src[i].reg], eip);
+ }
+ }
+ if (inst->dst.file == GRF && inst->dst.reg != 0) {
+ def[inst->dst.reg] = MIN2(def[inst->dst.reg], eip);
+ use[inst->dst.reg] = MAX2(use[inst->dst.reg], eip);
+ }
+ }
+
+ ip++;
+ }
+
+ this->virtual_grf_def = def;
+ this->virtual_grf_use = use;
+}
+
+bool
+fs_visitor::virtual_grf_interferes(int a, int b)
+{
+ int start = MAX2(this->virtual_grf_def[a], this->virtual_grf_def[b]);
+ int end = MIN2(this->virtual_grf_use[a], this->virtual_grf_use[b]);
+
+ return start <= end;
+}
+
static struct brw_reg brw_reg_from_fs_reg(fs_reg *reg)
{
struct brw_reg brw_reg;