summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Stellard <tstellar@gmail.com>2011-01-28 22:10:57 -0800
committerTom Stellard <tstellar@gmail.com>2011-01-29 21:38:24 -0800
commit908f61447f9ba593805b2b608f178e8b69e995d3 (patch)
treea3632bc9ba514e9b518de7b9c69a3b76faed18cc
parent158b9aeb384e2151b10a2b0ee0d779f4b4c8c5d0 (diff)
Temp
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c103
1 files changed, 99 insertions, 4 deletions
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c b/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c
index 5756055f9d5..c1cd2af094c 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c
@@ -144,6 +144,8 @@ static void add_live_intervals_array(struct regalloc_state * s,
static int overlap_live_intervals(struct live_intervals * dst, struct live_intervals * src)
{
+ unsigned int space_before;
+ unsigned int space_after;
if (VERBOSE) {
DBG("overlap_live_intervals: ");
print_live_intervals(dst);
@@ -154,21 +156,26 @@ static int overlap_live_intervals(struct live_intervals * dst, struct live_inter
while(src && dst) {
if (dst->End <= src->Start) {
+ space_before = src->Start - dst->End - 1;
dst = dst->Next;
} else if (dst->End <= src->End) {
DBG(" overlap\n");
- return 1;
+ return -1;
} else if (dst->Start < src->End) {
DBG(" overlap\n");
- return 1;
+ return -1;
} else {
+ /* This value is only valid if the original src passed to
+ * the function had src->Next == NULL. */
+ space_after = dst->Begin - src->End - 1;
src = src->Next;
}
}
DBG(" no overlap\n");
- return 0;
+ /* XXX: We could possibly use a better heuristic here. */
+ return space_before + space_after;
}
static void scan_read_callback(void * data, struct rc_instruction * inst,
@@ -332,7 +339,7 @@ static void do_regalloc(struct regalloc_state * s)
for (chan = 0; chan < 4; chan++) {
if (overlap_live_intervals(
s->HwTemporary[hwreg].UsedChan[chan],
- reg->LiveChan[chan])) {
+ reg->LiveChan[chan]) < 0) {
break;
}
@@ -413,6 +420,93 @@ static void do_regalloc_inputs_only(struct regalloc_state * s)
}
}
+static struct live_interval * remove_live_interval(
+ struct regalloc_state * s,
+ unsigned int ip,
+ unsigned int index,
+ unsigned int chan)
+{
+ struct live_interval * li = s->Temporary[index]->LiveChan[chan];
+ while (li->Start < ip) {
+ li = li->Next;
+ }
+ return li;
+}
+
+static void pack_registers_callback(
+ void * userdata,
+ struct rc_instruction * inst,
+ rc_register_file file,
+ unsigned int index,
+ unsigned int chan)
+
+{
+ struct regalloc_state * s = userdata;
+ struct live_interval * live_interval;
+ unsigned int i, chan_index;
+ unsigned int best_index = index;
+ unsigned int best_chan = chan;
+ unsigned int best_score = -1;
+ struct rc_reader_data reader_data;
+ /* We only want to rewrite instructions that write to a single channel.
+ * We can't rewrite instructions that write to the alpha channel,
+ * then we would have to convert them to vector instructions. */
+ if ((chan != RC_SWIZZLE_X && chan != RC_SWIZZLE_Y && chan != RC_SWIZZLE_Z)
+ || file != RC_FILE_TEMPORARY) {
+ return;
+ }
+
+ live_interval = remove_live_interval(s, inst->IP, index, chan);
+ for (i = 0; i < s->NumTemporaries; i++) {
+ for (chan_index = 0; chan_index < 4; chan++) {
+ int score;
+ if (chan_index == chan) {
+ continue;
+ }
+ score = overlap_live_intervals(
+ s->Temporary[i]->LiveChan[chan_index],
+ live_interval);
+
+ if(score != -1 &&
+ (best_score == -1 || score < best_score)) {
+
+ best_score = score;
+ best_index = i;
+ best_chan = chan_index;
+ }
+ }
+ }
+
+ rc_get_readers(s->C, inst, &reader_data, NULL, NULL, NULL);
+ /* Don't rewrite in this scenario. */
+ if (reader_data->Abort || (best_index == index && best_chan == chan)){
+ best_index = index;
+ best_chan = chan;
+ } else {
+ unsigned int rindex;
+ for (rindex = 0; rindex < reader_data; rindex++) {
+ struct rc_reader reader = reader_data.Readers[rindex];
+ if (reader.Inst->Type == RC_INSTRUCTION_NORMAL) {
+ reader.U.Src->Index = best_index;
+ reader.U.Src->Swizzle = chan;
+ } else {
+
+ }
+ }
+ }
+}
+
+static void pack_registers(struct regalloc_state * s)
+{
+ struct rc_instruction * inst;
+ for (inst = s->C->Program.Instructions.Next;
+ inst != c->C->Program.Instructions;
+ inst = inst->Next) {
+
+ rc_for_all_writes_mask(inst, pack_registers_callback, s);
+ }
+}
+
/**
* @param user This parameter should be a pointer to an integer value. If this
* integer value is zero, then a simple register allocator will be used that
@@ -432,6 +526,7 @@ void rc_pair_regalloc(struct radeon_compiler *cc, void *user)
c->AllocateHwInputs(c, &alloc_input_simple, &s);
do_regalloc_inputs_only(&s);
} else {
+ pack_registers(&s);
c->AllocateHwInputs(c, &alloc_input, &s);
do_regalloc(&s);
}