[llvm] Revert "[MergeFunctions] Preserve instruction-level profile metadata during merging" (PR #209987)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 16 00:01:12 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Nikita Popov (nikic)

<details>
<summary>Changes</summary>

Reverts llvm/llvm-project#<!-- -->208009

Causes unit test failures.

---

Patch is 45.03 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/209987.diff


7 Files Affected:

- (modified) llvm/include/llvm/Transforms/IPO/MergeFunctions.h (+2-2) 
- (modified) llvm/lib/Transforms/IPO/MergeFunctions.cpp (+32-247) 
- (removed) llvm/test/Transforms/MergeFunc/merge-functions-branch-weights.ll (-239) 
- (removed) llvm/test/Transforms/MergeFunc/merge-functions-reordered-blocks-branch-weights.ll (-121) 
- (removed) llvm/test/Transforms/MergeFunc/merge-functions-select-weights.ll (-50) 
- (removed) llvm/test/Transforms/MergeFunc/merge-functions-value-profile.ll (-142) 
- (modified) llvm/unittests/Transforms/IPO/MergeFunctionsTest.cpp (+27-48) 


``````````diff
diff --git a/llvm/include/llvm/Transforms/IPO/MergeFunctions.h b/llvm/include/llvm/Transforms/IPO/MergeFunctions.h
index d28d6167e5555..75399d3297a05 100644
--- a/llvm/include/llvm/Transforms/IPO/MergeFunctions.h
+++ b/llvm/include/llvm/Transforms/IPO/MergeFunctions.h
@@ -28,9 +28,9 @@ class MergeFunctionsPass : public OptionalPassInfoMixin<MergeFunctionsPass> {
 public:
   LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
 
-  LLVM_ABI static bool runOnModule(Module &M, ModuleAnalysisManager &AM);
+  LLVM_ABI static bool runOnModule(Module &M);
   LLVM_ABI static DenseMap<Function *, Function *>
-  runOnFunctions(ArrayRef<Function *> Funcs, ModuleAnalysisManager &AM);
+  runOnFunctions(ArrayRef<Function *> F);
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
index afe80da5843ca..c4e56855ea2fb 100644
--- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
@@ -89,15 +89,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Transforms/IPO/MergeFunctions.h"
-#include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/PostOrderIterator.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/BlockFrequencyInfo.h"
-#include "llvm/Analysis/BranchProbabilityInfo.h"
 #include "llvm/IR/Argument.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/DebugInfoMetadata.h"
@@ -110,21 +104,16 @@
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
-#include "llvm/IR/PassManager.h"
-#include "llvm/IR/ProfDataUtils.h"
 #include "llvm/IR/StructuralHash.h"
 #include "llvm/IR/Type.h"
 #include "llvm/IR/Use.h"
 #include "llvm/IR/User.h"
 #include "llvm/IR/Value.h"
 #include "llvm/IR/ValueHandle.h"
-#include "llvm/ProfileData/InstrProf.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Transforms/IPO.h"
@@ -132,10 +121,7 @@
 #include "llvm/Transforms/Utils/ModuleUtils.h"
 #include <algorithm>
 #include <cassert>
-#include <cstddef>
-#include <cstdint>
 #include <iterator>
-#include <memory>
 #include <optional>
 #include <set>
 #include <utility>
@@ -208,11 +194,11 @@ class FunctionNode {
 /// bitcast of the other.
 class MergeFunctions {
 public:
-  explicit MergeFunctions(FunctionAnalysisManager &FAM)
-      : FnTree(FunctionNodeCmp(&GlobalNumbers)), FAM(FAM) {}
+  MergeFunctions() : FnTree(FunctionNodeCmp(&GlobalNumbers)) {
+  }
 
   template <typename FuncContainer> bool run(FuncContainer &Functions);
-  DenseMap<Function *, Function *> runOnFunctions(ArrayRef<Function *> Funcs);
+  DenseMap<Function *, Function *> runOnFunctions(ArrayRef<Function *> F);
 
   SmallPtrSet<GlobalValue *, 4> &getUsed();
 
@@ -271,8 +257,6 @@ class MergeFunctions {
   /// again.
   void mergeTwoFunctions(Function *F, Function *G);
 
-  void mergeInstrProfMetadataInto(Function *Dst, Function *Src);
-
   /// Fill PDIUnrelatedWL with instructions from the entry block that are
   /// unrelated to parameter related debug info.
   /// \param PDVRUnrelatedWL The equivalent non-intrinsic debug records.
@@ -303,9 +287,7 @@ class MergeFunctions {
   // If needed, replace G with an alias to F if possible, or a thunk to F if
   // profitable. Returns false if neither is the case. If \p G is not needed
   // (i.e. it is discardable and not used), \p G is removed directly.
-  // \p MergeProfile must be true when G's profile should be preserved, it is
-  // merged into F before G is erased or rewritten.
-  bool writeThunkOrAliasIfNeeded(Function *F, Function *G, bool MergeProfile);
+  bool writeThunkOrAliasIfNeeded(Function *F, Function *G);
 
   /// Replace function F with function G in the function tree.
   void replaceFunctionInTree(const FunctionNode &FN, Function *G);
@@ -323,23 +305,20 @@ class MergeFunctions {
 
   /// Deleted-New functions mapping
   DenseMap<Function *, Function *> DelToNewMap;
-
-  FunctionAnalysisManager &FAM;
 };
 } // end anonymous namespace
 
 PreservedAnalyses MergeFunctionsPass::run(Module &M,
                                           ModuleAnalysisManager &AM) {
-  if (!MergeFunctionsPass::runOnModule(M, AM))
+  if (!MergeFunctionsPass::runOnModule(M))
     return PreservedAnalyses::all();
   return PreservedAnalyses::none();
 }
 
 SmallPtrSet<GlobalValue *, 4> &MergeFunctions::getUsed() { return Used; }
 
-bool MergeFunctionsPass::runOnModule(Module &M, ModuleAnalysisManager &AM) {
-  auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
-  MergeFunctions MF(FAM);
+bool MergeFunctionsPass::runOnModule(Module &M) {
+  MergeFunctions MF;
   SmallVector<GlobalValue *, 4> UsedV;
   collectUsedGlobalVariables(M, UsedV, /*CompilerUsed=*/false);
   collectUsedGlobalVariables(M, UsedV, /*CompilerUsed=*/true);
@@ -348,15 +327,9 @@ bool MergeFunctionsPass::runOnModule(Module &M, ModuleAnalysisManager &AM) {
 }
 
 DenseMap<Function *, Function *>
-MergeFunctionsPass::runOnFunctions(ArrayRef<Function *> Funcs,
-                                   ModuleAnalysisManager &AM) {
-  if (Funcs.empty())
-    return DenseMap<Function *, Function *>();
-
-  Module &M = *Funcs.front()->getParent();
-  auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
-  MergeFunctions MF(FAM);
-  return MF.runOnFunctions(Funcs);
+MergeFunctionsPass::runOnFunctions(ArrayRef<Function *> F) {
+  MergeFunctions MF;
+  return MF.runOnFunctions(F);
 }
 
 #ifndef NDEBUG
@@ -520,8 +493,8 @@ template <typename FuncContainer> bool MergeFunctions::run(FuncContainer &M) {
 }
 
 DenseMap<Function *, Function *>
-MergeFunctions::runOnFunctions(ArrayRef<Function *> Funcs) {
-  [[maybe_unused]] bool MergeResult = this->run(Funcs);
+MergeFunctions::runOnFunctions(ArrayRef<Function *> F) {
+  [[maybe_unused]] bool MergeResult = this->run(F);
   assert(MergeResult == !DelToNewMap.empty());
   return this->DelToNewMap;
 }
@@ -761,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<uint64_t> GEntryCount = G->getEntryCount();
+  std::optional<uint64_t> GEC = G->getEntryCount();
   BasicBlock *GEntryBlock = nullptr;
   std::vector<Instruction *> PDIUnrelatedWL;
   std::vector<DbgVariableRecord *> PDVRUnrelatedWL;
@@ -831,8 +804,8 @@ void MergeFunctions::writeThunk(Function *F, Function *G) {
                << G->getName() << "()\n");
   } else {
     NewG->copyAttributesFrom(G);
-    if (GEntryCount)
-      NewG->setEntryCount(*GEntryCount);
+    if (GEC)
+      NewG->setEntryCount(*GEC);
     NewG->takeName(G);
     // Ensure CFI type metadata is propagated to the new function.
     copyMetadataIfPresent(G, NewG, "type");
@@ -885,36 +858,21 @@ void MergeFunctions::writeAlias(Function *F, Function *G) {
 
 // If needed, replace G with an alias to F if possible, or a thunk to F if
 // profitable. Returns false if neither is the case. If \p G is not needed (i.e.
-// it is discardable and unused), \p G is removed directly. If \p MergeProfile
-// is set, G's profile metadata is merged into F.
-bool MergeFunctions::writeThunkOrAliasIfNeeded(Function *F, Function *G,
-                                               bool MergeProfile) {
-  bool ShouldErase =
-      G->isDiscardableIfUnused() && G->use_empty() && !MergeFunctionsPDI;
-  bool ShouldAlias = canCreateAliasFor(G);
-  bool ShouldThunk = canCreateThunkFor(F);
-
-  if (!ShouldErase && !ShouldAlias && !ShouldThunk)
-    return false;
-
-  if (MergeProfile)
-    mergeInstrProfMetadataInto(F, G);
-
-  if (ShouldErase) {
+// it is discardable and unused), \p G is removed directly.
+bool MergeFunctions::writeThunkOrAliasIfNeeded(Function *F, Function *G) {
+  if (G->isDiscardableIfUnused() && G->use_empty() && !MergeFunctionsPDI) {
     G->eraseFromParent();
     return true;
   }
-
-  if (ShouldAlias) {
+  if (canCreateAliasFor(G)) {
     writeAlias(F, G);
     return true;
   }
-  if (ShouldThunk) {
+  if (canCreateThunkFor(F)) {
     writeThunk(F, G);
     return true;
   }
-
-  llvm_unreachable("Erase, alias or thunk must apply");
+  return false;
 }
 
 /// Returns true if \p F is either weak_odr or linkonce_odr.
@@ -922,174 +880,6 @@ static bool isODR(const Function *F) {
   return F->hasWeakODRLinkage() || F->hasLinkOnceODRLinkage();
 }
 
-static uint64_t getBlockCountForMerging(const BlockFrequencyInfo &BFI,
-                                        const BasicBlock *BB) {
-  if (auto Count = BFI.getBlockProfileCount(BB, /*AllowSynthetic=*/true))
-    return *Count;
-  return 1;
-}
-
-// The branch weights are relative within a function. Before merging we
-// normalize these to absolute counts.
-// (weight * BlockCount / TotalWeight)
-static uint64_t scaleToBlockCount(uint64_t Weight, uint64_t TotalWeight,
-                                  uint64_t BlockCount) {
-  if (Weight == 0 || TotalWeight == 0 || BlockCount == 0)
-    return 0;
-  APInt Num(128, BlockCount);
-  Num *= APInt(128, Weight);
-  APInt Den(128, TotalWeight);
-  Num = (Num + Den.lshr(1)).udiv(Den);
-  assert(Num.getActiveBits() <= 64 &&
-         "scaleToBlockCount: result exceeds uint64_t; Weight > TotalWeight?");
-  return Num.getLimitedValue();
-}
-
-// Combine the scaled branch_weights of corresponding instructions of F and G.
-static void mergeBranchWeightsOnInstructions(Instruction *DstI,
-                                             const Instruction *SrcI,
-                                             const BlockFrequencyInfo &DstBFI,
-                                             const BlockFrequencyInfo &SrcBFI) {
-  SmallVector<uint32_t, 8> DstWeights, SrcWeights;
-  bool HasDst = extractBranchWeights(*DstI, DstWeights);
-  bool HasSrc = extractBranchWeights(*SrcI, SrcWeights);
-  if (!HasDst && !HasSrc)
-    return;
-
-  uint64_t DstBlockCount = getBlockCountForMerging(DstBFI, DstI->getParent());
-  uint64_t SrcBlockCount = getBlockCountForMerging(SrcBFI, SrcI->getParent());
-
-  uint64_t DstTotal = 0, SrcTotal = 0;
-  if (HasDst)
-    extractProfTotalWeight(*DstI, DstTotal);
-  if (HasSrc)
-    extractProfTotalWeight(*SrcI, SrcTotal);
-
-  assert((!HasDst || !HasSrc || DstWeights.size() == SrcWeights.size()) &&
-         "equivalent branch/select instructions must have matching weight "
-         "arity");
-  size_t NumWeights = HasDst ? DstWeights.size() : SrcWeights.size();
-  SmallVector<uint64_t, 8> MergedWeights;
-  MergedWeights.reserve(NumWeights);
-  for (size_t I = 0; I < NumWeights; ++I) {
-    uint64_t DstW = HasDst ? DstWeights[I] : 0;
-    uint64_t SrcW = HasSrc ? SrcWeights[I] : 0;
-    uint64_t DstAbs = scaleToBlockCount(DstW, DstTotal, DstBlockCount);
-    uint64_t SrcAbs = scaleToBlockCount(SrcW, SrcTotal, SrcBlockCount);
-    MergedWeights.push_back(SaturatingAdd(DstAbs, SrcAbs));
-  }
-
-  bool IsExpected =
-      hasBranchWeightOrigin(*DstI) && hasBranchWeightOrigin(*SrcI);
-  setFittedBranchWeights(*DstI, MergedWeights, IsExpected);
-}
-
-// Accumulate value profile counts of Instruction I into Merged. Value profile
-// counts are absolute, not relative branch-style weights.
-static void addValueProfile(const Instruction &I, InstrProfValueKind Kind,
-                            DenseMap<uint64_t, uint64_t> &Merged) {
-  uint64_t Total = 0;
-  SmallVector<InstrProfValueData, 4> VDs =
-      getValueProfDataFromInst(I, Kind, /*MaxNumValueData=*/UINT32_MAX, Total);
-  if (VDs.empty())
-    return;
-  for (const InstrProfValueData &VD : VDs)
-    Merged[VD.Value] = SaturatingAdd(Merged[VD.Value], VD.Count);
-}
-
-// Merge (union) value profiles of Dst and Src.
-static void mergeValueProfileOnInstructions(Instruction *DstI,
-                                            const Instruction *SrcI) {
-  MDNode *DstProf = DstI->getMetadata(LLVMContext::MD_prof);
-  MDNode *SrcProf = SrcI->getMetadata(LLVMContext::MD_prof);
-  bool HasDst = DstProf && isValueProfileMD(DstProf);
-  bool HasSrc = SrcProf && isValueProfileMD(SrcProf);
-  if (!HasDst && !HasSrc)
-    return;
-
-  auto *DstKind =
-      HasDst ? mdconst::dyn_extract<ConstantInt>(DstProf->getOperand(1))
-             : nullptr;
-  auto *SrcKind =
-      HasSrc ? mdconst::dyn_extract<ConstantInt>(SrcProf->getOperand(1))
-             : nullptr;
-  if (HasDst && HasSrc && DstKind && SrcKind &&
-      DstKind->getZExtValue() != SrcKind->getZExtValue()) {
-    DstI->setMetadata(LLVMContext::MD_prof, nullptr);
-    return;
-  }
-
-  const ConstantInt *KindCI = DstKind ? DstKind : SrcKind;
-  if (!KindCI) {
-    DstI->setMetadata(LLVMContext::MD_prof, nullptr);
-    return;
-  }
-
-  InstrProfValueKind Kind =
-      static_cast<InstrProfValueKind>(KindCI->getZExtValue());
-
-  DenseMap<uint64_t, uint64_t> Merged;
-  if (HasDst)
-    addValueProfile(*DstI, Kind, Merged);
-  if (HasSrc)
-    addValueProfile(*SrcI, Kind, Merged);
-
-  if (Merged.empty())
-    return;
-
-  SmallVector<InstrProfValueData, 8> VDs;
-  VDs.reserve(Merged.size());
-  uint64_t Sum = 0;
-  for (auto &[Value, Count] : Merged) {
-    VDs.push_back({Value, Count});
-    Sum = SaturatingAdd(Sum, Count);
-  }
-  llvm::sort(VDs, [](const InstrProfValueData &A, const InstrProfValueData &B) {
-    return A.Count > B.Count;
-  });
-  annotateValueSite(*DstI->getFunction()->getParent(), *DstI, VDs, Sum, Kind,
-                    VDs.size());
-}
-
-/// Merge \p Src's instruction-level branch weights and value profile
-/// metadata into the corresponding instructions of \p Dst. \p Dst is the
-/// surviving function; \p Src will be erased or rewritten after this call.
-/// Both functions must be structurally identical.
-void MergeFunctions::mergeInstrProfMetadataInto(Function *Dst, Function *Src) {
-  const BlockFrequencyInfo &DstBFI =
-      FAM.getResult<BlockFrequencyAnalysis>(*Dst);
-  const BlockFrequencyInfo &SrcBFI =
-      FAM.getResult<BlockFrequencyAnalysis>(*Src);
-
-  // FunctionComparator guarantees identical CFG topology and instruction
-  // ordering. Walk the CFGs in RPO rather than function block-list order, as
-  // equivalent functions need not store their basic blocks in the same order.
-  ReversePostOrderTraversal<Function *> DstRPOT(Dst);
-  ReversePostOrderTraversal<Function *> SrcRPOT(Src);
-  for (auto [DstBB, SrcBB] : llvm::zip_equal(DstRPOT, SrcRPOT)) {
-    for (auto [DstI, SrcI] : llvm::zip_equal(*DstBB, *SrcBB)) {
-      MDNode *DstProf = DstI.getMetadata(LLVMContext::MD_prof);
-      MDNode *SrcProf = SrcI.getMetadata(LLVMContext::MD_prof);
-      if ((DstProf && isValueProfileMD(DstProf)) ||
-          (SrcProf && isValueProfileMD(SrcProf)))
-        mergeValueProfileOnInstructions(&DstI, &SrcI);
-
-      // Handle branch weights on SelectInsts here. Terminators are handled
-      // separately below, outside the instruction loop.
-      if (isa<SelectInst>(DstI))
-        mergeBranchWeightsOnInstructions(&DstI, &SrcI, DstBFI, SrcBFI);
-    }
-    Instruction *DstTerm = DstBB->getTerminator();
-    const Instruction *SrcTerm = SrcBB->getTerminator();
-    mergeBranchWeightsOnInstructions(DstTerm, SrcTerm, DstBFI, SrcBFI);
-  }
-
-  PreservedAnalyses PA = PreservedAnalyses::all();
-  PA.abandon<BranchProbabilityAnalysis>();
-  PA.abandon<BlockFrequencyAnalysis>();
-  FAM.invalidate(*Dst, PA);
-}
-
 static void mergeEntryCountsInto(Function *F, std::optional<uint64_t> FC,
                                  std::optional<uint64_t> GC) {
   if (!FC && !GC)
@@ -1101,8 +891,8 @@ static void mergeEntryCountsInto(Function *F, std::optional<uint64_t> FC,
 // Merge two equivalent functions. Upon completion, Function G is deleted.
 void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
 
-  std::optional<uint64_t> FEntryCount = F->getEntryCount();
-  std::optional<uint64_t> GEntryCount = 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
@@ -1145,13 +935,10 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
     const MaybeAlign NewFAlign = NewF->getAlign();
     const MaybeAlign GAlign = G->getAlign();
 
-    // Merge !prof, while G still has its body.
-    writeThunkOrAliasIfNeeded(F, G, /*MergeProfile*/ true);
-    if (FEntryCount)
-      NewF->setEntryCount(*FEntryCount);
-    // NewF becomes thunk/alias to the shared body F, it has no profile to be
-    // merged.
-    writeThunkOrAliasIfNeeded(F, NewF, /*MergeProfile*/ false);
+    writeThunkOrAliasIfNeeded(F, G);
+    if (FEC)
+      NewF->setEntryCount(*FEC);
+    writeThunkOrAliasIfNeeded(F, NewF);
 
     if (NewFAlign || GAlign)
       F->setAlignment(std::max(NewFAlign.valueOrOne(), GAlign.valueOrOne()));
@@ -1159,9 +946,8 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
       F->setAlignment(std::nullopt);
     F->setLinkage(GlobalValue::PrivateLinkage);
     // The private shared implementation accumulates both symbols' entries
-    // (FEntryCount + GEntryCount), while each ODR thunk retains its own
-    // per-symbol entry count.
-    mergeEntryCountsInto(F, FEntryCount, GEntryCount);
+    // (FEC + GEC), while each ODR thunk retains its own per-symbol entry count.
+    mergeEntryCountsInto(F, FEC, GEC);
     ++NumDoubleWeak;
     ++NumFunctionsMerged;
   } else {
@@ -1189,15 +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) {
-      mergeInstrProfMetadataInto(F, G);
-      mergeEntryCountsInto(F, FEntryCount, GEntryCount);
+      mergeEntryCountsInto(F, FEC, GEC);
       G->eraseFromParent();
       ++NumFunctionsMerged;
       return;
     }
 
-    if (writeThunkOrAliasIfNeeded(F, G, /*MergeProfile*/ true)) {
-      mergeEntryCountsInto(F, FEntryCount, GEntryCount);
+    if (writeThunkOrAliasIfNeeded(F, G)) {
+      mergeEntryCountsInto(F, FEC, GEC);
       ++NumFunctionsMerged;
     }
   }
diff --git a/llvm/test/Transforms/MergeFunc/merge-functions-branch-weights.ll b/llvm/test/Transforms/MergeFunc/merge-functions-branch-weights.ll
deleted file mode 100644
index 46a80c2916766..0000000000000
--- a/llvm/test/Transforms/MergeFunc/merge-functions-branch-weights.ll
+++ /dev/null
@@ -1,239 +0,0 @@
-; 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
-
-; Verify that MergeFunctions correctly combines branch_weights on
-; conditional branches when merging structurally identical functions.
-; Because FunctionComparator only matches functions whose control-flow
-; structure and instruction sequence are identical, MergeFunctions can
-; process both functions side by side and merge any instruction-level
-; metadata, including branch weight information.
-; To compute the merged weights, the pass converts each function's
-; relative branch weights into absolute execution counts using the
-; function's entry count, then adds the corresponding counts together.
-
-; --------------------------------------------------------------------------
-; Both functions provide branch weight metadata.
-; br_both_a: entry count = 100, weights = 10:90
-;            absolute counts: true = 10, false = 90
-; br_both_b: entry count = 200, weights = 30:70
-;            absolute counts: true = 60, false = 140
-; After merging:
-;            true  = 10 + 60  = 70
-;            false = 90 + 140 = 230
-; --------------------------------------------------------------------------
-define internal i32 @br_both_a(i32 %x) !prof !1 {
-entry:
-  %cmp = icmp slt i32 %x, 0
-  br i1 %cmp, label %then, label %else, !prof !2
-
-then:
-  ret i32 ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/209987


More information about the llvm-commits mailing list