Source file src/pkg/cmd/compile/internal/ssa/cse.go
1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 "cmd/internal/src"
10 "fmt"
11 "sort"
12 )
13
14
15
16
17 func cse(f *Func) {
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 a := make([]*Value, 0, f.NumValues())
35 if f.auxmap == nil {
36 f.auxmap = auxmap{}
37 }
38 for _, b := range f.Blocks {
39 for _, v := range b.Values {
40 if v.Type.IsMemory() {
41 continue
42 }
43 if f.auxmap[v.Aux] == 0 {
44 f.auxmap[v.Aux] = int32(len(f.auxmap)) + 1
45 }
46 a = append(a, v)
47 }
48 }
49 partition := partitionValues(a, f.auxmap)
50
51
52 valueEqClass := make([]ID, f.NumValues())
53 for _, b := range f.Blocks {
54 for _, v := range b.Values {
55
56 valueEqClass[v.ID] = -v.ID
57 }
58 }
59 var pNum ID = 1
60 for _, e := range partition {
61 if f.pass.debug > 1 && len(e) > 500 {
62 fmt.Printf("CSE.large partition (%d): ", len(e))
63 for j := 0; j < 3; j++ {
64 fmt.Printf("%s ", e[j].LongString())
65 }
66 fmt.Println()
67 }
68
69 for _, v := range e {
70 valueEqClass[v.ID] = pNum
71 }
72 if f.pass.debug > 2 && len(e) > 1 {
73 fmt.Printf("CSE.partition #%d:", pNum)
74 for _, v := range e {
75 fmt.Printf(" %s", v.String())
76 }
77 fmt.Printf("\n")
78 }
79 pNum++
80 }
81
82
83
84
85 var splitPoints []int
86 byArgClass := new(partitionByArgClass)
87 for {
88 changed := false
89
90
91
92 for i := 0; i < len(partition); i++ {
93 e := partition[i]
94
95 if opcodeTable[e[0].Op].commutative {
96
97 for _, v := range e {
98 if valueEqClass[v.Args[0].ID] > valueEqClass[v.Args[1].ID] {
99 v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
100 }
101 }
102 }
103
104
105 byArgClass.a = e
106 byArgClass.eqClass = valueEqClass
107 sort.Sort(byArgClass)
108
109
110 splitPoints = append(splitPoints[:0], 0)
111 for j := 1; j < len(e); j++ {
112 v, w := e[j-1], e[j]
113
114 eqArgs := true
115 for k, a := range v.Args {
116 b := w.Args[k]
117 if valueEqClass[a.ID] != valueEqClass[b.ID] {
118 eqArgs = false
119 break
120 }
121 }
122 if !eqArgs {
123 splitPoints = append(splitPoints, j)
124 }
125 }
126 if len(splitPoints) == 1 {
127 continue
128 }
129
130
131 partition[i] = partition[len(partition)-1]
132 partition = partition[:len(partition)-1]
133 i--
134
135
136 splitPoints = append(splitPoints, len(e))
137 for j := 0; j < len(splitPoints)-1; j++ {
138 f := e[splitPoints[j]:splitPoints[j+1]]
139 if len(f) == 1 {
140
141 valueEqClass[f[0].ID] = -f[0].ID
142 continue
143 }
144 for _, v := range f {
145 valueEqClass[v.ID] = pNum
146 }
147 pNum++
148 partition = append(partition, f)
149 }
150 changed = true
151 }
152
153 if !changed {
154 break
155 }
156 }
157
158 sdom := f.sdom()
159
160
161
162 rewrite := make([]*Value, f.NumValues())
163 byDom := new(partitionByDom)
164 for _, e := range partition {
165 byDom.a = e
166 byDom.sdom = sdom
167 sort.Sort(byDom)
168 for i := 0; i < len(e)-1; i++ {
169
170 v := e[i]
171 if v == nil {
172 continue
173 }
174
175 e[i] = nil
176
177 for j := i + 1; j < len(e); j++ {
178 w := e[j]
179 if w == nil {
180 continue
181 }
182 if sdom.isAncestorEq(v.Block, w.Block) {
183 rewrite[w.ID] = v
184 e[j] = nil
185 } else {
186
187 break
188 }
189 }
190 }
191 }
192
193
194
195
196
197 copiedSelects := make(map[ID][]*Value)
198 for _, b := range f.Blocks {
199 out:
200 for _, v := range b.Values {
201
202
203
204 if int(v.ID) >= len(rewrite) || rewrite[v.ID] != nil {
205 continue
206 }
207 if v.Op != OpSelect0 && v.Op != OpSelect1 {
208 continue
209 }
210 if !v.Args[0].Type.IsTuple() {
211 f.Fatalf("arg of tuple selector %s is not a tuple: %s", v.String(), v.Args[0].LongString())
212 }
213 t := rewrite[v.Args[0].ID]
214 if t != nil && t.Block != b {
215
216 for _, c := range copiedSelects[t.ID] {
217 if v.Op == c.Op {
218
219 rewrite[v.ID] = c
220 continue out
221 }
222 }
223 c := v.copyInto(t.Block)
224 rewrite[v.ID] = c
225 copiedSelects[t.ID] = append(copiedSelects[t.ID], c)
226 }
227 }
228 }
229
230 rewrites := int64(0)
231
232
233 for _, b := range f.Blocks {
234 for _, v := range b.Values {
235 for i, w := range v.Args {
236 if x := rewrite[w.ID]; x != nil {
237 if w.Pos.IsStmt() == src.PosIsStmt {
238
239
240
241 if w.Block == v.Block && w.Pos.Line() == v.Pos.Line() {
242 v.Pos = v.Pos.WithIsStmt()
243 w.Pos = w.Pos.WithNotStmt()
244 }
245 }
246 v.SetArg(i, x)
247 rewrites++
248 }
249 }
250 }
251 if v := b.Control; v != nil {
252 if x := rewrite[v.ID]; x != nil {
253 if v.Op == OpNilCheck {
254
255
256 continue
257 }
258 b.SetControl(x)
259 }
260 }
261 }
262 if f.pass.stats > 0 {
263 f.LogStat("CSE REWRITES", rewrites)
264 }
265 }
266
267
268
269
270 type eqclass []*Value
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 func partitionValues(a []*Value, auxIDs auxmap) []eqclass {
287 sort.Sort(sortvalues{a, auxIDs})
288
289 var partition []eqclass
290 for len(a) > 0 {
291 v := a[0]
292 j := 1
293 for ; j < len(a); j++ {
294 w := a[j]
295 if cmpVal(v, w, auxIDs) != types.CMPeq {
296 break
297 }
298 }
299 if j > 1 {
300 partition = append(partition, a[:j])
301 }
302 a = a[j:]
303 }
304
305 return partition
306 }
307 func lt2Cmp(isLt bool) types.Cmp {
308 if isLt {
309 return types.CMPlt
310 }
311 return types.CMPgt
312 }
313
314 type auxmap map[interface{}]int32
315
316 func cmpVal(v, w *Value, auxIDs auxmap) types.Cmp {
317
318 if v.Op != w.Op {
319 return lt2Cmp(v.Op < w.Op)
320 }
321 if v.AuxInt != w.AuxInt {
322 return lt2Cmp(v.AuxInt < w.AuxInt)
323 }
324 if len(v.Args) != len(w.Args) {
325 return lt2Cmp(len(v.Args) < len(w.Args))
326 }
327 if v.Op == OpPhi && v.Block != w.Block {
328 return lt2Cmp(v.Block.ID < w.Block.ID)
329 }
330 if v.Type.IsMemory() {
331
332
333 return lt2Cmp(v.ID < w.ID)
334 }
335
336
337
338 if v.Op != OpSelect0 && v.Op != OpSelect1 {
339 if tc := v.Type.Compare(w.Type); tc != types.CMPeq {
340 return tc
341 }
342 }
343
344 if v.Aux != w.Aux {
345 if v.Aux == nil {
346 return types.CMPlt
347 }
348 if w.Aux == nil {
349 return types.CMPgt
350 }
351 return lt2Cmp(auxIDs[v.Aux] < auxIDs[w.Aux])
352 }
353
354 return types.CMPeq
355 }
356
357
358 type sortvalues struct {
359 a []*Value
360 auxIDs auxmap
361 }
362
363 func (sv sortvalues) Len() int { return len(sv.a) }
364 func (sv sortvalues) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
365 func (sv sortvalues) Less(i, j int) bool {
366 v := sv.a[i]
367 w := sv.a[j]
368 if cmp := cmpVal(v, w, sv.auxIDs); cmp != types.CMPeq {
369 return cmp == types.CMPlt
370 }
371
372
373 return v.ID < w.ID
374 }
375
376 type partitionByDom struct {
377 a []*Value
378 sdom SparseTree
379 }
380
381 func (sv partitionByDom) Len() int { return len(sv.a) }
382 func (sv partitionByDom) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
383 func (sv partitionByDom) Less(i, j int) bool {
384 v := sv.a[i]
385 w := sv.a[j]
386 return sv.sdom.domorder(v.Block) < sv.sdom.domorder(w.Block)
387 }
388
389 type partitionByArgClass struct {
390 a []*Value
391 eqClass []ID
392 }
393
394 func (sv partitionByArgClass) Len() int { return len(sv.a) }
395 func (sv partitionByArgClass) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
396 func (sv partitionByArgClass) Less(i, j int) bool {
397 v := sv.a[i]
398 w := sv.a[j]
399 for i, a := range v.Args {
400 b := w.Args[i]
401 if sv.eqClass[a.ID] < sv.eqClass[b.ID] {
402 return true
403 }
404 if sv.eqClass[a.ID] > sv.eqClass[b.ID] {
405 return false
406 }
407 }
408 return false
409 }
410
View as plain text