[2/3] libm: Remove __ieee754_gamma_r variants

Message ID 20200826170357.2551683-3-keithp@keithp.com
State New
Headers show
Series
  • libm: Clean up gamma functions
Related show

Commit Message

R. Diez via Newlib Aug. 26, 2020, 5:03 p.m.
Gamma should consume the sign reported by lgamma internally instead of
providing it back to the application. This removes the need to have _r
variants as there is no longer any re-entrancy issues with the API.

Signed-off-by: Keith Packard <keithp@keithp.com>

---
 newlib/libc/include/math.h                 |  2 -
 newlib/libc/sys/linux/cmath/math_private.h |  2 -
 newlib/libm/common/fdlibm.h                |  4 +-
 newlib/libm/math/Makefile.am               |  4 +-
 newlib/libm/math/Makefile.in               | 24 +++--------
 newlib/libm/math/er_gamma.c                | 12 ++++--
 newlib/libm/math/erf_gamma.c               | 12 ++++--
 newlib/libm/math/w_gamma.c                 | 15 +------
 newlib/libm/math/w_tgamma.c                |  4 +-
 newlib/libm/math/wf_gamma.c                | 15 +------
 newlib/libm/math/wf_tgamma.c               |  4 +-
 newlib/libm/math/wr_gamma.c                | 49 ----------------------
 newlib/libm/math/wrf_gamma.c               | 48 ---------------------
 13 files changed, 32 insertions(+), 163 deletions(-)
 delete mode 100644 newlib/libm/math/wr_gamma.c
 delete mode 100644 newlib/libm/math/wrf_gamma.c

-- 
2.28.0

Comments

R. Diez via Newlib Aug. 26, 2020, 6:20 p.m. | #1
Hi Keith,

On Aug 26 10:03, Keith Packard via Newlib wrote:
> Gamma should consume the sign reported by lgamma internally instead of

> providing it back to the application. This removes the need to have _r

> variants as there is no longer any re-entrancy issues with the API.


You can't do that.  gamma_r/gammaf_r/lgamma_r/lgammaf_r are BSD
functions.  They have been exported by Cygwin since 2001.  The entry
points need to be kept available with unchanged semantics.


Corinna
R. Diez via Newlib Aug. 26, 2020, 7:10 p.m. | #2
Corinna Vinschen via Newlib <newlib@sourceware.org> writes:

> You can't do that.  gamma_r/gammaf_r/lgamma_r/lgammaf_r are BSD

> functions.  They have been exported by Cygwin since 2001.  The entry

> points need to be kept available with unchanged semantics.


They changed on accident in 2002 -- gamma_r *used* to be an alias for
lgamma_r and was changed to be a (broken) alias for tgamma.

-- 
-keith
R. Diez via Newlib Aug. 27, 2020, 7:24 a.m. | #3
On Aug 26 12:10, Keith Packard via Newlib wrote:
> Corinna Vinschen via Newlib <newlib@sourceware.org> writes:

> 

> > You can't do that.  gamma_r/gammaf_r/lgamma_r/lgammaf_r are BSD

> > functions.  They have been exported by Cygwin since 2001.  The entry

> > points need to be kept available with unchanged semantics.

> 

> They changed on accident in 2002 -- gamma_r *used* to be an alias for

> lgamma_r and was changed to be a (broken) alias for tgamma.


Nevertheless, the symbols have to be exported for backward compatibility.
So you're saying aliasing gamma_r to lgamma_r and gammaf_r to lgammaf_r
in the DLLs export table would be sufficient?


Thanks,
Corinna
R. Diez via Newlib Aug. 27, 2020, 5:05 p.m. | #4
Corinna Vinschen via Newlib <newlib@sourceware.org> writes:

> Nevertheless, the symbols have to be exported for backward compatibility.

> So you're saying aliasing gamma_r to lgamma_r and gammaf_r to lgammaf_r

> in the DLLs export table would be sufficient?


It depends if you want the pre-2002 functionality or the post-2002
functionality.

Before 2002, gamma_r and gammaf_r were as BSD originally specified them,
returning the log of gamma (ln(|Γ(x)|)) with the sign of gamma stored
through the second, int *, argument. In 2002, this patch was made to
er_gamma.c:

$ git show 0953fe640f177b565578ed7ecc77169ec1a914fa er_gamma.c

diff --git a/newlib/libm/math/er_gamma.c b/newlib/libm/math/er_gamma.c
index a7183c50f..3c0e241e5 100644
@@ -28,5 +28,5 @@
 	double x; int *signgamp;
 #endif
 {
-	return __ieee754_lgamma_r(x,signgamp);
+	return __ieee754_exp (__ieee754_lgamma_r(x,signgamp));
 }

Before this patch, __ieee754_gamma_r was simply another name for
__ieee754_lgamma_r. After this patch, __ieee754_gamma_r became something
that doesn't exist in any other math library: it returns |Γ(x)| and
stores the sign through the second, int *, argument. Internally, this is
used in w_gamma.c, w_tgamma.c, wr_gamma.c.

w_tgamma.c uses it correctly:

	y = __ieee754_gamma_r(x,&local_signgam);
	if (local_signgam < 0) y = -y;

w_gamma.c, which exports the 'gamma' function uses it *incorrectly* --
it didn't change after the above patch, and so it unexpectedly changed
from returning ln(|Γ(x)|) to returning |Γ(x)|. Applications using
'gamma' instead of 'tgamma' will be getting the wrong answer for some
parameters.

I have to assume this was just an oversight. In 2009, another patch to
w_gamma.c adds a comment explicitly stating that gamma and gamma_r
return ln(|Γ(x)|), when in fact they had been changed to
|Γ(x)| due to the change to __ieee754_gamma_r in the above patch.

Even today, wr_gamma.c says:

	double gamma_r(double x, int *signgamp) /* wrapper lgamma_r */

which is incorrect, as it calls __ieee754_gamma_r.

I see a couple of options here:

 1) Leave things as they are. This makes the 'gamma' family of functions
    incompatible with all other libc implementations and creates a trap
    for applications expecting either lgamma or tgamma values.

 2) Finish the work started in 2002 and make the 'gamma' family
    compatible with their 'tgamma' equivalents. This is what my patch
    does. This makes newlib compatible with 4.4 BSD libc, and leaves
    'gamma' returning the same value anytime that value is non-negative.

 3) Revert the 2002 change so that all of the 'gamma' family return the
    same value as their lgamma equivalents. That would make gamma_r
    useful again, as an alias for lgamma_r. This would make newlib
    compatible with glibc.

 4) Remove the 'gamma' family completely. Given that the meaning of
    'gamma' differs between 4.4 BSD and glibc, it would be safest to
    force applications to select between tgamma and lgamma.

I chose option 2 because that offers the best API compatibility -- the
gamma functions return the same value for most arguments (any positive
arguments, and half of negative arguments).

Any code using the gamma_r functions are likely expecting that to return
lgamma_r (as documented in several places). I can't see how we can leave
that function in the library as-is responsibly.

-- 
-keith
R. Diez via Newlib Aug. 28, 2020, 8:19 a.m. | #5
On Aug 27 10:05, Keith Packard via Newlib wrote:
> Corinna Vinschen via Newlib <newlib@sourceware.org> writes:

> 

> > Nevertheless, the symbols have to be exported for backward compatibility.

> > So you're saying aliasing gamma_r to lgamma_r and gammaf_r to lgammaf_r

> > in the DLLs export table would be sufficient?

> 

> It depends if you want the pre-2002 functionality or the post-2002

> functionality.


The important point is that gamma_r and gammaf_r are exported by Cygwin
and must be kept available, otherwise building the DLL fails.  If they
returned the wrong vaslue, that's a bug and needs fixing.

Whether gamma_r and gammaf_r are still functions on their own, or if
they are just defined as aliases to lgamma_r and lgammaf_r in
winsup/cygwin/common.din, as in

  gamma_r = lgamma_r NOSIGFE
  gammaf_r = lgammaf_r NOSIGFE

is up to you.


Corinna
R. Diez via Newlib Aug. 28, 2020, 8:34 a.m. | #6
On Aug 28 10:19, Corinna Vinschen via Newlib wrote:
> On Aug 27 10:05, Keith Packard via Newlib wrote:

> > Corinna Vinschen via Newlib <newlib@sourceware.org> writes:

> > 

> > > Nevertheless, the symbols have to be exported for backward compatibility.

> > > So you're saying aliasing gamma_r to lgamma_r and gammaf_r to lgammaf_r

> > > in the DLLs export table would be sufficient?

> > 

> > It depends if you want the pre-2002 functionality or the post-2002

> > functionality.

> 

> The important point is that gamma_r and gammaf_r are exported by Cygwin

> and must be kept available, otherwise building the DLL fails.  If they

> returned the wrong vaslue, that's a bug and needs fixing.

> 

> Whether gamma_r and gammaf_r are still functions on their own, or if

> they are just defined as aliases to lgamma_r and lgammaf_r in

> winsup/cygwin/common.din, as in

> 

>   gamma_r = lgamma_r NOSIGFE

>   gammaf_r = lgammaf_r NOSIGFE

> 

> is up to you.


On second thought, given gamma_r and gammaf_r are BSD functions,
it might be a good idea to keep the wrapper functions for other
targets as well.

Any input from the RTEMS guys, perhaps?


Thanks,
Corinna
Fabian Schriever Sept. 1, 2020, 4:33 p.m. | #7
Hi Keith,

We welcome your efforts to clean up - and correct the error return 
values of - the gamma/lgamma/tgamma families.

Regarding Corinna's concern with lgamma_r/gamma_r being BSD-functions:

> You can't do  that.  gamma_r/gammaf_r/lgamma_r/lgammaf_r are BSD

> functions. They have been exported by Cygwin since 2001.  The entry

> points need  to be kept available with unchanged semantics.


We would favor the removal of all non C/POSIX(+XSI)-standard functions 
from the interface.
The reason to regard lgamma_r and gamma_r as "BSD-functions" comes from 
the fact that BSD (same as newlib) took fdlibm as the base for its libm 
back in the early 90s when some non-standard functions were part of that 
library.
We would encourage the use of only the C/POSIX(+XSI)-standard functions 
as the only way to get rid of the confusing semantics of the historical 
function interfaces otherwise the problem will only perpetuate into the 
future.

If something was changed in 2002, that is working incorrectly and no one 
found out until now, that is also not part of any standard, it suggests 
that no one is actually using it and should be able to be safely 
removed. Does Newlib have a policy to remove elements?

An interesting discussion about the standard lgamma/tgamma functions 
would be to discuss accuracy improvements in line with the glibc 
improvements from Joseph Myers (see 
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=050f29c18873ec05ba04a4034bed8cb3f6ae4463).

Best regards,
Fabian
R. Diez via Newlib Sept. 1, 2020, 5:23 p.m. | #8
Fabian Schriever <fabian.schriever@gtd-gmbh.de> writes:

> Hi Keith,

>

> We welcome your efforts to clean up - and correct the error return 

> values of - the gamma/lgamma/tgamma families.


Thanks! I'm doing continuous integration testing as a part of embedded
toolchain support for RISC-V as part of my SiFive dayjob; fixing bugs
like this is part of that process.

> We would favor the removal of all non C/POSIX(+XSI)-standard functions 

> from the interface.


Oh, that's probably the best idea of all. Applications should not be
using 'gamma' at all given the different definitions over time and
space.

Any thoughts about the newlib __ieee754 interfaces? Those are
essentially the same as the C/POSIX interfaces but do not use errno or
other global variables, reporting exceptions only through the fenv API.

> If something was changed in 2002, that is working incorrectly and no one 

> found out until now, that is also not part of any standard, it suggests 

> that no one is actually using it and should be able to be safely 

> removed. Does Newlib have a policy to remove elements?


I don't think it's 'newlib' which would need any policy; newlib is used
downstream in a wide variety of projects, including cygwin and picolibc,
which may have separate policies. Cygwin has binary interface
definitions, changing those could affect applications there.

I'm using newlib as part of picolibc which is used for embedded
toolchains where removing things from the ABI to fix bugs would be just
fine.

> An interesting discussion about the standard lgamma/tgamma functions 

> would be to discuss accuracy improvements in line with the glibc 

> improvements from Joseph Myers (see 

> https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=050f29c18873ec05ba04a4034bed8cb3f6ae4463).


I read through that patch and agree that it would be nice to incorporate
something similar. We need to be cautious as code cannot be directly
brought in from glibc due to licensing differences.

-- 
-keith
R. Diez via Newlib Sept. 2, 2020, 8:03 a.m. | #9
On Sep  1 10:23, Keith Packard via Newlib wrote:
> Fabian Schriever <fabian.schriever@gtd-gmbh.de> writes:

> 

> > Hi Keith,

> >

> > We welcome your efforts to clean up - and correct the error return 

> > values of - the gamma/lgamma/tgamma families.

> 

> Thanks! I'm doing continuous integration testing as a part of embedded

> toolchain support for RISC-V as part of my SiFive dayjob; fixing bugs

> like this is part of that process.

> 

> > We would favor the removal of all non C/POSIX(+XSI)-standard functions 

> > from the interface.

> 

> Oh, that's probably the best idea of all. Applications should not be

> using 'gamma' at all given the different definitions over time and

> space.

> 

> Any thoughts about the newlib __ieee754 interfaces? Those are

> essentially the same as the C/POSIX interfaces but do not use errno or

> other global variables, reporting exceptions only through the fenv API.

> 

> > If something was changed in 2002, that is working incorrectly and no one 

> > found out until now, that is also not part of any standard, it suggests 

> > that no one is actually using it and should be able to be safely 

> > removed. Does Newlib have a policy to remove elements?

> 

> I don't think it's 'newlib' which would need any policy; newlib is used

> downstream in a wide variety of projects, including cygwin and picolibc,

> which may have separate policies. Cygwin has binary interface

> definitions, changing those could affect applications there.


Removing interfaces is not an option for Cygwin.  If you remove
functions from newlib exported as symbols in Cygwin, you must provide
replacement interfaces for Cygwin alone, otherwise Cygwin won't build
anymore.  And one step further, removing interfaces from the list of
exported symbols of the Cygwin DLL will break user space and that's
simply a no-no.


Corinna
R. Diez via Newlib Sept. 2, 2020, 8:37 p.m. | #10
Corinna Vinschen via Newlib <newlib@sourceware.org> writes:

> Removing interfaces is not an option for Cygwin.  If you remove

> functions from newlib exported as symbols in Cygwin, you must provide

> replacement interfaces for Cygwin alone, otherwise Cygwin won't build

> anymore.  And one step further, removing interfaces from the list of

> exported symbols of the Cygwin DLL will break user space and that's

> simply a no-no.


Then tell us what you want gamma and gamma_r to do for Cygwin. They're
non-standard interfaces for POSIX, C99 and C17, so you get to
pick.

Removing them for non-Cygwin uses appears to be the safest choice as
that will (intentionally) break applications which were expecting them
to implement either the BSD or Linux behavior, when in fact they do
neither (!).

-- 
-keith
R. Diez via Newlib Sept. 3, 2020, 8:04 a.m. | #11
On Sep  2 13:37, Keith Packard via Newlib wrote:
> Corinna Vinschen via Newlib <newlib@sourceware.org> writes:

> 

> > Removing interfaces is not an option for Cygwin.  If you remove

> > functions from newlib exported as symbols in Cygwin, you must provide

> > replacement interfaces for Cygwin alone, otherwise Cygwin won't build

> > anymore.  And one step further, removing interfaces from the list of

> > exported symbols of the Cygwin DLL will break user space and that's

> > simply a no-no.

> 

> Then tell us what you want gamma and gamma_r to do for Cygwin.


I did: https://sourceware.org/pipermail/newlib/2020/017946.html


Thanks,
Corinna
Brian Inglis Sept. 3, 2020, 3:59 p.m. | #12
On 2020-09-03 02:04, Corinna Vinschen via Newlib wrote:
> On Sep  2 13:37, Keith Packard via Newlib wrote:

>> Corinna Vinschen via Newlib <newlib@sourceware.org> writes:

>>

>>> Removing interfaces is not an option for Cygwin.  If you remove

>>> functions from newlib exported as symbols in Cygwin, you must provide

>>> replacement interfaces for Cygwin alone, otherwise Cygwin won't build

>>> anymore.  And one step further, removing interfaces from the list of

>>> exported symbols of the Cygwin DLL will break user space and that's

>>> simply a no-no.

>>

>> Then tell us what you want gamma and gamma_r to do for Cygwin.

> 

> I did: https://sourceware.org/pipermail/newlib/2020/017946.html


FYI docs/spec:
https://sca.uwaterloo.ca/coldfire/gcc-doc/docs/libm_21.html#SEC21
http://www.ece.ualberta.ca/~cmpe401/docs/coldfire/libm.pdf#page=20
https://ftp.rtems.org/pub/rtems/docs/3.2.0/libm-3.2.0.ps - see p.18

-- 
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada

This email may be disturbing to some readers as it contains
too much technical detail. Reader discretion is advised.
[Data in IEC units and prefixes, physical quantities in SI.]
R. Diez via Newlib Sept. 3, 2020, 9:25 p.m. | #13
Brian Inglis <Brian.Inglis@SystematicSw.ab.ca> writes:

>>> Then tell us what you want gamma and gamma_r to do for Cygwin.

>> 

>> I did: https://sourceware.org/pipermail/newlib/2020/017946.html


Oops! I appear to have missed that mail.

> FYI docs/spec:

> https://sca.uwaterloo.ca/coldfire/gcc-doc/docs/libm_21.html#SEC21

> http://www.ece.ualberta.ca/~cmpe401/docs/coldfire/libm.pdf#page=20

> https://ftp.rtems.org/pub/rtems/docs/3.2.0/libm-3.2.0.ps - see p.18


That's quite helpful actually and says that cygwin's gamma matches
glibc, which makes the change from 2002 just a bug. Switching gamma back
to lgamma is quite simple.

Here's what I did:

 1. Remove the gamma* function implementations and make them explicit
    aliases to lgamma*.

 2. Change the name of the __ieee754_gamma* functions to
    __ieee754_tgamma* and remove the _ieee754_gamma*_r variants

I've sent a patch doing this to the list.

-- 
-keith
Brian Inglis Sept. 3, 2020, 10:09 p.m. | #14
On 2020-09-03 15:25, Keith Packard wrote:
> Brian Inglis <Brian.Inglis@SystematicSw.ab.ca> writes:

> 

>>>> Then tell us what you want gamma and gamma_r to do for Cygwin.

>>>

>>> I did: https://sourceware.org/pipermail/newlib/2020/017946.html

> 

> Oops! I appear to have missed that mail.

> 

>> FYI docs/spec:

>> https://sca.uwaterloo.ca/coldfire/gcc-doc/docs/libm_21.html#SEC21

>> http://www.ece.ualberta.ca/~cmpe401/docs/coldfire/libm.pdf#page=20

>> https://ftp.rtems.org/pub/rtems/docs/3.2.0/libm-3.2.0.ps - see p.18

> 

> That's quite helpful actually and says that cygwin's gamma matches

> glibc, which makes the change from 2002 just a bug. Switching gamma back

> to lgamma is quite simple.

> 

> Here's what I did:

> 

>  1. Remove the gamma* function implementations and make them explicit

>     aliases to lgamma*.

> 

>  2. Change the name of the __ieee754_gamma* functions to

>     __ieee754_tgamma* and remove the _ieee754_gamma*_r variants

> 

> I've sent a patch doing this to the list.


I don't think you can "remove the _ieee754_gamma*_r variants" as I believe
Cygwin has to keep these:

$ nm --defined-only --extern-only /bin/cygwin1.dll | fgrep gamma
00000001801a76c0 T __ieee754_gamma_r
00000001801a7f90 T __ieee754_gammaf_r
00000001801a76e0 T __ieee754_lgamma_r
00000001801a7fb0 T __ieee754_lgammaf_r
000000018018a8c0 T __lgammal_r
000000018018ce10 T __tgammal_r
000000018019f690 T gamma
00000001801a0a40 T gamma_r
00000001801a0200 T gammaf
00000001801a0b80 T gammaf_r
000000018019fb00 T lgamma
00000001801a0ae0 T lgamma_r
00000001801a0660 T lgammaf
00000001801a0c20 T lgammaf_r
000000018018ae10 T lgammal
000000018018ae90 T lgammal_r
000000018019fe50 T tgamma
00000001801a0970 T tgammaf
000000018018d290 T tgammal

although I don't have the Windows utilities to check the exports directly.

-- 
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada

This email may be disturbing to some readers as it contains
too much technical detail. Reader discretion is advised.
[Data in IEC units and prefixes, physical quantities in SI.]
R. Diez via Newlib Sept. 4, 2020, 12:01 a.m. | #15
Brian Inglis <Brian.Inglis@SystematicSw.ab.ca> writes:

> I don't think you can "remove the _ieee754_gamma*_r variants" as I believe

> Cygwin has to keep these:


I added a note to that effect in my patch email; if someone can let me
know, I'll add them back in. I'd prefer to leave them out if they aren't
needed though.

-- 
-keith
Brian Inglis Sept. 4, 2020, 12:27 a.m. | #16
On 2020-09-03 18:01, Keith Packard wrote:
> Brian Inglis <Brian.Inglis@SystematicSw.ab.ca> writes:

> 

>> I don't think you can "remove the _ieee754_gamma*_r variants" as I believe

>> Cygwin has to keep these:

> 

> I added a note to that effect in my patch email; if someone can let me

> know, I'll add them back in. I'd prefer to leave them out if they aren't

> needed though.


$ fgrep gamma newlib-cygwin/winsup/cygwin/common.din

and

$ fgrep gamma newlib-cygwin/x86_64-pc-cygwin/winsup/cygwin/cygwin.def

have the same 13 function names:

gamma
gamma_r
gammaf
gammaf_r
lgamma
lgamma_r
lgammaf
lgammaf_r
lgammal
lgammal_r
tgamma
tgammaf
tgammal

so these may be the official ABI, and the others don't matter?

-- 
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada

This email may be disturbing to some readers as it contains
too much technical detail. Reader discretion is advised.
[Data in IEC units and prefixes, physical quantities in SI.]
R. Diez via Newlib Sept. 4, 2020, 1:37 a.m. | #17
Brian Inglis <Brian.Inglis@SystematicSw.ab.ca> writes:

> gamma

> gamma_r

> gammaf

> gammaf_r

> lgamma

> lgamma_r

> lgammaf

> lgammaf_r

> lgammal

> lgammal_r

> tgamma

> tgammaf

> tgammal

>

> so these may be the official ABI, and the others don't matter?


I would hope so -- the __ieee754 functions seem mostly like an internal
implementation detail, but it's hard to know.

If this is true, then I think the patch as posted should be what we want.

-- 
-keith
R. Diez via Newlib Sept. 4, 2020, 1:03 p.m. | #18
On Sep  3 18:37, Keith Packard via Newlib wrote:
> Brian Inglis <Brian.Inglis@SystematicSw.ab.ca> writes:

> 

> > gamma

> > gamma_r

> > gammaf

> > gammaf_r

> > lgamma

> > lgamma_r

> > lgammaf

> > lgammaf_r

> > lgammal

> > lgammal_r

> > tgamma

> > tgammaf

> > tgammal

> >

> > so these may be the official ABI, and the others don't matter?

> 

> I would hope so -- the __ieee754 functions seem mostly like an internal

> implementation detail, but it's hard to know.

> 

> If this is true, then I think the patch as posted should be what we want.


The ieee functions can go away.  The symbols from cygwin1.dll don't
count, the ones exported from /usr/lib/libcygwin.a do.  These are
defined in winsup/cygwin/{common.din,i686.din,x86_64.din}


Corinna
R. Diez via Newlib Sept. 4, 2020, 4:19 p.m. | #19
Corinna Vinschen via Newlib <newlib@sourceware.org> writes:

> The ieee functions can go away.  The symbols from cygwin1.dll don't

> count, the ones exported from /usr/lib/libcygwin.a do.  These are

> defined in winsup/cygwin/{common.din,i686.din,x86_64.din}


Which matches what we had guessed.

-- 
-keith

Patch

diff --git a/newlib/libc/include/math.h b/newlib/libc/include/math.h
index 3399d3649..28d4df10f 100644
--- a/newlib/libc/include/math.h
+++ b/newlib/libc/include/math.h
@@ -515,9 +515,7 @@  extern float dremf (float, float);
 #ifdef __CYGWIN__
 extern float dreml (long double, long double);
 #endif /* __CYGWIN__ */
-extern double gamma_r (double, int *);
 extern double lgamma_r (double, int *);
-extern float gammaf_r (float, int *);
 extern float lgammaf_r (float, int *);
 #endif
 
diff --git a/newlib/libc/sys/linux/cmath/math_private.h b/newlib/libc/sys/linux/cmath/math_private.h
index 3e32b29ba..f5792f7fa 100644
--- a/newlib/libc/sys/linux/cmath/math_private.h
+++ b/newlib/libc/sys/linux/cmath/math_private.h
@@ -178,7 +178,6 @@  extern double __ieee754_cosh (double);
 extern double __ieee754_fmod (double,double);
 extern double __ieee754_pow (double,double);
 extern double __ieee754_lgamma_r (double,int *);
-extern double __ieee754_gamma_r (double,int *);
 extern double __ieee754_lgamma (double);
 extern double __ieee754_gamma (double);
 extern double __ieee754_log10 (double);
@@ -241,7 +240,6 @@  extern float __ieee754_coshf (float);
 extern float __ieee754_fmodf (float,float);
 extern float __ieee754_powf (float,float);
 extern float __ieee754_lgammaf_r (float,int *);
-extern float __ieee754_gammaf_r (float,int *);
 extern float __ieee754_lgammaf (float);
 extern float __ieee754_gammaf (float);
 extern float __ieee754_log10f (float);
diff --git a/newlib/libm/common/fdlibm.h b/newlib/libm/common/fdlibm.h
index 8dffc832d..5226c2e13 100644
--- a/newlib/libm/common/fdlibm.h
+++ b/newlib/libm/common/fdlibm.h
@@ -159,7 +159,7 @@  extern double __ieee754_cosh __P((double));
 extern double __ieee754_fmod __P((double,double));
 extern double __ieee754_pow __P((double,double));
 extern double __ieee754_lgamma_r __P((double,int *));
-extern double __ieee754_gamma_r __P((double,int *));
+extern double __ieee754_gamma __P((double));
 extern double __ieee754_log10 __P((double));
 extern double __ieee754_sinh __P((double));
 extern double __ieee754_hypot __P((double,double));
@@ -205,7 +205,7 @@  extern float __ieee754_coshf __P((float));
 extern float __ieee754_fmodf __P((float,float));
 extern float __ieee754_powf __P((float,float));
 extern float __ieee754_lgammaf_r __P((float,int *));
-extern float __ieee754_gammaf_r __P((float,int *));
+extern float __ieee754_gammaf __P((float));
 extern float __ieee754_log10f __P((float));
 extern float __ieee754_sinhf __P((float));
 extern float __ieee754_hypotf __P((float,float));
diff --git a/newlib/libm/math/Makefile.am b/newlib/libm/math/Makefile.am
index e745159ae..87e47dbd5 100644
--- a/newlib/libm/math/Makefile.am
+++ b/newlib/libm/math/Makefile.am
@@ -14,7 +14,7 @@  src = 	k_standard.c k_rem_pio2.c \
 	e_scalb.c e_sinh.c e_sqrt.c \
 	w_acos.c w_acosh.c w_asin.c w_atan2.c \
 	w_atanh.c w_cosh.c w_exp.c w_fmod.c \
-	w_gamma.c wr_gamma.c w_hypot.c w_j0.c \
+	w_gamma.c w_hypot.c w_j0.c \
 	w_j1.c w_jn.c w_lgamma.c wr_lgamma.c \
 	w_log.c w_log10.c w_pow.c w_remainder.c \
 	w_scalb.c w_sinh.c w_sqrt.c \
@@ -37,7 +37,7 @@  fsrc =	kf_rem_pio2.c \
 	ef_scalb.c ef_sinh.c ef_sqrt.c \
 	wf_acos.c wf_acosh.c wf_asin.c wf_atan2.c \
 	wf_atanh.c wf_cosh.c wf_exp.c wf_fmod.c \
-	wf_gamma.c wrf_gamma.c wf_hypot.c wf_j0.c \
+	wf_gamma.c wf_hypot.c wf_j0.c \
 	wf_j1.c wf_jn.c wf_lgamma.c wrf_lgamma.c \
 	wf_log.c wf_log10.c wf_pow.c wf_remainder.c \
 	wf_scalb.c wf_sinh.c wf_sqrt.c \
diff --git a/newlib/libm/math/Makefile.in b/newlib/libm/math/Makefile.in
index 0ac2b1668..9ba1be8ca 100644
--- a/newlib/libm/math/Makefile.in
+++ b/newlib/libm/math/Makefile.in
@@ -90,7 +90,7 @@  am__objects_1 = lib_a-k_standard.$(OBJEXT) lib_a-k_rem_pio2.$(OBJEXT) \
 	lib_a-w_atan2.$(OBJEXT) lib_a-w_atanh.$(OBJEXT) \
 	lib_a-w_cosh.$(OBJEXT) lib_a-w_exp.$(OBJEXT) \
 	lib_a-w_fmod.$(OBJEXT) lib_a-w_gamma.$(OBJEXT) \
-	lib_a-wr_gamma.$(OBJEXT) lib_a-w_hypot.$(OBJEXT) \
+	lib_a-w_hypot.$(OBJEXT) \
 	lib_a-w_j0.$(OBJEXT) lib_a-w_j1.$(OBJEXT) lib_a-w_jn.$(OBJEXT) \
 	lib_a-w_lgamma.$(OBJEXT) lib_a-wr_lgamma.$(OBJEXT) \
 	lib_a-w_log.$(OBJEXT) lib_a-w_log10.$(OBJEXT) \
@@ -122,7 +122,7 @@  am__objects_2 = lib_a-kf_rem_pio2.$(OBJEXT) lib_a-kf_cos.$(OBJEXT) \
 	lib_a-wf_asin.$(OBJEXT) lib_a-wf_atan2.$(OBJEXT) \
 	lib_a-wf_atanh.$(OBJEXT) lib_a-wf_cosh.$(OBJEXT) \
 	lib_a-wf_exp.$(OBJEXT) lib_a-wf_fmod.$(OBJEXT) \
-	lib_a-wf_gamma.$(OBJEXT) lib_a-wrf_gamma.$(OBJEXT) \
+	lib_a-wf_gamma.$(OBJEXT) \
 	lib_a-wf_hypot.$(OBJEXT) lib_a-wf_j0.$(OBJEXT) \
 	lib_a-wf_j1.$(OBJEXT) lib_a-wf_jn.$(OBJEXT) \
 	lib_a-wf_lgamma.$(OBJEXT) lib_a-wrf_lgamma.$(OBJEXT) \
@@ -151,7 +151,7 @@  am__objects_4 = k_standard.lo k_rem_pio2.lo k_cos.lo k_sin.lo k_tan.lo \
 	e_jn.lo er_lgamma.lo e_log.lo e_log10.lo e_pow.lo \
 	e_rem_pio2.lo e_remainder.lo e_scalb.lo e_sinh.lo e_sqrt.lo \
 	w_acos.lo w_acosh.lo w_asin.lo w_atan2.lo w_atanh.lo w_cosh.lo \
-	w_exp.lo w_fmod.lo w_gamma.lo wr_gamma.lo w_hypot.lo w_j0.lo \
+	w_exp.lo w_fmod.lo w_gamma.lo w_hypot.lo w_j0.lo \
 	w_j1.lo w_jn.lo w_lgamma.lo wr_lgamma.lo w_log.lo w_log10.lo \
 	w_pow.lo w_remainder.lo w_scalb.lo w_sinh.lo w_sqrt.lo \
 	w_sincos.lo w_drem.lo s_asinh.lo s_atan.lo s_ceil.lo s_cos.lo \
@@ -164,7 +164,7 @@  am__objects_5 = kf_rem_pio2.lo kf_cos.lo kf_sin.lo kf_tan.lo \
 	ef_pow.lo ef_rem_pio2.lo ef_remainder.lo ef_scalb.lo \
 	ef_sinh.lo ef_sqrt.lo wf_acos.lo wf_acosh.lo wf_asin.lo \
 	wf_atan2.lo wf_atanh.lo wf_cosh.lo wf_exp.lo wf_fmod.lo \
-	wf_gamma.lo wrf_gamma.lo wf_hypot.lo wf_j0.lo wf_j1.lo \
+	wf_gamma.lo wf_hypot.lo wf_j0.lo wf_j1.lo \
 	wf_jn.lo wf_lgamma.lo wrf_lgamma.lo wf_log.lo wf_log10.lo \
 	wf_pow.lo wf_remainder.lo wf_scalb.lo wf_sinh.lo wf_sqrt.lo \
 	wf_sincos.lo wf_drem.lo sf_asinh.lo sf_atan.lo sf_ceil.lo \
@@ -339,7 +339,7 @@  src = k_standard.c k_rem_pio2.c \
 	e_scalb.c e_sinh.c e_sqrt.c \
 	w_acos.c w_acosh.c w_asin.c w_atan2.c \
 	w_atanh.c w_cosh.c w_exp.c w_fmod.c \
-	w_gamma.c wr_gamma.c w_hypot.c w_j0.c \
+	w_gamma.c w_hypot.c w_j0.c \
 	w_j1.c w_jn.c w_lgamma.c wr_lgamma.c \
 	w_log.c w_log10.c w_pow.c w_remainder.c \
 	w_scalb.c w_sinh.c w_sqrt.c \
@@ -362,7 +362,7 @@  fsrc = kf_rem_pio2.c \
 	ef_scalb.c ef_sinh.c ef_sqrt.c \
 	wf_acos.c wf_acosh.c wf_asin.c wf_atan2.c \
 	wf_atanh.c wf_cosh.c wf_exp.c wf_fmod.c \
-	wf_gamma.c wrf_gamma.c wf_hypot.c wf_j0.c \
+	wf_gamma.c wf_hypot.c wf_j0.c \
 	wf_j1.c wf_jn.c wf_lgamma.c wrf_lgamma.c \
 	wf_log.c wf_log10.c wf_pow.c wf_remainder.c \
 	wf_scalb.c wf_sinh.c wf_sqrt.c \
@@ -690,12 +690,6 @@  lib_a-w_gamma.o: w_gamma.c
 lib_a-w_gamma.obj: w_gamma.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-w_gamma.obj `if test -f 'w_gamma.c'; then $(CYGPATH_W) 'w_gamma.c'; else $(CYGPATH_W) '$(srcdir)/w_gamma.c'; fi`
 
-lib_a-wr_gamma.o: wr_gamma.c
-	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-wr_gamma.o `test -f 'wr_gamma.c' || echo '$(srcdir)/'`wr_gamma.c
-
-lib_a-wr_gamma.obj: wr_gamma.c
-	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-wr_gamma.obj `if test -f 'wr_gamma.c'; then $(CYGPATH_W) 'wr_gamma.c'; else $(CYGPATH_W) '$(srcdir)/wr_gamma.c'; fi`
-
 lib_a-w_hypot.o: w_hypot.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-w_hypot.o `test -f 'w_hypot.c' || echo '$(srcdir)/'`w_hypot.c
 
@@ -1086,12 +1080,6 @@  lib_a-wf_gamma.o: wf_gamma.c
 lib_a-wf_gamma.obj: wf_gamma.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-wf_gamma.obj `if test -f 'wf_gamma.c'; then $(CYGPATH_W) 'wf_gamma.c'; else $(CYGPATH_W) '$(srcdir)/wf_gamma.c'; fi`
 
-lib_a-wrf_gamma.o: wrf_gamma.c
-	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-wrf_gamma.o `test -f 'wrf_gamma.c' || echo '$(srcdir)/'`wrf_gamma.c
-
-lib_a-wrf_gamma.obj: wrf_gamma.c
-	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-wrf_gamma.obj `if test -f 'wrf_gamma.c'; then $(CYGPATH_W) 'wrf_gamma.c'; else $(CYGPATH_W) '$(srcdir)/wrf_gamma.c'; fi`
-
 lib_a-wf_hypot.o: wf_hypot.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-wf_hypot.o `test -f 'wf_hypot.c' || echo '$(srcdir)/'`wf_hypot.c
 
diff --git a/newlib/libm/math/er_gamma.c b/newlib/libm/math/er_gamma.c
index 3c0e241e5..9252e2d04 100644
--- a/newlib/libm/math/er_gamma.c
+++ b/newlib/libm/math/er_gamma.c
@@ -22,11 +22,15 @@ 
 #include "fdlibm.h"
 
 #ifdef __STDC__
-	double __ieee754_gamma_r(double x, int *signgamp)
+	double __ieee754_gamma(double x)
 #else
-	double __ieee754_gamma_r(x,signgamp)
-	double x; int *signgamp;
+	double __ieee754_gamma(x)
+	double x;
 #endif
 {
-	return __ieee754_exp (__ieee754_lgamma_r(x,signgamp));
+	int local_signgam = 1;
+	double y = __ieee754_exp (__ieee754_lgamma_r(x, &local_signgam));
+	if (local_signgam < 0)
+		y = -y;
+	return y;
 }
diff --git a/newlib/libm/math/erf_gamma.c b/newlib/libm/math/erf_gamma.c
index 9e529dce0..bddac60c7 100644
--- a/newlib/libm/math/erf_gamma.c
+++ b/newlib/libm/math/erf_gamma.c
@@ -24,11 +24,15 @@ 
 #include "fdlibm.h"
 
 #ifdef __STDC__
-	float __ieee754_gammaf_r(float x, int *signgamp)
+	float __ieee754_gammaf(float x)
 #else
-	float __ieee754_gammaf_r(x,signgamp)
-	float x; int *signgamp;
+	float __ieee754_gammaf(x)
+	float x;
 #endif
 {
-	return __ieee754_expf (__ieee754_lgammaf_r(x,signgamp));
+	int local_signgam = 1;
+	float y = __ieee754_expf (__ieee754_lgammaf_r(x,&local_signgam));
+	if (local_signgam < 0)
+		y = -y;
+	return y;
 }
diff --git a/newlib/libm/math/w_gamma.c b/newlib/libm/math/w_gamma.c
index b65d5cc4b..bb47fab31 100644
--- a/newlib/libm/math/w_gamma.c
+++ b/newlib/libm/math/w_gamma.c
@@ -148,18 +148,7 @@  in terms of the base return values, although the <[signgam]> global for
 	double x;
 #endif
 {
-#ifdef _IEEE_LIBM
-	return __ieee754_gamma_r(x,&(_REENT_SIGNGAM(_REENT)));
-#else
-        double y;
-        y = __ieee754_gamma_r(x,&(_REENT_SIGNGAM(_REENT)));
-        if(_LIB_VERSION == _IEEE_) return y;
-        if(!finite(y)&&finite(x)) {
-	    /* gamma(finite) overflow */
-	    errno = ERANGE;
-        }
-	return y;
-#endif
-}             
+	return tgamma(x);
+}
 
 #endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/newlib/libm/math/w_tgamma.c b/newlib/libm/math/w_tgamma.c
index c0c011dd0..cbb3e7f7f 100644
--- a/newlib/libm/math/w_tgamma.c
+++ b/newlib/libm/math/w_tgamma.c
@@ -27,9 +27,7 @@ 
 #endif
 {
         double y;
-	int local_signgam;
-	y = __ieee754_gamma_r(x,&local_signgam);
-	if (local_signgam < 0) y = -y;
+	y = __ieee754_gamma(x);
 #ifdef _IEEE_LIBM
 	return y;
 #else
diff --git a/newlib/libm/math/wf_gamma.c b/newlib/libm/math/wf_gamma.c
index f0284a282..4e961c864 100644
--- a/newlib/libm/math/wf_gamma.c
+++ b/newlib/libm/math/wf_gamma.c
@@ -25,19 +25,8 @@ 
 	float x;
 #endif
 {
-#ifdef _IEEE_LIBM
-	return __ieee754_gammaf_r(x,&(_REENT_SIGNGAM(_REENT)));
-#else
-        float y;
-        y = __ieee754_gammaf_r(x,&(_REENT_SIGNGAM(_REENT)));
-        if(_LIB_VERSION == _IEEE_) return y;
-        if(!finitef(y)&&finitef(x)) {
-	    /* gammaf(finite) overflow */
-	    errno = ERANGE;
-        }
-	return y;
-#endif
-}             
+	return tgammaf(x);
+}
 
 #ifdef _DOUBLE_IS_32BITS
 
diff --git a/newlib/libm/math/wf_tgamma.c b/newlib/libm/math/wf_tgamma.c
index 92df39648..8f0c501b8 100644
--- a/newlib/libm/math/wf_tgamma.c
+++ b/newlib/libm/math/wf_tgamma.c
@@ -24,9 +24,7 @@ 
 #endif
 {
         float y;
-	int local_signgam;
-	y = __ieee754_gammaf_r(x,&local_signgam);
-	if (local_signgam < 0) y = -y;
+	y = __ieee754_gammaf(x);
 #ifdef _IEEE_LIBM
 	return y;
 #else
diff --git a/newlib/libm/math/wr_gamma.c b/newlib/libm/math/wr_gamma.c
deleted file mode 100644
index c4c2a829e..000000000
--- a/newlib/libm/math/wr_gamma.c
+++ /dev/null
@@ -1,49 +0,0 @@ 
-
-/* @(#)wr_gamma.c 5.1 93/09/24 */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice 
- * is preserved.
- * ====================================================
- */
-
-/* 
- * wrapper double gamma_r(double x, int *signgamp)
- */
-
-#include "fdlibm.h"
-#include <errno.h>
-
-#ifndef _DOUBLE_IS_32BITS
-
-#ifdef __STDC__
-	double gamma_r(double x, int *signgamp) /* wrapper lgamma_r */
-#else
-	double gamma_r(x,signgamp)              /* wrapper lgamma_r */
-	double x; int *signgamp;
-#endif
-{
-#ifdef _IEEE_LIBM
-	return __ieee754_gamma_r(x,signgamp);
-#else
-        double y;
-        y = __ieee754_gamma_r(x,signgamp);
-        if(_LIB_VERSION == _IEEE_) return y;
-        if(!finite(y)&&finite(x)) {
-	    if(floor(x)==x&&x<=0.0)
-	      /* gamma(-integer) or gamma(0) */
-	      errno = EDOM;
-	    else
-	      /* gamma(finite) overflow */
-	      errno = ERANGE;
-	    return HUGE_VALF;
-        } else
-            return y;
-#endif
-}
-
-#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/newlib/libm/math/wrf_gamma.c b/newlib/libm/math/wrf_gamma.c
deleted file mode 100644
index d43c7f03d..000000000
--- a/newlib/libm/math/wrf_gamma.c
+++ /dev/null
@@ -1,48 +0,0 @@ 
-/* wrf_gamma.c -- float version of wr_gamma.c.
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice 
- * is preserved.
- * ====================================================
- */
-
-/* 
- * wrapper float gammaf_r(float x, int *signgamp)
- */
-
-#include "fdlibm.h"
-#include <errno.h>
-
-#ifdef __STDC__
-	float gammaf_r(float x, int *signgamp) /* wrapper lgammaf_r */
-#else
-	float gammaf_r(x,signgamp)              /* wrapper lgammaf_r */
-	float x; int *signgamp;
-#endif
-{
-#ifdef _IEEE_LIBM
-	return __ieee754_gammaf_r(x,signgamp);
-#else
-        float y;
-        y = __ieee754_gammaf_r(x,signgamp);
-        if(_LIB_VERSION == _IEEE_) return y;
-        if(!finitef(y)&&finitef(x)) {
-	    if(floorf(x)==x&&x<=0.0f) {
-		/* gammaf(-integer) or gamma(0) */
-		errno = EDOM;
-	    } else {
-		/* gammaf(finite) overflow */
-		errno = ERANGE;
-	    }
-	    return HUGE_VALF;
-        } else
-            return y;
-#endif
-}