aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2001-06-04 20:44:57 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2001-06-04 18:44:57 +0000
commit1ffb3f9ac1b2ad3566c7dde4a2e7dd60ad7ce563 (patch)
tree30475c537d943f52186266be37590ce52d15ae8c
parent978f547fa2d821d32e86fc7ed775750301ace8b5 (diff)
downloadgcc-1ffb3f9ac1b2ad3566c7dde4a2e7dd60ad7ce563.zip
gcc-1ffb3f9ac1b2ad3566c7dde4a2e7dd60ad7ce563.tar.gz
gcc-1ffb3f9ac1b2ad3566c7dde4a2e7dd60ad7ce563.tar.bz2
simplify-rtx.c (simplify_subreg): Fix combining of paradoxical subregs.
* simplify-rtx.c (simplify_subreg): Fix combining of paradoxical subregs. From-SVN: r42868
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/simplify-rtx.c72
2 files changed, 52 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0542181..38d6aaf 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+Mon Jun 4 20:44:25 CEST 2001 Jan Hubicka <jh@suse.cz>
+
+ * simplify-rtx.c (simplify_subreg): Fix combining of
+ paradoxical subregs.
+
Mon Jun 4 20:15:25 CEST 2001 Jan Hubicka <jh@suse.cz>
* rtlanal.c (rtx_unsable_p): ADDRESSOF is stable.
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 574513f..97d6f6b 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -2297,41 +2297,63 @@ simplify_subreg (outermode, op, innermode, byte)
if (GET_CODE (op) == SUBREG)
{
enum machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
- unsigned int final_offset = byte + SUBREG_BYTE (op);
+ int final_offset = byte + SUBREG_BYTE (op);
rtx new;
if (outermode == innermostmode
&& byte == 0 && SUBREG_BYTE (op) == 0)
return SUBREG_REG (op);
- if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
- && GET_MODE_SIZE (innermode) > GET_MODE_SIZE (outermode)
- && GET_MODE_SIZE (innermode) > GET_MODE_SIZE (innermostmode))
+ /* The SUBREG_BYTE represents offset, as if the value were stored
+ in memory. Irritating exception is paradoxical subreg, where
+ we define SUBREG_BYTE to be 0. On big endian machines, this
+ value should be negative. For a moment, undo this exception. */
+ if (byte == 0 && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
{
- /* Inner SUBREG is paradoxical, outer is not. On big endian
- we have to special case this. */
- if (SUBREG_BYTE (op))
- abort(); /* Can a paradoxical subreg have nonzero offset? */
- if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
- final_offset = (byte - GET_MODE_SIZE (innermode)
- + GET_MODE_SIZE (innermostmode));
- else if (WORDS_BIG_ENDIAN)
- final_offset = ((final_offset % UNITS_PER_WORD)
- + ((byte - GET_MODE_SIZE (innermode)
- + GET_MODE_SIZE (innermostmode))
- * UNITS_PER_WORD) / UNITS_PER_WORD);
+ int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
+ if (WORDS_BIG_ENDIAN)
+ final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN)
+ final_offset += difference % UNITS_PER_WORD;
+ }
+ if (SUBREG_BYTE (op) == 0
+ && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode))
+ {
+ int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode));
+ if (WORDS_BIG_ENDIAN)
+ final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN)
+ final_offset += difference % UNITS_PER_WORD;
+ }
+
+ /* See whether resulting subreg will be paradoxical. */
+ if (GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (outermode))
+ {
+ /* In nonparadoxical subregs we can't handle negative offsets. */
+ if (final_offset < 0)
+ return NULL_RTX;
+ /* Bail out in case resulting subreg would be incorrect. */
+ if (final_offset % GET_MODE_SIZE (outermode)
+ || final_offset >= GET_MODE_SIZE (innermostmode))
+ return NULL;
+ }
+ else
+ {
+ int offset = 0;
+ int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (outermode));
+
+ /* In paradoxical subreg, see if we are still looking on lower part.
+ If so, our SUBREG_BYTE will be 0. */
+ if (WORDS_BIG_ENDIAN)
+ offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN)
+ offset += difference % UNITS_PER_WORD;
+ if (offset == final_offset)
+ final_offset = 0;
else
- final_offset = (((final_offset * UNITS_PER_WORD)
- / UNITS_PER_WORD)
- + ((byte - GET_MODE_SIZE (innermode)
- + GET_MODE_SIZE (innermostmode))
- % UNITS_PER_WORD));
+ return NULL;
}
- /* Bail out in case resulting subreg would be incorrect. */
- if (final_offset % GET_MODE_SIZE (outermode)
- || final_offset >= GET_MODE_SIZE (innermostmode))
- return NULL;
/* Recurse for futher possible simplifications. */
new = simplify_subreg (outermode, SUBREG_REG (op),
GET_MODE (SUBREG_REG (op)),