mirror of
https://github.com/golang/go
synced 2024-11-22 03:14:41 -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
|
} else
|
||||||
cgen_slice(n, res);
|
cgen_slice(n, res);
|
||||||
return;
|
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)
|
while(n->op == OCONVNOP)
|
||||||
@ -598,6 +606,12 @@ agen(Node *n, Node *res)
|
|||||||
agen(&n1, res);
|
agen(&n1, res);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OEFACE:
|
||||||
|
tempname(&n1, n->type);
|
||||||
|
cgen_eface(n, &n1);
|
||||||
|
agen(&n1, res);
|
||||||
|
break;
|
||||||
|
|
||||||
case OINDEX:
|
case OINDEX:
|
||||||
p2 = nil; // to be patched to panicindex.
|
p2 = nil; // to be patched to panicindex.
|
||||||
w = n->type->width;
|
w = n->type->width;
|
||||||
|
@ -44,6 +44,14 @@ cgen(Node *n, Node *res)
|
|||||||
} else
|
} else
|
||||||
cgen_slice(n, res);
|
cgen_slice(n, res);
|
||||||
goto ret;
|
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) {
|
if(n->ullman >= UINF) {
|
||||||
@ -549,6 +557,12 @@ agen(Node *n, Node *res)
|
|||||||
agen(&n1, res);
|
agen(&n1, res);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OEFACE:
|
||||||
|
tempname(&n1, n->type);
|
||||||
|
cgen_eface(n, &n1);
|
||||||
|
agen(&n1, res);
|
||||||
|
break;
|
||||||
|
|
||||||
case OINDEX:
|
case OINDEX:
|
||||||
w = n->type->width;
|
w = n->type->width;
|
||||||
if(nr->addable)
|
if(nr->addable)
|
||||||
|
@ -74,6 +74,14 @@ cgen(Node *n, Node *res)
|
|||||||
} else
|
} else
|
||||||
cgen_slice(n, res);
|
cgen_slice(n, res);
|
||||||
return;
|
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)
|
while(n->op == OCONVNOP)
|
||||||
@ -549,6 +557,12 @@ agen(Node *n, Node *res)
|
|||||||
agen(&n1, res);
|
agen(&n1, res);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OEFACE:
|
||||||
|
tempname(&n1, n->type);
|
||||||
|
cgen_eface(n, &n1);
|
||||||
|
agen(&n1, res);
|
||||||
|
break;
|
||||||
|
|
||||||
case OINDEX:
|
case OINDEX:
|
||||||
p2 = nil; // to be patched to panicindex.
|
p2 = nil; // to be patched to panicindex.
|
||||||
w = n->type->width;
|
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:
|
* generate:
|
||||||
@ -744,15 +760,12 @@ ret:
|
|||||||
* n->left is s
|
* n->left is s
|
||||||
* n->list is (cap(s)-lo(TUINT32), hi-lo(TUINT32)[, lo*width(TUINTPTR)])
|
* n->list is (cap(s)-lo(TUINT32), hi-lo(TUINT32)[, lo*width(TUINTPTR)])
|
||||||
* caller (cgen) guarantees res is an addable ONAME.
|
* caller (cgen) guarantees res is an addable ONAME.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
cgen_slice(Node *n, Node *res)
|
cgen_slice(Node *n, Node *res)
|
||||||
{
|
{
|
||||||
Node src, dst, *cap, *len, *offs, *add;
|
Node src, dst, *cap, *len, *offs, *add;
|
||||||
|
|
||||||
// print("cgen_slice: %N = %+N\n", res, n);
|
|
||||||
|
|
||||||
cap = n->list->n;
|
cap = n->list->n;
|
||||||
len = n->list->next->n;
|
len = n->list->next->n;
|
||||||
offs = N;
|
offs = N;
|
||||||
|
@ -488,6 +488,7 @@ enum
|
|||||||
ODDD,
|
ODDD,
|
||||||
ODDDARG,
|
ODDDARG,
|
||||||
OINLCALL, // intermediary representation of an inlined call
|
OINLCALL, // intermediary representation of an inlined call
|
||||||
|
OEFACE, // itable and data words of empty-interface value
|
||||||
OITAB, // itable word of interface value
|
OITAB, // itable word of interface value
|
||||||
|
|
||||||
// for back ends
|
// for back ends
|
||||||
@ -989,6 +990,7 @@ void dumplist(char *s, NodeList *l);
|
|||||||
void addrescapes(Node *n);
|
void addrescapes(Node *n);
|
||||||
void cgen_as(Node *nl, Node *nr);
|
void cgen_as(Node *nl, Node *nr);
|
||||||
void cgen_callmeth(Node *n, int proc);
|
void cgen_callmeth(Node *n, int proc);
|
||||||
|
void cgen_eface(Node* n, Node* res);
|
||||||
void cgen_slice(Node* n, Node* res);
|
void cgen_slice(Node* n, Node* res);
|
||||||
void clearlabels(void);
|
void clearlabels(void);
|
||||||
void checklabels(void);
|
void checklabels(void);
|
||||||
|
@ -436,6 +436,11 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
walkexpr(&n->left, init);
|
walkexpr(&n->left, init);
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
|
case OEFACE:
|
||||||
|
walkexpr(&n->left, init);
|
||||||
|
walkexpr(&n->right, init);
|
||||||
|
goto ret;
|
||||||
|
|
||||||
case OITAB:
|
case OITAB:
|
||||||
walkexpr(&n->left, init);
|
walkexpr(&n->left, init);
|
||||||
goto ret;
|
goto ret;
|
||||||
@ -713,10 +718,22 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
case OCONVIFACE:
|
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.
|
// Build name of function: convI2E etc.
|
||||||
// Not all names are possible
|
// Not all names are possible
|
||||||
// (e.g., we'll never generate convE2E or convE2I).
|
// (e.g., we'll never generate convE2E or convE2I).
|
||||||
walkexpr(&n->left, init);
|
|
||||||
strcpy(buf, "conv");
|
strcpy(buf, "conv");
|
||||||
p = buf+strlen(buf);
|
p = buf+strlen(buf);
|
||||||
if(isnilinter(n->left->type))
|
if(isnilinter(n->left->type))
|
||||||
|
@ -20,14 +20,20 @@ var (
|
|||||||
Big [2]*int
|
Big [2]*int
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkConvT2E(b *testing.B) {
|
func BenchmarkConvT2ESmall(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
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) {
|
func BenchmarkConvT2EBig(b *testing.B) {
|
||||||
v := [2]*int{}
|
v := [2]uintptr{1, 2}
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
I = v
|
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