OSDN Git Service

* simplify-rtx.c (simplify_subreg): Fix combining of
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 4 Jun 2001 18:44:57 +0000 (18:44 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 4 Jun 2001 18:44:57 +0000 (18:44 +0000)
paradoxical subregs.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@42868 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/simplify-rtx.c

index 0542181..38d6aaf 100644 (file)
@@ -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.
index 574513f..97d6f6b 100644 (file)
@@ -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)),