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 @@ -2361,6 +2361,45 @@ return false; } + /// Eliminates writes to locations where the value that is being written + /// is already stored at the same location. + bool eliminateRedundantStoresOfExisitingValues() { + bool MadeChange = false; + LLVM_DEBUG(dbgs() << "Trying to eliminate MemoryDefs that write the " + "already exisiting value\n"); + for (MemoryDef *Def : reverse(MemDefs)) { + if (SkipStores.find(Def) != SkipStores.end() || + !isRemovable(Def->getMemoryInst())) + continue; + + Instruction *DefI = Def->getMemoryInst(); + Optional MaybeDefLoc = getLocForWriteEx(DefI); + if (!MaybeDefLoc) + continue; + + // Remove any uses of Def, that are MemoryDefs that write the same value + // to the same location as Def. + for (Use &U : make_early_inc_range(Def->uses())) { + MemoryAccess *UseAccess = cast(U.getUser()); + MemoryDef *UseDef = dyn_cast_or_null(UseAccess); + if (!UseDef) + continue; + Instruction *UseI = UseDef->getMemoryInst(); + + // Skip self-reads. + if (isReadClobber(*MaybeDefLoc, UseI)) + continue; + + if (UseI->isIdenticalTo(DefI)) { + deleteDeadInstruction(UseI); + NumRedundantStores++; + MadeChange = true; + } + } + } + return MadeChange; + } + /// Eliminate writes to objects that are not visible in the caller and are not /// accessed before returning from the function. bool eliminateDeadWritesAtEndOfFunction() { @@ -2630,6 +2669,8 @@ } } + MadeChange |= State.eliminateRedundantStoresOfExisitingValues(); + if (EnablePartialOverwriteTracking) for (auto &KV : State.IOLs) MadeChange |= removePartiallyOverlappedStores(State.DL, KV.second, TLI); diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/stores-of-existing-values.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/stores-of-existing-values.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/stores-of-existing-values.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/stores-of-existing-values.ll @@ -11,7 +11,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: @@ -54,7 +53,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: @@ -74,6 +72,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: @@ -181,7 +212,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: @@ -216,7 +246,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 @@ -268,7 +297,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