1
2
3
4
5 package ssacompile
6
7 import (
8 "fmt"
9 "sort"
10
11 "cmd/compile/internal/ssa"
12 "cmd/compile/internal/ssa/ssaop"
13 "cmd/internal/src"
14 )
15
16 func isPoorStatementOp(op ssaop.Op) bool {
17 switch op {
18
19
20 case ssaop.OpAddr, ssaop.OpLocalAddr, ssaop.OpOffPtr, ssaop.OpStructSelect, ssaop.OpPhi, ssaop.OpITab, ssaop.OpIData,
21 ssaop.OpIMake, ssaop.OpStringMake, ssaop.OpSliceMake, ssaop.OpStructMake,
22 ssaop.OpConstBool, ssaop.OpConst8, ssaop.OpConst16, ssaop.OpConst32, ssaop.OpConst64, ssaop.OpConst32F, ssaop.OpConst64F, ssaop.OpSB, ssaop.OpSP,
23 ssaop.OpArgIntReg, ssaop.OpArgFloatReg:
24 return true
25 }
26 return false
27 }
28
29
30
31
32
33
34 func nextGoodStatementIndex(v *ssa.Value, i int, b *ssa.Block) int {
35
36
37
38
39 if i >= len(b.Values)-1 {
40 return i
41 }
42
43 if !isPoorStatementOp(v.Op) {
44 return i
45 }
46
47 for j := i + 1; j < len(b.Values); j++ {
48 u := b.Values[j]
49 if u.Pos.IsStmt() == src.PosNotStmt {
50 continue
51 }
52 if u.Pos.SameFileAndLine(v.Pos) {
53 if isPoorStatementOp(u.Op) {
54 continue
55 }
56 return j
57 }
58 return i
59 }
60 return i
61 }
62
63 func flc(p src.XPos) string {
64 if p == src.NoXPos {
65 return "none"
66 }
67 return fmt.Sprintf("(%d):%d:%d", p.FileIndex(), p.Line(), p.Col())
68 }
69
70 type fileAndPair struct {
71 f int32
72 lp ssa.LineRange
73 }
74
75 type fileAndPairs []fileAndPair
76
77 func (fap fileAndPairs) Len() int {
78 return len(fap)
79 }
80 func (fap fileAndPairs) Less(i, j int) bool {
81 return fap[i].f < fap[j].f
82 }
83 func (fap fileAndPairs) Swap(i, j int) {
84 fap[i], fap[j] = fap[j], fap[i]
85 }
86
87
88
89 func numberLines(f *ssa.Func) {
90 po := f.Postorder()
91 endlines := make(map[ssa.ID]src.XPos)
92 ranges := make(map[int]ssa.LineRange)
93 note := func(p src.XPos) {
94 line := uint32(p.Line())
95 i := int(p.FileIndex())
96 lp, found := ranges[i]
97 change := false
98 if line < lp.First || !found {
99 lp.First = line
100 change = true
101 }
102 if line > lp.Last {
103 lp.Last = line
104 change = true
105 }
106 if change {
107 ranges[i] = lp
108 }
109 }
110
111
112 for j := len(po) - 1; j >= 0; j-- {
113 b := po[j]
114
115 firstPos := src.NoXPos
116 firstPosIndex := -1
117 if b.Pos.IsStmt() != src.PosNotStmt {
118 note(b.Pos)
119 }
120 for i := 0; i < len(b.Values); i++ {
121 v := b.Values[i]
122 if v.Pos.IsStmt() != src.PosNotStmt {
123 note(v.Pos)
124
125 i = nextGoodStatementIndex(v, i, b)
126 v = b.Values[i]
127 firstPosIndex = i
128 firstPos = v.Pos
129 v.Pos = firstPos.WithDefaultStmt()
130 break
131 }
132 }
133
134 if firstPosIndex == -1 {
135 line := src.NoXPos
136 for _, p := range b.Preds {
137 pbi := p.Block().ID
138 if !endlines[pbi].SameFileAndLine(line) {
139 if line == src.NoXPos {
140 line = endlines[pbi]
141 continue
142 } else {
143 line = src.NoXPos
144 break
145 }
146
147 }
148 }
149
150 if b.Pos.IsStmt() == src.PosNotStmt {
151 b.Pos = line
152 endlines[b.ID] = line
153 continue
154 }
155
156 if line == src.NoXPos || !line.SameFileAndLine(b.Pos) {
157 b.Pos = b.Pos.WithIsStmt()
158 if f.Pass.Debug > 0 {
159 fmt.Printf("Mark stmt effectively-empty-block %s %s %s\n", f.Name, b, flc(b.Pos))
160 }
161 }
162 endlines[b.ID] = b.Pos
163 continue
164 }
165
166 if len(b.Preds) == 0 {
167 b.Values[firstPosIndex].Pos = firstPos.WithIsStmt()
168 if f.Pass.Debug > 0 {
169 fmt.Printf("Mark stmt entry-block %s %s %s %s\n", f.Name, b, b.Values[firstPosIndex], flc(firstPos))
170 }
171 } else {
172 for _, p := range b.Preds {
173 pbi := p.Block().ID
174 if !endlines[pbi].SameFileAndLine(firstPos) {
175 b.Values[firstPosIndex].Pos = firstPos.WithIsStmt()
176 if f.Pass.Debug > 0 {
177 fmt.Printf("Mark stmt differing-pred %s %s %s %s, different=%s ending %s\n",
178 f.Name, b, b.Values[firstPosIndex], flc(firstPos), p.Block(), flc(endlines[pbi]))
179 }
180 break
181 }
182 }
183 }
184
185 for i := firstPosIndex + 1; i < len(b.Values); i++ {
186 v := b.Values[i]
187 if v.Pos.IsStmt() == src.PosNotStmt {
188 continue
189 }
190 note(v.Pos)
191
192 i = nextGoodStatementIndex(v, i, b)
193 v = b.Values[i]
194 if !v.Pos.SameFileAndLine(firstPos) {
195 if f.Pass.Debug > 0 {
196 fmt.Printf("Mark stmt new line %s %s %s %s prev pos = %s\n", f.Name, b, v, flc(v.Pos), flc(firstPos))
197 }
198 firstPos = v.Pos
199 v.Pos = v.Pos.WithIsStmt()
200 } else {
201 v.Pos = v.Pos.WithDefaultStmt()
202 }
203 }
204 if b.Pos.IsStmt() != src.PosNotStmt && !b.Pos.SameFileAndLine(firstPos) {
205 if f.Pass.Debug > 0 {
206 fmt.Printf("Mark stmt end of block differs %s %s %s prev pos = %s\n", f.Name, b, flc(b.Pos), flc(firstPos))
207 }
208 b.Pos = b.Pos.WithIsStmt()
209 firstPos = b.Pos
210 }
211 endlines[b.ID] = firstPos
212 }
213 if f.Pass.Stats&1 != 0 {
214
215
216 var entries fileAndPairs
217 for k, v := range ranges {
218 entries = append(entries, fileAndPair{int32(k), v})
219 }
220 sort.Sort(entries)
221 total := uint64(0)
222 maxfile := int32(0)
223 minline := uint32(0xffffffff)
224 maxline := uint32(0)
225 for _, v := range entries {
226 if f.Pass.Stats > 1 {
227 f.LogStat("file", v.f, "low", v.lp.First, "high", v.lp.Last)
228 }
229 total += uint64(v.lp.Last - v.lp.First)
230 if maxfile < v.f {
231 maxfile = v.f
232 }
233 if minline > v.lp.First {
234 minline = v.lp.First
235 }
236 if maxline < v.lp.Last {
237 maxline = v.lp.Last
238 }
239 }
240 f.LogStat("SUM_LINE_RANGE", total, "MAXMIN_LINE_RANGE", maxline-minline, "MAXFILE", maxfile, "NFILES", len(entries))
241 }
242
243 f.CachedLineStarts = ssa.NewXPosMap(ranges)
244 }
245
View as plain text