1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -S -simplifycfg -bonus-inst-threshold=10 | FileCheck %s
3
4declare void @sideeffect0()
5declare void @sideeffect1()
6declare void @sideeffect2()
7declare void @use8(i8)
8
9; Basic cases, blocks have nothing other than the comparison itself.
10
11define void @one_pred(i8 %v0, i8 %v1) {
12; CHECK-LABEL: @one_pred(
13; CHECK-NEXT:  pred:
14; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
15; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
16; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
17; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
18; CHECK:       final_left:
19; CHECK-NEXT:    call void @sideeffect0()
20; CHECK-NEXT:    ret void
21; CHECK:       final_right:
22; CHECK-NEXT:    call void @sideeffect1()
23; CHECK-NEXT:    ret void
24;
25pred:
26  %c0 = icmp eq i8 %v0, 0
27  br i1 %c0, label %dispatch, label %final_right
28dispatch:
29  %c1 = icmp eq i8 %v1, 0
30  br i1 %c1, label %final_left, label %final_right
31final_left:
32  call void @sideeffect0()
33  ret void
34final_right:
35  call void @sideeffect1()
36  ret void
37}
38
39define void @two_preds(i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
40; CHECK-LABEL: @two_preds(
41; CHECK-NEXT:  entry:
42; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
43; CHECK-NEXT:    br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]]
44; CHECK:       pred0:
45; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
46; CHECK-NEXT:    [[DOTOLD:%.*]] = icmp eq i8 [[V3:%.*]], 0
47; CHECK-NEXT:    [[OR_COND2:%.*]] = or i1 [[C1]], [[DOTOLD]]
48; CHECK-NEXT:    br i1 [[OR_COND2]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
49; CHECK:       pred1:
50; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
51; CHECK-NEXT:    [[C3:%.*]] = icmp eq i8 [[V3]], 0
52; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
53; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
54; CHECK:       final_left:
55; CHECK-NEXT:    call void @sideeffect0()
56; CHECK-NEXT:    ret void
57; CHECK:       final_right:
58; CHECK-NEXT:    call void @sideeffect1()
59; CHECK-NEXT:    ret void
60;
61entry:
62  %c0 = icmp eq i8 %v0, 0
63  br i1 %c0, label %pred0, label %pred1
64pred0:
65  %c1 = icmp eq i8 %v1, 0
66  br i1 %c1, label %final_left, label %dispatch
67pred1:
68  %c2 = icmp eq i8 %v2, 0
69  br i1 %c2, label %dispatch, label %final_right
70dispatch:
71  %c3 = icmp eq i8 %v3, 0
72  br i1 %c3, label %final_left, label %final_right
73final_left:
74  call void @sideeffect0()
75  ret void
76final_right:
77  call void @sideeffect1()
78  ret void
79}
80
81; More complex case, there's an extra op that is safe to execute unconditionally.
82
83define void @one_pred_with_extra_op(i8 %v0, i8 %v1) {
84; CHECK-LABEL: @one_pred_with_extra_op(
85; CHECK-NEXT:  pred:
86; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
87; CHECK-NEXT:    [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
88; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1_ADJ]], 0
89; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
90; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
91; CHECK:       final_left:
92; CHECK-NEXT:    call void @sideeffect0()
93; CHECK-NEXT:    ret void
94; CHECK:       final_right:
95; CHECK-NEXT:    call void @sideeffect1()
96; CHECK-NEXT:    ret void
97;
98pred:
99  %c0 = icmp eq i8 %v0, 0
100  br i1 %c0, label %dispatch, label %final_right
101dispatch:
102  %v1_adj = add i8 %v0, %v1
103  %c1 = icmp eq i8 %v1_adj, 0
104  br i1 %c1, label %final_left, label %final_right
105final_left:
106  call void @sideeffect0()
107  ret void
108final_right:
109  call void @sideeffect1()
110  ret void
111}
112
113define void @two_preds_with_extra_op(i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
114; CHECK-LABEL: @two_preds_with_extra_op(
115; CHECK-NEXT:  entry:
116; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
117; CHECK-NEXT:    br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]]
118; CHECK:       pred0:
119; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
120; CHECK-NEXT:    [[DOTOLD:%.*]] = add i8 [[V1]], [[V2:%.*]]
121; CHECK-NEXT:    [[DOTOLD1:%.*]] = icmp eq i8 [[DOTOLD]], 0
122; CHECK-NEXT:    [[OR_COND4:%.*]] = or i1 [[C1]], [[DOTOLD1]]
123; CHECK-NEXT:    br i1 [[OR_COND4]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
124; CHECK:       pred1:
125; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[V2]], 0
126; CHECK-NEXT:    [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
127; CHECK-NEXT:    [[C3:%.*]] = icmp eq i8 [[V3_ADJ]], 0
128; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
129; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
130; CHECK:       final_left:
131; CHECK-NEXT:    call void @sideeffect0()
132; CHECK-NEXT:    ret void
133; CHECK:       final_right:
134; CHECK-NEXT:    call void @sideeffect1()
135; CHECK-NEXT:    ret void
136;
137entry:
138  %c0 = icmp eq i8 %v0, 0
139  br i1 %c0, label %pred0, label %pred1
140pred0:
141  %c1 = icmp eq i8 %v1, 0
142  br i1 %c1, label %final_left, label %dispatch
143pred1:
144  %c2 = icmp eq i8 %v2, 0
145  br i1 %c2, label %dispatch, label %final_right
146dispatch:
147  %v3_adj = add i8 %v1, %v2
148  %c3 = icmp eq i8 %v3_adj, 0
149  br i1 %c3, label %final_left, label %final_right
150final_left:
151  call void @sideeffect0()
152  ret void
153final_right:
154  call void @sideeffect1()
155  ret void
156}
157
158; More complex case, there's an extra op that is safe to execute unconditionally, and it has multiple uses.
159
160define void @one_pred_with_extra_op_multiuse(i8 %v0, i8 %v1) {
161; CHECK-LABEL: @one_pred_with_extra_op_multiuse(
162; CHECK-NEXT:  pred:
163; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
164; CHECK-NEXT:    [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
165; CHECK-NEXT:    [[V1_ADJ_ADJ:%.*]] = add i8 [[V1_ADJ]], [[V1_ADJ]]
166; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1_ADJ_ADJ]], 0
167; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
168; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
169; CHECK:       final_left:
170; CHECK-NEXT:    call void @sideeffect0()
171; CHECK-NEXT:    ret void
172; CHECK:       final_right:
173; CHECK-NEXT:    call void @sideeffect1()
174; CHECK-NEXT:    ret void
175;
176pred:
177  %c0 = icmp eq i8 %v0, 0
178  br i1 %c0, label %dispatch, label %final_right
179dispatch:
180  %v1_adj = add i8 %v0, %v1
181  %v1_adj_adj = add i8 %v1_adj, %v1_adj
182  %c1 = icmp eq i8 %v1_adj_adj, 0
183  br i1 %c1, label %final_left, label %final_right
184final_left:
185  call void @sideeffect0()
186  ret void
187final_right:
188  call void @sideeffect1()
189  ret void
190}
191
192define void @two_preds_with_extra_op_multiuse(i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
193; CHECK-LABEL: @two_preds_with_extra_op_multiuse(
194; CHECK-NEXT:  entry:
195; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
196; CHECK-NEXT:    br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]]
197; CHECK:       pred0:
198; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
199; CHECK-NEXT:    [[DOTOLD:%.*]] = add i8 [[V1]], [[V2:%.*]]
200; CHECK-NEXT:    [[DOTOLD1:%.*]] = add i8 [[DOTOLD]], [[DOTOLD]]
201; CHECK-NEXT:    [[DOTOLD2:%.*]] = icmp eq i8 [[DOTOLD1]], 0
202; CHECK-NEXT:    [[OR_COND6:%.*]] = or i1 [[C1]], [[DOTOLD2]]
203; CHECK-NEXT:    br i1 [[OR_COND6]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
204; CHECK:       pred1:
205; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[V2]], 0
206; CHECK-NEXT:    [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
207; CHECK-NEXT:    [[V3_ADJ_ADJ:%.*]] = add i8 [[V3_ADJ]], [[V3_ADJ]]
208; CHECK-NEXT:    [[C3:%.*]] = icmp eq i8 [[V3_ADJ_ADJ]], 0
209; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
210; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
211; CHECK:       final_left:
212; CHECK-NEXT:    call void @sideeffect0()
213; CHECK-NEXT:    ret void
214; CHECK:       final_right:
215; CHECK-NEXT:    call void @sideeffect1()
216; CHECK-NEXT:    ret void
217;
218entry:
219  %c0 = icmp eq i8 %v0, 0
220  br i1 %c0, label %pred0, label %pred1
221pred0:
222  %c1 = icmp eq i8 %v1, 0
223  br i1 %c1, label %final_left, label %dispatch
224pred1:
225  %c2 = icmp eq i8 %v2, 0
226  br i1 %c2, label %dispatch, label %final_right
227dispatch:
228  %v3_adj = add i8 %v1, %v2
229  %v3_adj_adj = add i8 %v3_adj, %v3_adj
230  %c3 = icmp eq i8 %v3_adj_adj, 0
231  br i1 %c3, label %final_left, label %final_right
232final_left:
233  call void @sideeffect0()
234  ret void
235final_right:
236  call void @sideeffect1()
237  ret void
238}
239
240; More complex case, there's an op that is safe to execute unconditionally,
241; and said op is live-out.
242
243define void @one_pred_with_extra_op_liveout(i8 %v0, i8 %v1) {
244; CHECK-LABEL: @one_pred_with_extra_op_liveout(
245; CHECK-NEXT:  pred:
246; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
247; CHECK-NEXT:    [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
248; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1_ADJ]], 0
249; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
250; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
251; CHECK:       final_left:
252; CHECK-NEXT:    call void @sideeffect0()
253; CHECK-NEXT:    call void @use8(i8 [[V1_ADJ]])
254; CHECK-NEXT:    ret void
255; CHECK:       final_right:
256; CHECK-NEXT:    call void @sideeffect1()
257; CHECK-NEXT:    ret void
258;
259pred:
260  %c0 = icmp eq i8 %v0, 0
261  br i1 %c0, label %dispatch, label %final_right
262dispatch:
263  %v1_adj = add i8 %v0, %v1
264  %c1 = icmp eq i8 %v1_adj, 0
265  br i1 %c1, label %final_left, label %final_right
266final_left:
267  call void @sideeffect0()
268  call void @use8(i8 %v1_adj)
269  ret void
270final_right:
271  call void @sideeffect1()
272  ret void
273}
274define void @one_pred_with_extra_op_liveout_multiuse(i8 %v0, i8 %v1) {
275; CHECK-LABEL: @one_pred_with_extra_op_liveout_multiuse(
276; CHECK-NEXT:  pred:
277; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
278; CHECK-NEXT:    [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
279; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1_ADJ]], 0
280; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
281; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
282; CHECK:       final_left:
283; CHECK-NEXT:    call void @sideeffect0()
284; CHECK-NEXT:    call void @use8(i8 [[V1_ADJ]])
285; CHECK-NEXT:    call void @use8(i8 [[V1_ADJ]])
286; CHECK-NEXT:    ret void
287; CHECK:       final_right:
288; CHECK-NEXT:    call void @sideeffect1()
289; CHECK-NEXT:    ret void
290;
291pred:
292  %c0 = icmp eq i8 %v0, 0
293  br i1 %c0, label %dispatch, label %final_right
294dispatch:
295  %v1_adj = add i8 %v0, %v1
296  %c1 = icmp eq i8 %v1_adj, 0
297  br i1 %c1, label %final_left, label %final_right
298final_left:
299  call void @sideeffect0()
300  call void @use8(i8 %v1_adj)
301  call void @use8(i8 %v1_adj)
302  ret void
303final_right:
304  call void @sideeffect1()
305  ret void
306}
307
308define void @one_pred_with_extra_op_liveout_distant_phi(i8 %v0, i8 %v1) {
309; CHECK-LABEL: @one_pred_with_extra_op_liveout_distant_phi(
310; CHECK-NEXT:  entry:
311; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
312; CHECK-NEXT:    br i1 [[C0]], label [[PRED:%.*]], label [[LEFT_END:%.*]]
313; CHECK:       pred:
314; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
315; CHECK-NEXT:    [[V2_ADJ:%.*]] = add i8 [[V0]], [[V1]]
316; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[V2_ADJ]], 0
317; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C1]], [[C2]]
318; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
319; CHECK:       final_left:
320; CHECK-NEXT:    call void @sideeffect0()
321; CHECK-NEXT:    call void @use8(i8 [[V2_ADJ]])
322; CHECK-NEXT:    br label [[LEFT_END]]
323; CHECK:       left_end:
324; CHECK-NEXT:    [[MERGE_LEFT:%.*]] = phi i8 [ [[V2_ADJ]], [[FINAL_LEFT]] ], [ 0, [[ENTRY:%.*]] ]
325; CHECK-NEXT:    call void @sideeffect1()
326; CHECK-NEXT:    call void @use8(i8 [[MERGE_LEFT]])
327; CHECK-NEXT:    ret void
328; CHECK:       final_right:
329; CHECK-NEXT:    call void @sideeffect2()
330; CHECK-NEXT:    ret void
331;
332entry:
333  %c0 = icmp eq i8 %v0, 0
334  br i1 %c0, label %pred, label %left_end
335pred:
336  %c1 = icmp eq i8 %v1, 0
337  br i1 %c1, label %dispatch, label %final_right
338dispatch:
339  %v2_adj = add i8 %v0, %v1
340  %c2 = icmp eq i8 %v2_adj, 0
341  br i1 %c2, label %final_left, label %final_right
342final_left:
343  call void @sideeffect0()
344  call void @use8(i8 %v2_adj)
345  br label %left_end
346left_end:
347  %merge_left = phi i8 [ %v2_adj, %final_left ], [ 0, %entry ]
348  call void @sideeffect1()
349  call void @use8(i8 %merge_left)
350  ret void
351final_right:
352  call void @sideeffect2()
353  ret void
354}
355
356define void @two_preds_with_extra_op_liveout(i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
357; CHECK-LABEL: @two_preds_with_extra_op_liveout(
358; CHECK-NEXT:  entry:
359; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
360; CHECK-NEXT:    br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]]
361; CHECK:       pred0:
362; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
363; CHECK-NEXT:    br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]]
364; CHECK:       pred1:
365; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
366; CHECK-NEXT:    [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
367; CHECK-NEXT:    [[C3:%.*]] = icmp eq i8 [[V3_ADJ]], 0
368; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
369; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
370; CHECK:       dispatch:
371; CHECK-NEXT:    [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]]
372; CHECK-NEXT:    [[DOTOLD1:%.*]] = icmp eq i8 [[DOTOLD]], 0
373; CHECK-NEXT:    br i1 [[DOTOLD1]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
374; CHECK:       final_left:
375; CHECK-NEXT:    [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
376; CHECK-NEXT:    call void @use8(i8 [[MERGE_LEFT]])
377; CHECK-NEXT:    call void @sideeffect0()
378; CHECK-NEXT:    ret void
379; CHECK:       final_right:
380; CHECK-NEXT:    call void @sideeffect1()
381; CHECK-NEXT:    ret void
382;
383entry:
384  %c0 = icmp eq i8 %v0, 0
385  br i1 %c0, label %pred0, label %pred1
386pred0:
387  %c1 = icmp eq i8 %v1, 0
388  br i1 %c1, label %final_left, label %dispatch
389pred1:
390  %c2 = icmp eq i8 %v2, 0
391  br i1 %c2, label %dispatch, label %final_right
392dispatch:
393  %v3_adj = add i8 %v1, %v2
394  %c3 = icmp eq i8 %v3_adj, 0
395  br i1 %c3, label %final_left, label %final_right
396final_left:
397  %merge_left = phi i8 [ %v3_adj, %dispatch ], [ 0, %pred0 ]
398  call void @use8(i8 %merge_left)
399  call void @sideeffect0()
400  ret void
401final_right:
402  call void @sideeffect1()
403  ret void
404}
405
406define void @two_preds_with_extra_op_liveout_multiuse(i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
407; CHECK-LABEL: @two_preds_with_extra_op_liveout_multiuse(
408; CHECK-NEXT:  entry:
409; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
410; CHECK-NEXT:    br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]]
411; CHECK:       pred0:
412; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
413; CHECK-NEXT:    br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]]
414; CHECK:       pred1:
415; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
416; CHECK-NEXT:    [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
417; CHECK-NEXT:    [[C3:%.*]] = icmp eq i8 [[V3_ADJ]], 0
418; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
419; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
420; CHECK:       dispatch:
421; CHECK-NEXT:    [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]]
422; CHECK-NEXT:    [[DOTOLD1:%.*]] = icmp eq i8 [[DOTOLD]], 0
423; CHECK-NEXT:    br i1 [[DOTOLD1]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
424; CHECK:       final_left:
425; CHECK-NEXT:    [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
426; CHECK-NEXT:    [[MERGE_LEFT_2:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 42, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
427; CHECK-NEXT:    call void @use8(i8 [[MERGE_LEFT]])
428; CHECK-NEXT:    call void @use8(i8 [[MERGE_LEFT_2]])
429; CHECK-NEXT:    call void @sideeffect0()
430; CHECK-NEXT:    ret void
431; CHECK:       final_right:
432; CHECK-NEXT:    call void @sideeffect1()
433; CHECK-NEXT:    ret void
434;
435entry:
436  %c0 = icmp eq i8 %v0, 0
437  br i1 %c0, label %pred0, label %pred1
438pred0:
439  %c1 = icmp eq i8 %v1, 0
440  br i1 %c1, label %final_left, label %dispatch
441pred1:
442  %c2 = icmp eq i8 %v2, 0
443  br i1 %c2, label %dispatch, label %final_right
444dispatch:
445  %v3_adj = add i8 %v1, %v2
446  %c3 = icmp eq i8 %v3_adj, 0
447  br i1 %c3, label %final_left, label %final_right
448final_left:
449  %merge_left = phi i8 [ %v3_adj, %dispatch ], [ 0, %pred0 ]
450  %merge_left_2 = phi i8 [ %v3_adj, %dispatch ], [ 42, %pred0 ]
451  call void @use8(i8 %merge_left)
452  call void @use8(i8 %merge_left_2)
453  call void @sideeffect0()
454  ret void
455final_right:
456  call void @sideeffect1()
457  ret void
458}
459
460; More complex case, there's an op that is safe to execute unconditionally,
461; and said op is live-out, and it is only used externally.
462
463define void @one_pred_with_extra_op_eexternally_used_only(i8 %v0, i8 %v1) {
464; CHECK-LABEL: @one_pred_with_extra_op_eexternally_used_only(
465; CHECK-NEXT:  pred:
466; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
467; CHECK-NEXT:    [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
468; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1]], 0
469; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
470; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
471; CHECK:       final_left:
472; CHECK-NEXT:    call void @sideeffect0()
473; CHECK-NEXT:    call void @use8(i8 [[V1_ADJ]])
474; CHECK-NEXT:    ret void
475; CHECK:       final_right:
476; CHECK-NEXT:    call void @sideeffect1()
477; CHECK-NEXT:    ret void
478;
479pred:
480  %c0 = icmp eq i8 %v0, 0
481  br i1 %c0, label %dispatch, label %final_right
482dispatch:
483  %v1_adj = add i8 %v0, %v1
484  %c1 = icmp eq i8 %v1, 0
485  br i1 %c1, label %final_left, label %final_right
486final_left:
487  call void @sideeffect0()
488  call void @use8(i8 %v1_adj)
489  ret void
490final_right:
491  call void @sideeffect1()
492  ret void
493}
494define void @one_pred_with_extra_op_externally_used_only_multiuse(i8 %v0, i8 %v1) {
495; CHECK-LABEL: @one_pred_with_extra_op_externally_used_only_multiuse(
496; CHECK-NEXT:  pred:
497; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
498; CHECK-NEXT:    [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
499; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1]], 0
500; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
501; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
502; CHECK:       final_left:
503; CHECK-NEXT:    call void @sideeffect0()
504; CHECK-NEXT:    call void @use8(i8 [[V1_ADJ]])
505; CHECK-NEXT:    call void @use8(i8 [[V1_ADJ]])
506; CHECK-NEXT:    ret void
507; CHECK:       final_right:
508; CHECK-NEXT:    call void @sideeffect1()
509; CHECK-NEXT:    ret void
510;
511pred:
512  %c0 = icmp eq i8 %v0, 0
513  br i1 %c0, label %dispatch, label %final_right
514dispatch:
515  %v1_adj = add i8 %v0, %v1
516  %c1 = icmp eq i8 %v1, 0
517  br i1 %c1, label %final_left, label %final_right
518final_left:
519  call void @sideeffect0()
520  call void @use8(i8 %v1_adj)
521  call void @use8(i8 %v1_adj)
522  ret void
523final_right:
524  call void @sideeffect1()
525  ret void
526}
527
528define void @two_preds_with_extra_op_externally_used_only(i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
529; CHECK-LABEL: @two_preds_with_extra_op_externally_used_only(
530; CHECK-NEXT:  entry:
531; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
532; CHECK-NEXT:    br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]]
533; CHECK:       pred0:
534; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
535; CHECK-NEXT:    br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]]
536; CHECK:       pred1:
537; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
538; CHECK-NEXT:    [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
539; CHECK-NEXT:    [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0
540; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
541; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
542; CHECK:       dispatch:
543; CHECK-NEXT:    [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]]
544; CHECK-NEXT:    [[DOTOLD1:%.*]] = icmp eq i8 [[V3]], 0
545; CHECK-NEXT:    br i1 [[DOTOLD1]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
546; CHECK:       final_left:
547; CHECK-NEXT:    [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
548; CHECK-NEXT:    call void @use8(i8 [[MERGE_LEFT]])
549; CHECK-NEXT:    call void @sideeffect0()
550; CHECK-NEXT:    ret void
551; CHECK:       final_right:
552; CHECK-NEXT:    call void @sideeffect1()
553; CHECK-NEXT:    ret void
554;
555entry:
556  %c0 = icmp eq i8 %v0, 0
557  br i1 %c0, label %pred0, label %pred1
558pred0:
559  %c1 = icmp eq i8 %v1, 0
560  br i1 %c1, label %final_left, label %dispatch
561pred1:
562  %c2 = icmp eq i8 %v2, 0
563  br i1 %c2, label %dispatch, label %final_right
564dispatch:
565  %v3_adj = add i8 %v1, %v2
566  %c3 = icmp eq i8 %v3, 0
567  br i1 %c3, label %final_left, label %final_right
568final_left:
569  %merge_left = phi i8 [ %v3_adj, %dispatch ], [ 0, %pred0 ]
570  call void @use8(i8 %merge_left)
571  call void @sideeffect0()
572  ret void
573final_right:
574  call void @sideeffect1()
575  ret void
576}
577
578define void @two_preds_with_extra_op_externally_used_only_multiuse(i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
579; CHECK-LABEL: @two_preds_with_extra_op_externally_used_only_multiuse(
580; CHECK-NEXT:  entry:
581; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
582; CHECK-NEXT:    br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]]
583; CHECK:       pred0:
584; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
585; CHECK-NEXT:    br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]]
586; CHECK:       pred1:
587; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
588; CHECK-NEXT:    [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
589; CHECK-NEXT:    [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0
590; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
591; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
592; CHECK:       dispatch:
593; CHECK-NEXT:    [[DOTOLD:%.*]] = add i8 [[V1]], [[V2]]
594; CHECK-NEXT:    [[DOTOLD1:%.*]] = icmp eq i8 [[V3]], 0
595; CHECK-NEXT:    br i1 [[DOTOLD1]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
596; CHECK:       final_left:
597; CHECK-NEXT:    [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
598; CHECK-NEXT:    [[MERGE_LEFT_2:%.*]] = phi i8 [ [[DOTOLD]], [[DISPATCH]] ], [ 42, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
599; CHECK-NEXT:    call void @use8(i8 [[MERGE_LEFT]])
600; CHECK-NEXT:    call void @use8(i8 [[MERGE_LEFT_2]])
601; CHECK-NEXT:    call void @sideeffect0()
602; CHECK-NEXT:    ret void
603; CHECK:       final_right:
604; CHECK-NEXT:    call void @sideeffect1()
605; CHECK-NEXT:    ret void
606;
607entry:
608  %c0 = icmp eq i8 %v0, 0
609  br i1 %c0, label %pred0, label %pred1
610pred0:
611  %c1 = icmp eq i8 %v1, 0
612  br i1 %c1, label %final_left, label %dispatch
613pred1:
614  %c2 = icmp eq i8 %v2, 0
615  br i1 %c2, label %dispatch, label %final_right
616dispatch:
617  %v3_adj = add i8 %v1, %v2
618  %c3 = icmp eq i8 %v3, 0
619  br i1 %c3, label %final_left, label %final_right
620final_left:
621  %merge_left = phi i8 [ %v3_adj, %dispatch ], [ 0, %pred0 ]
622  %merge_left_2 = phi i8 [ %v3_adj, %dispatch ], [ 42, %pred0 ]
623  call void @use8(i8 %merge_left)
624  call void @use8(i8 %merge_left_2)
625  call void @sideeffect0()
626  ret void
627final_right:
628  call void @sideeffect1()
629  ret void
630}
631
632; The liveout instruction can be located after the branch condition.
633define void @one_pred_with_extra_op_externally_used_only_after_cond_distant_phi(i8 %v0, i8 %v1, i8 %v3, i8 %v4, i8 %v5) {
634; CHECK-LABEL: @one_pred_with_extra_op_externally_used_only_after_cond_distant_phi(
635; CHECK-NEXT:  entry:
636; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
637; CHECK-NEXT:    br i1 [[C0]], label [[PRED:%.*]], label [[LEFT_END:%.*]]
638; CHECK:       pred:
639; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
640; CHECK-NEXT:    [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0
641; CHECK-NEXT:    [[V2_ADJ:%.*]] = add i8 [[V4:%.*]], [[V5:%.*]]
642; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C1]], [[C3]]
643; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
644; CHECK:       final_left:
645; CHECK-NEXT:    call void @sideeffect0()
646; CHECK-NEXT:    call void @use8(i8 [[V2_ADJ]])
647; CHECK-NEXT:    br label [[LEFT_END]]
648; CHECK:       left_end:
649; CHECK-NEXT:    [[MERGE_LEFT:%.*]] = phi i8 [ [[V2_ADJ]], [[FINAL_LEFT]] ], [ 0, [[ENTRY:%.*]] ]
650; CHECK-NEXT:    call void @sideeffect1()
651; CHECK-NEXT:    call void @use8(i8 [[MERGE_LEFT]])
652; CHECK-NEXT:    ret void
653; CHECK:       final_right:
654; CHECK-NEXT:    call void @sideeffect2()
655; CHECK-NEXT:    ret void
656;
657entry:
658  %c0 = icmp eq i8 %v0, 0
659  br i1 %c0, label %pred, label %left_end
660pred:
661  %c1 = icmp eq i8 %v1, 0
662  br i1 %c1, label %dispatch, label %final_right
663dispatch:
664  %c3 = icmp eq i8 %v3, 0
665  %v2_adj = add i8 %v4, %v5
666  br i1 %c3, label %final_left, label %final_right
667final_left:
668  call void @sideeffect0()
669  call void @use8(i8 %v2_adj)
670  br label %left_end
671left_end:
672  %merge_left = phi i8 [ %v2_adj, %final_left ], [ 0, %entry ]
673  call void @sideeffect1()
674  call void @use8(i8 %merge_left)
675  ret void
676final_right:
677  call void @sideeffect2()
678  ret void
679}
680define void @two_preds_with_extra_op_externally_used_only_after_cond(i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
681; CHECK-LABEL: @two_preds_with_extra_op_externally_used_only_after_cond(
682; CHECK-NEXT:  entry:
683; CHECK-NEXT:    [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
684; CHECK-NEXT:    br i1 [[C0]], label [[PRED0:%.*]], label [[PRED1:%.*]]
685; CHECK:       pred0:
686; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
687; CHECK-NEXT:    br i1 [[C1]], label [[FINAL_LEFT:%.*]], label [[DISPATCH:%.*]]
688; CHECK:       pred1:
689; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
690; CHECK-NEXT:    [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0
691; CHECK-NEXT:    [[V3_ADJ:%.*]] = add i8 [[V4:%.*]], [[V5:%.*]]
692; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
693; CHECK-NEXT:    br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
694; CHECK:       dispatch:
695; CHECK-NEXT:    [[DOTOLD:%.*]] = icmp eq i8 [[V3]], 0
696; CHECK-NEXT:    [[DOTOLD1:%.*]] = add i8 [[V4]], [[V5]]
697; CHECK-NEXT:    br i1 [[DOTOLD]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
698; CHECK:       final_left:
699; CHECK-NEXT:    [[MERGE_LEFT:%.*]] = phi i8 [ [[DOTOLD1]], [[DISPATCH]] ], [ 0, [[PRED0]] ], [ [[V3_ADJ]], [[PRED1]] ]
700; CHECK-NEXT:    call void @use8(i8 [[MERGE_LEFT]])
701; CHECK-NEXT:    call void @sideeffect0()
702; CHECK-NEXT:    ret void
703; CHECK:       final_right:
704; CHECK-NEXT:    call void @sideeffect1()
705; CHECK-NEXT:    ret void
706;
707entry:
708  %c0 = icmp eq i8 %v0, 0
709  br i1 %c0, label %pred0, label %pred1
710pred0:
711  %c1 = icmp eq i8 %v1, 0
712  br i1 %c1, label %final_left, label %dispatch
713pred1:
714  %c2 = icmp eq i8 %v2, 0
715  br i1 %c2, label %dispatch, label %final_right
716dispatch:
717  %c3 = icmp eq i8 %v3, 0
718  %v3_adj = add i8 %v4, %v5
719  br i1 %c3, label %final_left, label %final_right
720final_left:
721  %merge_left = phi i8 [ %v3_adj, %dispatch ], [ 0, %pred0 ]
722  call void @use8(i8 %merge_left)
723  call void @sideeffect0()
724  ret void
725final_right:
726  call void @sideeffect1()
727  ret void
728}
729