builtins.def (BUILT_IN_SIGNBIT, [...]): New GCC builtins.
authorRoger Sayle <roger@eyesopen.com>
Sun, 1 Feb 2004 14:59:15 +0000 (14:59 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Sun, 1 Feb 2004 14:59:15 +0000 (14:59 +0000)
* builtins.def (BUILT_IN_SIGNBIT, BUILT_IN_SIGNBITF,
BUILT_IN_SIGNBITL): New GCC builtins.
* builtins.c (expand_builtin_signbit): New function to RTL expand
calls to signbit, signbitf and signbitl as inline intrinsics.
(expand_builtin): Call expand_builtin_signbit for BUILT_IN_SIGNBIT*.
(fold_builtin_signbit): New function to perform constant folding
of signbit, signbitf and signbitl.
(fold_builtin): Call fold_builtin_signbit for BUILT_IN_SIGNBIT*.

* doc/extend.texi: Document new signbit{,f,l} builtins.

* gcc.dg/builtins-1.c: Also test for __builtin_signbit{,f,l}.
* gcc.dg/builtins-31.c: New testcase.
* gcc.dg/builtins-32.c: New testcase.

From-SVN: r77070

gcc/ChangeLog
gcc/builtins.c
gcc/builtins.def
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-1.c
gcc/testsuite/gcc.dg/builtins-31.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtins-32.c [new file with mode: 0644]

index 989f9e40456fa5303cf8e5ce84bd9834c265228c..64e15f3f56aea61287eb6b9c8b75006e5d853dff 100644 (file)
@@ -1,3 +1,16 @@
+2004-02-01  Roger Sayle  <roger@eyesopen.com>
+
+       * builtins.def (BUILT_IN_SIGNBIT, BUILT_IN_SIGNBITF,
+       BUILT_IN_SIGNBITL): New GCC builtins.
+       * builtins.c (expand_builtin_signbit): New function to RTL expand
+       calls to signbit, signbitf and signbitl as inline intrinsics.
+       (expand_builtin): Call expand_builtin_signbit for BUILT_IN_SIGNBIT*.
+       (fold_builtin_signbit): New function to perform constant folding
+       of signbit, signbitf and signbitl.
+       (fold_builtin): Call fold_builtin_signbit for BUILT_IN_SIGNBIT*.
+
+       * doc/extend.texi: Document new signbit{,f,l} builtins.
+
 2004-02-01  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/mips/mips.md (adddi3_internal_2): Remove superfluous %s.
index 2dfc0e8a89e3c13ca7ac9ecfc4b773399b987994..8b15e7c18d899a9c93fc71b40b0f006d186f1672 100644 (file)
@@ -152,6 +152,7 @@ static tree fold_trunc_transparent_mathfn (tree);
 static bool readonly_data_expr (tree);
 static rtx expand_builtin_fabs (tree, rtx, rtx);
 static rtx expand_builtin_cabs (tree, rtx);
+static rtx expand_builtin_signbit (tree, rtx);
 static tree fold_builtin_cabs (tree, tree, tree);
 static tree fold_builtin_trunc (tree);
 static tree fold_builtin_floor (tree);
@@ -166,6 +167,7 @@ static tree fold_builtin_strncpy (tree);
 static tree fold_builtin_memcmp (tree);
 static tree fold_builtin_strcmp (tree);
 static tree fold_builtin_strncmp (tree);
+static tree fold_builtin_signbit (tree);
 
 /* Return the alignment in bits of EXP, a pointer valued expression.
    But don't return more than MAX_ALIGN no matter what.
@@ -4920,6 +4922,97 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
 
   return 0;
 }
+
+/* Expand a call to the built-in signbit, signbitf or signbitl function.
+   Return NULL_RTX if a normal call should be emitted rather than expanding
+   the function in-line.  EXP is the expression that is a call to the builtin
+   function; if convenient, the result should be placed in TARGET.  */
+
+static rtx
+expand_builtin_signbit (tree exp, rtx target)
+{
+  const struct real_format *fmt;
+  enum machine_mode fmode, imode, rmode;
+  HOST_WIDE_INT hi, lo;
+  tree arg, arglist;
+  int bitpos;
+  rtx temp;
+
+  arglist = TREE_OPERAND (exp, 1);
+  if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+    return 0;
+
+  arg = TREE_VALUE (arglist);
+  fmode = TYPE_MODE (TREE_TYPE (arg));
+  rmode = TYPE_MODE (TREE_TYPE (exp));
+  fmt = REAL_MODE_FORMAT (fmode);
+
+  /* For floating point formats without a sign bit, implement signbit
+     as "ARG < 0.0".  */
+  if (fmt->signbit < 0)
+  {
+    /* But we can't do this if the format supports signed zero.  */
+    if (fmt->has_signed_zero && HONOR_SIGNED_ZEROS (fmode))
+      return 0;
+
+    arg = fold (build (LT_EXPR, TREE_TYPE (exp), arg,
+               build_real (TREE_TYPE (arg), dconst0)));
+    return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
+  }
+
+  imode = int_mode_for_mode (fmode);
+  if (imode == BLKmode)
+    return 0;
+
+  bitpos = fmt->signbit;
+  /* Handle targets with different FP word orders.  */
+  if (FLOAT_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+    {
+      int nwords = GET_MODE_BITSIZE (fmode) / BITS_PER_WORD;
+      int word = nwords - (bitpos / BITS_PER_WORD) - 1;
+      bitpos = word * BITS_PER_WORD + bitpos % BITS_PER_WORD;
+    }
+
+  /* If the sign bit is not in the lowpart and the floating point format
+     is wider than an integer, check that is twice the size of an integer
+     so that we can use gen_highpart below.  */
+  if (bitpos >= GET_MODE_BITSIZE (rmode)
+      && GET_MODE_BITSIZE (imode) != 2 * GET_MODE_BITSIZE (rmode))
+    return 0;
+
+  temp = expand_expr (arg, NULL_RTX, VOIDmode, 0);
+  temp = gen_lowpart (imode, temp);
+
+  if (GET_MODE_BITSIZE (imode) < GET_MODE_BITSIZE (rmode))
+    temp = gen_lowpart (rmode, temp);
+  else if (GET_MODE_BITSIZE (imode) > GET_MODE_BITSIZE (rmode))
+    {
+      if (bitpos > GET_MODE_BITSIZE (rmode))
+       {
+         temp = gen_highpart (rmode, temp);
+         bitpos %= GET_MODE_BITSIZE (rmode);
+       }
+      else
+       temp = gen_lowpart (rmode, temp);
+    }
+
+  if (bitpos < HOST_BITS_PER_WIDE_INT)
+    {
+      hi = 0;
+      lo = (HOST_WIDE_INT) 1 << bitpos;
+    }
+  else
+    {
+      hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+      lo = 0;
+    }
+
+  temp = force_reg (rmode, temp);
+  temp = expand_binop (rmode, and_optab, temp,
+                      immed_double_const (lo, hi, rmode),
+                      target, 1, OPTAB_LIB_WIDEN);
+  return temp;
+}
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -5411,6 +5504,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
+    case BUILT_IN_SIGNBIT:
+    case BUILT_IN_SIGNBITF:
+    case BUILT_IN_SIGNBITL:
+      target = expand_builtin_signbit (exp, target);
+      if (target)
+       return target;
+      break;
+
       /* Various hooks for the DWARF 2 __throw routine.  */
     case BUILT_IN_UNWIND_INIT:
       expand_builtin_unwind_init ();
@@ -6528,6 +6629,44 @@ fold_builtin_strncmp (tree exp)
   return 0;
 }
 
+/* Fold function call to builtin signbit, signbitf or signbitl.  Return
+   NULL_TREE if no simplification can be made.  */
+
+static tree
+fold_builtin_signbit (tree exp)
+{
+  tree arglist = TREE_OPERAND (exp, 1);
+  tree arg, temp;
+
+  if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+    return NULL_TREE;
+
+  arg = TREE_VALUE (arglist);
+
+  /* If ARG is a compile-time constant, determine the result.  */
+  if (TREE_CODE (arg) == REAL_CST
+      && !TREE_CONSTANT_OVERFLOW (arg))
+    {
+      REAL_VALUE_TYPE c;
+
+      c = TREE_REAL_CST (arg);
+      temp = REAL_VALUE_NEGATIVE (c) ? integer_one_node : integer_zero_node;
+      return convert (TREE_TYPE (exp), temp);
+    }
+
+  /* If ARG is non-negative, the result is always zero.  */
+  if (tree_expr_nonnegative_p (arg))
+    return omit_one_operand (TREE_TYPE (exp), integer_zero_node, arg);
+
+  /* If ARG's format doesn't have signed zeros, return "arg < 0.0".  */
+  if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg))))
+    return fold (build (LT_EXPR, TREE_TYPE (exp), arg,
+                       build_real (TREE_TYPE (arg), dconst0)));
+
+  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.  */
 
@@ -6949,6 +7088,11 @@ fold_builtin (tree exp)
     case BUILT_IN_STRNCMP:
       return fold_builtin_strncmp (exp);
 
+    case BUILT_IN_SIGNBIT:
+    case BUILT_IN_SIGNBITF:
+    case BUILT_IN_SIGNBITL:
+      return fold_builtin_signbit (exp);
+
     default:
       break;
     }
index 27cb2b6459a2d8e615d4b33975bff076383aef5a..a81358052a107149c73d5108fac411c06bf631c4 100644 (file)
@@ -321,6 +321,9 @@ DEF_C99_BUILTIN        (BUILT_IN_SCALBLNL, "scalblnl", BT_FN_LONGDOUBLE_LONGDOUB
 DEF_C99_BUILTIN        (BUILT_IN_SCALBN, "scalbn", BT_FN_DOUBLE_DOUBLE_INT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_SCALBNF, "scalbnf", BT_FN_FLOAT_FLOAT_INT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_SCALBNL, "scalbnl", BT_FN_LONGDOUBLE_LONGDOUBLE_INT, ATTR_MATHFN_FPROUNDING_ERRNO)
+DEF_EXT_LIB_BUILTIN    (BUILT_IN_SIGNBIT, "signbit", BT_FN_INT_DOUBLE, ATTR_CONST_NOTHROW_LIST)
+DEF_EXT_LIB_BUILTIN    (BUILT_IN_SIGNBITF, "signbitf", BT_FN_INT_FLOAT, ATTR_CONST_NOTHROW_LIST)
+DEF_EXT_LIB_BUILTIN    (BUILT_IN_SIGNBITL, "signbitl", BT_FN_INT_LONGDOUBLE, ATTR_CONST_NOTHROW_LIST)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SIGNIFICAND, "significand", BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SIGNIFICANDF, "significandf", BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SIGNIFICANDL, "significandl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
index e2bfd9348dfdfe9fbcc1603871c197805c7c5b8f..9f0f6b91d4ca8b73558a306110bfa562e6ba6e56 100644 (file)
@@ -4988,6 +4988,9 @@ v4si f (v4si a, v4si b, v4si c)
 @findex scalbn
 @findex scalbnf
 @findex scanfnl
+@findex signbit
+@findex signbitf
+@findex signbitl
 @findex significand
 @findex significandf
 @findex significandl
@@ -5082,6 +5085,7 @@ Outside strict ISO C mode (@option{-ansi}, @option{-std=c89} or
 @code{j1}, @code{jnf}, @code{jnl}, @code{jn}, @code{mempcpy},
 @code{pow10f}, @code{pow10l}, @code{pow10}, @code{printf_unlocked},
 @code{rindex}, @code{scalbf}, @code{scalbl}, @code{scalb},
+@code{signbit}, @code{signbitf}, @code{signbitl},
 @code{significandf}, @code{significandl}, @code{significand},
 @code{sincosf}, @code{sincosl}, @code{sincos}, @code{stpcpy},
 @code{strdup}, @code{strfmon}, @code{y0f}, @code{y0l}, @code{y0},
index 18aa48b55539e0248ba4399b59e895376634da9e..afd9ce64f244c10e58db831dd1b2e2b6713ec0c4 100644 (file)
@@ -1,3 +1,9 @@
+2004-02-01  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.dg/builtins-1.c: Also test for __builtin_signbit{,f,l}.
+       * gcc.dg/builtins-31.c: New testcase.
+       * gcc.dg/builtins-32.c: New testcase.
+
 2004-01-30  Andrew Pinski  <pinskia@physics.uc.edu>
 
        * objc.dg/call-super-2.m: Update line numbers
index 41bd8d5788cfeeb4c3b8d1a1e6f346ec33d19cb5..18c45d1419b482246b48faf60be4475bd6aafe2e 100644 (file)
@@ -165,6 +165,7 @@ FPTEST1     (round)
 FPTEST2     (scalb)
 FPTEST2ARG2 (scalbln, int)
 FPTEST2ARG2 (scalbn, int)
+FPTEST1RET  (signbit, int)
 FPTEST1     (significand)
 FPTEST1     (sin)
 FPTEST3FPP23VOID (sincos)
diff --git a/gcc/testsuite/gcc.dg/builtins-31.c b/gcc/testsuite/gcc.dg/builtins-31.c
new file mode 100644 (file)
index 0000000..6e1bda0
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2004 Free Software Foundation.
+
+   Check that constant folding of signbit, signbitf and signbitl math
+   functions doesn't break anything and produces the expected results.
+
+   Written by Roger Sayle, 28th January 2004.  */
+
+/* { dg-do link } */
+/* { dg-options "-O2" } */
+
+extern void link_error(void);
+
+extern int signbit(double);
+extern int signbitf(float);
+extern int signbitl(long double);
+
+int main()
+{
+  if (signbit (1.0) != 0)
+    link_error ();
+  if (signbit (-2.0) == 0)
+    link_error ();
+
+  if (signbitf (1.0f) != 0)
+    link_error ();
+  if (signbitf (-2.0f) == 0)
+    link_error ();
+
+  if (signbitl (1.0l) != 0)
+    link_error ();
+  if (signbitl (-2.0f) == 0)
+    link_error ();
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/builtins-32.c b/gcc/testsuite/gcc.dg/builtins-32.c
new file mode 100644 (file)
index 0000000..3a35dc6
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2004 Free Software Foundation.
+
+   Check that constant folding of signbit, signbitf and signbitl math
+   functions doesn't break anything and produces the expected results.
+
+   Written by Roger Sayle, 28th January 2004.  */
+
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern void abort(void);
+
+extern int signbit(double);
+extern int signbitf(float);
+
+int test (double x)
+{
+  return signbit(x);
+}
+
+int testf (float x)
+{
+  return signbitf(x);
+}
+
+int main()
+{
+  if (test (1.0) != 0)
+    abort ();
+  if (test (-2.0) == 0)
+    abort ();
+
+  if (testf (1.0f) != 0)
+    abort ();
+  if (testf (-2.0f) == 0)
+    abort ();
+
+  return 0;
+}
+