OSDN Git Service

* builtins.c (fold_builtin_frexp): New.
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 23 Feb 2007 04:49:21 +0000 (04:49 +0000)
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 23 Feb 2007 04:49:21 +0000 (04:49 +0000)
(fold_builtin_2): Use it.

testsuite:
* gcc.dg/torture/builtin-frexp-1.c: New test.

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

gcc/ChangeLog
gcc/builtins.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/builtin-frexp-1.c [new file with mode: 0644]

index 641648d..cd1e85d 100644 (file)
@@ -1,3 +1,8 @@
+2007-02-22  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * builtins.c (fold_builtin_frexp): New.
+       (fold_builtin_2): Use it.
+
 2007-02-22  Mark Mitchell  <mark@codesourcery.com>
 
        * doc/invoke.texi (Spec Files): Document getenv spec function.
index e1c2dee..5c6dd4d 100644 (file)
@@ -9017,6 +9017,62 @@ fold_builtin_carg (tree arg, tree type)
   return NULL_TREE;
 }
 
+/* Fold a call to builtin frexp, we can assume the base is 2.  */
+
+static tree
+fold_builtin_frexp (tree arg0, tree arg1, tree rettype)
+{
+  if (! validate_arg (arg0, REAL_TYPE) || ! validate_arg (arg1, POINTER_TYPE))
+    return NULL_TREE;
+  
+  STRIP_NOPS (arg0);
+      
+  if (!(TREE_CODE (arg0) == REAL_CST && ! TREE_OVERFLOW (arg0)))
+    return NULL_TREE;
+  
+  arg1 = build_fold_indirect_ref (arg1);
+
+  /* Proceed if a valid pointer type was passed in.  */
+  if (TYPE_MAIN_VARIANT (TREE_TYPE (arg1)) == integer_type_node)
+    {
+      const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg0);
+      tree frac, exp;
+         
+      switch (value->cl)
+      {
+      case rvc_zero:
+       /* For +-0, return (*exp = 0, +-0).  */
+       exp = integer_zero_node;
+       frac = arg0;
+       break;
+      case rvc_nan:
+      case rvc_inf:
+       /* For +-NaN or +-Inf, *exp is unspecified, return arg0.  */
+       return omit_one_operand (rettype, arg0, arg1);
+      case rvc_normal:
+       {
+         /* Since the frexp function always expects base 2, and in
+            GCC normalized significands are already in the range
+            [0.5, 1.0), we have exactly what frexp wants.  */
+         REAL_VALUE_TYPE frac_rvt = *value;
+         SET_REAL_EXP (&frac_rvt, 0);
+         frac = build_real (rettype, frac_rvt);
+         exp = build_int_cst (NULL_TREE, REAL_EXP (value));
+       }
+       break;
+      default:
+       gcc_unreachable ();
+      }
+               
+      /* Create the COMPOUND_EXPR (*arg1 = trunc, frac). */
+      arg1 = fold_build2 (MODIFY_EXPR, rettype, arg1, exp);
+      TREE_SIDE_EFFECTS (arg1) = 1;
+      return fold_build2 (COMPOUND_EXPR, rettype, arg1, frac);
+    }
+
+  return NULL_TREE;
+}
+
 /* Fold a call to builtin ldexp or scalbn/scalbln.  If LDEXP is true
    then we can assume the base is two.  If it's false, then we have to
    check the mode of the TYPE parameter in certain cases.  */
@@ -9544,6 +9600,9 @@ fold_builtin_2 (tree fndecl, tree arg0, tree arg1, bool ignore)
     CASE_FLT_FN (BUILT_IN_SCALBLN):
       return fold_builtin_load_exponent (arg0, arg1, type, /*ldexp=*/false);
 
+    CASE_FLT_FN (BUILT_IN_FREXP):
+      return fold_builtin_frexp (arg0, arg1, type);
+
     case BUILT_IN_BZERO:
       return fold_builtin_bzero (arg0, arg1, ignore);
 
index ad1b567..dd2deb4 100644 (file)
@@ -1,3 +1,7 @@
+2007-02-22  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * gcc.dg/torture/builtin-frexp-1.c: New test.
+
 2007-02-22  Mark Mitchell  <mark@codesourcery.com>
 
        * g++.dg/opt/switch4.C: Pass -fshort-enums -w.
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-frexp-1.c b/gcc/testsuite/gcc.dg/torture/builtin-frexp-1.c
new file mode 100644 (file)
index 0000000..d0662d7
--- /dev/null
@@ -0,0 +1,118 @@
+/* Copyright (C) 2007  Free Software Foundation.
+
+   Verify that built-in folding of frexp is correctly performed by the
+   compiler.
+
+   Origin: Kaveh R. Ghazi,  February 21, 2007.  */
+
+/* { dg-do link } */
+
+extern void link_error(int);
+
+/* Return TRUE if the sign of X != sign of Y.  This is important when
+   comparing signed zeros.  */
+#define CKSGN_F(X,Y) \
+  (__builtin_copysignf(1.0F,(X)) != __builtin_copysignf(1.0F,(Y)))
+#define CKSGN(X,Y) \
+  (__builtin_copysign(1.0,(X)) != __builtin_copysign(1.0,(Y)))
+#define CKSGN_L(X,Y) \
+  (__builtin_copysignl(1.0L,(X)) != __builtin_copysignl(1.0L,(Y)))
+
+/* We can only check the exponent when optimizing since we rely on
+   other optimizations to propagate the value.  TRUE means an error
+   occurred.  */
+#ifdef __OPTIMIZE__
+#define CKEXP(X,Y) X != Y
+#else
+#define CKEXP(X,Y) 0
+#endif
+
+/* Test that frexp(ARG,&i) == RES && i == EXP.  Check the sign in
+   case we get -0.0.  */
+#define TESTIT_FREXP(ARG,RES,EXP) do { \
+  int i = 123456; \
+  if (__builtin_frexpf(ARG##f,&i) != RES##f \
+      || CKEXP(i,EXP) \
+      || CKSGN_F(__builtin_frexpf(ARG##f,&i),RES##f)) \
+    link_error(__LINE__); \
+  i = 123456; \
+  if (__builtin_frexp(ARG,&i) != RES \
+      || CKEXP(i,EXP) \
+      || CKSGN(__builtin_frexp(ARG,&i),RES)) \
+    link_error(__LINE__); \
+  i = 123456; \
+  if (__builtin_frexpl(ARG##l,&i) != RES##l \
+      || CKEXP(i,EXP) \
+      || CKSGN_L(__builtin_frexpl(ARG##l,&i),RES##l)) \
+    link_error(__LINE__); \
+  } while (0)
+
+/* Test that FUNCRES(frexp(NEG FUNCARG(ARGARG),&i)) is false.  Check
+   the sign as well.  Ensure side-effects are evaluated in i.  */
+#define TESTIT_FREXP2(NEG,FUNCARG,ARGARG,FUNCRES) do { \
+  int i=5; \
+  if (!__builtin_##FUNCRES##f(__builtin_frexpf(NEG __builtin_##FUNCARG##f(ARGARG),&i)) \
+      || CKSGN_F(__builtin_frexpf(NEG __builtin_##FUNCARG##f(ARGARG),(i++,&i)), NEG __builtin_##FUNCARG##f(ARGARG)) \
+      || CKEXP(i,6)) \
+    link_error(__LINE__); \
+  if (!__builtin_##FUNCRES(__builtin_frexp(NEG __builtin_##FUNCARG(ARGARG),&i)) \
+      || CKSGN(__builtin_frexp(NEG __builtin_##FUNCARG(ARGARG),(i++,&i)), NEG __builtin_##FUNCARG(ARGARG)) \
+      || CKEXP(i,7)) \
+    link_error(__LINE__); \
+  if (!__builtin_##FUNCRES##l(__builtin_frexpl(NEG __builtin_##FUNCARG##l(ARGARG),&i)) \
+      || CKSGN_L(__builtin_frexpl(NEG __builtin_##FUNCARG##l(ARGARG),(i++,&i)), NEG __builtin_##FUNCARG##l(ARGARG)) \
+      || CKEXP(i,8)) \
+    link_error(__LINE__); \
+  } while (0)
+
+void __attribute__ ((__noinline__))
+foo(void)
+{
+  /* Test that frexp(ARG1,&i) -> ARG2 && i == ARG3.  */
+  TESTIT_FREXP (-0x1p40, -0.5, 41);
+  TESTIT_FREXP (-0x1p30, -0.5, 31);
+  TESTIT_FREXP (-0x1p20, -0.5, 21);
+  TESTIT_FREXP (-0x1p10, -0.5, 11);
+  TESTIT_FREXP (-0x1p5, -0.5, 6);
+  TESTIT_FREXP (-100/3.0, -100/192.0, 6);
+  TESTIT_FREXP (-1.5, -0.75, 1);
+  TESTIT_FREXP (-1.0, -0.5, 1);
+  TESTIT_FREXP (-1/3.0, -2/3.0, -1);
+  TESTIT_FREXP (-1/9.0, -8/9.0, -3);
+  TESTIT_FREXP (-0x1p-5, -0.5, -4);
+  TESTIT_FREXP (-0x1p-10, -0.5, -9);
+  TESTIT_FREXP (-0x1p-20, -0.5, -19);
+  TESTIT_FREXP (-0x1p-30, -0.5, -29);
+  TESTIT_FREXP (-0x1p-40, -0.5, -39);
+  TESTIT_FREXP (-0.0, -0.0, 0);
+  TESTIT_FREXP (0.0, 0.0, 0);
+  TESTIT_FREXP (0x1p-40, 0.5, -39);
+  TESTIT_FREXP (0x1p-30, 0.5, -29);
+  TESTIT_FREXP (0x1p-20, 0.5, -19);
+  TESTIT_FREXP (0x1p-10, 0.5, -9);
+  TESTIT_FREXP (0x1p-5, 0.5, -4);
+  TESTIT_FREXP (1/9.0, 8/9.0, -3);
+  TESTIT_FREXP (1/3.0, 2/3.0, -1);
+  TESTIT_FREXP (1.0, 0.5, 1);
+  TESTIT_FREXP (1.5, 0.75, 1);
+  TESTIT_FREXP (100/3.0, 100/192.0, 6);
+  TESTIT_FREXP (0x1p5, 0.5, 6);
+  TESTIT_FREXP (0x1p10, 0.5, 11);
+  TESTIT_FREXP (0x1p20, 0.5, 21);
+  TESTIT_FREXP (0x1p30, 0.5, 31);
+  TESTIT_FREXP (0x1p40, 0.5, 41);
+
+  /* Test for frexp(+-Inf,&i) -> +-Inf and frexp(+-NaN,&i) -> +-NaN.
+     Exponent is left unspecified, but we test for side-effects.  */
+  TESTIT_FREXP2 ( ,inf, , isinf);
+  TESTIT_FREXP2 (- ,inf, , isinf);
+  TESTIT_FREXP2 ( ,nan, "", isnan);
+  TESTIT_FREXP2 (- ,nan, "", isnan);
+}
+
+int main()
+{
+  foo ();
+  
+  return 0;
+}