[llvm] [MemoryLocation] Compute lifetime size from alloca size (PR #151982)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 4 07:57:55 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Nikita Popov (nikic)
<details>
<summary>Changes</summary>
Split out from #<!-- -->150248:
Since #<!-- -->150944 the size passed to lifetime.start/end is considered meaningless. The lifetime always applies to the whole alloca.
This adjusts MemoryLocation to determine the MemoryLocation size from the alloca size, instead of using the argument.
---
Full diff: https://github.com/llvm/llvm-project/pull/151982.diff
3 Files Affected:
- (modified) llvm/lib/Analysis/MemoryLocation.cpp (+15-1)
- (modified) llvm/test/Transforms/DeadStoreElimination/lifetime.ll (-106)
- (modified) llvm/unittests/Analysis/MemorySSATest.cpp (+15-20)
``````````diff
diff --git a/llvm/lib/Analysis/MemoryLocation.cpp b/llvm/lib/Analysis/MemoryLocation.cpp
index c8daab7abde18..28a264093af23 100644
--- a/llvm/lib/Analysis/MemoryLocation.cpp
+++ b/llvm/lib/Analysis/MemoryLocation.cpp
@@ -190,7 +190,21 @@ MemoryLocation MemoryLocation::getForArgument(const CallBase *Call,
return MemoryLocation::getAfter(Arg, AATags);
case Intrinsic::lifetime_start:
- case Intrinsic::lifetime_end:
+ case Intrinsic::lifetime_end: {
+ assert(ArgIdx == 1 && "Invalid argument index");
+ auto *AI = dyn_cast<AllocaInst>(Arg);
+ if (!AI)
+ // lifetime of poison value.
+ return MemoryLocation::getBeforeOrAfter(Arg);
+
+ std::optional<TypeSize> AllocSize =
+ AI->getAllocationSize(II->getDataLayout());
+ return MemoryLocation(Arg,
+ AllocSize ? LocationSize::precise(*AllocSize)
+ : LocationSize::afterPointer(),
+ AATags);
+ }
+
case Intrinsic::invariant_start:
assert(ArgIdx == 1 && "Invalid argument index");
return MemoryLocation(
diff --git a/llvm/test/Transforms/DeadStoreElimination/lifetime.ll b/llvm/test/Transforms/DeadStoreElimination/lifetime.ll
index 19e7b0d1eacd9..f2a372eafb0b7 100644
--- a/llvm/test/Transforms/DeadStoreElimination/lifetime.ll
+++ b/llvm/test/Transforms/DeadStoreElimination/lifetime.ll
@@ -37,110 +37,4 @@ define void @test2(ptr %P) {
ret void
}
-; lifetime.end only marks the first two bytes of %A as dead. Make sure
-; `store i8 20, ptr %A.2 is not removed.
-define void @test3_lifetime_end_partial() {
-; CHECK-LABEL: @test3_lifetime_end_partial(
-; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
-; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 2, ptr [[A]])
-; CHECK-NEXT: [[A_1:%.*]] = getelementptr i8, ptr [[A]], i64 1
-; CHECK-NEXT: [[A_2:%.*]] = getelementptr i8, ptr [[A]], i64 2
-; CHECK-NEXT: store i8 20, ptr [[A_2]], align 1
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 2, ptr [[A]])
-; CHECK-NEXT: call void @use(ptr [[A_1]])
-; CHECK-NEXT: ret void
-;
- %A = alloca i32
-
- call void @llvm.lifetime.start.p0(i64 2, ptr %A)
- %A.1 = getelementptr i8, ptr %A, i64 1
- %A.2 = getelementptr i8, ptr %A, i64 2
-
- store i8 0, ptr %A
- store i8 10, ptr %A.1
- store i8 20, ptr %A.2
-
- call void @llvm.lifetime.end.p0(i64 2, ptr %A)
- call void @use(ptr %A.1)
- ret void
-}
-
-; lifetime.end only marks the first two bytes of %A as dead. Make sure
-; `store i8 20, ptr %A.2 is not removed.
-define void @test4_lifetime_end_partial_loop() {
-; CHECK-LABEL: @test4_lifetime_end_partial_loop(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
-; CHECK-NEXT: br label [[LOOP:%.*]]
-; CHECK: loop:
-; CHECK-NEXT: [[IV:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
-; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 2, ptr [[A]])
-; CHECK-NEXT: [[A_1:%.*]] = getelementptr i8, ptr [[A]], i64 1
-; CHECK-NEXT: [[A_2:%.*]] = getelementptr i8, ptr [[A]], i64 2
-; CHECK-NEXT: call void @use(ptr [[A_1]])
-; CHECK-NEXT: store i8 20, ptr [[A_2]], align 1
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 2, ptr [[A]])
-; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 10
-; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i8 [[IV_NEXT]], 10
-; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[LOOP]]
-; CHECK: exit:
-; CHECK-NEXT: ret void
-;
-entry:
- %A = alloca i32
-
- br label %loop
-
-loop:
- %iv = phi i8 [ 0, %entry ], [ %iv.next, %loop ]
- call void @llvm.lifetime.start.p0(i64 2, ptr %A)
- %A.1 = getelementptr i8, ptr %A, i64 1
- %A.2 = getelementptr i8, ptr %A, i64 2
-
- call void @use(ptr %A.1)
-
- store i8 20, ptr %A.2
- store i8 10, ptr %A.1
- store i8 0, ptr %A
- call void @llvm.lifetime.end.p0(i64 2, ptr %A)
-
- %iv.next = add i8 %iv, 10
- %exitcond = icmp eq i8 %iv.next, 10
- br i1 %exitcond, label %exit, label %loop
-
-exit:
- ret void
-}
-
-; lifetime.end only marks the first two bytes of %A as dead. Make sure
-; `store i8 20, ptr %A.2 is not removed.
-define void @test5_lifetime_end_partial() {
-; CHECK-LABEL: @test5_lifetime_end_partial(
-; CHECK-NEXT: [[A:%.*]] = alloca [4 x i8], align 1
-; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 2, ptr [[A]])
-; CHECK-NEXT: [[A_1:%.*]] = getelementptr i8, ptr [[A]], i64 1
-; CHECK-NEXT: [[A_2:%.*]] = getelementptr i8, ptr [[A]], i64 2
-; CHECK-NEXT: store i8 20, ptr [[A_2]], align 1
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 2, ptr [[A]])
-; CHECK-NEXT: call void @use(ptr [[A_1]])
-; CHECK-NEXT: ret void
-;
-
- %A = alloca [4 x i8]
- call void @llvm.lifetime.start.p0(i64 2, ptr %A)
- %A.1 = getelementptr i8, ptr %A, i64 1
- %A.2 = getelementptr i8, ptr %A, i64 2
-
- store i8 0, ptr %A
- store i8 10, ptr %A.1
- store i8 20, ptr %A.2
-
- call void @llvm.lifetime.end.p0(i64 2, ptr %A)
-
- call void @use(ptr %A.1)
- store i8 30, ptr %A.1
- store i8 40, ptr %A.2
- ret void
-}
-
declare void @use(ptr) readonly
diff --git a/llvm/unittests/Analysis/MemorySSATest.cpp b/llvm/unittests/Analysis/MemorySSATest.cpp
index a6f002b63dff1..faf0519e7aff5 100644
--- a/llvm/unittests/Analysis/MemorySSATest.cpp
+++ b/llvm/unittests/Analysis/MemorySSATest.cpp
@@ -1086,16 +1086,17 @@ TEST_F(MemorySSATest, TestStoreMayAlias) {
TEST_F(MemorySSATest, LifetimeMarkersAreClobbers) {
// Example code:
- // define void @a(i8* %foo) {
- // %bar = getelementptr i8, i8* %foo, i64 1
- // %baz = getelementptr i8, i8* %foo, i64 2
- // store i8 0, i8* %foo
- // store i8 0, i8* %bar
- // call void @llvm.lifetime.end.p0i8(i64 3, i8* %foo)
- // call void @llvm.lifetime.start.p0i8(i64 3, i8* %foo)
- // store i8 0, i8* %foo
- // store i8 0, i8* %bar
- // call void @llvm.memset.p0i8(i8* %baz, i8 0, i64 1)
+ // define void @a() {
+ // %foo = alloca i32
+ // %bar = getelementptr i8, ptr %foo, i64 1
+ // %baz = getelementptr i8, ptr %foo, i64 2
+ // store i8 0, ptr %foo
+ // store i8 0, ptr %bar
+ // call void @llvm.lifetime.end.p0(i64 3, ptr %foo)
+ // call void @llvm.lifetime.start.p0(i64 3, ptr %foo)
+ // store i8 0, ptr %foo
+ // store i8 0, ptr %bar
+ // call void @llvm.memset.p0i8(ptr %baz, i8 0, i64 1)
// ret void
// }
//
@@ -1104,14 +1105,14 @@ TEST_F(MemorySSATest, LifetimeMarkersAreClobbers) {
// it.
IRBuilder<> B(C);
- F = Function::Create(FunctionType::get(B.getVoidTy(), {B.getPtrTy()}, false),
+ F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
GlobalValue::ExternalLinkage, "F", &M);
// Make blocks
BasicBlock *Entry = BasicBlock::Create(C, "entry", F);
B.SetInsertPoint(Entry);
- Value *Foo = &*F->arg_begin();
+ Value *Foo = B.CreateAlloca(B.getInt32Ty());
Value *Bar = B.CreatePtrAdd(Foo, B.getInt64(1), "bar");
Value *Baz = B.CreatePtrAdd(Foo, B.getInt64(2), "baz");
@@ -1119,14 +1120,8 @@ TEST_F(MemorySSATest, LifetimeMarkersAreClobbers) {
B.CreateStore(B.getInt8(0), Foo);
B.CreateStore(B.getInt8(0), Bar);
- auto GetLifetimeIntrinsic = [&](Intrinsic::ID ID) {
- return Intrinsic::getOrInsertDeclaration(&M, ID, {Foo->getType()});
- };
-
- B.CreateCall(GetLifetimeIntrinsic(Intrinsic::lifetime_end),
- {B.getInt64(3), Foo});
- Instruction *LifetimeStart = B.CreateCall(
- GetLifetimeIntrinsic(Intrinsic::lifetime_start), {B.getInt64(3), Foo});
+ B.CreateLifetimeEnd(Foo, B.getInt64(3));
+ Instruction *LifetimeStart = B.CreateLifetimeStart(Foo, B.getInt64(3));
Instruction *FooStore = B.CreateStore(B.getInt8(0), Foo);
Instruction *BarStore = B.CreateStore(B.getInt8(0), Bar);
``````````
</details>
https://github.com/llvm/llvm-project/pull/151982
More information about the llvm-commits
mailing list