Hello! The core of the problem was in fact the possibility of invalid addresses to sneak through various LEA patterns.
Attached patch adds handling of SImode SUBREGs of addresses to generic code. This way, we can use one LEA pattern that accepts all valid address RTXes (modulo segment prefixed ones). 2012-07-22 Uros Bizjak <ubiz...@gmail.com> PR target/53961 * config/i386/i386.md (*lea): New insn pattern. (*lea_1): Remove. (*lea<mode>_2): Ditto. (*lea_{3,4,5,6}_zext): Ditto. * config/i386/constraints.md (j): Remove address constraint. * config/i386/i386.c (ix86_decompose_address): Allow SImode subreg of an address. (ix86_print_operand_address): Handle SImode subreg of an address. (ix86_avoid_lea_for_add): Reject zero-extended addresses for now. Patch was bootstrapped and regression tested on x86_64-pc-linux-gnu {,-m32}. I have also compiled a bunch of x32 testcases and there were no code changes. I have committed patch to mainline SVN, and will keep an eye on x32 regression testers. Uros.
Index: i386.c =================================================================== --- i386.c (revision 189746) +++ i386.c (working copy) @@ -11576,9 +11576,18 @@ 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. */ - if (TARGET_64BIT && GET_MODE (addr) == DImode) + else if (TARGET_64BIT && GET_MODE (addr) == DImode) { if (GET_CODE (addr) == ZERO_EXTEND && GET_MODE (XEXP (addr, 0)) == SImode) @@ -14755,10 +14764,10 @@ ix86_print_operand_address (FILE *file, rtx addr) } else { - /* Print SImode register names for zero-extended - addresses to force addr32 prefix. */ + /* Print SImode register names to force addr32 prefix. */ if (TARGET_64BIT - && (GET_CODE (addr) == ZERO_EXTEND + && (GET_CODE (addr) == SUBREG + || GET_CODE (addr) == ZERO_EXTEND || GET_CODE (addr) == AND)) { gcc_assert (!code); @@ -16855,6 +16864,11 @@ ix86_avoid_lea_for_add (rtx insn, rtx operands[]) unsigned int regno1 = true_regnum (operands[1]); unsigned int regno2 = true_regnum (operands[2]); + /* FIXME: Handle zero-extended addresses. */ + if (GET_CODE (operands[1]) == ZERO_EXTEND + || GET_CODE (operands[1]) == AND) + return false; + /* Check if we need to optimize. */ if (!TARGET_OPT_AGU || optimize_function_for_size_p (cfun)) return false; Index: predicates.md =================================================================== --- predicates.md (revision 189746) +++ predicates.md (working copy) @@ -830,11 +830,6 @@ struct ix86_address parts; int ok; - /* LEA handles zero-extend by itself. */ - if (GET_CODE (op) == ZERO_EXTEND - || GET_CODE (op) == AND) - return false; - ok = ix86_decompose_address (op, &parts); gcc_assert (ok); return parts.seg == SEG_DEFAULT; Index: constraints.md =================================================================== --- constraints.md (revision 189746) +++ constraints.md (working copy) @@ -19,7 +19,7 @@ ;;; Unused letters: ;;; B H T -;;; h k v +;;; h jk v ;; Integer register constraints. ;; It is not necessary to define 'r' here. @@ -133,11 +133,6 @@ (and (not (match_test "TARGET_X32")) (match_operand 0 "memory_operand"))) -(define_address_constraint "j" - "@internal Address operand that can be zero extended in LEA instruction." - (and (not (match_code "const_int")) - (match_operand 0 "address_operand"))) - ;; Integer constant constraints. (define_constraint "I" "Integer constant in the range 0 @dots{} 31, for 32-bit shifts." Index: i386.md =================================================================== --- i386.md (revision 189746) +++ i386.md (working copy) @@ -5508,25 +5508,21 @@ [(set_attr "type" "alu") (set_attr "mode" "QI")]) -(define_insn_and_split "*lea_1" - [(set (match_operand:SI 0 "register_operand" "=r") - (subreg:SI (match_operand:DI 1 "lea_address_operand" "p") 0))] - "TARGET_64BIT" - "lea{l}\t{%E1, %0|%0, %E1}" - "&& reload_completed && ix86_avoid_lea_for_addr (insn, operands)" - [(const_int 0)] -{ - ix86_split_lea_for_addr (operands, SImode); - DONE; -} - [(set_attr "type" "lea") - (set_attr "mode" "SI")]) - -(define_insn_and_split "*lea<mode>_2" +(define_insn_and_split "*lea<mode>" [(set (match_operand:SWI48 0 "register_operand" "=r") (match_operand:SWI48 1 "lea_address_operand" "p"))] "" - "lea{<imodesuffix>}\t{%E1, %0|%0, %E1}" +{ + rtx addr = operands[1]; + + if (GET_CODE (addr) == SUBREG) + 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}"; + else + return "lea{<imodesuffix>}\t{%E1, %0|%0, %E1}"; +} "reload_completed && ix86_avoid_lea_for_addr (insn, operands)" [(const_int 0)] { @@ -5536,44 +5532,6 @@ [(set_attr "type" "lea") (set_attr "mode" "<MODE>")]) -(define_insn "*lea_3_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (subreg:SI (match_operand:DI 1 "lea_address_operand" "j") 0)))] - "TARGET_64BIT" - "lea{l}\t{%E1, %k0|%k0, %E1}" - [(set_attr "type" "lea") - (set_attr "mode" "SI")]) - -(define_insn "*lea_4_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (match_operand:SI 1 "lea_address_operand" "j")))] - "TARGET_64BIT" - "lea{l}\t{%E1, %k0|%k0, %E1}" - [(set_attr "type" "lea") - (set_attr "mode" "SI")]) - -(define_insn "*lea_5_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (and:DI - (subreg:DI (match_operand:SI 1 "lea_address_operand" "p") 0) - (match_operand:DI 2 "const_32bit_mask" "n")))] - "TARGET_64BIT" - "lea{l}\t{%E1, %k0|%k0, %E1}" - [(set_attr "type" "lea") - (set_attr "mode" "SI")]) - -(define_insn "*lea_6_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (and:DI - (match_operand:DI 1 "lea_address_operand" "p") - (match_operand:DI 2 "const_32bit_mask" "n")))] - "TARGET_64BIT" - "lea{l}\t{%E1, %k0|%k0, %E1}" - [(set_attr "type" "lea") - (set_attr "mode" "SI")]) - (define_insn "*add<mode>_1" [(set (match_operand:SWI48 0 "nonimmediate_operand" "=r,rm,r,r") (plus:SWI48