From 056c09bb88008f683904e88cea582722eeac2f27 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 28 Jan 2016 15:54:45 -0800 Subject: [PATCH] [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/19080 Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/ssa/block.go | 5 +++++ src/cmd/compile/internal/ssa/check.go | 2 +- src/cmd/compile/internal/ssa/deadcode.go | 9 +-------- src/cmd/compile/internal/ssa/func.go | 16 +++++++++++----- src/cmd/compile/internal/ssa/fuse.go | 7 ++++++- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go index 02673f0650..6585528b28 100644 --- a/src/cmd/compile/internal/ssa/block.go +++ b/src/cmd/compile/internal/ssa/block.go @@ -53,6 +53,11 @@ type Block struct { // After flagalloc, records whether flags are live at the end of the block. FlagsLiveAtEnd bool + + // Storage for Succs, Preds, and Values + succstorage [2]*Block + predstorage [4]*Block + valstorage [8]*Value } // kind control successors diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index e6f8716d5b..1c36160f8f 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -219,7 +219,7 @@ func checkFunc(f *Func) { 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] { f.Fatalf("used block b%d in free list", b.ID) } diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index faf16a3816..80e1490014 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -183,7 +183,7 @@ func deadcode(f *Func) { b.Values = b.Values[:i] } - // Remove unreachable blocks. Return dead block ids to allocator. + // Remove unreachable blocks. Return dead blocks to allocator. i = 0 for _, b := range f.Blocks { if reachable[b.ID] { @@ -193,10 +193,6 @@ func deadcode(f *Func) { if len(b.Values) > 0 { 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) } } @@ -206,9 +202,6 @@ func deadcode(f *Func) { tail[j] = nil } 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. diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 26e4283a23..6d20a2797d 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -30,7 +30,7 @@ type Func struct { Names []LocalSlot 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. @@ -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. func (f *Func) freeValue(v *Value) { - if v.Type == nil { + if v.Block == nil { f.Fatalf("trying to free an already freed value") } // Clear everything but ID (which we reuse). @@ -84,8 +84,8 @@ func (f *Func) NewBlock(kind BlockKind) *Block { var b *Block if f.freeBlocks != nil { b = f.freeBlocks - f.freeBlocks = b.Aux.(*Block) - b.Aux = nil + f.freeBlocks = b.succstorage[0] + b.succstorage[0] = nil } else { ID := f.bid.get() if int(ID) < len(f.Config.blocks) { @@ -96,16 +96,22 @@ func (f *Func) NewBlock(kind BlockKind) *Block { } b.Kind = kind b.Func = f + b.Preds = b.predstorage[:0] + b.Succs = b.succstorage[:0] + b.Values = b.valstorage[:0] f.Blocks = append(f.Blocks, b) return b } 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). id := b.ID *b = Block{} b.ID = id - b.Aux = f.freeBlocks + b.succstorage[0] = f.freeBlocks f.freeBlocks = b } diff --git a/src/cmd/compile/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go index e390fc4998..f191c7f9fd 100644 --- a/src/cmd/compile/internal/ssa/fuse.go +++ b/src/cmd/compile/internal/ssa/fuse.go @@ -22,7 +22,12 @@ func fuse(f *Func) { } // 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 i, q := range p.Succs { if q == b { -- 2.48.1