Skip to content

Commit 7272dd8

Browse files
committed
[ARM] r11 is reserved when using -mframe-chain=aapcs
When using the -mframe-chain=aapcs or -mframe-chain=aapcs-leaf options, we cannot use r11 as an allocatable register, even if -fomit-frame-pointer is also used. This is so that r11 will always point to a valid frame record, even if we don't create one in every function. This uses the new "frame-pointer"="reserved" function attribute to represent the case where the frame pointer is reserved but not (always) used. This means that we can remove the "aapcs-frame-chain-leaf" subtarget feature, so that the "frame-pointer" attribute always controls the emission of the frame pointer, and the "aapcs-frame-chain" subtarget feature seelcts which ABI is followed.
1 parent 1e141e8 commit 7272dd8

File tree

11 files changed

+133
-82
lines changed

11 files changed

+133
-82
lines changed

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -799,8 +799,6 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D,
799799
StringRef FrameChainOption = A->getValue();
800800
if (FrameChainOption.starts_with("aapcs"))
801801
Features.push_back("+aapcs-frame-chain");
802-
if (FrameChainOption == "aapcs+leaf")
803-
Features.push_back("+aapcs-frame-chain-leaf");
804802
}
805803

806804
// CMSE: Check for target 8M (for -mcmse to be applicable) is performed later.

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 88 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@ static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
164164
return true;
165165
}
166166

167+
static bool useLeafFramePointerForTargetByDefault(const llvm::Triple &Triple) {
168+
if (Triple.isAArch64() || Triple.isPS() || Triple.isVE() ||
169+
(Triple.isAndroid() && Triple.isRISCV64()))
170+
return false;
171+
172+
return true;
173+
}
174+
167175
static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
168176
switch (Triple.getArch()) {
169177
default:
@@ -176,38 +184,91 @@ static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
176184
}
177185
}
178186

187+
// True if a target-specific option requires the frame chain to be preserved,
188+
// even if new frame records are not created.
189+
static bool mustMaintainValidFrameChain(const llvm::opt::ArgList &Args,
190+
const llvm::Triple &Triple) {
191+
if (Triple.isARM() || Triple.isThumb()) {
192+
// For 32-bit Arm, the -mframe-chain=aapcs and -mframe-chain=aapcs+leaf
193+
// options require the frame pointer register to be reserved (or point to a
194+
// new AAPCS-compilant frame record), even with -fno-omit-frame-pointer.
195+
if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) {
196+
StringRef V = A->getValue();
197+
return V != "none";
198+
}
199+
return false;
200+
}
201+
return false;
202+
}
203+
204+
// True if a target-specific option causes -fno-omit-frame-pointer to also
205+
// cause frame records to be created in leaf functions.
206+
static bool framePointerImpliesLeafFramePointer(const llvm::opt::ArgList &Args,
207+
const llvm::Triple &Triple) {
208+
if (Triple.isARM() || Triple.isThumb()) {
209+
// For 32-bit Arm, the -mframe-chain=aapcs+leaf option causes the
210+
// -fno-omit-frame-pointer optiion to imply -mno-omit-leaf-frame-pointer,
211+
// but does not by itself imply either option.
212+
if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) {
213+
StringRef V = A->getValue();
214+
return V == "aapcs+leaf";
215+
}
216+
return false;
217+
}
218+
return false;
219+
}
220+
179221
clang::CodeGenOptions::FramePointerKind
180222
getFramePointerKind(const llvm::opt::ArgList &Args,
181223
const llvm::Triple &Triple) {
182-
// We have 4 states:
224+
// There are three things to consider here:
225+
// * Should a frame record be created for non-leaf functions?
226+
// * Should a frame record be created for leaf functions?
227+
// * Is the frame pointer register reserved, i.e. must it always point to
228+
// either a new, valid frame record or be un-modified?
183229
//
184-
// 00) leaf retained, non-leaf retained
185-
// 01) leaf retained, non-leaf omitted (this is invalid)
186-
// 10) leaf omitted, non-leaf retained
187-
// (what -momit-leaf-frame-pointer was designed for)
188-
// 11) leaf omitted, non-leaf omitted
230+
// Not all combinations of these are valid:
231+
// * It's not useful to have leaf frame records without non-leaf ones.
232+
// * It's not useful to have frame records without reserving the frame
233+
// pointer.
189234
//
190-
// "omit" options taking precedence over "no-omit" options is the only way
191-
// to make 3 valid states representable
192-
llvm::opt::Arg *A =
193-
Args.getLastArg(clang::driver::options::OPT_fomit_frame_pointer,
194-
clang::driver::options::OPT_fno_omit_frame_pointer);
195-
196-
bool OmitFP = A && A->getOption().matches(
197-
clang::driver::options::OPT_fomit_frame_pointer);
198-
bool NoOmitFP = A && A->getOption().matches(
199-
clang::driver::options::OPT_fno_omit_frame_pointer);
200-
bool OmitLeafFP =
201-
Args.hasFlag(clang::driver::options::OPT_momit_leaf_frame_pointer,
202-
clang::driver::options::OPT_mno_omit_leaf_frame_pointer,
203-
Triple.isAArch64() || Triple.isPS() || Triple.isVE() ||
204-
(Triple.isAndroid() && Triple.isRISCV64()));
205-
if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) ||
206-
(!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) {
207-
if (OmitLeafFP)
208-
return clang::CodeGenOptions::FramePointerKind::NonLeaf;
209-
return clang::CodeGenOptions::FramePointerKind::All;
210-
}
235+
// | Non-leaf | Leaf | Reserved |
236+
// | N | N | N | FramePointerKind::None
237+
// | N | N | Y | FramePointerKind::Reserved
238+
// | N | Y | N | Invalid
239+
// | N | Y | Y | Invalid
240+
// | Y | N | N | Invalid
241+
// | Y | N | Y | FramePointerKind::NonLeaf
242+
// | Y | Y | N | Invalid
243+
// | Y | Y | Y | FramePointerKind::All
244+
//
245+
// The FramePointerKind::Reserved case is currently only reachable for Arm,
246+
// which has the -mframe-chain= option which can (in combination with
247+
// -fno-omit-frame-pointer) specify that the frame chain must be valid,
248+
// without requiring new frame records to be created.
249+
250+
bool DefaultFP = useFramePointerForTargetByDefault(Args, Triple);
251+
bool EnableFP =
252+
mustUseNonLeafFramePointerForTarget(Triple) ||
253+
Args.hasFlag(clang::driver::options::OPT_fno_omit_frame_pointer,
254+
clang::driver::options::OPT_fomit_frame_pointer, DefaultFP);
255+
256+
bool DefaultLeafFP =
257+
useLeafFramePointerForTargetByDefault(Triple) ||
258+
(EnableFP && framePointerImpliesLeafFramePointer(Args, Triple));
259+
bool EnableLeafFP = Args.hasFlag(
260+
clang::driver::options::OPT_mno_omit_leaf_frame_pointer,
261+
clang::driver::options::OPT_momit_leaf_frame_pointer, DefaultLeafFP);
262+
263+
bool FPRegReserved = EnableFP || mustMaintainValidFrameChain(Args, Triple);
264+
265+
if (EnableFP) {
266+
if (EnableLeafFP)
267+
return clang::CodeGenOptions::FramePointerKind::All;
268+
return clang::CodeGenOptions::FramePointerKind::NonLeaf;
269+
}
270+
if (FPRegReserved)
271+
return clang::CodeGenOptions::FramePointerKind::Reserved;
211272
return clang::CodeGenOptions::FramePointerKind::None;
212273
}
213274

llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ getReservedRegs(const MachineFunction &MF) const {
207207
markSuperRegs(Reserved, ARM::PC);
208208
markSuperRegs(Reserved, ARM::FPSCR);
209209
markSuperRegs(Reserved, ARM::APSR_NZCV);
210-
if (TFI->hasFP(MF))
210+
if (TFI->isFPReserved(MF))
211211
markSuperRegs(Reserved, STI.getFramePointerReg());
212212
if (hasBasePointer(MF))
213213
markSuperRegs(Reserved, BasePtr);

llvm/lib/Target/ARM/ARMFeatures.td

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -548,16 +548,15 @@ def FeatureFixCortexA57AES1742098 : SubtargetFeature<"fix-cortex-a57-aes-1742098
548548
"FixCortexA57AES1742098", "true",
549549
"Work around Cortex-A57 Erratum 1742098 / Cortex-A72 Erratum 1655431 (AES)">;
550550

551+
// If frame pointers are in use, they must follow the AAPCS definition, which
552+
// always uses R11 as the frame pointer. If this is not set, we can use R7 as
553+
// the frame pointer for Thumb1-only code, which is more efficient, but less
554+
// compatible. Note that this feature does not control whether frame pointers
555+
// are emitted, that is controlled by the "frame-pointer" function attribute.
551556
def FeatureAAPCSFrameChain : SubtargetFeature<"aapcs-frame-chain",
552557
"CreateAAPCSFrameChain", "true",
553558
"Create an AAPCS compliant frame chain">;
554559

555-
def FeatureAAPCSFrameChainLeaf : SubtargetFeature<"aapcs-frame-chain-leaf",
556-
"CreateAAPCSFrameChainLeaf", "true",
557-
"Create an AAPCS compliant frame chain "
558-
"for leaf functions",
559-
[FeatureAAPCSFrameChain]>;
560-
561560
// Assume that lock-free 32-bit atomics are available, even if the target
562561
// and operating system combination would not usually provide them. The user
563562
// is responsible for providing any necessary __sync implementations. Code

llvm/lib/Target/ARM/ARMFrameLowering.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ bool ARMFrameLowering::hasFP(const MachineFunction &MF) const {
215215
/// isFPReserved - Return true if the frame pointer register should be
216216
/// considered a reserved register on the scope of the specified function.
217217
bool ARMFrameLowering::isFPReserved(const MachineFunction &MF) const {
218-
return hasFP(MF) || MF.getSubtarget<ARMSubtarget>().createAAPCSFrameChain();
218+
return hasFP(MF) || MF.getTarget().Options.FramePointerIsReserved(MF);
219219
}
220220

221221
/// hasReservedCallFrame - Under normal circumstances, when a frame pointer is
@@ -2233,10 +2233,10 @@ bool ARMFrameLowering::enableShrinkWrapping(const MachineFunction &MF) const {
22332233
return true;
22342234
}
22352235

2236-
static bool requiresAAPCSFrameRecord(const MachineFunction &MF) {
2236+
bool ARMFrameLowering::requiresAAPCSFrameRecord(
2237+
const MachineFunction &MF) const {
22372238
const auto &Subtarget = MF.getSubtarget<ARMSubtarget>();
2238-
return Subtarget.createAAPCSFrameChainLeaf() ||
2239-
(Subtarget.createAAPCSFrameChain() && MF.getFrameInfo().hasCalls());
2239+
return Subtarget.createAAPCSFrameChain() && hasFP(MF);
22402240
}
22412241

22422242
// Thumb1 may require a spill when storing to a frame index through FP (or any

llvm/lib/Target/ARM/ARMFrameLowering.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class ARMFrameLowering : public TargetFrameLowering {
4747

4848
bool hasFP(const MachineFunction &MF) const override;
4949
bool isFPReserved(const MachineFunction &MF) const;
50+
bool requiresAAPCSFrameRecord(const MachineFunction &MF) const;
5051
bool hasReservedCallFrame(const MachineFunction &MF) const override;
5152
bool canSimplifyCallFramePseudos(const MachineFunction &MF) const override;
5253
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
1-
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=all 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
2-
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
3-
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain-leaf 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
4-
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf 2>&1 | FileCheck %s --check-prefix=RESERVED-NONE
5-
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
6-
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain-leaf 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
7-
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=none 2>&1 | FileCheck %s --check-prefix=RESERVED-NONE
8-
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
9-
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain-leaf 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
1+
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=all 2>&1 | FileCheck %s --check-prefix=R7-FREE --check-prefix=R11-RESERVED
2+
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain 2>&1 | FileCheck %s --check-prefix=R7-FREE --check-prefix=R11-RESERVED
3+
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf 2>&1 | FileCheck %s --check-prefix=R7-FREE --check-prefix=R11-RESERVED
4+
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain 2>&1 | FileCheck %s --check-prefix=R7-FREE --check-prefix=R11-RESERVED
5+
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=none 2>&1 | FileCheck %s --check-prefix=R7-FREE --check-prefix=R11-FREE
6+
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain 2>&1 | FileCheck %s --check-prefix=R7-FREE --check-prefix=R11-FREE
7+
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=reserved 2>&1 | FileCheck %s --check-prefix=R7-FREE --check-prefix=R11-RESERVED
8+
; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=reserved -mattr=+aapcs-frame-chain 2>&1 | FileCheck %s --check-prefix=R7-FREE --check-prefix=R11-RESERVED
109

1110
declare void @leaf(i32 %input)
1211

1312
define void @reserved_r7(i32 %input) {
14-
; RESERVED-NONE-NOT: error: write to reserved register 'R7'
15-
; RESERVED-R11-NOT: error: write to reserved register 'R7'
13+
; R7-RESERVED: error: write to reserved register 'R7'
14+
; R7-FREE-NOT: error: write to reserved register 'R7'
1615
%1 = call i32 asm sideeffect "mov $0, $1", "={r7},r"(i32 %input)
1716
ret void
1817
}
1918

2019
define void @reserved_r11(i32 %input) {
21-
; RESERVED-NONE-NOT: error: write to reserved register 'R11'
22-
; RESERVED-R11: error: write to reserved register 'R11'
20+
; R11-RESERVED: error: write to reserved register 'R11'
21+
; R11-FREE-NOT: error: write to reserved register 'R11'
2322
%1 = call i32 asm sideeffect "mov $0, $1", "={r11},r"(i32 %input)
2423
ret void
2524
}

llvm/test/CodeGen/ARM/frame-chain.ll

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=all | FileCheck %s --check-prefixes=FP,LEAF-FP
2-
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-FP
3-
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain-leaf | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-FP-AAPCS
2+
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-FP-AAPCS
43
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf | FileCheck %s --check-prefixes=FP,LEAF-NOFP
5-
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-NOFP
6-
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain-leaf | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-NOFP-AAPCS
4+
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-NOFP-AAPCS
75
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=none | FileCheck %s --check-prefixes=NOFP,LEAF-NOFP
8-
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain | FileCheck %s --check-prefixes=NOFP-AAPCS,LEAF-NOFP
9-
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain-leaf | FileCheck %s --check-prefixes=NOFP-AAPCS,LEAF-NOFP-AAPCS
6+
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain | FileCheck %s --check-prefixes=NOFP-AAPCS,LEAF-NOFP-AAPCS
7+
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=reserved | FileCheck %s --check-prefixes=NOFP,LEAF-NOFP
8+
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=reserved -mattr=+aapcs-frame-chain | FileCheck %s --check-prefixes=NOFP-AAPCS,LEAF-NOFP-AAPCS
109

1110
define dso_local noundef i32 @leaf(i32 noundef %0) {
1211
; LEAF-FP-LABEL: leaf:

llvm/test/CodeGen/Thumb/frame-access.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=none %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-NOFP,CHECK-ATPCS
22
; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=all %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-FP-ATPCS,CHECK-ATPCS
3-
; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=none -mattr=+aapcs-frame-chain-leaf %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-NOFP,CHECK-AAPCS
4-
; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=all -mattr=+aapcs-frame-chain-leaf %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-FP-AAPCS,CHECK-AAPCS
3+
; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=none -mattr=+aapcs-frame-chain %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-NOFP,CHECK-AAPCS
4+
; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=all -mattr=+aapcs-frame-chain %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-FP-AAPCS,CHECK-AAPCS
55

66
; struct S { int x[128]; } s;
77
; int f(int *, int, int, int, struct S);

0 commit comments

Comments
 (0)