[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