https://github.com/kaviya2510 created https://github.com/llvm/llvm-project/pull/216650
Added support for -foptimize-sibling-calls and -fno-optimize-sibling-calls in Flang. - Sibling call optimization is on by default and the driver pass the option `-f[no-]optimize-sibling-calls` to flang -fc1. - When `-fno-optimize-sibling-calls` flag is passed, it sets boolen `DisableTailCalls` and this results in adding the LLVM IR attribute `"disable-tail-calls"="true"` which disables sibling call optimization. >From 45f4e1ca6b316f6c8bc138c0fbd0ad37e7a87034 Mon Sep 17 00:00:00 2001 From: Kaviya Rajendiran <[email protected]> Date: Mon, 17 Aug 2026 12:09:01 +0530 Subject: [PATCH] [Flang][Driver]Implemented the support for option -f[no-]optimize-sibling-calls in Flang --- clang/include/clang/Options/Options.td | 14 ++++++++----- clang/lib/Driver/ToolChains/Flang.cpp | 4 ++++ .../include/flang/Frontend/CodeGenOptions.def | 1 + .../flang/Optimizer/Transforms/Passes.td | 4 ++++ flang/include/flang/Tools/CrossToolHelpers.h | 2 ++ flang/lib/Frontend/CompilerInvocation.cpp | 6 ++++++ flang/lib/Optimizer/Passes/Pipelines.cpp | 3 ++- .../lib/Optimizer/Transforms/FunctionAttr.cpp | 7 +++++++ .../Driver/fno-optimize-sibling-calls.f90 | 20 +++++++++++++++++++ flang/test/Integration/disable-tail-calls.f90 | 12 +++++++++++ mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 3 ++- mlir/lib/Target/LLVMIR/ModuleImport.cpp | 5 +++++ mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 4 ++++ .../LLVMIR/Import/disable-tail-calls.ll | 9 +++++++++ .../Target/LLVMIR/disable-tail-calls.mlir | 7 +++++++ 15 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 flang/test/Driver/fno-optimize-sibling-calls.f90 create mode 100644 flang/test/Integration/disable-tail-calls.f90 create mode 100644 mlir/test/Target/LLVMIR/Import/disable-tail-calls.ll create mode 100644 mlir/test/Target/LLVMIR/disable-tail-calls.mlir diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index adc4224dd561c..71504c806d886 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -4342,11 +4342,15 @@ def fopenmp_new_driver : Flag<["-"], "fopenmp-new-driver">, Flags<[HelpHidden]>, def fno_openmp_new_driver : Flag<["-"], "fno-openmp-new-driver">, Flags<[HelpHidden]>, HelpText<"Don't use the new driver for OpenMP offloading.">; -def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>, - Visibility<[ClangOption, CC1Option]>, - HelpText<"Disable tail call optimization, keeping the call stack accurate">, - MarshallingInfoFlag<CodeGenOpts<"DisableTailCalls">>; -def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>; +def fno_optimize_sibling_calls + : Flag<["-"], "fno-optimize-sibling-calls">, + Group<f_Group>, + Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, + HelpText< + "Disable tail call optimization, keeping the call stack accurate">, + MarshallingInfoFlag<CodeGenOpts<"DisableTailCalls">>; +def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, + Group<f_Group>, Visibility<[ClangOption, FlangOption, FC1Option]>; defm escaping_block_tail_calls : BoolFOption<"escaping-block-tail-calls", CodeGenOpts<"NoEscapingBlockTailCalls">, DefaultFalse, NegFlag<SetTrue, [], [ClangOption, CC1Option]>, diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index a48e41159f367..0c74f2b8365db 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -367,6 +367,10 @@ void Flang::addCodegenOptions(const ArgList &Args, options::OPT_funroll_loops, options::OPT_fno_unroll_loops, options::OPT_relaxed_c_loc}); + if (Arg *A = Args.getLastArg(options::OPT_foptimize_sibling_calls, + options::OPT_fno_optimize_sibling_calls)) + A->render(Args, CmdArgs); + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); addSeparateSectionFlags(Triple, Args, CmdArgs); diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def index d49a7f3647eec..537a54f917d16 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.def +++ b/flang/include/flang/Frontend/CodeGenOptions.def @@ -32,6 +32,7 @@ ENUM_CODEGENOPT(ProfileUse, llvm::driver::ProfileInstrKind, 2, llvm::driver::Pro CODEGENOPT(InstrumentFunctions, 1, 0) ///< Set when -finstrument_functions is ///< enabled on the compile step. +CODEGENOPT(DisableTailCalls , 1, 0) ///< Do not emit tail calls CODEGENOPT(DisableIntegratedAS, 1, 0) ///< -no-integrated-as diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td index e7bb8ae9bb9bf..e770144dfc69e 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.td +++ b/flang/include/flang/Optimizer/Transforms/Passes.td @@ -489,6 +489,10 @@ def FunctionAttr : Pass<"function-attr", "mlir::func::FuncOp"> { /*default=*/"false", "Set the use-sample-profile attribute on functions in the " "module.">, + Option<"disableTailCalls", "disable-tail-calls", "bool", + /*default=*/"false", + "Set the disable-tail-calls attribute on functions to prevent " + "tail call optimization.">, Option<"tuneCPU", "tune-cpu", "std::string", /*default=*/"", "Set the tune-cpu attribute on functions in the module.">, Option<"setNoCapture", "set-nocapture", "bool", /*default=*/"false", diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h index fb8007637b114..3b49354a8ff96 100644 --- a/flang/include/flang/Tools/CrossToolHelpers.h +++ b/flang/include/flang/Tools/CrossToolHelpers.h @@ -143,6 +143,7 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks { InstrumentFunctionEntry = "__cyg_profile_func_enter"; InstrumentFunctionExit = "__cyg_profile_func_exit"; } + DisableTailCalls = opts.DisableTailCalls; DwarfVersion = opts.DwarfVersion; SplitDwarfFile = opts.SplitDwarfFile; DwarfDebugFlags = opts.DwarfDebugFlags; @@ -177,6 +178,7 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks { false; ///< Compiling for an OpenMP target device. bool UseSampleProfile = false; ///< Enable sample based profiling bool DebugInfoForProfiling = false; ///< Enable extra debugging info + bool DisableTailCalls = false; ///< Disable tail call optimization bool EnableOpenMPSimd = false; ///< Enable OpenMP simd-only mode. bool SkipConvertComplexPow = false; ///< Do not run complex pow conversion. std::string InstrumentFunctionEntry = diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index b57bc4583be38..b20ecc3000cfd 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -376,6 +376,12 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, if (args.hasArg(clang::options::OPT_finstrument_functions)) opts.InstrumentFunctions = 1; + if (const llvm::opt::Arg *a = args.getLastArg( + clang::options::OPT_foptimize_sibling_calls, + clang::options::OPT_fno_optimize_sibling_calls)) + opts.DisableTailCalls = + a->getOption().matches(clang::options::OPT_fno_optimize_sibling_calls); + // -fno-integrated-as: emit GNU Assembler compatible assembly. if (!args.hasFlag(clang::options::OPT_fintegrated_as, clang::options::OPT_fno_integrated_as, true)) diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp index 15a342e10fc7f..98b7574d0849a 100644 --- a/flang/lib/Optimizer/Passes/Pipelines.cpp +++ b/flang/lib/Optimizer/Passes/Pipelines.cpp @@ -441,7 +441,8 @@ void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm, config.InstrumentFunctionExit, config.NoInfsFPMath, config.NoNaNsFPMath, config.ApproxFuncFPMath, config.NoSignedZerosFPMath, config.UnsafeFPMath, config.Reciprocals, config.PreferVectorWidth, config.UseSampleProfile, - /*tuneCPU=*/"", setNoCapture, setNoAlias, setReadOnly})); + config.DisableTailCalls, /*tuneCPU=*/"", setNoCapture, setNoAlias, + setReadOnly})); if (config.EnableOpenMP) { pm.addNestedPass<mlir::func::FuncOp>( diff --git a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp index 45b32d13ad62e..1aadd16fe1cf4 100644 --- a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp +++ b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp @@ -145,5 +145,12 @@ void FunctionAttrPass::runOnOperation() { llvmFuncOpName)), mlir::BoolAttr::get(context, true)); + if (disableTailCalls) + func->setAttr( + getLlvmFuncPropertyAttrName( + context, mlir::LLVM::LLVMFuncOp::getDisableTailCallsAttrName( + llvmFuncOpName)), + mlir::BoolAttr::get(context, true)); + LLVM_DEBUG(llvm::dbgs() << "=== End " DEBUG_TYPE " ===\n"); } diff --git a/flang/test/Driver/fno-optimize-sibling-calls.f90 b/flang/test/Driver/fno-optimize-sibling-calls.f90 new file mode 100644 index 0000000000000..163803fdff759 --- /dev/null +++ b/flang/test/Driver/fno-optimize-sibling-calls.f90 @@ -0,0 +1,20 @@ +! Test -f[no-]optimize-sibling-calls driver forwarding to flang -fc1. + +! RUN: %flang -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-OPTIMIZE-SIBLING +! RUN: %flang -### -foptimize-sibling-calls %s 2>&1 | FileCheck %s --check-prefix=CHECK-OPTIMIZE-SIBLING-FORWARD +! RUN: %flang -### -fno-optimize-sibling-calls %s 2>&1 | FileCheck %s --check-prefix=CHECK-OPTIMIZE-NOSIBLING +! RUN: %flang -### -fno-optimize-sibling-calls -foptimize-sibling-calls %s 2>&1 | FileCheck %s --check-prefix=CHECK-OPTIMIZE-SIBLING-FORWARD +! RUN: %flang -### -foptimize-sibling-calls -fno-optimize-sibling-calls %s 2>&1 | FileCheck %s --check-prefix=CHECK-OPTIMIZE-NOSIBLING + +! CHECK-OPTIMIZE-SIBLING: "-fc1" +! CHECK-OPTIMIZE-SIBLING-NOT: "-fno-optimize-sibling-calls" +! CHECK-OPTIMIZE-SIBLING-NOT: "-foptimize-sibling-calls" + +! CHECK-OPTIMIZE-SIBLING-FORWARD: "-fc1"{{.*}}"-foptimize-sibling-calls" +! CHECK-OPTIMIZE-SIBLING-FORWARD-NOT: "-fno-optimize-sibling-calls" + +! CHECK-OPTIMIZE-NOSIBLING: "-fc1"{{.*}}"-fno-optimize-sibling-calls" +! CHECK-OPTIMIZE-NOSIBLING-NOT: "-foptimize-sibling-calls" + +subroutine test +end subroutine test diff --git a/flang/test/Integration/disable-tail-calls.f90 b/flang/test/Integration/disable-tail-calls.f90 new file mode 100644 index 0000000000000..117512bc7739c --- /dev/null +++ b/flang/test/Integration/disable-tail-calls.f90 @@ -0,0 +1,12 @@ +! test -fno-optimize-sibling-calls flag disables tail call optimization + +! RUN: %flang_fc1 -emit-llvm -O2 -fno-optimize-sibling-calls -o - %s | FileCheck %s + +recursive subroutine f(n) + integer, intent(in) :: n + if (n > 0) call f(n - 1) +end subroutine f + +! CHECK: define void @f_{{.*}}#[[ATTRS:[0-9]+]] +! CHECK: call void @f_ +! CHECK: attributes #[[ATTRS]]{{.*}}"disable-tail-calls"="true" diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index e670e6699e57d..e578d5c22d36c 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -2106,7 +2106,8 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [ OptionalAttr<DenseI32ArrayAttr>:$reqd_work_group_size, OptionalAttr<I32Attr>:$intel_reqd_sub_group_size, OptionalAttr<UWTableKindAttr>:$uwtable_kind, - OptionalAttr<BoolAttr>:$use_sample_profile + OptionalAttr<BoolAttr>:$use_sample_profile, + OptionalAttr<BoolAttr>:$disable_tail_calls ); let regions = (region AnyRegion:$body); diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp index 2ab4529ddef53..d061397d38edc 100644 --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -2833,6 +2833,7 @@ static constexpr std::array kExplicitLLVMFuncOpAttributes{ StringLiteral("alwaysinline"), StringLiteral("cold"), StringLiteral("convergent"), + StringLiteral("disable-tail-calls"), StringLiteral("fp-contract"), StringLiteral("frame-pointer"), StringLiteral("hot"), @@ -3020,6 +3021,10 @@ void ModuleImport::processFunctionAttributes(llvm::Function *func, if (func->hasFnAttribute("use-sample-profile")) funcOp.setUseSampleProfile(true); + if (llvm::Attribute attr = func->getFnAttribute("disable-tail-calls"); + attr.isStringAttribute()) + funcOp.setDisableTailCalls(attr.getValueAsString() == "true"); + if (llvm::Attribute attr = func->getFnAttribute("target-cpu"); attr.isStringAttribute()) funcOp.setTargetCpuAttr(StringAttr::get(context, attr.getValueAsString())); diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index b87a581a5185e..c5fd545bbbaae 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -1706,6 +1706,10 @@ LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) { if (func.getUseSampleProfile()) llvmFunc->addFnAttr("use-sample-profile"); + if (auto disableTailCalls = func.getDisableTailCalls()) + llvmFunc->addFnAttr("disable-tail-calls", + llvm::toStringRef(*disableTailCalls)); + if (auto attr = func.getVscaleRange()) llvmFunc->addFnAttr(llvm::Attribute::getWithVScaleRangeArgs( getLLVMContext(), attr->getMinRange().getInt(), diff --git a/mlir/test/Target/LLVMIR/Import/disable-tail-calls.ll b/mlir/test/Target/LLVMIR/Import/disable-tail-calls.ll new file mode 100644 index 0000000000000..3b1b894532d99 --- /dev/null +++ b/mlir/test/Target/LLVMIR/Import/disable-tail-calls.ll @@ -0,0 +1,9 @@ +; RUN: mlir-translate -import-llvm %s | FileCheck %s + +; CHECK-LABEL: llvm.func @disable_tail_calls() +; CHECK-SAME: disable_tail_calls = true +define void @disable_tail_calls() #0 { + ret void +} + +attributes #0 = { "disable-tail-calls"="true" } diff --git a/mlir/test/Target/LLVMIR/disable-tail-calls.mlir b/mlir/test/Target/LLVMIR/disable-tail-calls.mlir new file mode 100644 index 0000000000000..c28f248443c42 --- /dev/null +++ b/mlir/test/Target/LLVMIR/disable-tail-calls.mlir @@ -0,0 +1,7 @@ +// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s + +// CHECK: define void @disable_tail_calls() #[[ATTRS:.*]] { +// CHECK: attributes #[[ATTRS]] = { "disable-tail-calls"="true" } +llvm.func @disable_tail_calls() attributes {disable_tail_calls = true} { + llvm.return +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
