Hi, When combine sees:
(insn 5 2 7 2 (parallel [ (set (reg/f:DI 61) (plus:DI (reg/f:DI 20 frame) (const_int -64 [0xffffffffffffffc0]))) (clobber (reg:CC 17 flags)) ]) x.i:12 252 {*adddi_1} (expr_list:REG_UNUSED (reg:CC 17 flags) (nil))) (insn 17 9 18 2 (parallel [ (set (reg:SI 72) (plus:SI (subreg:SI (reg/f:DI 61) 0) (const_int 6 [0x6]))) (clobber (reg:CC 17 flags)) ]) x.i:14 251 {*addsi_1} (expr_list:REG_DEAD (reg/f:DI 61) (expr_list:REG_UNUSED (reg:CC 17 flags) (nil)))) (insn 18 17 10 2 (set (reg:DI 73) (zero_extend:DI (reg:SI 72))) x.i:14 112 {*zero_extendsidi2_rex64} (expr_list:REG_DEAD (reg:SI 72) (nil))) (insn 11 10 12 2 (set (reg:DI 68) (reg:DI 73)) x.i:14 62 {*movdi_internal_rex64} (expr_list:REG_DEAD (reg:DI 73) (nil))) it was turned into (insn 18 17 10 2 (set (reg:DI 73) (const_int 4294967238 [0xffffffc6])) x.i:14 62 {*movdi_internal_rex64} (nil)) (insn 11 10 12 2 (set (reg:DI 68) (plus:DI (reg/f:DI 20 frame) (reg:DI 73))) x.i:14 247 {*lea_1} (expr_list:REG_DEAD (reg:DI 73) (nil))) force_to_mode has /* If X is a CONST_INT, return a new one. Do this here since the test below will fail. */ if (CONST_INT_P (x)) { if (SCALAR_INT_MODE_P (mode)) return gen_int_mode (INTVAL (x) & mask, mode); else { x = GEN_INT (INTVAL (x) & mask); return gen_lowpart_common (mode, x); } } /* If X is narrower than MODE and we want all the bits in X's mode, just get X in the proper mode. */ if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode) && (GET_MODE_MASK (GET_MODE (x)) & ~mask) == 0) return gen_lowpart (mode, x); When it gets (zero_extend:DI (plus:SI (subreg:SI (reg/f:DI 20 frame) 0) (const_int -58 [0xffffffffffffffc6]))) It first sets mask to 32bit and leads to (subreg:DI (plus:SI (subreg:SI (reg/f:DI 20 frame) 0) (const_int -58 [0xffffffffffffffc6])) 0) with mask == 0xffffffff. The probem is binop: /* For most binary operations, just propagate into the operation and change the mode if we have an operation of that mode. */ op0 = force_to_mode (XEXP (x, 0), mode, mask, next_select); op1 = force_to_mode (XEXP (x, 1), mode, mask, next_select); where it calls force_to_mode with -58, 0xffffffff mask and DImode. This transformation is incorrect. This patch changes mask to MODE_MASK of mode if all the bits in CONST_INT are used. OK for trunk? Thanks. H.J. --- commit 3a590e037128ba64d74fb7b323d2a4d19a02248f Author: H.J. Lu <hjl.to...@gmail.com> Date: Sat May 21 06:20:09 2011 -0700 Properly handle CONST_INT operands. 2011-05-21 H.J. Lu <hongjiu...@intel.com> PR rtl-optimization/49088 * combine.c (force_to_mode): If X is narrower than MODE and we want all the bits in X's mode, just use the operand when it is CONST_INT. diff --git a/gcc/ChangeLog.x32 b/gcc/ChangeLog.x32 index abd57a4..bf844ea 100644 --- a/gcc/ChangeLog.x32 +++ b/gcc/ChangeLog.x32 @@ -1,3 +1,10 @@ +2011-05-21 H.J. Lu <hongjiu...@intel.com> + + PR rtl-optimization/49088 + * combine.c (force_to_mode): If X is narrower than MODE and we + want all the bits in X's mode, just use the operand when it + is CONST_INT. + 2011-05-20 H.J. Lu <hongjiu...@intel.com> PR target/48529 diff --git a/gcc/combine.c b/gcc/combine.c index 8af86f2..710fe0e 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -8321,8 +8321,26 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask, /* For most binary operations, just propagate into the operation and change the mode if we have an operation of that mode. */ - op0 = force_to_mode (XEXP (x, 0), mode, mask, next_select); - op1 = force_to_mode (XEXP (x, 1), mode, mask, next_select); + /* If X is narrower than MODE and we want all the bits in X's + mode, just use the operand when it is CONST_INT. */ + if (SCALAR_INT_MODE_P (mode) + && GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode) + && (GET_MODE_MASK (GET_MODE (x)) & ~mask) == 0) + { + if (CONST_INT_P (XEXP (x, 0))) + op0 = XEXP (x, 0); + else + op0 = force_to_mode (XEXP (x, 0), mode, mask, next_select); + if (CONST_INT_P (XEXP (x, 1))) + op1 = XEXP (x, 1); + else + op1 = force_to_mode (XEXP (x, 1), mode, mask, next_select); + } + else + { + op0 = force_to_mode (XEXP (x, 0), mode, mask, next_select); + op1 = force_to_mode (XEXP (x, 1), mode, mask, next_select); + } /* If we ended up truncating both operands, truncate the result of the operation instead. */