Commit c87a62f3 authored by David Chase's avatar David Chase

[dev.ssa] cmd/compile: reducing alloc footprint of dominator calc

Converted working slices of pointer into slices of pointer
index.  Half the size (on 64-bit machine) and no pointers
to trace if GC occurs while they're live.

TODO - could expose slice mapping ID->*Block; some dom
clients also construct these.

Minor optimization in regalloc that cuts allocation count.

Minor optimization in compile.go that cuts calls to Sprintf.

Change-Id: I28f0bfed422b7344af333dc52ea272441e28e463
Reviewed-on: https://go-review.googlesource.com/19104
Run-TryBot: Todd Neal <todd@tneal.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarTodd Neal <todd@tneal.org>
parent 25abe962
...@@ -57,6 +57,8 @@ func Compile(f *Func) { ...@@ -57,6 +57,8 @@ func Compile(f *Func) {
tStart := time.Now() tStart := time.Now()
p.fn(f) p.fn(f)
if f.Log() || f.Config.HTML != nil {
tEnd := time.Now() tEnd := time.Now()
time := tEnd.Sub(tStart).Nanoseconds() time := tEnd.Sub(tStart).Nanoseconds()
...@@ -71,11 +73,8 @@ func Compile(f *Func) { ...@@ -71,11 +73,8 @@ func Compile(f *Func) {
stats = fmt.Sprintf("[%d ns]", time) stats = fmt.Sprintf("[%d ns]", time)
} }
if f.Log() {
f.Logf(" pass %s end %s\n", p.name, stats) f.Logf(" pass %s end %s\n", p.name, stats)
}
printFunc(f) printFunc(f)
if f.Config.HTML != nil {
f.Config.HTML.WriteFunc(fmt.Sprintf("after %s <span class=\"stats\">%s</span>", phaseName, stats), f) f.Config.HTML.WriteFunc(fmt.Sprintf("after %s <span class=\"stats\">%s</span>", phaseName, stats), f)
} }
checkFunc(f) checkFunc(f)
......
...@@ -59,21 +59,30 @@ type linkedBlocks func(*Block) []*Block ...@@ -59,21 +59,30 @@ type linkedBlocks func(*Block) []*Block
// from block id to an int indicating the order the block was reached or // from block id to an int indicating the order the block was reached or
// notFound if the block was not reached. order contains a mapping from dfnum // notFound if the block was not reached. order contains a mapping from dfnum
// to block. // to block.
func dfs(entries []*Block, succFn linkedBlocks) (dfnum []int, order []*Block, parent []*Block) { func dfs(entries []*Block, succFn linkedBlocks) (fromID []*Block, dfnum []int32, order []ID, parent []ID) {
maxBlockID := entries[0].Func.NumBlocks() maxBlockID := entries[0].Func.NumBlocks()
dfnum = make([]int, maxBlockID) dfnum = make([]int32, maxBlockID)
order = make([]*Block, maxBlockID) order = make([]ID, maxBlockID)
parent = make([]*Block, maxBlockID) parent = make([]ID, maxBlockID)
fromID = make([]*Block, maxBlockID)
n := 0 for _, entry := range entries[0].Func.Blocks {
eid := entry.ID
if fromID[eid] != nil {
panic("Colliding entry IDs")
}
fromID[eid] = entry
}
n := int32(0)
s := make([]*Block, 0, 256) s := make([]*Block, 0, 256)
for _, entry := range entries { for _, entry := range entries {
if dfnum[entry.ID] != notFound { if dfnum[entry.ID] != notFound {
continue // already found from a previous entry continue // already found from a previous entry
} }
s = append(s, entry) s = append(s, entry)
parent[entry.ID] = entry parent[entry.ID] = entry.ID
for len(s) > 0 { for len(s) > 0 {
node := s[len(s)-1] node := s[len(s)-1]
s = s[:len(s)-1] s = s[:len(s)-1]
...@@ -83,12 +92,12 @@ func dfs(entries []*Block, succFn linkedBlocks) (dfnum []int, order []*Block, pa ...@@ -83,12 +92,12 @@ func dfs(entries []*Block, succFn linkedBlocks) (dfnum []int, order []*Block, pa
// if it has a dfnum, we've already visited it // if it has a dfnum, we've already visited it
if dfnum[w.ID] == notFound { if dfnum[w.ID] == notFound {
s = append(s, w) s = append(s, w)
parent[w.ID] = node parent[w.ID] = node.ID
dfnum[w.ID] = notExplored dfnum[w.ID] = notExplored
} }
} }
dfnum[node.ID] = n dfnum[node.ID] = n
order[n] = node order[n] = node.ID
} }
} }
...@@ -143,77 +152,77 @@ func dominatorsLT(entries []*Block, predFn linkedBlocks, succFn linkedBlocks) [] ...@@ -143,77 +152,77 @@ func dominatorsLT(entries []*Block, predFn linkedBlocks, succFn linkedBlocks) []
// Step 1. Carry out a depth first search of the problem graph. Number // Step 1. Carry out a depth first search of the problem graph. Number
// the vertices from 1 to n as they are reached during the search. // the vertices from 1 to n as they are reached during the search.
dfnum, vertex, parent := dfs(entries, succFn) fromID, dfnum, vertex, parent := dfs(entries, succFn)
maxBlockID := entries[0].Func.NumBlocks() maxBlockID := entries[0].Func.NumBlocks()
semi := make([]*Block, maxBlockID) semi := make([]ID, maxBlockID)
samedom := make([]*Block, maxBlockID) samedom := make([]ID, maxBlockID)
ancestor := make([]ID, maxBlockID)
best := make([]ID, maxBlockID)
bucket := make([]ID, maxBlockID)
idom := make([]*Block, maxBlockID) idom := make([]*Block, maxBlockID)
ancestor := make([]*Block, maxBlockID)
best := make([]*Block, maxBlockID)
bucket := make([]*Block, maxBlockID)
// Step 2. Compute the semidominators of all vertices by applying // Step 2. Compute the semidominators of all vertices by applying
// Theorem 4. Carry out the computation vertex by vertex in decreasing // Theorem 4. Carry out the computation vertex by vertex in decreasing
// order by number. // order by number.
for i := maxBlockID - 1; i > 0; i-- { for i := maxBlockID - 1; i > 0; i-- {
w := vertex[i] w := vertex[i]
if w == nil { if w == 0 {
continue continue
} }
if dfnum[w.ID] == notFound { if dfnum[w] == notFound {
// skip unreachable node // skip unreachable node
continue continue
} }
// Step 3. Implicitly define the immediate dominator of each // Step 3. Implicitly define the immediate dominator of each
// vertex by applying Corollary 1. (reordered) // vertex by applying Corollary 1. (reordered)
for v := bucket[w.ID]; v != nil; v = bucket[v.ID] { for v := bucket[w]; v != 0; v = bucket[v] {
u := eval(v, ancestor, semi, dfnum, best) u := eval(v, ancestor, semi, dfnum, best)
if semi[u.ID] == semi[v.ID] { if semi[u] == semi[v] {
idom[v.ID] = w // true dominator idom[v] = fromID[w] // true dominator
} else { } else {
samedom[v.ID] = u // v has same dominator as u samedom[v] = u // v has same dominator as u
} }
} }
p := parent[w.ID] p := parent[w]
s := p // semidominator s := p // semidominator
var sp *Block var sp ID
// calculate the semidominator of w // calculate the semidominator of w
for _, v := range w.Preds { for _, v := range predFn(fromID[w]) {
if dfnum[v.ID] == notFound { if dfnum[v.ID] == notFound {
// skip unreachable predecessor // skip unreachable predecessor
continue continue
} }
if dfnum[v.ID] <= dfnum[w.ID] { if dfnum[v.ID] <= dfnum[w] {
sp = v sp = v.ID
} else { } else {
sp = semi[eval(v, ancestor, semi, dfnum, best).ID] sp = semi[eval(v.ID, ancestor, semi, dfnum, best)]
} }
if dfnum[sp.ID] < dfnum[s.ID] { if dfnum[sp] < dfnum[s] {
s = sp s = sp
} }
} }
// link // link
ancestor[w.ID] = p ancestor[w] = p
best[w.ID] = w best[w] = w
semi[w.ID] = s semi[w] = s
if semi[s.ID] != parent[s.ID] { if semi[s] != parent[s] {
bucket[w.ID] = bucket[s.ID] bucket[w] = bucket[s]
bucket[s.ID] = w bucket[s] = w
} }
} }
// Final pass of step 3 // Final pass of step 3
for v := bucket[0]; v != nil; v = bucket[v.ID] { for v := bucket[0]; v != 0; v = bucket[v] {
idom[v.ID] = bucket[0] idom[v] = fromID[bucket[0]]
} }
// Step 4. Explictly define the immediate dominator of each vertex, // Step 4. Explictly define the immediate dominator of each vertex,
...@@ -221,28 +230,28 @@ func dominatorsLT(entries []*Block, predFn linkedBlocks, succFn linkedBlocks) [] ...@@ -221,28 +230,28 @@ func dominatorsLT(entries []*Block, predFn linkedBlocks, succFn linkedBlocks) []
// number. // number.
for i := 1; i < maxBlockID-1; i++ { for i := 1; i < maxBlockID-1; i++ {
w := vertex[i] w := vertex[i]
if w == nil { if w == 0 {
continue continue
} }
// w has the same dominator as samedom[w.ID] // w has the same dominator as samedom[w]
if samedom[w.ID] != nil { if samedom[w] != 0 {
idom[w.ID] = idom[samedom[w.ID].ID] idom[w] = idom[samedom[w]]
} }
} }
return idom return idom
} }
// eval function from LT paper with path compression // eval function from LT paper with path compression
func eval(v *Block, ancestor []*Block, semi []*Block, dfnum []int, best []*Block) *Block { func eval(v ID, ancestor []ID, semi []ID, dfnum []int32, best []ID) ID {
a := ancestor[v.ID] a := ancestor[v]
if ancestor[a.ID] != nil { if ancestor[a] != 0 {
b := eval(a, ancestor, semi, dfnum, best) bid := eval(a, ancestor, semi, dfnum, best)
ancestor[v.ID] = ancestor[a.ID] ancestor[v] = ancestor[a]
if dfnum[semi[b.ID].ID] < dfnum[semi[best[v.ID].ID].ID] { if dfnum[semi[bid]] < dfnum[semi[best[v]]] {
best[v.ID] = b best[v] = bid
} }
} }
return best[v.ID] return best[v]
} }
// dominators computes the dominator tree for f. It returns a slice // dominators computes the dominator tree for f. It returns a slice
......
...@@ -1624,6 +1624,9 @@ func (s *regAllocState) computeLive() { ...@@ -1624,6 +1624,9 @@ func (s *regAllocState) computeLive() {
} }
// The live set has changed, update it. // The live set has changed, update it.
l := s.live[p.ID][:0] l := s.live[p.ID][:0]
if cap(l) == 0 {
l = make([]liveInfo, 0, len(t.contents()))
}
for _, e := range t.contents() { for _, e := range t.contents() {
l = append(l, liveInfo{e.key, e.val}) l = append(l, liveInfo{e.key, e.val})
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment