From 410e6ebb59ba7d1a63ea4876f66087bd4ea9b6e6 Mon Sep 17 00:00:00 2001 From: Ed Schouten Date: Fri, 9 Jan 2015 13:57:45 +0100 Subject: [PATCH] Move CMPLX() into , as it is normally part of . While there, make CMPLX() work with Clang by using compound literals. Now that cimag*() uses __imag__, we can also just inline the unions. There is no need for the separate types anymore. Also just define CMPLX() unconditionally now, as we no longer pull in the host's . --- src/openlibm.h | 98 ------------------------------------------ src/openlibm_complex.h | 68 +++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 98 deletions(-) diff --git a/src/openlibm.h b/src/openlibm.h index 66c55b0..337da4c 100644 --- a/src/openlibm.h +++ b/src/openlibm.h @@ -17,8 +17,6 @@ #ifndef OPENLIBM_H #define OPENLIBM_H -#include - #if (defined(_WIN32) || defined (_MSC_VER)) && !defined(__WIN32__) #define __WIN32__ #endif @@ -180,102 +178,6 @@ extern int signgam; #endif #endif /* __BSD_VISIBLE */ -//VBS -//#ifdef _COMPLEX_H - -/* - * C99 specifies that complex numbers have the same representation as - * an array of two elements, where the first element is the real part - * and the second element is the imaginary part. - */ -typedef union { - float complex f; - float a[2]; -} float_complex; -typedef union { - double complex f; - double a[2]; -} double_complex; -typedef union { - long double complex f; - long double a[2]; -} long_double_complex; -#define REALPART(z) ((z).a[0]) -#define IMAGPART(z) ((z).a[1]) - -/* - * Macros that can be used to construct complex values. - * - * The C99 standard intends x+I*y to be used for this, but x+I*y is - * currently unusable in general since gcc introduces many overflow, - * underflow, sign and efficiency bugs by rewriting I*y as - * (0.0+I)*(y+0.0*I) and laboriously computing the full complex product. - * In particular, I*Inf is corrupted to NaN+I*Inf, and I*-0 is corrupted - * to -0.0+I*0.0. - * - * In C11, a CMPLX(x,y) macro was added to circumvent this limitation, - * and gcc 4.7 added a __builtin_complex feature to simplify implementation - * of CMPLX in libc, so we can take advantage of these features if they - * are available. - * - * If __builtin_complex is not available, resort to using inline - * functions instead. These can unfortunately not be used to construct - * compile-time constants. - */ - -#define HAVE_BUILTIN_COMPLEX (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__INTEL_COMPILER) - -#ifndef CMPLXF -#if HAVE_BUILTIN_COMPLEX -# define CMPLXF(x,y) __builtin_complex ((float) (x), (float) (y)) -#else -static __inline float complex -CMPLXF(float x, float y) -{ - float_complex z; - - REALPART(z) = x; - IMAGPART(z) = y; - return (z.f); -} -#endif -#endif - -#ifndef CMPLX -#if HAVE_BUILTIN_COMPLEX -# define CMPLX(x,y) __builtin_complex ((double) (x), (double) (y)) -#else -static __inline double complex -CMPLX(double x, double y) -{ - double_complex z; - - REALPART(z) = x; - IMAGPART(z) = y; - return (z.f); -} -#endif -#endif - -#ifndef CMPLXL -#if HAVE_BUILTIN_COMPLEX -# define CMPLXL(x,y) __builtin_complex ((long double) (x), (long double) (y)) -#else -static __inline long double complex -CMPLXL(long double x, long double y) -{ - long_double_complex z; - - REALPART(z) = x; - IMAGPART(z) = y; - return (z.f); -} -#endif -#endif - -//VBS -//#endif /* _COMPLEX_H */ - /* * Most of these functions depend on the rounding mode and have the side * effect of raising floating-point exceptions, so they are not declared diff --git a/src/openlibm_complex.h b/src/openlibm_complex.h index ba91803..7774eab 100644 --- a/src/openlibm_complex.h +++ b/src/openlibm_complex.h @@ -23,6 +23,74 @@ #define _Complex_I 1.0fi #define I _Complex_I +/* + * Macros that can be used to construct complex values. + * + * The C99 standard intends x+I*y to be used for this, but x+I*y is + * currently unusable in general since gcc introduces many overflow, + * underflow, sign and efficiency bugs by rewriting I*y as + * (0.0+I)*(y+0.0*I) and laboriously computing the full complex product. + * In particular, I*Inf is corrupted to NaN+I*Inf, and I*-0 is corrupted + * to -0.0+I*0.0. + * + * In C11, a CMPLX(x,y) macro was added to circumvent this limitation, + * and gcc 4.7 added a __builtin_complex feature to simplify implementation + * of CMPLX in libc, so we can take advantage of these features if they + * are available. Clang simply allows complex values to be constructed + * using a compound literal. + * + * If __builtin_complex is not available, resort to using inline + * functions instead. These can unfortunately not be used to construct + * compile-time constants. + * + * C99 specifies that complex numbers have the same representation as + * an array of two elements, where the first element is the real part + * and the second element is the imaginary part. + */ + +#ifdef __clang__ +# define CMPLXF(x, y) ((float complex){x, y}) +# define CMPLX(x, y) ((double complex){x, y}) +# define CMPLXL(x, y) ((long double complex){x, y}) +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__INTEL_COMPILER) +# define CMPLXF(x,y) __builtin_complex ((float) (x), (float) (y)) +# define CMPLX(x,y) __builtin_complex ((double) (x), (double) (y)) +# define CMPLXL(x,y) __builtin_complex ((long double) (x), (long double) (y)) +#else +static inline float complex +CMPLXF(float x, float y) +{ + union { + float a[2]; + float complex f; + } z = {{ x, y }}; + + return (z.f); +} + +static inline double complex +CMPLX(double x, double y) +{ + union { + double a[2]; + double complex f; + } z = {{ x, y }}; + + return (z.f); +} + +static inline long double complex +CMPLXL(long double x, long double y) +{ + union { + long double a[2]; + long double complex f; + } z = {{ x, y }}; + + return (z.f); +} +#endif + /* * Double versions of C99 functions */