builtins.c (expand_builtin_signbit): Extend to handle floating point modes wider...
authorRoger Sayle <roger@eyesopen.com>
Thu, 10 Mar 2005 21:39:01 +0000 (21:39 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Thu, 10 Mar 2005 21:39:01 +0000 (21:39 +0000)
* builtins.c (expand_builtin_signbit): Extend to handle floating
point modes wider than the largest integer type, using the
operand_subword_force function to obtain the signbit's word.

* gcc.dg/builtins-32.c: Add new run-time tests for long double.

From-SVN: r96263

gcc/ChangeLog
gcc/builtins.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-32.c

index ff1e60be2948665c92ced73bcff4b5ccf9527aaa..18efe597a39509fa01c0deaf97fa3e234c34a4b1 100644 (file)
@@ -1,3 +1,9 @@
+2005-03-10  Roger Sayle  <roger@eyesopen.com>
+
+       * builtins.c (expand_builtin_signbit): Extend to handle floating
+       point modes wider than the largest integer type, using the
+       operand_subword_force function to obtain the signbit's word.
+
 2005-03-10  Jakub Jelinek  <jakub@redhat.com>
 
        PR target/20322
index b113d9f770e6b62f5d3562d4586da180fa891023..4f464746b9a829c5059f89be013222b03dab8040 100644 (file)
@@ -4957,7 +4957,7 @@ expand_builtin_signbit (tree exp, rtx target)
   enum machine_mode fmode, imode, rmode;
   HOST_WIDE_INT hi, lo;
   tree arg, arglist;
-  int bitpos;
+  int word, bitpos;
   rtx temp;
 
   arglist = TREE_OPERAND (exp, 1);
@@ -4971,7 +4971,8 @@ expand_builtin_signbit (tree exp, rtx target)
 
   /* For floating point formats without a sign bit, implement signbit
      as "ARG < 0.0".  */
-  if (fmt->signbit < 0)
+  bitpos = fmt->signbit;
+  if (bitpos < 0)
   {
     /* But we can't do this if the format supports signed zero.  */
     if (fmt->has_signed_zero && HONOR_SIGNED_ZEROS (fmode))
@@ -4982,41 +4983,32 @@ expand_builtin_signbit (tree exp, rtx target)
     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))
+  if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
     {
-      if (BYTES_BIG_ENDIAN)
-       bitpos = GET_MODE_BITSIZE (imode) - 1 - bitpos;
-      temp = copy_to_mode_reg (imode, temp);
-      temp = extract_bit_field (temp, 1, bitpos, 1,
-                               NULL_RTX, rmode, rmode);
+      imode = int_mode_for_mode (fmode);
+      if (imode == BLKmode)
+       return 0;
+      temp = gen_lowpart (imode, temp);
     }
   else
     {
-      if (GET_MODE_BITSIZE (imode) < GET_MODE_BITSIZE (rmode))
-       temp = gen_lowpart (rmode, temp);
+      imode = word_mode;
+      /* Handle targets with different FP word orders.  */
+      if (FLOAT_WORDS_BIG_ENDIAN)
+        word = (GET_MODE_BITSIZE (fmode) - bitpos) / BITS_PER_WORD;
+      else
+        word = bitpos / BITS_PER_WORD;
+      temp = operand_subword_force (temp, word, fmode);
+      bitpos = bitpos % BITS_PER_WORD;
+    }
+
+  /* If the bitpos is within the "result mode" lowpart, the operation
+     can be implement with a single bitwise AND.  Otherwise, we need
+     a right shift and an AND.  */
+
+  if (bitpos < GET_MODE_BITSIZE (rmode))
+    {
       if (bitpos < HOST_BITS_PER_WIDE_INT)
        {
          hi = 0;
@@ -5028,11 +5020,24 @@ expand_builtin_signbit (tree exp, rtx target)
          lo = 0;
        }
 
-      temp = force_reg (rmode, temp);
+      if (imode != rmode)
+       temp = gen_lowpart (rmode, temp);
       temp = expand_binop (rmode, and_optab, temp,
                           immed_double_const (lo, hi, rmode),
-                          target, 1, OPTAB_LIB_WIDEN);
+                          NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
+  else
+    {
+      /* Perform a logical right shift to place the signbit in the least
+         significant bit, then truncate the result to the desired mode
+        and mask just this bit.  */
+      temp = expand_shift (RSHIFT_EXPR, imode, temp,
+                          build_int_cst (NULL_TREE, bitpos), NULL_RTX, 1);
+      temp = gen_lowpart (rmode, temp);
+      temp = expand_binop (rmode, and_optab, temp, const1_rtx,
+                          NULL_RTX, 1, OPTAB_LIB_WIDEN);
+    }
+
   return temp;
 }
 
index 082f18a33e6d7b515fddd935acce43d64dc55d44..bee3e6499bf8bf6413b15ffef0b89844f0d7f748 100644 (file)
@@ -1,3 +1,7 @@
+2005-03-10  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.dg/builtins-32.c: Add new run-time tests for long double.
+
 2005-03-10  Jakub Jelinek  <jakub@redhat.com>
 
        PR target/20322
index 3a35dc6dfe9b2fa5b3d2940cd7ffe5831f69adbb..3d2a36190a578f35296770f31d5303ee675def72 100644 (file)
@@ -12,6 +12,7 @@ extern void abort(void);
 
 extern int signbit(double);
 extern int signbitf(float);
+extern int signbitl(long double);
 
 int test (double x)
 {
@@ -23,18 +24,35 @@ int testf (float x)
   return signbitf(x);
 }
 
+int testl (long double x)
+{
+  return signbitl(x);
+}
+
+
 int main()
 {
+  if (test (0.0) != 0)
+    abort ();
   if (test (1.0) != 0)
     abort ();
   if (test (-2.0) == 0)
     abort ();
 
+  if (testf (0.0f) != 0)
+    abort ();
   if (testf (1.0f) != 0)
     abort ();
   if (testf (-2.0f) == 0)
     abort ();
 
+  if (testl (0.0l) != 0)
+    abort ();
+  if (testl (1.0l) != 0)
+    abort ();
+  if (testl (-2.0l) == 0)
+    abort ();
+
   return 0;
 }