Mesa (master): freedreno/ir3: avoid scheduler deadlock

Rob Clark robclark at kemper.freedesktop.org
Sun Mar 15 17:27:38 UTC 2015


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

Author: Rob Clark <robclark at freedesktop.org>
Date:   Wed Mar 11 13:21:42 2015 -0400

freedreno/ir3: avoid scheduler deadlock

Deadlock can occur if we schedule an address register write, yet some
instructions which depend on that address register value also depend on
other unscheduled instructions that depend on a different address
register value.  To solve this, before scheduling an address register
write, ensure that all the other dependencies of the instructions which
consume this address register are already scheduled.

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

---

 src/gallium/drivers/freedreno/ir3/ir3.h          |   13 ++++++++++
 src/gallium/drivers/freedreno/ir3/ir3_compiler.c |    2 ++
 src/gallium/drivers/freedreno/ir3/ir3_sched.c    |   30 ++++++++++++++++++++++
 3 files changed, 45 insertions(+)

diff --git a/src/gallium/drivers/freedreno/ir3/ir3.h b/src/gallium/drivers/freedreno/ir3/ir3.h
index fa866a2..14369ce 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3.h
+++ b/src/gallium/drivers/freedreno/ir3/ir3.h
@@ -321,6 +321,19 @@ struct ir3 {
 	unsigned baryfs_count, baryfs_sz;
 	struct ir3_instruction **baryfs;
 
+	/* Track all indirect instructions (read and write).  To avoid
+	 * deadlock scenario where an address register gets scheduled,
+	 * but other dependent src instructions cannot be scheduled due
+	 * to dependency on a *different* address register value, the
+	 * scheduler needs to ensure that all dependencies other than
+	 * the instruction other than the address register are scheduled
+	 * before the one that writes the address register.  Having a
+	 * convenient list of instructions that reference some address
+	 * register simplifies this.
+	 */
+	unsigned indirects_count, indirects_sz;
+	struct ir3_instruction **indirects;
+
 	struct ir3_block *block;
 	unsigned heap_idx;
 	struct ir3_heap_chunk *chunk;
diff --git a/src/gallium/drivers/freedreno/ir3/ir3_compiler.c b/src/gallium/drivers/freedreno/ir3/ir3_compiler.c
index 8ffa37c..f6bdc06 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3_compiler.c
+++ b/src/gallium/drivers/freedreno/ir3/ir3_compiler.c
@@ -771,6 +771,7 @@ add_dst_reg_wrmask(struct ir3_compile_context *ctx,
 			compile_assert(ctx, ctx->block->address == instr->address);
 
 		instr->address = ctx->block->address;
+		array_insert(ctx->ir->indirects, instr);
 	}
 
 	reg = ir3_reg_create(instr, regid(num, chan), flags);
@@ -901,6 +902,7 @@ add_src_reg_wrmask(struct ir3_compile_context *ctx,
 			compile_assert(ctx, ctx->block->address == instr->address);
 
 		instr->address = ctx->block->address;
+		array_insert(ctx->ir->indirects, instr);
 	}
 
 	reg = ir3_reg_create(instr, regid(num, chan), flags);
diff --git a/src/gallium/drivers/freedreno/ir3/ir3_sched.c b/src/gallium/drivers/freedreno/ir3/ir3_sched.c
index 7938c1f..c1921d0 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3_sched.c
+++ b/src/gallium/drivers/freedreno/ir3/ir3_sched.c
@@ -262,6 +262,36 @@ static int trysched(struct ir3_sched_ctx *ctx,
 		}
 	}
 
+	/* if instruction writes address register, we need to ensure
+	 * that the instructions which use the address register value
+	 * have all their other dependencies scheduled.
+	 * TODO we may possibly need to do the same thing with predicate
+	 * register usage, but for now we get by without since the
+	 * predicate usage patterns are more simple
+	 */
+	if (writes_addr(instr)) {
+		struct ir3 *ir = instr->block->shader;
+		unsigned i;
+
+		for (i = 0; i < ir->indirects_count; i++) {
+			struct ir3_instruction *indirect = ir->indirects[i];
+			if (indirect->depth == DEPTH_UNUSED)
+				continue;
+			if (indirect->address != instr)
+				continue;
+			/* NOTE: avoid recursively scheduling the dependency
+			 * on ourself (ie. avoid infinite recursion):
+			 */
+			foreach_ssa_src(src, indirect) {
+				if (src == instr)
+					continue;
+				delay = trysched(ctx, src);
+				if (delay)
+					return delay;
+			}
+		}
+	}
+
 	/* if this is a write to address/predicate register, and that
 	 * register is currently in use, we need to defer until it is
 	 * free:




More information about the mesa-commit mailing list