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 @@ -1874,8 +1874,31 @@ // 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->getDefiningAccess(), + MemoryLocation::get(LoadI))); + continue; + } + } return false; + } } return true; } diff --git a/llvm/test/Transforms/DeadStoreElimination/noop-stores-scoped-noalias.ll b/llvm/test/Transforms/DeadStoreElimination/noop-stores-scoped-noalias.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/DeadStoreElimination/noop-stores-scoped-noalias.ll @@ -0,0 +1,30 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -scoped-noalias-aa -dse -S | FileCheck %s +define void @cross_noalias_store(i32 %v2, ptr %p, ptr %p2, i1 %c) { +; CHECK-LABEL: @cross_noalias_store( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P2:%.*]], align 4 +; CHECK-NEXT: store i32 [[V2:%.*]], ptr [[P2]], align 4, !alias.scope !0 +; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: store i32 [[V]], ptr [[P:%.*]], align 4, !noalias !0 +; CHECK-NEXT: store i32 [[V]], ptr [[P2]], align 4 +; CHECK-NEXT: br label [[ELSE]] +; CHECK: else: +; CHECK-NEXT: ret void +; +entry: + %v = load i32, ptr %p2 + store i32 %v2, ptr %p2, !alias.scope !0 + br i1 %c, label %if.then, label %else +if.then: + store i32 %v, ptr %p, !noalias !0 + store i32 %v, ptr %p2 + br label %else +else: + ret void +} + +!0 = !{!1} +!1 = !{!1, !2, !"scope"} +!2 = !{!2, !"domain"} 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 @@ -672,7 +672,6 @@ ; CHECK-LABEL: @store_same_i32_to_mayalias_loc( ; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4 ; CHECK-NEXT: store i32 [[V]], ptr [[Q:%.*]], align 4 -; CHECK-NEXT: store i32 [[V]], ptr [[P]], align 4 ; CHECK-NEXT: ret void ; %v = load i32, ptr %p, align 4 @@ -698,7 +697,6 @@ ; CHECK-LABEL: @store_same_i12_to_mayalias_loc( ; CHECK-NEXT: [[V:%.*]] = load i12, ptr [[P:%.*]], align 2 ; CHECK-NEXT: store i12 [[V]], ptr [[Q:%.*]], align 2 -; CHECK-NEXT: store i12 [[V]], ptr [[P]], align 2 ; CHECK-NEXT: ret void ; %v = load i12, ptr %p, align 2 @@ -724,7 +722,6 @@ ; CHECK-LABEL: @store_same_ptr_to_mayalias_loc( ; CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[P:%.*]], align 8 ; CHECK-NEXT: store ptr [[V]], ptr [[Q:%.*]], align 8 -; CHECK-NEXT: store ptr [[V]], ptr [[P]], align 8 ; CHECK-NEXT: ret void ; %v = load ptr, ptr %p, align 8 @@ -785,3 +782,34 @@ store i8 %v, ptr %q, align 1 ret void } + +define void @multiple_defs_between_noop_store_and_load(ptr %arg, ptr %arg1, i1 %arg2) { +; CHECK-LABEL: @multiple_defs_between_noop_store_and_load( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP:%.*]] = load i32, ptr [[ARG:%.*]], align 8 +; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARG1:%.*]], align 8 +; CHECK-NEXT: store i32 [[TMP3]], ptr [[ARG]], align 8 +; CHECK-NEXT: store i32 [[TMP]], ptr [[ARG1]], align 8 +; CHECK-NEXT: br i1 [[ARG2:%.*]], label [[BB5:%.*]], label [[BB6:%.*]] +; CHECK: bb5: +; CHECK-NEXT: store i32 [[TMP]], ptr [[ARG]], align 8 +; CHECK-NEXT: store i32 [[TMP3]], ptr [[ARG1]], align 8 +; CHECK-NEXT: ret void +; CHECK: bb6: +; CHECK-NEXT: ret void +; +bb: + %tmp = load i32, ptr %arg, align 8 + %tmp3 = load i32, ptr %arg1, align 8 + store i32 %tmp3, ptr %arg, align 8 + store i32 %tmp, ptr %arg1, align 8 + br i1 %arg2, label %bb5, label %bb6 + +bb5: + store i32 %tmp, ptr %arg, align 8 + store i32 %tmp3, ptr %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 @@ -594,7 +594,6 @@ ; CHECK-LABEL: @pr49927( ; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4 ; CHECK-NEXT: store i32 [[V]], ptr [[Q:%.*]], align 4 -; CHECK-NEXT: store i32 [[V]], ptr [[P]], align 4 ; CHECK-NEXT: ret void ; %v = load i32, ptr %p, align 4