Skip to content

Commit 9865171

Browse files
authored
[AArch64] Add -mlr-for-calls-only to replace the now removed -ffixed-x30 flag. (#98073)
This re-introduces the effective behaviour that was reverted in 7ad481e. This time we're not using the same mechanism, exposing another reservation feature that prevents only regalloc from using the register, but not for other required uses like ABIs. This also fixes a consequent issue with reserving LR, which is that frame lowering was only adding live-in flags for non-reserved regs. This would cause issues later since the outliner needs accurate flags to determine when LR needs to be preserved. rdar://131313095
1 parent 9392b45 commit 9865171

File tree

10 files changed

+95
-3
lines changed

10 files changed

+95
-3
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4929,6 +4929,9 @@ foreach i = {1-31} in
49294929
def ffixed_x#i : Flag<["-"], "ffixed-x"#i>, Group<m_Group>,
49304930
HelpText<"Reserve the x"#i#" register (AArch64/RISC-V only)">;
49314931

4932+
def mlr_for_calls_only : Flag<["-"], "mlr-for-calls-only">, Group<m_aarch64_Features_Group>,
4933+
HelpText<"Do not allocate the LR register for general purpose usage, only for calls. (AArch64 only)">;
4934+
49324935
foreach i = {8-15,18} in
49334936
def fcall_saved_x#i : Flag<["-"], "fcall-saved-x"#i>, Group<m_aarch64_Features_Group>,
49344937
HelpText<"Make the x"#i#" register call-saved (AArch64 only)">;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// RUN: %clang --target=aarch64-none-gnu -mlr-for-calls-only -### %s 2> %t
2+
// RUN: FileCheck --check-prefix=CHECK < %t %s
3+
// CHECK: "-target-feature" "+reserve-lr-for-ra"

clang/lib/Driver/ToolChains/Arch/AArch64.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,9 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
398398
if (Args.hasArg(options::OPT_ffixed_x28))
399399
Features.push_back("+reserve-x28");
400400

401+
if (Args.hasArg(options::OPT_mlr_for_calls_only))
402+
Features.push_back("+reserve-lr-for-ra");
403+
401404
if (Args.hasArg(options::OPT_fcall_saved_x8))
402405
Features.push_back("+call-saved-x8");
403406

llvm/lib/Target/AArch64/AArch64Features.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,10 @@ foreach i = {1-7,9-15,18,20-28} in
571571
"Reserve X"#i#", making it unavailable "
572572
"as a GPR">;
573573

574+
def FeatureReserveLRForRA : SubtargetFeature<"reserve-lr-for-ra",
575+
"ReserveLRForRA", "true",
576+
"Reserve LR for call use only">;
577+
574578
foreach i = {8-15,18} in
575579
def FeatureCallSavedX#i : SubtargetFeature<"call-saved-x"#i,
576580
"CustomCallSavedXRegs["#i#"]", "true", "Make X"#i#" callee saved.">;

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3079,7 +3079,11 @@ bool AArch64FrameLowering::spillCalleeSavedRegisters(
30793079

30803080
computeCalleeSaveRegisterPairs(MF, CSI, TRI, RegPairs, hasFP(MF));
30813081

3082-
const MachineRegisterInfo &MRI = MF.getRegInfo();
3082+
MachineRegisterInfo &MRI = MF.getRegInfo();
3083+
// Refresh the reserved regs in case there are any potential changes since the
3084+
// last freeze.
3085+
MRI.freezeReservedRegs();
3086+
30833087
if (homogeneousPrologEpilog(MF)) {
30843088
auto MIB = BuildMI(MBB, MI, DL, TII.get(AArch64::HOM_Prolog))
30853089
.setMIFlag(MachineInstr::FrameSetup);

llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,17 @@ AArch64RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
501501
markSuperRegs(Reserved, AArch64::GPR32commonRegClass.getRegister(i));
502502
}
503503

504+
if (MF.getSubtarget<AArch64Subtarget>().isLRReservedForRA()) {
505+
// In order to prevent the register allocator from using LR, we need to
506+
// mark it as reserved. However we don't want to keep it reserved throughout
507+
// the pipeline since it prevents other infrastructure from reasoning about
508+
// it's liveness. We use the NoVRegs property instead of IsSSA because
509+
// IsSSA is removed before VirtRegRewriter runs.
510+
if (!MF.getProperties().hasProperty(
511+
MachineFunctionProperties::Property::NoVRegs))
512+
markSuperRegs(Reserved, AArch64::LR);
513+
}
514+
504515
assert(checkAllSuperRegsMarked(Reserved));
505516
return Reserved;
506517
}

llvm/lib/Target/AArch64/AArch64Subtarget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
209209
AllReservedX |= ReserveXRegisterForRA;
210210
return AllReservedX.count();
211211
}
212+
bool isLRReservedForRA() const { return ReserveLRForRA; }
212213
bool isXRegCustomCalleeSaved(size_t i) const {
213214
return CustomCallSavedXRegs[i];
214215
}

llvm/test/CodeGen/AArch64/arm64-platform-reg.ll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x26 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X26
3535
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x27 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X27
3636
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-x28 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-X28
37+
; RUN: llc -mtriple=arm64-linux-gnu -mattr=+reserve-lr-for-ra -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVE,CHECK-RESERVE-LR-RA
3738

3839
; Test multiple of reserve-x# options together.
3940
; RUN: llc -mtriple=arm64-linux-gnu \
@@ -72,6 +73,7 @@
7273
; RUN: -mattr=+reserve-x26 \
7374
; RUN: -mattr=+reserve-x27 \
7475
; RUN: -mattr=+reserve-x28 \
76+
; RUN: -mattr=+reserve-lr-for-ra \
7577
; RUN: -reserve-regs-for-regalloc=X8,X16,X17,X19 \
7678
; RUN: -o - %s | FileCheck %s \
7779
; RUN: --check-prefix=CHECK-RESERVE \
@@ -102,7 +104,8 @@
102104
; RUN: --check-prefix=CHECK-RESERVE-X25 \
103105
; RUN: --check-prefix=CHECK-RESERVE-X26 \
104106
; RUN: --check-prefix=CHECK-RESERVE-X27 \
105-
; RUN: --check-prefix=CHECK-RESERVE-X28
107+
; RUN: --check-prefix=CHECK-RESERVE-X28 \
108+
; RUN: --check-prefix=CHECK-RESERVE-LR-RA
106109

107110
; x18 is reserved as a platform register on Darwin but not on other
108111
; systems. Create loads of register pressure and make sure this is respected.
@@ -149,6 +152,7 @@ define void @keep_live() {
149152
; CHECK-RESERVE-X26-NOT: ldr x26
150153
; CHECK-RESERVE-X27-NOT: ldr x27
151154
; CHECK-RESERVE-X28-NOT: ldr x28
155+
; CHECK-RESERVE-LR-RA-NOT: ldr x30
152156
; CHECK-RESERVE: Spill
153157
; CHECK-RESERVE-NOT: ldr fp
154158
; CHECK-RESERVE-X1-NOT: ldr x1,
@@ -178,6 +182,7 @@ define void @keep_live() {
178182
; CHECK-RESERVE-X26-NOT: ldr x26
179183
; CHECK-RESERVE-X27-NOT: ldr x27
180184
; CHECK-RESERVE-X28-NOT: ldr x28
185+
; CHECK-RESERVE-LR-RA-NOT: ldr x30
181186
; CHECK-RESERVE: ret
182187
ret void
183188
}

llvm/test/CodeGen/AArch64/framelayout-sve.mir

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@
5757
# CHECK: stackSize: 32
5858

5959
# CHECK: bb.0.entry:
60-
# CHECK-NEXT: $sp = frame-setup STRXpre killed $[[SCRATCH:[a-z0-9]+]], $sp, -16
60+
# CHECK: liveins: $fp
61+
# CHECK: early-clobber $sp = frame-setup STRXpre killed $[[SCRATCH:[a-z0-9]+]], $sp, -16
6162
# CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
6263
# CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $w29, -16
6364
# CHECK-NEXT: $sp = frame-setup SUBXri $sp, 16, 0
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc -stop-after=prologepilog -simplify-mir -o - %s | FileCheck %s
3+
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
4+
target triple = "arm64e-apple-ios18.0"
5+
6+
declare void @spam()
7+
; This test checks that the live-in flags for LR are correctly set when LR is reserved, but live for a call.
8+
define i32 @check_lr_liveness(ptr %arg) #1 {
9+
; CHECK-LABEL: name: check_lr_liveness
10+
; CHECK: bb.0.bb:
11+
; CHECK-NEXT: successors: %bb.4(0x20000000), %bb.1(0x60000000)
12+
; CHECK-NEXT: liveins: $x0, $lr
13+
; CHECK-NEXT: {{ $}}
14+
; CHECK-NEXT: renamable $x8 = COPY $x0
15+
; CHECK-NEXT: renamable $w0 = MOVi32imm -536870206
16+
; CHECK-NEXT: CBNZX killed renamable $x8, %bb.1
17+
; CHECK-NEXT: {{ $}}
18+
; CHECK-NEXT: bb.4:
19+
; CHECK-NEXT: liveins: $w0, $lr
20+
; CHECK-NEXT: {{ $}}
21+
; CHECK-NEXT: B %bb.3
22+
; CHECK-NEXT: {{ $}}
23+
; CHECK-NEXT: bb.1.bb:
24+
; CHECK-NEXT: successors: %bb.3(0x2aaaaaab), %bb.2(0x55555555)
25+
; CHECK-NEXT: liveins: $w0, $lr
26+
; CHECK-NEXT: {{ $}}
27+
; CHECK-NEXT: CBNZW $wzr, %bb.3
28+
; CHECK-NEXT: B %bb.2
29+
; CHECK-NEXT: {{ $}}
30+
; CHECK-NEXT: bb.2.bb1:
31+
; CHECK-NEXT: liveins: $lr
32+
; CHECK-NEXT: {{ $}}
33+
; CHECK-NEXT: early-clobber $sp = frame-setup STPXpre killed $fp, killed $lr, $sp, -2 :: (store (s64) into %stack.1), (store (s64) into %stack.0)
34+
; CHECK-NEXT: BL @spam, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp
35+
; CHECK-NEXT: renamable $w0 = COPY $wzr
36+
; CHECK-NEXT: early-clobber $sp, $fp, $lr = frame-destroy LDPXpost $sp, 2 :: (load (s64) from %stack.1), (load (s64) from %stack.0)
37+
; CHECK-NEXT: {{ $}}
38+
; CHECK-NEXT: bb.3.bb2:
39+
; CHECK-NEXT: liveins: $w0, $lr
40+
; CHECK-NEXT: {{ $}}
41+
; CHECK-NEXT: RET_ReallyLR implicit $w0
42+
bb:
43+
%icmp = icmp eq ptr %arg, null
44+
%or = or i1 %icmp, false
45+
br i1 %or, label %bb2, label %bb1
46+
47+
bb1: ; preds = %bb
48+
call void @spam()
49+
br label %bb2
50+
51+
bb2: ; preds = %bb1, %bb
52+
%phi = phi i32 [ -536870206, %bb ], [ 0, %bb1 ]
53+
ret i32 %phi
54+
}
55+
56+
attributes #1 = { minsize nounwind "target-features"="+aes,+crc,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+reserve-lr-for-ra,+sha2,+v8.1a,+v8.2a,+v8.3a,+v8a,+zcm,+zcz" }
57+

0 commit comments

Comments
 (0)