diff options
Diffstat (limited to 'src/freedreno/ir3/ir3_sched.c')
-rw-r--r-- | src/freedreno/ir3/ir3_sched.c | 49 |
1 files changed, 42 insertions, 7 deletions
diff --git a/src/freedreno/ir3/ir3_sched.c b/src/freedreno/ir3/ir3_sched.c index a311956e925..9a544a8e651 100644 --- a/src/freedreno/ir3/ir3_sched.c +++ b/src/freedreno/ir3/ir3_sched.c @@ -59,6 +59,11 @@ struct ir3_sched_ctx { bool error; }; +static bool is_scheduled(struct ir3_instruction *instr) +{ + return !!(instr->flags & IR3_INSTR_MARK); +} + static bool is_sfu_or_mem(struct ir3_instruction *instr) { return is_sfu(instr) || is_mem(instr); @@ -87,8 +92,32 @@ unuse_each_src(struct ir3_sched_ctx *ctx, struct ir3_instruction *instr) } } +static void clear_cache(struct ir3_sched_ctx *ctx, struct ir3_instruction *instr); static void use_instr(struct ir3_instruction *instr); +/* transfers a use-count to new instruction, for cases where we + * "spill" address or predicate. Note this might cause the + * previous instruction that loaded a0.x/p0.x to become live + * again, when we previously thought it was dead. + */ +static void +transfer_use(struct ir3_sched_ctx *ctx, struct ir3_instruction *orig_instr, + struct ir3_instruction *new_instr) +{ + struct ir3_instruction *src; + + debug_assert(is_scheduled(orig_instr)); + + foreach_ssa_src_n(src, n, new_instr) { + if (__is_false_dep(new_instr, n)) + continue; + ctx->live_values += dest_regs(src); + use_instr(src); + } + + clear_cache(ctx, orig_instr); +} + static void use_each_src(struct ir3_instruction *instr) { @@ -346,11 +375,6 @@ struct ir3_sched_notes { bool addr_conflict, pred_conflict; }; -static bool is_scheduled(struct ir3_instruction *instr) -{ - return !!(instr->flags & IR3_INSTR_MARK); -} - /* could an instruction be scheduled if specified ssa src was scheduled? */ static bool could_sched(struct ir3_instruction *instr, struct ir3_instruction *src) @@ -372,6 +396,8 @@ static bool check_instr(struct ir3_sched_ctx *ctx, struct ir3_sched_notes *notes, struct ir3_instruction *instr) { + debug_assert(!is_scheduled(instr)); + /* For instructions that write address register we need to * make sure there is at least one instruction that uses the * addr value which is otherwise ready. @@ -640,6 +666,15 @@ find_eligible_instr(struct ir3_sched_ctx *ctx, struct ir3_sched_notes *notes, return best_instr; } +static struct ir3_instruction * +split_instr(struct ir3_sched_ctx *ctx, struct ir3_instruction *orig_instr) +{ + struct ir3_instruction *new_instr = ir3_instr_clone(orig_instr); + ir3_insert_by_depth(new_instr, &ctx->depth_list); + transfer_use(ctx, orig_instr, new_instr); + return new_instr; +} + /* "spill" the address register by remapping any unscheduled * instructions which depend on the current address register * to a clone of the instruction which wrote the address reg. @@ -670,7 +705,7 @@ split_addr(struct ir3_sched_ctx *ctx) */ if (indirect->address == ctx->addr) { if (!new_addr) { - new_addr = ir3_instr_clone(ctx->addr); + new_addr = split_instr(ctx, ctx->addr); /* original addr is scheduled, but new one isn't: */ new_addr->flags &= ~IR3_INSTR_MARK; } @@ -714,7 +749,7 @@ split_pred(struct ir3_sched_ctx *ctx) */ if (ssa(predicated->regs[1]) == ctx->pred) { if (!new_pred) { - new_pred = ir3_instr_clone(ctx->pred); + new_pred = split_instr(ctx, ctx->pred); /* original pred is scheduled, but new one isn't: */ new_pred->flags &= ~IR3_INSTR_MARK; } |