On 4/21/2026 2:29 AM, Jin Ma wrote:
The restrict_cost_classes function builds a "narrow" list of register
classes for IRA cost computation. When iterating over classes, it skips
a class if it is a subset of an already-added class. However, it does
not handle the reverse case: when a newly encountered class is a
superset of an already-added class.
Per GCC internals Section 19.8, subclasses should have lower class
numbers than their parent classes ("Order the classes so that if class x
is contained in class y then x has a lower class number than y"). This
means subclasses are enumerated first and may be added to the narrow
list before their parent class is encountered. When the parent class
arrives, it is not a subset of the subclass, so it is also added,
resulting in both classes coexisting in the narrow list.
This causes problems for targets with constrained register subsets.
For example, on RISC-V, RVC_FP_REGS (8 registers, f8-f15) appears
before FP_REGS (32 registers) in enum reg_class. Both end up in the
narrow list, and since their register move costs are equal, the
allocator may choose the smaller RVC_FP_REGS as the cost class. This
overestimates register pressure (8 vs 32 available registers), leading
to unnecessary spills and suboptimal instruction scheduling. This was
observed as a 6.3% performance regression in lmbench's double bogo
benchmark on the C907 rv32 platform.
Similarly, on AArch64, FP_LO8_REGS (8 registers) appears before
FP_LO_REGS (16 registers) and FP_REGS (32 registers), and could
exhibit the same issue.
Fix this by removing existing subset classes from the narrow list when
a superset class is added. This ensures the narrow list result is
independent of the enumeration order of reg_class, and the allocator
always uses the largest applicable class for pressure estimation.
gcc/ChangeLog:
* ira-costs.cc (restrict_cost_classes): When adding a new class
to the narrow list, remove any existing classes that are subsets
of the new class. Update the map array to reflect the removal.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/ira-cost-class-subset.c: New test.
* gcc.target/aarch64/ira-cost-class-subset.c: New test.
Has this been bootstrapped and regression tested? I threw it into my
tester and I see a large number of failures across a variety of
platforms. Now it's possible some other change in the last 12 hours is
the root cause, the most likely scenario based on what I'm seeing is
it's this patch.
I would start by verifying this bootstraps and regression tests on x86
which it seems to have introduced ~1400 regressions, many with the strub
tests, but also various assembler scanning tests. When x86 is clean I
would suggest regression testing riscv64-elf where I see:
Tests that now fail, but worked before (610 tests):
unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.dg/hoist-register-pressure-1.c
scan-rtl-dump hoist "PRE/HOIST: end of bb .* copying expression"
unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.dg/hoist-register-pressure-2.c
scan-rtl-dump hoist "PRE/HOIST: end of bb .* copying expression"
unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.dg/hoist-register-pressure-3.c
scan-rtl-dump hoist "PRE/HOIST: end of bb .* copying expression"
unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.target/riscv/fle-ieee.c -O0
scan-assembler \tfrflags\t([^\n]*)\n\tfle\\.d\t[^\n]*\n\tfsflags\t\\1\n
unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.target/riscv/fle-snan.c -O0
scan-assembler
\tfrflags\t([^\n]*)\n\tfle\\.d\t[^,]*,([^,]*),([^,]*)\n\tfsflags\t\\1\n\tfeq\\.d\tzero,\\2,\\3\n
unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.target/riscv/flef-ieee.c -O0
scan-assembler \tfrflags\t([^\n]*)\n\tfle\\.s\t[^\n]*\n\tfsflags\t\\1\n
unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.target/riscv/flef-snan.c -O0
scan-assembler
\tfrflags\t([^\n]*)\n\tfle\\.s\t[^,]*,([^,]*),([^,]*)\n\tfsflags\t\\1\n\tfeq\\.s\tzero,\\2,\\3\n
unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.target/riscv/flt-ieee.c -O0
scan-assembler \tfrflags\t([^\n]*)\n\tflt\\.d\t[^\n]*\n\tfsflags\t\\1\n
unix/-march=rv64gc_zba_zbb_zbs_zicond: gcc: gcc.target/riscv/flt-snan.c -O0
scan-assembler
\tfrflags\t([^\n]*)\n\tflt\\.d\t[^,]*,([^,]*),([^,]*)\n\tfsflags\t\\1\n\tfeq\\.d\tzero,\\2,\\3\n
[ ... ] And so-on. Those hoist-register-pressure-?.c tests are failing
on other targets as well.
Once both of those are working as we want, let me know and I'll repeat
my broader target testing.
jeff