mirror of
https://github.com/golang/go
synced 2024-11-12 08:10:21 -07:00
cmd/compile: use loop information in regalloc
This seems to help the problem reported in #14606; this change seems to produce about a 4% improvement (mostly for the 128-8192 shards). Fixes #14789. Change-Id: I1bd52c82d4ca81d9d5e9ab371fdfc860d7e8af50 Reviewed-on: https://go-review.googlesource.com/20660 Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
e4d489a85f
commit
815c9a7f28
@ -13,8 +13,9 @@ type loop struct {
|
||||
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
|
||||
@ -23,6 +24,21 @@ func (sdom sparseTree) outerinner(outer, inner *loop) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,6 +262,7 @@ func loopnestfor(f *Func) *loopnest {
|
||||
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
|
||||
@ -274,6 +291,7 @@ func loopnestfor(f *Func) *loopnest {
|
||||
|
||||
if innermost != nil {
|
||||
b2l[b.ID] = innermost
|
||||
innermost.checkContainsCall(b)
|
||||
innermost.nBlocks++
|
||||
}
|
||||
}
|
||||
|
@ -274,6 +274,8 @@ type regAllocState struct {
|
||||
|
||||
// spillLive[blockid] is the set of live spills at the end of each block
|
||||
spillLive [][]ID
|
||||
|
||||
loopnest *loopnest
|
||||
}
|
||||
|
||||
type endReg struct {
|
||||
@ -996,27 +998,12 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
// 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?
|
||||
@ -1620,7 +1607,8 @@ func (s *regAllocState) computeLive() {
|
||||
// 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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user