cmd/compile: pack bool fields in Node, Name, Func and Type structs to bitsets

This reduces compiler memory usage by up to 4% - see compilebench
results below.

name       old time/op     new time/op     delta
Template       245ms ± 4%      241ms ± 2%  -1.88%  (p=0.029 n=10+10)
Unicode        126ms ± 3%      124ms ± 3%    ~     (p=0.105 n=10+10)
GoTypes        805ms ± 2%      813ms ± 3%    ~     (p=0.515 n=8+10)
Compiler       3.95s ± 2%      3.83s ± 1%  -2.96%  (p=0.000 n=9+10)
MakeBash       47.4s ± 4%      46.6s ± 1%  -1.59%  (p=0.028 n=9+10)

name       old user-ns/op  new user-ns/op  delta
Template        324M ± 5%       326M ± 3%    ~     (p=0.935 n=10+10)
Unicode         186M ± 5%       178M ±10%    ~     (p=0.067 n=9+10)
GoTypes        1.08G ± 7%      1.09G ± 4%    ~     (p=0.956 n=10+10)
Compiler       5.34G ± 4%      5.31G ± 1%    ~     (p=0.501 n=10+8)

name       old alloc/op    new alloc/op    delta
Template      41.0MB ± 0%     39.8MB ± 0%  -3.03%  (p=0.000 n=10+10)
Unicode       32.3MB ± 0%     31.0MB ± 0%  -4.13%  (p=0.000 n=10+10)
GoTypes        119MB ± 0%      116MB ± 0%  -2.39%  (p=0.000 n=10+10)
Compiler       499MB ± 0%      487MB ± 0%  -2.48%  (p=0.000 n=10+10)

name       old allocs/op   new allocs/op   delta
Template        380k ± 1%       379k ± 1%    ~     (p=0.436 n=10+10)
Unicode         324k ± 1%       324k ± 0%    ~     (p=0.853 n=10+10)
GoTypes        1.15M ± 0%      1.15M ± 0%    ~     (p=0.481 n=10+10)
Compiler       4.41M ± 0%      4.41M ± 0%  -0.12%  (p=0.007 n=10+10)

name       old text-bytes  new text-bytes  delta
HelloSize       623k ± 0%       623k ± 0%    ~     (all equal)
CmdGoSize      6.64M ± 0%      6.64M ± 0%    ~     (all equal)

name       old data-bytes  new data-bytes  delta
HelloSize      5.81k ± 0%      5.81k ± 0%    ~     (all equal)
CmdGoSize       238k ± 0%       238k ± 0%    ~     (all equal)

name       old bss-bytes   new bss-bytes   delta
HelloSize       134k ± 0%       134k ± 0%    ~     (all equal)
CmdGoSize       152k ± 0%       152k ± 0%    ~     (all equal)

name       old exe-bytes   new exe-bytes   delta
HelloSize       967k ± 0%       967k ± 0%    ~     (all equal)
CmdGoSize      10.2M ± 0%      10.2M ± 0%    ~     (all equal)

Change-Id: I1f40af738254892bd6c8ba2eb43390b175753d52
Reviewed-on: https://go-review.googlesource.com/37445
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Aliaksandr Valialkin 2017-02-27 19:56:38 +02:00 committed by Matthew Dempsky
parent fbf4dd91b9
commit ed70f37e73
40 changed files with 610 additions and 524 deletions

View file

@ -49,31 +49,20 @@ type Node struct {
Pos src.XPos
flags bitset16
Esc uint16 // EscXXX
Op Op
Ullman uint8 // sethi/ullman number
Addable bool // addressable
Etype EType // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg, ChanDir for OTCHAN, for OINDEXMAP 1=LHS,0=RHS
Bounded bool // bounds check unnecessary
NonNil bool // guaranteed to be non-nil
Class Class // PPARAM, PAUTO, PEXTERN, etc
Embedded uint8 // ODCLFIELD embedded type
Colas bool // OAS resulting from :=
Diag bool // already printed error about this
Noescape bool // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
Walkdef uint8 // tracks state during typecheckdef; 2 == loop detected
Typecheck uint8 // tracks state during typechecking; 2 == loop detected
Local bool // type created in this file (see also Type.Local); TODO(gri): move this into flags
Initorder uint8
Used bool // for variable/label declared and not used error
Isddd bool // is the argument variadic
Implicit bool
Addrtaken bool // address taken, even if not moved to heap
Assigned bool // is the variable ever assigned to
Likely int8 // likeliness of if statement
hasVal int8 // +1 for Val, -1 for Opt, 0 for not yet set
flags uint8 // TODO: store more bool fields in this flag field
Likely int8 // likeliness of if statement
hasVal int8 // +1 for Val, -1 for Opt, 0 for not yet set
}
// IsAutoTmp indicates if n was created by the compiler as a temporary,
@ -82,57 +71,61 @@ func (n *Node) IsAutoTmp() bool {
if n == nil || n.Op != ONAME {
return false
}
return n.Name.AutoTemp
return n.Name.AutoTemp()
}
const (
hasBreak = 1 << iota
isClosureVar
isOutputParamHeapAddr
noInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
nodeHasBreak = 1 << iota
nodeIsClosureVar
nodeIsOutputParamHeapAddr
nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
nodeAssigned // is the variable ever assigned to
nodeAddrtaken // address taken, even if not moved to heap
nodeImplicit
nodeIsddd // is the argument variadic
nodeLocal // type created in this file (see also Type.Local)
nodeDiag // already printed error about this
nodeColas // OAS resulting from :=
nodeNonNil // guaranteed to be non-nil
nodeNoescape // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
nodeBounded // bounds check unnecessary
nodeAddable // addressable
nodeUsed // for variable/label declared and not used error
)
func (n *Node) HasBreak() bool {
return n.flags&hasBreak != 0
}
func (n *Node) SetHasBreak(b bool) {
if b {
n.flags |= hasBreak
} else {
n.flags &^= hasBreak
}
}
func (n *Node) isClosureVar() bool {
return n.flags&isClosureVar != 0
}
func (n *Node) setIsClosureVar(b bool) {
if b {
n.flags |= isClosureVar
} else {
n.flags &^= isClosureVar
}
}
func (n *Node) noInline() bool {
return n.flags&noInline != 0
}
func (n *Node) setNoInline(b bool) {
if b {
n.flags |= noInline
} else {
n.flags &^= noInline
}
}
func (n *Node) HasBreak() bool { return n.flags&nodeHasBreak != 0 }
func (n *Node) IsClosureVar() bool { return n.flags&nodeIsClosureVar != 0 }
func (n *Node) NoInline() bool { return n.flags&nodeNoInline != 0 }
func (n *Node) IsOutputParamHeapAddr() bool { return n.flags&nodeIsOutputParamHeapAddr != 0 }
func (n *Node) Assigned() bool { return n.flags&nodeAssigned != 0 }
func (n *Node) Addrtaken() bool { return n.flags&nodeAddrtaken != 0 }
func (n *Node) Implicit() bool { return n.flags&nodeImplicit != 0 }
func (n *Node) Isddd() bool { return n.flags&nodeIsddd != 0 }
func (n *Node) Local() bool { return n.flags&nodeLocal != 0 }
func (n *Node) Diag() bool { return n.flags&nodeDiag != 0 }
func (n *Node) Colas() bool { return n.flags&nodeColas != 0 }
func (n *Node) NonNil() bool { return n.flags&nodeNonNil != 0 }
func (n *Node) Noescape() bool { return n.flags&nodeNoescape != 0 }
func (n *Node) Bounded() bool { return n.flags&nodeBounded != 0 }
func (n *Node) Addable() bool { return n.flags&nodeAddable != 0 }
func (n *Node) Used() bool { return n.flags&nodeUsed != 0 }
func (n *Node) IsOutputParamHeapAddr() bool {
return n.flags&isOutputParamHeapAddr != 0
}
func (n *Node) setIsOutputParamHeapAddr(b bool) {
if b {
n.flags |= isOutputParamHeapAddr
} else {
n.flags &^= isOutputParamHeapAddr
}
}
func (n *Node) SetHasBreak(b bool) { n.flags.set(nodeHasBreak, b) }
func (n *Node) SetIsClosureVar(b bool) { n.flags.set(nodeIsClosureVar, b) }
func (n *Node) SetNoInline(b bool) { n.flags.set(nodeNoInline, b) }
func (n *Node) SetIsOutputParamHeapAddr(b bool) { n.flags.set(nodeIsOutputParamHeapAddr, b) }
func (n *Node) SetAssigned(b bool) { n.flags.set(nodeAssigned, b) }
func (n *Node) SetAddrtaken(b bool) { n.flags.set(nodeAddrtaken, b) }
func (n *Node) SetImplicit(b bool) { n.flags.set(nodeImplicit, b) }
func (n *Node) SetIsddd(b bool) { n.flags.set(nodeIsddd, b) }
func (n *Node) SetLocal(b bool) { n.flags.set(nodeLocal, b) }
func (n *Node) SetDiag(b bool) { n.flags.set(nodeDiag, b) }
func (n *Node) SetColas(b bool) { n.flags.set(nodeColas, b) }
func (n *Node) SetNonNil(b bool) { n.flags.set(nodeNonNil, b) }
func (n *Node) SetNoescape(b bool) { n.flags.set(nodeNoescape, b) }
func (n *Node) SetBounded(b bool) { n.flags.set(nodeBounded, b) }
func (n *Node) SetAddable(b bool) { n.flags.set(nodeAddable, b) }
func (n *Node) SetUsed(b bool) { n.flags.set(nodeUsed, b) }
// Val returns the Val for the node.
func (n *Node) Val() Val {
@ -194,14 +187,33 @@ type Name struct {
Decldepth int32 // declaration loop depth, increased for every loop or label
Vargen int32 // unique name for ONAME within a function. Function outputs are numbered starting at one.
Funcdepth int32
Readonly bool
Captured bool // is the variable captured by a closure
Byval bool // is the variable captured by value or by reference
Needzero bool // if it contains pointers, needs to be zeroed on function entry
Keepalive bool // mark value live across unknown assembly call
AutoTemp bool // is the variable a temporary (implies no dwarf info. reset if escapes to heap)
flags bitset8
}
const (
nameCaptured = 1 << iota // is the variable captured by a closure
nameReadonly
nameByval // is the variable captured by value or by reference
nameNeedzero // if it contains pointers, needs to be zeroed on function entry
nameKeepalive // mark value live across unknown assembly call
nameAutoTemp // is the variable a temporary (implies no dwarf info. reset if escapes to heap)
)
func (n *Name) Captured() bool { return n.flags&nameCaptured != 0 }
func (n *Name) Readonly() bool { return n.flags&nameReadonly != 0 }
func (n *Name) Byval() bool { return n.flags&nameByval != 0 }
func (n *Name) Needzero() bool { return n.flags&nameNeedzero != 0 }
func (n *Name) Keepalive() bool { return n.flags&nameKeepalive != 0 }
func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 }
func (n *Name) SetCaptured(b bool) { n.flags.set(nameCaptured, b) }
func (n *Name) SetReadonly(b bool) { n.flags.set(nameReadonly, b) }
func (n *Name) SetByval(b bool) { n.flags.set(nameByval, b) }
func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) }
func (n *Name) SetKeepalive(b bool) { n.flags.set(nameKeepalive, b) }
func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) }
type Param struct {
Ntype *Node
Heapaddr *Node // temp holding heap address of param
@ -239,10 +251,10 @@ type Param struct {
//
// - x1.Defn = original declaration statement for x (like most variables)
// - x1.Innermost = current innermost closure x (in this case x3), or nil for none
// - x1.isClosureVar() = false
// - x1.IsClosureVar() = false
//
// - xN.Defn = x1, N > 1
// - xN.isClosureVar() = true, N > 1
// - xN.IsClosureVar() = true, N > 1
// - x2.Outer = nil
// - xN.Outer = x(N-1), N > 2
//
@ -316,15 +328,34 @@ type Func struct {
Endlineno src.XPos
WBPos src.XPos // position of first write barrier
Pragma syntax.Pragma // go:xxx function annotations
Dupok bool // duplicate definitions ok
Wrapper bool // is method wrapper
Needctxt bool // function uses context register (has closure variables)
ReflectMethod bool // function calls reflect.Type.Method or MethodByName
IsHiddenClosure bool
NoFramePointer bool // Must not use a frame pointer for this function
Pragma syntax.Pragma // go:xxx function annotations
flags bitset8
}
const (
funcDupok = 1 << iota // duplicate definitions ok
funcWrapper // is method wrapper
funcNeedctxt // function uses context register (has closure variables)
funcReflectMethod // function calls reflect.Type.Method or MethodByName
funcIsHiddenClosure
funcNoFramePointer // Must not use a frame pointer for this function
)
func (f *Func) Dupok() bool { return f.flags&funcDupok != 0 }
func (f *Func) Wrapper() bool { return f.flags&funcWrapper != 0 }
func (f *Func) Needctxt() bool { return f.flags&funcNeedctxt != 0 }
func (f *Func) ReflectMethod() bool { return f.flags&funcReflectMethod != 0 }
func (f *Func) IsHiddenClosure() bool { return f.flags&funcIsHiddenClosure != 0 }
func (f *Func) NoFramePointer() bool { return f.flags&funcNoFramePointer != 0 }
func (f *Func) SetDupok(b bool) { f.flags.set(funcDupok, b) }
func (f *Func) SetWrapper(b bool) { f.flags.set(funcWrapper, b) }
func (f *Func) SetNeedctxt(b bool) { f.flags.set(funcNeedctxt, b) }
func (f *Func) SetReflectMethod(b bool) { f.flags.set(funcReflectMethod, b) }
func (f *Func) SetIsHiddenClosure(b bool) { f.flags.set(funcIsHiddenClosure, b) }
func (f *Func) SetNoFramePointer(b bool) { f.flags.set(funcNoFramePointer, b) }
type Op uint8
// Node ops.