Commit fe2c588b authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

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: default avatarMartin Möhrmann <moehrmann@google.com>
parent 6dd70fc5
...@@ -815,16 +815,21 @@ opswitch: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment