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 == OpArg:
141
142 score[v.ID] = ScoreArg
143 case v.Type.IsMemory():
144
145
146
147 score[v.ID] = ScoreMemory
148 case v.Op == OpSelect0 || v.Op == OpSelect1:
149
150
151
152
153
154 score[v.ID] = ScoreReadTuple
155 case v.Type.IsFlags() || v.Type.IsTuple() && v.Type.FieldType(1).IsFlags():
156
157
158
159 score[v.ID] = ScoreFlags
160 default:
161 score[v.ID] = ScoreDefault
162
163 for _, a := range v.Args {
164 if a.Type.IsFlags() {
165 score[v.ID] = ScoreReadFlags
166 }
167 }
168 }
169 }
170 }
171
172 for _, b := range f.Blocks {
173
174
175
176 for _, v := range b.Values {
177 if v.Op != OpPhi && v.Type.IsMemory() {
178 for _, w := range v.Args {
179 if w.Type.IsMemory() {
180 nextMem[w.ID] = v
181 }
182 }
183 }
184 }
185
186
187 for _, v := range b.Values {
188 if v.Op == OpPhi {
189
190
191
192 continue
193 }
194 for _, w := range v.Args {
195 if w.Block == b {
196 uses[w.ID]++
197 }
198
199 if !v.Type.IsMemory() && w.Type.IsMemory() {
200
201 s := nextMem[w.ID]
202 if s == nil || s.Block != b {
203 continue
204 }
205 additionalArgs[s.ID] = append(additionalArgs[s.ID], v)
206 uses[v.ID]++
207 }
208 }
209 }
210
211 for _, c := range b.ControlValues() {
212
213
214
215
216 if c.Op == OpPhi || c.Op == OpArg {
217 continue
218 }
219 score[c.ID] = ScoreControl
220
221
222
223
224
225
226 for _, v := range b.Values {
227 if v.Op != OpPhi {
228 for _, a := range v.Args {
229 if a == c {
230 score[v.ID] = ScoreControl
231 }
232 }
233 }
234 }
235
236 }
237
238
239
240 priq.score = score
241 priq.a = priq.a[:0]
242
243
244 for _, v := range b.Values {
245 if uses[v.ID] == 0 {
246 heap.Push(priq, v)
247 }
248 }
249
250
251 order = order[:0]
252 tuples := make(map[ID][]*Value)
253 for priq.Len() > 0 {
254
255
256
257 v := heap.Pop(priq).(*Value)
258
259
260
261
262 switch {
263 case v.Op == OpSelect0:
264 if tuples[v.Args[0].ID] == nil {
265 tuples[v.Args[0].ID] = make([]*Value, 2)
266 }
267 tuples[v.Args[0].ID][0] = v
268 case v.Op == OpSelect1:
269 if tuples[v.Args[0].ID] == nil {
270 tuples[v.Args[0].ID] = make([]*Value, 2)
271 }
272 tuples[v.Args[0].ID][1] = v
273 case v.Type.IsTuple() && tuples[v.ID] != nil:
274 if tuples[v.ID][1] != nil {
275 order = append(order, tuples[v.ID][1])
276 }
277 if tuples[v.ID][0] != nil {
278 order = append(order, tuples[v.ID][0])
279 }
280 delete(tuples, v.ID)
281 fallthrough
282 default:
283 order = append(order, v)
284 }
285
286
287 for _, w := range v.Args {
288 if w.Block != b {
289 continue
290 }
291 uses[w.ID]--
292 if uses[w.ID] == 0 {
293
294 heap.Push(priq, w)
295 }
296 }
297 for _, w := range additionalArgs[v.ID] {
298 uses[w.ID]--
299 if uses[w.ID] == 0 {
300
301 heap.Push(priq, w)
302 }
303 }
304 }
305 if len(order) != len(b.Values) {
306 f.Fatalf("schedule does not include all values in block %s", b)
307 }
308 for i := 0; i < len(b.Values); i++ {
309 b.Values[i] = order[len(b.Values)-1-i]
310 }
311 }
312
313 f.scheduled = true
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335 func storeOrder(values []*Value, sset *sparseSet, storeNumber []int32) []*Value {
336 if len(values) == 0 {
337 return values
338 }
339
340 f := values[0].Block.Func
341
342
343
344
345
346
347 stores := make([]*Value, 0, 64)
348 hasNilCheck := false
349 sset.clear()
350 for _, v := range values {
351 if v.Type.IsMemory() {
352 stores = append(stores, v)
353 if v.Op == OpInitMem || v.Op == OpPhi {
354 continue
355 }
356 sset.add(v.MemoryArg().ID)
357 }
358 if v.Op == OpNilCheck {
359 hasNilCheck = true
360 }
361 }
362 if len(stores) == 0 || !hasNilCheck && f.pass.name == "nilcheckelim" {
363
364 return values
365 }
366
367
368 var last *Value
369 for _, v := range stores {
370 if !sset.contains(v.ID) {
371 if last != nil {
372 f.Fatalf("two stores live simultaneously: %v and %v", v, last)
373 }
374 last = v
375 }
376 }
377
378
379
380
381
382
383
384
385
386
387 count := make([]int32, 3*(len(stores)+1))
388 sset.clear()
389 for n, w := len(stores), last; n > 0; n-- {
390 storeNumber[w.ID] = int32(3 * n)
391 count[3*n]++
392 sset.add(w.ID)
393 if w.Op == OpInitMem || w.Op == OpPhi {
394 if n != 1 {
395 f.Fatalf("store order is wrong: there are stores before %v", w)
396 }
397 break
398 }
399 w = w.MemoryArg()
400 }
401 var stack []*Value
402 for _, v := range values {
403 if sset.contains(v.ID) {
404
405 continue
406 }
407 stack = append(stack, v)
408 sset.add(v.ID)
409
410 for len(stack) > 0 {
411 w := stack[len(stack)-1]
412 if storeNumber[w.ID] != 0 {
413 stack = stack[:len(stack)-1]
414 continue
415 }
416 if w.Op == OpPhi {
417
418
419 storeNumber[w.ID] = 2
420 count[2]++
421 stack = stack[:len(stack)-1]
422 continue
423 }
424
425 max := int32(0)
426 argsdone := true
427 for _, a := range w.Args {
428 if a.Block != w.Block {
429 continue
430 }
431 if !sset.contains(a.ID) {
432 stack = append(stack, a)
433 sset.add(a.ID)
434 argsdone = false
435 break
436 }
437 if storeNumber[a.ID]/3 > max {
438 max = storeNumber[a.ID] / 3
439 }
440 }
441 if !argsdone {
442 continue
443 }
444
445 n := 3*max + 2
446 if w.Op == OpNilCheck {
447 n = 3*max + 1
448 }
449 storeNumber[w.ID] = n
450 count[n]++
451 stack = stack[:len(stack)-1]
452 }
453 }
454
455
456 for i := range count {
457 if i == 0 {
458 continue
459 }
460 count[i] += count[i-1]
461 }
462 if count[len(count)-1] != int32(len(values)) {
463 f.Fatalf("storeOrder: value is missing, total count = %d, values = %v", count[len(count)-1], values)
464 }
465
466
467 order := make([]*Value, len(values))
468 for _, v := range values {
469 s := storeNumber[v.ID]
470 order[count[s-1]] = v
471 count[s-1]++
472 }
473
474
475
476
477 if hasNilCheck {
478 start := -1
479 for i, v := range order {
480 if v.Op == OpNilCheck {
481 if start == -1 {
482 start = i
483 }
484 } else {
485 if start != -1 {
486 sort.Sort(bySourcePos(order[start:i]))
487 start = -1
488 }
489 }
490 }
491 if start != -1 {
492 sort.Sort(bySourcePos(order[start:]))
493 }
494 }
495
496 return order
497 }
498
499 type bySourcePos []*Value
500
501 func (s bySourcePos) Len() int { return len(s) }
502 func (s bySourcePos) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
503 func (s bySourcePos) Less(i, j int) bool { return s[i].Pos.Before(s[j].Pos) }
504
View as plain text