1
2
3
4
5 package ssa
6
7 import (
8 "cmd/internal/src"
9 "fmt"
10 )
11
12
13 type Block struct {
14
15
16 ID ID
17
18
19 Pos src.XPos
20
21
22 CPUfeatures CPUfeatures
23
24
25 Kind BlockKind
26
27
28
29
30
31
32 Likely BranchPrediction
33
34
35 FlagsLiveAtEnd bool
36
37
38 Hotness Hotness
39
40
41 Succs []Edge
42
43
44
45
46
47 Preds []Edge
48
49
50
51
52
53
54
55
56
57
58 Controls [2]*Value
59
60
61 Aux Aux
62 AuxInt int64
63
64
65
66 Values []*Value
67
68
69 Func *Func
70
71
72 succstorage [2]Edge
73 predstorage [4]Edge
74 valstorage [9]*Value
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 type Edge struct {
101
102 b *Block
103
104
105
106
107 i int
108 }
109
110 func (e Edge) Block() *Block {
111 return e.b
112 }
113 func (e Edge) Index() int {
114 return e.i
115 }
116 func (e Edge) String() string {
117 return fmt.Sprintf("{%v,%d}", e.b, e.i)
118 }
119
120
121 type BlockKind uint8
122
123
124 func (b *Block) String() string {
125 return fmt.Sprintf("b%d", b.ID)
126 }
127
128
129 func (b *Block) LongString() string {
130 s := b.Kind.String()
131 if b.Aux != nil {
132 s += fmt.Sprintf(" {%s}", b.Aux)
133 }
134 if t := b.AuxIntString(); t != "" {
135 s += fmt.Sprintf(" [%s]", t)
136 }
137 for _, c := range b.ControlValues() {
138 s += fmt.Sprintf(" %s", c)
139 }
140 if len(b.Succs) > 0 {
141 s += " ->"
142 for _, c := range b.Succs {
143 s += " " + c.b.String()
144 }
145 }
146 switch b.Likely {
147 case BranchUnlikely:
148 s += " (unlikely)"
149 case BranchLikely:
150 s += " (likely)"
151 }
152 return s
153 }
154
155
156
157 func (b *Block) NumControls() int {
158 if b.Controls[0] == nil {
159 return 0
160 }
161 if b.Controls[1] == nil {
162 return 1
163 }
164 return 2
165 }
166
167
168
169
170
171 func (b *Block) ControlValues() []*Value {
172 if b.Controls[0] == nil {
173 return b.Controls[:0]
174 }
175 if b.Controls[1] == nil {
176 return b.Controls[:1]
177 }
178 return b.Controls[:2]
179 }
180
181
182
183
184 func (b *Block) SetControl(v *Value) {
185 b.ResetControls()
186 b.Controls[0] = v
187 v.Uses++
188 }
189
190
191 func (b *Block) ResetControls() {
192 if b.Controls[0] != nil {
193 b.Controls[0].Uses--
194 }
195 if b.Controls[1] != nil {
196 b.Controls[1].Uses--
197 }
198 b.Controls = [2]*Value{}
199 }
200
201
202 func (b *Block) AddControl(v *Value) {
203 i := b.NumControls()
204 b.Controls[i] = v
205 v.Uses++
206 }
207
208
209
210 func (b *Block) ReplaceControl(i int, v *Value) {
211 b.Controls[i].Uses--
212 b.Controls[i] = v
213 v.Uses++
214 }
215
216
217
218 func (b *Block) CopyControls(from *Block) {
219 if b == from {
220 return
221 }
222 b.ResetControls()
223 for _, c := range from.ControlValues() {
224 b.AddControl(c)
225 }
226 }
227
228
229
230
231 func (b *Block) Reset(kind BlockKind) {
232 b.Kind = kind
233 b.ResetControls()
234 b.Aux = nil
235 b.AuxInt = 0
236 }
237
238
239
240
241
242 func (b *Block) resetWithControl(kind BlockKind, v *Value) {
243 b.Kind = kind
244 b.ResetControls()
245 b.Aux = nil
246 b.AuxInt = 0
247 b.Controls[0] = v
248 v.Uses++
249 }
250
251
252
253
254
255 func (b *Block) resetWithControl2(kind BlockKind, v, w *Value) {
256 b.Kind = kind
257 b.ResetControls()
258 b.Aux = nil
259 b.AuxInt = 0
260 b.Controls[0] = v
261 b.Controls[1] = w
262 v.Uses++
263 w.Uses++
264 }
265
266
267
268
269 func (b *Block) truncateValues(i int) {
270 clear(b.Values[i:])
271 b.Values = b.Values[:i]
272 }
273
274
275 func (b *Block) AddEdgeTo(c *Block) {
276 i := len(b.Succs)
277 j := len(c.Preds)
278 b.Succs = append(b.Succs, Edge{c, j})
279 c.Preds = append(c.Preds, Edge{b, i})
280 b.Func.invalidateCFG()
281 }
282
283
284
285
286
287 func (b *Block) removePred(i int) {
288 n := len(b.Preds) - 1
289 if i != n {
290 e := b.Preds[n]
291 b.Preds[i] = e
292
293 e.b.Succs[e.i].i = i
294 }
295 b.Preds[n] = Edge{}
296 b.Preds = b.Preds[:n]
297 b.Func.invalidateCFG()
298 }
299
300
301
302
303
304
305 func (b *Block) removeSucc(i int) {
306 n := len(b.Succs) - 1
307 if i != n {
308 e := b.Succs[n]
309 b.Succs[i] = e
310
311 e.b.Preds[e.i].i = i
312 }
313 b.Succs[n] = Edge{}
314 b.Succs = b.Succs[:n]
315 b.Func.invalidateCFG()
316 }
317
318 func (b *Block) swapSuccessors() {
319 if len(b.Succs) != 2 {
320 b.Fatalf("swapSuccessors with len(Succs)=%d", len(b.Succs))
321 }
322 e0 := b.Succs[0]
323 e1 := b.Succs[1]
324 b.Succs[0] = e1
325 b.Succs[1] = e0
326 e0.b.Preds[e0.i].i = 1
327 e1.b.Preds[e1.i].i = 0
328 b.Likely *= -1
329 }
330
331
332 func (b *Block) swapSuccessorsByIdx(x, y int) {
333 if x == y {
334 return
335 }
336 ex := b.Succs[x]
337 ey := b.Succs[y]
338 b.Succs[x] = ey
339 b.Succs[y] = ex
340 ex.b.Preds[ex.i].i = y
341 ey.b.Preds[ey.i].i = x
342 }
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357 func (b *Block) removePhiArg(phi *Value, i int) {
358 n := len(b.Preds)
359 if numPhiArgs := len(phi.Args); numPhiArgs-1 != n {
360 b.Fatalf("inconsistent state for %v, num predecessors: %d, num phi args: %d", phi, n, numPhiArgs)
361 }
362 phi.Args[i].Uses--
363 phi.Args[i] = phi.Args[n]
364 phi.Args[n] = nil
365 phi.Args = phi.Args[:n]
366 phielimValue(phi)
367 }
368
369
370
371 func (b *Block) uniquePred() *Block {
372 if len(b.Preds) != 1 {
373 return nil
374 }
375 return b.Preds[0].b
376 }
377
378
379
380
381
382 func (b *Block) LackingPos() bool {
383
384
385
386 if b.Kind != BlockPlain {
387 return false
388 }
389 if b.Pos != src.NoXPos {
390 return false
391 }
392 for _, v := range b.Values {
393 if v.LackingPos() {
394 continue
395 }
396 return false
397 }
398 return true
399 }
400
401 func (b *Block) AuxIntString() string {
402 switch b.Kind.AuxIntType() {
403 case "int8":
404 return fmt.Sprintf("%v", int8(b.AuxInt))
405 case "uint8":
406 return fmt.Sprintf("%v", uint8(b.AuxInt))
407 case "":
408 return ""
409 default:
410 return fmt.Sprintf("%v", b.AuxInt)
411 }
412 }
413
414
415 func (b *Block) likelyBranch() bool {
416 if len(b.Preds) == 0 {
417 return false
418 }
419 for _, e := range b.Preds {
420 p := e.b
421 if len(p.Succs) == 1 || len(p.Succs) == 2 && (p.Likely == BranchLikely && p.Succs[0].b == b ||
422 p.Likely == BranchUnlikely && p.Succs[1].b == b) {
423 continue
424 }
425 return false
426 }
427 return true
428 }
429
430 func (b *Block) Logf(msg string, args ...any) { b.Func.Logf(msg, args...) }
431 func (b *Block) Log() bool { return b.Func.Log() }
432 func (b *Block) Fatalf(msg string, args ...any) { b.Func.Fatalf(msg, args...) }
433
434 type BranchPrediction int8
435
436 const (
437 BranchUnlikely = BranchPrediction(-1)
438 BranchUnknown = BranchPrediction(0)
439 BranchLikely = BranchPrediction(+1)
440 )
441
442 type Hotness int8
443 const (
444
445
446 HotNotFlowIn Hotness = 1 << iota
447 HotInitial
448 HotPgo
449
450 HotNot = 0
451 HotInitialNotFlowIn = HotInitial | HotNotFlowIn
452 HotPgoInitial = HotPgo | HotInitial
453 HotPgoInitialNotFLowIn = HotPgo | HotInitial | HotNotFlowIn
454 )
455
456 type CPUfeatures uint32
457
458 const (
459 CPUNone CPUfeatures = 0
460 CPUAll CPUfeatures = ^CPUfeatures(0)
461 CPUavx CPUfeatures = 1 << iota
462 CPUavx2
463 CPUavxvnni
464 CPUavx512
465 CPUbitalg
466 CPUgfni
467 CPUvbmi
468 CPUvbmi2
469 CPUvpopcntdq
470 CPUavx512vnni
471
472 CPUneon
473 CPUsve2
474 )
475
476 func (f CPUfeatures) hasFeature(x CPUfeatures) bool {
477 return f&x == x
478 }
479
480 func (f CPUfeatures) String() string {
481 if f == CPUNone {
482 return "none"
483 }
484 if f == CPUAll {
485 return "all"
486 }
487 s := ""
488 foo := func(what string, feat CPUfeatures) {
489 if feat&f != 0 {
490 if s != "" {
491 s += "+"
492 }
493 s += what
494 }
495 }
496 foo("avx", CPUavx)
497 foo("avx2", CPUavx2)
498 foo("avx512", CPUavx512)
499 foo("avxvnni", CPUavxvnni)
500 foo("bitalg", CPUbitalg)
501 foo("gfni", CPUgfni)
502 foo("vbmi", CPUvbmi)
503 foo("vbmi2", CPUvbmi2)
504 foo("popcntdq", CPUvpopcntdq)
505 foo("avx512vnni", CPUavx512vnni)
506
507 return s
508 }
509
View as plain text