https://gcc.gnu.org/g:3dcf3410a743867a0744d3a3d737b2e0b9c035ac
commit r16-4276-g3dcf3410a743867a0744d3a3d737b2e0b9c035ac Author: H.J. Lu <[email protected]> Date: Sat Aug 30 11:46:31 2025 -0700 libbid: Set rounding mode to round-to-nearest for _Decimal128 arithmetic Since _Decimal128 arithmetic requires the round-to-nearest rounding mode, define DFP_INIT_ROUNDMODE and DFP_RESTORE_ROUNDMODE, similar to FP_INIT_ROUNDMODE in sfp-machine.h, to set the rounding mode to round-to-nearest at _Decimal128 related arithmetic function entrances and restores it upon return. This doesn't require linking with libm when libgcc is used. libgcc/ PR target/120691 * Makefile.in (DECNUMINC): Add -I$(srcdir)/config/$(cpu_type). * config/i386/dfp-machine.h: New file. * config/i386/32/dfp-machine.h: Likewise. * config/i386/64/dfp-machine.h: Likewise. libgcc/config/libbid/ PR target/120691 * bid128_div.c: Run DFP_INIT_ROUNDMODE at function entrace and DFP_RESTORE_ROUNDMODE at function exit. * bid128_rem.c: Likewise. * bid128_sqrt.c: Likewise. * bid64_div.c (bid64_div): Likewise. * bid64_sqrt.c (bid64_sqrt): Likewise. * bid_conf.h: Include <dfp-machine.h>. * dfp-machine.h: New file. gcc/testsuite/ PR target/120691 * gcc.target/i386/pr120691.c: New test. Signed-off-by: H.J. Lu <[email protected]> Diff: --- gcc/testsuite/gcc.target/i386/pr120691.c | 19 ++++++ libgcc/Makefile.in | 3 +- libgcc/config/i386/32/dfp-machine.h | 30 +++++++++ libgcc/config/i386/64/dfp-machine.h | 21 ++++++ libgcc/config/i386/dfp-machine.h | 59 +++++++++++++++++ libgcc/config/libbid/bid128_div.c | 107 ++++++++++++++++++++++++++++++ libgcc/config/libbid/bid128_rem.c | 29 ++++++++ libgcc/config/libbid/bid128_sqrt.c | 31 +++++++++ libgcc/config/libbid/bid64_div.c | 110 +++++++++++++++++++++++++++++++ libgcc/config/libbid/bid64_sqrt.c | 29 ++++++++ libgcc/config/libbid/bid_conf.h | 2 + libgcc/config/libbid/dfp-machine.h | 34 ++++++++++ 12 files changed, 473 insertions(+), 1 deletion(-) diff --git a/gcc/testsuite/gcc.target/i386/pr120691.c b/gcc/testsuite/gcc.target/i386/pr120691.c new file mode 100644 index 000000000000..9bbd61ed53d5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120691.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-options "-O0 -mfpmath=sse -msse2" } */ +/* { dg-require-effective-target sse2 } */ +/* { dg-require-effective-target fenv } */ +/* { dg-require-effective-target dfp } */ + +#include <fenv.h> + +int main() { + fesetround( FE_UPWARD ); + _Decimal128 x1 = 9825, x2 = 10000 ; + + double c = (double) (x1 / x2); + + if (c != 0.9825) + __builtin_abort (); + + return 0 ; +} diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in index e258f943dddd..32a5a15813f8 100644 --- a/libgcc/Makefile.in +++ b/libgcc/Makefile.in @@ -232,7 +232,8 @@ version := $(shell @get_gcc_base_ver@ $(srcdir)/../gcc/BASE-VER) ifeq ($(decimal_float),yes) ifeq ($(enable_decimal_float),bid) -DECNUMINC = -I$(srcdir)/config/libbid -DENABLE_DECIMAL_BID_FORMAT +DECNUMINC = -I$(srcdir)/config/$(cpu_type) -I$(srcdir)/config/libbid \ + -DENABLE_DECIMAL_BID_FORMAT else DECNUMINC = -I$(srcdir)/../libdecnumber/$(enable_decimal_float) \ -I$(srcdir)/../libdecnumber diff --git a/libgcc/config/i386/32/dfp-machine.h b/libgcc/config/i386/32/dfp-machine.h new file mode 100644 index 000000000000..ef8fa4f3600c --- /dev/null +++ b/libgcc/config/i386/32/dfp-machine.h @@ -0,0 +1,30 @@ +#ifndef _SOFT_FLOAT +/* Get the rounding mode. */ +#define DFP_GET_ROUNDMODE \ + unsigned int _frnd_orig; \ + do \ + { \ + __asm__ __volatile__ ("fnstcw\t%0" : "=m" (_frnd_orig)); \ + _frnd_orig &= FP_RND_MASK; \ + } \ + while (0); + +/* Set the rounding mode. */ +#define DFP_SET_ROUNDMODE(round) \ + do \ + { \ + unsigned int _cw; \ + __asm__ __volatile__ ("fnstcw\t%0" : "=m" (_cw)); \ + _cw &= ~FP_RND_MASK; \ + _cw |= round; \ + __asm__ __volatile__ ("fldcw\t%0" :: "m" (_cw)); \ + if (__builtin_cpu_supports ("sse")) \ + { \ + __asm__ __volatile__ ("%vstmxcsr\t%0" : "=m" (_cw)); \ + _cw &= ~0x6000; \ + _cw |= round << 3; \ + __asm__ __volatile__ ("%vldmxcsr\t%0" :: "m" (_cw)); \ + } \ + } \ + while (0); +#endif diff --git a/libgcc/config/i386/64/dfp-machine.h b/libgcc/config/i386/64/dfp-machine.h new file mode 100644 index 000000000000..19cc16a9f96d --- /dev/null +++ b/libgcc/config/i386/64/dfp-machine.h @@ -0,0 +1,21 @@ +/* Get the rounding mode. */ +#define DFP_GET_ROUNDMODE \ + unsigned int _frnd_orig; \ + do \ + { \ + __asm__ __volatile__ ("%vstmxcsr\t%0" : "=m" (_frnd_orig)); \ + _frnd_orig &= FP_RND_MASK; \ + } \ + while (0); + +/* Set the rounding mode. */ +#define DFP_SET_ROUNDMODE(round) \ + do \ + { \ + unsigned int _cw; \ + __asm__ __volatile__ ("%vstmxcsr\t%0" : "=m" (_cw)); \ + _cw &= ~FP_RND_MASK; \ + _cw |= round; \ + __asm__ __volatile__ ("%vldmxcsr\t%0" :: "m" (_cw)); \ + } \ + while (0); diff --git a/libgcc/config/i386/dfp-machine.h b/libgcc/config/i386/dfp-machine.h new file mode 100644 index 000000000000..f6efacc7299e --- /dev/null +++ b/libgcc/config/i386/dfp-machine.h @@ -0,0 +1,59 @@ +/* Rounding mode macros for DFP libbid. x86 version. + Copyright (C) 2025 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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; either version 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _X86_DFP_MACHINE_H +#define _X86_DFP_MACHINE_H + +#ifdef _SOFT_FLOAT +#include_next <dfp-machine.h> +#else +#include "config/i386/sfp-machine.h" + +#ifdef __x86_64__ +#include "config/i386/64/dfp-machine.h" +#else +#include "config/i386/32/dfp-machine.h" +#endif + +/* Initialize the rounding mode to round-to-nearest if needed. */ +#define DFP_INIT_ROUNDMODE \ + DFP_GET_ROUNDMODE; \ + do \ + { \ + if (_frnd_orig != FP_RND_NEAREST) \ + DFP_SET_ROUNDMODE (FP_RND_NEAREST); \ + } \ + while (0); + +/* Restore the rounding mode to round-to-nearest if changed. */ +#define DFP_RESTORE_ROUNDMODE \ + do \ + { \ + if (_frnd_orig != FP_RND_NEAREST) \ + DFP_SET_ROUNDMODE (_frnd_orig); \ + } \ + while (0); +#endif + +#endif /* _X86_DFP_MACHINE_H */ diff --git a/libgcc/config/libbid/bid128_div.c b/libgcc/config/libbid/bid128_div.c index 925bf14a3361..f05f9f468252 100644 --- a/libgcc/config/libbid/bid128_div.c +++ b/libgcc/config/libbid/bid128_div.c @@ -49,6 +49,9 @@ BID128_FUNCTION_ARG2 (bid128_div, x, y) fexcept_t binaryflags = 0; #endif + // Set the rounding mode to round-to-nearest (if different). + DFP_INIT_ROUNDMODE; + valid_y = unpack_BID128_value (&sign_y, &exponent_y, &CY, y); // unpack arguments, check for NaN or Infinity @@ -62,6 +65,8 @@ if ((x.w[1] & 0x7c00000000000000ull) == 0x7c00000000000000ull) { #endif res.w[1] = (CX.w[1]) & QUIET_MASK64; res.w[0] = CX.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is Infinity? @@ -75,6 +80,8 @@ if ((x.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) { #endif res.w[1] = 0x7c00000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is NaN? @@ -85,6 +92,8 @@ if ((x.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) { res.w[1] = ((x.w[1] ^ y.w[1]) & 0x8000000000000000ull) | 0x7800000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -97,6 +106,8 @@ if ((y.w[1] & 0x7800000000000000ull) < 0x7800000000000000ull) { // x=y=0, return NaN res.w[1] = 0x7c00000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // return 0 @@ -108,6 +119,8 @@ if ((y.w[1] & 0x7800000000000000ull) < 0x7800000000000000ull) { exponent_x = 0; res.w[1] |= (((UINT64) exponent_x) << 49); res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -122,6 +135,8 @@ if (!valid_y) { #endif res.w[1] = CY.w[1] & QUIET_MASK64; res.w[0] = CY.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is Infinity? @@ -129,6 +144,8 @@ if (!valid_y) { // return +/-0 res.w[1] = sign_x ^ sign_y; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is 0, return +/-Inf @@ -138,6 +155,8 @@ if (!valid_y) { res.w[1] = ((x.w[1] ^ y.w[1]) & 0x8000000000000000ull) | 0x7800000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -186,6 +205,8 @@ if (__unsigned_compare_gt_128 (CY, CX)) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // get number of decimal digits in CQ @@ -379,6 +400,8 @@ if (!CA4.w[0] && !CA4.w[1]) #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #endif @@ -469,6 +492,8 @@ if (diff_expon >= 0) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -477,6 +502,8 @@ get_BID128 (&res, sign_x ^ sign_y, diff_expon, CQ, &rnd_mode, pfpsf); #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif +// restore the rounding mode back if it has been changed +DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -500,6 +527,9 @@ TYPE0_FUNCTION_ARGTYPE1_ARGTYPE2 (UINT128, bid128dd_div, UINT64, x, fexcept_t binaryflags = 0; #endif + // Set the rounding mode to round-to-nearest (if different). + DFP_INIT_ROUNDMODE; + valid_y = unpack_BID64 (&sign_y, &exponent_y, &CY.w[0], y); // unpack arguments, check for NaN or Infinity @@ -519,6 +549,8 @@ if ((x & NAN_MASK64) == NAN_MASK64) { res.w[0] = (CX.w[0] & 0x0003ffffffffffffull); __mul_64x64_to_128 (res, res.w[0], power10_table_128[18].w[0]); res.w[1] |= ((CX.w[0]) & 0xfc00000000000000ull); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is Infinity? @@ -532,6 +564,8 @@ if (((x) & 0x7800000000000000ull) == 0x7800000000000000ull) { #endif res.w[1] = 0x7c00000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } if ((((y) & 0x7c00000000000000ull) != 0x7c00000000000000ull)) { @@ -539,6 +573,8 @@ if (((x) & 0x7800000000000000ull) == 0x7800000000000000ull) { res.w[1] = (((x) ^ (y)) & 0x8000000000000000ull) | 0x7800000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -551,6 +587,8 @@ if ((((y) & 0x7800000000000000ull) != 0x7800000000000000ull)) { // x=y=0, return NaN res.w[1] = 0x7c00000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // return 0 @@ -566,6 +604,8 @@ else if (exponent_x < 0) exponent_x = 0; res.w[1] |= (((UINT64) exponent_x) << 49); res.w[0] = 0; +// restore the rounding mode back if it has been changed +DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -583,6 +623,8 @@ if (!valid_y) { res.w[0] = (CY.w[0] & 0x0003ffffffffffffull); __mul_64x64_to_128 (res, res.w[0], power10_table_128[18].w[0]); res.w[1] |= ((CY.w[0]) & 0xfc00000000000000ull); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is Infinity? @@ -590,6 +632,8 @@ if (!valid_y) { // return +/-0 res.w[1] = sign_x ^ sign_y; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is 0, return +/-Inf @@ -599,6 +643,8 @@ if (!valid_y) { #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, ZERO_DIVIDE_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -647,6 +693,8 @@ if (__unsigned_compare_gt_128 (CY, CX)) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // get number of decimal digits in CQ @@ -843,6 +891,8 @@ __div_256_by_128 (&CQ, &CA4, CY); #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #endif @@ -932,6 +982,8 @@ if (diff_expon >= 0) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -940,6 +992,8 @@ get_BID128 (&res, sign_x ^ sign_y, diff_expon, CQ, &rnd_mode, pfpsf); #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif +// restore the rounding mode back if it has been changed +DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -959,6 +1013,9 @@ BID128_FUNCTION_ARGTYPE1_ARG128 (bid128dq_div, UINT64, x, y) fexcept_t binaryflags = 0; #endif + // Set the rounding mode to round-to-nearest (if different) + DFP_INIT_ROUNDMODE; + valid_y = unpack_BID128_value (&sign_y, &exponent_y, &CY, y); // unpack arguments, check for NaN or Infinity @@ -978,6 +1035,8 @@ if ((x & NAN_MASK64) == NAN_MASK64) { res.w[0] = (CX.w[0] & 0x0003ffffffffffffull); __mul_64x64_to_128 (res, res.w[0], power10_table_128[18].w[0]); res.w[1] |= ((CX.w[0]) & 0xfc00000000000000ull); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is Infinity? @@ -991,6 +1050,8 @@ if ((x & 0x7800000000000000ull) == 0x7800000000000000ull) { #endif res.w[1] = 0x7c00000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } if (((y.w[1] & 0x7c00000000000000ull) != 0x7c00000000000000ull)) { @@ -998,6 +1059,8 @@ if ((x & 0x7800000000000000ull) == 0x7800000000000000ull) { res.w[1] = ((x ^ y.w[1]) & 0x8000000000000000ull) | 0x7800000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -1010,6 +1073,8 @@ if ((y.w[1] & INFINITY_MASK64) != INFINITY_MASK64) { // x=y=0, return NaN res.w[1] = 0x7c00000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // return 0 @@ -1021,6 +1086,8 @@ if ((y.w[1] & INFINITY_MASK64) != INFINITY_MASK64) { exponent_x = 0; res.w[1] |= (((UINT64) exponent_x) << 49); res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -1037,6 +1104,8 @@ if (!valid_y) { #endif res.w[1] = CY.w[1] & QUIET_MASK64; res.w[0] = CY.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is Infinity? @@ -1044,6 +1113,8 @@ if (!valid_y) { // return +/-0 res.w[1] = sign_x ^ sign_y; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is 0, return +/-Inf @@ -1053,6 +1124,8 @@ if (!valid_y) { #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, ZERO_DIVIDE_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -1101,6 +1174,8 @@ if (__unsigned_compare_gt_128 (CY, CX)) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // get number of decimal digits in CQ @@ -1300,6 +1375,8 @@ __div_256_by_128 (&CQ, &CA4, CY); #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #endif @@ -1389,6 +1466,8 @@ if (diff_expon >= 0) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -1396,6 +1475,8 @@ get_BID128 (&res, sign_x ^ sign_y, diff_expon, CQ, &rnd_mode, pfpsf); #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif +// restore the rounding mode back if it has been changed +DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -1415,6 +1496,8 @@ BID128_FUNCTION_ARG128_ARGTYPE2 (bid128qd_div, x, UINT64, y) fexcept_t binaryflags = 0; #endif + // Set the rounding mode to round-to-nearest (if different) + DFP_INIT_ROUNDMODE; valid_y = unpack_BID64 (&sign_y, &exponent_y, &CY.w[0], y); // unpack arguments, check for NaN or Infinity @@ -1428,6 +1511,8 @@ if ((x.w[1] & 0x7c00000000000000ull) == 0x7c00000000000000ull) { #endif res.w[1] = (CX.w[1]) & QUIET_MASK64; res.w[0] = CX.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is Infinity? @@ -1441,6 +1526,8 @@ if ((x.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) { #endif res.w[1] = 0x7c00000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is NaN? @@ -1451,6 +1538,8 @@ if ((x.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) { res.w[1] = ((x.w[1] ^ y) & 0x8000000000000000ull) | 0x7800000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -1463,6 +1552,8 @@ if ((y & 0x7800000000000000ull) < 0x7800000000000000ull) { // x=y=0, return NaN res.w[1] = 0x7c00000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // return 0 @@ -1474,6 +1565,8 @@ if ((y & 0x7800000000000000ull) < 0x7800000000000000ull) { exponent_x = 0; res.w[1] |= (((UINT64) exponent_x) << 49); res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -1490,6 +1583,8 @@ if (!valid_y) { res.w[0] = (CY.w[0] & 0x0003ffffffffffffull); __mul_64x64_to_128 (res, res.w[0], power10_table_128[18].w[0]); res.w[1] |= ((CY.w[0]) & 0xfc00000000000000ull); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is Infinity? @@ -1497,6 +1592,8 @@ if (!valid_y) { // return +/-0 res.w[1] = ((x.w[1] ^ y) & 0x8000000000000000ull); res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is 0 @@ -1505,6 +1602,8 @@ if (!valid_y) { #endif res.w[1] = (sign_x ^ sign_y) | INFINITY_MASK64; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -1553,6 +1652,8 @@ if (__unsigned_compare_gt_128 (CY, CX)) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // get number of decimal digits in CQ @@ -1749,6 +1850,8 @@ __div_256_by_128 (&CQ, &CA4, CY); #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #endif @@ -1838,6 +1941,8 @@ if (diff_expon >= 0) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -1846,6 +1951,8 @@ get_BID128 (&res, sign_x ^ sign_y, diff_expon, CQ, &rnd_mode, pfpsf); #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif +// restore the rounding mode back if it has been changed +DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } diff --git a/libgcc/config/libbid/bid128_rem.c b/libgcc/config/libbid/bid128_rem.c index f229b2869af3..1c6da70cf590 100644 --- a/libgcc/config/libbid/bid128_rem.c +++ b/libgcc/config/libbid/bid128_rem.c @@ -35,6 +35,9 @@ BID128_FUNCTION_ARG2_NORND_CUSTOMRESTYPE (UINT128, bid128_rem, x, y) int exponent_x, exponent_y, diff_expon, bin_expon_cx, scale, scale0; + // Set the rounding mode to round-to-nearest (if different) + DFP_INIT_ROUNDMODE; + // unpack arguments, check for NaN or Infinity valid_y = unpack_BID128_value (&sign_y, &exponent_y, &CY, y); @@ -52,6 +55,8 @@ if ((x.w[1] & 0x7c00000000000000ull) == 0x7c00000000000000ull) { #endif res.w[1] = CX.w[1] & QUIET_MASK64; res.w[0] = CX.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is Infinity? @@ -66,6 +71,8 @@ if ((x.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) { #endif res.w[1] = 0x7c00000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -79,6 +86,8 @@ if ((!CY.w[1]) && (!CY.w[0])) { // x=y=0, return NaN res.w[1] = 0x7c00000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } if (valid_y || ((y.w[1] & NAN_MASK64) == INFINITY_MASK64)) { @@ -89,6 +98,8 @@ if (valid_y || ((y.w[1] & NAN_MASK64) == INFINITY_MASK64)) { res.w[1] = sign_x | (((UINT64) exponent_x) << 49); res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -103,6 +114,8 @@ if (!valid_y) { #endif res.w[1] = CY.w[1] & QUIET_MASK64; res.w[0] = CY.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is Infinity? @@ -110,6 +123,8 @@ if (!valid_y) { // return x res.w[1] = x.w[1]; res.w[0] = x.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is 0 @@ -119,6 +134,8 @@ if (!valid_y) { #endif res.w[1] = 0x7c00000000000000ull; res.w[0] = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -130,6 +147,8 @@ if (diff_expon <= 0) { if (diff_expon > 34) { // |x|<|y| in this case res = x; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // set exponent of y to exponent_x, scale coefficient_y @@ -139,6 +158,8 @@ if (diff_expon <= 0) { if (P256.w[2] || P256.w[3]) { // |x|<|y| in this case res = x; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -147,6 +168,8 @@ if (diff_expon <= 0) { if (__unsigned_compare_ge_128 (P256, CX2)) { // |x|<|y| in this case res = x; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -164,6 +187,8 @@ if (diff_expon <= 0) { } get_BID128_very_fast (&res, sign_x, exponent_x, CR); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // 2^64 @@ -200,6 +225,8 @@ while (diff_expon > 0) { // check for remainder == 0 if (!CX.w[1] && !CX.w[0]) { get_BID128_very_fast (&res, sign_x, exponent_y, CX); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -213,5 +240,7 @@ if ((__unsigned_compare_gt_128 (CX2, CY)) } get_BID128_very_fast (&res, sign_x, exponent_y, CX); +// restore the rounding mode back if it has been changed +DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } diff --git a/libgcc/config/libbid/bid128_sqrt.c b/libgcc/config/libbid/bid128_sqrt.c index b28038389ad1..71a033f54fe4 100644 --- a/libgcc/config/libbid/bid128_sqrt.c +++ b/libgcc/config/libbid/bid128_sqrt.c @@ -43,6 +43,9 @@ BID128_FUNCTION_ARG1 (bid128_sqrt, x) fexcept_t binaryflags = 0; #endif + // Set the rounding mode to round-to-nearest (if different) + DFP_INIT_ROUNDMODE; + // unpack arguments, check for NaN or Infinity if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { res.w[1] = CX.w[1]; @@ -54,6 +57,8 @@ if ((x.w[1] & 0x7c00000000000000ull) == 0x7c00000000000000ull) { __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif res.w[1] = CX.w[1] & QUIET_MASK64; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is Infinity? @@ -66,6 +71,8 @@ if ((x.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) { __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif } + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is 0 otherwise @@ -74,6 +81,8 @@ res.w[1] = sign_x | ((((UINT64) (exponent_x + DECIMAL_EXPONENT_BIAS_128)) >> 1) << 49); res.w[0] = 0; +// restore the rounding mode back if it has been changed +DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } if (sign_x) { @@ -82,6 +91,8 @@ if (sign_x) { #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -117,6 +128,8 @@ if (CS.w[0] * CS.w[0] == A10.w[0]) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -288,6 +301,8 @@ get_BID128_fast (&res, 0, #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif +// restore the rounding mode back if it has been changed +DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -302,10 +317,14 @@ BID128_FUNCTION_ARGTYPE1 (bid128d_sqrt, UINT64, x) int_float fx, f64; int exponent_x, bin_expon_cx; int digits, scale, exponent_q; + #ifdef UNCHANGED_BINARY_STATUS_FLAGS fexcept_t binaryflags = 0; #endif + // Set the rounding mode to round-to-nearest (if different) + DFP_INIT_ROUNDMODE; + // unpack arguments, check for NaN or Infinity // unpack arguments, check for NaN or Infinity CX.w[1] = 0; @@ -321,6 +340,8 @@ if ((x & 0x7c00000000000000ull) == 0x7c00000000000000ull) { res.w[0] = (CX.w[0] & 0x0003ffffffffffffull); __mul_64x64_to_128 (res, res.w[0], power10_table_128[18].w[0]); res.w[1] |= ((CX.w[0]) & 0xfc00000000000000ull); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is Infinity? @@ -332,6 +353,8 @@ if ((x & 0x7800000000000000ull) == 0x7800000000000000ull) { __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif } + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is 0 otherwise @@ -342,6 +365,8 @@ res.w[1] = sign_x | ((((UINT64) (exponent_x + DECIMAL_EXPONENT_BIAS_128)) >> 1) << 49); res.w[0] = 0; +// restore the rounding mode back if it has been changed +DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } if (sign_x) { @@ -350,6 +375,8 @@ if (sign_x) { #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -387,6 +414,8 @@ if (CS.w[0] * CS.w[0] == A10.w[0]) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -558,6 +587,8 @@ get_BID128_fast (&res, 0, (exponent_q + DECIMAL_EXPONENT_BIAS_128) >> 1, #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif +// restore the rounding mode back if it has been changed +DFP_RESTORE_ROUNDMODE; BID_RETURN (res); diff --git a/libgcc/config/libbid/bid64_div.c b/libgcc/config/libbid/bid64_div.c index 69758482b89e..5de1a4596cc9 100644 --- a/libgcc/config/libbid/bid64_div.c +++ b/libgcc/config/libbid/bid64_div.c @@ -106,6 +106,9 @@ bid64_div (UINT64 x, y = *py; #endif + // Set the rounding mode to round-to-nearest (if different) + DFP_INIT_ROUNDMODE; + valid_x = unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x); valid_y = unpack_BID64 (&sign_y, &exponent_y, &coefficient_y, y); @@ -123,6 +126,8 @@ bid64_div (UINT64 x, if ((x & SNAN_MASK64) == SNAN_MASK64) // sNaN __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (coefficient_x & QUIET_MASK64); } // x is Infinity? @@ -134,9 +139,13 @@ bid64_div (UINT64 x, #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (NAN_MASK64); } } else { + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; // otherwise return +/-Inf BID_RETURN (((x ^ y) & 0x8000000000000000ull) | INFINITY_MASK64); @@ -149,6 +158,8 @@ bid64_div (UINT64 x, #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (NAN_MASK64); } if (((y & INFINITY_MASK64) != INFINITY_MASK64)) { @@ -163,6 +174,8 @@ bid64_div (UINT64 x, exponent_x = DECIMAL_MAX_EXPON_64; else if (exponent_x < 0) exponent_x = 0; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN ((sign_x ^ sign_y) | (((UINT64) exponent_x) << 53)); } @@ -176,10 +189,14 @@ bid64_div (UINT64 x, if ((y & SNAN_MASK64) == SNAN_MASK64) // sNaN __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (coefficient_y & QUIET_MASK64); } // y is Infinity? if ((y & INFINITY_MASK64) == INFINITY_MASK64) { + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; // return +/-0 BID_RETURN (((x ^ y) & 0x8000000000000000ull)); } @@ -187,6 +204,8 @@ bid64_div (UINT64 x, #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, ZERO_DIVIDE_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN ((sign_x ^ sign_y) | INFINITY_MASK64); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -255,6 +274,8 @@ bid64_div (UINT64 x, #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // get decimal digits of Q @@ -424,6 +445,8 @@ bid64_div (UINT64 x, #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -494,6 +517,8 @@ bid64_div (UINT64 x, #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } else { // UF occurs @@ -510,6 +535,8 @@ bid64_div (UINT64 x, #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -532,6 +559,9 @@ unsigned rmode; fexcept_t binaryflags = 0; #endif +// Set the rounding mode to round-to-nearest (if different) +DFP_INIT_ROUNDMODE; + valid_y = unpack_BID128_value (&sign_y, &exponent_y, &CY, y); // unpack arguments, check for NaN or Infinity @@ -545,6 +575,8 @@ if (!unpack_BID64 (&sign_x, &exponent_x, &CX.w[0], (x))) { // test if x is NaN if (((x) & 0x7c00000000000000ull) == 0x7c00000000000000ull) { res = CX.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res & QUIET_MASK64); } // x is Infinity? @@ -557,12 +589,16 @@ if (!unpack_BID64 (&sign_x, &exponent_x, &CX.w[0], (x))) { __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif res = 0x7c00000000000000ull; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } if (((y.w[1] & 0x7c00000000000000ull) != 0x7c00000000000000ull)) { // otherwise return +/-Inf res = (((x) ^ y.w[1]) & 0x8000000000000000ull) | 0x7800000000000000ull; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -574,6 +610,8 @@ if (!unpack_BID64 (&sign_x, &exponent_x, &CX.w[0], (x))) { #endif // x=y=0, return NaN res = 0x7c00000000000000ull; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // return 0 @@ -584,6 +622,8 @@ if (!unpack_BID64 (&sign_x, &exponent_x, &CX.w[0], (x))) { else if (exponent_x < 0) exponent_x = 0; res |= (((UINT64) exponent_x) << 53); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -604,12 +644,16 @@ if (!valid_y) { amount = recip_scale[18]; __shr_128 (Tmp, Qh, amount); res = (CY.w[1] & 0xfc00000000000000ull) | Tmp.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is Infinity? if ((y.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) { // return +/-0 res = sign_x ^ sign_y; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is 0, return +/-Inf @@ -618,6 +662,8 @@ if (!valid_y) { #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, ZERO_DIVIDE_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -680,6 +726,8 @@ if (__unsigned_compare_gt_128 (CY, CX)) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -823,6 +871,8 @@ if (!done) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -905,6 +955,8 @@ if (!done) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } else { // UF occurs @@ -921,6 +973,8 @@ if (!done) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -946,6 +1000,9 @@ unsigned rmode; fexcept_t binaryflags = 0; #endif +// Set the rounding mode to round-to-nearest (if different) +DFP_INIT_ROUNDMODE; + valid_y = unpack_BID64 (&sign_y, &exponent_y, &CY.w[0], (y)); // unpack arguments, check for NaN or Infinity @@ -964,6 +1021,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { amount = recip_scale[18]; __shr_128 (Tmp, Qh, amount); res = (CX.w[1] & 0xfc00000000000000ull) | Tmp.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is Infinity? @@ -976,12 +1035,16 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif res = 0x7c00000000000000ull; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } if (((y & 0x7c00000000000000ull) != 0x7c00000000000000ull)) { // otherwise return +/-Inf res = ((x.w[1] ^ (y)) & 0x8000000000000000ull) | 0x7800000000000000ull; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -993,6 +1056,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { #endif // x=y=0, return NaN res = 0x7c00000000000000ull; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // return 0 @@ -1002,6 +1067,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif res = 0x7c00000000000000ull; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } exponent_x = @@ -1012,6 +1079,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { else if (exponent_x < 0) exponent_x = 0; res = (sign_x ^ sign_y) | (((UINT64) exponent_x) << 53); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -1025,12 +1094,16 @@ if (!valid_y) { if ((y & SNAN_MASK64) == SNAN_MASK64) // sNaN __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (CY.w[0] & QUIET_MASK64); } // y is Infinity? if (((y) & 0x7800000000000000ull) == 0x7800000000000000ull) { // return +/-0 res = sign_x ^ sign_y; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is 0, return +/-Inf @@ -1039,6 +1112,8 @@ if (!valid_y) { #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, ZERO_DIVIDE_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -1103,6 +1178,8 @@ if (__unsigned_compare_gt_128 (CY, CX)) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -1252,6 +1329,8 @@ if (!done) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -1337,6 +1416,8 @@ if (!done) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } else { // UF occurs @@ -1353,6 +1434,8 @@ if (!done) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -1383,6 +1466,9 @@ unsigned rmode; fexcept_t binaryflags = 0; #endif +// Set the rounding mode to round-to-nearest (if different) +DFP_INIT_ROUNDMODE; + valid_y = unpack_BID128_value (&sign_y, &exponent_y, &CY, y); // unpack arguments, check for NaN or Infinity @@ -1401,6 +1487,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { amount = recip_scale[18]; __shr_128 (Tmp, Qh, amount); res = (CX.w[1] & 0xfc00000000000000ull) | Tmp.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is Infinity? @@ -1413,6 +1501,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif res = 0x7c00000000000000ull; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } if (((y.w[1] & 0x7c00000000000000ull) != 0x7c00000000000000ull)) { @@ -1420,6 +1510,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { res = ((x.w[1] ^ y. w[1]) & 0x8000000000000000ull) | 0x7800000000000000ull; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -1431,6 +1523,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { #endif // x=y=0, return NaN res = 0x7c00000000000000ull; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // return 0 @@ -1441,6 +1535,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { else if (exponent_x < 0) exponent_x = 0; res |= (((UINT64) exponent_x) << 53); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -1460,12 +1556,16 @@ if (!valid_y) { amount = recip_scale[18]; __shr_128 (Tmp, Qh, amount); res = (CY.w[1] & 0xfc00000000000000ull) | Tmp.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is Infinity? if ((y.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) { // return +/-0 res = sign_x ^ sign_y; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // y is 0, return +/-Inf @@ -1474,6 +1574,8 @@ if (!valid_y) { #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, ZERO_DIVIDE_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -1536,6 +1638,8 @@ if (__unsigned_compare_gt_128 (CY, CX)) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -1686,6 +1790,8 @@ if (!done) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -1772,6 +1878,8 @@ if (!done) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } else { // UF occurs @@ -1788,6 +1896,8 @@ if (!done) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } diff --git a/libgcc/config/libbid/bid64_sqrt.c b/libgcc/config/libbid/bid64_sqrt.c index 29f4cf1f819f..dbd06eaa153d 100644 --- a/libgcc/config/libbid/bid64_sqrt.c +++ b/libgcc/config/libbid/bid64_sqrt.c @@ -73,6 +73,7 @@ bid64_sqrt (UINT64 x _RND_MODE_PARAM _EXC_FLAGS_PARAM int exponent_x, exponent_q, bin_expon_cx; int digits_x; int scale; + #ifdef UNCHANGED_BINARY_STATUS_FLAGS fexcept_t binaryflags = 0; #endif @@ -84,6 +85,9 @@ bid64_sqrt (UINT64 x _RND_MODE_PARAM _EXC_FLAGS_PARAM x = *px; #endif + // Set the rounding mode to round-to-nearest (if different) + DFP_INIT_ROUNDMODE; + // unpack arguments, check for NaN or Infinity if (!unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x)) { // x is Inf. or NaN or 0 @@ -100,11 +104,15 @@ bid64_sqrt (UINT64 x _RND_MODE_PARAM _EXC_FLAGS_PARAM if ((x & SNAN_MASK64) == SNAN_MASK64) // sNaN __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res & QUIET_MASK64); } // x is 0 exponent_x = (exponent_x + DECIMAL_EXPONENT_BIAS) >> 1; res = sign_x | (((UINT64) exponent_x) << 53); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x<0? @@ -113,6 +121,8 @@ bid64_sqrt (UINT64 x _RND_MODE_PARAM _EXC_FLAGS_PARAM #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -141,6 +151,8 @@ bid64_sqrt (UINT64 x _RND_MODE_PARAM _EXC_FLAGS_PARAM #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // if exponent is odd, scale coefficient by 10 @@ -206,6 +218,8 @@ bid64_sqrt (UINT64 x _RND_MODE_PARAM _EXC_FLAGS_PARAM #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } @@ -224,6 +238,9 @@ int digits, scale, exponent_q = 0, exact = 1, amount, extra_digits; fexcept_t binaryflags = 0; #endif +// Set the rounding mode to round-to-nearest (if different) +DFP_INIT_ROUNDMODE; + // unpack arguments, check for NaN or Infinity if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { res = CX.w[1]; @@ -240,6 +257,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { amount = recip_scale[18]; __shr_128 (Tmp, Qh, amount); res = (CX.w[1] & 0xfc00000000000000ull) | Tmp.w[0]; + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is Infinity? @@ -251,6 +270,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif } + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } // x is 0 otherwise @@ -264,6 +285,8 @@ if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { exponent_x = DECIMAL_MAX_EXPON_64; //res= sign_x | (((UINT64)exponent_x)<<53); res = get_BID64 (sign_x, exponent_x, 0, rnd_mode, pfpsf); + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } if (sign_x) { @@ -271,6 +294,8 @@ if (sign_x) { #ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, INVALID_EXCEPTION); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } #ifdef UNCHANGED_BINARY_STATUS_FLAGS @@ -312,6 +337,8 @@ if (CS.w[0] < 10000000000000000ull) { #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif + // restore the rounding mode back if it has been changed + DFP_RESTORE_ROUNDMODE; BID_RETURN (res); } } @@ -546,6 +573,8 @@ res = get_BID64 (0, exponent_q, CS.w[0], rnd_mode, pfpsf); #ifdef UNCHANGED_BINARY_STATUS_FLAGS (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS); #endif +// restore the rounding mode back if it has been changed +DFP_RESTORE_ROUNDMODE; BID_RETURN (res); diff --git a/libgcc/config/libbid/bid_conf.h b/libgcc/config/libbid/bid_conf.h index 0f39d58d3061..56f2b348ec03 100644 --- a/libgcc/config/libbid/bid_conf.h +++ b/libgcc/config/libbid/bid_conf.h @@ -559,6 +559,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #endif // #define HPUX_OS +#include <dfp-machine.h> + // If DECIMAL_CALL_BY_REFERENCE is defined then numerical arguments and results // are passed by reference otherwise they are passed by value (except that // a pointer is always passed to the status flags) diff --git a/libgcc/config/libbid/dfp-machine.h b/libgcc/config/libbid/dfp-machine.h new file mode 100644 index 000000000000..ae961157abba --- /dev/null +++ b/libgcc/config/libbid/dfp-machine.h @@ -0,0 +1,34 @@ +/* Rounding mode macros for DFP libbid. Dummy version. + Copyright (C) 2025 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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; either version 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _DFP_MACHINE_H +#define _DFP_MACHINE_H + +/* Initialize the rounding mode to round-to-nearest if needed. */ +#define DFP_INIT_ROUNDMODE + +/* Restore the rounding mode to round-to-nearest if changed. */ +#define DFP_RESTORE_ROUNDMODE + +#endif /* _DFP_MACHINE_H */
