freedreno/ir3: detect scheduler fail
authorRob Clark <robclark@freedesktop.org>
Fri, 29 Aug 2014 14:51:40 +0000 (10:51 -0400)
committerRob Clark <robclark@freedesktop.org>
Sat, 30 Aug 2014 22:02:50 +0000 (18:02 -0400)
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 <robclark@freedesktop.org>
src/gallium/drivers/freedreno/ir3/ir3.h
src/gallium/drivers/freedreno/ir3/ir3_compiler.c
src/gallium/drivers/freedreno/ir3/ir3_sched.c

index 9ed914ba2e4550405637c5305608ebd835f34c81..d4059ad004a305a309d1a2e9b25b25fc0a7b65ee 100644 (file)
@@ -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,
index 1fa2fd4e38935837ce418ff82de5acd6cded4bde..b587ee07a93cb4c6d503477e6626f903b6e394b2 100644 (file)
@@ -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");
index 3ef67731926bffca5bd16d6b57f7afd3ff975f65..33d1caacca63c5c97646917bcf4de192768a90d3 100644 (file)
@@ -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;
 }