[llvm] [JumpThreading] Fix lifetime markers when alloca requires SSA renaming (PR #188147)
Guilherme Lopes via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 8 06:59:44 PDT 2026
https://github.com/guilhermeglopess updated https://github.com/llvm/llvm-project/pull/188147
>From 7e6eefeb1dcf0d09ec8fde8d5dd2517612db9419 Mon Sep 17 00:00:00 2001
From: Guilherme Lopes <guilhermeglopes at tecnico.ulisboa.pt>
Date: Sun, 22 Mar 2026 00:23:40 +0000
Subject: [PATCH 1/6] [JumpThreading] Fix lifetime markers when alloca requires
SSA renaming
JumpThreading can create PHI nodes for alloca values when threading
across blocks. This violates the requirement introduced in #149310
that lifetime.start/end intrinsics must operate directly on allocas,
not on PHI nodes.
Fix this in two ways:
- For allocas with a constant size, move both the original
alloca and its clone in the threaded block to the entry
block before SSA reconstruction, so they dominate all uses
and lifetime markers remain valid after threading.
- For any remaining allocas where a lifetime marker is no longer
dominated by the alloca after jump threading, remove all lifetime
markers.
Fixes #167733
---
llvm/lib/Transforms/Scalar/JumpThreading.cpp | 44 +++++++++++++++++++
.../JumpThreading/lifetime-alloca.ll | 40 +++++++++++++++++
2 files changed, 84 insertions(+)
create mode 100644 llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 7f8e10eb201a6..3367d78c3a657 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -1975,6 +1975,32 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
SmallVector<Use *, 16> UsesToRename;
SmallVector<DbgVariableRecord *, 4> DbgVariableRecords;
+ // Move static allocas with lifetime markers to the entry block so they
+ // dominate all their uses after jump threading, preserving lifetime info.
+ // For dynamic allocas, lifetime markers will be dropped below.
+ BasicBlock &EntryBB = BB->getParent()->getEntryBlock();
+ SmallVector<AllocaInst *> AllocasToHoist;
+ for (Instruction &I : *BB) {
+ auto *AI = dyn_cast<AllocaInst>(&I);
+ // Use isa<ConstantInt> instead of isStaticAlloca() because the alloca
+ // is not in the entry block yet, so isStaticAlloca() would return false
+ // even for allocas with a constant size.
+ if (AI && isa<ConstantInt>(AI->getArraySize()) &&
+ any_of(AI->users(), [](User *U) {
+ return cast<Instruction>(U)->isLifetimeStartOrEnd();
+ }))
+ AllocasToHoist.push_back(AI);
+ }
+
+ if (!AllocasToHoist.empty()) {
+ auto HoistPoint = EntryBB.getFirstNonPHIOrDbgOrAlloca()->getIterator();
+ for (AllocaInst *AI : AllocasToHoist) {
+ AI->moveBefore(HoistPoint);
+ if (auto *NewAI = dyn_cast_or_null<AllocaInst>(ValueMapping[AI]))
+ NewAI->moveBefore(HoistPoint);
+ }
+ }
+
for (Instruction &I : *BB) {
// Scan all uses of this instruction to see if it is used outside of its
// block, and if so, record them in UsesToRename.
@@ -2000,6 +2026,24 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
continue;
LLVM_DEBUG(dbgs() << "JT: Renaming non-local uses of: " << I << "\n");
+ if (isa<AllocaInst>(&I)) {
+ // Static allocas with lifetime markers were moved to the entry block
+ // above. For any remaining allocas where a lifetime marker is no longer
+ // dominated by the alloca, remove all lifetime markers.
+ DominatorTree &DT = DTU->getDomTree();
+ bool HasNonDominatedLifetimeMarker = any_of(I.users(), [&](User *U) {
+ auto *UserI = cast<Instruction>(U);
+ return UserI->isLifetimeStartOrEnd() && !DT.dominates(&I, UserI);
+ });
+ if (HasNonDominatedLifetimeMarker) {
+ for (User *U : make_early_inc_range(I.users())) {
+ auto *UserI = cast<Instruction>(U);
+ if (UserI->isLifetimeStartOrEnd())
+ UserI->eraseFromParent();
+ }
+ }
+ }
+
// We found a use of I outside of BB. Rename all uses of I that are outside
// its block to be uses of the appropriate PHI node etc. See ValuesInBlocks
// with the two values we know.
diff --git a/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll b/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
new file mode 100644
index 0000000000000..9a9ce026942b0
--- /dev/null
+++ b/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
@@ -0,0 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=jump-threading -S %s | FileCheck %s
+
+; Test that JumpThreading does not create a PHI node for an alloca that is
+; used by a lifetime intrinsic, which would violate the requirement that
+; lifetime markers only operate on allocas.
+
+define void @widget(i1 %arg) {
+; CHECK-LABEL: @widget(
+; CHECK-NOT: phi ptr
+; CHECK: bb:
+; CHECK-NEXT: %alloca = alloca [4 x [4 x i32]], align 8
+; CHECK-NEXT: %alloca1 = alloca [4 x [4 x i32]], align 8
+; CHECK: call void @llvm.lifetime.start.p0(ptr %alloca)
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %alloca)
+bb:
+ br i1 %arg, label %bb1, label %bb2
+
+bb1:
+ call void @dummy()
+ br label %bb2
+
+bb2:
+ %alloca = alloca [4 x [4 x i32]], align 8
+ br i1 %arg, label %bb3, label %bb4
+
+bb3:
+ br label %bb4
+
+bb4:
+ call void @llvm.lifetime.start.p0(ptr %alloca)
+ call void @llvm.lifetime.end.p0(ptr %alloca)
+ ret void
+}
+
+declare void @llvm.lifetime.start.p0(ptr captures(none)) #0
+declare void @llvm.lifetime.end.p0(ptr captures(none)) #0
+declare void @dummy()
+
+attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
>From 3bf7c33352d134631e88beb3406e17a7ab8d62e3 Mon Sep 17 00:00:00 2001
From: Guilherme Lopes <guilhermeglopes at tecnico.ulisboa.pt>
Date: Mon, 30 Mar 2026 22:29:53 +0100
Subject: [PATCH 2/6] Address review: drop hoisting, remove non-dominated
lifetime markers
Hoisting allocas to the entry block is unsafe if the alloca is inside a loop. Instead, simply remove all lifetime markers for allocas that would become non-dominated after jump threading.
---
llvm/lib/Transforms/Scalar/JumpThreading.cpp | 57 +++++++------------
.../JumpThreading/lifetime-alloca.ll | 6 +-
2 files changed, 21 insertions(+), 42 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 3367d78c3a657..dcf6098f088fd 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -1975,32 +1975,6 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
SmallVector<Use *, 16> UsesToRename;
SmallVector<DbgVariableRecord *, 4> DbgVariableRecords;
- // Move static allocas with lifetime markers to the entry block so they
- // dominate all their uses after jump threading, preserving lifetime info.
- // For dynamic allocas, lifetime markers will be dropped below.
- BasicBlock &EntryBB = BB->getParent()->getEntryBlock();
- SmallVector<AllocaInst *> AllocasToHoist;
- for (Instruction &I : *BB) {
- auto *AI = dyn_cast<AllocaInst>(&I);
- // Use isa<ConstantInt> instead of isStaticAlloca() because the alloca
- // is not in the entry block yet, so isStaticAlloca() would return false
- // even for allocas with a constant size.
- if (AI && isa<ConstantInt>(AI->getArraySize()) &&
- any_of(AI->users(), [](User *U) {
- return cast<Instruction>(U)->isLifetimeStartOrEnd();
- }))
- AllocasToHoist.push_back(AI);
- }
-
- if (!AllocasToHoist.empty()) {
- auto HoistPoint = EntryBB.getFirstNonPHIOrDbgOrAlloca()->getIterator();
- for (AllocaInst *AI : AllocasToHoist) {
- AI->moveBefore(HoistPoint);
- if (auto *NewAI = dyn_cast_or_null<AllocaInst>(ValueMapping[AI]))
- NewAI->moveBefore(HoistPoint);
- }
- }
-
for (Instruction &I : *BB) {
// Scan all uses of this instruction to see if it is used outside of its
// block, and if so, record them in UsesToRename.
@@ -2027,21 +2001,30 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
LLVM_DEBUG(dbgs() << "JT: Renaming non-local uses of: " << I << "\n");
if (isa<AllocaInst>(&I)) {
- // Static allocas with lifetime markers were moved to the entry block
- // above. For any remaining allocas where a lifetime marker is no longer
- // dominated by the alloca, remove all lifetime markers.
+ // If any lifetime marker for the alloca is no longer dominated by the
+ // alloca after jump threading, remove all lifetime markers. This avoids
+ // inserting PHI nodes for lifetime markers, which is invalid.
DominatorTree &DT = DTU->getDomTree();
- bool HasNonDominatedLifetimeMarker = any_of(I.users(), [&](User *U) {
+ bool HasNonDominatedLifetimeMarker = false;
+ SmallVector<Instruction *> LifetimeMarkers;
+ for (User *U : I.users()) {
auto *UserI = cast<Instruction>(U);
- return UserI->isLifetimeStartOrEnd() && !DT.dominates(&I, UserI);
- });
- if (HasNonDominatedLifetimeMarker) {
- for (User *U : make_early_inc_range(I.users())) {
- auto *UserI = cast<Instruction>(U);
- if (UserI->isLifetimeStartOrEnd())
- UserI->eraseFromParent();
+ if (UserI->isLifetimeStartOrEnd()) {
+ if (!DT.dominates(&I, UserI))
+ HasNonDominatedLifetimeMarker = true;
+ LifetimeMarkers.push_back(UserI);
}
}
+ if (HasNonDominatedLifetimeMarker) {
+ // Remove all uses of lifetime markers from UsesToRename before
+ // erasing them. This prevents SSAUpdater from attempting to
+ // rewrite uses of instructions that have been deleted.
+ llvm::erase_if(UsesToRename, [](Use *U) {
+ return cast<Instruction>(U->getUser())->isLifetimeStartOrEnd();
+ });
+ for (Instruction *UserI : LifetimeMarkers)
+ UserI->eraseFromParent();
+ }
}
// We found a use of I outside of BB. Rename all uses of I that are outside
diff --git a/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll b/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
index 9a9ce026942b0..765049fe5c58d 100644
--- a/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
+++ b/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
@@ -8,11 +8,7 @@
define void @widget(i1 %arg) {
; CHECK-LABEL: @widget(
; CHECK-NOT: phi ptr
-; CHECK: bb:
-; CHECK-NEXT: %alloca = alloca [4 x [4 x i32]], align 8
-; CHECK-NEXT: %alloca1 = alloca [4 x [4 x i32]], align 8
-; CHECK: call void @llvm.lifetime.start.p0(ptr %alloca)
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr %alloca)
+; CHECK-NOT: call void @llvm.lifetime
bb:
br i1 %arg, label %bb1, label %bb2
>From 78ef62e1d45dc690aa5931c072062962c56b98e5 Mon Sep 17 00:00:00 2001
From: Guilherme Lopes <guilhermeglopes at tecnico.ulisboa.pt>
Date: Mon, 6 Apr 2026 15:53:20 +0100
Subject: [PATCH 3/6] Address review: prevent markers from entering
UsesToRename, add test
Move the check for non-dominated lifetime markers to the first loop to avoid adding them to UsesToRename entirely. Includes a new test case to ensure dominated lifetime markers are preserved during jump threading.
---
llvm/lib/Transforms/Scalar/JumpThreading.cpp | 56 ++++++++-----------
.../JumpThreading/lifetime-alloca.ll | 52 +++++++++++++++--
2 files changed, 71 insertions(+), 37 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index dcf6098f088fd..e82de4f6b1548 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -1978,15 +1978,32 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
for (Instruction &I : *BB) {
// Scan all uses of this instruction to see if it is used outside of its
// block, and if so, record them in UsesToRename.
+
+ SmallVector<Instruction *> LifetimeMarkers;
+ bool HasNonDominatedLifetimeMarker = false;
for (Use &U : I.uses()) {
Instruction *User = cast<Instruction>(U.getUser());
- if (PHINode *UserPN = dyn_cast<PHINode>(User)) {
- if (UserPN->getIncomingBlock(U) == BB)
+ if (isa<AllocaInst>(&I) && User->isLifetimeStartOrEnd()) {
+ // If any lifetime marker for the alloca is no longer dominated by the
+ // alloca after jump threading, we will remove all lifetime markers.
+ // This avoids inserting PHI nodes for lifetime markers, which is
+ // invalid.
+ DominatorTree &DT = DTU->getDomTree();
+ if (!DT.dominates(&I, User))
+ HasNonDominatedLifetimeMarker = true;
+ LifetimeMarkers.push_back(User);
+ } else {
+ if (PHINode *UserPN = dyn_cast<PHINode>(User)) {
+ if (UserPN->getIncomingBlock(U) == BB)
+ continue;
+ } else if (User->getParent() == BB)
continue;
- } else if (User->getParent() == BB)
- continue;
-
- UsesToRename.push_back(&U);
+ UsesToRename.push_back(&U);
+ }
+ }
+ if (HasNonDominatedLifetimeMarker) {
+ for (Instruction *User : LifetimeMarkers)
+ User->eraseFromParent();
}
// Find debug values outside of the block
@@ -2000,33 +2017,6 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
continue;
LLVM_DEBUG(dbgs() << "JT: Renaming non-local uses of: " << I << "\n");
- if (isa<AllocaInst>(&I)) {
- // If any lifetime marker for the alloca is no longer dominated by the
- // alloca after jump threading, remove all lifetime markers. This avoids
- // inserting PHI nodes for lifetime markers, which is invalid.
- DominatorTree &DT = DTU->getDomTree();
- bool HasNonDominatedLifetimeMarker = false;
- SmallVector<Instruction *> LifetimeMarkers;
- for (User *U : I.users()) {
- auto *UserI = cast<Instruction>(U);
- if (UserI->isLifetimeStartOrEnd()) {
- if (!DT.dominates(&I, UserI))
- HasNonDominatedLifetimeMarker = true;
- LifetimeMarkers.push_back(UserI);
- }
- }
- if (HasNonDominatedLifetimeMarker) {
- // Remove all uses of lifetime markers from UsesToRename before
- // erasing them. This prevents SSAUpdater from attempting to
- // rewrite uses of instructions that have been deleted.
- llvm::erase_if(UsesToRename, [](Use *U) {
- return cast<Instruction>(U->getUser())->isLifetimeStartOrEnd();
- });
- for (Instruction *UserI : LifetimeMarkers)
- UserI->eraseFromParent();
- }
- }
-
// We found a use of I outside of BB. Rename all uses of I that are outside
// its block to be uses of the appropriate PHI node etc. See ValuesInBlocks
// with the two values we know.
diff --git a/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll b/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
index 765049fe5c58d..9dccdb7279cfb 100644
--- a/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
+++ b/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
@@ -5,10 +5,19 @@
; used by a lifetime intrinsic, which would violate the requirement that
; lifetime markers only operate on allocas.
-define void @widget(i1 %arg) {
-; CHECK-LABEL: @widget(
-; CHECK-NOT: phi ptr
-; CHECK-NOT: call void @llvm.lifetime
+define void @widget_dropped(i1 %arg) {
+; CHECK-LABEL: @widget_dropped(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: br i1 [[ARG:%.*]], label [[BB3:%.*]], label [[BB2:%.*]]
+; CHECK: bb2:
+; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [4 x [4 x i32]], align 8
+; CHECK-NEXT: br label [[BB4:%.*]]
+; CHECK: bb3:
+; CHECK-NEXT: call void @dummy()
+; CHECK-NEXT: br label [[BB4]]
+; CHECK: bb4:
+; CHECK-NEXT: ret void
+;
bb:
br i1 %arg, label %bb1, label %bb2
@@ -29,6 +38,41 @@ bb4:
ret void
}
+; Because the alloca is in the entry block, it dominates all threaded blocks.
+; No PHI node is required, and the lifetime markers can be safely preserved.
+define void @widget_preserved(i1 %arg) {
+; CHECK-LABEL: @widget_preserved(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [4 x [4 x i32]], align 8
+; CHECK-NEXT: br i1 [[ARG:%.*]], label [[BB3:%.*]], label [[BB4:%.*]]
+; CHECK: bb3:
+; CHECK-NEXT: call void @dummy()
+; CHECK-NEXT: br label [[BB4]]
+; CHECK: bb4:
+; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[ALLOCA]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[ALLOCA]])
+; CHECK-NEXT: ret void
+;
+bb:
+ %alloca = alloca [4 x [4 x i32]], align 8
+ br i1 %arg, label %bb1, label %bb2
+
+bb1:
+ call void @dummy()
+ br label %bb2
+
+bb2:
+ br i1 %arg, label %bb3, label %bb4
+
+bb3:
+ br label %bb4
+
+bb4:
+ call void @llvm.lifetime.start.p0(ptr %alloca)
+ call void @llvm.lifetime.end.p0(ptr %alloca)
+ ret void
+}
+
declare void @llvm.lifetime.start.p0(ptr captures(none)) #0
declare void @llvm.lifetime.end.p0(ptr captures(none)) #0
declare void @dummy()
>From ca113176a0c2cc5eb7e93311e7cf218ecf278631 Mon Sep 17 00:00:00 2001
From: Guilherme Lopes <guilhermeglopes at tecnico.ulisboa.pt>
Date: Fri, 1 May 2026 12:11:57 +0100
Subject: [PATCH 4/6] Address review: drop DomTree check, check phi args after
SSAUpdate
---
llvm/lib/Transforms/Scalar/JumpThreading.cpp | 32 ++++++++++++-------
.../JumpThreading/lifetime-alloca.ll | 2 ++
2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index e82de4f6b1548..49bcab027fc02 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -1980,18 +1980,11 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
// block, and if so, record them in UsesToRename.
SmallVector<Instruction *> LifetimeMarkers;
- bool HasNonDominatedLifetimeMarker = false;
for (Use &U : I.uses()) {
Instruction *User = cast<Instruction>(U.getUser());
if (isa<AllocaInst>(&I) && User->isLifetimeStartOrEnd()) {
- // If any lifetime marker for the alloca is no longer dominated by the
- // alloca after jump threading, we will remove all lifetime markers.
- // This avoids inserting PHI nodes for lifetime markers, which is
- // invalid.
- DominatorTree &DT = DTU->getDomTree();
- if (!DT.dominates(&I, User))
- HasNonDominatedLifetimeMarker = true;
LifetimeMarkers.push_back(User);
+ UsesToRename.push_back(&U);
} else {
if (PHINode *UserPN = dyn_cast<PHINode>(User)) {
if (UserPN->getIncomingBlock(U) == BB)
@@ -2001,10 +1994,6 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
UsesToRename.push_back(&U);
}
}
- if (HasNonDominatedLifetimeMarker) {
- for (Instruction *User : LifetimeMarkers)
- User->eraseFromParent();
- }
// Find debug values outside of the block
findDbgValues(&I, DbgVariableRecords);
@@ -2031,6 +2020,25 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
DbgVariableRecords.clear();
}
+ // Lifetime markers cannot be rewritten through PHIs. If threading leaves
+ // one of them pointing at a PHI, drop the whole set.
+ bool HasPhiArg = false;
+ for (Instruction *User : LifetimeMarkers) {
+ auto *CB = cast<CallBase>(User);
+
+ // Lifetime markers have two common signatures:
+ // @llvm.lifetime.start.p0(ptr)
+ // @llvm.lifetime.start(i64, ptr)
+ if (isa<PHINode>(
+ CB->getOperand(CB->arg_size() - 1)->stripPointerCasts())) {
+ HasPhiArg = true;
+ break;
+ }
+ }
+ if (HasPhiArg) {
+ for (Instruction *User : LifetimeMarkers)
+ User->eraseFromParent();
+ }
LLVM_DEBUG(dbgs() << "\n");
}
}
diff --git a/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll b/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
index 9dccdb7279cfb..51f40cc5b90dc 100644
--- a/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
+++ b/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
@@ -14,8 +14,10 @@ define void @widget_dropped(i1 %arg) {
; CHECK-NEXT: br label [[BB4:%.*]]
; CHECK: bb3:
; CHECK-NEXT: call void @dummy()
+; CHECK-NEXT: [[ALLOCA1:%.*]] = alloca [4 x [4 x i32]], align 8
; CHECK-NEXT: br label [[BB4]]
; CHECK: bb4:
+; CHECK-NEXT: [[ALLOCA2:%.*]] = phi ptr [ [[ALLOCA1]], [[BB3]] ], [ [[ALLOCA]], [[BB2]] ]
; CHECK-NEXT: ret void
;
bb:
>From 5c0778a5eeb705027986ee621523ed6e0301cfd9 Mon Sep 17 00:00:00 2001
From: Guilherme Lopes <guilhermeglopes at tecnico.ulisboa.pt>
Date: Fri, 15 May 2026 20:16:42 +0100
Subject: [PATCH 5/6] address review: move UsesToRename, simplify signature,
drop strip cast move UsesToRename outside if block, simplify getOperand, to
use default signature, drop strip cast
---
llvm/lib/Transforms/Scalar/JumpThreading.cpp | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 49bcab027fc02..e21df535845e6 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -1984,15 +1984,14 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
Instruction *User = cast<Instruction>(U.getUser());
if (isa<AllocaInst>(&I) && User->isLifetimeStartOrEnd()) {
LifetimeMarkers.push_back(User);
- UsesToRename.push_back(&U);
} else {
if (PHINode *UserPN = dyn_cast<PHINode>(User)) {
if (UserPN->getIncomingBlock(U) == BB)
continue;
} else if (User->getParent() == BB)
continue;
- UsesToRename.push_back(&U);
}
+ UsesToRename.push_back(&U);
}
// Find debug values outside of the block
@@ -2025,12 +2024,7 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
bool HasPhiArg = false;
for (Instruction *User : LifetimeMarkers) {
auto *CB = cast<CallBase>(User);
-
- // Lifetime markers have two common signatures:
- // @llvm.lifetime.start.p0(ptr)
- // @llvm.lifetime.start(i64, ptr)
- if (isa<PHINode>(
- CB->getOperand(CB->arg_size() - 1)->stripPointerCasts())) {
+ if (isa<PHINode>(CB->getOperand(0))) {
HasPhiArg = true;
break;
}
>From f4fc934e8419bc9ee2f77c23edd34dc6685fd9a2 Mon Sep 17 00:00:00 2001
From: Guilherme Lopes <guilhermeglopes at tecnico.ulisboa.pt>
Date: Mon, 8 Jun 2026 14:59:03 +0100
Subject: [PATCH 6/6] [JumpThreading] Address review
---
llvm/lib/Transforms/Scalar/JumpThreading.cpp | 13 ++++---------
.../Transforms/JumpThreading/lifetime-alloca.ll | 2 --
2 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index e21df535845e6..31f3ffc9da745 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -1982,7 +1982,7 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
SmallVector<Instruction *> LifetimeMarkers;
for (Use &U : I.uses()) {
Instruction *User = cast<Instruction>(U.getUser());
- if (isa<AllocaInst>(&I) && User->isLifetimeStartOrEnd()) {
+ if (User->isLifetimeStartOrEnd()) {
LifetimeMarkers.push_back(User);
} else {
if (PHINode *UserPN = dyn_cast<PHINode>(User)) {
@@ -2021,14 +2021,9 @@ void JumpThreadingPass::updateSSA(BasicBlock *BB, BasicBlock *NewBB,
// Lifetime markers cannot be rewritten through PHIs. If threading leaves
// one of them pointing at a PHI, drop the whole set.
- bool HasPhiArg = false;
- for (Instruction *User : LifetimeMarkers) {
- auto *CB = cast<CallBase>(User);
- if (isa<PHINode>(CB->getOperand(0))) {
- HasPhiArg = true;
- break;
- }
- }
+ bool HasPhiArg = any_of(LifetimeMarkers, [](Instruction *User) {
+ return isa<PHINode>(cast<CallBase>(User)->getOperand(0));
+ });
if (HasPhiArg) {
for (Instruction *User : LifetimeMarkers)
User->eraseFromParent();
diff --git a/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll b/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
index 51f40cc5b90dc..81e05c70588f6 100644
--- a/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
+++ b/llvm/test/Transforms/JumpThreading/lifetime-alloca.ll
@@ -75,8 +75,6 @@ bb4:
ret void
}
-declare void @llvm.lifetime.start.p0(ptr captures(none)) #0
-declare void @llvm.lifetime.end.p0(ptr captures(none)) #0
declare void @dummy()
attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
More information about the llvm-commits
mailing list