mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.regabi] cmd/compile: replace *Node type with an interface Node [generated]
The plan is to introduce a Node interface that replaces the old *Node pointer-to-struct.
The previous CL defined an interface INode modeling a *Node.
This CL:
- Changes all references outside internal/ir to use INode,
along with many references inside internal/ir as well.
- Renames Node to node.
- Renames INode to Node
So now ir.Node is an interface implemented by *ir.node, which is otherwise inaccessible,
and the code outside package ir is now (clearly) using only the interface.
The usual rule is never to redefine an existing name with a new meaning,
so that old code that hasn't been updated gets a "unknown name" error
instead of more mysterious errors or silent misbehavior. That rule would
caution against replacing Node-the-struct with Node-the-interface,
as in this CL, because code that says *Node would now be using a pointer
to an interface. But this CL is being landed at the same time as another that
moves Node from gc to ir. So the net effect is to replace *gc.Node with ir.Node,
which does follow the rule: any lingering references to gc.Node will be told
it's gone, not silently start using pointers to interfaces. So the rule is followed
by the CL sequence, just not this specific CL.
Overall, the loss of inlining caused by using interfaces cuts the compiler speed
by about 6%, a not insignificant amount. However, as we convert the representation
to concrete structs that are not the giant Node over the next weeks, that speed
should come back as more of the compiler starts operating directly on concrete types
and the memory taken up by the graph of Nodes drops due to the more precise
structs. Honestly, I was expecting worse.
% benchstat bench.old bench.new
name old time/op new time/op delta
Template 168ms ± 4% 182ms ± 2% +8.34% (p=0.000 n=9+9)
Unicode 72.2ms ±10% 82.5ms ± 6% +14.38% (p=0.000 n=9+9)
GoTypes 563ms ± 8% 598ms ± 2% +6.14% (p=0.006 n=9+9)
Compiler 2.89s ± 4% 3.04s ± 2% +5.37% (p=0.000 n=10+9)
SSA 6.45s ± 4% 7.25s ± 5% +12.41% (p=0.000 n=9+10)
Flate 105ms ± 2% 115ms ± 1% +9.66% (p=0.000 n=10+8)
GoParser 144ms ±10% 152ms ± 2% +5.79% (p=0.011 n=9+8)
Reflect 345ms ± 9% 370ms ± 4% +7.28% (p=0.001 n=10+9)
Tar 149ms ± 9% 161ms ± 5% +8.05% (p=0.001 n=10+9)
XML 190ms ± 3% 209ms ± 2% +9.54% (p=0.000 n=9+8)
LinkCompiler 327ms ± 2% 325ms ± 2% ~ (p=0.382 n=8+8)
ExternalLinkCompiler 1.77s ± 4% 1.73s ± 6% ~ (p=0.113 n=9+10)
LinkWithoutDebugCompiler 214ms ± 4% 211ms ± 2% ~ (p=0.360 n=10+8)
StdCmd 14.8s ± 3% 15.9s ± 1% +6.98% (p=0.000 n=10+9)
[Geo mean] 480ms 510ms +6.31%
name old user-time/op new user-time/op delta
Template 223ms ± 3% 237ms ± 3% +6.16% (p=0.000 n=9+10)
Unicode 103ms ± 6% 113ms ± 3% +9.53% (p=0.000 n=9+9)
GoTypes 758ms ± 8% 800ms ± 2% +5.55% (p=0.003 n=10+9)
Compiler 3.95s ± 2% 4.12s ± 2% +4.34% (p=0.000 n=10+9)
SSA 9.43s ± 1% 9.74s ± 4% +3.25% (p=0.000 n=8+10)
Flate 132ms ± 2% 141ms ± 2% +6.89% (p=0.000 n=9+9)
GoParser 177ms ± 9% 183ms ± 4% ~ (p=0.050 n=9+9)
Reflect 467ms ±10% 495ms ± 7% +6.17% (p=0.029 n=10+10)
Tar 183ms ± 9% 197ms ± 5% +7.92% (p=0.001 n=10+10)
XML 249ms ± 5% 268ms ± 4% +7.82% (p=0.000 n=10+9)
LinkCompiler 544ms ± 5% 544ms ± 6% ~ (p=0.863 n=9+9)
ExternalLinkCompiler 1.79s ± 4% 1.75s ± 6% ~ (p=0.075 n=10+10)
LinkWithoutDebugCompiler 248ms ± 6% 246ms ± 2% ~ (p=0.965 n=10+8)
[Geo mean] 483ms 504ms +4.41%
[git-generate]
cd src/cmd/compile/internal/ir
: # We need to do the conversion in multiple steps, so we introduce
: # a temporary type alias that will start out meaning the pointer-to-struct
: # and then change to mean the interface.
rf '
mv Node OldNode
add node.go \
type Node = *OldNode
'
: # It should work to do this ex in ir, but it misses test files, due to a bug in rf.
: # Run the command in gc to handle gc's tests, and then again in ssa for ssa's tests.
cd ../gc
rf '
ex . ../arm ../riscv64 ../arm64 ../mips64 ../ppc64 ../mips ../wasm {
import "cmd/compile/internal/ir"
*ir.OldNode -> ir.Node
}
'
cd ../ssa
rf '
ex {
import "cmd/compile/internal/ir"
*ir.OldNode -> ir.Node
}
'
: # Back in ir, finish conversion clumsily with sed,
: # because type checking and circular aliases do not mix.
cd ../ir
sed -i '' '
/type Node = \*OldNode/d
s/\*OldNode/Node/g
s/^func (n Node)/func (n *OldNode)/
s/OldNode/node/g
s/type INode interface/type Node interface/
s/var _ INode = (Node)(nil)/var _ Node = (*node)(nil)/
' *.go
gofmt -w *.go
sed -i '' '
s/{Func{}, 136, 248}/{Func{}, 152, 280}/
s/{Name{}, 32, 56}/{Name{}, 44, 80}/
s/{Param{}, 24, 48}/{Param{}, 44, 88}/
s/{node{}, 76, 128}/{node{}, 88, 152}/
' sizeof_test.go
cd ../ssa
sed -i '' '
s/{LocalSlot{}, 28, 40}/{LocalSlot{}, 32, 48}/
' sizeof_test.go
cd ../gc
sed -i '' 's/\*ir.Node/ir.Node/' mkbuiltin.go
cd ../../../..
go install std cmd
cd cmd/compile
go test -u || go test -u
Change-Id: I196bbe3b648e4701662e4a2bada40bf155e2a553
Reviewed-on: https://go-review.googlesource.com/c/go/+/272935
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
4d0d9c2c5c
commit
41f3af9d04
62 changed files with 1273 additions and 1272 deletions
|
|
@ -24,10 +24,10 @@ import (
|
|||
// "Portable" code generation.
|
||||
|
||||
var (
|
||||
compilequeue []*ir.Node // functions waiting to be compiled
|
||||
compilequeue []ir.Node // functions waiting to be compiled
|
||||
)
|
||||
|
||||
func emitptrargsmap(fn *ir.Node) {
|
||||
func emitptrargsmap(fn ir.Node) {
|
||||
if ir.FuncName(fn) == "_" || fn.Func().Nname.Sym().Linkname != "" {
|
||||
return
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ func emitptrargsmap(fn *ir.Node) {
|
|||
// really means, in memory, things with pointers needing zeroing at
|
||||
// the top of the stack and increasing in size.
|
||||
// Non-autos sort on offset.
|
||||
func cmpstackvarlt(a, b *ir.Node) bool {
|
||||
func cmpstackvarlt(a, b ir.Node) bool {
|
||||
if (a.Class() == ir.PAUTO) != (b.Class() == ir.PAUTO) {
|
||||
return b.Class() == ir.PAUTO
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ func cmpstackvarlt(a, b *ir.Node) bool {
|
|||
}
|
||||
|
||||
// byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
|
||||
type byStackVar []*ir.Node
|
||||
type byStackVar []ir.Node
|
||||
|
||||
func (s byStackVar) Len() int { return len(s) }
|
||||
func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
|
||||
|
|
@ -128,7 +128,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
|
|||
scratchUsed := false
|
||||
for _, b := range f.Blocks {
|
||||
for _, v := range b.Values {
|
||||
if n, ok := v.Aux.(*ir.Node); ok {
|
||||
if n, ok := v.Aux.(ir.Node); ok {
|
||||
switch n.Class() {
|
||||
case ir.PPARAM, ir.PPARAMOUT:
|
||||
// Don't modify nodfp; it is a global.
|
||||
|
|
@ -193,7 +193,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
|
|||
s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
|
||||
}
|
||||
|
||||
func funccompile(fn *ir.Node) {
|
||||
func funccompile(fn ir.Node) {
|
||||
if Curfn != nil {
|
||||
base.Fatalf("funccompile %v inside %v", fn.Func().Nname.Sym(), Curfn.Func().Nname.Sym())
|
||||
}
|
||||
|
|
@ -224,7 +224,7 @@ func funccompile(fn *ir.Node) {
|
|||
dclcontext = ir.PEXTERN
|
||||
}
|
||||
|
||||
func compile(fn *ir.Node) {
|
||||
func compile(fn ir.Node) {
|
||||
errorsBefore := base.Errors()
|
||||
order(fn)
|
||||
if base.Errors() > errorsBefore {
|
||||
|
|
@ -284,7 +284,7 @@ func compile(fn *ir.Node) {
|
|||
// If functions are not compiled immediately,
|
||||
// they are enqueued in compilequeue,
|
||||
// which is drained by compileFunctions.
|
||||
func compilenow(fn *ir.Node) bool {
|
||||
func compilenow(fn ir.Node) bool {
|
||||
// Issue 38068: if this function is a method AND an inline
|
||||
// candidate AND was not inlined (yet), put it onto the compile
|
||||
// queue instead of compiling it immediately. This is in case we
|
||||
|
|
@ -299,7 +299,7 @@ func compilenow(fn *ir.Node) bool {
|
|||
// isInlinableButNotInlined returns true if 'fn' was marked as an
|
||||
// inline candidate but then never inlined (presumably because we
|
||||
// found no call sites).
|
||||
func isInlinableButNotInlined(fn *ir.Node) bool {
|
||||
func isInlinableButNotInlined(fn ir.Node) bool {
|
||||
if fn.Func().Nname.Func().Inl == nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -315,7 +315,7 @@ const maxStackSize = 1 << 30
|
|||
// uses it to generate a plist,
|
||||
// and flushes that plist to machine code.
|
||||
// worker indicates which of the backend workers is doing the processing.
|
||||
func compileSSA(fn *ir.Node, worker int) {
|
||||
func compileSSA(fn ir.Node, worker int) {
|
||||
f := buildssa(fn, worker)
|
||||
// Note: check arg size to fix issue 25507.
|
||||
if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type().ArgWidth() >= maxStackSize {
|
||||
|
|
@ -360,7 +360,7 @@ func compileFunctions() {
|
|||
sizeCalculationDisabled = true // not safe to calculate sizes concurrently
|
||||
if race.Enabled {
|
||||
// Randomize compilation order to try to shake out races.
|
||||
tmp := make([]*ir.Node, len(compilequeue))
|
||||
tmp := make([]ir.Node, len(compilequeue))
|
||||
perm := rand.Perm(len(compilequeue))
|
||||
for i, v := range perm {
|
||||
tmp[v] = compilequeue[i]
|
||||
|
|
@ -376,7 +376,7 @@ func compileFunctions() {
|
|||
}
|
||||
var wg sync.WaitGroup
|
||||
base.Ctxt.InParallel = true
|
||||
c := make(chan *ir.Node, base.Flag.LowerC)
|
||||
c := make(chan ir.Node, base.Flag.LowerC)
|
||||
for i := 0; i < base.Flag.LowerC; i++ {
|
||||
wg.Add(1)
|
||||
go func(worker int) {
|
||||
|
|
@ -398,7 +398,7 @@ func compileFunctions() {
|
|||
}
|
||||
|
||||
func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) {
|
||||
fn := curfn.(*ir.Node)
|
||||
fn := curfn.(ir.Node)
|
||||
if fn.Func().Nname != nil {
|
||||
if expect := fn.Func().Nname.Sym().Linksym(); fnsym != expect {
|
||||
base.Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
|
||||
|
|
@ -432,7 +432,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
|
|||
// Deciding the right answer is, as they say, future work.
|
||||
isODCLFUNC := fn.Op() == ir.ODCLFUNC
|
||||
|
||||
var apdecls []*ir.Node
|
||||
var apdecls []ir.Node
|
||||
// Populate decls for fn.
|
||||
if isODCLFUNC {
|
||||
for _, n := range fn.Func().Dcl {
|
||||
|
|
@ -489,7 +489,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
|
|||
return scopes, inlcalls
|
||||
}
|
||||
|
||||
func declPos(decl *ir.Node) src.XPos {
|
||||
func declPos(decl ir.Node) src.XPos {
|
||||
if decl.Name().Defn != nil && (decl.Name().Captured() || decl.Name().Byval()) {
|
||||
// It's not clear which position is correct for captured variables here:
|
||||
// * decl.Pos is the wrong position for captured variables, in the inner
|
||||
|
|
@ -512,10 +512,10 @@ func declPos(decl *ir.Node) src.XPos {
|
|||
|
||||
// createSimpleVars creates a DWARF entry for every variable declared in the
|
||||
// function, claiming that they are permanently on the stack.
|
||||
func createSimpleVars(fnsym *obj.LSym, apDecls []*ir.Node) ([]*ir.Node, []*dwarf.Var, map[*ir.Node]bool) {
|
||||
func createSimpleVars(fnsym *obj.LSym, apDecls []ir.Node) ([]ir.Node, []*dwarf.Var, map[ir.Node]bool) {
|
||||
var vars []*dwarf.Var
|
||||
var decls []*ir.Node
|
||||
selected := make(map[*ir.Node]bool)
|
||||
var decls []ir.Node
|
||||
selected := make(map[ir.Node]bool)
|
||||
for _, n := range apDecls {
|
||||
if ir.IsAutoTmp(n) {
|
||||
continue
|
||||
|
|
@ -528,7 +528,7 @@ func createSimpleVars(fnsym *obj.LSym, apDecls []*ir.Node) ([]*ir.Node, []*dwarf
|
|||
return decls, vars, selected
|
||||
}
|
||||
|
||||
func createSimpleVar(fnsym *obj.LSym, n *ir.Node) *dwarf.Var {
|
||||
func createSimpleVar(fnsym *obj.LSym, n ir.Node) *dwarf.Var {
|
||||
var abbrev int
|
||||
offs := n.Offset()
|
||||
|
||||
|
|
@ -579,13 +579,13 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Node) *dwarf.Var {
|
|||
|
||||
// createComplexVars creates recomposed DWARF vars with location lists,
|
||||
// suitable for describing optimized code.
|
||||
func createComplexVars(fnsym *obj.LSym, fn *ir.Func) ([]*ir.Node, []*dwarf.Var, map[*ir.Node]bool) {
|
||||
func createComplexVars(fnsym *obj.LSym, fn *ir.Func) ([]ir.Node, []*dwarf.Var, map[ir.Node]bool) {
|
||||
debugInfo := fn.DebugInfo.(*ssa.FuncDebug)
|
||||
|
||||
// Produce a DWARF variable entry for each user variable.
|
||||
var decls []*ir.Node
|
||||
var decls []ir.Node
|
||||
var vars []*dwarf.Var
|
||||
ssaVars := make(map[*ir.Node]bool)
|
||||
ssaVars := make(map[ir.Node]bool)
|
||||
|
||||
for varID, dvar := range debugInfo.Vars {
|
||||
n := dvar
|
||||
|
|
@ -605,11 +605,11 @@ func createComplexVars(fnsym *obj.LSym, fn *ir.Func) ([]*ir.Node, []*dwarf.Var,
|
|||
|
||||
// createDwarfVars process fn, returning a list of DWARF variables and the
|
||||
// Nodes they represent.
|
||||
func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir.Node) ([]*ir.Node, []*dwarf.Var) {
|
||||
func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []ir.Node) ([]ir.Node, []*dwarf.Var) {
|
||||
// Collect a raw list of DWARF vars.
|
||||
var vars []*dwarf.Var
|
||||
var decls []*ir.Node
|
||||
var selected map[*ir.Node]bool
|
||||
var decls []ir.Node
|
||||
var selected map[ir.Node]bool
|
||||
if base.Ctxt.Flag_locationlists && base.Ctxt.Flag_optimize && fn.DebugInfo != nil && complexOK {
|
||||
decls, vars, selected = createComplexVars(fnsym, fn)
|
||||
} else {
|
||||
|
|
@ -708,9 +708,9 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
|
|||
// function that is not local to the package being compiled, then the
|
||||
// names of the variables may have been "versioned" to avoid conflicts
|
||||
// with local vars; disregard this versioning when sorting.
|
||||
func preInliningDcls(fnsym *obj.LSym) []*ir.Node {
|
||||
fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*ir.Node)
|
||||
var rdcl []*ir.Node
|
||||
func preInliningDcls(fnsym *obj.LSym) []ir.Node {
|
||||
fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(ir.Node)
|
||||
var rdcl []ir.Node
|
||||
for _, n := range fn.Func().Inl.Dcl {
|
||||
c := n.Sym().Name[0]
|
||||
// Avoid reporting "_" parameters, since if there are more than
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue