OSDN Git Service

PR middle-end/29335
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 29 Oct 2006 02:02:10 +0000 (02:02 +0000)
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 29 Oct 2006 02:02:10 +0000 (02:02 +0000)
* builtins.c (do_mpfr_arg2, fold_builtin_hypot): New.
(fold_builtin_pow): Evaluate constant arguments at compile-time
using MPFR.
(fold_builtin_1): Handle BUILT_IN_ATAN2 and BUILT_IN_HYPOT.
(do_mpfr_ckconv): New helper function.
(do_mpfr_arg1): Use do_mpfr_ckconv.
(do_mpfr_arg2): New.

testsuite:
* gcc.dg/builtins-20.c: Add tests for hypot.
* gcc.dg/torture/builtin-math-2.c (TESTIT2): New.  Add tests for
two-argument builtins.
* gcc.dg/torture/builtin-math-3.c (TESTIT_R): Renamed from
TESTIT2.  Update all callers.
(TESTIT2, TESTIT2_R): New helper macros.
Add testcases for pow, hypot and atan2.

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

gcc/ChangeLog
gcc/builtins.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-20.c
gcc/testsuite/gcc.dg/torture/builtin-math-2.c
gcc/testsuite/gcc.dg/torture/builtin-math-3.c

index 05798ce..0f33ba8 100644 (file)
@@ -1,3 +1,14 @@
+2006-10-28  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       PR middle-end/29335
+       * builtins.c (do_mpfr_arg2, fold_builtin_hypot): New.
+       (fold_builtin_pow): Evaluate constant arguments at compile-time
+       using MPFR.
+       (fold_builtin_1): Handle BUILT_IN_ATAN2 and BUILT_IN_HYPOT.
+       (do_mpfr_ckconv): New helper function.
+       (do_mpfr_arg1): Use do_mpfr_ckconv.
+       (do_mpfr_arg2): New.
+
 2006-10-28  Andrew Pinski  <andrew_pinski@playstation.sony.com>
 
        PR tree-opt/29271
index ecd9461..aedecc9 100644 (file)
@@ -205,6 +205,8 @@ static char target_percent_s[3];
 static char target_percent_s_newline[4];
 static tree do_mpfr_arg1 (tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
                          const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, bool);
+static tree do_mpfr_arg2 (tree, tree, tree,
+                         int (*)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t));
 
 /* Return true if NODE should be considered for inline expansion regardless
    of the optimization level.  This means whenever a function is invoked with
@@ -7662,6 +7664,56 @@ fold_builtin_logarithm (tree fndecl, tree arglist,
   return 0;
 }
 
+/* Fold a builtin function call to hypot, hypotf, or hypotl.  Return
+   NULL_TREE if no simplification can be made.  */
+
+static tree
+fold_builtin_hypot (tree fndecl, tree arglist, tree type)
+{
+  tree arg0 = TREE_VALUE (arglist);
+  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  tree res;
+
+  if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+    return NULL_TREE;
+
+  /* Calculate the result when the argument is a constant.  */
+  if ((res = do_mpfr_arg2 (arg0, arg1, type, mpfr_hypot)))
+    return res;
+  
+  /* If either argument is zero, hypot is fabs of the other.  */
+  if (real_zerop (arg0))
+    return fold_build1 (ABS_EXPR, type, arg1);
+  else if (real_zerop (arg1))
+    return fold_build1 (ABS_EXPR, type, arg0);
+      
+  /* hypot(x,x) -> x*sqrt(2).  */
+  if (operand_equal_p (arg0, arg1, OEP_PURE_SAME))
+    {
+      REAL_VALUE_TYPE sqrt2;
+
+      real_sqrt (&sqrt2, TYPE_MODE (type), &dconst2);
+      return fold_build2 (MULT_EXPR, type, arg0,
+                         build_real (type, sqrt2));
+    }
+
+  /* Transform hypot(-x,y) or hypot(x,-y) or hypot(-x,-y) into
+     hypot(x,y).  */
+  if (TREE_CODE (arg0) == NEGATE_EXPR || TREE_CODE (arg1) == NEGATE_EXPR)
+    {
+      tree narg0 = (TREE_CODE (arg0) == NEGATE_EXPR)
+       ? TREE_OPERAND (arg0, 0) : arg0;
+      tree narg1 = (TREE_CODE (arg1) == NEGATE_EXPR)
+       ? TREE_OPERAND (arg1, 0) : arg1;
+      tree narglist = tree_cons (NULL_TREE, narg0,
+                                build_tree_list (NULL_TREE, narg1));
+      return build_function_call_expr (fndecl, narglist);
+    }
+  
+  return NULL_TREE;
+}
+
+
 /* Fold a builtin function call to pow, powf, or powl.  Return
    NULL_TREE if no simplification can be made.  */
 static tree
@@ -7669,10 +7721,15 @@ fold_builtin_pow (tree fndecl, tree arglist, tree type)
 {
   tree arg0 = TREE_VALUE (arglist);
   tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  tree res;
 
   if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
     return NULL_TREE;
 
+  /* Calculate the result when the argument is a constant.  */
+  if ((res = do_mpfr_arg2 (arg0, arg1, type, mpfr_pow)))
+    return res;
+
   /* Optimize pow(1.0,y) = 1.0.  */
   if (real_onep (arg0))
     return omit_one_operand (type, build_real (type, dconst1), arg1);
@@ -9093,6 +9150,16 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
                             &dconstm1, NULL, false);
     break;
 
+    CASE_FLT_FN (BUILT_IN_ATAN2):
+      if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+       return do_mpfr_arg2 (TREE_VALUE (arglist),
+                            TREE_VALUE (TREE_CHAIN (arglist)),
+                            type, mpfr_atan2);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_HYPOT):
+      return fold_builtin_hypot (fndecl, arglist, type);
+    
     CASE_FLT_FN (BUILT_IN_POW):
       return fold_builtin_pow (fndecl, arglist, type);
 
@@ -11303,6 +11370,43 @@ init_target_chars (void)
   return true;
 }
 
+/* Helper function for do_mpfr_arg*().  Ensure M is a normal number
+   and no overflow/underflow occurred.  INEXACT is true if M was not
+   exacly calculated.  TYPE is the tree type for the result.  This
+   function assumes that you cleared the MPFR flags and then
+   calculated M to see if anything subsequently set a flag prior to
+   entering this function.  Return NULL_TREE if any checks fail.  */
+
+static tree
+do_mpfr_ckconv(mpfr_srcptr m, tree type, int inexact)
+{
+  /* Proceed iff we get a normal number, i.e. not NaN or Inf and no
+     overflow/underflow occurred.  If -frounding-math, proceed iff the
+     result of calling FUNC was exact.  */
+  if (mpfr_number_p (m) && !mpfr_overflow_p() && !mpfr_underflow_p()
+      && (!flag_rounding_math || !inexact))
+    {
+      REAL_VALUE_TYPE rr;
+
+      real_from_mpfr (&rr, m);
+      /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR value,
+        check for overflow/underflow.  If the REAL_VALUE_TYPE is zero
+        but the mpft_t is not, then we underflowed in the
+        conversion.  */
+      if (!real_isnan (&rr) && !real_isinf (&rr)
+         && (rr.cl == rvc_zero) == (mpfr_zero_p (m) != 0))
+        {
+         REAL_VALUE_TYPE rmode;
+
+         real_convert (&rmode, TYPE_MODE (type), &rr);
+         /* Proceed iff the specified mode can hold the value.  */
+         if (real_identical (&rmode, &rr))
+           return build_real (type, rmode);
+       }
+    }
+  return NULL_TREE;
+}
+
 /* If argument ARG is a REAL_CST, call the one-argument mpfr function
    FUNC on it and return the resulting value as a tree with type TYPE.
    If MIN and/or MAX are not NULL, then the supplied ARG must be
@@ -11323,46 +11427,65 @@ do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
 
   if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
     {
-      REAL_VALUE_TYPE r = TREE_REAL_CST (arg);
+      const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg);
 
-      if (!real_isnan (&r) && !real_isinf (&r)
-         && (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , &r, min))
-         && (!max || real_compare (inclusive ? LE_EXPR: LT_EXPR , &r, max)))
+      if (!real_isnan (ra) && !real_isinf (ra)
+         && (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , ra, min))
+         && (!max || real_compare (inclusive ? LE_EXPR: LT_EXPR , ra, max)))
         {
-         const enum machine_mode mode = TYPE_MODE (type);
-         const int prec = REAL_MODE_FORMAT (mode)->p;
+         const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
          int inexact;
          mpfr_t m;
 
          mpfr_init2 (m, prec);
-         mpfr_from_real (m, &r);
+         mpfr_from_real (m, ra);
          mpfr_clear_flags();
          inexact = func (m, m, GMP_RNDN);
-
-         /* Proceed iff we get a normal number, i.e. not NaN or Inf
-            and no overflow/underflow occurred.  If -frounding-math,
-            proceed iff the result of calling FUNC was exact.  */
-         if (mpfr_number_p (m) && !mpfr_overflow_p() && !mpfr_underflow_p()
-             && (!flag_rounding_math || !inexact))
-           {
-             real_from_mpfr (&r, m);
-             /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR
-                value, check for overflow/underflow.  If the
-                REAL_VALUE_TYPE is zero but the mpft_t is not, then
-                we underflowed in the conversion.  */
-             if (!real_isnan (&r) && !real_isinf (&r)
-                 && (r.cl == rvc_zero) == (mpfr_zero_p (m) != 0))
-               {
-                 REAL_VALUE_TYPE rmode;
-                 real_convert (&rmode, mode, &r);
-                 /* Proceed iff the specified mode can hold the value.  */
-                 if (real_identical (&rmode, &r))
-                   result = build_real (type, rmode);
-               }
-           }
+         result = do_mpfr_ckconv (m, type, inexact);
          mpfr_clear (m);
        }
     }
   
   return result;
 }
+
+/* If argument ARG is a REAL_CST, call the two-argument mpfr function
+   FUNC on it and return the resulting value as a tree with type TYPE.
+   The mpfr precision is set to the precision of TYPE.  We assume that
+   function FUNC returns zero if the result could be calculated
+   exactly within the requested precision.  */
+
+static tree
+do_mpfr_arg2 (tree arg1, tree arg2, tree type,
+             int (*func)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t))
+{
+  tree result = NULL_TREE;
+  
+  STRIP_NOPS (arg1);
+  STRIP_NOPS (arg2);
+
+  if (TREE_CODE (arg1) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg1)
+      && TREE_CODE (arg2) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg2))
+    {
+      const REAL_VALUE_TYPE *const ra1 = &TREE_REAL_CST (arg1);
+      const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2);
+
+      if (!real_isnan (ra1) && !real_isinf (ra1)
+         && !real_isnan (ra2) && !real_isinf (ra2))
+        {
+         const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+         int inexact;
+         mpfr_t m1, m2;
+
+         mpfr_inits2 (prec, m1, m2, NULL);
+         mpfr_from_real (m1, ra1);
+         mpfr_from_real (m2, ra2);
+         mpfr_clear_flags();
+         inexact = func (m1, m1, m2, GMP_RNDN);
+         result = do_mpfr_ckconv (m1, type, inexact);
+         mpfr_clears (m1, m2, NULL);
+       }
+    }
+  
+  return result;
+}
index bec28c5..28024ec 100644 (file)
@@ -1,3 +1,13 @@
+2006-10-28  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * gcc.dg/builtins-20.c: Add tests for hypot.
+       * gcc.dg/torture/builtin-math-2.c (TESTIT2): New.  Add tests for
+       two-argument builtins.
+       * gcc.dg/torture/builtin-math-3.c (TESTIT_R): Renamed from
+       TESTIT2.  Update all callers.
+       (TESTIT2, TESTIT2_R): New helper macros.
+       Add testcases for pow, hypot and atan2.
+
 2006-10-28  Andrew Pinski  <andrew_pinski@playstation.sony.com>
 
        PR C++/29295
index 40a29c4..1c8bb9b 100644 (file)
 extern double cos (double);
 extern double sin (double);
 extern double tan (double);
+extern double hypot (double, double);
 extern float cosf (float);
 extern float sinf (float);
 extern float tanf (float);
+extern float hypotf (float, float);
 extern long double cosl (long double);
 extern long double sinl (long double);
 extern long double tanl (long double);
+extern long double hypotl (long double, long double);
 
 extern void link_error(void);
 
@@ -55,6 +58,24 @@ void test2(double x, double y)
 
   if (-sin(x-y) != sin(y-x))
     link_error ();
+
+  if (hypot (x, 0) != __builtin_fabs(x))
+    link_error ();
+
+  if (hypot (0, x) != __builtin_fabs(x))
+    link_error ();
+
+  if (hypot (x, x) != x * __builtin_sqrt(2))
+    link_error ();
+
+  if (hypot (-x, y) != hypot (x, y))
+    link_error ();
+
+  if (hypot (x, -y) != hypot (x, y))
+    link_error ();
+
+  if (hypot (-x, -y) != hypot (x, y))
+    link_error ();
 }
 
 void test1f(float x)
@@ -90,6 +111,24 @@ void test2f(float x, float y)
 
   if (-sinf(x-y) != sinf(y-x))
     link_error ();
+
+  if (hypotf (x, 0) != __builtin_fabsf(x))
+    link_error ();
+
+  if (hypotf (0, x) != __builtin_fabsf(x))
+    link_error ();
+
+  if (hypotf (x, x) != x * __builtin_sqrtf(2))
+    link_error ();
+
+  if (hypotf (-x, y) != hypotf (x, y))
+    link_error ();
+
+  if (hypotf (x, -y) != hypotf (x, y))
+    link_error ();
+
+  if (hypotf (-x, -y) != hypotf (x, y))
+    link_error ();
 }
 
 
@@ -126,6 +165,24 @@ void test2l(long double x, long double y)
 
   if (-sinl(x-y) != sinl(y-x))
     link_error ();
+
+  if (hypotl (x, 0) != __builtin_fabsl(x))
+    link_error ();
+
+  if (hypotl (0, x) != __builtin_fabsl(x))
+    link_error ();
+
+  if (hypotl (x, x) != x * __builtin_sqrtl(2))
+    link_error ();
+
+  if (hypotl (-x, y) != hypotl (x, y))
+    link_error ();
+
+  if (hypotl (x, -y) != hypotl (x, y))
+    link_error ();
+
+  if (hypotl (-x, -y) != hypotl (x, y))
+    link_error ();
 }
 
 int main()
index 8545600..a2213da 100644 (file)
@@ -18,6 +18,12 @@ extern void fool (long double);
   fool (__builtin_##FUNC##l (ARG##L)); \
 } while (0)
 
+#define TESTIT2(FUNC, ARG1, ARG2) do { \
+  foof (__builtin_##FUNC##f (ARG1##F, ARG2##F)); \
+  foo (__builtin_##FUNC (ARG1, ARG2)); \
+  fool (__builtin_##FUNC##l (ARG1##L, ARG2##L)); \
+} while (0)
+
 void bar()
 {
   /* An argument of NaN is not evaluated at compile-time.  */
@@ -83,6 +89,43 @@ void bar()
   /* The log1p arg must be [-1 ... Inf] EXclusive.  */
   TESTIT (log1p, -2.0);
   TESTIT (log1p, -1.0);
+
+  /* An argument of NaN is not evaluated at compile-time.  */
+  foof (__builtin_powf (__builtin_nanf(""), 2.5F));
+  foo (__builtin_pow (__builtin_nan(""), 2.5));
+  fool (__builtin_powl (__builtin_nanl(""), 2.5L));
+  foof (__builtin_powf (2.5F, __builtin_nanf("")));
+  foo (__builtin_pow (2.5, __builtin_nan("")));
+  fool (__builtin_powl (2.5L, __builtin_nanl("")));
+
+  /* An argument of Inf/-Inf is not evaluated at compile-time.  */
+  foof (__builtin_powf (__builtin_inff(), 2.5F));
+  foo (__builtin_pow (__builtin_inf(), 2.5));
+  fool (__builtin_powl (__builtin_infl(), 2.5L));
+  foof (__builtin_powf (-__builtin_inff(), 2.5F));
+  foo (__builtin_pow (-__builtin_inf(), 2.5));
+  fool (__builtin_powl (-__builtin_infl(), 2.5L));
+  foof (__builtin_powf (2.5F, __builtin_inff()));
+  foo (__builtin_pow (2.5, __builtin_inf()));
+  fool (__builtin_powl (2.5L, __builtin_infl()));
+  foof (__builtin_powf (2.5F, -__builtin_inff()));
+  foo (__builtin_pow (2.5, -__builtin_inf()));
+  fool (__builtin_powl (2.5L, -__builtin_infl()));
+
+  /* Check for Inv/NaN return values.  */
+  TESTIT2 (pow, -0.0, -4.5); /* Returns Inf */
+  TESTIT2 (pow, 0.0, -4.5); /* Returns Inf */
+  TESTIT2 (pow, -3.0, -4.5); /* Returns NaN */
+
+  /* Check for overflow/underflow.  */
+  foof (__builtin_powf (__FLT_MAX__, 3.5F));
+  foo (__builtin_pow (__DBL_MAX__, 3.5));
+  fool (__builtin_powl (__LDBL_MAX__, 3.5L));
+  TESTIT2 (pow, 2.0, 0x1p50);
+  foof (__builtin_powf (__FLT_MAX__, -3.5F));
+  foo (__builtin_pow (__DBL_MAX__, -3.5));
+  fool (__builtin_powl (__LDBL_MAX__, -3.5L));
+  TESTIT2 (pow, 2.0, -0x1p50);
 }
 
 /* { dg-final { scan-tree-dump-times "exp2 " 9 "original" } } */
@@ -112,4 +155,7 @@ void bar()
 /* { dg-final { scan-tree-dump-times "log1p " 2 "original" } } */
 /* { dg-final { scan-tree-dump-times "log1pf" 2 "original" } } */
 /* { dg-final { scan-tree-dump-times "log1pl" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "pow " 13 "original" } } */
+/* { dg-final { scan-tree-dump-times "powf" 13 "original" } } */
+/* { dg-final { scan-tree-dump-times "powl" 13 "original" } } */
 /* { dg-final { cleanup-tree-dump "original" } } */
index e3c9e98..3efe021 100644 (file)
@@ -23,8 +23,8 @@ extern void link_error(int);
     link_error(__LINE__); \
   } while (0);
 
-/* Test that (LOW) < FUNC(ARG) < (HI).  */
-#define TESTIT2(FUNC,ARG,LOW,HI) do { \
+/* Range test, check that (LOW) < FUNC(ARG) < (HI).  */
+#define TESTIT_R(FUNC,ARG,LOW,HI) do { \
   if (__builtin_##FUNC##f(ARG) <= (LOW) || __builtin_##FUNC##f(ARG) >= (HI)) \
     link_error(__LINE__); \
   if (__builtin_##FUNC(ARG) <= (LOW) || __builtin_##FUNC(ARG) >= (HI)) \
@@ -33,70 +33,93 @@ extern void link_error(int);
     link_error(__LINE__); \
   } while (0);
 
+/* Test that FUNC(ARG1, ARG2) == (RES).  */
+#define TESTIT2(FUNC,ARG1,ARG2,RES) do { \
+  if (__builtin_##FUNC##f(ARG1##F, ARG2##F) != RES##F) \
+    link_error(__LINE__); \
+  if (__builtin_##FUNC(ARG1, ARG2) != RES) \
+    link_error(__LINE__); \
+  if (__builtin_##FUNC##l(ARG1##L, ARG2##L) != RES##L) \
+    link_error(__LINE__); \
+  } while (0);
+
+/* Range test, check that (LOW) < FUNC(ARG1,ARG2) < (HI).  */
+#define TESTIT2_R(FUNC,ARG1,ARG2,LOW,HI) do { \
+  if (__builtin_##FUNC##f(ARG1, ARG2) <= (LOW) \
+      || __builtin_##FUNC##f(ARG1, ARG2) >= (HI)) \
+    link_error(__LINE__); \
+  if (__builtin_##FUNC(ARG1, ARG2) <= (LOW) \
+      || __builtin_##FUNC(ARG1, ARG2) >= (HI)) \
+    link_error(__LINE__); \
+  if (__builtin_##FUNC##l(ARG1, ARG2) <= (LOW) \
+      || __builtin_##FUNC##l(ARG1, ARG2) >= (HI)) \
+    link_error(__LINE__); \
+  } while (0);
+
 int main (void)
 {
-  TESTIT2 (asin, -1.0, -3.15/2.0, -3.14/2.0); /* asin(-1) == -pi/2 */
+  TESTIT_R (asin, -1.0, -3.15/2.0, -3.14/2.0); /* asin(-1) == -pi/2 */
   TESTIT (asin, 0.0, 0.0); /* asin(0) == 0 */
   TESTIT (asin, -0.0, -0.0); /* asin(-0) == -0 */
-  TESTIT2 (asin, 1.0, 3.14/2.0, 3.15/2.0); /* asin(1) == pi/2 */
+  TESTIT_R (asin, 1.0, 3.14/2.0, 3.15/2.0); /* asin(1) == pi/2 */
 
-  TESTIT2 (acos, -1.0, 3.14, 3.15); /* acos(-1) == pi */
-  TESTIT2 (acos, 0.0, 3.14/2.0, 3.15/2.0); /* acos(0) == pi/2 */
-  TESTIT2 (acos, -0.0, 3.14/2.0, 3.15/2.0); /* acos(-0) == pi/2 */
+  TESTIT_R (acos, -1.0, 3.14, 3.15); /* acos(-1) == pi */
+  TESTIT_R (acos, 0.0, 3.14/2.0, 3.15/2.0); /* acos(0) == pi/2 */
+  TESTIT_R (acos, -0.0, 3.14/2.0, 3.15/2.0); /* acos(-0) == pi/2 */
   TESTIT (acos, 1.0, 0.0); /* acos(1) == 0 */
 
-  TESTIT2 (atan, -1.0, -3.15/4.0, -3.14/4.0); /* atan(-1) == -pi/4 */
+  TESTIT_R (atan, -1.0, -3.15/4.0, -3.14/4.0); /* atan(-1) == -pi/4 */
   TESTIT (atan, 0.0, 0.0); /* atan(0) == 0 */
   TESTIT (atan, -0.0, -0.0); /* atan(-0) == -0 */
-  TESTIT2 (atan, 1.0, 3.14/4.0, 3.15/4.0); /* atan(1) == pi/4 */
+  TESTIT_R (atan, 1.0, 3.14/4.0, 3.15/4.0); /* atan(1) == pi/4 */
 
-  TESTIT2 (asinh, -1.0, -0.89, -0.88); /* asinh(-1) == -0.881... */
+  TESTIT_R (asinh, -1.0, -0.89, -0.88); /* asinh(-1) == -0.881... */
   TESTIT (asinh, 0.0, 0.0); /* asinh(0) == 0 */
   TESTIT (asinh, -0.0, -0.0); /* asinh(-0) == -0 */
-  TESTIT2 (asinh, 1.0, 0.88, 0.89); /* asinh(1) == 0.881... */
+  TESTIT_R (asinh, 1.0, 0.88, 0.89); /* asinh(1) == 0.881... */
 
   TESTIT (acosh, 1.0, 0.0); /* acosh(1) == 0. */
-  TESTIT2 (acosh, 2.0, 1.31, 1.32); /* acosh(2) == 1.316... */
+  TESTIT_R (acosh, 2.0, 1.31, 1.32); /* acosh(2) == 1.316... */
 
-  TESTIT2 (atanh, -0.5, -0.55, -0.54); /* atanh(-0.5) == -0.549... */
+  TESTIT_R (atanh, -0.5, -0.55, -0.54); /* atanh(-0.5) == -0.549... */
   TESTIT (atanh, 0.0, 0.0); /* atanh(0) == 0 */
   TESTIT (atanh, -0.0, -0.0); /* atanh(-0) == -0 */
-  TESTIT2 (atanh, 0.5, 0.54, 0.55); /* atanh(0.5) == 0.549... */
+  TESTIT_R (atanh, 0.5, 0.54, 0.55); /* atanh(0.5) == 0.549... */
 
-  TESTIT2 (sin, -1.0, -0.85, -0.84); /* sin(-1) == -0.841... */
+  TESTIT_R (sin, -1.0, -0.85, -0.84); /* sin(-1) == -0.841... */
   TESTIT (sin, 0.0, 0.0); /* sin(0) == 0 */
   TESTIT (sin, -0.0, -0.0); /* sin(-0) == -0 */
-  TESTIT2 (sin, 1.0, 0.84, 0.85); /* sin(1) == 0.841... */
+  TESTIT_R (sin, 1.0, 0.84, 0.85); /* sin(1) == 0.841... */
 
-  TESTIT2 (cos, -1.0, 0.54, 0.55); /* cos(-1) == 0.5403... */
+  TESTIT_R (cos, -1.0, 0.54, 0.55); /* cos(-1) == 0.5403... */
   TESTIT (cos, 0.0, 1.0); /* cos(0) == 1 */
   TESTIT (cos, -0.0, 1.0); /* cos(-0) == 1 */
-  TESTIT2 (cos, 1.0, 0.54, 0.55); /* cos(1) == 0.5403... */
+  TESTIT_R (cos, 1.0, 0.54, 0.55); /* cos(1) == 0.5403... */
 
-  TESTIT2 (tan, -1.0, -1.56, 1.55); /* tan(-1) == -1.557... */
+  TESTIT_R (tan, -1.0, -1.56, 1.55); /* tan(-1) == -1.557... */
   TESTIT (tan, 0.0, 0.0); /* tan(0) == 0 */
   TESTIT (tan, -0.0, -0.0); /* tan(-0) == -0 */
-  TESTIT2 (tan, 1.0, 1.55, 1.56); /* tan(1) == 1.557... */
+  TESTIT_R (tan, 1.0, 1.55, 1.56); /* tan(1) == 1.557... */
 
-  TESTIT2 (sinh, -1.0, -1.18, -1.17); /* sinh(-1) == -1.175... */
+  TESTIT_R (sinh, -1.0, -1.18, -1.17); /* sinh(-1) == -1.175... */
   TESTIT (sinh, 0.0, 0.0); /* sinh(0) == 0 */
   TESTIT (sinh, -0.0, -0.0); /* sinh(-0) == -0 */
-  TESTIT2 (sinh, 1.0, 1.17, 1.18); /* sinh(1) == 1.175... */
+  TESTIT_R (sinh, 1.0, 1.17, 1.18); /* sinh(1) == 1.175... */
 
-  TESTIT2 (cosh, -1.0, 1.54, 1.55); /* cosh(-1) == 1.543... */
+  TESTIT_R (cosh, -1.0, 1.54, 1.55); /* cosh(-1) == 1.543... */
   TESTIT (cosh, 0.0, 1.0); /* cosh(0) == 1 */
   TESTIT (cosh, -0.0, 1.0); /* cosh(-0) == 1 */
-  TESTIT2 (cosh, 1.0, 1.54, 1.55); /* cosh(1) == 1.543... */
+  TESTIT_R (cosh, 1.0, 1.54, 1.55); /* cosh(1) == 1.543... */
 
-  TESTIT2 (tanh, -1.0, -0.77, -0.76); /* tanh(-1) == -0.761... */
+  TESTIT_R (tanh, -1.0, -0.77, -0.76); /* tanh(-1) == -0.761... */
   TESTIT (tanh, -0.0, -0.0); /* tanh(-0) == -0 */
   TESTIT (tanh, 0.0, 0.0); /* tanh(0) == 0 */
-  TESTIT2 (tanh, 1.0, 0.76, 0.77); /* tanh(1) == 0.761... */
+  TESTIT_R (tanh, 1.0, 0.76, 0.77); /* tanh(1) == 0.761... */
 
-  TESTIT2 (exp, -1.0, 0.36, 0.37); /* exp(-1) == 1/e */
+  TESTIT_R (exp, -1.0, 0.36, 0.37); /* exp(-1) == 1/e */
   TESTIT (exp, -0.0, 1.0); /* exp(-0) == 1 */
   TESTIT (exp, 0.0, 1.0); /* exp(0) == 1 */
-  TESTIT2 (exp, 1.0, 2.71, 2.72); /* exp(1) == e */
+  TESTIT_R (exp, 1.0, 2.71, 2.72); /* exp(1) == e */
 
   TESTIT (exp2, -1.0, 0.5); /* exp2(-1) == 1/2 */
   TESTIT (exp2, -0.0, 1.0); /* exp2(-0) == 1 */
@@ -113,14 +136,14 @@ int main (void)
   TESTIT (pow10, 0.0, 1.0); /* pow10(0) == 1 */
   TESTIT (pow10, 1.0, 10.0); /* pow10(1) == 10 */
 
-  TESTIT2 (expm1, -1.0, -0.64, -0.63); /* expm1(-1) == 1/e - 1 */
+  TESTIT_R (expm1, -1.0, -0.64, -0.63); /* expm1(-1) == 1/e - 1 */
   TESTIT (expm1, -0.0, -0.0); /* expm1(-0) == 0 */
   TESTIT (expm1, 0.0, 0.0); /* expm1(0) == 0 */
-  TESTIT2 (expm1, 1.0, 1.71, 1.72); /* expm1(1) == e - 1 */
+  TESTIT_R (expm1, 1.0, 1.71, 1.72); /* expm1(1) == e - 1 */
 
   TESTIT (log, 1.0, 0.0); /* log(1) == 0 */
-  TESTIT2 (log, M_E, 0.99, 1.01); /* log(e) == 1.000... */
-  TESTIT2 (log, M_E*M_E, 1.99, 2.01); /* log(e*e) == 2.000... */
+  TESTIT_R (log, M_E, 0.99, 1.01); /* log(e) == 1.000... */
+  TESTIT_R (log, M_E*M_E, 1.99, 2.01); /* log(e*e) == 2.000... */
 
   TESTIT (log2, 1.0, 0.0); /* log2(1) == 0 */
   TESTIT (log2, 2.0, 1.0); /* log2(2) == 1 */
@@ -132,8 +155,8 @@ int main (void)
 
   TESTIT (log1p, 0.0, 0.0); /* log1p(0) == 0 */
   TESTIT (log1p, -0.0, -0.0); /* log1p(-0) == -0 */
-  TESTIT2 (log1p, M_E-1, 0.99, 1.01); /* log1p(e-1) == 1.000... */
-  TESTIT2 (log1p, M_E*M_E-1, 1.99, 2.01); /* log1p(e*e-1) == 2.000... */
+  TESTIT_R (log1p, M_E-1, 0.99, 1.01); /* log1p(e-1) == 1.000... */
+  TESTIT_R (log1p, M_E*M_E-1, 1.99, 2.01); /* log1p(e*e-1) == 2.000... */
 
   TESTIT (cbrt, -0.0, -0.0); /* cbrt(-0) == -0 */
   TESTIT (cbrt, 0.0, 0.0); /* cbrt(0) == 0 */
@@ -144,13 +167,41 @@ int main (void)
 
   TESTIT (erf, -0.0, -0.0); /* erf(-0) == -0 */
   TESTIT (erf, 0.0, 0.0); /* erf(0) == 0 */
-  TESTIT2 (erf, 1.0, 0.84, 0.85); /* erf(1) == 0.842... */
-  TESTIT2 (erf, -1.0, -0.85, -0.84); /* erf(-1) == -0.842... */
+  TESTIT_R (erf, 1.0, 0.84, 0.85); /* erf(1) == 0.842... */
+  TESTIT_R (erf, -1.0, -0.85, -0.84); /* erf(-1) == -0.842... */
 
   TESTIT (erfc, -0.0, 1.0); /* erfc(-0) == 1 */
   TESTIT (erfc, 0.0, 1.0); /* erfc(0) == 1 */
-  TESTIT2 (erfc, 1.0, 0.15, 0.16); /* erfc(1) == 0.157... */
-  TESTIT2 (erfc, -1.0, 1.84, 1.85); /* erfc(-1) == 1.842... */
+  TESTIT_R (erfc, 1.0, 0.15, 0.16); /* erfc(1) == 0.157... */
+  TESTIT_R (erfc, -1.0, 1.84, 1.85); /* erfc(-1) == 1.842... */
+
+  TESTIT2 (pow, 3.0, 4.0, 81.0); /* pow(3,4) == 81 */
+  TESTIT2 (pow, -3.0, 5.0, -243.0); /* pow(-3,5) == -243 */
+  TESTIT2 (pow, 16.0, 0.25, 2.0); /* pow(16,1/4) == 2 */
+  TESTIT2 (pow, 4.0, -2.0, 0.0625); /* pow(4,-2) == 1/16 */
+  TESTIT2 (pow, -2.0, -3.0, -0.125); /* pow(-2,-3) == -1/8 */
+  TESTIT2_R (pow, -1.5, -3.0, -0.297, -0.296); /* pow(-1.5,-3) == -1/3.375 */
+
+  TESTIT2 (hypot, 0.0, 0.0, 0.0); /* hypot(0,0) == 0 */
+  TESTIT2 (hypot, -0.0, 0.0, 0.0); /* hypot(-0,0) == 0 */
+  TESTIT2 (hypot, 0.0, -0.0, 0.0); /* hypot(0,-0) == 0 */
+  TESTIT2 (hypot, -0.0, -0.0, 0.0); /* hypot(-0,-0) == 0 */
+  TESTIT2 (hypot, 3.0, 4.0, 5.0); /* hypot(3,4) == 5 */
+  TESTIT2 (hypot, -3.0, 4.0, 5.0); /* hypot(-3,4) == 5 */
+  TESTIT2 (hypot, 3.0, -4.0, 5.0); /* hypot(3,-4) == 5 */
+  TESTIT2 (hypot, -3.0, -4.0, 5.0); /* hypot(-3,-4) == 5 */
+  TESTIT2_R (hypot, 4.0, 5.0, 6.40, 6.41); /* hypot(4,5) == 6.403... */
+
+  TESTIT2 (atan2, 0.0, 0.0, 0.0) /* atan2(0,0) == 0 */
+  TESTIT2 (atan2, -0.0, 0.0, -0.0) /* atan2(-0,0) == -0 */
+  TESTIT2_R (atan2, 0.0, -0.0, 3.14, 3.15) /* atan2(0,-0) == pi */
+  TESTIT2_R (atan2, -0.0, -0.0, -3.15, -3.14) /* atan2(-0,-0) == -pi */
+  TESTIT2_R (atan2, 0.0, -1.0, 3.14, 3.15) /* atan2(0,-1) == pi */
+  TESTIT2_R (atan2, -0.0, -1.0, -3.15, -3.14) /* atan2(-0,-1) == -pi */
+  TESTIT2 (atan2, 0.0, 1.0, 0.0) /* atan2(0,1) == 0 */
+  TESTIT2 (atan2, -0.0, 1.0, -0.0) /* atan2(-0,1) == -0 */
+  TESTIT2_R (atan2, -1.0, 0.0, -1.58, -1.57) /* atan2(-1,0) == -pi/2 */
+  TESTIT2_R (atan2, 1.0, 0.0, 1.57, 1.58) /* atan2(1,0) == pi/2 */
 
   return 0;
 }