mirror of
https://github.com/golang/go
synced 2024-11-24 04:00:13 -07: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
@ -50,16 +50,16 @@ var runtimeDecls = [...]struct {
|
||||
{"slicestringcopy", funcTag, 50},
|
||||
{"convI2I", funcTag, 51},
|
||||
{"convT2E", funcTag, 52},
|
||||
{"convT2E16", funcTag, 52},
|
||||
{"convT2E32", funcTag, 52},
|
||||
{"convT2E64", funcTag, 52},
|
||||
{"convT2E16", funcTag, 51},
|
||||
{"convT2E32", funcTag, 51},
|
||||
{"convT2E64", funcTag, 51},
|
||||
{"convT2Estring", funcTag, 52},
|
||||
{"convT2Eslice", funcTag, 52},
|
||||
{"convT2Enoptr", funcTag, 52},
|
||||
{"convT2I", funcTag, 52},
|
||||
{"convT2I16", funcTag, 52},
|
||||
{"convT2I32", funcTag, 52},
|
||||
{"convT2I64", funcTag, 52},
|
||||
{"convT2I16", funcTag, 51},
|
||||
{"convT2I32", funcTag, 51},
|
||||
{"convT2I64", funcTag, 51},
|
||||
{"convT2Istring", funcTag, 52},
|
||||
{"convT2Islice", funcTag, 52},
|
||||
{"convT2Inoptr", funcTag, 52},
|
||||
|
@ -62,17 +62,17 @@ func slicestringcopy(to any, fr any) int
|
||||
func convI2I(typ *byte, elem any) (ret any)
|
||||
|
||||
func convT2E(typ *byte, elem *any) (ret any)
|
||||
func convT2E16(typ *byte, elem *any) (ret any)
|
||||
func convT2E32(typ *byte, elem *any) (ret any)
|
||||
func convT2E64(typ *byte, elem *any) (ret any)
|
||||
func convT2E16(typ *byte, val any) (ret any)
|
||||
func convT2E32(typ *byte, val any) (ret any)
|
||||
func convT2E64(typ *byte, val any) (ret any)
|
||||
func convT2Estring(typ *byte, elem *any) (ret any)
|
||||
func convT2Eslice(typ *byte, elem *any) (ret any)
|
||||
func convT2Enoptr(typ *byte, elem *any) (ret any)
|
||||
|
||||
func convT2I(tab *byte, elem *any) (ret any)
|
||||
func convT2I16(tab *byte, elem *any) (ret any)
|
||||
func convT2I32(tab *byte, elem *any) (ret any)
|
||||
func convT2I64(tab *byte, elem *any) (ret any)
|
||||
func convT2I16(tab *byte, val any) (ret any)
|
||||
func convT2I32(tab *byte, val any) (ret any)
|
||||
func convT2I64(tab *byte, val any) (ret any)
|
||||
func convT2Istring(tab *byte, elem *any) (ret any)
|
||||
func convT2Islice(tab *byte, elem *any) (ret any)
|
||||
func convT2Inoptr(tab *byte, elem *any) (ret any)
|
||||
|
@ -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)
|
||||
|
@ -294,57 +294,39 @@ func convT2E(t *_type, elem unsafe.Pointer) (e eface) {
|
||||
return
|
||||
}
|
||||
|
||||
func convT2E16(t *_type, elem unsafe.Pointer) (e eface) {
|
||||
if raceenabled {
|
||||
raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2E16))
|
||||
}
|
||||
if msanenabled {
|
||||
msanread(elem, t.size)
|
||||
}
|
||||
func convT2E16(t *_type, val uint16) (e eface) {
|
||||
var x unsafe.Pointer
|
||||
if *(*uint16)(elem) == 0 {
|
||||
if val == 0 {
|
||||
x = unsafe.Pointer(&zeroVal[0])
|
||||
} else {
|
||||
x = mallocgc(2, t, false)
|
||||
*(*uint16)(x) = *(*uint16)(elem)
|
||||
*(*uint16)(x) = val
|
||||
}
|
||||
e._type = t
|
||||
e.data = x
|
||||
return
|
||||
}
|
||||
|
||||
func convT2E32(t *_type, elem unsafe.Pointer) (e eface) {
|
||||
if raceenabled {
|
||||
raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2E32))
|
||||
}
|
||||
if msanenabled {
|
||||
msanread(elem, t.size)
|
||||
}
|
||||
func convT2E32(t *_type, val uint32) (e eface) {
|
||||
var x unsafe.Pointer
|
||||
if *(*uint32)(elem) == 0 {
|
||||
if val == 0 {
|
||||
x = unsafe.Pointer(&zeroVal[0])
|
||||
} else {
|
||||
x = mallocgc(4, t, false)
|
||||
*(*uint32)(x) = *(*uint32)(elem)
|
||||
*(*uint32)(x) = val
|
||||
}
|
||||
e._type = t
|
||||
e.data = x
|
||||
return
|
||||
}
|
||||
|
||||
func convT2E64(t *_type, elem unsafe.Pointer) (e eface) {
|
||||
if raceenabled {
|
||||
raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2E64))
|
||||
}
|
||||
if msanenabled {
|
||||
msanread(elem, t.size)
|
||||
}
|
||||
func convT2E64(t *_type, val uint64) (e eface) {
|
||||
var x unsafe.Pointer
|
||||
if *(*uint64)(elem) == 0 {
|
||||
if val == 0 {
|
||||
x = unsafe.Pointer(&zeroVal[0])
|
||||
} else {
|
||||
x = mallocgc(8, t, false)
|
||||
*(*uint64)(x) = *(*uint64)(elem)
|
||||
*(*uint64)(x) = val
|
||||
}
|
||||
e._type = t
|
||||
e.data = x
|
||||
@ -418,60 +400,42 @@ func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {
|
||||
return
|
||||
}
|
||||
|
||||
func convT2I16(tab *itab, elem unsafe.Pointer) (i iface) {
|
||||
func convT2I16(tab *itab, val uint16) (i iface) {
|
||||
t := tab._type
|
||||
if raceenabled {
|
||||
raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2I16))
|
||||
}
|
||||
if msanenabled {
|
||||
msanread(elem, t.size)
|
||||
}
|
||||
var x unsafe.Pointer
|
||||
if *(*uint16)(elem) == 0 {
|
||||
if val == 0 {
|
||||
x = unsafe.Pointer(&zeroVal[0])
|
||||
} else {
|
||||
x = mallocgc(2, t, false)
|
||||
*(*uint16)(x) = *(*uint16)(elem)
|
||||
*(*uint16)(x) = val
|
||||
}
|
||||
i.tab = tab
|
||||
i.data = x
|
||||
return
|
||||
}
|
||||
|
||||
func convT2I32(tab *itab, elem unsafe.Pointer) (i iface) {
|
||||
func convT2I32(tab *itab, val uint32) (i iface) {
|
||||
t := tab._type
|
||||
if raceenabled {
|
||||
raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2I32))
|
||||
}
|
||||
if msanenabled {
|
||||
msanread(elem, t.size)
|
||||
}
|
||||
var x unsafe.Pointer
|
||||
if *(*uint32)(elem) == 0 {
|
||||
if val == 0 {
|
||||
x = unsafe.Pointer(&zeroVal[0])
|
||||
} else {
|
||||
x = mallocgc(4, t, false)
|
||||
*(*uint32)(x) = *(*uint32)(elem)
|
||||
*(*uint32)(x) = val
|
||||
}
|
||||
i.tab = tab
|
||||
i.data = x
|
||||
return
|
||||
}
|
||||
|
||||
func convT2I64(tab *itab, elem unsafe.Pointer) (i iface) {
|
||||
func convT2I64(tab *itab, val uint64) (i iface) {
|
||||
t := tab._type
|
||||
if raceenabled {
|
||||
raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2I64))
|
||||
}
|
||||
if msanenabled {
|
||||
msanread(elem, t.size)
|
||||
}
|
||||
var x unsafe.Pointer
|
||||
if *(*uint64)(elem) == 0 {
|
||||
if val == 0 {
|
||||
x = unsafe.Pointer(&zeroVal[0])
|
||||
} else {
|
||||
x = mallocgc(8, t, false)
|
||||
*(*uint64)(x) = *(*uint64)(elem)
|
||||
*(*uint64)(x) = val
|
||||
}
|
||||
i.tab = tab
|
||||
i.data = x
|
||||
|
Loading…
Reference in New Issue
Block a user