diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2025-01-23 13:57:01 +0000 |
---|---|---|
committer | Richard Sandiford <richard.sandiford@arm.com> | 2025-01-23 13:57:01 +0000 |
commit | ce6fc67da7f600b63985abeb39ba85440cbad549 (patch) | |
tree | bb582b87cdd9f0fbd609d838c4c2f257a5bfb02c /gcc/config/aarch64 | |
parent | 97beccb351901bf25af995830837d348c2e296c1 (diff) | |
download | gcc-ce6fc67da7f600b63985abeb39ba85440cbad549.zip gcc-ce6fc67da7f600b63985abeb39ba85440cbad549.tar.gz gcc-ce6fc67da7f600b63985abeb39ba85440cbad549.tar.bz2 |
aarch64: Fix memory cost for FPM_REGNUM
GCC 15 is going to be the first release to support FPMR.
While working on a follow-up patch, I noticed that for:
(set (reg:DI R) ...)
...
(set (reg:DI fpmr) (reg:DI R))
IRA would prefer to spill R to memory rather than allocate a GPR.
This is because the register move cost for GENERAL_REGS to
MOVEABLE_SYSREGS is very high:
/* Moves to/from sysregs are expensive, and must go via GPR. */
if (from == MOVEABLE_SYSREGS)
return 80 + aarch64_register_move_cost (mode, GENERAL_REGS, to);
if (to == MOVEABLE_SYSREGS)
return 80 + aarch64_register_move_cost (mode, from, GENERAL_REGS);
but the memory cost for MOVEABLE_SYSREGS was the same as for
GENERAL_REGS, making memory much cheaper.
Loading and storing FPMR involves a GPR temporary, so the cost should
account for moving into and out of that temporary.
This did show up indirectly in some of the existing asm tests,
where the stack frame allocated 16 bytes for callee saves (D8)
and another 16 bytes for spilling a temporary register.
It's possible that other registers need the same treatment
and it's more than probable that this code needs a rework.
None of that seems suitable for stage 4 though.
gcc/
* config/aarch64/aarch64.cc (aarch64_memory_move_cost): Account
for the cost of moving in and out of GENERAL_SYSREGS.
gcc/testsuite/
* gcc.target/aarch64/acle/fpmr-5.c: New test.
* gcc.target/aarch64/sve2/acle/asm/dot_lane_mf8.c: Don't expect
a spill slot to be allocated.
* gcc.target/aarch64/sve2/acle/asm/mlalb_lane_mf8.c: Likewise.
* gcc.target/aarch64/sve2/acle/asm/mlallbb_lane_mf8.c: Likewise.
* gcc.target/aarch64/sve2/acle/asm/mlallbt_lane_mf8.c: Likewise.
* gcc.target/aarch64/sve2/acle/asm/mlalltb_lane_mf8.c: Likewise.
* gcc.target/aarch64/sve2/acle/asm/mlalltt_lane_mf8.c: Likewise.
* gcc.target/aarch64/sve2/acle/asm/mlalt_lane_mf8.c: Likewise.
Diffstat (limited to 'gcc/config/aarch64')
-rw-r--r-- | gcc/config/aarch64/aarch64.cc | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index dba779a..a1f5619 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -15858,9 +15858,16 @@ aarch64_memory_move_cost (machine_mode mode, reg_class_t rclass_i, bool in) ? aarch64_tune_params.memmov_cost.load_fp : aarch64_tune_params.memmov_cost.store_fp); + /* If the move needs to go through GPRs, add the cost of doing that. */ + int base = 0; + if (rclass_i == MOVEABLE_SYSREGS) + base += (in + ? aarch64_register_move_cost (DImode, GENERAL_REGS, rclass_i) + : aarch64_register_move_cost (DImode, rclass_i, GENERAL_REGS)); + return (in - ? aarch64_tune_params.memmov_cost.load_int - : aarch64_tune_params.memmov_cost.store_int); + ? base + aarch64_tune_params.memmov_cost.load_int + : base + aarch64_tune_params.memmov_cost.store_int); } /* Implement TARGET_INSN_COST. We have the opportunity to do something |