|
@@ -27,34 +27,67 @@ sizeof(double) == sizeof(long double)
|
|
|
/* return type */
|
|
|
|
|
|
#ifdef __GNUC__
|
|
|
+/*
|
|
|
+the conditional expression (that selects the right function
|
|
|
+for evaluation) should be casted to the return type of the
|
|
|
+selected function (otherwise the result type is determined
|
|
|
+by the conversion rules applied to all the function return
|
|
|
+types so it is long double or long double _Complex)
|
|
|
+
|
|
|
+this cannot be done in c99 (c11 has _Generic that would help
|
|
|
+but is not yet widely supported), so the typeof extension of
|
|
|
+gcc is used and that ?: has special semantics when one of
|
|
|
+the operands is a null pointer constant
|
|
|
+
|
|
|
+unfortunately the standard is overly strict about the
|
|
|
+definition of null pointer constants (current gcc does not
|
|
|
+follow the standard but clang does) so we have to use a hack
|
|
|
+to be able to tell integer and floating-point types apart:
|
|
|
+both gcc and clang evaluate sizeof(void) to 1 even though it
|
|
|
+is a constraint violation, we only use this on clang for now
|
|
|
+*/
|
|
|
+/* predicates that evaluate to integer constant expressions */
|
|
|
+#ifdef __clang__
|
|
|
+/* TODO: __c_IS_FP(1.0) is a constraint violation */
|
|
|
+#define __c_IS_FP(x) (!(sizeof*(__typeof__(0?(int*)0:(void*)__IS_FP(x)))0-1))
|
|
|
+#else
|
|
|
+#define __c_IS_FP(x) __IS_FP(x)
|
|
|
+#endif
|
|
|
+#define __c_IS_CX(x) (__c_IS_FP(x) && sizeof(x) == sizeof((x)+I))
|
|
|
+#define __c_FLTCX(x) (__c_IS_CX(x) && sizeof(x) == sizeof(float complex))
|
|
|
+#define __c_DBLCX(x) (__c_IS_CX(x) && sizeof(x) == sizeof(double complex))
|
|
|
+#define __c_LDBLCX(x) (__c_IS_CX(x) && sizeof(x) == sizeof(long double complex) && sizeof(long double) != sizeof(double))
|
|
|
+/* if c then t else void */
|
|
|
+#define __type1(c,t) __typeof__(*(0?(t*)0:(void*)!(c)))
|
|
|
+/* if c then t1 else t2 */
|
|
|
+#define __type2(c,t1,t2) __typeof__(*(0?(__type1(c,t1)*)0:(__type1(!(c),t2)*)0))
|
|
|
/* cast to double when x is integral, otherwise use typeof(x) */
|
|
|
-#define __RETCAST(x) (__typeof__(*( \
|
|
|
- 0 ? (__typeof__(0 ? (double *)0 : (void *)__IS_FP(x)))0 : \
|
|
|
- (__typeof__(0 ? (__typeof__(x) *)0 : (void *)!__IS_FP(x)))0 )))
|
|
|
-/* 2 args case, consider complex types (for cpow) */
|
|
|
-#define __RETCAST_2(x, y) (__typeof__(*( \
|
|
|
- 0 ? (__typeof__(0 ? (double *)0 : \
|
|
|
- (void *)!((!__IS_FP(x) || !__IS_FP(y)) && __FLT((x)+(y)+1.0f))))0 : \
|
|
|
- 0 ? (__typeof__(0 ? (double complex *)0 : \
|
|
|
- (void *)!((!__IS_FP(x) || !__IS_FP(y)) && __FLTCX((x)+(y)))))0 : \
|
|
|
- (__typeof__(0 ? (__typeof__((x)+(y)) *)0 : \
|
|
|
- (void *)((!__IS_FP(x) || !__IS_FP(y)) && (__FLT((x)+(y)+1.0f) || __FLTCX((x)+(y))))))0 )))
|
|
|
-/* 3 args case, don't consider complex types (fma only) */
|
|
|
-#define __RETCAST_3(x, y, z) (__typeof__(*( \
|
|
|
- 0 ? (__typeof__(0 ? (double *)0 : \
|
|
|
- (void *)!((!__IS_FP(x) || !__IS_FP(y) || !__IS_FP(z)) && __FLT((x)+(y)+(z)+1.0f))))0 : \
|
|
|
- (__typeof__(0 ? (__typeof__((x)+(y)) *)0 : \
|
|
|
- (void *)((!__IS_FP(x) || !__IS_FP(y) || !__IS_FP(z)) && __FLT((x)+(y)+(z)+1.0f))))0 )))
|
|
|
+#define __RETCAST(x) ( \
|
|
|
+ __type2(__c_IS_FP(x), __typeof__(x), double))
|
|
|
+/* 2 args case, should work for complex types (cpow) */
|
|
|
+#define __RETCAST_2(x, y) ( \
|
|
|
+ __type2(__c_IS_FP(x) && __c_IS_FP(y), \
|
|
|
+ __typeof__((x)+(y)), \
|
|
|
+ __typeof__((x)+(y)+1.0)))
|
|
|
+/* 3 args case (fma only) */
|
|
|
+#define __RETCAST_3(x, y, z) ( \
|
|
|
+ __type2(__c_IS_FP(x) && __c_IS_FP(y) && __c_IS_FP(z), \
|
|
|
+ __typeof__((x)+(y)+(z)), \
|
|
|
+ __typeof__((x)+(y)+(z)+1.0)))
|
|
|
/* drop complex from the type of x */
|
|
|
-#define __TO_REAL(x) *( \
|
|
|
- 0 ? (__typeof__(0 ? (double *)0 : (void *)!__DBLCX(x)))0 : \
|
|
|
- 0 ? (__typeof__(0 ? (float *)0 : (void *)!__FLTCX(x)))0 : \
|
|
|
- 0 ? (__typeof__(0 ? (long double *)0 : (void *)!__LDBLCX(x)))0 : \
|
|
|
- (__typeof__(0 ? (__typeof__(x) *)0 : (void *)__IS_CX(x)))0 )
|
|
|
+/* TODO: wrong when sizeof(long double)==sizeof(double) */
|
|
|
+#define __RETCAST_REAL(x) ( \
|
|
|
+ __type2(sizeof(__RETCAST(x)0+I)==sizeof(float complex), float, \
|
|
|
+ __type2(sizeof(__RETCAST(x)0+I)==sizeof(double complex), double, \
|
|
|
+ long double)))
|
|
|
+/* add complex to the type of x */
|
|
|
+#define __RETCAST_CX(x) (__typeof__(__RETCAST(x)0+I))
|
|
|
#else
|
|
|
#define __RETCAST(x)
|
|
|
#define __RETCAST_2(x, y)
|
|
|
#define __RETCAST_3(x, y, z)
|
|
|
+#define __RETCAST_REAL(x)
|
|
|
+#define __RETCAST_CX(x)
|
|
|
#endif
|
|
|
|
|
|
/* function selection */
|
|
@@ -76,12 +109,12 @@ sizeof(double) == sizeof(long double)
|
|
|
__LDBL((x)+(y)) ? fun ## l (x, y) : \
|
|
|
fun(x, y) ))
|
|
|
|
|
|
-#define __tg_complex(fun, x) (__RETCAST((x)+I)( \
|
|
|
+#define __tg_complex(fun, x) (__RETCAST_CX(x)( \
|
|
|
__FLTCX((x)+I) && __IS_FP(x) ? fun ## f (x) : \
|
|
|
__LDBLCX((x)+I) ? fun ## l (x) : \
|
|
|
fun(x) ))
|
|
|
|
|
|
-#define __tg_complex_retreal(fun, x) (__RETCAST(__TO_REAL(x))( \
|
|
|
+#define __tg_complex_retreal(fun, x) (__RETCAST_REAL(x)( \
|
|
|
__FLTCX((x)+I) && __IS_FP(x) ? fun ## f (x) : \
|
|
|
__LDBLCX((x)+I) ? fun ## l (x) : \
|
|
|
fun(x) ))
|
|
@@ -115,7 +148,7 @@ sizeof(double) == sizeof(long double)
|
|
|
__LDBL((x)+(y)) ? powl(x, y) : \
|
|
|
pow(x, y) ))
|
|
|
|
|
|
-#define __tg_real_complex_fabs(x) (__RETCAST(__TO_REAL(x))( \
|
|
|
+#define __tg_real_complex_fabs(x) (__RETCAST_REAL(x)( \
|
|
|
__FLTCX(x) ? cabsf(x) : \
|
|
|
__DBLCX(x) ? cabs(x) : \
|
|
|
__LDBLCX(x) ? cabsl(x) : \
|