From de03118d092c3b87f593a7c5ebd54ff2818d218c Mon Sep 17 00:00:00 2001 From: Sascha Wildner Date: Thu, 15 Oct 2015 00:29:13 +0200 Subject: [PATCH] : Revert to using the C11 _Generic keyword if it is available. This commit brings back FreeBSD's version of which has this optimization over OpenBSD's and compiles much faster when _Generic is part of the language. --- contrib/openbsd_libm/include/global/tgmath.h | 137 ++++++++++++------- 1 file changed, 89 insertions(+), 48 deletions(-) diff --git a/contrib/openbsd_libm/include/global/tgmath.h b/contrib/openbsd_libm/include/global/tgmath.h index 46fade4ee1..985d0a1722 100644 --- a/contrib/openbsd_libm/include/global/tgmath.h +++ b/contrib/openbsd_libm/include/global/tgmath.h @@ -1,9 +1,10 @@ -/* $OpenBSD: tgmath.h,v 1.1 2011/07/08 19:28:06 martynas Exp $ */ - /*- * Copyright (c) 2004 Stefan Farfeleder. * All rights reserved. * + * Copyright (c) 2012 Ed Schouten + * All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -25,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/include/tgmath.h,v 1.5 2007/02/02 18:30:23 schweikh Exp $ + * $FreeBSD: head/include/tgmath.h 271155 2014-09-05 05:36:32Z ed $ */ #ifndef _TGMATH_H_ @@ -35,64 +36,105 @@ #include /* - * This implementation of requires two implementation-dependent - * macros to be defined: - * __tg_impl_simple(x, y, z, fn, fnf, fnl, ...) + * This implementation of uses the two following macros, + * which are based on the macros described in C11 proposal N1404: + * __tg_impl_simple(x, y, z, fnl, fn, fnf, ...) * Invokes fnl() if the corresponding real type of x, y or z is long * double, fn() if it is double or any has an integer type, and fnf() * otherwise. - * __tg_impl_full(x, y, z, fn, fnf, fnl, cfn, cfnf, cfnl, ...) - * Invokes [c]fnl() if the corresponding real type of x, y or z is long + * __tg_impl_full(x, y, cfnl, cfn, cfnf, fnl, fn, fnf, ...) + * Invokes [c]fnl() if the corresponding real type of x or y is long * double, [c]fn() if it is double or any has an integer type, and * [c]fnf() otherwise. The function with the 'c' prefix is called if - * any of x, y or z is a complex number. + * any of x or y is a complex number. * Both macros call the chosen function with all additional arguments passed * to them, as given by __VA_ARGS__. * * Note that these macros cannot be implemented with C's ?: operator, * because the return type of the whole expression would incorrectly be long * double complex regardless of the argument types. + * + * The structure of the C11 implementation of these macros can in + * principle be reused for non-C11 compilers, but due to an integer + * promotion bug for complex types in GCC 4.2, simply let non-C11 + * compilers use an inefficient yet reliable version. */ -#if __GNUC_PREREQ__(3, 1) -#define __tg_type(e, t) __builtin_types_compatible_p(__typeof__(e), t) -#define __tg_type3(e1, e2, e3, t) \ - (__tg_type(e1, t) || __tg_type(e2, t) || __tg_type(e3, t)) -#define __tg_type_corr(e1, e2, e3, t) \ - (__tg_type3(e1, e2, e3, t) || __tg_type3(e1, e2, e3, t _Complex)) -#define __tg_integer(e1, e2, e3) \ - (((__typeof__(e1))1.5 == 1) || ((__typeof__(e2))1.5 == 1) || \ - ((__typeof__(e3))1.5 == 1)) -#define __tg_is_complex(e1, e2, e3) \ - (__tg_type3(e1, e2, e3, float _Complex) || \ - __tg_type3(e1, e2, e3, double _Complex) || \ - __tg_type3(e1, e2, e3, long double _Complex) || \ - __tg_type3(e1, e2, e3, __typeof__(_Complex_I))) - -#define __tg_impl_simple(x, y, z, fn, fnf, fnl, ...) \ - __builtin_choose_expr(__tg_type_corr(x, y, z, long double), \ - fnl(__VA_ARGS__), __builtin_choose_expr( \ - __tg_type_corr(x, y, z, double) || __tg_integer(x, y, z),\ - fn(__VA_ARGS__), fnf(__VA_ARGS__))) - -#define __tg_impl_full(x, y, z, fn, fnf, fnl, cfn, cfnf, cfnl, ...) \ - __builtin_choose_expr(__tg_is_complex(x, y, z), \ - __tg_impl_simple(x, y, z, cfn, cfnf, cfnl, __VA_ARGS__), \ - __tg_impl_simple(x, y, z, fn, fnf, fnl, __VA_ARGS__)) - -#else /* __GNUC__ */ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \ + __has_extension(c_generic_selections) +#define __tg_generic(x, cfnl, cfn, cfnf, fnl, fn, fnf) \ + _Generic(x, \ + long double _Complex: cfnl, \ + double _Complex: cfn, \ + float _Complex: cfnf, \ + long double: fnl, \ + default: fn, \ + float: fnf \ + ) +#define __tg_type(x) \ + __tg_generic(x, (long double _Complex)0, (double _Complex)0, \ + (float _Complex)0, (long double)0, (double)0, (float)0) +#define __tg_impl_simple(x, y, z, fnl, fn, fnf, ...) \ + __tg_generic( \ + __tg_type(x) + __tg_type(y) + __tg_type(z), \ + fnl, fn, fnf, fnl, fn, fnf)(__VA_ARGS__) +#define __tg_impl_full(x, y, cfnl, cfn, cfnf, fnl, fn, fnf, ...) \ + __tg_generic( \ + __tg_type(x) + __tg_type(y), \ + cfnl, cfn, cfnf, fnl, fn, fnf)(__VA_ARGS__) +#elif defined(__generic) +#define __tg_generic_simple(x, fnl, fn, fnf) \ + __generic(x, long double _Complex, fnl, \ + __generic(x, double _Complex, fn, \ + __generic(x, float _Complex, fnf, \ + __generic(x, long double, fnl, \ + __generic(x, float, fnf, fn))))) +#define __tg_impl_simple(x, y, z, fnl, fn, fnf, ...) \ + __tg_generic_simple(x, \ + __tg_generic_simple(y, \ + __tg_generic_simple(z, fnl, fnl, fnl), \ + __tg_generic_simple(z, fnl, fnl, fnl), \ + __tg_generic_simple(z, fnl, fnl, fnl)), \ + __tg_generic_simple(y, \ + __tg_generic_simple(z, fnl, fnl, fnl), \ + __tg_generic_simple(z, fnl, fn , fn ), \ + __tg_generic_simple(z, fnl, fn , fn )), \ + __tg_generic_simple(y, \ + __tg_generic_simple(z, fnl, fnl, fnl), \ + __tg_generic_simple(z, fnl, fn , fn ), \ + __tg_generic_simple(z, fnl, fn , fnf)))(__VA_ARGS__) +#define __tg_generic_full(x, cfnl, cfn, cfnf, fnl, fn, fnf) \ + __generic(x, long double _Complex, cfnl, \ + __generic(x, double _Complex, cfn, \ + __generic(x, float _Complex, cfnf, \ + __generic(x, long double, fnl, \ + __generic(x, float, fnf, fn))))) +#define __tg_impl_full(x, y, cfnl, cfn, cfnf, fnl, fn, fnf, ...) \ + __tg_generic_full(x, \ + __tg_generic_full(y, cfnl, cfnl, cfnl, cfnl, cfnl, cfnl), \ + __tg_generic_full(y, cfnl, cfn , cfn , cfnl, cfn , cfn ), \ + __tg_generic_full(y, cfnl, cfn , cfnf, cfnl, cfn , cfnf), \ + __tg_generic_full(y, cfnl, cfnl, cfnl, fnl , fnl , fnl ), \ + __tg_generic_full(y, cfnl, cfn , cfn , fnl , fn , fn ), \ + __tg_generic_full(y, cfnl, cfn , cfnf, fnl , fn , fnf )) \ + (__VA_ARGS__) +#else #error " not implemented for this compiler" -#endif /* !__GNUC__ */ +#endif /* Macros to save lots of repetition below */ #define __tg_simple(x, fn) \ - __tg_impl_simple(x, x, x, fn, fn##f, fn##l, x) + __tg_impl_simple(x, x, x, fn##l, fn, fn##f, x) #define __tg_simple2(x, y, fn) \ - __tg_impl_simple(x, x, y, fn, fn##f, fn##l, x, y) + __tg_impl_simple(x, x, y, fn##l, fn, fn##f, x, y) +#define __tg_simple3(x, y, z, fn) \ + __tg_impl_simple(x, y, z, fn##l, fn, fn##f, x, y, z) #define __tg_simplev(x, fn, ...) \ - __tg_impl_simple(x, x, x, fn, fn##f, fn##l, __VA_ARGS__) + __tg_impl_simple(x, x, x, fn##l, fn, fn##f, __VA_ARGS__) #define __tg_full(x, fn) \ - __tg_impl_full(x, x, x, fn, fn##f, fn##l, c##fn, c##fn##f, c##fn##l, x) + __tg_impl_full(x, x, c##fn##l, c##fn, c##fn##f, fn##l, fn, fn##f, x) +#define __tg_full2(x, y, fn) \ + __tg_impl_full(x, y, c##fn##l, c##fn, c##fn##f, fn##l, fn, fn##f, x, y) /* 7.22#4 -- These macros expand to real or complex functions, depending on * the type of their arguments. */ @@ -110,13 +152,12 @@ #define tanh(x) __tg_full(x, tanh) #define exp(x) __tg_full(x, exp) #define log(x) __tg_full(x, log) -#define pow(x, y) __tg_impl_full(x, x, y, pow, powf, powl, \ - cpow, cpowf, cpowl, x, y) +#define pow(x, y) __tg_full2(x, y, pow) #define sqrt(x) __tg_full(x, sqrt) /* "The corresponding type-generic macro for fabs and cabs is fabs." */ -#define fabs(x) __tg_impl_full(x, x, x, fabs, fabsf, fabsl, \ - cabs, cabsf, cabsl, x) +#define fabs(x) __tg_impl_full(x, x, cabsl, cabs, cabsf, \ + fabsl, fabs, fabsf, x) /* 7.22#5 -- These macros are only defined for arguments with real type. */ #define atan2(x, y) __tg_simple2(x, y, atan2) @@ -129,7 +170,7 @@ #define expm1(x) __tg_simple(x, expm1) #define fdim(x, y) __tg_simple2(x, y, fdim) #define floor(x) __tg_simple(x, floor) -#define fma(x, y, z) __tg_impl_simple(x, y, z, fma, fmaf, fmal, x, y, z) +#define fma(x, y, z) __tg_simple3(x, y, z, fma) #define fmax(x, y) __tg_simple2(x, y, fmax) #define fmin(x, y) __tg_simple2(x, y, fmin) #define fmod(x, y) __tg_simple2(x, y, fmod) @@ -150,8 +191,8 @@ #define nextafter(x, y) __tg_simple2(x, y, nextafter) #define nexttoward(x, y) __tg_simplev(x, nexttoward, x, y) #define remainder(x, y) __tg_simple2(x, y, remainder) -#define remquo(x, y, z) __tg_impl_simple(x, x, y, remquo, remquof, \ - remquol, x, y, z) +#define remquo(x, y, z) __tg_impl_simple(x, x, y, remquol, remquo, \ + remquof, x, y, z) #define rint(x) __tg_simple(x, rint) #define round(x) __tg_simple(x, round) #define scalbn(x, y) __tg_simplev(x, scalbn, x, y) -- 2.41.0