This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Support long doubles in expand_builtin_signbit (take 2)
- From: Roger Sayle <roger at eyesopen dot com>
- To: Richard Henderson <rth at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org, "Kaveh R. Ghazi" <ghazi at caip dot rutgers dot edu>
- Date: Thu, 10 Mar 2005 12:25:34 -0700 (MST)
- Subject: [PATCH] Support long doubles in expand_builtin_signbit (take 2)
On Tue, 8 Mar 2005, Richard Henderson wrote:
> No objections, except I think we should generate
>
> (x >> bitpos) & 1
> instead of
> (x & (1 << bitpos)) >> bitpos
Here's an updated version of this patch, that implements this suggestion
and generates "(x >> bitpos) & 1" for those platform/machine mode
combinations that require both a bitwise AND and a right shift.
> It'd be nice to verify in the testsuite that this gets simplified
> to (x < 0) or ((unsigned)x >> width-1) as appropriate to the target.
This is trickier as it's very target specific, however I've confirmed
by hand that on x86, for example, the following testcase generates the
code below:
extern void foo();
int test1(double x)
{
return __builtin_signbit(x);
}
void test2(double x)
{
if (__builtin_signbit(x))
foo();
}
int test1f(float x)
{
return __builtin_signbitf(x);
}
void test2f(float x)
{
if (__builtin_signbitf(x))
foo();
}
int test1l(long double x)
{
return __builtin_signbitl(x);
}
void test2l(long double x)
{
if (__builtin_signbitl(x))
foo();
}
test1: movl 8(%esp), %eax
andl $-2147483648, %eax
ret
test2: movl 8(%esp), %eax
testl %eax, %eax
js .L8
ret
.L8: jmp foo
test1f: movl 4(%esp), %eax
andl $-2147483648, %eax
ret
test2f: movl 4(%esp), %edx
testl %edx, %edx
js .L15
ret
.L15: jmp foo
test1l: movl 12(%esp), %eax
andl $32768, %eax
ret
test2l: testb $-128, 13(%esp)
jne .L22
ret
.L22: jmp foo
This confirms that we're generating an efficient signedness test when
appropriate, and avoiding shifts and/or jump sequences otherwise.
The following patch has been tested on i686-pc-linux-gnu with a full
"make bootstrap", all default languages, and regression tested with
a top-level "make -k check" with no new failures.
Ok for mainline?
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.
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.427
diff -c -3 -p -r1.427 builtins.c
*** builtins.c 9 Mar 2005 17:30:11 -0000 1.427
--- builtins.c 10 Mar 2005 05:03:56 -0000
*************** expand_builtin_signbit (tree exp, rtx ta
*** 4957,4963 ****
enum machine_mode fmode, imode, rmode;
HOST_WIDE_INT hi, lo;
tree arg, arglist;
! int bitpos;
rtx temp;
arglist = TREE_OPERAND (exp, 1);
--- 4957,4963 ----
enum machine_mode fmode, imode, rmode;
HOST_WIDE_INT hi, lo;
tree arg, arglist;
! int word, bitpos;
rtx temp;
arglist = TREE_OPERAND (exp, 1);
*************** expand_builtin_signbit (tree exp, rtx ta
*** 4971,4977 ****
/* 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))
--- 4971,4978 ----
/* For floating point formats without a sign bit, implement signbit
as "ARG < 0.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))
*************** expand_builtin_signbit (tree exp, rtx ta
*** 4982,5022 ****
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 (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);
}
else
{
! if (GET_MODE_BITSIZE (imode) < GET_MODE_BITSIZE (rmode))
! temp = gen_lowpart (rmode, temp);
if (bitpos < HOST_BITS_PER_WIDE_INT)
{
hi = 0;
--- 4983,5014 ----
return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
}
temp = expand_expr (arg, NULL_RTX, VOIDmode, 0);
! if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
{
! imode = int_mode_for_mode (fmode);
! if (imode == BLKmode)
! return 0;
! temp = gen_lowpart (imode, temp);
}
else
{
! 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;
*************** expand_builtin_signbit (tree exp, rtx ta
*** 5028,5038 ****
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;
}
--- 5020,5043 ----
lo = 0;
}
! if (imode != rmode)
! temp = gen_lowpart (rmode, temp);
temp = expand_binop (rmode, and_optab, temp,
immed_double_const (lo, hi, rmode),
! 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;
}
Roger
--