]> Cypherpunks repositories - gostls13.git/commitdiff
math: check overflow in amd64 Exp implementation
authorAlberto Donizetti <alb.donizetti@gmail.com>
Fri, 3 Feb 2017 09:36:47 +0000 (10:36 +0100)
committerRuss Cox <rsc@golang.org>
Fri, 10 Feb 2017 13:40:08 +0000 (13:40 +0000)
Unlike the pure go implementation used by every other architecture,
the amd64 asm implementation of Exp does not fail early if the
argument is known to overflow. Make it fail early.

Cost of the check is < 1ns (on an old Sandy Bridge machine):

name   old time/op  new time/op  delta
Exp-4  18.3ns ± 1%  18.7ns ± 1%  +2.08%  (p=0.000 n=18+20)

Fixes #14932
Fixes #18912

Change-Id: I04b3f9b4ee853822cbdc97feade726fbe2907289
Reviewed-on: https://go-review.googlesource.com/36271
Run-TryBot: Alberto Donizetti <alb.donizetti@gmail.com>
Reviewed-by: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/math/all_test.go
src/math/exp_amd64.s

index 3d8cd7223de0681cc0609c54da3c1f4979826d95..3328904aa79dcbf64f635e9269d5668d1b58338f 100644 (file)
@@ -947,6 +947,11 @@ var vfexpSC = []float64{
        2000,
        Inf(1),
        NaN(),
+       // smallest float64 that overflows Exp(x)
+       7.097827128933841e+02,
+       // Issue 18912
+       1.48852223e+09,
+       1.4885222e+09,
 }
 var expSC = []float64{
        0,
@@ -954,6 +959,27 @@ var expSC = []float64{
        Inf(1),
        Inf(1),
        NaN(),
+       Inf(1),
+       Inf(1),
+       Inf(1),
+}
+
+var vfexp2SC = []float64{
+       Inf(-1),
+       -2000,
+       2000,
+       Inf(1),
+       NaN(),
+       // smallest float64 that overflows Exp2(x)
+       1024,
+}
+var exp2SC = []float64{
+       0,
+       0,
+       Inf(1),
+       Inf(1),
+       NaN(),
+       Inf(1),
 }
 
 var vfexpm1SC = []float64{
@@ -2089,8 +2115,8 @@ func testExp2(t *testing.T, Exp2 func(float64) float64, name string) {
                        t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp2[i])
                }
        }
-       for i := 0; i < len(vfexpSC); i++ {
-               if f := Exp2(vfexpSC[i]); !alike(expSC[i], f) {
+       for i := 0; i < len(vfexp2SC); i++ {
+               if f := Exp2(vfexp2SC[i]); !alike(exp2SC[i], f) {
                        t.Errorf("%s(%g) = %g, want %g", name, vfexpSC[i], f, expSC[i])
                }
        }
index f63efecc414c03bedd9c175237b8cb8b6fb74a0c..96f01b78e7403fd7d744095c8f9cef72e5c2881e 100644 (file)
 #define T7 2.4801587301587301587e-5
 #define PosInf 0x7FF0000000000000
 #define NegInf 0xFFF0000000000000
+#define Overflow 7.09782712893384e+02
 
 // func Exp(x float64) float64
 TEXT ·Exp(SB),NOSPLIT,$0
-// test bits for not-finite
+       // test bits for not-finite
        MOVQ    x+0(FP), BX
        MOVQ    $~(1<<63), AX // sign bit mask
        MOVQ    BX, DX
@@ -42,7 +43,11 @@ TEXT ·Exp(SB),NOSPLIT,$0
        MOVQ    $PosInf, AX
        CMPQ    AX, DX
        JLE     notFinite
+       // check if argument will overflow
        MOVQ    BX, X0
+       MOVSD   $Overflow, X1
+       COMISD  X1, X0
+       JA      overflow
        MOVSD   $LOG2E, X1
        MULSD   X0, X1
        CVTSD2SL X1, BX // BX = exponent