summaryrefslogtreecommitdiffstats
path: root/src/libs/softfloat-3e/source/extF80_scale_extF80.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/softfloat-3e/source/extF80_scale_extF80.c')
-rw-r--r--src/libs/softfloat-3e/source/extF80_scale_extF80.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/src/libs/softfloat-3e/source/extF80_scale_extF80.c b/src/libs/softfloat-3e/source/extF80_scale_extF80.c
new file mode 100644
index 00000000..bb61034e
--- /dev/null
+++ b/src/libs/softfloat-3e/source/extF80_scale_extF80.c
@@ -0,0 +1,191 @@
+/* $Id: extF80_scale_extF80.c $ */
+/** @file
+ * SoftFloat - 387-style fscale.
+ */
+
+/*
+ * Copyright (C) 2022-2023 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 "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+
+
+/**
+ * Wrapper around softfloat_propagateNaNExtF80UI that returns extFloat80_t
+ * and takes fully unpacked input.
+ */
+DECLINLINE(extFloat80_t)
+softfloat_extF80_propagateNaN(bool fSignA, int_fast32_t iExpA, uint_fast64_t uSigA,
+ bool fSignB, int_fast32_t iExpB, uint_fast64_t uSigB SOFTFLOAT_STATE_DECL_COMMA)
+{
+ struct uint128 uiZ = softfloat_propagateNaNExtF80UI(packToExtF80UI64(fSignA, iExpA), uSigA,
+ packToExtF80UI64(fSignB, iExpB), uSigB SOFTFLOAT_STATE_ARG_COMMA);
+ union extF80M_extF80 Ret;
+ Ret.fM.signExp = uiZ.v64;
+ Ret.fM.signif = uiZ.v0;
+ return Ret.f;
+}
+
+
+/**
+ * This performs a function similar to extF80_to_i32_r_minMag, but returns
+ * proper MIN/MAX values and no NaNs.
+ *
+ * ASSUMES the input is normalized.
+ *
+ * @returns Values in the range -2^24...+2^24.
+ */
+static int_fast32_t convertToInt(bool fSign, uint_fast64_t uSig, int_fast32_t iExp)
+{
+ iExp -= RTFLOAT80U_EXP_BIAS;
+ if (iExp < 0)
+ return 0;
+
+ /* Restrict the range to -2^24...+2^24 to prevent overflows during scaling. */
+ if (iExp >= 24)
+ return fSign ? INT32_MIN / 128 : INT32_MAX / 128;
+
+ int_fast32_t iRet = (int_fast32_t)(uSig >> (63 - iExp));
+ if (fSign)
+ return -iRet;
+ return iRet;
+}
+
+
+/**
+ * VBox: scale @a a by 2^truncateToInt(@a b)
+ *
+ * This function accepts and deals correctly with denormals (pseudo and
+ * otherwise).
+ */
+extFloat80_t extF80_scale_extF80(extFloat80_t a, extFloat80_t b, softfloat_state_t *pState)
+{
+ static union extF80M_extF80 const s_extF80Indefinite = EXTF80M_EXTF80_INIT(defaultNaNExtF80UI64, defaultNaNExtF80UI0);
+ static union extF80M_extF80 const s_aExtF80Zero[2] =
+ {
+ EXTF80M_EXTF80_INIT3_C(0, 0, 0), EXTF80M_EXTF80_INIT3_C(1, 0, 0),
+ };
+ static union extF80M_extF80 const s_aExtF80Infinity[2] =
+ {
+ EXTF80M_EXTF80_INIT3(0, RT_BIT_64(63), RTFLOAT80U_EXP_MAX),
+ EXTF80M_EXTF80_INIT3(1, RT_BIT_64(63), RTFLOAT80U_EXP_MAX),
+ };
+
+ /*
+ * Unpack the input.
+ */
+ bool const fSignA = signExtF80UI64(a.signExp);
+ int_fast32_t iExpA = expExtF80UI64(a.signExp);
+ uint_fast64_t uSigA = a.signif;
+
+ bool const fSignB = signExtF80UI64(b.signExp);
+ int_fast32_t iExpB = expExtF80UI64(b.signExp);
+ uint_fast64_t uSigB = b.signif;
+
+ /*
+ * Deal with funny input.
+ */
+ /* Invalid first. We ASSUME subnormals are rejected here. */
+ if ( RTFLOAT80U_IS_387_INVALID_EX(uSigA, iExpA)
+ || RTFLOAT80U_IS_387_INVALID_EX(uSigB, iExpB))
+ {
+ softfloat_raiseFlags(softfloat_flag_invalid, pState);
+ return s_extF80Indefinite.f;
+ }
+
+ /* Then NaNs and indefinites (special NaNs): */
+ if ( RTFLOAT80U_IS_INDEFINITE_OR_QUIET_OR_SIGNALLING_NAN_EX(uSigA, iExpA)
+ || RTFLOAT80U_IS_INDEFINITE_OR_QUIET_OR_SIGNALLING_NAN_EX(uSigB, iExpB))
+ return softfloat_extF80_propagateNaN(fSignA, iExpA, uSigA, fSignB, iExpB, uSigB, pState);
+
+ /* Normalize denormal inputs: */
+ if (RTFLOAT80U_IS_DENORMAL_OR_PSEUDO_DENORMAL_EX(uSigA, iExpA))
+ {
+ softfloat_raiseFlags(softfloat_flag_denormal, pState);
+ if (uSigA & RT_BIT_64(63))
+ iExpA = 1; /* -16382 */
+ else
+ {
+ /* We must return the denormal a value unchanged when b=zero, intel 10980XE
+ does this at least. Where-as pseudo-denormals are normalized. Go figure. */
+ if (RTFLOAT80U_IS_ZERO_EX(uSigB, iExpB))
+ return a;
+ iExpA = 64 - ASMBitLastSetU64(uSigA);
+ uSigA <<= iExpA;
+ iExpA = 1 - iExpA; /* -16382 - shift */
+ }
+ }
+
+ if (RTFLOAT80U_IS_DENORMAL_OR_PSEUDO_DENORMAL_EX(uSigB, iExpB))
+ {
+ softfloat_raiseFlags(softfloat_flag_denormal, pState);
+ if (uSigB & RT_BIT_64(63))
+ iExpB = 1; /* -16382 */
+ else
+ {
+ iExpB = 64 - ASMBitLastSetU64(uSigB);
+ uSigB <<= iExpB;
+ iExpB = 1 - iExpB; /* -16382 - shift */
+ }
+ }
+
+ /* Infinities and zeros: If a is Zero or Infinity, return it as-is unless
+ b=-Infinity & a=+/-Infinity or b=+Infinity & a=+/-zero when we have to
+ raise #I and return indefinite instead.
+
+ Note! If b is zero, don't, because pseudo-denormals should be returned
+ normalized (intel does that at least). Excpetion is b=zero and
+ a=denormal, which is handled above. */
+ if ( RTFLOAT80U_IS_INF_EX(uSigA, iExpA)
+ || RTFLOAT80U_IS_ZERO_EX(uSigA, iExpA))
+ {
+ if (RTFLOAT80U_IS_INF_EX(uSigB, iExpB) && fSignB == RTFLOAT80U_IS_INF_EX(uSigA, iExpA))
+ {
+ softfloat_raiseFlags(softfloat_flag_invalid, pState);
+ return s_extF80Indefinite.f;
+ }
+ return a;
+ }
+
+ if (RTFLOAT80U_IS_INF_EX(uSigB, iExpB))
+ {
+ if (fSignB)
+ return s_aExtF80Zero[fSignA].f;
+ return s_aExtF80Infinity[fSignA].f;
+ }
+
+ /*
+ * Convert b to an integer and do the scaling.
+ */
+ int_fast32_t iScaleFactor = convertToInt(fSignB, uSigB, iExpB);
+ int_fast32_t iScaledExp = iExpA + iScaleFactor;
+ return softfloat_normRoundPackToExtF80(fSignA, iScaledExp, uSigA, 0 /*sigExtra*/, 80 /*precision*/, pState);
+}
+