outer *loop // loop containing this loop
// Next two fields not currently used, but cheap to maintain,
// and aid in computation of inner-ness and list of blocks.
- nBlocks int32 // Number of blocks in this loop but not within inner loops
- isInner bool // True if never discovered to contain a loop
+ nBlocks int32 // Number of blocks in this loop but not within inner loops
+ isInner bool // True if never discovered to contain a loop
+ containsCall bool // if any block in this loop or any loop it contains is a BlockCall or BlockDefer
}
// outerinner records that outer contains inner
if oldouter == nil || sdom.isAncestorEq(oldouter.header, outer.header) {
inner.outer = outer
outer.isInner = false
+ if inner.containsCall {
+ outer.setContainsCall()
+ }
+ }
+}
+
+func (l *loop) setContainsCall() {
+ for ; l != nil && !l.containsCall; l = l.outer {
+ l.containsCall = true
+ }
+
+}
+func (l *loop) checkContainsCall(bb *Block) {
+ if bb.Kind == BlockCall || bb.Kind == BlockDefer {
+ l.setContainsCall()
}
}
l = &loop{header: bb, isInner: true}
loops = append(loops, l)
b2l[bb.ID] = l
+ l.checkContainsCall(bb)
}
} else { // Perhaps a loop header is inherited.
// is there any loop containing our successor whose
if innermost != nil {
b2l[b.ID] = innermost
+ innermost.checkContainsCall(b)
innermost.nBlocks++
}
}
// spillLive[blockid] is the set of live spills at the end of each block
spillLive [][]ID
+
+ loopnest *loopnest
}
type endReg struct {
// If we are approaching a merge point and we are the primary
// predecessor of it, find live values that we use soon after
// the merge point and promote them to registers now.
- if len(b.Succs) == 1 && len(b.Succs[0].Preds) > 1 && b.Succs[0].Preds[s.primary[b.Succs[0].ID]] == b {
+ if len(b.Succs) == 1 {
// For this to be worthwhile, the loop must have no calls in it.
- // Use a very simple loop detector. TODO: incorporate David's loop stuff
- // once it is in.
top := b.Succs[0]
- for _, p := range top.Preds {
- if p == b {
- continue
- }
- for {
- if p.Kind == BlockCall || p.Kind == BlockDefer {
- goto badloop
- }
- if p == top {
- break
- }
- if len(p.Preds) != 1 {
- goto badloop
- }
- p = p.Preds[0]
- }
+ loop := s.loopnest.b2l[top.ID]
+ if loop == nil || loop.header != top || loop.containsCall {
+ goto badloop
}
// TODO: sort by distance, pick the closest ones?
// Walk the dominator tree from end to beginning, just once, treating SCC
// components as single blocks, duplicated calculated liveness information
// out to all of them.
- po := postorder(f)
+ s.loopnest = loopnestfor(f)
+ po := s.loopnest.po
for {
changed := false