From c544f42a795679efbebf62600a413a857922ae77 Mon Sep 17 00:00:00 2001 From: Job Noorman Date: Fri, 10 Oct 2025 11:25:30 +0200 Subject: [PATCH] ir3/ra: reset merge set preferred reg when unavailable When a reg's merge set has a preferred reg but is currently unavailable, it's often preferable to reset its preferred reg and assign a new one, as this potentially reduces the number of movs needed for the as of yet unallocated regs. Totals from 18278 (11.10% of 164705) affected shaders: Instrs: 14380961 -> 14340094 (-0.28%); split: -0.58%, +0.29% CodeSize: 28522270 -> 28460942 (-0.22%); split: -0.44%, +0.23% NOPs: 2771602 -> 2759456 (-0.44%); split: -1.17%, +0.73% MOVs: 589951 -> 577832 (-2.05%); split: -6.63%, +4.57% COVs: 233094 -> 232938 (-0.07%); split: -0.11%, +0.05% Full: 276629 -> 276632 (+0.00%); split: -0.00%, +0.00% (ss): 364508 -> 365702 (+0.33%); split: -0.73%, +1.06% (sy): 177032 -> 176310 (-0.41%); split: -0.98%, +0.57% (ss)-stall: 1512210 -> 1512312 (+0.01%); split: -0.92%, +0.93% (sy)-stall: 5783986 -> 5723012 (-1.05%); split: -1.93%, +0.88% Preamble Instrs: 2905654 -> 2904919 (-0.03%); split: -0.09%, +0.07% Last helper: 3397081 -> 3390054 (-0.21%); split: -0.57%, +0.36% Last baryf: 136198 -> 136439 (+0.18%); split: -0.07%, +0.25% Cat0: 3061954 -> 3051187 (-0.35%); split: -1.11%, +0.76% Cat1: 874681 -> 843044 (-3.62%); split: -6.57%, +2.96% Cat2: 5226994 -> 5226663 (-0.01%); split: -0.01%, +0.00% Cat7: 357258 -> 359126 (+0.52%); split: -0.33%, +0.85% Signed-off-by: Job Noorman Part-of: --- src/freedreno/ir3/ir3_ra.c | 29 +++++++++++++++++++++++++++++ src/freedreno/ir3/ir3_ra.h | 2 ++ src/freedreno/ir3/ir3_shared_ra.c | 2 ++ 3 files changed, 33 insertions(+) diff --git a/src/freedreno/ir3/ir3_ra.c b/src/freedreno/ir3/ir3_ra.c index 6bc42ddbd98..60d3eadb837 100644 --- a/src/freedreno/ir3/ir3_ra.c +++ b/src/freedreno/ir3/ir3_ra.c @@ -1438,6 +1438,33 @@ rpt_has_unique_merge_set(struct ir3_instruction *instr) return true; } +/* Handles this case when a reg's merge set has a preferred reg but is currently + * unavailable. In this case, it's often preferable to reset its preferred reg + * and assign a new one, as this potentially reduces the number of movs needed + * for the as of yet unallocated regs. + */ +void +ir3_ra_handle_unavailable_merge_set(struct ir3_register *reg) +{ + unsigned num_unallocated = 0; + + for (unsigned i = 0; i < reg->merge_set->regs_count; i++) { + if (reg->merge_set->regs[i]->num == INVALID_REG) { + num_unallocated++; + + /* Only reset the preferred reg if there are at least two still + * unallocated regs. It doesn't make sense to reassign the merge set + * for a single reg, and increasing the bound more doesn't seem to + * improve shader stats. + */ + if (num_unallocated >= 2) { + reg->merge_set->preferred_reg = (physreg_t)~0; + return; + } + } + } +} + /* This is the main entrypoint for picking a register. Pick a free register * for "reg", shuffling around sources if necessary. In the normal case where * "is_source" is false, this register can overlap with killed sources @@ -1458,6 +1485,8 @@ get_reg(struct ra_ctx *ctx, struct ra_file *file, struct ir3_register *reg) preferred_reg % reg_elem_size(reg) == 0 && get_reg_specified(ctx, file, reg, preferred_reg, false)) return preferred_reg; + + ir3_ra_handle_unavailable_merge_set(reg); } /* For repeated instructions whose merge set is unique (i.e., only used for diff --git a/src/freedreno/ir3/ir3_ra.h b/src/freedreno/ir3/ir3_ra.h index 03ae9a27deb..d87d1d4bb3e 100644 --- a/src/freedreno/ir3/ir3_ra.h +++ b/src/freedreno/ir3/ir3_ra.h @@ -294,4 +294,6 @@ void ir3_reg_interval_remove_all(struct ir3_reg_ctx *ctx, void ra_update_affinity(unsigned file_size, struct ir3_register *reg, physreg_t physreg); +void ir3_ra_handle_unavailable_merge_set(struct ir3_register *reg); + #endif diff --git a/src/freedreno/ir3/ir3_shared_ra.c b/src/freedreno/ir3/ir3_shared_ra.c index 6c7c4d5ea4d..a122c17e728 100644 --- a/src/freedreno/ir3/ir3_shared_ra.c +++ b/src/freedreno/ir3/ir3_shared_ra.c @@ -677,6 +677,8 @@ get_reg(struct ra_ctx *ctx, struct ir3_register *reg, bool src) preferred_reg % reg_elem_size(reg) == 0 && get_reg_specified(ctx, reg, preferred_reg)) return preferred_reg; + + ir3_ra_handle_unavailable_merge_set(reg); } /* If this register is a subset of a merge set which we have not picked a