[llvm] [IndirectBrExpand] Preserve profile weights (PR #227784)

Aiden Grossman via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 30 09:49:17 PDT 2026


https://github.com/boomanaiden154 updated https://github.com/llvm/llvm-project/pull/227784

>From a282b7299293ea66a0b8787cb9f7b4d7cfcdb6ef Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Wed, 30 Sep 2026 14:11:25 +0000
Subject: [PATCH] [IndirectBrExpand] Preserve profile weights

We can derive the weights for the created select instruction from the
weights of the indirectbr instructions that are used to compose it.

This is a no-op most of the time outside of some contexts, but
production users that utilize PGO do enable this (e.g., the kernel).
---
 llvm/lib/CodeGen/IndirectBrExpandPass.cpp    | 105 +++++++++++--
 llvm/test/CodeGen/X86/O0-pipeline.ll         |   6 +-
 llvm/test/CodeGen/X86/opt-pipeline.ll        |   5 +-
 llvm/test/Transforms/IndirectBrExpand/pgo.ll | 148 +++++++++++++++++++
 llvm/utils/profcheck-xfail.txt               |   1 -
 5 files changed, 249 insertions(+), 16 deletions(-)
 create mode 100644 llvm/test/Transforms/IndirectBrExpand/pgo.ll

diff --git a/llvm/lib/CodeGen/IndirectBrExpandPass.cpp b/llvm/lib/CodeGen/IndirectBrExpandPass.cpp
index e7a22656f17c2..d04c964be8788 100644
--- a/llvm/lib/CodeGen/IndirectBrExpandPass.cpp
+++ b/llvm/lib/CodeGen/IndirectBrExpandPass.cpp
@@ -25,9 +25,12 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Sequence.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/BlockFrequencyInfo.h"
 #include "llvm/Analysis/DomTreeUpdater.h"
+#include "llvm/Analysis/LazyBlockFrequencyInfo.h"
 #include "llvm/CodeGen/IndirectBrExpand.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
@@ -36,6 +39,7 @@
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/IR/ProfDataUtils.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -46,6 +50,10 @@ using namespace llvm;
 
 #define DEBUG_TYPE "indirectbr-expand"
 
+namespace llvm {
+extern cl::opt<bool> ProfcheckDisableMetadataFixes;
+} // namespace llvm
+
 namespace {
 
 class IndirectBrExpandLegacyPass : public FunctionPass {
@@ -55,6 +63,7 @@ class IndirectBrExpandLegacyPass : public FunctionPass {
   IndirectBrExpandLegacyPass() : FunctionPass(ID) {}
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
+    LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
     AU.addPreserved<DominatorTreeWrapperPass>();
   }
 
@@ -63,8 +72,8 @@ class IndirectBrExpandLegacyPass : public FunctionPass {
 
 } // end anonymous namespace
 
-static bool runImpl(Function &F, const TargetLowering *TLI,
-                    DomTreeUpdater *DTU);
+static bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU,
+                    function_ref<BlockFrequencyInfo *()> GetBFI);
 
 PreservedAnalyses IndirectBrExpandPass::run(Function &F,
                                             FunctionAnalysisManager &FAM) {
@@ -76,7 +85,9 @@ PreservedAnalyses IndirectBrExpandPass::run(Function &F,
   auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
   DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
 
-  bool Changed = runImpl(F, TLI, DT ? &DTU : nullptr);
+  bool Changed = runImpl(F, TLI, DT ? &DTU : nullptr, [&]() {
+    return &FAM.getResult<BlockFrequencyAnalysis>(F);
+  });
   if (!Changed)
     return PreservedAnalyses::all();
   PreservedAnalyses PA;
@@ -96,13 +107,19 @@ FunctionPass *llvm::createIndirectBrExpandPass() {
   return new IndirectBrExpandLegacyPass();
 }
 
-bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU) {
+bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU,
+             function_ref<BlockFrequencyInfo *()> GetBFI) {
   auto &DL = F.getDataLayout();
 
   SmallVector<IndirectBrInst *, 1> IndirectBrs;
+  SmallVector<uint64_t, 1> IndirectBrsBlockFrequencies;
+  SmallVector<uint64_t, 1> IndirectBrsBranchWeightSums;
+  bool SkipProfileUpdates = false;
+  BlockFrequencyInfo *BFI = nullptr;
 
   // Set of all potential successors for indirectbr instructions.
-  SmallPtrSet<BasicBlock *, 4> IndirectBrSuccs;
+  DenseMap<const BasicBlock *, SmallVector<std::pair<size_t, uint64_t>>>
+      IndirectBrSuccToIndirectBr;
 
   // Build a list of indirectbrs that we want to rewrite.
   for (BasicBlock &BB : F)
@@ -116,7 +133,31 @@ bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU) {
       }
 
       IndirectBrs.push_back(IBr);
-      IndirectBrSuccs.insert_range(IBr->successors());
+      for (const BasicBlock *SuccessorBB : IBr->successors())
+        IndirectBrSuccToIndirectBr.insert({SuccessorBB, {}});
+
+      if (SkipProfileUpdates)
+        continue;
+      if (!BFI)
+        BFI = GetBFI();
+      std::optional<uint64_t> BlockFrequency = BFI->getBlockProfileCount(&BB);
+      if (!BlockFrequency.has_value()) {
+        SkipProfileUpdates = true;
+        continue;
+      }
+      IndirectBrsBlockFrequencies.push_back(*BlockFrequency);
+      SmallVector<uint32_t> IndirectBrBranchWeights;
+      bool HasBranchWeights =
+          extractBranchWeights(*IBr, IndirectBrBranchWeights);
+      if (!HasBranchWeights) {
+        SkipProfileUpdates = true;
+        continue;
+      }
+      for (const auto [SuccessorBB, SuccessorBranchWeight] :
+           zip_equal(IBr->successors(), IndirectBrBranchWeights))
+        IndirectBrSuccToIndirectBr[SuccessorBB].push_back(
+            {IndirectBrs.size() - 1, SuccessorBranchWeight});
+      IndirectBrsBranchWeightSums.push_back(sum_of(IndirectBrBranchWeights));
     }
 
   if (IndirectBrs.empty())
@@ -127,11 +168,13 @@ bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU) {
   // whose address escapes. We do that here and rewrite all the blockaddress
   // constants to just be those integer constants cast to a pointer type.
   SmallVector<BasicBlock *, 4> BBs;
+  SmallVector<ScaledNumber<uint64_t>, 4> BBWeights;
 
   for (BasicBlock &BB : F) {
     // Skip blocks that aren't successors to an indirectbr we're going to
     // rewrite.
-    if (!IndirectBrSuccs.count(&BB))
+    auto IndirectBrSuccToIndirectBrIt = IndirectBrSuccToIndirectBr.find(&BB);
+    if (IndirectBrSuccToIndirectBrIt == IndirectBrSuccToIndirectBr.end())
       continue;
 
     auto *BA = BlockAddress::lookup(&BB);
@@ -154,6 +197,23 @@ bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU) {
     // expressions, for instance, where they are used to pass labels to
     // asm-goto. This part of the pass needs a rework.
     BA->replaceAllUsesWith(ConstantExpr::getIntToPtr(BBIndexC, BA->getType()));
+
+    if (SkipProfileUpdates)
+      continue;
+    ScaledNumber<uint64_t> BranchWeightSumsProduct(1, 0);
+    for (uint64_t BranchWeightSum : IndirectBrsBranchWeightSums)
+      BranchWeightSumsProduct *= ScaledNumber<uint64_t>(BranchWeightSum, 0);
+    ScaledNumber<uint64_t> BlockWeight(0, 0);
+    for (const auto &[IndirectBrIndex, BlockBranchProbability] :
+         IndirectBrSuccToIndirectBrIt->second) {
+      BlockWeight += ScaledNumber<uint64_t>(
+                         IndirectBrsBlockFrequencies[IndirectBrIndex], 0) *
+                     ScaledNumber<uint64_t>(BlockBranchProbability, 0) *
+                     (BranchWeightSumsProduct /
+                      ScaledNumber<uint64_t>(
+                          IndirectBrsBranchWeightSums[IndirectBrIndex], 0));
+    }
+    BBWeights.push_back(BlockWeight);
   }
 
   if (BBs.empty()) {
@@ -161,7 +221,7 @@ bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU) {
     // cannot get a valid input and we can replace all of them with unreachable.
     SmallVector<DominatorTree::UpdateType, 8> Updates;
     if (DTU)
-      Updates.reserve(IndirectBrSuccs.size());
+      Updates.reserve(IndirectBrSuccToIndirectBr.size());
     for (auto *IBr : IndirectBrs) {
       if (DTU) {
         for (BasicBlock *SuccBB : IBr->successors())
@@ -171,7 +231,7 @@ bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU) {
       IBr->eraseFromParent();
     }
     if (DTU) {
-      assert(Updates.size() == IndirectBrSuccs.size() &&
+      assert(Updates.size() == IndirectBrSuccToIndirectBr.size() &&
              "Got unexpected update count.");
       DTU->applyUpdates(Updates);
     }
@@ -206,10 +266,10 @@ bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU) {
     SwitchBB = IBr->getParent();
     SwitchValue = GetSwitchValue(IBr);
     if (DTU) {
-      Updates.reserve(IndirectBrSuccs.size());
+      Updates.reserve(IndirectBrSuccToIndirectBr.size());
       for (BasicBlock *SuccBB : IBr->successors())
         Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB});
-      assert(Updates.size() == IndirectBrSuccs.size() &&
+      assert(Updates.size() == IndirectBrSuccToIndirectBr.size() &&
              "Got unexpected update count.");
     }
     IBr->eraseFromParent();
@@ -225,7 +285,8 @@ bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU) {
     // Now replace the indirectbr instructions with direct branches to the
     // switch block and fill out the PHI operands.
     if (DTU)
-      Updates.reserve(IndirectBrs.size() + 2 * IndirectBrSuccs.size());
+      Updates.reserve(IndirectBrs.size() +
+                      2 * IndirectBrSuccToIndirectBr.size());
     for (auto *IBr : IndirectBrs) {
       SwitchPN->addIncoming(GetSwitchValue(IBr), IBr->getParent());
       UncondBrInst::Create(SwitchBB, IBr->getIterator());
@@ -258,6 +319,22 @@ bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU) {
     DTU->applyUpdates(Updates);
   }
 
+  if (SkipProfileUpdates || ProfcheckDisableMetadataFixes) {
+    setExplicitlyUnknownBranchWeightsIfProfiled(*SI, DEBUG_TYPE);
+    return true;
+  }
+
+  int16_t MaxScale = 0;
+  for (const ScaledNumber<uint64_t> &BBWeight : BBWeights)
+    MaxScale = std::max(MaxScale, BBWeight.getScale());
+  SmallVector<uint64_t, 4> ExtractedBBWeights;
+  ExtractedBBWeights.reserve(BBWeights.size());
+  for (ScaledNumber<uint64_t> &BBWeight : BBWeights) {
+    int16_t Shift = MaxScale - BBWeight.getScale();
+    ExtractedBBWeights.push_back(BBWeight.getDigits() >> Shift);
+  }
+  setFittedBranchWeights(*SI, ExtractedBBWeights, false);
+
   return true;
 }
 
@@ -276,5 +353,7 @@ bool IndirectBrExpandLegacyPass::runOnFunction(Function &F) {
   if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
     DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);
 
-  return runImpl(F, TLI, DTU ? &*DTU : nullptr);
+  return runImpl(F, TLI, DTU ? &*DTU : nullptr, [&]() {
+    return &getAnalysis<LazyBlockFrequencyInfoPass>().getBFI();
+  });
 }
diff --git a/llvm/test/CodeGen/X86/O0-pipeline.ll b/llvm/test/CodeGen/X86/O0-pipeline.ll
index e8a3084563573..a139af7720e3d 100644
--- a/llvm/test/CodeGen/X86/O0-pipeline.ll
+++ b/llvm/test/CodeGen/X86/O0-pipeline.ll
@@ -30,7 +30,11 @@
 ; CHECK-NEXT:       Instrument function entry/exit with calls to e.g. mcount() (post inlining)
 ; CHECK-NEXT:       Scalarize Masked Memory Intrinsics
 ; CHECK-NEXT:       Expand reduction intrinsics
-; CHECK-NEXT:       Expand indirectbr instructions
+; CHECK-NEXT:       Dominator Tree Construction 
+; CHECK-NEXT:       Cycle Info Analysis 
+; CHECK-NEXT:       Lazy Branch Probability Analysis 
+; CHECK-NEXT:       Lazy Block Frequency Analysis 
+; CHECK-NEXT:       Expand indirectbr instructions 
 ; CHECK-NEXT:       Exception handling preparation
 ; CHECK-NEXT:       Prepare inline asm insts
 ; CHECK-NEXT:       Safe Stack instrumentation pass
diff --git a/llvm/test/CodeGen/X86/opt-pipeline.ll b/llvm/test/CodeGen/X86/opt-pipeline.ll
index 47d97871274ae..58fb03b8f94a5 100644
--- a/llvm/test/CodeGen/X86/opt-pipeline.ll
+++ b/llvm/test/CodeGen/X86/opt-pipeline.ll
@@ -66,7 +66,10 @@
 ; CHECK-NEXT:       Expand reduction intrinsics
 ; CHECK-NEXT:       Interleaved Access Pass
 ; CHECK-NEXT:       X86 Partial Reduction
-; CHECK-NEXT:       Expand indirectbr instructions
+; CHECK-NEXT:       Cycle Info Analysis 
+; CHECK-NEXT:       Lazy Branch Probability Analysis 
+; CHECK-NEXT:       Lazy Block Frequency Analysis 
+; CHECK-NEXT:       Expand indirectbr instructions 
 ; CHECK-NEXT:       Natural Loop Information
 ; CHECK-NEXT:       Cycle Info Analysis
 ; CHECK-NEXT:       Post-Dominator Tree Construction
diff --git a/llvm/test/Transforms/IndirectBrExpand/pgo.ll b/llvm/test/Transforms/IndirectBrExpand/pgo.ll
new file mode 100644
index 0000000000000..82f9ca445660f
--- /dev/null
+++ b/llvm/test/Transforms/IndirectBrExpand/pgo.ll
@@ -0,0 +1,148 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt < %s -passes=indirectbr-expand -S | FileCheck %s
+;
+; REQUIRES: x86-registered-target
+
+target triple = "x86_64-unknown-linux-gnu"
+
+ at test1.targets = constant [4 x ptr] [ptr blockaddress(@test1, %bb0),
+  ptr blockaddress(@test1, %bb1),
+  ptr blockaddress(@test1, %bb2),
+  ptr blockaddress(@test1, %bb3)]
+
+;.
+; CHECK: @test1.targets = constant [4 x ptr] [ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 2 to ptr), ptr inttoptr (i64 3 to ptr), ptr blockaddress(@test1, %bb3)]
+; CHECK: @missing_branch_weights.targets = constant [2 x ptr] [ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 2 to ptr)]
+;.
+define void @test1(ptr readonly %p, ptr %sink) #0 !prof !0 {
+; CHECK-LABEL: define void @test1(
+; CHECK-SAME: ptr readonly [[P:%.*]], ptr [[SINK:%.*]]) #[[ATTR0:[0-9]+]] !prof [[PROF0:![0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[BR_SELECT_I:%.*]] = load i64, ptr [[P]], align 8
+; CHECK-NEXT:    [[BR_SELECT_CMP:%.*]] = icmp eq i64 [[BR_SELECT_I]], 64
+; CHECK-NEXT:    br i1 [[BR_SELECT_CMP]], label %[[BR1:.*]], label %[[BR2:.*]], !prof [[PROF1:![0-9]+]]
+; CHECK:       [[BR1]]:
+; CHECK-NEXT:    [[I0:%.*]] = load i64, ptr [[P]], align 8
+; CHECK-NEXT:    [[TARGET_I0:%.*]] = getelementptr [4 x ptr], ptr @test1.targets, i64 0, i64 [[I0]]
+; CHECK-NEXT:    [[TARGET0:%.*]] = load ptr, ptr [[TARGET_I0]], align 8
+; CHECK-NEXT:    [[TARGET0_SWITCH_CAST:%.*]] = ptrtoint ptr [[TARGET0]] to i64
+; CHECK-NEXT:    br label %[[SWITCH_BB:.*]]
+; CHECK:       [[BR2]]:
+; CHECK-NEXT:    [[I_NEXT:%.*]] = load i64, ptr [[P]], align 8
+; CHECK-NEXT:    [[TARGET_I_NEXT:%.*]] = getelementptr [4 x ptr], ptr @test1.targets, i64 0, i64 [[I_NEXT]]
+; CHECK-NEXT:    [[TARGET_NEXT:%.*]] = load ptr, ptr [[TARGET_I_NEXT]], align 8
+; CHECK-NEXT:    [[TARGET_NEXT_SWITCH_CAST:%.*]] = ptrtoint ptr [[TARGET_NEXT]] to i64
+; CHECK-NEXT:    br label %[[SWITCH_BB]]
+; CHECK:       [[BB0:.*]]:
+; CHECK-NEXT:    store volatile i64 0, ptr [[SINK]], align 8
+; CHECK-NEXT:    br label %[[EXIT:.*]]
+; CHECK:       [[BB1:.*]]:
+; CHECK-NEXT:    store volatile i64 1, ptr [[SINK]], align 8
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[BB2:.*]]:
+; CHECK-NEXT:    store volatile i64 2, ptr [[SINK]], align 8
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[BB3:.*:]]
+; CHECK-NEXT:    store volatile i64 3, ptr [[SINK]], align 8
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[SWITCH_BB]]:
+; CHECK-NEXT:    [[SWITCH_VALUE_PHI:%.*]] = phi i64 [ [[TARGET0_SWITCH_CAST]], %[[BR1]] ], [ [[TARGET_NEXT_SWITCH_CAST]], %[[BR2]] ]
+; CHECK-NEXT:    switch i64 [[SWITCH_VALUE_PHI]], label %[[BB0]] [
+; CHECK-NEXT:      i64 2, label %[[BB1]]
+; CHECK-NEXT:      i64 3, label %[[BB2]]
+; CHECK-NEXT:    ], !prof [[PROF2:![0-9]+]]
+;
+entry:
+  %br.select.i = load i64, ptr %p
+  %br.select.cmp = icmp eq i64 %br.select.i, 64
+  br i1 %br.select.cmp, label %br1, label %br2, !prof !1
+
+br1:
+  %i0 = load i64, ptr %p
+  %target.i0 = getelementptr [4 x ptr], ptr @test1.targets, i64 0, i64 %i0
+  %target0 = load ptr, ptr %target.i0
+  ; Only a subset of blocks are viable successors here.
+  indirectbr ptr %target0, [label %bb0, label %bb1], !prof !2
+
+br2:
+  %i.next = load i64, ptr %p
+  %target.i.next = getelementptr [4 x ptr], ptr @test1.targets, i64 0, i64 %i.next
+  %target.next = load ptr, ptr %target.i.next
+  ; A different subset of blocks are viable successors here.
+  indirectbr ptr %target.next, [label %bb1, label %bb2], !prof !3
+
+bb0:
+  store volatile i64 0, ptr %sink
+  br label %exit
+
+bb1:
+  store volatile i64 1, ptr %sink
+  br label %exit
+
+bb2:
+  store volatile i64 2, ptr %sink
+  br label %exit
+
+bb3:
+  store volatile i64 3, ptr %sink
+  br label %exit
+
+exit:
+  ret void
+}
+
+ at missing_branch_weights.targets = constant [2 x ptr] [ptr blockaddress(@missing_branch_weights, %bb0),
+  ptr blockaddress(@missing_branch_weights, %bb1)]
+
+define void @missing_branch_weights(ptr readonly %p, ptr %sink) #0 !prof !0 {
+; CHECK-LABEL: define void @missing_branch_weights(
+; CHECK-SAME: ptr readonly [[P:%.*]], ptr [[SINK:%.*]]) #[[ATTR0]] !prof [[PROF0]] {
+; CHECK-NEXT:    [[I0:%.*]] = load i64, ptr [[P]], align 8
+; CHECK-NEXT:    [[TARGET_I0:%.*]] = getelementptr [4 x ptr], ptr @missing_branch_weights.targets, i64 0, i64 [[I0]]
+; CHECK-NEXT:    [[TARGET0:%.*]] = load ptr, ptr [[TARGET_I0]], align 8
+; CHECK-NEXT:    [[TARGET0_SWITCH_CAST:%.*]] = ptrtoint ptr [[TARGET0]] to i64
+; CHECK-NEXT:    switch i64 [[TARGET0_SWITCH_CAST]], label %[[BB0:.*]] [
+; CHECK-NEXT:      i64 2, label %[[BB1:.*]]
+; CHECK-NEXT:    ], !prof [[PROF3:![0-9]+]]
+; CHECK:       [[BB0]]:
+; CHECK-NEXT:    store volatile i64 0, ptr [[SINK]], align 8
+; CHECK-NEXT:    br label %[[EXIT:.*]]
+; CHECK:       [[BB1]]:
+; CHECK-NEXT:    store volatile i64 1, ptr [[SINK]], align 8
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+  %i0 = load i64, ptr %p
+  %target.i0 = getelementptr [4 x ptr], ptr @missing_branch_weights.targets, i64 0, i64 %i0
+  %target0 = load ptr, ptr %target.i0
+  indirectbr ptr %target0, [label %bb0, label %bb1]
+
+bb0:
+  store volatile i64 0, ptr %sink
+  br label %exit
+
+bb1:
+  store volatile i64 1, ptr %sink
+  br label %exit
+
+exit:
+  ret void
+}
+
+attributes #0 = { "target-features"="+retpoline" }
+
+!0 = !{!"function_entry_count", i32 10}
+!1 = !{!"branch_weights", i32 1, i32 2}
+!2 = !{!"branch_weights", i32 3, i32 5}
+!3 = !{!"branch_weights", i32 7, i32 11}
+;.
+; CHECK: attributes #[[ATTR0]] = { "target-features"="+retpoline" }
+;.
+; CHECK: [[PROF0]] = !{!"function_entry_count", i32 10}
+; CHECK: [[PROF1]] = !{!"branch_weights", i32 1, i32 2}
+; CHECK: [[PROF2]] = !{!"branch_weights", i32 162, i32 662, i32 616}
+; CHECK: [[PROF3]] = !{!"unknown", !"indirectbr-expand"}
+;.
diff --git a/llvm/utils/profcheck-xfail.txt b/llvm/utils/profcheck-xfail.txt
index c2b5009a63c80..a12670679eb24 100644
--- a/llvm/utils/profcheck-xfail.txt
+++ b/llvm/utils/profcheck-xfail.txt
@@ -26,7 +26,6 @@ Transforms/IndVarSimplify/debugloc-rem-subst.ll
 Transforms/IndVarSimplify/eliminate-rem.ll
 Transforms/IndVarSimplify/pr45835.ll
 Transforms/IndVarSimplify/preserving-debugloc-rem-div.ll
-Transforms/IndirectBrExpand/basic.ll
 Transforms/InstCombine/canonicalize-clamp-like-pattern-between-negative-and-positive-thresholds.ll
 Transforms/InstCombine/canonicalize-clamp-like-pattern-between-zero-and-positive-threshold.ll
 Transforms/InstCombine/cast-mul-select.ll



More information about the llvm-commits mailing list