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 @@ -1941,6 +1941,32 @@ return false; } + + /// Eliminates writes to locations where the value that is being written + /// is already stored at the same location. + bool eliminateRedundantStoresOfExistingValues() { + bool MadeChange = false; + LLVM_DEBUG(dbgs() << "Trying to eliminate MemoryDefs that write the " + "already existing value\n"); + for (auto *Def : MemDefs) { + if (SkipStores.contains(Def) || MSSA.isLiveOnEntryDef(Def) || + !isRemovable(Def->getMemoryInst())) + continue; + auto *UpperDef = dyn_cast(Def->getDefiningAccess()); + if (!UpperDef || MSSA.isLiveOnEntryDef(UpperDef)) + continue; + auto *DefInst = Def->getMemoryInst(); + auto *UpperInst = UpperDef->getMemoryInst(); + auto MaybeUpperLoc = getLocForWriteEx(UpperInst); + if (!MaybeUpperLoc || !DefInst->isIdenticalTo(UpperInst) || + isReadClobber(*MaybeUpperLoc, DefInst)) + continue; + deleteDeadInstruction(DefInst); + NumRedundantStores++; + MadeChange = true; + } + return MadeChange; + } }; static bool eliminateDeadStores(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, @@ -2102,6 +2128,7 @@ } } + MadeChange |= State.eliminateRedundantStoresOfExistingValues(); if (EnablePartialOverwriteTracking) for (auto &KV : State.IOLs) MadeChange |= removePartiallyOverlappedStores(State.DL, KV.second, TLI); diff --git a/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll b/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll --- a/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll +++ b/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll @@ -7,7 +7,7 @@ declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) -; Test case for PR16520. The store in %if.then is dead, because the same value +; Test case for PR16520. The store in %if.then is redundant, because the same value ; has been stored earlier to the same location. define void @test1_pr16520(i1 %b, i8* nocapture %r) { ; CHECK-LABEL: @test1_pr16520( @@ -15,7 +15,6 @@ ; CHECK-NEXT: store i8 1, i8* [[R:%.*]], align 1 ; CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] ; CHECK: if.then: -; CHECK-NEXT: store i8 1, i8* [[R]], align 1 ; CHECK-NEXT: tail call void @fn_mayread_or_clobber() ; CHECK-NEXT: br label [[IF_END:%.*]] ; CHECK: if.else: @@ -42,8 +41,6 @@ } declare void @fn_mayread_or_clobber() - - declare void @fn_readonly() readonly define void @test2(i1 %b, i8* nocapture %r) { @@ -58,7 +55,6 @@ ; CHECK-NEXT: tail call void @fn_readonly() ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: -; CHECK-NEXT: store i8 1, i8* [[R]], align 1 ; CHECK-NEXT: ret void ; entry: @@ -78,6 +74,39 @@ ret void } +; Make sure volatile stores are not removed. +define void @test2_volatile(i1 %b, i8* nocapture %r) { +; CHECK-LABEL: @test2_volatile( +; CHECK-NEXT: entry: +; CHECK-NEXT: store volatile i8 1, i8* [[R:%.*]], align 1 +; CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: tail call void @fn_readonly() +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: tail call void @fn_readonly() +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: store volatile i8 1, i8* [[R]], align 1 +; CHECK-NEXT: ret void +; +entry: + store volatile i8 1, i8* %r, align 1 + br i1 %b, label %if.then, label %if.else + +if.then: ; preds = %entry + tail call void @fn_readonly() + br label %if.end + +if.else: ; preds = %entry + tail call void @fn_readonly() + br label %if.end + +if.end: ; preds = %if.else, %if.then + store volatile i8 1, i8* %r, align 1 + ret void +} + define void @test3(i1 %b, i8* nocapture %r) { ; CHECK-LABEL: @test3( ; CHECK-NEXT: entry: @@ -185,7 +214,6 @@ ; CHECK-NEXT: [[C1:%.*]] = call i1 @cond() ; CHECK-NEXT: br i1 [[C1]], label [[FOR_BODY:%.*]], label [[END:%.*]] ; CHECK: for.body: -; CHECK-NEXT: store i32 1, i32* [[P]], align 4 ; CHECK-NEXT: [[LV:%.*]] = load i32, i32* [[P]], align 4 ; CHECK-NEXT: br label [[FOR_HEADER]] ; CHECK: end: @@ -220,7 +248,6 @@ ; CHECK: bb2: ; CHECK-NEXT: ret void ; CHECK: bb3: -; CHECK-NEXT: store i32 0, i32* [[P]], align 4 ; CHECK-NEXT: ret void ; store i32 0, i32* %P @@ -272,7 +299,6 @@ ; CHECK-NEXT: call void @fn_mayread_or_clobber() ; CHECK-NEXT: ret void ; CHECK: bb3: -; CHECK-NEXT: store i32 0, i32* [[P]], align 4 ; CHECK-NEXT: ret void ; store i32 0, i32* %P