diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp index cb4d482a634d..d05f57f0d029 100644 --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -152,12 +152,27 @@ getLocForWrite(Instruction *Inst, AliasAnalysis &AA) { /// isRemovable - If the value of this instruction and the memory it writes to /// is unused, may we delete this instruction? static bool isRemovable(Instruction *I) { - assert(hasMemoryWrite(I)); - if (IntrinsicInst *II = dyn_cast(I)) - return II->getIntrinsicID() != Intrinsic::lifetime_end; + // Don't remove volatile stores. if (StoreInst *SI = dyn_cast(I)) return !SI->isVolatile(); - return true; + + IntrinsicInst *II = cast(I); + switch (II->getIntrinsicID()) { + default: assert(0 && "doesn't pass 'hasMemoryWrite' predicate"); + case Intrinsic::lifetime_end: + // Never remove dead lifetime_end's, e.g. because it is followed by a + // free. + return false; + case Intrinsic::init_trampoline: + // Always safe to remove init_trampoline. + return true; + + case Intrinsic::memset: + case Intrinsic::memmove: + case Intrinsic::memcpy: + // Don't remove volatile memory intrinsics. + return !cast(II)->isVolatile(); + } } /// getPointerOperand - Return the pointer that is being written to. diff --git a/llvm/test/Transforms/DeadStoreElimination/simple.ll b/llvm/test/Transforms/DeadStoreElimination/simple.ll index 0c05b1535716..203cf37193b6 100644 --- a/llvm/test/Transforms/DeadStoreElimination/simple.ll +++ b/llvm/test/Transforms/DeadStoreElimination/simple.ll @@ -1,6 +1,12 @@ ; RUN: opt < %s -basicaa -dse -S | FileCheck %s target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind +declare void @llvm.memset.i64(i8*, i8, i64, i32) +declare void @llvm.memcpy.i64(i8*, i8*, i64, i32) +declare i8* @llvm.init.trampoline(i8*, i8*, i8*) + define void @test1(i32* %Q, i32* %P) { %DEAD = load i32* %Q store i32 %DEAD, i32* %P @@ -55,9 +61,6 @@ define void @test5(i32* %Q) { ; CHECK-NEXT: ret void } -declare void @llvm.memset.i64(i8*, i8, i64, i32) -declare void @llvm.memcpy.i64(i8*, i8*, i64, i32) - ; Should delete store of 10 even though memset is a may-store to P (P and Q may ; alias). define void @test6(i32 *%p, i8 *%q) { @@ -116,7 +119,6 @@ define double @test10(i8* %X) { ; DSE should delete the dead trampoline. -declare i8* @llvm.init.trampoline(i8*, i8*, i8*) declare void @test11f() define void @test11() { ; CHECK: @test11 @@ -210,3 +212,13 @@ define void @test17(i8* %P, i8* %Q) nounwind ssp { ; CHECK-NEXT: ret } +; Should not delete the volatile memset. +define void @test17v(i8* %P, i8* %Q) nounwind ssp { + tail call void @llvm.memset.p0i8.i64(i8* %P, i8 42, i64 8, i32 1, i1 true) + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + ret void +; CHECK: @test17v +; CHECK-NEXT: call void @llvm.memset +; CHECK-NEXT: call void @llvm.memcpy +; CHECK-NEXT: ret +}