| // Copyright 2012 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 "textflag.h" | |
| #define Big 0x4330000000000000 // 2**52 | |
| // func hasSSE4() bool | |
| // returns whether SSE4.1 is supported | |
| TEXT ·hasSSE4(SB),NOSPLIT,$0 | |
| XORQ AX, AX | |
| INCL AX | |
| CPUID | |
| SHRQ $19, CX | |
| ANDQ $1, CX | |
| MOVB CX, ret+0(FP) | |
| RET | |
| // func Floor(x float64) float64 | |
| TEXT ·Floor(SB),NOSPLIT,$0 | |
| CMPB math·useSSE4(SB), $1 | |
| JNE nosse4 | |
| ROUNDSD $1, x+0(FP), X0 | |
| MOVQ X0, ret+8(FP) | |
| RET | |
| nosse4: | |
| MOVQ x+0(FP), AX | |
| MOVQ $~(1<<63), DX // sign bit mask | |
| ANDQ AX,DX // DX = |x| | |
| SUBQ $1,DX | |
| MOVQ $(Big - 1), CX // if |x| >= 2**52-1 or IsNaN(x) or |x| == 0, return x | |
| CMPQ DX,CX | |
| JAE isBig_floor | |
| MOVQ AX, X0 // X0 = x | |
| CVTTSD2SQ X0, AX | |
| CVTSQ2SD AX, X1 // X1 = float(int(x)) | |
| CMPSD X1, X0, 1 // compare LT; X0 = 0xffffffffffffffff or 0 | |
| MOVSD $(-1.0), X2 | |
| ANDPD X2, X0 // if x < float(int(x)) {X0 = -1} else {X0 = 0} | |
| ADDSD X1, X0 | |
| MOVSD X0, ret+8(FP) | |
| RET | |
| isBig_floor: | |
| MOVQ AX, ret+8(FP) // return x | |
| RET | |
| // func Ceil(x float64) float64 | |
| TEXT ·Ceil(SB),NOSPLIT,$0 | |
| CMPB math·useSSE4(SB), $1 | |
| JNE nosse4 | |
| ROUNDSD $2, x+0(FP), X0 | |
| MOVQ X0, ret+8(FP) | |
| RET | |
| nosse4: | |
| MOVQ x+0(FP), AX | |
| MOVQ $~(1<<63), DX // sign bit mask | |
| MOVQ AX, BX // BX = copy of x | |
| ANDQ DX, BX // BX = |x| | |
| MOVQ $Big, CX // if |x| >= 2**52 or IsNaN(x), return x | |
| CMPQ BX, CX | |
| JAE isBig_ceil | |
| MOVQ AX, X0 // X0 = x | |
| MOVQ DX, X2 // X2 = sign bit mask | |
| CVTTSD2SQ X0, AX | |
| ANDNPD X0, X2 // X2 = sign | |
| CVTSQ2SD AX, X1 // X1 = float(int(x)) | |
| CMPSD X1, X0, 2 // compare LE; X0 = 0xffffffffffffffff or 0 | |
| ORPD X2, X1 // if X1 = 0.0, incorporate sign | |
| MOVSD $1.0, X3 | |
| ANDNPD X3, X0 | |
| ORPD X2, X0 // if float(int(x)) <= x {X0 = 1} else {X0 = -0} | |
| ADDSD X1, X0 | |
| MOVSD X0, ret+8(FP) | |
| RET | |
| isBig_ceil: | |
| MOVQ AX, ret+8(FP) | |
| RET | |
| // func Trunc(x float64) float64 | |
| TEXT ·Trunc(SB),NOSPLIT,$0 | |
| MOVQ x+0(FP), AX | |
| MOVQ $~(1<<63), DX // sign bit mask | |
| MOVQ AX, BX // BX = copy of x | |
| ANDQ DX, BX // BX = |x| | |
| MOVQ $Big, CX // if |x| >= 2**52 or IsNaN(x), return x | |
| CMPQ BX, CX | |
| JAE isBig_trunc | |
| MOVQ AX, X0 | |
| MOVQ DX, X2 // X2 = sign bit mask | |
| CVTTSD2SQ X0, AX | |
| ANDNPD X0, X2 // X2 = sign | |
| CVTSQ2SD AX, X0 // X0 = float(int(x)) | |
| ORPD X2, X0 // if X0 = 0.0, incorporate sign | |
| MOVSD X0, ret+8(FP) | |
| RET | |
| isBig_trunc: | |
| MOVQ AX, ret+8(FP) // return x | |
| RET |