mirror of
https://github.com/golang/go
synced 2024-11-20 09:14:46 -07:00
cmd/compile: make loop finder more aware of irreducible loops
The loop finder doesn't return good information if it encounters an irreducible loop. Make a start on improving this, and set a function-level flag to indicate when there is such a loop (and the returned information might be flaky). Use that flag to prevent the loop rotater from getting confused; the existing code seems to depend on artifacts of the previous loop-finding algorithm. (There is one irreducible loop in the go library, in "inflate.go"). Change-Id: If6e26feab38d9b009d2252d556e1470c803bde40 Reviewed-on: https://go-review.googlesource.com/42150 Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
acdb44765d
commit
9e21e9c5cb
@ -280,6 +280,7 @@ func checkFunc(f *Func) {
|
|||||||
// Check loop construction
|
// Check loop construction
|
||||||
if f.RegAlloc == nil && f.pass != nil { // non-nil pass allows better-targeted debug printing
|
if f.RegAlloc == nil && f.pass != nil { // non-nil pass allows better-targeted debug printing
|
||||||
ln := f.loopnest()
|
ln := f.loopnest()
|
||||||
|
if !ln.hasIrreducible {
|
||||||
po := f.postorder() // use po to avoid unreachable blocks.
|
po := f.postorder() // use po to avoid unreachable blocks.
|
||||||
for _, b := range po {
|
for _, b := range po {
|
||||||
for _, s := range b.Succs {
|
for _, s := range b.Succs {
|
||||||
@ -293,6 +294,7 @@ func checkFunc(f *Func) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check use counts
|
// Check use counts
|
||||||
uses := make([]int32, f.NumValues())
|
uses := make([]int32, f.NumValues())
|
||||||
|
@ -12,7 +12,7 @@ type loop struct {
|
|||||||
header *Block // The header node of this (reducible) loop
|
header *Block // The header node of this (reducible) loop
|
||||||
outer *loop // loop containing this loop
|
outer *loop // loop containing this loop
|
||||||
|
|
||||||
// By default, children exits, and depth are not initialized.
|
// By default, children, exits, and depth are not initialized.
|
||||||
children []*loop // loops nested directly within this loop. Initialized by assembleChildren().
|
children []*loop // loops nested directly within this loop. Initialized by assembleChildren().
|
||||||
exits []*Block // exits records blocks reached by exits from this loop. Initialized by findExits().
|
exits []*Block // exits records blocks reached by exits from this loop. Initialized by findExits().
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ type loop struct {
|
|||||||
isInner bool // True if never discovered to contain a loop
|
isInner bool // True if never discovered to contain a loop
|
||||||
|
|
||||||
// register allocation uses this.
|
// register allocation uses this.
|
||||||
containsCall bool // if any block in this loop or any loop it contains has a call
|
containsCall bool // if any block in this loop or any loop within it contains has a call
|
||||||
}
|
}
|
||||||
|
|
||||||
// outerinner records that outer contains inner
|
// outerinner records that outer contains inner
|
||||||
@ -77,6 +77,7 @@ type loopnest struct {
|
|||||||
po []*Block
|
po []*Block
|
||||||
sdom SparseTree
|
sdom SparseTree
|
||||||
loops []*loop
|
loops []*loop
|
||||||
|
hasIrreducible bool // TODO current treatment of irreducible loops is very flaky, if accurate loops are needed, must punt at function level.
|
||||||
|
|
||||||
// Record which of the lazily initialized fields have actually been initialized.
|
// Record which of the lazily initialized fields have actually been initialized.
|
||||||
initializedChildren, initializedDepth, initializedExits bool
|
initializedChildren, initializedDepth, initializedExits bool
|
||||||
@ -285,6 +286,12 @@ func loopnestfor(f *Func) *loopnest {
|
|||||||
sdom := f.sdom()
|
sdom := f.sdom()
|
||||||
b2l := make([]*loop, f.NumBlocks())
|
b2l := make([]*loop, f.NumBlocks())
|
||||||
loops := make([]*loop, 0)
|
loops := make([]*loop, 0)
|
||||||
|
visited := make([]bool, f.NumBlocks())
|
||||||
|
sawIrred := false
|
||||||
|
|
||||||
|
if f.pass.debug > 2 {
|
||||||
|
fmt.Printf("loop finding in %s\n", f.Name)
|
||||||
|
}
|
||||||
|
|
||||||
// Reducible-loop-nest-finding.
|
// Reducible-loop-nest-finding.
|
||||||
for _, b := range po {
|
for _, b := range po {
|
||||||
@ -318,10 +325,17 @@ func loopnestfor(f *Func) *loopnest {
|
|||||||
b2l[bb.ID] = l
|
b2l[bb.ID] = l
|
||||||
l.checkContainsCall(bb)
|
l.checkContainsCall(bb)
|
||||||
}
|
}
|
||||||
} else { // Perhaps a loop header is inherited.
|
} else if !visited[bb.ID] { // Found an irreducible loop
|
||||||
|
sawIrred = true
|
||||||
|
if f.pass != nil && f.pass.debug > 4 {
|
||||||
|
fmt.Printf("loop finding succ %s of %s is IRRED, in %s\n", bb.String(), b.String(), f.Name)
|
||||||
|
}
|
||||||
|
} else if l != nil {
|
||||||
|
// TODO handle case where l is irreducible.
|
||||||
|
// Perhaps a loop header is inherited.
|
||||||
// is there any loop containing our successor whose
|
// is there any loop containing our successor whose
|
||||||
// header dominates b?
|
// header dominates b?
|
||||||
if l != nil && !sdom.isAncestorEq(l.header, b) {
|
if !sdom.isAncestorEq(l.header, b) {
|
||||||
l = l.nearestOuterLoop(sdom, b)
|
l = l.nearestOuterLoop(sdom, b)
|
||||||
}
|
}
|
||||||
if f.pass != nil && f.pass.debug > 4 {
|
if f.pass != nil && f.pass.debug > 4 {
|
||||||
@ -331,6 +345,11 @@ func loopnestfor(f *Func) *loopnest {
|
|||||||
fmt.Printf("loop finding succ %s of %s provides loop with header %s\n", bb.String(), b.String(), l.header.String())
|
fmt.Printf("loop finding succ %s of %s provides loop with header %s\n", bb.String(), b.String(), l.header.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else { // No loop
|
||||||
|
if f.pass != nil && f.pass.debug > 4 {
|
||||||
|
fmt.Printf("loop finding succ %s of %s has no loop\n", bb.String(), b.String())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if l == nil || innermost == l {
|
if l == nil || innermost == l {
|
||||||
@ -355,9 +374,10 @@ func loopnestfor(f *Func) *loopnest {
|
|||||||
innermost.checkContainsCall(b)
|
innermost.checkContainsCall(b)
|
||||||
innermost.nBlocks++
|
innermost.nBlocks++
|
||||||
}
|
}
|
||||||
|
visited[b.ID] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
ln := &loopnest{f: f, b2l: b2l, po: po, sdom: sdom, loops: loops}
|
ln := &loopnest{f: f, b2l: b2l, po: po, sdom: sdom, loops: loops, hasIrreducible: sawIrred}
|
||||||
|
|
||||||
// Curious about the loopiness? "-d=ssa/likelyadjust/stats"
|
// Curious about the loopiness? "-d=ssa/likelyadjust/stats"
|
||||||
if f.pass != nil && f.pass.stats > 0 && len(loops) > 0 {
|
if f.pass != nil && f.pass.stats > 0 && len(loops) > 0 {
|
||||||
|
@ -23,6 +23,9 @@ package ssa
|
|||||||
// JLT loop
|
// JLT loop
|
||||||
func loopRotate(f *Func) {
|
func loopRotate(f *Func) {
|
||||||
loopnest := f.loopnest()
|
loopnest := f.loopnest()
|
||||||
|
if loopnest.hasIrreducible {
|
||||||
|
return
|
||||||
|
}
|
||||||
if len(loopnest.loops) == 0 {
|
if len(loopnest.loops) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user