Skip to content

Commit abd81ec

Browse files
committed
Pre-commit test cases
1 parent 2a7abb0 commit abd81ec

File tree

2 files changed

+237
-0
lines changed

2 files changed

+237
-0
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2+
; RUN: opt < %s -passes=memcpyopt -S -verify-memoryssa | FileCheck %s
3+
4+
%buf = type [9 x i8]
5+
6+
; We can forward `memcpy` because the copy location are the same,
7+
define void @forward_offset(ptr %dep_src) {
8+
; CHECK-LABEL: define void @forward_offset(
9+
; CHECK-SAME: ptr [[DEP_SRC:%.*]]) {
10+
; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
11+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[DEP_SRC]], i64 7, i1 false)
12+
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1
13+
; CHECK-NEXT: [[DEP:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 1
14+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP]], ptr align 1 [[SRC]], i64 6, i1 false)
15+
; CHECK-NEXT: ret void
16+
;
17+
%dep_dest = alloca %buf, align 1
18+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dep_dest, ptr align 1 %dep_src, i64 7, i1 false)
19+
%src = getelementptr inbounds i8, ptr %dep_dest, i64 1
20+
%dest = getelementptr inbounds i8, ptr %dep_src, i64 1
21+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %src, i64 6, i1 false)
22+
ret void
23+
}
24+
25+
; We need to update the align value of the source of `memcpy` when forwarding.
26+
define void @forward_offset_align(ptr %dep_src) {
27+
; CHECK-LABEL: define void @forward_offset_align(
28+
; CHECK-SAME: ptr [[DEP_SRC:%.*]]) {
29+
; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
30+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 4 [[DEP_SRC]], i64 9, i1 false)
31+
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 3
32+
; CHECK-NEXT: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 3
33+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[SRC]], i64 5, i1 false)
34+
; CHECK-NEXT: ret void
35+
;
36+
%dep_dest = alloca %buf, align 1
37+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dep_dest, ptr align 4 %dep_src, i64 9, i1 false)
38+
%src = getelementptr inbounds i8, ptr %dep_dest, i64 3
39+
%dest = getelementptr inbounds i8, ptr %dep_src, i64 3
40+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %src, i64 5, i1 false)
41+
ret void
42+
}
43+
44+
; We can change the align value to 2 when forwarding.
45+
define void @forward_offset_align_2(ptr %dep_src) {
46+
; CHECK-LABEL: define void @forward_offset_align_2(
47+
; CHECK-SAME: ptr [[DEP_SRC:%.*]]) {
48+
; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
49+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 4 [[DEP_SRC]], i64 9, i1 false)
50+
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 2
51+
; CHECK-NEXT: [[DEP:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 2
52+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP]], ptr align 1 [[SRC]], i64 6, i1 false)
53+
; CHECK-NEXT: ret void
54+
;
55+
%dep_dest = alloca %buf, align 1
56+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dep_dest, ptr align 4 %dep_src, i64 9, i1 false)
57+
%src = getelementptr inbounds i8, ptr %dep_dest, i64 2
58+
%dest = getelementptr inbounds i8, ptr %dep_src, i64 2
59+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %src, i64 6, i1 false)
60+
ret void
61+
}
62+
63+
; We need to create a GEP instruction when forwarding.
64+
define void @forward_offset_with_gep(ptr %dep_src) {
65+
; CHECK-LABEL: define void @forward_offset_with_gep(
66+
; CHECK-SAME: ptr [[DEP_SRC:%.*]]) {
67+
; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
68+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[DEP_SRC]], i64 7, i1 false)
69+
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1
70+
; CHECK-NEXT: [[DEP1:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 2
71+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP1]], ptr align 1 [[SRC]], i64 6, i1 false)
72+
; CHECK-NEXT: ret void
73+
;
74+
%dep_dest = alloca %buf, align 1
75+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dep_dest, ptr align 1 %dep_src, i64 7, i1 false)
76+
%src = getelementptr inbounds i8, ptr %dep_dest, i64 1
77+
%dest = getelementptr inbounds i8, ptr %dep_src, i64 2
78+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %src, i64 6, i1 false)
79+
ret void
80+
}
81+
82+
; Make sure we pass the right parameters when calling `memcpy`.
83+
define void @forward_offset_memcpy(ptr %dep_src) {
84+
; CHECK-LABEL: define void @forward_offset_memcpy(
85+
; CHECK-SAME: ptr [[DEP_SRC:%.*]]) {
86+
; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
87+
; CHECK-NEXT: [[DEST:%.*]] = alloca [9 x i8], align 1
88+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[DEP_SRC]], i64 7, i1 false)
89+
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1
90+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[SRC]], i64 6, i1 false)
91+
; CHECK-NEXT: call void @use(ptr [[DEST]])
92+
; CHECK-NEXT: ret void
93+
;
94+
%dep_dest = alloca %buf, align 1
95+
%dest = alloca %buf, align 1
96+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dep_dest, ptr align 1 %dep_src, i64 7, i1 false)
97+
%src = getelementptr inbounds i8, ptr %dep_dest, i64 1
98+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %src, i64 6, i1 false)
99+
call void @use(ptr %dest)
100+
ret void
101+
}
102+
103+
; Make sure we pass the right parameters when calling `memcpy.inline`.
104+
define void @forward_offset_memcpy_inline(ptr %dep_src) {
105+
; CHECK-LABEL: define void @forward_offset_memcpy_inline(
106+
; CHECK-SAME: ptr [[DEP_SRC:%.*]]) {
107+
; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
108+
; CHECK-NEXT: [[DEST:%.*]] = alloca [9 x i8], align 1
109+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[DEP_SRC]], i64 7, i1 false)
110+
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1
111+
; CHECK-NEXT: call void @llvm.memcpy.inline.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[SRC]], i64 6, i1 false)
112+
; CHECK-NEXT: call void @use(ptr [[DEST]])
113+
; CHECK-NEXT: ret void
114+
;
115+
%dep_dest = alloca %buf, align 1
116+
%dest = alloca %buf, align 1
117+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dep_dest, ptr align 1 %dep_src, i64 7, i1 false)
118+
%src = getelementptr inbounds i8, ptr %dep_dest, i64 1
119+
call void @llvm.memcpy.inline.p0.p0.i64(ptr align 1 %dest, ptr align 1 %src, i64 6, i1 false)
120+
call void @use(ptr %dest)
121+
ret void
122+
}
123+
124+
; We cannot forward `memcpy` because it exceeds the size of `memcpy` it depends on.
125+
define void @do_not_forward_oversize_offset(ptr %dep_src) {
126+
; CHECK-LABEL: define void @do_not_forward_oversize_offset(
127+
; CHECK-SAME: ptr [[DEP_SRC:%.*]]) {
128+
; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
129+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[DEP_SRC]], i64 6, i1 false)
130+
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1
131+
; CHECK-NEXT: [[DEP:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 1
132+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP]], ptr align 1 [[SRC]], i64 6, i1 false)
133+
; CHECK-NEXT: ret void
134+
;
135+
%dep_dest = alloca %buf, align 1
136+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dep_dest, ptr align 1 %dep_src, i64 6, i1 false)
137+
%src = getelementptr inbounds i8, ptr %dep_dest, i64 1
138+
%dest = getelementptr inbounds i8, ptr %dep_src, i64 1
139+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %src, i64 6, i1 false)
140+
ret void
141+
}
142+
143+
; We can forward `memcpy` because the write operation does not corrupt the location to be copied.
144+
define void @forward_offset_and_store(ptr %dep_src) {
145+
; CHECK-LABEL: define void @forward_offset_and_store(
146+
; CHECK-SAME: ptr [[DEP_SRC:%.*]]) {
147+
; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
148+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[DEP_SRC]], i64 7, i1 false)
149+
; CHECK-NEXT: store i8 1, ptr [[DEP_SRC]], align 1
150+
; CHECK-NEXT: [[DEP_SRC_END:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 6
151+
; CHECK-NEXT: store i8 1, ptr [[DEP_SRC_END]], align 1
152+
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1
153+
; CHECK-NEXT: [[DEP:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 1
154+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP]], ptr align 1 [[SRC]], i64 5, i1 false)
155+
; CHECK-NEXT: ret void
156+
;
157+
%dep_dest = alloca %buf, align 1
158+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dep_dest, ptr align 1 %dep_src, i64 7, i1 false)
159+
store i8 1, ptr %dep_src, align 1
160+
%dep_src_end = getelementptr inbounds i8, ptr %dep_src, i64 6
161+
store i8 1, ptr %dep_src_end, align 1
162+
%src = getelementptr inbounds i8, ptr %dep_dest, i64 1
163+
%dest = getelementptr inbounds i8, ptr %dep_src, i64 1
164+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %src, i64 5, i1 false)
165+
ret void
166+
}
167+
168+
; We cannot forward `memcpy` because the write operation alters the location to be copied.
169+
; Also, make sure we have removed the GEP instruction that was created temporarily.
170+
define void @do_not_forward_offset_and_store(ptr %dep_src) {
171+
; CHECK-LABEL: define void @do_not_forward_offset_and_store(
172+
; CHECK-SAME: ptr [[DEP_SRC:%.*]]) {
173+
; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
174+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[DEP_SRC]], i64 7, i1 false)
175+
; CHECK-NEXT: [[DEP:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 1
176+
; CHECK-NEXT: store i8 1, ptr [[DEP]], align 1
177+
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1
178+
; CHECK-NEXT: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 2
179+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[SRC]], i64 5, i1 false)
180+
; CHECK-NEXT: ret void
181+
;
182+
%dep_dest = alloca %buf, align 1
183+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dep_dest, ptr align 1 %dep_src, i64 7, i1 false)
184+
%dep_src_offset = getelementptr inbounds i8, ptr %dep_src, i64 1
185+
store i8 1, ptr %dep_src_offset, align 1
186+
%src = getelementptr inbounds i8, ptr %dep_dest, i64 1
187+
%dest = getelementptr inbounds i8, ptr %dep_src, i64 2
188+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %src, i64 5, i1 false)
189+
ret void
190+
}
191+
192+
declare void @use(ptr)
193+
194+
declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1)
195+
declare void @llvm.memcpy.inline.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2+
; RUN: opt < %s -passes=memcpyopt,dse,instcombine -S -verify-memoryssa | FileCheck --check-prefix=CUSTOM %s
3+
; RUN: opt < %s -O2 -S | FileCheck --check-prefix=O2 %s
4+
5+
%buf = type [7 x i8]
6+
7+
; Check that we eliminate all `memcpy` calls in this function.
8+
define void @forward_offset_and_store(ptr %dep_src) {
9+
; CUSTOM-LABEL: define void @forward_offset_and_store(
10+
; CUSTOM-SAME: ptr [[DEP_SRC:%.*]]) {
11+
; CUSTOM-NEXT: [[DEP_DEST:%.*]] = alloca [7 x i8], align 1
12+
; CUSTOM-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(7) [[DEP_DEST]], ptr noundef nonnull align 1 dereferenceable(7) [[DEP_SRC]], i64 7, i1 false)
13+
; CUSTOM-NEXT: store i8 1, ptr [[DEP_SRC]], align 1
14+
; CUSTOM-NEXT: [[DEP_SRC_END:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 6
15+
; CUSTOM-NEXT: store i8 1, ptr [[DEP_SRC_END]], align 1
16+
; CUSTOM-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1
17+
; CUSTOM-NEXT: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 1
18+
; CUSTOM-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DEST]], ptr noundef nonnull align 1 dereferenceable(5) [[SRC]], i64 5, i1 false)
19+
; CUSTOM-NEXT: ret void
20+
;
21+
; O2-LABEL: define void @forward_offset_and_store(
22+
; O2-SAME: ptr nocapture [[DEP_SRC:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
23+
; O2-NEXT: [[DEP_DEST:%.*]] = alloca [7 x i8], align 1
24+
; O2-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(7) [[DEP_DEST]], ptr noundef nonnull align 1 dereferenceable(7) [[DEP_SRC]], i64 7, i1 false)
25+
; O2-NEXT: store i8 1, ptr [[DEP_SRC]], align 1
26+
; O2-NEXT: [[DEP_SRC_END:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 6
27+
; O2-NEXT: store i8 1, ptr [[DEP_SRC_END]], align 1
28+
; O2-NEXT: [[SRC:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1
29+
; O2-NEXT: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[DEP_SRC]], i64 1
30+
; O2-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DEST]], ptr noundef nonnull align 1 dereferenceable(5) [[SRC]], i64 5, i1 false)
31+
; O2-NEXT: ret void
32+
;
33+
%dep_dest = alloca %buf, align 1
34+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dep_dest, ptr align 1 %dep_src, i64 7, i1 false)
35+
store i8 1, ptr %dep_src, align 1
36+
%dep_src_end = getelementptr inbounds i8, ptr %dep_src, i64 6
37+
store i8 1, ptr %dep_src_end, align 1
38+
%src = getelementptr inbounds i8, ptr %dep_dest, i64 1
39+
%dest = getelementptr inbounds i8, ptr %dep_src, i64 1
40+
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %src, i64 5, i1 false)
41+
ret void
42+
}

0 commit comments

Comments
 (0)