-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[MemoryLocation] Compute lifetime size from alloca size #151982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Split out from llvm#150248: Since llvm#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.
@llvm/pr-subscribers-llvm-transforms Author: Nikita Popov (nikic) ChangesSplit 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:
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);
|
@llvm/pr-subscribers-llvm-analysis Author: Nikita Popov (nikic) ChangesSplit 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:
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);
|
auto *AI = dyn_cast<AllocaInst>(Arg); | ||
if (!AI) | ||
// lifetime of poison value. | ||
return MemoryLocation::getBeforeOrAfter(Arg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be worth asserting here or does the verifier check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The verifier checks it (see #151148).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG
{B.getInt64(3), Foo}); | ||
Instruction *LifetimeStart = B.CreateCall( | ||
GetLifetimeIntrinsic(Intrinsic::lifetime_start), {B.getInt64(3), Foo}); | ||
B.CreateLifetimeEnd(Foo, B.getInt64(3)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The size argument is removed in https://github.com/llvm/llvm-project/pull/150248/files#diff-16948aeaf132f6b1a976b2d2f9cd58673b70ca216a46c4e846267813b16707e0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dropped it in this PR as well. I didn't realize the argument in the IRBuilder API was already optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks
auto *AI = dyn_cast<AllocaInst>(Arg); | ||
if (!AI) | ||
// lifetime of poison value. | ||
return MemoryLocation::getBeforeOrAfter(Arg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good
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.