The arm backend implements neither register-allocator cost hook added by
r15-7895-gb191e8bdecf, so IRA charges nothing for the frame a spill slot
needs. Price that sub sp, add sp as a core register move, as aarch64 does
with regmove_cost->GP2GP, and a callee-saved register at the memory cost
of its save or restore alone, since a push or pop adjusts SP as it
transfers. The transfer is not discounted: a cheaper price lets values
that cross cold calls take every free callee-saved register before
long-lived loop values are allocated. Thumb-1 keeps the default for
r8-r11, which PUSH and POP cannot name. -Os code is unchanged: IRA does
not consult TARGET_CALLEE_SAVE_COST there and the frame cost is zero.
vmlinux .text, github.com/raspberrypi/linux f5a99b953, arm-none-eabi
crosses built from the same base, SOURCE_DATE_EPOCH and KBUILD_BUILD_*
pinned:
bcmrpi_defconfig ARMv6 -O2 10879804 -> 10842296 -37508 B (-0.34%)
bcm2709_defconfig ARMv7 -O2 11395700 -> 11352180 -43520 B (-0.38%)
On gcc.c-torture/execute under qemu, -marm -march=armv6zk executes 1.3%
fewer instructions over the 60 tests whose code changes (5 more, 23
fewer, worst +0.03%); Cortex-M33 is flat.
Regression tested on arm-none-eabi against a pristine compiler built
from the same base: arm.exp, simd.exp, mve.exp, acle.exp, cmse.exp and
advsimd-intrinsics.exp with the default options and with -mthumb
-march=armv7-a -mfloat-abi=hard -mfpu=neon-fp-armv8 -mtune=cortex-a9,
gcc.c-torture/compile.exp, and gcc.c-torture/execute.exp at -O2 under
qemu for -marm -march=armv6zk and -mthumb -mcpu=cortex-m4; no new
failures.
Assisted-by: Claude Opus 5 (Anthropic)
gcc/ChangeLog:
* config/arm/arm.cc (arm_callee_save_cost): New function.
(arm_frame_allocation_cost): New function.
(TARGET_CALLEE_SAVE_COST): Define.
(TARGET_FRAME_ALLOCATION_COST): Define.
gcc/testsuite/ChangeLog:
* gcc.target/arm/callee-save-cost-1.c: New test.
* gcc.target/arm/callee-save-cost-mprofile-1.c: New test.
* gcc.target/arm/callee-save-cost-vfp-1.c: New test.
Signed-off-by: Dominic P <[email protected]>
---
Changes in v3:
v2 priced a register joining an existing push or pop at nregs, the number
of words, where the hook returns a cost on the memory-move scale. At -O2
every callee-saved register then looked almost free, and values crossing
cold calls took them before long-lived loop values were allocated. In
PiTubeDirect's 6502 interpreter (lib6502.c, M6502_run) a loop-invariant
address lost its register and was reloaded from the literal pool at 274
more sites in the dispatch loop: 4.2% more instructions executed under
qemu.
v3 prices the save and restore at the memory cost and keeps only the
frame allocation that a push or pop avoids. The 6502, Z80 and RV32
emulator cores now compile identically to trunk. Kernel .text drops by
0.34% (ARMv6) and 0.38% (ARMv7) instead of 1.81% and 1.87%. The
dlstp-compile-asm-2.c change and cross_call_live_si are gone: v3 no longer
changes those allocations. The tests pin the -mtune their architecture
selects and accept the (PLT) suffix.
OK for trunk?
gcc/config/arm/arm.cc | 39 +++++++++++++++++
.../gcc.target/arm/callee-save-cost-1.c | 25 +++++++++++
.../arm/callee-save-cost-mprofile-1.c | 42 +++++++++++++++++++
.../gcc.target/arm/callee-save-cost-vfp-1.c | 42 +++++++++++++++++++
4 files changed, 148 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/arm/callee-save-cost-1.c
create mode 100644 gcc/testsuite/gcc.target/arm/callee-save-cost-mprofile-1.c
create mode 100644 gcc/testsuite/gcc.target/arm/callee-save-cost-vfp-1.c
diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
index 33b64995442..ffcef9634d0 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -187,6 +187,9 @@ static int arm_insn_cost (rtx_insn *, bool);
static int arm_address_cost (rtx, machine_mode, addr_space_t, bool);
static int arm_register_move_cost (machine_mode, reg_class_t, reg_class_t);
static int arm_memory_move_cost (machine_mode, reg_class_t, bool);
+static int arm_callee_save_cost (spill_cost_type, unsigned int, machine_mode,
+ unsigned int, int, const HARD_REG_SET &, bool);
+static int arm_frame_allocation_cost (frame_cost_type, const HARD_REG_SET &);
static void emit_constant_insn (rtx cond, rtx pattern);
static rtx_insn *emit_set_insn (rtx, rtx);
static void arm_add_cfa_adjust_cfa_note (rtx, int, rtx, rtx);
@@ -474,6 +477,12 @@ static const scoped_attribute_specs *const
arm_attribute_table[] =
#undef TARGET_MEMORY_MOVE_COST
#define TARGET_MEMORY_MOVE_COST arm_memory_move_cost
+#undef TARGET_CALLEE_SAVE_COST
+#define TARGET_CALLEE_SAVE_COST arm_callee_save_cost
+
+#undef TARGET_FRAME_ALLOCATION_COST
+#define TARGET_FRAME_ALLOCATION_COST arm_frame_allocation_cost
+
#undef TARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO arm_encode_section_info
@@ -12677,6 +12686,36 @@ arm_memory_move_cost (machine_mode mode, reg_class_t
rclass,
}
}
+/* Implement TARGET_CALLEE_SAVE_COST. */
+
+static int
+arm_callee_save_cost (spill_cost_type spill_type, unsigned int regno,
+ machine_mode mode, unsigned int nregs, int mem_cost,
+ const HARD_REG_SET &allocated_callee_regs,
+ bool existing_spills_p)
+{
+ /* Only r0-r7 and LR may be named in a Thumb-1 PUSH or POP reglist. */
+ if (TARGET_THUMB1 && regno > LAST_LO_REGNUM)
+ return default_callee_save_cost (spill_type, regno, mode, nregs, mem_cost,
+ allocated_callee_regs, existing_spills_p);
+
+ /* The push and the pop adjust SP as they transfer, so the save needs no
+ frame allocation. */
+ return mem_cost;
+}
+
+/* Implement TARGET_FRAME_ALLOCATION_COST. Price the sub sp, add sp that a
+ spill slot needs as a core register move. */
+
+static int
+arm_frame_allocation_cost (frame_cost_type, const HARD_REG_SET &)
+{
+ if (optimize_function_for_size_p (cfun))
+ return 0;
+
+ return arm_register_move_cost (word_mode, GENERAL_REGS, GENERAL_REGS);
+}
+
/* Vectorizer cost model implementation. */
/* Implement targetm.vectorize.builtin_vectorization_cost. */
diff --git a/gcc/testsuite/gcc.target/arm/callee-save-cost-1.c
b/gcc/testsuite/gcc.target/arm/callee-save-cost-1.c
new file mode 100644
index 00000000000..61671ccb5f2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/callee-save-cost-1.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v7a_arm_ok } */
+/* { dg-options "-O2 -mtune=cortex-a53" } */
+/* { dg-add-options arm_arch_v7a_arm } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+extern int g (int);
+
+/*
+** cross_call_live:
+** push\t{r4, r5, r6, lr}
+** mov\tr4, r0
+** add\tr0, r0, r1
+** mov\tr5, r1
+** bl\tg(?:\(PLT\))?
+** add\tr0, r4, r0
+** sub\tr0, r0, r5
+** pop\t{r4, r5, r6, pc}
+*/
+int
+cross_call_live (int a, int b)
+{
+ int t = g (a + b);
+ return t + a - b;
+}
diff --git a/gcc/testsuite/gcc.target/arm/callee-save-cost-mprofile-1.c
b/gcc/testsuite/gcc.target/arm/callee-save-cost-mprofile-1.c
new file mode 100644
index 00000000000..e4d72e61b62
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/callee-save-cost-mprofile-1.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v7em_hard_ok } */
+/* { dg-options "-O2 -mtune=cortex-m4" } */
+/* { dg-add-options arm_arch_v7em_hard } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+extern float fwork (float);
+
+/*
+** cross_call_live_sf:
+** push\t{r3, lr}
+** vpush.64\t{d8, d9, d10}
+** vmov.f32\ts18, s1
+** vmov.f32\ts17, s2
+** vmov.f32\ts20, s3
+** vmov.f32\ts19, s4
+** vmov.f32\ts21, s0
+** bl\tfwork(?:\(PLT\))?
+** vmov.f32\ts16, s0
+** vmov.f32\ts0, s18
+** bl\tfwork(?:\(PLT\))?
+** vmov.f32\ts15, s0
+** vmov.f32\ts0, s17
+** vadd.f32\ts16, s16, s15
+** bl\tfwork(?:\(PLT\))?
+** vadd.f32\ts0, s16, s0
+** vadd.f32\ts0, s0, s21
+** vadd.f32\ts0, s0, s18
+** vadd.f32\ts0, s0, s17
+** vadd.f32\ts0, s0, s20
+** vadd.f32\ts0, s0, s19
+** vldm\tsp!, {d8-d10}
+** pop\t{r3, pc}
+*/
+float
+cross_call_live_sf (float a, float b, float c, float d, float e)
+{
+ float r = fwork (a);
+ r += fwork (b);
+ r += fwork (c);
+ return r + a + b + c + d + e;
+}
diff --git a/gcc/testsuite/gcc.target/arm/callee-save-cost-vfp-1.c
b/gcc/testsuite/gcc.target/arm/callee-save-cost-vfp-1.c
new file mode 100644
index 00000000000..9d16f7a579e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/callee-save-cost-vfp-1.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v7a_fp_hard_ok } */
+/* { dg-options "-O2 -marm -mtune=cortex-a53" } */
+/* { dg-add-options arm_arch_v7a_fp_hard } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+extern double g (double);
+
+/*
+** cross_call_live_df:
+** push\t{r4, lr}
+** vpush.64\t{d8, d9, d10, d11, d12, d13}
+** vmov.f64\td10, d1
+** vmov.f64\td9, d2
+** vmov.f64\td13, d3
+** vmov.f64\td11, d4
+** vmov.f64\td12, d0
+** bl\tg(?:\(PLT\))?
+** vmov.f64\td8, d0
+** vmov.f64\td0, d10
+** bl\tg(?:\(PLT\))?
+** vmov.f64\td7, d0
+** vmov.f64\td0, d9
+** vadd.f64\td8, d8, d7
+** bl\tg(?:\(PLT\))?
+** vadd.f64\td0, d8, d0
+** vadd.f64\td0, d0, d12
+** vadd.f64\td0, d0, d10
+** vadd.f64\td0, d0, d9
+** vadd.f64\td0, d0, d13
+** vadd.f64\td0, d0, d11
+** vldm\tsp!, {d8-d13}
+** pop\t{r4, pc}
+*/
+double
+cross_call_live_df (double a, double b, double c, double d, double e)
+{
+ double r = g (a);
+ r += g (b);
+ r += g (c);
+ return r + a + b + c + d + e;
+}
--
2.55.0