Skip to content

Commit d42b520

Browse files
committed
math/big: make NewInt inlineable and zero allocation
Mark the assembly routines as not escaping their arguments. Add a special case to NewInt that, when inlined, can do all of its allocations (a big.Int and a [1]Word) on the stack. Update #29951 Change-Id: I9bd38c262eb97df98c0ed9874da7daac381243ea Reviewed-on: https://go-review.googlesource.com/c/go/+/411254 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Keith Randall <[email protected]> Run-TryBot: Keith Randall <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent c2a9c55 commit d42b520

File tree

3 files changed

+55
-2
lines changed

3 files changed

+55
-2
lines changed

src/math/big/arith_decl.go

+16
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,27 @@
88
package big
99

1010
// implemented in arith_$GOARCH.s
11+
12+
//go:noescape
1113
func addVV(z, x, y []Word) (c Word)
14+
15+
//go:noescape
1216
func subVV(z, x, y []Word) (c Word)
17+
18+
//go:noescape
1319
func addVW(z, x []Word, y Word) (c Word)
20+
21+
//go:noescape
1422
func subVW(z, x []Word, y Word) (c Word)
23+
24+
//go:noescape
1525
func shlVU(z, x []Word, s uint) (c Word)
26+
27+
//go:noescape
1628
func shrVU(z, x []Word, s uint) (c Word)
29+
30+
//go:noescape
1731
func mulAddVWW(z, x []Word, y, r Word) (c Word)
32+
33+
//go:noescape
1834
func addMulVVW(z, x []Word, y Word) (c Word)

src/math/big/int.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,20 @@ func (z *Int) SetUint64(x uint64) *Int {
6565

6666
// NewInt allocates and returns a new Int set to x.
6767
func NewInt(x int64) *Int {
68-
return new(Int).SetInt64(x)
68+
// This code is arranged to be inlineable and produce
69+
// zero allocations when inlined. See issue 29951.
70+
u := uint64(x)
71+
if x < 0 {
72+
u = -u
73+
}
74+
var abs []Word
75+
if x == 0 {
76+
} else if _W == 32 && u>>32 != 0 {
77+
abs = []Word{Word(u), Word(u >> 32)}
78+
} else {
79+
abs = []Word{Word(u)}
80+
}
81+
return &Int{neg: x < 0, abs: abs}
6982
}
7083

7184
// Set sets z to x and returns z.

src/math/big/int_test.go

+25-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"bytes"
99
"encoding/hex"
1010
"fmt"
11+
"math"
1112
"math/rand"
1213
"strconv"
1314
"strings"
@@ -92,7 +93,7 @@ func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
9293
t.Errorf("%s%v is not normalized", msg, z)
9394
}
9495
if (&z).Cmp(a.z) != 0 {
95-
t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z)
96+
t.Errorf("%v %s %v\n\tgot z = %v; want %v", a.x, msg, a.y, &z, a.z)
9697
}
9798
}
9899

@@ -1894,3 +1895,26 @@ func TestFillBytes(t *testing.T) {
18941895
})
18951896
}
18961897
}
1898+
1899+
func TestNewIntMinInt64(t *testing.T) {
1900+
// Test for uint64 cast in NewInt.
1901+
want := int64(math.MinInt64)
1902+
if got := NewInt(want).Int64(); got != want {
1903+
t.Fatalf("wanted %d, got %d", want, got)
1904+
}
1905+
}
1906+
1907+
func TestNewIntAllocs(t *testing.T) {
1908+
for _, n := range []int64{0, 7, -7, 1 << 30, -1 << 30, 1 << 50, -1 << 50} {
1909+
x := NewInt(3)
1910+
got := testing.AllocsPerRun(100, func() {
1911+
// NewInt should inline, and all its allocations
1912+
// can happen on the stack. Passing the result of NewInt
1913+
// to Add should not cause any of those allocations to escape.
1914+
x.Add(x, NewInt(n))
1915+
})
1916+
if got != 0 {
1917+
t.Errorf("x.Add(x, NewInt(%d)), wanted 0 allocations, got %f", n, got)
1918+
}
1919+
}
1920+
}

0 commit comments

Comments
 (0)