1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -memcpyopt < %s -verify-memoryssa | FileCheck %s
4 define i8 @read_dest_between_call_and_memcpy() {
5 ; CHECK-LABEL: @read_dest_between_call_and_memcpy(
6 ; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1
7 ; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1
8 ; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
9 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
10 ; CHECK-NEXT: store i8 1, i8* [[DEST_I8]], align 1
11 ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false)
12 ; CHECK-NEXT: [[X:%.*]] = load i8, i8* [[DEST_I8]], align 1
13 ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[DEST_I8]], i8 0, i64 16, i1 false)
14 ; CHECK-NEXT: ret i8 [[X]]
16 %dest = alloca [16 x i8]
17 %src = alloca [16 x i8]
18 %dest.i8 = bitcast [16 x i8]* %dest to i8*
19 %src.i8 = bitcast [16 x i8]* %src to i8*
20 store i8 1, i8* %dest.i8
21 call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false)
22 %x = load i8, i8* %dest.i8
23 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
27 define i8 @read_src_between_call_and_memcpy() {
28 ; CHECK-LABEL: @read_src_between_call_and_memcpy(
29 ; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1
30 ; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1
31 ; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
32 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
33 ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false)
34 ; CHECK-NEXT: [[X:%.*]] = load i8, i8* [[SRC_I8]], align 1
35 ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[DEST_I8]], i8 0, i64 16, i1 false)
36 ; CHECK-NEXT: ret i8 [[X]]
38 %dest = alloca [16 x i8]
39 %src = alloca [16 x i8]
40 %dest.i8 = bitcast [16 x i8]* %dest to i8*
41 %src.i8 = bitcast [16 x i8]* %src to i8*
42 call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false)
43 %x = load i8, i8* %src.i8
44 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
48 define void @write_dest_between_call_and_memcpy() {
49 ; CHECK-LABEL: @write_dest_between_call_and_memcpy(
50 ; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1
51 ; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1
52 ; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
53 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
54 ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false)
55 ; CHECK-NEXT: store i8 1, i8* [[DEST_I8]], align 1
56 ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[DEST_I8]], i8 0, i64 16, i1 false)
57 ; CHECK-NEXT: ret void
59 %dest = alloca [16 x i8]
60 %src = alloca [16 x i8]
61 %dest.i8 = bitcast [16 x i8]* %dest to i8*
62 %src.i8 = bitcast [16 x i8]* %src to i8*
63 call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false)
64 store i8 1, i8* %dest.i8
65 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
69 define void @write_src_between_call_and_memcpy() {
70 ; CHECK-LABEL: @write_src_between_call_and_memcpy(
71 ; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1
72 ; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1
73 ; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
74 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
75 ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false)
76 ; CHECK-NEXT: store i8 1, i8* [[SRC_I8]], align 1
77 ; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DEST_I8]], i8* [[SRC_I8]], i64 16, i1 false)
78 ; CHECK-NEXT: ret void
80 %dest = alloca [16 x i8]
81 %src = alloca [16 x i8]
82 %dest.i8 = bitcast [16 x i8]* %dest to i8*
83 %src.i8 = bitcast [16 x i8]* %src to i8*
84 call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false)
85 store i8 1, i8* %src.i8
86 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
90 define void @throw_between_call_and_mempy(i8* dereferenceable(16) %dest.i8) {
91 ; CHECK-LABEL: @throw_between_call_and_mempy(
92 ; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1
93 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
94 ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false)
95 ; CHECK-NEXT: call void @may_throw() #[[ATTR2:[0-9]+]]
96 ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[DEST_I8:%.*]], i8 0, i64 16, i1 false)
97 ; CHECK-NEXT: ret void
99 %src = alloca [16 x i8]
100 %src.i8 = bitcast [16 x i8]* %src to i8*
101 call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false)
102 call void @may_throw() readnone
103 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
107 define void @dest_is_gep_nounwind_call() {
108 ; CHECK-LABEL: @dest_is_gep_nounwind_call(
109 ; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1
110 ; CHECK-NEXT: [[SRC:%.*]] = alloca [8 x i8], align 1
111 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [8 x i8]* [[SRC]] to i8*
112 ; CHECK-NEXT: [[DEST_I8:%.*]] = getelementptr [16 x i8], [16 x i8]* [[DEST]], i64 0, i64 8
113 ; CHECK-NEXT: [[DEST_I81:%.*]] = bitcast i8* [[DEST_I8]] to [8 x i8]*
114 ; CHECK-NEXT: [[DEST_I812:%.*]] = bitcast [8 x i8]* [[DEST_I81]] to i8*
115 ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I812]]) #[[ATTR3:[0-9]+]]
116 ; CHECK-NEXT: ret void
118 %dest = alloca [16 x i8]
119 %src = alloca [8 x i8]
120 %src.i8 = bitcast [8 x i8]* %src to i8*
121 %dest.i8 = getelementptr [16 x i8], [16 x i8]* %dest, i64 0, i64 8
122 call void @accept_ptr(i8* %src.i8) nounwind
123 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 8, i1 false)
127 define void @dest_is_gep_may_throw_call() {
128 ; CHECK-LABEL: @dest_is_gep_may_throw_call(
129 ; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1
130 ; CHECK-NEXT: [[SRC:%.*]] = alloca [8 x i8], align 1
131 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [8 x i8]* [[SRC]] to i8*
132 ; CHECK-NEXT: [[DEST_I8:%.*]] = getelementptr [16 x i8], [16 x i8]* [[DEST]], i64 0, i64 8
133 ; CHECK-NEXT: [[DEST_I81:%.*]] = bitcast i8* [[DEST_I8]] to [8 x i8]*
134 ; CHECK-NEXT: [[DEST_I812:%.*]] = bitcast [8 x i8]* [[DEST_I81]] to i8*
135 ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I812]])
136 ; CHECK-NEXT: ret void
138 %dest = alloca [16 x i8]
139 %src = alloca [8 x i8]
140 %src.i8 = bitcast [8 x i8]* %src to i8*
141 %dest.i8 = getelementptr [16 x i8], [16 x i8]* %dest, i64 0, i64 8
142 call void @accept_ptr(i8* %src.i8)
143 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 8, i1 false)
147 define void @dest_is_gep_requires_movement() {
148 ; CHECK-LABEL: @dest_is_gep_requires_movement(
149 ; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1
150 ; CHECK-NEXT: [[SRC:%.*]] = alloca [8 x i8], align 1
151 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [8 x i8]* [[SRC]] to i8*
152 ; CHECK-NEXT: [[DEST_I8:%.*]] = getelementptr [16 x i8], [16 x i8]* [[DEST]], i64 0, i64 8
153 ; CHECK-NEXT: [[DEST_I81:%.*]] = bitcast i8* [[DEST_I8]] to [8 x i8]*
154 ; CHECK-NEXT: [[DEST_I812:%.*]] = bitcast [8 x i8]* [[DEST_I81]] to i8*
155 ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I812]]) #[[ATTR3]]
156 ; CHECK-NEXT: ret void
158 %dest = alloca [16 x i8]
159 %src = alloca [8 x i8]
160 %src.i8 = bitcast [8 x i8]* %src to i8*
161 call void @accept_ptr(i8* %src.i8) nounwind
162 %dest.i8 = getelementptr [16 x i8], [16 x i8]* %dest, i64 0, i64 8
163 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 8, i1 false)
167 define void @capture_before_call_argmemonly() {
168 ; CHECK-LABEL: @capture_before_call_argmemonly(
169 ; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1
170 ; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1
171 ; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
172 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
173 ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I8]])
174 ; CHECK-NEXT: [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
175 ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST1]]) #[[ATTR4:[0-9]+]]
176 ; CHECK-NEXT: ret void
178 %dest = alloca [16 x i8]
179 %src = alloca [16 x i8]
180 %dest.i8 = bitcast [16 x i8]* %dest to i8*
181 %src.i8 = bitcast [16 x i8]* %src to i8*
182 call void @accept_ptr(i8* %dest.i8) ; capture
183 call void @accept_ptr(i8* %src.i8) argmemonly
184 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
188 define void @capture_before_call_argmemonly_nounwind() {
189 ; CHECK-LABEL: @capture_before_call_argmemonly_nounwind(
190 ; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1
191 ; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1
192 ; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
193 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
194 ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I8]])
195 ; CHECK-NEXT: [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
196 ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST1]]) #[[ATTR5:[0-9]+]]
197 ; CHECK-NEXT: ret void
199 %dest = alloca [16 x i8]
200 %src = alloca [16 x i8]
201 %dest.i8 = bitcast [16 x i8]* %dest to i8*
202 %src.i8 = bitcast [16 x i8]* %src to i8*
203 call void @accept_ptr(i8* %dest.i8) ; capture
204 ; NB: argmemonly currently implies willreturn.
205 call void @accept_ptr(i8* %src.i8) argmemonly nounwind
206 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
210 define void @capture_before_call_argmemonly_nounwind_willreturn() {
211 ; CHECK-LABEL: @capture_before_call_argmemonly_nounwind_willreturn(
212 ; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1
213 ; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1
214 ; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
215 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
216 ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I8]])
217 ; CHECK-NEXT: [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
218 ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST1]]) #[[ATTR6:[0-9]+]]
219 ; CHECK-NEXT: ret void
221 %dest = alloca [16 x i8]
222 %src = alloca [16 x i8]
223 %dest.i8 = bitcast [16 x i8]* %dest to i8*
224 %src.i8 = bitcast [16 x i8]* %src to i8*
225 call void @accept_ptr(i8* %dest.i8) ; capture
226 call void @accept_ptr(i8* %src.i8) argmemonly nounwind willreturn
227 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
231 ; There is no path from the capture back to the memcpy.
232 ; So we are allowed to perform the call slot optimization.
233 define void @capture_nopath_call(i1 %cond) {
234 ; CHECK-LABEL: @capture_nopath_call(
235 ; CHECK-NEXT: [[DEST:%.*]] = alloca [16 x i8], align 1
236 ; CHECK-NEXT: [[SRC:%.*]] = alloca [16 x i8], align 1
237 ; CHECK-NEXT: [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
238 ; CHECK-NEXT: [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
239 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[CAPTURES:%.*]], label [[NOCAPTURES:%.*]]
241 ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I8]])
242 ; CHECK-NEXT: ret void
244 ; CHECK-NEXT: [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
245 ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST1]]) #[[ATTR3]]
246 ; CHECK-NEXT: ret void
248 %dest = alloca [16 x i8]
249 %src = alloca [16 x i8]
250 %dest.i8 = bitcast [16 x i8]* %dest to i8*
251 %src.i8 = bitcast [16 x i8]* %src to i8*
252 br i1 %cond, label %captures, label %nocaptures
255 call void @accept_ptr(i8* %dest.i8) ; capture
259 call void @accept_ptr(i8* %src.i8) nounwind
260 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
264 declare void @may_throw()
265 declare void @accept_ptr(i8*)
266 declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1)
267 declare void @llvm.memset.p0i8.i64(i8*, i8, i64, i1)