diff options
author | Jan Hubicka <jh@suse.cz> | 2001-06-04 20:44:57 +0200 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2001-06-04 18:44:57 +0000 |
commit | 1ffb3f9ac1b2ad3566c7dde4a2e7dd60ad7ce563 (patch) | |
tree | 30475c537d943f52186266be37590ce52d15ae8c | |
parent | 978f547fa2d821d32e86fc7ed775750301ace8b5 (diff) | |
download | gcc-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/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/simplify-rtx.c | 72 |
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)), |