[clang] [llvm] [LLVM][Clang][Flang] Move framepointer kind selection to LLVMFrontend (PR #218870)
Kiran Chandramohan via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 26 02:48:01 PDT 2026
https://github.com/kiranchandramohan created https://github.com/llvm/llvm-project/pull/218870
Move getFramePointerKind and its target-specific helpers from clangDriver to LLVMFrontendDriver so they can be shared by the Clang and Flang drivers.
Keep Clang-specific option parsing in clangDriver and pass normalized options to the shared implementation.
>From 59fded4799b4aefb515b834378dd73f99ff24f09 Mon Sep 17 00:00:00 2001
From: Kiran Chandramohan <kiran.chandramohan at arm.com>
Date: Wed, 26 Aug 2026 11:21:20 +0200
Subject: [PATCH] [LLVM][Clang][Flang] Move framepointer kind selection to
LLVMFrontend
Move getFramePointerKind and its target-specific helpers from clangDriver
to LLVMFrontendDriver so they can be shared by the Clang and Flang
drivers.
Keep Clang-specific option parsing in clangDriver and pass normalized
options to the shared implementation.
---
clang/include/clang/Driver/CommonArgs.h | 3 +-
clang/lib/Driver/CMakeLists.txt | 1 +
clang/lib/Driver/ToolChains/Clang.cpp | 15 +-
clang/lib/Driver/ToolChains/CommonArgs.cpp | 255 +++---------------
clang/lib/Driver/ToolChains/Flang.cpp | 14 +-
.../llvm/Frontend/Driver/CodeGenOptions.h | 26 ++
llvm/lib/Frontend/Driver/CodeGenOptions.cpp | 234 ++++++++++++++++
7 files changed, 308 insertions(+), 240 deletions(-)
diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h
index be15d15a1661e..1e09250147f93 100644
--- a/clang/include/clang/Driver/CommonArgs.h
+++ b/clang/include/clang/Driver/CommonArgs.h
@@ -9,7 +9,6 @@
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H
-#include "clang/Basic/CodeGenOptions.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Multilib.h"
@@ -364,7 +363,7 @@ void constructLLVMLinkCommand(Compilation &C, const Tool &T,
} // end namespace driver
} // end namespace clang
-clang::CodeGenOptions::FramePointerKind
+llvm::FramePointerKind
getFramePointerKind(const llvm::opt::ArgList &Args, const llvm::Triple &Triple);
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H
diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt
index 506536cdc04f5..85817735de80b 100644
--- a/clang/lib/Driver/CMakeLists.txt
+++ b/clang/lib/Driver/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
BinaryFormat
+ FrontendDriver
MC
Object
Option
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index dabc8c8d964d6..329616a10aa53 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6144,23 +6144,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- CodeGenOptions::FramePointerKind FPKeepKind =
- getFramePointerKind(Args, RawTriple);
+ llvm::FramePointerKind FPKeepKind = getFramePointerKind(Args, RawTriple);
const char *FPKeepKindStr = nullptr;
switch (FPKeepKind) {
- case CodeGenOptions::FramePointerKind::None:
+ case llvm::FramePointerKind::None:
FPKeepKindStr = "-mframe-pointer=none";
break;
- case CodeGenOptions::FramePointerKind::Reserved:
+ case llvm::FramePointerKind::Reserved:
FPKeepKindStr = "-mframe-pointer=reserved";
break;
- case CodeGenOptions::FramePointerKind::NonLeafNoReserve:
+ case llvm::FramePointerKind::NonLeafNoReserve:
FPKeepKindStr = "-mframe-pointer=non-leaf-no-reserve";
break;
- case CodeGenOptions::FramePointerKind::NonLeaf:
+ case llvm::FramePointerKind::NonLeaf:
FPKeepKindStr = "-mframe-pointer=non-leaf";
break;
- case CodeGenOptions::FramePointerKind::All:
+ case llvm::FramePointerKind::All:
FPKeepKindStr = "-mframe-pointer=all";
break;
}
@@ -8635,7 +8634,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
if (Arg *A = Args.getLastArg(options::OPT_pg))
- if (FPKeepKind == CodeGenOptions::FramePointerKind::None &&
+ if (FPKeepKind == llvm::FramePointerKind::None &&
!Args.hasArg(options::OPT_mfentry))
D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer"
<< A->getAsString(Args);
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 74e27bf8b9cde..a4a760f3dad32 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -24,7 +24,6 @@
#include "MSP430.h"
#include "Solaris.h"
#include "ToolChains/Cuda.h"
-#include "clang/Basic/CodeGenOptions.h"
#include "clang/Config/config.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Compilation.h"
@@ -45,6 +44,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/Frontend/Driver/CodeGenOptions.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
@@ -84,229 +84,40 @@ OffloadJobsOpt tools::parseOffloadJobs(const ArgList &Args) {
return {OffloadJobsOpt::Kind::Fixed, A, Val, unsigned(NumThreads)};
}
-static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
- const llvm::Triple &Triple) {
- if (Args.hasArg(options::OPT_pg) && !Args.hasArg(options::OPT_mfentry))
- return true;
-
- if (Triple.isAndroid())
- return true;
-
- switch (Triple.getArch()) {
- case llvm::Triple::xcore:
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- case llvm::Triple::msp430:
- // XCore never wants frame pointers, regardless of OS.
- // WebAssembly never wants frame pointers.
- return false;
- case llvm::Triple::ppc:
- case llvm::Triple::ppcle:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- case llvm::Triple::riscv32:
- case llvm::Triple::riscv64:
- case llvm::Triple::riscv32be:
- case llvm::Triple::riscv64be:
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- case llvm::Triple::sparcv9:
- case llvm::Triple::amdgpu:
- case llvm::Triple::r600:
- case llvm::Triple::csky:
- case llvm::Triple::loongarch32:
- case llvm::Triple::loongarch64:
- case llvm::Triple::m68k:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- return !clang::driver::tools::areOptimizationsEnabled(Args);
- default:
- break;
- }
-
- if (Triple.isOSFuchsia() || Triple.isOSNetBSD()) {
- return !clang::driver::tools::areOptimizationsEnabled(Args);
- }
-
- if (Triple.isOSLinux() || Triple.isOSHurd()) {
- switch (Triple.getArch()) {
- // Don't use a frame pointer on linux if optimizing for certain targets.
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- case llvm::Triple::systemz:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- return !clang::driver::tools::areOptimizationsEnabled(Args);
- default:
- return true;
- }
- }
-
- if (Triple.isOSWindows()) {
- switch (Triple.getArch()) {
- case llvm::Triple::x86:
- return !clang::driver::tools::areOptimizationsEnabled(Args);
- case llvm::Triple::x86_64:
- return Triple.isOSBinFormatMachO();
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- // Windows on ARM builds with FPO disabled to aid fast stack walking
- return true;
- default:
- // All other supported Windows ISAs use xdata unwind information, so frame
- // pointers are not generally useful.
- return false;
- }
- }
-
- if (arm::isARMEABIBareMetal(Triple))
- return false;
-
- return true;
-}
-
-static bool useLeafFramePointerForTargetByDefault(const llvm::Triple &Triple) {
- if (Triple.isAArch64() || Triple.isPS() || Triple.isVE() ||
- (Triple.isAndroid() && !Triple.isARM()))
- return false;
-
- if ((Triple.isARM() || Triple.isThumb()) && Triple.isOSBinFormatMachO())
- return false;
-
- return true;
-}
-
-static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
- switch (Triple.getArch()) {
- default:
- return false;
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- // ARM Darwin targets require a frame pointer to be always present to aid
- // offline debugging via backtraces.
- return Triple.isOSDarwin();
- }
-}
-
-// 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) {
- switch (Triple.getArch()) {
- default:
- return false;
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- // 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;
-
- case llvm::Triple::aarch64:
- // Arm64 Windows requires that the frame chain is valid, as there is no
- // way to indicate during a stack walk that a frame has used the frame
- // pointer as a general purpose register.
- return Triple.isOSWindows();
- }
-}
-
-// 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
+llvm::FramePointerKind
getFramePointerKind(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple) {
- // There are four 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 in non-leaf functions?
- // i.e. must it always point to either a new, valid frame record or be
- // un-modified?
- // * Is the frame pointer register reserved in leaf functions?
- //
- // 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.
- //
- // | Frame Setup | Reg Reserved |
- // |-----------------|-----------------|
- // | Non-leaf | Leaf | Non-Leaf | Leaf |
- // |----------|------|----------|------|
- // | N | N | N | N | FramePointerKind::None
- // | N | N | N | Y | Invalid
- // | N | N | Y | N | Invalid
- // | N | N | Y | Y | FramePointerKind::Reserved
- // | N | Y | N | N | Invalid
- // | N | Y | N | Y | Invalid
- // | N | Y | Y | N | Invalid
- // | N | Y | Y | Y | Invalid
- // | Y | N | N | N | Invalid
- // | Y | N | N | Y | Invalid
- // | Y | N | Y | N | FramePointerKind::NonLeafNoReserve
- // | Y | N | Y | Y | FramePointerKind::NonLeaf
- // | Y | Y | N | N | Invalid
- // | Y | Y | N | Y | Invalid
- // | Y | Y | Y | N | Invalid
- // | Y | 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(options::OPT_fno_omit_frame_pointer,
- options::OPT_fomit_frame_pointer, DefaultFP);
-
- bool DefaultLeafFP =
- useLeafFramePointerForTargetByDefault(Triple) ||
- (EnableFP && framePointerImpliesLeafFramePointer(Args, Triple));
- bool EnableLeafFP =
- Args.hasFlag(options::OPT_mno_omit_leaf_frame_pointer,
- options::OPT_momit_leaf_frame_pointer, DefaultLeafFP);
-
- bool FPRegReserved = Args.hasFlag(options::OPT_mreserve_frame_pointer_reg,
- options::OPT_mno_reserve_frame_pointer_reg,
- mustMaintainValidFrameChain(Args, Triple));
-
- if (EnableFP) {
- if (EnableLeafFP)
- return clang::CodeGenOptions::FramePointerKind::All;
-
- if (FPRegReserved)
- return clang::CodeGenOptions::FramePointerKind::NonLeaf;
-
- return clang::CodeGenOptions::FramePointerKind::NonLeafNoReserve;
- }
- if (FPRegReserved)
- return clang::CodeGenOptions::FramePointerKind::Reserved;
- return clang::CodeGenOptions::FramePointerKind::None;
+ llvm::driver::FramePointerOptions Opts;
+ Opts.Optimized = tools::areOptimizationsEnabled(Args);
+ Opts.InstrumentationRequiresFramePointer =
+ Args.hasArg(options::OPT_pg) && !Args.hasArg(options::OPT_mfentry);
+
+ if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
+ options::OPT_fomit_frame_pointer))
+ Opts.EnableFramePointer =
+ A->getOption().matches(options::OPT_fno_omit_frame_pointer);
+ if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer,
+ options::OPT_momit_leaf_frame_pointer))
+ Opts.EnableLeafFramePointer =
+ A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer);
+ if (Arg *A = Args.getLastArg(options::OPT_mreserve_frame_pointer_reg,
+ options::OPT_mno_reserve_frame_pointer_reg))
+ Opts.ReserveFramePointerRegister =
+ A->getOption().matches(options::OPT_mreserve_frame_pointer_reg);
+
+ if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) {
+ Opts.FrameChain =
+ llvm::StringSwitch<llvm::driver::FramePointerOptions::FrameChainKind>(
+ A->getValue())
+ .Case("aapcs",
+ llvm::driver::FramePointerOptions::FrameChainKind::AAPCS)
+ .Case("aapcs+leaf",
+ llvm::driver::FramePointerOptions::FrameChainKind::AAPCSLeaf)
+ .Default(
+ llvm::driver::FramePointerOptions::FrameChainKind::None);
+ }
+
+ return llvm::driver::getFramePointerKind(Triple, Opts);
}
static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs,
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 5824f59400323..38bc33410b1d6 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -10,7 +10,6 @@
#include "Arch/RISCV.h"
#include "Cuda.h"
-#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/MakeSupport.h"
#include "clang/Driver/CommonArgs.h"
#include "clang/Options/OptionUtils.h"
@@ -1452,24 +1451,23 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
// Forward -Xflang arguments to -fc1
Args.AddAllArgValues(CmdArgs, options::OPT_Xflang);
- CodeGenOptions::FramePointerKind FPKeepKind =
- getFramePointerKind(Args, Triple);
+ llvm::FramePointerKind FPKeepKind = getFramePointerKind(Args, Triple);
const char *FPKeepKindStr = nullptr;
switch (FPKeepKind) {
- case CodeGenOptions::FramePointerKind::None:
+ case llvm::FramePointerKind::None:
FPKeepKindStr = "-mframe-pointer=none";
break;
- case CodeGenOptions::FramePointerKind::Reserved:
+ case llvm::FramePointerKind::Reserved:
FPKeepKindStr = "-mframe-pointer=reserved";
break;
- case CodeGenOptions::FramePointerKind::NonLeafNoReserve:
+ case llvm::FramePointerKind::NonLeafNoReserve:
FPKeepKindStr = "-mframe-pointer=non-leaf-no-reserve";
break;
- case CodeGenOptions::FramePointerKind::NonLeaf:
+ case llvm::FramePointerKind::NonLeaf:
FPKeepKindStr = "-mframe-pointer=non-leaf";
break;
- case CodeGenOptions::FramePointerKind::All:
+ case llvm::FramePointerKind::All:
FPKeepKindStr = "-mframe-pointer=all";
break;
}
diff --git a/llvm/include/llvm/Frontend/Driver/CodeGenOptions.h b/llvm/include/llvm/Frontend/Driver/CodeGenOptions.h
index 77ab477986d31..af58dfc027499 100644
--- a/llvm/include/llvm/Frontend/Driver/CodeGenOptions.h
+++ b/llvm/include/llvm/Frontend/Driver/CodeGenOptions.h
@@ -14,6 +14,8 @@
#define LLVM_FRONTEND_DRIVER_CODEGENOPTIONS_H
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/CodeGen.h"
+#include <optional>
#include <string>
namespace llvm {
@@ -23,6 +25,30 @@ enum class VectorLibrary;
} // namespace llvm
namespace llvm::driver {
+/// Driver options which affect the target's frame pointer policy. Frontends
+/// are responsible for translating their option table into this structure.
+struct FramePointerOptions {
+ /// Whether an optimization level other than -O0 is enabled.
+ bool Optimized = false;
+
+ /// Whether instrumentation such as -pg requires a frame pointer.
+ bool InstrumentationRequiresFramePointer = false;
+
+ /// Explicit overrides for non-leaf frame records, leaf frame records, and
+ /// reserving the frame pointer register, respectively.
+ std::optional<bool> EnableFramePointer;
+ std::optional<bool> EnableLeafFramePointer;
+ std::optional<bool> ReserveFramePointerRegister;
+
+ enum class FrameChainKind { None, AAPCS, AAPCSLeaf };
+ FrameChainKind FrameChain = FrameChainKind::None;
+};
+
+/// Determine the frame pointer policy for \p TargetTriple.
+LLVM_ABI llvm::FramePointerKind
+getFramePointerKind(const llvm::Triple &TargetTriple,
+ const FramePointerOptions &Opts);
+
// The current supported vector libraries in enum \VectorLibrary are 9(including
// the NoLibrary). Changing the bitcount from 3 to 4 so that more than 8 values
// can be supported. Now the maximum number of vector libraries supported
diff --git a/llvm/lib/Frontend/Driver/CodeGenOptions.cpp b/llvm/lib/Frontend/Driver/CodeGenOptions.cpp
index d22202598a28d..adbd3922477b7 100644
--- a/llvm/lib/Frontend/Driver/CodeGenOptions.cpp
+++ b/llvm/lib/Frontend/Driver/CodeGenOptions.cpp
@@ -19,6 +19,240 @@ extern llvm::cl::opt<llvm::InstrProfCorrelator::ProfCorrelatorKind>
namespace llvm::driver {
+/// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ?
+static bool isARMEABIBareMetal(const llvm::Triple &Triple) {
+ auto Arch = Triple.getArch();
+ if (Arch != llvm::Triple::arm && Arch != llvm::Triple::thumb &&
+ Arch != llvm::Triple::armeb && Arch != llvm::Triple::thumbeb)
+ return false;
+
+ if (Triple.getVendor() != llvm::Triple::UnknownVendor)
+ return false;
+
+ if (Triple.getOS() != llvm::Triple::UnknownOS)
+ return false;
+
+ if (Triple.getEnvironment() != llvm::Triple::EABI &&
+ Triple.getEnvironment() != llvm::Triple::EABIHF)
+ return false;
+
+ return true;
+}
+
+static bool useFramePointerForTargetByDefault(
+ const llvm::Triple &Triple, const FramePointerOptions &Opts) {
+ if (Opts.InstrumentationRequiresFramePointer)
+ return true;
+
+ if (Triple.isAndroid())
+ return true;
+
+ switch (Triple.getArch()) {
+ case llvm::Triple::xcore:
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ case llvm::Triple::msp430:
+ // XCore never wants frame pointers, regardless of OS.
+ // WebAssembly never wants frame pointers.
+ return false;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppcle:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::riscv32:
+ case llvm::Triple::riscv64:
+ case llvm::Triple::riscv32be:
+ case llvm::Triple::riscv64be:
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::sparcv9:
+ case llvm::Triple::amdgpu:
+ case llvm::Triple::r600:
+ case llvm::Triple::csky:
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
+ case llvm::Triple::m68k:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return !Opts.Optimized;
+ default:
+ break;
+ }
+
+ if (Triple.isOSFuchsia() || Triple.isOSNetBSD()) {
+ return !Opts.Optimized;
+ }
+
+ if (Triple.isOSLinux() || Triple.isOSHurd()) {
+ switch (Triple.getArch()) {
+ // Don't use a frame pointer on linux if optimizing for certain targets.
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::systemz:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return !Opts.Optimized;
+ default:
+ return true;
+ }
+ }
+
+ if (Triple.isOSWindows()) {
+ switch (Triple.getArch()) {
+ case llvm::Triple::x86:
+ return !Opts.Optimized;
+ case llvm::Triple::x86_64:
+ return Triple.isOSBinFormatMachO();
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // Windows on ARM builds with FPO disabled to aid fast stack walking
+ return true;
+ default:
+ // All other supported Windows ISAs use xdata unwind information, so frame
+ // pointers are not generally useful.
+ return false;
+ }
+ }
+
+ if (isARMEABIBareMetal(Triple))
+ return false;
+
+ return true;
+}
+
+static bool useLeafFramePointerForTargetByDefault(
+ const llvm::Triple &Triple) {
+ if (Triple.isAArch64() || Triple.isPS() || Triple.isVE() ||
+ (Triple.isAndroid() && !Triple.isARM()))
+ return false;
+
+ if ((Triple.isARM() || Triple.isThumb()) && Triple.isOSBinFormatMachO())
+ return false;
+
+ return true;
+}
+
+static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
+ switch (Triple.getArch()) {
+ default:
+ return false;
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // ARM Darwin targets require a frame pointer to be always present to aid
+ // offline debugging via backtraces.
+ return Triple.isOSDarwin();
+ }
+}
+
+// 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 FramePointerOptions &Opts,
+ const llvm::Triple &Triple) {
+ switch (Triple.getArch()) {
+ default:
+ return false;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ // 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.
+ return Opts.FrameChain != FramePointerOptions::FrameChainKind::None;
+
+ case llvm::Triple::aarch64:
+ // Arm64 Windows requires that the frame chain is valid, as there is no
+ // way to indicate during a stack walk that a frame has used the frame
+ // pointer as a general purpose register.
+ return Triple.isOSWindows();
+ }
+}
+
+// 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 FramePointerOptions &Opts, 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.
+ return Opts.FrameChain == FramePointerOptions::FrameChainKind::AAPCSLeaf;
+ }
+ return false;
+}
+
+llvm::FramePointerKind
+getFramePointerKind(const llvm::Triple &Triple,
+ const FramePointerOptions &Opts) {
+ // There are four 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 in non-leaf functions?
+ // i.e. must it always point to either a new, valid frame record or be
+ // un-modified?
+ // * Is the frame pointer register reserved in leaf functions?
+ //
+ // 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.
+ //
+ // | Frame Setup | Reg Reserved |
+ // |-----------------|-----------------|
+ // | Non-leaf | Leaf | Non-Leaf | Leaf |
+ // |----------|------|----------|------|
+ // | N | N | N | N | FramePointerKind::None
+ // | N | N | N | Y | Invalid
+ // | N | N | Y | N | Invalid
+ // | N | N | Y | Y | FramePointerKind::Reserved
+ // | N | Y | N | N | Invalid
+ // | N | Y | N | Y | Invalid
+ // | N | Y | Y | N | Invalid
+ // | N | Y | Y | Y | Invalid
+ // | Y | N | N | N | Invalid
+ // | Y | N | N | Y | Invalid
+ // | Y | N | Y | N | FramePointerKind::NonLeafNoReserve
+ // | Y | N | Y | Y | FramePointerKind::NonLeaf
+ // | Y | Y | N | N | Invalid
+ // | Y | Y | N | Y | Invalid
+ // | Y | Y | Y | N | Invalid
+ // | Y | 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(Triple, Opts);
+ bool EnableFP = mustUseNonLeafFramePointerForTarget(Triple) ||
+ Opts.EnableFramePointer.value_or(DefaultFP);
+
+ bool DefaultLeafFP =
+ useLeafFramePointerForTargetByDefault(Triple) ||
+ (EnableFP && framePointerImpliesLeafFramePointer(Opts, Triple));
+ bool EnableLeafFP = Opts.EnableLeafFramePointer.value_or(DefaultLeafFP);
+
+ bool FPRegReserved = Opts.ReserveFramePointerRegister.value_or(
+ mustMaintainValidFrameChain(Opts, Triple));
+
+ if (EnableFP) {
+ if (EnableLeafFP)
+ return llvm::FramePointerKind::All;
+
+ if (FPRegReserved)
+ return llvm::FramePointerKind::NonLeaf;
+
+ return llvm::FramePointerKind::NonLeafNoReserve;
+ }
+ if (FPRegReserved)
+ return llvm::FramePointerKind::Reserved;
+ return llvm::FramePointerKind::None;
+}
+
llvm::VectorLibrary
convertDriverVectorLibraryToVectorLibrary(llvm::driver::VectorLibrary VecLib) {
switch (VecLib) {
More information about the cfe-commits
mailing list