xref: /llvm-project/llvm/test/Transforms/InstCombine/sink_to_unreachable.ll (revision d4798498c4a30efb03eebb56415a69fa60107414)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -passes=instcombine -S < %s | FileCheck %s
3
4declare void @use(i32 %x)
5declare i1 @cond()
6
7define void @test_01(i32 %x, i32 %y) {
8; CHECK-LABEL: @test_01(
9; CHECK-NEXT:  entry:
10; CHECK-NEXT:    [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
11; CHECK-NEXT:    br i1 [[C2]], label [[EXIT:%.*]], label [[UNREACHED:%.*]]
12; CHECK:       unreached:
13; CHECK-NEXT:    [[COMPARATOR:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
14; CHECK-NEXT:    call void @use(i32 [[COMPARATOR]])
15; CHECK-NEXT:    unreachable
16; CHECK:       exit:
17; CHECK-NEXT:    ret void
18;
19entry:
20  %c1 = icmp eq i32 %x, %y
21  %c2 = icmp slt i32 %x, %y
22  %signed = select i1 %c2, i32 -1, i32 1
23  %comparator = select i1 %c1, i32 0, i32 %signed
24  br i1 %c2, label %exit, label %unreached
25
26unreached:
27  call void @use(i32 %comparator)
28  unreachable
29
30exit:
31  ret void
32}
33
34
35define void @test_02(i32 %x, i32 %y) {
36; CHECK-LABEL: @test_02(
37; CHECK-NEXT:  entry:
38; CHECK-NEXT:    [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
39; CHECK-NEXT:    br i1 [[C2]], label [[EXIT:%.*]], label [[MEDIUM:%.*]]
40; CHECK:       medium:
41; CHECK-NEXT:    [[C3:%.*]] = icmp sgt i32 [[X]], [[Y]]
42; CHECK-NEXT:    br i1 [[C3]], label [[EXIT]], label [[UNREACHED:%.*]]
43; CHECK:       unreached:
44; CHECK-NEXT:    [[COMPARATOR:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
45; CHECK-NEXT:    call void @use(i32 [[COMPARATOR]])
46; CHECK-NEXT:    unreachable
47; CHECK:       exit:
48; CHECK-NEXT:    ret void
49;
50entry:
51  %c1 = icmp eq i32 %x, %y
52  %c2 = icmp slt i32 %x, %y
53  %signed = select i1 %c2, i32 -1, i32 1
54  %comparator = select i1 %c1, i32 0, i32 %signed
55  br i1 %c2, label %exit, label %medium
56
57medium:
58  %c3 = icmp sgt i32 %x, %y
59  br i1 %c3, label %exit, label %unreached
60
61unreached:
62  call void @use(i32 %comparator)
63  unreachable
64
65exit:
66  ret void
67}
68
69define i32 @test_03(i32 %x, i32 %y) {
70; CHECK-LABEL: @test_03(
71; CHECK-NEXT:  entry:
72; CHECK-NEXT:    [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
73; CHECK-NEXT:    br i1 [[C2]], label [[EXIT:%.*]], label [[MEDIUM:%.*]]
74; CHECK:       medium:
75; CHECK-NEXT:    [[C3:%.*]] = icmp sgt i32 [[X]], [[Y]]
76; CHECK-NEXT:    br i1 [[C3]], label [[EXIT]], label [[UNREACHED:%.*]]
77; CHECK:       unreached:
78; CHECK-NEXT:    [[COMPARATOR:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
79; CHECK-NEXT:    ret i32 [[COMPARATOR]]
80; CHECK:       exit:
81; CHECK-NEXT:    ret i32 0
82;
83entry:
84  %c1 = icmp eq i32 %x, %y
85  %c2 = icmp slt i32 %x, %y
86  %signed = select i1 %c2, i32 -1, i32 1
87  %comparator = select i1 %c1, i32 0, i32 %signed
88  br i1 %c2, label %exit, label %medium
89
90medium:
91  %c3 = icmp sgt i32 %x, %y
92  br i1 %c3, label %exit, label %unreached
93
94unreached:
95  ret i32 %comparator
96
97exit:
98  ret i32 0
99}
100
101define i32 @test_04(i32 %x, i1 %c) {
102; CHECK-LABEL: @test_04(
103; CHECK-NEXT:  bb0:
104; CHECK-NEXT:    br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
105; CHECK:       bb1:
106; CHECK-NEXT:    br label [[BB3:%.*]]
107; CHECK:       bb2:
108; CHECK-NEXT:    br label [[BB3]]
109; CHECK:       bb3:
110; CHECK-NEXT:    [[P:%.*]] = phi i32 [ 0, [[BB1]] ], [ 1, [[BB2]] ]
111; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], 1
112; CHECK-NEXT:    [[R:%.*]] = add i32 [[P]], [[A]]
113; CHECK-NEXT:    ret i32 [[R]]
114;
115bb0:
116  %a = add i32 %x, 1
117  br i1 %c, label %bb1, label %bb2
118bb1:
119  br label %bb3
120bb2:
121  br label %bb3
122bb3:
123  %p = phi i32 [0, %bb1], [1, %bb2]
124  %r = add i32 %p, %a
125  ret i32 %r
126}
127
128; Do not sink into a potentially hotter block.
129define i32 @test_05_neg(i32 %x, i1 %cond) {
130; CHECK-LABEL: @test_05_neg(
131; CHECK-NEXT:  bb0:
132; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], 1
133; CHECK-NEXT:    br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
134; CHECK:       bb1:
135; CHECK-NEXT:    br label [[BB3:%.*]]
136; CHECK:       bb2:
137; CHECK-NEXT:    [[CALL:%.*]] = call i1 @cond()
138; CHECK-NEXT:    br i1 [[CALL]], label [[BB2]], label [[BB3]]
139; CHECK:       bb3:
140; CHECK-NEXT:    [[P:%.*]] = phi i32 [ 0, [[BB1]] ], [ [[A]], [[BB2]] ]
141; CHECK-NEXT:    ret i32 [[P]]
142;
143bb0:
144  %a = add i32 %x, 1
145  br i1 %cond, label %bb1, label %bb2
146bb1:
147  br label %bb3
148bb2:
149  %call = call i1 @cond()
150  br i1 %call, label %bb2, label %bb3
151bb3:
152  %p = phi i32 [0, %bb1], [%a, %bb2]
153  ret i32 %p
154}
155
156define i1 @sink_to_unreachable_ret(i16 %X)  {
157; CHECK-LABEL: @sink_to_unreachable_ret(
158; CHECK-NEXT:  entry:
159; CHECK-NEXT:    br label [[LOOP:%.*]]
160; CHECK:       loop:
161; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
162; CHECK:       unreach:
163; CHECK-NEXT:    ret i1 poison
164;
165entry:
166  br label %loop
167
168loop:
169  %p = icmp sgt i16 %X, 16
170  br i1 true, label %loop, label %unreach
171
172unreach:
173  ret i1 %p
174}
175
176define void @sink_to_unreachable_condbr(i16 %X)  {
177; CHECK-LABEL: @sink_to_unreachable_condbr(
178; CHECK-NEXT:  entry:
179; CHECK-NEXT:    br label [[LOOP:%.*]]
180; CHECK:       loop:
181; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
182; CHECK:       unreach:
183; CHECK-NEXT:    br i1 poison, label [[DUMMY:%.*]], label [[LOOP]]
184; CHECK:       dummy:
185; CHECK-NEXT:    unreachable
186;
187entry:
188  br label %loop
189
190loop:
191  %p = icmp sgt i16 %X, 16
192  br i1 true, label %loop, label %unreach
193
194unreach:
195  br i1 %p, label %dummy, label %loop
196
197dummy:
198  unreachable
199}
200
201define void @sink_to_unreachable_switch(i16 %X)  {
202; CHECK-LABEL: @sink_to_unreachable_switch(
203; CHECK-NEXT:  entry:
204; CHECK-NEXT:    br label [[LOOP:%.*]]
205; CHECK:       loop:
206; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
207; CHECK:       unreach:
208; CHECK-NEXT:    switch i16 poison, label [[UNREACH_RET:%.*]] [
209; CHECK-NEXT:    ]
210; CHECK:       unreach.ret:
211; CHECK-NEXT:    unreachable
212;
213entry:
214  br label %loop
215
216loop:
217  %quantum = srem i16 %X, 32
218  br i1 true, label %loop, label %unreach
219
220unreach:
221  switch i16 %quantum, label %unreach.ret []
222
223unreach.ret:
224  unreachable
225}
226
227define void @sink_to_unreachable_indirectbr(ptr %Ptr)  {
228; CHECK-LABEL: @sink_to_unreachable_indirectbr(
229; CHECK-NEXT:  entry:
230; CHECK-NEXT:    br label [[LOOP:%.*]]
231; CHECK:       loop:
232; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
233; CHECK:       unreach:
234; CHECK-NEXT:    indirectbr ptr poison, [label %loop]
235;
236entry:
237  br label %loop
238
239loop:
240  %gep = getelementptr inbounds ptr, ptr %Ptr, i16 1
241  br i1 true, label %loop, label %unreach
242
243unreach:
244  indirectbr ptr %gep, [label %loop]
245}
246
247define void @sink_to_unreachable_invoke(ptr %Ptr) personality ptr @__CxxFrameHandler3 {
248; CHECK-LABEL: @sink_to_unreachable_invoke(
249; CHECK-NEXT:  entry:
250; CHECK-NEXT:    br label [[LOOP:%.*]]
251; CHECK:       loop:
252; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[UNREACH:%.*]]
253; CHECK:       unreach:
254; CHECK-NEXT:    invoke void poison(i1 false)
255; CHECK-NEXT:            to label [[DUMMY:%.*]] unwind label [[ICATCH_DISPATCH:%.*]]
256; CHECK:       unreach2:
257; CHECK-NEXT:    invoke void @__CxxFrameHandler3(ptr poison)
258; CHECK-NEXT:            to label [[DUMMY]] unwind label [[ICATCH_DISPATCH]]
259; CHECK:       unreach3:
260; CHECK-NEXT:    [[CLEAN:%.*]] = cleanuppad within none []
261; CHECK-NEXT:    invoke void @__CxxFrameHandler3(ptr poison) [ "funclet"(token [[CLEAN]]) ]
262; CHECK-NEXT:            to label [[DUMMY]] unwind label [[ICATCH_DISPATCH]]
263; CHECK:       icatch.dispatch:
264; CHECK-NEXT:    [[TMP1:%.*]] = catchswitch within none [label %icatch] unwind to caller
265; CHECK:       icatch:
266; CHECK-NEXT:    [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 64, ptr null]
267; CHECK-NEXT:    catchret from [[TMP2]] to label [[DUMMY2:%.*]]
268; CHECK:       dummy:
269; CHECK-NEXT:    ret void
270; CHECK:       dummy2:
271; CHECK-NEXT:    ret void
272;
273entry:
274  br label %loop
275
276loop:
277  %gep = getelementptr inbounds ptr, ptr %Ptr, i16 1
278  br i1 true, label %loop, label %unreach
279
280unreach:
281  invoke void %gep(i1 false)
282  to label %dummy unwind label %icatch.dispatch
283
284unreach2:
285  invoke void @__CxxFrameHandler3(ptr %gep)
286  to label %dummy unwind label %icatch.dispatch
287
288unreach3:
289  %clean = cleanuppad within none []
290  invoke void @__CxxFrameHandler3(ptr %gep) [ "funclet"(token %clean) ]
291  to label %dummy unwind label %icatch.dispatch
292
293icatch.dispatch:
294  %tmp1 = catchswitch within none [label %icatch] unwind to caller
295
296icatch:
297  %tmp2 = catchpad within %tmp1 [ptr null, i32 64, ptr null]
298  catchret from %tmp2 to label %dummy2
299
300dummy:
301  ret void
302
303dummy2:
304  ret void
305}
306
307declare void @may_throw()
308declare i32 @__CxxFrameHandler3(...)
309