[llvm] [SampleProfileMatcher] Sample profile duplication to avoid stale CFG profile matching conflicts (PR #202460)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 10 15:50:46 PDT 2026


https://github.com/HighW4y2H3ll updated https://github.com/llvm/llvm-project/pull/202460

>From b2a8038f9bf6c47d3d91bffdce8ed414fd1847df Mon Sep 17 00:00:00 2001
From: h2h <h2h at meta.com>
Date: Mon, 8 Jun 2026 16:21:54 -0700
Subject: [PATCH 1/5] [SampleProfileMatcher] Sample profile duplication to
 avoid stale CFG profile matching conflicts

---
 .../Transforms/IPO/SampleProfileMatcher.h     |   3 +
 .../Transforms/IPO/SampleProfileMatcher.cpp   |  47 +++++
 ...o-probe-stale-profile-orphan-conflict.prof |   5 +
 ...udo-probe-stale-profile-orphan-conflict.ll | 160 ++++++++++++++++++
 4 files changed, 215 insertions(+)
 create mode 100644 llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-orphan-conflict.prof
 create mode 100644 llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll

diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
index fa69177a822f4..5e1cd1ec05e21 100644
--- a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
+++ b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
@@ -206,6 +206,9 @@ class SampleProfileMatcher {
   LocToLocMap &getIRToProfileLocationMap(const FunctionSamples &FS) {
     return FuncMappings[FS.getFuncName()];
   }
+  LocToLocMap &getIRToProfileLocationMap(const Function &F) {
+    return FuncMappings[F.getName()];
+  }
   void distributeIRToProfileLocationMap();
   void distributeIRToProfileLocationMap(FunctionSamples &FS);
   LocToLocMap longestCommonSequence(const AnchorList &IRCallsiteAnchors,
diff --git a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
index 73eda1b9cd48a..13cda52be3a7f 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
@@ -364,6 +364,53 @@ void SampleProfileMatcher::runStaleProfileMatching(
       longestCommonSequence(FilteredIRAnchorsList, FilteredProfileAnchorList,
                             RunCGMatching /* Match unused functions */);
 
+  // Scan through the matched anchors to make sure functions and profiles are
+  // 1:1 mapped. If the profile has already been mapped to another function
+  // during previous fuzzy matching, create a new profile with the same sample
+  // counts and assumed to be pre-inlined.
+  std::unordered_map<uint64_t, uint64_t> StagedMatches;
+  for (const auto &IR : IRAnchors) {
+    bool ProfileConflicted = false;
+    const auto &Loc = IR.first;
+    auto AnchorLoc = MatchedAnchors.find(Loc);
+    if (AnchorLoc == MatchedAnchors.end())
+      continue;
+    const auto &Prof = ProfileAnchors.find(AnchorLoc->second);
+    if (Prof == ProfileAnchors.end())
+      continue;
+
+    // Conflicting profile matched with previous matchings
+    const auto *FSForMatching = getFlattenedSamplesFor(Prof->second);
+    if (!FSForMatching)
+      FSForMatching = Reader.getSamplesFor(Prof->second.stringRef());
+    if (!FSForMatching)
+      continue;
+    auto &PrevMap = getIRToProfileLocationMap(*FSForMatching);
+    if (!PrevMap.empty())
+      ProfileConflicted = true;
+
+    // Conflicting profile matched in the current run
+    if (!ProfileConflicted) {
+      uint64_t IRHash = IR.second.getHashCode();
+      uint64_t ProfHash = Prof->second.getHashCode();
+      auto Cached = StagedMatches.find(ProfHash);
+      if (Cached == StagedMatches.end() || Cached->second == IRHash) {
+        StagedMatches[ProfHash] = IRHash;
+      } else {
+        ProfileConflicted = true;
+      }
+    }
+
+    if (ProfileConflicted) {
+      // Create a flattened profile using the IR function name to avoid profile
+      // name conflicts
+      FunctionSamples &NewFS = FlattenedProfiles.create(IR.second);
+      NewFS.merge(*FSForMatching);
+      FuncToProfileNameMap[const_cast<Function *>(&F)] = IR.second;
+      IRToProfileLocationMap = getIRToProfileLocationMap(NewFS);
+    }
+  }
+
   // CFG level matching:
   // Apply the callsite matchings to infer matching for the basic
   // block(non-callsite) locations and write the result to
diff --git a/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-orphan-conflict.prof b/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-orphan-conflict.prof
new file mode 100644
index 0000000000000..4aae1f1f38b3a
--- /dev/null
+++ b/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-orphan-conflict.prof
@@ -0,0 +1,5 @@
+_Z3fooi:1:0
+ 57: _Z3bari:1
+ 72: _Z3topi:1
+  2: _Z3midi:1
+   11: _Z3subi:1
diff --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll
new file mode 100644
index 0000000000000..d3235203c280e
--- /dev/null
+++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll
@@ -0,0 +1,160 @@
+; Test direct basename matching for orphan functions where multiple callee anchors may be
+; matched to one same profile during stale profile matching. In this test case, both of the
+; `mid` functions will be matched to the same `_Z3midi` function in the profile during stale
+; profile matching. This ends up causing an assertation error because only one profile
+; function is supposed to be matched to an IR function.
+;
+; IR Function:
+;   foo: top ; bar ; top(2)
+;         |_mid       |_ mid(2)
+;                          |_ sub
+; 
+; Profile Function:
+;   foo: bar ; top ; mid
+;                     |_ sub
+; 
+; Stale profile match order:
+;   foo:  top<ir>   ; bar<ir>   ; top(2)<ir>
+;            |           |           |
+;         top<prof> ; bar<prof> ; top<prof>
+;
+;   top(2)<ir>:  mid(2)<ir>
+;                  |
+;                mid<prof>
+;
+;   top<ir>:  mid<ir>
+;               |
+;             mid<prof>    => (Assertation error)
+
+
+; REQUIRES: x86_64-linux
+; REQUIRES: asserts
+; RUN: llvm-profdata merge --sample --extbinary %S/Inputs/pseudo-probe-stale-profile-orphan-conflict.prof -o %t.prof
+; RUN: opt < %s -passes=sample-profile -sample-profile-file=%t.prof --salvage-stale-profile --salvage-unused-profile -S --debug-only=sample-profile,sample-profile-matcher,sample-profile-impl 2>&1 | FileCheck %s
+
+; CHECK: Function _Z3fool is not in profile or profile symbol list.
+; CHECK: Function _Z3topl is not in profile or profile symbol list.
+; CHECK: Function _Z3barl is not in profile or profile symbol list.
+; CHECK: Function _Z3topll is not in profile or profile symbol list.
+; CHECK: Function _Z3midl is not in profile or profile symbol list.
+; CHECK: Function _Z3midll is not in profile or profile symbol list.
+; CHECK: Direct basename match: _Z3barl (IR) -> _Z3bari (Profile) [basename: bar]
+; CHECK: Direct basename match: _Z3fool (IR) -> _Z3fooi (Profile) [basename: foo]
+; CHECK: Direct basename matching found 2 matches
+; CHECK: Run stale profile matching for _Z3fool
+; CHECK: The functions _Z3topl(IR) and _Z3topi(Profile) share the same base name: top.
+; CHECK: Function:_Z3topl matches profile:_Z3topi
+; CHECK: The functions _Z3barl(IR) and _Z3bari(Profile) share the same base name: bar.
+; CHECK: Function:_Z3barl matches profile:_Z3bari
+; CHECK: The functions _Z3topll(IR) and _Z3topi(Profile) share the same base name: top.
+; CHECK: Function:_Z3topll matches profile:_Z3topi
+; CHECK: Location is matched from 47 to 47
+; CHECK: Callsite with callee:_Z3barl is matched from 63.1 to 57
+; CHECK: Callsite with callee:_Z3topll is matched from 65 to 72
+; CHECK: Run stale profile matching for _Z3topll
+; CHECK: The functions _Z3midll(IR) and _Z3midi(Profile) share the same base name: mid.
+; CHECK: Function:_Z3midll matches profile:_Z3midi
+; CHECK: Callsite with callee:_Z3midll is matched from 2 to 2
+; CHECK: Run stale profile matching for _Z3midll
+; CHECK: Callsite with callee:_Z3subi is matched from 14 to 11
+; CHECK: Run stale profile matching for _Z3topl
+; CHECK: The functions _Z3midl(IR) and _Z3midi(Profile) share the same base name: mid.
+; CHECK: Function:_Z3midl matches profile:_Z3midi
+; CHECK: Callsite with callee:_Z3midl is matched from 2 to 2
+; CHECK: Run stale profile matching for _Z3midl
+; CHECK: Profile Function _Z3midl has already been matched to another IR function.
+; CHECK: Profile Function _Z3midi has already been matched to another IR function.
+; CHECK: Function processing order:
+; CHECK: _Z3fool
+; CHECK: _Z3topll
+; CHECK: _Z3midll
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-redhat-linux-gnu"
+
+define ptr @_Z3fool(i64 %x) #0 {
+entry:
+  br i1 false, label %if.then, label %if.end63
+
+if.then:                                          ; preds = %entry
+  %call45 = call ptr @_Z3topl(i64 0), !dbg !5
+  ret ptr %call45
+
+if.end63:                                         ; preds = %entry
+  call void @_Z3barl(i64 0), !dbg !15
+  %call103 = call ptr @_Z3topll(i64 0, i64 1), !dbg !19
+  ret ptr null
+}
+
+define ptr @_Z3topl(i64 %x) #0 {
+entry:
+  %call = call ptr @_Z3midl(i64 0), !dbg !21
+  ret ptr %call
+}
+
+define void @_Z3barl(i64 %x) {
+entry:
+  ret void
+}
+
+define ptr @_Z3topll(i64 %x, i64 %y) #0 {
+entry:
+  %call = call ptr @_Z3midll(i64 0, i64 1), !dbg !25
+  ret ptr %call
+}
+
+define ptr @_Z3midl(i64 %x) #0 {
+entry:
+  ret ptr null
+}
+
+define ptr @_Z3midll(i64 %x, i64 %y) #0 {
+entry:
+  %call18 = call ptr @_Z3subi(i64 0), !dbg !29
+  ret ptr %call18
+}
+
+define ptr @_Z3subi(i64 %x) {
+entry:
+  ret ptr null
+}
+
+attributes #0 = { "use-sample-profile" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3}
+!llvm.pseudo_probe_desc = !{!4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 23.0.0git (https://github.com/llvm/llvm-project.git 4e38fa748a8de3a7bc2d8c27bb43f53ea78af395)", isOptimized: true, runtimeVersion: 0, splitDebugFilename: "out.ll", emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2, imports: !2, splitDebugInlining: false, debugInfoForProfiling: true)
+!1 = !DIFile(filename: "tree.cpp", directory: ".", checksumkind: CSK_MD5, checksum: "dbfcb2083a71f1367256c8fcc6263915")
+!2 = !{}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i64 -4689275162925682552, i64 2251974424712944, !"_Z3midll"}
+!5 = !DILocation(line: 2378, scope: !6, atomGroup: 28279, atomRank: 2)
+!6 = !DILexicalBlockFile(scope: !8, file: !7, discriminator: 455082215)
+!7 = !DIFile(filename: "format.h", directory: ".", checksumkind: CSK_MD5, checksum: "24094ed6f9970cebe9f2fedff5aac8b9")
+!8 = distinct !DILexicalBlock(scope: !9, file: !7, line: 2353)
+!9 = distinct !DILexicalBlock(scope: !10, file: !7, line: 2353)
+!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fool", scope: !11, file: !7, line: 2331, type: !14, scopeLine: 2333, flags: DIFlagPrototyped | DIFlagAllCallsDescribed | DIFlagNameIsSimplified, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, templateParams: !2, retainedNodes: !2, keyInstructions: true)
+!11 = !DINamespace(name: "c", scope: !12)
+!12 = !DINamespace(name: "b", scope: !13, exportSymbols: true)
+!13 = !DINamespace(name: "a", scope: null)
+!14 = distinct !DISubroutineType(types: !2)
+!15 = !DILocation(line: 2394, scope: !16)
+!16 = !DILexicalBlockFile(scope: !17, file: !7, discriminator: 455147919)
+!17 = distinct !DILexicalBlock(scope: !18, file: !7, line: 2383)
+!18 = distinct !DILexicalBlock(scope: !10, file: !7, line: 2383)
+!19 = !DILocation(line: 2396, scope: !20, atomGroup: 28280, atomRank: 2)
+!20 = !DILexicalBlockFile(scope: !17, file: !7, discriminator: 455082407)
+!21 = !DILocation(line: 1652, scope: !22, atomGroup: 28281, atomRank: 2)
+!22 = !DILexicalBlockFile(scope: !23, file: !7, discriminator: 455082007)
+!23 = distinct !DISubprogram(name: "top", linkageName: "_Z3topl", scope: !11, file: !7, line: 1650, type: !24, scopeLine: 1651, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, templateParams: !2, retainedNodes: !2, keyInstructions: true)
+!24 = distinct !DISubroutineType(types: !2)
+!25 = !DILocation(line: 1652, scope: !26, atomGroup: 28282, atomRank: 2)
+!26 = !DILexicalBlockFile(scope: !27, file: !7, discriminator: 455082007)
+!27 = distinct !DISubprogram(name: "top", linkageName: "_Z3topll", scope: !11, file: !7, line: 1650, type: !28, scopeLine: 1651, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, templateParams: !2, retainedNodes: !2, keyInstructions: true)
+!28 = distinct !DISubroutineType(types: !2)
+!29 = !DILocation(line: 1643, scope: !30)
+!30 = !DILexicalBlockFile(scope: !31, file: !7, discriminator: 455082087)
+!31 = distinct !DISubprogram(name: "mid", linkageName: "_Z3midll", scope: !11, file: !7, line: 1629, type: !32, scopeLine: 1630, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, templateParams: !2, retainedNodes: !2, keyInstructions: true)
+!32 = distinct !DISubroutineType(types: !2)

>From 19f9c9623b39f6630285a93c605f8ac9c6dfcbdc Mon Sep 17 00:00:00 2001
From: h2h <h2h at meta.com>
Date: Tue, 9 Jun 2026 10:43:43 -0700
Subject: [PATCH 2/5] Clean up unnecessary change

---
 llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
index 5e1cd1ec05e21..fa69177a822f4 100644
--- a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
+++ b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
@@ -206,9 +206,6 @@ class SampleProfileMatcher {
   LocToLocMap &getIRToProfileLocationMap(const FunctionSamples &FS) {
     return FuncMappings[FS.getFuncName()];
   }
-  LocToLocMap &getIRToProfileLocationMap(const Function &F) {
-    return FuncMappings[F.getName()];
-  }
   void distributeIRToProfileLocationMap();
   void distributeIRToProfileLocationMap(FunctionSamples &FS);
   LocToLocMap longestCommonSequence(const AnchorList &IRCallsiteAnchors,

>From 1a3576325de01b2535a1f304da8d633d7c7d09ab Mon Sep 17 00:00:00 2001
From: h2h <h2h at meta.com>
Date: Tue, 9 Jun 2026 16:17:14 -0700
Subject: [PATCH 3/5] Update checks and test to fix more corner cases

---
 .../Transforms/IPO/SampleProfileMatcher.h     |   2 +
 .../Transforms/IPO/SampleProfileMatcher.cpp   |  56 ++--
 ...udo-probe-stale-profile-orphan-conflict.ll | 264 +++++++++++++-----
 3 files changed, 223 insertions(+), 99 deletions(-)

diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
index fa69177a822f4..6573b5c0c9fdb 100644
--- a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
+++ b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
@@ -37,6 +37,8 @@ class SampleProfileMatcher {
   // mapping from the source location of current build to the source location
   // in the profile.
   StringMap<LocToLocMap> FuncMappings;
+  // Hash mapping cache for matched anchor pairs in stale profile matching
+  std::unordered_map<uint64_t, uint64_t> MatchedAnchorCache;
 
   // Match state for an anchor/callsite.
   enum class MatchState {
diff --git a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
index 13cda52be3a7f..4db73f5672ba3 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
@@ -368,42 +368,46 @@ void SampleProfileMatcher::runStaleProfileMatching(
   // 1:1 mapped. If the profile has already been mapped to another function
   // during previous fuzzy matching, create a new profile with the same sample
   // counts and assumed to be pre-inlined.
-  std::unordered_map<uint64_t, uint64_t> StagedMatches;
   for (const auto &IR : IRAnchors) {
     bool ProfileConflicted = false;
     const auto &Loc = IR.first;
+    FunctionId ProfAnchor;
     auto AnchorLoc = MatchedAnchors.find(Loc);
-    if (AnchorLoc == MatchedAnchors.end())
-      continue;
-    const auto &Prof = ProfileAnchors.find(AnchorLoc->second);
-    if (Prof == ProfileAnchors.end())
-      continue;
+    if (AnchorLoc == MatchedAnchors.end()) {
+      // Search within the module and find if we have conflicts in pre-matched
+      // profiles for this anchor
+      Function *Sub = M.getFunction(IR.second.stringRef());
+      if (!Sub)
+        continue;
+      auto PreMatched = FuncToProfileNameMap.find(Sub);
+      if (PreMatched == FuncToProfileNameMap.end())
+        continue;
+      ProfAnchor = PreMatched->second;
+    } else {
+      const auto &Prof = ProfileAnchors.find(AnchorLoc->second);
+      if (Prof == ProfileAnchors.end())
+        continue;
+      ProfAnchor = Prof->second;
+    }
 
-    // Conflicting profile matched with previous matchings
-    const auto *FSForMatching = getFlattenedSamplesFor(Prof->second);
-    if (!FSForMatching)
-      FSForMatching = Reader.getSamplesFor(Prof->second.stringRef());
-    if (!FSForMatching)
-      continue;
-    auto &PrevMap = getIRToProfileLocationMap(*FSForMatching);
-    if (!PrevMap.empty())
+    // Conflicting profile previously matched
+    uint64_t IRHash = IR.second.getHashCode();
+    uint64_t ProfHash = ProfAnchor.getHashCode();
+    auto Cached = MatchedAnchorCache.find(ProfHash);
+    if (Cached == MatchedAnchorCache.end())
+      MatchedAnchorCache[ProfHash] = IRHash;
+    else if (Cached->second != IRHash)
       ProfileConflicted = true;
 
-    // Conflicting profile matched in the current run
-    if (!ProfileConflicted) {
-      uint64_t IRHash = IR.second.getHashCode();
-      uint64_t ProfHash = Prof->second.getHashCode();
-      auto Cached = StagedMatches.find(ProfHash);
-      if (Cached == StagedMatches.end() || Cached->second == IRHash) {
-        StagedMatches[ProfHash] = IRHash;
-      } else {
-        ProfileConflicted = true;
-      }
-    }
-
     if (ProfileConflicted) {
       // Create a flattened profile using the IR function name to avoid profile
       // name conflicts
+      const auto *FSForMatching = getFlattenedSamplesFor(ProfAnchor);
+      if (!FSForMatching)
+        FSForMatching = Reader.getSamplesFor(ProfAnchor.stringRef());
+      if (!FSForMatching)
+        continue;
+
       FunctionSamples &NewFS = FlattenedProfiles.create(IR.second);
       NewFS.merge(*FSForMatching);
       FuncToProfileNameMap[const_cast<Function *>(&F)] = IR.second;
diff --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll
index d3235203c280e..e6ddaa9d97aef 100644
--- a/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll
+++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll
@@ -32,12 +32,12 @@
 ; RUN: llvm-profdata merge --sample --extbinary %S/Inputs/pseudo-probe-stale-profile-orphan-conflict.prof -o %t.prof
 ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%t.prof --salvage-stale-profile --salvage-unused-profile -S --debug-only=sample-profile,sample-profile-matcher,sample-profile-impl 2>&1 | FileCheck %s
 
-; CHECK: Function _Z3fool is not in profile or profile symbol list.
+; CHECK: Function _Z3midl is not in profile or profile symbol list.
+; CHECK: Function _Z3midll is not in profile or profile symbol list.
 ; CHECK: Function _Z3topl is not in profile or profile symbol list.
 ; CHECK: Function _Z3barl is not in profile or profile symbol list.
 ; CHECK: Function _Z3topll is not in profile or profile symbol list.
-; CHECK: Function _Z3midl is not in profile or profile symbol list.
-; CHECK: Function _Z3midll is not in profile or profile symbol list.
+; CHECK: Function _Z3fool is not in profile or profile symbol list.
 ; CHECK: Direct basename match: _Z3barl (IR) -> _Z3bari (Profile) [basename: bar]
 ; CHECK: Direct basename match: _Z3fool (IR) -> _Z3fooi (Profile) [basename: foo]
 ; CHECK: Direct basename matching found 2 matches
@@ -48,113 +48,231 @@
 ; CHECK: Function:_Z3barl matches profile:_Z3bari
 ; CHECK: The functions _Z3topll(IR) and _Z3topi(Profile) share the same base name: top.
 ; CHECK: Function:_Z3topll matches profile:_Z3topi
-; CHECK: Location is matched from 47 to 47
-; CHECK: Callsite with callee:_Z3barl is matched from 63.1 to 57
-; CHECK: Callsite with callee:_Z3topll is matched from 65 to 72
+; CHECK: Location is matched from 2 to 2
+; CHECK: Callsite with callee:_Z3barl is matched from 3 to 57
+; CHECK: Callsite with callee:_Z3topll is matched from 4 to 72
 ; CHECK: Run stale profile matching for _Z3topll
 ; CHECK: The functions _Z3midll(IR) and _Z3midi(Profile) share the same base name: mid.
 ; CHECK: Function:_Z3midll matches profile:_Z3midi
-; CHECK: Callsite with callee:_Z3midll is matched from 2 to 2
-; CHECK: Run stale profile matching for _Z3midll
-; CHECK: Callsite with callee:_Z3subi is matched from 14 to 11
+; CHECK: Callsite with callee:_Z3midll is matched from 1 to 2
+; CHECK: Run stale profile matching for _Z3barl
 ; CHECK: Run stale profile matching for _Z3topl
 ; CHECK: The functions _Z3midl(IR) and _Z3midi(Profile) share the same base name: mid.
 ; CHECK: Function:_Z3midl matches profile:_Z3midi
-; CHECK: Callsite with callee:_Z3midl is matched from 2 to 2
+; CHECK: Callsite with callee:_Z3midl is matched from 1 to 2
+; CHECK: Run stale profile matching for _Z3midll
+; CHECK: Callsite with callee:_Z3subi is matched from 1 to 11
+; CHECK: Run stale profile matching for _Z3subi
 ; CHECK: Run stale profile matching for _Z3midl
+; CHECK: Profile Function _Z3topll has already been matched to another IR function.
 ; CHECK: Profile Function _Z3midl has already been matched to another IR function.
 ; CHECK: Profile Function _Z3midi has already been matched to another IR function.
 ; CHECK: Function processing order:
-; CHECK: _Z3fool
 ; CHECK: _Z3topll
 ; CHECK: _Z3midll
+; CHECK: _Z3subi
+; CHECK: _Z3barl
 
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-redhat-linux-gnu"
 
-define ptr @_Z3fool(i64 %x) #0 {
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef ptr @_Z3midl(i64 noundef %l) #0 !dbg !14 {
 entry:
-  br i1 false, label %if.then, label %if.end63
-
-if.then:                                          ; preds = %entry
-  %call45 = call ptr @_Z3topl(i64 0), !dbg !5
-  ret ptr %call45
-
-if.end63:                                         ; preds = %entry
-  call void @_Z3barl(i64 0), !dbg !15
-  %call103 = call ptr @_Z3topll(i64 0, i64 1), !dbg !19
-  ret ptr null
+  %l.addr = alloca i64, align 8
+  store i64 %l, ptr %l.addr, align 8
+    #dbg_declare(ptr %l.addr, !21, !DIExpression(), !22)
+  call void @llvm.pseudoprobe(i64 -4458821264266946817, i64 1, i32 0, i64 -1), !dbg !23
+  ret ptr null, !dbg !23
 }
 
-define ptr @_Z3topl(i64 %x) #0 {
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef ptr @_Z3subi(i32 noundef %i) #0 !dbg !24 {
 entry:
-  %call = call ptr @_Z3midl(i64 0), !dbg !21
-  ret ptr %call
+  %i.addr = alloca i32, align 4
+  store i32 %i, ptr %i.addr, align 4
+    #dbg_declare(ptr %i.addr, !28, !DIExpression(), !29)
+  call void @llvm.pseudoprobe(i64 8307782004441981189, i64 1, i32 0, i64 -1), !dbg !30
+  ret ptr null, !dbg !30
 }
 
-define void @_Z3barl(i64 %x) {
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef ptr @_Z3midll(i64 noundef %l, i64 noundef %m) #0 !dbg !31 {
 entry:
-  ret void
+  %l.addr = alloca i64, align 8
+  %m.addr = alloca i64, align 8
+  store i64 %l, ptr %l.addr, align 8
+    #dbg_declare(ptr %l.addr, !34, !DIExpression(), !35)
+  store i64 %m, ptr %m.addr, align 8
+    #dbg_declare(ptr %m.addr, !36, !DIExpression(), !37)
+  call void @llvm.pseudoprobe(i64 -835688601043669768, i64 1, i32 0, i64 -1), !dbg !38
+  %call = call noundef ptr @_Z3subi(i32 noundef 0), !dbg !39
+  ret ptr %call, !dbg !41
 }
 
-define ptr @_Z3topll(i64 %x, i64 %y) #0 {
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef ptr @_Z3topl(i64 noundef %l) #0 !dbg !42 {
 entry:
-  %call = call ptr @_Z3midll(i64 0, i64 1), !dbg !25
-  ret ptr %call
+  %l.addr = alloca i64, align 8
+  store i64 %l, ptr %l.addr, align 8
+    #dbg_declare(ptr %l.addr, !43, !DIExpression(), !44)
+  call void @llvm.pseudoprobe(i64 7421866232655760046, i64 1, i32 0, i64 -1), !dbg !45
+  %0 = load i64, ptr %l.addr, align 8, !dbg !45
+  %call = call noundef ptr @_Z3midl(i64 noundef %0), !dbg !46
+  ret ptr %call, !dbg !48
 }
 
-define ptr @_Z3midl(i64 %x) #0 {
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local void @_Z3barl(i64 noundef %l) #0 !dbg !49 {
 entry:
-  ret ptr null
+  %l.addr = alloca i64, align 8
+  store i64 %l, ptr %l.addr, align 8
+    #dbg_declare(ptr %l.addr, !52, !DIExpression(), !53)
+  call void @llvm.pseudoprobe(i64 -9164787269840974918, i64 1, i32 0, i64 -1), !dbg !54
+  ret void, !dbg !54
 }
 
-define ptr @_Z3midll(i64 %x, i64 %y) #0 {
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef ptr @_Z3topll(i64 noundef %l, i64 noundef %m) #0 !dbg !55 {
 entry:
-  %call18 = call ptr @_Z3subi(i64 0), !dbg !29
-  ret ptr %call18
+  %l.addr = alloca i64, align 8
+  %m.addr = alloca i64, align 8
+  store i64 %l, ptr %l.addr, align 8
+    #dbg_declare(ptr %l.addr, !56, !DIExpression(), !57)
+  store i64 %m, ptr %m.addr, align 8
+    #dbg_declare(ptr %m.addr, !58, !DIExpression(), !59)
+  call void @llvm.pseudoprobe(i64 997868883951813144, i64 1, i32 0, i64 -1), !dbg !60
+  %0 = load i64, ptr %l.addr, align 8, !dbg !60
+  %1 = load i64, ptr %m.addr, align 8, !dbg !61
+  %call = call noundef ptr @_Z3midll(i64 noundef %0, i64 noundef %1), !dbg !62
+  ret ptr %call, !dbg !64
 }
 
-define ptr @_Z3subi(i64 %x) {
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef ptr @_Z3fool(i64 noundef %l) #0 !dbg !65 {
 entry:
-  ret ptr null
+  %retval = alloca ptr, align 8
+  %l.addr = alloca i64, align 8
+  store i64 %l, ptr %l.addr, align 8
+    #dbg_declare(ptr %l.addr, !66, !DIExpression(), !67)
+  call void @llvm.pseudoprobe(i64 5326982120444056491, i64 1, i32 0, i64 -1), !dbg !68
+  %0 = load i64, ptr %l.addr, align 8, !dbg !68
+  %tobool = icmp ne i64 %0, 0, !dbg !68
+  br i1 %tobool, label %if.then, label %if.end, !dbg !68
+
+if.then:                                          ; preds = %entry
+  call void @llvm.pseudoprobe(i64 5326982120444056491, i64 2, i32 0, i64 -1), !dbg !70
+  %1 = load i64, ptr %l.addr, align 8, !dbg !70
+  %call = call noundef ptr @_Z3topl(i64 noundef %1), !dbg !71
+  store ptr %call, ptr %retval, align 8, !dbg !73
+  br label %return, !dbg !73
+
+if.end:                                           ; preds = %entry
+  call void @llvm.pseudoprobe(i64 5326982120444056491, i64 4, i32 0, i64 -1), !dbg !74
+  %2 = load i64, ptr %l.addr, align 8, !dbg !74
+  call void @_Z3barl(i64 noundef %2), !dbg !75
+  %3 = load i64, ptr %l.addr, align 8, !dbg !77
+  %4 = load i64, ptr %l.addr, align 8, !dbg !78
+  %call1 = call noundef ptr @_Z3topll(i64 noundef %3, i64 noundef %4), !dbg !79
+  store ptr %call1, ptr %retval, align 8, !dbg !81
+  br label %return, !dbg !81
+
+return:                                           ; preds = %if.end, %if.then
+  call void @llvm.pseudoprobe(i64 5326982120444056491, i64 7, i32 0, i64 -1), !dbg !82
+  %5 = load ptr, ptr %retval, align 8, !dbg !82
+  ret ptr %5, !dbg !82
 }
 
-attributes #0 = { "use-sample-profile" }
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite)
+declare void @llvm.pseudoprobe(i64, i64, i32, i64) #1
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "use-sample-profile" }
+attributes #1 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) }
 
 !llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!3}
-!llvm.pseudo_probe_desc = !{!4}
+!llvm.module.flags = !{!2, !3, !4, !5}
+!llvm.ident = !{!6}
+!llvm.pseudo_probe_desc = !{!7, !8, !9, !10, !11, !12, !13}
 
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 23.0.0git (https://github.com/llvm/llvm-project.git 4e38fa748a8de3a7bc2d8c27bb43f53ea78af395)", isOptimized: true, runtimeVersion: 0, splitDebugFilename: "out.ll", emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2, imports: !2, splitDebugInlining: false, debugInfoForProfiling: true)
-!1 = !DIFile(filename: "tree.cpp", directory: ".", checksumkind: CSK_MD5, checksum: "dbfcb2083a71f1367256c8fcc6263915")
-!2 = !{}
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.cc", directory: "", checksumkind: CSK_MD5, checksum: "44fecbd11c1385709b8c0c240594ca47")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
 !3 = !{i32 2, !"Debug Info Version", i32 3}
-!4 = !{i64 -4689275162925682552, i64 2251974424712944, !"_Z3midll"}
-!5 = !DILocation(line: 2378, scope: !6, atomGroup: 28279, atomRank: 2)
-!6 = !DILexicalBlockFile(scope: !8, file: !7, discriminator: 455082215)
-!7 = !DIFile(filename: "format.h", directory: ".", checksumkind: CSK_MD5, checksum: "24094ed6f9970cebe9f2fedff5aac8b9")
-!8 = distinct !DILexicalBlock(scope: !9, file: !7, line: 2353)
-!9 = distinct !DILexicalBlock(scope: !10, file: !7, line: 2353)
-!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fool", scope: !11, file: !7, line: 2331, type: !14, scopeLine: 2333, flags: DIFlagPrototyped | DIFlagAllCallsDescribed | DIFlagNameIsSimplified, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, templateParams: !2, retainedNodes: !2, keyInstructions: true)
-!11 = !DINamespace(name: "c", scope: !12)
-!12 = !DINamespace(name: "b", scope: !13, exportSymbols: true)
-!13 = !DINamespace(name: "a", scope: null)
-!14 = distinct !DISubroutineType(types: !2)
-!15 = !DILocation(line: 2394, scope: !16)
-!16 = !DILexicalBlockFile(scope: !17, file: !7, discriminator: 455147919)
-!17 = distinct !DILexicalBlock(scope: !18, file: !7, line: 2383)
-!18 = distinct !DILexicalBlock(scope: !10, file: !7, line: 2383)
-!19 = !DILocation(line: 2396, scope: !20, atomGroup: 28280, atomRank: 2)
-!20 = !DILexicalBlockFile(scope: !17, file: !7, discriminator: 455082407)
-!21 = !DILocation(line: 1652, scope: !22, atomGroup: 28281, atomRank: 2)
-!22 = !DILexicalBlockFile(scope: !23, file: !7, discriminator: 455082007)
-!23 = distinct !DISubprogram(name: "top", linkageName: "_Z3topl", scope: !11, file: !7, line: 1650, type: !24, scopeLine: 1651, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, templateParams: !2, retainedNodes: !2, keyInstructions: true)
-!24 = distinct !DISubroutineType(types: !2)
-!25 = !DILocation(line: 1652, scope: !26, atomGroup: 28282, atomRank: 2)
-!26 = !DILexicalBlockFile(scope: !27, file: !7, discriminator: 455082007)
-!27 = distinct !DISubprogram(name: "top", linkageName: "_Z3topll", scope: !11, file: !7, line: 1650, type: !28, scopeLine: 1651, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, templateParams: !2, retainedNodes: !2, keyInstructions: true)
-!28 = distinct !DISubroutineType(types: !2)
-!29 = !DILocation(line: 1643, scope: !30)
-!30 = !DILexicalBlockFile(scope: !31, file: !7, discriminator: 455082087)
-!31 = distinct !DISubprogram(name: "mid", linkageName: "_Z3midll", scope: !11, file: !7, line: 1629, type: !32, scopeLine: 1630, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, templateParams: !2, retainedNodes: !2, keyInstructions: true)
-!32 = distinct !DISubroutineType(types: !2)
+!4 = !{i32 7, !"uwtable", i32 2}
+!5 = !{i32 7, !"frame-pointer", i32 2}
+!6 = !{!"clang"}
+!7 = !{i64 -4458821264266946817, i64 4294967295, !"_Z3midl"}
+!8 = !{i64 8307782004441981189, i64 4294967295, !"_Z3subi"}
+!9 = !{i64 -835688601043669768, i64 281479271677951, !"_Z3midll"}
+!10 = !{i64 7421866232655760046, i64 281479271677951, !"_Z3topl"}
+!11 = !{i64 -9164787269840974918, i64 4294967295, !"_Z3barl"}
+!12 = !{i64 997868883951813144, i64 281479271677951, !"_Z3topll"}
+!13 = !{i64 5326982120444056491, i64 844493665377046, !"_Z3fool"}
+!14 = distinct !DISubprogram(name: "mid", linkageName: "_Z3midl", scope: !15, file: !15, line: 1, type: !16, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !20)
+!15 = !DIFile(filename: "test.cc", directory: "", checksumkind: CSK_MD5, checksum: "44fecbd11c1385709b8c0c240594ca47")
+!16 = !DISubroutineType(types: !17)
+!17 = !{!18, !19}
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!19 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed)
+!20 = !{}
+!21 = !DILocalVariable(name: "l", arg: 1, scope: !14, file: !15, line: 1, type: !19)
+!22 = !DILocation(line: 1, column: 16, scope: !14)
+!23 = !DILocation(line: 2, column: 3, scope: !14)
+!24 = distinct !DISubprogram(name: "sub", linkageName: "_Z3subi", scope: !15, file: !15, line: 5, type: !25, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !20)
+!25 = !DISubroutineType(types: !26)
+!26 = !{!18, !27}
+!27 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!28 = !DILocalVariable(name: "i", arg: 1, scope: !24, file: !15, line: 5, type: !27)
+!29 = !DILocation(line: 5, column: 15, scope: !24)
+!30 = !DILocation(line: 6, column: 3, scope: !24)
+!31 = distinct !DISubprogram(name: "mid", linkageName: "_Z3midll", scope: !15, file: !15, line: 9, type: !32, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !20)
+!32 = !DISubroutineType(types: !33)
+!33 = !{!18, !19, !19}
+!34 = !DILocalVariable(name: "l", arg: 1, scope: !31, file: !15, line: 9, type: !19)
+!35 = !DILocation(line: 9, column: 16, scope: !31)
+!36 = !DILocalVariable(name: "m", arg: 2, scope: !31, file: !15, line: 9, type: !19)
+!37 = !DILocation(line: 9, column: 24, scope: !31)
+!38 = !DILocation(line: 10, column: 10, scope: !31)
+!39 = !DILocation(line: 10, column: 10, scope: !40)
+!40 = !DILexicalBlockFile(scope: !31, file: !15, discriminator: 455082007)
+!41 = !DILocation(line: 10, column: 3, scope: !31)
+!42 = distinct !DISubprogram(name: "top", linkageName: "_Z3topl", scope: !15, file: !15, line: 13, type: !16, scopeLine: 13, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !20)
+!43 = !DILocalVariable(name: "l", arg: 1, scope: !42, file: !15, line: 13, type: !19)
+!44 = !DILocation(line: 13, column: 16, scope: !42)
+!45 = !DILocation(line: 14, column: 14, scope: !42)
+!46 = !DILocation(line: 14, column: 10, scope: !47)
+!47 = !DILexicalBlockFile(scope: !42, file: !15, discriminator: 455082007)
+!48 = !DILocation(line: 14, column: 3, scope: !42)
+!49 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barl", scope: !15, file: !15, line: 17, type: !50, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !20)
+!50 = !DISubroutineType(types: !51)
+!51 = !{null, !19}
+!52 = !DILocalVariable(name: "l", arg: 1, scope: !49, file: !15, line: 17, type: !19)
+!53 = !DILocation(line: 17, column: 15, scope: !49)
+!54 = !DILocation(line: 17, column: 19, scope: !49)
+!55 = distinct !DISubprogram(name: "top", linkageName: "_Z3topll", scope: !15, file: !15, line: 19, type: !32, scopeLine: 19, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !20)
+!56 = !DILocalVariable(name: "l", arg: 1, scope: !55, file: !15, line: 19, type: !19)
+!57 = !DILocation(line: 19, column: 16, scope: !55)
+!58 = !DILocalVariable(name: "m", arg: 2, scope: !55, file: !15, line: 19, type: !19)
+!59 = !DILocation(line: 19, column: 24, scope: !55)
+!60 = !DILocation(line: 20, column: 14, scope: !55)
+!61 = !DILocation(line: 20, column: 17, scope: !55)
+!62 = !DILocation(line: 20, column: 10, scope: !63)
+!63 = !DILexicalBlockFile(scope: !55, file: !15, discriminator: 455082007)
+!64 = !DILocation(line: 20, column: 3, scope: !55)
+!65 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fool", scope: !15, file: !15, line: 23, type: !16, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !20)
+!66 = !DILocalVariable(name: "l", arg: 1, scope: !65, file: !15, line: 23, type: !19)
+!67 = !DILocation(line: 23, column: 16, scope: !65)
+!68 = !DILocation(line: 24, column: 7, scope: !69)
+!69 = distinct !DILexicalBlock(scope: !65, file: !15, line: 24, column: 7)
+!70 = !DILocation(line: 25, column: 16, scope: !69)
+!71 = !DILocation(line: 25, column: 12, scope: !72)
+!72 = !DILexicalBlockFile(scope: !69, file: !15, discriminator: 455082015)
+!73 = !DILocation(line: 25, column: 5, scope: !69)
+!74 = !DILocation(line: 26, column: 7, scope: !65)
+!75 = !DILocation(line: 26, column: 3, scope: !76)
+!76 = !DILexicalBlockFile(scope: !65, file: !15, discriminator: 455082031)
+!77 = !DILocation(line: 27, column: 14, scope: !65)
+!78 = !DILocation(line: 27, column: 17, scope: !65)
+!79 = !DILocation(line: 27, column: 10, scope: !80)
+!80 = !DILexicalBlockFile(scope: !65, file: !15, discriminator: 455082039)
+!81 = !DILocation(line: 27, column: 3, scope: !65)
+!82 = !DILocation(line: 28, column: 1, scope: !65)

>From ac05c3edb04a7afba46e91aaf0147179667fad17 Mon Sep 17 00:00:00 2001
From: h2h <h2h at meta.com>
Date: Wed, 10 Jun 2026 11:06:27 -0700
Subject: [PATCH 4/5] Fixup sample reader with the created new profiles

---
 llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
index 4db73f5672ba3..8250b6d925e08 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
@@ -408,10 +408,18 @@ void SampleProfileMatcher::runStaleProfileMatching(
       if (!FSForMatching)
         continue;
 
-      FunctionSamples &NewFS = FlattenedProfiles.create(IR.second);
+      FunctionId NewAnchor(FunctionSamples::getCanonicalFnName(IR.second.stringRef()));
+      FunctionSamples &NewFS = FlattenedProfiles.create(NewAnchor);
       NewFS.merge(*FSForMatching);
-      FuncToProfileNameMap[const_cast<Function *>(&F)] = IR.second;
+      FuncToProfileNameMap[const_cast<Function *>(&F)] = NewAnchor;
       IRToProfileLocationMap = getIRToProfileLocationMap(NewFS);
+
+      // Update profile in the sample profile reader
+      SampleProfileMap &Profiles = Reader.getProfiles();
+      SampleContext FContext(NewAnchor);
+      auto Res = Profiles.try_emplace(FContext.getHashCode(), FContext, NewFS);
+      FunctionSamples &FProfile = Res.first->second;
+      FProfile.setContext(FContext);
     }
   }
 

>From 92a756d88d5804a2e67aa56941da8ec1439a6fda Mon Sep 17 00:00:00 2001
From: h2h <h2h at meta.com>
Date: Wed, 10 Jun 2026 15:50:25 -0700
Subject: [PATCH 5/5] Fix an error in the new anchor mapping

---
 llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp    | 13 +++++++------
 .../pseudo-probe-stale-profile-orphan-conflict.ll   |  6 +++---
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
index 8250b6d925e08..5026125b8336b 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
@@ -371,15 +371,15 @@ void SampleProfileMatcher::runStaleProfileMatching(
   for (const auto &IR : IRAnchors) {
     bool ProfileConflicted = false;
     const auto &Loc = IR.first;
+    Function *Callee = M.getFunction(IR.second.stringRef());
+    if (!Callee)
+      continue;
     FunctionId ProfAnchor;
     auto AnchorLoc = MatchedAnchors.find(Loc);
     if (AnchorLoc == MatchedAnchors.end()) {
       // Search within the module and find if we have conflicts in pre-matched
       // profiles for this anchor
-      Function *Sub = M.getFunction(IR.second.stringRef());
-      if (!Sub)
-        continue;
-      auto PreMatched = FuncToProfileNameMap.find(Sub);
+      auto PreMatched = FuncToProfileNameMap.find(Callee);
       if (PreMatched == FuncToProfileNameMap.end())
         continue;
       ProfAnchor = PreMatched->second;
@@ -408,10 +408,11 @@ void SampleProfileMatcher::runStaleProfileMatching(
       if (!FSForMatching)
         continue;
 
-      FunctionId NewAnchor(FunctionSamples::getCanonicalFnName(IR.second.stringRef()));
+      FunctionId NewAnchor(
+          FunctionSamples::getCanonicalFnName(IR.second.stringRef()));
       FunctionSamples &NewFS = FlattenedProfiles.create(NewAnchor);
       NewFS.merge(*FSForMatching);
-      FuncToProfileNameMap[const_cast<Function *>(&F)] = NewAnchor;
+      FuncToProfileNameMap[Callee] = NewAnchor;
       IRToProfileLocationMap = getIRToProfileLocationMap(NewFS);
 
       // Update profile in the sample profile reader
diff --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll
index e6ddaa9d97aef..d7886cc72dc8f 100644
--- a/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll
+++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-orphan-conflict.ll
@@ -64,11 +64,11 @@
 ; CHECK: Callsite with callee:_Z3subi is matched from 1 to 11
 ; CHECK: Run stale profile matching for _Z3subi
 ; CHECK: Run stale profile matching for _Z3midl
-; CHECK: Profile Function _Z3topll has already been matched to another IR function.
-; CHECK: Profile Function _Z3midl has already been matched to another IR function.
-; CHECK: Profile Function _Z3midi has already been matched to another IR function.
 ; CHECK: Function processing order:
 ; CHECK: _Z3topll
+; CHECK: _Z3midl
+; CHECK: _Z3fool
+; CHECK: _Z3topl
 ; CHECK: _Z3midll
 ; CHECK: _Z3subi
 ; CHECK: _Z3barl



More information about the llvm-commits mailing list