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
|
|
@ -41,11 +41,11 @@ func (s *state) insertPhis() {
|
|||
}
|
||||
|
||||
type phiState struct {
|
||||
s *state // SSA state
|
||||
f *ssa.Func // function to work on
|
||||
defvars []map[*ir.Node]*ssa.Value // defined variables at end of each block
|
||||
s *state // SSA state
|
||||
f *ssa.Func // function to work on
|
||||
defvars []map[ir.Node]*ssa.Value // defined variables at end of each block
|
||||
|
||||
varnum map[*ir.Node]int32 // variable numbering
|
||||
varnum map[ir.Node]int32 // variable numbering
|
||||
|
||||
// properties of the dominator tree
|
||||
idom []*ssa.Block // dominator parents
|
||||
|
|
@ -71,15 +71,15 @@ func (s *phiState) insertPhis() {
|
|||
// Find all the variables for which we need to match up reads & writes.
|
||||
// This step prunes any basic-block-only variables from consideration.
|
||||
// Generate a numbering for these variables.
|
||||
s.varnum = map[*ir.Node]int32{}
|
||||
var vars []*ir.Node
|
||||
s.varnum = map[ir.Node]int32{}
|
||||
var vars []ir.Node
|
||||
var vartypes []*types.Type
|
||||
for _, b := range s.f.Blocks {
|
||||
for _, v := range b.Values {
|
||||
if v.Op != ssa.OpFwdRef {
|
||||
continue
|
||||
}
|
||||
var_ := v.Aux.(*ir.Node)
|
||||
var_ := v.Aux.(ir.Node)
|
||||
|
||||
// Optimization: look back 1 block for the definition.
|
||||
if len(b.Preds) == 1 {
|
||||
|
|
@ -184,7 +184,7 @@ levels:
|
|||
}
|
||||
}
|
||||
|
||||
func (s *phiState) insertVarPhis(n int, var_ *ir.Node, defs []*ssa.Block, typ *types.Type) {
|
||||
func (s *phiState) insertVarPhis(n int, var_ ir.Node, defs []*ssa.Block, typ *types.Type) {
|
||||
priq := &s.priq
|
||||
q := s.q
|
||||
queued := s.queued
|
||||
|
|
@ -319,7 +319,7 @@ func (s *phiState) resolveFwdRefs() {
|
|||
if v.Op != ssa.OpFwdRef {
|
||||
continue
|
||||
}
|
||||
n := s.varnum[v.Aux.(*ir.Node)]
|
||||
n := s.varnum[v.Aux.(ir.Node)]
|
||||
v.Op = ssa.OpCopy
|
||||
v.Aux = nil
|
||||
v.AddArg(values[n])
|
||||
|
|
@ -433,11 +433,11 @@ func (s *sparseSet) clear() {
|
|||
|
||||
// Variant to use for small functions.
|
||||
type simplePhiState struct {
|
||||
s *state // SSA state
|
||||
f *ssa.Func // function to work on
|
||||
fwdrefs []*ssa.Value // list of FwdRefs to be processed
|
||||
defvars []map[*ir.Node]*ssa.Value // defined variables at end of each block
|
||||
reachable []bool // which blocks are reachable
|
||||
s *state // SSA state
|
||||
f *ssa.Func // function to work on
|
||||
fwdrefs []*ssa.Value // list of FwdRefs to be processed
|
||||
defvars []map[ir.Node]*ssa.Value // defined variables at end of each block
|
||||
reachable []bool // which blocks are reachable
|
||||
}
|
||||
|
||||
func (s *simplePhiState) insertPhis() {
|
||||
|
|
@ -450,7 +450,7 @@ func (s *simplePhiState) insertPhis() {
|
|||
continue
|
||||
}
|
||||
s.fwdrefs = append(s.fwdrefs, v)
|
||||
var_ := v.Aux.(*ir.Node)
|
||||
var_ := v.Aux.(ir.Node)
|
||||
if _, ok := s.defvars[b.ID][var_]; !ok {
|
||||
s.defvars[b.ID][var_] = v // treat FwdDefs as definitions.
|
||||
}
|
||||
|
|
@ -464,7 +464,7 @@ loop:
|
|||
v := s.fwdrefs[len(s.fwdrefs)-1]
|
||||
s.fwdrefs = s.fwdrefs[:len(s.fwdrefs)-1]
|
||||
b := v.Block
|
||||
var_ := v.Aux.(*ir.Node)
|
||||
var_ := v.Aux.(ir.Node)
|
||||
if b == s.f.Entry {
|
||||
// No variable should be live at entry.
|
||||
s.s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, var_, v)
|
||||
|
|
@ -512,7 +512,7 @@ loop:
|
|||
}
|
||||
|
||||
// lookupVarOutgoing finds the variable's value at the end of block b.
|
||||
func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t *types.Type, var_ *ir.Node, line src.XPos) *ssa.Value {
|
||||
func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t *types.Type, var_ ir.Node, line src.XPos) *ssa.Value {
|
||||
for {
|
||||
if v := s.defvars[b.ID][var_]; v != nil {
|
||||
return v
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue