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 @@ -371,6 +371,25 @@ // 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(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 --- 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 @@ 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 @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 @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)