[llvm] [IR] Avoid self-referencing values caused by PHI node removal (PR #129501)

Robert Imschweiler via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 7 08:18:11 PST 2025


https://github.com/ro-i updated https://github.com/llvm/llvm-project/pull/129501

>From b1b2f0acbcee984e8e085df77f6b117b05b6406b Mon Sep 17 00:00:00 2001
From: Robert Imschweiler <robert.imschweiler at amd.com>
Date: Sun, 2 Mar 2025 17:30:53 -0600
Subject: [PATCH 1/5] [IR] Avoid self-referencing values caused by PHI node
 removal

In case of an unreachable loop, for example, the JumpThreading pass
might attempt to remove the PHI node in the loop entry and replace it
with its constant value. However, this fails in case the value is an
instruction using the PHI node.

This LLVM defect was identified via the AMD Fuzzing project.
---
 llvm/lib/IR/BasicBlock.cpp                    | 10 +++-
 .../JumpThreading/unreachable-loops.ll        | 60 +++++++++++++++++++
 2 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp
index dca42a57fa9e3..9c644e0330258 100644
--- a/llvm/lib/IR/BasicBlock.cpp
+++ b/llvm/lib/IR/BasicBlock.cpp
@@ -556,8 +556,14 @@ void BasicBlock::removePredecessor(BasicBlock *Pred,
     if (NumPreds == 1)
       continue;
 
-    // Try to replace the PHI node with a constant value.
-    if (Value *PhiConstant = Phi.hasConstantValue()) {
+    // Try to replace the PHI node with a constant value, but make sure that
+    // this value isn't using the PHI node. (Except it's a PHI node itself. PHI
+    // nodes are allowed to reference themselves.)
+    if (Value *PhiConstant = Phi.hasConstantValue();
+        PhiConstant &&
+        (!isa<Instruction>(PhiConstant) || isa<PHINode>(PhiConstant) ||
+         llvm::all_of(Phi.users(),
+                      [PhiConstant](User *U) { return U != PhiConstant; }))) {
       Phi.replaceAllUsesWith(PhiConstant);
       Phi.eraseFromParent();
     }
diff --git a/llvm/test/Transforms/JumpThreading/unreachable-loops.ll b/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
index d8bd3f389aae8..1a1a4ca15f649 100644
--- a/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
+++ b/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
@@ -180,4 +180,64 @@ cleanup2343.loopexit4:                            ; preds = %cleanup1491
   unreachable
 }
 
+; This segfaults due to recursion in %C4. Reason: %L6 is identified to be a
+; "partially redundant load" and is replaced by a PHI node. The PHI node is then
+; simplified to be constant and is removed. This leads to %L6 being replaced by
+; %C4, which makes %C4 invalid since it uses %L6.
+; The test case has been generated by the AMD Fuzzing project and simplified
+; manually and by llvm-reduce.
+
+define i32 @constant_phi_leads_to_self_reference() {
+; CHECK-LABEL: @constant_phi_leads_to_self_reference(
+; CHECK-NEXT:    [[A9:%.*]] = alloca i1, align 1
+; CHECK-NEXT:    br label [[F6:%.*]]
+; CHECK:       T3:
+; CHECK-NEXT:    [[L6:%.*]] = phi i1 [ [[C4:%.*]], [[BB6:%.*]] ]
+; CHECK-NEXT:    br label [[BB5:%.*]]
+; CHECK:       BB5:
+; CHECK-NEXT:    [[L10:%.*]] = load i1, ptr [[A9]], align 1
+; CHECK-NEXT:    br i1 [[L10]], label [[BB6]], label [[F6]]
+; CHECK:       BB6:
+; CHECK-NEXT:    [[LGV3:%.*]] = load i1, ptr null, align 1
+; CHECK-NEXT:    [[C4]] = icmp sle i1 [[L6]], true
+; CHECK-NEXT:    store i1 [[C4]], ptr null, align 1
+; CHECK-NEXT:    br i1 [[L6]], label [[F6]], label [[T3:%.*]]
+; CHECK:       F6:
+; CHECK-NEXT:    ret i32 0
+; CHECK:       F7:
+; CHECK-NEXT:    br label [[BB5]]
+;
+  %A9 = alloca i1, align 1
+  br i1 false, label %BB4, label %F6
+
+BB4:                                              ; preds = %0
+  br i1 false, label %F6, label %F1
+
+F1:                                               ; preds = %BB4
+  br i1 false, label %T4, label %T3
+
+T3:                                               ; preds = %T4, %BB6, %F1
+  %L6 = load i1, ptr null, align 1
+  br label %BB5
+
+BB5:                                              ; preds = %F7, %T3
+  %L10 = load i1, ptr %A9, align 1
+  br i1 %L10, label %BB6, label %F6
+
+BB6:                                              ; preds = %BB5
+  %LGV3 = load i1, ptr null, align 1
+  %C4 = icmp sle i1 %L6, true
+  store i1 %C4, ptr null, align 1
+  br i1 %L6, label %F6, label %T3
+
+T4:                                               ; preds = %F1
+  br label %T3
+
+F6:                                               ; preds = %BB6, %BB5, %BB4, %0
+  ret i32 0
+
+F7:                                               ; No predecessors!
+  br label %BB5
+}
+
 !0 = !{!"branch_weights", i32 2146410443, i32 1073205}

>From c97a6c65c3935653d8431daf31976c31266ab38f Mon Sep 17 00:00:00 2001
From: Robert Imschweiler <robert.imschweiler at amd.com>
Date: Mon, 3 Mar 2025 08:48:26 -0600
Subject: [PATCH 2/5] implement feedback

---
 .../JumpThreading/unreachable-loops.ll           | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/llvm/test/Transforms/JumpThreading/unreachable-loops.ll b/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
index 1a1a4ca15f649..785166f26e45c 100644
--- a/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
+++ b/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
@@ -187,20 +187,20 @@ cleanup2343.loopexit4:                            ; preds = %cleanup1491
 ; The test case has been generated by the AMD Fuzzing project and simplified
 ; manually and by llvm-reduce.
 
-define i32 @constant_phi_leads_to_self_reference() {
+define i32 @constant_phi_leads_to_self_reference(ptr %ptr) {
 ; CHECK-LABEL: @constant_phi_leads_to_self_reference(
-; CHECK-NEXT:    [[A9:%.*]] = alloca i1, align 1
+; CHECK-NEXT:    [[A10:%.*]] = alloca i1, align 1
 ; CHECK-NEXT:    br label [[F6:%.*]]
 ; CHECK:       T3:
 ; CHECK-NEXT:    [[L6:%.*]] = phi i1 [ [[C4:%.*]], [[BB6:%.*]] ]
 ; CHECK-NEXT:    br label [[BB5:%.*]]
 ; CHECK:       BB5:
-; CHECK-NEXT:    [[L10:%.*]] = load i1, ptr [[A9]], align 1
+; CHECK-NEXT:    [[L10:%.*]] = load i1, ptr [[A10]], align 1
 ; CHECK-NEXT:    br i1 [[L10]], label [[BB6]], label [[F6]]
 ; CHECK:       BB6:
-; CHECK-NEXT:    [[LGV3:%.*]] = load i1, ptr null, align 1
+; CHECK-NEXT:    [[LGV3:%.*]] = load i1, ptr [[A7:%.*]], align 1
 ; CHECK-NEXT:    [[C4]] = icmp sle i1 [[L6]], true
-; CHECK-NEXT:    store i1 [[C4]], ptr null, align 1
+; CHECK-NEXT:    store i1 [[C4]], ptr [[A7]], align 1
 ; CHECK-NEXT:    br i1 [[L6]], label [[F6]], label [[T3:%.*]]
 ; CHECK:       F6:
 ; CHECK-NEXT:    ret i32 0
@@ -217,7 +217,7 @@ F1:                                               ; preds = %BB4
   br i1 false, label %T4, label %T3
 
 T3:                                               ; preds = %T4, %BB6, %F1
-  %L6 = load i1, ptr null, align 1
+  %L6 = load i1, ptr %ptr, align 1
   br label %BB5
 
 BB5:                                              ; preds = %F7, %T3
@@ -225,9 +225,9 @@ BB5:                                              ; preds = %F7, %T3
   br i1 %L10, label %BB6, label %F6
 
 BB6:                                              ; preds = %BB5
-  %LGV3 = load i1, ptr null, align 1
+  %LGV3 = load i1, ptr %ptr, align 1
   %C4 = icmp sle i1 %L6, true
-  store i1 %C4, ptr null, align 1
+  store i1 %C4, ptr %ptr, align 1
   br i1 %L6, label %F6, label %T3
 
 T4:                                               ; preds = %F1

>From d9e764ffdf4c18dcae3e7589d0cc56a8350428b7 Mon Sep 17 00:00:00 2001
From: Robert Imschweiler <robert.imschweiler at amd.com>
Date: Wed, 5 Mar 2025 08:52:51 -0600
Subject: [PATCH 3/5] implement another approach

---
 .../llvm/Transforms/Scalar/JumpThreading.h    |  6 +++
 llvm/lib/IR/BasicBlock.cpp                    | 10 +---
 llvm/lib/Transforms/Scalar/JumpThreading.cpp  | 38 +++++++++++---
 .../JumpThreading/PR33357-lvi-recursion.ll    | 15 +++---
 .../test/Transforms/JumpThreading/ne-undef.ll | 15 +-----
 .../JumpThreading/phi-xor-branch.ll           |  9 +---
 llvm/test/Transforms/JumpThreading/pr62908.ll | 13 +----
 llvm/test/Transforms/JumpThreading/pr9331.ll  |  2 -
 .../JumpThreading/preserving-debugloc-br.ll   | 49 +++++++++++++++----
 .../Transforms/JumpThreading/removed-use.ll   | 18 ++++---
 .../JumpThreading/unreachable-loops.ll        | 36 +-------------
 11 files changed, 102 insertions(+), 109 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Scalar/JumpThreading.h b/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
index 84292c716a0a9..168c36fe397f1 100644
--- a/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
+++ b/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
@@ -169,6 +169,12 @@ class JumpThreadingPass : public PassInfoMixin<JumpThreadingPass> {
   bool processGuards(BasicBlock *BB);
   bool threadGuard(BasicBlock *BB, IntrinsicInst *Guard, BranchInst *BI);
 
+  // Determine unreachability with a possibly not up-to-date DominatorTree.
+  // If BB is unreachable, return a list of BB and all its predecessors.
+  // Otherwise, return an empty list.
+  SmallVector<BasicBlock *, 32> unreachableFromBB(BasicBlock *BB,
+                                                  DomTreeUpdater *DTU);
+
 private:
   BasicBlock *splitBlockPreds(BasicBlock *BB, ArrayRef<BasicBlock *> Preds,
                               const char *Suffix);
diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp
index 9c644e0330258..dca42a57fa9e3 100644
--- a/llvm/lib/IR/BasicBlock.cpp
+++ b/llvm/lib/IR/BasicBlock.cpp
@@ -556,14 +556,8 @@ void BasicBlock::removePredecessor(BasicBlock *Pred,
     if (NumPreds == 1)
       continue;
 
-    // Try to replace the PHI node with a constant value, but make sure that
-    // this value isn't using the PHI node. (Except it's a PHI node itself. PHI
-    // nodes are allowed to reference themselves.)
-    if (Value *PhiConstant = Phi.hasConstantValue();
-        PhiConstant &&
-        (!isa<Instruction>(PhiConstant) || isa<PHINode>(PhiConstant) ||
-         llvm::all_of(Phi.users(),
-                      [PhiConstant](User *U) { return U != PhiConstant; }))) {
+    // Try to replace the PHI node with a constant value.
+    if (Value *PhiConstant = Phi.hasConstantValue()) {
       Phi.replaceAllUsesWith(PhiConstant);
       Phi.eraseFromParent();
     }
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 9cae65bbdcfbc..8efe957909b33 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -335,15 +335,19 @@ bool JumpThreadingPass::runImpl(Function &F_, FunctionAnalysisManager *FAM_,
       if (&BB == &F->getEntryBlock() || DTU->isBBPendingDeletion(&BB))
         continue;
 
-      if (pred_empty(&BB)) {
+      if (SmallVector<BasicBlock *, 32> Unreachable =
+              unreachableFromBB(&BB, DTU.get());
+          !Unreachable.empty()) {
         // When processBlock makes BB unreachable it doesn't bother to fix up
         // the instructions in it. We must remove BB to prevent invalid IR.
-        LLVM_DEBUG(dbgs() << "  JT: Deleting dead block '" << BB.getName()
-                          << "' with terminator: " << *BB.getTerminator()
-                          << '\n');
-        LoopHeaders.erase(&BB);
-        LVI->eraseBlock(&BB);
-        DeleteDeadBlock(&BB, DTU.get());
+        for (BasicBlock *UBB : Unreachable) {
+          LLVM_DEBUG(dbgs()
+                     << "  JT: Deleting dead block '" << UBB->getName()
+                     << "' with terminator: " << *UBB->getTerminator() << '\n');
+          LoopHeaders.erase(UBB);
+          LVI->eraseBlock(UBB);
+        }
+        DeleteDeadBlocks(Unreachable, DTU.get());
         Changed = ChangedSinceLastAnalysisUpdate = true;
         continue;
       }
@@ -381,6 +385,26 @@ bool JumpThreadingPass::runImpl(Function &F_, FunctionAnalysisManager *FAM_,
   return EverChanged;
 }
 
+SmallVector<BasicBlock *, 32>
+JumpThreadingPass::unreachableFromBB(BasicBlock *BB, DomTreeUpdater *DTU) {
+  if (BB->isEntryBlock() || DTU->isBBPendingDeletion(BB))
+    return {};
+
+  SmallVector<BasicBlock *, 32> Unreachable({BB});
+  SmallPtrSet<BasicBlock *, 32> Seen({BB});
+
+  for (unsigned U = 0; U < Unreachable.size(); ++U) {
+    for (BasicBlock *Pred : predecessors(Unreachable[U])) {
+      if (Pred->isEntryBlock())
+        return {};
+      if (Seen.insert(Pred).second && !DTU->isBBPendingDeletion(Pred))
+        Unreachable.push_back(Pred);
+    }
+  }
+
+  return Unreachable;
+}
+
 // Replace uses of Cond with ToVal when safe to do so. If all uses are
 // replaced, we can remove Cond. We cannot blindly replace all uses of Cond
 // because we may incorrectly replace uses when guards/assumes are uses of
diff --git a/llvm/test/Transforms/JumpThreading/PR33357-lvi-recursion.ll b/llvm/test/Transforms/JumpThreading/PR33357-lvi-recursion.ll
index a36f81bda55ab..0c58b09ffdc86 100644
--- a/llvm/test/Transforms/JumpThreading/PR33357-lvi-recursion.ll
+++ b/llvm/test/Transforms/JumpThreading/PR33357-lvi-recursion.ll
@@ -1,15 +1,14 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt -S -passes=jump-threading,verify -o - %s | FileCheck %s
 @a = external global i16, align 1
 
-; CHECK-LABEL: f
-; CHECK: bb6:
-; CHECK: bb2:
-; CHECK: bb3:
-; CHECK-NOT: bb0:
-; CHECK-NOT: bb1:
-; CHECK-NOT: bb4:
-; CHECK-NOT: bb5:
 define void @f(i32 %p1) {
+; CHECK-LABEL: define void @f(
+; CHECK-SAME: i32 [[P1:%.*]]) {
+; CHECK-NEXT:  [[BB6:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[P1]], 0
+; CHECK-NEXT:    ret void
+;
 bb0:
   %0 = icmp eq i32 %p1, 0
   br i1 true, label %bb6, label %bb1
diff --git a/llvm/test/Transforms/JumpThreading/ne-undef.ll b/llvm/test/Transforms/JumpThreading/ne-undef.ll
index 437ff3824ef43..5189f8aacc359 100644
--- a/llvm/test/Transforms/JumpThreading/ne-undef.ll
+++ b/llvm/test/Transforms/JumpThreading/ne-undef.ll
@@ -5,20 +5,7 @@ declare i1 @cond()
 
 define hidden void @hoge(i1 %c1, i32 %x)  {
 ; CHECK-LABEL: @hoge(
-; CHECK-NEXT:  bb:
-; CHECK-NEXT:    br label [[BB13:%.*]]
-; CHECK:       bb4:
-; CHECK-NEXT:    [[TMP3:%.*]] = icmp ne i32 [[TMP7:%.*]], undef
-; CHECK-NEXT:    br i1 [[TMP3]], label [[BB5:%.*]], label [[BB13]]
-; CHECK:       bb5:
-; CHECK-NEXT:    br label [[BB6:%.*]]
-; CHECK:       bb6:
-; CHECK-NEXT:    [[TMP7]] = phi i32 [ [[TMP7]], [[BB5]] ], [ [[X:%.*]], [[BB8:%.*]] ]
-; CHECK-NEXT:    [[C:%.*]] = call i1 @cond()
-; CHECK-NEXT:    br i1 [[C]], label [[BB4:%.*]], label [[BB8]]
-; CHECK:       bb8:
-; CHECK-NEXT:    br label [[BB6]]
-; CHECK:       bb13:
+; CHECK-NEXT:  bb13:
 ; CHECK-NEXT:    ret void
 ;
 bb:
diff --git a/llvm/test/Transforms/JumpThreading/phi-xor-branch.ll b/llvm/test/Transforms/JumpThreading/phi-xor-branch.ll
index bd667906dba31..bf0dc6997eef2 100644
--- a/llvm/test/Transforms/JumpThreading/phi-xor-branch.ll
+++ b/llvm/test/Transforms/JumpThreading/phi-xor-branch.ll
@@ -5,14 +5,7 @@
 
 define void @test() {
 ; CHECK-LABEL: @test(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[EXIT:%.*]]
-; CHECK:       loop:
-; CHECK-NEXT:    [[DUMMY:%.*]] = phi i16 [ 0, [[LOOP:%.*]] ]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 0, 1
-; CHECK-NEXT:    [[XOR:%.*]] = xor i1 false, [[XOR]]
-; CHECK-NEXT:    br i1 [[XOR]], label [[LOOP]], label [[EXIT]]
-; CHECK:       exit:
+; CHECK-NEXT:  exit:
 ; CHECK-NEXT:    ret void
 ;
 entry:
diff --git a/llvm/test/Transforms/JumpThreading/pr62908.ll b/llvm/test/Transforms/JumpThreading/pr62908.ll
index cfb647c509f8e..4c389ee040b90 100644
--- a/llvm/test/Transforms/JumpThreading/pr62908.ll
+++ b/llvm/test/Transforms/JumpThreading/pr62908.ll
@@ -5,18 +5,7 @@
 
 define i32 @test() {
 ; CHECK-LABEL: define i32 @test() {
-; CHECK-NEXT:  join.thread:
-; CHECK-NEXT:    br label [[END:%.*]]
-; CHECK:       unreachable:
-; CHECK-NEXT:    [[SH_PROM:%.*]] = zext i32 -1 to i64
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i64 -1, [[SH_PROM]]
-; CHECK-NEXT:    [[CONV:%.*]] = trunc i64 [[SHL]] to i32
-; CHECK-NEXT:    br label [[JOIN:%.*]]
-; CHECK:       join:
-; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[CONV]], [[UNREACHABLE:%.*]] ]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[PHI]], 0
-; CHECK-NEXT:    br i1 [[CMP]], label [[END]], label [[END]]
-; CHECK:       end:
+; CHECK-NEXT:  end:
 ; CHECK-NEXT:    ret i32 0
 ;
 entry:
diff --git a/llvm/test/Transforms/JumpThreading/pr9331.ll b/llvm/test/Transforms/JumpThreading/pr9331.ll
index 06c0a42bd849a..fdd9283efd56c 100644
--- a/llvm/test/Transforms/JumpThreading/pr9331.ll
+++ b/llvm/test/Transforms/JumpThreading/pr9331.ll
@@ -5,8 +5,6 @@ define void @func(i8 zeroext %p_44) nounwind {
 ; CHECK-LABEL: @func(
 ; CHECK-NEXT:  return:
 ; CHECK-NEXT:    ret void
-; CHECK:       for.inc46:
-; CHECK-NEXT:    br label [[FOR_INC46:%.*]]
 ;
 entry:
   br i1 false, label %for.cond2, label %if.end50
diff --git a/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll b/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll
index 521c697c71208..be1ba343b5e4f 100644
--- a/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll
+++ b/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll
@@ -1,6 +1,7 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt -S -passes=jump-threading < %s | FileCheck %s
 
-; @process_block_branch checks that JumpThreading's processBlock() propagates 
+; @process_block_branch checks that JumpThreading's processBlock() propagates
 ; the debug location to the new branch instruction.
 
 ; @process_threadable_edges_branch checks that JumpThreading's processThreadableEdges()
@@ -8,8 +9,14 @@
 
 define i32 @process_block_branch(i32 %action) #0 !dbg !5 {
 ; CHECK-LABEL: define i32 @process_block_branch(
-; CHECK:       for.cond:
-; CHECK-NEXT:    br label %for.cond, !dbg [[DBG10:![0-9]+]]
+; CHECK-SAME: i32 [[ACTION:%.*]]) #[[ATTR0:[0-9]+]] !dbg [[DBG5:![0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    switch i32 [[ACTION]], label %[[IF_THEN:.*]] [
+; CHECK-NEXT:      i32 1, label %[[IF_THEN]]
+; CHECK-NEXT:      i32 0, label %[[IF_THEN]]
+; CHECK-NEXT:    ], !dbg [[DBG8:![0-9]+]]
+; CHECK:       [[IF_THEN]]:
+; CHECK-NEXT:    ret i32 undef, !dbg [[DBG9:![0-9]+]]
 ;
 entry:
   switch i32 %action, label %lor.rhs [
@@ -35,8 +42,18 @@ for.body:                                         ; preds = %for.cond
 
 define void @process_threadable_edges_branch(i32 %value) #0 !dbg !15 {
 ; CHECK-LABEL: define void @process_threadable_edges_branch(
-; CHECK:    L0:
-; CHECK:      br label %L2, !dbg [[DBG17:![0-9]+]]
+; CHECK-SAME: i32 [[VALUE:%.*]]) #[[ATTR0]] !dbg [[DBG10:![0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[VALUE]], 32, !dbg [[DBG11:![0-9]+]]
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[VALUE]], 64, !dbg [[DBG12:![0-9]+]]
+; CHECK-NEXT:    br i1 [[CMP]], label %[[L0:.*]], label %[[L2:.*]], !dbg [[DBG13:![0-9]+]]
+; CHECK:       [[L0]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @f2(), !dbg [[DBG14:![0-9]+]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @f2(), !dbg [[DBG15:![0-9]+]]
+; CHECK-NEXT:    br label %[[L2]], !dbg [[DBG16:![0-9]+]]
+; CHECK:       [[L2]]:
+; CHECK-NEXT:    call void @f4(i32 [[ADD]]), !dbg [[DBG17:![0-9]+]]
+; CHECK-NEXT:    ret void, !dbg [[DBG18:![0-9]+]]
 ;
 entry:
   %cmp = icmp eq i32 %value, 32, !dbg !16
@@ -78,10 +95,6 @@ attributes #0 = { nounwind }
 !llvm.debugify = !{!2, !3}
 !llvm.module.flags = !{!4}
 
-;.
-; CHECK: [[DBG10]] = !DILocation(line: 6,
-; CHECK: [[DBG17]] = !DILocation(line: 13,
-;.
 
 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
 !1 = !DIFile(filename: "temp.ll", directory: "/")
@@ -111,3 +124,21 @@ attributes #0 = { nounwind }
 !25 = !DILocation(line: 17, column: 1, scope: !15)
 !26 = !DILocation(line: 18, column: 1, scope: !15)
 !27 = !DILocation(line: 19, column: 1, scope: !15)
+;.
+; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C, file: [[META1:![0-9]+]], producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+; CHECK: [[META1]] = !DIFile(filename: "temp.ll", directory: {{.*}})
+; CHECK: [[DBG5]] = distinct !DISubprogram(name: "process_block_branch", linkageName: "process_block_branch", scope: null, file: [[META1]], line: 1, type: [[META6:![0-9]+]], scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]])
+; CHECK: [[META6]] = !DISubroutineType(types: [[META7:![0-9]+]])
+; CHECK: [[META7]] = !{}
+; CHECK: [[DBG8]] = !DILocation(line: 1, column: 1, scope: [[DBG5]])
+; CHECK: [[DBG9]] = !DILocation(line: 2, column: 1, scope: [[DBG5]])
+; CHECK: [[DBG10]] = distinct !DISubprogram(name: "process_threadable_edges_branch", linkageName: "process_threadable_edges_branch", scope: null, file: [[META1]], line: 8, type: [[META6]], scopeLine: 8, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]])
+; CHECK: [[DBG11]] = !DILocation(line: 8, column: 1, scope: [[DBG10]])
+; CHECK: [[DBG12]] = !DILocation(line: 9, column: 1, scope: [[DBG10]])
+; CHECK: [[DBG13]] = !DILocation(line: 10, column: 1, scope: [[DBG10]])
+; CHECK: [[DBG14]] = !DILocation(line: 11, column: 1, scope: [[DBG10]])
+; CHECK: [[DBG15]] = !DILocation(line: 12, column: 1, scope: [[DBG10]])
+; CHECK: [[DBG16]] = !DILocation(line: 13, column: 1, scope: [[DBG10]])
+; CHECK: [[DBG17]] = !DILocation(line: 16, column: 1, scope: [[DBG10]])
+; CHECK: [[DBG18]] = !DILocation(line: 17, column: 1, scope: [[DBG10]])
+;.
diff --git a/llvm/test/Transforms/JumpThreading/removed-use.ll b/llvm/test/Transforms/JumpThreading/removed-use.ll
index 40b82d21ad081..4cd1b75f78c00 100644
--- a/llvm/test/Transforms/JumpThreading/removed-use.ll
+++ b/llvm/test/Transforms/JumpThreading/removed-use.ll
@@ -1,10 +1,10 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt -S < %s -passes=jump-threading | FileCheck %s
-; CHECK-LABEL: @foo
-; CHECK: bb6:
-; CHECK-NEXT: ret void
-; CHECK: bb3:
-; CHECK: br label %bb3
 define void @foo() {
+; CHECK-LABEL: define void @foo() {
+; CHECK-NEXT:  [[BB6:.*:]]
+; CHECK-NEXT:    ret void
+;
 entry:
   br i1 true, label %bb6, label %bb3
 
@@ -27,9 +27,13 @@ bb6:
   ret void
 }
 
-; CHECK-LABEL: @bar
 ; Just check that we don't crash on this test.
 define void @bar(i1 %p) {
+; CHECK-LABEL: define void @bar(
+; CHECK-SAME: i1 [[P:%.*]]) {
+; CHECK-NEXT:  [[EXIT:.*:]]
+; CHECK-NEXT:    ret void
+;
 entry:
   br i1 false, label %bb2, label %exit
 
@@ -46,7 +50,7 @@ bb4:
 bb5:
   %x1 = phi i32 [ %x0, %bb3 ], [ 0, %bb4 ]
   switch i32 %x1, label %exit [
-    i32 10, label %bb2
+  i32 10, label %bb2
   ]
 
 exit:
diff --git a/llvm/test/Transforms/JumpThreading/unreachable-loops.ll b/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
index 785166f26e45c..edddc13d61d0d 100644
--- a/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
+++ b/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
@@ -12,12 +12,6 @@ define void @unreachable_single_bb_loop() {
 ; CHECK-NEXT:    [[TMP:%.*]] = call i32 @a()
 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[TMP]], 1
 ; CHECK-NEXT:    br i1 [[TMP1]], label [[BB8:%.*]], label [[BB8]]
-; CHECK:       bb2:
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP]], 1
-; CHECK-NEXT:    switch i1 [[TMP4]], label [[BB2:%.*]] [
-; CHECK-NEXT:      i1 false, label [[BB8]]
-; CHECK-NEXT:      i1 true, label [[BB8]]
-; CHECK-NEXT:    ]
 ; CHECK:       bb8:
 ; CHECK-NEXT:    ret void
 ;
@@ -52,14 +46,6 @@ define void @unreachable_multi_bbs_loop() {
 ; CHECK-NEXT:    [[TMP:%.*]] = call i32 @a()
 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[TMP]], 1
 ; CHECK-NEXT:    br i1 [[TMP1]], label [[BB8:%.*]], label [[BB8]]
-; CHECK:       bb3:
-; CHECK-NEXT:    br label [[BB2:%.*]]
-; CHECK:       bb2:
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP]], 1
-; CHECK-NEXT:    switch i1 [[TMP4]], label [[BB3:%.*]] [
-; CHECK-NEXT:      i1 false, label [[BB8]]
-; CHECK-NEXT:      i1 true, label [[BB8]]
-; CHECK-NEXT:    ]
 ; CHECK:       bb8:
 ; CHECK-NEXT:    ret void
 ;
@@ -99,10 +85,6 @@ define void @PR48362(i1 %arg) {
 ; CHECK-LABEL: @PR48362(
 ; CHECK-NEXT:  cleanup.cont1500:
 ; CHECK-NEXT:    unreachable
-; CHECK:       if.end1733:
-; CHECK-NEXT:    [[I82:%.*]] = load i32, ptr undef, align 1
-; CHECK-NEXT:    [[TOBOOL1731_NOT:%.*]] = icmp eq i32 [[I82]], 0
-; CHECK-NEXT:    br label [[IF_END1733:%.*]]
 ;
 cleanup1491:                                      ; preds = %for.body1140
   switch i32 0, label %cleanup2343.loopexit4 [
@@ -189,23 +171,9 @@ cleanup2343.loopexit4:                            ; preds = %cleanup1491
 
 define i32 @constant_phi_leads_to_self_reference(ptr %ptr) {
 ; CHECK-LABEL: @constant_phi_leads_to_self_reference(
-; CHECK-NEXT:    [[A10:%.*]] = alloca i1, align 1
-; CHECK-NEXT:    br label [[F6:%.*]]
-; CHECK:       T3:
-; CHECK-NEXT:    [[L6:%.*]] = phi i1 [ [[C4:%.*]], [[BB6:%.*]] ]
-; CHECK-NEXT:    br label [[BB5:%.*]]
-; CHECK:       BB5:
-; CHECK-NEXT:    [[L10:%.*]] = load i1, ptr [[A10]], align 1
-; CHECK-NEXT:    br i1 [[L10]], label [[BB6]], label [[F6]]
-; CHECK:       BB6:
-; CHECK-NEXT:    [[LGV3:%.*]] = load i1, ptr [[A7:%.*]], align 1
-; CHECK-NEXT:    [[C4]] = icmp sle i1 [[L6]], true
-; CHECK-NEXT:    store i1 [[C4]], ptr [[A7]], align 1
-; CHECK-NEXT:    br i1 [[L6]], label [[F6]], label [[T3:%.*]]
-; CHECK:       F6:
+; CHECK-NEXT:  F6:
+; CHECK-NEXT:    [[A9:%.*]] = alloca i1, align 1
 ; CHECK-NEXT:    ret i32 0
-; CHECK:       F7:
-; CHECK-NEXT:    br label [[BB5]]
 ;
   %A9 = alloca i1, align 1
   br i1 false, label %BB4, label %F6

>From e0ccb61acbb90ca486be6d0b89aa18602febcc82 Mon Sep 17 00:00:00 2001
From: Robert Imschweiler <robert.imschweiler at amd.com>
Date: Wed, 5 Mar 2025 09:16:34 -0600
Subject: [PATCH 4/5] replace undef

---
 llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll b/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll
index be1ba343b5e4f..3eb9a04bb4016 100644
--- a/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll
+++ b/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll
@@ -16,7 +16,7 @@ define i32 @process_block_branch(i32 %action) #0 !dbg !5 {
 ; CHECK-NEXT:      i32 0, label %[[IF_THEN]]
 ; CHECK-NEXT:    ], !dbg [[DBG8:![0-9]+]]
 ; CHECK:       [[IF_THEN]]:
-; CHECK-NEXT:    ret i32 undef, !dbg [[DBG9:![0-9]+]]
+; CHECK-NEXT:    ret i32 0, !dbg [[DBG9:![0-9]+]]
 ;
 entry:
   switch i32 %action, label %lor.rhs [
@@ -25,7 +25,7 @@ entry:
   ], !dbg !8
 
 if.then:                                          ; preds = %for.cond, %lor.end, %entry
-  ret i32 undef, !dbg !9
+  ret i32 0, !dbg !9
 
 lor.rhs:                                          ; preds = %entry
   br label %lor.end, !dbg !10

>From 35aa07dbad7731d0ce52d3b6045db9f29d106053 Mon Sep 17 00:00:00 2001
From: Robert Imschweiler <robert.imschweiler at amd.com>
Date: Fri, 7 Mar 2025 10:17:49 -0600
Subject: [PATCH 5/5] implement another approach; reset existing tests

---
 .../llvm/Transforms/Scalar/JumpThreading.h    |  6 +-
 llvm/lib/Transforms/Scalar/JumpThreading.cpp  | 73 +++++++++++--------
 .../JumpThreading/PR33357-lvi-recursion.ll    | 15 ++--
 .../test/Transforms/JumpThreading/ne-undef.ll | 15 +++-
 .../JumpThreading/phi-xor-branch.ll           |  9 ++-
 llvm/test/Transforms/JumpThreading/pr62908.ll | 13 +++-
 llvm/test/Transforms/JumpThreading/pr9331.ll  |  2 +
 .../JumpThreading/preserving-debugloc-br.ll   | 51 +++----------
 .../Transforms/JumpThreading/removed-use.ll   | 18 ++---
 .../JumpThreading/unreachable-loops.ll        | 41 ++++++++++-
 10 files changed, 142 insertions(+), 101 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Scalar/JumpThreading.h b/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
index 168c36fe397f1..f93fe78cc3600 100644
--- a/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
+++ b/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
@@ -169,11 +169,7 @@ class JumpThreadingPass : public PassInfoMixin<JumpThreadingPass> {
   bool processGuards(BasicBlock *BB);
   bool threadGuard(BasicBlock *BB, IntrinsicInst *Guard, BranchInst *BI);
 
-  // Determine unreachability with a possibly not up-to-date DominatorTree.
-  // If BB is unreachable, return a list of BB and all its predecessors.
-  // Otherwise, return an empty list.
-  SmallVector<BasicBlock *, 32> unreachableFromBB(BasicBlock *BB,
-                                                  DomTreeUpdater *DTU);
+  bool preserveLoopPreHeader(BasicBlock *BB);
 
 private:
   BasicBlock *splitBlockPreds(BasicBlock *BB, ArrayRef<BasicBlock *> Preds,
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 8efe957909b33..b9f5e86cfa6c4 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -335,19 +335,15 @@ bool JumpThreadingPass::runImpl(Function &F_, FunctionAnalysisManager *FAM_,
       if (&BB == &F->getEntryBlock() || DTU->isBBPendingDeletion(&BB))
         continue;
 
-      if (SmallVector<BasicBlock *, 32> Unreachable =
-              unreachableFromBB(&BB, DTU.get());
-          !Unreachable.empty()) {
+      if (pred_empty(&BB) && !preserveLoopPreHeader(&BB)) {
         // When processBlock makes BB unreachable it doesn't bother to fix up
         // the instructions in it. We must remove BB to prevent invalid IR.
-        for (BasicBlock *UBB : Unreachable) {
-          LLVM_DEBUG(dbgs()
-                     << "  JT: Deleting dead block '" << UBB->getName()
-                     << "' with terminator: " << *UBB->getTerminator() << '\n');
-          LoopHeaders.erase(UBB);
-          LVI->eraseBlock(UBB);
-        }
-        DeleteDeadBlocks(Unreachable, DTU.get());
+        LLVM_DEBUG(dbgs() << "  JT: Deleting dead block '" << BB.getName()
+                          << "' with terminator: " << *BB.getTerminator()
+                          << '\n');
+        LoopHeaders.erase(&BB);
+        LVI->eraseBlock(&BB);
+        DeleteDeadBlock(&BB, DTU.get());
         Changed = ChangedSinceLastAnalysisUpdate = true;
         continue;
       }
@@ -385,26 +381,6 @@ bool JumpThreadingPass::runImpl(Function &F_, FunctionAnalysisManager *FAM_,
   return EverChanged;
 }
 
-SmallVector<BasicBlock *, 32>
-JumpThreadingPass::unreachableFromBB(BasicBlock *BB, DomTreeUpdater *DTU) {
-  if (BB->isEntryBlock() || DTU->isBBPendingDeletion(BB))
-    return {};
-
-  SmallVector<BasicBlock *, 32> Unreachable({BB});
-  SmallPtrSet<BasicBlock *, 32> Seen({BB});
-
-  for (unsigned U = 0; U < Unreachable.size(); ++U) {
-    for (BasicBlock *Pred : predecessors(Unreachable[U])) {
-      if (Pred->isEntryBlock())
-        return {};
-      if (Seen.insert(Pred).second && !DTU->isBBPendingDeletion(Pred))
-        Unreachable.push_back(Pred);
-    }
-  }
-
-  return Unreachable;
-}
-
 // Replace uses of Cond with ToVal when safe to do so. If all uses are
 // replaced, we can remove Cond. We cannot blindly replace all uses of Cond
 // because we may incorrectly replace uses when guards/assumes are uses of
@@ -1238,6 +1214,41 @@ static bool isOpDefinedInBlock(Value *Op, BasicBlock *BB) {
   return false;
 }
 
+// Check if BB is a loop pre-header and if it has to be preserved to avoid
+// invalid IR.
+bool JumpThreadingPass::preserveLoopPreHeader(BasicBlock *BB) {
+  BasicBlock *Succ = BB->getUniqueSuccessor();
+  // Check if BB is a pre-header
+  if (!LoopHeaders.contains(Succ))
+    return false;
+  // Check for each PHI node in Succ if it uses BB.
+  // For each PHI node fulfilling this check, check if it is used by one of its
+  // operands, so if there is a circular use. Only verify this for non-PHI
+  // instructions since self-references are OK for PHIs. And only verify this
+  // for instructions that are defined in BB.
+  // If we find corresponding instructions, preserve the pre-header because
+  // otherwise, the PHI node may become constant and may be removed, which could
+  // lead to a circular reference.
+  return llvm::any_of(Succ->phis(), [BB](PHINode &PHI) {
+    if (PHI.getBasicBlockIndex(BB) == -1)
+      return false;
+    bool HasValueDefinedInPreHeader = false;
+    bool HasPotentialSelfReference = false;
+    for (Value *Op : PHI.operand_values()) {
+      Instruction *Inst = dyn_cast<Instruction>(Op);
+      if (!Inst)
+        continue;
+      if (isOpDefinedInBlock(Op, BB))
+        HasValueDefinedInPreHeader = true;
+      else if (!isa<PHINode>(Inst) &&
+             llvm::any_of(Inst->operand_values(),
+                          [&PHI](Value *V) { return V == &PHI; }))
+        HasPotentialSelfReference = true;
+    }
+    return HasValueDefinedInPreHeader && HasPotentialSelfReference;
+  });
+}
+
 /// simplifyPartiallyRedundantLoad - If LoadI is an obviously partially
 /// redundant load instruction, eliminate it by replacing it with a PHI node.
 /// This is an important optimization that encourages jump threading, and needs
diff --git a/llvm/test/Transforms/JumpThreading/PR33357-lvi-recursion.ll b/llvm/test/Transforms/JumpThreading/PR33357-lvi-recursion.ll
index 0c58b09ffdc86..a36f81bda55ab 100644
--- a/llvm/test/Transforms/JumpThreading/PR33357-lvi-recursion.ll
+++ b/llvm/test/Transforms/JumpThreading/PR33357-lvi-recursion.ll
@@ -1,14 +1,15 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt -S -passes=jump-threading,verify -o - %s | FileCheck %s
 @a = external global i16, align 1
 
+; CHECK-LABEL: f
+; CHECK: bb6:
+; CHECK: bb2:
+; CHECK: bb3:
+; CHECK-NOT: bb0:
+; CHECK-NOT: bb1:
+; CHECK-NOT: bb4:
+; CHECK-NOT: bb5:
 define void @f(i32 %p1) {
-; CHECK-LABEL: define void @f(
-; CHECK-SAME: i32 [[P1:%.*]]) {
-; CHECK-NEXT:  [[BB6:.*:]]
-; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[P1]], 0
-; CHECK-NEXT:    ret void
-;
 bb0:
   %0 = icmp eq i32 %p1, 0
   br i1 true, label %bb6, label %bb1
diff --git a/llvm/test/Transforms/JumpThreading/ne-undef.ll b/llvm/test/Transforms/JumpThreading/ne-undef.ll
index 5189f8aacc359..437ff3824ef43 100644
--- a/llvm/test/Transforms/JumpThreading/ne-undef.ll
+++ b/llvm/test/Transforms/JumpThreading/ne-undef.ll
@@ -5,7 +5,20 @@ declare i1 @cond()
 
 define hidden void @hoge(i1 %c1, i32 %x)  {
 ; CHECK-LABEL: @hoge(
-; CHECK-NEXT:  bb13:
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    br label [[BB13:%.*]]
+; CHECK:       bb4:
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ne i32 [[TMP7:%.*]], undef
+; CHECK-NEXT:    br i1 [[TMP3]], label [[BB5:%.*]], label [[BB13]]
+; CHECK:       bb5:
+; CHECK-NEXT:    br label [[BB6:%.*]]
+; CHECK:       bb6:
+; CHECK-NEXT:    [[TMP7]] = phi i32 [ [[TMP7]], [[BB5]] ], [ [[X:%.*]], [[BB8:%.*]] ]
+; CHECK-NEXT:    [[C:%.*]] = call i1 @cond()
+; CHECK-NEXT:    br i1 [[C]], label [[BB4:%.*]], label [[BB8]]
+; CHECK:       bb8:
+; CHECK-NEXT:    br label [[BB6]]
+; CHECK:       bb13:
 ; CHECK-NEXT:    ret void
 ;
 bb:
diff --git a/llvm/test/Transforms/JumpThreading/phi-xor-branch.ll b/llvm/test/Transforms/JumpThreading/phi-xor-branch.ll
index bf0dc6997eef2..bd667906dba31 100644
--- a/llvm/test/Transforms/JumpThreading/phi-xor-branch.ll
+++ b/llvm/test/Transforms/JumpThreading/phi-xor-branch.ll
@@ -5,7 +5,14 @@
 
 define void @test() {
 ; CHECK-LABEL: @test(
-; CHECK-NEXT:  exit:
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[EXIT:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[DUMMY:%.*]] = phi i16 [ 0, [[LOOP:%.*]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 0, 1
+; CHECK-NEXT:    [[XOR:%.*]] = xor i1 false, [[XOR]]
+; CHECK-NEXT:    br i1 [[XOR]], label [[LOOP]], label [[EXIT]]
+; CHECK:       exit:
 ; CHECK-NEXT:    ret void
 ;
 entry:
diff --git a/llvm/test/Transforms/JumpThreading/pr62908.ll b/llvm/test/Transforms/JumpThreading/pr62908.ll
index 4c389ee040b90..cfb647c509f8e 100644
--- a/llvm/test/Transforms/JumpThreading/pr62908.ll
+++ b/llvm/test/Transforms/JumpThreading/pr62908.ll
@@ -5,7 +5,18 @@
 
 define i32 @test() {
 ; CHECK-LABEL: define i32 @test() {
-; CHECK-NEXT:  end:
+; CHECK-NEXT:  join.thread:
+; CHECK-NEXT:    br label [[END:%.*]]
+; CHECK:       unreachable:
+; CHECK-NEXT:    [[SH_PROM:%.*]] = zext i32 -1 to i64
+; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i64 -1, [[SH_PROM]]
+; CHECK-NEXT:    [[CONV:%.*]] = trunc i64 [[SHL]] to i32
+; CHECK-NEXT:    br label [[JOIN:%.*]]
+; CHECK:       join:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[CONV]], [[UNREACHABLE:%.*]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[PHI]], 0
+; CHECK-NEXT:    br i1 [[CMP]], label [[END]], label [[END]]
+; CHECK:       end:
 ; CHECK-NEXT:    ret i32 0
 ;
 entry:
diff --git a/llvm/test/Transforms/JumpThreading/pr9331.ll b/llvm/test/Transforms/JumpThreading/pr9331.ll
index fdd9283efd56c..06c0a42bd849a 100644
--- a/llvm/test/Transforms/JumpThreading/pr9331.ll
+++ b/llvm/test/Transforms/JumpThreading/pr9331.ll
@@ -5,6 +5,8 @@ define void @func(i8 zeroext %p_44) nounwind {
 ; CHECK-LABEL: @func(
 ; CHECK-NEXT:  return:
 ; CHECK-NEXT:    ret void
+; CHECK:       for.inc46:
+; CHECK-NEXT:    br label [[FOR_INC46:%.*]]
 ;
 entry:
   br i1 false, label %for.cond2, label %if.end50
diff --git a/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll b/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll
index 3eb9a04bb4016..521c697c71208 100644
--- a/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll
+++ b/llvm/test/Transforms/JumpThreading/preserving-debugloc-br.ll
@@ -1,7 +1,6 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt -S -passes=jump-threading < %s | FileCheck %s
 
-; @process_block_branch checks that JumpThreading's processBlock() propagates
+; @process_block_branch checks that JumpThreading's processBlock() propagates 
 ; the debug location to the new branch instruction.
 
 ; @process_threadable_edges_branch checks that JumpThreading's processThreadableEdges()
@@ -9,14 +8,8 @@
 
 define i32 @process_block_branch(i32 %action) #0 !dbg !5 {
 ; CHECK-LABEL: define i32 @process_block_branch(
-; CHECK-SAME: i32 [[ACTION:%.*]]) #[[ATTR0:[0-9]+]] !dbg [[DBG5:![0-9]+]] {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    switch i32 [[ACTION]], label %[[IF_THEN:.*]] [
-; CHECK-NEXT:      i32 1, label %[[IF_THEN]]
-; CHECK-NEXT:      i32 0, label %[[IF_THEN]]
-; CHECK-NEXT:    ], !dbg [[DBG8:![0-9]+]]
-; CHECK:       [[IF_THEN]]:
-; CHECK-NEXT:    ret i32 0, !dbg [[DBG9:![0-9]+]]
+; CHECK:       for.cond:
+; CHECK-NEXT:    br label %for.cond, !dbg [[DBG10:![0-9]+]]
 ;
 entry:
   switch i32 %action, label %lor.rhs [
@@ -25,7 +18,7 @@ entry:
   ], !dbg !8
 
 if.then:                                          ; preds = %for.cond, %lor.end, %entry
-  ret i32 0, !dbg !9
+  ret i32 undef, !dbg !9
 
 lor.rhs:                                          ; preds = %entry
   br label %lor.end, !dbg !10
@@ -42,18 +35,8 @@ for.body:                                         ; preds = %for.cond
 
 define void @process_threadable_edges_branch(i32 %value) #0 !dbg !15 {
 ; CHECK-LABEL: define void @process_threadable_edges_branch(
-; CHECK-SAME: i32 [[VALUE:%.*]]) #[[ATTR0]] !dbg [[DBG10:![0-9]+]] {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[VALUE]], 32, !dbg [[DBG11:![0-9]+]]
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[VALUE]], 64, !dbg [[DBG12:![0-9]+]]
-; CHECK-NEXT:    br i1 [[CMP]], label %[[L0:.*]], label %[[L2:.*]], !dbg [[DBG13:![0-9]+]]
-; CHECK:       [[L0]]:
-; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @f2(), !dbg [[DBG14:![0-9]+]]
-; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @f2(), !dbg [[DBG15:![0-9]+]]
-; CHECK-NEXT:    br label %[[L2]], !dbg [[DBG16:![0-9]+]]
-; CHECK:       [[L2]]:
-; CHECK-NEXT:    call void @f4(i32 [[ADD]]), !dbg [[DBG17:![0-9]+]]
-; CHECK-NEXT:    ret void, !dbg [[DBG18:![0-9]+]]
+; CHECK:    L0:
+; CHECK:      br label %L2, !dbg [[DBG17:![0-9]+]]
 ;
 entry:
   %cmp = icmp eq i32 %value, 32, !dbg !16
@@ -95,6 +78,10 @@ attributes #0 = { nounwind }
 !llvm.debugify = !{!2, !3}
 !llvm.module.flags = !{!4}
 
+;.
+; CHECK: [[DBG10]] = !DILocation(line: 6,
+; CHECK: [[DBG17]] = !DILocation(line: 13,
+;.
 
 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
 !1 = !DIFile(filename: "temp.ll", directory: "/")
@@ -124,21 +111,3 @@ attributes #0 = { nounwind }
 !25 = !DILocation(line: 17, column: 1, scope: !15)
 !26 = !DILocation(line: 18, column: 1, scope: !15)
 !27 = !DILocation(line: 19, column: 1, scope: !15)
-;.
-; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C, file: [[META1:![0-9]+]], producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
-; CHECK: [[META1]] = !DIFile(filename: "temp.ll", directory: {{.*}})
-; CHECK: [[DBG5]] = distinct !DISubprogram(name: "process_block_branch", linkageName: "process_block_branch", scope: null, file: [[META1]], line: 1, type: [[META6:![0-9]+]], scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]])
-; CHECK: [[META6]] = !DISubroutineType(types: [[META7:![0-9]+]])
-; CHECK: [[META7]] = !{}
-; CHECK: [[DBG8]] = !DILocation(line: 1, column: 1, scope: [[DBG5]])
-; CHECK: [[DBG9]] = !DILocation(line: 2, column: 1, scope: [[DBG5]])
-; CHECK: [[DBG10]] = distinct !DISubprogram(name: "process_threadable_edges_branch", linkageName: "process_threadable_edges_branch", scope: null, file: [[META1]], line: 8, type: [[META6]], scopeLine: 8, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]])
-; CHECK: [[DBG11]] = !DILocation(line: 8, column: 1, scope: [[DBG10]])
-; CHECK: [[DBG12]] = !DILocation(line: 9, column: 1, scope: [[DBG10]])
-; CHECK: [[DBG13]] = !DILocation(line: 10, column: 1, scope: [[DBG10]])
-; CHECK: [[DBG14]] = !DILocation(line: 11, column: 1, scope: [[DBG10]])
-; CHECK: [[DBG15]] = !DILocation(line: 12, column: 1, scope: [[DBG10]])
-; CHECK: [[DBG16]] = !DILocation(line: 13, column: 1, scope: [[DBG10]])
-; CHECK: [[DBG17]] = !DILocation(line: 16, column: 1, scope: [[DBG10]])
-; CHECK: [[DBG18]] = !DILocation(line: 17, column: 1, scope: [[DBG10]])
-;.
diff --git a/llvm/test/Transforms/JumpThreading/removed-use.ll b/llvm/test/Transforms/JumpThreading/removed-use.ll
index 4cd1b75f78c00..40b82d21ad081 100644
--- a/llvm/test/Transforms/JumpThreading/removed-use.ll
+++ b/llvm/test/Transforms/JumpThreading/removed-use.ll
@@ -1,10 +1,10 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt -S < %s -passes=jump-threading | FileCheck %s
+; CHECK-LABEL: @foo
+; CHECK: bb6:
+; CHECK-NEXT: ret void
+; CHECK: bb3:
+; CHECK: br label %bb3
 define void @foo() {
-; CHECK-LABEL: define void @foo() {
-; CHECK-NEXT:  [[BB6:.*:]]
-; CHECK-NEXT:    ret void
-;
 entry:
   br i1 true, label %bb6, label %bb3
 
@@ -27,13 +27,9 @@ bb6:
   ret void
 }
 
+; CHECK-LABEL: @bar
 ; Just check that we don't crash on this test.
 define void @bar(i1 %p) {
-; CHECK-LABEL: define void @bar(
-; CHECK-SAME: i1 [[P:%.*]]) {
-; CHECK-NEXT:  [[EXIT:.*:]]
-; CHECK-NEXT:    ret void
-;
 entry:
   br i1 false, label %bb2, label %exit
 
@@ -50,7 +46,7 @@ bb4:
 bb5:
   %x1 = phi i32 [ %x0, %bb3 ], [ 0, %bb4 ]
   switch i32 %x1, label %exit [
-  i32 10, label %bb2
+    i32 10, label %bb2
   ]
 
 exit:
diff --git a/llvm/test/Transforms/JumpThreading/unreachable-loops.ll b/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
index edddc13d61d0d..e082505f10b5a 100644
--- a/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
+++ b/llvm/test/Transforms/JumpThreading/unreachable-loops.ll
@@ -12,6 +12,12 @@ define void @unreachable_single_bb_loop() {
 ; CHECK-NEXT:    [[TMP:%.*]] = call i32 @a()
 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[TMP]], 1
 ; CHECK-NEXT:    br i1 [[TMP1]], label [[BB8:%.*]], label [[BB8]]
+; CHECK:       bb2:
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP]], 1
+; CHECK-NEXT:    switch i1 [[TMP4]], label [[BB2:%.*]] [
+; CHECK-NEXT:      i1 false, label [[BB8]]
+; CHECK-NEXT:      i1 true, label [[BB8]]
+; CHECK-NEXT:    ]
 ; CHECK:       bb8:
 ; CHECK-NEXT:    ret void
 ;
@@ -46,6 +52,14 @@ define void @unreachable_multi_bbs_loop() {
 ; CHECK-NEXT:    [[TMP:%.*]] = call i32 @a()
 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[TMP]], 1
 ; CHECK-NEXT:    br i1 [[TMP1]], label [[BB8:%.*]], label [[BB8]]
+; CHECK:       bb3:
+; CHECK-NEXT:    br label [[BB2:%.*]]
+; CHECK:       bb2:
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP]], 1
+; CHECK-NEXT:    switch i1 [[TMP4]], label [[BB3:%.*]] [
+; CHECK-NEXT:      i1 false, label [[BB8]]
+; CHECK-NEXT:      i1 true, label [[BB8]]
+; CHECK-NEXT:    ]
 ; CHECK:       bb8:
 ; CHECK-NEXT:    ret void
 ;
@@ -85,6 +99,10 @@ define void @PR48362(i1 %arg) {
 ; CHECK-LABEL: @PR48362(
 ; CHECK-NEXT:  cleanup.cont1500:
 ; CHECK-NEXT:    unreachable
+; CHECK:       if.end1733:
+; CHECK-NEXT:    [[I82:%.*]] = load i32, ptr undef, align 1
+; CHECK-NEXT:    [[TOBOOL1731_NOT:%.*]] = icmp eq i32 [[I82]], 0
+; CHECK-NEXT:    br label [[IF_END1733:%.*]]
 ;
 cleanup1491:                                      ; preds = %for.body1140
   switch i32 0, label %cleanup2343.loopexit4 [
@@ -171,9 +189,26 @@ cleanup2343.loopexit4:                            ; preds = %cleanup1491
 
 define i32 @constant_phi_leads_to_self_reference(ptr %ptr) {
 ; CHECK-LABEL: @constant_phi_leads_to_self_reference(
-; CHECK-NEXT:  F6:
 ; CHECK-NEXT:    [[A9:%.*]] = alloca i1, align 1
+; CHECK-NEXT:    br label [[F6:%.*]]
+; CHECK:       T3:
+; CHECK-NEXT:    [[L6:%.*]] = phi i1 [ [[L6_PR:%.*]], [[T4:%.*]] ], [ [[C4:%.*]], [[BB6:%.*]] ]
+; CHECK-NEXT:    br label [[BB5:%.*]]
+; CHECK:       BB5:
+; CHECK-NEXT:    [[L10:%.*]] = load i1, ptr [[A9]], align 1
+; CHECK-NEXT:    br i1 [[L10]], label [[BB6]], label [[F6]]
+; CHECK:       BB6:
+; CHECK-NEXT:    [[LGV3:%.*]] = load i1, ptr [[PTR:%.*]], align 1
+; CHECK-NEXT:    [[C4]] = icmp sle i1 [[L6]], true
+; CHECK-NEXT:    store i1 [[C4]], ptr [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[L6]], label [[F6]], label [[T3:%.*]]
+; CHECK:       T4:
+; CHECK-NEXT:    [[L6_PR]] = load i1, ptr [[PTR]], align 1
+; CHECK-NEXT:    br label [[T3]]
+; CHECK:       F6:
 ; CHECK-NEXT:    ret i32 0
+; CHECK:       F7:
+; CHECK-NEXT:    br label [[BB5]]
 ;
   %A9 = alloca i1, align 1
   br i1 false, label %BB4, label %F6
@@ -184,7 +219,7 @@ BB4:                                              ; preds = %0
 F1:                                               ; preds = %BB4
   br i1 false, label %T4, label %T3
 
-T3:                                               ; preds = %T4, %BB6, %F1
+  T3:                                               ; preds = %T4, %BB6, %F1
   %L6 = load i1, ptr %ptr, align 1
   br label %BB5
 
@@ -206,6 +241,6 @@ F6:                                               ; preds = %BB6, %BB5, %BB4, %0
 
 F7:                                               ; No predecessors!
   br label %BB5
-}
+  }
 
 !0 = !{!"branch_weights", i32 2146410443, i32 1073205}



More information about the llvm-commits mailing list