summaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/gc/subr.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2020-11-25 01:11:56 -0500
committerRuss Cox <rsc@golang.org>2020-11-25 17:30:43 +0000
commit41f3af9d04362a56c1af186af134c704a03fa97b (patch)
treee67e7c1b67dd5c48a4c18fdb2f973bf789c7b2d1 /src/cmd/compile/internal/gc/subr.go
parent4d0d9c2c5c35377b0662f2fd0995867919552251 (diff)
downloadgo-git-41f3af9d04362a56c1af186af134c704a03fa97b.tar.gz
[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>
Diffstat (limited to 'src/cmd/compile/internal/gc/subr.go')
-rw-r--r--src/cmd/compile/internal/gc/subr.go74
1 files changed, 37 insertions, 37 deletions
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 542dc49bb0..fcda219737 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -40,7 +40,7 @@ var (
// It's primarily used to distinguish references to named objects,
// whose Pos will point back to their declaration position rather than
// their usage position.
-func hasUniquePos(n *ir.Node) bool {
+func hasUniquePos(n ir.Node) bool {
switch n.Op() {
case ir.ONAME, ir.OPACK:
return false
@@ -60,7 +60,7 @@ func hasUniquePos(n *ir.Node) bool {
return true
}
-func setlineno(n *ir.Node) src.XPos {
+func setlineno(n ir.Node) src.XPos {
lno := base.Pos
if n != nil && hasUniquePos(n) {
base.Pos = n.Pos()
@@ -102,7 +102,7 @@ func autolabel(prefix string) *types.Sym {
// find all the exported symbols in package opkg
// and make them available in the current package
-func importdot(opkg *types.Pkg, pack *ir.Node) {
+func importdot(opkg *types.Pkg, pack ir.Node) {
n := 0
for _, s := range opkg.Syms {
if s.Def == nil {
@@ -136,7 +136,7 @@ func importdot(opkg *types.Pkg, pack *ir.Node) {
}
// newname returns a new ONAME Node associated with symbol s.
-func NewName(s *types.Sym) *ir.Node {
+func NewName(s *types.Sym) ir.Node {
n := ir.NewNameAt(base.Pos, s)
n.Name().Curfn = Curfn
return n
@@ -144,13 +144,13 @@ func NewName(s *types.Sym) *ir.Node {
// nodSym makes a Node with Op op and with the Left field set to left
// and the Sym field set to sym. This is for ODOT and friends.
-func nodSym(op ir.Op, left *ir.Node, sym *types.Sym) *ir.Node {
+func nodSym(op ir.Op, left ir.Node, sym *types.Sym) ir.Node {
return nodlSym(base.Pos, op, left, sym)
}
// nodlSym makes a Node with position Pos, with Op op, and with the Left field set to left
// and the Sym field set to sym. This is for ODOT and friends.
-func nodlSym(pos src.XPos, op ir.Op, left *ir.Node, sym *types.Sym) *ir.Node {
+func nodlSym(pos src.XPos, op ir.Op, left ir.Node, sym *types.Sym) ir.Node {
n := ir.NodAt(pos, op, left, nil)
n.SetSym(sym)
return n
@@ -163,21 +163,21 @@ func (x methcmp) Len() int { return len(x) }
func (x methcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x methcmp) Less(i, j int) bool { return x[i].Sym.Less(x[j].Sym) }
-func nodintconst(v int64) *ir.Node {
+func nodintconst(v int64) ir.Node {
return ir.NewLiteral(constant.MakeInt64(v))
}
-func nodnil() *ir.Node {
+func nodnil() ir.Node {
n := ir.Nod(ir.ONIL, nil, nil)
n.SetType(types.Types[types.TNIL])
return n
}
-func nodbool(b bool) *ir.Node {
+func nodbool(b bool) ir.Node {
return ir.NewLiteral(constant.MakeBool(b))
}
-func nodstr(s string) *ir.Node {
+func nodstr(s string) ir.Node {
return ir.NewLiteral(constant.MakeString(s))
}
@@ -185,7 +185,7 @@ func nodstr(s string) *ir.Node {
// ONAME, OLITERAL, OTYPE, and ONONAME leaves.
// If pos.IsKnown(), it sets the source position of newly
// allocated nodes to pos.
-func treecopy(n *ir.Node, pos src.XPos) *ir.Node {
+func treecopy(n ir.Node, pos src.XPos) ir.Node {
if n == nil {
return nil
}
@@ -511,12 +511,12 @@ func convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
return ir.OXXX, ""
}
-func assignconv(n *ir.Node, t *types.Type, context string) *ir.Node {
+func assignconv(n ir.Node, t *types.Type, context string) ir.Node {
return assignconvfn(n, t, func() string { return context })
}
// Convert node n for assignment to type t.
-func assignconvfn(n *ir.Node, t *types.Type, context func() string) *ir.Node {
+func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node {
if n == nil || n.Type() == nil || n.Type().Broke() {
return n
}
@@ -565,7 +565,7 @@ func assignconvfn(n *ir.Node, t *types.Type, context func() string) *ir.Node {
// backingArrayPtrLen extracts the pointer and length from a slice or string.
// This constructs two nodes referring to n, so n must be a cheapexpr.
-func backingArrayPtrLen(n *ir.Node) (ptr, len *ir.Node) {
+func backingArrayPtrLen(n ir.Node) (ptr, len ir.Node) {
var init ir.Nodes
c := cheapexpr(n, &init)
if c != n || init.Len() != 0 {
@@ -584,7 +584,7 @@ func backingArrayPtrLen(n *ir.Node) (ptr, len *ir.Node) {
// labeledControl returns the control flow Node (for, switch, select)
// associated with the label n, if any.
-func labeledControl(n *ir.Node) *ir.Node {
+func labeledControl(n ir.Node) ir.Node {
if n.Op() != ir.OLABEL {
base.Fatalf("labeledControl %v", n.Op())
}
@@ -599,7 +599,7 @@ func labeledControl(n *ir.Node) *ir.Node {
return nil
}
-func syslook(name string) *ir.Node {
+func syslook(name string) ir.Node {
s := Runtimepkg.Lookup(name)
if s == nil || s.Def == nil {
base.Fatalf("syslook: can't find runtime.%s", name)
@@ -618,14 +618,14 @@ func typehash(t *types.Type) uint32 {
// updateHasCall checks whether expression n contains any function
// calls and sets the n.HasCall flag if so.
-func updateHasCall(n *ir.Node) {
+func updateHasCall(n ir.Node) {
if n == nil {
return
}
n.SetHasCall(calcHasCall(n))
}
-func calcHasCall(n *ir.Node) bool {
+func calcHasCall(n ir.Node) bool {
if n.Init().Len() != 0 {
// TODO(mdempsky): This seems overly conservative.
return true
@@ -740,7 +740,7 @@ func brrev(op ir.Op) ir.Op {
// return side effect-free n, appending side effects to init.
// result is assignable if n is.
-func safeexpr(n *ir.Node, init *ir.Nodes) *ir.Node {
+func safeexpr(n ir.Node, init *ir.Nodes) ir.Node {
if n == nil {
return nil
}
@@ -800,7 +800,7 @@ func safeexpr(n *ir.Node, init *ir.Nodes) *ir.Node {
return cheapexpr(n, init)
}
-func copyexpr(n *ir.Node, t *types.Type, init *ir.Nodes) *ir.Node {
+func copyexpr(n ir.Node, t *types.Type, init *ir.Nodes) ir.Node {
l := temp(t)
a := ir.Nod(ir.OAS, l, n)
a = typecheck(a, ctxStmt)
@@ -811,7 +811,7 @@ func copyexpr(n *ir.Node, t *types.Type, init *ir.Nodes) *ir.Node {
// return side-effect free and cheap n, appending side effects to init.
// result may not be assignable.
-func cheapexpr(n *ir.Node, init *ir.Nodes) *ir.Node {
+func cheapexpr(n ir.Node, init *ir.Nodes) ir.Node {
switch n.Op() {
case ir.ONAME, ir.OLITERAL, ir.ONIL:
return n
@@ -957,7 +957,7 @@ func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) (
// find missing fields that
// will give shortest unique addressing.
// modify the tree with missing type names.
-func adddot(n *ir.Node) *ir.Node {
+func adddot(n ir.Node) ir.Node {
n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr))
if n.Left().Diag() {
n.SetDiag(true)
@@ -1116,8 +1116,8 @@ func expandmeth(t *types.Type) {
}
// Given funarg struct list, return list of ODCLFIELD Node fn args.
-func structargs(tl *types.Type, mustname bool) []*ir.Node {
- var args []*ir.Node
+func structargs(tl *types.Type, mustname bool) []ir.Node {
+ var args []ir.Node
gen := 0
for _, t := range tl.Fields().Slice() {
s := t.Sym
@@ -1250,30 +1250,30 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym != nil {
inlcalls(fn)
}
- escapeFuncs([]*ir.Node{fn}, false)
+ escapeFuncs([]ir.Node{fn}, false)
Curfn = nil
xtop = append(xtop, fn)
}
-func paramNnames(ft *types.Type) []*ir.Node {
- args := make([]*ir.Node, ft.NumParams())
+func paramNnames(ft *types.Type) []ir.Node {
+ args := make([]ir.Node, ft.NumParams())
for i, f := range ft.Params().FieldSlice() {
args[i] = ir.AsNode(f.Nname)
}
return args
}
-func hashmem(t *types.Type) *ir.Node {
+func hashmem(t *types.Type) ir.Node {
sym := Runtimepkg.Lookup("memhash")
n := NewName(sym)
setNodeNameFunc(n)
- n.SetType(functype(nil, []*ir.Node{
+ n.SetType(functype(nil, []ir.Node{
anonfield(types.NewPtr(t)),
anonfield(types.Types[types.TUINTPTR]),
anonfield(types.Types[types.TUINTPTR]),
- }, []*ir.Node{
+ }, []ir.Node{
anonfield(types.Types[types.TUINTPTR]),
}))
return n
@@ -1393,15 +1393,15 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
return true
}
-func listtreecopy(l []*ir.Node, pos src.XPos) []*ir.Node {
- var out []*ir.Node
+func listtreecopy(l []ir.Node, pos src.XPos) []ir.Node {
+ var out []ir.Node
for _, n := range l {
out = append(out, treecopy(n, pos))
}
return out
}
-func liststmt(l []*ir.Node) *ir.Node {
+func liststmt(l []ir.Node) ir.Node {
n := ir.Nod(ir.OBLOCK, nil, nil)
n.PtrList().Set(l)
if len(l) != 0 {
@@ -1410,7 +1410,7 @@ func liststmt(l []*ir.Node) *ir.Node {
return n
}
-func ngotype(n *ir.Node) *types.Sym {
+func ngotype(n ir.Node) *types.Sym {
if n.Type() != nil {
return typenamesym(n.Type())
}
@@ -1419,7 +1419,7 @@ func ngotype(n *ir.Node) *types.Sym {
// The result of addinit MUST be assigned back to n, e.g.
// n.Left = addinit(n.Left, init)
-func addinit(n *ir.Node, init []*ir.Node) *ir.Node {
+func addinit(n ir.Node, init []ir.Node) ir.Node {
if len(init) == 0 {
return n
}
@@ -1518,7 +1518,7 @@ func isdirectiface(t *types.Type) bool {
}
// itabType loads the _type field from a runtime.itab struct.
-func itabType(itab *ir.Node) *ir.Node {
+func itabType(itab ir.Node) ir.Node {
typ := nodSym(ir.ODOTPTR, itab, nil)
typ.SetType(types.NewPtr(types.Types[types.TUINT8]))
typ.SetTypecheck(1)
@@ -1530,7 +1530,7 @@ func itabType(itab *ir.Node) *ir.Node {
// ifaceData loads the data field from an interface.
// The concrete type must be known to have type t.
// It follows the pointer if !isdirectiface(t).
-func ifaceData(pos src.XPos, n *ir.Node, t *types.Type) *ir.Node {
+func ifaceData(pos src.XPos, n ir.Node, t *types.Type) ir.Node {
if t.IsInterface() {
base.Fatalf("ifaceData interface: %v", t)
}