Skip to content

[ARM] r11 is reserved when using -mframe-chain=aapcs #86951

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
9 changes: 6 additions & 3 deletions clang/include/clang/Basic/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,18 @@ class CodeGenOptions : public CodeGenOptionsBase {
std::string BinutilsVersion;

enum class FramePointerKind {
None, // Omit all frame pointers.
NonLeaf, // Keep non-leaf frame pointers.
All, // Keep all frame pointers.
None, // Omit all frame pointers.
Reserved, // Maintain valid frame pointer chain.
NonLeaf, // Keep non-leaf frame pointers.
All, // Keep all frame pointers.
};

static StringRef getFramePointerKindName(FramePointerKind Kind) {
switch (Kind) {
case FramePointerKind::None:
return "none";
case FramePointerKind::Reserved:
return "reserved";
case FramePointerKind::NonLeaf:
return "non-leaf";
case FramePointerKind::All:
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;


Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Driver/ToolChains/Arch/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
115 changes: 88 additions & 27 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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;
}

Expand Down
6 changes: 5 additions & 1 deletion llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/Support/CodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/Target/TargetOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/CommandFlags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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");
}
Expand Down
21 changes: 19 additions & 2 deletions llvm/lib/CodeGen/TargetOptionsImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/StringSwitch.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
Expand All @@ -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;

Expand All @@ -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 {
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/IR/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 5 additions & 6 deletions llvm/lib/Target/ARM/ARMFeatures.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/Target/ARM/ARMFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/ARM/ARMFrameLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading
Loading