]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: avoid dynamic type when possible
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Mon, 30 Sep 2024 19:30:39 +0000 (02:30 +0700)
committerGopher Robot <gobot@golang.org>
Mon, 7 Oct 2024 19:12:01 +0000 (19:12 +0000)
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>
src/cmd/compile/internal/ir/type.go
src/cmd/compile/internal/noder/reader.go
src/cmd/compile/internal/walk/switch.go
test/codegen/typeswitch.go [new file with mode: 0644]

index 7db76c1427f4bdb6995525810eafed3d600eda29..6daca856a67c1dcb49f5780f092f65e34b2d98d1 100644 (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
+}
index 55fbf860dfd00fbb327ca16e900e76bc81e561d4..39ac1400a0f8c6d8d8d0f46d97f4bc2cfd38dc45 100644 (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 {
index e451a95d69f7e4f571d4d866a5975e32c6430344..a45ca6e638e2f052f3fd9c3e1c48fcb8e06d73db 100644 (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,
diff --git a/test/codegen/typeswitch.go b/test/codegen/typeswitch.go
new file mode 100644 (file)
index 0000000..495853e
--- /dev/null
@@ -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))
+}