[RFC] Support for type-generic libm function implementations libm
diff mbox

Message ID 55807bea-73b6-2b68-df1d-bf94b841be49@linux.vnet.ibm.com
State New
Headers show

Commit Message

Paul E. Murphy June 14, 2016, 8:40 p.m. UTC
This builds from https://sourceware.org/ml/libc-alpha/2016-06/msg00550.html
to further tweak the math Makefile.

As it stands, there is much duplication when building
wrappers for IEEE functions and complex functions.
With a little creativity, this can reduce much 
redundant source, and simplify supporting new types.

Only two platforms (alpha and m68k) override complex
functions.  Both should work with the approach.

---8<---
This defines two new classes of libm objects. g for
generated objects, and t for templates to generate
those objects.

As a simple example, carg is converted to use this
new infrastructure.

This uses some makefile hackery to generate g_*
objects from from the base t_*.c.  The intent is to
convert most or all of the complex function wrappers,
possibly even the wrappers for the e functions.

The only interesting gotcha's are alpha and m68k
which override an interesting subset of the complex
functions.  m68k conversions should be fairly trivial,
as they already use a similar approach to what is
done here.  Likewise, alpha requires legacy support
for an older ABI for complex floats.  This mechanism
can also be used there too.

Note, I have not tested this on alpha.  If anyone can
assist me in testing (or just point out a reasonable
mechanism to do it myself) it would be much
appreciated.  Likewise for m68k.

	* math/Makefile: Add support for routines generated
	via a macroed template file.
	(gen-libm-calls): New variable.
	(gen-suffixes): Likewise.
	(CPPFLAGS-mtype_l): Likewise.
	(CPPFLAGS-mtype_): Likewise.
	(CPPFLAGS-mtype_f): Likewise.

	* math/carg.c: Refactor using new template infrastructe.
	* math/math-type-macros.h: New file.
	* math/cargf.c: Removed.
	* math/cargl.c: Removed.
	* sysdeps/alpha/fpu/cargf.c: Refactor into
	* sysdeps/alpha/fpu/t_carg.c: New file.
---
 math/Makefile              | 38 ++++++++++++++++++++++++++++++-
 math/carg.c                | 32 --------------------------
 math/cargf.c               | 28 -----------------------
 math/cargl.c               | 28 -----------------------
 math/math-type-macros.h    | 57 ++++++++++++++++++++++++++++++++++++++++++++++
 math/t_carg.c              | 30 ++++++++++++++++++++++++
 sysdeps/alpha/fpu/cargf.c  | 41 ---------------------------------
 sysdeps/alpha/fpu/t_carg.c | 49 +++++++++++++++++++++++++++++++++++++++
 8 files changed, 173 insertions(+), 130 deletions(-)
 delete mode 100644 math/carg.c
 delete mode 100644 math/cargf.c
 delete mode 100644 math/cargl.c
 create mode 100644 math/math-type-macros.h
 create mode 100644 math/t_carg.c
 delete mode 100644 sysdeps/alpha/fpu/cargf.c
 create mode 100644 sysdeps/alpha/fpu/t_carg.c

Comments

Joseph Myers June 14, 2016, 9:20 p.m. UTC | #1
On Tue, 14 Jun 2016, Paul E. Murphy wrote:

> This builds from https://sourceware.org/ml/libc-alpha/2016-06/msg00550.html
> to further tweak the math Makefile.
> 
> As it stands, there is much duplication when building
> wrappers for IEEE functions and complex functions.
> With a little creativity, this can reduce much 
> redundant source, and simplify supporting new types.
> 
> Only two platforms (alpha and m68k) override complex
> functions.  Both should work with the approach.

What about the ldbl-opt code that wraps complex functions?  Does that need 
updating?

> This defines two new classes of libm objects. g for
> generated objects, and t for templates to generate
> those objects.

Note that right now t_* is used in libm for generated tables....

> Note, I have not tested this on alpha.  If anyone can
> assist me in testing (or just point out a reasonable
> mechanism to do it myself) it would be much
> appreciated.  Likewise for m68k.

I don't really like how platforms needing to override a file have to 
override the template file with something containing conditionals on the 
type.  Is it hard to arrange things so that: if an appropriately named 
file with a name depending on the type is present in sysdeps, that file is 
used instead of the template (so compiling from a per-type file in sysdeps 
takes precedence over compiling from the template)?

On whatever platforms you have tested, did you make sure the installed 
stripped shared libraries were unchanged (or at least that the relevant 
objects were after stripping debug info, if the changes have the effect of 
changing the order in which objects are linked into libm.so)?

> +#if M_TYPE == M_FLOAT
> +# define M_PFX FLT
> +# define M_LIT f
> +# define M_SUF(c) c ## f
> +# define FLOAT float
> +#elif M_TYPE == M_DOUBLE
> +# define M_PFX DBL
> +# define M_LIT
> +# define M_SUF(c) c
> +# define FLOAT double
> +#elif M_TYPE == M_LDOUBLE
> +# define M_PFX LDBL
> +# define M_LIT L
> +# define M_SUF(c) c ## l
> +# define FLOAT long double
> +#else
> +# error Error: M_TYPE must be defined before including
> +#endif

I'd expect more macros making use of M_PFX, M_LIT - are those intended to 
be added as needed?  I'd also expect macros relating to use of M_* 
constants from <math.h>.  Probably the undefine / redefine of LDBL_EPSILON 
for IBM long double also belongs in this header.

> +FLOAT
> +M_SUF (__carg) (__complex__ FLOAT x)

You can't use __complex__ FLOAT because that won't work with __float128 
(as it's a built-in typedef not a keyword; GCC bug 32187).  Instead, you 
need another macro for the complex type.
Paul E. Murphy June 14, 2016, 10:59 p.m. UTC | #2
On 06/14/2016 04:20 PM, Joseph Myers wrote:
> On Tue, 14 Jun 2016, Paul E. Murphy wrote:
> 
>> This builds from https://sourceware.org/ml/libc-alpha/2016-06/msg00550.html
>> to further tweak the math Makefile.
>>
>> As it stands, there is much duplication when building
>> wrappers for IEEE functions and complex functions.
>> With a little creativity, this can reduce much 
>> redundant source, and simplify supporting new types.
>>
>> Only two platforms (alpha and m68k) override complex
>> functions.  Both should work with the approach.
> 
> What about the ldbl-opt code that wraps complex functions?  Does that need 
> updating?

My current understanding is that ldbl-opt is fairly self contained,
and builds its interesting bits more or less independently of the
math makefile.  Irrespective, the patch still needs more work
in fundamental areas.

> 
>> This defines two new classes of libm objects. g for
>> generated objects, and t for templates to generate
>> those objects.
> 
> Note that right now t_* is used in libm for generated tables....
> 
>> Note, I have not tested this on alpha.  If anyone can
>> assist me in testing (or just point out a reasonable
>> mechanism to do it myself) it would be much
>> appreciated.  Likewise for m68k.
> 
> I don't really like how platforms needing to override a file have to 
> override the template file with something containing conditionals on the 
> type.  Is it hard to arrange things so that: if an appropriately named 
> file with a name depending on the type is present in sysdeps, that file is 
> used instead of the template (so compiling from a per-type file in sysdeps 
> takes precedence over compiling from the template)?

That is indeed one of the drawbacks.  One thought might be to have
such platforms add a fragment declaring what they override. I.e

libm-gen-call-overrides = g_cargf

and the obviously incorrect, but handwavy change to patchup libm-calls:

libm-calls = $(filter-out $(libm-gen-call-overrides), $(libm-calls)) \
   $(libm-gen-call-overrides:g_%=s_%))

Though, such blatantly goes against the desirable ability to
quietly override common files.  This is an area where I
welcome feedback from the glibc makefile experts.  There is
much subtlety.

> 
> On whatever platforms you have tested, did you make sure the installed 
> stripped shared libraries were unchanged (or at least that the relevant 
> objects were after stripping debug info, if the changes have the effect of 
> changing the order in which objects are linked into libm.so)?

I've been working this out and running the tests on x86_64.  The intent
is these changes *should* be generic.  I've only verified the the correct
flavor of atan is called.  More complex wrappers deserve more inspection.
Perhaps adding a few extra test cases is a better way to catch unwanted
silent conversions.

The Makefile changes are not trivial.  Thus, I'd like feedback on what
I'm doing wrong sooner, rather than later.

> 
>> +#if M_TYPE == M_FLOAT
>> +# define M_PFX FLT
>> +# define M_LIT f
>> +# define M_SUF(c) c ## f
>> +# define FLOAT float
>> +#elif M_TYPE == M_DOUBLE
>> +# define M_PFX DBL
>> +# define M_LIT
>> +# define M_SUF(c) c
>> +# define FLOAT double
>> +#elif M_TYPE == M_LDOUBLE
>> +# define M_PFX LDBL
>> +# define M_LIT L
>> +# define M_SUF(c) c ## l
>> +# define FLOAT long double
>> +#else
>> +# error Error: M_TYPE must be defined before including
>> +#endif
> 
> I'd expect more macros making use of M_PFX, M_LIT - are those intended to 
> be added as needed?  I'd also expect macros relating to use of M_* 
> constants from <math.h>.  Probably the undefine / redefine of LDBL_EPSILON 
> for IBM long double also belongs in this header.

Yes, they would only be added as needed.

> 
>> +FLOAT
>> +M_SUF (__carg) (__complex__ FLOAT x)
> 
> You can't use __complex__ FLOAT because that won't work with __float128 
> (as it's a built-in typedef not a keyword; GCC bug 32187).  Instead, you 
> need another macro for the complex type.

That is indeed annoying.
Joseph Myers June 15, 2016, 1:09 a.m. UTC | #3
On Tue, 14 Jun 2016, Paul E. Murphy wrote:

> > What about the ldbl-opt code that wraps complex functions?  Does that need 
> > updating?
> 
> My current understanding is that ldbl-opt is fairly self contained,
> and builds its interesting bits more or less independently of the
> math makefile.  Irrespective, the patch still needs more work
> in fundamental areas.

Well, it includes files carg.c and cargl.c, for example, both of which 
include the corresponding math/ files and do other things before or after 
that inclusion.

> > On whatever platforms you have tested, did you make sure the installed 
> > stripped shared libraries were unchanged (or at least that the relevant 
> > objects were after stripping debug info, if the changes have the effect of 
> > changing the order in which objects are linked into libm.so)?
> 
> I've been working this out and running the tests on x86_64.  The intent
> is these changes *should* be generic.  I've only verified the the correct
> flavor of atan is called.  More complex wrappers deserve more inspection.
> Perhaps adding a few extra test cases is a better way to catch unwanted
> silent conversions.

My point is that as a general principle, certain sorts of cleanup patches 
are expected not to change the generated code, and if your patch is one of 
them, you should do the comparison, and have an explanation for any 
differences found so we can see if they are harmless.  (For example, there 
might be differences because the existing files are unintentionally out of 
sync, or float files are accidentally using double operations at present, 
or if there's inconsistency in how M_* constants are used in float files 
that it doesn't make sense to replicate when making them type-generic.  I 
don't know if there are such issues at present, but those would be 
plausible reasons for making a function type-generic changing the code 
generated for it.)

Patch
diff mbox

diff --git a/math/Makefile b/math/Makefile
index 9d18ade..f19cdfd 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -43,6 +43,12 @@  libm-support = s_lib_version s_matherr s_signgam			\
 	       fesetenv feupdateenv t_exp fedisblxcpt feenablxcpt	\
 	       fegetexcept
 
+# These functions are generated from a common source with a select macros
+# for each type they built for.  There is an explicit underscore between
+# the function name and the type suffix to simplify matching to the
+# rule used to build it.  These all build from a common t_func.c file.
+gen-libm-calls = g_carg_F
+
 libm-calls = e_acosF e_acoshF e_asinF e_atan2F e_atanhF e_coshF e_expF e_fmodF	\
 	     e_hypotF e_j0F e_j1F e_jnF e_lgammaF_r e_logF e_log10F e_powF	\
 	     e_rem_pio2F e_remainderF e_scalbF e_sinhF e_sqrtF e_gammaF_r	\
@@ -58,12 +64,13 @@  libm-calls = e_acosF e_acoshF e_asinF e_atan2F e_atanhF e_coshF e_expF e_fmodF	\
 	     w_ilogbF								\
 	     s_fpclassifyF s_fmaxF s_fminF s_fdimF s_nanF s_truncF		\
 	     s_remquoF e_log2F e_exp2F s_roundF s_nearbyintF s_sincosF		\
-	     conjF cimagF crealF cabsF cargF s_cexpF s_csinhF s_ccoshF s_clogF	\
+	     conjF cimagF crealF cabsF s_cexpF s_csinhF s_ccoshF s_clogF	\
 	     s_catanF s_casinF s_ccosF s_csinF s_ctanF s_ctanhF s_cacosF	\
 	     s_casinhF s_cacoshF s_catanhF s_csqrtF s_cpowF s_cprojF s_clog10F 	\
 	     s_fmaF s_lrintF s_llrintF s_lroundF s_llroundF e_exp10F w_log2F	\
 	     s_issignalingF $(calls:s_%=m_%) x2y2m1F k_casinhF			\
 	     gamma_productF k_standardF lgamma_negF lgamma_productF		\
+	     $(gen-libm-calls)
 
 libm-compat-calls = w_lgamma_compatf w_lgamma_compat w_lgamma_compatl
 
@@ -114,6 +121,9 @@  calls = s_isinfF s_isnanF s_finiteF s_copysignF s_modfF s_scalbnF s_frexpF \
 generated += $(foreach s,.c .S,$(call type-foreach, $(calls:s_%=m_%)))
 routines = $(call type-foreach, $(calls))
 
+# Wrappers and what not are generated per type to keep the noise down.
+generated += $(foreach g,.c .S,$(call type-foreach, $(gen-libm-calls)))
+
 ifeq ($(build-mathvec),yes)
 # We need to install libm.so as linker script
 # for more comfortable use of vector math library.
@@ -301,6 +311,32 @@  endef
 object-suffixes-left := $(all-object-suffixes)
 include $(o-iterator)
 
+# Generated per-type files.
+#
+# Suffixes for each generated file.  This hackery makes it possible
+# to correctly identify name of the templated file.
+gen-suffixes := $(foreach s,$(all-object-suffixes), \
+			$(foreach t,$(types),_$(type-$(t)-suffix)$s))
+
+# Declare the type for each build of the type-generic files.
+CPPFLAGS-mtype_l = -DM_TYPE=M_LDOUBLE
+CPPFLAGS-mtype_  = -DM_TYPE=M_DOUBLE
+CPPFLAGS-mtype_f = -DM_TYPE=M_FLOAT
+
+# One rule to build to them all.
+define o-iterator-doit
+$(objpfx)g_%$o: t_%.c $(before-compile); $$(compile-command.c)
+endef
+object-suffixes-left := $(gen-suffixes)
+include $(o-iterator)
+
+# And anther one to pass in the extra cpp flags to build them
+# correctly.
+define o-iterator-doit
+$(objpfx)g_%$o: CPPFLAGS += $(CPPFLAGS-mtype$(basename $o))
+endef
+object-suffixes-left := $(gen-suffixes)
+include $(o-iterator)
 
 # This file defines the default _LIB_VERSION variable that controls
 # the error return conventions for the math functions.
diff --git a/math/carg.c b/math/carg.c
deleted file mode 100644
index 61f1e0d..0000000
--- a/math/carg.c
+++ /dev/null
@@ -1,32 +0,0 @@ 
-/* Compute argument of complex double value.
-   Copyright (C) 1997-2016 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
-
-   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 <complex.h>
-#include <math.h>
-
-double
-__carg (__complex__ double x)
-{
-  return __atan2 (__imag__ x, __real__ x);
-}
-weak_alias (__carg, carg)
-#ifdef NO_LONG_DOUBLE
-strong_alias (__carg, __cargl)
-weak_alias (__carg, cargl)
-#endif
diff --git a/math/cargf.c b/math/cargf.c
deleted file mode 100644
index 620db3e..0000000
--- a/math/cargf.c
+++ /dev/null
@@ -1,28 +0,0 @@ 
-/* Compute argument of complex float value.
-   Copyright (C) 1997-2016 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
-
-   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 <complex.h>
-#include <math.h>
-
-float
-__cargf (__complex__ float x)
-{
-  return __atan2f (__imag__ x, __real__ x);
-}
-weak_alias (__cargf, cargf)
diff --git a/math/cargl.c b/math/cargl.c
deleted file mode 100644
index 31b7292..0000000
--- a/math/cargl.c
+++ /dev/null
@@ -1,28 +0,0 @@ 
-/* Compute argument of complex long double value.
-   Copyright (C) 1997-2016 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
-
-   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 <complex.h>
-#include <math.h>
-
-long double
-__cargl (__complex__ long double x)
-{
-  return __atan2l (__imag__ x, __real__ x);
-}
-weak_alias (__cargl, cargl)
diff --git a/math/math-type-macros.h b/math/math-type-macros.h
new file mode 100644
index 0000000..a80bb18
--- /dev/null
+++ b/math/math-type-macros.h
@@ -0,0 +1,57 @@ 
+/* Helper macros for type generic function implementations within libm.
+   Copyright (C) 2016 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/>.  */
+
+#ifndef _MATH_TYPE_MACROS
+#define _MATH_TYPE_MACROS
+
+#define M_FLOAT 1
+#define M_DOUBLE 2
+#define M_LDOUBLE 3
+
+#if M_TYPE == M_FLOAT
+# define M_PFX FLT
+# define M_LIT f
+# define M_SUF(c) c ## f
+# define FLOAT float
+#elif M_TYPE == M_DOUBLE
+# define M_PFX DBL
+# define M_LIT
+# define M_SUF(c) c
+# define FLOAT double
+#elif M_TYPE == M_LDOUBLE
+# define M_PFX LDBL
+# define M_LIT L
+# define M_SUF(c) c ## l
+# define FLOAT long double
+#else
+# error Error: M_TYPE must be defined before including
+#endif
+
+/* Optional long double aliasing for targets without a distinct
+   long double type.  */
+#if M_TYPE == M_DOUBLE && defined NO_LONG_DOUBLE
+# define declare_mgen_alias(from, to)	  \
+    weak_alias (from, to ## l)		  \
+    strong_alias (from, to ## l)	  \
+    weak_alias (from, to ## l)
+#else
+# define declare_mgen_alias(from, to)	  \
+    weak_alias (M_SUF (from), M_SUF (to))
+#endif
+
+#endif
diff --git a/math/t_carg.c b/math/t_carg.c
new file mode 100644
index 0000000..4bf6e53
--- /dev/null
+++ b/math/t_carg.c
@@ -0,0 +1,30 @@ 
+/* Compute argument of complex float type.
+   Copyright (C) 1997-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   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 <complex.h>
+#include <math.h>
+
+#include "math-type-macros.h"
+
+FLOAT
+M_SUF (__carg) (__complex__ FLOAT x)
+{
+  return M_SUF (__atan2) (__imag__ x, __real__ x);
+}
+declare_mgen_alias (__carg, carg)
diff --git a/sysdeps/alpha/fpu/cargf.c b/sysdeps/alpha/fpu/cargf.c
deleted file mode 100644
index d798a5b..0000000
--- a/sysdeps/alpha/fpu/cargf.c
+++ /dev/null
@@ -1,41 +0,0 @@ 
-/* Compute argument of complex float value.
-   Copyright (C) 2004-2016 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/>.  */
-
-#define __cargf __cargf_not_defined
-#define cargf cargf_not_defined
-
-#include <complex.h>
-#include <math.h>
-#include "cfloat-compat.h"
-
-#undef __cargf
-#undef cargf
-
-float
-__c1_cargf (c1_cfloat_decl (x))
-{
-  return __atan2f (c1_cfloat_imag (x), c1_cfloat_real (x));
-}
-
-float
-__c2_cargf (c2_cfloat_decl (x))
-{
-  return __atan2f (c2_cfloat_imag (x), c2_cfloat_real (x));
-}
-
-cfloat_versions (cargf);
diff --git a/sysdeps/alpha/fpu/t_carg.c b/sysdeps/alpha/fpu/t_carg.c
new file mode 100644
index 0000000..3f5619b
--- /dev/null
+++ b/sysdeps/alpha/fpu/t_carg.c
@@ -0,0 +1,49 @@ 
+/* Compute argument of complex float value.
+   Copyright (C) 2004-2016 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 "math-type-macros.h"
+
+#if M_TYPE == M_FLOAT
+
+# define __cargf __cargf_not_defined
+# define cargf cargf_not_defined
+
+# include <complex.h>
+# include <math.h>
+# include "cfloat-compat.h"
+
+# undef __cargf
+# undef cargf
+
+float
+__c1_cargf (c1_cfloat_decl (x))
+{
+  return __atan2f (c1_cfloat_imag (x), c1_cfloat_real (x));
+}
+
+float
+__c2_cargf (c2_cfloat_decl (x))
+{
+  return __atan2f (c2_cfloat_imag (x), c2_cfloat_real (x));
+}
+
+cfloat_versions (cargf);
+
+#else
+# include <math/t_carg.c>
+#endif