1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -correlated-propagation -S | FileCheck %s
3
4define void @test1(i8* %ptr) {
5; CHECK-LABEL: @test1(
6; CHECK-NEXT:    [[A:%.*]] = load i8, i8* [[PTR:%.*]], align 1
7; CHECK-NEXT:    br label [[BB:%.*]]
8; CHECK:       bb:
9; CHECK-NEXT:    ret void
10;
11  %A = load i8, i8* %ptr
12  br label %bb
13bb:
14  icmp ne i8* %ptr, null
15  ret void
16}
17
18define void @test1_no_null_opt(i8* %ptr) #0 {
19; CHECK-LABEL: @test1_no_null_opt(
20; CHECK-NEXT:    [[A:%.*]] = load i8, i8* [[PTR:%.*]], align 1
21; CHECK-NEXT:    br label [[BB:%.*]]
22; CHECK:       bb:
23; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i8* [[PTR]], null
24; CHECK-NEXT:    ret void
25;
26  %A = load i8, i8* %ptr
27  br label %bb
28bb:
29  icmp ne i8* %ptr, null
30  ret void
31}
32
33define void @test2(i8* %ptr) {
34; CHECK-LABEL: @test2(
35; CHECK-NEXT:    store i8 0, i8* [[PTR:%.*]], align 1
36; CHECK-NEXT:    br label [[BB:%.*]]
37; CHECK:       bb:
38; CHECK-NEXT:    ret void
39;
40  store i8 0, i8* %ptr
41  br label %bb
42bb:
43  icmp ne i8* %ptr, null
44  ret void
45}
46
47define void @test2_no_null_opt(i8* %ptr) #0 {
48; CHECK-LABEL: @test2_no_null_opt(
49; CHECK-NEXT:    store i8 0, i8* [[PTR:%.*]], align 1
50; CHECK-NEXT:    br label [[BB:%.*]]
51; CHECK:       bb:
52; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i8* [[PTR]], null
53; CHECK-NEXT:    ret void
54;
55  store i8 0, i8* %ptr
56  br label %bb
57bb:
58  icmp ne i8* %ptr, null
59  ret void
60}
61
62define void @test3() {
63; CHECK-LABEL: @test3(
64; CHECK-NEXT:    [[PTR:%.*]] = alloca i8, align 1
65; CHECK-NEXT:    br label [[BB:%.*]]
66; CHECK:       bb:
67; CHECK-NEXT:    ret void
68;
69  %ptr = alloca i8
70  br label %bb
71bb:
72  icmp ne i8* %ptr, null
73  ret void
74}
75
76;; OK to remove icmp here since ptr is coming from alloca.
77
78define void @test3_no_null_opt() #0 {
79; CHECK-LABEL: @test3_no_null_opt(
80; CHECK-NEXT:    [[PTR:%.*]] = alloca i8, align 1
81; CHECK-NEXT:    br label [[BB:%.*]]
82; CHECK:       bb:
83; CHECK-NEXT:    ret void
84;
85  %ptr = alloca i8
86  br label %bb
87bb:
88  icmp ne i8* %ptr, null
89  ret void
90}
91
92declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1)
93
94define void @test4(i8* %dest, i8* %src) {
95; CHECK-LABEL: @test4(
96; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[DEST:%.*]], i8* [[SRC:%.*]], i32 1, i1 false)
97; CHECK-NEXT:    br label [[BB:%.*]]
98; CHECK:       bb:
99; CHECK-NEXT:    ret void
100;
101  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 1, i1 false)
102  br label %bb
103bb:
104  icmp ne i8* %dest, null
105  icmp ne i8* %src, null
106  ret void
107}
108
109define void @test4_no_null_opt(i8* %dest, i8* %src) #0 {
110; CHECK-LABEL: @test4_no_null_opt(
111; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[DEST:%.*]], i8* [[SRC:%.*]], i32 1, i1 false)
112; CHECK-NEXT:    br label [[BB:%.*]]
113; CHECK:       bb:
114; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i8* [[DEST]], null
115; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8* [[SRC]], null
116; CHECK-NEXT:    ret void
117;
118  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 1, i1 false)
119  br label %bb
120bb:
121  icmp ne i8* %dest, null
122  icmp ne i8* %src, null
123  ret void
124}
125
126declare void @llvm.memmove.p0i8.p0i8.i32(i8*, i8*, i32, i1)
127define void @test5(i8* %dest, i8* %src) {
128; CHECK-LABEL: @test5(
129; CHECK-NEXT:    call void @llvm.memmove.p0i8.p0i8.i32(i8* [[DEST:%.*]], i8* [[SRC:%.*]], i32 1, i1 false)
130; CHECK-NEXT:    br label [[BB:%.*]]
131; CHECK:       bb:
132; CHECK-NEXT:    ret void
133;
134  call void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 1, i1 false)
135  br label %bb
136bb:
137  icmp ne i8* %dest, null
138  icmp ne i8* %src, null
139  ret void
140}
141
142define void @test5_no_null_opt(i8* %dest, i8* %src) #0 {
143; CHECK-LABEL: @test5_no_null_opt(
144; CHECK-NEXT:    call void @llvm.memmove.p0i8.p0i8.i32(i8* [[DEST:%.*]], i8* [[SRC:%.*]], i32 1, i1 false)
145; CHECK-NEXT:    br label [[BB:%.*]]
146; CHECK:       bb:
147; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i8* [[DEST]], null
148; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8* [[SRC]], null
149; CHECK-NEXT:    ret void
150;
151  call void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 1, i1 false)
152  br label %bb
153bb:
154  icmp ne i8* %dest, null
155  icmp ne i8* %src, null
156  ret void
157}
158
159declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i1)
160define void @test6(i8* %dest) {
161; CHECK-LABEL: @test6(
162; CHECK-NEXT:    call void @llvm.memset.p0i8.i32(i8* [[DEST:%.*]], i8 -1, i32 1, i1 false)
163; CHECK-NEXT:    br label [[BB:%.*]]
164; CHECK:       bb:
165; CHECK-NEXT:    ret void
166;
167  call void @llvm.memset.p0i8.i32(i8* %dest, i8 255, i32 1, i1 false)
168  br label %bb
169bb:
170  icmp ne i8* %dest, null
171  ret void
172}
173
174define void @test6_no_null_opt(i8* %dest) #0 {
175; CHECK-LABEL: @test6_no_null_opt(
176; CHECK-NEXT:    call void @llvm.memset.p0i8.i32(i8* [[DEST:%.*]], i8 -1, i32 1, i1 false)
177; CHECK-NEXT:    br label [[BB:%.*]]
178; CHECK:       bb:
179; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i8* [[DEST]], null
180; CHECK-NEXT:    ret void
181;
182  call void @llvm.memset.p0i8.i32(i8* %dest, i8 255, i32 1, i1 false)
183  br label %bb
184bb:
185  icmp ne i8* %dest, null
186  ret void
187}
188
189define void @test7(i8* %dest, i8* %src, i32 %len) {
190; CHECK-LABEL: @test7(
191; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[DEST:%.*]], i8* [[SRC:%.*]], i32 [[LEN:%.*]], i1 false)
192; CHECK-NEXT:    br label [[BB:%.*]]
193; CHECK:       bb:
194; CHECK-NEXT:    [[KEEP1:%.*]] = icmp ne i8* [[DEST]], null
195; CHECK-NEXT:    [[KEEP2:%.*]] = icmp ne i8* [[SRC]], null
196; CHECK-NEXT:    ret void
197;
198  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 false)
199  br label %bb
200bb:
201  %KEEP1 = icmp ne i8* %dest, null
202  %KEEP2 = icmp ne i8* %src, null
203  ret void
204}
205
206declare void @llvm.memcpy.p1i8.p1i8.i32(i8 addrspace(1) *, i8 addrspace(1) *, i32, i1)
207define void @test8(i8 addrspace(1) * %dest, i8 addrspace(1) * %src) {
208; CHECK-LABEL: @test8(
209; CHECK-NEXT:    call void @llvm.memcpy.p1i8.p1i8.i32(i8 addrspace(1)* [[DEST:%.*]], i8 addrspace(1)* [[SRC:%.*]], i32 1, i1 false)
210; CHECK-NEXT:    br label [[BB:%.*]]
211; CHECK:       bb:
212; CHECK-NEXT:    [[KEEP1:%.*]] = icmp ne i8 addrspace(1)* [[DEST]], null
213; CHECK-NEXT:    [[KEEP2:%.*]] = icmp ne i8 addrspace(1)* [[SRC]], null
214; CHECK-NEXT:    ret void
215;
216  call void @llvm.memcpy.p1i8.p1i8.i32(i8 addrspace(1) * %dest, i8 addrspace(1) * %src, i32 1, i1 false)
217  br label %bb
218bb:
219  %KEEP1 = icmp ne i8 addrspace(1) * %dest, null
220  %KEEP2 = icmp ne i8 addrspace(1) * %src, null
221  ret void
222}
223
224define void @test9(i8* %dest, i8* %src) {
225; CHECK-LABEL: @test9(
226; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[DEST:%.*]], i8* [[SRC:%.*]], i32 1, i1 true)
227; CHECK-NEXT:    br label [[BB:%.*]]
228; CHECK:       bb:
229; CHECK-NEXT:    [[KEEP1:%.*]] = icmp ne i8* [[DEST]], null
230; CHECK-NEXT:    [[KEEP2:%.*]] = icmp ne i8* [[SRC]], null
231; CHECK-NEXT:    ret void
232;
233  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 1, i1 true)
234  br label %bb
235bb:
236  %KEEP1 = icmp ne i8* %dest, null
237  %KEEP2 = icmp ne i8* %src, null
238  ret void
239}
240
241declare void @test10_helper(i8* %arg1, i8* %arg2, i32 %non-pointer-arg)
242
243define void @test10(i8* %arg1, i8* %arg2, i32 %non-pointer-arg) {
244; CHECK-LABEL: @test10(
245; CHECK-NEXT:  entry:
246; CHECK-NEXT:    [[IS_NULL:%.*]] = icmp eq i8* [[ARG1:%.*]], null
247; CHECK-NEXT:    br i1 [[IS_NULL]], label [[NULL:%.*]], label [[NON_NULL:%.*]]
248; CHECK:       non_null:
249; CHECK-NEXT:    call void @test10_helper(i8* nonnull [[ARG1]], i8* [[ARG2:%.*]], i32 [[NON_POINTER_ARG:%.*]])
250; CHECK-NEXT:    br label [[NULL]]
251; CHECK:       null:
252; CHECK-NEXT:    call void @test10_helper(i8* [[ARG1]], i8* [[ARG2]], i32 [[NON_POINTER_ARG]])
253; CHECK-NEXT:    ret void
254;
255entry:
256  %is_null = icmp eq i8* %arg1, null
257  br i1 %is_null, label %null, label %non_null
258
259non_null:
260  call void @test10_helper(i8* %arg1, i8* %arg2, i32 %non-pointer-arg)
261  br label %null
262
263null:
264  call void @test10_helper(i8* %arg1, i8* %arg2, i32 %non-pointer-arg)
265  ret void
266}
267
268declare void @test11_helper(i8* %arg)
269
270define void @test11(i8* %arg1, i8** %arg2) {
271; CHECK-LABEL: @test11(
272; CHECK-NEXT:  entry:
273; CHECK-NEXT:    [[IS_NULL:%.*]] = icmp eq i8* [[ARG1:%.*]], null
274; CHECK-NEXT:    br i1 [[IS_NULL]], label [[NULL:%.*]], label [[NON_NULL:%.*]]
275; CHECK:       non_null:
276; CHECK-NEXT:    br label [[MERGE:%.*]]
277; CHECK:       null:
278; CHECK-NEXT:    [[ANOTHER_ARG:%.*]] = alloca i8, align 1
279; CHECK-NEXT:    br label [[MERGE]]
280; CHECK:       merge:
281; CHECK-NEXT:    [[MERGED_ARG:%.*]] = phi i8* [ [[ANOTHER_ARG]], [[NULL]] ], [ [[ARG1]], [[NON_NULL]] ]
282; CHECK-NEXT:    call void @test11_helper(i8* nonnull [[MERGED_ARG]])
283; CHECK-NEXT:    ret void
284;
285entry:
286  %is_null = icmp eq i8* %arg1, null
287  br i1 %is_null, label %null, label %non_null
288
289non_null:
290  br label %merge
291
292null:
293  %another_arg = alloca i8
294  br label %merge
295
296merge:
297  %merged_arg = phi i8* [%another_arg, %null], [%arg1, %non_null]
298  call void @test11_helper(i8* %merged_arg)
299  ret void
300}
301
302declare void @test12_helper(i8* %arg)
303
304define void @test12(i8* %arg1, i8** %arg2) {
305; CHECK-LABEL: @test12(
306; CHECK-NEXT:  entry:
307; CHECK-NEXT:    [[IS_NULL:%.*]] = icmp eq i8* [[ARG1:%.*]], null
308; CHECK-NEXT:    br i1 [[IS_NULL]], label [[NULL:%.*]], label [[NON_NULL:%.*]]
309; CHECK:       non_null:
310; CHECK-NEXT:    br label [[MERGE:%.*]]
311; CHECK:       null:
312; CHECK-NEXT:    [[ANOTHER_ARG:%.*]] = load i8*, i8** [[ARG2:%.*]], align 8, !nonnull !0
313; CHECK-NEXT:    br label [[MERGE]]
314; CHECK:       merge:
315; CHECK-NEXT:    [[MERGED_ARG:%.*]] = phi i8* [ [[ANOTHER_ARG]], [[NULL]] ], [ [[ARG1]], [[NON_NULL]] ]
316; CHECK-NEXT:    call void @test12_helper(i8* nonnull [[MERGED_ARG]])
317; CHECK-NEXT:    ret void
318;
319entry:
320  %is_null = icmp eq i8* %arg1, null
321  br i1 %is_null, label %null, label %non_null
322
323non_null:
324  br label %merge
325
326null:
327  %another_arg = load i8*, i8** %arg2, !nonnull !{}
328  br label %merge
329
330merge:
331  %merged_arg = phi i8* [%another_arg, %null], [%arg1, %non_null]
332  call void @test12_helper(i8* %merged_arg)
333  ret void
334}
335
336define i1 @test_store_same_block(i8* %arg) {
337; CHECK-LABEL: @test_store_same_block(
338; CHECK-NEXT:    store i8 0, i8* [[ARG:%.*]], align 1
339; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8* [[ARG]], null
340; CHECK-NEXT:    ret i1 true
341;
342  store i8 0, i8* %arg
343  %cmp = icmp ne i8* %arg, null
344  ret i1 %cmp
345}
346
347attributes #0 = { null_pointer_is_valid }
348