Skip to content

Commit 117cc4a

Browse files
authored
[MemCpyOpt] No need to create memcpy(a <- a) (#98321)
When forwarding `memcpy`, we don't need to create `memcpy(a, a)`.
1 parent 0ff13f7 commit 117cc4a

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,14 @@ bool MemCpyOptPass::processMemCpyMemCpyDependence(MemCpyInst *M,
11611161
MSSA->getMemoryAccess(MDep), MSSA->getMemoryAccess(M)))
11621162
return false;
11631163

1164+
// No need to create `memcpy(a <- a)`.
1165+
if (BAA.isMustAlias(M->getDest(), MDep->getSource())) {
1166+
// Remove the instruction we're replacing.
1167+
eraseInstruction(M);
1168+
++NumMemCpyInstr;
1169+
return true;
1170+
}
1171+
11641172
// If the dest of the second might alias the source of the first, then the
11651173
// source and dest might overlap. In addition, if the source of the first
11661174
// points to constant memory, they won't overlap by definition. Otherwise, we

llvm/test/Transforms/MemCpyOpt/memcpy.ll

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,37 @@ define void @test6_memcpy(ptr %src, ptr %dest) nounwind {
139139
ret void
140140
}
141141

142+
; When forwarding to memcpy(arg+1, arg+1), we don't need to create this memcpy.
143+
define void @test6_memcpy_forward_back(ptr %arg) nounwind {
144+
; CHECK-LABEL: @test6_memcpy_forward_back(
145+
; CHECK-NEXT: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[ARG:%.*]], i64 1
146+
; CHECK-NEXT: ret void
147+
;
148+
%tmp = alloca [16 x i8], align 1
149+
%src = getelementptr inbounds i8, ptr %arg, i64 1
150+
%dest = getelementptr inbounds i8, ptr %arg, i64 1
151+
call void @llvm.memcpy.inline.p0.p0.i32(ptr align 1 %tmp, ptr align 1 %src, i32 16, i1 false)
152+
call void @llvm.memcpy.inline.p0.p0.i32(ptr align 1 %dest, ptr align 1 %tmp, i32 16, i1 false)
153+
ret void
154+
}
155+
156+
; We have to retain this `memcpy(arg+2, arg+1)` forwarding.
157+
define void @test6_memcpy_forward_not_back(ptr %arg) nounwind {
158+
; CHECK-LABEL: @test6_memcpy_forward_not_back(
159+
; CHECK-NEXT: [[TMP:%.*]] = alloca [16 x i8], align 1
160+
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[ARG:%.*]], i64 1
161+
; CHECK-NEXT: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[ARG]], i64 2
162+
; CHECK-NEXT: call void @llvm.memcpy.inline.p0.p0.i32(ptr align 1 [[TMP]], ptr align 1 [[SRC]], i32 16, i1 false)
163+
; CHECK-NEXT: call void @llvm.memcpy.inline.p0.p0.i32(ptr align 1 [[DEST]], ptr align 1 [[TMP]], i32 16, i1 false)
164+
; CHECK-NEXT: ret void
165+
;
166+
%tmp = alloca [16 x i8], align 1
167+
%src = getelementptr inbounds i8, ptr %arg, i64 1
168+
%dest = getelementptr inbounds i8, ptr %arg, i64 2
169+
call void @llvm.memcpy.inline.p0.p0.i32(ptr align 1 %tmp, ptr align 1 %src, i32 16, i1 false)
170+
call void @llvm.memcpy.inline.p0.p0.i32(ptr align 1 %dest, ptr align 1 %tmp, i32 16, i1 false)
171+
ret void
172+
}
142173

143174
@x = external global %0
144175

0 commit comments

Comments
 (0)