diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/builtins.c | 332 | ||||
-rw-r--r-- | gcc/emit-rtl.c | 9 | ||||
-rw-r--r-- | gcc/fold-const.c | 40 | ||||
-rw-r--r-- | gcc/real.h | 5 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/builtin-explog-1.c | 185 |
7 files changed, 481 insertions, 106 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 49a3826553e..cbffdfcdbbb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2003-09-09 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> + + * builtins.c (real_dconstp, fold_builtin_logarithm, + fold_builtin_exponent): New, split out from fold_builtin. Also + generalize to add log2, log10, exp2 and exp10/pow10 equivalents. + * emit-rtl.c (dconst3, dconst10, dconstthird): New. + (init_emit_once): Initialize new dconsts, use ARRAY_SIZE in lieu + of hardcoded array size. + * fold-const.c (fold): Add cases for exp2, exp10 and pow10. + (tree_expr_nonnegative_p): Likewise. + * real.h (dconst3, dconst10, dconstthird): New. + Tue Sep 9 22:18:48 CEST 2003 Jan Hubicka <jh@suse.cz> * cgraphunit.c (cgraph_finalize_function): Fix handling of extern diff --git a/gcc/builtins.c b/gcc/builtins.c index 92e6a706514..dfa047f06f5 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -5939,6 +5939,213 @@ fold_builtin_bitop (tree exp) return NULL_TREE; } +/* Return true if EXPR is the real constant contained in VALUE. */ + +static bool +real_dconstp (tree expr, const REAL_VALUE_TYPE *value) +{ + STRIP_NOPS (expr); + + return ((TREE_CODE (expr) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (expr) + && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), *value)) + || (TREE_CODE (expr) == COMPLEX_CST + && real_dconstp (TREE_REALPART (expr), value) + && real_zerop (TREE_IMAGPART (expr)))); +} + +/* A subroutine of fold_builtin to fold the various logarithmic + functions. EXP is the CALL_EXPR of a call to a builtin log* + function. VALUE is the base of the log* function. */ + +static tree +fold_builtin_logarithm (tree exp, const REAL_VALUE_TYPE *value) +{ + tree arglist = TREE_OPERAND (exp, 1); + + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + { + tree fndecl = get_callee_fndecl (exp); + tree type = TREE_TYPE (TREE_TYPE (fndecl)); + tree arg = TREE_VALUE (arglist); + const enum built_in_function fcode = builtin_mathfn_code (arg); + const REAL_VALUE_TYPE value_mode = + real_value_truncate (TYPE_MODE (type), *value); + + /* Optimize log*(1.0) = 0.0. */ + if (real_onep (arg)) + return build_real (type, dconst0); + + /* Optimize logN(N) = 1.0. */ + if (real_dconstp (arg, &value_mode)) + return build_real (type, dconst1); + + /* Special case, optimize logN(expN(x)) = x. */ + if (flag_unsafe_math_optimizations + && ((value == &dconste + && (fcode == BUILT_IN_EXP + || fcode == BUILT_IN_EXPF + || fcode == BUILT_IN_EXPL)) + || (value == &dconst2 + && (fcode == BUILT_IN_EXP2 + || fcode == BUILT_IN_EXP2F + || fcode == BUILT_IN_EXP2L)) + || (value == &dconst10 + && (fcode == BUILT_IN_EXP10 + || fcode == BUILT_IN_EXP10F + || fcode == BUILT_IN_EXP10L)))) + return convert (type, TREE_VALUE (TREE_OPERAND (arg, 1))); + + /* Optimize log*(func()) for various exponential functions. We + want to determine the value "x" and the power "exponent" in + order to transform logN(x**exponent) into exponent*logN(x). */ + if (flag_unsafe_math_optimizations) + { + tree exponent = 0, x = 0; + + switch (fcode) + { + case BUILT_IN_EXP: + case BUILT_IN_EXPF: + case BUILT_IN_EXPL: + /* Prepare to do logN(exp(exponent) -> exponent*logN(e). */ + if (! builtin_dconsts_init) + init_builtin_dconsts (); + x = build_real (type, + real_value_truncate (TYPE_MODE (type), dconste)); + exponent = TREE_VALUE (TREE_OPERAND (arg, 1)); + break; + case BUILT_IN_EXP2: + case BUILT_IN_EXP2F: + case BUILT_IN_EXP2L: + /* Prepare to do logN(exp2(exponent) -> exponent*logN(2). */ + x = build_real (type, dconst2); + exponent = TREE_VALUE (TREE_OPERAND (arg, 1)); + break; + case BUILT_IN_EXP10: + case BUILT_IN_EXP10F: + case BUILT_IN_EXP10L: + case BUILT_IN_POW10: + case BUILT_IN_POW10F: + case BUILT_IN_POW10L: + /* Prepare to do logN(exp10(exponent) -> exponent*logN(10). */ + x = build_real (type, dconst10); + exponent = TREE_VALUE (TREE_OPERAND (arg, 1)); + break; + case BUILT_IN_SQRT: + case BUILT_IN_SQRTF: + case BUILT_IN_SQRTL: + /* Prepare to do logN(sqrt(x) -> 0.5*logN(x). */ + x = TREE_VALUE (TREE_OPERAND (arg, 1)); + exponent = build_real (type, dconsthalf); + break; + case BUILT_IN_CBRT: + case BUILT_IN_CBRTF: + case BUILT_IN_CBRTL: + /* Prepare to do logN(cbrt(x) -> (1/3)*logN(x). */ + x = TREE_VALUE (TREE_OPERAND (arg, 1)); + exponent = build_real (type, real_value_truncate (TYPE_MODE (type), + dconstthird)); + break; + case BUILT_IN_POW: + case BUILT_IN_POWF: + case BUILT_IN_POWL: + /* Prepare to do logN(pow(x,exponent) -> exponent*logN(x). */ + x = TREE_VALUE (TREE_OPERAND (arg, 1)); + exponent = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1))); + break; + default: + break; + } + + /* Now perform the optimization. */ + if (x && exponent) + { + tree logfn; + arglist = build_tree_list (NULL_TREE, x); + logfn = build_function_call_expr (fndecl, arglist); + return fold (build (MULT_EXPR, type, exponent, logfn)); + } + } + } + + return 0; +} + +/* A subroutine of fold_builtin to fold the various exponent + functions. EXP is the CALL_EXPR of a call to a builtin function. + VALUE is the value which will be raised to a power. */ + +static tree +fold_builtin_exponent (tree exp, const REAL_VALUE_TYPE *value) +{ + tree arglist = TREE_OPERAND (exp, 1); + + if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + { + tree fndecl = get_callee_fndecl (exp); + tree type = TREE_TYPE (TREE_TYPE (fndecl)); + tree arg = TREE_VALUE (arglist); + + /* Optimize exp*(0.0) = 1.0. */ + if (real_zerop (arg)) + return build_real (type, dconst1); + + /* Optimize expN(1.0) = N. */ + if (real_onep (arg)) + { + REAL_VALUE_TYPE cst; + + real_convert (&cst, TYPE_MODE (type), value); + return build_real (type, cst); + } + + /* Attempt to evaluate expN(integer) at compile-time. */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (arg)) + { + REAL_VALUE_TYPE cint; + REAL_VALUE_TYPE c; + HOST_WIDE_INT n; + + c = TREE_REAL_CST (arg); + n = real_to_integer (&c); + real_from_integer (&cint, VOIDmode, n, + n < 0 ? -1 : 0, 0); + if (real_identical (&c, &cint)) + { + REAL_VALUE_TYPE x; + + real_powi (&x, TYPE_MODE (type), value, n); + return build_real (type, x); + } + } + + /* Optimize expN(logN(x)) = x. */ + if (flag_unsafe_math_optimizations) + { + const enum built_in_function fcode = builtin_mathfn_code (arg); + + if ((value == &dconste + && (fcode == BUILT_IN_LOG + || fcode == BUILT_IN_LOGF + || fcode == BUILT_IN_LOGL)) + || (value == &dconst2 + && (fcode == BUILT_IN_LOG2 + || fcode == BUILT_IN_LOG2F + || fcode == BUILT_IN_LOG2L)) + || (value == &dconst10 + && (fcode == BUILT_IN_LOG10 + || fcode == BUILT_IN_LOG10F + || fcode == BUILT_IN_LOG10L))) + return convert (type, TREE_VALUE (TREE_OPERAND (arg, 1))); + } + } + + return 0; +} + /* Used by constant folding to eliminate some builtin calls early. EXP is the CALL_EXPR of a call to a builtin function. */ @@ -6076,107 +6283,36 @@ fold_builtin (tree exp) case BUILT_IN_EXP: case BUILT_IN_EXPF: case BUILT_IN_EXPL: - if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - { - enum built_in_function fcode; - tree arg = TREE_VALUE (arglist); - - /* Optimize exp(0.0) = 1.0. */ - if (real_zerop (arg)) - return build_real (type, dconst1); - - /* Optimize exp(1.0) = e. */ - if (real_onep (arg)) - { - REAL_VALUE_TYPE cst; - - if (! builtin_dconsts_init) - init_builtin_dconsts (); - real_convert (&cst, TYPE_MODE (type), &dconste); - return build_real (type, cst); - } - - /* Attempt to evaluate exp at compile-time. */ - if (flag_unsafe_math_optimizations - && TREE_CODE (arg) == REAL_CST - && ! TREE_CONSTANT_OVERFLOW (arg)) - { - REAL_VALUE_TYPE cint; - REAL_VALUE_TYPE c; - HOST_WIDE_INT n; - - c = TREE_REAL_CST (arg); - n = real_to_integer (&c); - real_from_integer (&cint, VOIDmode, n, - n < 0 ? -1 : 0, 0); - if (real_identical (&c, &cint)) - { - REAL_VALUE_TYPE x; - - if (! builtin_dconsts_init) - init_builtin_dconsts (); - real_powi (&x, TYPE_MODE (type), &dconste, n); - return build_real (type, x); - } - } - - /* Optimize exp(log(x)) = x. */ - fcode = builtin_mathfn_code (arg); - if (flag_unsafe_math_optimizations - && (fcode == BUILT_IN_LOG - || fcode == BUILT_IN_LOGF - || fcode == BUILT_IN_LOGL)) - return TREE_VALUE (TREE_OPERAND (arg, 1)); - } - break; - + if (! builtin_dconsts_init) + init_builtin_dconsts (); + return fold_builtin_exponent (exp, &dconste); + case BUILT_IN_EXP2: + case BUILT_IN_EXP2F: + case BUILT_IN_EXP2L: + return fold_builtin_exponent (exp, &dconst2); + case BUILT_IN_EXP10: + case BUILT_IN_EXP10F: + case BUILT_IN_EXP10L: + case BUILT_IN_POW10: + case BUILT_IN_POW10F: + case BUILT_IN_POW10L: + return fold_builtin_exponent (exp, &dconst10); case BUILT_IN_LOG: case BUILT_IN_LOGF: case BUILT_IN_LOGL: - if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) - { - enum built_in_function fcode; - tree arg = TREE_VALUE (arglist); - - /* Optimize log(1.0) = 0.0. */ - if (real_onep (arg)) - return build_real (type, dconst0); - - /* Optimize log(exp(x)) = x. */ - fcode = builtin_mathfn_code (arg); - if (flag_unsafe_math_optimizations - && (fcode == BUILT_IN_EXP - || fcode == BUILT_IN_EXPF - || fcode == BUILT_IN_EXPL)) - return TREE_VALUE (TREE_OPERAND (arg, 1)); - - /* Optimize log(sqrt(x)) = log(x)*0.5. */ - if (flag_unsafe_math_optimizations - && (fcode == BUILT_IN_SQRT - || fcode == BUILT_IN_SQRTF - || fcode == BUILT_IN_SQRTL)) - { - tree logfn = build_function_call_expr (fndecl, - TREE_OPERAND (arg, 1)); - return fold (build (MULT_EXPR, type, logfn, - build_real (type, dconsthalf))); - } - - /* Optimize log(pow(x,y)) = y*log(x). */ - if (flag_unsafe_math_optimizations - && (fcode == BUILT_IN_POW - || fcode == BUILT_IN_POWF - || fcode == BUILT_IN_POWL)) - { - tree arg0, arg1, logfn; - - arg0 = TREE_VALUE (TREE_OPERAND (arg, 1)); - arg1 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1))); - arglist = build_tree_list (NULL_TREE, arg0); - logfn = build_function_call_expr (fndecl, arglist); - return fold (build (MULT_EXPR, type, arg1, logfn)); - } - } + if (! builtin_dconsts_init) + init_builtin_dconsts (); + return fold_builtin_logarithm (exp, &dconste); + break; + case BUILT_IN_LOG2: + case BUILT_IN_LOG2F: + case BUILT_IN_LOG2L: + return fold_builtin_logarithm (exp, &dconst2); + break; + case BUILT_IN_LOG10: + case BUILT_IN_LOG10F: + case BUILT_IN_LOG10L: + return fold_builtin_logarithm (exp, &dconst10); break; case BUILT_IN_TAN: diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 0668cfb20e4..fbd72244b91 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -110,9 +110,12 @@ rtx const_true_rtx; REAL_VALUE_TYPE dconst0; REAL_VALUE_TYPE dconst1; REAL_VALUE_TYPE dconst2; +REAL_VALUE_TYPE dconst3; +REAL_VALUE_TYPE dconst10; REAL_VALUE_TYPE dconstm1; REAL_VALUE_TYPE dconstm2; REAL_VALUE_TYPE dconsthalf; +REAL_VALUE_TYPE dconstthird; /* All references to the following fixed hard registers go through these unique rtl objects. On machines where the frame-pointer and @@ -5414,13 +5417,17 @@ init_emit_once (int line_numbers) REAL_VALUE_FROM_INT (dconst0, 0, 0, double_mode); REAL_VALUE_FROM_INT (dconst1, 1, 0, double_mode); REAL_VALUE_FROM_INT (dconst2, 2, 0, double_mode); + REAL_VALUE_FROM_INT (dconst3, 3, 0, double_mode); + REAL_VALUE_FROM_INT (dconst10, 10, 0, double_mode); REAL_VALUE_FROM_INT (dconstm1, -1, -1, double_mode); REAL_VALUE_FROM_INT (dconstm2, -2, -1, double_mode); dconsthalf = dconst1; dconsthalf.exp--; - for (i = 0; i <= 2; i++) + real_arithmetic (&dconstthird, RDIV_EXPR, &dconst1, &dconst3); + + for (i = 0; i < (int) ARRAY_SIZE (const_tiny_rtx); i++) { REAL_VALUE_TYPE *r = (i == 0 ? &dconst0 : i == 1 ? &dconst1 : &dconst2); diff --git a/gcc/fold-const.c b/gcc/fold-const.c index d5b98fe488d..c9a43e6d7ac 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -6110,10 +6110,20 @@ fold (tree expr) return build_function_call_expr (sqrtfn, arglist); } - /* Optimize exp(x)*exp(y) as exp(x+y). */ - if ((fcode0 == BUILT_IN_EXP && fcode1 == BUILT_IN_EXP) - || (fcode0 == BUILT_IN_EXPF && fcode1 == BUILT_IN_EXPF) - || (fcode0 == BUILT_IN_EXPL && fcode1 == BUILT_IN_EXPL)) + /* Optimize expN(x)*expN(y) as expN(x+y). */ + if (fcode0 == fcode1 + && (fcode0 == BUILT_IN_EXP + || fcode0 == BUILT_IN_EXPF + || fcode0 == BUILT_IN_EXPL + || fcode0 == BUILT_IN_EXP2 + || fcode0 == BUILT_IN_EXP2F + || fcode0 == BUILT_IN_EXP2L + || fcode0 == BUILT_IN_EXP10 + || fcode0 == BUILT_IN_EXP10F + || fcode0 == BUILT_IN_EXP10L + || fcode0 == BUILT_IN_POW10 + || fcode0 == BUILT_IN_POW10F + || fcode0 == BUILT_IN_POW10L)) { tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0); tree arg = build (PLUS_EXPR, type, @@ -6445,10 +6455,19 @@ fold (tree expr) if (flag_unsafe_math_optimizations) { enum built_in_function fcode = builtin_mathfn_code (arg1); - /* Optimize x/exp(y) into x*exp(-y). */ + /* Optimize x/expN(y) into x*expN(-y). */ if (fcode == BUILT_IN_EXP || fcode == BUILT_IN_EXPF - || fcode == BUILT_IN_EXPL) + || fcode == BUILT_IN_EXPL + || fcode == BUILT_IN_EXP2 + || fcode == BUILT_IN_EXP2F + || fcode == BUILT_IN_EXP2L + || fcode == BUILT_IN_EXP10 + || fcode == BUILT_IN_EXP10F + || fcode == BUILT_IN_EXP10L + || fcode == BUILT_IN_POW10 + || fcode == BUILT_IN_POW10F + || fcode == BUILT_IN_POW10L) { tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0); tree arg = build1 (NEGATE_EXPR, type, @@ -8674,6 +8693,15 @@ tree_expr_nonnegative_p (tree t) case BUILT_IN_EXP: case BUILT_IN_EXPF: case BUILT_IN_EXPL: + case BUILT_IN_EXP2: + case BUILT_IN_EXP2F: + case BUILT_IN_EXP2L: + case BUILT_IN_EXP10: + case BUILT_IN_EXP10F: + case BUILT_IN_EXP10L: + case BUILT_IN_POW10: + case BUILT_IN_POW10F: + case BUILT_IN_POW10L: case BUILT_IN_FABS: case BUILT_IN_FABSF: case BUILT_IN_FABSL: diff --git a/gcc/real.h b/gcc/real.h index dbce7bb54f4..0543b8f8f9d 100644 --- a/gcc/real.h +++ b/gcc/real.h @@ -322,14 +322,17 @@ extern void real_ldexp (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, int); /* **** End of software floating point emulator interface macros **** */ -/* Constant real values 0, 1, 2, -1, -2 and 0.5. */ +/* Constant real values 0, 1, 2, 3, 10, -1, -2, 0.5 and 1/3. */ extern REAL_VALUE_TYPE dconst0; extern REAL_VALUE_TYPE dconst1; extern REAL_VALUE_TYPE dconst2; +extern REAL_VALUE_TYPE dconst3; +extern REAL_VALUE_TYPE dconst10; extern REAL_VALUE_TYPE dconstm1; extern REAL_VALUE_TYPE dconstm2; extern REAL_VALUE_TYPE dconsthalf; +extern REAL_VALUE_TYPE dconstthird; /* Function to return a real value (not a tree node) from a given integer constant. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bc34f5b182a..2745abe955a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2003-09-09 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> + + * gcc.dg/torture/builtin-explog-1.c: New testcase. + 2003-09-08 Mark Mitchell <mark@codesourcery.com> * gcc.dg/ia64-types1.c: New test. diff --git a/gcc/testsuite/gcc.dg/torture/builtin-explog-1.c b/gcc/testsuite/gcc.dg/torture/builtin-explog-1.c new file mode 100644 index 00000000000..352f5b037b1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-explog-1.c @@ -0,0 +1,185 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Verify that built-in math function constant folding of log & exp is + correctly performed by the compiler. + + Written by Kaveh Ghazi, 2003-09-05. */ + +/* { dg-do link } */ +/* { dg-options "-ffast-math" } */ + +/* Define "e" with as many bits as found in builtins.c:dconste. */ +#define M_E 2.7182818284590452353602874713526624977572470936999595749669676277241 +#define M_EF 2.7182818284590452353602874713526624977572470936999595749669676277241F +#define M_EL 2.7182818284590452353602874713526624977572470936999595749669676277241L +/* Precision for comparison tests. */ +#define PREC 0.0000001 +#define PRECF 0.0001F +#define PRECL 0.0000000000001L +#define PROTOTYPE(FN) extern double FN(double); extern float FN##f(float); \ + extern long double FN##l(long double); +#define PROTOTYPE2(FN) extern double FN(double, double); \ + extern float FN##f(float, float); \ + extern long double FN##l(long double, long double); + +PROTOTYPE(exp) +PROTOTYPE(exp2) +PROTOTYPE(exp10) +PROTOTYPE(log) +PROTOTYPE(log2) +PROTOTYPE(log10) +PROTOTYPE(pow10) +PROTOTYPE(sqrt) +PROTOTYPE(cbrt) +PROTOTYPE2(pow) + +void test(double d1, double d2, float f1, float f2, + long double ld1, long double ld2) +{ +#define LOG_1(LOG) \ + extern void link_failure_##LOG##_1(void); \ + if (LOG(1.0) != 0.0 || LOG##f(1.0F) != 0.0F || LOG##l(1.0L) != 0.0L) \ + link_failure_##LOG##_1() + + LOG_1(log); + LOG_1(log2); + LOG_1(log10); + +#define LOG_N(LOG, BASE) \ + extern void link_failure_##LOG##_N(void); \ + if (LOG(BASE) != 1.0 || LOG##f(BASE##F) != 1.0F || LOG##l(BASE##L) != 1.0L) \ + link_failure_##LOG##_N() + + LOG_N(log, M_E); + LOG_N(log2, 2.0); + LOG_N(log10, 10.0); + +#define LOGEXP_SAME(LOG, EXP) \ + extern void link_failure_##LOG##_##EXP##_same(void); \ + if (LOG(EXP(d1)) != d1 || LOG##f(EXP##f(f1)) != f1 \ + || LOG##l(EXP##l(ld1)) != ld1) link_failure_##LOG##_##EXP##_same() + + LOGEXP_SAME(log,exp); + LOGEXP_SAME(log2,exp2); + LOGEXP_SAME(log10,exp10); + LOGEXP_SAME(log10,pow10); + +#define LOGEXP(LOG, EXP, BASE) \ + extern void link_failure_##LOG##_##EXP(void); \ + if (LOG(EXP(d1)) != d1*LOG(BASE) || LOG##f(EXP##f(f1)) != f1*LOG##f(BASE##F) \ + || LOG##l(EXP##l(ld1)) != ld1*LOG##l(BASE##L)) link_failure_##LOG##_##EXP() + + LOGEXP(log,exp,M_E); + LOGEXP(log,exp2,2.0); + LOGEXP(log,exp10,10.0); + LOGEXP(log,pow10,10.0); + LOGEXP(log2,exp,M_E); + LOGEXP(log2,exp2,2.0); + LOGEXP(log2,exp10,10.0); + LOGEXP(log2,pow10,10.0); + LOGEXP(log10,exp,M_E); + LOGEXP(log10,exp2,2.0); + LOGEXP(log10,exp10,10.0); + LOGEXP(log10,pow10,10.0); + +#define LOG_SQRT(LOG) \ + extern void link_failure_##LOG##_sqrt(void); \ + if (LOG(sqrt(d1)) != 0.5*LOG(d1) || LOG##f(sqrtf(f1)) != 0.5F*LOG##f(f1) \ + || LOG##l(sqrtl(ld1)) != 0.5L*LOG##l(ld1)) link_failure_##LOG##_sqrt() + + LOG_SQRT(log); + LOG_SQRT(log2); + LOG_SQRT(log10); + +#define LOG_CBRT(LOG) \ + extern void link_failure_##LOG##_cbrt(void); \ + if (LOG(cbrt(d1)) != (1.0/3)*LOG(d1) \ + || LOG##f(cbrtf(f1)) != (1.0F/3)*LOG##f(f1) \ + || LOG##l(cbrtl(ld1)) != (1.0L/3)*LOG##l(ld1)) link_failure_##LOG##_cbrt() + + LOG_CBRT(log); + LOG_CBRT(log2); + LOG_CBRT(log10); + +#define LOGPOW(LOG, POW) \ + extern void link_failure_##LOG##_##POW(void); \ + if (LOG(POW(d1,d2)) != d2*LOG(d1) || LOG##f(POW##f(f1,f2)) != f2*LOG##f(f1) \ + || LOG##l(POW##l(ld1,ld2)) != ld2*LOG##l(ld1)) link_failure_##LOG##_##POW() + + LOGPOW(log,pow); + LOGPOW(log2,pow); + LOGPOW(log10,pow); + +#define EXP_0(EXP) \ + extern void link_failure_##EXP##_0(void); \ + if (EXP(0.0) != 1.0 || EXP##f(0.0F) != 1.0F || EXP##l(0.0L) != 1.0L) \ + link_failure_##EXP##_0() + + EXP_0(exp); + EXP_0(exp2); + EXP_0(exp10); + EXP_0(pow10); + +#define EXP_N(EXP, BASE) \ + extern void link_failure_##EXP##_N(void); \ + if (EXP(1.0) != BASE || EXP##f(1.0F) != BASE##F || EXP##l(1.0L) != BASE##L) \ + link_failure_##EXP##_N() + + EXP_N(exp, M_E); + EXP_N(exp2, 2.0); + EXP_N(exp10, 10.0); + EXP_N(pow10, 10.0); + +#define EXP_INT(EXP, BASE) \ + extern void link_failure_##EXP##_INT(void); \ + if (EXP(5.0) < (BASE)*(BASE)*(BASE)*(BASE)*(BASE) - PREC \ + || EXP(5.0) > (BASE)*(BASE)*(BASE)*(BASE)*(BASE) + PREC \ + || EXP##f(5.0F) < (BASE##F)*(BASE##F)*(BASE##F)*(BASE##F)*(BASE##F) -PRECF \ + || EXP##f(5.0F) > (BASE##F)*(BASE##F)*(BASE##F)*(BASE##F)*(BASE##F) +PRECF \ + || EXP##l(5.0L) < (BASE##L)*(BASE##L)*(BASE##L)*(BASE##L)*(BASE##L) -PRECL \ + || EXP##l(5.0L) > (BASE##L)*(BASE##L)*(BASE##L)*(BASE##L)*(BASE##L) +PRECL) \ + link_failure_##EXP##_INT() + + EXP_INT(exp, M_E); + EXP_INT(exp2, 2.0); + EXP_INT(exp10, 10.0); + EXP_INT(pow10, 10.0); + +#define EXPLOG_SAME(EXP, LOG) \ + extern void link_failure_##EXP##_##LOG##_same(void); \ + if (EXP(LOG(d1)) != d1 || EXP##f(LOG##f(f1)) != f1 \ + || EXP##l(LOG##l(ld1)) != ld1) link_failure_##EXP##_##LOG##_same() + + EXPLOG_SAME(exp, log); + EXPLOG_SAME(exp2, log2); + EXPLOG_SAME(exp10, log10); + EXPLOG_SAME(pow10, log10); + +#define EXPXEXP(EXP) \ + extern void link_failure_##EXP##X##EXP(void); \ + if (EXP(d1)*EXP(d2) != EXP(d1+d2) || EXP##f(f1)*EXP##f(f2) != EXP##f(f1+f2) \ + || EXP##l(ld1)*EXP##l(ld2) != EXP##l(ld1+ld2)) link_failure_##EXP##X##EXP() + + EXPXEXP(exp); + EXPXEXP(exp2); + EXPXEXP(exp10); + EXPXEXP(pow10); + +#define DIVEXP(EXP) \ + extern void link_failure_div1_##EXP(void); \ + if (d1/EXP(d2) != d1*EXP(-d2) || f1/EXP##f(f2) != f1*EXP##f(-f2) \ + || ld1/EXP##l(ld2) != ld1*EXP##l(-ld2)) link_failure_div1_##EXP(); \ + extern void link_failure_div2_##EXP(void); \ + if (EXP(d1)/EXP(d2) != EXP(d1-d2) || EXP##f(f1)/EXP##f(f2) != EXP##f(f1-f2) \ + || EXP##l(ld1)/EXP##l(ld2) != EXP##l(ld1-ld2)) link_failure_div2_##EXP() + + DIVEXP(exp); + DIVEXP(exp2); + DIVEXP(exp10); + DIVEXP(pow10); +} + +int main (void) +{ + return 0; +} |