This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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
--


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]