1
0
mirror of https://github.com/golang/go synced 2024-11-23 07:00: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:
Josh Bleecher Snyder 2018-11-05 15:42:14 -08:00
parent 6dd70fc5e3
commit fe2c588b1c

View File

@ -815,16 +815,21 @@ opswitch:
case OCONVIFACE:
n.Left = walkexpr(n.Left, init)
// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
if isdirectiface(n.Left.Type) {
var t *Node
if n.Type.IsEmptyInterface() {
t = typename(n.Left.Type)
} else {
t = itabname(n.Left.Type, n.Type)
fromType := n.Left.Type
toType := n.Type
// typeword generates the type word of the interface value.
typeword := func() *Node {
if toType.IsEmptyInterface() {
return typename(fromType)
}
l := nod(OEFACE, t, n.Left)
l.Type = n.Type
return itabname(fromType, toType)
}
// 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())
n = l
break
@ -844,11 +849,11 @@ opswitch:
// or creating one on the stack.
var value *Node
switch {
case n.Left.Type.Size() == 0:
case fromType.Size() == 0:
// n.Left is zero-sized. Use zerobase.
cheapexpr(n.Left, init) // Evaluate n.Left for side-effects. See issue 19246.
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 = cheapexpr(n.Left, init)
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():
// n.Left is a readonly global; use it directly.
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.
value = temp(n.Left.Type)
value = temp(fromType)
init.Append(typecheck(nod(OAS, value, n.Left), Etop))
}
if value != nil {
// Value is identical to n.Left.
// Construct the interface directly: {type/itab, &value}.
var t *Node
if n.Type.IsEmptyInterface() {
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 := nod(OEFACE, typeword(), typecheck(nod(OADDR, value, nil), Erv))
l.Type = toType
l.SetTypecheck(n.Typecheck())
n = l
break
@ -884,9 +883,9 @@ opswitch:
// tmp = tmp.type
// }
// 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.
c := temp(n.Left.Type)
c := temp(fromType)
init.Append(nod(OAS, c, n.Left))
// Get the itab out of the interface.
@ -900,51 +899,41 @@ opswitch:
// Build the result.
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)
n = e
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.
// ptr = convT2X(val)
// e = iface{typ/tab, ptr}
fn := syslook(fnname)
dowidth(n.Left.Type)
fn = substArgTypes(fn, n.Left.Type)
dowidth(fromType)
fn = substArgTypes(fn, fromType)
dowidth(fn.Type)
call := nod(OCALL, fn, nil)
call.List.Set1(n.Left)
call = typecheck(call, Erv)
call = walkexpr(call, init)
call = safeexpr(call, init)
var tab *Node
if n.Type.IsEmptyInterface() {
tab = typename(n.Left.Type)
} else {
tab = itabname(n.Left.Type, n.Type)
}
e := nod(OEFACE, tab, call)
e.Type = n.Type
e := nod(OEFACE, typeword(), call)
e.Type = toType
e.SetTypecheck(1)
n = e
break
}
var ll []*Node
if n.Type.IsEmptyInterface() {
if !n.Left.Type.IsInterface() {
ll = append(ll, typename(n.Left.Type))
}
var tab *Node
if fromType.IsInterface() {
// convI2I
tab = typename(toType)
} else {
if n.Left.Type.IsInterface() {
ll = append(ll, typename(n.Type))
} else {
ll = append(ll, itabname(n.Left.Type, n.Type))
}
// convT2x
tab = typeword()
}
v := n.Left
@ -960,14 +949,13 @@ opswitch:
}
v = nod(OADDR, v, nil)
}
ll = append(ll, v)
dowidth(n.Left.Type)
dowidth(fromType)
fn := syslook(fnname)
fn = substArgTypes(fn, n.Left.Type, n.Type)
fn = substArgTypes(fn, fromType, toType)
dowidth(fn.Type)
n = nod(OCALL, fn, nil)
n.List.Set(ll)
n.List.Set2(tab, v)
n = typecheck(n, Erv)
n = walkexpr(n, init)