mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-03 10:21:05 +00:00
21378ae0d3
The powerpc hard-float round and roundf functions, both 32-bit and 64-bit, raise spurious "inexact" exceptions for integer arguments from adding 0.5 and rounding to integer toward zero. Since these functions already save and restore the rounding mode, it's natural to make them restore the full floating-point state instead to fix this bug, which this patch does. The save of the state is moved after the first floating-point operation on the input so that any "invalid" exceptions from signaling NaN inputs are properly preserved. As a consequence of this approach to the fix, "inexact" for noninteger arguments (disallowed by TS 18661-1 but not by C99/C11, see bug 15479) is also avoided for these implementations; this is *not* a general fix for bug 15479 since plenty of other implementations of various functions still raise spurious "inexact" for noninteger arguments. This issue and fix do not apply to builds using power5+ versions of round and roundf, which use the frin instruction and avoid "inexact" exceptions that way. This patch should get hard-float powerpc32 and powerpc64 (default function implementations) back to a state where test-float and test-double will pass after ulps regeneration. Tested for powerpc32 and powerpc64. [BZ #15479] [BZ #19238] * sysdeps/powerpc/powerpc32/fpu/s_round.S (__round): Save floating-point state after first operation on input. Restore full state rather than just rounding mode. * sysdeps/powerpc/powerpc32/fpu/s_roundf.S (__roundf): Likewise. * sysdeps/powerpc/powerpc64/fpu/s_round.S (__round): Likewise. * sysdeps/powerpc/powerpc64/fpu/s_roundf.S (__roundf): Likewise.
76 lines
2.5 KiB
ArmAsm
76 lines
2.5 KiB
ArmAsm
/* roundf function. PowerPC64 version.
|
|
Copyright (C) 2004-2015 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#include <sysdep.h>
|
|
|
|
.section ".toc","aw"
|
|
.p2align 3
|
|
.LC0: /* 2**23 */
|
|
.long 0x4b000000
|
|
.LC1: /* 0.5 */
|
|
.long 0x3f000000
|
|
|
|
.section ".text"
|
|
|
|
/* float [fp1] roundf (float x [fp1])
|
|
IEEE 1003.1 round function. IEEE specifies "round to the nearest
|
|
integer value, rounding halfway cases away from zero, regardless of
|
|
the current rounding mode." However PowerPC Architecture defines
|
|
"Round to Nearest" as "Choose the best approximation. In case of a
|
|
tie, choose the one that is even (least significant bit o).".
|
|
So we can't use the PowerPC "Round to Nearest" mode. Instead we set
|
|
"Round toward Zero" mode and round by adding +-0.5 before rounding
|
|
to the integer value. */
|
|
|
|
EALIGN (__roundf, 4, 0)
|
|
CALL_MCOUNT 0
|
|
lfs fp13,.LC0@toc(2)
|
|
fabs fp0,fp1
|
|
fsubs fp12,fp13,fp13 /* generate 0.0 */
|
|
fcmpu cr7,fp0,fp13 /* if (fabs(x) > TWO23) */
|
|
mffs fp11 /* Save current FPU rounding mode and
|
|
"inexact" state. */
|
|
fcmpu cr6,fp1,fp12 /* if (x > 0.0) */
|
|
bnllr- cr7
|
|
mtfsfi 7,1 /* Set rounding mode toward 0. */
|
|
lfs fp10,.LC1@toc(2)
|
|
ble- cr6,.L4
|
|
fadds fp1,fp1,fp10 /* x+= 0.5; */
|
|
fadds fp1,fp1,fp13 /* x+= TWO23; */
|
|
fsubs fp1,fp1,fp13 /* x-= TWO23; */
|
|
fabs fp1,fp1 /* if (x == 0.0) */
|
|
/* x = 0.0; */
|
|
mtfsf 0xff,fp11 /* Restore previous rounding mode and
|
|
"inexact" state. */
|
|
blr
|
|
.L4:
|
|
fsubs fp9,fp1,fp10 /* x+= 0.5; */
|
|
bge- cr6,.L9 /* if (x < 0.0) */
|
|
fsubs fp1,fp9,fp13 /* x-= TWO23; */
|
|
fadds fp1,fp1,fp13 /* x+= TWO23; */
|
|
fnabs fp1,fp1 /* if (x == 0.0) */
|
|
/* x = -0.0; */
|
|
.L9:
|
|
mtfsf 0xff,fp11 /* Restore previous rounding mode and
|
|
"inexact" state. */
|
|
blr
|
|
END (__roundf)
|
|
|
|
weak_alias (__roundf, roundf)
|
|
|