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