mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: pass arguments to convt2E/I integer functions by value
The motivation is avoid generating a pointer to the data being converted so it can be garbage collected. The change also slightly reduces binary size by shrinking call sites. Fixes #24286 Benchmark results: name old time/op new time/op delta ConvT2ESmall-4 2.86ns ± 0% 2.80ns ± 1% -2.12% (p=0.000 n=29+28) ConvT2EUintptr-4 2.88ns ± 1% 2.88ns ± 0% -0.20% (p=0.002 n=28+30) ConvT2ELarge-4 19.6ns ± 0% 20.4ns ± 1% +4.22% (p=0.000 n=19+30) ConvT2ISmall-4 3.01ns ± 0% 2.85ns ± 0% -5.32% (p=0.000 n=24+28) ConvT2IUintptr-4 3.00ns ± 1% 2.87ns ± 0% -4.44% (p=0.000 n=29+25) ConvT2ILarge-4 20.4ns ± 1% 21.3ns ± 1% +4.41% (p=0.000 n=30+26) ConvT2Ezero/zero/16-4 2.84ns ± 1% 2.99ns ± 0% +5.38% (p=0.000 n=30+25) ConvT2Ezero/zero/32-4 2.83ns ± 2% 3.00ns ± 0% +5.91% (p=0.004 n=27+3) Change-Id: I65016ec94c53f97c52113121cab582d0c342b7a8 Reviewed-on: https://go-review.googlesource.com/102636 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com> Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
e0d37a33ab
commit
22ff9521da
4 changed files with 61 additions and 97 deletions
|
|
@ -388,51 +388,51 @@ func walkexprlistcheap(s []*Node, init *Nodes) {
|
|||
}
|
||||
}
|
||||
|
||||
// Build name of function for interface conversion.
|
||||
// Not all names are possible
|
||||
// (e.g., we'll never generate convE2E or convE2I or convI2E).
|
||||
func convFuncName(from, to *types.Type) string {
|
||||
// convFuncName builds the runtime function name for interface conversion.
|
||||
// It also reports whether the function expects the data by address.
|
||||
// Not all names are possible. For example, we never generate convE2E or convE2I.
|
||||
func convFuncName(from, to *types.Type) (fnname string, needsaddr bool) {
|
||||
tkind := to.Tie()
|
||||
switch from.Tie() {
|
||||
case 'I':
|
||||
switch tkind {
|
||||
case 'I':
|
||||
return "convI2I"
|
||||
return "convI2I", false
|
||||
}
|
||||
case 'T':
|
||||
switch tkind {
|
||||
case 'E':
|
||||
switch {
|
||||
case from.Size() == 2 && from.Align == 2:
|
||||
return "convT2E16"
|
||||
return "convT2E16", false
|
||||
case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
|
||||
return "convT2E32"
|
||||
return "convT2E32", false
|
||||
case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
|
||||
return "convT2E64"
|
||||
return "convT2E64", false
|
||||
case from.IsString():
|
||||
return "convT2Estring"
|
||||
return "convT2Estring", true
|
||||
case from.IsSlice():
|
||||
return "convT2Eslice"
|
||||
return "convT2Eslice", true
|
||||
case !types.Haspointers(from):
|
||||
return "convT2Enoptr"
|
||||
return "convT2Enoptr", true
|
||||
}
|
||||
return "convT2E"
|
||||
return "convT2E", true
|
||||
case 'I':
|
||||
switch {
|
||||
case from.Size() == 2 && from.Align == 2:
|
||||
return "convT2I16"
|
||||
return "convT2I16", false
|
||||
case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
|
||||
return "convT2I32"
|
||||
return "convT2I32", false
|
||||
case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
|
||||
return "convT2I64"
|
||||
return "convT2I64", false
|
||||
case from.IsString():
|
||||
return "convT2Istring"
|
||||
return "convT2Istring", true
|
||||
case from.IsSlice():
|
||||
return "convT2Islice"
|
||||
return "convT2Islice", true
|
||||
case !types.Haspointers(from):
|
||||
return "convT2Inoptr"
|
||||
return "convT2Inoptr", true
|
||||
}
|
||||
return "convT2I"
|
||||
return "convT2I", true
|
||||
}
|
||||
}
|
||||
Fatalf("unknown conv func %c2%c", from.Tie(), to.Tie())
|
||||
|
|
@ -980,24 +980,24 @@ opswitch:
|
|||
}
|
||||
}
|
||||
|
||||
if n.Left.Type.IsInterface() {
|
||||
ll = append(ll, n.Left)
|
||||
} else {
|
||||
// regular types are passed by reference to avoid C vararg calls
|
||||
// orderexpr arranged for n.Left to be a temporary for all
|
||||
// the conversions it could see. comparison of an interface
|
||||
fnname, needsaddr := convFuncName(n.Left.Type, n.Type)
|
||||
v := n.Left
|
||||
if needsaddr {
|
||||
// Types of large or unknown size are passed by reference.
|
||||
// Orderexpr arranged for n.Left to be a temporary for all
|
||||
// the conversions it could see. Comparison of an interface
|
||||
// with a non-interface, especially in a switch on interface value
|
||||
// with non-interface cases, is not visible to orderstmt, so we
|
||||
// have to fall back on allocating a temp here.
|
||||
if islvalue(n.Left) {
|
||||
ll = append(ll, nod(OADDR, n.Left, nil))
|
||||
} else {
|
||||
ll = append(ll, nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
|
||||
if !islvalue(v) {
|
||||
v = copyexpr(v, v.Type, init)
|
||||
}
|
||||
dowidth(n.Left.Type)
|
||||
v = nod(OADDR, v, nil)
|
||||
}
|
||||
ll = append(ll, v)
|
||||
|
||||
fn := syslook(convFuncName(n.Left.Type, n.Type))
|
||||
dowidth(n.Left.Type)
|
||||
fn := syslook(fnname)
|
||||
fn = substArgTypes(fn, n.Left.Type, n.Type)
|
||||
dowidth(fn.Type)
|
||||
n = nod(OCALL, fn, nil)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue