Hello!

On a register starved i686, the relaxation that we allow DImode values
in addresses can lead to register shortages and spill failures.

Attached patch puts back the requirement that we allow subregs up to
and including WORD_MODE width, nicely packed in a new function.

2011-08-01  Uros Bizjak  <ubiz...@gmail.com>

        PR target/49927
        * config/i386/i386.c (ix86_address_subreg_operand): New.
        (ix86_decompose_address): Use ix86_address_subreg_operand.
        (ix86_legitimate_address_p): Do not assert that subregs satisfy
        register_no_elim_operand in DImode.

testsuite/ChangeLog:

2011-08-01  Uros Bizjak  <ubiz...@gmail.com>

        PR target/49927
        * gcc.target/i386/pr49927.c: New test.

Tested on x86_64-pc-linux-gnu {,-m32}, committed to mainline SVN.

Uros.
Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c  (revision 177036)
+++ config/i386/i386.c  (working copy)
@@ -11096,6 +11096,30 @@ ix86_live_on_entry (bitmap regs)
     }
 }
 
+/* Determine if op is suitable SUBREG RTX for address.  */
+
+static bool
+ix86_address_subreg_operand (rtx op)
+{
+  enum machine_mode mode;
+
+  if (!REG_P (op))
+    return false;
+
+  mode = GET_MODE (op);
+
+  if (GET_MODE_CLASS (mode) != MODE_INT)
+    return false;
+
+  /* Don't allow SUBREGs that span more than a word.  It can lead to spill
+     failures when the register is one word out of a two word structure.  */
+  if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+    return false;
+
+  /* Allow only SUBREGs of non-eliminable hard registers.  */
+  return register_no_elim_operand (op, mode);
+}
+
 /* Extract the parts of an RTL expression that is a valid memory address
    for an instruction.  Return 0 if the structure of the address is
    grossly off.  Return -1 if the address contains ASHIFT, so it is not
@@ -11116,8 +11140,7 @@ ix86_decompose_address (rtx addr, struct
     base = addr;
   else if (GET_CODE (addr) == SUBREG)
     {
-      /* Allow only subregs of DImode hard regs.  */
-      if (register_no_elim_operand (SUBREG_REG (addr), DImode))
+      if (ix86_address_subreg_operand (SUBREG_REG (addr)))
        base = addr;
       else
        return 0;
@@ -11175,8 +11198,7 @@ ix86_decompose_address (rtx addr, struct
              break;
 
            case SUBREG:
-             /* Allow only subregs of DImode hard regs in PLUS chains.  */
-             if (!register_no_elim_operand (SUBREG_REG (op), DImode))
+             if (!ix86_address_subreg_operand (SUBREG_REG (op)))
                return 0;
              /* FALLTHRU */
 
@@ -11228,9 +11250,8 @@ ix86_decompose_address (rtx addr, struct
     {
       if (REG_P (index))
        ;
-      /* Allow only subregs of DImode hard regs.  */
       else if (GET_CODE (index) == SUBREG
-              && register_no_elim_operand (SUBREG_REG (index), DImode))
+              && ix86_address_subreg_operand (SUBREG_REG (index)))
        ;
       else
        return 0;
@@ -11677,10 +11698,7 @@ ix86_legitimate_address_p (enum machine_
       if (REG_P (base))
        reg = base;
       else if (GET_CODE (base) == SUBREG && REG_P (SUBREG_REG (base)))
-       {
-         reg = SUBREG_REG (base);
-         gcc_assert (register_no_elim_operand (reg, DImode));
-       }
+       reg = SUBREG_REG (base);
       else
        /* Base is not a register.  */
        return false;
@@ -11702,10 +11720,7 @@ ix86_legitimate_address_p (enum machine_
       if (REG_P (index))
        reg = index;
       else if (GET_CODE (index) == SUBREG && REG_P (SUBREG_REG (index)))
-       {
-         reg = SUBREG_REG (index);
-         gcc_assert (register_no_elim_operand (reg, DImode));
-       }
+       reg = SUBREG_REG (index);
       else
        /* Index is not a register.  */
        return false;
Index: testsuite/gcc.target/i386/pr49927.c
===================================================================
--- testsuite/gcc.target/i386/pr49927.c (revision 0)
+++ testsuite/gcc.target/i386/pr49927.c (revision 0)
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+char a[1][1];
+long long b;
+
+void
+foo (void)
+{
+  --a[b][b];
+}

Reply via email to