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 := f.Cache.allocValueSlice(f.NumBlocks())
98 defer f.Cache.freeValueSlice(memDefsAtBlockEnds)
99
100
101 for i := len(po) - 1; i >= 0; i-- {
102 b := po[i]
103 mem := lastMems[b.ID]
104 for j := 0; mem == nil; j++ {
105
106 mem = memDefsAtBlockEnds[b.Preds[j].b.ID]
107 }
108 memDefsAtBlockEnds[b.ID] = mem
109 if f.pass.debug > 2 {
110 fmt.Printf("memDefsAtBlockEnds[%s] = %s\n", b, mem)
111 }
112 }
113
114
115 newmemphis := make(map[*Block]rewrite)
116
117
118 for i, emc := range tofixBackedges {
119 e := emc.e
120 h := e.b
121
122
123 var headerMemPhi *Value
124
125 for _, v := range h.Values {
126 if v.Op == OpPhi && v.Type.IsMemory() {
127 headerMemPhi = v
128 }
129 }
130
131 if headerMemPhi == nil {
132
133 mem0 := memDefsAtBlockEnds[idom[h.ID].ID]
134 headerMemPhi = newPhiFor(h, mem0)
135 newmemphis[h] = rewrite{before: mem0, after: headerMemPhi}
136 addDFphis(mem0, h, h, f, memDefsAtBlockEnds, newmemphis, sdom)
137
138 }
139 tofixBackedges[i].m = headerMemPhi
140
141 }
142 if f.pass.debug > 0 {
143 for b, r := range newmemphis {
144 fmt.Printf("before b=%s, rewrite=%s\n", b, r.String())
145 }
146 }
147
148
149
150 dfPhiTargets := make(map[rewriteTarget]bool)
151
152 rewriteNewPhis(f.Entry, f.Entry, f, memDefsAtBlockEnds, newmemphis, dfPhiTargets, sdom)
153
154 if f.pass.debug > 0 {
155 for b, r := range newmemphis {
156 fmt.Printf("after b=%s, rewrite=%s\n", b, r.String())
157 }
158 }
159
160
161 for _, r := range newmemphis {
162 for _, rw := range r.rewrites {
163 rw.v.SetArg(rw.i, r.after)
164 }
165 }
166
167
168 for _, emc := range tofixBackedges {
169 e := emc.e
170 headerMemPhi := emc.m
171 h := e.b
172 i := e.i
173 p := h.Preds[i]
174 bb := p.b
175 mem0 := headerMemPhi.Args[i]
176
177
178
179 likely := BranchLikely
180 if p.i != 0 {
181 likely = BranchUnlikely
182 }
183 if bb.Kind != BlockPlain {
184 bb.Likely = likely
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
212 test := f.NewBlock(BlockIf)
213 sched := f.NewBlock(BlockPlain)
214
215 test.Pos = bb.Pos
216 sched.Pos = bb.Pos
217
218
219
220
221 cfgtypes := &f.Config.Types
222 pt := cfgtypes.Uintptr
223 g := test.NewValue1(bb.Pos, OpGetG, pt, mem0)
224 sp := test.NewValue0(bb.Pos, OpSP, pt)
225 cmpOp := OpLess64U
226 if pt.Size() == 4 {
227 cmpOp = OpLess32U
228 }
229 limaddr := test.NewValue1I(bb.Pos, OpOffPtr, pt, 2*pt.Size(), g)
230 lim := test.NewValue2(bb.Pos, OpLoad, pt, limaddr, mem0)
231 cmp := test.NewValue2(bb.Pos, cmpOp, cfgtypes.Bool, sp, lim)
232 test.SetControl(cmp)
233
234
235 test.AddEdgeTo(sched)
236
237
238
239
240 test.Succs = append(test.Succs, Edge{h, i})
241 h.Preds[i] = Edge{test, 1}
242 headerMemPhi.SetArg(i, mem0)
243
244 test.Likely = BranchUnlikely
245
246
247
248
249 resched := f.fe.Syslook("goschedguarded")
250 call := sched.NewValue1A(bb.Pos, OpStaticCall, types.TypeResultMem, StaticAuxCall(resched, bb.Func.ABIDefault.ABIAnalyzeTypes(nil, nil)), mem0)
251 mem1 := sched.NewValue1I(bb.Pos, OpSelectN, types.TypeMem, 0, call)
252 sched.AddEdgeTo(h)
253 headerMemPhi.AddArg(mem1)
254
255 bb.Succs[p.i] = Edge{test, 0}
256 test.Preds = append(test.Preds, Edge{bb, p.i})
257
258
259
260
261 for _, v := range h.Values {
262 if v.Op == OpPhi && v != headerMemPhi {
263 v.AddArg(v.Args[i])
264 }
265 }
266 }
267
268 f.invalidateCFG()
269
270 if f.pass.debug > 1 {
271 sdom = newSparseTree(f, f.Idom())
272 fmt.Printf("after %s = %s\n", f.Name, sdom.treestructure(f.Entry))
273 }
274 }
275
276
277
278 func newPhiFor(b *Block, v *Value) *Value {
279 phiV := b.NewValue0(b.Pos, OpPhi, v.Type)
280
281 for range b.Preds {
282 phiV.AddArg(v)
283 }
284 return phiV
285 }
286
287
288
289
290
291
292
293
294
295 func rewriteNewPhis(h, b *Block, f *Func, defsForUses []*Value, newphis map[*Block]rewrite, dfPhiTargets map[rewriteTarget]bool, sdom SparseTree) {
296
297 if _, ok := newphis[b]; ok {
298 h = b
299 }
300 change := newphis[h]
301 x := change.before
302 y := change.after
303
304
305 if x != nil {
306 p := &change.rewrites
307 for _, v := range b.Values {
308 if v == y {
309 continue
310 }
311 for i, w := range v.Args {
312 if w != x {
313 continue
314 }
315 tgt := rewriteTarget{v, i}
316
317
318
319
320 if dfPhiTargets[tgt] {
321 continue
322 }
323 *p = append(*p, tgt)
324 if f.pass.debug > 1 {
325 fmt.Printf("added block target for h=%v, b=%v, x=%v, y=%v, tgt.v=%s, tgt.i=%d\n",
326 h, b, x, y, v, i)
327 }
328 }
329 }
330
331
332
333
334
335
336 if dfu := defsForUses[b.ID]; dfu != nil && dfu.Block != b {
337 for _, e := range b.Succs {
338 s := e.b
339
340 for _, v := range s.Values {
341 if v.Op == OpPhi && v.Args[e.i] == x {
342 tgt := rewriteTarget{v, e.i}
343 *p = append(*p, tgt)
344 dfPhiTargets[tgt] = true
345 if f.pass.debug > 1 {
346 fmt.Printf("added phi target for h=%v, b=%v, s=%v, x=%v, y=%v, tgt.v=%s, tgt.i=%d\n",
347 h, b, s, x, y, v.LongString(), e.i)
348 }
349 break
350 }
351 }
352 }
353 }
354 newphis[h] = change
355 }
356
357 for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
358 rewriteNewPhis(h, c, f, defsForUses, newphis, dfPhiTargets, sdom)
359 }
360 }
361
362
363
364
365
366
367
368
369 func addDFphis(x *Value, h, b *Block, f *Func, defForUses []*Value, newphis map[*Block]rewrite, sdom SparseTree) {
370 oldv := defForUses[b.ID]
371 if oldv != x {
372 return
373 }
374 idom := f.Idom()
375 outer:
376 for _, e := range b.Succs {
377 s := e.b
378
379 if sdom.isAncestor(h, s) {
380 continue
381 }
382 if _, ok := newphis[s]; ok {
383 continue
384 }
385 if x != nil {
386 for _, v := range s.Values {
387 if v.Op == OpPhi && v.Args[e.i] == x {
388 continue outer
389 }
390 }
391 }
392
393 old := defForUses[idom[s.ID].ID]
394 headerPhi := newPhiFor(s, old)
395
396 newphis[s] = rewrite{before: old, after: headerPhi}
397 addDFphis(old, s, s, f, defForUses, newphis, sdom)
398 }
399 for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
400 addDFphis(x, h, c, f, defForUses, newphis, sdom)
401 }
402 }
403
404
405 func findLastMems(f *Func) []*Value {
406
407 var stores []*Value
408 lastMems := f.Cache.allocValueSlice(f.NumBlocks())
409 defer f.Cache.freeValueSlice(lastMems)
410 storeUse := f.newSparseSet(f.NumValues())
411 defer f.retSparseSet(storeUse)
412 for _, b := range f.Blocks {
413
414
415 storeUse.clear()
416 stores = stores[:0]
417 var memPhi *Value
418 for _, v := range b.Values {
419 if v.Op == OpPhi {
420 if v.Type.IsMemory() {
421 memPhi = v
422 }
423 continue
424 }
425 if v.Type.IsMemory() {
426 stores = append(stores, v)
427 for _, a := range v.Args {
428 if a.Block == b && a.Type.IsMemory() {
429 storeUse.add(a.ID)
430 }
431 }
432 }
433 }
434 if len(stores) == 0 {
435 lastMems[b.ID] = memPhi
436 continue
437 }
438
439
440 var last *Value
441 for _, v := range stores {
442 if storeUse.contains(v.ID) {
443 continue
444 }
445 if last != nil {
446 b.Fatalf("two final stores - simultaneous live stores %s %s", last, v)
447 }
448 last = v
449 }
450 if last == nil {
451 b.Fatalf("no last store found - cycle?")
452 }
453
454
455
456
457 if last.Type.IsTuple() {
458 last = b.NewValue1(last.Pos, OpSelect1, types.TypeMem, last)
459 } else if last.Type.IsResults() {
460 last = b.NewValue1I(last.Pos, OpSelectN, types.TypeMem, int64(last.Type.NumFields()-1), last)
461 }
462
463 lastMems[b.ID] = last
464 }
465 return lastMems
466 }
467
468
469 type markKind uint8
470
471 const (
472 notFound markKind = iota
473 notExplored
474 explored
475 done
476 )
477
478 type backedgesState struct {
479 b *Block
480 i int
481 }
482
483
484
485 func backedges(f *Func) []Edge {
486 edges := []Edge{}
487 mark := make([]markKind, f.NumBlocks())
488 stack := []backedgesState{}
489
490 mark[f.Entry.ID] = notExplored
491 stack = append(stack, backedgesState{f.Entry, 0})
492
493 for len(stack) > 0 {
494 l := len(stack)
495 x := stack[l-1]
496 if x.i < len(x.b.Succs) {
497 e := x.b.Succs[x.i]
498 stack[l-1].i++
499 s := e.b
500 if mark[s.ID] == notFound {
501 mark[s.ID] = notExplored
502 stack = append(stack, backedgesState{s, 0})
503 } else if mark[s.ID] == notExplored {
504 edges = append(edges, e)
505 }
506 } else {
507 mark[x.b.ID] = done
508 stack = stack[0 : l-1]
509 }
510 }
511 return edges
512 }
513
View as plain text