cmd/compile: generate makeslice calls with int arguments

Where possible generate calls to runtime makeslice with int arguments
during compile time instead of makeslice with int64 arguments.

This eliminates converting arguments for calls to makeslice with
int64 arguments for platforms where int64 values do not fit into
arguments of type int.

godoc 386 binary shrinks by approximately 12 kilobyte.

amd64:
name         old time/op  new time/op  delta
MakeSlice-2  29.8ns ± 1%  29.8ns ± 1%   ~     (p=1.000 n=24+24)

386:
name         old time/op  new time/op  delta
MakeSlice-2  52.3ns ± 0%  45.9ns ± 0%  -12.17%  (p=0.000 n=25+22)

Fixes  #15357

Change-Id: Icb8701bb63c5a83877d26c8a4b78e782ba76de7c
Reviewed-on: https://go-review.googlesource.com/27851
Run-TryBot: Martin Möhrmann <martisch@uos.de>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
This commit is contained in:
Martin Möhrmann 2016-08-25 14:17:52 +02:00 committed by Martin Möhrmann
parent 595cebb055
commit e6f9f39ce5
5 changed files with 74 additions and 41 deletions

View file

@ -83,27 +83,28 @@ const runtimeimport = "" +
"\t\x15selectrecv2\x00\b\x17\"\xb4\x02\x00\x00\x1f\x02:\xfc\x01\x00\x00\x17:\xfe\x01\x00\x00\x17\x00\x15rec" +
"eived·5\x00\x00\x02\x00\xb6\x02\x00\x00\t\x19selectdefault\x00\x02\x17\"\xb4\x02\x00\x00\x02" +
"\x00\xb6\x02\x00\x00\t\x0fselectgo\x00\x02\x17\"\xac\x02\x00\x00\x00\t\tblock\x00\x00\x00\t\x11make" +
"slice\x00\x06\x17\"\x06\x00\x00\n\vnel·3\x00\x00\n\vcap·4\x00\x00\x02\x11:\vary\xc2" +
"\xb71\x00\x00\t\x11growslice\x00\x06\x17\"\x06\x00\x00\x11:\vold·3\x00\x00\x02\xc8\x02\x00\x00\x02\x11" +
":\xca\x02\x00\x00\t\rmemmove\x00\x06\x17:\tto·1\x00\x00\x17:\vfrm·2\x00\x00\x16\x11l" +
"ength·3\x00b\x00\t\vmemclr\x00\x04\x17\"\vptr·1\x00\x00\x16\x11length" +
"·2\x00b\x00\t\x0fmemequal\x00\x06\x17:\ax·2\x00\x00\x17:\ay·3\x00\x00\x16\rsi" +
"ze·4\x00b\x01\x00\x00\t\x11memequal8\x00\x04\x17:\xe0\x02\x00\x00\x17:\xe2\x02\x00\x00\x01\x00\x00\t\x13" +
"memequal16\x00\x04\x17:\xe0\x02\x00\x00\x17:\xe2\x02\x00\x00\x01\x00\x00\t\x13memequal32\x00" +
"\x04\x17:\xe0\x02\x00\x00\x17:\xe2\x02\x00\x00\x01\x00\x00\t\x13memequal64\x00\x04\x17:\xe0\x02\x00\x00\x17:\xe2\x02" +
"\x00\x00\x01\x00\x00\t\x15memequal128\x00\x04\x17:\xe0\x02\x00\x00\x17:\xe2\x02\x00\x00\x01\x00\x00\t\x0fint" +
"64div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint6" +
"4mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat" +
"64toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64touint64\x00\x01\x1a\x00\x01\x14\x00" +
"\t\x1dfloat64touint32\x00\x01\x1a\x00\x01\x12\x00\t\x1bint64tofloat64" +
"\x00\x01\n\x00\x01\x1a\x00\t\x1duint64tofloat64\x00\x01\x14\x00\x01\x1a\x00\t\x1duint32t" +
"ofloat64\x00\x01\x12\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e\vnum·2" +
"\x00\x00\x1e\vden·3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefuncenter\x00\x01" +
"\x16b\x00\t\x17racefuncexit\x00\x00\x00\t\x0fraceread\x00\x01\x16b\x00\t\x11rac" +
"ewrite\x00\x01\x16b\x00\t\x19racereadrange\x00\x04\x16\raddr·1\x00b\x16" +
"\rsize·2\x00b\x00\t\x1bracewriterange\x00\x04\x16\x96\x03\x00b\x16\x98\x03\x00b\x00" +
"\t\x0fmsanread\x00\x04\x16\x96\x03\x00b\x16\x98\x03\x00b\x00\t\x11msanwrite\x00\x04\x16\x96\x03\x00" +
"b\x16\x98\x03\x00b\x00\v\xf8\x01\v\x00\x01\x00\n$$\n"
"slice\x00\x06\x17\"\x06\x00\x00\x02\vlen·3\x00\x00\x02\vcap·4\x00\x00\x02\x11:\vary\xc2" +
"\xb71\x00\x00\t\x15makeslice64\x00\x06\x17\"\x06\x00\x00\n\xc6\x02\x00\x00\n\xc8\x02\x00\x00\x02\x11:\xca\x02\x00" +
"\x00\t\x11growslice\x00\x06\x17\"\x06\x00\x00\x11:\vold·3\x00\x00\x02\xc8\x02\x00\x00\x02\x11:\xca\x02" +
"\x00\x00\t\rmemmove\x00\x06\x17:\tto·1\x00\x00\x17:\vfrm·2\x00\x00\x16\x11leng" +
"th·3\x00b\x00\t\vmemclr\x00\x04\x17\"\vptr·1\x00\x00\x16\x11length·2" +
"\x00b\x00\t\x0fmemequal\x00\x06\x17:\ax·2\x00\x00\x17:\ay·3\x00\x00\x16\rsize\xc2" +
"\xb74\x00b\x01\x00\x00\t\x11memequal8\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13mem" +
"equal16\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal32\x00\x04\x17:" +
"\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal64\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01" +
"\x00\x00\t\x15memequal128\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x0fint64d" +
"iv\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64mo" +
"d\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat64t" +
"oint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64touint64\x00\x01\x1a\x00\x01\x14\x00\t\x1df" +
"loat64touint32\x00\x01\x1a\x00\x01\x12\x00\t\x1bint64tofloat64\x00\x01\n" +
"\x00\x01\x1a\x00\t\x1duint64tofloat64\x00\x01\x14\x00\x01\x1a\x00\t\x1duint32tofl" +
"oat64\x00\x01\x12\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e\vnum·2\x00\x00\x1e" +
"\vden·3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefuncenter\x00\x01\x16b\x00" +
"\t\x17racefuncexit\x00\x00\x00\t\x0fraceread\x00\x01\x16b\x00\t\x11racewr" +
"ite\x00\x01\x16b\x00\t\x19racereadrange\x00\x04\x16\raddr·1\x00b\x16\rsi" +
"ze·2\x00b\x00\t\x1bracewriterange\x00\x04\x16\x98\x03\x00b\x16\x9a\x03\x00b\x00\t\x0fm" +
"sanread\x00\x04\x16\x98\x03\x00b\x16\x9a\x03\x00b\x00\t\x11msanwrite\x00\x04\x16\x98\x03\x00b\x16\x9a" +
"\x03\x00b\x00\v\xfa\x01\v\x00\x01\x00\n$$\n"
const unsafeimport = "" +
"version 2\n\n\x00\x00\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOff" +

View file

@ -131,7 +131,8 @@ func selectdefault(sel *byte) (selected bool)
func selectgo(sel *byte)
func block()
func makeslice(typ *byte, nel int64, cap int64) (ary []any)
func makeslice(typ *byte, len int, cap int) (ary []any)
func makeslice64(typ *byte, len int64, cap int64) (ary []any)
func growslice(typ *byte, old []any, cap int) (ary []any)
func memmove(to *any, frm *any, length uintptr)
func memclr(ptr *byte, length uintptr)

View file

@ -1506,11 +1506,27 @@ opswitch:
r = walkexpr(r, init)
n = r
} else {
// makeslice(et *Type, nel int64, max int64) (ary []any)
fn := syslook("makeslice")
// n escapes; set up a call to makeslice.
// When len and cap can fit into int, use makeslice instead of
// makeslice64, which is faster and shorter on 32 bit platforms.
len, cap := l, r
fnname := "makeslice64"
argtype := Types[TINT64]
// typechecking guarantees that TIDEAL len/cap are positive and fit in an int.
// The case of len or cap overflow when converting TUINT or TUINTPTR to TINT
// will be handled by the negative range checks in makeslice during runtime.
if (len.Type.IsKind(TIDEAL) || Maxintval[len.Type.Etype].Cmp(Maxintval[TUINT]) <= 0) &&
(cap.Type.IsKind(TIDEAL) || Maxintval[cap.Type.Etype].Cmp(Maxintval[TUINT]) <= 0) {
fnname = "makeslice"
argtype = Types[TINT]
}
fn := syslook(fnname)
fn = substArgTypes(fn, t.Elem()) // any-1
n = mkcall1(fn, n.Type, init, typename(t.Elem()), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
n = mkcall1(fn, t, init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
}
case ORUNESTR:

View file

@ -36,21 +36,18 @@ func maxSliceCap(elemsize uintptr) uintptr {
return _MaxMem / elemsize
}
// TODO: take uintptrs instead of int64s?
func makeslice(et *_type, len64, cap64 int64) slice {
func makeslice(et *_type, len, cap int) slice {
// NOTE: The len > maxElements check here is not strictly necessary,
// but it produces a 'len out of range' error instead of a 'cap out of range' error
// when someone does make([]T, bignumber). 'cap out of range' is true too,
// but since the cap is only being supplied implicitly, saying len is clearer.
// See issue 4085.
maxElements := maxSliceCap(et.size)
len := int(len64)
if len64 < 0 || int64(len) != len64 || uintptr(len) > maxElements {
if len < 0 || uintptr(len) > maxElements {
panic(errorString("makeslice: len out of range"))
}
cap := int(cap64)
if cap < len || int64(cap) != cap64 || uintptr(cap) > maxElements {
if cap < len || uintptr(cap) > maxElements {
panic(errorString("makeslice: cap out of range"))
}
@ -58,6 +55,20 @@ func makeslice(et *_type, len64, cap64 int64) slice {
return slice{p, len, cap}
}
func makeslice64(et *_type, len64, cap64 int64) slice {
len := int(len64)
if int64(len) != len64 {
panic(errorString("makeslice: len out of range"))
}
cap := int(cap64)
if int64(cap) != cap64 {
panic(errorString("makeslice: cap out of range"))
}
return makeslice(et, len, cap)
}
// growslice handles slice growth during append.
// It is passed the slice element type, the old slice, and the desired new minimum capacity,
// and it returns a new slice with at least that capacity, with the old data

View file

@ -15,21 +15,25 @@ type T []int
func main() {
n := -1
shouldPanic("len out of range", func() {_ = make(T, n)})
shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
shouldPanic("len out of range", func() { _ = make(T, n) })
shouldPanic("cap out of range", func() { _ = make(T, 0, n) })
shouldPanic("len out of range", func() { _ = make(T, int64(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) })
var t *byte
if unsafe.Sizeof(t) == 8 {
n = 1<<20
n = 1 << 20
n <<= 20
shouldPanic("len out of range", func() {_ = make(T, n)})
shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
shouldPanic("len out of range", func() { _ = make(T, n) })
shouldPanic("cap out of range", func() { _ = make(T, 0, n) })
n <<= 20
shouldPanic("len out of range", func() {_ = make(T, n)})
shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
shouldPanic("len out of range", func() { _ = make(T, n) })
shouldPanic("cap out of range", func() { _ = make(T, 0, n) })
} else {
n = 1<<31 - 1
shouldPanic("len out of range", func() {_ = make(T, n)})
shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
shouldPanic("len out of range", func() { _ = make(T, n) })
shouldPanic("cap out of range", func() { _ = make(T, 0, n) })
shouldPanic("len out of range", func() { _ = make(T, int64(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) })
}
}
@ -44,6 +48,6 @@ func shouldPanic(str string, f func()) {
panic("got panic " + s + ", want " + str)
}
}()
f()
}