1
0
mirror of https://github.com/golang/go synced 2024-11-24 23:57:57 -07:00

cmd/compile: avoid dynamic type when possible

If the expression type is a single compile-time known type, use that
type instead of the dynamic one, so the later passes of the compiler
could skip un-necessary runtime calls.

Thanks Youlin Feng for writing the original test case.

Change-Id: I3f65ab90f041474a9731338a82136c1d394c1773
Reviewed-on: https://go-review.googlesource.com/c/go/+/616975
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
Cuong Manh Le 2024-10-01 02:30:39 +07:00 committed by Gopher Robot
parent 6a3f39a9b8
commit 7e2487cf65
4 changed files with 72 additions and 18 deletions

View File

@ -67,3 +67,23 @@ func NewDynamicType(pos src.XPos, rtype Node) *DynamicType {
n.op = ODYNAMICTYPE
return n
}
// ToStatic returns static type of dt if it is actually static.
func (dt *DynamicType) ToStatic() Node {
if dt.Typecheck() == 0 {
base.Fatalf("missing typecheck: %v", dt)
}
if dt.RType != nil && dt.RType.Op() == OADDR {
addr := dt.RType.(*AddrExpr)
if addr.X.Op() == OLINKSYMOFFSET {
return TypeNode(dt.Type())
}
}
if dt.ITab != nil && dt.ITab.Op() == OADDR {
addr := dt.ITab.(*AddrExpr)
if addr.X.Op() == OLINKSYMOFFSET {
return TypeNode(dt.Type())
}
}
return nil
}

View File

@ -3242,7 +3242,11 @@ func (r *reader) exprType() ir.Node {
dt := ir.NewDynamicType(pos, rtype)
dt.ITab = itab
return typed(typ, dt)
dt = typed(typ, dt).(*ir.DynamicType)
if st := dt.ToStatic(); st != nil {
return st
}
return dt
}
func (r *reader) op() ir.Op {

View File

@ -459,23 +459,6 @@ func walkSwitchType(sw *ir.SwitchStmt) {
nilGoto = jmp
continue
}
if n1.Op() == ir.ODYNAMICTYPE {
// Convert dynamic to static, if the dynamic is actually static.
// TODO: why isn't this OTYPE to begin with?
dt := n1.(*ir.DynamicType)
if dt.RType != nil && dt.RType.Op() == ir.OADDR {
addr := dt.RType.(*ir.AddrExpr)
if addr.X.Op() == ir.OLINKSYMOFFSET {
n1 = ir.TypeNode(n1.Type())
}
}
if dt.ITab != nil && dt.ITab.Op() == ir.OADDR {
addr := dt.ITab.(*ir.AddrExpr)
if addr.X.Op() == ir.OLINKSYMOFFSET {
n1 = ir.TypeNode(n1.Type())
}
}
}
cases = append(cases, oneCase{
pos: ncase.Pos(),
typ: n1,

View File

@ -0,0 +1,47 @@
// asmcheck
// Copyright 2024 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.
package codegen
type Ix interface {
X()
}
type Iy interface {
Y()
}
type Iz interface {
Z()
}
func swXYZ(a Ix) {
switch t := a.(type) {
case Iy: // amd64:-".*typeAssert"
t.Y()
case Iz: // amd64:-".*typeAssert"
t.Z()
}
}
type Ig[T any] interface {
G() T
}
func swGYZ[T any](a Ig[T]) {
switch t := a.(type) {
case Iy: // amd64:-".*typeAssert"
t.Y()
case Iz: // amd64:-".*typeAssert"
t.Z()
case interface{ G() T }: // amd64:-".*typeAssert",".*assertE2I"
t.G()
}
}
func swCaller() {
swGYZ[int]((Ig[int])(nil))
}