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
250 mem1 := sched.NewValue1A(bb.Pos, OpStaticCall, types.TypeMem, StaticAuxCall(resched, nil), mem0)
251 sched.AddEdgeTo(h)
252 headerMemPhi.AddArg(mem1)
253
254 bb.Succs[p.i] = Edge{test, 0}
255 test.Preds = append(test.Preds, Edge{bb, p.i})
256
257
258
259
260 for _, v := range h.Values {
261 if v.Op == OpPhi && v != headerMemPhi {
262 v.AddArg(v.Args[i])
263 }
264 }
265 }
266
267 f.invalidateCFG()
268
269 if f.pass.debug > 1 {
270 sdom = newSparseTree(f, f.Idom())
271 fmt.Printf("after %s = %s\n", f.Name, sdom.treestructure(f.Entry))
272 }
273 }
274
275
276
277 func newPhiFor(b *Block, v *Value) *Value {
278 phiV := b.NewValue0(b.Pos, OpPhi, v.Type)
279
280 for range b.Preds {
281 phiV.AddArg(v)
282 }
283 return phiV
284 }
285
286
287
288
289
290
291
292
293
294 func rewriteNewPhis(h, b *Block, f *Func, defsForUses []*Value, newphis map[*Block]rewrite, dfPhiTargets map[rewriteTarget]bool, sdom SparseTree) {
295
296 if _, ok := newphis[b]; ok {
297 h = b
298 }
299 change := newphis[h]
300 x := change.before
301 y := change.after
302
303
304 if x != nil {
305 p := &change.rewrites
306 for _, v := range b.Values {
307 if v == y {
308 continue
309 }
310 for i, w := range v.Args {
311 if w != x {
312 continue
313 }
314 tgt := rewriteTarget{v, i}
315
316
317
318
319 if dfPhiTargets[tgt] {
320 continue
321 }
322 *p = append(*p, tgt)
323 if f.pass.debug > 1 {
324 fmt.Printf("added block target for h=%v, b=%v, x=%v, y=%v, tgt.v=%s, tgt.i=%d\n",
325 h, b, x, y, v, i)
326 }
327 }
328 }
329
330
331
332
333
334
335 if dfu := defsForUses[b.ID]; dfu != nil && dfu.Block != b {
336 for _, e := range b.Succs {
337 s := e.b
338
339 for _, v := range s.Values {
340 if v.Op == OpPhi && v.Args[e.i] == x {
341 tgt := rewriteTarget{v, e.i}
342 *p = append(*p, tgt)
343 dfPhiTargets[tgt] = true
344 if f.pass.debug > 1 {
345 fmt.Printf("added phi target for h=%v, b=%v, s=%v, x=%v, y=%v, tgt.v=%s, tgt.i=%d\n",
346 h, b, s, x, y, v.LongString(), e.i)
347 }
348 break
349 }
350 }
351 }
352 }
353 newphis[h] = change
354 }
355
356 for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
357 rewriteNewPhis(h, c, f, defsForUses, newphis, dfPhiTargets, sdom)
358 }
359 }
360
361
362
363
364
365
366
367
368 func addDFphis(x *Value, h, b *Block, f *Func, defForUses []*Value, newphis map[*Block]rewrite, sdom SparseTree) {
369 oldv := defForUses[b.ID]
370 if oldv != x {
371 return
372 }
373 idom := f.Idom()
374 outer:
375 for _, e := range b.Succs {
376 s := e.b
377
378 if sdom.isAncestor(h, s) {
379 continue
380 }
381 if _, ok := newphis[s]; ok {
382 continue
383 }
384 if x != nil {
385 for _, v := range s.Values {
386 if v.Op == OpPhi && v.Args[e.i] == x {
387 continue outer
388 }
389 }
390 }
391
392 old := defForUses[idom[s.ID].ID]
393 headerPhi := newPhiFor(s, old)
394
395 newphis[s] = rewrite{before: old, after: headerPhi}
396 addDFphis(old, s, s, f, defForUses, newphis, sdom)
397 }
398 for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
399 addDFphis(x, h, c, f, defForUses, newphis, sdom)
400 }
401 }
402
403
404 func findLastMems(f *Func) []*Value {
405
406 var stores []*Value
407 lastMems := make([]*Value, f.NumBlocks())
408 storeUse := f.newSparseSet(f.NumValues())
409 defer f.retSparseSet(storeUse)
410 for _, b := range f.Blocks {
411
412
413 storeUse.clear()
414 stores = stores[:0]
415 var memPhi *Value
416 for _, v := range b.Values {
417 if v.Op == OpPhi {
418 if v.Type.IsMemory() {
419 memPhi = v
420 }
421 continue
422 }
423 if v.Type.IsMemory() {
424 stores = append(stores, v)
425 for _, a := range v.Args {
426 if a.Block == b && a.Type.IsMemory() {
427 storeUse.add(a.ID)
428 }
429 }
430 }
431 }
432 if len(stores) == 0 {
433 lastMems[b.ID] = memPhi
434 continue
435 }
436
437
438 var last *Value
439 for _, v := range stores {
440 if storeUse.contains(v.ID) {
441 continue
442 }
443 if last != nil {
444 b.Fatalf("two final stores - simultaneous live stores %s %s", last, v)
445 }
446 last = v
447 }
448 if last == nil {
449 b.Fatalf("no last store found - cycle?")
450 }
451 lastMems[b.ID] = last
452 }
453 return lastMems
454 }
455
456
457 type markKind uint8
458
459 const (
460 notFound markKind = iota
461 notExplored
462 explored
463 done
464 )
465
466 type backedgesState struct {
467 b *Block
468 i int
469 }
470
471
472
473 func backedges(f *Func) []Edge {
474 edges := []Edge{}
475 mark := make([]markKind, f.NumBlocks())
476 stack := []backedgesState{}
477
478 mark[f.Entry.ID] = notExplored
479 stack = append(stack, backedgesState{f.Entry, 0})
480
481 for len(stack) > 0 {
482 l := len(stack)
483 x := stack[l-1]
484 if x.i < len(x.b.Succs) {
485 e := x.b.Succs[x.i]
486 stack[l-1].i++
487 s := e.b
488 if mark[s.ID] == notFound {
489 mark[s.ID] = notExplored
490 stack = append(stack, backedgesState{s, 0})
491 } else if mark[s.ID] == notExplored {
492 edges = append(edges, e)
493 }
494 } else {
495 mark[x.b.ID] = done
496 stack = stack[0 : l-1]
497 }
498 }
499 return edges
500 }
501
View as plain text