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 @@ -1875,8 +1875,30 @@ // 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) { + 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) { + // This is a potentially clobbering store, but it writes the + // same value, so we can safely ignore it if alignment is as + // expected. + + TypeSize StoreSize = DL.getTypeStoreSize(LoadI->getType()); + // Check alignment to ensure load or store does not access at + // an offset. + if (!StoreSize.isScalable() && + std::min(CurrentStoreI->getAlign(), LoadI->getAlign()) >= + StoreSize) { + ToCheck.insert(MSSA.getWalker()->getClobberingMemoryAccess( + CurrentDef)); + 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,150 @@ 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 +} + + +define void @multiple_defs_between_noop_store_and_load(i32* %arg, i32* %arg1, i1 %arg2) { +; CHECK-LABEL: @multiple_defs_between_noop_store_and_load( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[ARG:%.*]], align 8 +; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[ARG1:%.*]], align 8 +; CHECK-NEXT: store i32 [[TMP3]], i32* [[ARG]], align 8 +; CHECK-NEXT: store i32 [[TMP]], i32* [[ARG1]], align 8 +; CHECK-NEXT: br i1 [[ARG2:%.*]], label [[BB5:%.*]], label [[BB6:%.*]] +; CHECK: bb5: +; CHECK-NEXT: store i32 [[TMP]], i32* [[ARG]], align 8 +; CHECK-NEXT: store i32 [[TMP3]], i32* [[ARG1]], align 8 +; CHECK-NEXT: ret void +; CHECK: bb6: +; CHECK-NEXT: ret void +; +bb: + %tmp = load i32, i32* %arg, align 8 + %tmp3 = load i32, i32* %arg1, align 8 + store i32 %tmp3, i32* %arg, align 8 + store i32 %tmp, i32* %arg1, align 8 + br i1 %arg2, label %bb5, label %bb6 + +bb5: + store i32 %tmp, i32* %arg, align 8 ; this store is incorrectly removed + store i32 %tmp3, i32* %arg1, align 8 + ret void + +bb6: + 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 }