aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Bleecher Snyder <josharian@gmail.com>2020-04-03 18:23:04 -0700
committerJosh Bleecher Snyder <josharian@gmail.com>2020-04-06 16:08:18 +0000
commit42d4df94597626a84b81053792b445c318f6bdf1 (patch)
tree310a509fc06fe8ae5eb3f6e2b35100eea70dfbdf
parent23866aedd960b920d8c95250818d26d2b9023c5a (diff)
downloadgo-42d4df94597626a84b81053792b445c318f6bdf1.tar.gz
go-42d4df94597626a84b81053792b445c318f6bdf1.zip
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>
-rw-r--r--src/cmd/compile/internal/ssa/layout.go37
1 files changed, 34 insertions, 3 deletions
diff --git a/src/cmd/compile/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go
index 338cd91c47..30b7b97d04 100644
--- a/src/cmd/compile/internal/ssa/layout.go
+++ b/src/cmd/compile/internal/ssa/layout.go
@@ -46,13 +46,44 @@ func layoutOrder(f *Func) []*Block {
exit := f.newSparseSet(f.NumBlocks()) // exit blocks
defer f.retSparseSet(exit)
- // Initialize indegree of each block
+ // Populate idToBlock and find exit blocks.
for _, b := range f.Blocks {
idToBlock[b.ID] = b
if b.Kind == BlockExit {
- // exit blocks are always scheduled last
- // TODO: also add blocks post-dominated by exit blocks
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
}
indegree[b.ID] = len(b.Preds)