Mesa (master): freedreno/ir3: detect scheduler fail

Rob Clark robclark at kemper.freedesktop.org
Sat Aug 30 22:15:10 UTC 2014


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

Author: Rob Clark <robclark at freedesktop.org>
Date:   Fri Aug 29 10:51:40 2014 -0400

freedreno/ir3: detect scheduler fail

There are some cases where the scheduler can get itself into impossible
situations, by scheduling the wrong write to pred or addr register
first.  (Ie. it could end up being unable to schedule any instruction if
some instruction which depends on the current addr/reg value also
depends on another addr/reg value.)

To solve this we'd need to be able to insert extra mov instructions
(which would also help when register assignment gets into impossible
situations).  To do that, we'd need to move the nop padding from sched
into legalize.

But to start with, just detect when we get into an impossible situation
and bail, rather than sitting forever in an infinite loop.  This way it
will at least fall back to the old compiler, which might even work if
you are lucky.

Signed-off-by: Rob Clark <robclark at freedesktop.org>

---

 src/gallium/drivers/freedreno/ir3/ir3.h          |    2 +-
 src/gallium/drivers/freedreno/ir3/ir3_compiler.c |    4 +++-
 src/gallium/drivers/freedreno/ir3/ir3_sched.c    |   19 +++++++++++++++++--
 3 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/src/gallium/drivers/freedreno/ir3/ir3.h b/src/gallium/drivers/freedreno/ir3/ir3.h
index 9ed914b..d4059ad 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3.h
+++ b/src/gallium/drivers/freedreno/ir3/ir3.h
@@ -406,7 +406,7 @@ void ir3_block_depth(struct ir3_block *block);
 void ir3_block_cp(struct ir3_block *block);
 
 /* scheduling: */
-void ir3_block_sched(struct ir3_block *block);
+int ir3_block_sched(struct ir3_block *block);
 
 /* register assignment: */
 int ir3_block_ra(struct ir3_block *block, enum shader_t type,
diff --git a/src/gallium/drivers/freedreno/ir3/ir3_compiler.c b/src/gallium/drivers/freedreno/ir3/ir3_compiler.c
index 1fa2fd4..b587ee0 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3_compiler.c
+++ b/src/gallium/drivers/freedreno/ir3/ir3_compiler.c
@@ -2574,7 +2574,9 @@ ir3_compile_shader(struct ir3_shader_variant *so,
 		ir3_dump_instr_list(block->head);
 	}
 
-	ir3_block_sched(block);
+	ret = ir3_block_sched(block);
+	if (ret)
+		goto out;
 
 	if (fd_mesa_debug & FD_DBG_OPTMSGS) {
 		printf("AFTER SCHED:\n");
diff --git a/src/gallium/drivers/freedreno/ir3/ir3_sched.c b/src/gallium/drivers/freedreno/ir3/ir3_sched.c
index 3ef6773..33d1caa 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3_sched.c
+++ b/src/gallium/drivers/freedreno/ir3/ir3_sched.c
@@ -64,6 +64,7 @@ struct ir3_sched_ctx {
 	struct ir3_instruction *addr;      /* current a0.x user, if any */
 	struct ir3_instruction *pred;      /* current p0.x user, if any */
 	unsigned cnt;
+	bool error;
 };
 
 static struct ir3_instruction *
@@ -308,6 +309,7 @@ static int block_sched_undelayed(struct ir3_sched_ctx *ctx,
 	struct ir3_instruction *instr = block->head;
 	bool addr_in_use = false;
 	bool pred_in_use = false;
+	bool all_delayed = true;
 	unsigned cnt = ~0;
 
 	while (instr) {
@@ -317,6 +319,10 @@ static int block_sched_undelayed(struct ir3_sched_ctx *ctx,
 
 		if (addr || pred) {
 			int ret = trysched(ctx, instr);
+
+			if (ret != DELAYED)
+				all_delayed = false;
+
 			if (ret == SCHEDULED)
 				cnt = 0;
 			else if (ret > 0)
@@ -336,6 +342,12 @@ static int block_sched_undelayed(struct ir3_sched_ctx *ctx,
 	if (!pred_in_use)
 		ctx->pred = NULL;
 
+	/* detect if we've gotten ourselves into an impossible situation
+	 * and bail if needed
+	 */
+	if (all_delayed)
+		ctx->error = true;
+
 	return cnt;
 }
 
@@ -356,7 +368,7 @@ static void block_sched(struct ir3_sched_ctx *ctx, struct ir3_block *block)
 		}
 	}
 
-	while ((instr = block->head)) {
+	while ((instr = block->head) && !ctx->error) {
 		/* NOTE: always grab next *before* trysched(), in case the
 		 * instruction is actually scheduled (and therefore moved
 		 * from depth list into scheduled list)
@@ -393,9 +405,12 @@ static void block_sched(struct ir3_sched_ctx *ctx, struct ir3_block *block)
 	block->head = reverse(ctx->scheduled);
 }
 
-void ir3_block_sched(struct ir3_block *block)
+int ir3_block_sched(struct ir3_block *block)
 {
 	struct ir3_sched_ctx ctx = {0};
 	ir3_clear_mark(block->shader);
 	block_sched(&ctx, block);
+	if (ctx.error)
+		return -1;
+	return 0;
 }




More information about the mesa-commit mailing list