]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
fold-const.c (fold <ABS_EXPR>): Re-fold the result of folding fabs(-x) into fabs(x).
authorRoger Sayle <sayle@gcc.gnu.org>
Fri, 6 Jun 2003 12:36:26 +0000 (12:36 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Fri, 6 Jun 2003 12:36:26 +0000 (12:36 +0000)
* fold-const.c (fold <ABS_EXPR>):  Re-fold the result of folding
fabs(-x) into fabs(x).  Use tree_expr_nonnegative_p to determine
when the ABS_EXPR (fabs or abs) is not required.
   (tree_expr_nonnegative_p): Move the logic that sqrt and exp are
always nonnegative from fold to here.  Additionally, cabs and fabs
are always non-negative, and pow and atan are non-negative if
their first argument is non-negative.

* builtins.c (fold_builtin_cabs): New function to fold cabs{,f,l}.
Evaluate cabs of a constant at compile-time.  Convert cabs of a
non-complex argument into fabs.  Convert cabs(z) into
sqrt(z.r*z.r + z.i*z.i) at the tree-level with -ffast-math or
-funsafe-math-optimizations or -ffast-math.
(fold_builtin): Convert BUILT_IN_FABS{,F,L} into an ABS_EXPR.
Fold BUILT_IN_CABS{,F,L} using fold_builtin_cabs.

* gcc.dg/builtins-2.c: Add some more tests.
* gcc.dg/builtins-18.c: New test case.
* gcc.dg/builtins-19.c: New test case.

From-SVN: r67541

gcc/ChangeLog
gcc/builtins.c
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-18.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtins-19.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtins-2.c

index 208fff0b0c56c837234b615c422e26f7c9b8296b..cc46df80755ce57fae2b26e6e58f9c40295759de 100644 (file)
@@ -1,3 +1,21 @@
+2003-06-06  Roger Sayle  <roger@eyesopen.com>
+
+       * fold-const.c (fold <ABS_EXPR>):  Re-fold the result of folding
+       fabs(-x) into fabs(x).  Use tree_expr_nonnegative_p to determine
+       when the ABS_EXPR (fabs or abs) is not required.
+       (tree_expr_nonnegative_p): Move the logic that sqrt and exp are
+       always nonnegative from fold to here.  Additionally, cabs and fabs
+       are always non-negative, and pow and atan are non-negative if
+       their first argument is non-negative.
+
+       * builtins.c (fold_builtin_cabs): New function to fold cabs{,f,l}.
+       Evaluate cabs of a constant at compile-time.  Convert cabs of a
+       non-complex argument into fabs.  Convert cabs(z) into
+       sqrt(z.r*z.r + z.i*z.i) at the tree-level with -ffast-math or
+       -funsafe-math-optimizations or -ffast-math.
+       (fold_builtin): Convert BUILT_IN_FABS{,F,L} into an ABS_EXPR.
+       Fold BUILT_IN_CABS{,F,L} using fold_builtin_cabs.
+
 Thu Jun  5 20:51:09 CEST 2003  Jan Hubicka  <jh@suse.cz>
 
        * sourcebuild.texi (Front End Directory): Document new hooks.
@@ -5,7 +23,8 @@ Thu Jun  5 20:51:09 CEST 2003  Jan Hubicka  <jh@suse.cz>
 Fri Jun  6 11:02:35 CEST 2003  Jan Hubicka  <jh@suse.cz>
 
        * function.c (FLOOR_ROUND, CEIL_ROUND): Fix.
-       * i386.md (gen_pro_epilogue_adjust_stack): Deal with gigantic stack frames.
+       * i386.md (gen_pro_epilogue_adjust_stack): Deal with gigantic
+       stack frames.
        (pro_epilogue_adjust_stack_rex64_2): New pattern
 
 Fri Jun  6 11:03:14 CEST 2003  Jan Hubicka  <jh@suse.cz>
index b227ffbcd2c527699b1656cf7e4ce50569169bdc..79d46bce2a0e9fc3d6e72fb6c7d0c101710fe64b 100644 (file)
@@ -177,6 +177,7 @@ static bool readonly_data_expr              PARAMS ((tree));
 static rtx expand_builtin_fabs         PARAMS ((tree, rtx, rtx));
 static rtx expand_builtin_cabs         PARAMS ((tree, rtx));
 static void init_builtin_dconsts       PARAMS ((void));
+static tree fold_builtin_cabs          PARAMS ((tree, tree, tree));
 
 /* Initialize mathematical constants for constant folding builtins.
    These constants need to be given to atleast 160 bits precision.  */
@@ -5135,6 +5136,92 @@ fold_trunc_transparent_mathfn (exp)
   return 0;
 }
 
+/* Fold function call to builtin cabs, cabsf or cabsl.  FNDECL is the
+   function's DECL, ARGLIST is the argument list and TYPE is the return
+   type.  Return NULL_TREE if no simplification can be made.  */
+
+static tree
+fold_builtin_cabs (fndecl, arglist, type)
+     tree fndecl, arglist, type;
+{
+  tree arg;
+
+  if (!arglist || TREE_CHAIN (arglist))
+    return NULL_TREE;
+
+  arg = TREE_VALUE (arglist);
+  if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
+    return NULL_TREE;
+
+  /* Evaluate cabs of a constant at compile-time.  */
+  if (flag_unsafe_math_optimizations
+      && TREE_CODE (arg) == COMPLEX_CST
+      && TREE_CODE (TREE_REALPART (arg)) == REAL_CST
+      && TREE_CODE (TREE_IMAGPART (arg)) == REAL_CST
+      && ! TREE_CONSTANT_OVERFLOW (TREE_REALPART (arg))
+      && ! TREE_CONSTANT_OVERFLOW (TREE_IMAGPART (arg)))
+    {
+      REAL_VALUE_TYPE r, i;
+
+      r = TREE_REAL_CST (TREE_REALPART (arg));
+      i = TREE_REAL_CST (TREE_IMAGPART (arg));
+
+      real_arithmetic (&r, MULT_EXPR, &r, &r);
+      real_arithmetic (&i, MULT_EXPR, &i, &i);
+      real_arithmetic (&r, PLUS_EXPR, &r, &i);
+      if (real_sqrt (&r, TYPE_MODE (type), &r)
+         || ! flag_trapping_math)
+       return build_real (type, r);
+    }
+
+  /* If either part is zero, cabs is fabs of the other.  */
+  if (TREE_CODE (arg) == COMPLEX_EXPR
+      && real_zerop (TREE_OPERAND (arg, 0)))
+    return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 1)));
+  if (TREE_CODE (arg) == COMPLEX_EXPR
+      && real_zerop (TREE_OPERAND (arg, 1)))
+    return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 0)));
+
+  if (flag_unsafe_math_optimizations)
+    {
+      enum built_in_function fcode;
+      tree sqrtfn;
+
+      fcode = DECL_FUNCTION_CODE (fndecl);
+      if (fcode == BUILT_IN_CABS)
+       sqrtfn = implicit_built_in_decls[BUILT_IN_SQRT];
+      else if (fcode == BUILT_IN_CABSF)
+       sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTF];
+      else if (fcode == BUILT_IN_CABSL)
+       sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTL];
+      else
+       sqrtfn = NULL_TREE;
+
+      if (sqrtfn != NULL_TREE)
+       {
+         tree rpart, ipart, result, arglist;
+
+         rpart = fold (build1 (REALPART_EXPR, type, arg));
+         ipart = fold (build1 (IMAGPART_EXPR, type, arg));
+
+         rpart = save_expr (rpart);
+         ipart = save_expr (ipart);
+
+         result = fold (build (PLUS_EXPR, type,
+                               fold (build (MULT_EXPR, type,
+                                            rpart, rpart)),
+                               fold (build (MULT_EXPR, type,
+                                            ipart, ipart))));
+
+         arglist = build_tree_list (NULL_TREE, result);
+         return build_function_call_expr (sqrtfn, arglist);
+       }
+    }
+
+  return NULL_TREE;
+}
+
 /* Used by constant folding to eliminate some builtin calls early.  EXP is
    the CALL_EXPR of a call to a builtin function.  */
 
@@ -5171,6 +5258,18 @@ fold_builtin (exp)
        }
       break;
 
+    case BUILT_IN_FABS:
+    case BUILT_IN_FABSF:
+    case BUILT_IN_FABSL:
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return fold (build1 (ABS_EXPR, type, TREE_VALUE (arglist)));
+      break;
+
+    case BUILT_IN_CABS:
+    case BUILT_IN_CABSF:
+    case BUILT_IN_CABSL:
+      return fold_builtin_cabs (fndecl, arglist, type);
+
     case BUILT_IN_SQRT:
     case BUILT_IN_SQRTF:
     case BUILT_IN_SQRTL:
index e81e8090cf00207c0bf9fb9e5a0cc9fe82a9fd31..aa99e40aaac55548afcc27f4b19e9df82fd05d34 100644 (file)
@@ -5405,29 +5405,19 @@ fold (expr)
                                REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
            }
        }
-      else if (TREE_CODE (arg0) == ABS_EXPR || TREE_CODE (arg0) == NEGATE_EXPR)
-       return build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0));
+      else if (TREE_CODE (arg0) == NEGATE_EXPR)
+       return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0)));
       /* Convert fabs((double)float) into (double)fabsf(float).  */
       else if (TREE_CODE (arg0) == NOP_EXPR
               && TREE_CODE (type) == REAL_TYPE)
        {
          tree targ0 = strip_float_extensions (arg0);
          if (targ0 != arg0)
-           return convert (type, build1 (ABS_EXPR, TREE_TYPE (targ0), targ0));
-                          
-       }
-      else
-       {
-         /* fabs(sqrt(x)) = sqrt(x) and fabs(exp(x)) = exp(x).  */
-         enum built_in_function fcode = builtin_mathfn_code (arg0);
-         if (fcode == BUILT_IN_SQRT
-             || fcode == BUILT_IN_SQRTF
-             || fcode == BUILT_IN_SQRTL
-             || fcode == BUILT_IN_EXP
-             || fcode == BUILT_IN_EXPF
-             || fcode == BUILT_IN_EXPL)
-           t = arg0;
+           return convert (type, fold (build1 (ABS_EXPR, TREE_TYPE (targ0),
+                                               targ0)));
        }
+      else if (tree_expr_nonnegative_p (arg0))
+       return arg0;
       return t;
 
     case CONJ_EXPR:
@@ -7928,6 +7918,47 @@ tree_expr_nonnegative_p (t)
     case RTL_EXPR:
       return rtl_expr_nonnegative_p (RTL_EXPR_RTL (t));
 
+    case CALL_EXPR:
+      if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
+       {
+         tree fndecl = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
+         tree arglist = TREE_OPERAND (t, 1);
+         if (TREE_CODE (fndecl) == FUNCTION_DECL
+             && DECL_BUILT_IN (fndecl)
+             && DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_MD)
+           switch (DECL_FUNCTION_CODE (fndecl))
+             {
+             case BUILT_IN_CABS:
+             case BUILT_IN_CABSL:
+             case BUILT_IN_CABSF:
+             case BUILT_IN_EXP:
+             case BUILT_IN_EXPF:
+             case BUILT_IN_EXPL:
+             case BUILT_IN_FABS:
+             case BUILT_IN_FABSF:
+             case BUILT_IN_FABSL:
+             case BUILT_IN_SQRT:
+             case BUILT_IN_SQRTF:
+             case BUILT_IN_SQRTL:
+               return 1;
+
+             case BUILT_IN_ATAN:
+             case BUILT_IN_ATANF:
+             case BUILT_IN_ATANL:
+               return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+
+             case BUILT_IN_POW:
+             case BUILT_IN_POWF:
+             case BUILT_IN_POWL:
+               return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+
+             default:
+               break;
+             }
+       }
+
+      /* ... fall through ... */
+
     default:
       if (truth_value_p (TREE_CODE (t)))
        /* Truth values evaluate to 0 or 1, which is nonnegative.  */
index 0adc2da05f54a70f11c27293c41dc2598ae1fdae..0454ea51aa1ab546ce6ef6e74cd54776e082bd90 100644 (file)
@@ -1,3 +1,9 @@
+2003-06-06  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.dg/builtins-2.c: Add some more tests.
+       * gcc.dg/builtins-18.c: New test case.
+       * gcc.dg/builtins-19.c: New test case.
+
 2003-06-06  Roger Sayle  <roger@eyesopen.com>
            Jim Wilson  <wilson@tuliptree.org>
 
diff --git a/gcc/testsuite/gcc.dg/builtins-18.c b/gcc/testsuite/gcc.dg/builtins-18.c
new file mode 100644 (file)
index 0000000..86338c0
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright (C) 2003 Free Software Foundation.
+
+   Check that built-in cabs, cabsf and cabsl functions don't
+   break anything and produces the expected results.
+
+   Written by Roger Sayle, 1st June 2003.  */
+
+/* { dg-do link } */
+/* { dg-options "-O2 -ffast-math" } */
+
+extern void link_error(void);
+
+extern float cabsf (float _Complex);
+extern double cabs (double _Complex);
+extern long double cabsl (long double _Complex);
+
+int
+main (void)
+{
+  /* For each type, test both runtime and compile time (constant folding)
+     optimization.  */
+  float _Complex fc = 3.0F + 4.0iF;
+  double _Complex dc = 3.0 + 4.0i;
+  long double _Complex ldc = 3.0L + 4.0iL;
+
+  /* Test floats.  */
+  if (cabsf (fc) != 5.0F)
+    link_error ();
+  if (__builtin_cabsf (fc) != 5.0F)
+    link_error ();
+  if (cabsf (3.0F + 4.0iF) != 5.0F)
+    link_failure ();
+  if (__builtin_cabsf (3.0F + 4.0iF) != 5.0F)
+    link_failure ();
+
+  /* Test doubles.  */
+  if (cabs (dc) != 5.0)
+    link_error ();
+  if (__builtin_cabs (dc) != 5.0)
+    link_error ();
+  if (cabs (3.0 + 4.0i) != 5.0)
+    link_failure ();
+  if (__builtin_cabs (3.0 + 4.0i) != 5.0)
+    link_failure ();
+
+  /* Test long doubles.  */
+  if (cabsl (ldc) != 5.0L)
+    link_error ();
+  if (__builtin_cabsl (ldc) != 5.0L)
+    link_error ();
+  if (cabsl (3.0L + 4.0iL) != 5.0L)
+    link_failure ();
+  if (__builtin_cabsl (3.0L + 4.0iL) != 5.0L)
+    link_failure ();
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/builtins-19.c b/gcc/testsuite/gcc.dg/builtins-19.c
new file mode 100644 (file)
index 0000000..064321f
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2003  Free Software Foundation.
+
+   Check that cabs of a non-complex argument is converted into fabs.
+
+   Written by Roger Sayle, 1st June 2003.  */
+
+/* { dg-do link } */
+/* { dg-options "-O2 -ansi" } */
+
+double cabs (__complex__ double);
+float cabsf (__complex__ float);
+long double cabsl (__complex__ long double);
+
+void link_error (void);
+
+void test (double x)
+{
+  if (cabs (x) != fabs (x))
+    link_error ();
+}
+
+void testf (float x)
+{
+  if (cabsf (x) != fabsf (x))
+    link_error ();
+}
+
+void testl (long double x)
+{
+  if (cabsl (x) != fabsl (x))
+    link_error ();
+}
+
+int main ()
+{
+  test (1.0);
+  testf (1.0f);
+  testl (1.0l);
+  return 0;
+}
+
index ebd054f229a0ed94bf79a7685e6be8996a47abbf..895b80a2ef98d235dc494eebd3f225e568b3802d 100644 (file)
@@ -58,6 +58,21 @@ double test10(double x)
   return tan(atan(x));
 }
 
+double test11(double x)
+{
+  return fabs(fabs(x));
+}
+
+double test12(double x)
+{
+  return fabs(atan(x));
+}
+
+double test13(double x)
+{
+  return fabs(pow(2.0,x));
+}
+
 float test1f(float x)
 {
   return logf(expf(x));
@@ -108,6 +123,21 @@ float test10f(float x)
   return tanf(atanf(x));
 }
 
+floatf test11f(float x)
+{
+  return fabsf(fabsf(x));
+}
+
+floatf test12f(float x)
+{
+  return fabsf(atanf(x));
+}
+
+float test13f(float x)
+{
+  return fabsf(powf(2.0f,x));
+}
+
 long double test1l(long double x)
 {
   return logl(expl(x));
@@ -158,3 +188,18 @@ long double test10l(long double x)
   return tanl(atanl(x));
 }
 
+long double test11l(long double x)
+{
+  return fabsl(fabsl(x));
+}
+
+long double test12l(long double x)
+{
+  return fabsl(atanl(x));
+}
+
+long double test13l(long double x)
+{
+  return fabsl(powl(2.0l,x));
+}
+