aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2005-03-10 21:39:01 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2005-03-10 21:39:01 +0000
commite4fbead1e43a019db4cd1e7364ca47737d13fa39 (patch)
tree9fee6ed62b160ba480074e89b8d8be41b4e3194f /gcc
parent985f2d8fa38d5c97b7f28208f0a571a568622039 (diff)
downloadgcc-e4fbead1e43a019db4cd1e7364ca47737d13fa39.zip
gcc-e4fbead1e43a019db4cd1e7364ca47737d13fa39.tar.gz
gcc-e4fbead1e43a019db4cd1e7364ca47737d13fa39.tar.bz2
builtins.c (expand_builtin_signbit): Extend to handle floating point modes wider than the largest integer type...
* 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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/builtins.c73
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/builtins-32.c18
4 files changed, 67 insertions, 34 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ff1e60b..18efe59 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/builtins.c b/gcc/builtins.c
index b113d9f..4f46474 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -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;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 082f18a..bee3e64 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/gcc.dg/builtins-32.c b/gcc/testsuite/gcc.dg/builtins-32.c
index 3a35dc6..3d2a361 100644
--- a/gcc/testsuite/gcc.dg/builtins-32.c
+++ b/gcc/testsuite/gcc.dg/builtins-32.c
@@ -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;
}