diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -1209,17 +1209,10 @@ /// loop. In particular, this guarantees that it only references a single /// MemoryLocation during execution of the containing function. bool isGuaranteedLoopInvariant(const Value *Ptr) { - auto IsGuaranteedLoopInvariantBase = [this](const Value *Ptr) { + auto IsGuaranteedLoopInvariantBase = [](const Value *Ptr) { Ptr = Ptr->stripPointerCasts(); - if (auto *I = dyn_cast(Ptr)) { - if (isa(Ptr)) - return true; - - if (isAllocLikeFn(I, &TLI)) - return true; - - return false; - } + if (auto *I = dyn_cast(Ptr)) + return I->getParent()->isEntryBlock(); return true; }; diff --git a/llvm/test/Transforms/DeadStoreElimination/store-after-loop.ll b/llvm/test/Transforms/DeadStoreElimination/store-after-loop.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/DeadStoreElimination/store-after-loop.ll @@ -0,0 +1,52 @@ +; RUN: opt -passes=dse -S %s | FileCheck %s + +target datalayout = "E-m:e-p:32:32-i64:32-f64:32:64-a:0:32-n32-S32" + +%struct.ilist = type { i32, %struct.ilist* } + +; There is no dead store in this test. Make sure no store is deleted by DSE. + +; CHECK-LABEL: @test( +; CHECK: loop1: +; CHECK: store +; CHECK: store +; CHECK: br +; CHECK: loop1.end: +; CHECK: store +; CHECK: br +; CHECK: loop2: +; CHECK: load +; CHECK: ret + +define %struct.ilist* @test() { + br label %loop1 + +loop1: + %iv = phi i32 [ 0, %0 ], [ %iv.next, %loop1 ] + %list.next = phi %struct.ilist* [ null, %0 ], [ %list.new.ilist.ptr, %loop1 ] + %list.new.i8.ptr = tail call align 8 dereferenceable_or_null(8) i8* @malloc(i32 8) + %list.new.ilist.ptr = bitcast i8* %list.new.i8.ptr to %struct.ilist* + %gep.new.value = getelementptr inbounds %struct.ilist, %struct.ilist* %list.new.ilist.ptr, i32 0, i32 0 + store i32 42, i32* %gep.new.value, align 8 + %gep.new.next = getelementptr inbounds %struct.ilist, %struct.ilist* %list.new.ilist.ptr, i32 0, i32 1 + store %struct.ilist* %list.next, %struct.ilist** %gep.new.next, align 4 + %iv.next = add nuw nsw i32 %iv, 1 + %cond = icmp eq i32 %iv.next, 10 + br i1 %cond, label %loop1.end, label %loop1 + +loop1.end: + %list.last.ilist.ptr = bitcast i8* %list.new.i8.ptr to %struct.ilist* + %gep.list.last.next = getelementptr inbounds %struct.ilist, %struct.ilist* %list.last.ilist.ptr, i32 0, i32 1 + store %struct.ilist* null, %struct.ilist** %gep.list.last.next, align 4 + br label %loop2 + +loop2: + %gep.list.next.next = getelementptr inbounds %struct.ilist, %struct.ilist* %list.next, i32 0, i32 1 + %loaded_ptr = load %struct.ilist*, %struct.ilist** %gep.list.next.next, align 4 + ret %struct.ilist* %loaded_ptr ; use loaded pointer +} + +; Function Attrs: inaccessiblememonly nounwind +declare noalias noundef align 8 i8* @malloc(i32 noundef) local_unnamed_addr #0 + +attributes #0 = { inaccessiblememonly nounwind} \ No newline at end of file