https://github.com/xgupta updated https://github.com/llvm/llvm-project/pull/223315
>From 947084c95b9e1f0b0e7713760525a48309c1c59d Mon Sep 17 00:00:00 2001 From: Shivam Gupta <[email protected]> Date: Wed, 2 Sep 2026 08:35:24 +0530 Subject: [PATCH 1/3] [Clang] Add -fno-inline-functions-called-once GCC provides -fno-inline-functions-called-once to inhibit inlining of TU-local functions that are called exactly once. Clang currently accepts the corresponding option only as an ignored GCC optimization flag. This patch makes the option a real Clang driver option and forwards it to LLVM as -mllvm -no-inline-functions-called-once. The LLVM inliner disables the special bonus normally applied to internal functions with a single call site and assigns the call a prohibitively high cost, preventing it from being inlined. As alternative one can use __attribute__((noinline)) but that requires application changes and not feasible for large codebases. Rework of #160343. --- clang/include/clang/Options/Options.td | 5 +++- clang/lib/Driver/ToolChains/Clang.cpp | 8 ++++++ .../no-inline-functions-called-once.cpp | 27 +++++++++++++++++++ clang/test/Driver/clang_f_opts.c | 3 --- .../Driver/no-inline-functions-called-once.c | 13 +++++++++ llvm/lib/Analysis/InlineCost.cpp | 17 ++++++++++-- 6 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 clang/test/CodeGen/no-inline-functions-called-once.cpp create mode 100644 clang/test/Driver/no-inline-functions-called-once.c diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 3b88dce9c822b..34f63855e9dc4 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -7694,7 +7694,10 @@ defm modulo_sched : BooleanFFlag<"modulo-sched">, Group<clang_ignored_gcc_optimi defm modulo_sched_allow_regmoves : BooleanFFlag<"modulo-sched-allow-regmoves">, Group<clang_ignored_gcc_optimization_f_Group>; defm inline_functions_called_once : BooleanFFlag<"inline-functions-called-once">, - Group<clang_ignored_gcc_optimization_f_Group>; + Group<f_Group>, + Visibility<[ClangOption]>, + HelpText<"Control inlining of TU-local functions called exactly once " + "(Use -fno-inline-functions-called-once to inhibit it)">; def finline_limit_EQ : Joined<["-"], "finline-limit=">, Group<clang_ignored_gcc_optimization_f_Group>; defm finline_limit : BooleanFFlag<"inline-limit">, Group<clang_ignored_gcc_optimization_f_Group>; defm inline_small_functions : BooleanFFlag<"inline-small-functions">, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 072664e6040f3..fb70f75c83b2d 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5414,6 +5414,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, << TripleStr; } + // Respect the last -f[no-]inline-functions-called-once option. + if (!Args.hasFlag(options::OPT_finline_functions_called_once, + options::OPT_fno_inline_functions_called_once, + /*Default=*/true)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-no-inline-functions-called-once"); + } + // Push all default warning arguments that are specific to // the given target. These come before user provided warning options // are provided. diff --git a/clang/test/CodeGen/no-inline-functions-called-once.cpp b/clang/test/CodeGen/no-inline-functions-called-once.cpp new file mode 100644 index 0000000000000..049ec28643f06 --- /dev/null +++ b/clang/test/CodeGen/no-inline-functions-called-once.cpp @@ -0,0 +1,27 @@ +// RUN: %clang -O2 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=INLINE +// RUN: %clang -O2 -S -emit-llvm %s -fno-inline-functions-called-once -o - | FileCheck %s --check-prefix=NOINLINE + +// INLINE-LABEL: define{{.*}}@main +// INLINE-NOT: call{{.*}}@_ZL12bad_functionv +// INLINE: ret void + +// NOINLINE-LABEL: define{{.*}}@_ZL4testv +// NOINLINE: call{{.*}}@_ZL12bad_functionv +// NOINLINE: ret void + +// NOINLINE: define internal{{.*}}@_ZL12bad_functionv + +volatile int G; + +static void bad_function(void) { + G++; +} + +static void test(void) { + bad_function(); +} + +int main(void) { + test(); + return 0; +} diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index 5871f1580d6b7..0b29fc5920552 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -283,7 +283,6 @@ // RUN: -fgcse-las \ // RUN: -fgcse-sm \ // RUN: -fipa-cp \ -// RUN: -finline-functions-called-once \ // RUN: -fmodulo-sched \ // RUN: -fmodulo-sched-allow-regmoves \ // RUN: -fpeel-loops \ @@ -355,7 +354,6 @@ // RUN: -fgcse-las \ // RUN: -fgcse-sm \ // RUN: -fipa-cp \ -// RUN: -finline-functions-called-once \ // RUN: -fmodulo-sched \ // RUN: -fmodulo-sched-allow-regmoves \ // RUN: -fpeel-loops \ @@ -414,7 +412,6 @@ // CHECK-WARNING-DAG: optimization flag '-fgcse-las' is not supported // CHECK-WARNING-DAG: optimization flag '-fgcse-sm' is not supported // CHECK-WARNING-DAG: optimization flag '-fipa-cp' is not supported -// CHECK-WARNING-DAG: optimization flag '-finline-functions-called-once' is not supported // CHECK-WARNING-DAG: optimization flag '-fmodulo-sched' is not supported // CHECK-WARNING-DAG: optimization flag '-fmodulo-sched-allow-regmoves' is not supported // CHECK-WARNING-DAG: optimization flag '-fpeel-loops' is not supported diff --git a/clang/test/Driver/no-inline-functions-called-once.c b/clang/test/Driver/no-inline-functions-called-once.c new file mode 100644 index 0000000000000..402fdaa11254c --- /dev/null +++ b/clang/test/Driver/no-inline-functions-called-once.c @@ -0,0 +1,13 @@ +// RUN: %clang -### -c %s 2>&1 | FileCheck %s --check-prefix=DEFAULT +// DEFAULT-NOT: "-no-inline-functions-called-once" + +// RUN: %clang -### -c -fno-inline-functions-called-once %s 2>&1 | FileCheck %s --check-prefix=DISABLED +// DISABLED: "-mllvm" "-no-inline-functions-called-once" + +// RUN: %clang -### -c -fno-inline-functions-called-once -finline-functions-called-once %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=REENABLED +// REENABLED-NOT: "-no-inline-functions-called-once" + +// RUN: %clang -### -c -finline-functions-called-once -fno-inline-functions-called-once %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=DISABLED +// DISABLED: "-mllvm" "-no-inline-functions-called-once" diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp index d4f4d937aa06a..8645bee789d4a 100644 --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -183,6 +183,11 @@ static cl::opt<bool> InlineAllViableCalls( "inline-all-viable-calls", cl::Hidden, cl::init(false), cl::desc("Inline all viable calls, even if they exceed the inlining " "threshold")); + +static cl::opt<bool> NoInlineFunctionsCalledOnce( + "no-inline-functions-called-once", cl::Hidden, cl::init(false), + cl::desc("Disable inlining of functions with internal linkage that are " + "called only once")); namespace llvm { std::optional<int> getStringFnAttrAsInt(const Attribute &Attr) { if (Attr.isValid()) { @@ -2197,9 +2202,17 @@ void InlineCostCallAnalyzer::updateThreshold(CallBase &Call, Function &Callee) { // If there is only one call of the function, and it has internal linkage, // the cost of inlining it drops dramatically. It may seem odd to update // Cost in updateThreshold, but the bonus depends on the logic in this method. + // When -fno-inline-functions-called-once is enabled, disable this bonus + // and instead apply a large cost penalty to prevent inlining of such + // functions. if (isSoleCallToLocalFunction(Call, F)) { - addCost(-LastCallToStaticBonus); - StaticBonusApplied = LastCallToStaticBonus; + if (NoInlineFunctionsCalledOnce) { + addCost(INT_MAX); + StaticBonusApplied = 0; + } else { + addCost(-LastCallToStaticBonus); + StaticBonusApplied = LastCallToStaticBonus; + } } } >From 305a1590e7345ae03ab4722318b76d554a802b59 Mon Sep 17 00:00:00 2001 From: Shivam Gupta <[email protected]> Date: Mon, 14 Sep 2026 16:33:46 +0530 Subject: [PATCH 2/3] fix test cases --- clang/test/CodeGen/no-inline-functions-called-once.cpp | 2 +- clang/test/Driver/no-inline-functions-called-once.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/test/CodeGen/no-inline-functions-called-once.cpp b/clang/test/CodeGen/no-inline-functions-called-once.cpp index 049ec28643f06..3867f0a646358 100644 --- a/clang/test/CodeGen/no-inline-functions-called-once.cpp +++ b/clang/test/CodeGen/no-inline-functions-called-once.cpp @@ -3,7 +3,7 @@ // INLINE-LABEL: define{{.*}}@main // INLINE-NOT: call{{.*}}@_ZL12bad_functionv -// INLINE: ret void +// INLINE: ret i32 0 // NOINLINE-LABEL: define{{.*}}@_ZL4testv // NOINLINE: call{{.*}}@_ZL12bad_functionv diff --git a/clang/test/Driver/no-inline-functions-called-once.c b/clang/test/Driver/no-inline-functions-called-once.c index 402fdaa11254c..8c7b286479810 100644 --- a/clang/test/Driver/no-inline-functions-called-once.c +++ b/clang/test/Driver/no-inline-functions-called-once.c @@ -2,12 +2,12 @@ // DEFAULT-NOT: "-no-inline-functions-called-once" // RUN: %clang -### -c -fno-inline-functions-called-once %s 2>&1 | FileCheck %s --check-prefix=DISABLED -// DISABLED: "-mllvm" "-no-inline-functions-called-once" +// DISABLED: {{.*}} "-mllvm" "-no-inline-functions-called-once" // RUN: %clang -### -c -fno-inline-functions-called-once -finline-functions-called-once %s 2>&1 \ // RUN: | FileCheck %s --check-prefix=REENABLED // REENABLED-NOT: "-no-inline-functions-called-once" // RUN: %clang -### -c -finline-functions-called-once -fno-inline-functions-called-once %s 2>&1 \ -// RUN: | FileCheck %s --check-prefix=DISABLED -// DISABLED: "-mllvm" "-no-inline-functions-called-once" +// RUN: | FileCheck %s --check-prefix=DISABLED2 +// DISABLED2: {{.*}} "-mllvm" "-no-inline-functions-called-once" >From 43a34c2a7767cb1e2ac79b764d6083291dc80aae Mon Sep 17 00:00:00 2001 From: Shivam Gupta <[email protected]> Date: Mon, 14 Sep 2026 19:35:11 +0530 Subject: [PATCH 3/3] fix flang test case --- flang/test/Driver/flang-f-opts.f90 | 2 -- 1 file changed, 2 deletions(-) diff --git a/flang/test/Driver/flang-f-opts.f90 b/flang/test/Driver/flang-f-opts.f90 index a082545206ea3..ee82fd0e44f23 100644 --- a/flang/test/Driver/flang-f-opts.f90 +++ b/flang/test/Driver/flang-f-opts.f90 @@ -94,7 +94,6 @@ ! RUN: -fgcse-las \ ! RUN: -fgcse-sm \ ! RUN: -fipa-cp \ -! RUN: -finline-functions-called-once \ ! RUN: -fmodulo-sched \ ! RUN: -fmodulo-sched-allow-regmoves \ ! RUN: -fpeel-loops \ @@ -148,7 +147,6 @@ ! CHECK-WARNING-DAG: optimization flag '-fgcse-las' is not supported ! CHECK-WARNING-DAG: optimization flag '-fgcse-sm' is not supported ! CHECK-WARNING-DAG: optimization flag '-fipa-cp' is not supported -! CHECK-WARNING-DAG: optimization flag '-finline-functions-called-once' is not supported ! CHECK-WARNING-DAG: optimization flag '-fmodulo-sched' is not supported ! CHECK-WARNING-DAG: optimization flag '-fmodulo-sched-allow-regmoves' is not supported ! CHECK-WARNING-DAG: optimization flag '-fpeel-loops' is not supported _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
