summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <[email protected]>2015-04-08 11:04:37 -0400
committerRob Clark <[email protected]>2015-04-11 11:40:15 -0400
commit49be76166b0b3c93bd2287fabc31d76d143d314c (patch)
tree3d03c23057ce84e32ac79b67e5d8731b60d7e1e6
parent4cf4006674bd7c507688316e2033d77066c45c90 (diff)
freedreno/ir3/sched: avoid getting stuck on addr conflicts
When we get in a scenario where we cannot schedule any more instructions due to address register conflict, clone the instruction that writes the address register, and switch the remaining unscheduled users for the current address register over to the new clone. This is simpler and more robust than the previous attempt (which tried and sometimes failed to ensure all other dependencies of users of the address register were scheduled first).. hint it would try to schedule instructions that were not actually needed for any output value. We probably need to do the same with predicate register, although so far it isn't so heavily used so we aren't running into problems with it (yet). Signed-off-by: Rob Clark <[email protected]>
-rw-r--r--src/gallium/drivers/freedreno/ir3/ir3_sched.c74
1 files changed, 42 insertions, 32 deletions
diff --git a/src/gallium/drivers/freedreno/ir3/ir3_sched.c b/src/gallium/drivers/freedreno/ir3/ir3_sched.c
index 653f679fe1e..a790cba129b 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3_sched.c
+++ b/src/gallium/drivers/freedreno/ir3/ir3_sched.c
@@ -267,36 +267,6 @@ 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) || (src->address == 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:
@@ -390,8 +360,48 @@ static int block_sched_undelayed(struct ir3_sched_ctx *ctx,
/* detect if we've gotten ourselves into an impossible situation
* and bail if needed
*/
- if (all_delayed && (attempted > 0))
- ctx->error = true;
+ if (all_delayed && (attempted > 0)) {
+ if (pred_in_use) {
+ /* TODO we probably need to keep a list of instructions
+ * that reference predicate, similar to indirects
+ */
+ ctx->error = true;
+ return DELAYED;
+ }
+ if (addr_in_use) {
+ struct ir3 *ir = ctx->addr->block->shader;
+ struct ir3_instruction *new_addr =
+ ir3_instr_clone(ctx->addr);
+ unsigned i;
+
+ /* original addr is scheduled, but new one isn't: */
+ new_addr->flags &= ~IR3_INSTR_MARK;
+
+ for (i = 0; i < ir->indirects_count; i++) {
+ struct ir3_instruction *indirect = ir->indirects[i];
+
+ /* skip instructions already scheduled: */
+ if (indirect->flags & IR3_INSTR_MARK)
+ continue;
+
+ /* remap remaining instructions using current addr
+ * to new addr:
+ */
+ if (indirect->address == ctx->addr)
+ indirect->address = new_addr;
+ }
+
+ /* all remaining indirects remapped to new addr: */
+ ctx->addr = NULL;
+
+ /* not really, but this will trigger us to go back to
+ * main trysched() loop now that we've resolved the
+ * conflict by duplicating the instr that writes to
+ * the address register.
+ */
+ return SCHEDULED;
+ }
+ }
return cnt;
}