summaryrefslogtreecommitdiffstats
path: root/gcc
diff options
context:
space:
mode:
authorsayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2004-01-22 12:44:54 +0000
committersayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2004-01-22 12:44:54 +0000
commitf36eb1e90c6e27ff4f72826c76afaec43219a8a8 (patch)
tree3c307eaa8d9217b307aed75ea2e9ba109fafafb0 /gcc
parent745f32290d2ee826d468bbad01d4bbd545ef8974 (diff)
downloadppe42-gcc-f36eb1e90c6e27ff4f72826c76afaec43219a8a8.tar.gz
ppe42-gcc-f36eb1e90c6e27ff4f72826c76afaec43219a8a8.zip
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@76352 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/rtl.h2
-rw-r--r--gcc/rtlanal.c39
-rw-r--r--gcc/simplify-rtx.c37
4 files changed, 72 insertions, 15 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index eeee09e71ed..22c095a6254 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2004-01-22 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.
+
2004-01-22 Kazu Hirata <kazu@cs.umass.edu>
* doc/tm.texi (CASE_VECTOR_PC_RELATIVE): Mention that the
diff --git a/gcc/rtl.h b/gcc/rtl.h
index c1949f18e12..7fde7eac820 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1065,6 +1065,8 @@ enum label_kind
/* 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,
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 44a6c6c40f8..4dda1786996 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -3187,48 +3187,59 @@ loc_mentioned_in_p (rtx *loc, rtx in)
return 0;
}
-/* Given a subreg X, return the bit offset where the subreg begins
- (counting from the least significant bit of the reg). */
+/* 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 (rtx x)
+subreg_lsb_1 (enum machine_mode outer_mode,
+ enum machine_mode inner_mode,
+ unsigned int subreg_byte)
{
- 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))
+ 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 (x) % UNITS_PER_WORD
- + GET_MODE_SIZE (mode)) > UNITS_PER_WORD
- && (SUBREG_BYTE (x) % UNITS_PER_WORD
- || GET_MODE_SIZE (mode) % UNITS_PER_WORD))
+ 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 (x) + GET_MODE_SIZE (mode))) / UNITS_PER_WORD;
+ - (subreg_byte + GET_MODE_SIZE (outer_mode))) / UNITS_PER_WORD;
else
- word = SUBREG_BYTE (x) / UNITS_PER_WORD;
+ word = subreg_byte / 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;
+ - (subreg_byte + GET_MODE_SIZE (outer_mode))) % UNITS_PER_WORD;
else
- byte = SUBREG_BYTE (x) % UNITS_PER_WORD;
+ 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.
xregno - A regno of an inner hard subreg_reg (or what will become one).
xmode - The mode of xregno.
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 7272424f8cc..5ba6882e680 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -3379,10 +3379,45 @@ simplify_subreg (enum machine_mode outermode, rtx op,
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. */
+ /* 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;
}
OpenPOWER on IntegriCloud