[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