diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp index 1ed52cce8c2086..2f9988bfe8a407 100644 --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -1875,8 +1875,23 @@ struct DSEState { // 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 = cast(Current)) + if (auto *CurrentStoreI = + dyn_cast_or_null(CurrentDef->getMemoryInst())) + // Check alignment to ensure load or store does not access at an + // offset. + if (CurrentStoreI->getValueOperand() == LoadI) { + TypeSize StoreSize = DL.getTypeStoreSize(LoadI->getType()); + if (!StoreSize.isScalable() && + std::min(CurrentStoreI->getAlign(), LoadI->getAlign()) >= + StoreSize) + continue; + } return false; + } } return true; } diff --git a/llvm/test/Transforms/DeadStoreElimination/noop-stores.ll b/llvm/test/Transforms/DeadStoreElimination/noop-stores.ll index 6eaa13a6c12044..075e49ac23d588 100644 --- a/llvm/test/Transforms/DeadStoreElimination/noop-stores.ll +++ b/llvm/test/Transforms/DeadStoreElimination/noop-stores.ll @@ -673,3 +673,118 @@ if.then: 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_i12_to_mayalias_loc_unalign(i12* %q, i12* %p) { +; CHECK-LABEL: @store_same_i12_to_mayalias_loc_unalign( +; CHECK-NEXT: [[V:%.*]] = load i12, i12* [[P:%.*]], align 1 +; CHECK-NEXT: store i12 [[V]], i12* [[Q:%.*]], align 1 +; CHECK-NEXT: store i12 [[V]], i12* [[P]], align 1 +; CHECK-NEXT: ret void +; + %v = load i12, i12* %p, align 1 + store i12 %v, i12* %q, align 1 + store i12 %v, i12* %p, align 1 + 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_scalable_to_mayalias_loc(* %q, * %p) { +; CHECK-LABEL: @store_same_scalable_to_mayalias_loc( +; CHECK-NEXT: [[V:%.*]] = load , * [[P:%.*]], align 4 +; CHECK-NEXT: store [[V]], * [[Q:%.*]], align 4 +; CHECK-NEXT: store [[V]], * [[P]], align 4 +; CHECK-NEXT: ret void +; + %v = load , * %p, align 4 + store %v, * %q, align 4 + store %v, * %p, align 4 + 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 +} + +define void @do_not_crash_on_liveonentrydef(i1 %c, i8* %p, i8* noalias %q) { +; CHECK-LABEL: @do_not_crash_on_liveonentrydef( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[JOIN:%.*]] +; CHECK: if: +; CHECK-NEXT: store i8 0, i8* [[Q:%.*]], align 1 +; CHECK-NEXT: br label [[JOIN]] +; CHECK: join: +; CHECK-NEXT: [[V:%.*]] = load i8, i8* [[Q]], align 1 +; CHECK-NEXT: store i8 0, i8* [[P:%.*]], align 1 +; CHECK-NEXT: store i8 [[V]], i8* [[Q]], align 1 +; CHECK-NEXT: ret void +; +entry: + br i1 %c, label %if, label %join + +if: + store i8 0, i8* %q, align 1 + br label %join + +join: + %v = load i8, i8* %q, align 1 + store i8 0, i8* %p, align 1 + store i8 %v, i8* %q, align 1 + ret void +} diff --git a/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll b/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll index e5630cca1aba50..06a5f8690c26a0 100644 --- a/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll +++ b/llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll @@ -612,12 +612,10 @@ define void @pr49927(i32* %q, i32* %p) { ; 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 }