Mesa (master): r300/compiler: Handle loops in the register allocator

Tom Stellard tstellar at kemper.freedesktop.org
Sat Apr 30 11:26:21 PDT 2011


Module: Mesa
Branch: master
Commit: 1b75d48e849aaefbff25486133ab67c782492b7c
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=1b75d48e849aaefbff25486133ab67c782492b7c

Author: Tom Stellard <tstellar at gmail.com>
Date:   Sun Apr 17 22:33:04 2011 -0700

r300/compiler: Handle loops in the register allocator

---

 .../dri/r300/compiler/radeon_compiler_util.c       |   22 ++++++
 .../dri/r300/compiler/radeon_compiler_util.h       |    1 +
 .../dri/r300/compiler/radeon_pair_regalloc.c       |   26 +++----
 .../drivers/dri/r300/compiler/radeon_variable.c    |   73 ++++++++++++++++++--
 4 files changed, 103 insertions(+), 19 deletions(-)

diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c b/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c
index ce7b008..3a6b0a7 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c
@@ -583,3 +583,25 @@ struct rc_instruction * rc_match_endloop(struct rc_instruction * endloop)
 	}
 	return NULL;
 }
+
+/**
+ * @return The ENDLOOP instruction that ends the loop started by bgnloop.
+ */
+struct rc_instruction * rc_match_bgnloop(struct rc_instruction * bgnloop)
+{
+	unsigned int bgnloop_count = 0;
+	struct rc_instruction * inst;
+	for (inst = bgnloop->Next; inst!=bgnloop; inst = inst->Next) {
+		rc_opcode op = rc_get_flow_control_inst(inst);
+		if (op == RC_OPCODE_BGNLOOP) {
+			bgnloop_count++;
+		} else if (op == RC_OPCODE_ENDLOOP) {
+			if (bgnloop_count == 0) {
+				return inst;
+			} else {
+				bgnloop_count--;
+			}
+		}
+	}
+	return NULL;
+}
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.h b/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.h
index 0ba25aa..1a0b962 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.h
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.h
@@ -76,5 +76,6 @@ unsigned int rc_pair_remove_src(
 rc_opcode rc_get_flow_control_inst(struct rc_instruction * inst);
 
 struct rc_instruction * rc_match_endloop(struct rc_instruction * endloop);
+struct rc_instruction * rc_match_bgnloop(struct rc_instruction * bgnloop);
 
 #endif /* RADEON_PROGRAM_UTIL_H */
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 52c0216..fd03c73 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c
@@ -66,7 +66,7 @@ struct regalloc_state {
 	unsigned int NumTemporaries;
 
 	unsigned int Simple;
-	unsigned int HasLoop;
+	int LoopEnd;
 };
 
 enum rc_reg_class {
@@ -176,7 +176,8 @@ static void scan_read_callback(void * data, struct rc_instruction * inst,
 		}
 		reg->Live[i].Used = 1;
 		reg->Live[i].Start = 0;
-		reg->Live[i].End = inst->IP;
+		reg->Live[i].End =
+			s->LoopEnd > inst->IP ? s->LoopEnd : inst->IP;
 	}
 }
 
@@ -509,6 +510,14 @@ static void do_advanced_regalloc(struct regalloc_state * s)
 	for (inst = s->C->Program.Instructions.Next;
 					inst != &s->C->Program.Instructions;
 					inst = inst->Next) {
+		rc_opcode op = rc_get_flow_control_inst(inst);
+		if (op == RC_OPCODE_BGNLOOP) {
+			struct rc_instruction * endloop =
+							rc_match_bgnloop(inst);
+			if (endloop->IP > s->LoopEnd) {
+				s->LoopEnd = endloop->IP;
+			}
+		}
 		rc_for_all_reads_mask(inst, scan_read_callback, s);
 	}
 
@@ -622,7 +631,6 @@ void rc_pair_regalloc(struct radeon_compiler *cc, void *user)
 				(struct r300_fragment_program_compiler*)cc;
 	struct regalloc_state s;
 	int do_full_regalloc = (int)user;
-	struct rc_instruction * inst;
 
 	memset(&s, 0, sizeof(s));
 	s.C = cc;
@@ -636,20 +644,10 @@ void rc_pair_regalloc(struct radeon_compiler *cc, void *user)
 			s.NumTemporaries * sizeof(struct register_info));
 	memset(s.Temporary, 0, s.NumTemporaries * sizeof(struct register_info));
 
-	for(inst = cc->Program.Instructions.Next;
-	    inst != &cc->Program.Instructions;
-	    inst = inst->Next) {
-
-		if (inst->U.I.Opcode == RC_OPCODE_BGNLOOP) {
-			s.HasLoop = 1;
-			break;
-		}
-	}
-
 	rc_recompute_ips(s.C);
 
 	c->AllocateHwInputs(c, &alloc_input_simple, &s);
-	if (!s.HasLoop && do_full_regalloc) {
+	if (do_full_regalloc) {
 		do_advanced_regalloc(&s);
 	} else {
 		s.Simple = 1;
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_variable.c b/src/mesa/drivers/dri/r300/compiler/radeon_variable.c
index 91a4d45..082717e 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_variable.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_variable.c
@@ -164,12 +164,75 @@ void rc_variable_compute_live_intervals(struct rc_variable * var)
 
 		for (i = 0; i < var->ReaderCount; i++) {
 			unsigned int chan;
+			unsigned int chan_start = start;
+			unsigned int chan_end = var->Readers[i].Inst->IP;
 			unsigned int mask = var->Readers[i].WriteMask;
+			struct rc_instruction * inst;
+
+			/* Extend the live interval of T0 to the start of the
+			 * loop for sequences like:
+			 * BGNLOOP
+			 * read T0
+			 * ...
+			 * write T0
+			 * ENDLOOP
+			 */
+			if (var->Readers[i].Inst->IP < start) {
+				struct rc_instruction * bgnloop =
+					rc_match_endloop(var->Readers[i].Inst);
+				chan_start = bgnloop->IP;
+			}
+
+			/* Extend the live interval of T0 to the start of the
+			 * loop in case there is a BRK instruction in the loop
+			 * (we don't actually check for a BRK instruction we
+			 * assume there is one somewhere in the loop, which
+			 * there usually is) for sequences like:
+			 * BGNLOOP
+			 * ...
+			 * conditional BRK
+			 * ...
+			 * write T0
+			 * ENDLOOP
+			 * read T0
+			 ***************************************************
+			 * Extend the live interval of T0 to the end of the
+			 * loop for sequences like:
+			 * write T0
+			 * BGNLOOP
+			 * ...
+			 * read T0
+			 * ENDLOOP
+			 */
+			for (inst = var->Inst; inst != var->Readers[i].Inst;
+							inst = inst->Next) {
+				rc_opcode op = rc_get_flow_control_inst(inst);
+				if (op == RC_OPCODE_ENDLOOP) {
+					struct rc_instruction * bgnloop =
+						rc_match_endloop(inst);
+					if (bgnloop->IP < chan_start) {
+						chan_start = bgnloop->IP;
+					}
+				} else if (op == RC_OPCODE_BGNLOOP) {
+					struct rc_instruction * endloop =
+						rc_match_bgnloop(inst);
+					if (endloop->IP > chan_end) {
+						chan_end = endloop->IP;
+					}
+				}
+			}
+
 			for (chan = 0; chan < 4; chan++) {
 				if ((mask >> chan) & 0x1) {
-					var->Live[chan].Start = start;
-					var->Live[chan].End =
-						var->Readers[i].Inst->IP;
+					if (!var->Live[chan].Used
+					|| chan_start < var->Live[chan].Start) {
+						var->Live[chan].Start =
+								chan_start;
+					}
+					if (!var->Live[chan].Used
+					|| chan_end > var->Live[chan].End) {
+						var->Live[chan].End = chan_end;
+					}
 					var->Live[chan].Used = 1;
 				}
 			}
@@ -197,10 +260,9 @@ static unsigned int readers_intersect(
 
 				return 1;
 			}
-
 			if (reader_a.Inst->Type == RC_INSTRUCTION_PAIR
 				&& reader_b.Inst->Type == RC_INSTRUCTION_PAIR
-				&& reader_a.U.P.Arg == reader_b.U.P.Arg) {
+				&& reader_a.U.P.Src == reader_b.U.P.Src) {
 
 				return 1;
 			}
@@ -213,6 +275,7 @@ void rc_variable_add_friend(
 	struct rc_variable * var,
 	struct rc_variable * friend)
 {
+	assert(var->Dst.Index == friend->Dst.Index);
 	while(var->Friend) {
 		var = var->Friend;
 	}



More information about the mesa-commit mailing list