[llvm] [MergeFunctions] Fix build failure in PR #202218 (PR #206651)

Alok Kumar Sharma via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 29 23:00:38 PDT 2026


https://github.com/alokkrsharma created https://github.com/llvm/llvm-project/pull/206651

Address the build issue that caused the original change to be reverted and reapply the fix.


>From d32ef3aca1f70aa3d22eafe91605959e49ecc8a4 Mon Sep 17 00:00:00 2001
From: Alok Kumar Sharma <AlokKumar.Sharma at amd.com>
Date: Sun, 7 Jun 2026 22:01:43 +0530
Subject: [PATCH 1/3] [MergeFunctions] Preserve entry counts on folds

When folding two equivalent functions, keep profile entry count
metadata meaningful by combining the entry counts of the folded
functions on the surviving implementation.
---
 llvm/lib/Transforms/IPO/MergeFunctions.cpp    |  34 ++
 .../MergeFunc/merge-functions-entry-count.ll  | 330 ++++++++++++++++++
 2 files changed, 364 insertions(+)
 create mode 100644 llvm/test/Transforms/MergeFunc/merge-functions-entry-count.ll

diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
index 5c8624ba56a27..8110653aac88e 100644
--- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
@@ -114,6 +114,7 @@
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/Utils/FunctionComparator.h"
@@ -121,6 +122,7 @@
 #include <algorithm>
 #include <cassert>
 #include <iterator>
+#include <optional>
 #include <set>
 #include <utility>
 #include <vector>
@@ -732,6 +734,7 @@ static void copyMetadataIfPresent(Function *From, Function *To,
 // For better debugability, under MergeFunctionsPDI, we do not modify G's
 // call sites to point to F even when within the same translation unit.
 void MergeFunctions::writeThunk(Function *F, Function *G) {
+  auto GEC = G->getEntryCount(/*AllowSynthetic=*/true);
   BasicBlock *GEntryBlock = nullptr;
   std::vector<Instruction *> PDIUnrelatedWL;
   std::vector<DbgVariableRecord *> PDVRUnrelatedWL;
@@ -801,6 +804,8 @@ void MergeFunctions::writeThunk(Function *F, Function *G) {
                << G->getName() << "()\n");
   } else {
     NewG->copyAttributesFrom(G);
+    if (GEC)
+      NewG->setEntryCount(*GEC);
     NewG->takeName(G);
     // Ensure CFI type metadata is propagated to the new function.
     copyMetadataIfPresent(G, NewG, "type");
@@ -874,6 +879,25 @@ static bool isODR(const Function *F) {
   return F->hasWeakODRLinkage() || F->hasLinkOnceODRLinkage();
 }
 
+static void mergeEntryCountsInto(Function *F,
+                                 std::optional<Function::ProfileCount> FC,
+                                 std::optional<Function::ProfileCount> GC) {
+  if (!FC && !GC)
+    return;
+  uint64_t Sum = SaturatingAdd(FC ? FC->getCount() : uint64_t{0},
+                               GC ? GC->getCount() : uint64_t{0});
+  Function::ProfileCountType PCT =
+      ((FC && FC->isSynthetic()) || (GC && GC->isSynthetic()))
+          ? Function::PCT_Synthetic
+          : Function::PCT_Real;
+  if (FC && FC->getType() != PCT) {
+    F->setMetadata(LLVMContext::MD_prof, nullptr);
+    F->setEntryCount(Function::ProfileCount(Sum, PCT));
+    return;
+  }
+  F->setEntryCount(Sum, PCT);
+}
+
 // Merge two equivalent functions. Upon completion, Function G is deleted.
 void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
 
@@ -902,6 +926,8 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
     // Ensure CFI type metadata is propagated to the new function.
     copyMetadataIfPresent(F, NewF, "type");
     copyMetadataIfPresent(F, NewF, "kcfi_type");
+    auto FEC = F->getEntryCount(/*AllowSynthetic=*/true);
+    auto GEC = G->getEntryCount(/*AllowSynthetic=*/true);
     removeUsers(F);
     F->replaceAllUsesWith(NewF);
 
@@ -918,6 +944,8 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
     const MaybeAlign GAlign = G->getAlign();
 
     writeThunkOrAliasIfNeeded(F, G);
+    if (FEC)
+      NewF->setEntryCount(*FEC);
     writeThunkOrAliasIfNeeded(F, NewF);
 
     if (NewFAlign || GAlign)
@@ -925,9 +953,13 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
     else
       F->setAlignment(std::nullopt);
     F->setLinkage(GlobalValue::PrivateLinkage);
+    mergeEntryCountsInto(F, FEC, GEC);
     ++NumDoubleWeak;
     ++NumFunctionsMerged;
   } else {
+    auto FEC = F->getEntryCount(/*AllowSynthetic=*/true);
+    auto GEC = G->getEntryCount(/*AllowSynthetic=*/true);
+
     // For better debugability, under MergeFunctionsPDI, we do not modify G's
     // call sites to point to F even when within the same translation unit.
     if (!G->isInterposable() && !MergeFunctionsPDI) {
@@ -952,12 +984,14 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
     // stop here and delete G. There's no need for a thunk. (See note on
     // MergeFunctionsPDI above).
     if (G->isDiscardableIfUnused() && G->use_empty() && !MergeFunctionsPDI) {
+      mergeEntryCountsInto(F, FEC, GEC);
       G->eraseFromParent();
       ++NumFunctionsMerged;
       return;
     }
 
     if (writeThunkOrAliasIfNeeded(F, G)) {
+      mergeEntryCountsInto(F, FEC, GEC);
       ++NumFunctionsMerged;
     }
   }
diff --git a/llvm/test/Transforms/MergeFunc/merge-functions-entry-count.ll b/llvm/test/Transforms/MergeFunc/merge-functions-entry-count.ll
new file mode 100644
index 0000000000000..7bcab278b7055
--- /dev/null
+++ b/llvm/test/Transforms/MergeFunc/merge-functions-entry-count.ll
@@ -0,0 +1,330 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 5
+; RUN: opt -S -passes=mergefunc < %s | FileCheck %s
+; RUN: opt -S -passes=mergefunc -mergefunc-use-aliases < %s | FileCheck %s --check-prefix=ALIAS
+
+define internal i32 @basic_a(i32 %x) !prof !1 {
+entry:
+  %add = add nsw i32 %x, 1
+  ret i32 %add
+}
+
+define internal i32 @basic_b(i32 %x) !prof !1 {
+entry:
+  %add = add nsw i32 %x, 1
+  ret i32 %add
+}
+
+define internal i32 @asym_a(i32 %x) !prof !2 {
+entry:
+  %add = add nsw i32 %x, 2
+  ret i32 %add
+}
+
+define internal i32 @asym_b(i32 %x) !prof !3 {
+entry:
+  %add = add nsw i32 %x, 2
+  ret i32 %add
+}
+
+define internal i32 @onesided_a(i32 %x) {
+entry:
+  %add = add nsw i32 %x, 3
+  ret i32 %add
+}
+
+define internal i32 @onesided_b(i32 %x) !prof !4 {
+entry:
+  %add = add nsw i32 %x, 3
+  ret i32 %add
+}
+
+define internal i32 @real_synth_a(i32 %x) !prof !5 {
+entry:
+  %add = add nsw i32 %x, 4
+  ret i32 %add
+}
+
+define internal i32 @real_synth_b(i32 %x) !prof !6 {
+entry:
+  %add = add nsw i32 %x, 4
+  ret i32 %add
+}
+
+define linkonce_odr i32 @odr_a(i32 %x) !prof !1 {
+entry:
+  %add = add nsw i32 %x, 5
+  ret i32 %add
+}
+
+define linkonce_odr i32 @odr_b(i32 %x) !prof !1 {
+entry:
+  %add = add nsw i32 %x, 5
+  ret i32 %add
+}
+
+ at llvm.used = appending global [2 x ptr] [ptr @odr_a, ptr @odr_b], section "llvm.metadata"
+
+define void @alias_a() unnamed_addr !prof !7 {
+  ret void
+}
+
+define void @alias_b() unnamed_addr !prof !8 {
+  ret void
+}
+
+define i32 @use_counts(i32 %x) {
+entry:
+  %basic = call i32 @basic_a(i32 %x)
+  %basic2 = call i32 @basic_b(i32 %x)
+  %asym = call i32 @asym_a(i32 %x)
+  %asym2 = call i32 @asym_b(i32 %x)
+  %onesided = call i32 @onesided_a(i32 %x)
+  %onesided2 = call i32 @onesided_b(i32 %x)
+  %real_synth = call i32 @real_synth_a(i32 %x)
+  %real_synth2 = call i32 @real_synth_b(i32 %x)
+  %odr = call i32 @odr_a(i32 %x)
+  %odr2 = call i32 @odr_b(i32 %x)
+  call void @alias_a()
+  call void @alias_b()
+  %sum0 = add i32 %basic, %basic2
+  %sum1 = add i32 %sum0, %asym
+  %sum2 = add i32 %sum1, %asym2
+  %sum3 = add i32 %sum2, %onesided
+  %sum4 = add i32 %sum3, %onesided2
+  %sum5 = add i32 %sum4, %real_synth
+  %sum6 = add i32 %sum5, %real_synth2
+  %sum7 = add i32 %sum6, %odr
+  %sum8 = add i32 %sum7, %odr2
+  ret i32 %sum8
+}
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 1, !"ProfileSummary", !9}
+!1 = !{!"function_entry_count", i64 1}
+!2 = !{!"function_entry_count", i64 2000}
+!3 = !{!"function_entry_count", i64 1000}
+!4 = !{!"function_entry_count", i64 500}
+!5 = !{!"function_entry_count", i64 10}
+!6 = !{!"synthetic_function_entry_count", i64 5}
+!7 = !{!"function_entry_count", i64 7}
+!8 = !{!"function_entry_count", i64 5}
+!9 = !{!10, !11, !12, !13, !14, !15, !16, !17}
+!10 = !{!"ProfileFormat", !"InstrProf"}
+!11 = !{!"TotalCount", i64 3531}
+!12 = !{!"MaxCount", i64 2000}
+!13 = !{!"MaxInternalCount", i64 2000}
+!14 = !{!"MaxFunctionCount", i64 2000}
+!15 = !{!"NumCounts", i64 12}
+!16 = !{!"NumFunctions", i64 12}
+!17 = !{!"DetailedSummary", !18}
+!18 = !{!19}
+!19 = !{i32 10000, i64 1, i32 1}
+;.
+; CHECK: @llvm.used = appending global [2 x ptr] [ptr @odr_a, ptr @odr_b], section "llvm.metadata"
+;.
+; ALIAS: @llvm.used = appending global [2 x ptr] [ptr @odr_a, ptr @odr_b], section "llvm.metadata"
+; ALIAS: @alias_b = unnamed_addr alias void (), ptr @alias_a
+;.
+; CHECK-LABEL: define internal i32 @basic_a(
+; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF12:![0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 1
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+;
+; CHECK-LABEL: define internal i32 @asym_a(
+; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF13:![0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 2
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+;
+; CHECK-LABEL: define internal i32 @onesided_a(
+; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF14:![0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 3
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+;
+; CHECK-LABEL: define internal i32 @real_synth_a(
+; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF15:![0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 4
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+;
+; CHECK-LABEL: define private i32 @0(
+; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF12]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 5
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+;
+; CHECK-LABEL: define void @alias_a(
+; CHECK-SAME: ) unnamed_addr !prof [[PROF16:![0-9]+]] {
+; CHECK-NEXT:    ret void
+;
+;
+; CHECK-LABEL: define void @alias_b(
+; CHECK-SAME: ) unnamed_addr !prof [[PROF17:![0-9]+]] {
+; CHECK-NEXT:    ret void
+;
+;
+; CHECK-LABEL: define i32 @use_counts(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[BASIC:%.*]] = call i32 @basic_a(i32 [[X]])
+; CHECK-NEXT:    [[BASIC2:%.*]] = call i32 @basic_a(i32 [[X]])
+; CHECK-NEXT:    [[ASYM:%.*]] = call i32 @asym_a(i32 [[X]])
+; CHECK-NEXT:    [[ASYM2:%.*]] = call i32 @asym_a(i32 [[X]])
+; CHECK-NEXT:    [[ONESIDED:%.*]] = call i32 @onesided_a(i32 [[X]])
+; CHECK-NEXT:    [[ONESIDED2:%.*]] = call i32 @onesided_a(i32 [[X]])
+; CHECK-NEXT:    [[REAL_SYNTH:%.*]] = call i32 @real_synth_a(i32 [[X]])
+; CHECK-NEXT:    [[REAL_SYNTH2:%.*]] = call i32 @real_synth_a(i32 [[X]])
+; CHECK-NEXT:    [[ODR:%.*]] = call i32 @[[GLOB0:[0-9]+]](i32 [[X]])
+; CHECK-NEXT:    [[ODR2:%.*]] = call i32 @[[GLOB0]](i32 [[X]])
+; CHECK-NEXT:    call void @alias_a()
+; CHECK-NEXT:    call void @alias_a()
+; CHECK-NEXT:    [[SUM0:%.*]] = add i32 [[BASIC]], [[BASIC2]]
+; CHECK-NEXT:    [[SUM1:%.*]] = add i32 [[SUM0]], [[ASYM]]
+; CHECK-NEXT:    [[SUM2:%.*]] = add i32 [[SUM1]], [[ASYM2]]
+; CHECK-NEXT:    [[SUM3:%.*]] = add i32 [[SUM2]], [[ONESIDED]]
+; CHECK-NEXT:    [[SUM4:%.*]] = add i32 [[SUM3]], [[ONESIDED2]]
+; CHECK-NEXT:    [[SUM5:%.*]] = add i32 [[SUM4]], [[REAL_SYNTH]]
+; CHECK-NEXT:    [[SUM6:%.*]] = add i32 [[SUM5]], [[REAL_SYNTH2]]
+; CHECK-NEXT:    [[SUM7:%.*]] = add i32 [[SUM6]], [[ODR]]
+; CHECK-NEXT:    [[SUM8:%.*]] = add i32 [[SUM7]], [[ODR2]]
+; CHECK-NEXT:    ret i32 [[SUM8]]
+;
+;
+; CHECK-LABEL: define linkonce_odr i32 @odr_b(
+; CHECK-SAME: i32 [[TMP0:%.*]]) !prof [[PROF18:![0-9]+]] {
+; CHECK-NEXT:    [[TMP2:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]])
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+;
+; CHECK-LABEL: define linkonce_odr i32 @odr_a(
+; CHECK-SAME: i32 [[TMP0:%.*]]) !prof [[PROF18]] {
+; CHECK-NEXT:    [[TMP2:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]])
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+;
+; ALIAS-LABEL: define internal i32 @basic_a(
+; ALIAS-SAME: i32 [[X:%.*]]) !prof [[PROF12:![0-9]+]] {
+; ALIAS-NEXT:  [[ENTRY:.*:]]
+; ALIAS-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 1
+; ALIAS-NEXT:    ret i32 [[ADD]]
+;
+;
+; ALIAS-LABEL: define internal i32 @asym_a(
+; ALIAS-SAME: i32 [[X:%.*]]) !prof [[PROF13:![0-9]+]] {
+; ALIAS-NEXT:  [[ENTRY:.*:]]
+; ALIAS-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 2
+; ALIAS-NEXT:    ret i32 [[ADD]]
+;
+;
+; ALIAS-LABEL: define internal i32 @onesided_a(
+; ALIAS-SAME: i32 [[X:%.*]]) !prof [[PROF14:![0-9]+]] {
+; ALIAS-NEXT:  [[ENTRY:.*:]]
+; ALIAS-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 3
+; ALIAS-NEXT:    ret i32 [[ADD]]
+;
+;
+; ALIAS-LABEL: define internal i32 @real_synth_a(
+; ALIAS-SAME: i32 [[X:%.*]]) !prof [[PROF15:![0-9]+]] {
+; ALIAS-NEXT:  [[ENTRY:.*:]]
+; ALIAS-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 4
+; ALIAS-NEXT:    ret i32 [[ADD]]
+;
+;
+; ALIAS-LABEL: define private i32 @0(
+; ALIAS-SAME: i32 [[X:%.*]]) !prof [[PROF12]] {
+; ALIAS-NEXT:  [[ENTRY:.*:]]
+; ALIAS-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 5
+; ALIAS-NEXT:    ret i32 [[ADD]]
+;
+;
+; ALIAS-LABEL: define void @alias_a(
+; ALIAS-SAME: ) unnamed_addr !prof [[PROF16:![0-9]+]] {
+; ALIAS-NEXT:    ret void
+;
+;
+; ALIAS-LABEL: define i32 @use_counts(
+; ALIAS-SAME: i32 [[X:%.*]]) {
+; ALIAS-NEXT:  [[ENTRY:.*:]]
+; ALIAS-NEXT:    [[BASIC:%.*]] = call i32 @basic_a(i32 [[X]])
+; ALIAS-NEXT:    [[BASIC2:%.*]] = call i32 @basic_a(i32 [[X]])
+; ALIAS-NEXT:    [[ASYM:%.*]] = call i32 @asym_a(i32 [[X]])
+; ALIAS-NEXT:    [[ASYM2:%.*]] = call i32 @asym_a(i32 [[X]])
+; ALIAS-NEXT:    [[ONESIDED:%.*]] = call i32 @onesided_a(i32 [[X]])
+; ALIAS-NEXT:    [[ONESIDED2:%.*]] = call i32 @onesided_a(i32 [[X]])
+; ALIAS-NEXT:    [[REAL_SYNTH:%.*]] = call i32 @real_synth_a(i32 [[X]])
+; ALIAS-NEXT:    [[REAL_SYNTH2:%.*]] = call i32 @real_synth_a(i32 [[X]])
+; ALIAS-NEXT:    [[ODR:%.*]] = call i32 @[[GLOB0:[0-9]+]](i32 [[X]])
+; ALIAS-NEXT:    [[ODR2:%.*]] = call i32 @[[GLOB0]](i32 [[X]])
+; ALIAS-NEXT:    call void @alias_a()
+; ALIAS-NEXT:    call void @alias_a()
+; ALIAS-NEXT:    [[SUM0:%.*]] = add i32 [[BASIC]], [[BASIC2]]
+; ALIAS-NEXT:    [[SUM1:%.*]] = add i32 [[SUM0]], [[ASYM]]
+; ALIAS-NEXT:    [[SUM2:%.*]] = add i32 [[SUM1]], [[ASYM2]]
+; ALIAS-NEXT:    [[SUM3:%.*]] = add i32 [[SUM2]], [[ONESIDED]]
+; ALIAS-NEXT:    [[SUM4:%.*]] = add i32 [[SUM3]], [[ONESIDED2]]
+; ALIAS-NEXT:    [[SUM5:%.*]] = add i32 [[SUM4]], [[REAL_SYNTH]]
+; ALIAS-NEXT:    [[SUM6:%.*]] = add i32 [[SUM5]], [[REAL_SYNTH2]]
+; ALIAS-NEXT:    [[SUM7:%.*]] = add i32 [[SUM6]], [[ODR]]
+; ALIAS-NEXT:    [[SUM8:%.*]] = add i32 [[SUM7]], [[ODR2]]
+; ALIAS-NEXT:    ret i32 [[SUM8]]
+;
+;
+; ALIAS-LABEL: define linkonce_odr i32 @odr_b(
+; ALIAS-SAME: i32 [[TMP0:%.*]]) !prof [[PROF17:![0-9]+]] {
+; ALIAS-NEXT:    [[TMP2:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]])
+; ALIAS-NEXT:    ret i32 [[TMP2]]
+;
+;
+; ALIAS-LABEL: define linkonce_odr i32 @odr_a(
+; ALIAS-SAME: i32 [[TMP0:%.*]]) !prof [[PROF17]] {
+; ALIAS-NEXT:    [[TMP2:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]])
+; ALIAS-NEXT:    ret i32 [[TMP2]]
+;
+;.
+; CHECK: [[META0:![0-9]+]] = !{i32 1, !"ProfileSummary", [[META1:![0-9]+]]}
+; CHECK: [[META1]] = !{[[META2:![0-9]+]], [[META3:![0-9]+]], [[META4:![0-9]+]], [[META5:![0-9]+]], [[META6:![0-9]+]], [[META7:![0-9]+]], [[META8:![0-9]+]], [[META9:![0-9]+]]}
+; CHECK: [[META2]] = !{!"ProfileFormat", !"InstrProf"}
+; CHECK: [[META3]] = !{!"TotalCount", i64 3531}
+; CHECK: [[META4]] = !{!"MaxCount", i64 2000}
+; CHECK: [[META5]] = !{!"MaxInternalCount", i64 2000}
+; CHECK: [[META6]] = !{!"MaxFunctionCount", i64 2000}
+; CHECK: [[META7]] = !{!"NumCounts", i64 12}
+; CHECK: [[META8]] = !{!"NumFunctions", i64 12}
+; CHECK: [[META9]] = !{!"DetailedSummary", [[META10:![0-9]+]]}
+; CHECK: [[META10]] = !{[[META11:![0-9]+]]}
+; CHECK: [[META11]] = !{i32 10000, i64 1, i32 1}
+; CHECK: [[PROF12]] = !{!"function_entry_count", i64 2}
+; CHECK: [[PROF13]] = !{!"function_entry_count", i64 3000}
+; CHECK: [[PROF14]] = !{!"function_entry_count", i64 500}
+; CHECK: [[PROF15]] = !{!"synthetic_function_entry_count", i64 15}
+; CHECK: [[PROF16]] = !{!"function_entry_count", i64 7}
+; CHECK: [[PROF17]] = !{!"function_entry_count", i64 5}
+; CHECK: [[PROF18]] = !{!"function_entry_count", i64 1}
+;.
+; ALIAS: [[META0:![0-9]+]] = !{i32 1, !"ProfileSummary", [[META1:![0-9]+]]}
+; ALIAS: [[META1]] = !{[[META2:![0-9]+]], [[META3:![0-9]+]], [[META4:![0-9]+]], [[META5:![0-9]+]], [[META6:![0-9]+]], [[META7:![0-9]+]], [[META8:![0-9]+]], [[META9:![0-9]+]]}
+; ALIAS: [[META2]] = !{!"ProfileFormat", !"InstrProf"}
+; ALIAS: [[META3]] = !{!"TotalCount", i64 3531}
+; ALIAS: [[META4]] = !{!"MaxCount", i64 2000}
+; ALIAS: [[META5]] = !{!"MaxInternalCount", i64 2000}
+; ALIAS: [[META6]] = !{!"MaxFunctionCount", i64 2000}
+; ALIAS: [[META7]] = !{!"NumCounts", i64 12}
+; ALIAS: [[META8]] = !{!"NumFunctions", i64 12}
+; ALIAS: [[META9]] = !{!"DetailedSummary", [[META10:![0-9]+]]}
+; ALIAS: [[META10]] = !{[[META11:![0-9]+]]}
+; ALIAS: [[META11]] = !{i32 10000, i64 1, i32 1}
+; ALIAS: [[PROF12]] = !{!"function_entry_count", i64 2}
+; ALIAS: [[PROF13]] = !{!"function_entry_count", i64 3000}
+; ALIAS: [[PROF14]] = !{!"function_entry_count", i64 500}
+; ALIAS: [[PROF15]] = !{!"synthetic_function_entry_count", i64 15}
+; ALIAS: [[PROF16]] = !{!"function_entry_count", i64 12}
+; ALIAS: [[PROF17]] = !{!"function_entry_count", i64 1}
+;.

>From a24d3cebc91e3a49efa5cdfa99957da50b1fe61c Mon Sep 17 00:00:00 2001
From: Alok Kumar Sharma <AlokKumar.Sharma at amd.com>
Date: Tue, 23 Jun 2026 12:12:38 +0530
Subject: [PATCH 2/3] Addressed review.

---
 llvm/lib/Transforms/IPO/MergeFunctions.cpp    |  23 +-
 .../merge-functions-entry-count-alias.ll      |  51 +++
 .../merge-functions-entry-count-no-alias.ll   | 157 +++++++++
 .../MergeFunc/merge-functions-entry-count.ll  | 330 ------------------
 4 files changed, 215 insertions(+), 346 deletions(-)
 create mode 100644 llvm/test/Transforms/MergeFunc/merge-functions-entry-count-alias.ll
 create mode 100644 llvm/test/Transforms/MergeFunc/merge-functions-entry-count-no-alias.ll
 delete mode 100644 llvm/test/Transforms/MergeFunc/merge-functions-entry-count.ll

diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
index 8110653aac88e..703895cdd5b71 100644
--- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
@@ -734,7 +734,7 @@ static void copyMetadataIfPresent(Function *From, Function *To,
 // For better debugability, under MergeFunctionsPDI, we do not modify G's
 // call sites to point to F even when within the same translation unit.
 void MergeFunctions::writeThunk(Function *F, Function *G) {
-  auto GEC = G->getEntryCount(/*AllowSynthetic=*/true);
+  std::optional<Function::ProfileCount> GEC = G->getEntryCount();
   BasicBlock *GEntryBlock = nullptr;
   std::vector<Instruction *> PDIUnrelatedWL;
   std::vector<DbgVariableRecord *> PDVRUnrelatedWL;
@@ -886,21 +886,15 @@ static void mergeEntryCountsInto(Function *F,
     return;
   uint64_t Sum = SaturatingAdd(FC ? FC->getCount() : uint64_t{0},
                                GC ? GC->getCount() : uint64_t{0});
-  Function::ProfileCountType PCT =
-      ((FC && FC->isSynthetic()) || (GC && GC->isSynthetic()))
-          ? Function::PCT_Synthetic
-          : Function::PCT_Real;
-  if (FC && FC->getType() != PCT) {
-    F->setMetadata(LLVMContext::MD_prof, nullptr);
-    F->setEntryCount(Function::ProfileCount(Sum, PCT));
-    return;
-  }
-  F->setEntryCount(Sum, PCT);
+  F->setEntryCount(Sum);
 }
 
 // Merge two equivalent functions. Upon completion, Function G is deleted.
 void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
 
+  std::optional<Function::ProfileCount> FEC = F->getEntryCount();
+  std::optional<Function::ProfileCount> GEC = G->getEntryCount();
+
   // Create a new thunk that both F and G can call, if F cannot call G directly.
   // That is the case if F is either interposable or if G is either weak_odr or
   // linkonce_odr.
@@ -926,8 +920,6 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
     // Ensure CFI type metadata is propagated to the new function.
     copyMetadataIfPresent(F, NewF, "type");
     copyMetadataIfPresent(F, NewF, "kcfi_type");
-    auto FEC = F->getEntryCount(/*AllowSynthetic=*/true);
-    auto GEC = G->getEntryCount(/*AllowSynthetic=*/true);
     removeUsers(F);
     F->replaceAllUsesWith(NewF);
 
@@ -953,13 +945,12 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
     else
       F->setAlignment(std::nullopt);
     F->setLinkage(GlobalValue::PrivateLinkage);
+    // The private shared implementation accumulates both symbols' entries
+    // (FEC + GEC), while each ODR thunk retains its own per-symbol entry count.
     mergeEntryCountsInto(F, FEC, GEC);
     ++NumDoubleWeak;
     ++NumFunctionsMerged;
   } else {
-    auto FEC = F->getEntryCount(/*AllowSynthetic=*/true);
-    auto GEC = G->getEntryCount(/*AllowSynthetic=*/true);
-
     // For better debugability, under MergeFunctionsPDI, we do not modify G's
     // call sites to point to F even when within the same translation unit.
     if (!G->isInterposable() && !MergeFunctionsPDI) {
diff --git a/llvm/test/Transforms/MergeFunc/merge-functions-entry-count-alias.ll b/llvm/test/Transforms/MergeFunc/merge-functions-entry-count-alias.ll
new file mode 100644
index 0000000000000..16e3717c034a8
--- /dev/null
+++ b/llvm/test/Transforms/MergeFunc/merge-functions-entry-count-alias.ll
@@ -0,0 +1,51 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=mergefunc -mergefunc-use-aliases < %s | FileCheck %s
+
+define void @alias_a() unnamed_addr !prof !12 {
+; CHECK-LABEL: define void @alias_a(
+; CHECK-SAME: ) unnamed_addr !prof [[PROF12:![0-9]+]] {
+; CHECK-NEXT:    ret void
+;
+  ret void
+}
+
+define void @alias_b() unnamed_addr !prof !13 {
+  ret void
+}
+
+define i32 @use(i32 %x) {
+; CHECK-LABEL: define i32 @use(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    call void @alias_a()
+; CHECK-NEXT:    call void @alias_a()
+; CHECK-NEXT:    ret i32 [[X]]
+;
+entry:
+  call void @alias_a()
+  call void @alias_b()
+  ret i32 %x
+}
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 1, !"ProfileSummary", !1}
+!1 = !{!2, !3, !4, !5, !6, !7, !8, !9}
+!2 = !{!"ProfileFormat", !"InstrProf"}
+!3 = !{!"TotalCount", i64 3531}
+!4 = !{!"MaxCount", i64 2000}
+!5 = !{!"MaxInternalCount", i64 2000}
+!6 = !{!"MaxFunctionCount", i64 2000}
+!7 = !{!"NumCounts", i64 12}
+!8 = !{!"NumFunctions", i64 12}
+!9 = !{!"DetailedSummary", !10}
+!10 = !{!11}
+!11 = !{i32 10000, i64 1, i32 1}
+!12 = !{!"function_entry_count", i64 7}
+!13 = !{!"function_entry_count", i64 5}
+;
+;
+;
+;.
+; CHECK: [[PROF12]] = !{!"function_entry_count", i64 12}
+;.
diff --git a/llvm/test/Transforms/MergeFunc/merge-functions-entry-count-no-alias.ll b/llvm/test/Transforms/MergeFunc/merge-functions-entry-count-no-alias.ll
new file mode 100644
index 0000000000000..a03e11a226060
--- /dev/null
+++ b/llvm/test/Transforms/MergeFunc/merge-functions-entry-count-no-alias.ll
@@ -0,0 +1,157 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs --version 6
+; RUN: opt -S -passes=mergefunc < %s | FileCheck %s
+
+ at llvm.used = appending global [2 x ptr] [ptr @odr_a, ptr @odr_b], section "llvm.metadata"
+
+define internal i32 @basic_a(i32 %x) !prof !12 {
+entry:
+  %add = add nsw i32 %x, 1
+  ret i32 %add
+}
+
+define internal i32 @basic_b(i32 %x) !prof !12 {
+entry:
+  %add = add nsw i32 %x, 1
+  ret i32 %add
+}
+
+define internal i32 @asym_a(i32 %x) !prof !13 {
+entry:
+  %add = add nsw i32 %x, 2
+  ret i32 %add
+}
+
+define internal i32 @asym_b(i32 %x) !prof !14 {
+entry:
+  %add = add nsw i32 %x, 2
+  ret i32 %add
+}
+
+define internal i32 @onesided_a(i32 %x) {
+entry:
+  %add = add nsw i32 %x, 3
+  ret i32 %add
+}
+
+define internal i32 @onesided_b(i32 %x) !prof !15 {
+entry:
+  %add = add nsw i32 %x, 3
+  ret i32 %add
+}
+
+define linkonce_odr i32 @odr_a(i32 %x) !prof !12 {
+entry:
+  %add = add nsw i32 %x, 5
+  ret i32 %add
+}
+
+define linkonce_odr i32 @odr_b(i32 %x) !prof !12 {
+entry:
+  %add = add nsw i32 %x, 5
+  ret i32 %add
+}
+
+define i32 @use_counts(i32 %x) {
+entry:
+  %basic = call i32 @basic_a(i32 %x)
+  %basic2 = call i32 @basic_b(i32 %x)
+  %asym = call i32 @asym_a(i32 %x)
+  %asym2 = call i32 @asym_b(i32 %x)
+  %onesided = call i32 @onesided_a(i32 %x)
+  %onesided2 = call i32 @onesided_b(i32 %x)
+  %odr = call i32 @odr_a(i32 %x)
+  %odr2 = call i32 @odr_b(i32 %x)
+  %sum0 = add i32 %basic, %basic2
+  %sum1 = add i32 %sum0, %asym
+  %sum2 = add i32 %sum1, %asym2
+  %sum3 = add i32 %sum2, %onesided
+  %sum4 = add i32 %sum3, %onesided2
+  %sum5 = add i32 %sum4, %odr
+  %sum6 = add i32 %sum5, %odr2
+  ret i32 %sum6
+}
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 1, !"ProfileSummary", !1}
+!1 = !{!2, !3, !4, !5, !6, !7, !8, !9}
+!2 = !{!"ProfileFormat", !"InstrProf"}
+!3 = !{!"TotalCount", i64 3531}
+!4 = !{!"MaxCount", i64 2000}
+!5 = !{!"MaxInternalCount", i64 2000}
+!6 = !{!"MaxFunctionCount", i64 2000}
+!7 = !{!"NumCounts", i64 12}
+!8 = !{!"NumFunctions", i64 12}
+!9 = !{!"DetailedSummary", !10}
+!10 = !{!11}
+!11 = !{i32 10000, i64 1, i32 1}
+!12 = !{!"function_entry_count", i64 1}
+!13 = !{!"function_entry_count", i64 2000}
+!14 = !{!"function_entry_count", i64 1000}
+!15 = !{!"function_entry_count", i64 500}
+; CHECK-LABEL: define internal i32 @basic_a(
+; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF12:![0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 1
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+;
+; CHECK-LABEL: define internal i32 @asym_a(
+; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF13:![0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 2
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+;
+; CHECK-LABEL: define internal i32 @onesided_a(
+; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF14:![0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 3
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+;
+; CHECK-LABEL: define private i32 @0(
+; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF12]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 5
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+;
+; CHECK-LABEL: define i32 @use_counts(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[BASIC:%.*]] = call i32 @basic_a(i32 [[X]])
+; CHECK-NEXT:    [[BASIC2:%.*]] = call i32 @basic_a(i32 [[X]])
+; CHECK-NEXT:    [[ASYM:%.*]] = call i32 @asym_a(i32 [[X]])
+; CHECK-NEXT:    [[ASYM2:%.*]] = call i32 @asym_a(i32 [[X]])
+; CHECK-NEXT:    [[ONESIDED:%.*]] = call i32 @onesided_a(i32 [[X]])
+; CHECK-NEXT:    [[ONESIDED2:%.*]] = call i32 @onesided_a(i32 [[X]])
+; CHECK-NEXT:    [[ODR:%.*]] = call i32 @[[GLOB0:[0-9]+]](i32 [[X]])
+; CHECK-NEXT:    [[ODR2:%.*]] = call i32 @[[GLOB0]](i32 [[X]])
+; CHECK-NEXT:    [[SUM0:%.*]] = add i32 [[BASIC]], [[BASIC2]]
+; CHECK-NEXT:    [[SUM1:%.*]] = add i32 [[SUM0]], [[ASYM]]
+; CHECK-NEXT:    [[SUM2:%.*]] = add i32 [[SUM1]], [[ASYM2]]
+; CHECK-NEXT:    [[SUM3:%.*]] = add i32 [[SUM2]], [[ONESIDED]]
+; CHECK-NEXT:    [[SUM4:%.*]] = add i32 [[SUM3]], [[ONESIDED2]]
+; CHECK-NEXT:    [[SUM5:%.*]] = add i32 [[SUM4]], [[ODR]]
+; CHECK-NEXT:    [[SUM6:%.*]] = add i32 [[SUM5]], [[ODR2]]
+; CHECK-NEXT:    ret i32 [[SUM6]]
+;
+;
+; CHECK-LABEL: define linkonce_odr i32 @odr_b(
+; CHECK-SAME: i32 [[TMP0:%.*]]) !prof [[PROF15:![0-9]+]] {
+; CHECK-NEXT:    [[TMP2:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]])
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+;
+; CHECK-LABEL: define linkonce_odr i32 @odr_a(
+; CHECK-SAME: i32 [[TMP0:%.*]]) !prof [[PROF15]] {
+; CHECK-NEXT:    [[TMP2:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]])
+; CHECK-NEXT:    ret i32 [[TMP2]]
+;
+;.
+; CHECK: [[PROF12]] = !{!"function_entry_count", i64 2}
+; CHECK: [[PROF13]] = !{!"function_entry_count", i64 3000}
+; CHECK: [[PROF14]] = !{!"function_entry_count", i64 500}
+; CHECK: [[PROF15]] = !{!"function_entry_count", i64 1}
+;.
diff --git a/llvm/test/Transforms/MergeFunc/merge-functions-entry-count.ll b/llvm/test/Transforms/MergeFunc/merge-functions-entry-count.ll
deleted file mode 100644
index 7bcab278b7055..0000000000000
--- a/llvm/test/Transforms/MergeFunc/merge-functions-entry-count.ll
+++ /dev/null
@@ -1,330 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 5
-; RUN: opt -S -passes=mergefunc < %s | FileCheck %s
-; RUN: opt -S -passes=mergefunc -mergefunc-use-aliases < %s | FileCheck %s --check-prefix=ALIAS
-
-define internal i32 @basic_a(i32 %x) !prof !1 {
-entry:
-  %add = add nsw i32 %x, 1
-  ret i32 %add
-}
-
-define internal i32 @basic_b(i32 %x) !prof !1 {
-entry:
-  %add = add nsw i32 %x, 1
-  ret i32 %add
-}
-
-define internal i32 @asym_a(i32 %x) !prof !2 {
-entry:
-  %add = add nsw i32 %x, 2
-  ret i32 %add
-}
-
-define internal i32 @asym_b(i32 %x) !prof !3 {
-entry:
-  %add = add nsw i32 %x, 2
-  ret i32 %add
-}
-
-define internal i32 @onesided_a(i32 %x) {
-entry:
-  %add = add nsw i32 %x, 3
-  ret i32 %add
-}
-
-define internal i32 @onesided_b(i32 %x) !prof !4 {
-entry:
-  %add = add nsw i32 %x, 3
-  ret i32 %add
-}
-
-define internal i32 @real_synth_a(i32 %x) !prof !5 {
-entry:
-  %add = add nsw i32 %x, 4
-  ret i32 %add
-}
-
-define internal i32 @real_synth_b(i32 %x) !prof !6 {
-entry:
-  %add = add nsw i32 %x, 4
-  ret i32 %add
-}
-
-define linkonce_odr i32 @odr_a(i32 %x) !prof !1 {
-entry:
-  %add = add nsw i32 %x, 5
-  ret i32 %add
-}
-
-define linkonce_odr i32 @odr_b(i32 %x) !prof !1 {
-entry:
-  %add = add nsw i32 %x, 5
-  ret i32 %add
-}
-
- at llvm.used = appending global [2 x ptr] [ptr @odr_a, ptr @odr_b], section "llvm.metadata"
-
-define void @alias_a() unnamed_addr !prof !7 {
-  ret void
-}
-
-define void @alias_b() unnamed_addr !prof !8 {
-  ret void
-}
-
-define i32 @use_counts(i32 %x) {
-entry:
-  %basic = call i32 @basic_a(i32 %x)
-  %basic2 = call i32 @basic_b(i32 %x)
-  %asym = call i32 @asym_a(i32 %x)
-  %asym2 = call i32 @asym_b(i32 %x)
-  %onesided = call i32 @onesided_a(i32 %x)
-  %onesided2 = call i32 @onesided_b(i32 %x)
-  %real_synth = call i32 @real_synth_a(i32 %x)
-  %real_synth2 = call i32 @real_synth_b(i32 %x)
-  %odr = call i32 @odr_a(i32 %x)
-  %odr2 = call i32 @odr_b(i32 %x)
-  call void @alias_a()
-  call void @alias_b()
-  %sum0 = add i32 %basic, %basic2
-  %sum1 = add i32 %sum0, %asym
-  %sum2 = add i32 %sum1, %asym2
-  %sum3 = add i32 %sum2, %onesided
-  %sum4 = add i32 %sum3, %onesided2
-  %sum5 = add i32 %sum4, %real_synth
-  %sum6 = add i32 %sum5, %real_synth2
-  %sum7 = add i32 %sum6, %odr
-  %sum8 = add i32 %sum7, %odr2
-  ret i32 %sum8
-}
-
-!llvm.module.flags = !{!0}
-
-!0 = !{i32 1, !"ProfileSummary", !9}
-!1 = !{!"function_entry_count", i64 1}
-!2 = !{!"function_entry_count", i64 2000}
-!3 = !{!"function_entry_count", i64 1000}
-!4 = !{!"function_entry_count", i64 500}
-!5 = !{!"function_entry_count", i64 10}
-!6 = !{!"synthetic_function_entry_count", i64 5}
-!7 = !{!"function_entry_count", i64 7}
-!8 = !{!"function_entry_count", i64 5}
-!9 = !{!10, !11, !12, !13, !14, !15, !16, !17}
-!10 = !{!"ProfileFormat", !"InstrProf"}
-!11 = !{!"TotalCount", i64 3531}
-!12 = !{!"MaxCount", i64 2000}
-!13 = !{!"MaxInternalCount", i64 2000}
-!14 = !{!"MaxFunctionCount", i64 2000}
-!15 = !{!"NumCounts", i64 12}
-!16 = !{!"NumFunctions", i64 12}
-!17 = !{!"DetailedSummary", !18}
-!18 = !{!19}
-!19 = !{i32 10000, i64 1, i32 1}
-;.
-; CHECK: @llvm.used = appending global [2 x ptr] [ptr @odr_a, ptr @odr_b], section "llvm.metadata"
-;.
-; ALIAS: @llvm.used = appending global [2 x ptr] [ptr @odr_a, ptr @odr_b], section "llvm.metadata"
-; ALIAS: @alias_b = unnamed_addr alias void (), ptr @alias_a
-;.
-; CHECK-LABEL: define internal i32 @basic_a(
-; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF12:![0-9]+]] {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 1
-; CHECK-NEXT:    ret i32 [[ADD]]
-;
-;
-; CHECK-LABEL: define internal i32 @asym_a(
-; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF13:![0-9]+]] {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 2
-; CHECK-NEXT:    ret i32 [[ADD]]
-;
-;
-; CHECK-LABEL: define internal i32 @onesided_a(
-; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF14:![0-9]+]] {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 3
-; CHECK-NEXT:    ret i32 [[ADD]]
-;
-;
-; CHECK-LABEL: define internal i32 @real_synth_a(
-; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF15:![0-9]+]] {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 4
-; CHECK-NEXT:    ret i32 [[ADD]]
-;
-;
-; CHECK-LABEL: define private i32 @0(
-; CHECK-SAME: i32 [[X:%.*]]) !prof [[PROF12]] {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 5
-; CHECK-NEXT:    ret i32 [[ADD]]
-;
-;
-; CHECK-LABEL: define void @alias_a(
-; CHECK-SAME: ) unnamed_addr !prof [[PROF16:![0-9]+]] {
-; CHECK-NEXT:    ret void
-;
-;
-; CHECK-LABEL: define void @alias_b(
-; CHECK-SAME: ) unnamed_addr !prof [[PROF17:![0-9]+]] {
-; CHECK-NEXT:    ret void
-;
-;
-; CHECK-LABEL: define i32 @use_counts(
-; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[BASIC:%.*]] = call i32 @basic_a(i32 [[X]])
-; CHECK-NEXT:    [[BASIC2:%.*]] = call i32 @basic_a(i32 [[X]])
-; CHECK-NEXT:    [[ASYM:%.*]] = call i32 @asym_a(i32 [[X]])
-; CHECK-NEXT:    [[ASYM2:%.*]] = call i32 @asym_a(i32 [[X]])
-; CHECK-NEXT:    [[ONESIDED:%.*]] = call i32 @onesided_a(i32 [[X]])
-; CHECK-NEXT:    [[ONESIDED2:%.*]] = call i32 @onesided_a(i32 [[X]])
-; CHECK-NEXT:    [[REAL_SYNTH:%.*]] = call i32 @real_synth_a(i32 [[X]])
-; CHECK-NEXT:    [[REAL_SYNTH2:%.*]] = call i32 @real_synth_a(i32 [[X]])
-; CHECK-NEXT:    [[ODR:%.*]] = call i32 @[[GLOB0:[0-9]+]](i32 [[X]])
-; CHECK-NEXT:    [[ODR2:%.*]] = call i32 @[[GLOB0]](i32 [[X]])
-; CHECK-NEXT:    call void @alias_a()
-; CHECK-NEXT:    call void @alias_a()
-; CHECK-NEXT:    [[SUM0:%.*]] = add i32 [[BASIC]], [[BASIC2]]
-; CHECK-NEXT:    [[SUM1:%.*]] = add i32 [[SUM0]], [[ASYM]]
-; CHECK-NEXT:    [[SUM2:%.*]] = add i32 [[SUM1]], [[ASYM2]]
-; CHECK-NEXT:    [[SUM3:%.*]] = add i32 [[SUM2]], [[ONESIDED]]
-; CHECK-NEXT:    [[SUM4:%.*]] = add i32 [[SUM3]], [[ONESIDED2]]
-; CHECK-NEXT:    [[SUM5:%.*]] = add i32 [[SUM4]], [[REAL_SYNTH]]
-; CHECK-NEXT:    [[SUM6:%.*]] = add i32 [[SUM5]], [[REAL_SYNTH2]]
-; CHECK-NEXT:    [[SUM7:%.*]] = add i32 [[SUM6]], [[ODR]]
-; CHECK-NEXT:    [[SUM8:%.*]] = add i32 [[SUM7]], [[ODR2]]
-; CHECK-NEXT:    ret i32 [[SUM8]]
-;
-;
-; CHECK-LABEL: define linkonce_odr i32 @odr_b(
-; CHECK-SAME: i32 [[TMP0:%.*]]) !prof [[PROF18:![0-9]+]] {
-; CHECK-NEXT:    [[TMP2:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]])
-; CHECK-NEXT:    ret i32 [[TMP2]]
-;
-;
-; CHECK-LABEL: define linkonce_odr i32 @odr_a(
-; CHECK-SAME: i32 [[TMP0:%.*]]) !prof [[PROF18]] {
-; CHECK-NEXT:    [[TMP2:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]])
-; CHECK-NEXT:    ret i32 [[TMP2]]
-;
-;
-; ALIAS-LABEL: define internal i32 @basic_a(
-; ALIAS-SAME: i32 [[X:%.*]]) !prof [[PROF12:![0-9]+]] {
-; ALIAS-NEXT:  [[ENTRY:.*:]]
-; ALIAS-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 1
-; ALIAS-NEXT:    ret i32 [[ADD]]
-;
-;
-; ALIAS-LABEL: define internal i32 @asym_a(
-; ALIAS-SAME: i32 [[X:%.*]]) !prof [[PROF13:![0-9]+]] {
-; ALIAS-NEXT:  [[ENTRY:.*:]]
-; ALIAS-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 2
-; ALIAS-NEXT:    ret i32 [[ADD]]
-;
-;
-; ALIAS-LABEL: define internal i32 @onesided_a(
-; ALIAS-SAME: i32 [[X:%.*]]) !prof [[PROF14:![0-9]+]] {
-; ALIAS-NEXT:  [[ENTRY:.*:]]
-; ALIAS-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 3
-; ALIAS-NEXT:    ret i32 [[ADD]]
-;
-;
-; ALIAS-LABEL: define internal i32 @real_synth_a(
-; ALIAS-SAME: i32 [[X:%.*]]) !prof [[PROF15:![0-9]+]] {
-; ALIAS-NEXT:  [[ENTRY:.*:]]
-; ALIAS-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 4
-; ALIAS-NEXT:    ret i32 [[ADD]]
-;
-;
-; ALIAS-LABEL: define private i32 @0(
-; ALIAS-SAME: i32 [[X:%.*]]) !prof [[PROF12]] {
-; ALIAS-NEXT:  [[ENTRY:.*:]]
-; ALIAS-NEXT:    [[ADD:%.*]] = add nsw i32 [[X]], 5
-; ALIAS-NEXT:    ret i32 [[ADD]]
-;
-;
-; ALIAS-LABEL: define void @alias_a(
-; ALIAS-SAME: ) unnamed_addr !prof [[PROF16:![0-9]+]] {
-; ALIAS-NEXT:    ret void
-;
-;
-; ALIAS-LABEL: define i32 @use_counts(
-; ALIAS-SAME: i32 [[X:%.*]]) {
-; ALIAS-NEXT:  [[ENTRY:.*:]]
-; ALIAS-NEXT:    [[BASIC:%.*]] = call i32 @basic_a(i32 [[X]])
-; ALIAS-NEXT:    [[BASIC2:%.*]] = call i32 @basic_a(i32 [[X]])
-; ALIAS-NEXT:    [[ASYM:%.*]] = call i32 @asym_a(i32 [[X]])
-; ALIAS-NEXT:    [[ASYM2:%.*]] = call i32 @asym_a(i32 [[X]])
-; ALIAS-NEXT:    [[ONESIDED:%.*]] = call i32 @onesided_a(i32 [[X]])
-; ALIAS-NEXT:    [[ONESIDED2:%.*]] = call i32 @onesided_a(i32 [[X]])
-; ALIAS-NEXT:    [[REAL_SYNTH:%.*]] = call i32 @real_synth_a(i32 [[X]])
-; ALIAS-NEXT:    [[REAL_SYNTH2:%.*]] = call i32 @real_synth_a(i32 [[X]])
-; ALIAS-NEXT:    [[ODR:%.*]] = call i32 @[[GLOB0:[0-9]+]](i32 [[X]])
-; ALIAS-NEXT:    [[ODR2:%.*]] = call i32 @[[GLOB0]](i32 [[X]])
-; ALIAS-NEXT:    call void @alias_a()
-; ALIAS-NEXT:    call void @alias_a()
-; ALIAS-NEXT:    [[SUM0:%.*]] = add i32 [[BASIC]], [[BASIC2]]
-; ALIAS-NEXT:    [[SUM1:%.*]] = add i32 [[SUM0]], [[ASYM]]
-; ALIAS-NEXT:    [[SUM2:%.*]] = add i32 [[SUM1]], [[ASYM2]]
-; ALIAS-NEXT:    [[SUM3:%.*]] = add i32 [[SUM2]], [[ONESIDED]]
-; ALIAS-NEXT:    [[SUM4:%.*]] = add i32 [[SUM3]], [[ONESIDED2]]
-; ALIAS-NEXT:    [[SUM5:%.*]] = add i32 [[SUM4]], [[REAL_SYNTH]]
-; ALIAS-NEXT:    [[SUM6:%.*]] = add i32 [[SUM5]], [[REAL_SYNTH2]]
-; ALIAS-NEXT:    [[SUM7:%.*]] = add i32 [[SUM6]], [[ODR]]
-; ALIAS-NEXT:    [[SUM8:%.*]] = add i32 [[SUM7]], [[ODR2]]
-; ALIAS-NEXT:    ret i32 [[SUM8]]
-;
-;
-; ALIAS-LABEL: define linkonce_odr i32 @odr_b(
-; ALIAS-SAME: i32 [[TMP0:%.*]]) !prof [[PROF17:![0-9]+]] {
-; ALIAS-NEXT:    [[TMP2:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]])
-; ALIAS-NEXT:    ret i32 [[TMP2]]
-;
-;
-; ALIAS-LABEL: define linkonce_odr i32 @odr_a(
-; ALIAS-SAME: i32 [[TMP0:%.*]]) !prof [[PROF17]] {
-; ALIAS-NEXT:    [[TMP2:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]])
-; ALIAS-NEXT:    ret i32 [[TMP2]]
-;
-;.
-; CHECK: [[META0:![0-9]+]] = !{i32 1, !"ProfileSummary", [[META1:![0-9]+]]}
-; CHECK: [[META1]] = !{[[META2:![0-9]+]], [[META3:![0-9]+]], [[META4:![0-9]+]], [[META5:![0-9]+]], [[META6:![0-9]+]], [[META7:![0-9]+]], [[META8:![0-9]+]], [[META9:![0-9]+]]}
-; CHECK: [[META2]] = !{!"ProfileFormat", !"InstrProf"}
-; CHECK: [[META3]] = !{!"TotalCount", i64 3531}
-; CHECK: [[META4]] = !{!"MaxCount", i64 2000}
-; CHECK: [[META5]] = !{!"MaxInternalCount", i64 2000}
-; CHECK: [[META6]] = !{!"MaxFunctionCount", i64 2000}
-; CHECK: [[META7]] = !{!"NumCounts", i64 12}
-; CHECK: [[META8]] = !{!"NumFunctions", i64 12}
-; CHECK: [[META9]] = !{!"DetailedSummary", [[META10:![0-9]+]]}
-; CHECK: [[META10]] = !{[[META11:![0-9]+]]}
-; CHECK: [[META11]] = !{i32 10000, i64 1, i32 1}
-; CHECK: [[PROF12]] = !{!"function_entry_count", i64 2}
-; CHECK: [[PROF13]] = !{!"function_entry_count", i64 3000}
-; CHECK: [[PROF14]] = !{!"function_entry_count", i64 500}
-; CHECK: [[PROF15]] = !{!"synthetic_function_entry_count", i64 15}
-; CHECK: [[PROF16]] = !{!"function_entry_count", i64 7}
-; CHECK: [[PROF17]] = !{!"function_entry_count", i64 5}
-; CHECK: [[PROF18]] = !{!"function_entry_count", i64 1}
-;.
-; ALIAS: [[META0:![0-9]+]] = !{i32 1, !"ProfileSummary", [[META1:![0-9]+]]}
-; ALIAS: [[META1]] = !{[[META2:![0-9]+]], [[META3:![0-9]+]], [[META4:![0-9]+]], [[META5:![0-9]+]], [[META6:![0-9]+]], [[META7:![0-9]+]], [[META8:![0-9]+]], [[META9:![0-9]+]]}
-; ALIAS: [[META2]] = !{!"ProfileFormat", !"InstrProf"}
-; ALIAS: [[META3]] = !{!"TotalCount", i64 3531}
-; ALIAS: [[META4]] = !{!"MaxCount", i64 2000}
-; ALIAS: [[META5]] = !{!"MaxInternalCount", i64 2000}
-; ALIAS: [[META6]] = !{!"MaxFunctionCount", i64 2000}
-; ALIAS: [[META7]] = !{!"NumCounts", i64 12}
-; ALIAS: [[META8]] = !{!"NumFunctions", i64 12}
-; ALIAS: [[META9]] = !{!"DetailedSummary", [[META10:![0-9]+]]}
-; ALIAS: [[META10]] = !{[[META11:![0-9]+]]}
-; ALIAS: [[META11]] = !{i32 10000, i64 1, i32 1}
-; ALIAS: [[PROF12]] = !{!"function_entry_count", i64 2}
-; ALIAS: [[PROF13]] = !{!"function_entry_count", i64 3000}
-; ALIAS: [[PROF14]] = !{!"function_entry_count", i64 500}
-; ALIAS: [[PROF15]] = !{!"synthetic_function_entry_count", i64 15}
-; ALIAS: [[PROF16]] = !{!"function_entry_count", i64 12}
-; ALIAS: [[PROF17]] = !{!"function_entry_count", i64 1}
-;.

>From f1a8e123a6244e6c0556b7586344a58534a13349 Mon Sep 17 00:00:00 2001
From: Alok Kumar Sharma <AlokKumar.Sharma at amd.com>
Date: Tue, 30 Jun 2026 11:04:58 +0530
Subject: [PATCH 3/3] Fixed build failure on rebase caused due to API change.

---
 llvm/lib/Transforms/IPO/MergeFunctions.cpp | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
index 703895cdd5b71..d407511880a99 100644
--- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
@@ -734,7 +734,7 @@ static void copyMetadataIfPresent(Function *From, Function *To,
 // For better debugability, under MergeFunctionsPDI, we do not modify G's
 // call sites to point to F even when within the same translation unit.
 void MergeFunctions::writeThunk(Function *F, Function *G) {
-  std::optional<Function::ProfileCount> GEC = G->getEntryCount();
+  std::optional<uint64_t> GEC = G->getEntryCount();
   BasicBlock *GEntryBlock = nullptr;
   std::vector<Instruction *> PDIUnrelatedWL;
   std::vector<DbgVariableRecord *> PDVRUnrelatedWL;
@@ -879,21 +879,19 @@ static bool isODR(const Function *F) {
   return F->hasWeakODRLinkage() || F->hasLinkOnceODRLinkage();
 }
 
-static void mergeEntryCountsInto(Function *F,
-                                 std::optional<Function::ProfileCount> FC,
-                                 std::optional<Function::ProfileCount> GC) {
+static void mergeEntryCountsInto(Function *F, std::optional<uint64_t> FC,
+                                 std::optional<uint64_t> GC) {
   if (!FC && !GC)
     return;
-  uint64_t Sum = SaturatingAdd(FC ? FC->getCount() : uint64_t{0},
-                               GC ? GC->getCount() : uint64_t{0});
+  uint64_t Sum = SaturatingAdd(FC ? *FC : uint64_t{0}, GC ? *GC : uint64_t{0});
   F->setEntryCount(Sum);
 }
 
 // Merge two equivalent functions. Upon completion, Function G is deleted.
 void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
 
-  std::optional<Function::ProfileCount> FEC = F->getEntryCount();
-  std::optional<Function::ProfileCount> GEC = G->getEntryCount();
+  std::optional<uint64_t> FEC = F->getEntryCount();
+  std::optional<uint64_t> GEC = G->getEntryCount();
 
   // Create a new thunk that both F and G can call, if F cannot call G directly.
   // That is the case if F is either interposable or if G is either weak_odr or



More information about the llvm-commits mailing list