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>
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index 637a661..c7223e0 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -83,27 +83,28 @@
"\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" +
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index ef7e408..ee70105 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -131,7 +131,8 @@
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)
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 8173a2e..91895dd 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -1506,11 +1506,27 @@
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:
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index e15e6c4..dd8dcb1 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -36,21 +36,18 @@
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 @@
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
diff --git a/test/fixedbugs/issue4085b.go b/test/fixedbugs/issue4085b.go
index 583c417..b91bbd7 100644
--- a/test/fixedbugs/issue4085b.go
+++ b/test/fixedbugs/issue4085b.go
@@ -15,21 +15,25 @@
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 @@
panic("got panic " + s + ", want " + str)
}
}()
-
+
f()
}