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
|
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package inlheur
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/internal/src"
"fmt"
"io"
"path/filepath"
"sort"
"strings"
)
// CallSite records useful information about a potentially inlinable
// (direct) function call. "Callee" is the target of the call, "Call"
// is the ir node corresponding to the call itself, "Assign" is
// the top-level assignment statement containing the call (if the call
// appears in the form of a top-level statement, e.g. "x := foo()"),
// "Flags" contains properties of the call that might be useful for
// making inlining decisions, "Score" is the final score assigned to
// the site, and "ID" is a numeric ID for the site within its
// containing function.
type CallSite struct {
Callee *ir.Func
Call *ir.CallExpr
parent *CallSite
Assign ir.Node
Flags CSPropBits
ArgProps []ActualExprPropBits
Score int
ScoreMask scoreAdjustTyp
ID uint
aux uint8
}
// CallSiteTab is a table of call sites, keyed by call expr.
// Ideally it would be nice to key the table by src.XPos, but
// this results in collisions for calls on very long lines (the
// front end saturates column numbers at 255). We also wind up
// with many calls that share the same auto-generated pos.
type CallSiteTab map[*ir.CallExpr]*CallSite
// ActualExprPropBits describes a property of an actual expression (value
// passed to some specific func argument at a call site).
type ActualExprPropBits uint8
const (
ActualExprConstant ActualExprPropBits = 1 << iota
ActualExprIsConcreteConvIface
ActualExprIsFunc
ActualExprIsInlinableFunc
)
type CSPropBits uint32
const (
CallSiteInLoop CSPropBits = 1 << iota
CallSiteOnPanicPath
CallSiteInInitFunc
)
type csAuxBits uint8
const (
csAuxInlined = 1 << iota
)
// encodedCallSiteTab is a table keyed by "encoded" callsite
// (stringified src.XPos plus call site ID) mapping to a value of call
// property bits and score.
type encodedCallSiteTab map[string]propsAndScore
type propsAndScore struct {
props CSPropBits
score int
mask scoreAdjustTyp
}
func (pas propsAndScore) String() string {
return fmt.Sprintf("P=%s|S=%d|M=%s", pas.props.String(),
pas.score, pas.mask.String())
}
func (cst CallSiteTab) merge(other CallSiteTab) error {
for k, v := range other {
if prev, ok := cst[k]; ok {
return fmt.Errorf("internal error: collision during call site table merge, fn=%s callsite=%s", prev.Callee.Sym().Name, fmtFullPos(prev.Call.Pos()))
}
cst[k] = v
}
return nil
}
func fmtFullPos(p src.XPos) string {
var sb strings.Builder
sep := ""
base.Ctxt.AllPos(p, func(pos src.Pos) {
fmt.Fprintf(&sb, sep)
sep = "|"
file := filepath.Base(pos.Filename())
fmt.Fprintf(&sb, "%s:%d:%d", file, pos.Line(), pos.Col())
})
return sb.String()
}
func EncodeCallSiteKey(cs *CallSite) string {
var sb strings.Builder
// FIXME: maybe rewrite line offsets relative to function start?
sb.WriteString(fmtFullPos(cs.Call.Pos()))
fmt.Fprintf(&sb, "|%d", cs.ID)
return sb.String()
}
func buildEncodedCallSiteTab(tab CallSiteTab) encodedCallSiteTab {
r := make(encodedCallSiteTab)
for _, cs := range tab {
k := EncodeCallSiteKey(cs)
r[k] = propsAndScore{
props: cs.Flags,
score: cs.Score,
mask: cs.ScoreMask,
}
}
return r
}
// dumpCallSiteComments emits comments into the dump file for the
// callsites in the function of interest. If "ecst" is non-nil, we use
// that, otherwise generated a fresh encodedCallSiteTab from "tab".
func dumpCallSiteComments(w io.Writer, tab CallSiteTab, ecst encodedCallSiteTab) {
if ecst == nil {
ecst = buildEncodedCallSiteTab(tab)
}
tags := make([]string, 0, len(ecst))
for k := range ecst {
tags = append(tags, k)
}
sort.Strings(tags)
for _, s := range tags {
v := ecst[s]
fmt.Fprintf(w, "// callsite: %s flagstr %q flagval %d score %d mask %d maskstr %q\n", s, v.props.String(), v.props, v.score, v.mask, v.mask.String())
}
fmt.Fprintf(w, "// %s\n", csDelimiter)
}
|