cgscc-update.ll
4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs,inline)' -S | FileCheck %s
; This test runs the inliner and the function attribute deduction. It ensures
; that when the inliner mutates the call graph it correctly updates the CGSCC
; iteration so that we can compute refined function attributes. In this way it
; is leveraging function attribute computation to observe correct call graph
; updates.
; Boring unknown external function call.
; CHECK: declare void @unknown()
declare void @unknown()
; Sanity check: this should get annotated as readnone.
; CHECK: Function Attrs: nounwind readnone
; CHECK-NEXT: declare void @readnone()
declare void @readnone() readnone nounwind
; The 'test1_' prefixed functions are designed to trigger forming a new direct
; call in the inlined body of the function. After that, we form a new SCC and
; using that can deduce precise function attrs.
; This function should no longer exist.
; CHECK-NOT: @test1_f()
define internal void @test1_f(void()* %p) {
entry:
call void %p()
ret void
}
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test1_g()
define void @test1_g() noinline {
entry:
call void @test1_f(void()* @test1_h)
ret void
}
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test1_h()
define void @test1_h() noinline {
entry:
call void @test1_g()
call void @readnone()
ret void
}
; The 'test2_' prefixed functions are designed to trigger forming a new direct
; call due to RAUW-ing the returned value of a called function into the caller.
; This too should form a new SCC which can then be reasoned about to compute
; precise function attrs.
; This function should no longer exist.
; CHECK-NOT: @test2_f()
define internal void()* @test2_f() {
entry:
ret void()* @test2_h
}
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test2_g()
define void @test2_g() noinline {
entry:
%p = call void()* @test2_f()
call void %p()
ret void
}
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test2_h()
define void @test2_h() noinline {
entry:
call void @test2_g()
call void @readnone()
ret void
}
; The 'test3_' prefixed functions are designed to inline in a way that causes
; call sites to become trivially dead during the middle of inlining callsites of
; a single function to make sure that the inliner does not get confused by this
; pattern.
; CHECK-NOT: @test3_maybe_unknown(
define internal void @test3_maybe_unknown(i1 %b) {
entry:
br i1 %b, label %then, label %exit
then:
call void @unknown()
br label %exit
exit:
ret void
}
; CHECK-NOT: @test3_f(
define internal i1 @test3_f() {
entry:
ret i1 false
}
; CHECK-NOT: @test3_g(
define internal i1 @test3_g(i1 %b) {
entry:
br i1 %b, label %then1, label %if2
then1:
call void @test3_maybe_unknown(i1 true)
br label %if2
if2:
%f = call i1 @test3_f()
br i1 %f, label %then2, label %exit
then2:
call void @test3_maybe_unknown(i1 true)
br label %exit
exit:
ret i1 false
}
; FIXME: Currently the inliner doesn't successfully mark this as readnone
; because while it simplifies trivially dead CFGs when inlining callees it
; doesn't simplify the caller's trivially dead CFG and so we end with a dead
; block calling @unknown.
; CHECK-NOT: Function Attrs: readnone
; CHECK: define void @test3_h()
define void @test3_h() {
entry:
%g = call i1 @test3_g(i1 false)
br i1 %g, label %then, label %exit
then:
call void @test3_maybe_unknown(i1 true)
br label %exit
exit:
call void @test3_maybe_unknown(i1 false)
ret void
}
; The 'test4_' prefixed functions are designed to trigger forming a new direct
; call in the inlined body of the function similar to 'test1_'. However, after
; that we continue to inline another edge of the graph forcing us to do a more
; interesting call graph update for the new call edge. Eventually, we still
; form a new SCC and should use that can deduce precise function attrs.
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test4_f1()
define void @test4_f1() noinline {
entry:
call void @test4_h()
ret void
}
; CHECK-NOT: @test4_f2
define internal void @test4_f2() {
entry:
call void @test4_f1()
ret void
}
; CHECK-NOT: @test4_g
define internal void @test4_g(void()* %p) {
entry:
call void %p()
ret void
}
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test4_h()
define void @test4_h() noinline {
entry:
call void @test4_g(void()* @test4_f2)
ret void
}