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]; +}