1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 "container/heap"
10 "sort"
11 )
12
13 const (
14 ScorePhi = iota
15 ScoreArg
16 ScoreNilCheck
17 ScoreReadTuple
18 ScoreVarDef
19 ScoreMemory
20 ScoreReadFlags
21 ScoreDefault
22 ScoreFlags
23 ScoreControl
24 )
25
26 type ValHeap struct {
27 a []*Value
28 score []int8
29 }
30
31 func (h ValHeap) Len() int { return len(h.a) }
32 func (h ValHeap) Swap(i, j int) { a := h.a; a[i], a[j] = a[j], a[i] }
33
34 func (h *ValHeap) Push(x interface{}) {
35
36
37 v := x.(*Value)
38 h.a = append(h.a, v)
39 }
40 func (h *ValHeap) Pop() interface{} {
41 old := h.a
42 n := len(old)
43 x := old[n-1]
44 h.a = old[0 : n-1]
45 return x
46 }
47 func (h ValHeap) Less(i, j int) bool {
48 x := h.a[i]
49 y := h.a[j]
50 sx := h.score[x.ID]
51 sy := h.score[y.ID]
52 if c := sx - sy; c != 0 {
53 return c > 0
54 }
55 if x.Pos != y.Pos {
56 return x.Pos.After(y.Pos)
57 }
58 if x.Op != OpPhi {
59 if c := len(x.Args) - len(y.Args); c != 0 {
60 return c < 0
61 }
62 }
63 if c := x.Uses - y.Uses; c != 0 {
64 return c < 0
65 }
66
67
68
69 if c := x.AuxInt - y.AuxInt; c != 0 {
70 return c > 0
71 }
72 if cmp := x.Type.Compare(y.Type); cmp != types.CMPeq {
73 return cmp == types.CMPgt
74 }
75 return x.ID > y.ID
76 }
77
78 func (op Op) isLoweredGetClosurePtr() bool {
79 switch op {
80 case OpAMD64LoweredGetClosurePtr, OpPPC64LoweredGetClosurePtr, OpARMLoweredGetClosurePtr, OpARM64LoweredGetClosurePtr,
81 Op386LoweredGetClosurePtr, OpMIPS64LoweredGetClosurePtr, OpS390XLoweredGetClosurePtr, OpMIPSLoweredGetClosurePtr,
82 OpRISCV64LoweredGetClosurePtr, OpWasmLoweredGetClosurePtr:
83 return true
84 }
85 return false
86 }
87
88
89
90
91
92
93 func schedule(f *Func) {
94
95
96 uses := make([]int32, f.NumValues())
97
98
99 priq := new(ValHeap)
100
101
102 score := make([]int8, f.NumValues())
103
104
105
106
107 order := make([]*Value, 0, 64)
108
109
110 nextMem := make([]*Value, f.NumValues())
111
112 additionalArgs := make([][]*Value, f.NumValues())
113
114 for _, b := range f.Blocks {
115
116 for _, v := range b.Values {
117 switch {
118 case v.Op.isLoweredGetClosurePtr():
119
120
121
122
123 if b != f.Entry {
124 f.Fatalf("LoweredGetClosurePtr appeared outside of entry block, b=%s", b.String())
125 }
126 score[v.ID] = ScorePhi
127 case v.Op == OpAMD64LoweredNilCheck || v.Op == OpPPC64LoweredNilCheck ||
128 v.Op == OpARMLoweredNilCheck || v.Op == OpARM64LoweredNilCheck ||
129 v.Op == Op386LoweredNilCheck || v.Op == OpMIPS64LoweredNilCheck ||
130 v.Op == OpS390XLoweredNilCheck || v.Op == OpMIPSLoweredNilCheck ||
131 v.Op == OpRISCV64LoweredNilCheck || v.Op == OpWasmLoweredNilCheck:
132
133 score[v.ID] = ScoreNilCheck
134 case v.Op == OpPhi:
135
136 score[v.ID] = ScorePhi
137 case v.Op == OpVarDef:
138
139 score[v.ID] = ScoreVarDef
140 case v.Op == OpArgIntReg || v.Op == OpArgFloatReg:
141
142
143 if b != f.Entry {
144 f.Fatalf("%s appeared outside of entry block, b=%s", v.Op, b.String())
145 }
146 score[v.ID] = ScorePhi
147 case v.Op == OpArg:
148
149 score[v.ID] = ScoreArg
150 case v.Type.IsMemory():
151
152
153
154 score[v.ID] = ScoreMemory
155 case v.Op == OpSelect0 || v.Op == OpSelect1 || v.Op == OpSelectN:
156
157
158
159
160
161 score[v.ID] = ScoreReadTuple
162 case v.Type.IsFlags() || v.Type.IsTuple() && v.Type.FieldType(1).IsFlags():
163
164
165
166 score[v.ID] = ScoreFlags
167 default:
168 score[v.ID] = ScoreDefault
169
170 for _, a := range v.Args {
171 if a.Type.IsFlags() {
172 score[v.ID] = ScoreReadFlags
173 }
174 }
175 }
176 }
177 }
178
179 for _, b := range f.Blocks {
180
181
182
183 for _, v := range b.Values {
184 if v.Op != OpPhi && v.Type.IsMemory() {
185 for _, w := range v.Args {
186 if w.Type.IsMemory() {
187 nextMem[w.ID] = v
188 }
189 }
190 }
191 }
192
193
194 for _, v := range b.Values {
195 if v.Op == OpPhi {
196
197
198
199 continue
200 }
201 for _, w := range v.Args {
202 if w.Block == b {
203 uses[w.ID]++
204 }
205
206 if !v.Type.IsMemory() && w.Type.IsMemory() {
207
208 s := nextMem[w.ID]
209 if s == nil || s.Block != b {
210 continue
211 }
212 additionalArgs[s.ID] = append(additionalArgs[s.ID], v)
213 uses[v.ID]++
214 }
215 }
216 }
217
218 for _, c := range b.ControlValues() {
219
220
221
222
223 if score[c.ID] == ScorePhi || score[c.ID] == ScoreArg {
224 continue
225 }
226 score[c.ID] = ScoreControl
227
228
229
230
231
232
233 for _, v := range b.Values {
234 if v.Op != OpPhi {
235 for _, a := range v.Args {
236 if a == c {
237 score[v.ID] = ScoreControl
238 }
239 }
240 }
241 }
242
243 }
244
245
246
247 priq.score = score
248 priq.a = priq.a[:0]
249
250
251 for _, v := range b.Values {
252 if uses[v.ID] == 0 {
253 heap.Push(priq, v)
254 }
255 }
256
257
258 order = order[:0]
259 tuples := make(map[ID][]*Value)
260 for priq.Len() > 0 {
261
262
263
264 v := heap.Pop(priq).(*Value)
265
266
267
268
269 switch {
270 case v.Op == OpSelect0:
271 if tuples[v.Args[0].ID] == nil {
272 tuples[v.Args[0].ID] = make([]*Value, 2)
273 }
274 tuples[v.Args[0].ID][0] = v
275 case v.Op == OpSelect1:
276 if tuples[v.Args[0].ID] == nil {
277 tuples[v.Args[0].ID] = make([]*Value, 2)
278 }
279 tuples[v.Args[0].ID][1] = v
280 case v.Op == OpSelectN:
281 if tuples[v.Args[0].ID] == nil {
282 tuples[v.Args[0].ID] = make([]*Value, v.Args[0].Type.NumFields())
283 }
284 tuples[v.Args[0].ID][v.AuxInt] = v
285 case v.Type.IsResults() && tuples[v.ID] != nil:
286 tup := tuples[v.ID]
287 for i := len(tup) - 1; i >= 0; i-- {
288 if tup[i] != nil {
289 order = append(order, tup[i])
290 }
291 }
292 delete(tuples, v.ID)
293 order = append(order, v)
294 case v.Type.IsTuple() && tuples[v.ID] != nil:
295 if tuples[v.ID][1] != nil {
296 order = append(order, tuples[v.ID][1])
297 }
298 if tuples[v.ID][0] != nil {
299 order = append(order, tuples[v.ID][0])
300 }
301 delete(tuples, v.ID)
302 fallthrough
303 default:
304 order = append(order, v)
305 }
306
307
308 for _, w := range v.Args {
309 if w.Block != b {
310 continue
311 }
312 uses[w.ID]--
313 if uses[w.ID] == 0 {
314
315 heap.Push(priq, w)
316 }
317 }
318 for _, w := range additionalArgs[v.ID] {
319 uses[w.ID]--
320 if uses[w.ID] == 0 {
321
322 heap.Push(priq, w)
323 }
324 }
325 }
326 if len(order) != len(b.Values) {
327 f.Fatalf("schedule does not include all values in block %s", b)
328 }
329 for i := 0; i < len(b.Values); i++ {
330 b.Values[i] = order[len(b.Values)-1-i]
331 }
332 }
333
334 f.scheduled = true
335 }
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356 func storeOrder(values []*Value, sset *sparseSet, storeNumber []int32) []*Value {
357 if len(values) == 0 {
358 return values
359 }
360
361 f := values[0].Block.Func
362
363
364
365
366
367
368 stores := make([]*Value, 0, 64)
369 hasNilCheck := false
370 sset.clear()
371 for _, v := range values {
372 if v.Type.IsMemory() {
373 stores = append(stores, v)
374 if v.Op == OpInitMem || v.Op == OpPhi {
375 continue
376 }
377 sset.add(v.MemoryArg().ID)
378 }
379 if v.Op == OpNilCheck {
380 hasNilCheck = true
381 }
382 }
383 if len(stores) == 0 || !hasNilCheck && f.pass.name == "nilcheckelim" {
384
385 return values
386 }
387
388
389 var last *Value
390 for _, v := range stores {
391 if !sset.contains(v.ID) {
392 if last != nil {
393 f.Fatalf("two stores live simultaneously: %v and %v", v, last)
394 }
395 last = v
396 }
397 }
398
399
400
401
402
403
404
405
406
407
408 count := make([]int32, 3*(len(stores)+1))
409 sset.clear()
410 for n, w := len(stores), last; n > 0; n-- {
411 storeNumber[w.ID] = int32(3 * n)
412 count[3*n]++
413 sset.add(w.ID)
414 if w.Op == OpInitMem || w.Op == OpPhi {
415 if n != 1 {
416 f.Fatalf("store order is wrong: there are stores before %v", w)
417 }
418 break
419 }
420 w = w.MemoryArg()
421 }
422 var stack []*Value
423 for _, v := range values {
424 if sset.contains(v.ID) {
425
426 continue
427 }
428 stack = append(stack, v)
429 sset.add(v.ID)
430
431 for len(stack) > 0 {
432 w := stack[len(stack)-1]
433 if storeNumber[w.ID] != 0 {
434 stack = stack[:len(stack)-1]
435 continue
436 }
437 if w.Op == OpPhi {
438
439
440 storeNumber[w.ID] = 2
441 count[2]++
442 stack = stack[:len(stack)-1]
443 continue
444 }
445
446 max := int32(0)
447 argsdone := true
448 for _, a := range w.Args {
449 if a.Block != w.Block {
450 continue
451 }
452 if !sset.contains(a.ID) {
453 stack = append(stack, a)
454 sset.add(a.ID)
455 argsdone = false
456 break
457 }
458 if storeNumber[a.ID]/3 > max {
459 max = storeNumber[a.ID] / 3
460 }
461 }
462 if !argsdone {
463 continue
464 }
465
466 n := 3*max + 2
467 if w.Op == OpNilCheck {
468 n = 3*max + 1
469 }
470 storeNumber[w.ID] = n
471 count[n]++
472 stack = stack[:len(stack)-1]
473 }
474 }
475
476
477 for i := range count {
478 if i == 0 {
479 continue
480 }
481 count[i] += count[i-1]
482 }
483 if count[len(count)-1] != int32(len(values)) {
484 f.Fatalf("storeOrder: value is missing, total count = %d, values = %v", count[len(count)-1], values)
485 }
486
487
488 order := make([]*Value, len(values))
489 for _, v := range values {
490 s := storeNumber[v.ID]
491 order[count[s-1]] = v
492 count[s-1]++
493 }
494
495
496
497
498 if hasNilCheck {
499 start := -1
500 for i, v := range order {
501 if v.Op == OpNilCheck {
502 if start == -1 {
503 start = i
504 }
505 } else {
506 if start != -1 {
507 sort.Sort(bySourcePos(order[start:i]))
508 start = -1
509 }
510 }
511 }
512 if start != -1 {
513 sort.Sort(bySourcePos(order[start:]))
514 }
515 }
516
517 return order
518 }
519
520 type bySourcePos []*Value
521
522 func (s bySourcePos) Len() int { return len(s) }
523 func (s bySourcePos) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
524 func (s bySourcePos) Less(i, j int) bool { return s[i].Pos.Before(s[j].Pos) }
525
View as plain text