• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -memcpyopt < %s -enable-memcpyopt-memoryssa=0 | FileCheck %s --check-prefixes=CHECK,NO_MSSA
3; RUN: opt -S -memcpyopt < %s -enable-memcpyopt-memoryssa=1 -verify-memoryssa | FileCheck %s --check-prefixes=CHECK,MSSA
4
5define i8 @read_dest_between_call_and_memcpy() {
6; CHECK-LABEL: @read_dest_between_call_and_memcpy(
7; CHECK-NEXT:    [[DEST:%.*]] = alloca [16 x i8], align 1
8; CHECK-NEXT:    [[SRC:%.*]] = alloca [16 x i8], align 1
9; CHECK-NEXT:    [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
10; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
11; CHECK-NEXT:    store i8 1, i8* [[DEST_I8]], align 1
12; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false)
13; CHECK-NEXT:    [[X:%.*]] = load i8, i8* [[DEST_I8]], align 1
14; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[DEST_I8]], i8 0, i64 16, i1 false)
15; CHECK-NEXT:    ret i8 [[X]]
16;
17  %dest = alloca [16 x i8]
18  %src = alloca [16 x i8]
19  %dest.i8 = bitcast [16 x i8]* %dest to i8*
20  %src.i8 = bitcast [16 x i8]* %src to i8*
21  store i8 1, i8* %dest.i8
22  call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false)
23  %x = load i8, i8* %dest.i8
24  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
25  ret i8 %x
26}
27
28define i8 @read_src_between_call_and_memcpy() {
29; NO_MSSA-LABEL: @read_src_between_call_and_memcpy(
30; NO_MSSA-NEXT:    [[DEST:%.*]] = alloca [16 x i8], align 1
31; NO_MSSA-NEXT:    [[SRC:%.*]] = alloca [16 x i8], align 1
32; NO_MSSA-NEXT:    [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
33; NO_MSSA-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
34; NO_MSSA-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false)
35; NO_MSSA-NEXT:    [[X:%.*]] = load i8, i8* [[SRC_I8]], align 1
36; NO_MSSA-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DEST_I8]], i8* [[SRC_I8]], i64 16, i1 false)
37; NO_MSSA-NEXT:    ret i8 [[X]]
38;
39; MSSA-LABEL: @read_src_between_call_and_memcpy(
40; MSSA-NEXT:    [[DEST:%.*]] = alloca [16 x i8], align 1
41; MSSA-NEXT:    [[SRC:%.*]] = alloca [16 x i8], align 1
42; MSSA-NEXT:    [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
43; MSSA-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
44; MSSA-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false)
45; MSSA-NEXT:    [[X:%.*]] = load i8, i8* [[SRC_I8]], align 1
46; MSSA-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[DEST_I8]], i8 0, i64 16, i1 false)
47; MSSA-NEXT:    ret i8 [[X]]
48;
49  %dest = alloca [16 x i8]
50  %src = alloca [16 x i8]
51  %dest.i8 = bitcast [16 x i8]* %dest to i8*
52  %src.i8 = bitcast [16 x i8]* %src to i8*
53  call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false)
54  %x = load i8, i8* %src.i8
55  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
56  ret i8 %x
57}
58
59define void @write_dest_between_call_and_memcpy() {
60; CHECK-LABEL: @write_dest_between_call_and_memcpy(
61; CHECK-NEXT:    [[DEST:%.*]] = alloca [16 x i8], align 1
62; CHECK-NEXT:    [[SRC:%.*]] = alloca [16 x i8], align 1
63; CHECK-NEXT:    [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
64; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
65; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false)
66; CHECK-NEXT:    store i8 1, i8* [[DEST_I8]], align 1
67; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[DEST_I8]], i8 0, i64 16, i1 false)
68; CHECK-NEXT:    ret void
69;
70  %dest = alloca [16 x i8]
71  %src = alloca [16 x i8]
72  %dest.i8 = bitcast [16 x i8]* %dest to i8*
73  %src.i8 = bitcast [16 x i8]* %src to i8*
74  call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false)
75  store i8 1, i8* %dest.i8
76  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
77  ret void
78}
79
80define void @write_src_between_call_and_memcpy() {
81; CHECK-LABEL: @write_src_between_call_and_memcpy(
82; CHECK-NEXT:    [[DEST:%.*]] = alloca [16 x i8], align 1
83; CHECK-NEXT:    [[SRC:%.*]] = alloca [16 x i8], align 1
84; CHECK-NEXT:    [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
85; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
86; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false)
87; CHECK-NEXT:    store i8 1, i8* [[SRC_I8]], align 1
88; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DEST_I8]], i8* [[SRC_I8]], i64 16, i1 false)
89; CHECK-NEXT:    ret void
90;
91  %dest = alloca [16 x i8]
92  %src = alloca [16 x i8]
93  %dest.i8 = bitcast [16 x i8]* %dest to i8*
94  %src.i8 = bitcast [16 x i8]* %src to i8*
95  call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false)
96  store i8 1, i8* %src.i8
97  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
98  ret void
99}
100
101define void @throw_between_call_and_mempy(i8* dereferenceable(16) %dest.i8) {
102; CHECK-LABEL: @throw_between_call_and_mempy(
103; CHECK-NEXT:    [[SRC:%.*]] = alloca [16 x i8], align 1
104; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
105; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[SRC_I8]], i8 0, i64 16, i1 false)
106; CHECK-NEXT:    call void @may_throw() [[ATTR2:#.*]]
107; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[DEST_I8:%.*]], i8 0, i64 16, i1 false)
108; CHECK-NEXT:    ret void
109;
110  %src = alloca [16 x i8]
111  %src.i8 = bitcast [16 x i8]* %src to i8*
112  call void @llvm.memset.p0i8.i64(i8* %src.i8, i8 0, i64 16, i1 false)
113  call void @may_throw() readnone
114  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
115  ret void
116}
117
118define void @dest_is_gep_nounwind_call() {
119; CHECK-LABEL: @dest_is_gep_nounwind_call(
120; CHECK-NEXT:    [[DEST:%.*]] = alloca [16 x i8], align 1
121; CHECK-NEXT:    [[SRC:%.*]] = alloca [8 x i8], align 1
122; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [8 x i8]* [[SRC]] to i8*
123; CHECK-NEXT:    [[DEST_I8:%.*]] = getelementptr [16 x i8], [16 x i8]* [[DEST]], i64 0, i64 8
124; CHECK-NEXT:    [[DEST_I81:%.*]] = bitcast i8* [[DEST_I8]] to [8 x i8]*
125; CHECK-NEXT:    [[DEST_I812:%.*]] = bitcast [8 x i8]* [[DEST_I81]] to i8*
126; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST_I812]]) [[ATTR3:#.*]]
127; CHECK-NEXT:    ret void
128;
129  %dest = alloca [16 x i8]
130  %src = alloca [8 x i8]
131  %src.i8 = bitcast [8 x i8]* %src to i8*
132  %dest.i8 = getelementptr [16 x i8], [16 x i8]* %dest, i64 0, i64 8
133  call void @accept_ptr(i8* %src.i8) nounwind
134  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 8, i1 false)
135  ret void
136}
137
138define void @dest_is_gep_may_throw_call() {
139; CHECK-LABEL: @dest_is_gep_may_throw_call(
140; CHECK-NEXT:    [[DEST:%.*]] = alloca [16 x i8], align 1
141; CHECK-NEXT:    [[SRC:%.*]] = alloca [8 x i8], align 1
142; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [8 x i8]* [[SRC]] to i8*
143; CHECK-NEXT:    [[DEST_I8:%.*]] = getelementptr [16 x i8], [16 x i8]* [[DEST]], i64 0, i64 8
144; CHECK-NEXT:    [[DEST_I81:%.*]] = bitcast i8* [[DEST_I8]] to [8 x i8]*
145; CHECK-NEXT:    [[DEST_I812:%.*]] = bitcast [8 x i8]* [[DEST_I81]] to i8*
146; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST_I812]])
147; CHECK-NEXT:    ret void
148;
149  %dest = alloca [16 x i8]
150  %src = alloca [8 x i8]
151  %src.i8 = bitcast [8 x i8]* %src to i8*
152  %dest.i8 = getelementptr [16 x i8], [16 x i8]* %dest, i64 0, i64 8
153  call void @accept_ptr(i8* %src.i8)
154  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 8, i1 false)
155  ret void
156}
157
158define void @dest_is_gep_requires_movement() {
159; CHECK-LABEL: @dest_is_gep_requires_movement(
160; CHECK-NEXT:    [[DEST:%.*]] = alloca [16 x i8], align 1
161; CHECK-NEXT:    [[SRC:%.*]] = alloca [8 x i8], align 1
162; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [8 x i8]* [[SRC]] to i8*
163; CHECK-NEXT:    [[DEST_I8:%.*]] = getelementptr [16 x i8], [16 x i8]* [[DEST]], i64 0, i64 8
164; CHECK-NEXT:    [[DEST_I81:%.*]] = bitcast i8* [[DEST_I8]] to [8 x i8]*
165; CHECK-NEXT:    [[DEST_I812:%.*]] = bitcast [8 x i8]* [[DEST_I81]] to i8*
166; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST_I812]]) [[ATTR3]]
167; CHECK-NEXT:    ret void
168;
169  %dest = alloca [16 x i8]
170  %src = alloca [8 x i8]
171  %src.i8 = bitcast [8 x i8]* %src to i8*
172  call void @accept_ptr(i8* %src.i8) nounwind
173  %dest.i8 = getelementptr [16 x i8], [16 x i8]* %dest, i64 0, i64 8
174  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 8, i1 false)
175  ret void
176}
177
178define void @capture_before_call_argmemonly() {
179; CHECK-LABEL: @capture_before_call_argmemonly(
180; CHECK-NEXT:    [[DEST:%.*]] = alloca [16 x i8], align 1
181; CHECK-NEXT:    [[SRC:%.*]] = alloca [16 x i8], align 1
182; CHECK-NEXT:    [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
183; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
184; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST_I8]])
185; CHECK-NEXT:    [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
186; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST1]]) [[ATTR4:#.*]]
187; CHECK-NEXT:    ret void
188;
189  %dest = alloca [16 x i8]
190  %src = alloca [16 x i8]
191  %dest.i8 = bitcast [16 x i8]* %dest to i8*
192  %src.i8 = bitcast [16 x i8]* %src to i8*
193  call void @accept_ptr(i8* %dest.i8) ; capture
194  call void @accept_ptr(i8* %src.i8) argmemonly
195  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
196  ret void
197}
198
199define void @capture_before_call_argmemonly_nounwind() {
200; CHECK-LABEL: @capture_before_call_argmemonly_nounwind(
201; CHECK-NEXT:    [[DEST:%.*]] = alloca [16 x i8], align 1
202; CHECK-NEXT:    [[SRC:%.*]] = alloca [16 x i8], align 1
203; CHECK-NEXT:    [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
204; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
205; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST_I8]])
206; CHECK-NEXT:    [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
207; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST1]]) [[ATTR5:#.*]]
208; CHECK-NEXT:    ret void
209;
210  %dest = alloca [16 x i8]
211  %src = alloca [16 x i8]
212  %dest.i8 = bitcast [16 x i8]* %dest to i8*
213  %src.i8 = bitcast [16 x i8]* %src to i8*
214  call void @accept_ptr(i8* %dest.i8) ; capture
215  ; NB: argmemonly currently implies willreturn.
216  call void @accept_ptr(i8* %src.i8) argmemonly nounwind
217  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
218  ret void
219}
220
221define void @capture_before_call_argmemonly_nounwind_willreturn() {
222; CHECK-LABEL: @capture_before_call_argmemonly_nounwind_willreturn(
223; CHECK-NEXT:    [[DEST:%.*]] = alloca [16 x i8], align 1
224; CHECK-NEXT:    [[SRC:%.*]] = alloca [16 x i8], align 1
225; CHECK-NEXT:    [[DEST_I8:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
226; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
227; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST_I8]])
228; CHECK-NEXT:    [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
229; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST1]]) [[ATTR0:#.*]]
230; CHECK-NEXT:    ret void
231;
232  %dest = alloca [16 x i8]
233  %src = alloca [16 x i8]
234  %dest.i8 = bitcast [16 x i8]* %dest to i8*
235  %src.i8 = bitcast [16 x i8]* %src to i8*
236  call void @accept_ptr(i8* %dest.i8) ; capture
237  call void @accept_ptr(i8* %src.i8) argmemonly nounwind willreturn
238  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
239  ret void
240}
241
242declare void @may_throw()
243declare void @accept_ptr(i8*)
244declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1)
245declare void @llvm.memset.p0i8.i64(i8*, i8, i64, i1)
246