[clang] [llvm] [ARM] r11 is reserved when using -mframe-chain=aapcs (PR #86951)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 6 02:11:09 PDT 2024
https://github.com/ostannard updated https://github.com/llvm/llvm-project/pull/86951
>From 1e141e80b0abf45f160c06f8eb39623df16434d8 Mon Sep 17 00:00:00 2001
From: Oliver Stannard <oliver.stannard at arm.com>
Date: Thu, 6 Jun 2024 09:34:13 +0100
Subject: [PATCH 1/2] [IR] Add target-independent option to preserve
frame-pointer register
This adds a new value "reserved" to the "frame-pointer" function
attribute. When this value is used, the frame pointer register must
either be reserved, or updated to point to a new frame record, but must
not be used for any other purpose.
This is not yet supported by most targets, but will be used for the Arm
-mframe-chain= option.
---
clang/include/clang/Basic/CodeGenOptions.def | 2 +-
clang/include/clang/Basic/CodeGenOptions.h | 3 +++
clang/include/clang/Driver/Options.td | 4 ++--
clang/lib/CodeGen/CGCall.cpp | 1 +
clang/lib/CodeGen/CodeGenModule.cpp | 3 +++
clang/lib/Driver/ToolChains/Clang.cpp | 3 +++
llvm/docs/LangRef.rst | 6 +++++-
llvm/include/llvm/Support/CodeGen.h | 2 +-
llvm/include/llvm/Target/TargetOptions.h | 5 +++++
llvm/lib/CodeGen/CommandFlags.cpp | 5 +++++
llvm/lib/CodeGen/TargetOptionsImpl.cpp | 21 ++++++++++++++++++--
llvm/lib/IR/Function.cpp | 3 +++
llvm/lib/IR/Verifier.cpp | 2 +-
13 files changed, 52 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 07b0ca1691a67..7ffc40a00504f 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -61,7 +61,7 @@ CODEGENOPT(SeparateNamedSections, 1, 0) ///< Set for -fseparate-named-sections.
CODEGENOPT(EnableAIXExtendedAltivecABI, 1, 0) ///< Set for -mabi=vec-extabi. Enables the extended Altivec ABI on AIX.
CODEGENOPT(XCOFFReadOnlyPointers, 1, 0) ///< Set for -mxcoff-roptr.
CODEGENOPT(AllTocData, 1, 0) ///< AIX -mtocdata
-ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,none
+ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,reserved,none
CODEGENOPT(ClearASTBeforeBackend , 1, 0) ///< Free the AST before running backend code generation. Only works with -disable-free.
CODEGENOPT(DisableFree , 1, 0) ///< Don't free memory.
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 9469a424045bb..6887926cb34da 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -128,6 +128,7 @@ class CodeGenOptions : public CodeGenOptionsBase {
enum class FramePointerKind {
None, // Omit all frame pointers.
+ Reserved, // Maintain valid frame pointer chain.
NonLeaf, // Keep non-leaf frame pointers.
All, // Keep all frame pointers.
};
@@ -136,6 +137,8 @@ class CodeGenOptions : public CodeGenOptionsBase {
switch (Kind) {
case FramePointerKind::None:
return "none";
+ case FramePointerKind::Reserved:
+ return "reserved";
case FramePointerKind::NonLeaf:
return "non-leaf";
case FramePointerKind::All:
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 57f37c5023110..9b89b394cef52 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -7706,8 +7706,8 @@ def pic_is_pie : Flag<["-"], "pic-is-pie">,
MarshallingInfoFlag<LangOpts<"PIE">>;
def mframe_pointer_EQ : Joined<["-"], "mframe-pointer=">,
- HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,none">,
- NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "None"]>,
+ HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,reserved,none">,
+ NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "Reserved", "None"]>,
MarshallingInfoEnum<CodeGenOpts<"FramePointer">, "None">;
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 97449a5e51e73..65d82285b907b 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1917,6 +1917,7 @@ static void getTrivialDefaultFunctionAttributes(
case CodeGenOptions::FramePointerKind::None:
// This is the default behavior.
break;
+ case CodeGenOptions::FramePointerKind::Reserved:
case CodeGenOptions::FramePointerKind::NonLeaf:
case CodeGenOptions::FramePointerKind::All:
FuncAttrs.addAttribute("frame-pointer",
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index be7bf0b72dc0c..75b1449090389 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1328,6 +1328,9 @@ void CodeGenModule::Release() {
case CodeGenOptions::FramePointerKind::None:
// 0 ("none") is the default.
break;
+ case CodeGenOptions::FramePointerKind::Reserved:
+ getModule().setFramePointer(llvm::FramePointerKind::Reserved);
+ break;
case CodeGenOptions::FramePointerKind::NonLeaf:
getModule().setFramePointer(llvm::FramePointerKind::NonLeaf);
break;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 4e1c52462e584..b8d8ff3db5d1f 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5678,6 +5678,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
case CodeGenOptions::FramePointerKind::None:
FPKeepKindStr = "-mframe-pointer=none";
break;
+ case CodeGenOptions::FramePointerKind::Reserved:
+ FPKeepKindStr = "-mframe-pointer=reserved";
+ break;
case CodeGenOptions::FramePointerKind::NonLeaf:
FPKeepKindStr = "-mframe-pointer=non-leaf";
break;
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 9d7ade8eb523b..564dce1db825b 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1924,7 +1924,11 @@ example:
even if this attribute says the frame pointer can be eliminated.
The allowed string values are:
- * ``"none"`` (default) - the frame pointer can be eliminated.
+ * ``"none"`` (default) - the frame pointer can be eliminated, and it's
+ register can be used for other purposes.
+ * ``"reserved"`` - the frame pointer register must either be updated to
+ point to a valid frame record for the current function, or not be
+ modified.
* ``"non-leaf"`` - the frame pointer should be kept if the function calls
other functions.
* ``"all"`` - the frame pointer should be kept.
diff --git a/llvm/include/llvm/Support/CodeGen.h b/llvm/include/llvm/Support/CodeGen.h
index 46f99811763a8..0e42789ba932e 100644
--- a/llvm/include/llvm/Support/CodeGen.h
+++ b/llvm/include/llvm/Support/CodeGen.h
@@ -87,7 +87,7 @@ namespace llvm {
};
// Specify what functions should keep the frame pointer.
- enum class FramePointerKind { None, NonLeaf, All };
+ enum class FramePointerKind { None, NonLeaf, All, Reserved };
// Specify what type of zeroing callee-used registers.
namespace ZeroCallUsedRegs {
diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h
index 98a8b7ba337cb..d3464b5202ff3 100644
--- a/llvm/include/llvm/Target/TargetOptions.h
+++ b/llvm/include/llvm/Target/TargetOptions.h
@@ -161,6 +161,11 @@ namespace llvm {
/// optimization should be disabled for the given machine function.
bool DisableFramePointerElim(const MachineFunction &MF) const;
+ /// FramePointerIsReserved - This returns true if the frame pointer must
+ /// always either point to a new frame record or be un-modified in the given
+ /// function.
+ bool FramePointerIsReserved(const MachineFunction &MF) const;
+
/// If greater than 0, override the default value of
/// MCAsmInfo::BinutilsVersion.
std::pair<int, int> BinutilsVersion{0, 0};
diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp
index 677460a2d8e40..8fc65d78ff2c9 100644
--- a/llvm/lib/CodeGen/CommandFlags.cpp
+++ b/llvm/lib/CodeGen/CommandFlags.cpp
@@ -211,6 +211,9 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
"Disable frame pointer elimination"),
clEnumValN(FramePointerKind::NonLeaf, "non-leaf",
"Disable frame pointer elimination for non-leaf frame"),
+ clEnumValN(FramePointerKind::Reserved, "reserved",
+ "Enable frame pointer elimination, but reserve the frame "
+ "pointer register"),
clEnumValN(FramePointerKind::None, "none",
"Enable frame pointer elimination")));
CGBINDOPT(FramePointerUsage);
@@ -693,6 +696,8 @@ void codegen::setFunctionAttributes(StringRef CPU, StringRef Features,
NewAttrs.addAttribute("frame-pointer", "all");
else if (getFramePointerUsage() == FramePointerKind::NonLeaf)
NewAttrs.addAttribute("frame-pointer", "non-leaf");
+ else if (getFramePointerUsage() == FramePointerKind::Reserved)
+ NewAttrs.addAttribute("frame-pointer", "reserved");
else if (getFramePointerUsage() == FramePointerKind::None)
NewAttrs.addAttribute("frame-pointer", "none");
}
diff --git a/llvm/lib/CodeGen/TargetOptionsImpl.cpp b/llvm/lib/CodeGen/TargetOptionsImpl.cpp
index af5d10103f78b..5bf1d265092f6 100644
--- a/llvm/lib/CodeGen/TargetOptionsImpl.cpp
+++ b/llvm/lib/CodeGen/TargetOptionsImpl.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
@@ -21,7 +22,7 @@ using namespace llvm;
/// DisableFramePointerElim - This returns true if frame pointer elimination
/// optimization should be disabled for the given machine function.
bool TargetOptions::DisableFramePointerElim(const MachineFunction &MF) const {
- // Check to see if the target want to forcably keep frame pointer.
+ // Check to see if the target want to forcibly keep frame pointer.
if (MF.getSubtarget().getFrameLowering()->keepFramePointer(MF))
return true;
@@ -34,11 +35,27 @@ bool TargetOptions::DisableFramePointerElim(const MachineFunction &MF) const {
return true;
if (FP == "non-leaf")
return MF.getFrameInfo().hasCalls();
- if (FP == "none")
+ if (FP == "none" || FP == "reserved")
return false;
llvm_unreachable("unknown frame pointer flag");
}
+bool TargetOptions::FramePointerIsReserved(const MachineFunction &MF) const {
+ // Check to see if the target want to forcibly keep frame pointer.
+ if (MF.getSubtarget().getFrameLowering()->keepFramePointer(MF))
+ return true;
+
+ const Function &F = MF.getFunction();
+
+ if (!F.hasFnAttribute("frame-pointer"))
+ return false;
+
+ StringRef FP = F.getFnAttribute("frame-pointer").getValueAsString();
+ return StringSwitch<bool>(FP)
+ .Cases("all", "non-leaf", "reserved", true)
+ .Case("none", false);
+}
+
/// HonorSignDependentRoundingFPMath - Return true if the codegen must assume
/// that the rounding mode of the FPU can change from its default.
bool TargetOptions::HonorSignDependentRoundingFPMath() const {
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 13fa1afeaaff2..3f735020e8740 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -383,6 +383,9 @@ Function *Function::createWithDefaultAttr(FunctionType *Ty,
case FramePointerKind::None:
// 0 ("none") is the default.
break;
+ case FramePointerKind::Reserved:
+ B.addAttribute("frame-pointer", "reserved");
+ break;
case FramePointerKind::NonLeaf:
B.addAttribute("frame-pointer", "non-leaf");
break;
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 684e54444621b..e5927203f33a2 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2322,7 +2322,7 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
if (Attrs.hasFnAttr("frame-pointer")) {
StringRef FP = Attrs.getFnAttr("frame-pointer").getValueAsString();
- if (FP != "all" && FP != "non-leaf" && FP != "none")
+ if (FP != "all" && FP != "non-leaf" && FP != "none" && FP != "reserved")
CheckFailed("invalid value for 'frame-pointer' attribute: " + FP, V);
}
>From 7272dd8f58e9f445f758a10ae3d91aaa166c91f1 Mon Sep 17 00:00:00 2001
From: Oliver Stannard <oliver.stannard at arm.com>
Date: Thu, 6 Jun 2024 09:45:30 +0100
Subject: [PATCH 2/2] [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.
---
clang/lib/Driver/ToolChains/Arch/ARM.cpp | 2 -
clang/lib/Driver/ToolChains/CommonArgs.cpp | 115 ++++++++++++++----
llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp | 2 +-
llvm/lib/Target/ARM/ARMFeatures.td | 11 +-
llvm/lib/Target/ARM/ARMFrameLowering.cpp | 8 +-
llvm/lib/Target/ARM/ARMFrameLowering.h | 1 +
.../CodeGen/ARM/frame-chain-reserved-fp.ll | 25 ++--
llvm/test/CodeGen/ARM/frame-chain.ll | 11 +-
llvm/test/CodeGen/Thumb/frame-access.ll | 4 +-
.../CodeGen/Thumb/frame-chain-reserved-fp.ll | 27 ++--
llvm/test/CodeGen/Thumb/frame-chain.ll | 9 +-
11 files changed, 133 insertions(+), 82 deletions(-)
diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
index a68368c475865..8ae22cc37a136 100644
--- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -799,8 +799,6 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D,
StringRef FrameChainOption = A->getValue();
if (FrameChainOption.starts_with("aapcs"))
Features.push_back("+aapcs-frame-chain");
- if (FrameChainOption == "aapcs+leaf")
- Features.push_back("+aapcs-frame-chain-leaf");
}
// CMSE: Check for target 8M (for -mcmse to be applicable) is performed later.
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 71e993119436a..61c8f6812c368 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -164,6 +164,14 @@ static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
return true;
}
+static bool useLeafFramePointerForTargetByDefault(const llvm::Triple &Triple) {
+ if (Triple.isAArch64() || Triple.isPS() || Triple.isVE() ||
+ (Triple.isAndroid() && Triple.isRISCV64()))
+ return false;
+
+ return true;
+}
+
static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
switch (Triple.getArch()) {
default:
@@ -176,38 +184,91 @@ static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
}
}
+// True if a target-specific option requires the frame chain to be preserved,
+// even if new frame records are not created.
+static bool mustMaintainValidFrameChain(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (Triple.isARM() || Triple.isThumb()) {
+ // For 32-bit Arm, the -mframe-chain=aapcs and -mframe-chain=aapcs+leaf
+ // options require the frame pointer register to be reserved (or point to a
+ // new AAPCS-compilant frame record), even with -fno-omit-frame-pointer.
+ if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) {
+ StringRef V = A->getValue();
+ return V != "none";
+ }
+ return false;
+ }
+ return false;
+}
+
+// True if a target-specific option causes -fno-omit-frame-pointer to also
+// cause frame records to be created in leaf functions.
+static bool framePointerImpliesLeafFramePointer(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (Triple.isARM() || Triple.isThumb()) {
+ // For 32-bit Arm, the -mframe-chain=aapcs+leaf option causes the
+ // -fno-omit-frame-pointer optiion to imply -mno-omit-leaf-frame-pointer,
+ // but does not by itself imply either option.
+ if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) {
+ StringRef V = A->getValue();
+ return V == "aapcs+leaf";
+ }
+ return false;
+ }
+ return false;
+}
+
clang::CodeGenOptions::FramePointerKind
getFramePointerKind(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple) {
- // We have 4 states:
+ // There are three things to consider here:
+ // * Should a frame record be created for non-leaf functions?
+ // * Should a frame record be created for leaf functions?
+ // * Is the frame pointer register reserved, i.e. must it always point to
+ // either a new, valid frame record or be un-modified?
//
- // 00) leaf retained, non-leaf retained
- // 01) leaf retained, non-leaf omitted (this is invalid)
- // 10) leaf omitted, non-leaf retained
- // (what -momit-leaf-frame-pointer was designed for)
- // 11) leaf omitted, non-leaf omitted
+ // Not all combinations of these are valid:
+ // * It's not useful to have leaf frame records without non-leaf ones.
+ // * It's not useful to have frame records without reserving the frame
+ // pointer.
//
- // "omit" options taking precedence over "no-omit" options is the only way
- // to make 3 valid states representable
- llvm::opt::Arg *A =
- Args.getLastArg(clang::driver::options::OPT_fomit_frame_pointer,
- clang::driver::options::OPT_fno_omit_frame_pointer);
-
- bool OmitFP = A && A->getOption().matches(
- clang::driver::options::OPT_fomit_frame_pointer);
- bool NoOmitFP = A && A->getOption().matches(
- clang::driver::options::OPT_fno_omit_frame_pointer);
- bool OmitLeafFP =
- Args.hasFlag(clang::driver::options::OPT_momit_leaf_frame_pointer,
- clang::driver::options::OPT_mno_omit_leaf_frame_pointer,
- Triple.isAArch64() || Triple.isPS() || Triple.isVE() ||
- (Triple.isAndroid() && Triple.isRISCV64()));
- if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) ||
- (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) {
- if (OmitLeafFP)
- return clang::CodeGenOptions::FramePointerKind::NonLeaf;
- return clang::CodeGenOptions::FramePointerKind::All;
- }
+ // | Non-leaf | Leaf | Reserved |
+ // | N | N | N | FramePointerKind::None
+ // | N | N | Y | FramePointerKind::Reserved
+ // | N | Y | N | Invalid
+ // | N | Y | Y | Invalid
+ // | Y | N | N | Invalid
+ // | Y | N | Y | FramePointerKind::NonLeaf
+ // | Y | Y | N | Invalid
+ // | Y | Y | Y | FramePointerKind::All
+ //
+ // The FramePointerKind::Reserved case is currently only reachable for Arm,
+ // which has the -mframe-chain= option which can (in combination with
+ // -fno-omit-frame-pointer) specify that the frame chain must be valid,
+ // without requiring new frame records to be created.
+
+ bool DefaultFP = useFramePointerForTargetByDefault(Args, Triple);
+ bool EnableFP =
+ mustUseNonLeafFramePointerForTarget(Triple) ||
+ Args.hasFlag(clang::driver::options::OPT_fno_omit_frame_pointer,
+ clang::driver::options::OPT_fomit_frame_pointer, DefaultFP);
+
+ bool DefaultLeafFP =
+ useLeafFramePointerForTargetByDefault(Triple) ||
+ (EnableFP && framePointerImpliesLeafFramePointer(Args, Triple));
+ bool EnableLeafFP = Args.hasFlag(
+ clang::driver::options::OPT_mno_omit_leaf_frame_pointer,
+ clang::driver::options::OPT_momit_leaf_frame_pointer, DefaultLeafFP);
+
+ bool FPRegReserved = EnableFP || mustMaintainValidFrameChain(Args, Triple);
+
+ if (EnableFP) {
+ if (EnableLeafFP)
+ return clang::CodeGenOptions::FramePointerKind::All;
+ return clang::CodeGenOptions::FramePointerKind::NonLeaf;
+ }
+ if (FPRegReserved)
+ return clang::CodeGenOptions::FramePointerKind::Reserved;
return clang::CodeGenOptions::FramePointerKind::None;
}
diff --git a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
index 9adf758b46c48..c149db3144c7c 100644
--- a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
@@ -207,7 +207,7 @@ getReservedRegs(const MachineFunction &MF) const {
markSuperRegs(Reserved, ARM::PC);
markSuperRegs(Reserved, ARM::FPSCR);
markSuperRegs(Reserved, ARM::APSR_NZCV);
- if (TFI->hasFP(MF))
+ if (TFI->isFPReserved(MF))
markSuperRegs(Reserved, STI.getFramePointerReg());
if (hasBasePointer(MF))
markSuperRegs(Reserved, BasePtr);
diff --git a/llvm/lib/Target/ARM/ARMFeatures.td b/llvm/lib/Target/ARM/ARMFeatures.td
index 84481af650be7..8b0ade54b46d3 100644
--- a/llvm/lib/Target/ARM/ARMFeatures.td
+++ b/llvm/lib/Target/ARM/ARMFeatures.td
@@ -548,16 +548,15 @@ def FeatureFixCortexA57AES1742098 : SubtargetFeature<"fix-cortex-a57-aes-1742098
"FixCortexA57AES1742098", "true",
"Work around Cortex-A57 Erratum 1742098 / Cortex-A72 Erratum 1655431 (AES)">;
+// If frame pointers are in use, they must follow the AAPCS definition, which
+// always uses R11 as the frame pointer. If this is not set, we can use R7 as
+// the frame pointer for Thumb1-only code, which is more efficient, but less
+// compatible. Note that this feature does not control whether frame pointers
+// are emitted, that is controlled by the "frame-pointer" function attribute.
def FeatureAAPCSFrameChain : SubtargetFeature<"aapcs-frame-chain",
"CreateAAPCSFrameChain", "true",
"Create an AAPCS compliant frame chain">;
-def FeatureAAPCSFrameChainLeaf : SubtargetFeature<"aapcs-frame-chain-leaf",
- "CreateAAPCSFrameChainLeaf", "true",
- "Create an AAPCS compliant frame chain "
- "for leaf functions",
- [FeatureAAPCSFrameChain]>;
-
// Assume that lock-free 32-bit atomics are available, even if the target
// and operating system combination would not usually provide them. The user
// is responsible for providing any necessary __sync implementations. Code
diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.cpp b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
index 11496a6e032dd..831b6b0fc7223 100644
--- a/llvm/lib/Target/ARM/ARMFrameLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
@@ -215,7 +215,7 @@ bool ARMFrameLowering::hasFP(const MachineFunction &MF) const {
/// isFPReserved - Return true if the frame pointer register should be
/// considered a reserved register on the scope of the specified function.
bool ARMFrameLowering::isFPReserved(const MachineFunction &MF) const {
- return hasFP(MF) || MF.getSubtarget<ARMSubtarget>().createAAPCSFrameChain();
+ return hasFP(MF) || MF.getTarget().Options.FramePointerIsReserved(MF);
}
/// hasReservedCallFrame - Under normal circumstances, when a frame pointer is
@@ -2233,10 +2233,10 @@ bool ARMFrameLowering::enableShrinkWrapping(const MachineFunction &MF) const {
return true;
}
-static bool requiresAAPCSFrameRecord(const MachineFunction &MF) {
+bool ARMFrameLowering::requiresAAPCSFrameRecord(
+ const MachineFunction &MF) const {
const auto &Subtarget = MF.getSubtarget<ARMSubtarget>();
- return Subtarget.createAAPCSFrameChainLeaf() ||
- (Subtarget.createAAPCSFrameChain() && MF.getFrameInfo().hasCalls());
+ return Subtarget.createAAPCSFrameChain() && hasFP(MF);
}
// Thumb1 may require a spill when storing to a frame index through FP (or any
diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.h b/llvm/lib/Target/ARM/ARMFrameLowering.h
index 3c7358d8cd53e..6a31b73957f13 100644
--- a/llvm/lib/Target/ARM/ARMFrameLowering.h
+++ b/llvm/lib/Target/ARM/ARMFrameLowering.h
@@ -47,6 +47,7 @@ class ARMFrameLowering : public TargetFrameLowering {
bool hasFP(const MachineFunction &MF) const override;
bool isFPReserved(const MachineFunction &MF) const;
+ bool requiresAAPCSFrameRecord(const MachineFunction &MF) const;
bool hasReservedCallFrame(const MachineFunction &MF) const override;
bool canSimplifyCallFramePseudos(const MachineFunction &MF) const override;
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
diff --git a/llvm/test/CodeGen/ARM/frame-chain-reserved-fp.ll b/llvm/test/CodeGen/ARM/frame-chain-reserved-fp.ll
index 6540381d624b8..a265dd10c0afa 100644
--- a/llvm/test/CodeGen/ARM/frame-chain-reserved-fp.ll
+++ b/llvm/test/CodeGen/ARM/frame-chain-reserved-fp.ll
@@ -1,25 +1,24 @@
-; RUN: not llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=all 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
-; 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
-; 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
-; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf 2>&1 | FileCheck %s --check-prefix=RESERVED-NONE
-; 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
-; 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
-; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=none 2>&1 | FileCheck %s --check-prefix=RESERVED-NONE
-; 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
-; 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
+; 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
+; 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
+; 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
+; 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
+; 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
+; 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
+; 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
+; 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
declare void @leaf(i32 %input)
define void @reserved_r7(i32 %input) {
-; RESERVED-NONE-NOT: error: write to reserved register 'R7'
-; RESERVED-R11-NOT: error: write to reserved register 'R7'
+; R7-RESERVED: error: write to reserved register 'R7'
+; R7-FREE-NOT: error: write to reserved register 'R7'
%1 = call i32 asm sideeffect "mov $0, $1", "={r7},r"(i32 %input)
ret void
}
define void @reserved_r11(i32 %input) {
-; RESERVED-NONE-NOT: error: write to reserved register 'R11'
-; RESERVED-R11: error: write to reserved register 'R11'
+; R11-RESERVED: error: write to reserved register 'R11'
+; R11-FREE-NOT: error: write to reserved register 'R11'
%1 = call i32 asm sideeffect "mov $0, $1", "={r11},r"(i32 %input)
ret void
}
diff --git a/llvm/test/CodeGen/ARM/frame-chain.ll b/llvm/test/CodeGen/ARM/frame-chain.ll
index a0f03e51b4613..e37213e4aaf8b 100644
--- a/llvm/test/CodeGen/ARM/frame-chain.ll
+++ b/llvm/test/CodeGen/ARM/frame-chain.ll
@@ -1,12 +1,11 @@
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=all | FileCheck %s --check-prefixes=FP,LEAF-FP
-; 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
-; 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
+; 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
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf | FileCheck %s --check-prefixes=FP,LEAF-NOFP
-; 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
-; 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
+; 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
; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=none | FileCheck %s --check-prefixes=NOFP,LEAF-NOFP
-; 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
-; 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
+; 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
+; RUN: llc -mtriple arm-arm-none-eabi -filetype asm -o - %s -frame-pointer=reserved | FileCheck %s --check-prefixes=NOFP,LEAF-NOFP
+; 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
define dso_local noundef i32 @leaf(i32 noundef %0) {
; LEAF-FP-LABEL: leaf:
diff --git a/llvm/test/CodeGen/Thumb/frame-access.ll b/llvm/test/CodeGen/Thumb/frame-access.ll
index 422c595472ee4..07a6b6d0b9490 100644
--- a/llvm/test/CodeGen/Thumb/frame-access.ll
+++ b/llvm/test/CodeGen/Thumb/frame-access.ll
@@ -1,7 +1,7 @@
; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=none %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-NOFP,CHECK-ATPCS
; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=all %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-FP-ATPCS,CHECK-ATPCS
-; 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
-; 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
+; 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
+; 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
; struct S { int x[128]; } s;
; int f(int *, int, int, int, struct S);
diff --git a/llvm/test/CodeGen/Thumb/frame-chain-reserved-fp.ll b/llvm/test/CodeGen/Thumb/frame-chain-reserved-fp.ll
index 37dd16bd9dd92..d62eb20b84593 100644
--- a/llvm/test/CodeGen/Thumb/frame-chain-reserved-fp.ll
+++ b/llvm/test/CodeGen/Thumb/frame-chain-reserved-fp.ll
@@ -1,27 +1,24 @@
-; RUN: not llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=all 2>&1 | FileCheck %s --check-prefix=RESERVED-R7
-; RUN: not llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
-; RUN: not llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain-leaf 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
-; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf 2>&1 | FileCheck %s --check-prefix=RESERVED-NONE
-; RUN: not llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
-; RUN: not llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain-leaf 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
-; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=none 2>&1 | FileCheck %s --check-prefix=RESERVED-NONE
-; RUN: not llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
-; RUN: not llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain-leaf 2>&1 | FileCheck %s --check-prefix=RESERVED-R11
+; RUN: not llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=all 2>&1 | FileCheck %s --check-prefix=R7-RESERVED --check-prefix=R11-FREE
+; RUN: not llc -mtriple thumbv6m-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
+; RUN: not llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf 2>&1 | FileCheck %s --check-prefix=R7-RESERVED --check-prefix=R11-FREE
+; RUN: not llc -mtriple thumbv6m-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
+; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=none 2>&1 | FileCheck %s --check-prefix=R7-FREE --check-prefix=R11-FREE
+; RUN: llc -mtriple thumbv6m-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
+; RUN: not llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=reserved 2>&1 | FileCheck %s --check-prefix=R7-RESERVED --check-prefix=R11-FREE
+; RUN: not llc -mtriple thumbv6m-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
declare void @leaf(i32 %input)
define void @reserved_r7(i32 %input) {
-; RESERVED-NONE-NOT: error: write to reserved register 'R7'
-; RESERVED-R7: error: write to reserved register 'R7'
-; RESERVED-R11-NOT: error: write to reserved register 'R7'
+; R7-RESERVED: error: write to reserved register 'R7'
+; R7-FREE-NOT: error: write to reserved register 'R7'
%1 = call i32 asm sideeffect "mov $0, $1", "={r7},r"(i32 %input)
ret void
}
define void @reserved_r11(i32 %input) {
-; RESERVED-NONE-NOT: error: write to reserved register 'R11'
-; RESERVED-R7-NOT: error: write to reserved register 'R11'
-; RESERVED-R11: error: write to reserved register 'R11'
+; R11-RESERVED: error: write to reserved register 'R11'
+; R11-FREE-NOT: error: write to reserved register 'R11'
%1 = call i32 asm sideeffect "mov $0, $1", "={r11},r"(i32 %input)
ret void
}
diff --git a/llvm/test/CodeGen/Thumb/frame-chain.ll b/llvm/test/CodeGen/Thumb/frame-chain.ll
index c92235e0f8279..eb62ce09caf1b 100644
--- a/llvm/test/CodeGen/Thumb/frame-chain.ll
+++ b/llvm/test/CodeGen/Thumb/frame-chain.ll
@@ -1,12 +1,9 @@
; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=all --verify-machineinstrs | FileCheck %s --check-prefixes=FP,LEAF-FP
-; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain --verify-machineinstrs | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-FP
-; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain-leaf --verify-machineinstrs | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-FP-AAPCS
+; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=all -mattr=+aapcs-frame-chain --verify-machineinstrs | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-FP-AAPCS
; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf --verify-machineinstrs | FileCheck %s --check-prefixes=FP,LEAF-NOFP
-; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain --verify-machineinstrs | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-NOFP
-; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain-leaf --verify-machineinstrs | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-NOFP-AAPCS
+; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=non-leaf -mattr=+aapcs-frame-chain --verify-machineinstrs | FileCheck %s --check-prefixes=FP-AAPCS,LEAF-NOFP-AAPCS
; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=none --verify-machineinstrs | FileCheck %s --check-prefixes=NOFP,LEAF-NOFP
-; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain --verify-machineinstrs | FileCheck %s --check-prefixes=NOFP-AAPCS,LEAF-NOFP
-; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain-leaf --verify-machineinstrs | FileCheck %s --check-prefixes=NOFP-AAPCS,LEAF-NOFP-AAPCS
+; RUN: llc -mtriple thumbv6m-arm-none-eabi -filetype asm -o - %s -frame-pointer=none -mattr=+aapcs-frame-chain --verify-machineinstrs | FileCheck %s --check-prefixes=NOFP-AAPCS,LEAF-NOFP-AAPCS
define dso_local noundef i32 @leaf(i32 noundef %0) {
; LEAF-FP-LABEL: leaf:
More information about the cfe-commits
mailing list