[llvm] Handle lifetime.end-only allocas (PR #210581)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 19 01:39:10 PDT 2026
https://github.com/SomeFlyingThing created https://github.com/llvm/llvm-project/pull/210581
StackLifetime previously only tracked allocas with a lifetime.start marker, so an alloca with only lifetime.end markers incorrectly received a full-function live range.It now tracks every alloca with either llvm.lifetime.start or llvm.lifetime.end
>From 6a10d0c88e8e98d8033afbb12606068297450641 Mon Sep 17 00:00:00 2001
From: SomeFlyingThing <306498559+SomeFlyingThing at users.noreply.github.com>
Date: Sun, 19 Jul 2026 09:32:33 +0100
Subject: [PATCH] [StackLifetime] Handle lifetime.end-only allocas
---
llvm/include/llvm/Analysis/StackLifetime.h | 8 ++-
llvm/lib/Analysis/StackLifetime.cpp | 21 +++++---
.../Analysis/StackSafetyAnalysis/lifetime.ll | 54 +++++++++++++++++--
3 files changed, 71 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/Analysis/StackLifetime.h b/llvm/include/llvm/Analysis/StackLifetime.h
index ccc5fae1bc0cc..6ff3fad3f368e 100644
--- a/llvm/include/llvm/Analysis/StackLifetime.h
+++ b/llvm/include/llvm/Analysis/StackLifetime.h
@@ -108,9 +108,13 @@ class StackLifetime {
/// LiveRange for allocas.
SmallVector<LiveRange, 8> LiveRanges;
- /// The set of allocas that have at least one lifetime.start. All other
+ /// The set of allocas that have at least one lifetime marker. All other
/// allocas get LiveRange that corresponds to the entire function.
- BitVector InterestingAllocas;
+ BitVector MarkerAllocas;
+
+ /// The set of allocas that have at least one lifetime.start and are
+ /// therefore initially dead.
+ BitVector StartAllocas;
struct Marker {
unsigned AllocaNo;
diff --git a/llvm/lib/Analysis/StackLifetime.cpp b/llvm/lib/Analysis/StackLifetime.cpp
index 30e0316b882cc..726b743f60ae3 100644
--- a/llvm/lib/Analysis/StackLifetime.cpp
+++ b/llvm/lib/Analysis/StackLifetime.cpp
@@ -60,7 +60,8 @@ bool StackLifetime::isAliveAfter(const AllocaInst *AI,
}
void StackLifetime::collectMarkers() {
- InterestingAllocas.resize(NumAllocas);
+ MarkerAllocas.resize(NumAllocas);
+ StartAllocas.resize(NumAllocas);
DenseMap<const BasicBlock *, SmallDenseMap<const IntrinsicInst *, Marker>>
BBMarkerSet;
@@ -78,8 +79,9 @@ void StackLifetime::collectMarkers() {
continue;
auto AllocaNo = It->second;
bool IsStart = II->getIntrinsicID() == Intrinsic::lifetime_start;
+ MarkerAllocas.set(AllocaNo);
if (IsStart)
- InterestingAllocas.set(AllocaNo);
+ StartAllocas.set(AllocaNo);
BBMarkerSet[BB][II] = {AllocaNo, IsStart};
}
}
@@ -168,9 +170,16 @@ void StackLifetime::calculateLocalLiveness() {
BitsIn |= I->second.LiveOut;
}
- // Everything is "may be dead" for entry without predecessors.
- if (Type == LivenessType::Must && BitsIn.empty())
- BitsIn.resize(NumAllocas, true);
+ // Allocas with a lifetime.start are initially dead. Allocas with only
+ // lifetime.end markers are initially alive.
+ if (BB == &F.getEntryBlock()) {
+ if (Type == LivenessType::May) {
+ BitsIn = MarkerAllocas;
+ BitsIn.reset(StartAllocas);
+ } else {
+ BitsIn = StartAllocas;
+ }
+ }
// Update block LiveIn set, noting whether it has changed.
if (!BitsIn.subsetOf(BlockInfo.LiveIn)) {
@@ -303,7 +312,7 @@ StackLifetime::StackLifetime(const Function &F,
void StackLifetime::run() {
LiveRanges.resize(NumAllocas, LiveRange(Instructions.size()));
for (unsigned I = 0; I < NumAllocas; ++I)
- if (!InterestingAllocas.test(I))
+ if (!MarkerAllocas.test(I))
LiveRanges[I] = getFullLiveRange();
calculateLocalLiveness();
diff --git a/llvm/test/Analysis/StackSafetyAnalysis/lifetime.ll b/llvm/test/Analysis/StackSafetyAnalysis/lifetime.ll
index 51bfa154e957a..e67c96a3becbd 100644
--- a/llvm/test/Analysis/StackSafetyAnalysis/lifetime.ll
+++ b/llvm/test/Analysis/StackSafetyAnalysis/lifetime.ll
@@ -438,23 +438,23 @@ entry:
call void @capture32(ptr %x)
call void @llvm.lifetime.end.p0(ptr %x)
; CHECK: call void @llvm.lifetime.end.p0(ptr %x)
-; CHECK-NEXT: Alive: <x>
+; CHECK-NEXT: Alive: <>
br i1 %d, label %bb2, label %bb3
bb2: ; preds = %entry
; CHECK: bb2:
-; CHECK-NEXT: Alive: <x>
+; CHECK-NEXT: Alive: <>
call void @llvm.lifetime.start.p0(ptr %y)
; CHECK: call void @llvm.lifetime.start.p0(ptr %y)
-; CHECK-NEXT: Alive: <x y>
+; CHECK-NEXT: Alive: <y>
call void @capture32(ptr %y)
ret void
bb3: ; preds = %entry
; CHECK: bb3:
-; CHECK-NEXT: Alive: <x>
+; CHECK-NEXT: Alive: <>
ret void
}
@@ -949,6 +949,52 @@ if.end:
ret void
}
+define void @end_only() {
+; CHECK-LABEL: define void @end_only()
+entry:
+ %x = alloca i8
+; CHECK: %x = alloca i8
+; CHECK-NEXT: Alive: <x>
+
+ call void @llvm.lifetime.end.p0(ptr %x)
+; CHECK: call void @llvm.lifetime.end.p0(ptr %x)
+; CHECK-NEXT: Alive: <>
+
+ ret void
+}
+
+define void @end_only_propagates() {
+; CHECK-LABEL: define void @end_only_propagates()
+entry:
+ %x = alloca i8
+ call void @llvm.lifetime.end.p0(ptr %x)
+
+ br label %next
+; CHECK: br label %next
+; CHECK-NEXT: Alive: <>
+
+next:
+; CHECK: next:
+; CHECK-NEXT: Alive: <>
+ ret void
+}
+
+define void @start_propagates() {
+; CHECK-LABEL: define void @start_propagates()
+entry:
+ %x = alloca i8
+ call void @llvm.lifetime.start.p0(ptr %x)
+
+ br label %next
+; CHECK: br label %next
+; CHECK-NEXT: Alive: <x>
+
+next:
+; CHECK: next:
+; CHECK-NEXT: Alive: <x>
+ ret void
+}
+
declare void @llvm.lifetime.start.p0(ptr captures(none))
declare void @llvm.lifetime.end.p0(ptr captures(none))
declare void @capture8(ptr)
More information about the llvm-commits
mailing list