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 defer f.Cache.freeValueSlice(lastMems)
75
76 idom := f.Idom()
77 po := f.postorder()
78
79
80
81 sdom := newSparseOrderedTree(f, idom, po)
82
83 if f.pass.debug > 1 {
84 fmt.Printf("before %s = %s\n", f.Name, sdom.treestructure(f.Entry))
85 }
86
87 tofixBackedges := []edgeMem{}
88
89 for _, e := range backedges {
90 tofixBackedges = append(tofixBackedges, edgeMem{e, nil})
91 }
92
93
94 if lastMems[f.Entry.ID] == nil {
95 lastMems[f.Entry.ID] = f.Entry.NewValue0(f.Entry.Pos, OpInitMem, types.TypeMem)
96 }
97
98 memDefsAtBlockEnds := f.Cache.allocValueSlice(f.NumBlocks())
99 defer f.Cache.freeValueSlice(memDefsAtBlockEnds)
100
101
102 for i := len(po) - 1; i >= 0; i-- {
103 b := po[i]
104 mem := lastMems[b.ID]
105 for j := 0; mem == nil; j++ {
106
107 mem = memDefsAtBlockEnds[b.Preds[j].b.ID]
108 }
109 memDefsAtBlockEnds[b.ID] = mem
110 if f.pass.debug > 2 {
111 fmt.Printf("memDefsAtBlockEnds[%s] = %s\n", b, mem)
112 }
113 }
114
115
116 newmemphis := make(map[*Block]rewrite)
117
118
119 for i, emc := range tofixBackedges {
120 e := emc.e
121 h := e.b
122
123
124 var headerMemPhi *Value
125
126 for _, v := range h.Values {
127 if v.Op == OpPhi && v.Type.IsMemory() {
128 headerMemPhi = v
129 }
130 }
131
132 if headerMemPhi == nil {
133
134 mem0 := memDefsAtBlockEnds[idom[h.ID].ID]
135 headerMemPhi = newPhiFor(h, mem0)
136 newmemphis[h] = rewrite{before: mem0, after: headerMemPhi}
137 addDFphis(mem0, h, h, f, memDefsAtBlockEnds, newmemphis, sdom)
138
139 }
140 tofixBackedges[i].m = headerMemPhi
141
142 }
143 if f.pass.debug > 0 {
144 for b, r := range newmemphis {
145 fmt.Printf("before b=%s, rewrite=%s\n", b, r.String())
146 }
147 }
148
149
150
151 dfPhiTargets := make(map[rewriteTarget]bool)
152
153 rewriteNewPhis(f.Entry, f.Entry, f, memDefsAtBlockEnds, newmemphis, dfPhiTargets, sdom)
154
155 if f.pass.debug > 0 {
156 for b, r := range newmemphis {
157 fmt.Printf("after b=%s, rewrite=%s\n", b, r.String())
158 }
159 }
160
161
162 for _, r := range newmemphis {
163 for _, rw := range r.rewrites {
164 rw.v.SetArg(rw.i, r.after)
165 }
166 }
167
168
169 for _, emc := range tofixBackedges {
170 e := emc.e
171 headerMemPhi := emc.m
172 h := e.b
173 i := e.i
174 p := h.Preds[i]
175 bb := p.b
176 mem0 := headerMemPhi.Args[i]
177
178
179
180 likely := BranchLikely
181 if p.i != 0 {
182 likely = BranchUnlikely
183 }
184 if bb.Kind != BlockPlain {
185 bb.Likely = likely
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
213 test := f.NewBlock(BlockIf)
214 sched := f.NewBlock(BlockPlain)
215
216 test.Pos = bb.Pos
217 sched.Pos = bb.Pos
218
219
220
221
222 cfgtypes := &f.Config.Types
223 pt := cfgtypes.Uintptr
224 g := test.NewValue1(bb.Pos, OpGetG, pt, mem0)
225 sp := test.NewValue0(bb.Pos, OpSP, pt)
226 cmpOp := OpLess64U
227 if pt.Size() == 4 {
228 cmpOp = OpLess32U
229 }
230 limaddr := test.NewValue1I(bb.Pos, OpOffPtr, pt, 2*pt.Size(), g)
231 lim := test.NewValue2(bb.Pos, OpLoad, pt, limaddr, mem0)
232 cmp := test.NewValue2(bb.Pos, cmpOp, cfgtypes.Bool, sp, lim)
233 test.SetControl(cmp)
234
235
236 test.AddEdgeTo(sched)
237
238
239
240
241 test.Succs = append(test.Succs, Edge{h, i})
242 h.Preds[i] = Edge{test, 1}
243 headerMemPhi.SetArg(i, mem0)
244
245 test.Likely = BranchUnlikely
246
247
248
249
250 resched := f.fe.Syslook("goschedguarded")
251 call := sched.NewValue1A(bb.Pos, OpStaticCall, types.TypeResultMem, StaticAuxCall(resched, bb.Func.ABIDefault.ABIAnalyzeTypes(nil, nil)), mem0)
252 mem1 := sched.NewValue1I(bb.Pos, OpSelectN, types.TypeMem, 0, call)
253 sched.AddEdgeTo(h)
254 headerMemPhi.AddArg(mem1)
255
256 bb.Succs[p.i] = Edge{test, 0}
257 test.Preds = append(test.Preds, Edge{bb, p.i})
258
259
260
261
262 for _, v := range h.Values {
263 if v.Op == OpPhi && v != headerMemPhi {
264 v.AddArg(v.Args[i])
265 }
266 }
267 }
268
269 f.invalidateCFG()
270
271 if f.pass.debug > 1 {
272 sdom = newSparseTree(f, f.Idom())
273 fmt.Printf("after %s = %s\n", f.Name, sdom.treestructure(f.Entry))
274 }
275 }
276
277
278
279 func newPhiFor(b *Block, v *Value) *Value {
280 phiV := b.NewValue0(b.Pos, OpPhi, v.Type)
281
282 for range b.Preds {
283 phiV.AddArg(v)
284 }
285 return phiV
286 }
287
288
289
290
291
292
293
294
295
296 func rewriteNewPhis(h, b *Block, f *Func, defsForUses []*Value, newphis map[*Block]rewrite, dfPhiTargets map[rewriteTarget]bool, sdom SparseTree) {
297
298 if _, ok := newphis[b]; ok {
299 h = b
300 }
301 change := newphis[h]
302 x := change.before
303 y := change.after
304
305
306 if x != nil {
307 p := &change.rewrites
308 for _, v := range b.Values {
309 if v == y {
310 continue
311 }
312 for i, w := range v.Args {
313 if w != x {
314 continue
315 }
316 tgt := rewriteTarget{v, i}
317
318
319
320
321 if dfPhiTargets[tgt] {
322 continue
323 }
324 *p = append(*p, tgt)
325 if f.pass.debug > 1 {
326 fmt.Printf("added block target for h=%v, b=%v, x=%v, y=%v, tgt.v=%s, tgt.i=%d\n",
327 h, b, x, y, v, i)
328 }
329 }
330 }
331
332
333
334
335
336
337 if dfu := defsForUses[b.ID]; dfu != nil && dfu.Block != b {
338 for _, e := range b.Succs {
339 s := e.b
340
341 for _, v := range s.Values {
342 if v.Op == OpPhi && v.Args[e.i] == x {
343 tgt := rewriteTarget{v, e.i}
344 *p = append(*p, tgt)
345 dfPhiTargets[tgt] = true
346 if f.pass.debug > 1 {
347 fmt.Printf("added phi target for h=%v, b=%v, s=%v, x=%v, y=%v, tgt.v=%s, tgt.i=%d\n",
348 h, b, s, x, y, v.LongString(), e.i)
349 }
350 break
351 }
352 }
353 }
354 }
355 newphis[h] = change
356 }
357
358 for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
359 rewriteNewPhis(h, c, f, defsForUses, newphis, dfPhiTargets, sdom)
360 }
361 }
362
363
364
365
366
367
368
369
370 func addDFphis(x *Value, h, b *Block, f *Func, defForUses []*Value, newphis map[*Block]rewrite, sdom SparseTree) {
371 oldv := defForUses[b.ID]
372 if oldv != x {
373 return
374 }
375 idom := f.Idom()
376 outer:
377 for _, e := range b.Succs {
378 s := e.b
379
380 if sdom.isAncestor(h, s) {
381 continue
382 }
383 if _, ok := newphis[s]; ok {
384 continue
385 }
386 if x != nil {
387 for _, v := range s.Values {
388 if v.Op == OpPhi && v.Args[e.i] == x {
389 continue outer
390 }
391 }
392 }
393
394 old := defForUses[idom[s.ID].ID]
395 headerPhi := newPhiFor(s, old)
396
397 newphis[s] = rewrite{before: old, after: headerPhi}
398 addDFphis(old, s, s, f, defForUses, newphis, sdom)
399 }
400 for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
401 addDFphis(x, h, c, f, defForUses, newphis, sdom)
402 }
403 }
404
405
406 func findLastMems(f *Func) []*Value {
407
408 var stores []*Value
409 lastMems := f.Cache.allocValueSlice(f.NumBlocks())
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