mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: lay out exit post-dominated blocks at the end
Complete a long-standing TODO in the code. Exit blocks are cold code, so we lay them out at the end of the function. Blocks that are post-dominated by exit blocks are also ipso facto exit blocks. Treat them as such. Implement using a simple loop, because there are generally very few exit blocks. In addition to improved instruction cache, this empirically yields better register allocation. Binary size impact: file before after Δ % cgo 4812872 4808776 -4096 -0.085% fix 3370072 3365976 -4096 -0.122% vet 8252280 8248184 -4096 -0.050% total 115052984 115040696 -12288 -0.011% This also appears to improve compiler performance (-0.15% geomean time/op, -1.20% geomean user time/op), but that could just be alignment effects. Compiler benchmarking hasn't been super reliably recently, and there's no particular reason to think this should speed up the compiler that much. Change-Id: I3d262c4f5cb80626a67a5c17285e2fa09f423c00 Reviewed-on: https://go-review.googlesource.com/c/go/+/227217 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
23866aedd9
commit
42d4df9459
1 changed files with 34 additions and 3 deletions
|
|
@ -46,13 +46,44 @@ func layoutOrder(f *Func) []*Block {
|
||||||
exit := f.newSparseSet(f.NumBlocks()) // exit blocks
|
exit := f.newSparseSet(f.NumBlocks()) // exit blocks
|
||||||
defer f.retSparseSet(exit)
|
defer f.retSparseSet(exit)
|
||||||
|
|
||||||
// Initialize indegree of each block
|
// Populate idToBlock and find exit blocks.
|
||||||
for _, b := range f.Blocks {
|
for _, b := range f.Blocks {
|
||||||
idToBlock[b.ID] = b
|
idToBlock[b.ID] = b
|
||||||
if b.Kind == BlockExit {
|
if b.Kind == BlockExit {
|
||||||
// exit blocks are always scheduled last
|
|
||||||
// TODO: also add blocks post-dominated by exit blocks
|
|
||||||
exit.add(b.ID)
|
exit.add(b.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand exit to include blocks post-dominated by exit blocks.
|
||||||
|
for {
|
||||||
|
changed := false
|
||||||
|
for _, id := range exit.contents() {
|
||||||
|
b := idToBlock[id]
|
||||||
|
NextPred:
|
||||||
|
for _, pe := range b.Preds {
|
||||||
|
p := pe.b
|
||||||
|
if exit.contains(p.ID) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, s := range p.Succs {
|
||||||
|
if !exit.contains(s.b.ID) {
|
||||||
|
continue NextPred
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// All Succs are in exit; add p.
|
||||||
|
exit.add(p.ID)
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !changed {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize indegree of each block
|
||||||
|
for _, b := range f.Blocks {
|
||||||
|
if exit.contains(b.ID) {
|
||||||
|
// exit blocks are always scheduled last
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
indegree[b.ID] = len(b.Preds)
|
indegree[b.ID] = len(b.Preds)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue