diff options
author | Rob Clark <[email protected]> | 2015-04-08 11:04:37 -0400 |
---|---|---|
committer | Rob Clark <[email protected]> | 2015-04-11 11:40:15 -0400 |
commit | 49be76166b0b3c93bd2287fabc31d76d143d314c (patch) | |
tree | 3d03c23057ce84e32ac79b67e5d8731b60d7e1e6 /src/gallium/drivers/freedreno | |
parent | 4cf4006674bd7c507688316e2033d77066c45c90 (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]>
Diffstat (limited to 'src/gallium/drivers/freedreno')
-rw-r--r-- | src/gallium/drivers/freedreno/ir3/ir3_sched.c | 74 |
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; } |