• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; 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 }
342