root/src/pkg/math/sincos_amd64.s

/* [<][>][^][v][top][bottom][index][help] */
// Copyright 2010 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.

#include "../../cmd/ld/textflag.h"

// The method is based on a paper by Naoki Shibata: "Efficient evaluation
// methods of elementary functions suitable for SIMD computation", Proc.
// of International Supercomputing Conference 2010 (ISC'10), pp. 25 -- 32
// (May 2010). The paper is available at
// http://www.springerlink.com/content/340228x165742104/
//
// The original code and the constants below are from the author's
// implementation available at http://freshmeat.net/projects/sleef.
// The README file says, "The software is in public domain.
// You can use the software without any obligation."
//
// This code is a simplified version of the original.  The CMPSD
// instruction, not generated by the compiler, eliminates jumps in the
// body of the calculation.

#define PosOne 0x3FF0000000000000
#define PosInf 0x7FF0000000000000
#define NaN    0x7FF8000000000001
#define PI4A 0.7853981554508209228515625 // pi/4 split into three parts
#define PI4B 0.794662735614792836713604629039764404296875e-8
#define PI4C 0.306161699786838294306516483068750264552437361480769e-16
#define M4PI 1.273239544735162542821171882678754627704620361328125 // 4/pi
#define T0 1.0
#define T1 -8.33333333333333333333333e-02 // (-1.0/12)
#define T2 2.77777777777777777777778e-03 // (+1.0/360)
#define T3 -4.96031746031746031746032e-05 // (-1.0/20160)
#define T4 5.51146384479717813051146e-07 // (+1.0/1814400)

// func Sincos(d float64) (sin, cos float64)
TEXT ·Sincos(SB),NOSPLIT,$0
        // test for special cases
        MOVQ    $~(1<<63), DX // sign bit mask
        MOVQ    x+0(FP), BX
        ANDQ    BX, DX
        JEQ     isZero
        MOVQ    $PosInf, AX
        CMPQ    AX, DX
        JLE     isInfOrNaN
        // Reduce argument
        MOVQ    BX, X7 // x7= d
        MOVQ    DX, X0 // x0= |d|
        MOVSD   $M4PI, X2
        MULSD   X0, X2
        CVTTSD2SQ X2, BX // bx= q
        MOVQ    $1, AX
        ANDQ    BX, AX
        ADDQ    BX, AX
        CVTSQ2SD AX, X2
        MOVSD   $PI4A, X3
        MULSD   X2, X3
        SUBSD   X3, X0
        MOVSD   $PI4B, X3
        MULSD   X2, X3
        SUBSD   X3, X0
        MOVSD   $PI4C, X3
        MULSD   X2, X3
        SUBSD   X3, X0
        MULSD   $0.125, X0 // x0= x, x7= d, bx= q
        // Evaluate Taylor series
        MULSD   X0, X0
        MOVSD   $T4, X2
        MULSD   X0, X2
        ADDSD   $T3, X2
        MULSD   X0, X2
        ADDSD   $T2, X2
        MULSD   X0, X2
        ADDSD   $T1, X2
        MULSD   X0, X2
        ADDSD   $T0, X2
        MULSD   X2, X0 // x0= x, x7= d, bx= q
        // Apply double angle formula
        MOVSD   $4.0, X2
        SUBSD   X0, X2
        MULSD   X2, X0
        MOVSD   $4.0, X2
        SUBSD   X0, X2
        MULSD   X2, X0
        MOVSD   $4.0, X2
        SUBSD   X0, X2
        MULSD   X2, X0
        MULSD   $0.5, X0 // x0= x, x7= d, bx= q
        // sin = sqrt((2 - x) * x)
        MOVSD   $2.0, X2
        SUBSD   X0, X2
        MULSD   X0, X2
        SQRTSD  X2, X2 // x0= x, x2= z, x7= d, bx= q
        // cos = 1 - x
        MOVSD   $1.0, X1
        SUBSD   X0, X1 // x1= x, x2= z, x7= d, bx= q
        // if ((q + 1) & 2) != 0 { sin, cos = cos, sin }
        MOVQ    $1, DX
        ADDQ    BX, DX
        MOVQ    $2, AX
        ANDQ    AX, DX
        MOVQ    DX, X0
        MOVSD   $0.0, X3
        CMPSD   X0, X3, 0 // cmpeq; x1= x, x2= z, x3 = y, x7= d, bx= q
        // sin = (y & z) | (^y & x)
        MOVAPD  X2, X0
        ANDPD   X3, X0 // x0= sin
        MOVAPD  X3, X4
        ANDNPD  X1, X4
        ORPD    X4, X0 // x0= sin, x1= x, x2= z, x3= y, x7= d, bx= q
        // cos = (y & x) | (^y & z)
        ANDPD   X3, X1 // x1= cos
        ANDNPD  X2, X3
        ORPD    X3, X1 // x0= sin, x1= cos, x7= d, bx= q
        // if ((q & 4) != 0) != (d < 0) { sin = -sin }
        MOVQ    BX, AX
        MOVQ    $61, CX
        SHLQ    CX, AX
        MOVQ    AX, X3
        XORPD   X7, X3
        MOVQ    $(1<<63), AX
        MOVQ    AX, X2 // x2= -0.0
        ANDPD   X2, X3
        ORPD    X3, X0 // x0= sin, x1= cos, x2= -0.0, bx= q
        // if ((q + 2) & 4) != 0 { cos = -cos }
        MOVQ    $2, AX
        ADDQ    AX, BX
        MOVQ    $61, CX
        SHLQ    CX, BX
        MOVQ    BX, X3
        ANDPD   X2, X3
        ORPD    X3, X1 // x0= sin, x1= cos
        // return (sin, cos)
        MOVSD   X0, sin+8(FP)
        MOVSD   X1, cos+16(FP)
        RET
isZero: // return (±0.0, 1.0)
        MOVQ    BX, sin+8(FP)
        MOVQ    $PosOne, AX
        MOVQ    AX, cos+16(FP)
        RET
isInfOrNaN: // return (NaN, NaN)
        MOVQ    $NaN, AX
        MOVQ    AX, sin+8(FP)
        MOVQ    AX, cos+16(FP)
        RET

/* [<][>][^][v][top][bottom][index][help] */