From b36a7ce0f1988dd93ec31059cd6ab0ccec32ee91 Mon Sep 17 00:00:00 2001 From: Job Noorman Date: Tue, 5 Nov 2024 12:27:27 +0100 Subject: [PATCH] ir3/ra: prevent moving source intervals for shared collects Non-trivial collects (i.e., ones that will introduce moves because the sources don't line-up with the destination) may cause source intervals to get implicitly moved when they are inserted as children of the destination interval. Since we don't support moving intervals in shared RA, this may cause illegal register allocations. Prevent this by creating a new top-level interval for the destination so that the source intervals will be left alone. Signed-off-by: Job Noorman Fixes: fa22b0901af ("ir3/ra: Add specialized shared register RA/spilling") Part-of: --- src/freedreno/ir3/ir3_shared_ra.c | 36 ++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/freedreno/ir3/ir3_shared_ra.c b/src/freedreno/ir3/ir3_shared_ra.c index 96d9767753e..5812afa0609 100644 --- a/src/freedreno/ir3/ir3_shared_ra.c +++ b/src/freedreno/ir3/ir3_shared_ra.c @@ -825,6 +825,24 @@ assign_src(struct ra_ctx *ctx, struct ir3_register *src) interval->src = false; } +static bool +is_nontrivial_collect(struct ir3_instruction *collect) +{ + if (collect->opc != OPC_META_COLLECT) { + return false; + } + + struct ir3_register *dst = collect->dsts[0]; + + foreach_src_n (src, src_n, collect) { + if (src->num != dst->num + src_n) { + return true; + } + } + + return false; +} + static void handle_dst(struct ra_ctx *ctx, struct ir3_instruction *instr, struct ir3_register *dst) @@ -861,10 +879,26 @@ handle_dst(struct ra_ctx *ctx, struct ir3_instruction *instr, free_space(ctx, physreg, size); } + dst->num = ra_physreg_to_num(physreg, dst->flags); + + /* Non-trivial collects (i.e., ones that will introduce moves because the + * sources don't line-up with the destination) may cause source intervals to + * get implicitly moved when they are inserted as children of the destination + * interval. Since we don't support moving intervals in shared RA, this may + * cause illegal register allocations. Prevent this by creating a new + * top-level interval for the destination so that the source intervals will + * be left alone. + */ + if (is_nontrivial_collect(instr)) { + dst->merge_set = NULL; + dst->interval_start = ctx->live->interval_offset; + dst->interval_end = dst->interval_start + reg_size(dst); + ctx->live->interval_offset = dst->interval_end; + } + ra_update_affinity(reg_file_size(dst), dst, physreg); interval->physreg_start = physreg; interval->physreg_end = physreg + reg_size(dst); - dst->num = ra_physreg_to_num(physreg, dst->flags); ir3_reg_interval_insert(&ctx->reg_ctx, &interval->interval); d("insert dst %u physreg %u", dst->name, physreg);