xref: /llvm-project/llvm/test/Transforms/SimplifyCFG/hoist-common-code.ll (revision b3fa45b64265d182ba081b2cfdcce454b72280d5)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S -hoist-common-insts=true | FileCheck %s
3
4declare void @bar(i32)
5
6define void @test(i1 %P, ptr %Q) {
7; CHECK-LABEL: @test(
8; CHECK-NEXT:  common.ret:
9; CHECK-NEXT:    store i32 1, ptr [[Q:%.*]], align 4
10; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[Q]], align 4
11; CHECK-NEXT:    call void @bar(i32 [[A]])
12; CHECK-NEXT:    ret void
13;
14  br i1 %P, label %T, label %F
15T:              ; preds = %0
16  store i32 1, ptr %Q
17  %A = load i32, ptr %Q               ; <i32> [#uses=1]
18  call void @bar( i32 %A )
19  ret void
20F:              ; preds = %0
21  store i32 1, ptr %Q
22  %B = load i32, ptr %Q               ; <i32> [#uses=1]
23  call void @bar( i32 %B )
24  ret void
25}
26
27define void @test_switch(i64 %i, ptr %Q) {
28; CHECK-LABEL: @test_switch(
29; CHECK-NEXT:  common.ret:
30; CHECK-NEXT:    store i32 1, ptr [[Q:%.*]], align 4
31; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[Q]], align 4
32; CHECK-NEXT:    call void @bar(i32 [[A]])
33; CHECK-NEXT:    ret void
34;
35  switch i64 %i, label %bb0 [
36  i64 1, label %bb1
37  i64 2, label %bb2
38  ]
39bb0:              ; preds = %0
40  store i32 1, ptr %Q
41  %A = load i32, ptr %Q               ; <i32> [#uses=1]
42  call void @bar( i32 %A )
43  ret void
44bb1:              ; preds = %0
45  store i32 1, ptr %Q
46  %B = load i32, ptr %Q               ; <i32> [#uses=1]
47  call void @bar( i32 %B )
48  ret void
49bb2:              ; preds = %0
50  store i32 1, ptr %Q
51  %C = load i32, ptr %Q               ; <i32> [#uses=1]
52  call void @bar( i32 %C )
53  ret void
54}
55
56; We ensure that we examine all instructions during each iteration to confirm the presence of a terminating one.
57define void @test_switch_reach_terminator(i64 %i, ptr %p) {
58; CHECK-LABEL: @test_switch_reach_terminator(
59; CHECK-NEXT:    switch i64 [[I:%.*]], label [[BB0:%.*]] [
60; CHECK-NEXT:      i64 1, label [[BB1:%.*]]
61; CHECK-NEXT:      i64 2, label [[COMMON_RET:%.*]]
62; CHECK-NEXT:    ]
63; CHECK:       common.ret:
64; CHECK-NEXT:    ret void
65; CHECK:       bb0:
66; CHECK-NEXT:    store i32 1, ptr [[P:%.*]], align 4
67; CHECK-NEXT:    br label [[COMMON_RET]]
68; CHECK:       bb1:
69; CHECK-NEXT:    store i32 2, ptr [[P]], align 4
70; CHECK-NEXT:    br label [[COMMON_RET]]
71;
72  switch i64 %i, label %bb0 [
73  i64 1, label %bb1
74  i64 2, label %bb2
75  ]
76bb0:              ; preds = %0
77  store i32 1, ptr %p
78  ret void
79bb1:              ; preds = %0
80  store i32 2, ptr %p
81  ret void
82bb2:              ; preds = %0
83  ret void
84}
85
86define i1 @common_instr_on_switch(i64 %a, i64 %b, i64 %c) unnamed_addr {
87; CHECK-LABEL: @common_instr_on_switch(
88; CHECK-NEXT:  start:
89; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
90; CHECK-NEXT:    ret i1 [[TMP0]]
91;
92start:
93  switch i64 %a, label %bb0 [
94  i64 1, label %bb1
95  i64 2, label %bb2
96  ]
97
98bb0:                                              ; preds = %start
99  %0 = icmp eq i64 %b, %c
100  br label %exit
101
102bb1:                                              ; preds = %start
103  %1 = icmp eq i64 %b, %c
104  br label %exit
105
106bb2:                                              ; preds = %start
107  %2 = icmp eq i64 %b, %c
108  br label %exit
109
110exit:                                             ; preds = %bb2, %bb1, %bb0
111  %result = phi i1 [ %0, %bb0 ], [ %1, %bb1 ], [ %2, %bb2 ]
112  ret i1 %result
113}
114
115define i1 @partial_common_instr_on_switch(i64 %a, i64 %b, i64 %c) unnamed_addr {
116; CHECK-LABEL: @partial_common_instr_on_switch(
117; CHECK-NEXT:  start:
118; CHECK-NEXT:    switch i64 [[A:%.*]], label [[BB0:%.*]] [
119; CHECK-NEXT:      i64 1, label [[BB1:%.*]]
120; CHECK-NEXT:      i64 2, label [[BB2:%.*]]
121; CHECK-NEXT:    ]
122; CHECK:       bb0:
123; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
124; CHECK-NEXT:    br label [[EXIT:%.*]]
125; CHECK:       bb1:
126; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i64 [[B]], [[C]]
127; CHECK-NEXT:    br label [[EXIT]]
128; CHECK:       bb2:
129; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[B]], [[C]]
130; CHECK-NEXT:    br label [[EXIT]]
131; CHECK:       exit:
132; CHECK-NEXT:    [[RESULT:%.*]] = phi i1 [ [[TMP0]], [[BB0]] ], [ [[TMP1]], [[BB1]] ], [ [[TMP2]], [[BB2]] ]
133; CHECK-NEXT:    ret i1 [[RESULT]]
134;
135start:
136  switch i64 %a, label %bb0 [
137  i64 1, label %bb1
138  i64 2, label %bb2
139  ]
140
141bb0:                                              ; preds = %start
142  %0 = icmp eq i64 %b, %c
143  br label %exit
144
145bb1:                                              ; preds = %start
146  %1 = icmp ne i64 %b, %c
147  br label %exit
148
149bb2:                                              ; preds = %start
150  %2 = icmp eq i64 %b, %c
151  br label %exit
152
153exit:                                             ; preds = %bb2, %bb1, %bb0
154  %result = phi i1 [ %0, %bb0 ], [ %1, %bb1 ], [ %2, %bb2 ]
155  ret i1 %result
156}
157
158declare void @foo()
159
160define i1 @test_icmp_simple(i1 %c, i32 %a, i32 %b) {
161; CHECK-LABEL: @test_icmp_simple(
162; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
163; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
164; CHECK:       common.ret:
165; CHECK-NEXT:    ret i1 [[CMP1]]
166; CHECK:       if:
167; CHECK-NEXT:    call void @foo()
168; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
169; CHECK:       else:
170; CHECK-NEXT:    call void @bar()
171; CHECK-NEXT:    br label [[COMMON_RET]]
172;
173  br i1 %c, label %if, label %else
174
175if:
176  %cmp1 = icmp ult i32 %a, %b
177  call void @foo()
178  ret i1 %cmp1
179
180else:
181  %cmp2 = icmp ugt i32 %b, %a
182  call void @bar()
183  ret i1 %cmp2
184}
185
186define void @test_icmp_complex(i1 %c, i32 %a, i32 %b) {
187; CHECK-LABEL: @test_icmp_complex(
188; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
189; CHECK-NEXT:    br i1 [[CMP1]], label [[IF2:%.*]], label [[ELSE2:%.*]]
190; CHECK:       common.ret:
191; CHECK-NEXT:    ret void
192; CHECK:       if2:
193; CHECK-NEXT:    call void @foo()
194; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
195; CHECK:       else2:
196; CHECK-NEXT:    call void @bar()
197; CHECK-NEXT:    br label [[COMMON_RET]]
198;
199  br i1 %c, label %if, label %else
200
201if:
202  %cmp1 = icmp ult i32 %a, %b
203  br i1 %cmp1, label %if2, label %else2
204
205else:
206  %cmp2 = icmp ugt i32 %b, %a
207  br i1 %cmp2, label %if2, label %else2
208
209if2:
210  call void @foo()
211  ret void
212
213else2:
214  call void @bar()
215  ret void
216}
217
218define i1 @test_icmp_wrong_operands(i1 %c, i32 %a, i32 %b) {
219; CHECK-LABEL: @test_icmp_wrong_operands(
220; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
221; CHECK:       common.ret:
222; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i1 [ [[CMP1:%.*]], [[IF]] ], [ [[CMP2:%.*]], [[ELSE]] ]
223; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
224; CHECK:       if:
225; CHECK-NEXT:    [[CMP1]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
226; CHECK-NEXT:    call void @foo()
227; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
228; CHECK:       else:
229; CHECK-NEXT:    [[CMP2]] = icmp ugt i32 [[A]], [[B]]
230; CHECK-NEXT:    call void @bar()
231; CHECK-NEXT:    br label [[COMMON_RET]]
232;
233  br i1 %c, label %if, label %else
234
235if:
236  %cmp1 = icmp ult i32 %a, %b
237  call void @foo()
238  ret i1 %cmp1
239
240else:
241  %cmp2 = icmp ugt i32 %a, %b
242  call void @bar()
243  ret i1 %cmp2
244}
245
246define i1 @test_icmp_wrong_pred(i1 %c, i32 %a, i32 %b) {
247; CHECK-LABEL: @test_icmp_wrong_pred(
248; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
249; CHECK:       common.ret:
250; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i1 [ [[CMP1:%.*]], [[IF]] ], [ [[CMP2:%.*]], [[ELSE]] ]
251; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
252; CHECK:       if:
253; CHECK-NEXT:    [[CMP1]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
254; CHECK-NEXT:    call void @foo()
255; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
256; CHECK:       else:
257; CHECK-NEXT:    [[CMP2]] = icmp uge i32 [[B]], [[A]]
258; CHECK-NEXT:    call void @bar()
259; CHECK-NEXT:    br label [[COMMON_RET]]
260;
261  br i1 %c, label %if, label %else
262
263if:
264  %cmp1 = icmp ult i32 %a, %b
265  call void @foo()
266  ret i1 %cmp1
267
268else:
269  %cmp2 = icmp uge i32 %b, %a
270  call void @bar()
271  ret i1 %cmp2
272}
273
274define i32 @test_binop(i1 %c, i32 %a, i32 %b) {
275; CHECK-LABEL: @test_binop(
276; CHECK-NEXT:    [[OP1:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
277; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
278; CHECK:       common.ret:
279; CHECK-NEXT:    ret i32 [[OP1]]
280; CHECK:       if:
281; CHECK-NEXT:    call void @foo()
282; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
283; CHECK:       else:
284; CHECK-NEXT:    call void @bar()
285; CHECK-NEXT:    br label [[COMMON_RET]]
286;
287  br i1 %c, label %if, label %else
288
289if:
290  %op1 = add i32 %a, %b
291  call void @foo()
292  ret i32 %op1
293
294else:
295  %op2 = add i32 %b, %a
296  call void @bar()
297  ret i32 %op2
298}
299
300define i32 @test_binop_flags(i1 %c, i32 %a, i32 %b) {
301; CHECK-LABEL: @test_binop_flags(
302; CHECK-NEXT:    [[OP1:%.*]] = add nsw i32 [[A:%.*]], [[B:%.*]]
303; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
304; CHECK:       common.ret:
305; CHECK-NEXT:    ret i32 [[OP1]]
306; CHECK:       if:
307; CHECK-NEXT:    call void @foo()
308; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
309; CHECK:       else:
310; CHECK-NEXT:    call void @bar()
311; CHECK-NEXT:    br label [[COMMON_RET]]
312;
313  br i1 %c, label %if, label %else
314
315if:
316  %op1 = add nuw nsw i32 %a, %b
317  call void @foo()
318  ret i32 %op1
319
320else:
321  %op2 = add nsw i32 %b, %a
322  call void @bar()
323  ret i32 %op2
324}
325
326define i32 @test_binop_not_commutative(i1 %c, i32 %a, i32 %b) {
327; CHECK-LABEL: @test_binop_not_commutative(
328; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
329; CHECK:       common.ret:
330; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
331; CHECK-NEXT:    ret i32 [[COMMON_RET_OP]]
332; CHECK:       if:
333; CHECK-NEXT:    [[OP1]] = sub i32 [[A:%.*]], [[B:%.*]]
334; CHECK-NEXT:    call void @foo()
335; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
336; CHECK:       else:
337; CHECK-NEXT:    [[OP2]] = sub i32 [[B]], [[A]]
338; CHECK-NEXT:    call void @bar()
339; CHECK-NEXT:    br label [[COMMON_RET]]
340;
341  br i1 %c, label %if, label %else
342
343if:
344  %op1 = sub i32 %a, %b
345  call void @foo()
346  ret i32 %op1
347
348else:
349  %op2 = sub i32 %b, %a
350  call void @bar()
351  ret i32 %op2
352}
353
354define i32 @test_binop_wrong_ops(i1 %c, i32 %a, i32 %b, i32 %d) {
355; CHECK-LABEL: @test_binop_wrong_ops(
356; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
357; CHECK:       common.ret:
358; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
359; CHECK-NEXT:    ret i32 [[COMMON_RET_OP]]
360; CHECK:       if:
361; CHECK-NEXT:    [[OP1]] = add i32 [[A:%.*]], [[B:%.*]]
362; CHECK-NEXT:    call void @foo()
363; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
364; CHECK:       else:
365; CHECK-NEXT:    [[OP2]] = add i32 [[B]], [[D:%.*]]
366; CHECK-NEXT:    call void @bar()
367; CHECK-NEXT:    br label [[COMMON_RET]]
368;
369  br i1 %c, label %if, label %else
370
371if:
372  %op1 = add i32 %a, %b
373  call void @foo()
374  ret i32 %op1
375
376else:
377  %op2 = add i32 %b, %d
378  call void @bar()
379  ret i32 %op2
380}
381
382define i32 @test_intrin(i1 %c, i32 %a, i32 %b) {
383; CHECK-LABEL: @test_intrin(
384; CHECK-NEXT:    [[OP1:%.*]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 [[B:%.*]])
385; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
386; CHECK:       common.ret:
387; CHECK-NEXT:    ret i32 [[OP1]]
388; CHECK:       if:
389; CHECK-NEXT:    call void @foo()
390; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
391; CHECK:       else:
392; CHECK-NEXT:    call void @bar()
393; CHECK-NEXT:    br label [[COMMON_RET]]
394;
395  br i1 %c, label %if, label %else
396
397if:
398  %op1 = call i32 @llvm.umin(i32 %a, i32 %b)
399  call void @foo()
400  ret i32 %op1
401
402else:
403  %op2 = call i32 @llvm.umin(i32 %b, i32 %a)
404  call void @bar()
405  ret i32 %op2
406}
407
408define i32 @test_intrin_not_same(i1 %c, i32 %a, i32 %b) {
409; CHECK-LABEL: @test_intrin_not_same(
410; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
411; CHECK:       common.ret:
412; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
413; CHECK-NEXT:    ret i32 [[COMMON_RET_OP]]
414; CHECK:       if:
415; CHECK-NEXT:    [[OP1]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 [[B:%.*]])
416; CHECK-NEXT:    call void @foo()
417; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
418; CHECK:       else:
419; CHECK-NEXT:    [[OP2]] = call i32 @llvm.umax.i32(i32 [[B]], i32 [[A]])
420; CHECK-NEXT:    call void @bar()
421; CHECK-NEXT:    br label [[COMMON_RET]]
422;
423  br i1 %c, label %if, label %else
424
425if:
426  %op1 = call i32 @llvm.umin(i32 %a, i32 %b)
427  call void @foo()
428  ret i32 %op1
429
430else:
431  %op2 = call i32 @llvm.umax(i32 %b, i32 %a)
432  call void @bar()
433  ret i32 %op2
434}
435
436define float @test_intrin_3arg(i1 %c, float %a, float %b, float %d) {
437; CHECK-LABEL: @test_intrin_3arg(
438; CHECK-NEXT:    [[OP1:%.*]] = call float @llvm.fma.f32(float [[A:%.*]], float [[B:%.*]], float [[D:%.*]])
439; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
440; CHECK:       common.ret:
441; CHECK-NEXT:    ret float [[OP1]]
442; CHECK:       if:
443; CHECK-NEXT:    call void @foo()
444; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
445; CHECK:       else:
446; CHECK-NEXT:    call void @bar()
447; CHECK-NEXT:    br label [[COMMON_RET]]
448;
449  br i1 %c, label %if, label %else
450
451if:
452  %op1 = call float @llvm.fma(float %a, float %b, float %d)
453  call void @foo()
454  ret float %op1
455
456else:
457  %op2 = call float @llvm.fma(float %b, float %a, float %d)
458  call void @bar()
459  ret float %op2
460}
461
462define float @test_intrin_3arg_wrong_args_commuted(i1 %c, float %a, float %b, float %d) {
463; CHECK-LABEL: @test_intrin_3arg_wrong_args_commuted(
464; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
465; CHECK:       common.ret:
466; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi float [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
467; CHECK-NEXT:    ret float [[COMMON_RET_OP]]
468; CHECK:       if:
469; CHECK-NEXT:    [[OP1]] = call float @llvm.fma.f32(float [[A:%.*]], float [[B:%.*]], float [[D:%.*]])
470; CHECK-NEXT:    call void @foo()
471; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
472; CHECK:       else:
473; CHECK-NEXT:    [[OP2]] = call float @llvm.fma.f32(float [[A]], float [[D]], float [[B]])
474; CHECK-NEXT:    call void @bar()
475; CHECK-NEXT:    br label [[COMMON_RET]]
476;
477  br i1 %c, label %if, label %else
478
479if:
480  %op1 = call float @llvm.fma(float %a, float %b, float %d)
481  call void @foo()
482  ret float %op1
483
484else:
485  %op2 = call float @llvm.fma(float %a, float %d, float %b)
486  call void @bar()
487  ret float %op2
488}
489