Skip to content

Commit ea4eb69

Browse files
Radu2ktblah
authored andcommitted
[Flang][Clang] Add support for frame pointers in Flang
1 parent 7832a85 commit ea4eb69

File tree

9 files changed

+184
-138
lines changed

9 files changed

+184
-138
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3172,7 +3172,8 @@ def fno_ms_compatibility : Flag<["-"], "fno-ms-compatibility">, Group<f_Group>,
31723172
def fno_objc_legacy_dispatch : Flag<["-"], "fno-objc-legacy-dispatch">, Group<f_Group>;
31733173
def fno_objc_weak : Flag<["-"], "fno-objc-weak">, Group<f_Group>,
31743174
Visibility<[ClangOption, CC1Option]>;
3175-
def fno_omit_frame_pointer : Flag<["-"], "fno-omit-frame-pointer">, Group<f_Group>;
3175+
def fno_omit_frame_pointer : Flag<["-"], "fno-omit-frame-pointer">, Group<f_Group>,
3176+
Visibility<[ClangOption, FlangOption]>;
31763177
defm operator_names : BoolFOption<"operator-names",
31773178
LangOpts<"CXXOperatorNames">, Default<cplusplus.KeyPath>,
31783179
NegFlag<SetFalse, [], [ClangOption, CC1Option],
@@ -3298,6 +3299,7 @@ defm objc_avoid_heapify_local_blocks : BoolFOption<"objc-avoid-heapify-local-blo
32983299
BothFlags<[], [CC1Option], " to avoid heapifying local blocks">>;
32993300

33003301
def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>,
3302+
Visibility<[ClangOption, FlangOption]>,
33013303
HelpText<"Omit the frame pointer from functions that don't need it. "
33023304
"Some stack unwinding cases, such as profilers and sanitizers, may prefer specifying -fno-omit-frame-pointer. "
33033305
"On many targets, -O1 and higher omit the frame pointer by default. "
@@ -6786,10 +6788,6 @@ def new_struct_path_tbaa : Flag<["-"], "new-struct-path-tbaa">,
67866788
def mdebug_pass : Separate<["-"], "mdebug-pass">,
67876789
HelpText<"Enable additional debug output">,
67886790
MarshallingInfoString<CodeGenOpts<"DebugPass">>;
6789-
def mframe_pointer_EQ : Joined<["-"], "mframe-pointer=">,
6790-
HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,none">,
6791-
NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "None"]>,
6792-
MarshallingInfoEnum<CodeGenOpts<"FramePointer">, "None">;
67936791
def mabi_EQ_ieeelongdouble : Flag<["-"], "mabi=ieeelongdouble">,
67946792
HelpText<"Use IEEE 754 quadruple-precision for long double">,
67956793
MarshallingInfoFlag<LangOpts<"PPCIEEELongDouble">>;
@@ -7400,6 +7398,11 @@ def pic_is_pie : Flag<["-"], "pic-is-pie">,
74007398
HelpText<"File is for a position independent executable">,
74017399
MarshallingInfoFlag<LangOpts<"PIE">>;
74027400

7401+
def mframe_pointer_EQ : Joined<["-"], "mframe-pointer=">,
7402+
HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,none">,
7403+
NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "None"]>,
7404+
MarshallingInfoEnum<CodeGenOpts<"FramePointer">, "None">;
7405+
74037406

74047407
def dependent_lib : Joined<["--"], "dependent-lib=">,
74057408
HelpText<"Add dependent library">,

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 0 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -409,139 +409,6 @@ static bool ShouldEnableAutolink(const ArgList &Args, const ToolChain &TC,
409409
Default);
410410
}
411411

412-
static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
413-
switch (Triple.getArch()){
414-
default:
415-
return false;
416-
case llvm::Triple::arm:
417-
case llvm::Triple::thumb:
418-
// ARM Darwin targets require a frame pointer to be always present to aid
419-
// offline debugging via backtraces.
420-
return Triple.isOSDarwin();
421-
}
422-
}
423-
424-
static bool useFramePointerForTargetByDefault(const ArgList &Args,
425-
const llvm::Triple &Triple) {
426-
if (Args.hasArg(options::OPT_pg) && !Args.hasArg(options::OPT_mfentry))
427-
return true;
428-
429-
if (Triple.isAndroid()) {
430-
switch (Triple.getArch()) {
431-
case llvm::Triple::aarch64:
432-
case llvm::Triple::arm:
433-
case llvm::Triple::armeb:
434-
case llvm::Triple::thumb:
435-
case llvm::Triple::thumbeb:
436-
case llvm::Triple::riscv64:
437-
return true;
438-
default:
439-
break;
440-
}
441-
}
442-
443-
switch (Triple.getArch()) {
444-
case llvm::Triple::xcore:
445-
case llvm::Triple::wasm32:
446-
case llvm::Triple::wasm64:
447-
case llvm::Triple::msp430:
448-
// XCore never wants frame pointers, regardless of OS.
449-
// WebAssembly never wants frame pointers.
450-
return false;
451-
case llvm::Triple::ppc:
452-
case llvm::Triple::ppcle:
453-
case llvm::Triple::ppc64:
454-
case llvm::Triple::ppc64le:
455-
case llvm::Triple::riscv32:
456-
case llvm::Triple::riscv64:
457-
case llvm::Triple::sparc:
458-
case llvm::Triple::sparcel:
459-
case llvm::Triple::sparcv9:
460-
case llvm::Triple::amdgcn:
461-
case llvm::Triple::r600:
462-
case llvm::Triple::csky:
463-
case llvm::Triple::loongarch32:
464-
case llvm::Triple::loongarch64:
465-
return !areOptimizationsEnabled(Args);
466-
default:
467-
break;
468-
}
469-
470-
if (Triple.isOSFuchsia() || Triple.isOSNetBSD()) {
471-
return !areOptimizationsEnabled(Args);
472-
}
473-
474-
if (Triple.isOSLinux() || Triple.isOSHurd()) {
475-
switch (Triple.getArch()) {
476-
// Don't use a frame pointer on linux if optimizing for certain targets.
477-
case llvm::Triple::arm:
478-
case llvm::Triple::armeb:
479-
case llvm::Triple::thumb:
480-
case llvm::Triple::thumbeb:
481-
case llvm::Triple::mips64:
482-
case llvm::Triple::mips64el:
483-
case llvm::Triple::mips:
484-
case llvm::Triple::mipsel:
485-
case llvm::Triple::systemz:
486-
case llvm::Triple::x86:
487-
case llvm::Triple::x86_64:
488-
return !areOptimizationsEnabled(Args);
489-
default:
490-
return true;
491-
}
492-
}
493-
494-
if (Triple.isOSWindows()) {
495-
switch (Triple.getArch()) {
496-
case llvm::Triple::x86:
497-
return !areOptimizationsEnabled(Args);
498-
case llvm::Triple::x86_64:
499-
return Triple.isOSBinFormatMachO();
500-
case llvm::Triple::arm:
501-
case llvm::Triple::thumb:
502-
// Windows on ARM builds with FPO disabled to aid fast stack walking
503-
return true;
504-
default:
505-
// All other supported Windows ISAs use xdata unwind information, so frame
506-
// pointers are not generally useful.
507-
return false;
508-
}
509-
}
510-
511-
return true;
512-
}
513-
514-
static CodeGenOptions::FramePointerKind
515-
getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) {
516-
// We have 4 states:
517-
//
518-
// 00) leaf retained, non-leaf retained
519-
// 01) leaf retained, non-leaf omitted (this is invalid)
520-
// 10) leaf omitted, non-leaf retained
521-
// (what -momit-leaf-frame-pointer was designed for)
522-
// 11) leaf omitted, non-leaf omitted
523-
//
524-
// "omit" options taking precedence over "no-omit" options is the only way
525-
// to make 3 valid states representable
526-
Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer,
527-
options::OPT_fno_omit_frame_pointer);
528-
bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer);
529-
bool NoOmitFP =
530-
A && A->getOption().matches(options::OPT_fno_omit_frame_pointer);
531-
bool OmitLeafFP =
532-
Args.hasFlag(options::OPT_momit_leaf_frame_pointer,
533-
options::OPT_mno_omit_leaf_frame_pointer,
534-
Triple.isAArch64() || Triple.isPS() || Triple.isVE() ||
535-
(Triple.isAndroid() && Triple.isRISCV64()));
536-
if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) ||
537-
(!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) {
538-
if (OmitLeafFP)
539-
return CodeGenOptions::FramePointerKind::NonLeaf;
540-
return CodeGenOptions::FramePointerKind::All;
541-
}
542-
return CodeGenOptions::FramePointerKind::None;
543-
}
544-
545412
/// Add a CC1 option to specify the debug compilation directory.
546413
static const char *addDebugCompDirArg(const ArgList &Args,
547414
ArgStringList &CmdArgs,

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "MSP430.h"
2525
#include "Solaris.h"
2626
#include "clang/Basic/CharInfo.h"
27+
#include "clang/Basic/CodeGenOptions.h"
2728
#include "clang/Basic/LangOptions.h"
2829
#include "clang/Basic/ObjCRuntime.h"
2930
#include "clang/Basic/Version.h"
@@ -71,6 +72,144 @@ using namespace clang::driver::tools;
7172
using namespace clang;
7273
using namespace llvm::opt;
7374

75+
static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
76+
const llvm::Triple &Triple) {
77+
if (Args.hasArg(clang::driver::options::OPT_pg) &&
78+
!Args.hasArg(clang::driver::options::OPT_mfentry))
79+
return true;
80+
81+
if (Triple.isAndroid()) {
82+
switch (Triple.getArch()) {
83+
case llvm::Triple::aarch64:
84+
case llvm::Triple::arm:
85+
case llvm::Triple::armeb:
86+
case llvm::Triple::thumb:
87+
case llvm::Triple::thumbeb:
88+
case llvm::Triple::riscv64:
89+
return true;
90+
default:
91+
break;
92+
}
93+
}
94+
95+
switch (Triple.getArch()) {
96+
case llvm::Triple::xcore:
97+
case llvm::Triple::wasm32:
98+
case llvm::Triple::wasm64:
99+
case llvm::Triple::msp430:
100+
// XCore never wants frame pointers, regardless of OS.
101+
// WebAssembly never wants frame pointers.
102+
return false;
103+
case llvm::Triple::ppc:
104+
case llvm::Triple::ppcle:
105+
case llvm::Triple::ppc64:
106+
case llvm::Triple::ppc64le:
107+
case llvm::Triple::riscv32:
108+
case llvm::Triple::riscv64:
109+
case llvm::Triple::sparc:
110+
case llvm::Triple::sparcel:
111+
case llvm::Triple::sparcv9:
112+
case llvm::Triple::amdgcn:
113+
case llvm::Triple::r600:
114+
case llvm::Triple::csky:
115+
case llvm::Triple::loongarch32:
116+
case llvm::Triple::loongarch64:
117+
return !clang::driver::tools::areOptimizationsEnabled(Args);
118+
default:
119+
break;
120+
}
121+
122+
if (Triple.isOSFuchsia() || Triple.isOSNetBSD()) {
123+
return !clang::driver::tools::areOptimizationsEnabled(Args);
124+
}
125+
126+
if (Triple.isOSLinux() || Triple.isOSHurd()) {
127+
switch (Triple.getArch()) {
128+
// Don't use a frame pointer on linux if optimizing for certain targets.
129+
case llvm::Triple::arm:
130+
case llvm::Triple::armeb:
131+
case llvm::Triple::thumb:
132+
case llvm::Triple::thumbeb:
133+
case llvm::Triple::mips64:
134+
case llvm::Triple::mips64el:
135+
case llvm::Triple::mips:
136+
case llvm::Triple::mipsel:
137+
case llvm::Triple::systemz:
138+
case llvm::Triple::x86:
139+
case llvm::Triple::x86_64:
140+
return !clang::driver::tools::areOptimizationsEnabled(Args);
141+
default:
142+
return true;
143+
}
144+
}
145+
146+
if (Triple.isOSWindows()) {
147+
switch (Triple.getArch()) {
148+
case llvm::Triple::x86:
149+
return !clang::driver::tools::areOptimizationsEnabled(Args);
150+
case llvm::Triple::x86_64:
151+
return Triple.isOSBinFormatMachO();
152+
case llvm::Triple::arm:
153+
case llvm::Triple::thumb:
154+
// Windows on ARM builds with FPO disabled to aid fast stack walking
155+
return true;
156+
default:
157+
// All other supported Windows ISAs use xdata unwind information, so frame
158+
// pointers are not generally useful.
159+
return false;
160+
}
161+
}
162+
163+
return true;
164+
}
165+
166+
static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
167+
switch (Triple.getArch()) {
168+
default:
169+
return false;
170+
case llvm::Triple::arm:
171+
case llvm::Triple::thumb:
172+
// ARM Darwin targets require a frame pointer to be always present to aid
173+
// offline debugging via backtraces.
174+
return Triple.isOSDarwin();
175+
}
176+
}
177+
178+
clang::CodeGenOptions::FramePointerKind
179+
getFramePointerKind(const llvm::opt::ArgList &Args,
180+
const llvm::Triple &Triple) {
181+
// We have 4 states:
182+
//
183+
// 00) leaf retained, non-leaf retained
184+
// 01) leaf retained, non-leaf omitted (this is invalid)
185+
// 10) leaf omitted, non-leaf retained
186+
// (what -momit-leaf-frame-pointer was designed for)
187+
// 11) leaf omitted, non-leaf omitted
188+
//
189+
// "omit" options taking precedence over "no-omit" options is the only way
190+
// to make 3 valid states representable
191+
llvm::opt::Arg *A =
192+
Args.getLastArg(clang::driver::options::OPT_fomit_frame_pointer,
193+
clang::driver::options::OPT_fno_omit_frame_pointer);
194+
195+
bool OmitFP = A && A->getOption().matches(
196+
clang::driver::options::OPT_fomit_frame_pointer);
197+
bool NoOmitFP = A && A->getOption().matches(
198+
clang::driver::options::OPT_fno_omit_frame_pointer);
199+
bool OmitLeafFP =
200+
Args.hasFlag(clang::driver::options::OPT_momit_leaf_frame_pointer,
201+
clang::driver::options::OPT_mno_omit_leaf_frame_pointer,
202+
Triple.isAArch64() || Triple.isPS() || Triple.isVE() ||
203+
(Triple.isAndroid() && Triple.isRISCV64()));
204+
if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) ||
205+
(!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) {
206+
if (OmitLeafFP)
207+
return clang::CodeGenOptions::FramePointerKind::NonLeaf;
208+
return clang::CodeGenOptions::FramePointerKind::All;
209+
}
210+
return clang::CodeGenOptions::FramePointerKind::None;
211+
}
212+
74213
static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs,
75214
const StringRef PluginOptPrefix) {
76215
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ))

clang/lib/Driver/ToolChains/CommonArgs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H
1010
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H
1111

12+
#include "clang/Basic/CodeGenOptions.h"
1213
#include "clang/Driver/Driver.h"
1314
#include "clang/Driver/InputInfo.h"
1415
#include "clang/Driver/Multilib.h"
@@ -215,4 +216,7 @@ void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs,
215216
} // end namespace driver
216217
} // end namespace clang
217218

219+
clang::CodeGenOptions::FramePointerKind
220+
getFramePointerKind(const llvm::opt::ArgList &Args, const llvm::Triple &Triple);
221+
218222
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H

clang/lib/Driver/ToolChains/Flang.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "Flang.h"
1010
#include "CommonArgs.h"
1111

12+
#include "clang/Basic/CodeGenOptions.h"
1213
#include "clang/Driver/Options.h"
1314
#include "llvm/Frontend/Debug/Options.h"
1415
#include "llvm/Support/FileSystem.h"
@@ -674,6 +675,24 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
674675
// Forward -Xflang arguments to -fc1
675676
Args.AddAllArgValues(CmdArgs, options::OPT_Xflang);
676677

678+
CodeGenOptions::FramePointerKind FPKeepKind =
679+
getFramePointerKind(Args, Triple);
680+
681+
const char *FPKeepKindStr = nullptr;
682+
switch (FPKeepKind) {
683+
case CodeGenOptions::FramePointerKind::None:
684+
FPKeepKindStr = "-mframe-pointer=none";
685+
break;
686+
case CodeGenOptions::FramePointerKind::NonLeaf:
687+
FPKeepKindStr = "-mframe-pointer=non-leaf";
688+
break;
689+
case CodeGenOptions::FramePointerKind::All:
690+
FPKeepKindStr = "-mframe-pointer=all";
691+
break;
692+
}
693+
assert(FPKeepKindStr && "unknown FramePointerKind");
694+
CmdArgs.push_back(FPKeepKindStr);
695+
677696
// Forward -mllvm options to the LLVM option parser. In practice, this means
678697
// forwarding to `-fc1` as that's where the LLVM parser is run.
679698
for (const Arg *A : Args.filtered(options::OPT_mllvm)) {

flang/test/Driver/driver-help-hidden.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
! CHECK-NEXT: -fno-stack-arrays Allocate array temporaries on the heap (default)
7575
! CHECK-NEXT: -fno-version-loops-for-stride
7676
! CHECK-NEXT: Do not create unit-strided loops (default)
77+
! CHECK-NEXT: -fomit-frame-pointer Omit the frame pointer from functions that don't need it. Some stack unwinding cases, such as profilers and sanitizers, may prefer specifying -fno-omit-frame-pointer. On many targets, -O1 and higher omit the frame pointer by default. -m[no-]omit-leaf-frame-pointer takes precedence for leaf functions
7778
! CHECK-NEXT: -fopenacc Enable OpenACC
7879
! CHECK-NEXT: -fopenmp-assume-no-nested-parallelism
7980
! CHECK-NEXT: Assert no nested parallel regions in the GPU

0 commit comments

Comments
 (0)