Index: llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp =================================================================== --- llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -2383,6 +2383,40 @@ return false; } + /// Eliminates writes to variables where the value that is being written + /// is already stored in the variable + bool eliminateDeadStoresOfExisitingValues() { + bool MadeChange = false; + LLVM_DEBUG(dbgs() << "Trying to eliminate MemoryDefs that write the " + "already exisiting value\n"); + for (int I = MemDefs.size() - 1; I >= 0; I--) { + MemoryDef *Def = MemDefs[I]; + if (SkipStores.find(Def) != SkipStores.end() || + !isRemovable(Def->getMemoryInst())) + continue; + MemoryAccess *DefAccess = dyn_cast(Def); + if (!DefAccess || isa(DefAccess)) + continue; + Instruction *DefInst = cast(DefAccess)->getMemoryInst(); + if (!DefInst) + continue; + for (auto UI = DefAccess->use_begin(), IE = DefAccess->use_end(); + UI != IE;) { + MemoryAccess *UseAccess = cast((UI++)->getUser()); + if (MemoryDef *UseDef = dyn_cast_or_null(UseAccess)) { + Instruction *UseInst = UseDef->getMemoryInst(); + if (!UseInst) + continue; + if (UseInst->isIdenticalTo(DefInst)) { + deleteDeadInstruction(UseInst); + 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() { @@ -2653,6 +2687,8 @@ } } + MadeChange |= State.eliminateDeadStoresOfExisitingValues(); + if (EnablePartialOverwriteTracking) for (auto &KV : State.IOLs) MadeChange |= removePartiallyOverlappedStores(State.DL, KV.second, TLI); Index: llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-loops.ll =================================================================== --- llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-loops.ll +++ llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-loops.ll @@ -183,7 +183,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: Index: llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-memoryphis.ll =================================================================== --- llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-memoryphis.ll +++ llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-memoryphis.ll @@ -14,7 +14,6 @@ ; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P]], align 4 ; CHECK-NEXT: br label [[BB3]] ; CHECK: bb3: -; CHECK-NEXT: store i32 0, i32* [[P]], align 4 ; CHECK-NEXT: ret void ; store i32 0, i32* %P @@ -177,11 +176,11 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[EXIT:%.*]] ; CHECK: if.then: -; CHECK-NEXT: tail call void @fn2_test11() #0 +; CHECK-NEXT: tail call void @fn2_test11() [[ATTR0:#.*]] ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: store i8* null, i8** [[PTR_1:%.*]], align 8 -; CHECK-NEXT: tail call void @fn2_test11() #0 +; CHECK-NEXT: tail call void @fn2_test11() [[ATTR0]] ; CHECK-NEXT: ret void ; entry: Index: llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-simple.ll =================================================================== --- llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-simple.ll +++ llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-simple.ll @@ -33,7 +33,6 @@ ; CHECK: bb1: ; CHECK-NEXT: br label [[BB3:%.*]] ; CHECK: bb2: -; CHECK-NEXT: store i32 0, i32* [[P]], align 4 ; CHECK-NEXT: br label [[BB3]] ; CHECK: bb3: ; CHECK-NEXT: ret void @@ -99,7 +98,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 @@ -153,7 +151,6 @@ ; CHECK-NEXT: store i32 0, i32* [[P:%.*]], align 4 ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: -; CHECK-NEXT: store i32 0, i32* [[P]], align 4 ; CHECK-NEXT: br label [[BB3:%.*]] ; CHECK: bb2: ; CHECK-NEXT: ret void Index: llvm/test/Transforms/DeadStoreElimination/MSSA/pr16520.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/DeadStoreElimination/MSSA/pr16520.ll @@ -0,0 +1,37 @@ +; RUN: opt -basic-aa -dse -S < %s | FileCheck %s +; PR16520 + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @_Z1fbRb(i1 zeroext %b, i8* nocapture %r) { +; CHECK-LABEL: @_Z1fbRb( +; CHECK-NEXT: entry: +; CHECK-NEXT: store i8 1, i8* %r, align 1 +; CHECK-NEXT: br i1 %b, label %if.then, label %if.else +; CHECK: if.then: ; preds = %entry +; CHECK-NEXT: tail call void @_Z1gv() +; CHECK-NEXT: br label %if.end +; CHECK: if.else: ; preds = %entry +; CHECK-NEXT: tail call void @_Z1hv() +; CHECK-NEXT: br label %if.end +; CHECK: if.end: ; preds = %if.else, %if.then +; CHECK-NEXT: ret void +; CHECK: declare void @_Z1gv() +; CHECK: declare void @_Z1hv() +; +entry: + store i8 1, i8* %r, align 1 + br i1 %b, label %if.then, label %if.else +if.then: ; preds = %entry + store i8 1, i8* %r, align 1 + tail call void @_Z1gv() + br label %if.end +if.else: ; preds = %entry + tail call void @_Z1hv() + br label %if.end +if.end: ; preds = %if.else, %if.then + ret void +} +declare void @_Z1gv() +declare void @_Z1hv() Index: llvm/test/Transforms/DeadStoreElimination/MSSA/simple.ll =================================================================== --- llvm/test/Transforms/DeadStoreElimination/MSSA/simple.ll +++ llvm/test/Transforms/DeadStoreElimination/MSSA/simple.ll @@ -312,7 +312,7 @@ ; CHECK-NEXT: store i8 97, i8* [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [2 x i8], [2 x i8]* [[X]], i64 0, i64 1 ; CHECK-NEXT: store i8 0, i8* [[ARRAYIDX1]], align 1 -; CHECK-NEXT: [[CALL:%.*]] = call i8* @strdup(i8* [[ARRAYIDX]]) [[ATTR3:#.*]] +; CHECK-NEXT: [[CALL:%.*]] = call i8* @strdup(i8* [[ARRAYIDX]]) [[ATTR5:#.*]] ; CHECK-NEXT: ret i8* [[CALL]] ; %x = alloca [2 x i8], align 1 @@ -350,7 +350,7 @@ ; CHECK-NEXT: [[P_4:%.*]] = getelementptr i8, i8* [[P:%.*]], i64 4 ; CHECK-NEXT: [[TMP:%.*]] = load i8, i8* [[P_4]], align 1 ; CHECK-NEXT: store i8 0, i8* [[P_4]], align 1 -; CHECK-NEXT: [[Q:%.*]] = call i8* @strdup(i8* [[P]]) [[ATTR6:#.*]] +; CHECK-NEXT: [[Q:%.*]] = call i8* @strdup(i8* [[P]]) [[ATTR8:#.*]] ; CHECK-NEXT: store i8 [[TMP]], i8* [[P_4]], align 1 ; CHECK-NEXT: ret i8* [[Q]] ; @@ -509,7 +509,6 @@ define void @test36(i8* %P, i8* %Q) { ; CHECK-LABEL: @test36( ; CHECK-NEXT: tail call void @llvm.memmove.p0i8.p0i8.i64(i8* [[P:%.*]], i8* [[Q:%.*]], i64 12, i1 false) -; CHECK-NEXT: tail call void @llvm.memmove.p0i8.p0i8.i64(i8* [[P]], i8* [[Q]], i64 12, i1 false) ; CHECK-NEXT: ret void ; @@ -521,7 +520,6 @@ define void @test36_atomic(i8* %P, i8* %Q) { ; CHECK-LABEL: @test36_atomic( ; CHECK-NEXT: tail call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 [[P:%.*]], i8* align 1 [[Q:%.*]], i64 12, i32 1) -; CHECK-NEXT: tail call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 [[P]], i8* align 1 [[Q]], i64 12, i32 1) ; CHECK-NEXT: ret void ;