232b6ec5df
The ABS.fmt and NEG.fmt instructions have been specified as arithmetic in the MIPS architecture, which in particular implies handling NaN data in the usual way with qNaN bit patterns propagated unchanged and sNaN bit patterns signalling the usual IEEE 754 Invalid Operation exception and quieted by default. A series of changes applied over time to our implementation:c5033d78
[MIPS] ieee754[sd]p_neg workaroundcea2be44
MIPS: Fix abs.[sd] and neg.[sd] emulation for NaN operands has led to the current situation where the sign bit is updated according to the operation requested even for NaN inputs. This is according to these commits a workaround so that broken binaries produced by GCC disregarding the properties of these instructions have a chance to work. For sNaN inputs this remains within IEEE Std 754 as the standard leaves the choice of output qNaN bit patterns produced under the default Invalid Operation exception handling for individual sNaN input bit patterns to implementer's discretion, even though it still recommends as much NaN input information to be preserved in NaN outputs. For qNaN inputs however it violates the standard as it requires a qNaN input bit patterns to propagate unchanged to output. This is also unlike real MIPS FPU hardware behaves where sNaN and/or qNaN processing has been fully implemented with no Unimplemented Operation exception signalled. Such hardware propagates any input qNaN bit pattern unchanged. It also quiets any input sNaN bit pattern in an implementer-specific manner, for example the MIPS 74Kf processor returns the default qNaN pattern with the sign bit always clear and the Broadcom SB-1 and BMIPS5000 processors propagate the input sNaN bit pattern with the sign bit unchanged and the quiet bit first cleared in the trailing significand field and then the next lower bit set if clearing the quiet bit left the field with no other bit set. Especially the latter observation indicates the limited usefulness of the workaround as it will cover many hardware configurations, but not all of them, only making it harder to discover such broken binaries that need to be recompiled with GCC told to avoid the use of ABS.fmt and NEG.fmt instructions where non-arithmetic semantics is required by the algorithm used. Revert the damage done by the series of changes then, and take the opportunity to simplify implementation by calling `ieee754dp_sub' and `ieee754dp_add' as required and also the rounding mode set towards -Inf temporarily so that the sign of 0 is correctly handled. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9710/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
49 lines
1.3 KiB
C
49 lines
1.3 KiB
C
/* IEEE754 floating point arithmetic
|
|
* double precision: common utilities
|
|
*/
|
|
/*
|
|
* MIPS floating point support
|
|
* Copyright (C) 1994-2000 Algorithmics Ltd.
|
|
*
|
|
* This program is free software; you can distribute it and/or modify it
|
|
* under the terms of the GNU General Public License (Version 2) as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope 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, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "ieee754dp.h"
|
|
|
|
union ieee754dp ieee754dp_neg(union ieee754dp x)
|
|
{
|
|
unsigned int oldrm;
|
|
union ieee754dp y;
|
|
|
|
oldrm = ieee754_csr.rm;
|
|
ieee754_csr.rm = FPU_CSR_RD;
|
|
y = ieee754dp_sub(ieee754dp_zero(0), x);
|
|
ieee754_csr.rm = oldrm;
|
|
return y;
|
|
}
|
|
|
|
union ieee754dp ieee754dp_abs(union ieee754dp x)
|
|
{
|
|
unsigned int oldrm;
|
|
union ieee754dp y;
|
|
|
|
oldrm = ieee754_csr.rm;
|
|
ieee754_csr.rm = FPU_CSR_RD;
|
|
if (DPSIGN(x))
|
|
y = ieee754dp_sub(ieee754dp_zero(0), x);
|
|
else
|
|
y = ieee754dp_add(ieee754dp_zero(0), x);
|
|
ieee754_csr.rm = oldrm;
|
|
return y;
|
|
}
|