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

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 30 22:53:08 PDT 2026


Author: Alok Kumar Sharma
Date: 2026-07-01T11:23:03+05:30
New Revision: 25d46e474debb04c55127e77fde8c99b61f2c065

URL: https://github.com/llvm/llvm-project/commit/25d46e474debb04c55127e77fde8c99b61f2c065
DIFF: https://github.com/llvm/llvm-project/commit/25d46e474debb04c55127e77fde8c99b61f2c065.diff

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

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

Added: 
    llvm/test/Transforms/MergeFunc/merge-functions-entry-count-alias.ll
    llvm/test/Transforms/MergeFunc/merge-functions-entry-count-no-alias.ll

Modified: 
    llvm/lib/Transforms/IPO/MergeFunctions.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
index 0b2315faaeb94..c4e56855ea2fb 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) {
+  std::optional<uint64_t> GEC = G->getEntryCount();
   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");
@@ -875,9 +880,20 @@ static bool isODR(const Function *F) {
   return F->hasWeakODRLinkage() || F->hasLinkOnceODRLinkage();
 }
 
+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 : 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<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
   // linkonce_odr.
@@ -920,6 +936,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)
@@ -927,6 +945,9 @@ 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 {
@@ -954,12 +975,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-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}
+;.


        


More information about the llvm-commits mailing list