[llvm] f079ba7 - [DSE] Eliminate noop store even through has clobbering between LoadI and StoreI
via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 29 09:44:13 PDT 2022
Author: luxufan
Date: 2022-09-29T00:51:56Z
New Revision: f079ba76cf0fe0c105f1ce05636342bc2dbe57b4
URL: https://github.com/llvm/llvm-project/commit/f079ba76cf0fe0c105f1ce05636342bc2dbe57b4
DIFF: https://github.com/llvm/llvm-project/commit/f079ba76cf0fe0c105f1ce05636342bc2dbe57b4.diff
LOG: [DSE] Eliminate noop store even through has clobbering between LoadI and StoreI
For noop store of the form of LoadI and StoreI,
An invariant should be kept is that the memory state of the related
MemoryLoc before LoadI is the same as before StoreI.
For this example:
```
define void @pr49927(i32* %q, i32* %p) {
%v = load i32, i32* %p, align 4
store i32 %v, i32* %q, align 4
store i32 %v, i32* %p, align 4
ret void
}
```
Here the definition of the store's destination is different with the
definition of the load's destination, which it seems that the
invariant mentioned above is broken. But the definition of the
store's destination would write a value that is LoadI, actually, the
invariant is still kept. So we can safely ignore it.
Fixes https://github.com/llvm/llvm-project/issues/49271
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D132657
Added:
Modified:
llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
llvm/test/Transforms/DeadStoreElimination/noop-stores.ll
llvm/test/Transforms/DeadStoreElimination/stores-of-existing-values.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 1ed52cce8c208..2f9988bfe8a40 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<MemoryDef>(Current))
+ if (auto *CurrentStoreI =
+ dyn_cast_or_null<StoreInst>(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 6eaa13a6c1204..075e49ac23d58 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(<vscale x 4 x i32>* %q, <vscale x 4 x i32>* %p) {
+; CHECK-LABEL: @store_same_scalable_to_mayalias_loc(
+; CHECK-NEXT: [[V:%.*]] = load <vscale x 4 x i32>, <vscale x 4 x i32>* [[P:%.*]], align 4
+; CHECK-NEXT: store <vscale x 4 x i32> [[V]], <vscale x 4 x i32>* [[Q:%.*]], align 4
+; CHECK-NEXT: store <vscale x 4 x i32> [[V]], <vscale x 4 x i32>* [[P]], align 4
+; CHECK-NEXT: ret void
+;
+ %v = load <vscale x 4 x i32>, <vscale x 4 x i32>* %p, align 4
+ store <vscale x 4 x i32> %v, <vscale x 4 x i32>* %q, align 4
+ store <vscale x 4 x i32> %v, <vscale x 4 x i32>* %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 e5630cca1aba5..06a5f8690c26a 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
}
More information about the llvm-commits
mailing list