Skip to content

Commit 1a52392

Browse files
authored
[ARM] r11 is reserved when using -mframe-chain=aapcs (#86951)
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.
1 parent b87a80d commit 1a52392

24 files changed

+188
-93
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ CODEGENOPT(SeparateNamedSections, 1, 0) ///< Set for -fseparate-named-sections.
6161
CODEGENOPT(EnableAIXExtendedAltivecABI, 1, 0) ///< Set for -mabi=vec-extabi. Enables the extended Altivec ABI on AIX.
6262
CODEGENOPT(XCOFFReadOnlyPointers, 1, 0) ///< Set for -mxcoff-roptr.
6363
CODEGENOPT(AllTocData, 1, 0) ///< AIX -mtocdata
64-
ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,none
64+
ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,reserved,none
6565

6666
CODEGENOPT(ClearASTBeforeBackend , 1, 0) ///< Free the AST before running backend code generation. Only works with -disable-free.
6767
CODEGENOPT(DisableFree , 1, 0) ///< Don't free memory.

clang/include/clang/Basic/CodeGenOptions.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,18 @@ class CodeGenOptions : public CodeGenOptionsBase {
127127
std::string BinutilsVersion;
128128

129129
enum class FramePointerKind {
130-
None, // Omit all frame pointers.
131-
NonLeaf, // Keep non-leaf frame pointers.
132-
All, // Keep all frame pointers.
130+
None, // Omit all frame pointers.
131+
Reserved, // Maintain valid frame pointer chain.
132+
NonLeaf, // Keep non-leaf frame pointers.
133+
All, // Keep all frame pointers.
133134
};
134135

135136
static StringRef getFramePointerKindName(FramePointerKind Kind) {
136137
switch (Kind) {
137138
case FramePointerKind::None:
138139
return "none";
140+
case FramePointerKind::Reserved:
141+
return "reserved";
139142
case FramePointerKind::NonLeaf:
140143
return "non-leaf";
141144
case FramePointerKind::All:

clang/include/clang/Driver/Options.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7724,8 +7724,8 @@ def pic_is_pie : Flag<["-"], "pic-is-pie">,
77247724
MarshallingInfoFlag<LangOpts<"PIE">>;
77257725

77267726
def mframe_pointer_EQ : Joined<["-"], "mframe-pointer=">,
7727-
HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,none">,
7728-
NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "None"]>,
7727+
HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,reserved,none">,
7728+
NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "Reserved", "None"]>,
77297729
MarshallingInfoEnum<CodeGenOpts<"FramePointer">, "None">;
77307730

77317731

clang/lib/CodeGen/CGCall.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,6 +1917,7 @@ static void getTrivialDefaultFunctionAttributes(
19171917
case CodeGenOptions::FramePointerKind::None:
19181918
// This is the default behavior.
19191919
break;
1920+
case CodeGenOptions::FramePointerKind::Reserved:
19201921
case CodeGenOptions::FramePointerKind::NonLeaf:
19211922
case CodeGenOptions::FramePointerKind::All:
19221923
FuncAttrs.addAttribute("frame-pointer",

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,9 @@ void CodeGenModule::Release() {
13281328
case CodeGenOptions::FramePointerKind::None:
13291329
// 0 ("none") is the default.
13301330
break;
1331+
case CodeGenOptions::FramePointerKind::Reserved:
1332+
getModule().setFramePointer(llvm::FramePointerKind::Reserved);
1333+
break;
13311334
case CodeGenOptions::FramePointerKind::NonLeaf:
13321335
getModule().setFramePointer(llvm::FramePointerKind::NonLeaf);
13331336
break;

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

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

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

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5678,6 +5678,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
56785678
case CodeGenOptions::FramePointerKind::None:
56795679
FPKeepKindStr = "-mframe-pointer=none";
56805680
break;
5681+
case CodeGenOptions::FramePointerKind::Reserved:
5682+
FPKeepKindStr = "-mframe-pointer=reserved";
5683+
break;
56815684
case CodeGenOptions::FramePointerKind::NonLeaf:
56825685
FPKeepKindStr = "-mframe-pointer=non-leaf";
56835686
break;

clang/lib/Driver/ToolChains/CommonArgs.cpp

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

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

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

llvm/docs/LangRef.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1924,7 +1924,11 @@ example:
19241924
even if this attribute says the frame pointer can be eliminated.
19251925
The allowed string values are:
19261926

1927-
* ``"none"`` (default) - the frame pointer can be eliminated.
1927+
* ``"none"`` (default) - the frame pointer can be eliminated, and it's
1928+
register can be used for other purposes.
1929+
* ``"reserved"`` - the frame pointer register must either be updated to
1930+
point to a valid frame record for the current function, or not be
1931+
modified.
19281932
* ``"non-leaf"`` - the frame pointer should be kept if the function calls
19291933
other functions.
19301934
* ``"all"`` - the frame pointer should be kept.

llvm/include/llvm/Support/CodeGen.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ namespace llvm {
8787
};
8888

8989
// Specify what functions should keep the frame pointer.
90-
enum class FramePointerKind { None, NonLeaf, All };
90+
enum class FramePointerKind { None, NonLeaf, All, Reserved };
9191

9292
// Specify what type of zeroing callee-used registers.
9393
namespace ZeroCallUsedRegs {

0 commit comments

Comments
 (0)