blob: 6689639311bd00f855a2a0937fadf13ec658784e [file] [log] [blame]
Chandler Carruth88823462016-08-24 09:37:14 +00001; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(function-attrs,function(simplify-cfg))' -S < %s | FileCheck %s
2
3declare void @readnone() readnone
4declare void @unknown()
5declare void @reference_function_pointer(void()*) readnone
6
7; The @test1_* set of functions checks that when we mutate functions with
8; simplify-cfg to delete call edges and this ends up splitting both the SCCs
9; and the RefSCCs that those functions are in, we re-run the CGSCC passes to
10; observe the refined call graph structure.
11
12; CHECK: define void @test1_a() {
13define void @test1_a() {
14 call void @test1_b1()
15 call void @test1_b2()
16 call void @test1_b3()
17 call void @test1_b4()
18 ret void
19}
20
21; CHECK: define void @test1_b1() #0 {
22define void @test1_b1() {
23 call void @readnone()
24 ret void
25}
26
27; CHECK: define void @test1_b2() #0 {
28define void @test1_b2() {
29 call void @readnone()
30 br i1 false, label %dead, label %exit
31
32dead:
33 call void @test1_a()
34 br label %exit
35
36exit:
37 ret void
38}
39
40; CHECK: define void @test1_b3() {
41define void @test1_b3() {
42 call void @unknown()
43 br i1 false, label %dead, label %exit
44
45dead:
46 call void @test1_a()
47 br label %exit
48
49exit:
50 ret void
51}
52
53; CHECK: define void @test1_b4() #0 {
54define void @test1_b4() {
55 call void @readnone()
56 br i1 false, label %dead, label %exit
57
58dead:
59 call void @test1_a()
60 br label %exit
61
62exit:
63 ret void
64}
65
66
67; The @test2_* set of functions provide similar checks to @test1_* but only
68; splitting the SCCs while leaving the RefSCC intact. This is accomplished by
69; having dummy ref edges to the root function.
70
71; CHECK: define void @test2_a() {
72define void @test2_a() {
73 call void @test2_b1()
74 call void @test2_b2()
75 call void @test2_b3()
76 call void @test2_b4()
77 ret void
78}
79
80; CHECK: define void @test2_b1() #0 {
81define void @test2_b1() {
82 call void @readnone()
83 ret void
84}
85
86; CHECK: define void @test2_b2() #0 {
87define void @test2_b2() {
88 call void @reference_function_pointer(void()* @test2_a)
89 br i1 false, label %dead, label %exit
90
91dead:
92 call void @test2_a()
93 br label %exit
94
95exit:
96 ret void
97}
98
99; CHECK: define void @test2_b3() {
100define void @test2_b3() {
101 call void @reference_function_pointer(void()* @test2_a)
102 call void @unknown()
103 br i1 false, label %dead, label %exit
104
105dead:
106 call void @test2_a()
107 br label %exit
108
109exit:
110 ret void
111}
112
113; CHECK: define void @test2_b4() #0 {
114define void @test2_b4() {
115 call void @reference_function_pointer(void()* @test2_a)
116 br i1 false, label %dead, label %exit
117
118dead:
119 call void @test2_a()
120 br label %exit
121
122exit:
123 ret void
124}
125
126
127; The @test3_* set of functions are the same challenge as @test1_* but with
128; multiple layers that have to be traversed in the correct order instead of
129; a single node.
130
131; CHECK: define void @test3_a() {
132define void @test3_a() {
133 call void @test3_b11()
134 call void @test3_b21()
135 call void @test3_b31()
136 call void @test3_b41()
137 ret void
138}
139
140; CHECK: define void @test3_b11() #0 {
141define void @test3_b11() {
142 call void @test3_b12()
143 ret void
144}
145
146; CHECK: define void @test3_b12() #0 {
147define void @test3_b12() {
148 call void @test3_b13()
149 ret void
150}
151
152; CHECK: define void @test3_b13() #0 {
153define void @test3_b13() {
154 call void @readnone()
155 ret void
156}
157
158; CHECK: define void @test3_b21() #0 {
159define void @test3_b21() {
160 call void @test3_b22()
161 ret void
162}
163
164; CHECK: define void @test3_b22() #0 {
165define void @test3_b22() {
166 call void @test3_b23()
167 ret void
168}
169
170; CHECK: define void @test3_b23() #0 {
171define void @test3_b23() {
172 call void @readnone()
173 br i1 false, label %dead, label %exit
174
175dead:
176 call void @test3_a()
177 br label %exit
178
179exit:
180 ret void
181}
182
183; CHECK: define void @test3_b31() {
184define void @test3_b31() {
185 call void @test3_b32()
186 ret void
187}
188
189; CHECK: define void @test3_b32() {
190define void @test3_b32() {
191 call void @test3_b33()
192 ret void
193}
194
195; CHECK: define void @test3_b33() {
196define void @test3_b33() {
197 call void @unknown()
198 br i1 false, label %dead, label %exit
199
200dead:
201 call void @test3_a()
202 br label %exit
203
204exit:
205 ret void
206}
207
208; CHECK: define void @test3_b41() #0 {
209define void @test3_b41() {
210 call void @test3_b42()
211 ret void
212}
213
214; CHECK: define void @test3_b42() #0 {
215define void @test3_b42() {
216 call void @test3_b43()
217 ret void
218}
219
220; CHECK: define void @test3_b43() #0 {
221define void @test3_b43() {
222 call void @readnone()
223 br i1 false, label %dead, label %exit
224
225dead:
226 call void @test3_a()
227 br label %exit
228
229exit:
230 ret void
231}
232
233
234; The @test4_* functions exercise the same core challenge as the @test2_*
235; functions, but again include long chains instead of single nodes and ensure
236; we traverse the chains in the correct order.
237
238; CHECK: define void @test4_a() {
239define void @test4_a() {
240 call void @test4_b11()
241 call void @test4_b21()
242 call void @test4_b31()
243 call void @test4_b41()
244 ret void
245}
246
247; CHECK: define void @test4_b11() #0 {
248define void @test4_b11() {
249 call void @test4_b12()
250 ret void
251}
252
253; CHECK: define void @test4_b12() #0 {
254define void @test4_b12() {
255 call void @test4_b13()
256 ret void
257}
258
259; CHECK: define void @test4_b13() #0 {
260define void @test4_b13() {
261 call void @readnone()
262 ret void
263}
264
265; CHECK: define void @test4_b21() #0 {
266define void @test4_b21() {
267 call void @test4_b22()
268 ret void
269}
270
271; CHECK: define void @test4_b22() #0 {
272define void @test4_b22() {
273 call void @test4_b23()
274 ret void
275}
276
277; CHECK: define void @test4_b23() #0 {
278define void @test4_b23() {
279 call void @reference_function_pointer(void()* @test4_a)
280 br i1 false, label %dead, label %exit
281
282dead:
283 call void @test4_a()
284 br label %exit
285
286exit:
287 ret void
288}
289
290; CHECK: define void @test4_b31() {
291define void @test4_b31() {
292 call void @test4_b32()
293 ret void
294}
295
296; CHECK: define void @test4_b32() {
297define void @test4_b32() {
298 call void @test4_b33()
299 ret void
300}
301
302; CHECK: define void @test4_b33() {
303define void @test4_b33() {
304 call void @reference_function_pointer(void()* @test4_a)
305 call void @unknown()
306 br i1 false, label %dead, label %exit
307
308dead:
309 call void @test4_a()
310 br label %exit
311
312exit:
313 ret void
314}
315
316; CHECK: define void @test4_b41() #0 {
317define void @test4_b41() {
318 call void @test4_b42()
319 ret void
320}
321
322; CHECK: define void @test4_b42() #0 {
323define void @test4_b42() {
324 call void @test4_b43()
325 ret void
326}
327
328; CHECK: define void @test4_b43() #0 {
329define void @test4_b43() {
330 call void @reference_function_pointer(void()* @test4_a)
331 br i1 false, label %dead, label %exit
332
333dead:
334 call void @test4_a()
335 br label %exit
336
337exit:
338 ret void
339}
340
341; CHECK: attributes #0 = { readnone }