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 <git...@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 <m...@m-sp.org> Co-authored-by: Mehdi Amini <joker....@gmail.com> Co-authored-by: Felix Schneider <fx.s...@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 +} + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits