Commit 056c09bb authored by Keith Randall's avatar Keith Randall

[dev.ssa] cmd/compile: add backing store buffers for block.{Preds,Succs,Values}

Speeds up compilation by 6%.

Change-Id: Ibaad95710323ddbe13c1b0351843fe43a48d776e
Reviewed-on: https://go-review.googlesource.com/19080Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 4c5459da
...@@ -53,6 +53,11 @@ type Block struct { ...@@ -53,6 +53,11 @@ type Block struct {
// After flagalloc, records whether flags are live at the end of the block. // After flagalloc, records whether flags are live at the end of the block.
FlagsLiveAtEnd bool FlagsLiveAtEnd bool
// Storage for Succs, Preds, and Values
succstorage [2]*Block
predstorage [4]*Block
valstorage [8]*Value
} }
// kind control successors // kind control successors
......
...@@ -219,7 +219,7 @@ func checkFunc(f *Func) { ...@@ -219,7 +219,7 @@ func checkFunc(f *Func) {
f.Fatalf("control value for %s is missing: %v", b, b.Control) f.Fatalf("control value for %s is missing: %v", b, b.Control)
} }
} }
for b := f.freeBlocks; b != nil; b = b.Aux.(*Block) { for b := f.freeBlocks; b != nil; b = b.succstorage[0] {
if blockMark[b.ID] { if blockMark[b.ID] {
f.Fatalf("used block b%d in free list", b.ID) f.Fatalf("used block b%d in free list", b.ID)
} }
......
...@@ -183,7 +183,7 @@ func deadcode(f *Func) { ...@@ -183,7 +183,7 @@ func deadcode(f *Func) {
b.Values = b.Values[:i] b.Values = b.Values[:i]
} }
// Remove unreachable blocks. Return dead block ids to allocator. // Remove unreachable blocks. Return dead blocks to allocator.
i = 0 i = 0
for _, b := range f.Blocks { for _, b := range f.Blocks {
if reachable[b.ID] { if reachable[b.ID] {
...@@ -193,10 +193,6 @@ func deadcode(f *Func) { ...@@ -193,10 +193,6 @@ func deadcode(f *Func) {
if len(b.Values) > 0 { if len(b.Values) > 0 {
b.Fatalf("live values in unreachable block %v: %v", b, b.Values) b.Fatalf("live values in unreachable block %v: %v", b, b.Values)
} }
b.Preds = nil
b.Succs = nil
b.Control = nil
b.Kind = BlockDead
f.freeBlock(b) f.freeBlock(b)
} }
} }
...@@ -206,9 +202,6 @@ func deadcode(f *Func) { ...@@ -206,9 +202,6 @@ func deadcode(f *Func) {
tail[j] = nil tail[j] = nil
} }
f.Blocks = f.Blocks[:i] f.Blocks = f.Blocks[:i]
// TODO: renumber Blocks and Values densely?
// TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it?
} }
// removePred removes the predecessor p from b's predecessor list. // removePred removes the predecessor p from b's predecessor list.
......
...@@ -30,7 +30,7 @@ type Func struct { ...@@ -30,7 +30,7 @@ type Func struct {
Names []LocalSlot Names []LocalSlot
freeValues *Value // free Values linked by argstorage[0]. All other fields except ID are 0/nil. freeValues *Value // free Values linked by argstorage[0]. All other fields except ID are 0/nil.
freeBlocks *Block // free Blocks linked by Aux.(*Block). All other fields except ID are 0/nil. freeBlocks *Block // free Blocks linked by succstorage[0]. All other fields except ID are 0/nil.
} }
// NumBlocks returns an integer larger than the id of any Block in the Func. // NumBlocks returns an integer larger than the id of any Block in the Func.
...@@ -68,7 +68,7 @@ func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value { ...@@ -68,7 +68,7 @@ func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value {
// freeValue frees a value. It must no longer be referenced. // freeValue frees a value. It must no longer be referenced.
func (f *Func) freeValue(v *Value) { func (f *Func) freeValue(v *Value) {
if v.Type == nil { if v.Block == nil {
f.Fatalf("trying to free an already freed value") f.Fatalf("trying to free an already freed value")
} }
// Clear everything but ID (which we reuse). // Clear everything but ID (which we reuse).
...@@ -84,8 +84,8 @@ func (f *Func) NewBlock(kind BlockKind) *Block { ...@@ -84,8 +84,8 @@ func (f *Func) NewBlock(kind BlockKind) *Block {
var b *Block var b *Block
if f.freeBlocks != nil { if f.freeBlocks != nil {
b = f.freeBlocks b = f.freeBlocks
f.freeBlocks = b.Aux.(*Block) f.freeBlocks = b.succstorage[0]
b.Aux = nil b.succstorage[0] = nil
} else { } else {
ID := f.bid.get() ID := f.bid.get()
if int(ID) < len(f.Config.blocks) { if int(ID) < len(f.Config.blocks) {
...@@ -96,16 +96,22 @@ func (f *Func) NewBlock(kind BlockKind) *Block { ...@@ -96,16 +96,22 @@ func (f *Func) NewBlock(kind BlockKind) *Block {
} }
b.Kind = kind b.Kind = kind
b.Func = f b.Func = f
b.Preds = b.predstorage[:0]
b.Succs = b.succstorage[:0]
b.Values = b.valstorage[:0]
f.Blocks = append(f.Blocks, b) f.Blocks = append(f.Blocks, b)
return b return b
} }
func (f *Func) freeBlock(b *Block) { func (f *Func) freeBlock(b *Block) {
if b.Func == nil {
f.Fatalf("trying to free an already freed block")
}
// Clear everything but ID (which we reuse). // Clear everything but ID (which we reuse).
id := b.ID id := b.ID
*b = Block{} *b = Block{}
b.ID = id b.ID = id
b.Aux = f.freeBlocks b.succstorage[0] = f.freeBlocks
f.freeBlocks = b f.freeBlocks = b
} }
......
...@@ -22,7 +22,12 @@ func fuse(f *Func) { ...@@ -22,7 +22,12 @@ func fuse(f *Func) {
} }
// replace b->c edge with preds(b) -> c // replace b->c edge with preds(b) -> c
c.Preds = b.Preds c.predstorage[0] = nil
if len(b.Preds) > len(b.predstorage) {
c.Preds = b.Preds
} else {
c.Preds = append(c.predstorage[:0], b.Preds...)
}
for _, p := range c.Preds { for _, p := range c.Preds {
for i, q := range p.Succs { for i, q := range p.Succs {
if q == b { if q == b {
......
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