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 @@ -1864,8 +1864,20 @@ // We are searching for the definition of the store's destination. // So, if that is the same definition as the load, then this is a // noop. Otherwise, fail. - if (LoadAccess != Current) + if (LoadAccess != Current) { + // This is a potentially clobbering store, but it writes the same + // value, so we can safely ignore it if alignment is as expected. + if (auto *CurrentDef = dyn_cast(Current)) + if (auto *CurrentStoreI = + dyn_cast(CurrentDef->getMemoryInst())) + // Check alignment to ensure load or store does not access at an + // offset. + if (CurrentStoreI->getOperand(0) == LoadI && + std::min(CurrentStoreI->getAlign(), LoadI->getAlign()) >= + DL.getTypeStoreSize(LoadI->getType())) + continue; return false; + } } return true; } diff --git a/llvm/test/Transforms/DeadStoreElimination/noop-stores.ll b/llvm/test/Transforms/DeadStoreElimination/noop-stores.ll --- a/llvm/test/Transforms/DeadStoreElimination/noop-stores.ll +++ b/llvm/test/Transforms/DeadStoreElimination/noop-stores.ll @@ -673,3 +673,65 @@ if.end: ret i8* %3 } + +define void @store_same_i32_to_mayalias_loc(i32* %q, i32* %p) { +; CHECK-LABEL: @store_same_i32_to_mayalias_loc( +; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[P:%.*]], align 4 +; CHECK-NEXT: store i32 [[V]], i32* [[Q:%.*]], align 4 +; CHECK-NEXT: ret void +; + %v = load i32, i32* %p, align 4 + store i32 %v, i32* %q, align 4 + store i32 %v, i32* %p, align 4 + ret void +} + +define void @store_same_i32_to_mayalias_loc_unalign(i32* %q, i32* %p) { +; CHECK-LABEL: @store_same_i32_to_mayalias_loc_unalign( +; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[P:%.*]], align 1 +; CHECK-NEXT: store i32 [[V]], i32* [[Q:%.*]], align 1 +; CHECK-NEXT: store i32 [[V]], i32* [[P]], align 1 +; CHECK-NEXT: ret void +; + %v = load i32, i32* %p, align 1 + store i32 %v, i32* %q, align 1 + store i32 %v, i32* %p, align 1 + ret void +} + +define void @store_same_i12_to_mayalias_loc(i12* %q, i12* %p) { +; CHECK-LABEL: @store_same_i12_to_mayalias_loc( +; CHECK-NEXT: [[V:%.*]] = load i12, i12* [[P:%.*]], align 2 +; CHECK-NEXT: store i12 [[V]], i12* [[Q:%.*]], align 2 +; CHECK-NEXT: ret void +; + %v = load i12, i12* %p, align 2 + store i12 %v, i12* %q, align 2 + store i12 %v, i12* %p, align 2 + ret void +} + +define void @store_same_ptr_to_mayalias_loc(i32** %q, i32** %p) { +; CHECK-LABEL: @store_same_ptr_to_mayalias_loc( +; CHECK-NEXT: [[V:%.*]] = load i32*, i32** [[P:%.*]], align 8 +; CHECK-NEXT: store i32* [[V]], i32** [[Q:%.*]], align 8 +; CHECK-NEXT: ret void +; + %v = load i32*, i32** %p, align 8 + store i32* %v, i32** %q, align 8 + store i32* %v, i32** %p, align 8 + ret void +} + +define void @store_same_i32_to_mayalias_loc_inconsistent_align(i32* %q, i32* %p) { +; CHECK-LABEL: @store_same_i32_to_mayalias_loc_inconsistent_align( +; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[P:%.*]], align 2 +; CHECK-NEXT: store i32 [[V]], i32* [[Q:%.*]], align 4 +; CHECK-NEXT: store i32 [[V]], i32* [[P]], align 4 +; CHECK-NEXT: ret void +; + %v = load i32, i32* %p, align 2 + store i32 %v, i32* %q, align 4 + store i32 %v, i32* %p, align 4 + ret void +} 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 @@ -612,12 +612,10 @@ ; CHECK-LABEL: @pr49927( ; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[P:%.*]], align 4 ; CHECK-NEXT: store i32 [[V]], i32* [[Q:%.*]], align 4 -; CHECK-NEXT: store i32 [[V]], i32* [[P]], align 4 ; CHECK-NEXT: ret void ; %v = load i32, i32* %p, align 4 store i32 %v, i32* %q, align 4 - ; FIXME: this store can be eliminated store i32 %v, i32* %p, align 4 ret void }