Author: Kaviya Rajendiran
Date: 2026-09-17T14:07:46+05:30
New Revision: 9a3d449079fc97194c1aadcd9c8c999da6fe0a69

URL: 
https://github.com/llvm/llvm-project/commit/9a3d449079fc97194c1aadcd9c8c999da6fe0a69
DIFF: 
https://github.com/llvm/llvm-project/commit/9a3d449079fc97194c1aadcd9c8c999da6fe0a69.diff

LOG: [Flang][Driver]Implemented the support for option 
-f[no-]optimize-sibling-calls in Flang (#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.

Added: 
    flang/test/Driver/fno-optimize-sibling-calls.f90
    flang/test/Transforms/function-attr-disable-tail-calls.fir
    mlir/test/Target/LLVMIR/Import/disable-tail-calls.ll
    mlir/test/Target/LLVMIR/disable-tail-calls.mlir

Modified: 
    clang/include/clang/Options/Options.td
    clang/lib/Driver/ToolChains/Flang.cpp
    flang/include/flang/Frontend/CodeGenOptions.def
    flang/include/flang/Optimizer/Transforms/Passes.td
    flang/include/flang/Tools/CrossToolHelpers.h
    flang/lib/Frontend/CompilerInvocation.cpp
    flang/lib/Optimizer/Passes/Pipelines.cpp
    flang/lib/Optimizer/Transforms/FunctionAttr.cpp
    mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
    mlir/lib/Target/LLVMIR/ModuleImport.cpp
    mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
    mlir/test/Target/LLVMIR/Import/import-failure.ll

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 06461acdf216e..c4c49df73c15a 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4395,11 +4395,12 @@ def fopenmp_new_driver : Flag<["-"], 
"fopenmp-new-driver">,
   Flags<[HelpHidden]>, Alias<offload_new_driver>;
 def fno_openmp_new_driver : Flag<["-"], "fno-openmp-new-driver">,
   Flags<[HelpHidden]>, Alias<no_offload_new_driver>;
-def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, 
Group<f_Group>,
-  Visibility<[ClangOption, CC1Option]>,
+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>;
+def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">,
+  Group<f_Group>, Visibility<[ClangOption, FlangOption]>;
 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 dc1dd71526511..95a11eb36be08 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -385,6 +385,9 @@ void Flang::addCodegenOptions(const ArgList &Args,
        options::OPT_funroll_loops, options::OPT_fno_unroll_loops,
        options::OPT_relaxed_c_loc});
 
+  Args.addOptOutFlag(CmdArgs, options::OPT_foptimize_sibling_calls,
+                     options::OPT_fno_optimize_sibling_calls);
+
   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..a036311829e28 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 d7e271e1ed7b3..be2cbe31811e8 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -523,6 +523,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 6c980c32c08c2..692b7fd7129f2 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;
@@ -178,6 +179,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 9d333d473cb7c..85e5f477dcb8c 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -380,6 +380,9 @@ static void 
parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
   if (args.hasArg(clang::options::OPT_finstrument_functions))
     opts.InstrumentFunctions = 1;
 
+  if (args.hasArg(clang::options::OPT_fno_optimize_sibling_calls))
+    opts.DisableTailCalls = 1;
+
   // -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 2b8c0fa7f2e8f..b73a1ce4a47c6 100644
--- a/flang/lib/Optimizer/Passes/Pipelines.cpp
+++ b/flang/lib/Optimizer/Passes/Pipelines.cpp
@@ -464,7 +464,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..6603e59c57875
--- /dev/null
+++ b/flang/test/Driver/fno-optimize-sibling-calls.f90
@@ -0,0 +1,11 @@
+! Test -f[no-]optimize-sibling-calls driver forwarding to flang -fc1.
+
+! RUN: %flang -### %s 2>&1 | FileCheck %s --check-prefixes=FC1,OPTIMIZE-SIBLING
+! RUN: %flang -### -foptimize-sibling-calls %s 2>&1 | FileCheck %s 
--check-prefixes=FC1,OPTIMIZE-SIBLING
+! RUN: %flang -### -fno-optimize-sibling-calls %s 2>&1 | FileCheck %s 
--check-prefixes=FC1,NO-OPTIMIZE-SIBLING
+! RUN: %flang -### -fno-optimize-sibling-calls -foptimize-sibling-calls %s 
2>&1 | FileCheck %s --check-prefixes=FC1,OPTIMIZE-SIBLING
+! RUN: %flang -### -foptimize-sibling-calls -fno-optimize-sibling-calls %s 
2>&1 | FileCheck %s --check-prefixes=FC1,NO-OPTIMIZE-SIBLING
+
+! FC1: "-fc1"
+! OPTIMIZE-SIBLING-NOT: "-fno-optimize-sibling-calls"
+! NO-OPTIMIZE-SIBLING-SAME: "-fno-optimize-sibling-calls"

diff  --git a/flang/test/Transforms/function-attr-disable-tail-calls.fir 
b/flang/test/Transforms/function-attr-disable-tail-calls.fir
new file mode 100644
index 0000000000000..d8657a1294d30
--- /dev/null
+++ b/flang/test/Transforms/function-attr-disable-tail-calls.fir
@@ -0,0 +1,11 @@
+// RUN: fir-opt --function-attr="disable-tail-calls=true" %s | FileCheck %s 
--check-prefix=ENABLED
+// RUN: fir-opt --function-attr="disable-tail-calls=false" %s | FileCheck %s 
--check-prefix=DISABLED
+
+func.func @_QPf() {
+  return
+}
+
+// ENABLED: func.func @_QPf() attributes {llvm.disable_tail_calls = true} 
+
+// DISABLED: func.func @_QPf() 
+// DISABLED-NOT: llvm.disable_tail_calls

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td 
b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index edd52db2a4a5b..5998bd01f9bdf 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -2159,7 +2159,8 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [
     OptionalAttr<I32Attr>:$intel_reqd_sub_group_size,
     OptionalAttr<LLVM_FunctionMetadataArrayAttr>:$function_metadata,
     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 fa40b51c22f05..bfecde8b664a9 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -2903,6 +2903,7 @@ static constexpr std::array kExplicitLLVMFuncOpAttributes{
     StringLiteral("alwaysinline"),
     StringLiteral("cold"),
     StringLiteral("convergent"),
+    StringLiteral("disable-tail-calls"),
     StringLiteral("fp-contract"),
     StringLiteral("frame-pointer"),
     StringLiteral("hot"),
@@ -3093,6 +3094,16 @@ 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()) {
+    StringRef val = attr.getValueAsString();
+    if (val == "true")
+      funcOp.setDisableTailCalls(true);
+    else if (val != "false")
+      emitError(funcOp.getLoc())
+          << "unknown value '" << val << "' for 'disable-tail-calls' 
attribute";
+  }
+
   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 ee088aefcb2c4..50365b5a5b3a1 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1742,6 +1742,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..33822291e1c45
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/disable-tail-calls.ll
@@ -0,0 +1,16 @@
+; RUN: mlir-translate -import-llvm -split-input-file %s 2>&1 | FileCheck %s
+
+; CHECK-LABEL: llvm.func @disable_tail_calls()
+; CHECK-SAME: disable_tail_calls = true
+define void @disable_tail_calls() #0 {
+  ret void
+}
+
+; CHECK-LABEL: llvm.func @disable_tail_calls_false()
+; CHECK-NOT: disable_tail_calls
+define void @disable_tail_calls_false() #1 {
+  ret void
+}
+
+attributes #0 = { "disable-tail-calls"="true" }
+attributes #1 = { "disable-tail-calls"="false" }

diff  --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll 
b/mlir/test/Target/LLVMIR/Import/import-failure.ll
index 9015eff87a8c7..5bf45ccfbec55 100644
--- a/mlir/test/Target/LLVMIR/Import/import-failure.ll
+++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll
@@ -567,3 +567,10 @@ define i32 @metadata_ref_global_dtors() {
 !9 = !{!"DetailedSummary", !10}
 !10 = !{!11}
 !11 = !{i32 10000, i64 1, i32 1}
+
+; CHECK: error: unknown value 'invalid' for 'disable-tail-calls' attribute
+define void @disable_tail_calls_invalid() #0 {
+  ret void
+}
+
+attributes #0 = { "disable-tail-calls"="invalid" }

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..fc7ecd185b492
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/disable-tail-calls.mlir
@@ -0,0 +1,14 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+// CHECK: define void @disable_tail_calls() #[[ATTRS_TRUE:.*]] {
+llvm.func @disable_tail_calls() attributes {disable_tail_calls = true} {
+  llvm.return
+}
+
+// CHECK: define void @disable_tail_calls_false() #[[ATTRS_FALSE:.*]] {
+llvm.func @disable_tail_calls_false() attributes {disable_tail_calls = false} {
+  llvm.return
+}
+
+// CHECK: attributes #[[ATTRS_TRUE]] = { "disable-tail-calls"="true" }
+// CHECK: attributes #[[ATTRS_FALSE]] = { "disable-tail-calls"="false" }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to