[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