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(Arg); + if (!AI) + // lifetime of poison value. + return MemoryLocation::getBeforeOrAfter(Arg); + + std::optional 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..1a9296f042578 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); + Instruction *LifetimeStart = B.CreateLifetimeStart(Foo); Instruction *FooStore = B.CreateStore(B.getInt8(0), Foo); Instruction *BarStore = B.CreateStore(B.getInt8(0), Bar);