Skip to content

Commit 26f97ee

Browse files
authored
[AArch64] Stop reserved registers from being saved in prolog/epilog (#138448)
[GCC's documentation](https://gcc.gnu.org/onlinedocs/gcc-15.1.0/gcc/Code-Gen-Options.html) is clear on how -ffixed-reg must behave: ``` Treat the register named reg as a fixed register; generated code should never refer to it (except perhaps as a stack pointer, frame pointer or in some other fixed role). ``` This implies prolog/epilog code also must not save/restore explicitly fixed registers, even when it is callee-saved. Some projects rely on this (GCC's) behavior. For example, ``` void f() { register uint64_t x28 asm("x28") = 0xee; asm volatile("" : "+r"(x28)); // avoid mov being eliminated } ``` should not touch x28 outside of `mov w28,#0xee`. For riscv64, clang behaves the same as GCC, so I am inclined to believe this is indeed a bug. Fixes #111379.
1 parent 6408291 commit 26f97ee

File tree

5 files changed

+370
-41
lines changed

5 files changed

+370
-41
lines changed

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3619,6 +3619,13 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
36193619
if (Reg == BasePointerReg)
36203620
SavedRegs.set(Reg);
36213621

3622+
// Don't save manually reserved registers set through +reserve-x#i,
3623+
// even for callee-saved registers, as per GCC's behavior.
3624+
if (RegInfo->isUserReservedReg(MF, Reg)) {
3625+
SavedRegs.reset(Reg);
3626+
continue;
3627+
}
3628+
36223629
bool RegUsed = SavedRegs.test(Reg);
36233630
unsigned PairedReg = AArch64::NoRegister;
36243631
const bool RegIsGPR64 = AArch64::GPR64RegClass.contains(Reg);

llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,18 @@ AArch64RegisterInfo::getStrictlyReservedRegs(const MachineFunction &MF) const {
518518
return Reserved;
519519
}
520520

521+
BitVector
522+
AArch64RegisterInfo::getUserReservedRegs(const MachineFunction &MF) const {
523+
BitVector Reserved(getNumRegs());
524+
for (size_t i = 0; i < AArch64::GPR32commonRegClass.getNumRegs(); ++i) {
525+
// ReserveXRegister is set for registers manually reserved
526+
// through +reserve-x#i.
527+
if (MF.getSubtarget<AArch64Subtarget>().isXRegisterReserved(i))
528+
markSuperRegs(Reserved, AArch64::GPR32commonRegClass.getRegister(i));
529+
}
530+
return Reserved;
531+
}
532+
521533
BitVector
522534
AArch64RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
523535
BitVector Reserved(getNumRegs());
@@ -551,6 +563,11 @@ bool AArch64RegisterInfo::isReservedReg(const MachineFunction &MF,
551563
return getReservedRegs(MF)[Reg];
552564
}
553565

566+
bool AArch64RegisterInfo::isUserReservedReg(const MachineFunction &MF,
567+
MCRegister Reg) const {
568+
return getUserReservedRegs(MF)[Reg];
569+
}
570+
554571
bool AArch64RegisterInfo::isStrictlyReservedReg(const MachineFunction &MF,
555572
MCRegister Reg) const {
556573
return getStrictlyReservedRegs(MF)[Reg];

llvm/lib/Target/AArch64/AArch64RegisterInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class AArch64RegisterInfo final : public AArch64GenRegisterInfo {
3535
}
3636

3737
bool isReservedReg(const MachineFunction &MF, MCRegister Reg) const;
38+
bool isUserReservedReg(const MachineFunction &MF, MCRegister Reg) const;
3839
bool isStrictlyReservedReg(const MachineFunction &MF, MCRegister Reg) const;
3940
bool isAnyArgRegReserved(const MachineFunction &MF) const;
4041
void emitReservedArgRegCallError(const MachineFunction &MF) const;
@@ -93,6 +94,7 @@ class AArch64RegisterInfo final : public AArch64GenRegisterInfo {
9394
const uint32_t *getWindowsStackProbePreservedMask() const;
9495

9596
BitVector getStrictlyReservedRegs(const MachineFunction &MF) const;
97+
BitVector getUserReservedRegs(const MachineFunction &MF) const;
9698
BitVector getReservedRegs(const MachineFunction &MF) const override;
9799
std::optional<std::string>
98100
explainReservedReg(const MachineFunction &MF,
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -reserve-regs-for-regalloc=LR,FP,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4 | FileCheck %s
3+
; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -reserve-regs-for-regalloc=X30,X29,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4 | FileCheck %s
4+
5+
; LR, FP, X30 and X29 should be correctly recognized and not used.
6+
7+
define void @foo(i64 %v1, i64 %v2, ptr %ptr) {
8+
; CHECK-LABEL: foo:
9+
; CHECK: // %bb.0:
10+
; CHECK-NEXT: sub sp, sp, #16
11+
; CHECK-NEXT: .cfi_def_cfa_offset 16
12+
; CHECK-NEXT: add x3, x0, x1
13+
; CHECK-NEXT: str x3, [sp, #8] // 8-byte Folded Spill
14+
; CHECK-NEXT: str x3, [x2, #8]
15+
; CHECK-NEXT: ldr x3, [x2, #16]
16+
; CHECK-NEXT: add x3, x0, x3
17+
; CHECK-NEXT: sub x3, x3, x1
18+
; CHECK-NEXT: str x3, [x2, #16]
19+
; CHECK-NEXT: ldr x3, [sp, #8] // 8-byte Folded Reload
20+
; CHECK-NEXT: str x3, [x2, #24]
21+
; CHECK-NEXT: str x0, [x2, #32]
22+
; CHECK-NEXT: str x1, [x2, #40]
23+
; CHECK-NEXT: add sp, sp, #16
24+
; CHECK-NEXT: ret
25+
%v3 = add i64 %v1, %v2
26+
%p1 = getelementptr i64, ptr %ptr, i64 1
27+
store volatile i64 %v3, ptr %p1, align 8
28+
29+
%p2 = getelementptr i64, ptr %ptr, i64 2
30+
%v4 = load volatile i64, ptr %p2, align 8
31+
%v5 = add i64 %v1, %v4
32+
%v6 = sub i64 %v5, %v2
33+
store volatile i64 %v6, ptr %p2, align 8
34+
35+
%p3 = getelementptr i64, ptr %ptr, i64 3
36+
store volatile i64 %v3, ptr %p3, align 8
37+
38+
%p4 = getelementptr i64, ptr %ptr, i64 4
39+
store volatile i64 %v1, ptr %p4, align 8
40+
%p5 = getelementptr i64, ptr %ptr, i64 5
41+
store volatile i64 %v2, ptr %p5, align 8
42+
ret void
43+
}

0 commit comments

Comments
 (0)