mirror of
https://github.com/golang/go.git
synced 2025-05-25 09:21:21 +00:00
[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: Todd Neal <todd@tneal.org>
This commit is contained in:
parent
25abe96214
commit
c87a62f32b
@ -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) {
|
|||||||
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
|
|||||||
// 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
|
|||||||
// 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) []
|
|||||||
|
|
||||||
// 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) []
|
|||||||
// 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() {
|
|||||||
}
|
}
|
||||||
// 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})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user