xref: /llvm-project/llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll (revision b7e51b4f139ec18c498c818c6bcaa5a842cea83c)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
2; RUN: opt -passes=ipsccp -S %s | FileCheck %s
3
4%t1 = type opaque
5
6@e = common global i32 0, align 4
7
8; Test that we a skip unknown values depending on a unknown tracked call, until the call gets resolved. The @test1 and @test2 variants are very similar, they just check 2 different kinds of users (icmp and zext)
9
10define i32 @test1_m(i32 %h) {
11; CHECK-LABEL: define {{[^@]+}}@test1_m
12; CHECK-SAME: (i32 [[H:%.*]]) {
13; CHECK-NEXT:  entry:
14; CHECK-NEXT:    [[CONV:%.*]] = trunc i32 [[H]] to i8
15; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test1_k(i8 [[CONV]], i32 0)
16; CHECK-NEXT:    [[CONV1:%.*]] = sext i32 [[H]] to i64
17; CHECK-NEXT:    [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to ptr
18; CHECK-NEXT:    [[CALL2:%.*]] = call i1 @test1_g(ptr [[TMP0]], i32 1)
19; CHECK-NEXT:    ret i32 undef
20;
21entry:
22  %conv = trunc i32 %h to i8
23  %call = call i32 @test1_k(i8 %conv, i32 0)
24  %conv1 = sext i32 %h to i64
25  %0 = inttoptr i64 %conv1 to ptr
26  %call2 = call i1 @test1_g(ptr %0, i32 1)
27  ret i32 undef
28
29; uselistorder directives
30  uselistorder i32 %h, { 1, 0 }
31}
32
33declare void @use.1(i1)
34
35define internal i32 @test1_k(i8 %h, i32 %i) {
36; CHECK-LABEL: define {{[^@]+}}@test1_k
37; CHECK-SAME: (i8 [[H:%.*]], i32 [[I:%.*]]) {
38; CHECK-NEXT:  entry:
39; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @e, align 4
40; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[TMP0]] to i64
41; CHECK-NEXT:    [[TMP1:%.*]] = inttoptr i64 [[CONV]] to ptr
42; CHECK-NEXT:    [[CALL:%.*]] = call i1 @test1_g(ptr [[TMP1]], i32 0)
43; CHECK-NEXT:    call void @use.1(i1 false)
44; CHECK-NEXT:    ret i32 undef
45;
46entry:
47  %0 = load i32, ptr @e, align 4
48  %conv = sext i32 %0 to i64
49  %1 = inttoptr i64 %conv to ptr
50  %call = call i1 @test1_g(ptr %1, i32 %i)
51  %frombool.1 = zext i1 %call to i8
52  %tobool.1 = trunc i8 %frombool.1 to i1
53  call void @use.1(i1 %tobool.1)
54  ret i32 undef
55}
56
57define internal i1 @test1_g(ptr %h, i32 %i) #0 {
58; CHECK-LABEL: define {{[^@]+}}@test1_g
59; CHECK-SAME: (ptr [[H:%.*]], i32 range(i32 0, 2) [[I:%.*]]) {
60; CHECK-NEXT:  entry:
61; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[I]], 0
62; CHECK-NEXT:    br i1 [[TOBOOL]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]]
63; CHECK:       land.rhs:
64; CHECK-NEXT:    [[CALL:%.*]] = call i32 (...) @test1_j()
65; CHECK-NEXT:    [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0
66; CHECK-NEXT:    br label [[LAND_END]]
67; CHECK:       land.end:
68; CHECK-NEXT:    [[TMP0:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[TOBOOL1]], [[LAND_RHS]] ]
69; CHECK-NEXT:    ret i1 poison
70;
71entry:
72  %tobool = icmp ne i32 %i, 0
73  br i1 %tobool, label %land.rhs, label %land.end
74
75land.rhs:                                         ; preds = %entry
76  %call = call i32 (...) @test1_j()
77  %tobool1 = icmp ne i32 %call, 0
78  br label %land.end
79
80land.end:                                         ; preds = %land.rhs, %entry
81  %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ]
82  ret i1 false
83}
84
85declare i32 @test1_j(...)
86
87define i32 @test2_m(i32 %h) #0 {
88; CHECK-LABEL: define {{[^@]+}}@test2_m
89; CHECK-SAME: (i32 [[H:%.*]]) {
90; CHECK-NEXT:  entry:
91; CHECK-NEXT:    [[CONV:%.*]] = trunc i32 [[H]] to i8
92; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test2_k(i8 [[CONV]], i32 0)
93; CHECK-NEXT:    [[CONV1:%.*]] = sext i32 [[H]] to i64
94; CHECK-NEXT:    [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to ptr
95; CHECK-NEXT:    [[CALL2:%.*]] = call i1 @test2_g(ptr [[TMP0]], i32 1)
96; CHECK-NEXT:    ret i32 undef
97;
98entry:
99  %conv = trunc i32 %h to i8
100  %call = call i32 @test2_k(i8 %conv, i32 0)
101  %conv1 = sext i32 %h to i64
102  %0 = inttoptr i64 %conv1 to ptr
103  %call2 = call i1 @test2_g(ptr %0, i32 1)
104  ret i32 undef
105
106; uselistorder directives
107  uselistorder i32 %h, { 1, 0 }
108}
109
110; TODO: We could do better for the return value of call i1 @test3_g, if we
111;       resolve the unknown values there first.
112define internal i32 @test2_k(i8 %h, i32 %i) {
113; CHECK-LABEL: define {{[^@]+}}@test2_k
114; CHECK-SAME: (i8 [[H:%.*]], i32 [[I:%.*]]) {
115; CHECK-NEXT:  entry:
116; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @e, align 4
117; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[TMP0]] to i64
118; CHECK-NEXT:    [[TMP1:%.*]] = inttoptr i64 [[CONV]] to ptr
119; CHECK-NEXT:    [[CALL:%.*]] = call i1 @test3_g(ptr [[TMP1]], i32 0)
120; CHECK-NEXT:    call void @use.1(i1 false)
121; CHECK-NEXT:    ret i32 undef
122;
123entry:
124  %0 = load i32, ptr @e, align 4
125  %conv = sext i32 %0 to i64
126  %1 = inttoptr i64 %conv to ptr
127  %call = call i1 @test3_g(ptr %1, i32 %i)
128  %frombool = icmp slt i1 %call, 1
129  %add = add i1 %frombool, %frombool
130  call void @use.1(i1 %frombool)
131  ret i32 undef
132
133}
134
135define internal i1 @test2_g(ptr %h, i32 %i) {
136; CHECK-LABEL: define {{[^@]+}}@test2_g
137; CHECK-SAME: (ptr [[H:%.*]], i32 [[I:%.*]]) {
138; CHECK-NEXT:  entry:
139; CHECK-NEXT:    br label [[LAND_RHS:%.*]]
140; CHECK:       land.rhs:
141; CHECK-NEXT:    [[CALL:%.*]] = call i32 (...) @test2_j()
142; CHECK-NEXT:    [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0
143; CHECK-NEXT:    br label [[LAND_END:%.*]]
144; CHECK:       land.end:
145; CHECK-NEXT:    ret i1 poison
146;
147entry:
148  %tobool = icmp ne i32 %i, 0
149  br i1 %tobool, label %land.rhs, label %land.end
150
151land.rhs:                                         ; preds = %entry
152  %call = call i32 (...) @test2_j()
153  %tobool1 = icmp ne i32 %call, 0
154  br label %land.end
155
156land.end:                                         ; preds = %land.rhs, %entry
157  %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ]
158  ret i1 false
159}
160
161declare i32 @test2_j(...)
162
163
164
165; Same as test_2*, but with a PHI node depending on a tracked  call result.
166define i32 @test3_m(i32 %h) #0 {
167; CHECK-LABEL: define {{[^@]+}}@test3_m
168; CHECK-SAME: (i32 [[H:%.*]]) {
169; CHECK-NEXT:  entry:
170; CHECK-NEXT:    [[CONV:%.*]] = trunc i32 [[H]] to i8
171; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test3_k(i8 [[CONV]], i32 0)
172; CHECK-NEXT:    [[CONV1:%.*]] = sext i32 [[H]] to i64
173; CHECK-NEXT:    [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to ptr
174; CHECK-NEXT:    [[CALL2:%.*]] = call i1 @test3_g(ptr [[TMP0]], i32 1)
175; CHECK-NEXT:    ret i32 undef
176;
177entry:
178  %conv = trunc i32 %h to i8
179  %call = call i32 @test3_k(i8 %conv, i32 0)
180  %conv1 = sext i32 %h to i64
181  %0 = inttoptr i64 %conv1 to ptr
182  %call2 = call i1 @test3_g(ptr %0, i32 1)
183  ret i32 undef
184
185; uselistorder directives
186  uselistorder i32 %h, { 1, 0 }
187}
188
189define internal i32 @test3_k(i8 %h, i32 %i) {
190; CHECK-LABEL: define {{[^@]+}}@test3_k
191; CHECK-SAME: (i8 [[H:%.*]], i32 [[I:%.*]]) {
192; CHECK-NEXT:  entry:
193; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @e, align 4
194; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[TMP0]] to i64
195; CHECK-NEXT:    [[TMP1:%.*]] = inttoptr i64 [[CONV]] to ptr
196; CHECK-NEXT:    br label [[LOOP:%.*]]
197; CHECK:       loop:
198; CHECK-NEXT:    [[CALL:%.*]] = call i1 @test3_g(ptr [[TMP1]], i32 0)
199; CHECK-NEXT:    call void @use.1(i1 false)
200; CHECK-NEXT:    br label [[EXIT:%.*]]
201; CHECK:       exit:
202; CHECK-NEXT:    ret i32 undef
203;
204entry:
205  %0 = load i32, ptr @e, align 4
206  %conv = sext i32 %0 to i64
207  %1 = inttoptr i64 %conv to ptr
208  br label %loop
209
210loop:
211  %phi = phi i1 [ undef, %entry], [ %call, %loop ]
212  %call = call i1 @test3_g(ptr %1, i32 %i)
213  %frombool = icmp slt i1 %call, 1
214  %add = add i1 %frombool, %frombool
215  call void @use.1(i1 %frombool)
216  br i1 %call, label %loop, label %exit
217
218exit:
219  ret i32 undef
220}
221
222define internal i1 @test3_g(ptr %h, i32 %i) {
223; CHECK-LABEL: define {{[^@]+}}@test3_g
224; CHECK-SAME: (ptr [[H:%.*]], i32 range(i32 0, 2) [[I:%.*]]) {
225; CHECK-NEXT:  entry:
226; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[I]], 0
227; CHECK-NEXT:    br i1 [[TOBOOL]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]]
228; CHECK:       land.rhs:
229; CHECK-NEXT:    [[CALL:%.*]] = call i32 (...) @test3_j()
230; CHECK-NEXT:    [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0
231; CHECK-NEXT:    br label [[LAND_END]]
232; CHECK:       land.end:
233; CHECK-NEXT:    [[TMP0:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[TOBOOL1]], [[LAND_RHS]] ]
234; CHECK-NEXT:    ret i1 poison
235;
236entry:
237  %tobool = icmp ne i32 %i, 0
238  br i1 %tobool, label %land.rhs, label %land.end
239
240land.rhs:                                         ; preds = %entry
241  %call = call i32 (...) @test3_j()
242  %tobool1 = icmp ne i32 %call, 0
243  br label %land.end
244
245land.end:                                         ; preds = %land.rhs, %entry
246  %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ]
247  ret i1 false
248}
249
250declare i32 @test3_j(...)
251
252
253; TODO: We can eliminate the bitcast, if we resolve the unknown argument of
254;       @test4_b first.
255
256declare void @use.16(ptr)
257declare void @use.8(ptr)
258
259define void @test4_a() {
260; CHECK-LABEL: define {{[^@]+}}@test4_a() {
261; CHECK-NEXT:  bb:
262; CHECK-NEXT:    [[TMP:%.*]] = call ptr @test4_c(ptr null)
263; CHECK-NEXT:    call void @test4_b(ptr null)
264; CHECK-NEXT:    ret void
265;
266bb:
267  %tmp = call ptr @test4_c(ptr null)
268  call void @test4_b(ptr %tmp)
269  ret void
270}
271
272define internal void @test4_b(ptr %arg) {
273; CHECK-LABEL: define {{[^@]+}}@test4_b
274; CHECK-SAME: (ptr [[ARG:%.*]]) {
275; CHECK-NEXT:  bb:
276; CHECK-NEXT:    [[SEL:%.*]] = select i1 false, ptr null, ptr null
277; CHECK-NEXT:    call void @use.16(ptr null)
278; CHECK-NEXT:    call void @use.8(ptr [[SEL]])
279; CHECK-NEXT:    ret void
280;
281bb:
282  %sel = select i1 false, ptr %arg, ptr %arg
283  call void @use.16(ptr %arg)
284  call void @use.8(ptr %sel)
285  ret void
286}
287
288define internal ptr @test4_c(ptr %arg) {
289; CHECK-LABEL: define {{[^@]+}}@test4_c
290; CHECK-SAME: (ptr [[ARG:%.*]]) {
291; CHECK-NEXT:  bb1:
292; CHECK-NEXT:    [[TMP:%.*]] = and i1 undef, undef
293; CHECK-NEXT:    br i1 [[TMP]], label [[BB3:%.*]], label [[BB2:%.*]]
294; CHECK:       bb2:
295; CHECK-NEXT:    unreachable
296; CHECK:       bb3:
297; CHECK-NEXT:    ret ptr poison
298;
299bb1:                                              ; preds = %bb
300  %tmp = and i1 undef, undef
301  br i1 %tmp, label %bb3, label %bb2
302
303bb2:                                              ; preds = %bb1
304  unreachable
305
306bb3:                                              ; preds = %bb1
307  ret ptr null
308}
309
310; TODO: Same as test4, but with a select instead of a bitcast.
311
312define void @test5_a() {
313; CHECK-LABEL: define {{[^@]+}}@test5_a() {
314; CHECK-NEXT:  bb:
315; CHECK-NEXT:    [[TMP:%.*]] = call ptr @test5_c(ptr null)
316; CHECK-NEXT:    call void @test5_b(ptr null)
317; CHECK-NEXT:    ret void
318;
319bb:
320  %tmp = call ptr @test5_c(ptr null)
321  call void @test5_b(ptr %tmp)
322  ret void
323}
324
325define internal void @test5_b(ptr %arg) {
326; CHECK-LABEL: define {{[^@]+}}@test5_b
327; CHECK-SAME: (ptr [[ARG:%.*]]) {
328; CHECK-NEXT:  bb:
329; CHECK-NEXT:    [[SEL:%.*]] = select i1 false, ptr null, ptr null
330; CHECK-NEXT:    call void @use.8(ptr [[SEL]])
331; CHECK-NEXT:    ret void
332;
333bb:
334  %sel = select i1 false, ptr %arg, ptr %arg
335  call void @use.8(ptr %sel)
336  ret void
337}
338
339define internal ptr @test5_c(ptr %arg) {
340; CHECK-LABEL: define {{[^@]+}}@test5_c
341; CHECK-SAME: (ptr [[ARG:%.*]]) {
342; CHECK-NEXT:  bb1:
343; CHECK-NEXT:    [[TMP:%.*]] = and i1 undef, undef
344; CHECK-NEXT:    br i1 [[TMP]], label [[BB3:%.*]], label [[BB2:%.*]]
345; CHECK:       bb2:
346; CHECK-NEXT:    unreachable
347; CHECK:       bb3:
348; CHECK-NEXT:    ret ptr poison
349;
350bb1:                                              ; preds = %bb
351  %tmp = and i1 undef, undef
352  br i1 %tmp, label %bb3, label %bb2
353
354bb2:                                              ; preds = %bb1
355  unreachable
356
357bb3:                                              ; preds = %bb1
358  ret ptr null
359}
360
361
362
363@contextsize = external dso_local local_unnamed_addr global i32, align 4
364@pcount = internal local_unnamed_addr global i32 0, align 4
365@maxposslen = external dso_local local_unnamed_addr global i32, align 4
366
367define void @test3() {
368; CHECK-LABEL: define {{[^@]+}}@test3() {
369; CHECK-NEXT:  entry:
370; CHECK-NEXT:    br label [[IF_END16:%.*]]
371; CHECK:       if.end16:
372; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @contextsize, align 4
373; CHECK-NEXT:    [[SUB18:%.*]] = sub i32 undef, [[TMP0]]
374; CHECK-NEXT:    [[SUB19:%.*]] = sub i32 [[SUB18]], undef
375; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr @maxposslen, align 4
376; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP1]], 8
377; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 undef, [[ADD]]
378; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr @pcount, align 4
379; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[DIV]], [[SUB19]]
380; CHECK-NEXT:    [[CMP20:%.*]] = icmp sgt i32 [[TMP2]], [[MUL]]
381; CHECK-NEXT:    br i1 [[CMP20]], label [[IF_THEN22:%.*]], label [[IF_END24:%.*]]
382; CHECK:       if.then22:
383; CHECK-NEXT:    store i32 [[MUL]], ptr @pcount, align 4
384; CHECK-NEXT:    ret void
385; CHECK:       if.end24:
386; CHECK-NEXT:    [[CMP25474:%.*]] = icmp sgt i32 [[TMP2]], 0
387; CHECK-NEXT:    br i1 [[CMP25474]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
388; CHECK:       for.body:
389; CHECK-NEXT:    ret void
390; CHECK:       for.end:
391; CHECK-NEXT:    ret void
392;
393entry:
394  br label %if.end16
395
396if.end16:                                         ; preds = %entry
397  %0 = load i32, ptr @contextsize, align 4
398  %sub18 = sub i32 undef, %0
399  %sub19 = sub i32 %sub18, undef
400  %1 = load i32, ptr @maxposslen, align 4
401  %add = add nsw i32 %1, 8
402  %div = sdiv i32 undef, %add
403  %2 = load i32, ptr @pcount, align 4
404  %mul = mul nsw i32 %div, %sub19
405  %cmp20 = icmp sgt i32 %2, %mul
406  br i1 %cmp20, label %if.then22, label %if.end24
407
408if.then22:                                        ; preds = %if.end16
409  store i32 %mul, ptr @pcount, align 4
410  ret void
411
412if.end24:                                         ; preds = %if.end16
413  %cmp25474 = icmp sgt i32 %2, 0
414  br i1 %cmp25474, label %for.body, label %for.end
415
416for.body:                                         ; preds = %if.end24
417  %3 = trunc i64 0 to i32
418  %div30 = sdiv i32 %3, %sub19
419  ret void
420
421for.end:                                          ; preds = %if.end24
422  ret void
423}
424