mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00:00
[BZ #2466]
* math/gen-libm-test.pl (parse_args): Take function name for pretty output as an argument. (generate_testfile): Pass it the name given in the START macro. [BZ #2466] * math/libm-test.inc (llrint_test, llround_test): Fix last change to protect large-precision cases with [LDBL_MANT_DIG > 100]. (llrint_test_tonearest, llrint_test_towardzero): Likewise. (llrint_test_downward, llrint_test_upward): Likewise. 2006-03-15 Steven Munroe <sjmunroe@us.ibm.com> Alan Modra <amodra@bigpond.net.au> [BZ #2466] * math/libm-test.inc (llrint_test, llround_test) [TEST_LDOUBLE]: Add new test values. (llrint_test_tonearest, llrint_test_towardzero, llrint_test_downward, llrint_test_upward): New functions. (main): Call them. * sysdeps/ieee754/ldbl-128ibm/s_llrintl.c (__llrintl): Handle rounding that spans doubles in IBM long double format. * sysdeps/ieee754/ldbl-128ibm/s_llroundl.c (__llroundl): Likewise. * sysdeps/powerpc/powerpc64/fpu/s_llrintl.S: Removed. * sysdeps/powerpc/powerpc64/fpu/s_llroundl.S: Removed. * sysdeps/powerpc/powerpc64/fpu/s_lrintl.S: Removed. * sysdeps/powerpc/powerpc64/fpu/s_lroundl.S: Removed. 2006-03-16 Roland McGrath <roland@redhat.com>
This commit is contained in:
parent
27c0e0d863
commit
830fce0415
30
ChangeLog
30
ChangeLog
@ -1,3 +1,33 @@
|
||||
2006-03-16 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* math/gen-libm-test.pl (parse_args): Take function name for pretty
|
||||
output as an argument.
|
||||
(generate_testfile): Pass it the name given in the START macro.
|
||||
|
||||
[BZ #2466]
|
||||
* math/libm-test.inc (llrint_test, llround_test): Fix last change to
|
||||
protect large-precision cases with [LDBL_MANT_DIG > 100].
|
||||
(llrint_test_tonearest, llrint_test_towardzero): Likewise.
|
||||
(llrint_test_downward, llrint_test_upward): Likewise.
|
||||
|
||||
2006-03-15 Steven Munroe <sjmunroe@us.ibm.com>
|
||||
Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
[BZ #2466]
|
||||
* math/libm-test.inc (llrint_test, llround_test) [TEST_LDOUBLE]:
|
||||
Add new test values.
|
||||
(llrint_test_tonearest, llrint_test_towardzero, llrint_test_downward,
|
||||
llrint_test_upward): New functions.
|
||||
(main): Call them.
|
||||
|
||||
* sysdeps/ieee754/ldbl-128ibm/s_llrintl.c (__llrintl): Handle
|
||||
rounding that spans doubles in IBM long double format.
|
||||
* sysdeps/ieee754/ldbl-128ibm/s_llroundl.c (__llroundl): Likewise.
|
||||
* sysdeps/powerpc/powerpc64/fpu/s_llrintl.S: Removed.
|
||||
* sysdeps/powerpc/powerpc64/fpu/s_llroundl.S: Removed.
|
||||
* sysdeps/powerpc/powerpc64/fpu/s_lrintl.S: Removed.
|
||||
* sysdeps/powerpc/powerpc64/fpu/s_lroundl.S: Removed.
|
||||
|
||||
2006-03-16 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* wcsmbs/wchar.h (__wcstol_internal, __wcstoul_internal): Declare these
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/perl -w
|
||||
# Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1999, 2006 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
# Contributed by Andreas Jaeger <aj@suse.de>, 1999.
|
||||
|
||||
@ -234,7 +234,7 @@ sub special_functions {
|
||||
|
||||
# Parse the arguments to TEST_x_y
|
||||
sub parse_args {
|
||||
my ($file, $descr, $args) = @_;
|
||||
my ($file, $descr, $fct, $args) = @_;
|
||||
my (@args, $str, $descr_args, $descr_res, @descr);
|
||||
my ($current_arg, $cline, $i);
|
||||
my ($pre, $post, @special);
|
||||
@ -248,7 +248,7 @@ sub parse_args {
|
||||
|
||||
@args = split /,\s*/, $args;
|
||||
|
||||
$call = "$args[0] (";
|
||||
$call = "$fct (";
|
||||
|
||||
# Generate first the string that's shown to the user
|
||||
$current_arg = 1;
|
||||
@ -423,7 +423,7 @@ sub parse_args {
|
||||
sub generate_testfile {
|
||||
my ($input, $output) = @_;
|
||||
my ($lasttext);
|
||||
my (@args, $i, $str);
|
||||
my (@args, $i, $str, $thisfct);
|
||||
|
||||
open INPUT, $input or die ("Can't open $input: $!");
|
||||
open OUTPUT, ">$output" or die ("Can't open $output: $!");
|
||||
@ -436,11 +436,12 @@ sub generate_testfile {
|
||||
my ($descr, $args);
|
||||
chop;
|
||||
($descr, $args) = ($_ =~ /TEST_(\w+)\s*\((.*)\)/);
|
||||
&parse_args (\*OUTPUT, $descr, $args);
|
||||
&parse_args (\*OUTPUT, $descr, $thisfct, $args);
|
||||
next;
|
||||
}
|
||||
# START (function)
|
||||
if (/START/) {
|
||||
($thisfct) = ($_ =~ /START\s*\((.*)\)/);
|
||||
print OUTPUT " init_max_error ();\n";
|
||||
next;
|
||||
}
|
||||
|
1037
math/libm-test.inc
1037
math/libm-test.inc
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,7 @@
|
||||
when it's coded in C. */
|
||||
|
||||
#include <math.h>
|
||||
#include <fenv_libc.h>
|
||||
#include <math_ldbl_opt.h>
|
||||
#include <float.h>
|
||||
#include <ieee754.h>
|
||||
@ -36,89 +37,114 @@ __llrintl (x)
|
||||
long double x;
|
||||
#endif
|
||||
{
|
||||
static const double TWO52 = 4503599627370496.0L;
|
||||
union ibm_extended_long_double u;
|
||||
long long result = __LONG_LONG_MAX__;
|
||||
double xh, xl;
|
||||
long long res, hi, lo;
|
||||
int save_round;
|
||||
|
||||
u.d = x;
|
||||
ldbl_unpack (x, &xh, &xl);
|
||||
|
||||
if (fabs (u.dd[0]) < TWO52)
|
||||
/* Limit the range of values handled by the conversion to long long.
|
||||
We do this because we aren't sure whether that conversion properly
|
||||
raises FE_INVALID. */
|
||||
if (__builtin_expect
|
||||
((__builtin_fabs (xh) <= -(double) (-__LONG_LONG_MAX__ - 1)), 1)
|
||||
#if !defined (FE_INVALID)
|
||||
|| 1
|
||||
#endif
|
||||
)
|
||||
{
|
||||
double high = u.dd[0];
|
||||
if (high > 0.0)
|
||||
save_round = fegetround ();
|
||||
|
||||
if (__builtin_expect ((xh == -(double) (-__LONG_LONG_MAX__ - 1)), 0))
|
||||
{
|
||||
high += TWO52;
|
||||
high -= TWO52;
|
||||
if (high == -0.0) high = 0.0;
|
||||
/* When XH is 9223372036854775808.0, converting to long long will
|
||||
overflow, resulting in an invalid operation. However, XL might
|
||||
be negative and of sufficient magnitude that the overall long
|
||||
double is in fact in range. Avoid raising an exception. In any
|
||||
case we need to convert this value specially, because
|
||||
the converted value is not exactly represented as a double
|
||||
thus subtracting HI from XH suffers rounding error. */
|
||||
hi = __LONG_LONG_MAX__;
|
||||
xh = 1.0;
|
||||
}
|
||||
else if (high < 0.0)
|
||||
else
|
||||
{
|
||||
high -= TWO52;
|
||||
high += TWO52;
|
||||
if (high == 0.0) high = -0.0;
|
||||
hi = (long long) xh;
|
||||
xh -= hi;
|
||||
}
|
||||
result = high;
|
||||
}
|
||||
else if (fabs (u.dd[1]) < TWO52 && u.dd[1] != 0.0)
|
||||
{
|
||||
double high, low, tau;
|
||||
long long lowint;
|
||||
/* In this case we have to round the low double and handle any
|
||||
adjustment to the high double that may be caused by rounding
|
||||
(up). This is complicated by the fact that the high double
|
||||
may already be rounded and the low double may have the
|
||||
opposite sign to compensate. */
|
||||
if (u.dd[0] > 0.0)
|
||||
ldbl_canonicalize (&xh, &xl);
|
||||
|
||||
lo = (long long) xh;
|
||||
|
||||
/* Peg at max/min values, assuming that the above conversions do so.
|
||||
Strictly speaking, we can return anything for values that overflow,
|
||||
but this is more useful. */
|
||||
res = hi + lo;
|
||||
|
||||
/* This is just sign(hi) == sign(lo) && sign(res) != sign(hi). */
|
||||
if (__builtin_expect (((~(hi ^ lo) & (res ^ hi)) < 0), 0))
|
||||
goto overflow;
|
||||
|
||||
xh -= lo;
|
||||
ldbl_canonicalize (&xh, &xl);
|
||||
|
||||
hi = res;
|
||||
switch (save_round)
|
||||
{
|
||||
if (u.dd[1] > 0.0)
|
||||
{
|
||||
/* If the high/low doubles are the same sign then simply
|
||||
round the low double. */
|
||||
high = u.dd[0];
|
||||
low = u.dd[1];
|
||||
}
|
||||
else if (u.dd[1] < 0.0)
|
||||
{
|
||||
/* Else the high double is pre rounded and we need to
|
||||
adjust for that. */
|
||||
|
||||
tau = nextafter (u.dd[0], 0.0);
|
||||
tau = (u.dd[0] - tau) * 2.0;
|
||||
high = u.dd[0] - tau;
|
||||
low = u.dd[1] + tau;
|
||||
}
|
||||
low += TWO52;
|
||||
low -= TWO52;
|
||||
case FE_TONEAREST:
|
||||
if (fabs (xh) < 0.5
|
||||
|| (fabs (xh) == 0.5
|
||||
&& ((xh > 0.0 && xl < 0.0)
|
||||
|| (xh < 0.0 && xl > 0.0)
|
||||
|| (xl == 0.0 && (res & 1) == 0))))
|
||||
return res;
|
||||
|
||||
if (xh < 0.0)
|
||||
res -= 1;
|
||||
else
|
||||
res += 1;
|
||||
break;
|
||||
|
||||
case FE_TOWARDZERO:
|
||||
if (res > 0 && (xh < 0.0 || (xh == 0.0 && xl < 0.0)))
|
||||
res -= 1;
|
||||
else if (res < 0 && (xh > 0.0 || (xh == 0.0 && xl > 0.0)))
|
||||
res += 1;
|
||||
return res;
|
||||
break;
|
||||
|
||||
case FE_UPWARD:
|
||||
if (xh > 0.0 || (xh == 0.0 && xl > 0.0))
|
||||
res += 1;
|
||||
break;
|
||||
|
||||
case FE_DOWNWARD:
|
||||
if (xh < 0.0 || (xh == 0.0 && xl < 0.0))
|
||||
res -= 1;
|
||||
break;
|
||||
}
|
||||
else if (u.dd[0] < 0.0)
|
||||
{
|
||||
if (u.dd[1] < 0.0)
|
||||
{
|
||||
/* If the high/low doubles are the same sign then simply
|
||||
round the low double. */
|
||||
high = u.dd[0];
|
||||
low = u.dd[1];
|
||||
}
|
||||
else if (u.dd[1] > 0.0)
|
||||
{
|
||||
/* Else the high double is pre rounded and we need to
|
||||
adjust for that. */
|
||||
tau = nextafter (u.dd[0], 0.0);
|
||||
tau = (u.dd[0] - tau) * 2.0;
|
||||
high = u.dd[0] - tau;
|
||||
low = u.dd[1] + tau;
|
||||
}
|
||||
low = TWO52 - low;
|
||||
low = -(low - TWO52);
|
||||
}
|
||||
lowint = low;
|
||||
result = high;
|
||||
result += lowint;
|
||||
|
||||
if (__builtin_expect (((~(hi ^ (res - hi)) & (res ^ hi)) < 0), 0))
|
||||
goto overflow;
|
||||
|
||||
return res;
|
||||
}
|
||||
else
|
||||
result = u.dd[0];
|
||||
{
|
||||
if (xh > 0.0)
|
||||
hi = __LONG_LONG_MAX__;
|
||||
else if (xh < 0.0)
|
||||
hi = -__LONG_LONG_MAX__ - 1;
|
||||
else
|
||||
/* Nan */
|
||||
hi = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
overflow:
|
||||
#ifdef FE_INVALID
|
||||
feraiseexcept (FE_INVALID);
|
||||
#endif
|
||||
return hi;
|
||||
}
|
||||
|
||||
long_double_symbol (libm, __llrintl, llrintl);
|
||||
|
@ -22,12 +22,11 @@
|
||||
when it's coded in C. */
|
||||
|
||||
#include <math.h>
|
||||
#include <fenv.h>
|
||||
#include <fenv_libc.h>
|
||||
#include <math_ldbl_opt.h>
|
||||
#include <float.h>
|
||||
#include <ieee754.h>
|
||||
|
||||
|
||||
#ifdef __STDC__
|
||||
long long
|
||||
__llroundl (long double x)
|
||||
@ -37,92 +36,95 @@ __llroundl (x)
|
||||
long double x;
|
||||
#endif
|
||||
{
|
||||
static const double TWO52 = 4503599627370496.0;
|
||||
static const double HALF = 0.5;
|
||||
int mode = fegetround();
|
||||
union ibm_extended_long_double u;
|
||||
long long result = __LONG_LONG_MAX__;
|
||||
double xh, xl;
|
||||
long long res, hi, lo;
|
||||
|
||||
u.d = x;
|
||||
ldbl_unpack (x, &xh, &xl);
|
||||
|
||||
if (fabs (u.dd[0]) < TWO52)
|
||||
{
|
||||
fesetround(FE_TOWARDZERO);
|
||||
if (u.dd[0] > 0.0)
|
||||
{
|
||||
u.dd[0] += HALF;
|
||||
u.dd[0] += TWO52;
|
||||
u.dd[0] -= TWO52;
|
||||
}
|
||||
else if (u.dd[0] < 0.0)
|
||||
{
|
||||
u.dd[0] = TWO52 - (u.dd[0] - HALF);
|
||||
u.dd[0] = -(u.dd[0] - TWO52);
|
||||
}
|
||||
fesetround(mode);
|
||||
result = u.dd[0];
|
||||
}
|
||||
else if (fabs (u.dd[1]) < TWO52 && u.dd[1] != 0.0)
|
||||
/* Limit the range of values handled by the conversion to long long.
|
||||
We do this because we aren't sure whether that conversion properly
|
||||
raises FE_INVALID. */
|
||||
if (__builtin_expect
|
||||
((__builtin_fabs (xh) <= -(double) (-__LONG_LONG_MAX__ - 1)), 1)
|
||||
#if !defined (FE_INVALID)
|
||||
|| 1
|
||||
#endif
|
||||
)
|
||||
{
|
||||
double high, low;
|
||||
long long lowint;
|
||||
/* In this case we have to round the low double and handle any
|
||||
adjustment to the high double that may be caused by rounding
|
||||
(up). This is complicated by the fact that the high double
|
||||
may already be rounded and the low double may have the
|
||||
opposite sign to compensate. */
|
||||
if (u.dd[0] > 0.0)
|
||||
if (__builtin_expect ((xh == -(double) (-__LONG_LONG_MAX__ - 1)), 0))
|
||||
{
|
||||
if (u.dd[1] > 0.0)
|
||||
{
|
||||
/* If the high/low doubles are the same sign then simply
|
||||
round the low double. */
|
||||
high = u.dd[0];
|
||||
low = u.dd[1];
|
||||
}
|
||||
else if (u.dd[1] < 0.0)
|
||||
{
|
||||
/* Else the high double is pre rounded and we need to
|
||||
adjust for that. */
|
||||
high = nextafter (u.dd[0], 0.0);
|
||||
low = u.dd[1] + (u.dd[0] - high);
|
||||
}
|
||||
fesetround(FE_TOWARDZERO);
|
||||
low += HALF;
|
||||
low += TWO52;
|
||||
low -= TWO52;
|
||||
/* When XH is 9223372036854775808.0, converting to long long will
|
||||
overflow, resulting in an invalid operation. However, XL might
|
||||
be negative and of sufficient magnitude that the overall long
|
||||
double is in fact in range. Avoid raising an exception. In any
|
||||
case we need to convert this value specially, because
|
||||
the converted value is not exactly represented as a double
|
||||
thus subtracting HI from XH suffers rounding error. */
|
||||
hi = __LONG_LONG_MAX__;
|
||||
xh = 1.0;
|
||||
}
|
||||
else if (u.dd[0] < 0.0)
|
||||
else
|
||||
{
|
||||
if (u.dd[1] < 0.0)
|
||||
{
|
||||
/* If the high/low doubles are the same sign then simply
|
||||
round the low double. */
|
||||
high = u.dd[0];
|
||||
low = u.dd[1];
|
||||
}
|
||||
else if (u.dd[1] > 0.0)
|
||||
{
|
||||
/* Else the high double is pre rounded and we need to
|
||||
adjust for that. */
|
||||
high = nextafter (u.dd[0], 0.0);
|
||||
low = u.dd[1] + (u.dd[0] - high);
|
||||
}
|
||||
fesetround(FE_TOWARDZERO);
|
||||
low -= HALF;
|
||||
low = TWO52 - low;
|
||||
low = -(low - TWO52);
|
||||
hi = (long long) xh;
|
||||
xh -= hi;
|
||||
}
|
||||
fesetround(mode);
|
||||
lowint = low;
|
||||
result = high;
|
||||
result += lowint;
|
||||
ldbl_canonicalize (&xh, &xl);
|
||||
|
||||
lo = (long long) xh;
|
||||
|
||||
/* Peg at max/min values, assuming that the above conversions do so.
|
||||
Strictly speaking, we can return anything for values that overflow,
|
||||
but this is more useful. */
|
||||
res = hi + lo;
|
||||
|
||||
/* This is just sign(hi) == sign(lo) && sign(res) != sign(hi). */
|
||||
if (__builtin_expect (((~(hi ^ lo) & (res ^ hi)) < 0), 0))
|
||||
goto overflow;
|
||||
|
||||
xh -= lo;
|
||||
ldbl_canonicalize (&xh, &xl);
|
||||
|
||||
hi = res;
|
||||
if (xh > 0.5)
|
||||
{
|
||||
res += 1;
|
||||
}
|
||||
else if (xh == 0.5)
|
||||
{
|
||||
if (xl > 0.0 || (xl == 0.0 && res >= 0))
|
||||
res += 1;
|
||||
}
|
||||
else if (-xh > 0.5)
|
||||
{
|
||||
res -= 1;
|
||||
}
|
||||
else if (-xh == 0.5)
|
||||
{
|
||||
if (xl < 0.0 || (xl == 0.0 && res <= 0))
|
||||
res -= 1;
|
||||
}
|
||||
|
||||
if (__builtin_expect (((~(hi ^ (res - hi)) & (res ^ hi)) < 0), 0))
|
||||
goto overflow;
|
||||
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = u.dd[0];
|
||||
}
|
||||
return result;
|
||||
{
|
||||
if (xh > 0.0)
|
||||
hi = __LONG_LONG_MAX__;
|
||||
else if (xh < 0.0)
|
||||
hi = -__LONG_LONG_MAX__ - 1;
|
||||
else
|
||||
/* Nan */
|
||||
hi = 0;
|
||||
}
|
||||
|
||||
overflow:
|
||||
#ifdef FE_INVALID
|
||||
feraiseexcept (FE_INVALID);
|
||||
#endif
|
||||
return hi;
|
||||
}
|
||||
|
||||
long_double_symbol (libm, __llroundl, llroundl);
|
||||
|
@ -1,94 +0,0 @@
|
||||
/* Round long double to long int.
|
||||
IBM extended format long double version.
|
||||
Copyright (C) 2004,2006 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, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <sysdep.h>
|
||||
#include <math_ldbl_opt.h>
|
||||
|
||||
.section ".toc","aw"
|
||||
.LC0: /* 2**52 */
|
||||
.tc FD_43300000_0[TC],0x4330000000000000
|
||||
.LC1: /* 2**63 */
|
||||
.tc FD_43E00000_0[TC],0x43e0000000000000
|
||||
.section ".text"
|
||||
|
||||
/* long long int[r3] __llrintl (long double x[fp1,fp2]) */
|
||||
ENTRY (__llrintl)
|
||||
lfd fp13,.LC0@toc(2)
|
||||
lfd fp10,.LC1@toc(2)
|
||||
fabs fp0,fp1
|
||||
fcmpu cr7,fp0,fp13 /* if (fabs(x) > TWO52) */
|
||||
fcmpu cr6,fp0,fp10 /* if (fabs(x) > TWO63) */
|
||||
beq- cr6,.L2
|
||||
fctid fp11,fp1 /* must delay this opperation to here */
|
||||
fctid fp12,fp2 /* and avoid setting "invalid operation". */
|
||||
li r0,0
|
||||
stfd fp11,-16(r1)
|
||||
bgt- cr6,.L9 /* if > TWO63 return "invalid operation". */
|
||||
ble+ cr7,.L9 /* If < TWO52 only thy high double is used. */
|
||||
stfd fp12,-8(r1)
|
||||
nop /* Insure the following load is in a different dispatch group */
|
||||
nop /* to avoid pipe stall on POWER4&5. */
|
||||
nop
|
||||
.L8:
|
||||
ld r0,-8(r1)
|
||||
.L9:
|
||||
ld r3,-16(r1)
|
||||
add r3,r3,r0
|
||||
blr
|
||||
|
||||
/* The high double is >= TWO63 so it looks like we are "out of range".
|
||||
But this may be caused by rounding of the high double and the
|
||||
negative low double may bring it back into range. So we need to
|
||||
de-round the high double and invert the low double without changing
|
||||
the effective long double value. To do this we compute a special
|
||||
value (tau) that we can subtract from the high double and add to
|
||||
the low double before conversion. The resulting integers can be
|
||||
summed to get the total value.
|
||||
|
||||
tau = floor(x_high/TWO52);
|
||||
x0 = x_high - tau;
|
||||
x1 = x_low + tau; */
|
||||
.L2:
|
||||
fdiv fp8,fp1,fp13 /* x_high/TWO52 */
|
||||
fctidz fp0,fp8
|
||||
fcfid fp8,fp0 /* tau = floor(x_high/TWO52); */
|
||||
fsub fp3,fp1,fp8 /* x0 = x_high - tau; */
|
||||
fadd fp4,fp2,fp8 /* x1 = x_low + tau; */
|
||||
fctid fp11,fp3
|
||||
fctid fp12,fp4
|
||||
stfd fp11,-16(r1)
|
||||
stfd fp12,-8(r1)
|
||||
nop /* Insure the following load is in a different dispatch group */
|
||||
nop /* to avoid pipe stall on POWER4&5. */
|
||||
nop
|
||||
ld r3,-16(r1)
|
||||
ld r0,-8(r1)
|
||||
addo. r3,r3,r0
|
||||
bnslr+ cr0 /* if the sum does not overflow, return. */
|
||||
fctid fp11,fp1 /* Otherwise we want to set "invalid operation". */
|
||||
li r0,0
|
||||
stfd fp11,-16(r1)
|
||||
b .L9
|
||||
|
||||
END (__llrintl)
|
||||
|
||||
strong_alias (__llrintl, __lrintl)
|
||||
long_double_symbol (libm, __llrintl, llrintl)
|
||||
long_double_symbol (libm, __lrintl, lrintl)
|
@ -1,167 +0,0 @@
|
||||
/* llroundl function.
|
||||
IBM extended format long double version.
|
||||
Copyright (C) 2004, 2006 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, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <sysdep.h>
|
||||
#include <math_ldbl_opt.h>
|
||||
|
||||
.section ".toc","aw"
|
||||
.LC0: /* 0.0 */
|
||||
.tc FD_00000000_0[TC],0x0000000000000000
|
||||
.LC1: /* 0.5 */
|
||||
.tc FD_3fe00000_0[TC],0x3fe0000000000000
|
||||
.LC2: /* 2**52 */
|
||||
.tc FD_43300000_0[TC],0x4330000000000000
|
||||
.LC3: /* 2**63 */
|
||||
.tc FD_43E00000_0[TC],0x43e0000000000000
|
||||
.section ".text"
|
||||
|
||||
/* long long [r3] llround (long double x [fp1,fp2])
|
||||
IEEE 1003.1 llroundl 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
|
||||
toward zero. The "Floating Convert To Integer Doubleword with round
|
||||
toward zero" instruction handles the conversion including the
|
||||
overflow cases and signalling "Invalid Operation".
|
||||
|
||||
PowerPC64 long double uses the IBM extended format which is
|
||||
represented two 64-floating point double values. The values are
|
||||
non-overlapping giving an effective precision of 106 bits. The first
|
||||
double contains the high order bits of mantisa and is always rounded
|
||||
to represent a normal rounding of long double to double. Since the
|
||||
long double value is sum of the high and low values, the low double
|
||||
normally has the opposite sign to compensate for the this rounding.
|
||||
|
||||
For long double there is 4 cases:
|
||||
1) |x| < 2**52, all the integer bits are in the high double.
|
||||
Round and convert the high double to long long.
|
||||
2) 2**52 <= |x|< 2**63, Still fits but need bits from both doubles.
|
||||
Round the low double, convert both, then sum the long long values.
|
||||
3) |x| == 2**63, Looks like an overflow but may not be due to rounding
|
||||
of the high double.
|
||||
See the description following lable L2.
|
||||
4) |x| > 2**63, This will overflow the 64-bit signed integer.
|
||||
Treat like case #1. The fctidz instruction will generate the
|
||||
appropriate and signal "invalid operation".
|
||||
|
||||
*/
|
||||
|
||||
ENTRY (__llroundl)
|
||||
mffs fp7 /* Save current FPU rounding mode. */
|
||||
fabs fp0,fp1
|
||||
lfd fp13,.LC2@toc(2) /* 2**52 */
|
||||
lfd fp12,.LC3@toc(2) /* 2**63 */
|
||||
lfd fp11,.LC0@toc(2) /* 0.0 */
|
||||
lfd fp10,.LC1@toc(2) /* 0.5 */
|
||||
fabs fp9,fp2
|
||||
fcmpu cr7,fp0,fp13 /* if (fabs(x) > TWO52) */
|
||||
fcmpu cr6,fp1,fp11 /* if (x > 0.0) */
|
||||
bnl- cr7,.L2
|
||||
mtfsfi 7,1 /* Set rounding mode toward 0. */
|
||||
ble- cr6,.L1
|
||||
fadd fp9,fp1,fp10 /* x+= 0.5; */
|
||||
b .L0
|
||||
.L1:
|
||||
fsub fp9,fp1,fp10 /* x-= 0.5; */
|
||||
.L0:
|
||||
fctid fp0,fp9
|
||||
stfd fp0,-16(r1)
|
||||
mtfsf 0x01,fp7 /* restore previous rounding mode. */
|
||||
nop /* Insure the following load is in a different dispatch group */
|
||||
nop /* to avoid pipe stall on POWER4&5. */
|
||||
nop
|
||||
ld r3,-16(r1)
|
||||
blr
|
||||
|
||||
/* The high double is > TWO52 so we need to round the low double and
|
||||
perhaps the high double. In this case we have to round the low
|
||||
double and handle any adjustment to the high double that may be
|
||||
caused by rounding (up). This is complicated by the fact that the
|
||||
high double may already be rounded and the low double may have the
|
||||
opposite sign to compensate.This gets a bit tricky so we use the
|
||||
following algorithm:
|
||||
|
||||
tau = trunc(x_high/TWO52);
|
||||
x0 = x_high - tau;
|
||||
x1 = x_low + tau;
|
||||
r1 = round(x1);
|
||||
y_high = x0 + r1;
|
||||
y_low = x0 - y_high + r1;
|
||||
return y; */
|
||||
.L2:
|
||||
fcmpu cr7,fp0,fp12 /* if (|x_high| > TWO63) */
|
||||
fcmpu cr0,fp9,fp11 /* || (|x_low| == 0.0) */
|
||||
fmr fp9,fp1
|
||||
fcmpu cr5,fp2,fp11 /* if (x_low > 0.0) */
|
||||
bgt- cr7,.L0 /* return llround(x); */
|
||||
mtfsfi 7,1 /* Set rounding mode toward 0. */
|
||||
fdiv fp8,fp1,fp13 /* x_high/TWO52 */
|
||||
|
||||
bng- cr6,.L6 /* if (x > 0.0) */
|
||||
fctidz fp0,fp8
|
||||
fcfid fp8,fp0 /* tau = trunc(x_high/TWO52); */
|
||||
bng cr5,.L4 /* if (x_low > 0.0) */
|
||||
fmr fp3,fp1
|
||||
fmr fp4,fp2
|
||||
b .L5
|
||||
.L4: /* if (x_low < 0.0) */
|
||||
fsub fp3,fp1,fp8 /* x0 = x_high - tau; */
|
||||
fadd fp4,fp2,fp8 /* x1 = x_low + tau; */
|
||||
.L5:
|
||||
fadd fp5,fp4,fp10 /* r1 = x1 + 0.5; */
|
||||
b .L9
|
||||
.L6: /* if (x < 0.0) */
|
||||
fctidz fp0,fp8
|
||||
fcfid fp8,fp0 /* tau = trunc(x_high/TWO52); */
|
||||
bnl cr5,.L7 /* if (x_low < 0.0) */
|
||||
fmr fp3,fp1
|
||||
fmr fp4,fp2
|
||||
b .L8
|
||||
.L7: /* if (x_low > 0.0) */
|
||||
fsub fp3,fp1,fp8 /* x0 = x_high - tau; */
|
||||
fadd fp4,fp2,fp8 /* x1 = x_low + tau; */
|
||||
.L8:
|
||||
fsub fp5,fp4,fp10 /* r1 = x1 - 0.5; */
|
||||
.L9:
|
||||
fctid. fp11,fp3
|
||||
fctid fp12,fp5
|
||||
stfd fp11,-16(r1)
|
||||
stfd fp12,-8(r1)
|
||||
mtfsf 0x01,fp7 /* restore previous rounding mode. */
|
||||
nop /* Insure the following load is in a different dispatch group */
|
||||
nop /* to avoid pipe stall on POWER4&5. */
|
||||
nop
|
||||
ld r3,-16(r1)
|
||||
bunlr cr1 /* if not overflow, return. */
|
||||
ld r0,-8(r1)
|
||||
addo. r3,r3,r0
|
||||
bnslr cr0
|
||||
fmr fp9,fp12
|
||||
bng cr6,.L0
|
||||
fneg fp9,fp12
|
||||
b .L0
|
||||
END (__llroundl)
|
||||
|
||||
strong_alias (__llroundl, __lroundl)
|
||||
long_double_symbol (libm, __llroundl, llroundl)
|
||||
long_double_symbol (libm, __lroundl, lroundl)
|
@ -1,2 +0,0 @@
|
||||
/* __lrintl is in s_llrintl.c */
|
||||
/* __lrintl is in s_llrintl.c */
|
@ -1,2 +0,0 @@
|
||||
/* __lroundl is in s_llroundl.S */
|
||||
/* __lroundl is in s_llroundl.S */
|
Loading…
Reference in New Issue
Block a user