...
Source file src/pkg/cmd/compile/internal/ssa/fuse.go
1
2
3
4
5 package ssa
6
7 import (
8 "cmd/internal/src"
9 )
10
11
12 func fusePlain(f *Func) { fuse(f, fuseTypePlain) }
13
14
15 func fuseAll(f *Func) { fuse(f, fuseTypeAll) }
16
17 type fuseType uint8
18
19 const (
20 fuseTypePlain fuseType = 1 << iota
21 fuseTypeIf
22 fuseTypeAll = fuseTypePlain | fuseTypeIf
23 )
24
25
26 func fuse(f *Func, typ fuseType) {
27 for changed := true; changed; {
28 changed = false
29
30 for i := len(f.Blocks) - 1; i >= 0; i-- {
31 b := f.Blocks[i]
32 if typ&fuseTypeIf != 0 {
33 changed = fuseBlockIf(b) || changed
34 }
35 if typ&fuseTypePlain != 0 {
36 changed = fuseBlockPlain(b) || changed
37 }
38 }
39 if changed {
40 f.invalidateCFG()
41 }
42 }
43 }
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 func fuseBlockIf(b *Block) bool {
62 if b.Kind != BlockIf {
63 return false
64 }
65
66 var ss0, ss1 *Block
67 s0 := b.Succs[0].b
68 i0 := b.Succs[0].i
69 if s0.Kind != BlockPlain || len(s0.Preds) != 1 || !isEmpty(s0) {
70 s0, ss0 = b, s0
71 } else {
72 ss0 = s0.Succs[0].b
73 i0 = s0.Succs[0].i
74 }
75 s1 := b.Succs[1].b
76 i1 := b.Succs[1].i
77 if s1.Kind != BlockPlain || len(s1.Preds) != 1 || !isEmpty(s1) {
78 s1, ss1 = b, s1
79 } else {
80 ss1 = s1.Succs[0].b
81 i1 = s1.Succs[0].i
82 }
83
84 if ss0 != ss1 {
85 return false
86 }
87 ss := ss0
88
89
90
91
92 for _, v := range ss.Values {
93 if v.Op == OpPhi && v.Uses > 0 && v.Args[i0] != v.Args[i1] {
94 return false
95 }
96 }
97
98
99
100
101
102
103 if s0 != b && s1 != b {
104
105
106 b.Succs[0] = Edge{ss, i0}
107 ss.Preds[i0] = Edge{b, 0}
108 b.removeEdge(1)
109 s1.removeEdge(0)
110 } else if s0 != b {
111 b.removeEdge(0)
112 s0.removeEdge(0)
113 } else if s1 != b {
114 b.removeEdge(1)
115 s1.removeEdge(0)
116 } else {
117 b.removeEdge(1)
118 }
119 b.Kind = BlockPlain
120 b.Likely = BranchUnknown
121 b.SetControl(nil)
122
123
124 blocks := [...]*Block{s0, s1}
125 for _, s := range &blocks {
126 if s == b {
127 continue
128 }
129
130
131 for _, v := range s.Values {
132 v.Block = b
133 }
134 b.Values = append(b.Values, s.Values...)
135
136 s.Kind = BlockInvalid
137 s.Values = nil
138 s.Succs = nil
139 s.Preds = nil
140 }
141 return true
142 }
143
144
145
146 func isEmpty(b *Block) bool {
147 for _, v := range b.Values {
148 if v.Uses > 0 || v.Type.IsVoid() {
149 return false
150 }
151 }
152 return true
153 }
154
155 func fuseBlockPlain(b *Block) bool {
156 if b.Kind != BlockPlain {
157 return false
158 }
159
160 c := b.Succs[0].b
161 if len(c.Preds) != 1 {
162 return false
163 }
164
165
166
167 if b.Pos.IsStmt() == src.PosIsStmt {
168 l := b.Pos.Line()
169 for _, v := range c.Values {
170 if v.Pos.IsStmt() == src.PosNotStmt {
171 continue
172 }
173 if l == v.Pos.Line() {
174 v.Pos = v.Pos.WithIsStmt()
175 l = 0
176 break
177 }
178 }
179 if l != 0 && c.Pos.Line() == l {
180 c.Pos = c.Pos.WithIsStmt()
181 }
182 }
183
184
185 for _, v := range b.Values {
186 v.Block = c
187 }
188
189
190
191
192
193
194
195
196 if cap(c.Values) >= cap(b.Values) || len(b.Values) <= len(b.valstorage) {
197 bl := len(b.Values)
198 cl := len(c.Values)
199 var t []*Value
200 if cap(c.Values) < bl+cl {
201
202 t = make([]*Value, bl+cl)
203 } else {
204
205 t = c.Values[0 : bl+cl]
206 }
207 copy(t[bl:], c.Values)
208 c.Values = t
209 copy(c.Values, b.Values)
210 } else {
211 c.Values = append(b.Values, c.Values...)
212 }
213
214
215 c.predstorage[0] = Edge{}
216 if len(b.Preds) > len(b.predstorage) {
217 c.Preds = b.Preds
218 } else {
219 c.Preds = append(c.predstorage[:0], b.Preds...)
220 }
221 for i, e := range c.Preds {
222 p := e.b
223 p.Succs[e.i] = Edge{c, i}
224 }
225 f := b.Func
226 if f.Entry == b {
227 f.Entry = c
228 }
229
230
231 b.Kind = BlockInvalid
232 b.Values = nil
233 b.Preds = nil
234 b.Succs = nil
235 return true
236 }
237
View as plain text