OSDN Git Service

* builtins.c (real_dconstp, fold_builtin_logarithm,
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 9 Sep 2003 22:10:32 +0000 (22:10 +0000)
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 9 Sep 2003 22:10:32 +0000 (22:10 +0000)
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.

testsuite:
* gcc.dg/torture/builtin-explog-1.c: New testcase.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@71252 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/builtins.c
gcc/emit-rtl.c
gcc/fold-const.c
gcc/real.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/builtin-explog-1.c [new file with mode: 0644]

index 49a3826..cbffdfc 100644 (file)
@@ -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
index 92e6a70..dfa047f 100644 (file)
@@ -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:
index 0668cfb..fbd7224 100644 (file)
@@ -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);
index d5b98fe..c9a43e6 100644 (file)
@@ -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:
index dbce7bb..0543b8f 100644 (file)
@@ -322,14 +322,17 @@ extern void real_ldexp (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, int);
 
 /* **** End of software floating point emulator interface macros **** */
 \f
-/* 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.  */
index bc34f5b..2745abe 100644 (file)
@@ -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 (file)
index 0000000..352f5b0
--- /dev/null
@@ -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;
+}