diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index f74327ce51b..02819b6d153 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -856,6 +856,7 @@ unsigned ir3_block_get_pred_index(struct ir3_block *block, void ir3_calc_dominance(struct ir3 *ir); bool ir3_block_dominates(struct ir3_block *a, struct ir3_block *b); +struct ir3_block *ir3_dominance_lca(struct ir3_block *b1, struct ir3_block *b2); struct ir3_shader_variant; diff --git a/src/freedreno/ir3/ir3_dominance.c b/src/freedreno/ir3/ir3_dominance.c index 7d04145de31..fc94a648cd6 100644 --- a/src/freedreno/ir3/ir3_dominance.c +++ b/src/freedreno/ir3/ir3_dominance.c @@ -105,3 +105,19 @@ ir3_block_dominates(struct ir3_block *a, struct ir3_block *b) return a->dom_pre_index <= b->dom_pre_index && a->dom_post_index >= b->dom_post_index; } + +/** + * Computes the least common ancestor of two blocks. If one of the blocks is + * null, the other block is returned. + */ +struct ir3_block * +ir3_dominance_lca(struct ir3_block *b1, struct ir3_block *b2) +{ + if (b1 == NULL) + return b2; + + if (b2 == NULL) + return b1; + + return intersect(b1, b2); +} diff --git a/src/freedreno/ir3/ir3_spill.c b/src/freedreno/ir3/ir3_spill.c index 857ff971072..c665eb18abc 100644 --- a/src/freedreno/ir3/ir3_spill.c +++ b/src/freedreno/ir3/ir3_spill.c @@ -109,6 +109,13 @@ struct ra_spill_ctx { */ struct ir3_register *base_reg; + /* During spilling/reloading, we keep track of the least common ancestor of + * all spill/reload blocks and move base_reg there. This prevents using a GPR + * in the preamble, end hence disabling early preamble, if nothing is spilled + * there. + */ + struct ir3_block *base_reg_block; + /* Current pvtmem offset in bytes. */ unsigned spill_slot; @@ -757,6 +764,8 @@ spill(struct ra_spill_ctx *ctx, const struct reg_or_immed *val, } else { src->wrmask = reg->wrmask; } + + ctx->base_reg_block = ir3_dominance_lca(ctx->base_reg_block, spill->block); } static void @@ -927,6 +936,7 @@ reload(struct ra_spill_ctx *ctx, struct ir3_register *reg, dst->merge_set_offset = reg->merge_set_offset; dst->interval_start = reg->interval_start; dst->interval_end = reg->interval_end; + ctx->base_reg_block = ir3_dominance_lca(ctx->base_reg_block, reload->block); return dst; } @@ -2164,6 +2174,12 @@ ir3_spill(struct ir3 *ir, struct ir3_shader_variant *v, ir3_create_parallel_copies(ir); + if (ctx->base_reg_block && + ctx->base_reg_block != ctx->base_reg->instr->block) { + ir3_instr_move_after_phis(ctx->base_reg->instr, ctx->base_reg_block); + ctx->base_reg->instr->block = ctx->base_reg_block; + } + /* After this point, we're done mutating the IR. Liveness has been trashed, * so recalculate it. We'll need it for recalculating the merge sets. */