mirror of
https://github.com/golang/go
synced 2024-11-23 06:50:05 -07:00
cmd/compile: simplify walk OCONVIFACE
n.Type and n.Left.Type are used heavily. Give them useful names. We generate the type word frequently. Make it a closure. (We don't want to generate it up front, since there are some code paths that don't need it, and generating it has side-effects.) Simplify and document the final call construction. Follow-up to address feedback on CL 147360. Change-Id: I251134a55cf80d8b1676280a345d150f2288c09a Reviewed-on: https://go-review.googlesource.com/c/147538 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Martin Möhrmann <moehrmann@google.com>
This commit is contained in:
parent
6dd70fc5e3
commit
fe2c588b1c
@ -815,16 +815,21 @@ opswitch:
|
|||||||
case OCONVIFACE:
|
case OCONVIFACE:
|
||||||
n.Left = walkexpr(n.Left, init)
|
n.Left = walkexpr(n.Left, init)
|
||||||
|
|
||||||
// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
|
fromType := n.Left.Type
|
||||||
if isdirectiface(n.Left.Type) {
|
toType := n.Type
|
||||||
var t *Node
|
|
||||||
if n.Type.IsEmptyInterface() {
|
// typeword generates the type word of the interface value.
|
||||||
t = typename(n.Left.Type)
|
typeword := func() *Node {
|
||||||
} else {
|
if toType.IsEmptyInterface() {
|
||||||
t = itabname(n.Left.Type, n.Type)
|
return typename(fromType)
|
||||||
}
|
}
|
||||||
l := nod(OEFACE, t, n.Left)
|
return itabname(fromType, toType)
|
||||||
l.Type = n.Type
|
}
|
||||||
|
|
||||||
|
// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
|
||||||
|
if isdirectiface(fromType) {
|
||||||
|
l := nod(OEFACE, typeword(), n.Left)
|
||||||
|
l.Type = toType
|
||||||
l.SetTypecheck(n.Typecheck())
|
l.SetTypecheck(n.Typecheck())
|
||||||
n = l
|
n = l
|
||||||
break
|
break
|
||||||
@ -844,11 +849,11 @@ opswitch:
|
|||||||
// or creating one on the stack.
|
// or creating one on the stack.
|
||||||
var value *Node
|
var value *Node
|
||||||
switch {
|
switch {
|
||||||
case n.Left.Type.Size() == 0:
|
case fromType.Size() == 0:
|
||||||
// n.Left is zero-sized. Use zerobase.
|
// n.Left is zero-sized. Use zerobase.
|
||||||
cheapexpr(n.Left, init) // Evaluate n.Left for side-effects. See issue 19246.
|
cheapexpr(n.Left, init) // Evaluate n.Left for side-effects. See issue 19246.
|
||||||
value = zerobase
|
value = zerobase
|
||||||
case n.Left.Type.IsBoolean() || (n.Left.Type.Size() == 1 && n.Left.Type.IsInteger()):
|
case fromType.IsBoolean() || (fromType.Size() == 1 && fromType.IsInteger()):
|
||||||
// n.Left is a bool/byte. Use staticbytes[n.Left].
|
// n.Left is a bool/byte. Use staticbytes[n.Left].
|
||||||
n.Left = cheapexpr(n.Left, init)
|
n.Left = cheapexpr(n.Left, init)
|
||||||
value = nod(OINDEX, staticbytes, byteindex(n.Left))
|
value = nod(OINDEX, staticbytes, byteindex(n.Left))
|
||||||
@ -856,23 +861,17 @@ opswitch:
|
|||||||
case n.Left.Class() == PEXTERN && n.Left.Name != nil && n.Left.Name.Readonly():
|
case n.Left.Class() == PEXTERN && n.Left.Name != nil && n.Left.Name.Readonly():
|
||||||
// n.Left is a readonly global; use it directly.
|
// n.Left is a readonly global; use it directly.
|
||||||
value = n.Left
|
value = n.Left
|
||||||
case !n.Left.Type.IsInterface() && n.Esc == EscNone && n.Left.Type.Width <= 1024:
|
case !fromType.IsInterface() && n.Esc == EscNone && fromType.Width <= 1024:
|
||||||
// n.Left does not escape. Use a stack temporary initialized to n.Left.
|
// n.Left does not escape. Use a stack temporary initialized to n.Left.
|
||||||
value = temp(n.Left.Type)
|
value = temp(fromType)
|
||||||
init.Append(typecheck(nod(OAS, value, n.Left), Etop))
|
init.Append(typecheck(nod(OAS, value, n.Left), Etop))
|
||||||
}
|
}
|
||||||
|
|
||||||
if value != nil {
|
if value != nil {
|
||||||
// Value is identical to n.Left.
|
// Value is identical to n.Left.
|
||||||
// Construct the interface directly: {type/itab, &value}.
|
// Construct the interface directly: {type/itab, &value}.
|
||||||
var t *Node
|
l := nod(OEFACE, typeword(), typecheck(nod(OADDR, value, nil), Erv))
|
||||||
if n.Type.IsEmptyInterface() {
|
l.Type = toType
|
||||||
t = typename(n.Left.Type)
|
|
||||||
} else {
|
|
||||||
t = itabname(n.Left.Type, n.Type)
|
|
||||||
}
|
|
||||||
l := nod(OEFACE, t, typecheck(nod(OADDR, value, nil), Erv))
|
|
||||||
l.Type = n.Type
|
|
||||||
l.SetTypecheck(n.Typecheck())
|
l.SetTypecheck(n.Typecheck())
|
||||||
n = l
|
n = l
|
||||||
break
|
break
|
||||||
@ -884,9 +883,9 @@ opswitch:
|
|||||||
// tmp = tmp.type
|
// tmp = tmp.type
|
||||||
// }
|
// }
|
||||||
// e = iface{tmp, i.data}
|
// e = iface{tmp, i.data}
|
||||||
if n.Type.IsEmptyInterface() && n.Left.Type.IsInterface() && !n.Left.Type.IsEmptyInterface() {
|
if toType.IsEmptyInterface() && fromType.IsInterface() && !fromType.IsEmptyInterface() {
|
||||||
// Evaluate the input interface.
|
// Evaluate the input interface.
|
||||||
c := temp(n.Left.Type)
|
c := temp(fromType)
|
||||||
init.Append(nod(OAS, c, n.Left))
|
init.Append(nod(OAS, c, n.Left))
|
||||||
|
|
||||||
// Get the itab out of the interface.
|
// Get the itab out of the interface.
|
||||||
@ -900,51 +899,41 @@ opswitch:
|
|||||||
|
|
||||||
// Build the result.
|
// Build the result.
|
||||||
e := nod(OEFACE, tmp, ifaceData(c, types.NewPtr(types.Types[TUINT8])))
|
e := nod(OEFACE, tmp, ifaceData(c, types.NewPtr(types.Types[TUINT8])))
|
||||||
e.Type = n.Type // assign type manually, typecheck doesn't understand OEFACE.
|
e.Type = toType // assign type manually, typecheck doesn't understand OEFACE.
|
||||||
e.SetTypecheck(1)
|
e.SetTypecheck(1)
|
||||||
n = e
|
n = e
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
fnname, needsaddr := convFuncName(n.Left.Type, n.Type)
|
fnname, needsaddr := convFuncName(fromType, toType)
|
||||||
|
|
||||||
if !needsaddr && !n.Left.Type.IsInterface() {
|
if !needsaddr && !fromType.IsInterface() {
|
||||||
// Use a specialized conversion routine that only returns a data pointer.
|
// Use a specialized conversion routine that only returns a data pointer.
|
||||||
// ptr = convT2X(val)
|
// ptr = convT2X(val)
|
||||||
// e = iface{typ/tab, ptr}
|
// e = iface{typ/tab, ptr}
|
||||||
fn := syslook(fnname)
|
fn := syslook(fnname)
|
||||||
dowidth(n.Left.Type)
|
dowidth(fromType)
|
||||||
fn = substArgTypes(fn, n.Left.Type)
|
fn = substArgTypes(fn, fromType)
|
||||||
dowidth(fn.Type)
|
dowidth(fn.Type)
|
||||||
call := nod(OCALL, fn, nil)
|
call := nod(OCALL, fn, nil)
|
||||||
call.List.Set1(n.Left)
|
call.List.Set1(n.Left)
|
||||||
call = typecheck(call, Erv)
|
call = typecheck(call, Erv)
|
||||||
call = walkexpr(call, init)
|
call = walkexpr(call, init)
|
||||||
call = safeexpr(call, init)
|
call = safeexpr(call, init)
|
||||||
var tab *Node
|
e := nod(OEFACE, typeword(), call)
|
||||||
if n.Type.IsEmptyInterface() {
|
e.Type = toType
|
||||||
tab = typename(n.Left.Type)
|
|
||||||
} else {
|
|
||||||
tab = itabname(n.Left.Type, n.Type)
|
|
||||||
}
|
|
||||||
e := nod(OEFACE, tab, call)
|
|
||||||
e.Type = n.Type
|
|
||||||
e.SetTypecheck(1)
|
e.SetTypecheck(1)
|
||||||
n = e
|
n = e
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
var ll []*Node
|
var tab *Node
|
||||||
if n.Type.IsEmptyInterface() {
|
if fromType.IsInterface() {
|
||||||
if !n.Left.Type.IsInterface() {
|
// convI2I
|
||||||
ll = append(ll, typename(n.Left.Type))
|
tab = typename(toType)
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if n.Left.Type.IsInterface() {
|
// convT2x
|
||||||
ll = append(ll, typename(n.Type))
|
tab = typeword()
|
||||||
} else {
|
|
||||||
ll = append(ll, itabname(n.Left.Type, n.Type))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v := n.Left
|
v := n.Left
|
||||||
@ -960,14 +949,13 @@ opswitch:
|
|||||||
}
|
}
|
||||||
v = nod(OADDR, v, nil)
|
v = nod(OADDR, v, nil)
|
||||||
}
|
}
|
||||||
ll = append(ll, v)
|
|
||||||
|
|
||||||
dowidth(n.Left.Type)
|
dowidth(fromType)
|
||||||
fn := syslook(fnname)
|
fn := syslook(fnname)
|
||||||
fn = substArgTypes(fn, n.Left.Type, n.Type)
|
fn = substArgTypes(fn, fromType, toType)
|
||||||
dowidth(fn.Type)
|
dowidth(fn.Type)
|
||||||
n = nod(OCALL, fn, nil)
|
n = nod(OCALL, fn, nil)
|
||||||
n.List.Set(ll)
|
n.List.Set2(tab, v)
|
||||||
n = typecheck(n, Erv)
|
n = typecheck(n, Erv)
|
||||||
n = walkexpr(n, init)
|
n = walkexpr(n, init)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user