1
2
3
4
5 package ssacompile
6
7 import (
8 "cmd/compile/internal/ssa"
9 "cmd/compile/internal/ssa/block"
10 "cmd/compile/internal/ssa/ssaop"
11 )
12
13
14
15
16 func critical(f *ssa.Func) {
17
18 blocks := f.Cache.AllocBlockSlice(f.NumValues())
19 defer f.Cache.FreeBlockSlice(blocks)
20
21
22 for j := 0; j < len(f.Blocks); j++ {
23 b := f.Blocks[j]
24 if len(b.Preds) <= 1 {
25 continue
26 }
27
28 var phi *ssa.Value
29
30
31
32 for _, v := range b.Values {
33 if v.Op == ssaop.OpPhi {
34 if phi != nil {
35 phi = nil
36 break
37 }
38 phi = v
39 }
40 }
41
42
43 if phi != nil {
44 for _, v := range phi.Args {
45 blocks[v.ID] = nil
46 }
47 }
48
49
50 for i := 0; i < len(b.Preds); {
51 e := b.Preds[i]
52 p := e.B
53 pi := e.I
54 if p.Kind == block.BlockPlain {
55 i++
56 continue
57 }
58
59 var d *ssa.Block
60 reusedBlock := false
61 if phi != nil {
62 argID := phi.Args[i].ID
63
64
65 if d = blocks[argID]; d == nil {
66
67
68
69 d = f.NewBlock(block.BlockPlain)
70 d.Pos = p.Pos
71 blocks[argID] = d
72 if f.Pass.Debug > 0 {
73 f.Warnl(p.Pos, "split critical edge")
74 }
75 } else {
76 reusedBlock = true
77 }
78 } else {
79
80
81 d = f.NewBlock(block.BlockPlain)
82 d.Pos = p.Pos
83 if f.Pass.Debug > 0 {
84 f.Warnl(p.Pos, "split critical edge")
85 }
86 }
87
88
89
90
91
92 if reusedBlock {
93
94 p.Succs[pi] = ssa.Edge{B: d, I: len(d.Preds)}
95 d.Preds = append(d.Preds, ssa.Edge{B: p, I: pi})
96
97
98 b.RemovePred(i)
99
100
101 b.RemovePhiArg(phi, i)
102
103
104
105
106
107 } else {
108
109 p.Succs[pi] = ssa.Edge{B: d, I: 0}
110 b.Preds[i] = ssa.Edge{B: d, I: 0}
111 d.Preds = append(d.Preds, ssa.Edge{B: p, I: pi})
112 d.Succs = append(d.Succs, ssa.Edge{B: b, I: i})
113 i++
114 }
115 }
116 }
117 }
118
View as plain text