Source file src/pkg/cmd/compile/internal/gc/phi.go
1
2
3
4
5 package gc
6
7 import (
8 "cmd/compile/internal/ssa"
9 "cmd/compile/internal/types"
10 "cmd/internal/src"
11 "container/heap"
12 "fmt"
13 )
14
15
16
17
18
19
20
21 const smallBlocks = 500
22
23 const debugPhi = false
24
25
26
27
28
29
30
31
32 func (s *state) insertPhis() {
33 if len(s.f.Blocks) <= smallBlocks {
34 sps := simplePhiState{s: s, f: s.f, defvars: s.defvars}
35 sps.insertPhis()
36 return
37 }
38 ps := phiState{s: s, f: s.f, defvars: s.defvars}
39 ps.insertPhis()
40 }
41
42 type phiState struct {
43 s *state
44 f *ssa.Func
45 defvars []map[*Node]*ssa.Value
46
47 varnum map[*Node]int32
48
49
50 idom []*ssa.Block
51 tree []domBlock
52 level []int32
53
54
55 priq blockHeap
56 q []*ssa.Block
57 queued *sparseSet
58 hasPhi *sparseSet
59 hasDef *sparseSet
60
61
62 placeholder *ssa.Value
63 }
64
65 func (s *phiState) insertPhis() {
66 if debugPhi {
67 fmt.Println(s.f.String())
68 }
69
70
71
72
73 s.varnum = map[*Node]int32{}
74 var vars []*Node
75 var vartypes []*types.Type
76 for _, b := range s.f.Blocks {
77 for _, v := range b.Values {
78 if v.Op != ssa.OpFwdRef {
79 continue
80 }
81 var_ := v.Aux.(*Node)
82
83
84 if len(b.Preds) == 1 {
85 c := b.Preds[0].Block()
86 if w := s.defvars[c.ID][var_]; w != nil {
87 v.Op = ssa.OpCopy
88 v.Aux = nil
89 v.AddArg(w)
90 continue
91 }
92 }
93
94 if _, ok := s.varnum[var_]; ok {
95 continue
96 }
97 s.varnum[var_] = int32(len(vartypes))
98 if debugPhi {
99 fmt.Printf("var%d = %v\n", len(vartypes), var_)
100 }
101 vars = append(vars, var_)
102 vartypes = append(vartypes, v.Type)
103 }
104 }
105
106 if len(vartypes) == 0 {
107 return
108 }
109
110
111
112 defs := make([][]*ssa.Block, len(vartypes))
113 for _, b := range s.f.Blocks {
114 for var_ := range s.defvars[b.ID] {
115 if n, ok := s.varnum[var_]; ok {
116 defs[n] = append(defs[n], b)
117 }
118 }
119 }
120
121
122 s.idom = s.f.Idom()
123 s.tree = make([]domBlock, s.f.NumBlocks())
124 for _, b := range s.f.Blocks {
125 p := s.idom[b.ID]
126 if p != nil {
127 s.tree[b.ID].sibling = s.tree[p.ID].firstChild
128 s.tree[p.ID].firstChild = b
129 }
130 }
131
132
133
134 s.level = make([]int32, s.f.NumBlocks())
135 b := s.f.Entry
136 levels:
137 for {
138 if p := s.idom[b.ID]; p != nil {
139 s.level[b.ID] = s.level[p.ID] + 1
140 if debugPhi {
141 fmt.Printf("level %s = %d\n", b, s.level[b.ID])
142 }
143 }
144 if c := s.tree[b.ID].firstChild; c != nil {
145 b = c
146 continue
147 }
148 for {
149 if c := s.tree[b.ID].sibling; c != nil {
150 b = c
151 continue levels
152 }
153 b = s.idom[b.ID]
154 if b == nil {
155 break levels
156 }
157 }
158 }
159
160
161 s.priq.level = s.level
162 s.q = make([]*ssa.Block, 0, s.f.NumBlocks())
163 s.queued = newSparseSet(s.f.NumBlocks())
164 s.hasPhi = newSparseSet(s.f.NumBlocks())
165 s.hasDef = newSparseSet(s.f.NumBlocks())
166 s.placeholder = s.s.entryNewValue0(ssa.OpUnknown, types.TypeInvalid)
167
168
169 for n := range vartypes {
170 s.insertVarPhis(n, vars[n], defs[n], vartypes[n])
171 }
172
173
174 s.resolveFwdRefs()
175
176
177 for _, b := range s.f.Blocks {
178 for _, v := range b.Values {
179 if v.Op == ssa.OpPhi {
180 v.AuxInt = 0
181 }
182 }
183 }
184 }
185
186 func (s *phiState) insertVarPhis(n int, var_ *Node, defs []*ssa.Block, typ *types.Type) {
187 priq := &s.priq
188 q := s.q
189 queued := s.queued
190 queued.clear()
191 hasPhi := s.hasPhi
192 hasPhi.clear()
193 hasDef := s.hasDef
194 hasDef.clear()
195
196
197 for _, b := range defs {
198 priq.a = append(priq.a, b)
199 hasDef.add(b.ID)
200 if debugPhi {
201 fmt.Printf("def of var%d in %s\n", n, b)
202 }
203 }
204 heap.Init(priq)
205
206
207 for len(priq.a) > 0 {
208 currentRoot := heap.Pop(priq).(*ssa.Block)
209 if debugPhi {
210 fmt.Printf("currentRoot %s\n", currentRoot)
211 }
212
213
214
215
216 if queued.contains(currentRoot.ID) {
217 s.s.Fatalf("root already in queue")
218 }
219 q = append(q, currentRoot)
220 queued.add(currentRoot.ID)
221 for len(q) > 0 {
222 b := q[len(q)-1]
223 q = q[:len(q)-1]
224 if debugPhi {
225 fmt.Printf(" processing %s\n", b)
226 }
227
228 currentRootLevel := s.level[currentRoot.ID]
229 for _, e := range b.Succs {
230 c := e.Block()
231
232 if s.level[c.ID] > currentRootLevel {
233
234 continue
235 }
236 if hasPhi.contains(c.ID) {
237 continue
238 }
239
240 hasPhi.add(c.ID)
241 v := c.NewValue0I(currentRoot.Pos, ssa.OpPhi, typ, int64(n))
242
243 s.s.addNamedValue(var_, v)
244 for range c.Preds {
245 v.AddArg(s.placeholder)
246 }
247 if debugPhi {
248 fmt.Printf("new phi for var%d in %s: %s\n", n, c, v)
249 }
250 if !hasDef.contains(c.ID) {
251
252
253 heap.Push(priq, c)
254 hasDef.add(c.ID)
255 }
256 }
257
258
259 for c := s.tree[b.ID].firstChild; c != nil; c = s.tree[c.ID].sibling {
260 if !queued.contains(c.ID) {
261 q = append(q, c)
262 queued.add(c.ID)
263 }
264 }
265 }
266 }
267 }
268
269
270 func (s *phiState) resolveFwdRefs() {
271
272
273
274
275 values := make([]*ssa.Value, len(s.varnum))
276 for i := range values {
277 values[i] = s.placeholder
278 }
279
280
281 type stackEntry struct {
282 b *ssa.Block
283
284
285 n int32
286 v *ssa.Value
287
288
289 }
290 var stk []stackEntry
291
292 stk = append(stk, stackEntry{b: s.f.Entry})
293 for len(stk) > 0 {
294 work := stk[len(stk)-1]
295 stk = stk[:len(stk)-1]
296
297 b := work.b
298 if b == nil {
299
300 values[work.n] = work.v
301 continue
302 }
303
304
305 for _, v := range b.Values {
306 if v.Op != ssa.OpPhi {
307 continue
308 }
309 n := int32(v.AuxInt)
310
311 stk = append(stk, stackEntry{n: n, v: values[n]})
312
313 values[n] = v
314 }
315
316
317 for _, v := range b.Values {
318 if v.Op != ssa.OpFwdRef {
319 continue
320 }
321 n := s.varnum[v.Aux.(*Node)]
322 v.Op = ssa.OpCopy
323 v.Aux = nil
324 v.AddArg(values[n])
325 }
326
327
328 for var_, v := range s.defvars[b.ID] {
329 n, ok := s.varnum[var_]
330 if !ok {
331
332 continue
333 }
334
335 stk = append(stk, stackEntry{n: n, v: values[n]})
336
337 values[n] = v
338 }
339
340
341 for _, e := range b.Succs {
342 c, i := e.Block(), e.Index()
343 for j := len(c.Values) - 1; j >= 0; j-- {
344 v := c.Values[j]
345 if v.Op != ssa.OpPhi {
346 break
347 }
348
349
350
351 if w := values[v.AuxInt]; w.Op != ssa.OpUnknown {
352 v.SetArg(i, w)
353 }
354 }
355 }
356
357
358 for c := s.tree[b.ID].firstChild; c != nil; c = s.tree[c.ID].sibling {
359 stk = append(stk, stackEntry{b: c})
360 }
361 }
362 }
363
364
365 type domBlock struct {
366 firstChild *ssa.Block
367 sibling *ssa.Block
368 }
369
370
371
372
373
374 type blockHeap struct {
375 a []*ssa.Block
376 level []int32
377 }
378
379 func (h *blockHeap) Len() int { return len(h.a) }
380 func (h *blockHeap) Swap(i, j int) { a := h.a; a[i], a[j] = a[j], a[i] }
381
382 func (h *blockHeap) Push(x interface{}) {
383 v := x.(*ssa.Block)
384 h.a = append(h.a, v)
385 }
386 func (h *blockHeap) Pop() interface{} {
387 old := h.a
388 n := len(old)
389 x := old[n-1]
390 h.a = old[:n-1]
391 return x
392 }
393 func (h *blockHeap) Less(i, j int) bool {
394 return h.level[h.a[i].ID] > h.level[h.a[j].ID]
395 }
396
397
398
399
400
401
402
403
404 type sparseSet struct {
405 dense []ssa.ID
406 sparse []int32
407 }
408
409
410
411 func newSparseSet(n int) *sparseSet {
412 return &sparseSet{dense: nil, sparse: make([]int32, n)}
413 }
414
415 func (s *sparseSet) contains(x ssa.ID) bool {
416 i := s.sparse[x]
417 return i < int32(len(s.dense)) && s.dense[i] == x
418 }
419
420 func (s *sparseSet) add(x ssa.ID) {
421 i := s.sparse[x]
422 if i < int32(len(s.dense)) && s.dense[i] == x {
423 return
424 }
425 s.dense = append(s.dense, x)
426 s.sparse[x] = int32(len(s.dense)) - 1
427 }
428
429 func (s *sparseSet) clear() {
430 s.dense = s.dense[:0]
431 }
432
433
434 type simplePhiState struct {
435 s *state
436 f *ssa.Func
437 fwdrefs []*ssa.Value
438 defvars []map[*Node]*ssa.Value
439 reachable []bool
440 }
441
442 func (s *simplePhiState) insertPhis() {
443 s.reachable = ssa.ReachableBlocks(s.f)
444
445
446 for _, b := range s.f.Blocks {
447 for _, v := range b.Values {
448 if v.Op != ssa.OpFwdRef {
449 continue
450 }
451 s.fwdrefs = append(s.fwdrefs, v)
452 var_ := v.Aux.(*Node)
453 if _, ok := s.defvars[b.ID][var_]; !ok {
454 s.defvars[b.ID][var_] = v
455 }
456 }
457 }
458
459 var args []*ssa.Value
460
461 loop:
462 for len(s.fwdrefs) > 0 {
463 v := s.fwdrefs[len(s.fwdrefs)-1]
464 s.fwdrefs = s.fwdrefs[:len(s.fwdrefs)-1]
465 b := v.Block
466 var_ := v.Aux.(*Node)
467 if b == s.f.Entry {
468
469 s.s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, var_, v)
470 }
471 if !s.reachable[b.ID] {
472
473
474 v.Op = ssa.OpUnknown
475 v.Aux = nil
476 continue
477 }
478
479 args = args[:0]
480 for _, e := range b.Preds {
481 args = append(args, s.lookupVarOutgoing(e.Block(), v.Type, var_, v.Pos))
482 }
483
484
485
486 var w *ssa.Value
487 for _, a := range args {
488 if a == v {
489 continue
490 }
491 if a == w {
492 continue
493 }
494 if w != nil {
495
496 v.Op = ssa.OpPhi
497 v.AddArgs(args...)
498 v.Aux = nil
499 continue loop
500 }
501 w = a
502 }
503 if w == nil {
504 s.s.Fatalf("no witness for reachable phi %s", v)
505 }
506
507 v.Op = ssa.OpCopy
508 v.Aux = nil
509 v.AddArg(w)
510 }
511 }
512
513
514 func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t *types.Type, var_ *Node, line src.XPos) *ssa.Value {
515 for {
516 if v := s.defvars[b.ID][var_]; v != nil {
517 return v
518 }
519
520
521
522 if len(b.Preds) != 1 {
523 break
524 }
525 b = b.Preds[0].Block()
526 if !s.reachable[b.ID] {
527
528
529 break
530 }
531 }
532
533 v := b.NewValue0A(line, ssa.OpFwdRef, t, var_)
534 s.defvars[b.ID][var_] = v
535 s.s.addNamedValue(var_, v)
536 s.fwdrefs = append(s.fwdrefs, v)
537 return v
538 }
539
View as plain text