[llvm-branch-commits] [llvm] 5d2e5c0 - Revert "[ProfileSummaryInfo] Honor the hot function attribute in hotness quer…"
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Oct 18 21:02:36 PDT 2026
Author: Teresa Johnson
Date: 2026-10-18T21:02:32-07:00
New Revision: 5d2e5c075ad8bfbadb40ca8f485b2988a54a7670
URL: https://github.com/llvm/llvm-project/commit/5d2e5c075ad8bfbadb40ca8f485b2988a54a7670
DIFF: https://github.com/llvm/llvm-project/commit/5d2e5c075ad8bfbadb40ca8f485b2988a54a7670.diff
LOG: Revert "[ProfileSummaryInfo] Honor the hot function attribute in hotness quer…"
This reverts commit 21740d6b79279a829446725484cfcfc92a208a27.
Added:
Modified:
llvm/include/llvm/Analysis/ProfileSummaryInfo.h
llvm/lib/Analysis/ProfileSummaryInfo.cpp
llvm/lib/CodeGen/MachineFunction.cpp
llvm/test/Instrumentation/PGOForceFunctionAttrs/basic.ll
llvm/test/Transforms/TailCallElim/disable-tail-call-elim-for-cold-calls.ll
llvm/unittests/Analysis/ProfileSummaryInfoTest.cpp
Removed:
llvm/test/Analysis/ProfileSummary/hot-attribute-no-summary.ll
llvm/test/Analysis/ProfileSummary/hot-attribute.ll
################################################################################
diff --git a/llvm/include/llvm/Analysis/ProfileSummaryInfo.h b/llvm/include/llvm/Analysis/ProfileSummaryInfo.h
index d21c5edf661a4..55b195b93f6da 100644
--- a/llvm/include/llvm/Analysis/ProfileSummaryInfo.h
+++ b/llvm/include/llvm/Analysis/ProfileSummaryInfo.h
@@ -113,14 +113,7 @@ class ProfileSummaryInfo {
/// either means it is not hot or it is unknown whether it is hot or not (for
/// example, no profile data is available).
template <typename FuncT> bool isFunctionEntryHot(const FuncT *F) const {
- if (!F)
- return false;
- // The hot attribute is a manual alternative to profile data, and takes
- // precedence over it. Check it before the profile summary so that it is
- // also honored when no profile is available.
- if (hasHotAttr(F))
- return true;
- if (!hasProfileSummary())
+ if (!F || !hasProfileSummary())
return false;
std::optional<uint64_t> FunctionCount = getEntryCount(F);
// FIXME: The heuristic used below for determining hotness is based on
@@ -132,14 +125,7 @@ class ProfileSummaryInfo {
/// Returns true if \p F contains hot code.
template <typename FuncT, typename BFIT>
bool isFunctionHotInCallGraph(const FuncT *F, BFIT &BFI) const {
- if (!F)
- return false;
- // The hot attribute is a manual alternative to profile data, and takes
- // precedence over it. Check it before the profile summary so that it is
- // also honored when no profile is available.
- if (hasHotAttr(F))
- return true;
- if (!hasProfileSummary())
+ if (!F || !hasProfileSummary())
return false;
if (auto FunctionCount = getEntryCount(F))
if (isHotCount(*FunctionCount))
@@ -159,14 +145,7 @@ class ProfileSummaryInfo {
/// Returns true if \p F contains only cold code.
template <typename FuncT, typename BFIT>
bool isFunctionColdInCallGraph(const FuncT *F, BFIT &BFI) const {
- if (!F)
- return false;
- // The hot attribute is a manual alternative to profile data, and takes
- // precedence over it. Check it before the profile summary so that it is
- // also honored when no profile is available.
- if (hasHotAttr(F))
- return false;
- if (!hasProfileSummary())
+ if (!F || !hasProfileSummary())
return false;
if (auto FunctionCount = getEntryCount(F))
if (!isColdCount(*FunctionCount))
@@ -348,12 +327,6 @@ class ProfileSummaryInfo {
std::optional<uint64_t> getEntryCount(const FuncT *F) const {
return F->getEntryCount();
}
-
- /// Returns true if \p F is annotated with the hot attribute, which takes
- /// precedence over any profile information.
- template <typename FuncT> bool hasHotAttr(const FuncT *F) const {
- return F->hasFnAttribute(Attribute::Hot);
- }
};
template <>
@@ -370,17 +343,13 @@ ProfileSummaryInfo::getTotalCallCount<Function>(const Function *F) const {
return TotalCallCount;
}
-// Declare template specializations for llvm::MachineFunction. Do not implement
+// Declare template specialization for llvm::MachineFunction. Do not implement
// here, because we cannot include MachineFunction header here, that would break
// dependency rules.
template <>
std::optional<uint64_t> ProfileSummaryInfo::getEntryCount<MachineFunction>(
const MachineFunction *F) const;
-template <>
-bool ProfileSummaryInfo::hasHotAttr<MachineFunction>(
- const MachineFunction *F) const;
-
/// An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo.
class LLVM_ABI ProfileSummaryInfoWrapperPass : public ImmutablePass {
std::unique_ptr<ProfileSummaryInfo> PSI;
diff --git a/llvm/lib/Analysis/ProfileSummaryInfo.cpp b/llvm/lib/Analysis/ProfileSummaryInfo.cpp
index 5813da091ece9..a50c34d1b1007 100644
--- a/llvm/lib/Analysis/ProfileSummaryInfo.cpp
+++ b/llvm/lib/Analysis/ProfileSummaryInfo.cpp
@@ -106,12 +106,6 @@ bool ProfileSummaryInfo::isFunctionHotnessUnknown(const Function &F) const {
bool ProfileSummaryInfo::isFunctionEntryCold(const Function *F) const {
if (!F)
return false;
- // The hot attribute is a manual alternative to profile data, and takes
- // precedence over both the profile and the cold attribute. Clang makes the
- // hot and cold attributes mutually exclusive, but nothing enforces that in
- // IR, so the order matters here.
- if (hasHotAttr(F))
- return false;
if (F->hasFnAttribute(Attribute::Cold))
return true;
if (!hasProfileSummary())
diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp
index 8ccc5637a1448..b0f06907ef9da 100644
--- a/llvm/lib/CodeGen/MachineFunction.cpp
+++ b/llvm/lib/CodeGen/MachineFunction.cpp
@@ -1706,8 +1706,8 @@ void MachineConstantPool::print(raw_ostream &OS) const {
}
//===----------------------------------------------------------------------===//
-// Template specializations for MachineFunction implementations of
-// ProfileSummaryInfo::getEntryCount() and ProfileSummaryInfo::hasHotAttr().
+// Template specialization for MachineFunction implementation of
+// ProfileSummaryInfo::getEntryCount().
//===----------------------------------------------------------------------===//
template <>
std::optional<uint64_t>
@@ -1716,12 +1716,6 @@ ProfileSummaryInfo::getEntryCount<llvm::MachineFunction>(
return F->getFunction().getEntryCount();
}
-template <>
-bool ProfileSummaryInfo::hasHotAttr<llvm::MachineFunction>(
- const llvm::MachineFunction *F) const {
- return F->getFunction().hasFnAttribute(Attribute::Hot);
-}
-
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void MachineConstantPool::dump() const { print(dbgs()); }
#endif
diff --git a/llvm/test/Analysis/ProfileSummary/hot-attribute-no-summary.ll b/llvm/test/Analysis/ProfileSummary/hot-attribute-no-summary.ll
deleted file mode 100644
index 38501afc910fe..0000000000000
--- a/llvm/test/Analysis/ProfileSummary/hot-attribute-no-summary.ll
+++ /dev/null
@@ -1,19 +0,0 @@
-; RUN: opt < %s -disable-output -passes=print-profile-summary -S 2>&1 | FileCheck %s
-
-; The "hot" attribute is a manual alternative to PGO hotness data, so it must
-; also apply when the module has no profile summary at all.
-
-define void @hot_attr() hot {
-; CHECK: hot_attr :hot entry
- ret void
-}
-
-define void @cold_attr() cold {
-; CHECK: cold_attr :cold entry
- ret void
-}
-
-define void @plain() {
-; CHECK: plain{{$}}
- ret void
-}
diff --git a/llvm/test/Analysis/ProfileSummary/hot-attribute.ll b/llvm/test/Analysis/ProfileSummary/hot-attribute.ll
deleted file mode 100644
index 947d607895e84..0000000000000
--- a/llvm/test/Analysis/ProfileSummary/hot-attribute.ll
+++ /dev/null
@@ -1,62 +0,0 @@
-; RUN: opt < %s -disable-output -passes=print-profile-summary -S 2>&1 | FileCheck %s
-
-; The "hot" function attribute is documented (LangRef, and Clang's
-; AttributeReference for __attribute__((hot))) to take precedence over profile
-; information, so that users can compensate for training input that does not
-; cover all of the hot functions. Check that ProfileSummaryInfo honors it.
-
-; An entry count of 0 would otherwise make this function cold.
-define void @hot_attr_cold_count() hot !prof !20 {
-; CHECK: hot_attr_cold_count :hot entry
- ret void
-}
-
-; No entry count at all: the hotness would otherwise be unknown.
-define void @hot_attr_no_count() hot {
-; CHECK: hot_attr_no_count :hot entry
- ret void
-}
-
-; The hot attribute wins over the cold attribute. Clang makes the two mutually
-; exclusive, but nothing enforces that in IR, so the order must be defined.
-define void @hot_and_cold_attrs() hot cold !prof !20 {
-; CHECK: hot_and_cold_attrs :hot entry
- ret void
-}
-
-; Without the attribute, an entry count of 0 is cold.
-define void @plain_cold_count() !prof !20 {
-; CHECK: plain_cold_count :cold entry
- ret void
-}
-
-; The cold attribute is unaffected.
-define void @cold_attr() cold !prof !20 {
-; CHECK: cold_attr :cold entry
- ret void
-}
-
-; A hot entry count is still hot without the attribute.
-define void @plain_hot_count() !prof !21 {
-; CHECK: plain_hot_count :hot entry
- ret void
-}
-
-!llvm.module.flags = !{!1}
-!20 = !{!"function_entry_count", i64 0}
-!21 = !{!"function_entry_count", i64 400}
-
-!1 = !{i32 1, !"ProfileSummary", !2}
-!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
-!3 = !{!"ProfileFormat", !"InstrProf"}
-!4 = !{!"TotalCount", i64 10000}
-!5 = !{!"MaxCount", i64 10}
-!6 = !{!"MaxInternalCount", i64 1}
-!7 = !{!"MaxFunctionCount", i64 1000}
-!8 = !{!"NumCounts", i64 3}
-!9 = !{!"NumFunctions", i64 3}
-!10 = !{!"DetailedSummary", !11}
-!11 = !{!12, !13, !14}
-!12 = !{i32 10000, i64 100, i32 1}
-!13 = !{i32 999000, i64 100, i32 1}
-!14 = !{i32 999999, i64 1, i32 2}
diff --git a/llvm/test/Instrumentation/PGOForceFunctionAttrs/basic.ll b/llvm/test/Instrumentation/PGOForceFunctionAttrs/basic.ll
index f8377b3c30779..bc966f39fda14 100644
--- a/llvm/test/Instrumentation/PGOForceFunctionAttrs/basic.ll
+++ b/llvm/test/Instrumentation/PGOForceFunctionAttrs/basic.ll
@@ -79,15 +79,6 @@ define void @hot() !prof !28 {
ret void
}
-; The hot attribute takes precedence over the profile, so this must not be
-; treated as cold even though its entry count is.
-define void @hot_attr_cold_count() hot !prof !27 {
- %l = load i32, ptr @s, align 4
- %add = add nsw i32 %l, 4
- store i32 %add, ptr @s, align 4
- ret void
-}
-
attributes #0 = { optsize }
attributes #1 = { minsize }
attributes #2 = { noinline optnone }
diff --git a/llvm/test/Transforms/TailCallElim/disable-tail-call-elim-for-cold-calls.ll b/llvm/test/Transforms/TailCallElim/disable-tail-call-elim-for-cold-calls.ll
index 70a05b534adcf..ee48b050175f5 100644
--- a/llvm/test/Transforms/TailCallElim/disable-tail-call-elim-for-cold-calls.ll
+++ b/llvm/test/Transforms/TailCallElim/disable-tail-call-elim-for-cold-calls.ll
@@ -137,43 +137,6 @@ exit:
ret void
}
-; The hot attribute takes precedence over the profile, so a call inside a
-; function with a cold entry count (function_entry_count = 0) IS marked as tail
-; when the function is annotated hot.
-define void @test_hot_attr_cold_block() hot !prof !14 {
-; CHECK-LABEL: @test_hot_attr_cold_block(
-; CHECK: tail call void @normal_callee()
- call void @normal_callee()
- ret void
-}
-
-; Same, when the callee is cold.
-define void @test_hot_attr_cold_callee() hot !prof !14 {
-; CHECK-LABEL: @test_hot_attr_cold_callee(
-; CHECK: tail call void @cold_callee()
- call void @cold_callee()
- ret void
-}
-
-; Tail recursion elimination is likewise still performed in a function with a
-; cold entry count that is annotated hot.
-define i32 @test_hot_attr_recursive(i32 %X) hot !prof !14 {
-; CHECK-LABEL: @test_hot_attr_recursive(
-; CHECK: tailrecurse:
-; CHECK-NOT: call i32 @test_hot_attr_recursive(
-entry:
- %cmp = icmp eq i32 %X, 0
- br i1 %cmp, label %if.then, label %if.else
-
-if.then:
- ret i32 0
-
-if.else:
- %dec = sub i32 %X, 1
- %call = call i32 @test_hot_attr_recursive(i32 %dec)
- ret i32 %call
-}
-
!llvm.module.flags = !{!0}
!0 = !{i32 1, !"ProfileSummary", !1}
!1 = !{!2, !3, !4, !5, !6, !7, !8, !9}
diff --git a/llvm/unittests/Analysis/ProfileSummaryInfoTest.cpp b/llvm/unittests/Analysis/ProfileSummaryInfoTest.cpp
index 994ce1976b9c0..2f68a8bf5f915 100644
--- a/llvm/unittests/Analysis/ProfileSummaryInfoTest.cpp
+++ b/llvm/unittests/Analysis/ProfileSummaryInfoTest.cpp
@@ -433,95 +433,5 @@ TEST_F(ProfileSummaryInfoTest, PartialSampleProfWorkingSetSize) {
EXPECT_TRUE(PSI3.hasLargeWorkingSetSize());
}
-// The hot attribute is documented (LangRef, and Clang's AttributeReference for
-// __attribute__((hot))) to take precedence over profile information, so that
-// users can compensate for training input that does not cover all of the hot
-// functions. These tests pin that behavior down for every hotness query.
-
-TEST_F(ProfileSummaryInfoTest, TestHotAttributeInstrProf) {
- auto M = makeLLVMModule("InstrProf");
- // @g has an entry count of 1, which is cold under this summary.
- Function *G = M->getFunction("g");
- BlockFrequencyInfo BFI = buildBFI(*G);
-
- {
- ProfileSummaryInfo PSI = buildPSI(M.get());
- EXPECT_FALSE(PSI.isFunctionEntryHot(G));
- EXPECT_TRUE(PSI.isFunctionEntryCold(G));
- EXPECT_FALSE(PSI.isFunctionHotInCallGraph(G, BFI));
- EXPECT_TRUE(PSI.isFunctionColdInCallGraph(G, BFI));
- }
-
- G->addFnAttr(Attribute::Hot);
-
- {
- ProfileSummaryInfo PSI = buildPSI(M.get());
- EXPECT_TRUE(PSI.isFunctionEntryHot(G));
- EXPECT_FALSE(PSI.isFunctionEntryCold(G));
- EXPECT_TRUE(PSI.isFunctionHotInCallGraph(G, BFI));
- EXPECT_FALSE(PSI.isFunctionColdInCallGraph(G, BFI));
- }
-}
-
-TEST_F(ProfileSummaryInfoTest, TestHotAttributeSampleProf) {
- auto M = makeLLVMModule("SampleProfile");
- Function *G = M->getFunction("g");
- BlockFrequencyInfo BFI = buildBFI(*G);
-
- G->addFnAttr(Attribute::Hot);
-
- ProfileSummaryInfo PSI = buildPSI(M.get());
- EXPECT_TRUE(PSI.isFunctionEntryHot(G));
- EXPECT_FALSE(PSI.isFunctionEntryCold(G));
- EXPECT_TRUE(PSI.isFunctionHotInCallGraph(G, BFI));
- EXPECT_FALSE(PSI.isFunctionColdInCallGraph(G, BFI));
-}
-
-// The attribute is a manual alternative to PGO data, so it must also apply when
-// there is no profile summary at all.
-TEST_F(ProfileSummaryInfoTest, TestHotAttributeNoProfile) {
- auto M = makeLLVMModule(/*ProfKind=*/nullptr);
- Function *F = M->getFunction("f");
- BlockFrequencyInfo BFI = buildBFI(*F);
-
- {
- ProfileSummaryInfo PSI = buildPSI(M.get());
- EXPECT_FALSE(PSI.hasProfileSummary());
- EXPECT_FALSE(PSI.isFunctionEntryHot(F));
- EXPECT_FALSE(PSI.isFunctionHotInCallGraph(F, BFI));
- }
-
- F->addFnAttr(Attribute::Hot);
-
- {
- ProfileSummaryInfo PSI = buildPSI(M.get());
- EXPECT_FALSE(PSI.hasProfileSummary());
- EXPECT_TRUE(PSI.isFunctionEntryHot(F));
- EXPECT_FALSE(PSI.isFunctionEntryCold(F));
- EXPECT_TRUE(PSI.isFunctionHotInCallGraph(F, BFI));
- EXPECT_FALSE(PSI.isFunctionColdInCallGraph(F, BFI));
- }
-}
-
-// Clang declares the hot and cold attributes mutually exclusive, but nothing
-// enforces that in IR, so the precedence has to be defined. Hot wins.
-TEST_F(ProfileSummaryInfoTest, TestHotAttributeBeatsColdAttribute) {
- auto M = makeLLVMModule("InstrProf");
- Function *G = M->getFunction("g");
-
- G->addFnAttr(Attribute::Cold);
- {
- ProfileSummaryInfo PSI = buildPSI(M.get());
- EXPECT_TRUE(PSI.isFunctionEntryCold(G));
- }
-
- G->addFnAttr(Attribute::Hot);
- {
- ProfileSummaryInfo PSI = buildPSI(M.get());
- EXPECT_FALSE(PSI.isFunctionEntryCold(G));
- EXPECT_TRUE(PSI.isFunctionEntryHot(G));
- }
-}
-
} // end anonymous namespace
} // end namespace llvm
More information about the llvm-branch-commits
mailing list