Hello! Attached patch further improves ix86_decompose_address to allow (zero_extend:DI (subreg:SI (...))) addresses and prevent zero extended CONST_INT operands (as was previously the case with LEA operands only). This improvement allows us to put quite some asserts to strategic places, in order to detect invalid addresses before they generate invalid code.
2012-07-23 Uros Bizjak <ubiz...@gmail.com> PR target/53961 * config/i386/i386.md (*lea): Add asserts to detect invalid addresses. * config/i386/i386.c (ix86_print_operand_address): Ditto. (ix86_decompose_address): Allow (zero_extend:DI (subreg:SI (...))) addresses. Prevent zero extensions of CONST_INT operands. Tested on x86_64-pc-linux-gnu {,-m32} and committed to mainline SVN. I will again watch x32 autotesters for possible breakage. Uros.
Index: config/i386/i386.md =================================================================== --- config/i386/i386.md (revision 189786) +++ config/i386/i386.md (working copy) @@ -5458,10 +5458,19 @@ rtx addr = operands[1]; if (GET_CODE (addr) == SUBREG) - return "lea{l}\t{%E1, %0|%0, %E1}"; + { + gcc_assert (TARGET_64BIT); + gcc_assert (<MODE>mode == SImode); + gcc_assert (GET_MODE (SUBREG_REG (addr)) == DImode); + return "lea{l}\t{%E1, %0|%0, %E1}"; + } else if (GET_CODE (addr) == ZERO_EXTEND || GET_CODE (addr) == AND) - return "lea{l}\t{%E1, %k0|%k0, %E1}"; + { + gcc_assert (TARGET_64BIT); + gcc_assert (<MODE>mode == DImode); + return "lea{l}\t{%E1, %k0|%k0, %E1}"; + } else return "lea{<imodesuffix>}\t{%E1, %0|%0, %E1}"; } Index: config/i386/i386.c =================================================================== --- config/i386/i386.c (revision 189786) +++ config/i386/i386.c (working copy) @@ -11576,22 +11576,17 @@ ix86_decompose_address (rtx addr, struct ix86_addr int retval = 1; enum ix86_address_seg seg = SEG_DEFAULT; - /* Allow SImode subregs of DImode addresses, - they will be emitted with addr32 prefix. */ - if (TARGET_64BIT && GET_MODE (addr) == SImode) - { - if (GET_CODE (addr) == SUBREG - && GET_MODE (XEXP (addr, 0)) == DImode) - addr = SUBREG_REG (addr); - } - /* Allow zero-extended SImode addresses, they will be emitted with addr32 prefix. */ - else if (TARGET_64BIT && GET_MODE (addr) == DImode) + if (TARGET_64BIT && GET_MODE (addr) == DImode) { if (GET_CODE (addr) == ZERO_EXTEND && GET_MODE (XEXP (addr, 0)) == SImode) - addr = XEXP (addr, 0); + { + addr = XEXP (addr, 0); + if (CONST_INT_P (addr)) + return 0; + } else if (GET_CODE (addr) == AND && const_32bit_mask (XEXP (addr, 1), DImode)) { @@ -11600,7 +11595,11 @@ ix86_decompose_address (rtx addr, struct ix86_addr /* Adjust SUBREGs. */ if (GET_CODE (addr) == SUBREG && GET_MODE (SUBREG_REG (addr)) == SImode) - addr = SUBREG_REG (addr); + { + addr = SUBREG_REG (addr); + if (CONST_INT_P (addr)) + return 0; + } else if (GET_MODE (addr) == DImode) addr = gen_rtx_SUBREG (SImode, addr, 0); else if (GET_MODE (addr) != VOIDmode) @@ -11608,6 +11607,19 @@ ix86_decompose_address (rtx addr, struct ix86_addr } } + /* Allow SImode subregs of DImode addresses, + they will be emitted with addr32 prefix. */ + if (TARGET_64BIT && GET_MODE (addr) == SImode) + { + if (GET_CODE (addr) == SUBREG + && GET_MODE (SUBREG_REG (addr)) == DImode) + { + addr = SUBREG_REG (addr); + if (CONST_INT_P (addr)) + return 0; + } + } + if (REG_P (addr)) base = addr; else if (GET_CODE (addr) == SUBREG) @@ -14765,14 +14777,22 @@ ix86_print_operand_address (FILE *file, rtx addr) else { /* Print SImode register names to force addr32 prefix. */ - if (TARGET_64BIT - && (GET_CODE (addr) == SUBREG - || GET_CODE (addr) == ZERO_EXTEND - || GET_CODE (addr) == AND)) + if (GET_CODE (addr) == SUBREG) { + gcc_assert (TARGET_64BIT); + gcc_assert (GET_MODE (addr) == SImode); + gcc_assert (GET_MODE (SUBREG_REG (addr)) == DImode); gcc_assert (!code); code = 'l'; } + else if (GET_CODE (addr) == ZERO_EXTEND + || GET_CODE (addr) == AND) + { + gcc_assert (TARGET_64BIT); + gcc_assert (GET_MODE (addr) == DImode); + gcc_assert (!code); + code = 'l'; + } if (ASSEMBLER_DIALECT == ASM_ATT) {