[llvm] [JumpThreading] Thread a common icmp across PHI nodes (PR #221125)

Abhay Kanhere via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 07:09:10 PDT 2026


https://github.com/AbhayKanhere updated https://github.com/llvm/llvm-project/pull/221125

>From 5aa655b070a1f4ced005ea502151e325c84f4f6e Mon Sep 17 00:00:00 2001
From: Abhay Kanhere <a_kanhere at apple.com>
Date: Thu, 3 Sep 2026 10:32:40 -0700
Subject: [PATCH 1/5] [JumpThreading] Thread a common icmp across PHI nodes

When both icmp operands are block PHIs, use isImpliedCondition of the
predecessor's branch to recover its per-edge value and thread known edges.
---
 llvm/lib/Transforms/Scalar/JumpThreading.cpp  |  28 ++++
 .../JumpThreading/thread-cmp-of-phis.ll       | 134 ++++++++++++++++++
 2 files changed, 162 insertions(+)
 create mode 100644 llvm/test/Transforms/JumpThreading/thread-cmp-of-phis.ll

diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 7a0542aac83fc..203165bb27672 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -767,6 +767,34 @@ bool JumpThreadingPass::computeValueKnownInPredecessorsImpl(
           RHS = PN->getIncomingValue(i);
         }
         Value *Res = simplifyCmpInst(Pred, LHS, RHS, {DL});
+
+        // Even without folding, the compare may be known on this edge if
+        // PredBB's branch tests a condition that implies it -- most usefully
+        // the same compare, when both operands are PHIs. PredBB's false arm
+        // reaches BB, so C is false there; BB re-tests C via the PHIs:
+        //
+        //   PredBB: br (C = icmp <pred> A, B), T, BB   ; BB is the false arm
+        //                                          \
+        //                                           v
+        //   BB: L = phi [A, PredBB], ...   ; L -> A on the PredBB edge
+        //       R = phi [B, PredBB], ...   ; R -> B on the PredBB edge
+        //       br (icmp <pred> L, R)      ; == C, false => thread past it
+        //
+        // Require both operands available on the edge (not defined in BB).
+        if (!Res && isa<ICmpInst>(Cmp) && !CmpType->isVectorTy()) {
+          auto DefinedInBB = [&](Value *V) {
+            auto *VI = dyn_cast<Instruction>(V);
+            return VI && VI->getParent() == BB;
+          };
+          auto *PredBI = dyn_cast<CondBrInst>(PredBB->getTerminator());
+          if (PredBI && !DefinedInBB(LHS) && !DefinedInBB(RHS) &&
+              PredBI->getSuccessor(0) != PredBI->getSuccessor(1))
+            if (std::optional<bool> Implied = isImpliedCondition(
+                    PredBI->getCondition(), Pred, LHS, RHS, DL,
+                    /*LHSIsTrue=*/PredBI->getSuccessor(0) == BB))
+              Res = ConstantInt::getBool(Cmp->getContext(), *Implied);
+        }
+
         if (!Res) {
           if (!isa<Constant>(RHS))
             continue;
diff --git a/llvm/test/Transforms/JumpThreading/thread-cmp-of-phis.ll b/llvm/test/Transforms/JumpThreading/thread-cmp-of-phis.ll
new file mode 100644
index 0000000000000..d56ae2ae6a4e9
--- /dev/null
+++ b/llvm/test/Transforms/JumpThreading/thread-cmp-of-phis.ll
@@ -0,0 +1,134 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=jump-threading -S < %s | FileCheck %s
+;
+; JumpThreading can thread a block whose condition is `icmp <pred> (phiA, phiB)`
+; (both operands PHIs defined in the block) on the predecessor edges where the
+; predecessor's controlling branch implies the comparison. Threading is partial:
+; only edges with a proven result are threaded; others keep the branch.
+
+declare i64 @opaque()
+
+; Positive: on the %entry edge the PHIs reconstruct to `icmp eq %a, %b` = %c
+; (false there), so thread %entry -> %if.ne; the opaque %grow edge keeps its branch.
+define i32 @thread_cmp_of_phis(i64 %a, i64 %b) {
+; CHECK-LABEL: @thread_cmp_of_phis(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i64 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[JOIN:%.*]], label [[IF_NE:%.*]]
+; CHECK:       join:
+; CHECK-NEXT:    [[A2:%.*]] = call i64 @opaque()
+; CHECK-NEXT:    [[B2:%.*]] = call i64 @opaque()
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[A2]], [[B2]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_EQ:%.*]], label [[IF_NE]]
+; CHECK:       if.eq:
+; CHECK-NEXT:    ret i32 1
+; CHECK:       if.ne:
+; CHECK-NEXT:    ret i32 0
+;
+entry:
+  %c = icmp eq i64 %a, %b
+  br i1 %c, label %grow, label %join
+
+grow:
+  %a2 = call i64 @opaque()
+  %b2 = call i64 @opaque()
+  br label %join
+
+join:
+  %p1 = phi i64 [ %a, %entry ], [ %a2, %grow ]
+  %p2 = phi i64 [ %b, %entry ], [ %b2, %grow ]
+  %cmp = icmp eq i64 %p1, %p2
+  br i1 %cmp, label %if.eq, label %if.ne
+
+if.eq:
+  ret i32 1
+
+if.ne:
+  ret i32 0
+}
+
+; Negative: %c compares %a/%b, but the join re-tests %a2/%b2 -- different
+; operands, so %c does not imply it; %entry is not threaded.
+define i32 @no_thread_operands_differ(i64 %a, i64 %b, i64 %a2, i64 %b2) {
+; CHECK-LABEL: @no_thread_operands_differ(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i64 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[MID:%.*]], label [[JOIN:%.*]]
+; CHECK:       mid:
+; CHECK-NEXT:    [[PA:%.*]] = call i64 @opaque()
+; CHECK-NEXT:    [[PB:%.*]] = call i64 @opaque()
+; CHECK-NEXT:    br label [[JOIN]]
+; CHECK:       join:
+; CHECK-NEXT:    [[P1:%.*]] = phi i64 [ [[A2:%.*]], [[ENTRY:%.*]] ], [ [[PA]], [[MID]] ]
+; CHECK-NEXT:    [[P2:%.*]] = phi i64 [ [[B2:%.*]], [[ENTRY]] ], [ [[PB]], [[MID]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[P1]], [[P2]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_EQ:%.*]], label [[IF_NE:%.*]]
+; CHECK:       if.eq:
+; CHECK-NEXT:    ret i32 1
+; CHECK:       if.ne:
+; CHECK-NEXT:    ret i32 0
+;
+entry:
+  %c = icmp eq i64 %a, %b
+  br i1 %c, label %mid, label %join
+
+mid:
+  %pa = call i64 @opaque()
+  %pb = call i64 @opaque()
+  br label %join
+
+join:
+  %p1 = phi i64 [ %a2, %entry ], [ %pa, %mid ]
+  %p2 = phi i64 [ %b2, %entry ], [ %pb, %mid ]
+  %cmp = icmp eq i64 %p1, %p2
+  br i1 %cmp, label %if.eq, label %if.ne
+
+if.eq:
+  ret i32 1
+
+if.ne:
+  ret i32 0
+}
+
+; Negative: same operands, but %c is unsigned (ult) while the join re-tests
+; signed (slt) -- ult does not imply slt; %entry is not threaded.
+define i32 @no_thread_predicate_differs(i64 %a, i64 %b) {
+; CHECK-LABEL: @no_thread_predicate_differs(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i64 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    br i1 [[C]], label [[GROW:%.*]], label [[JOIN:%.*]]
+; CHECK:       grow:
+; CHECK-NEXT:    [[A2:%.*]] = call i64 @opaque()
+; CHECK-NEXT:    [[B2:%.*]] = call i64 @opaque()
+; CHECK-NEXT:    br label [[JOIN]]
+; CHECK:       join:
+; CHECK-NEXT:    [[P1:%.*]] = phi i64 [ [[A]], [[ENTRY:%.*]] ], [ [[A2]], [[GROW]] ]
+; CHECK-NEXT:    [[P2:%.*]] = phi i64 [ [[B]], [[ENTRY]] ], [ [[B2]], [[GROW]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[P1]], [[P2]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_EQ:%.*]], label [[IF_NE:%.*]]
+; CHECK:       if.eq:
+; CHECK-NEXT:    ret i32 1
+; CHECK:       if.ne:
+; CHECK-NEXT:    ret i32 0
+;
+entry:
+  %c = icmp ult i64 %a, %b
+  br i1 %c, label %grow, label %join
+
+grow:
+  %a2 = call i64 @opaque()
+  %b2 = call i64 @opaque()
+  br label %join
+
+join:
+  %p1 = phi i64 [ %a, %entry ], [ %a2, %grow ]
+  %p2 = phi i64 [ %b, %entry ], [ %b2, %grow ]
+  %cmp = icmp slt i64 %p1, %p2
+  br i1 %cmp, label %if.eq, label %if.ne
+
+if.eq:
+  ret i32 1
+
+if.ne:
+  ret i32 0
+}

>From 0454212f84f7995936977a3e5a2a96c319dd3ccb Mon Sep 17 00:00:00 2001
From: Abhay Kanhere <a_kanhere at apple.com>
Date: Tue, 8 Sep 2026 10:40:07 -0700
Subject: [PATCH 2/5] [JumpThreading] Address review feedback; refactor for
 readability (NFC)

Extract the edge-implied-compare check into a static isImpliedByEdgeBranch
helper (keeping the CFG diagram). No functional change.
---
 llvm/lib/Transforms/Scalar/JumpThreading.cpp | 62 ++++++++++++--------
 1 file changed, 36 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 203165bb27672..3e20249478306 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -549,6 +549,36 @@ static Constant *getKnownConstant(Value *Val, ConstantPreference Preference) {
   return dyn_cast<ConstantInt>(Val);
 }
 
+/// If the edge PredBB->BB is controlled by a conditional branch whose condition
+/// implies `icmp Pred LHS, RHS`, return that compare's value on the edge (else
+/// std::nullopt). LHS/RHS are the operands as seen on the edge and must be
+/// available there -- a compare operand defined in BB does not exist on the
+/// edge. Most useful when both compare operands are PHIs in BB and PredBB
+/// already branched on the same compare:
+///
+///   PredBB: br (C = icmp <pred> A, B), T, BB   ; here BB is the false arm
+///                                          \
+///                                           v
+///   BB: L = phi [A, PredBB], ...   ; L -> A on the PredBB edge
+///       R = phi [B, PredBB], ...   ; R -> B on the PredBB edge
+///       br (icmp <pred> L, R)      ; == C, false => thread past it
+static std::optional<bool> isImpliedByEdgeBranch(BasicBlock *PredBB,
+                                                 BasicBlock *BB,
+                                                 CmpInst::Predicate Pred,
+                                                 Value *LHS, Value *RHS,
+                                                 const DataLayout &DL) {
+  auto DefinedInBB = [&](Value *V) {
+    auto *I = dyn_cast<Instruction>(V);
+    return I && I->getParent() == BB;
+  };
+  auto *PredBI = dyn_cast<CondBrInst>(PredBB->getTerminator());
+  if (!PredBI || PredBI->getSuccessor(0) == PredBI->getSuccessor(1) ||
+      DefinedInBB(LHS) || DefinedInBB(RHS))
+    return std::nullopt;
+  return isImpliedCondition(PredBI->getCondition(), Pred, LHS, RHS, DL,
+                            /*LHSIsTrue=*/PredBI->getSuccessor(0) == BB);
+}
+
 /// computeValueKnownInPredecessors - Given a basic block BB and a value V, see
 /// if we can infer that the value is a known ConstantInt/BlockAddress or undef
 /// in any of our predecessors.  If so, return the known list of value and pred
@@ -768,32 +798,12 @@ bool JumpThreadingPass::computeValueKnownInPredecessorsImpl(
         }
         Value *Res = simplifyCmpInst(Pred, LHS, RHS, {DL});
 
-        // Even without folding, the compare may be known on this edge if
-        // PredBB's branch tests a condition that implies it -- most usefully
-        // the same compare, when both operands are PHIs. PredBB's false arm
-        // reaches BB, so C is false there; BB re-tests C via the PHIs:
-        //
-        //   PredBB: br (C = icmp <pred> A, B), T, BB   ; BB is the false arm
-        //                                          \
-        //                                           v
-        //   BB: L = phi [A, PredBB], ...   ; L -> A on the PredBB edge
-        //       R = phi [B, PredBB], ...   ; R -> B on the PredBB edge
-        //       br (icmp <pred> L, R)      ; == C, false => thread past it
-        //
-        // Require both operands available on the edge (not defined in BB).
-        if (!Res && isa<ICmpInst>(Cmp) && !CmpType->isVectorTy()) {
-          auto DefinedInBB = [&](Value *V) {
-            auto *VI = dyn_cast<Instruction>(V);
-            return VI && VI->getParent() == BB;
-          };
-          auto *PredBI = dyn_cast<CondBrInst>(PredBB->getTerminator());
-          if (PredBI && !DefinedInBB(LHS) && !DefinedInBB(RHS) &&
-              PredBI->getSuccessor(0) != PredBI->getSuccessor(1))
-            if (std::optional<bool> Implied = isImpliedCondition(
-                    PredBI->getCondition(), Pred, LHS, RHS, DL,
-                    /*LHSIsTrue=*/PredBI->getSuccessor(0) == BB))
-              Res = ConstantInt::getBool(Cmp->getContext(), *Implied);
-        }
+        // If it doesn't fold, the compare may still be known on this edge when
+        // PredBB's branch condition implies it (see isImpliedByEdgeBranch).
+        if (!Res && isa<ICmpInst>(Cmp) && !CmpType->isVectorTy())
+          if (std::optional<bool> Implied =
+                  isImpliedByEdgeBranch(PredBB, BB, Pred, LHS, RHS, DL))
+            Res = ConstantInt::getBool(Cmp->getContext(), *Implied);
 
         if (!Res) {
           if (!isa<Constant>(RHS))

>From 5e37f71300356be1a53b3a770c29f8c46c6ca1c9 Mon Sep 17 00:00:00 2001
From: Abhay Kanhere <a_kanhere at apple.com>
Date: Mon, 21 Sep 2026 17:18:02 -0700
Subject: [PATCH 3/5] [Transforms/Utils] Add isImpliedByEdgeCondition to Local

Extract the shared check that returns an icmp's value on the edge
PredBB->SuccBB when the predecessor's conditional branch implies it, so
JumpThreading and InstCombine can reuse it instead of duplicating it.
---
 llvm/include/llvm/Transforms/Utils/Local.h |  9 +++++++++
 llvm/lib/Transforms/Utils/Local.cpp        | 10 ++++++++++
 2 files changed, 19 insertions(+)

diff --git a/llvm/include/llvm/Transforms/Utils/Local.h b/llvm/include/llvm/Transforms/Utils/Local.h
index a7b687304d63c..abae9cb60ac7b 100644
--- a/llvm/include/llvm/Transforms/Utils/Local.h
+++ b/llvm/include/llvm/Transforms/Utils/Local.h
@@ -36,6 +36,7 @@ class AssumptionCache;
 class BasicBlock;
 class CallBase;
 class CallInst;
+class CmpPredicate;
 class CondBrInst;
 class DIBuilder;
 class DomTreeUpdater;
@@ -566,6 +567,14 @@ LLVM_ABI bool canReplaceOperandWithVariable(const Instruction *I,
 /// Invert the given true/false value, possibly reusing an existing copy.
 LLVM_ABI Value *invertCondition(Value *Condition);
 
+/// If PredBB's conditional branch implies `icmp Pred, LHS, RHS` on the
+/// PredBB->SuccBB edge, return that compare's value on the edge, else
+/// std::nullopt.
+LLVM_ABI std::optional<bool>
+isImpliedByEdgeCondition(const BasicBlock *PredBB, const BasicBlock *SuccBB,
+                         CmpPredicate Pred, const Value *LHS, const Value *RHS,
+                         const DataLayout &DL);
+
 //===----------------------------------------------------------------------===//
 //  Assorted
 //
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index b88e506ae681a..43a98176045ab 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -4021,6 +4021,16 @@ Value *llvm::invertCondition(Value *Condition) {
   return Inverted;
 }
 
+std::optional<bool> llvm::isImpliedByEdgeCondition(
+    const BasicBlock *PredBB, const BasicBlock *SuccBB, CmpPredicate Pred,
+    const Value *LHS, const Value *RHS, const DataLayout &DL) {
+  const auto *PredBI = dyn_cast<CondBrInst>(PredBB->getTerminator());
+  if (!PredBI || PredBI->getSuccessor(0) == PredBI->getSuccessor(1))
+    return std::nullopt;
+  return isImpliedCondition(PredBI->getCondition(), Pred, LHS, RHS, DL,
+                            /*LHSIsTrue=*/PredBI->getSuccessor(0) == SuccBB);
+}
+
 bool llvm::inferAttributesFromOthers(Function &F) {
   // Note: We explicitly check for attributes rather than using cover functions
   // because some of the cover functions include the logic being implemented.

>From cea47ab4dd53a4eb8932d936592e8a5e44a2907f Mon Sep 17 00:00:00 2001
From: Abhay Kanhere <a_kanhere at apple.com>
Date: Mon, 21 Sep 2026 17:18:03 -0700
Subject: [PATCH 4/5] [InstCombine] Reuse isImpliedByEdgeCondition helper (NFC)

Replace the inline predecessor-branch implied-condition check in
simplifyInstructionWithPHI with the shared helper; no functional change.
---
 .../InstCombine/InstructionCombining.cpp       | 18 +++++-------------
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index b877f79a000cf..9a23d0834be84 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -1869,19 +1869,11 @@ static Value *simplifyInstructionWithPHI(Instruction &I, PHINode *PN,
   if (NewVal && NewVal != PN && !match(NewVal, m_ConstantExpr()))
     return NewVal;
 
-  // Check if incoming PHI value can be replaced with constant
-  // based on implied condition.
-  CondBrInst *TerminatorBI = dyn_cast<CondBrInst>(InBB->getTerminator());
-  const ICmpInst *ICmp = dyn_cast<ICmpInst>(&I);
-  if (TerminatorBI &&
-      TerminatorBI->getSuccessor(0) != TerminatorBI->getSuccessor(1) && ICmp) {
-    bool LHSIsTrue = TerminatorBI->getSuccessor(0) == PN->getParent();
-    std::optional<bool> ImpliedCond = isImpliedCondition(
-        TerminatorBI->getCondition(), ICmp->getCmpPredicate(), Ops[0], Ops[1],
-        DL, LHSIsTrue);
-    if (ImpliedCond)
-      return ConstantInt::getBool(I.getType(), ImpliedCond.value());
-  }
+  // Fold to a constant when the predecessor edge's branch implies the compare.
+  if (auto *ICmp = dyn_cast<ICmpInst>(&I))
+    if (std::optional<bool> ImpliedCond = isImpliedByEdgeCondition(
+            InBB, PN->getParent(), ICmp->getCmpPredicate(), Ops[0], Ops[1], DL))
+      return ConstantInt::getBool(I.getType(), *ImpliedCond);
 
   return nullptr;
 }

>From e5d2fbdfbb3ddfdb0488950134c16e6a1b5dcbb4 Mon Sep 17 00:00:00 2001
From: Abhay Kanhere <a_kanhere at apple.com>
Date: Mon, 21 Sep 2026 17:18:03 -0700
Subject: [PATCH 5/5] [JumpThreading] Reuse isImpliedByEdgeCondition for
 edge-implied compares

Delegate the predecessor-branch implied-condition check to the shared
Local helper, keeping the JumpThreading-specific guard that rejects
operands defined in BB. Regenerate thread-cmp-of-phis.ll with UTC v6.
---
 llvm/lib/Transforms/Scalar/JumpThreading.cpp  |  7 +-
 .../JumpThreading/thread-cmp-of-phis.ll       | 69 ++++++++++---------
 2 files changed, 38 insertions(+), 38 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 3e20249478306..15c855c9c5a80 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -571,12 +571,9 @@ static std::optional<bool> isImpliedByEdgeBranch(BasicBlock *PredBB,
     auto *I = dyn_cast<Instruction>(V);
     return I && I->getParent() == BB;
   };
-  auto *PredBI = dyn_cast<CondBrInst>(PredBB->getTerminator());
-  if (!PredBI || PredBI->getSuccessor(0) == PredBI->getSuccessor(1) ||
-      DefinedInBB(LHS) || DefinedInBB(RHS))
+  if (DefinedInBB(LHS) || DefinedInBB(RHS))
     return std::nullopt;
-  return isImpliedCondition(PredBI->getCondition(), Pred, LHS, RHS, DL,
-                            /*LHSIsTrue=*/PredBI->getSuccessor(0) == BB);
+  return isImpliedByEdgeCondition(PredBB, BB, Pred, LHS, RHS, DL);
 }
 
 /// computeValueKnownInPredecessors - Given a basic block BB and a value V, see
diff --git a/llvm/test/Transforms/JumpThreading/thread-cmp-of-phis.ll b/llvm/test/Transforms/JumpThreading/thread-cmp-of-phis.ll
index d56ae2ae6a4e9..169a26fc774f4 100644
--- a/llvm/test/Transforms/JumpThreading/thread-cmp-of-phis.ll
+++ b/llvm/test/Transforms/JumpThreading/thread-cmp-of-phis.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt -passes=jump-threading -S < %s | FileCheck %s
 ;
 ; JumpThreading can thread a block whose condition is `icmp <pred> (phiA, phiB)`
@@ -11,18 +11,19 @@ declare i64 @opaque()
 ; Positive: on the %entry edge the PHIs reconstruct to `icmp eq %a, %b` = %c
 ; (false there), so thread %entry -> %if.ne; the opaque %grow edge keeps its branch.
 define i32 @thread_cmp_of_phis(i64 %a, i64 %b) {
-; CHECK-LABEL: @thread_cmp_of_phis(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i64 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    br i1 [[C]], label [[JOIN:%.*]], label [[IF_NE:%.*]]
-; CHECK:       join:
+; CHECK-LABEL: define i32 @thread_cmp_of_phis(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i64 [[A]], [[B]]
+; CHECK-NEXT:    br i1 [[C]], label %[[JOIN:.*]], label %[[IF_NE:.*]]
+; CHECK:       [[JOIN]]:
 ; CHECK-NEXT:    [[A2:%.*]] = call i64 @opaque()
 ; CHECK-NEXT:    [[B2:%.*]] = call i64 @opaque()
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[A2]], [[B2]]
-; CHECK-NEXT:    br i1 [[CMP]], label [[IF_EQ:%.*]], label [[IF_NE]]
-; CHECK:       if.eq:
+; CHECK-NEXT:    br i1 [[CMP]], label %[[IF_EQ:.*]], label %[[IF_NE]]
+; CHECK:       [[IF_EQ]]:
 ; CHECK-NEXT:    ret i32 1
-; CHECK:       if.ne:
+; CHECK:       [[IF_NE]]:
 ; CHECK-NEXT:    ret i32 0
 ;
 entry:
@@ -50,22 +51,23 @@ if.ne:
 ; Negative: %c compares %a/%b, but the join re-tests %a2/%b2 -- different
 ; operands, so %c does not imply it; %entry is not threaded.
 define i32 @no_thread_operands_differ(i64 %a, i64 %b, i64 %a2, i64 %b2) {
-; CHECK-LABEL: @no_thread_operands_differ(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i64 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    br i1 [[C]], label [[MID:%.*]], label [[JOIN:%.*]]
-; CHECK:       mid:
+; CHECK-LABEL: define i32 @no_thread_operands_differ(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]], i64 [[A2:%.*]], i64 [[B2:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i64 [[A]], [[B]]
+; CHECK-NEXT:    br i1 [[C]], label %[[MID:.*]], label %[[JOIN:.*]]
+; CHECK:       [[MID]]:
 ; CHECK-NEXT:    [[PA:%.*]] = call i64 @opaque()
 ; CHECK-NEXT:    [[PB:%.*]] = call i64 @opaque()
-; CHECK-NEXT:    br label [[JOIN]]
-; CHECK:       join:
-; CHECK-NEXT:    [[P1:%.*]] = phi i64 [ [[A2:%.*]], [[ENTRY:%.*]] ], [ [[PA]], [[MID]] ]
-; CHECK-NEXT:    [[P2:%.*]] = phi i64 [ [[B2:%.*]], [[ENTRY]] ], [ [[PB]], [[MID]] ]
+; CHECK-NEXT:    br label %[[JOIN]]
+; CHECK:       [[JOIN]]:
+; CHECK-NEXT:    [[P1:%.*]] = phi i64 [ [[A2]], %[[ENTRY]] ], [ [[PA]], %[[MID]] ]
+; CHECK-NEXT:    [[P2:%.*]] = phi i64 [ [[B2]], %[[ENTRY]] ], [ [[PB]], %[[MID]] ]
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[P1]], [[P2]]
-; CHECK-NEXT:    br i1 [[CMP]], label [[IF_EQ:%.*]], label [[IF_NE:%.*]]
-; CHECK:       if.eq:
+; CHECK-NEXT:    br i1 [[CMP]], label %[[IF_EQ:.*]], label %[[IF_NE:.*]]
+; CHECK:       [[IF_EQ]]:
 ; CHECK-NEXT:    ret i32 1
-; CHECK:       if.ne:
+; CHECK:       [[IF_NE]]:
 ; CHECK-NEXT:    ret i32 0
 ;
 entry:
@@ -93,22 +95,23 @@ if.ne:
 ; Negative: same operands, but %c is unsigned (ult) while the join re-tests
 ; signed (slt) -- ult does not imply slt; %entry is not threaded.
 define i32 @no_thread_predicate_differs(i64 %a, i64 %b) {
-; CHECK-LABEL: @no_thread_predicate_differs(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[C:%.*]] = icmp ult i64 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    br i1 [[C]], label [[GROW:%.*]], label [[JOIN:%.*]]
-; CHECK:       grow:
+; CHECK-LABEL: define i32 @no_thread_predicate_differs(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i64 [[A]], [[B]]
+; CHECK-NEXT:    br i1 [[C]], label %[[GROW:.*]], label %[[JOIN:.*]]
+; CHECK:       [[GROW]]:
 ; CHECK-NEXT:    [[A2:%.*]] = call i64 @opaque()
 ; CHECK-NEXT:    [[B2:%.*]] = call i64 @opaque()
-; CHECK-NEXT:    br label [[JOIN]]
-; CHECK:       join:
-; CHECK-NEXT:    [[P1:%.*]] = phi i64 [ [[A]], [[ENTRY:%.*]] ], [ [[A2]], [[GROW]] ]
-; CHECK-NEXT:    [[P2:%.*]] = phi i64 [ [[B]], [[ENTRY]] ], [ [[B2]], [[GROW]] ]
+; CHECK-NEXT:    br label %[[JOIN]]
+; CHECK:       [[JOIN]]:
+; CHECK-NEXT:    [[P1:%.*]] = phi i64 [ [[A]], %[[ENTRY]] ], [ [[A2]], %[[GROW]] ]
+; CHECK-NEXT:    [[P2:%.*]] = phi i64 [ [[B]], %[[ENTRY]] ], [ [[B2]], %[[GROW]] ]
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[P1]], [[P2]]
-; CHECK-NEXT:    br i1 [[CMP]], label [[IF_EQ:%.*]], label [[IF_NE:%.*]]
-; CHECK:       if.eq:
+; CHECK-NEXT:    br i1 [[CMP]], label %[[IF_EQ:.*]], label %[[IF_NE:.*]]
+; CHECK:       [[IF_EQ]]:
 ; CHECK-NEXT:    ret i32 1
-; CHECK:       if.ne:
+; CHECK:       [[IF_NE]]:
 ; CHECK-NEXT:    ret i32 0
 ;
 entry:



More information about the llvm-commits mailing list