• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: opt -S -simplifycfg < %s | FileCheck %s
2
3; SimplifyCFG should eliminate redundant indirectbr edges.
4
5; CHECK: indbrtest0
6; CHECK: indirectbr i8* %t, [label %BB0, label %BB1, label %BB2]
7; CHECK: %x = phi i32 [ 0, %BB0 ], [ 1, %entry ]
8
9declare void @foo()
10declare void @A()
11declare void @B(i32)
12declare void @C()
13
14define void @indbrtest0(i8** %P, i8** %Q) {
15entry:
16  store i8* blockaddress(@indbrtest0, %BB0), i8** %P
17  store i8* blockaddress(@indbrtest0, %BB1), i8** %P
18  store i8* blockaddress(@indbrtest0, %BB2), i8** %P
19  call void @foo()
20  %t = load i8** %Q
21  indirectbr i8* %t, [label %BB0, label %BB1, label %BB2, label %BB0, label %BB1, label %BB2]
22BB0:
23  call void @A()
24  br label %BB1
25BB1:
26  %x = phi i32 [ 0, %BB0 ], [ 1, %entry ], [ 1, %entry ]
27  call void @B(i32 %x)
28  ret void
29BB2:
30  call void @C()
31  ret void
32}
33
34; SimplifyCFG should convert the indirectbr into a directbr. It would be even
35; better if it removed the branch altogether, but simplifycfdg currently misses
36; that because the predecessor is the entry block.
37
38; CHECK: indbrtest1
39; CHECK: br label %BB0
40
41define void @indbrtest1(i8** %P, i8** %Q) {
42entry:
43  store i8* blockaddress(@indbrtest1, %BB0), i8** %P
44  call void @foo()
45  %t = load i8** %Q
46  indirectbr i8* %t, [label %BB0, label %BB0]
47BB0:
48  call void @A()
49  ret void
50}
51
52; SimplifyCFG should notice that BB0 does not have its address taken and
53; remove it from entry's successor list.
54
55; CHECK: indbrtest2
56; CHECK: entry:
57; CHECK-NEXT: unreachable
58
59define void @indbrtest2(i8* %t) {
60entry:
61  indirectbr i8* %t, [label %BB0, label %BB0]
62BB0:
63  ret void
64}
65
66
67; Make sure the blocks in the next few tests aren't trivially removable as
68; successors by taking their addresses.
69
70@anchor = constant [13 x i8*] [
71  i8* blockaddress(@indbrtest3, %L1), i8* blockaddress(@indbrtest3, %L2), i8* blockaddress(@indbrtest3, %L3),
72  i8* blockaddress(@indbrtest4, %L1), i8* blockaddress(@indbrtest4, %L2), i8* blockaddress(@indbrtest4, %L3),
73  i8* blockaddress(@indbrtest5, %L1), i8* blockaddress(@indbrtest5, %L2), i8* blockaddress(@indbrtest5, %L3), i8* blockaddress(@indbrtest5, %L4),
74  i8* blockaddress(@indbrtest6, %L1), i8* blockaddress(@indbrtest6, %L2), i8* blockaddress(@indbrtest6, %L3)
75]
76
77; SimplifyCFG should turn the indirectbr into a conditional branch on the
78; condition of the select.
79
80; CHECK: @indbrtest3
81; CHECK-NEXT: entry:
82; CHECK-NEXT: br i1 %cond, label %L1, label %L2
83; CHECK-NOT: indirectbr
84; CHECK-NOT: br
85; CHECK-NOT: L3:
86define void @indbrtest3(i1 %cond, i8* %address) nounwind {
87entry:
88  %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest3, %L1), i8* blockaddress(@indbrtest3, %L2)
89  indirectbr i8* %indirect.goto.dest, [label %L1, label %L2, label %L3]
90
91L1:
92  call void @A()
93  ret void
94L2:
95  call void @C()
96  ret void
97L3:
98  call void @foo()
99  ret void
100}
101
102; SimplifyCFG should turn the indirectbr into an unconditional branch to the
103; only possible destination.
104; As in @indbrtest1, it should really remove the branch entirely, but it doesn't
105; because it's in the entry block.
106
107; CHECK: @indbrtest4
108; CHECK-NEXT: entry:
109; CHECK-NEXT: br label %L1
110define void @indbrtest4(i1 %cond) nounwind {
111entry:
112  %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest4, %L1), i8* blockaddress(@indbrtest4, %L1)
113  indirectbr i8* %indirect.goto.dest, [label %L1, label %L2, label %L3]
114
115L1:
116  call void @A()
117  ret void
118L2:
119  call void @C()
120  ret void
121L3:
122  call void @foo()
123  ret void
124}
125
126; SimplifyCFG should turn the indirectbr into an unreachable because neither
127; destination is listed as a successor.
128
129; CHECK: @indbrtest5
130; CHECK-NEXT: entry:
131; CHECK-NEXT: unreachable
132; CHECK-NEXT: }
133define void @indbrtest5(i1 %cond, i8* %anchor) nounwind {
134entry:
135  %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest5, %L1), i8* blockaddress(@indbrtest5, %L2)
136; This needs to have more than one successor for this test, otherwise it gets
137; replaced with an unconditional branch to the single successor.
138  indirectbr i8* %indirect.goto.dest, [label %L3, label %L4]
139
140L1:
141  call void @A()
142  ret void
143L2:
144  call void @C()
145  ret void
146L3:
147  call void @foo()
148  ret void
149L4:
150  call void @foo()
151
152; This keeps blockaddresses not otherwise listed as successors from being zapped
153; before SimplifyCFG even looks at the indirectbr.
154  indirectbr i8* %anchor, [label %L1, label %L2]
155}
156
157; The same as above, except the selected addresses are equal.
158
159; CHECK: @indbrtest6
160; CHECK-NEXT: entry:
161; CHECK-NEXT: unreachable
162; CHECK-NEXT: }
163define void @indbrtest6(i1 %cond, i8* %anchor) nounwind {
164entry:
165  %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest6, %L1), i8* blockaddress(@indbrtest6, %L1)
166; This needs to have more than one successor for this test, otherwise it gets
167; replaced with an unconditional branch to the single successor.
168  indirectbr i8* %indirect.goto.dest, [label %L2, label %L3]
169
170L1:
171  call void @A()
172  ret void
173L2:
174  call void @C()
175  ret void
176L3:
177  call void @foo()
178
179; This keeps blockaddresses not otherwise listed as successors from being zapped
180; before SimplifyCFG even looks at the indirectbr.
181  indirectbr i8* %anchor, [label %L1, label %L2]
182}
183
184; PR10072
185
186@xblkx.bbs = internal unnamed_addr constant [9 x i8*] [i8* blockaddress(@indbrtest7, %xblkx.begin), i8* blockaddress(@indbrtest7, %xblkx.begin3), i8* blockaddress(@indbrtest7, %xblkx.begin4), i8* blockaddress(@indbrtest7, %xblkx.begin5), i8* blockaddress(@indbrtest7, %xblkx.begin6), i8* blockaddress(@indbrtest7, %xblkx.begin7), i8* blockaddress(@indbrtest7, %xblkx.begin8), i8* blockaddress(@indbrtest7, %xblkx.begin9), i8* blockaddress(@indbrtest7, %xblkx.end)]
187
188define void @indbrtest7() {
189escape-string.top:
190  %xval202x = call i32 @xfunc5x()
191  br label %xlab5x
192
193xlab8x:                                           ; preds = %xlab5x
194  %xvaluex = call i32 @xselectorx()
195  %xblkx.x = getelementptr [9 x i8*]* @xblkx.bbs, i32 0, i32 %xvaluex
196  %xblkx.load = load i8** %xblkx.x
197  indirectbr i8* %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]
198
199xblkx.begin:
200  br label %xblkx.end
201
202xblkx.begin3:
203  br label %xblkx.end
204
205xblkx.begin4:
206  br label %xblkx.end
207
208xblkx.begin5:
209  br label %xblkx.end
210
211xblkx.begin6:
212  br label %xblkx.end
213
214xblkx.begin7:
215  br label %xblkx.end
216
217xblkx.begin8:
218  br label %xblkx.end
219
220xblkx.begin9:
221  br label %xblkx.end
222
223xblkx.end:
224  %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 ]
225  br i1 %yes.0, label %v2j, label %xlab17x
226
227v2j:
228; CHECK: %xunusedx = call i32 @xactionx()
229  %xunusedx = call i32 @xactionx()
230  br label %xlab4x
231
232xlab17x:
233  br label %xlab4x
234
235xlab4x:
236  %incr19 = add i32 %xval704x.0, 1
237  br label %xlab5x
238
239xlab5x:
240  %xval704x.0 = phi i32 [ 0, %escape-string.top ], [ %incr19, %xlab4x ]
241  %xval10x = icmp ult i32 %xval704x.0, %xval202x
242  br i1 %xval10x, label %xlab8x, label %xlab9x
243
244xlab9x:
245  ret void
246}
247
248declare i32 @xfunc5x()
249declare i8 @xfunc7x()
250declare i32 @xselectorx()
251declare i32 @xactionx()
252