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