xref: /llvm-project/llvm/test/Transforms/SimplifyCFG/indirectbr.ll (revision 8979ae42769e529b0f6fce3268492ffb49bd54b9)
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 | FileCheck %s
3
4; SimplifyCFG should eliminate redundant indirectbr edges.
5
6declare void @foo()
7declare void @A()
8declare void @B(i32)
9declare void @C()
10
11define void @indbrtest0(ptr %P, ptr %Q) {
12; CHECK-LABEL: @indbrtest0(
13; CHECK-NEXT:  entry:
14; CHECK-NEXT:    store ptr blockaddress(@indbrtest0, [[BB0:%.*]]), ptr [[P:%.*]], align 8
15; CHECK-NEXT:    store ptr blockaddress(@indbrtest0, [[BB1:%.*]]), ptr [[P]], align 8
16; CHECK-NEXT:    store ptr blockaddress(@indbrtest0, [[BB2:%.*]]), ptr [[P]], align 8
17; CHECK-NEXT:    call void @foo()
18; CHECK-NEXT:    [[T:%.*]] = load ptr, ptr [[Q:%.*]], align 8
19; CHECK-NEXT:    indirectbr ptr [[T]], [label [[BB0]], label [[BB1]], label %BB2]
20; CHECK:       BB0:
21; CHECK-NEXT:    call void @A()
22; CHECK-NEXT:    br label [[BB1]]
23; CHECK:       common.ret:
24; CHECK-NEXT:    ret void
25; CHECK:       BB1:
26; CHECK-NEXT:    [[X:%.*]] = phi i32 [ 0, [[BB0]] ], [ 1, [[ENTRY:%.*]] ]
27; CHECK-NEXT:    call void @B(i32 [[X]])
28; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
29; CHECK:       BB2:
30; CHECK-NEXT:    call void @C()
31; CHECK-NEXT:    br label [[COMMON_RET]]
32;
33entry:
34  store ptr blockaddress(@indbrtest0, %BB0), ptr %P
35  store ptr blockaddress(@indbrtest0, %BB1), ptr %P
36  store ptr blockaddress(@indbrtest0, %BB2), ptr %P
37  call void @foo()
38  %t = load ptr, ptr %Q
39  indirectbr ptr %t, [label %BB0, label %BB1, label %BB2, label %BB0, label %BB1, label %BB2]
40BB0:
41  call void @A()
42  br label %BB1
43BB1:
44  %x = phi i32 [ 0, %BB0 ], [ 1, %entry ], [ 1, %entry ]
45  call void @B(i32 %x)
46  ret void
47BB2:
48  call void @C()
49  ret void
50}
51
52; SimplifyCFG should convert the indirectbr into a directbr. It would be even
53; better if it removed the branch altogether, but simplifycfdg currently misses
54; that because the predecessor is the entry block.
55
56
57define void @indbrtest1(ptr %P, ptr %Q) {
58; CHECK-LABEL: @indbrtest1(
59; CHECK-NEXT:  entry:
60; CHECK-NEXT:    store ptr blockaddress(@indbrtest1, [[BB0:%.*]]), ptr [[P:%.*]], align 8
61; CHECK-NEXT:    call void @foo()
62; CHECK-NEXT:    br label [[BB0]]
63; CHECK:       BB0:
64; CHECK-NEXT:    call void @A()
65; CHECK-NEXT:    ret void
66;
67entry:
68  store ptr blockaddress(@indbrtest1, %BB0), ptr %P
69  call void @foo()
70  %t = load ptr, ptr %Q
71  indirectbr ptr %t, [label %BB0, label %BB0]
72BB0:
73  call void @A()
74  ret void
75}
76
77; SimplifyCFG should notice that BB0 does not have its address taken and
78; remove it from entry's successor list.
79
80
81define void @indbrtest2(ptr %t) {
82; CHECK-LABEL: @indbrtest2(
83; CHECK-NEXT:  entry:
84; CHECK-NEXT:    unreachable
85;
86entry:
87  indirectbr ptr %t, [label %BB0, label %BB0]
88BB0:
89  ret void
90}
91
92
93; Make sure the blocks in the next few tests aren't trivially removable as
94; successors by taking their addresses.
95
96@anchor = constant [13 x ptr] [
97  ptr blockaddress(@indbrtest3, %L1), ptr blockaddress(@indbrtest3, %L2), ptr blockaddress(@indbrtest3, %L3),
98  ptr blockaddress(@indbrtest4, %L1), ptr blockaddress(@indbrtest4, %L2), ptr blockaddress(@indbrtest4, %L3),
99  ptr blockaddress(@indbrtest5, %L1), ptr blockaddress(@indbrtest5, %L2), ptr blockaddress(@indbrtest5, %L3), ptr blockaddress(@indbrtest5, %L4),
100  ptr blockaddress(@indbrtest6, %L1), ptr blockaddress(@indbrtest6, %L2), ptr blockaddress(@indbrtest6, %L3)
101]
102
103; SimplifyCFG should turn the indirectbr into a conditional branch on the
104; condition of the select.
105
106define void @indbrtest3(i1 %cond, ptr %address) nounwind {
107; CHECK-LABEL: @indbrtest3(
108; CHECK-NEXT:  entry:
109; CHECK-NEXT:    br i1 [[COND:%.*]], label [[L1:%.*]], label [[L2:%.*]]
110; CHECK:       common.ret:
111; CHECK-NEXT:    ret void
112; CHECK:       L1:
113; CHECK-NEXT:    call void @A()
114; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
115; CHECK:       L2:
116; CHECK-NEXT:    call void @C()
117; CHECK-NEXT:    br label [[COMMON_RET]]
118;
119entry:
120  %indirect.goto.dest = select i1 %cond, ptr blockaddress(@indbrtest3, %L1), ptr blockaddress(@indbrtest3, %L2)
121  indirectbr ptr %indirect.goto.dest, [label %L1, label %L2, label %L3]
122
123L1:
124  call void @A()
125  ret void
126L2:
127  call void @C()
128  ret void
129L3:
130  call void @foo()
131  ret void
132}
133
134; SimplifyCFG should turn the indirectbr into an unconditional branch to the
135; only possible destination.
136; As in @indbrtest1, it should really remove the branch entirely, but it doesn't
137; because it's in the entry block.
138
139define void @indbrtest4(i1 %cond) nounwind {
140; CHECK-LABEL: @indbrtest4(
141; CHECK-NEXT:  entry:
142; CHECK-NEXT:    br label [[L1:%.*]]
143; CHECK:       L1:
144; CHECK-NEXT:    call void @A()
145; CHECK-NEXT:    ret void
146;
147entry:
148  %indirect.goto.dest = select i1 %cond, ptr blockaddress(@indbrtest4, %L1), ptr blockaddress(@indbrtest4, %L1)
149  indirectbr ptr %indirect.goto.dest, [label %L1, label %L2, label %L3]
150
151L1:
152  call void @A()
153  ret void
154L2:
155  call void @C()
156  ret void
157L3:
158  call void @foo()
159  ret void
160}
161
162; SimplifyCFG should turn the indirectbr into an unreachable because neither
163; destination is listed as a successor.
164
165define void @indbrtest5(i1 %cond, ptr %anchor) nounwind {
166; CHECK-LABEL: @indbrtest5(
167; CHECK-NEXT:  entry:
168; CHECK-NEXT:    unreachable
169;
170entry:
171  %indirect.goto.dest = select i1 %cond, ptr blockaddress(@indbrtest5, %L1), ptr blockaddress(@indbrtest5, %L2)
172; This needs to have more than one successor for this test, otherwise it gets
173; replaced with an unconditional branch to the single successor.
174  indirectbr ptr %indirect.goto.dest, [label %L3, label %L4]
175
176L1:
177  call void @A()
178  ret void
179L2:
180  call void @C()
181  ret void
182L3:
183  call void @foo()
184  ret void
185L4:
186  call void @foo()
187
188; This keeps blockaddresses not otherwise listed as successors from being zapped
189; before SimplifyCFG even looks at the indirectbr.
190  indirectbr ptr %anchor, [label %L1, label %L2]
191}
192
193; The same as above, except the selected addresses are equal.
194
195define void @indbrtest6(i1 %cond, ptr %anchor) nounwind {
196; CHECK-LABEL: @indbrtest6(
197; CHECK-NEXT:  entry:
198; CHECK-NEXT:    unreachable
199;
200entry:
201  %indirect.goto.dest = select i1 %cond, ptr blockaddress(@indbrtest6, %L1), ptr blockaddress(@indbrtest6, %L1)
202; This needs to have more than one successor for this test, otherwise it gets
203; replaced with an unconditional branch to the single successor.
204  indirectbr ptr %indirect.goto.dest, [label %L2, label %L3]
205
206L1:
207  call void @A()
208  ret void
209L2:
210  call void @C()
211  ret void
212L3:
213  call void @foo()
214
215; This keeps blockaddresses not otherwise listed as successors from being zapped
216; before SimplifyCFG even looks at the indirectbr.
217  indirectbr ptr %anchor, [label %L1, label %L2]
218}
219
220; PR10072
221
222@xblkx.bbs = internal unnamed_addr constant [9 x ptr] [ptr blockaddress(@indbrtest7, %xblkx.begin), ptr blockaddress(@indbrtest7, %xblkx.begin3), ptr blockaddress(@indbrtest7, %xblkx.begin4), ptr blockaddress(@indbrtest7, %xblkx.begin5), ptr blockaddress(@indbrtest7, %xblkx.begin6), ptr blockaddress(@indbrtest7, %xblkx.begin7), ptr blockaddress(@indbrtest7, %xblkx.begin8), ptr blockaddress(@indbrtest7, %xblkx.begin9), ptr blockaddress(@indbrtest7, %xblkx.end)]
223
224define void @indbrtest7() {
225; CHECK-LABEL: @indbrtest7(
226; CHECK-NEXT:  escape-string.top:
227; CHECK-NEXT:    [[XVAL202X:%.*]] = call i32 @xfunc5x()
228; CHECK-NEXT:    br label [[XLAB5X:%.*]]
229; CHECK:       xlab8x:
230; CHECK-NEXT:    [[XVALUEX:%.*]] = call i32 @xselectorx()
231; CHECK-NEXT:    [[XBLKX_X:%.*]] = getelementptr [9 x ptr], ptr @xblkx.bbs, i32 0, i32 [[XVALUEX]]
232; CHECK-NEXT:    [[XBLKX_LOAD:%.*]] = load ptr, ptr [[XBLKX_X]], align 8
233; CHECK-NEXT:    indirectbr ptr [[XBLKX_LOAD]], [label [[XLAB4X:%.*]], label %v2j]
234; CHECK:       v2j:
235; CHECK-NEXT:    [[XUNUSEDX:%.*]] = call i32 @xactionx()
236; CHECK-NEXT:    br label [[XLAB4X]]
237; CHECK:       xlab4x:
238; CHECK-NEXT:    [[INCR19:%.*]] = add i32 [[XVAL704X_0:%.*]], 1
239; CHECK-NEXT:    br label [[XLAB5X]]
240; CHECK:       xlab5x:
241; CHECK-NEXT:    [[XVAL704X_0]] = phi i32 [ 0, [[ESCAPE_STRING_TOP:%.*]] ], [ [[INCR19]], [[XLAB4X]] ]
242; CHECK-NEXT:    [[XVAL10X:%.*]] = icmp ult i32 [[XVAL704X_0]], [[XVAL202X]]
243; CHECK-NEXT:    br i1 [[XVAL10X]], label [[XLAB8X:%.*]], label [[XLAB9X:%.*]]
244; CHECK:       xlab9x:
245; CHECK-NEXT:    ret void
246;
247escape-string.top:
248  %xval202x = call i32 @xfunc5x()
249  br label %xlab5x
250
251xlab8x:                                           ; preds = %xlab5x
252  %xvaluex = call i32 @xselectorx()
253  %xblkx.x = getelementptr [9 x ptr], ptr @xblkx.bbs, i32 0, i32 %xvaluex
254  %xblkx.load = load ptr, ptr %xblkx.x
255  indirectbr ptr %xblkx.load, [label %xblkx.begin, label %xblkx.begin3, label %xblkx.begin4, label %xblkx.begin5, label %xblkx.begin6, label %xblkx.begin7, label %xblkx.begin8, label %xblkx.begin9, label %xblkx.end]
256
257xblkx.begin:
258  br label %xblkx.end
259
260xblkx.begin3:
261  br label %xblkx.end
262
263xblkx.begin4:
264  br label %xblkx.end
265
266xblkx.begin5:
267  br label %xblkx.end
268
269xblkx.begin6:
270  br label %xblkx.end
271
272xblkx.begin7:
273  br label %xblkx.end
274
275xblkx.begin8:
276  br label %xblkx.end
277
278xblkx.begin9:
279  br label %xblkx.end
280
281xblkx.end:
282  %yes.0 = phi i1 [ false, %xblkx.begin ], [ true, %xlab8x ], [ false, %xblkx.begin9 ], [ false, %xblkx.begin8 ], [ false, %xblkx.begin7 ], [ false, %xblkx.begin6 ], [ false, %xblkx.begin5 ], [ true, %xblkx.begin4 ], [ false, %xblkx.begin3 ]
283  br i1 %yes.0, label %v2j, label %xlab17x
284
285v2j:
286  %xunusedx = call i32 @xactionx()
287  br label %xlab4x
288
289xlab17x:
290  br label %xlab4x
291
292xlab4x:
293  %incr19 = add i32 %xval704x.0, 1
294  br label %xlab5x
295
296xlab5x:
297  %xval704x.0 = phi i32 [ 0, %escape-string.top ], [ %incr19, %xlab4x ]
298  %xval10x = icmp ult i32 %xval704x.0, %xval202x
299  br i1 %xval10x, label %xlab8x, label %xlab9x
300
301xlab9x:
302  ret void
303}
304
305define void @indbrtest8() {
306; CHECK-LABEL: @indbrtest8(
307; CHECK-NEXT:  entry:
308; CHECK-NEXT:    call void @B(i32 undef)
309; CHECK-NEXT:    ret void
310;
311entry:
312  indirectbr ptr blockaddress(@indbrtest8, %BB1), [label %BB0, label %BB1]
313BB0:
314  call void @A()
315  ret void
316BB1:
317  call void @B(i32 undef)
318  ret void
319}
320
321define void @indbrtest9() {
322; CHECK-LABEL: @indbrtest9(
323; CHECK-NEXT:  entry:
324; CHECK-NEXT:    unreachable
325;
326entry:
327  indirectbr ptr blockaddress(@indbrtest9, %BB1), [label %BB0]
328BB0:
329  call void @A()
330  ret void
331BB1:
332  call void @B(i32 undef)
333  ret void
334}
335
336define void @indbrtest10() {
337; CHECK-LABEL: @indbrtest10(
338; CHECK-NEXT:  entry:
339; CHECK-NEXT:    call void @B(i32 undef)
340; CHECK-NEXT:    ret void
341;
342entry:
343  indirectbr ptr blockaddress(@indbrtest10, %BB1), [label %BB1]
344BB0:
345  call void @A()
346  ret void
347BB1:
348  call void @B(i32 undef)
349  ret void
350}
351
352define void @indbrtest11() {
353; CHECK-LABEL: @indbrtest11(
354; CHECK-NEXT:  entry:
355; CHECK-NEXT:    call void @A()
356; CHECK-NEXT:    ret void
357;
358entry:
359  indirectbr ptr blockaddress(@indbrtest11, %BB0), [label %BB0, label %BB1, label %BB1]
360BB0:
361  call void @A()
362  ret void
363BB1:
364  call void @B(i32 undef)
365  ret void
366}
367
368define void @indbrtest12() {
369; CHECK-LABEL: @indbrtest12(
370; CHECK-NEXT:  entry:
371; CHECK-NEXT:    call void @B(i32 undef)
372; CHECK-NEXT:    ret void
373;
374entry:
375  indirectbr ptr blockaddress(@indbrtest12, %BB1), [label %BB0, label %BB1, label %BB1]
376BB0:
377  call void @A()
378  ret void
379BB1:
380  call void @B(i32 undef)
381  ret void
382}
383
384declare i32 @xfunc5x()
385declare i8 @xfunc7x()
386declare i32 @xselectorx()
387declare i32 @xactionx()
388