1
2
3
4
5
6
7 package interleaved
8
9 import (
10 "cmd/compile/internal/base"
11 "cmd/compile/internal/devirtualize"
12 "cmd/compile/internal/inline"
13 "cmd/compile/internal/inline/inlheur"
14 "cmd/compile/internal/ir"
15 "cmd/compile/internal/pgoir"
16 "cmd/compile/internal/typecheck"
17 "fmt"
18 )
19
20
21
22 func DevirtualizeAndInlinePackage(pkg *ir.Package, profile *pgoir.Profile) {
23 if profile != nil && base.Debug.PGODevirtualize > 0 {
24
25 ir.VisitFuncsBottomUp(typecheck.Target.Funcs, func(list []*ir.Func, recursive bool) {
26 for _, fn := range list {
27 devirtualize.ProfileGuided(fn, profile)
28 }
29 })
30 ir.CurFunc = nil
31 }
32
33 if base.Flag.LowerL != 0 {
34 inlheur.SetupScoreAdjustments()
35 }
36
37 var inlProfile *pgoir.Profile
38 if base.Debug.PGOInline != 0 {
39 inlProfile = profile
40 }
41
42
43 inline.CanInlineFuncs(pkg.Funcs, inlProfile)
44
45
46
47 for _, fn := range pkg.Funcs {
48 DevirtualizeAndInlineFunc(fn, inlProfile)
49 }
50
51 if base.Flag.LowerL != 0 {
52 if base.Debug.DumpInlFuncProps != "" {
53 inlheur.DumpFuncProps(nil, base.Debug.DumpInlFuncProps)
54 }
55 if inlheur.Enabled() {
56 inline.PostProcessCallSites(inlProfile)
57 inlheur.TearDown()
58 }
59 }
60 }
61
62
63
64 func DevirtualizeAndInlineFunc(fn *ir.Func, profile *pgoir.Profile) {
65 ir.WithFunc(fn, func() {
66 if base.Flag.LowerL != 0 {
67 if inlheur.Enabled() && !fn.Wrapper() {
68 inlheur.ScoreCalls(fn)
69 defer inlheur.ScoreCallsCleanup()
70 }
71 if base.Debug.DumpInlFuncProps != "" && !fn.Wrapper() {
72 inlheur.DumpFuncProps(fn, base.Debug.DumpInlFuncProps)
73 }
74 }
75
76 bigCaller := base.Flag.LowerL != 0 && inline.IsBigFunc(fn)
77 if bigCaller && base.Flag.LowerM > 1 {
78 fmt.Printf("%v: function %v considered 'big'; reducing max cost of inlinees\n", ir.Line(fn), fn)
79 }
80
81 match := func(n ir.Node) bool {
82 switch n := n.(type) {
83 case *ir.CallExpr:
84 return true
85 case *ir.TailCallStmt:
86 n.Call.NoInline = true
87 }
88 return false
89 }
90
91 edit := func(n ir.Node) ir.Node {
92 call, ok := n.(*ir.CallExpr)
93 if !ok {
94 return nil
95 }
96
97 devirtualize.StaticCall(call)
98 if inlCall := inline.TryInlineCall(fn, call, bigCaller, profile); inlCall != nil {
99 return inlCall
100 }
101 return nil
102 }
103
104 fixpoint(fn, match, edit)
105 })
106 }
107
108
109
110 func isTestingBLoop(t ir.Node) bool {
111 if t.Op() != ir.OFOR {
112 return false
113 }
114 nFor, ok := t.(*ir.ForStmt)
115 if !ok || nFor.Cond == nil || nFor.Cond.Op() != ir.OCALLFUNC {
116 return false
117 }
118 n, ok := nFor.Cond.(*ir.CallExpr)
119 if !ok || n.Fun == nil || n.Fun.Op() != ir.OMETHEXPR {
120 return false
121 }
122 name := ir.MethodExprName(n.Fun)
123 if name == nil {
124 return false
125 }
126 if fSym := name.Sym(); fSym != nil && name.Class == ir.PFUNC && fSym.Pkg != nil &&
127 fSym.Name == "(*B).Loop" && fSym.Pkg.Path == "testing" {
128
129 return true
130 }
131 return false
132 }
133
134
135
136
137
138
139
140
141
142
143
144 func fixpoint(fn *ir.Func, match func(ir.Node) bool, edit func(ir.Node) ir.Node) {
145
146
147
148
149
150
151
152
153
154
155 var parens []*ir.ParenExpr
156 var mark func(ir.Node) ir.Node
157 mark = func(n ir.Node) ir.Node {
158 if _, ok := n.(*ir.ParenExpr); ok {
159 return n
160 }
161
162 if isTestingBLoop(n) {
163
164 if base.Flag.LowerM > 1 {
165 fmt.Printf("%v: skip inlining within testing.B.loop for %v\n", ir.Line(n), n)
166 }
167 return n
168 }
169
170 ok := match(n)
171
172
173 if t, ok := n.(*ir.TailCallStmt); ok {
174 ir.EditChildren(t.Call, mark)
175 } else {
176 ir.EditChildren(n, mark)
177 }
178
179 if ok {
180 paren := ir.NewParenExpr(n.Pos(), n)
181 paren.SetType(n.Type())
182 paren.SetTypecheck(n.Typecheck())
183
184 parens = append(parens, paren)
185 n = paren
186 }
187
188 return n
189 }
190 ir.EditChildren(fn, mark)
191
192
193 for {
194 done := true
195
196 for i := 0; i < len(parens); i++ {
197 paren := parens[i]
198 if new := edit(paren.X); new != nil {
199
200 paren.X = new
201 ir.EditChildren(new, mark)
202 done = false
203 }
204 }
205
206 if done {
207 break
208 }
209 }
210
211
212 if len(parens) == 0 {
213 return
214 }
215 var unparen func(ir.Node) ir.Node
216 unparen = func(n ir.Node) ir.Node {
217 if paren, ok := n.(*ir.ParenExpr); ok {
218 n = paren.X
219 }
220 ir.EditChildren(n, unparen)
221 return n
222 }
223 ir.EditChildren(fn, unparen)
224 }
225
View as plain text