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]

Re: [PATCH] Optimize subregs of zero and sign extensions (take 2)


On Wed, 21 Jan 2004, Richard Henderson wrote:
> Ok, except,
>
> > + 	return const0_rtx;
>
> How about CONST0_RTX (outermode)?


Third times a charm! :>  Paolo's CSE patch probably needs a similar fix.

The following patch has been tested on i686-pc-linux-gnu with a full
"make bootstrap", all languages except treelang, and regression tested
with a top-level "make -k check" with no new failures.


Ok for mainline?

2004-01-21  Roger Sayle  <roger@eyesopen.com>
	    Paolo Bonzini  <bonzini@gnu.org>

	* rtlanal.c (subreg_lsb_1): New function split out from subreg_lsb.
	(subreg_lsb): Change to call new subreg_lsb_1 helper function.
	* rtl.h (subreg_lsb_1): Prototype here.
	* simplify-rtx.c (simplify_subreg): Optimize subregs of zero and
	sign extensions.


Index: rtlanal.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtlanal.c,v
retrieving revision 1.172
diff -c -3 -p -r1.172 rtlanal.c
*** rtlanal.c	19 Jan 2004 21:51:06 -0000	1.172
--- rtlanal.c	22 Jan 2004 00:42:44 -0000
*************** loc_mentioned_in_p (rtx *loc, rtx in)
*** 3187,3232 ****
    return 0;
  }

! /* Given a subreg X, return the bit offset where the subreg begins
!    (counting from the least significant bit of the reg).  */

  unsigned int
! subreg_lsb (rtx x)
  {
-   enum machine_mode inner_mode = GET_MODE (SUBREG_REG (x));
-   enum machine_mode mode = GET_MODE (x);
    unsigned int bitpos;
    unsigned int byte;
    unsigned int word;

    /* A paradoxical subreg begins at bit position 0.  */
!   if (GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (inner_mode))
      return 0;

    if (WORDS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
      /* If the subreg crosses a word boundary ensure that
         it also begins and ends on a word boundary.  */
!     if ((SUBREG_BYTE (x) % UNITS_PER_WORD
! 	 + GET_MODE_SIZE (mode)) > UNITS_PER_WORD
! 	&& (SUBREG_BYTE (x) % UNITS_PER_WORD
! 	    || GET_MODE_SIZE (mode) % UNITS_PER_WORD))
  	abort ();

    if (WORDS_BIG_ENDIAN)
      word = (GET_MODE_SIZE (inner_mode)
! 	    - (SUBREG_BYTE (x) + GET_MODE_SIZE (mode))) / UNITS_PER_WORD;
    else
!     word = SUBREG_BYTE (x) / UNITS_PER_WORD;
    bitpos = word * BITS_PER_WORD;

    if (BYTES_BIG_ENDIAN)
      byte = (GET_MODE_SIZE (inner_mode)
! 	    - (SUBREG_BYTE (x) + GET_MODE_SIZE (mode))) % UNITS_PER_WORD;
    else
!     byte = SUBREG_BYTE (x) % UNITS_PER_WORD;
    bitpos += byte * BITS_PER_UNIT;

    return bitpos;
  }

  /* This function returns the regno offset of a subreg expression.
--- 3187,3243 ----
    return 0;
  }

! /* Helper function for subreg_lsb.  Given a subreg's OUTER_MODE, INNER_MODE,
!    and SUBREG_BYTE, return the bit offset where the subreg begins
!    (counting from the least significant bit of the operand).  */

  unsigned int
! subreg_lsb_1 (enum machine_mode outer_mode,
! 	      enum machine_mode inner_mode,
! 	      unsigned int subreg_byte)
  {
    unsigned int bitpos;
    unsigned int byte;
    unsigned int word;

    /* A paradoxical subreg begins at bit position 0.  */
!   if (GET_MODE_BITSIZE (outer_mode) > GET_MODE_BITSIZE (inner_mode))
      return 0;

    if (WORDS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
      /* If the subreg crosses a word boundary ensure that
         it also begins and ends on a word boundary.  */
!     if ((subreg_byte % UNITS_PER_WORD
! 	 + GET_MODE_SIZE (outer_mode)) > UNITS_PER_WORD
! 	&& (subreg_byte % UNITS_PER_WORD
! 	    || GET_MODE_SIZE (outer_mode) % UNITS_PER_WORD))
  	abort ();

    if (WORDS_BIG_ENDIAN)
      word = (GET_MODE_SIZE (inner_mode)
! 	    - (subreg_byte + GET_MODE_SIZE (outer_mode))) / UNITS_PER_WORD;
    else
!     word = subreg_byte / UNITS_PER_WORD;
    bitpos = word * BITS_PER_WORD;

    if (BYTES_BIG_ENDIAN)
      byte = (GET_MODE_SIZE (inner_mode)
! 	    - (subreg_byte + GET_MODE_SIZE (outer_mode))) % UNITS_PER_WORD;
    else
!     byte = subreg_byte % UNITS_PER_WORD;
    bitpos += byte * BITS_PER_UNIT;

    return bitpos;
+ }
+
+ /* Given a subreg X, return the bit offset where the subreg begins
+    (counting from the least significant bit of the reg).  */
+
+ unsigned int
+ subreg_lsb (rtx x)
+ {
+   return subreg_lsb_1 (GET_MODE (x), GET_MODE (SUBREG_REG (x)),
+ 		       SUBREG_BYTE (x));
  }

  /* This function returns the regno offset of a subreg expression.
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.449
diff -c -3 -p -r1.449 rtl.h
*** rtl.h	17 Jan 2004 22:14:17 -0000	1.449
--- rtl.h	22 Jan 2004 00:42:44 -0000
*************** enum label_kind
*** 1065,1070 ****
--- 1065,1072 ----

  /* in rtlanal.c */
  extern unsigned int subreg_lsb (rtx);
+ extern unsigned int subreg_lsb_1 (enum machine_mode, enum machine_mode,
+ 				  unsigned int);
  extern unsigned int subreg_regno_offset	(unsigned int, enum machine_mode,
  					 unsigned int, enum machine_mode);
  extern bool subreg_offset_representable_p (unsigned int, enum machine_mode,
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.173
diff -c -3 -p -r1.173 simplify-rtx.c
*** simplify-rtx.c	19 Jan 2004 21:51:06 -0000	1.173
--- simplify-rtx.c	22 Jan 2004 00:42:45 -0000
*************** simplify_subreg (enum machine_mode outer
*** 3379,3386 ****
        res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
        if (res)
  	return res;
!       /* We can at least simplify it by referring directly to the relevant part.  */
        return gen_rtx_SUBREG (outermode, part, final_offset);
      }

    return NULL_RTX;
--- 3379,3421 ----
        res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
        if (res)
  	return res;
!       /* We can at least simplify it by referring directly to the
! 	 relevant part.  */
        return gen_rtx_SUBREG (outermode, part, final_offset);
+     }
+
+   /* Optimize SUBREG truncations of zero and sign extended values.  */
+   if ((GET_CODE (op) == ZERO_EXTEND
+        || GET_CODE (op) == SIGN_EXTEND)
+       && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode))
+     {
+       unsigned int bitpos = subreg_lsb_1 (outermode, innermode, byte);
+
+       /* If we're requesting the lowpart of a zero or sign extension,
+ 	 there are three possibilities.  If the outermode is the same
+ 	 as the origmode, we can omit both the extension and the subreg.
+ 	 If the outermode is not larger than the origmode, we can apply
+ 	 the truncation without the extension.  Finally, if the outermode
+ 	 is larger than the origmode, but both are integer modes, we
+ 	 can just extend to the appropriate mode.  */
+       if (bitpos == 0)
+ 	{
+ 	  enum machine_mode origmode = GET_MODE (XEXP (op, 0));
+ 	  if (outermode == origmode)
+ 	    return XEXP (op, 0);
+ 	  if (GET_MODE_BITSIZE (outermode) <= GET_MODE_BITSIZE (origmode))
+ 	    return simplify_gen_subreg (outermode, XEXP (op, 0),
+ 					origmode, byte);
+ 	  if (SCALAR_INT_MODE_P (outermode))
+ 	    return simplify_gen_unary (GET_CODE (op), outermode,
+ 				       XEXP (op, 0), origmode);
+ 	}
+
+       /* A SUBREG resulting from a zero extension may fold to zero if
+ 	 it extracts higher bits that the ZERO_EXTEND's source bits.  */
+       if (GET_CODE (op) == ZERO_EXTEND
+ 	  && bitpos >= GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0))))
+ 	return CONST0_RTX (outermode);
      }

    return NULL_RTX;


Roger
--


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