[flang-commits] [clang] [flang] [mlir] [Flang][Driver][MLIR] Add support for fomit-frame-pointer (PR #72135)
Radu Salavat via flang-commits
flang-commits at lists.llvm.org
Mon Nov 13 08:54:19 PST 2023
https://github.com/Radu2k created https://github.com/llvm/llvm-project/pull/72135
Made appropriate changes in Flang and MLIR to support 'fomit-frame-pointer' and 'fno-omit-frame-pointer'.
>From cd5cbb9ebd0f075b436b5b00b9b43e28551f5a07 Mon Sep 17 00:00:00 2001
From: Rik Huijzer <github at huijzer.xyz>
Date: Mon, 13 Nov 2023 16:37:54 +0100
Subject: [PATCH] [mlir][tensor] Document `dest` operand (#71726)
Based on the tips from @ubfx and @joker-eph in
https://github.com/llvm/llvm-project/issues/70030, this patch suggest to
introduce the `dest` operand in the `tensor` dialect description. To do
so, this patch also suggests to move some things around to make it more
clear how the paragraphs relate to each other.
---------
Co-authored-by: Matthias Springer <me at m-sp.org>
Co-authored-by: Mehdi Amini <joker.eph at gmail.com>
Co-authored-by: Felix Schneider <fx.schn at gmail.com>
---
clang/include/clang/Driver/Options.td | 14 +-
clang/lib/Driver/ToolChains/Clang.cpp | 133 -----------------
clang/lib/Driver/ToolChains/CommonArgs.cpp | 141 ++++++++++++++++++
clang/lib/Driver/ToolChains/CommonArgs.h | 4 +
clang/lib/Driver/ToolChains/Flang.cpp | 19 +++
.../include/flang/Frontend/CodeGenOptions.def | 1 +
flang/include/flang/Frontend/CodeGenOptions.h | 23 +++
flang/include/flang/Tools/CrossToolHelpers.h | 2 +
flang/lib/Frontend/CompilerInvocation.cpp | 13 ++
flang/lib/Frontend/FrontendActions.cpp | 5 +
flang/test/Driver/driver-help-hidden.f90 | 1 +
flang/test/Driver/driver-help.f90 | 2 +
flang/test/Driver/frontend-forwarding.f90 | 2 +
mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td | 19 +++
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 3 +-
.../mlir/Dialect/Tensor/IR/TensorBase.td | 44 +++---
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 25 +++-
mlir/lib/Target/LLVMIR/ModuleImport.cpp | 11 +-
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 4 +
mlir/test/Dialect/LLVMIR/func.mlir | 6 +
.../Target/LLVMIR/Import/frame-pointer.ll | 7 +
mlir/test/Target/LLVMIR/frame-pointer.mlir | 8 +
22 files changed, 325 insertions(+), 162 deletions(-)
create mode 100644 mlir/test/Target/LLVMIR/Import/frame-pointer.ll
create mode 100644 mlir/test/Target/LLVMIR/frame-pointer.mlir
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 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
! CHECK-NEXT: -fopenacc Enable OpenACC
! CHECK-NEXT: -fopenmp-assume-no-nested-parallelism
! CHECK-NEXT: Assert no nested parallel regions in the GPU
diff --git a/flang/test/Driver/driver-help.f90 b/flang/test/Driver/driver-help.f90
index ea9c892bd621058..a6c4012362c1e22 100644
--- a/flang/test/Driver/driver-help.f90
+++ b/flang/test/Driver/driver-help.f90
@@ -207,6 +207,7 @@
! HELP-FC1-NEXT: -fno-stack-arrays Allocate array temporaries on the heap (default)
! HELP-FC1-NEXT: -fno-version-loops-for-stride
! HELP-FC1-NEXT: Do not create unit-strided loops (default)
+! HELP-FC1-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
! HELP-FC1-NEXT: -fopenacc Enable OpenACC
! HELP-FC1-NEXT: -fopenmp-host-ir-file-path <value>
! HELP-FC1-NEXT: Path to the IR file produced by the frontend for the host.
@@ -233,6 +234,7 @@
! HELP-FC1-NEXT: -load <dsopath> Load the named plugin (dynamic shared object)
! HELP-FC1-NEXT: -menable-no-infs Allow optimization to assume there are no infinities.
! HELP-FC1-NEXT: -menable-no-nans Allow optimization to assume there are no NaNs.
+! HELP-FC1-NEXT: -mframe-pointer=<value> Specify which frame pointers to retain.
! HELP-FC1-NEXT: -mllvm <value> Additional arguments to forward to LLVM's option processing
! HELP-FC1-NEXT: -mmlir <value> Additional arguments to forward to MLIR's option processing
! HELP-FC1-NEXT: -module-dir <dir> Put MODULE files in <dir>
diff --git a/flang/test/Driver/frontend-forwarding.f90 b/flang/test/Driver/frontend-forwarding.f90
index 20455791c9ff4d6..8e9c9b78c3c10a4 100644
--- a/flang/test/Driver/frontend-forwarding.f90
+++ b/flang/test/Driver/frontend-forwarding.f90
@@ -14,6 +14,7 @@
! RUN: -fno-signed-zeros \
! RUN: -fassociative-math \
! RUN: -freciprocal-math \
+! RUN: -fomit-frame-pointer \
! RUN: -fpass-plugin=Bye%pluginext \
! RUN: -fversion-loops-for-stride \
! RUN: -flang-experimental-polymorphism \
@@ -60,5 +61,6 @@
! CHECK: "-Reverything"
! CHECK: "-Rno-everything"
! CHECK: "-Rpass=inline"
+! CHECK: "-mframe-pointer=none"
! CHECK: "-mllvm" "-print-before-all"
! CHECK: "-save-temps=obj"
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
index f05230526c21f55..446850d6dc7bb96 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
@@ -664,4 +664,23 @@ def ModRefInfoEnum : LLVM_EnumAttr<
let cppNamespace = "::mlir::LLVM";
}
+//===----------------------------------------------------------------------===//
+// FramePointerAttr
+//===----------------------------------------------------------------------===//
+
+def FramePointerKindNone
+ : LLVM_EnumAttrCase<"None", "none", "None", 0>;
+def FramePointerKindNonLeaf
+ : LLVM_EnumAttrCase<"NonLeaf", "non-leaf", "NonLeaf", 1>;
+def FramePointerKindAll
+ : LLVM_EnumAttrCase<"All", "all", "All", 2>;
+
+def FramePointerKindAttr : LLVM_EnumAttr<
+ "FramePointerKind",
+ "::llvm::FramePointerKind",
+ "LLVM FramePointerKind",
+ [FramePointerKindNone, FramePointerKindNonLeaf, FramePointerKindAll]> {
+ let cppNamespace = "::mlir::LLVM";
+}
+
#endif // LLVMIR_ENUMS
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 9fa6f23ce4de2dd..3feb20bc9faa4f2 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -1390,7 +1390,8 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [
OptionalAttr<StrAttr>:$section,
OptionalAttr<UnnamedAddr>:$unnamed_addr,
OptionalAttr<I64Attr>:$alignment,
- OptionalAttr<LLVM_VScaleRangeAttr>:$vscale_range
+ OptionalAttr<LLVM_VScaleRangeAttr>:$vscale_range,
+ OptionalAttr<FramePointerKindAttr>:$frame_pointer
);
let regions = (region AnyRegion:$body);
diff --git a/mlir/include/mlir/Dialect/Tensor/IR/TensorBase.td b/mlir/include/mlir/Dialect/Tensor/IR/TensorBase.td
index 1231c0a67bc305f..9d0add92737f3c6 100644
--- a/mlir/include/mlir/Dialect/Tensor/IR/TensorBase.td
+++ b/mlir/include/mlir/Dialect/Tensor/IR/TensorBase.td
@@ -18,31 +18,35 @@ def Tensor_Dialect : Dialect {
let description = [{
The `tensor` dialect is intended to hold core tensor creation and
manipulation ops, which are not strongly associated with any particular
- other dialect or domain abstraction. The primary smoke test of this is ops
- that make sense for any tensor element type.
-
- We leave it to other dialects to hold the vast swath of possible
- computations one might want to do on a tensor.
-
- The `tensor` type is (for better or for worse) used to represent all kinds
- of things, and supports an open-ended set of element types. Examples:
+ other dialect or domain abstraction. The aim for ops in this dialect is
+ that they make sense for any tensor element type. When this is not the
+ case, the op is left to live in other dialects. Examples of element types
+ that could be supported by the `tensor` dialect include:
- representing large, dense aggregations of primitive types, suitable for
high-performance numerical computing.
- - representing shapes in the `shape` dialect, which consist of small
- 1D tensors of `index` data type.
+ - representing shapes in the `shape` dialect, which consist of small 1D
+ tensors of `index` data type.
- representing aggregations of strings or “variant” types.
- - representing large, sparse aggregations of primitive types, suitable
- for high-performance numerical computing.
-
- Thus, for the `tensor` dialect, we prefer for now to constrain the
- scope as much as possible. The expectation is that at some point
- in the future, the `tensor` dialect’s scope may be broadened through a
- careful discussion of the tradeoffs.
-
- The `tensor` type is actually a builtin type (it lives in the builtin
- dialect), and does not live in this dialect.
+ - representing large, sparse aggregations of primitive types, suitable for
+ high-performance numerical computing.
+ Because of this broad element type support and because of the existence of
+ more dedicated dialects, such as the `sparse_tensor` and `linalg` dialects,
+ we prefer for now to keep the `tensor` dialect as small as possible. The
+ expectation is that at some point in the future, the `tensor` dialect’s
+ scope may be broadened through a careful discussion of the tradeoffs.
+
+ On the `tensor` type itself, note that it is actually a builtin type (it
+ lives in the builtin dialect), and does not live in this dialect.
+ Furthermore, a `tensor` is an immutable object. For example, this means
+ that a copy will always be made of the `tensor` object when it is passed to
+ the `dest` operand used by some ops in this dialect. As an optimization,
+ an implementation can eliminate these copies during lowering when they
+ are redundant and perform in-place mutation, see the [Destination-Passing
+ Style](
+ https://mlir.llvm.org/docs/Bufferization/#destination-passing-style)
+ documentation for more information.
}];
let hasCanonicalizer = 1;
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index f6c8f388732c3da..510d81e46cbb43a 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -2309,7 +2309,7 @@ ParseResult LLVMFuncOp::parse(OpAsmParser &parser, OperationState &result) {
IntegerAttr::get(intTy, minRange),
IntegerAttr::get(intTy, maxRange)));
}
- // Parse the optional comdat selector.
+ // Parse the optional comdat selector.:q
if (succeeded(parser.parseOptionalKeyword("comdat"))) {
SymbolRefAttr comdat;
if (parser.parseLParen() || parser.parseAttribute(comdat) ||
@@ -2319,6 +2319,23 @@ ParseResult LLVMFuncOp::parse(OpAsmParser &parser, OperationState &result) {
result.addAttribute(getComdatAttrName(result.name), comdat);
}
+ // Parse the optional frame_pointer
+ if (succeeded(parser.parseOptionalKeyword("frame_pointer"))) {
+ std::string string;
+
+ if (parser.parseEqual() || parser.parseString(&string))
+ return failure();
+ if (!LLVM::symbolizeFramePointerKind(string))
+ {
+ llvm::outs() << "failure: frame-pointer option not recognized: " << string << "\n";
+ return failure();
+ }
+
+ result.addAttribute(getFramePointerAttrName(result.name),
+ LLVM::FramePointerKindAttr::get(parser.getContext(),
+ LLVM::symbolizeFramePointerKind(string).value()));
+ }
+
if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
return failure();
function_interface_impl::addArgAndResultAttrs(
@@ -2373,13 +2390,17 @@ void LLVMFuncOp::print(OpAsmPrinter &p) {
// Print the optional comdat selector.
if (auto comdat = getComdat())
p << " comdat(" << *comdat << ')';
+
+ // Print the optional frame pointer option.
+ if (std::optional<FramePointerKind> frame_pointer = getFramePointer())
+ p << " frame_pointer=" << "\"" << stringifyFramePointerKind(frame_pointer.value()) << "\"";
function_interface_impl::printFunctionAttributes(
p, *this,
{getFunctionTypeAttrName(), getArgAttrsAttrName(), getResAttrsAttrName(),
getLinkageAttrName(), getCConvAttrName(), getVisibility_AttrName(),
getComdatAttrName(), getUnnamedAddrAttrName(),
- getVscaleRangeAttrName()});
+ getVscaleRangeAttrName(), getFramePointerAttrName()});
// Print the body if this is not an external function.
Region &body = getBody();
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index dd2da66caf428bf..e3b08ce4e868b7f 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -1602,7 +1602,9 @@ static void processPassthroughAttrs(llvm::Function *func, LLVMFuncOp funcOp) {
// explicit attribute.
// Also skip the vscale_range, it is also an explicit attribute.
if (attrName == "aarch64_pstate_sm_enabled" ||
- attrName == "aarch64_pstate_sm_body" || attrName == "vscale_range")
+ attrName == "aarch64_pstate_sm_body" ||
+ attrName == "vscale_range" ||
+ attrName == "frame-pointer")
continue;
if (attr.isStringAttribute()) {
@@ -1650,6 +1652,13 @@ void ModuleImport::processFunctionAttributes(llvm::Function *func,
context, IntegerAttr::get(intTy, attr.getVScaleRangeMin()),
IntegerAttr::get(intTy, attr.getVScaleRangeMax().value_or(0))));
}
+
+ // Process frame-pointer attribute
+ if (func->hasFnAttribute("frame-pointer")) {
+ llvm::StringRef stringRefFramePointerKind = func->getFnAttribute("frame-pointer").getValueAsString();
+ funcOp.setFramePointerAttr(LLVM::FramePointerKindAttr::get(funcOp.getContext(),
+ symbolizeFramePointerKind(stringRefFramePointerKind).value()));
+ }
}
DictionaryAttr
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 388ae61958b78b9..d97d4a1b1e50b2d 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -894,6 +894,10 @@ LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
llvmFunc->addFnAttr(llvm::Attribute::getWithVScaleRangeArgs(
getLLVMContext(), attr->getMinRange().getInt(),
attr->getMaxRange().getInt()));
+
+ // Add function attribute frame-pointer, if found.
+ if (auto attr = func.getFramePointerAttr())
+ llvmFunc->addFnAttr("frame-pointer", stringifyFramePointerKind(attr.getValue()));
// First, create all blocks so we can jump to them.
llvm::LLVMContext &llvmContext = llvmFunc->getContext();
diff --git a/mlir/test/Dialect/LLVMIR/func.mlir b/mlir/test/Dialect/LLVMIR/func.mlir
index 63e20b1d8fc31ab..9e68a3dff4bca85 100644
--- a/mlir/test/Dialect/LLVMIR/func.mlir
+++ b/mlir/test/Dialect/LLVMIR/func.mlir
@@ -249,6 +249,12 @@ module {
// CHECK-SAME: vscale_range(1, 2)
llvm.return
}
+
+ llvm.func @frame_pointer_roundtrip() frame_pointer="non-leaf" {
+ // CHECK: @frame_pointer_roundtrip()
+ // CHECK-SAME: frame_pointer="non-leaf"
+ llvm.return
+ }
}
// -----
diff --git a/mlir/test/Target/LLVMIR/Import/frame-pointer.ll b/mlir/test/Target/LLVMIR/Import/frame-pointer.ll
new file mode 100644
index 000000000000000..698771f4ae04c3e
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/frame-pointer.ll
@@ -0,0 +1,7 @@
+; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
+
+define void @frame_pointer_func() "frame-pointer"="non-leaf" {
+ ; CHECK: llvm.func @frame_pointer_func()
+ ; CHECK-SAME: frame_pointer="non-leaf"
+ ret void
+}
diff --git a/mlir/test/Target/LLVMIR/frame-pointer.mlir b/mlir/test/Target/LLVMIR/frame-pointer.mlir
new file mode 100644
index 000000000000000..543b6b1af1761b8
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/frame-pointer.mlir
@@ -0,0 +1,8 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+llvm.func @frame_pointer_func() frame_pointer="non-leaf" {
+ // CHECK-LABEL: define void @frame_pointer_func
+ // CHECK: attributes #{{.*}} = { "frame-pointer"="non-leaf" }
+ llvm.return
+}
+
More information about the flang-commits
mailing list