For LEA operation with SImode_address_operand, which zero-extends SImode to DImode, ix86_split_lea_for_addr turns
(set (reg:DI) ...) into (set (reg:SI) ...) We need to do (set (reg:DI) (zero_extend:DI (reg:SI))) at the end. If the LEA operation is (set (reg:DI) (zero_extend:DI (reg:SI))) we don't need to do it twice. This patch implements above. Tested on Linux/x86-64 without regressions. OK for trunk and release branches? Thanks. H.J. --- 2014-01-18 H.J. Lu <hongjiu...@intel.com> PR target/59379 * config/i386/i386.c (ix86_split_lea_for_addr): Properly zero-extends SImode to DImode. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index ff210c8..346b0cb 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -18342,6 +18342,23 @@ ix86_split_lea_for_addr (rtx insn, rtx operands[], enum machine_mode mode) } else { + if (mode != GET_MODE (operands[0])) + { + gcc_assert (mode == SImode && GET_MODE (operands[0]) == DImode); + if ((!parts.disp || parts.disp == const0_rtx) + && ((parts.base && !parts.index) + || (!parts.base && parts.index))) + { + if (parts.base) + emit_insn (gen_zero_extendsidi2 (operands[0], + parts.base)); + else + emit_insn (gen_zero_extendsidi2 (operands[0], + parts.index)); + return; + } + } + if (!parts.base) { if (regno0 != regno2) @@ -18375,7 +18392,7 @@ ix86_split_lea_for_addr (rtx insn, rtx operands[], enum machine_mode mode) ix86_emit_binop (PLUS, mode, target, parts.disp); ix86_emit_binop (PLUS, mode, target, tmp1); - return; + goto check_mode; } ix86_emit_binop (PLUS, mode, target, tmp); @@ -18384,6 +18401,13 @@ ix86_split_lea_for_addr (rtx insn, rtx operands[], enum machine_mode mode) if (parts.disp && parts.disp != const0_rtx) ix86_emit_binop (PLUS, mode, target, parts.disp); } + +check_mode: + if (mode != GET_MODE (operands[0])) + { + gcc_assert (mode == SImode && GET_MODE (operands[0]) == DImode); + emit_insn (gen_zero_extendsidi2 (operands[0], target)); + } } /* Return true if it is ok to optimize an ADD operation to LEA