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.stann...@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.stann...@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: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits