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 <[email protected]> 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) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
