xref: /llvm-project/llvm/test/Transforms/SimplifyCFG/jump-threading.ll (revision 07b9d231ff9baa6473b0dd588a3ce5330d3e4871)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes=simplifycfg < %s | FileCheck %s
3
4declare void @foo()
5declare void @bar()
6declare void @use.i1(i1)
7declare void @use.i32(i32)
8
9define void @test_phi_simple(i1 %c) {
10; CHECK-LABEL: @test_phi_simple(
11; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
12; CHECK:       if:
13; CHECK-NEXT:    call void @foo()
14; CHECK-NEXT:    call void @foo()
15; CHECK-NEXT:    br label [[JOIN2:%.*]]
16; CHECK:       else:
17; CHECK-NEXT:    call void @bar()
18; CHECK-NEXT:    call void @bar()
19; CHECK-NEXT:    br label [[JOIN2]]
20; CHECK:       join2:
21; CHECK-NEXT:    ret void
22;
23  br i1 %c, label %if, label %else
24
25if:
26  call void @foo()
27  br label %join
28
29else:
30  call void @bar()
31  br label %join
32
33join:
34  %c2 = phi i1 [ true, %if ], [ false, %else ]
35  br i1 %c2, label %if2, label %else2
36
37if2:
38  call void @foo()
39  br label %join2
40
41else2:
42  call void @bar()
43  br label %join2
44
45join2:
46  ret void
47}
48
49define void @test_phi_extra_use(i1 %c) {
50; CHECK-LABEL: @test_phi_extra_use(
51; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
52; CHECK:       if:
53; CHECK-NEXT:    call void @foo()
54; CHECK-NEXT:    call void @use.i1(i1 true)
55; CHECK-NEXT:    call void @foo()
56; CHECK-NEXT:    br label [[JOIN2:%.*]]
57; CHECK:       else:
58; CHECK-NEXT:    call void @bar()
59; CHECK-NEXT:    call void @use.i1(i1 false)
60; CHECK-NEXT:    call void @bar()
61; CHECK-NEXT:    br label [[JOIN2]]
62; CHECK:       join2:
63; CHECK-NEXT:    ret void
64;
65  br i1 %c, label %if, label %else
66
67if:
68  call void @foo()
69  br label %join
70
71else:
72  call void @bar()
73  br label %join
74
75join:
76  %c2 = phi i1 [ true, %if ], [ false, %else ]
77  call void @use.i1(i1 %c2)
78  br i1 %c2, label %if2, label %else2
79
80if2:
81  call void @foo()
82  br label %join2
83
84else2:
85  call void @bar()
86  br label %join2
87
88join2:
89  ret void
90}
91
92define void @test_phi_extra_use_different_block(i1 %c) {
93; CHECK-LABEL: @test_phi_extra_use_different_block(
94; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
95; CHECK:       if:
96; CHECK-NEXT:    call void @foo()
97; CHECK-NEXT:    br label [[JOIN:%.*]]
98; CHECK:       else:
99; CHECK-NEXT:    call void @bar()
100; CHECK-NEXT:    br label [[JOIN]]
101; CHECK:       join:
102; CHECK-NEXT:    [[C2:%.*]] = phi i1 [ true, [[IF]] ], [ false, [[ELSE]] ]
103; CHECK-NEXT:    br i1 [[C2]], label [[IF2:%.*]], label [[ELSE2:%.*]]
104; CHECK:       if2:
105; CHECK-NEXT:    call void @use.i1(i1 [[C2]])
106; CHECK-NEXT:    call void @foo()
107; CHECK-NEXT:    br label [[JOIN2:%.*]]
108; CHECK:       else2:
109; CHECK-NEXT:    call void @use.i1(i1 [[C2]])
110; CHECK-NEXT:    call void @bar()
111; CHECK-NEXT:    br label [[JOIN2]]
112; CHECK:       join2:
113; CHECK-NEXT:    ret void
114;
115  br i1 %c, label %if, label %else
116
117if:
118  call void @foo()
119  br label %join
120
121else:
122  call void @bar()
123  br label %join
124
125join:
126  %c2 = phi i1 [ true, %if ], [ false, %else ]
127  br i1 %c2, label %if2, label %else2
128
129if2:
130  call void @use.i1(i1 %c2)
131  call void @foo()
132  br label %join2
133
134else2:
135  call void @use.i1(i1 %c2)
136  call void @bar()
137  br label %join2
138
139join2:
140  ret void
141}
142
143define void @test_same_cond_simple(i1 %c) {
144; CHECK-LABEL: @test_same_cond_simple(
145; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
146; CHECK:       if:
147; CHECK-NEXT:    call void @foo()
148; CHECK-NEXT:    br label [[JOIN:%.*]]
149; CHECK:       else:
150; CHECK-NEXT:    call void @bar()
151; CHECK-NEXT:    br label [[JOIN]]
152; CHECK:       join:
153; CHECK-NEXT:    br i1 [[C]], label [[IF2:%.*]], label [[ELSE2:%.*]]
154; CHECK:       if2:
155; CHECK-NEXT:    call void @foo()
156; CHECK-NEXT:    br label [[JOIN2:%.*]]
157; CHECK:       else2:
158; CHECK-NEXT:    call void @bar()
159; CHECK-NEXT:    br label [[JOIN2]]
160; CHECK:       join2:
161; CHECK-NEXT:    ret void
162;
163  br i1 %c, label %if, label %else
164
165if:
166  call void @foo()
167  br label %join
168
169else:
170  call void @bar()
171  br label %join
172
173join:
174  br i1 %c, label %if2, label %else2
175
176if2:
177  call void @foo()
178  br label %join2
179
180else2:
181  call void @bar()
182  br label %join2
183
184join2:
185  ret void
186}
187
188define void @test_same_cond_extra_use(i1 %c) {
189; CHECK-LABEL: @test_same_cond_extra_use(
190; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
191; CHECK:       if:
192; CHECK-NEXT:    call void @foo()
193; CHECK-NEXT:    br label [[JOIN:%.*]]
194; CHECK:       else:
195; CHECK-NEXT:    call void @bar()
196; CHECK-NEXT:    br label [[JOIN]]
197; CHECK:       join:
198; CHECK-NEXT:    call void @use.i1(i1 [[C]])
199; CHECK-NEXT:    br i1 [[C]], label [[IF2:%.*]], label [[ELSE2:%.*]]
200; CHECK:       if2:
201; CHECK-NEXT:    call void @foo()
202; CHECK-NEXT:    br label [[JOIN2:%.*]]
203; CHECK:       else2:
204; CHECK-NEXT:    call void @bar()
205; CHECK-NEXT:    br label [[JOIN2]]
206; CHECK:       join2:
207; CHECK-NEXT:    ret void
208;
209  br i1 %c, label %if, label %else
210
211if:
212  call void @foo()
213  br label %join
214
215else:
216  call void @bar()
217  br label %join
218
219join:
220  call void @use.i1(i1 %c)
221  br i1 %c, label %if2, label %else2
222
223if2:
224  call void @foo()
225  br label %join2
226
227else2:
228  call void @bar()
229  br label %join2
230
231join2:
232  ret void
233}
234
235define void @test_same_cond_extra_use_different_block(i1 %c) {
236; CHECK-LABEL: @test_same_cond_extra_use_different_block(
237; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
238; CHECK:       if:
239; CHECK-NEXT:    call void @foo()
240; CHECK-NEXT:    br label [[JOIN:%.*]]
241; CHECK:       else:
242; CHECK-NEXT:    call void @bar()
243; CHECK-NEXT:    br label [[JOIN]]
244; CHECK:       join:
245; CHECK-NEXT:    br i1 [[C]], label [[IF2:%.*]], label [[ELSE2:%.*]]
246; CHECK:       if2:
247; CHECK-NEXT:    call void @use.i1(i1 [[C]])
248; CHECK-NEXT:    call void @foo()
249; CHECK-NEXT:    br label [[JOIN2:%.*]]
250; CHECK:       else2:
251; CHECK-NEXT:    call void @use.i1(i1 [[C]])
252; CHECK-NEXT:    call void @bar()
253; CHECK-NEXT:    br label [[JOIN2]]
254; CHECK:       join2:
255; CHECK-NEXT:    ret void
256;
257  br i1 %c, label %if, label %else
258
259if:
260  call void @foo()
261  br label %join
262
263else:
264  call void @bar()
265  br label %join
266
267join:
268  br i1 %c, label %if2, label %else2
269
270if2:
271  call void @use.i1(i1 %c)
272  call void @foo()
273  br label %join2
274
275else2:
276  call void @use.i1(i1 %c)
277  call void @bar()
278  br label %join2
279
280join2:
281  ret void
282}
283
284define void @test_multiple_threadable_preds_with_phi(i1 %cond1, i1 %cond2) {
285; CHECK-LABEL: @test_multiple_threadable_preds_with_phi(
286; CHECK-NEXT:    br i1 [[COND1:%.*]], label [[IF1:%.*]], label [[IF2:%.*]]
287; CHECK:       if1:
288; CHECK-NEXT:    call void @foo()
289; CHECK-NEXT:    br i1 [[COND2:%.*]], label [[IF3_CRITEDGE:%.*]], label [[EXIT:%.*]]
290; CHECK:       if2:
291; CHECK-NEXT:    call void @bar()
292; CHECK-NEXT:    br i1 [[COND2]], label [[IF3_CRITEDGE]], label [[EXIT]]
293; CHECK:       if3.critedge:
294; CHECK-NEXT:    [[PHI_PH:%.*]] = phi i32 [ 2, [[IF2]] ], [ 1, [[IF1]] ]
295; CHECK-NEXT:    call void @use.i32(i32 [[PHI_PH]])
296; CHECK-NEXT:    call void @foo()
297; CHECK-NEXT:    br label [[EXIT]]
298; CHECK:       exit:
299; CHECK-NEXT:    ret void
300;
301  br i1 %cond1, label %if1, label %if2
302
303if1:
304  call void @foo()
305  br i1 %cond2, label %join, label %exit
306
307if2:
308  call void @bar()
309  br i1 %cond2, label %join, label %exit
310
311join:
312  %phi = phi i32 [ 1, %if1 ], [ 2, %if2 ]
313  call void @use.i32(i32 %phi)
314  br i1 %cond2, label %if3, label %exit
315
316if3:
317  call void @foo()
318  br label %exit
319
320exit:
321  ret void
322}
323
324; This test case used to infinite loop.
325
326define void @infloop(i1 %cmp.a, i1 %cmp.b, i1 %cmp.c) {
327; CHECK-LABEL: @infloop(
328; CHECK-NEXT:  entry:
329; CHECK-NEXT:    br label [[WHILE_COND:%.*]]
330; CHECK:       while.cond:
331; CHECK-NEXT:    br i1 [[CMP_A:%.*]], label [[FOR:%.*]], label [[WHILE_BODY_THREAD:%.*]]
332; CHECK:       for.body:
333; CHECK-NEXT:    br i1 [[CMP_B:%.*]], label [[WHILE_BODY:%.*]], label [[FOR_BODY:%.*]]
334; CHECK:       for:
335; CHECK-NEXT:    tail call void @foo()
336; CHECK-NEXT:    br label [[FOR_BODY]]
337; CHECK:       while.body:
338; CHECK-NEXT:    br i1 [[CMP_C:%.*]], label [[C_EXIT:%.*]], label [[LAND:%.*]]
339; CHECK:       while.body.thread:
340; CHECK-NEXT:    br i1 [[CMP_C]], label [[WHILE_COND]], label [[LAND]]
341; CHECK:       land:
342; CHECK-NEXT:    tail call void @bar()
343; CHECK-NEXT:    br label [[WHILE_COND]]
344; CHECK:       c.exit:
345; CHECK-NEXT:    br i1 [[CMP_A]], label [[FOR_D:%.*]], label [[WHILE_BODY_THREAD]]
346; CHECK:       for.d:
347; CHECK-NEXT:    ret void
348;
349entry:
350  br label %while.cond
351
352while.cond:                                       ; preds = %land, %while.body.thread, %entry
353  br i1 %cmp.a, label %for, label %while.body.thread
354
355for.body:                                         ; preds = %for, %for.body
356  br i1 %cmp.b, label %while.body, label %for.body
357
358for:                                              ; preds = %while.cond
359  tail call void @foo()
360  br label %for.body
361
362while.body:                                       ; preds = %for.body
363  br i1 %cmp.c, label %c.exit, label %land
364
365while.body.thread:                                ; preds = %c.exit, %while.cond
366  br i1 %cmp.c, label %while.cond, label %land
367
368land:                                             ; preds = %while.body.thread, %while.body
369  tail call void @bar()
370  br label %while.cond
371
372c.exit:                                           ; preds = %while.body
373  br i1 %cmp.a, label %for.d, label %while.cond
374
375for.d:                                            ; preds = %c.exit
376  ret void
377}
378
379; A combination of "branch to common dest" and jump threading kept peeling
380; off loop iterations here.
381
382define void @infloop_pr56203(i1 %c1, i1 %c2) {
383; CHECK-LABEL: @infloop_pr56203(
384; CHECK-NEXT:  entry:
385; CHECK-NEXT:    br i1 [[C1:%.*]], label [[EXIT:%.*]], label [[IF:%.*]]
386; CHECK:       if:
387; CHECK-NEXT:    call void @foo()
388; CHECK-NEXT:    [[C3:%.*]] = icmp eq i64 0, 0
389; CHECK-NEXT:    [[OR_COND:%.*]] = or i1 [[C2:%.*]], [[C3]]
390; CHECK-NEXT:    br i1 [[OR_COND]], label [[EXIT]], label [[LOOP_SPLIT:%.*]]
391; CHECK:       loop:
392; CHECK-NEXT:    [[C3_OLD:%.*]] = icmp eq i64 0, 0
393; CHECK-NEXT:    br i1 [[C3_OLD]], label [[EXIT]], label [[LOOP_SPLIT]]
394; CHECK:       loop.split:
395; CHECK-NEXT:    br i1 [[C1]], label [[LOOP_LATCH:%.*]], label [[LOOP:%.*]]
396; CHECK:       loop.latch:
397; CHECK-NEXT:    call void @foo()
398; CHECK-NEXT:    br label [[LOOP]]
399; CHECK:       exit:
400; CHECK-NEXT:    ret void
401;
402entry:
403  br i1 %c1, label %exit, label %if
404
405if:
406  call void @foo()
407  br i1 %c2, label %exit, label %loop
408
409loop:
410  %c3 = icmp eq i64 0, 0
411  br i1 %c3, label %exit, label %loop.split
412
413loop.split:
414  br i1 %c1, label %loop.latch, label %loop
415
416loop.latch:
417  call void @foo()
418  br label %loop
419
420exit:
421  ret void
422}
423
424define void @callbr() {
425; CHECK-LABEL: @callbr(
426; CHECK-NEXT:  entry:
427; CHECK-NEXT:    callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"()
428; CHECK-NEXT:            to label [[IF_END:%.*]] [label %if.end]
429; CHECK:       if.end:
430; CHECK-NEXT:    ret void
431;
432entry:
433  callbr void asm sideeffect "", "!i,~{dirflag},~{fpsr},~{flags}"()
434  to label %join [label %target]
435
436target:
437  br label %join
438
439join:
440  %phi = phi i1 [ false, %target ], [ false, %entry ]
441  br i1 %phi, label %if.then, label %if.end
442
443if.then:
444  call void @foo()
445  br label %if.end
446
447if.end:
448  ret void
449}
450