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 <jnoorman@igalia.com>
Fixes: fa22b0901a ("ir3/ra: Add specialized shared register RA/spilling")
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31978>
This commit is contained in:
Job Noorman 2024-11-05 12:27:27 +01:00 committed by Marge Bot
parent a2c4a34303
commit b36a7ce0f1

View file

@ -825,6 +825,24 @@ assign_src(struct ra_ctx *ctx, struct ir3_register *src)
interval->src = false; 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 static void
handle_dst(struct ra_ctx *ctx, struct ir3_instruction *instr, handle_dst(struct ra_ctx *ctx, struct ir3_instruction *instr,
struct ir3_register *dst) struct ir3_register *dst)
@ -861,10 +879,26 @@ handle_dst(struct ra_ctx *ctx, struct ir3_instruction *instr,
free_space(ctx, physreg, size); 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); ra_update_affinity(reg_file_size(dst), dst, physreg);
interval->physreg_start = physreg; interval->physreg_start = physreg;
interval->physreg_end = physreg + reg_size(dst); 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); ir3_reg_interval_insert(&ctx->reg_ctx, &interval->interval);
d("insert dst %u physreg %u", dst->name, physreg); d("insert dst %u physreg %u", dst->name, physreg);