]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.ssa] cmd/compile: add backing store buffers for block.{Preds,Succs,Values}
authorKeith Randall <khr@golang.org>
Thu, 28 Jan 2016 23:54:45 +0000 (15:54 -0800)
committerKeith Randall <khr@golang.org>
Fri, 29 Jan 2016 01:01:39 +0000 (01:01 +0000)
Speeds up compilation by 6%.

Change-Id: Ibaad95710323ddbe13c1b0351843fe43a48d776e
Reviewed-on: https://go-review.googlesource.com/19080
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/cmd/compile/internal/ssa/block.go
src/cmd/compile/internal/ssa/check.go
src/cmd/compile/internal/ssa/deadcode.go
src/cmd/compile/internal/ssa/func.go
src/cmd/compile/internal/ssa/fuse.go

index 02673f06500ad8af64e1fa48955e29e2da69419d..6585528b28b25da2532a483a6351239fcd41c7f0 100644 (file)
@@ -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
index e6f8716d5b23a9fbf1675ea4af692b6236bb78b2..1c36160f8fa3c1ad3fddc83482e15acdcb23b267 100644 (file)
@@ -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)
                }
index faf16a381677b4a5b127fe5046b2e67bcfe09e1b..80e14900142f7afcb79b73ab5c36aafaf3bc6441 100644 (file)
@@ -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.
index 26e4283a238bb4ce9848dbd4791a26d0d91361e2..6d20a2797df87dc6ea98d245cbe3993ca25ce044 100644 (file)
@@ -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
 }
 
index e390fc4998825130d9dfcbdfbadefa05eedb55fe..f191c7f9fd9125d76beb8c8b88f37d703addb2ad 100644 (file)
@@ -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 {