| /* |
| * Copyright (c) 2023, 2024, Intel Corporation. All rights reserved. |
| * Intel Math Library (LIBM) Source Code |
| * |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #include "macroAssembler_x86.hpp" |
| #include "stubGenerator_x86_64.hpp" |
| #include "runtime/stubRoutines.hpp" |
| |
| /******************************************************************************/ |
| // ALGORITHM DESCRIPTION - FMOD() |
| // --------------------- |
| // |
| // If either value1 or value2 is NaN, the result is NaN. |
| // |
| // If neither value1 nor value2 is NaN, the sign of the result equals the sign of the dividend. |
| // |
| // If the dividend is an infinity or the divisor is a zero or both, the result is NaN. |
| // |
| // If the dividend is finite and the divisor is an infinity, the result equals the dividend. |
| // |
| // If the dividend is a zero and the divisor is finite, the result equals the dividend. |
| // |
| // In the remaining cases, where neither operand is an infinity, a zero, or NaN, the floating-point |
| // remainder result from a dividend value1 and a divisor value2 is defined by the mathematical |
| // relation result = value1 - (value2 * q), where q is an integer that is negative only if |
| // value1 / value2 is negative, and positive only if value1 / value2 is positive, and whose magnitude |
| // is as large as possible without exceeding the magnitude of the true mathematical quotient of value1 and value2. |
| // |
| /******************************************************************************/ |
| |
| #define __ _masm-> |
| |
| ATTRIBUTE_ALIGNED(32) static const uint64_t CONST_NaN[] = { |
| 0x7FFFFFFFFFFFFFFFULL, 0x7FFFFFFFFFFFFFFFULL // NaN vector |
| }; |
| ATTRIBUTE_ALIGNED(32) static const uint64_t CONST_1p260[] = { |
| 0x5030000000000000ULL, // 0x1p+260 |
| }; |
| |
| ATTRIBUTE_ALIGNED(32) static const uint64_t CONST_MAX[] = { |
| 0x7FEFFFFFFFFFFFFFULL, // Max |
| }; |
| |
| ATTRIBUTE_ALIGNED(32) static const uint64_t CONST_INF[] = { |
| 0x7FF0000000000000ULL, // Inf |
| }; |
| |
| ATTRIBUTE_ALIGNED(32) static const uint64_t CONST_e307[] = { |
| 0x7FE0000000000000ULL |
| }; |
| |
| address StubGenerator::generate_libmFmod() { |
| __ align(CodeEntryAlignment); |
| StubGenStubId stub_id = StubGenStubId::fmod_id; |
| StubCodeMark mark(this, stub_id); |
| address start = __ pc(); |
| __ enter(); // required for proper stackwalking of RuntimeStub frame |
| |
| if (VM_Version::supports_avx512vlbwdq()) { // AVX512 version |
| |
| // Source used to generate the AVX512 fmod assembly below: |
| // |
| // #include <ia32intrin.h> |
| // #include <emmintrin.h> |
| // #pragma float_control(precise, on) |
| // |
| // #define UINT32 unsigned int |
| // #define SINT32 int |
| // #define UINT64 unsigned __int64 |
| // #define SINT64 __int64 |
| // |
| // #define DP_FMA(a, b, c) __fence(_mm_cvtsd_f64(_mm_fmadd_sd(_mm_set_sd(a), _mm_set_sd(b), _mm_set_sd(c)))) |
| // #define DP_FMA_RN(a, b, c) _mm_cvtsd_f64(_mm_fmadd_round_sd(_mm_set_sd(a), _mm_set_sd(b), _mm_set_sd(c), (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC))) |
| // #define DP_FMA_RZ(a, b, c) __fence(_mm_cvtsd_f64(_mm_fmadd_round_sd(_mm_set_sd(a), _mm_set_sd(b), _mm_set_sd(c), (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC)))) |
| // |
| // #define DP_ROUND_RZ(a) _mm_cvtsd_f64(_mm_roundscale_sd(_mm_setzero_pd(), _mm_set_sd(a), (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC))) |
| // |
| // #define DP_CONST(C) _castu64_f64(0x##C##ull) |
| // #define DP_AND(X, Y) _mm_cvtsd_f64(_mm_and_pd(_mm_set_sd(X), _mm_set_sd(Y))) |
| // #define DP_XOR(X, Y) _mm_cvtsd_f64(_mm_xor_pd(_mm_set_sd(X), _mm_set_sd(Y))) |
| // #define DP_OR(X, Y) _mm_cvtsd_f64(_mm_or_pd(_mm_set_sd(X), _mm_set_sd(Y))) |
| // #define DP_DIV_RZ(a, b) __fence(_mm_cvtsd_f64(_mm_div_round_sd(_mm_set_sd(a), _mm_set_sd(b), (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC)))) |
| // #define DP_FNMA(a, b, c) __fence(_mm_cvtsd_f64(_mm_fnmadd_sd(_mm_set_sd(a), _mm_set_sd(b), _mm_set_sd(c)))) |
| // #define DP_FNMA_RZ(a, b, c) __fence(_mm_cvtsd_f64(_mm_fnmadd_round_sd(_mm_set_sd(a), _mm_set_sd(b), _mm_set_sd(c), (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC)))) |
| // |
| // #define D2L(x) _mm_castpd_si128(x) |
| // // transfer highest 32 bits (of low 64b) to GPR |
| // #define TRANSFER_HIGH_INT32(X) _mm_extract_epi32(D2L(_mm_set_sd(X)), 1) |
| // |
| // double fmod(double x, double y) |
| // { |
| // double a, b, sgn_a, q, bs, bs2; |
| // unsigned eq; |
| |
| Label L_5280, L_52a0, L_5256, L_5300, L_5320, L_52c0, L_52d0, L_5360, L_5380, L_53b0, L_5390; |
| Label L_53c0, L_52a6, L_53d0, L_exit; |
| |
| __ movdqa(xmm2, xmm0); |
| // // |x|, |y| |
| // a = DP_AND(x, DP_CONST(7fffffffffffffff)); |
| __ movq(xmm0, xmm0); |
| __ mov64(rax, 0x7FFFFFFFFFFFFFFFULL); |
| __ evpbroadcastq(xmm3, rax, Assembler::AVX_128bit); |
| __ vpand(xmm6, xmm0, xmm3, Assembler::AVX_128bit); |
| // b = DP_AND(y, DP_CONST(7fffffffffffffff)); |
| __ vpand(xmm4, xmm1, xmm3, Assembler::AVX_128bit); |
| // // sign(x) |
| // sgn_a = DP_XOR(x, a); |
| __ vpxor(xmm3, xmm6, xmm0, Assembler::AVX_128bit); |
| // q = DP_DIV_RZ(a, b); |
| __ movq(xmm5, xmm4); |
| __ evdivsd(xmm0, xmm6, xmm5, Assembler::EVEX_RZ); |
| // q = DP_ROUND_RZ(q); |
| __ movq(xmm0, xmm0); |
| // a = DP_AND(x, DP_CONST(7fffffffffffffff)); |
| __ vxorpd(xmm7, xmm7, xmm7, Assembler::AVX_128bit); |
| // q = DP_ROUND_RZ(q); |
| __ vroundsd(xmm0, xmm7, xmm0, 0xb); |
| // eq = TRANSFER_HIGH_INT32(q); |
| __ extractps(rax, xmm0, 1); |
| // if (!eq) return x + sgn_a; |
| __ testl(rax, rax); |
| __ jcc(Assembler::equal, L_5280); |
| // if (eq >= 0x7fefffffu) goto SPECIAL_FMOD; |
| __ cmpl(rax, 0x7feffffe); |
| __ jcc(Assembler::belowEqual, L_52a0); |
| __ vpxor(xmm2, xmm2, xmm2, Assembler::AVX_128bit); |
| // SPECIAL_FMOD: |
| // |
| // // y==0 or x==Inf? |
| // if ((b == 0.0) || (!(a <= DP_CONST(7fefffffffffffff)))) |
| __ ucomisd(xmm4, xmm2); |
| __ jcc(Assembler::notEqual, L_5256); |
| __ jcc(Assembler::noParity, L_5300); |
| __ bind(L_5256); |
| __ movsd(xmm2, ExternalAddress((address)CONST_MAX), rax); |
| __ ucomisd(xmm2, xmm6); |
| __ jcc(Assembler::below, L_5300); |
| __ movsd(xmm0, ExternalAddress((address)CONST_INF), rax); |
| // return DP_FNMA(b, q, a); // NaN |
| // // y is NaN? |
| // if (!(b <= DP_CONST(7ff0000000000000))) return y + y; |
| __ ucomisd(xmm0, xmm4); |
| __ jcc(Assembler::aboveEqual, L_5320); |
| __ vaddsd(xmm0, xmm1, xmm1); |
| __ jmp(L_exit); |
| // if (!eq) return x + sgn_a; |
| __ align32(); |
| __ bind(L_5280); |
| __ vaddsd(xmm0, xmm3, xmm2); |
| __ jmp(L_exit); |
| // a = DP_FNMA_RZ(b, q, a); |
| __ align(8); |
| __ bind(L_52a0); |
| __ evfnmadd213sd(xmm0, xmm4, xmm6, Assembler::EVEX_RZ); |
| // while (b <= a) |
| __ bind(L_52a6); |
| __ ucomisd(xmm0, xmm4); |
| __ jcc(Assembler::aboveEqual, L_52c0); |
| // a = DP_XOR(a, sgn_a); |
| __ vpxor(xmm0, xmm3, xmm0, Assembler::AVX_128bit); |
| __ jmp(L_exit); |
| __ bind(L_52c0); |
| __ movq(xmm6, xmm0); |
| // q = DP_ROUND_RZ(q); |
| __ vpxor(xmm1, xmm1, xmm1, Assembler::AVX_128bit); |
| __ align32(); |
| __ bind(L_52d0); |
| // q = DP_DIV_RZ(a, b); |
| __ evdivsd(xmm2, xmm6, xmm5, Assembler::EVEX_RZ); |
| // q = DP_ROUND_RZ(q); |
| __ movq(xmm2, xmm2); |
| __ vroundsd(xmm2, xmm1, xmm2, 0xb); |
| // a = DP_FNMA_RZ(b, q, a); |
| __ evfnmadd213sd(xmm2, xmm4, xmm0, Assembler::EVEX_RZ); |
| // while (b <= a) |
| __ ucomisd(xmm2, xmm4); |
| __ movq(xmm6, xmm2); |
| __ movapd(xmm0, xmm2); |
| __ jcc(Assembler::aboveEqual, L_52d0); |
| // a = DP_XOR(a, sgn_a); |
| __ vpxor(xmm0, xmm3, xmm2, Assembler::AVX_128bit); |
| __ jmp(L_exit); |
| // return DP_FNMA(b, q, a); // NaN |
| __ bind(L_5300); |
| __ vfnmadd213sd(xmm0, xmm4, xmm6); |
| __ jmp(L_exit); |
| // bs = b * DP_CONST(7fe0000000000000); |
| __ bind(L_5320); |
| __ vmulsd(xmm1, xmm4, ExternalAddress((address)CONST_e307), rax); |
| // q = DP_DIV_RZ(a, bs); |
| __ movq(xmm2, xmm1); |
| __ evdivsd(xmm0, xmm6, xmm2, Assembler::EVEX_RZ); |
| // q = DP_ROUND_RZ(q); |
| __ movq(xmm0, xmm0); |
| __ vroundsd(xmm7, xmm7, xmm0, 0xb); |
| // eq = TRANSFER_HIGH_INT32(q); |
| __ extractps(rax, xmm7, 1); |
| // if (eq >= 0x7fefffffu) |
| __ cmpl(rax, 0x7fefffff); |
| __ jcc(Assembler::below, L_5360); |
| // // b* 2*1023 * 2^1023 |
| // bs2 = bs * DP_CONST(7fe0000000000000); |
| __ vmulsd(xmm0, xmm1, ExternalAddress((address)CONST_e307), rax); |
| // while (bs2 <= a) |
| __ ucomisd(xmm6, xmm0); |
| __ jcc(Assembler::aboveEqual, L_5380); |
| __ movapd(xmm7, xmm6); |
| __ jmp(L_53b0); |
| // a = DP_FNMA_RZ(b, q, a); |
| __ bind(L_5360); |
| __ evfnmadd213sd(xmm7, xmm1, xmm6, Assembler::EVEX_RZ); |
| __ jmp(L_53b0); |
| // q = DP_ROUND_RZ(q); |
| __ bind(L_5380); |
| __ vxorpd(xmm8, xmm8, xmm8, Assembler::AVX_128bit); |
| // q = DP_DIV_RZ(qa, bs2); |
| __ align32(); |
| __ bind(L_5390); |
| __ evdivsd(xmm7, xmm6, xmm0, Assembler::EVEX_RZ); |
| // q = DP_ROUND_RZ(q); |
| __ movq(xmm7, xmm7); |
| __ vroundsd(xmm7, xmm8, xmm7, 0xb); |
| // a = DP_FNMA_RZ(bs2, q, a); |
| __ evfnmadd213sd(xmm7, xmm0, xmm6, Assembler::EVEX_RZ); |
| // while (bs2 <= a) |
| __ ucomisd(xmm7, xmm0); |
| __ movapd(xmm6, xmm7); |
| __ jcc(Assembler::aboveEqual, L_5390); |
| // while (bs <= a) |
| __ bind(L_53b0); |
| __ ucomisd(xmm7, xmm1); |
| __ jcc(Assembler::aboveEqual, L_53c0); |
| __ movapd(xmm0, xmm7); |
| __ jmp(L_52a6); |
| // q = DP_ROUND_RZ(q); |
| __ bind(L_53c0); |
| __ vxorpd(xmm6, xmm6, xmm6, Assembler::AVX_128bit); |
| // q = DP_DIV_RZ(a, bs); |
| __ align32(); |
| __ bind(L_53d0); |
| __ evdivsd(xmm0, xmm7, xmm2, Assembler::EVEX_RZ); |
| // q = DP_ROUND_RZ(q); |
| __ movq(xmm0, xmm0); |
| __ vroundsd(xmm0, xmm6, xmm0, 0xb); |
| // a = DP_FNMA_RZ(bs, q, a); |
| __ evfnmadd213sd(xmm0, xmm1, xmm7, Assembler::EVEX_RZ); |
| // while (bs <= a) |
| __ ucomisd(xmm0, xmm1); |
| __ movapd(xmm7, xmm0); |
| __ jcc(Assembler::aboveEqual, L_53d0); |
| __ jmp(L_52a6); |
| |
| __ bind(L_exit); |
| |
| //////////////////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////////////// |
| // AVX2 code |
| //////////////////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////////////// |
| } else if (VM_Version::supports_fma()) { // AVX2 version |
| |
| Label L_104a, L_11bd, L_10c1, L_1090, L_11b9, L_10e7, L_11af, L_111c, L_10f3, L_116e, L_112a; |
| Label L_1173, L_1157, L_117f, L_11a0; |
| |
| // double fmod(double x, double y) |
| // { |
| // double a, b, sgn_a, q, bs, bs2, corr, res; |
| // unsigned eq; |
| |
| // // |x|, |y| |
| // a = DP_AND(x, DP_CONST(7fffffffffffffff)); |
| __ movq(xmm2, xmm0); |
| __ movdqu(xmm3, ExternalAddress((address)CONST_NaN), rcx); |
| __ vpand(xmm4, xmm2, xmm3, Assembler::AVX_128bit); |
| // b = DP_AND(y, DP_CONST(7fffffffffffffff)); |
| __ vpand(xmm3, xmm1, xmm3, Assembler::AVX_128bit); |
| // // sign(x) |
| // sgn_a = DP_XOR(x, a); |
| __ mov64(rcx, 0x8000000000000000ULL); |
| __ movq(xmm5, rcx); |
| __ vpand(xmm2, xmm2, xmm5, Assembler::AVX_128bit); |
| |
| // if (a < b) return x + sgn_a; |
| __ ucomisd(xmm3, xmm4); |
| __ jccb(Assembler::belowEqual, L_104a); |
| __ vaddsd(xmm0, xmm2, xmm0); |
| __ jmp(L_11bd); |
| |
| // if (a < b * 0x1p+260) |
| __ bind(L_104a); |
| |
| __ vmulsd(xmm0, xmm3, ExternalAddress((address)CONST_1p260), rax); |
| __ ucomisd(xmm0, xmm4); |
| __ jccb(Assembler::belowEqual, L_10c1); |
| // { |
| // q = DP_DIV(a, b); |
| __ vdivpd(xmm0, xmm4, xmm3, Assembler::AVX_128bit); |
| // corr = DP_SHR(DP_FNMA(b, q, a), 63); |
| __ movapd(xmm1, xmm0); |
| __ vfnmadd213sd(xmm1, xmm3, xmm4); |
| __ movq(xmm5, xmm1); |
| __ vpxor(xmm1, xmm1, xmm1, Assembler::AVX_128bit); |
| __ vpcmpgtq(xmm5, xmm1, xmm5, Assembler::AVX_128bit); |
| // q = DP_PSUBQ(q, corr); |
| __ vpaddq(xmm0, xmm5, xmm0, Assembler::AVX_128bit); |
| // q = DP_TRUNC(q); |
| __ vroundsd(xmm0, xmm0, xmm0, 3); |
| // a = DP_FNMA(b, q, a); |
| __ vfnmadd213sd(xmm0, xmm3, xmm4); |
| __ align(16); |
| // while (b <= a) |
| __ bind(L_1090); |
| __ ucomisd(xmm0, xmm3); |
| __ jcc(Assembler::below, L_11b9); |
| // { |
| // q = DP_DIV(a, b); |
| __ vdivsd(xmm4, xmm0, xmm3); |
| // corr = DP_SHR(DP_FNMA(b, q, a), 63); |
| __ movapd(xmm5, xmm4); |
| __ vfnmadd213sd(xmm5, xmm3, xmm0); |
| __ movq(xmm5, xmm5); |
| __ vpcmpgtq(xmm5, xmm1, xmm5, Assembler::AVX_128bit); |
| // q = DP_PSUBQ(q, corr); |
| __ vpaddq(xmm4, xmm5, xmm4, Assembler::AVX_128bit); |
| // q = DP_TRUNC(q); |
| __ vroundsd(xmm4, xmm4, xmm4, 3); |
| // a = DP_FNMA(b, q, a); |
| __ vfnmadd231sd(xmm0, xmm3, xmm4); |
| __ jmpb(L_1090); |
| // } |
| // return DP_XOR(a, sgn_a); |
| // } |
| |
| // __asm { ldmxcsr DWORD PTR [mxcsr_rz] } |
| __ bind(L_10c1); |
| __ ldmxcsr(ExternalAddress(StubRoutines::x86::addr_mxcsr_rz()), rax /*rscratch*/); |
| |
| // q = DP_DIV(a, b); |
| __ vdivpd(xmm0, xmm4, xmm3, Assembler::AVX_128bit); |
| // q = DP_TRUNC(q); |
| __ vroundsd(xmm0, xmm0, xmm0, 3); |
| |
| // eq = TRANSFER_HIGH_INT32(q); |
| __ extractps(rax, xmm0, 1); |
| |
| // if (__builtin_expect((eq >= 0x7fefffffu), (0==1))) goto SPECIAL_FMOD; |
| __ cmpl(rax, 0x7feffffe); |
| __ jccb(Assembler::above, L_10e7); |
| |
| // a = DP_FNMA(b, q, a); |
| __ vfnmadd213sd(xmm0, xmm3, xmm4); |
| __ jmp(L_11af); |
| |
| // SPECIAL_FMOD: |
| |
| // // y==0 or x==Inf? |
| // if ((b == 0.0) || (!(a <= DP_CONST(7fefffffffffffff)))) |
| __ bind(L_10e7); |
| __ vpxor(xmm5, xmm5, xmm5, Assembler::AVX_128bit); |
| __ ucomisd(xmm3, xmm5); |
| __ jccb(Assembler::notEqual, L_10f3); |
| __ jccb(Assembler::noParity, L_111c); |
| |
| __ bind(L_10f3); |
| __ movsd(xmm5, ExternalAddress((address)CONST_MAX), rax); |
| __ ucomisd(xmm5, xmm4); |
| __ jccb(Assembler::below, L_111c); |
| // return res; |
| // } |
| // // y is NaN? |
| // if (!(b <= DP_CONST(7ff0000000000000))) { |
| __ movsd(xmm0, ExternalAddress((address)CONST_INF), rax); |
| __ ucomisd(xmm0, xmm3); |
| __ jccb(Assembler::aboveEqual, L_112a); |
| // res = y + y; |
| __ vaddsd(xmm0, xmm1, xmm1); |
| // __asm { ldmxcsr DWORD PTR[mxcsr] } |
| __ ldmxcsr(ExternalAddress(StubRoutines::x86::addr_mxcsr_std()), rax /*rscratch*/); |
| __ jmp(L_11bd); |
| // { |
| // res = DP_FNMA(b, q, a); // NaN |
| __ bind(L_111c); |
| __ vfnmadd213sd(xmm0, xmm3, xmm4); |
| // __asm { ldmxcsr DWORD PTR[mxcsr] } |
| __ ldmxcsr(ExternalAddress(StubRoutines::x86::addr_mxcsr_std()), rax /*rscratch*/); |
| __ jmp(L_11bd); |
| // return res; |
| // } |
| |
| // // b* 2*1023 |
| // bs = b * DP_CONST(7fe0000000000000); |
| __ bind(L_112a); |
| __ vmulsd(xmm1, xmm3, ExternalAddress((address)CONST_e307), rax); |
| |
| // q = DP_DIV(a, bs); |
| __ vdivsd(xmm0, xmm4, xmm1); |
| // q = DP_TRUNC(q); |
| __ vroundsd(xmm0, xmm0, xmm0, 3); |
| |
| // eq = TRANSFER_HIGH_INT32(q); |
| __ extractps(rax, xmm0, 1); |
| |
| // if (eq >= 0x7fefffffu) |
| __ cmpl(rax, 0x7fefffff); |
| __ jccb(Assembler::below, L_116e); |
| // { |
| // // b* 2*1023 * 2^1023 |
| // bs2 = bs * DP_CONST(7fe0000000000000); |
| __ vmulsd(xmm0, xmm1, ExternalAddress((address)CONST_e307), rax); |
| // while (bs2 <= a) |
| __ ucomisd(xmm4, xmm0); |
| __ jccb(Assembler::below, L_1173); |
| // { |
| // q = DP_DIV(a, bs2); |
| __ bind(L_1157); |
| __ vdivsd(xmm5, xmm4, xmm0); |
| // q = DP_TRUNC(q); |
| __ vroundsd(xmm5, xmm5, xmm5, 3); |
| // a = DP_FNMA(bs2, q, a); |
| __ vfnmadd231sd(xmm4, xmm0, xmm5); |
| // while (bs2 <= a) |
| __ ucomisd(xmm4, xmm0); |
| __ jccb(Assembler::aboveEqual, L_1157); |
| __ jmpb(L_1173); |
| // } |
| // } |
| // else |
| // a = DP_FNMA(bs, q, a); |
| __ bind(L_116e); |
| __ vfnmadd231sd(xmm4, xmm1, xmm0); |
| |
| // while (bs <= a) |
| __ bind(L_1173); |
| __ ucomisd(xmm4, xmm1); |
| __ jccb(Assembler::aboveEqual, L_117f); |
| __ movapd(xmm0, xmm4); |
| __ jmpb(L_11af); |
| // { |
| // q = DP_DIV(a, bs); |
| __ bind(L_117f); |
| __ vdivsd(xmm0, xmm4, xmm1); |
| // q = DP_TRUNC(q); |
| __ vroundsd(xmm0, xmm0, xmm0, 3); |
| // a = DP_FNMA(bs, q, a); |
| __ vfnmadd213sd(xmm0, xmm1, xmm4); |
| |
| // while (bs <= a) |
| __ ucomisd(xmm0, xmm1); |
| __ movapd(xmm4, xmm0); |
| __ jccb(Assembler::aboveEqual, L_117f); |
| __ jmpb(L_11af); |
| __ align(16); |
| // { |
| // q = DP_DIV(a, b); |
| __ bind(L_11a0); |
| __ vdivsd(xmm1, xmm0, xmm3); |
| // q = DP_TRUNC(q); |
| __ vroundsd(xmm1, xmm1, xmm1, 3); |
| // a = DP_FNMA(b, q, a); |
| __ vfnmadd231sd(xmm0, xmm3, xmm1); |
| |
| // FMOD_CONT: |
| // while (b <= a) |
| __ bind(L_11af); |
| __ ucomisd(xmm0, xmm3); |
| __ jccb(Assembler::aboveEqual, L_11a0); |
| // } |
| |
| // __asm { ldmxcsr DWORD PTR[mxcsr] } |
| __ ldmxcsr(ExternalAddress(StubRoutines::x86::addr_mxcsr_std()), rax /*rscratch*/); |
| __ bind(L_11b9); |
| __ vpxor(xmm0, xmm2, xmm0, Assembler::AVX_128bit); |
| // } |
| |
| // goto FMOD_CONT; |
| |
| // } |
| __ bind(L_11bd); |
| |
| } else { // SSE version |
| Label x87_loop; |
| __ movsd(Address(rbp, -8), xmm1); |
| __ movsd(Address(rbp, -16), xmm0); |
| __ fld_d(Address(rbp, -8)); |
| __ fld_d(Address(rbp, -16)); |
| |
| __ bind(x87_loop); |
| __ fprem(); |
| __ fnstsw_ax(); |
| __ testb(rax, 0x4, false); |
| __ jcc(Assembler::notZero, x87_loop); |
| |
| __ fstp_d(1); |
| __ fstp_d(Address(rbp, -8)); |
| __ movsd(xmm0, Address(rbp, -8)); |
| } |
| |
| __ leave(); // required for proper stackwalking of RuntimeStub frame |
| __ ret(0); |
| |
| return start; |
| } |
| |
| #undef __ |