diff options
author | Rob Clark <[email protected]> | 2014-08-29 10:51:40 -0400 |
---|---|---|
committer | Rob Clark <[email protected]> | 2014-08-30 18:02:50 -0400 |
commit | b823abedf8d1ddba9aeaa43c4a239cb90664dae4 (patch) | |
tree | 4fc302e800e73c97f3f6ab364354ca61a019691e | |
parent | 932b0ef1ceecf873213447a8778e5cbe1b3b6be7 (diff) |
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 <[email protected]>
-rw-r--r-- | src/gallium/drivers/freedreno/ir3/ir3.h | 2 | ||||
-rw-r--r-- | src/gallium/drivers/freedreno/ir3/ir3_compiler.c | 4 | ||||
-rw-r--r-- | 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 9ed914ba2e4..d4059ad004a 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 1fa2fd4e389..b587ee07a93 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 3ef67731926..33d1caacca6 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; } |