[dev.ssa] cmd/compile: preallocate small-numbered values and blocks

Speeds up the compiler ~5%.

Change-Id: Ia5cf0bcd58701fd14018ec77d01f03d5c7d6385b
Reviewed-on: https://go-review.googlesource.com/19060
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Keith Randall 2016-01-28 13:46:30 -08:00
parent 6a96a2fe5a
commit 2f57d0fe02
8 changed files with 168 additions and 176 deletions

View file

@ -4,10 +4,7 @@
package ssa
import (
"math"
"sync"
)
import "math"
// A Func represents a Go func declaration (or function literal) and
// its body. This package compiles each Func independently.
@ -31,6 +28,9 @@ type Func struct {
// Names is a copy of NamedValues.Keys. We keep a separate list
// of keys to make iteration order deterministic.
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.
}
// NumBlocks returns an integer larger than the id of any Block in the Func.
@ -43,68 +43,85 @@ func (f *Func) NumValues() int {
return f.vid.num()
}
const (
blockSize = 100
)
// blockPool provides a contiguous array of Blocks which
// improves the speed of traversing dominator trees.
type blockPool struct {
blocks []Block
mu sync.Mutex
}
func (bp *blockPool) newBlock() *Block {
bp.mu.Lock()
defer bp.mu.Unlock()
if len(bp.blocks) == 0 {
bp.blocks = make([]Block, blockSize, blockSize)
// newValue allocates a new Value with the given fields and places it at the end of b.Values.
func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value {
var v *Value
if f.freeValues != nil {
v = f.freeValues
f.freeValues = v.argstorage[0]
v.argstorage[0] = nil
} else {
ID := f.vid.get()
if int(ID) < len(f.Config.values) {
v = &f.Config.values[ID]
} else {
v = &Value{ID: ID}
}
}
res := &bp.blocks[0]
bp.blocks = bp.blocks[1:]
return res
v.Op = op
v.Type = t
v.Block = b
v.Line = line
b.Values = append(b.Values, v)
return v
}
var bp blockPool
// freeValue frees a value. It must no longer be referenced.
func (f *Func) freeValue(v *Value) {
if v.Type == nil {
f.Fatalf("trying to free an already freed value")
}
// Clear everything but ID (which we reuse).
id := v.ID
*v = Value{}
v.ID = id
v.argstorage[0] = f.freeValues
f.freeValues = v
}
// NewBlock returns a new block of the given kind and appends it to f.Blocks.
// newBlock allocates a new Block of the given kind and places it at the end of f.Blocks.
func (f *Func) NewBlock(kind BlockKind) *Block {
b := bp.newBlock()
b.ID = f.bid.get()
var b *Block
if f.freeBlocks != nil {
b = f.freeBlocks
f.freeBlocks = b.Aux.(*Block)
b.Aux = nil
} else {
ID := f.bid.get()
if int(ID) < len(f.Config.blocks) {
b = &f.Config.blocks[ID]
} else {
b = &Block{ID: ID}
}
}
b.Kind = kind
b.Func = f
f.Blocks = append(f.Blocks, b)
return b
}
func (f *Func) freeBlock(b *Block) {
// Clear everything but ID (which we reuse).
id := b.ID
*b = Block{}
b.ID = id
b.Aux = f.freeBlocks
f.freeBlocks = b
}
// NewValue0 returns a new value in the block with no arguments and zero aux values.
func (b *Block) NewValue0(line int32, op Op, t Type) *Value {
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
Block: b,
Line: line,
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = 0
v.Args = v.argstorage[:0]
b.Values = append(b.Values, v)
return v
}
// NewValue returns a new value in the block with no arguments and an auxint value.
func (b *Block) NewValue0I(line int32, op Op, t Type, auxint int64) *Value {
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
AuxInt: auxint,
Block: b,
Line: line,
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = auxint
v.Args = v.argstorage[:0]
b.Values = append(b.Values, v)
return v
}
@ -116,158 +133,93 @@ func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value {
// to prevent errors like using NewValue1A instead of NewValue1I.
b.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux)
}
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
Aux: aux,
Block: b,
Line: line,
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = 0
v.Aux = aux
v.Args = v.argstorage[:0]
b.Values = append(b.Values, v)
return v
}
// NewValue returns a new value in the block with no arguments and both an auxint and aux values.
func (b *Block) NewValue0IA(line int32, op Op, t Type, auxint int64, aux interface{}) *Value {
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
AuxInt: auxint,
Aux: aux,
Block: b,
Line: line,
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = auxint
v.Aux = aux
v.Args = v.argstorage[:0]
b.Values = append(b.Values, v)
return v
}
// NewValue1 returns a new value in the block with one argument and zero aux values.
func (b *Block) NewValue1(line int32, op Op, t Type, arg *Value) *Value {
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
Block: b,
Line: line,
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = 0
v.Args = v.argstorage[:1]
v.Args[0] = arg
b.Values = append(b.Values, v)
v.argstorage[0] = arg
return v
}
// NewValue1I returns a new value in the block with one argument and an auxint value.
func (b *Block) NewValue1I(line int32, op Op, t Type, auxint int64, arg *Value) *Value {
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
AuxInt: auxint,
Block: b,
Line: line,
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = auxint
v.Args = v.argstorage[:1]
v.Args[0] = arg
b.Values = append(b.Values, v)
v.argstorage[0] = arg
return v
}
// NewValue1A returns a new value in the block with one argument and an aux value.
func (b *Block) NewValue1A(line int32, op Op, t Type, aux interface{}, arg *Value) *Value {
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
Aux: aux,
Block: b,
Line: line,
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = 0
v.Aux = aux
v.Args = v.argstorage[:1]
v.Args[0] = arg
b.Values = append(b.Values, v)
v.argstorage[0] = arg
return v
}
// NewValue1IA returns a new value in the block with one argument and both an auxint and aux values.
func (b *Block) NewValue1IA(line int32, op Op, t Type, auxint int64, aux interface{}, arg *Value) *Value {
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
AuxInt: auxint,
Aux: aux,
Block: b,
Line: line,
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = auxint
v.Aux = aux
v.Args = v.argstorage[:1]
v.Args[0] = arg
b.Values = append(b.Values, v)
v.argstorage[0] = arg
return v
}
// NewValue2 returns a new value in the block with two arguments and zero aux values.
func (b *Block) NewValue2(line int32, op Op, t Type, arg0, arg1 *Value) *Value {
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
Block: b,
Line: line,
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = 0
v.Args = v.argstorage[:2]
v.Args[0] = arg0
v.Args[1] = arg1
b.Values = append(b.Values, v)
v.argstorage[0] = arg0
v.argstorage[1] = arg1
return v
}
// NewValue2I returns a new value in the block with two arguments and an auxint value.
func (b *Block) NewValue2I(line int32, op Op, t Type, aux int64, arg0, arg1 *Value) *Value {
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
AuxInt: aux,
Block: b,
Line: line,
}
func (b *Block) NewValue2I(line int32, op Op, t Type, auxint int64, arg0, arg1 *Value) *Value {
v := b.Func.newValue(op, t, b, line)
v.AuxInt = auxint
v.Args = v.argstorage[:2]
v.Args[0] = arg0
v.Args[1] = arg1
b.Values = append(b.Values, v)
v.argstorage[0] = arg0
v.argstorage[1] = arg1
return v
}
// NewValue3 returns a new value in the block with three arguments and zero aux values.
func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *Value {
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
Block: b,
Line: line,
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = 0
v.Args = []*Value{arg0, arg1, arg2}
b.Values = append(b.Values, v)
return v
}
// NewValue3I returns a new value in the block with three arguments and an auxint value.
func (b *Block) NewValue3I(line int32, op Op, t Type, aux int64, arg0, arg1, arg2 *Value) *Value {
v := &Value{
ID: b.Func.vid.get(),
Op: op,
Type: t,
AuxInt: aux,
Block: b,
Line: line,
}
func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1, arg2 *Value) *Value {
v := b.Func.newValue(op, t, b, line)
v.AuxInt = auxint
v.Args = []*Value{arg0, arg1, arg2}
b.Values = append(b.Values, v)
return v
}
@ -310,3 +262,32 @@ func (f *Func) Fatalf(msg string, args ...interface{}) { f.Config.Fatalf(f.Entry
func (f *Func) Unimplementedf(msg string, args ...interface{}) {
f.Config.Unimplementedf(f.Entry.Line, msg, args...)
}
func (f *Func) Free() {
// Clear values.
n := f.vid.num()
if n > len(f.Config.values) {
n = len(f.Config.values)
}
for i := 1; i < n; i++ {
f.Config.values[i] = Value{}
f.Config.values[i].ID = ID(i)
}
// Clear blocks.
n = f.bid.num()
if n > len(f.Config.blocks) {
n = len(f.Config.blocks)
}
for i := 1; i < n; i++ {
f.Config.blocks[i] = Block{}
f.Config.blocks[i].ID = ID(i)
}
// Unregister from config.
if f.Config.curFunc != f {
f.Fatalf("free of function which isn't the last one allocated")
}
f.Config.curFunc = nil
*f = Func{} // just in case
}