aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2020-12-24 15:42:37 -0800
committerMatthew Dempsky <mdempsky@google.com>2020-12-25 00:39:24 +0000
commit4b1d0fe66f3fcd80febc0e4be2850c06e3469da3 (patch)
tree26e5493a7e8c75e7111a638d9ffcf6d56d77c1d6 /src/cmd/compile
parent082cc8b7d9daf88db8779262aca8ab5692a00dfb (diff)
downloadgo-4b1d0fe66f3fcd80febc0e4be2850c06e3469da3.tar.gz
go-4b1d0fe66f3fcd80febc0e4be2850c06e3469da3.zip
[dev.regabi] cmd/compile: new devirtualization pkg [generated]
The devirtualization code was only in inl.go because it reused some of the same helper functions as inlining (notably staticValue), but that code all ended up in package ir instead anyway. Beyond that minor commonality, it's entirely separate from inlining. It's definitely on the small side, but consistent with the new micropass-as-a-package approach we're trying. [git-generate] cd src/cmd/compile/internal/inline rf ' mv Devirtualize Func mv devirtualizeCall Call mv Func Call devirtualize.go mv devirtualize.go cmd/compile/internal/devirtualize ' Change-Id: Iff7b9fe486856660a8107d5391c54b7e8d238706 Reviewed-on: https://go-review.googlesource.com/c/go/+/280212 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Diffstat (limited to 'src/cmd/compile')
-rw-r--r--src/cmd/compile/internal/devirtualize/devirtualize.go101
-rw-r--r--src/cmd/compile/internal/gc/main.go3
-rw-r--r--src/cmd/compile/internal/inline/inl.go67
3 files changed, 103 insertions, 68 deletions
diff --git a/src/cmd/compile/internal/devirtualize/devirtualize.go b/src/cmd/compile/internal/devirtualize/devirtualize.go
new file mode 100644
index 0000000000..95b28eff61
--- /dev/null
+++ b/src/cmd/compile/internal/devirtualize/devirtualize.go
@@ -0,0 +1,101 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// The inlining facility makes 2 passes: first caninl determines which
+// functions are suitable for inlining, and for those that are it
+// saves a copy of the body. Then inlcalls walks each function body to
+// expand calls to inlinable functions.
+//
+// The Debug.l flag controls the aggressiveness. Note that main() swaps level 0 and 1,
+// making 1 the default and -l disable. Additional levels (beyond -l) may be buggy and
+// are not supported.
+// 0: disabled
+// 1: 80-nodes leaf functions, oneliners, panic, lazy typechecking (default)
+// 2: (unassigned)
+// 3: (unassigned)
+// 4: allow non-leaf functions
+//
+// At some point this may get another default and become switch-offable with -N.
+//
+// The -d typcheckinl flag enables early typechecking of all imported bodies,
+// which is useful to flush out bugs.
+//
+// The Debug.m flag enables diagnostic output. a single -m is useful for verifying
+// which calls get inlined or not, more is for debugging, and may go away at any point.
+
+package devirtualize
+
+import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
+ "cmd/compile/internal/types"
+)
+
+// Devirtualize replaces interface method calls within fn with direct
+// concrete-type method calls where applicable.
+func Func(fn *ir.Func) {
+ ir.CurFunc = fn
+ ir.VisitList(fn.Body, func(n ir.Node) {
+ if n.Op() == ir.OCALLINTER {
+ Call(n.(*ir.CallExpr))
+ }
+ })
+}
+
+func Call(call *ir.CallExpr) {
+ sel := call.X.(*ir.SelectorExpr)
+ r := ir.StaticValue(sel.X)
+ if r.Op() != ir.OCONVIFACE {
+ return
+ }
+ recv := r.(*ir.ConvExpr)
+
+ typ := recv.X.Type()
+ if typ.IsInterface() {
+ return
+ }
+
+ dt := ir.NewTypeAssertExpr(sel.Pos(), sel.X, nil)
+ dt.SetType(typ)
+ x := typecheck.Callee(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sel))
+ switch x.Op() {
+ case ir.ODOTMETH:
+ x := x.(*ir.SelectorExpr)
+ if base.Flag.LowerM != 0 {
+ base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
+ }
+ call.SetOp(ir.OCALLMETH)
+ call.X = x
+ case ir.ODOTINTER:
+ // Promoted method from embedded interface-typed field (#42279).
+ x := x.(*ir.SelectorExpr)
+ if base.Flag.LowerM != 0 {
+ base.WarnfAt(call.Pos(), "partially devirtualizing %v to %v", sel, typ)
+ }
+ call.SetOp(ir.OCALLINTER)
+ call.X = x
+ default:
+ // TODO(mdempsky): Turn back into Fatalf after more testing.
+ if base.Flag.LowerM != 0 {
+ base.WarnfAt(call.Pos(), "failed to devirtualize %v (%v)", x, x.Op())
+ }
+ return
+ }
+
+ // Duplicated logic from typecheck for function call return
+ // value types.
+ //
+ // Receiver parameter size may have changed; need to update
+ // call.Type to get correct stack offsets for result
+ // parameters.
+ types.CheckSize(x.Type())
+ switch ft := x.Type(); ft.NumResults() {
+ case 0:
+ case 1:
+ call.SetType(ft.Results().Field(0).Type)
+ default:
+ call.SetType(ft.Results())
+ }
+}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 8483c87a38..ba3620e676 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -10,6 +10,7 @@ import (
"bufio"
"bytes"
"cmd/compile/internal/base"
+ "cmd/compile/internal/devirtualize"
"cmd/compile/internal/dwarfgen"
"cmd/compile/internal/escape"
"cmd/compile/internal/inline"
@@ -237,7 +238,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
// Devirtualize.
for _, n := range typecheck.Target.Decls {
if n.Op() == ir.ODCLFUNC {
- inline.Devirtualize(n.(*ir.Func))
+ devirtualize.Func(n.(*ir.Func))
}
}
ir.CurFunc = nil
diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go
index 222e62d0cc..9ffb08048a 100644
--- a/src/cmd/compile/internal/inline/inl.go
+++ b/src/cmd/compile/internal/inline/inl.go
@@ -1203,73 +1203,6 @@ func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
return s
}
-// Devirtualize replaces interface method calls within fn with direct
-// concrete-type method calls where applicable.
-func Devirtualize(fn *ir.Func) {
- ir.CurFunc = fn
- ir.VisitList(fn.Body, func(n ir.Node) {
- if n.Op() == ir.OCALLINTER {
- devirtualizeCall(n.(*ir.CallExpr))
- }
- })
-}
-
-func devirtualizeCall(call *ir.CallExpr) {
- sel := call.X.(*ir.SelectorExpr)
- r := ir.StaticValue(sel.X)
- if r.Op() != ir.OCONVIFACE {
- return
- }
- recv := r.(*ir.ConvExpr)
-
- typ := recv.X.Type()
- if typ.IsInterface() {
- return
- }
-
- dt := ir.NewTypeAssertExpr(sel.Pos(), sel.X, nil)
- dt.SetType(typ)
- x := typecheck.Callee(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sel))
- switch x.Op() {
- case ir.ODOTMETH:
- x := x.(*ir.SelectorExpr)
- if base.Flag.LowerM != 0 {
- base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
- }
- call.SetOp(ir.OCALLMETH)
- call.X = x
- case ir.ODOTINTER:
- // Promoted method from embedded interface-typed field (#42279).
- x := x.(*ir.SelectorExpr)
- if base.Flag.LowerM != 0 {
- base.WarnfAt(call.Pos(), "partially devirtualizing %v to %v", sel, typ)
- }
- call.SetOp(ir.OCALLINTER)
- call.X = x
- default:
- // TODO(mdempsky): Turn back into Fatalf after more testing.
- if base.Flag.LowerM != 0 {
- base.WarnfAt(call.Pos(), "failed to devirtualize %v (%v)", x, x.Op())
- }
- return
- }
-
- // Duplicated logic from typecheck for function call return
- // value types.
- //
- // Receiver parameter size may have changed; need to update
- // call.Type to get correct stack offsets for result
- // parameters.
- types.CheckSize(x.Type())
- switch ft := x.Type(); ft.NumResults() {
- case 0:
- case 1:
- call.SetType(ft.Results().Field(0).Type)
- default:
- call.SetType(ft.Results())
- }
-}
-
// numNonClosures returns the number of functions in list which are not closures.
func numNonClosures(list []*ir.Func) int {
count := 0