]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: optimize type switch for a single runtime known type with a case var
authorYoulin Feng <fengyoulin@live.com>
Tue, 8 Oct 2024 04:49:30 +0000 (12:49 +0800)
committerGopher Robot <gobot@golang.org>
Fri, 25 Oct 2024 02:56:11 +0000 (02:56 +0000)
Change-Id: I03ba70076d6dd3c0b9624d14699b7dd91a3c0e9b
Reviewed-on: https://go-review.googlesource.com/c/go/+/618476
Reviewed-by: Keith Randall <khr@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Keith Randall <khr@google.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>

src/cmd/compile/internal/walk/switch.go
test/codegen/typeswitch.go

index a45ca6e638e2f052f3fd9c3e1c48fcb8e06d73db..cbe38b54bcd03872ddf0041dc5400f87e565c3d7 100644 (file)
@@ -440,6 +440,13 @@ func walkSwitchType(sw *ir.SwitchStmt) {
                // we're looking for is not a compile-time constant (typ.Type()
                // will be its shape).
                typ ir.Node
+
+               // For a single runtime known type with a case var, create a
+               // temporary variable to hold the value returned by the dynamic
+               // type assert expr, so that we do not need one more dynamic
+               // type assert expr later.
+               val ir.Node
+               idx int // index of the single runtime known type in sw.Cases
        }
        var cases []oneCase
        var defaultGoto, nilGoto ir.Node
@@ -459,10 +466,19 @@ func walkSwitchType(sw *ir.SwitchStmt) {
                                nilGoto = jmp
                                continue
                        }
+                       idx := -1
+                       var val ir.Node
+                       // for a single runtime known type with a case var, create the tmpVar
+                       if len(ncase.List) == 1 && ncase.List[0].Op() == ir.ODYNAMICTYPE && ncase.Var != nil {
+                               val = typecheck.TempAt(ncase.Pos(), ir.CurFunc, ncase.Var.Type())
+                               idx = i
+                       }
                        cases = append(cases, oneCase{
                                pos: ncase.Pos(),
                                typ: n1,
                                jmp: jmp,
+                               val: val,
+                               idx: idx,
                        })
                }
        }
@@ -570,6 +586,9 @@ caseLoop:
 
                        as := ir.NewAssignListStmt(c.pos, ir.OAS2, nil, nil)
                        as.Lhs = []ir.Node{ir.BlankNode, s.okName} // _, ok =
+                       if c.val != nil {
+                               as.Lhs[0] = c.val // tmpVar, ok =
+                       }
                        as.Rhs = []ir.Node{dot}
                        typecheck.Stmt(as)
 
@@ -640,10 +659,18 @@ caseLoop:
                                                val = ifaceData(ncase.Pos(), s.srcName, t)
                                        }
                                } else if ncase.List[0].Op() == ir.ODYNAMICTYPE { // single runtime known type
-                                       dt := ncase.List[0].(*ir.DynamicType)
-                                       x := ir.NewDynamicTypeAssertExpr(ncase.Pos(), ir.ODYNAMICDOTTYPE, val, dt.RType)
-                                       x.ITab = dt.ITab
-                                       val = x
+                                       var found bool
+                                       for _, c := range cases {
+                                               if c.idx == i {
+                                                       val = c.val
+                                                       found = val != nil
+                                                       break
+                                               }
+                                       }
+                                       // the tmpVar must always be found
+                                       if !found {
+                                               base.Fatalf("an error occurred when processing type switch case %v", ncase.List[0])
+                                       }
                                } else if ir.IsNil(ncase.List[0]) {
                                } else {
                                        base.Fatalf("unhandled type switch case %v", ncase.List[0])
index 495853ed3c0753d22606594afece7dec0953dee7..93f8e84269f5e5afc5c667cc2d8e2ddec9e40bcd 100644 (file)
@@ -37,11 +37,31 @@ func swGYZ[T any](a Ig[T]) {
                t.Y()
        case Iz: // amd64:-".*typeAssert"
                t.Z()
-       case interface{ G() T }: // amd64:-".*typeAssert",".*assertE2I"
+       case interface{ G() T }: // amd64:-".*typeAssert",-".*assertE2I\\(",".*assertE2I2"
+               t.G()
+       }
+}
+
+func swE2G[T any](a any) {
+       switch t := a.(type) {
+       case Iy:
+               t.Y()
+       case Ig[T]: // amd64:-".*assertE2I\\(",".*assertE2I2"
+               t.G()
+       }
+}
+
+func swI2G[T any](a Ix) {
+       switch t := a.(type) {
+       case Iy:
+               t.Y()
+       case Ig[T]: // amd64:-".*assertE2I\\(",".*assertE2I2"
                t.G()
        }
 }
 
 func swCaller() {
        swGYZ[int]((Ig[int])(nil))
+       swE2G[int]((Ig[int])(nil))
+       swI2G[int]((Ix)(nil))
 }