mirror of
https://github.com/golang/go
synced 2024-11-21 15:24:45 -07:00
cmd/gc: inline convT2E when T is uintptr-shaped.
GOARCH=amd64 benchmarks src/pkg/runtime benchmark old ns/op new ns/op delta BenchmarkConvT2ESmall 10 10 +1.00% BenchmarkConvT2EUintptr 9 0 -92.07% BenchmarkConvT2EBig 74 74 -0.27% BenchmarkConvT2I 27 26 -3.62% BenchmarkConvI2E 4 4 -7.05% BenchmarkConvI2I 20 19 -2.99% test/bench/go1 benchmark old ns/op new ns/op delta BenchmarkBinaryTree17 5930908000 5937260000 +0.11% BenchmarkFannkuch11 3927057000 3933556000 +0.17% BenchmarkGobDecode 21998090 21870620 -0.58% BenchmarkGobEncode 12725310 12734480 +0.07% BenchmarkGzip 567617600 567892800 +0.05% BenchmarkGunzip 178284100 178706900 +0.24% BenchmarkJSONEncode 87693550 86794300 -1.03% BenchmarkJSONDecode 314212600 324115000 +3.15% BenchmarkMandelbrot200 7016640 7073766 +0.81% BenchmarkParse 7852100 7892085 +0.51% BenchmarkRevcomp 1285663000 1286147000 +0.04% BenchmarkTemplate 566823800 567606200 +0.14% I'm not entirely sure why the JSON* numbers have changed, but eyeballing the profile suggests that it could be spending less and more time in runtime.{new,old}stack, so it could simply be stack-split boundary noise. R=rsc, dave, bsiegert, dsymonds CC=golang-dev https://golang.org/cl/6280049
This commit is contained in:
parent
733ee91786
commit
8f84328fdc
@ -41,6 +41,14 @@ cgen(Node *n, Node *res)
|
||||
} else
|
||||
cgen_slice(n, res);
|
||||
return;
|
||||
case OEFACE:
|
||||
if (res->op != ONAME || !res->addable) {
|
||||
tempname(&n1, n->type);
|
||||
cgen_eface(n, &n1);
|
||||
cgen(&n1, res);
|
||||
} else
|
||||
cgen_eface(n, res);
|
||||
return;
|
||||
}
|
||||
|
||||
while(n->op == OCONVNOP)
|
||||
@ -598,6 +606,12 @@ agen(Node *n, Node *res)
|
||||
agen(&n1, res);
|
||||
break;
|
||||
|
||||
case OEFACE:
|
||||
tempname(&n1, n->type);
|
||||
cgen_eface(n, &n1);
|
||||
agen(&n1, res);
|
||||
break;
|
||||
|
||||
case OINDEX:
|
||||
p2 = nil; // to be patched to panicindex.
|
||||
w = n->type->width;
|
||||
|
@ -44,6 +44,14 @@ cgen(Node *n, Node *res)
|
||||
} else
|
||||
cgen_slice(n, res);
|
||||
goto ret;
|
||||
case OEFACE:
|
||||
if (res->op != ONAME || !res->addable) {
|
||||
tempname(&n1, n->type);
|
||||
cgen_eface(n, &n1);
|
||||
cgen(&n1, res);
|
||||
} else
|
||||
cgen_eface(n, res);
|
||||
goto ret;
|
||||
}
|
||||
|
||||
if(n->ullman >= UINF) {
|
||||
@ -549,6 +557,12 @@ agen(Node *n, Node *res)
|
||||
agen(&n1, res);
|
||||
break;
|
||||
|
||||
case OEFACE:
|
||||
tempname(&n1, n->type);
|
||||
cgen_eface(n, &n1);
|
||||
agen(&n1, res);
|
||||
break;
|
||||
|
||||
case OINDEX:
|
||||
w = n->type->width;
|
||||
if(nr->addable)
|
||||
|
@ -74,6 +74,14 @@ cgen(Node *n, Node *res)
|
||||
} else
|
||||
cgen_slice(n, res);
|
||||
return;
|
||||
case OEFACE:
|
||||
if (res->op != ONAME || !res->addable) {
|
||||
tempname(&n1, n->type);
|
||||
cgen_eface(n, &n1);
|
||||
cgen(&n1, res);
|
||||
} else
|
||||
cgen_eface(n, res);
|
||||
return;
|
||||
}
|
||||
|
||||
while(n->op == OCONVNOP)
|
||||
@ -549,6 +557,12 @@ agen(Node *n, Node *res)
|
||||
agen(&n1, res);
|
||||
break;
|
||||
|
||||
case OEFACE:
|
||||
tempname(&n1, n->type);
|
||||
cgen_eface(n, &n1);
|
||||
agen(&n1, res);
|
||||
break;
|
||||
|
||||
case OINDEX:
|
||||
p2 = nil; // to be patched to panicindex.
|
||||
w = n->type->width;
|
||||
|
@ -737,6 +737,22 @@ ret:
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate:
|
||||
* res = iface{typ, data}
|
||||
* n->left is typ
|
||||
* n->right is data
|
||||
*/
|
||||
void
|
||||
cgen_eface(Node *n, Node *res)
|
||||
{
|
||||
Node dst;
|
||||
dst = *res;
|
||||
dst.type = types[tptr];
|
||||
cgen(n->left, &dst);
|
||||
dst.xoffset += widthptr;
|
||||
cgen(n->right, &dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* generate:
|
||||
@ -744,15 +760,12 @@ ret:
|
||||
* n->left is s
|
||||
* n->list is (cap(s)-lo(TUINT32), hi-lo(TUINT32)[, lo*width(TUINTPTR)])
|
||||
* caller (cgen) guarantees res is an addable ONAME.
|
||||
*
|
||||
*/
|
||||
void
|
||||
cgen_slice(Node *n, Node *res)
|
||||
{
|
||||
Node src, dst, *cap, *len, *offs, *add;
|
||||
|
||||
// print("cgen_slice: %N = %+N\n", res, n);
|
||||
|
||||
cap = n->list->n;
|
||||
len = n->list->next->n;
|
||||
offs = N;
|
||||
|
@ -488,6 +488,7 @@ enum
|
||||
ODDD,
|
||||
ODDDARG,
|
||||
OINLCALL, // intermediary representation of an inlined call
|
||||
OEFACE, // itable and data words of empty-interface value
|
||||
OITAB, // itable word of interface value
|
||||
|
||||
// for back ends
|
||||
@ -989,6 +990,7 @@ void dumplist(char *s, NodeList *l);
|
||||
void addrescapes(Node *n);
|
||||
void cgen_as(Node *nl, Node *nr);
|
||||
void cgen_callmeth(Node *n, int proc);
|
||||
void cgen_eface(Node* n, Node* res);
|
||||
void cgen_slice(Node* n, Node* res);
|
||||
void clearlabels(void);
|
||||
void checklabels(void);
|
||||
|
@ -436,6 +436,11 @@ walkexpr(Node **np, NodeList **init)
|
||||
walkexpr(&n->left, init);
|
||||
goto ret;
|
||||
|
||||
case OEFACE:
|
||||
walkexpr(&n->left, init);
|
||||
walkexpr(&n->right, init);
|
||||
goto ret;
|
||||
|
||||
case OITAB:
|
||||
walkexpr(&n->left, init);
|
||||
goto ret;
|
||||
@ -713,10 +718,22 @@ walkexpr(Node **np, NodeList **init)
|
||||
goto ret;
|
||||
|
||||
case OCONVIFACE:
|
||||
walkexpr(&n->left, init);
|
||||
|
||||
// Optimize convT2E as a two-word copy when T is uintptr-shaped.
|
||||
if(!isinter(n->left->type) && isnilinter(n->type) &&
|
||||
(n->left->type->width == widthptr) &&
|
||||
isint[simsimtype(n->left->type)]) {
|
||||
l = nod(OEFACE, typename(n->left->type), n->left);
|
||||
l->type = n->type;
|
||||
l->typecheck = n->typecheck;
|
||||
n = l;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// Build name of function: convI2E etc.
|
||||
// Not all names are possible
|
||||
// (e.g., we'll never generate convE2E or convE2I).
|
||||
walkexpr(&n->left, init);
|
||||
strcpy(buf, "conv");
|
||||
p = buf+strlen(buf);
|
||||
if(isnilinter(n->left->type))
|
||||
|
@ -20,14 +20,20 @@ var (
|
||||
Big [2]*int
|
||||
)
|
||||
|
||||
func BenchmarkConvT2E(b *testing.B) {
|
||||
func BenchmarkConvT2ESmall(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
I = 1
|
||||
I = uint16(1)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConvT2EUintptr(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
I = uintptr(1)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConvT2EBig(b *testing.B) {
|
||||
v := [2]*int{}
|
||||
v := [2]uintptr{1, 2}
|
||||
for i := 0; i < b.N; i++ {
|
||||
I = v
|
||||
}
|
||||
|
114
test/convT2E.go
Normal file
114
test/convT2E.go
Normal file
@ -0,0 +1,114 @@
|
||||
// run
|
||||
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Test conversion from non-interface types to the empty interface.
|
||||
|
||||
package main
|
||||
|
||||
var (
|
||||
z = struct{}{}
|
||||
p = &z
|
||||
pp = &p
|
||||
u16 = uint16(1)
|
||||
u32 = uint32(2)
|
||||
u64 = uint64(3)
|
||||
u128 = [2]uint64{4, 5}
|
||||
f32 = float32(6)
|
||||
f64 = float64(7)
|
||||
c128 = complex128(8 + 9i)
|
||||
s = "10"
|
||||
b = []byte("11")
|
||||
m = map[int]int{12: 13}
|
||||
c = make(chan int, 14)
|
||||
)
|
||||
|
||||
var (
|
||||
iz interface{} = z
|
||||
ip interface{} = p
|
||||
ipp interface{} = pp
|
||||
iu16 interface{} = u16
|
||||
iu32 interface{} = u32
|
||||
iu64 interface{} = u64
|
||||
iu128 interface{} = u128
|
||||
if32 interface{} = f32
|
||||
if64 interface{} = f64
|
||||
ic128 interface{} = c128
|
||||
is interface{} = s
|
||||
ib interface{} = b
|
||||
im interface{} = m
|
||||
ic interface{} = c
|
||||
)
|
||||
|
||||
func second(a ...interface{}) interface{} {
|
||||
return a[1]
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Test equality. There are no tests for b and m, as slices and
|
||||
// maps are not comparable by ==.
|
||||
if z != iz {
|
||||
panic("z != iz")
|
||||
}
|
||||
if p != ip {
|
||||
panic("p != ip")
|
||||
}
|
||||
if pp != ipp {
|
||||
panic("pp != ipp")
|
||||
}
|
||||
if u16 != iu16 {
|
||||
panic("u16 != iu16")
|
||||
}
|
||||
if u32 != iu32 {
|
||||
panic("u32 != iu32")
|
||||
}
|
||||
if u64 != iu64 {
|
||||
panic("u64 != iu64")
|
||||
}
|
||||
if u128 != iu128 {
|
||||
panic("u128 != iu128")
|
||||
}
|
||||
if f32 != if32 {
|
||||
panic("f32 != if32")
|
||||
}
|
||||
if f64 != if64 {
|
||||
panic("f64 != if64")
|
||||
}
|
||||
if c128 != ic128 {
|
||||
panic("c128 != ic128")
|
||||
}
|
||||
if s != is {
|
||||
panic("s != is")
|
||||
}
|
||||
if c != ic {
|
||||
panic("c != ic")
|
||||
}
|
||||
|
||||
// Test that non-interface types can be used as ...interface{} arguments.
|
||||
if got := second(z, p, pp, u16, u32, u64, u128, f32, f64, c128, s, b, m, c); got != ip {
|
||||
println("second: got", got, "want", ip)
|
||||
panic("fail")
|
||||
}
|
||||
|
||||
// Test that non-interface types can be sent on a chan interface{}.
|
||||
const n = 100
|
||||
uc := make(chan interface{})
|
||||
go func() {
|
||||
for i := 0; i < n; i++ {
|
||||
select {
|
||||
case uc <- nil:
|
||||
case uc <- u32:
|
||||
case uc <- u64:
|
||||
case uc <- u128:
|
||||
}
|
||||
}
|
||||
}()
|
||||
for i := 0; i < n; i++ {
|
||||
if got := <-uc; got != nil && got != u32 && got != u64 && got != u128 {
|
||||
println("recv: i", i, "got", got)
|
||||
panic("fail")
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user