1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[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
This commit is contained in:
Florian Hahn 2021-03-10 09:47:53 +00:00
parent cf11e8978e
commit 9450d09863
2 changed files with 47 additions and 6 deletions

View File

@ -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);

View File

@ -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_different_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_different_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_different_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)