summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers')
-rw-r--r--src/gallium/drivers/freedreno/ir3/ir3.h13
-rw-r--r--src/gallium/drivers/freedreno/ir3/ir3_compiler.c2
-rw-r--r--src/gallium/drivers/freedreno/ir3/ir3_sched.c30
3 files changed, 45 insertions, 0 deletions
diff --git a/src/gallium/drivers/freedreno/ir3/ir3.h b/src/gallium/drivers/freedreno/ir3/ir3.h
index fa866a29850..14369ce772c 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 8ffa37cf34f..f6bdc06130e 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 7938c1f9bea..c1921d04e4e 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: