llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-driver Author: Radu Salavat (Radu2k) <details> <summary>Changes</summary> Add support for frame pointers in Flang. --- Patch is 22.74 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/72146.diff 13 Files Affected: - (modified) clang/include/clang/Driver/Options.td (+9-5) - (modified) clang/lib/Driver/ToolChains/Clang.cpp (-133) - (modified) clang/lib/Driver/ToolChains/CommonArgs.cpp (+141) - (modified) clang/lib/Driver/ToolChains/CommonArgs.h (+4) - (modified) clang/lib/Driver/ToolChains/Flang.cpp (+19) - (modified) flang/include/flang/Frontend/CodeGenOptions.def (+1) - (modified) flang/include/flang/Frontend/CodeGenOptions.h (+23) - (modified) flang/include/flang/Tools/CrossToolHelpers.h (+2) - (modified) flang/lib/Frontend/CompilerInvocation.cpp (+13) - (modified) flang/lib/Frontend/FrontendActions.cpp (+5) - (modified) flang/test/Driver/driver-help-hidden.f90 (+1) - (modified) flang/test/Driver/driver-help.f90 (+2) - (modified) flang/test/Driver/frontend-forwarding.f90 (+2) ``````````diff diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index d1b67a448b2a59b..bf99786d017b318 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3147,7 +3147,8 @@ def fno_ms_compatibility : Flag<["-"], "fno-ms-compatibility">, Group<f_Group>, def fno_objc_legacy_dispatch : Flag<["-"], "fno-objc-legacy-dispatch">, Group<f_Group>; def fno_objc_weak : Flag<["-"], "fno-objc-weak">, Group<f_Group>, Visibility<[ClangOption, CC1Option]>; -def fno_omit_frame_pointer : Flag<["-"], "fno-omit-frame-pointer">, Group<f_Group>; +def fno_omit_frame_pointer : Flag<["-"], "fno-omit-frame-pointer">, Group<f_Group>, + Visibility<[ClangOption, FlangOption]>; defm operator_names : BoolFOption<"operator-names", LangOpts<"CXXOperatorNames">, Default<cplusplus.KeyPath>, NegFlag<SetFalse, [], [ClangOption, CC1Option], @@ -3273,6 +3274,7 @@ defm objc_avoid_heapify_local_blocks : BoolFOption<"objc-avoid-heapify-local-blo BothFlags<[], [CC1Option], " to avoid heapifying local blocks">>; def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>, + Visibility<[ClangOption, FlangOption]>, HelpText<"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. " @@ -6752,10 +6754,7 @@ def new_struct_path_tbaa : Flag<["-"], "new-struct-path-tbaa">, def mdebug_pass : Separate<["-"], "mdebug-pass">, HelpText<"Enable additional debug output">, MarshallingInfoString<CodeGenOpts<"DebugPass">>; -def mframe_pointer_EQ : Joined<["-"], "mframe-pointer=">, - HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,none">, - NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "None"]>, - MarshallingInfoEnum<CodeGenOpts<"FramePointer">, "None">; + def mabi_EQ_ieeelongdouble : Flag<["-"], "mabi=ieeelongdouble">, HelpText<"Use IEEE 754 quadruple-precision for long double">, MarshallingInfoFlag<LangOpts<"PPCIEEELongDouble">>; @@ -7368,6 +7367,11 @@ def pic_level : Separate<["-"], "pic-level">, def pic_is_pie : Flag<["-"], "pic-is-pie">, HelpText<"File is for a position independent executable">, MarshallingInfoFlag<LangOpts<"PIE">>; + +def mframe_pointer_EQ : Joined<["-"], "mframe-pointer=">, + HelpText<"Specify which frame pointers to retain.">, Values<"all,non-leaf,none">, + NormalizedValuesScope<"CodeGenOptions::FramePointerKind">, NormalizedValues<["All", "NonLeaf", "None"]>, + MarshallingInfoEnum<CodeGenOpts<"FramePointer">, "None">; } // let Visibility = [CC1Option, FC1Option] diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 3b98c7ae6e6ec66..3273bd1d2c0c6fa 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -409,139 +409,6 @@ static bool ShouldEnableAutolink(const ArgList &Args, const ToolChain &TC, Default); } -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(); - } -} - -static bool useFramePointerForTargetByDefault(const ArgList &Args, - const llvm::Triple &Triple) { - if (Args.hasArg(options::OPT_pg) && !Args.hasArg(options::OPT_mfentry)) - return true; - - if (Triple.isAndroid()) { - switch (Triple.getArch()) { - case llvm::Triple::aarch64: - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - case llvm::Triple::riscv64: - return true; - default: - break; - } - } - - 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::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - case llvm::Triple::amdgcn: - case llvm::Triple::r600: - case llvm::Triple::csky: - case llvm::Triple::loongarch32: - case llvm::Triple::loongarch64: - return !areOptimizationsEnabled(Args); - default: - break; - } - - if (Triple.isOSFuchsia() || Triple.isOSNetBSD()) { - return !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::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::systemz: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - return !areOptimizationsEnabled(Args); - default: - return true; - } - } - - if (Triple.isOSWindows()) { - switch (Triple.getArch()) { - case llvm::Triple::x86: - return !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; - } - } - - return true; -} - -static CodeGenOptions::FramePointerKind -getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) { - // We have 4 states: - // - // 00) leaf retained, non-leaf retained - // 01) leaf retained, non-leaf omitted (this is invalid) - // 10) leaf omitted, non-leaf retained - // (what -momit-leaf-frame-pointer was designed for) - // 11) leaf omitted, non-leaf omitted - // - // "omit" options taking precedence over "no-omit" options is the only way - // to make 3 valid states representable - Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer, - options::OPT_fno_omit_frame_pointer); - bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer); - bool NoOmitFP = - A && A->getOption().matches(options::OPT_fno_omit_frame_pointer); - bool OmitLeafFP = - Args.hasFlag(options::OPT_momit_leaf_frame_pointer, - options::OPT_mno_omit_leaf_frame_pointer, - Triple.isAArch64() || Triple.isPS() || Triple.isVE() || - (Triple.isAndroid() && Triple.isRISCV64())); - if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || - (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { - if (OmitLeafFP) - return CodeGenOptions::FramePointerKind::NonLeaf; - return CodeGenOptions::FramePointerKind::All; - } - return CodeGenOptions::FramePointerKind::None; -} - /// Add a CC1 option to specify the debug compilation directory. static const char *addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs, diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 5d2cd1959b06925..f81bca14363a22a 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -24,6 +24,7 @@ #include "MSP430.h" #include "Solaris.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" @@ -71,6 +72,146 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; +static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + if (Args.hasArg(clang::driver::options::OPT_pg) && + !Args.hasArg(clang::driver::options::OPT_mfentry)) + return true; + + if (Triple.isAndroid()) { + switch (Triple.getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::riscv64: + return true; + default: + break; + } + } + + 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::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + case llvm::Triple::amdgcn: + case llvm::Triple::r600: + case llvm::Triple::csky: + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + return !clang::driver::tools::areOptimizationsEnabled(Args); + default: + break; + } + + if (Triple.isOSFuchsia() || Triple.isOSNetBSD()) { + return !clang::driver::tools::areOptimizationsEnabled(Args); + } + + //if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI || + 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::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + 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; + } + } + + 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(); + } +} + +clang::CodeGenOptions::FramePointerKind +getFramePointerKind(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + // We have 4 states: + // + // 00) leaf retained, non-leaf retained + // 01) leaf retained, non-leaf omitted (this is invalid) + // 10) leaf omitted, non-leaf retained + // (what -momit-leaf-frame-pointer was designed for) + // 11) leaf omitted, non-leaf omitted + // + // "omit" options taking precedence over "no-omit" options is the only way + // to make 3 valid states representable + llvm::opt::Arg *A = + Args.getLastArg(clang::driver::options::OPT_fomit_frame_pointer, + clang::driver::options::OPT_fno_omit_frame_pointer); + + bool OmitFP = A && A->getOption().matches( + clang::driver::options::OPT_fomit_frame_pointer); + bool NoOmitFP = A && A->getOption().matches( + clang::driver::options::OPT_fno_omit_frame_pointer); + bool OmitLeafFP = + Args.hasFlag(clang::driver::options::OPT_momit_leaf_frame_pointer, + clang::driver::options::OPT_mno_omit_leaf_frame_pointer, + Triple.isAArch64() || Triple.isPS() || Triple.isVE() || + (Triple.isAndroid() && Triple.isRISCV64())); + if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || + (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { + if (OmitLeafFP) + return clang::CodeGenOptions::FramePointerKind::NonLeaf; + return clang::CodeGenOptions::FramePointerKind::All; + } + return clang::CodeGenOptions::FramePointerKind::None; +} + + static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs, const StringRef PluginOptPrefix) { if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ)) diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index 0a0951c5386e601..abe8948c5387dce 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -9,6 +9,7 @@ #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" @@ -215,4 +216,7 @@ void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs, } // end namespace driver } // end namespace clang +clang::CodeGenOptions::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/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 8bdd920c3dcbb79..d53bed8e6c1f3b1 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -9,6 +9,7 @@ #include "Flang.h" #include "CommonArgs.h" +#include "clang/Basic/CodeGenOptions.h" #include "clang/Driver/Options.h" #include "llvm/Frontend/Debug/Options.h" #include "llvm/Support/FileSystem.h" @@ -606,6 +607,24 @@ 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); + + const char *FPKeepKindStr = nullptr; + switch (FPKeepKind) { + case CodeGenOptions::FramePointerKind::None: + FPKeepKindStr = "-mframe-pointer=none"; + break; + case CodeGenOptions::FramePointerKind::NonLeaf: + FPKeepKindStr = "-mframe-pointer=non-leaf"; + break; + case CodeGenOptions::FramePointerKind::All: + FPKeepKindStr = "-mframe-pointer=all"; + break; + } + assert(FPKeepKindStr && "unknown FramePointerKind"); + CmdArgs.push_back(FPKeepKindStr); + // Forward -mllvm options to the LLVM option parser. In practice, this means // forwarding to `-fc1` as that's where the LLVM parser is run. for (const Arg *A : Args.filtered(options::OPT_mllvm)) { diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def index 72e7bdab12a14da..d9e6cdfda8598bb 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.def +++ b/flang/include/flang/Frontend/CodeGenOptions.def @@ -38,6 +38,7 @@ CODEGENOPT(Underscoring, 1, 1) ENUM_CODEGENOPT(RelocationModel, llvm::Reloc::Model, 3, llvm::Reloc::PIC_) ///< Name of the relocation model to use. ENUM_CODEGENOPT(DebugInfo, llvm::codegenoptions::DebugInfoKind, 4, llvm::codegenoptions::NoDebugInfo) ///< Level of debug info to generate ENUM_CODEGENOPT(VecLib, llvm::driver::VectorLibrary, 3, llvm::driver::VectorLibrary::NoLibrary) ///< Vector functions library to use +ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,none #undef CODEGENOPT #undef ENUM_CODEGENOPT diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h index a3c39bda10667be..9ccd567678be95f 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.h +++ b/flang/include/flang/Frontend/CodeGenOptions.h @@ -49,6 +49,29 @@ class CodeGenOptionsBase { class CodeGenOptions : public CodeGenOptionsBase { public: + //Added + ///* + enum class FramePointerKind { + None, // Omit all frame pointers. + NonLeaf, // Keep non-leaf frame pointers. + All, // Keep all frame pointers. + }; + + static llvm::StringRef getFramePointerKindName(FramePointerKind Kind) { + switch (Kind) { + case FramePointerKind::None: + return "none"; + case FramePointerKind::NonLeaf: + return "non-leaf"; + case FramePointerKind::All: + return "all"; + } + + llvm_unreachable("invalid FramePointerKind"); + }; + // + //*/ + /// The paths to the pass plugins that were registered using -fpass-plugin. std::vector<std::string> LLVMPassPlugins; diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h index ddec70fa9824c52..7fc5776a61abc5d 100644 --- a/flang/include/flang/Tools/CrossToolHelpers.h +++ b/flang/include/flang/Tools/CrossToolHelpers.h @@ -44,6 +44,8 @@ struct MLIRToLLVMPassPipelineConfig { bool AliasAnalysis = false; ///< Add TBAA tags to generated LLVMIR llvm::codegenoptions::DebugInfoKind DebugInfo = llvm::codegenoptions::NoDebugInfo; ///< Debug info generation. + llvm::FramePointerKind FramePointer = + llvm::FramePointerKind::None; ///< FramePointerInfo unsigned VScaleMin = 0; ///< SVE vector range minimum. unsigned VScaleMax = 0; ///< SVE vector range maximum. }; diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 334da3ac287e3bf..4340981ae9d642a 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -247,6 +247,19 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, clang::driver::options::OPT_fno_alias_analysis, /*default=*/false); + if (const llvm::opt::Arg *a = + args.getLastArg(clang::driver::options::OPT_mframe_pointer_EQ)) { + llvm::StringRef s = a->getValue(); + assert(s == "none" || s == "non-leaf"|| s == "all"); + if (s == "none") + opts.setFramePointer(CodeGenOptions::FramePointerKind::None); + else + if (s == "non-leaf") + opts.setFramePointer(CodeGenOptions::FramePointerKind::NonLeaf); + else + opts.setFramePointer(CodeGenOptions::FramePointerKind::All); + } + for (auto *a : args.filtered(clang::driver::options::OPT_fpass_plugin_EQ)) opts.LLVMPassPlugins.push_back(a->getValue()); diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index d7ca7b66584dd52..06273a07e84f2a0 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -783,6 +783,11 @@ void CodeGenAction::generateLLVMIR() { llvmModule->setPIELevel( static_cast<llvm::PIELevel::Level>(opts.PICLevel)); } + + // Set FramePointer LLVM module flag. + llvmModule->setFramePointer( + static_cast<llvm::FramePointerKind>(opts.getFramePointer())); + } bool CodeGenAction::setUpTargetMachine() { diff --git a/flang/test/Driver/driver-help-hidden.f90 b/flang/test/Driver/driver-help-hidden.f90 index b276f1906e1a457..57a1710709940f3 100644 --- a/flang/test/Driver/driver-help-hidden.f90 +++ b/flang/test/Driver/driver-help-hidden.f90 @@ -74,6 +74,7 @@ ! CHECK-NEXT: -fno-stack-arrays Allocate array temporaries on the heap (default) ! CHECK-NEXT: -fno-version-loops-for-stride ! CHECK-NEXT: Do not create unit-strided loops (default) +! CHECK-NEXT: -fomit-frame-pointer Omit the frame pointer from functions that don't need it. Some... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/72146 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits