Source file src/pkg/cmd/compile/internal/ssa/loopreschedchecks.go
1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 "fmt"
10 )
11
12
13
14
15 type edgeMem struct {
16 e Edge
17 m *Value
18 }
19
20
21
22
23
24 type rewriteTarget struct {
25 v *Value
26 i int
27 }
28
29 type rewrite struct {
30 before, after *Value
31 rewrites []rewriteTarget
32 }
33
34 func (r *rewrite) String() string {
35 s := "\n\tbefore=" + r.before.String() + ", after=" + r.after.String()
36 for _, rw := range r.rewrites {
37 s += ", (i=" + fmt.Sprint(rw.i) + ", v=" + rw.v.LongString() + ")"
38 }
39 s += "\n"
40 return s
41 }
42
43
44 func insertLoopReschedChecks(f *Func) {
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 if f.NoSplit {
65 return
66 }
67
68 backedges := backedges(f)
69 if len(backedges) == 0 {
70 return
71 }
72
73 lastMems := findLastMems(f)
74
75 idom := f.Idom()
76 po := f.postorder()
77
78
79
80 sdom := newSparseOrderedTree(f, idom, po)
81
82 if f.pass.debug > 1 {
83 fmt.Printf("before %s = %s\n", f.Name, sdom.treestructure(f.Entry))
84 }
85
86 tofixBackedges := []edgeMem{}
87
88 for _, e := range backedges {
89 tofixBackedges = append(tofixBackedges, edgeMem{e, nil})
90 }
91
92
93 if lastMems[f.Entry.ID] == nil {
94 lastMems[f.Entry.ID] = f.Entry.NewValue0(f.Entry.Pos, OpInitMem, types.TypeMem)
95 }
96
97 memDefsAtBlockEnds := make([]*Value, f.NumBlocks())
98
99
100 for i := len(po) - 1; i >= 0; i-- {
101 b := po[i]
102 mem := lastMems[b.ID]
103 for j := 0; mem == nil; j++ {
104
105 mem = memDefsAtBlockEnds[b.Preds[j].b.ID]
106 }
107 memDefsAtBlockEnds[b.ID] = mem
108 if f.pass.debug > 2 {
109 fmt.Printf("memDefsAtBlockEnds[%s] = %s\n", b, mem)
110 }
111 }
112
113
114 newmemphis := make(map[*Block]rewrite)
115
116
117 for i, emc := range tofixBackedges {
118 e := emc.e
119 h := e.b
120
121
122 var headerMemPhi *Value
123
124 for _, v := range h.Values {
125 if v.Op == OpPhi && v.Type.IsMemory() {
126 headerMemPhi = v
127 }
128 }
129
130 if headerMemPhi == nil {
131
132 mem0 := memDefsAtBlockEnds[idom[h.ID].ID]
133 headerMemPhi = newPhiFor(h, mem0)
134 newmemphis[h] = rewrite{before: mem0, after: headerMemPhi}
135 addDFphis(mem0, h, h, f, memDefsAtBlockEnds, newmemphis, sdom)
136
137 }
138 tofixBackedges[i].m = headerMemPhi
139
140 }
141 if f.pass.debug > 0 {
142 for b, r := range newmemphis {
143 fmt.Printf("before b=%s, rewrite=%s\n", b, r.String())
144 }
145 }
146
147
148
149 dfPhiTargets := make(map[rewriteTarget]bool)
150
151 rewriteNewPhis(f.Entry, f.Entry, f, memDefsAtBlockEnds, newmemphis, dfPhiTargets, sdom)
152
153 if f.pass.debug > 0 {
154 for b, r := range newmemphis {
155 fmt.Printf("after b=%s, rewrite=%s\n", b, r.String())
156 }
157 }
158
159
160 for _, r := range newmemphis {
161 for _, rw := range r.rewrites {
162 rw.v.SetArg(rw.i, r.after)
163 }
164 }
165
166
167 for _, emc := range tofixBackedges {
168 e := emc.e
169 headerMemPhi := emc.m
170 h := e.b
171 i := e.i
172 p := h.Preds[i]
173 bb := p.b
174 mem0 := headerMemPhi.Args[i]
175
176
177
178 likely := BranchLikely
179 if p.i != 0 {
180 likely = BranchUnlikely
181 }
182 if bb.Kind != BlockPlain {
183 bb.Likely = likely
184 }
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211 test := f.NewBlock(BlockIf)
212 sched := f.NewBlock(BlockPlain)
213
214 test.Pos = bb.Pos
215 sched.Pos = bb.Pos
216
217
218
219
220 cfgtypes := &f.Config.Types
221 pt := cfgtypes.Uintptr
222 g := test.NewValue1(bb.Pos, OpGetG, pt, mem0)
223 sp := test.NewValue0(bb.Pos, OpSP, pt)
224 cmpOp := OpLess64U
225 if pt.Size() == 4 {
226 cmpOp = OpLess32U
227 }
228 limaddr := test.NewValue1I(bb.Pos, OpOffPtr, pt, 2*pt.Size(), g)
229 lim := test.NewValue2(bb.Pos, OpLoad, pt, limaddr, mem0)
230 cmp := test.NewValue2(bb.Pos, cmpOp, cfgtypes.Bool, sp, lim)
231 test.SetControl(cmp)
232
233
234 test.AddEdgeTo(sched)
235
236
237
238
239 test.Succs = append(test.Succs, Edge{h, i})
240 h.Preds[i] = Edge{test, 1}
241 headerMemPhi.SetArg(i, mem0)
242
243 test.Likely = BranchUnlikely
244
245
246
247
248 resched := f.fe.Syslook("goschedguarded")
249 mem1 := sched.NewValue1A(bb.Pos, OpStaticCall, types.TypeMem, resched, mem0)
250 sched.AddEdgeTo(h)
251 headerMemPhi.AddArg(mem1)
252
253 bb.Succs[p.i] = Edge{test, 0}
254 test.Preds = append(test.Preds, Edge{bb, p.i})
255
256
257
258
259 for _, v := range h.Values {
260 if v.Op == OpPhi && v != headerMemPhi {
261 v.AddArg(v.Args[i])
262 }
263 }
264 }
265
266 f.invalidateCFG()
267
268 if f.pass.debug > 1 {
269 sdom = newSparseTree(f, f.Idom())
270 fmt.Printf("after %s = %s\n", f.Name, sdom.treestructure(f.Entry))
271 }
272 }
273
274
275
276 func newPhiFor(b *Block, v *Value) *Value {
277 phiV := b.NewValue0(b.Pos, OpPhi, v.Type)
278
279 for range b.Preds {
280 phiV.AddArg(v)
281 }
282 return phiV
283 }
284
285
286
287
288
289
290
291
292
293 func rewriteNewPhis(h, b *Block, f *Func, defsForUses []*Value, newphis map[*Block]rewrite, dfPhiTargets map[rewriteTarget]bool, sdom SparseTree) {
294
295 if _, ok := newphis[b]; ok {
296 h = b
297 }
298 change := newphis[h]
299 x := change.before
300 y := change.after
301
302
303 if x != nil {
304 p := &change.rewrites
305 for _, v := range b.Values {
306 if v == y {
307 continue
308 }
309 for i, w := range v.Args {
310 if w != x {
311 continue
312 }
313 tgt := rewriteTarget{v, i}
314
315
316
317
318 if dfPhiTargets[tgt] {
319 continue
320 }
321 *p = append(*p, tgt)
322 if f.pass.debug > 1 {
323 fmt.Printf("added block target for h=%v, b=%v, x=%v, y=%v, tgt.v=%s, tgt.i=%d\n",
324 h, b, x, y, v, i)
325 }
326 }
327 }
328
329
330
331
332
333
334 if dfu := defsForUses[b.ID]; dfu != nil && dfu.Block != b {
335 for _, e := range b.Succs {
336 s := e.b
337
338 for _, v := range s.Values {
339 if v.Op == OpPhi && v.Args[e.i] == x {
340 tgt := rewriteTarget{v, e.i}
341 *p = append(*p, tgt)
342 dfPhiTargets[tgt] = true
343 if f.pass.debug > 1 {
344 fmt.Printf("added phi target for h=%v, b=%v, s=%v, x=%v, y=%v, tgt.v=%s, tgt.i=%d\n",
345 h, b, s, x, y, v.LongString(), e.i)
346 }
347 break
348 }
349 }
350 }
351 }
352 newphis[h] = change
353 }
354
355 for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
356 rewriteNewPhis(h, c, f, defsForUses, newphis, dfPhiTargets, sdom)
357 }
358 }
359
360
361
362
363
364
365
366
367 func addDFphis(x *Value, h, b *Block, f *Func, defForUses []*Value, newphis map[*Block]rewrite, sdom SparseTree) {
368 oldv := defForUses[b.ID]
369 if oldv != x {
370 return
371 }
372 idom := f.Idom()
373 outer:
374 for _, e := range b.Succs {
375 s := e.b
376
377 if sdom.isAncestor(h, s) {
378 continue
379 }
380 if _, ok := newphis[s]; ok {
381 continue
382 }
383 if x != nil {
384 for _, v := range s.Values {
385 if v.Op == OpPhi && v.Args[e.i] == x {
386 continue outer
387 }
388 }
389 }
390
391 old := defForUses[idom[s.ID].ID]
392 headerPhi := newPhiFor(s, old)
393
394 newphis[s] = rewrite{before: old, after: headerPhi}
395 addDFphis(old, s, s, f, defForUses, newphis, sdom)
396 }
397 for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
398 addDFphis(x, h, c, f, defForUses, newphis, sdom)
399 }
400 }
401
402
403 func findLastMems(f *Func) []*Value {
404
405 var stores []*Value
406 lastMems := make([]*Value, f.NumBlocks())
407 storeUse := f.newSparseSet(f.NumValues())
408 defer f.retSparseSet(storeUse)
409 for _, b := range f.Blocks {
410
411
412 storeUse.clear()
413 stores = stores[:0]
414 var memPhi *Value
415 for _, v := range b.Values {
416 if v.Op == OpPhi {
417 if v.Type.IsMemory() {
418 memPhi = v
419 }
420 continue
421 }
422 if v.Type.IsMemory() {
423 stores = append(stores, v)
424 for _, a := range v.Args {
425 if a.Block == b && a.Type.IsMemory() {
426 storeUse.add(a.ID)
427 }
428 }
429 }
430 }
431 if len(stores) == 0 {
432 lastMems[b.ID] = memPhi
433 continue
434 }
435
436
437 var last *Value
438 for _, v := range stores {
439 if storeUse.contains(v.ID) {
440 continue
441 }
442 if last != nil {
443 b.Fatalf("two final stores - simultaneous live stores %s %s", last, v)
444 }
445 last = v
446 }
447 if last == nil {
448 b.Fatalf("no last store found - cycle?")
449 }
450 lastMems[b.ID] = last
451 }
452 return lastMems
453 }
454
455 type backedgesState struct {
456 b *Block
457 i int
458 }
459
460
461
462 func backedges(f *Func) []Edge {
463 edges := []Edge{}
464 mark := make([]markKind, f.NumBlocks())
465 stack := []backedgesState{}
466
467 mark[f.Entry.ID] = notExplored
468 stack = append(stack, backedgesState{f.Entry, 0})
469
470 for len(stack) > 0 {
471 l := len(stack)
472 x := stack[l-1]
473 if x.i < len(x.b.Succs) {
474 e := x.b.Succs[x.i]
475 stack[l-1].i++
476 s := e.b
477 if mark[s.ID] == notFound {
478 mark[s.ID] = notExplored
479 stack = append(stack, backedgesState{s, 0})
480 } else if mark[s.ID] == notExplored {
481 edges = append(edges, e)
482 }
483 } else {
484 mark[x.b.ID] = done
485 stack = stack[0 : l-1]
486 }
487 }
488 return edges
489 }
490
View as plain text