@@ -164,6 +164,14 @@ static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
164
164
return true ;
165
165
}
166
166
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
+
167
175
static bool mustUseNonLeafFramePointerForTarget (const llvm::Triple &Triple) {
168
176
switch (Triple.getArch ()) {
169
177
default :
@@ -176,38 +184,91 @@ static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
176
184
}
177
185
}
178
186
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
+
179
221
clang::CodeGenOptions::FramePointerKind
180
222
getFramePointerKind (const llvm::opt::ArgList &Args,
181
223
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?
183
229
//
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.
189
234
//
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;
211
272
return clang::CodeGenOptions::FramePointerKind::None;
212
273
}
213
274
0 commit comments