mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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:
parent
fbf4dd91b9
commit
ed70f37e73
40 changed files with 610 additions and 524 deletions
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue