[llvm] [GlobalOpt] Skip cold call analysis when no function can use coldcc (PR #227944)
Malavika Samak via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 30 20:47:35 PDT 2026
https://github.com/malavikasamak created https://github.com/llvm/llvm-project/pull/227944
OptimizeFunctions() starts by calling hasOnlyColdCalls() on every function in the module to find functions whose callers are all cold. That analysis needs BlockFrequencyInfo for each caller and can be expensive on large modules.
The result is only used to switch functions to the cold calling convention, which happens only if TargetTransformInfo:: useColdCCForColdCall() returns true for the function (or if -enable-coldcc-stress-test is set). On targets where that hook never returns true, the analysis is wasted work.
Add a cheap pre-scan that asks TTI whether any non-intrinsic function in the module can use coldcc, and only run the hasOnlyColdCalls() loop if one can, or if the stress-test flag is set. The pre-scan stops at the first match.
This is a compile-time improvement only; there is no change in output. The new loop cannot be fused with the existing one, since the existing loop must be skipped entirely when the pre-scan finds nothing.
>From f70e30985492d28d348d96a2d4ef321c8ad46849 Mon Sep 17 00:00:00 2001
From: mmalavika <mmalavika at nvidia.com>
Date: Wed, 30 Sep 2026 22:06:28 +0000
Subject: [PATCH] [GlobalOpt] Skip cold call analysis when no function can use
coldcc
OptimizeFunctions() starts by calling hasOnlyColdCalls() on every
function in the module to find functions whose callers are all cold.
That analysis needs BlockFrequencyInfo for each caller and can be
expensive on large modules.
The result is only used to switch functions to the cold calling
convention, which happens only if TargetTransformInfo::
useColdCCForColdCall() returns true for the function (or if
-enable-coldcc-stress-test is set). On targets where that hook never
returns true, the analysis is wasted work.
Add a cheap pre-scan that asks TTI whether any non-intrinsic function
in the module can use coldcc, and only run the hasOnlyColdCalls() loop
if one can, or if the stress-test flag is set. The pre-scan stops at
the first match.
This is a compile-time improvement only; there is no change in output.
The new loop cannot be fused with the existing one, since the existing
loop must be skipped entirely when the pre-scan finds nothing.
Co-Authored-By: Claude Sonnet 5.5 <noreply at anthropic.com>
---
llvm/lib/Transforms/IPO/GlobalOpt.cpp | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index 36563e25cc7f7..23dd5a175c5da 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -1926,9 +1926,22 @@ OptimizeFunctions(Module &M,
ChangeableCCCacheTy ChangeableCCCache;
std::vector<Function *> AllCallsCold;
- for (Function &F : llvm::make_early_inc_range(M))
- if (hasOnlyColdCalls(F, GetBFI, ChangeableCCCache))
- AllCallsCold.push_back(&F);
+ // This is a preprocessing step to determine if any function in the module
+ // can use Cold calling convention. This is supposed to help compile time
+ // on targets that do not use Cold for any function. Note this loop cannot
+ // be fused with the following loop.
+ bool CanUseColdCCForAnyColdCall = false;
+ for (Function &F : llvm::make_early_inc_range(M)) {
+ if (!F.isIntrinsic() && GetTTI(F).useColdCCForColdCall(F)) {
+ CanUseColdCCForAnyColdCall = true;
+ break;
+ }
+ }
+
+ if (EnableColdCCStressTest || CanUseColdCCForAnyColdCall)
+ for (Function &F : llvm::make_early_inc_range(M))
+ if (hasOnlyColdCalls(F, GetBFI, ChangeableCCCache))
+ AllCallsCold.push_back(&F);
// Optimize functions.
for (Function &F : llvm::make_early_inc_range(M)) {
More information about the llvm-commits
mailing list