mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
cmd/compile: optimize type switch for a single runtime known type with a case var
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>
This commit is contained in:
parent
15c5580160
commit
711552e98a
@ -440,6 +440,13 @@ func walkSwitchType(sw *ir.SwitchStmt) {
|
|||||||
// we're looking for is not a compile-time constant (typ.Type()
|
// we're looking for is not a compile-time constant (typ.Type()
|
||||||
// will be its shape).
|
// will be its shape).
|
||||||
typ ir.Node
|
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 cases []oneCase
|
||||||
var defaultGoto, nilGoto ir.Node
|
var defaultGoto, nilGoto ir.Node
|
||||||
@ -459,10 +466,19 @@ func walkSwitchType(sw *ir.SwitchStmt) {
|
|||||||
nilGoto = jmp
|
nilGoto = jmp
|
||||||
continue
|
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{
|
cases = append(cases, oneCase{
|
||||||
pos: ncase.Pos(),
|
pos: ncase.Pos(),
|
||||||
typ: n1,
|
typ: n1,
|
||||||
jmp: jmp,
|
jmp: jmp,
|
||||||
|
val: val,
|
||||||
|
idx: idx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -570,6 +586,9 @@ caseLoop:
|
|||||||
|
|
||||||
as := ir.NewAssignListStmt(c.pos, ir.OAS2, nil, nil)
|
as := ir.NewAssignListStmt(c.pos, ir.OAS2, nil, nil)
|
||||||
as.Lhs = []ir.Node{ir.BlankNode, s.okName} // _, ok =
|
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}
|
as.Rhs = []ir.Node{dot}
|
||||||
typecheck.Stmt(as)
|
typecheck.Stmt(as)
|
||||||
|
|
||||||
@ -640,10 +659,18 @@ caseLoop:
|
|||||||
val = ifaceData(ncase.Pos(), s.srcName, t)
|
val = ifaceData(ncase.Pos(), s.srcName, t)
|
||||||
}
|
}
|
||||||
} else if ncase.List[0].Op() == ir.ODYNAMICTYPE { // single runtime known type
|
} else if ncase.List[0].Op() == ir.ODYNAMICTYPE { // single runtime known type
|
||||||
dt := ncase.List[0].(*ir.DynamicType)
|
var found bool
|
||||||
x := ir.NewDynamicTypeAssertExpr(ncase.Pos(), ir.ODYNAMICDOTTYPE, val, dt.RType)
|
for _, c := range cases {
|
||||||
x.ITab = dt.ITab
|
if c.idx == i {
|
||||||
val = x
|
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 if ir.IsNil(ncase.List[0]) {
|
||||||
} else {
|
} else {
|
||||||
base.Fatalf("unhandled type switch case %v", ncase.List[0])
|
base.Fatalf("unhandled type switch case %v", ncase.List[0])
|
||||||
|
@ -37,11 +37,31 @@ func swGYZ[T any](a Ig[T]) {
|
|||||||
t.Y()
|
t.Y()
|
||||||
case Iz: // amd64:-".*typeAssert"
|
case Iz: // amd64:-".*typeAssert"
|
||||||
t.Z()
|
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()
|
t.G()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func swCaller() {
|
func swCaller() {
|
||||||
swGYZ[int]((Ig[int])(nil))
|
swGYZ[int]((Ig[int])(nil))
|
||||||
|
swE2G[int]((Ig[int])(nil))
|
||||||
|
swI2G[int]((Ix)(nil))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user