[llvm] 8d9b9c0 - [DSE] Handle memcpy/memset with equal non-const sizes.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 10 02:14:40 PST 2021


Author: Florian Hahn
Date: 2021-03-10T10:13:58Z
New Revision: 8d9b9c0edcebb2ce3723e581be40a9a26300f697

URL: https://github.com/llvm/llvm-project/commit/8d9b9c0edcebb2ce3723e581be40a9a26300f697
DIFF: https://github.com/llvm/llvm-project/commit/8d9b9c0edcebb2ce3723e581be40a9a26300f697.diff

LOG: [DSE] Handle memcpy/memset with equal non-const sizes.

Currently DSE misses cases where the size is a non-const IR value, even
if they match. For example, this means that llvm.memcpy/llvm.memset
calls are not eliminated, even if they write the same number of bytes.

This patch extends isOverwite to try to get IR values for the number of
bytes written from the analyzed instructions. If the values match,
alias checks are performed and the result is returned.

At the moment this only covers llvm.memcpy/llvm.memset. In the future,
we may enable MemoryLocation to also track variable sizes, but this
simple approach should allow us to cover the important cases in DSE.

Reviewed By: asbirlea

Differential Revision: https://reviews.llvm.org/D98284

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
    llvm/test/Transforms/DeadStoreElimination/memory-intrinsics-sizes.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 64cff4a2599c..61cc4e3b06a3 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -371,6 +371,25 @@ isOverwrite(const Instruction *LaterI, const Instruction *EarlierI,
   // FIXME: Vet that this works for size upper-bounds. Seems unlikely that we'll
   // get imprecise values here, though (except for unknown sizes).
   if (!Later.Size.isPrecise() || !Earlier.Size.isPrecise()) {
+    // In case no constant size is known, try to an IR values for the number
+    // of bytes written and check if they match.
+    auto GetSizeFromInstr = [](const Instruction *I) -> Value * {
+      if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
+        switch (II->getIntrinsicID()) {
+        default:
+          return nullptr;
+        case Intrinsic::memcpy:
+        case Intrinsic::memset:
+          return II->getArgOperand(2);
+        }
+      }
+      return nullptr;
+    };
+    Value *LaterV = GetSizeFromInstr(LaterI);
+    Value *EarlierV = GetSizeFromInstr(EarlierI);
+    if (LaterV && LaterV == EarlierV && AA.isMustAlias(Earlier, Later))
+      return OW_Complete;
+
     // Masked stores have imprecise locations, but we can reason about them
     // to some extent.
     return isMaskedStoreOverwrite(LaterI, EarlierI, AA);

diff  --git a/llvm/test/Transforms/DeadStoreElimination/memory-intrinsics-sizes.ll b/llvm/test/Transforms/DeadStoreElimination/memory-intrinsics-sizes.ll
index 261e029ecff9..412ae6569154 100644
--- a/llvm/test/Transforms/DeadStoreElimination/memory-intrinsics-sizes.ll
+++ b/llvm/test/Transforms/DeadStoreElimination/memory-intrinsics-sizes.ll
@@ -4,7 +4,6 @@
 define void @memset_equal_size_values(i8* %ptr, i64 %len) {
 ; CHECK-LABEL: @memset_equal_size_values(
 ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 1 [[PTR:%.*]], i8 0, i64 [[LEN:%.*]], i1 false)
-; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 1 [[PTR]], i8 0, i64 [[LEN]], i1 false)
 ; CHECK-NEXT:    ret void
 ;
   call void @llvm.memset.p0i8.i64(i8* align 1 %ptr, i8 0, i64 %len, i1 false)
@@ -45,10 +44,35 @@ define void @memset_
diff erent_size_values_3(i8* %ptr, i64 %len) {
   ret void
 }
 
+define void @memset_and_store_1(i8* %ptr, i64 %len) {
+; CHECK-LABEL: @memset_and_store_1(
+; CHECK-NEXT:    [[BC:%.*]] = bitcast i8* [[PTR:%.*]] to i64*
+; CHECK-NEXT:    store i64 123, i64* [[BC]], align 4
+; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 1 [[PTR]], i8 0, i64 [[LEN:%.*]], i1 false)
+; CHECK-NEXT:    ret void
+;
+  %bc = bitcast i8* %ptr to i64*
+  store i64 123, i64* %bc
+  call void @llvm.memset.p0i8.i64(i8* align 1 %ptr, i8 0, i64 %len, i1 false)
+  ret void
+}
+
+define void @memset_and_store_2(i8* %ptr, i64 %len) {
+; CHECK-LABEL: @memset_and_store_2(
+; CHECK-NEXT:    [[BC:%.*]] = bitcast i8* [[PTR:%.*]] to i64*
+; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 1 [[PTR]], i8 0, i64 [[LEN:%.*]], i1 false)
+; CHECK-NEXT:    store i64 123, i64* [[BC]], align 4
+; CHECK-NEXT:    ret void
+;
+  %bc = bitcast i8* %ptr to i64*
+  call void @llvm.memset.p0i8.i64(i8* align 1 %ptr, i8 0, i64 %len, i1 false)
+  store i64 123, i64* %bc
+  ret void
+}
+
 define void @memcpy_equal_size_values(i8* noalias %src, i8* noalias %dst, i64 %len) {
 ; CHECK-LABEL: @memcpy_equal_size_values(
 ; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[SRC:%.*]], i64 [[LEN:%.*]], i1 false)
-; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST]], i8* [[SRC]], i64 [[LEN]], i1 false)
 ; CHECK-NEXT:    ret void
 ;
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %len, i1 false)
@@ -91,8 +115,7 @@ define void @memcpy_
diff erent_size_values_3(i8* noalias %src, i8* noalias %dst,
 
 define void @memset_and_memcpy_equal_size_values(i8* noalias %src, i8* noalias %dst, i64 %len) {
 ; CHECK-LABEL: @memset_and_memcpy_equal_size_values(
-; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 1 [[DST:%.*]], i8 0, i64 [[LEN:%.*]], i1 false)
-; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST]], i8* [[SRC:%.*]], i64 [[LEN]], i1 false)
+; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[SRC:%.*]], i64 [[LEN:%.*]], i1 false)
 ; CHECK-NEXT:    ret void
 ;
   call void @llvm.memset.p0i8.i64(i8* align 1 %dst, i8 0, i64 %len, i1 false)
@@ -135,8 +158,7 @@ define void @memset_and_memcpy_
diff erent_size_values_3(i8* noalias %src, i8* noa
 
 define void @memcpy_and_memset_equal_size_values(i8* noalias %src, i8* noalias %dst, i64 %len) {
 ; CHECK-LABEL: @memcpy_and_memset_equal_size_values(
-; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[SRC:%.*]], i64 [[LEN:%.*]], i1 false)
-; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 1 [[DST]], i8 0, i64 [[LEN]], i1 false)
+; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 1 [[DST:%.*]], i8 0, i64 [[LEN:%.*]], i1 false)
 ; CHECK-NEXT:    ret void
 ;
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %len, i1 false)


        


More information about the llvm-commits mailing list