Skip to content

Commit 6a0125e

Browse files
committed
[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
1 parent 7346e8d commit 6a0125e

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,25 @@ isOverwrite(const Instruction *LaterI, const Instruction *EarlierI,
452452
// FIXME: Vet that this works for size upper-bounds. Seems unlikely that we'll
453453
// get imprecise values here, though (except for unknown sizes).
454454
if (!Later.Size.isPrecise() || !Earlier.Size.isPrecise()) {
455+
// In case no constant size is known, try to an IR values for the number
456+
// of bytes written and check if they match.
457+
auto GetSizeFromInstr = [](const Instruction *I) -> Value * {
458+
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
459+
switch (II->getIntrinsicID()) {
460+
default:
461+
return nullptr;
462+
case Intrinsic::memcpy:
463+
case Intrinsic::memset:
464+
return II->getArgOperand(2);
465+
}
466+
}
467+
return nullptr;
468+
};
469+
Value *LaterV = GetSizeFromInstr(LaterI);
470+
Value *EarlierV = GetSizeFromInstr(EarlierI);
471+
if (LaterV && LaterV == EarlierV && AA.isMustAlias(Earlier, Later))
472+
return OW_Complete;
473+
455474
// Masked stores have imprecise locations, but we can reason about them
456475
// to some extent.
457476
return isMaskedStoreOverwrite(LaterI, EarlierI, AA);

llvm/test/Transforms/DeadStoreElimination/memory-intrinsics-sizes.ll

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
define void @memset_equal_size_values(i8* %ptr, i64 %len) {
55
; CHECK-LABEL: @memset_equal_size_values(
66
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[PTR:%.*]], i8 0, i64 [[LEN:%.*]], i1 false)
7-
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[PTR]], i8 0, i64 [[LEN]], i1 false)
87
; CHECK-NEXT: ret void
98
;
109
call void @llvm.memset.p0i8.i64(i8* align 1 %ptr, i8 0, i64 %len, i1 false)
@@ -45,10 +44,35 @@ define void @memset_different_size_values_3(i8* %ptr, i64 %len) {
4544
ret void
4645
}
4746

47+
define void @memset_and_store_1(i8* %ptr, i64 %len) {
48+
; CHECK-LABEL: @memset_and_store_1(
49+
; CHECK-NEXT: [[BC:%.*]] = bitcast i8* [[PTR:%.*]] to i64*
50+
; CHECK-NEXT: store i64 123, i64* [[BC]], align 4
51+
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[PTR]], i8 0, i64 [[LEN:%.*]], i1 false)
52+
; CHECK-NEXT: ret void
53+
;
54+
%bc = bitcast i8* %ptr to i64*
55+
store i64 123, i64* %bc
56+
call void @llvm.memset.p0i8.i64(i8* align 1 %ptr, i8 0, i64 %len, i1 false)
57+
ret void
58+
}
59+
60+
define void @memset_and_store_2(i8* %ptr, i64 %len) {
61+
; CHECK-LABEL: @memset_and_store_2(
62+
; CHECK-NEXT: [[BC:%.*]] = bitcast i8* [[PTR:%.*]] to i64*
63+
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[PTR]], i8 0, i64 [[LEN:%.*]], i1 false)
64+
; CHECK-NEXT: store i64 123, i64* [[BC]], align 4
65+
; CHECK-NEXT: ret void
66+
;
67+
%bc = bitcast i8* %ptr to i64*
68+
call void @llvm.memset.p0i8.i64(i8* align 1 %ptr, i8 0, i64 %len, i1 false)
69+
store i64 123, i64* %bc
70+
ret void
71+
}
72+
4873
define void @memcpy_equal_size_values(i8* noalias %src, i8* noalias %dst, i64 %len) {
4974
; CHECK-LABEL: @memcpy_equal_size_values(
5075
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[SRC:%.*]], i64 [[LEN:%.*]], i1 false)
51-
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST]], i8* [[SRC]], i64 [[LEN]], i1 false)
5276
; CHECK-NEXT: ret void
5377
;
5478
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %len, i1 false)
@@ -91,8 +115,7 @@ define void @memcpy_different_size_values_3(i8* noalias %src, i8* noalias %dst,
91115

92116
define void @memset_and_memcpy_equal_size_values(i8* noalias %src, i8* noalias %dst, i64 %len) {
93117
; CHECK-LABEL: @memset_and_memcpy_equal_size_values(
94-
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[DST:%.*]], i8 0, i64 [[LEN:%.*]], i1 false)
95-
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST]], i8* [[SRC:%.*]], i64 [[LEN]], i1 false)
118+
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[SRC:%.*]], i64 [[LEN:%.*]], i1 false)
96119
; CHECK-NEXT: ret void
97120
;
98121
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_different_size_values_3(i8* noalias %src, i8* noa
135158

136159
define void @memcpy_and_memset_equal_size_values(i8* noalias %src, i8* noalias %dst, i64 %len) {
137160
; CHECK-LABEL: @memcpy_and_memset_equal_size_values(
138-
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[SRC:%.*]], i64 [[LEN:%.*]], i1 false)
139-
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[DST]], i8 0, i64 [[LEN]], i1 false)
161+
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[DST:%.*]], i8 0, i64 [[LEN:%.*]], i1 false)
140162
; CHECK-NEXT: ret void
141163
;
142164
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %len, i1 false)

0 commit comments

Comments
 (0)