This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Optimize subregs of zero and sign extensions (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, Paolo Bonzini <bonzini at gnu dot org>
- Date: Wed, 21 Jan 2004 15:33:23 -0700 (MST)
- Subject: [PATCH] Optimize subregs of zero and sign extensions (take 2)
On Wed, 21 Jan 2004, Richard Henderson wrote:
> > I'll prepare a modified patch that splits subreg_lsb into a helper
> > function subreg_lsb_1, and then export that so that it can be used
> > here.
>
> That would be fine, thanks.
Here's a revised version of the patch that splits the computation of
a bitpos from a subreg's byte offset into a new helper function.
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 21 Jan 2004 21:20:47 -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 21 Jan 2004 21:20:48 -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 21 Jan 2004 21:20:49 -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;
}
return NULL_RTX;
Roger
--
Roger Sayle, E-mail: roger@eyesopen.com
OpenEye Scientific Software, WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road, Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507. Fax: (+1) 505-473-0833