[flang-commits] [clang] [flang] [flang][Driver] Add support for -f[no]keep-inline-functions option (PR #230007)
via flang-commits
flang-commits at lists.llvm.org
Thu Oct 8 00:11:14 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-driver
Author: shivaramaarao
<details>
<summary>Changes</summary>
Treat definitions marked alwaysinline (!dir$ inlinealways) as the functions inlined, and keep those definitions after they are inlined into every caller.
added a testcase to validate this option
Assisted by Cursor to generate the testcase.
addresses the issue #<!-- -->223359
---
Full diff: https://github.com/llvm/llvm-project/pull/230007.diff
6 Files Affected:
- (modified) clang/include/clang/Options/Options.td (+2-2)
- (modified) clang/lib/Driver/ToolChains/Flang.cpp (+2)
- (modified) flang/include/flang/Frontend/CodeGenOptions.def (+1)
- (modified) flang/lib/Frontend/CompilerInvocation.cpp (+4)
- (modified) flang/lib/Frontend/FrontendActions.cpp (+22)
- (added) flang/test/Driver/inline-functions.f90 (+50)
``````````diff
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 56194af32f68f..72a0a0ee05c95 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2598,8 +2598,8 @@ defm keep_persistent_storage_variables : BoolFOption<"keep-persistent-storage-va
" keeping all variables that have a persistent storage duration, including global, static and thread-local variables, to guarantee that they can be directly addressed">>;
defm keep_inline_functions : BoolFOption<"keep-inline-functions",
CodeGenOpts<"KeepInlineFunctions">, DefaultFalse,
- PosFlag<SetTrue, [], [ClangOption, CC1Option], "Keep">,
- NegFlag<SetFalse, [], [ClangOption], "Don't keep">,
+ PosFlag<SetTrue, [], [ClangOption, CC1Option, FlangOption, FC1Option], "Keep">,
+ NegFlag<SetFalse, [], [ClangOption, FlangOption], "Don't keep">,
BothFlags<[], [],
" inline functions whose definition is owned by this translation unit, even if they are inlined into all callers.">>;
defm fixed_point : BoolFOption<"fixed-point",
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 0e6858d3bb645..4f64b3ba050c1 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -355,6 +355,8 @@ void Flang::addCodegenOptions(const ArgList &Args,
Args.addOptInFlag(CmdArgs, options::OPT_fexperimental_loop_fusion,
options::OPT_fno_experimental_loop_fusion);
+ Args.addOptInFlag(CmdArgs, options::OPT_fkeep_inline_functions,
+ options::OPT_fno_keep_inline_functions);
Args.AddLastArg(CmdArgs, options::OPT_ffp_sum_reassociation,
options::OPT_fno_fp_sum_reassociation);
diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def
index d49a7f3647eec..4cc8cbd008d8a 100644
--- a/flang/include/flang/Frontend/CodeGenOptions.def
+++ b/flang/include/flang/Frontend/CodeGenOptions.def
@@ -30,6 +30,7 @@ ENUM_CODEGENOPT(ProfileInstr, llvm::driver::ProfileInstrKind, 2, llvm::driver::P
/// Choose profile kind for PGO use compilation.
ENUM_CODEGENOPT(ProfileUse, llvm::driver::ProfileInstrKind, 2, llvm::driver::ProfileInstrKind::ProfileNone)
+CODEGENOPT(KeepInlineFunctions, 1, 0) ///< -fkeep-inline-functions.
CODEGENOPT(InstrumentFunctions, 1, 0) ///< Set when -finstrument_functions is
///< enabled on the compile step.
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index b76b38ff6497f..9e5d805f4ca68 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -380,6 +380,10 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
if (args.hasArg(clang::options::OPT_finstrument_functions))
opts.InstrumentFunctions = 1;
+ // -fkeep-inline-functions. The driver forwards only the positive flag.
+ opts.KeepInlineFunctions =
+ args.hasArg(clang::options::OPT_fkeep_inline_functions);
+
// -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/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 35c2b9ec881e8..9f947f9f93a89 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -1103,6 +1103,28 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
return;
}
+ // -fkeep-inline-functions: retain definitions of inline functions (those
+ // marked alwaysinline) after they have been inlined into every caller.
+ // On ELF this uses llvm.compiler.used so the compiler keeps the definition
+ // but the linker may still drop it. Other object formats use llvm.used.
+ // This is matching Clang functionality.
+ if (opts.KeepInlineFunctions) {
+ llvm::SmallVector<llvm::GlobalValue *, 8> kept;
+ for (llvm::Function &func : *llvmModule) {
+ if (func.isDeclaration() || func.hasAvailableExternallyLinkage())
+ continue;
+ if (!func.hasFnAttribute(llvm::Attribute::AlwaysInline))
+ continue;
+ kept.push_back(&func);
+ }
+ if (!kept.empty()) {
+ if (triple.isOSBinFormatELF())
+ llvm::appendToCompilerUsed(*llvmModule, kept);
+ else
+ llvm::appendToUsed(*llvmModule, kept);
+ }
+ }
+
// Run the passes.
mpm.run(*llvmModule, mam);
diff --git a/flang/test/Driver/inline-functions.f90 b/flang/test/Driver/inline-functions.f90
new file mode 100644
index 0000000000000..1d76c555943bc
--- /dev/null
+++ b/flang/test/Driver/inline-functions.f90
@@ -0,0 +1,50 @@
+! RUN: %flang -### -fkeep-inline-functions %s 2>&1 | FileCheck %s --check-prefix=DRIVER-KEEP
+! RUN: %flang -### -fno-keep-inline-functions %s 2>&1 | FileCheck %s --check-prefix=DRIVER-NOKEEP
+! RUN: %flang -### -fkeep-inline-functions -fno-keep-inline-functions %s 2>&1 | FileCheck %s --check-prefix=DRIVER-NOKEEP
+! RUN: %flang -### -fno-keep-inline-functions -fkeep-inline-functions %s 2>&1 | FileCheck %s --check-prefix=DRIVER-KEEP
+
+! DRIVER-KEEP: "-fc1"
+! DRIVER-KEEP-SAME: "-fkeep-inline-functions"
+! DRIVER-NOKEEP: "-fc1"
+! DRIVER-NOKEEP-NOT: "-fkeep-inline-functions"
+! DRIVER-NOKEEP-NOT: "-fno-keep-inline-functions"
+
+! Without the flag, an alwaysinline contained procedure is inlined and deleted.
+! RUN: %flang_fc1 -emit-llvm -O2 -o - %s | FileCheck %s --check-prefix=DEFAULT
+! -fkeep-inline-functions retains that definition, matching Clang's retention
+! of inline functions owned by this translation unit.
+! RUN: %flang_fc1 -emit-llvm -O2 -fkeep-inline-functions -o - %s | FileCheck %s --check-prefix=KEEP
+
+subroutine test_always(n)
+ integer :: n
+ n = add_two(n)
+contains
+ integer function add_two(n)
+ !dir$ inlinealways add_two
+ integer :: n
+ add_two = n + 2
+ end function
+end subroutine
+
+subroutine test_plain(n)
+ integer :: n
+ n = add_one(n)
+contains
+ integer function add_one(n)
+ integer :: n
+ add_one = n + 1
+ end function
+end subroutine
+
+! DEFAULT-LABEL: define void @test_always_(
+! DEFAULT-NOT: @_QFtest_alwaysPadd_two(
+! DEFAULT-NOT: define {{.*}}@_QFtest_alwaysPadd_two(
+
+! KEEP: @llvm.{{(compiler.)?}}used = {{.*}}@_QFtest_alwaysPadd_two
+! KEEP-LABEL: define void @test_always_(
+! KEEP-NOT: call {{.*}}@_QFtest_alwaysPadd_two(
+! KEEP: define internal {{.*}}@_QFtest_alwaysPadd_two(
+! A contained procedure that is not marked inline is still deleted.
+! KEEP-LABEL: define void @test_plain_(
+! KEEP-NOT: @_QFtest_plainPadd_one(
+! KEEP-NOT: define {{.*}}@_QFtest_plainPadd_one(
``````````
</details>
https://github.com/llvm/llvm-project/pull/230007
More information about the flang-commits
mailing list