diff options
Diffstat (limited to 'src/libs/softfloat-3e/source/extF80_sincos.c')
-rw-r--r-- | src/libs/softfloat-3e/source/extF80_sincos.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/src/libs/softfloat-3e/source/extF80_sincos.c b/src/libs/softfloat-3e/source/extF80_sincos.c new file mode 100644 index 00000000..3905439d --- /dev/null +++ b/src/libs/softfloat-3e/source/extF80_sincos.c @@ -0,0 +1,323 @@ +/* $Id: extF80_sincos.c $ */ +/** @file + * SoftFloat - VBox Extension - extF80_sin, extF80_cos, extF80_sincos, extF80_atan2. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <stdbool.h> +#include <stdint.h> +#include "platform.h" +#include "internals.h" +#include "specialize.h" +#include "softfloat.h" +#include <iprt/types.h> +#include <iprt/x86.h> + +#include "extF80_sincos.h" + + +static void cordic_sincos( float128_t z, float128_t *pv1, float128_t *pv2 SOFTFLOAT_STATE_DECL_COMMA ) +{ + float128_t v1 = { { 0, 0 } }; /* MSC thinks it can be used uninitialized */ + float128_t v2 = { { 0, 0 } }; /* MSC thinks it can be used uninitialized */ + /** @todo TBD: CORDIC kernel should be easily implemented in assembly * */ + + float128_t x1 = ui32_to_f128(1, pState); + float128_t x2 = ui32_to_f128(0, pState); + float128_t zz = ui32_to_f128(0, pState); + + float128_t p2m = ui32_to_f128(1, pState); + float128_t two = ui32_to_f128(2, pState); + + for (unsigned k = 0; k < RT_ELEMENTS(g_ar128FsincosCORDICConsts); k++) + { + float128_t atg = *(float128_t *)&g_ar128FsincosCORDICConsts[k]; + float128_t scale = *(float128_t *)&g_ar128FsincosCORDICConsts2[k]; + + float128_t px1 = f128_mul(x1, p2m, pState); + float128_t px2 = f128_mul(x2, p2m, pState); + + if (f128_le(zz, z, pState)) + { + x1 = f128_sub(x1, px2, pState); + x2 = f128_add(x2, px1, pState); + zz = f128_add(zz, atg, pState); + } + else + { + x1 = f128_add(x1, px2, pState); + x2 = f128_sub(x2, px1, pState); + zz = f128_sub(zz, atg, pState); + } + + p2m = f128_div(p2m, two, pState); + + v1 = f128_mul(x1, scale, pState); + v2 = f128_mul(x2, scale, pState); + } + + *pv1 = v1; + *pv2 = v2; +} + +static float128_t cordic_atan2( float128_t y, float128_t x SOFTFLOAT_STATE_DECL_COMMA ) +{ + float128_t v1 = { { 0, 0 } }; /* MSC thinks it can be used uninitialized */ + float128_t v2 = { { 0, 0 } }; /* MSC thinks it can be used uninitialized */ + /** @todo TBD: CORDIC kernel should be easily implemented in assembly * */ + + float128_t x1 = x, x2 = y; + float128_t z = ui32_to_f128(0, pState); + float128_t zero = ui32_to_f128(0, pState); + float128_t p2m = ui32_to_f128(1, pState); + float128_t two = ui32_to_f128(2, pState); + + for (unsigned k = 0; k < RT_ELEMENTS(g_ar128FsincosCORDICConsts); k++) + { + float128_t atg = *(float128_t *)&g_ar128FsincosCORDICConsts[k]; + float128_t scale = *(float128_t *)&g_ar128FsincosCORDICConsts2[k]; + + float128_t px1 = f128_mul(x1, p2m, pState); + float128_t px2 = f128_mul(x2, p2m, pState); + + if (f128_le(x2, zero, pState)) + { + x1 = f128_sub(x1, px2, pState); + x2 = f128_add(x2, px1, pState); + z = f128_sub(z, atg, pState); + } + else + { + x1 = f128_add(x1, px2, pState); + x2 = f128_sub(x2, px1, pState); + z = f128_add(z, atg, pState); + } + + p2m = f128_div(p2m, two, pState); + + v1 = f128_mul(x1, scale, pState); + v2 = f128_mul(x2, scale, pState); + } + + return z; +} + +extFloat80_t extF80_sin( extFloat80_t x SOFTFLOAT_STATE_DECL_COMMA ) +{ + int32_t fSign = 0; + extFloat80_t f80zero = ui32_to_extF80(0, pState); + if (extF80_le(x, f80zero, pState)) + { + x = extF80_sub(f80zero, x, pState); + fSign = 1; + } + + extFloat80_t f80pi2 = f128_to_extF80(*(float128_t *)&g_r128pi2, pState); + + /** @todo TBD: Partial remainder should be calculated using float128 value of pi2 to increase precision **/ + uint16_t fCxFlags = 0; + extFloat80_t rem = extF80_partialRem(x, f80pi2, pState->roundingMode, &fCxFlags, pState); + int32_t const quo = X86_FSW_CX_TO_QUOTIENT(fCxFlags); + + float128_t z = extF80_to_f128(rem, pState); + float128_t f128zero = ui32_to_f128(0, pState); + + float128_t v1, v2; + cordic_sincos(z, &v1, &v2, pState); + + float128_t v; + switch(quo % 4) + { +#ifdef _MSC_VER /* stupid MSC thinks v might be used uninitialized otherwise: */ + default: +#endif + case 0: + v = v2; + break; + + case 1: + v = v1; + break; + + case 2: + v = f128_sub(f128zero, v2, pState); + break; + + case 3: + v = f128_sub(f128zero, v1, pState); + break; + } + + if (fSign) + v = f128_sub(f128zero, v, pState); + + return f128_to_extF80(v, pState); +} + +extFloat80_t extF80_cos( extFloat80_t x SOFTFLOAT_STATE_DECL_COMMA ) +{ + extFloat80_t f80zero = ui32_to_extF80(0, pState); + if (extF80_le(x, f80zero, pState)) + x = extF80_sub(f80zero, x, pState); + + extFloat80_t f80pi2 = f128_to_extF80(*(float128_t *)&g_r128pi2, pState); + + /** TBD: Partial remainder should be calculated using float128 value of pi2 to increase precision **/ + uint16_t fCxFlags = 0; + extFloat80_t rem = extF80_partialRem(x, f80pi2, pState->roundingMode, &fCxFlags, pState); + int32_t const quo = X86_FSW_CX_TO_QUOTIENT(fCxFlags); + + float128_t z = extF80_to_f128(rem, pState); + float128_t f128zero = ui32_to_f128(0, pState); + + float128_t v1, v2; + cordic_sincos(z, &v1, &v2, pState); + + float128_t v; + switch(quo % 4) + { +#ifdef _MSC_VER /* stupid MSC thinks v might be used uninitialized otherwise: */ + default: +#endif + case 0: + v = v1; + break; + + case 1: + v = f128_sub(f128zero, v2, pState);; + break; + + case 2: + v = f128_sub(f128zero, v1, pState); + break; + + case 3: + v = v2; + break; + } + + return f128_to_extF80(v, pState); +} + +void extF80_sincos( extFloat80_t x, extFloat80_t* pSin, extFloat80_t* pCos SOFTFLOAT_STATE_DECL_COMMA ) +{ + uint16_t fCxFlags = 0; + int32_t quo; + extFloat80_t rem, f80pi2, f80zero; + int32_t fSign = 0; + + f80zero = ui32_to_extF80(0, pState); + if (extF80_le(x, f80zero, pState)) + { + x = extF80_sub(f80zero, x, pState); + fSign = 1; + } + + f80pi2 = f128_to_extF80(*(float128_t const *)&g_r128pi2, pState); + + /** @todo TBD: Partial remainder should be calculated using float128 value of pi2 to increase precision **/ + rem = extF80_partialRem(x, f80pi2, pState->roundingMode, &fCxFlags, pState); + quo = X86_FSW_CX_TO_QUOTIENT(fCxFlags); + + float128_t z = extF80_to_f128(rem, pState); + float128_t f128zero = ui32_to_f128(0, pState); + + float128_t v1, v2; + cordic_sincos(z, &v1, &v2, pState); + + float128_t vCos, vSin; + switch(quo % 4) + { +#ifdef _MSC_VER /* stupid MSC thinks vCos & cSin might be used uninitialized otherwise: */ + default: +#endif + case 0: + vCos = v1; + vSin = v2; + break; + + case 1: + vCos = f128_sub(f128zero, v2, pState); + vSin = v1; + break; + + case 2: + vCos = f128_sub(f128zero, v1, pState); + vSin = f128_sub(f128zero, v2, pState); + break; + + case 3: + vCos = v2; + vSin = f128_sub(f128zero, v1, pState); + break; + } + + if (fSign) + vSin = f128_sub(f128zero, vSin, pState); + + *pCos = f128_to_extF80(vCos, pState); + *pSin = f128_to_extF80(vSin, pState); +} + +extFloat80_t extF80_atan2( extFloat80_t f80y, extFloat80_t f80x SOFTFLOAT_STATE_DECL_COMMA ) +{ + float128_t v; + int32_t fSignX = 0, fSignY = 0; + float128_t f128zero = ui32_to_f128(0, pState); + float128_t y = extF80_to_f128(f80y, pState); + float128_t x = extF80_to_f128(f80x, pState); + + if (f128_le(x, f128zero, pState)) + { + x = f128_sub(f128zero, x, pState); + fSignX = 1; + } + + if (f128_le(y, f128zero, pState)) + { + y = f128_sub(f128zero, y, pState); + fSignY = 1; + } + + v = cordic_atan2(y, x, pState); + + if (fSignX) + { + if (fSignY) + v = f128_sub(v, *(float128_t const *)&g_r128pi, pState); + else + v = f128_sub(*(float128_t const *)&g_r128pi, v, pState); + } + else + { + if (fSignY) + v = f128_sub(f128zero, v, pState); + } + + return f128_to_extF80(v, pState); +} |