[llvm] [llvm-profgen] Add branch/target validation (PR #188620)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 15 19:53:41 PDT 2026


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

>From 57920ac1116c94e0d8ab781a8381a90b456586b7 Mon Sep 17 00:00:00 2001
From: h2h <h2h at meta.com>
Date: Tue, 24 Mar 2026 14:35:38 -0700
Subject: [PATCH 1/4] [llvm-profgen] Add branch/target validation

---
 llvm/tools/llvm-profgen/PerfReader.cpp     | 55 ++++++++++++++++++++++
 llvm/tools/llvm-profgen/PerfReader.h       |  2 +
 llvm/tools/llvm-profgen/ProfiledBinary.cpp | 13 +++++
 llvm/tools/llvm-profgen/ProfiledBinary.h   | 10 ++++
 4 files changed, 80 insertions(+)

diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp
index 1dc59321fd91f..56d91044f8441 100644
--- a/llvm/tools/llvm-profgen/PerfReader.cpp
+++ b/llvm/tools/llvm-profgen/PerfReader.cpp
@@ -1344,6 +1344,60 @@ void PerfScriptReader::warnInvalidRange() {
       "range end acrossing the unconditinal jmp.");
 }
 
+void PerfScriptReader::warnIfBranchTargetMismatch() {
+  // Collect unique branch source and target addresses from LBR samples,
+  // then check what percentage don't match known instructions in the binary.
+
+  std::unordered_set<uint64_t> SampleBranches;
+  std::unordered_set<uint64_t> SampleIndirectTargets;
+  std::unordered_set<uint64_t> SampleTargets;
+
+  for (const auto &Item : AggregatedSamples) {
+    const PerfSample *Sample = Item.first.getPtr();
+    for (const LBREntry &LBR : Sample->LBRStack) {
+      uint64_t Source = LBR.Source;
+      uint64_t Target = LBR.Target;
+      if (Source == ExternalAddr || Target == ExternalAddr)
+        continue;
+      SampleBranches.insert(Source);
+      if (Binary->addressIsIndirectBranch(Source))
+        SampleIndirectTargets.insert(Target);
+      else
+        SampleTargets.insert(Target);
+    }
+  }
+
+  auto CheckMismatch = [&](StringRef Kind,
+                           const std::unordered_set<uint64_t> &SampleAddrs,
+                           auto IsValidAddr) {
+    if (SampleAddrs.empty())
+      return;
+    uint64_t Mismatched = 0;
+    for (uint64_t Addr : SampleAddrs) {
+      if (!IsValidAddr(Addr))
+        Mismatched++;
+    }
+    double MismatchPct =
+        static_cast<double>(Mismatched) / SampleAddrs.size() * 100;
+    if (Mismatched) {
+      WithColor::warning()
+          << format("%.2f", MismatchPct) << "% of sampled " << Kind
+          << " addresses (" << Mismatched << "/" << SampleAddrs.size()
+          << ") do not match the binary, likely due to problematic raw samples or mismatch in binary.\n"
+    }
+  };
+
+  CheckMismatch("branch", SampleBranches, [&](uint64_t Addr) {
+    return Binary->addressIsTransfer(Addr);
+  });
+  CheckMismatch("target", SampleTargets, [&](uint64_t Addr) {
+    return Binary->addressIsBranchTarget(Addr) || Binary->findFuncRangeForStartAddr(Addr);
+  });
+  CheckMismatch("indirect branch target", SampleIndirectTargets, [&](uint64_t Addr) {
+    return Binary->addressIsCode(Addr);
+  });
+}
+
 void PerfScriptReader::parsePerfTraces() {
   // Parse perf traces and do aggregation.
   parseAndAggregateTrace();
@@ -1360,6 +1414,7 @@ void PerfScriptReader::parsePerfTraces() {
   // Generate unsymbolized profile.
   warnTruncatedStack();
   warnInvalidRange();
+  warnIfBranchTargetMismatch();
   generateUnsymbolizedProfile();
   AggregatedSamples.clear();
 
diff --git a/llvm/tools/llvm-profgen/PerfReader.h b/llvm/tools/llvm-profgen/PerfReader.h
index 6e233d17f8e62..1ee6369de649a 100644
--- a/llvm/tools/llvm-profgen/PerfReader.h
+++ b/llvm/tools/llvm-profgen/PerfReader.h
@@ -650,6 +650,8 @@ class PerfScriptReader : public PerfReaderBase {
   void warnTruncatedStack();
   // Warn if range is invalid.
   void warnInvalidRange();
+  // Warn if sampled branch/target addresses don't match the binary.
+  void warnIfBranchTargetMismatch();
   // Extract call stack from the perf trace lines
   bool extractCallstack(TraceStream &TraceIt,
                         SmallVectorImpl<uint64_t> &CallStack);
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.cpp b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
index 915e991e4068c..6a4ab7d6a854b 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.cpp
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
@@ -628,6 +628,8 @@ bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes,
       if (MCDesc.isCall()) {
         CallAddressSet.insert(Address);
         UncondBranchAddrSet.insert(Address);
+        // Record the instruction after call as the branch target of a ret
+        BranchTargetAddressSet.insert(Address + Size);
       } else if (MCDesc.isReturn()) {
         RetAddressSet.insert(Address);
         UncondBranchAddrSet.insert(Address);
@@ -637,6 +639,17 @@ bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes,
         BranchAddressSet.insert(Address);
       }
 
+      if (MCDesc.isIndirectBranch()) {
+        IndirectBranchAddressSet.insert(Address);
+      }
+
+      // Record branch target addresses for branches and calls.
+      if (MCDesc.isCall() || MCDesc.isBranch()) {
+        uint64_t Target = 0;
+        if (MIA->evaluateBranch(Inst, Address, Size, Target))
+          BranchTargetAddressSet.insert(Target);
+      }
+
       // Record potential call targets for tail frame inference later-on.
       if (InferMissingFrames && FRange) {
         uint64_t Target = 0;
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.h b/llvm/tools/llvm-profgen/ProfiledBinary.h
index e907c4a8a1647..f72c2ba44f5e2 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.h
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.h
@@ -282,6 +282,10 @@ class ProfiledBinary {
   std::set<uint64_t> UncondBranchAddrSet;
   // A set of branch instruction addresses.
   std::unordered_set<uint64_t> BranchAddressSet;
+  // A set of indirect branch instruction addresses.
+  std::unordered_set<uint64_t> IndirectBranchAddressSet;
+  // A set of branch target addresses (destinations of branches/calls).
+  std::unordered_set<uint64_t> BranchTargetAddressSet;
 
   // Estimate and track function prolog and epilog ranges.
   PrologEpilogTracker ProEpilogTracker;
@@ -465,6 +469,12 @@ class ProfiledBinary {
     return ProEpilogTracker.PrologEpilogSet.count(Address);
   }
 
+  bool addressIsBranchTarget(uint64_t Address) const {
+    return BranchTargetAddressSet.count(Address);
+  }
+  bool addressIsIndirectBranch(uint64_t Address) const {
+    return IndirectBranchAddressSet.count(Address);
+  }
   bool addressIsTransfer(uint64_t Address) {
     return BranchAddressSet.count(Address) || RetAddressSet.count(Address) ||
            CallAddressSet.count(Address);

>From 428e86c0d2cc9cce79b6b06b6748e28cffd2fe44 Mon Sep 17 00:00:00 2001
From: h2h <h2h at meta.com>
Date: Wed, 25 Mar 2026 15:59:10 -0700
Subject: [PATCH 2/4] formatting

---
 llvm/tools/llvm-profgen/PerfReader.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp
index 56d91044f8441..e306539fb09f1 100644
--- a/llvm/tools/llvm-profgen/PerfReader.cpp
+++ b/llvm/tools/llvm-profgen/PerfReader.cpp
@@ -1383,7 +1383,7 @@ void PerfScriptReader::warnIfBranchTargetMismatch() {
       WithColor::warning()
           << format("%.2f", MismatchPct) << "% of sampled " << Kind
           << " addresses (" << Mismatched << "/" << SampleAddrs.size()
-          << ") do not match the binary, likely due to problematic raw samples or mismatch in binary.\n"
+          << ") do not match the binary, likely due to problematic raw samples or mismatch in binary.\n";
     }
   };
 

>From 3af39ce3e6c245eb0f78f1097317195997999690 Mon Sep 17 00:00:00 2001
From: h2h <h2h at meta.com>
Date: Tue, 7 Apr 2026 08:11:11 -0700
Subject: [PATCH 3/4] Improve performance

---
 llvm/tools/llvm-profgen/PerfReader.cpp | 66 +++++++++++---------------
 1 file changed, 29 insertions(+), 37 deletions(-)

diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp
index e306539fb09f1..7cd961e0bf527 100644
--- a/llvm/tools/llvm-profgen/PerfReader.cpp
+++ b/llvm/tools/llvm-profgen/PerfReader.cpp
@@ -1348,9 +1348,10 @@ void PerfScriptReader::warnIfBranchTargetMismatch() {
   // Collect unique branch source and target addresses from LBR samples,
   // then check what percentage don't match known instructions in the binary.
 
-  std::unordered_set<uint64_t> SampleBranches;
-  std::unordered_set<uint64_t> SampleIndirectTargets;
-  std::unordered_set<uint64_t> SampleTargets;
+  uint64_t MismatchedBranches = 0;
+  uint64_t MismatchedIndirectTargets = 0;
+  uint64_t MismatchedTargets = 0;
+  uint64_t TotalSamples = 0;
 
   for (const auto &Item : AggregatedSamples) {
     const PerfSample *Sample = Item.first.getPtr();
@@ -1359,43 +1360,34 @@ void PerfScriptReader::warnIfBranchTargetMismatch() {
       uint64_t Target = LBR.Target;
       if (Source == ExternalAddr || Target == ExternalAddr)
         continue;
-      SampleBranches.insert(Source);
-      if (Binary->addressIsIndirectBranch(Source))
-        SampleIndirectTargets.insert(Target);
-      else
-        SampleTargets.insert(Target);
+      TotalSamples++;
+
+      // Validate Branch sources are Call/Branch/Indirect Branch
+      if (!Binary->addressIsTransfer(Source))
+        MismatchedBranches++;
+
+      // Validate Indirect Branch targets landed in code. This may over estimate
+      // the vaid targets only because there's no good way to determine jump
+      // table targets
+      if (Binary->addressIsIndirectBranch(Source)) {
+        if (!Binary->addressIsCode(Target))
+          MismatchedIndirectTargets++;
+      } else if (!Binary->addressIsBranchTarget(Target) &&
+                 !Binary->findFuncRangeForStartAddr(Target))
+        MismatchedTargets++;
     }
   }
 
-  auto CheckMismatch = [&](StringRef Kind,
-                           const std::unordered_set<uint64_t> &SampleAddrs,
-                           auto IsValidAddr) {
-    if (SampleAddrs.empty())
-      return;
-    uint64_t Mismatched = 0;
-    for (uint64_t Addr : SampleAddrs) {
-      if (!IsValidAddr(Addr))
-        Mismatched++;
-    }
-    double MismatchPct =
-        static_cast<double>(Mismatched) / SampleAddrs.size() * 100;
-    if (Mismatched) {
-      WithColor::warning()
-          << format("%.2f", MismatchPct) << "% of sampled " << Kind
-          << " addresses (" << Mismatched << "/" << SampleAddrs.size()
-          << ") do not match the binary, likely due to problematic raw samples or mismatch in binary.\n";
-    }
-  };
-
-  CheckMismatch("branch", SampleBranches, [&](uint64_t Addr) {
-    return Binary->addressIsTransfer(Addr);
-  });
-  CheckMismatch("target", SampleTargets, [&](uint64_t Addr) {
-    return Binary->addressIsBranchTarget(Addr) || Binary->findFuncRangeForStartAddr(Addr);
-  });
-  CheckMismatch("indirect branch target", SampleIndirectTargets, [&](uint64_t Addr) {
-    return Binary->addressIsCode(Addr);
-  });
+  emitWarningSummary(MismatchedBranches, TotalSamples,
+                     "of branches do not match the binary, likely due to "
+                     "problematic raw samples or mismatch in binary.");
+  emitWarningSummary(MismatchedTargets, TotalSamples,
+                     "of branch targets do not match the binary, likely due to "
+                     "problematic raw samples or mismatch in binary.");
+  emitWarningSummary(
+      MismatchedIndirectTargets, TotalSamples,
+      "of indirect branch targets do not match the binary, likely due to "
+      "problematic raw samples or mismatch in binary.");
 }
 
 void PerfScriptReader::parsePerfTraces() {

>From 7dddc5bca44dac83c1581392976dd0842bd2cf4e Mon Sep 17 00:00:00 2001
From: HighW4y2H3ll <zhenghaohuu at gmail.com>
Date: Wed, 15 Apr 2026 19:53:30 -0700
Subject: [PATCH 4/4] Update llvm/tools/llvm-profgen/PerfReader.cpp

Co-authored-by: Amir Ayupov <fads93 at gmail.com>
---
 llvm/tools/llvm-profgen/PerfReader.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp
index 7cd961e0bf527..009503017ec00 100644
--- a/llvm/tools/llvm-profgen/PerfReader.cpp
+++ b/llvm/tools/llvm-profgen/PerfReader.cpp
@@ -1379,8 +1379,7 @@ void PerfScriptReader::warnIfBranchTargetMismatch() {
   }
 
   emitWarningSummary(MismatchedBranches, TotalSamples,
-                     "of branches do not match the binary, likely due to "
-                     "problematic raw samples or mismatch in binary.");
+                     "of branch samples do not match the binary.");
   emitWarningSummary(MismatchedTargets, TotalSamples,
                      "of branch targets do not match the binary, likely due to "
                      "problematic raw samples or mismatch in binary.");



More information about the llvm-commits mailing list