Make sure we can represent the difference between two 64-bit DImode immediate values in 64-bit HOST_WIDE_INT and return false if this is not the case.
ix86_expand_int_movcc is used in mov<mode>cc expadner. Expander will FAIL when the function returns false and middle-end will retry expansion with values forced to registers. PR target/120604 gcc/ChangeLog: * config/i386/i386-expand.cc (ix86_expand_int_movcc): Make sure we can represent the difference between two 64-bit DImode immediate values in 64-bit HOST_WIDE_INT. Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}. Uros.
diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index 5c8c18f9883..4946f87a131 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -3609,7 +3609,11 @@ ix86_expand_int_movcc (rtx operands[]) negate_cc_compare_p = true; } - diff = (unsigned HOST_WIDE_INT) ct - (unsigned HOST_WIDE_INT) cf; + diff = (unsigned HOST_WIDE_INT) ct - cf; + /* Make sure we can represent the difference between the two values. */ + if ((diff > 0) != ((cf < 0) != (ct < 0) ? cf < 0 : cf < ct)) + return false; + /* Sign bit compares are better done using shifts than we do by using sbb. */ if (sign_bit_compare_p @@ -3668,7 +3672,11 @@ ix86_expand_int_movcc (rtx operands[]) reverse_condition (GET_CODE (compare_op))); } - diff = (unsigned HOST_WIDE_INT) ct - (unsigned HOST_WIDE_INT) cf; + diff = (unsigned HOST_WIDE_INT) ct - cf; + /* Make sure we can represent the difference + between the two values. */ + if ((diff > 0) != ((cf < 0) != (ct < 0) ? cf < 0 : cf < ct)) + return false; if (reg_overlap_mentioned_p (out, compare_op)) tmp = gen_reg_rtx (mode); @@ -3686,8 +3694,12 @@ ix86_expand_int_movcc (rtx operands[]) else { std::swap (ct, cf); - diff = (unsigned HOST_WIDE_INT) ct - - (unsigned HOST_WIDE_INT) cf; + + diff = (unsigned HOST_WIDE_INT) ct - cf; + /* Make sure we can represent the difference + between the two values. */ + if ((diff > 0) != ((cf < 0) != (ct < 0) ? cf < 0 : cf < ct)) + return false; } tmp = emit_store_flag (tmp, code, op0, op1, VOIDmode, 0, -1); } @@ -3754,8 +3766,12 @@ ix86_expand_int_movcc (rtx operands[]) tmp = expand_simple_unop (mode, NOT, tmp, copy_rtx (tmp), 1); } - HOST_WIDE_INT ival = (unsigned HOST_WIDE_INT) cf - - (unsigned HOST_WIDE_INT) ct; + HOST_WIDE_INT ival = (unsigned HOST_WIDE_INT) cf - ct; + /* Make sure we can represent the difference + between the two values. */ + if ((ival > 0) != ((ct < 0) != (cf < 0) ? ct < 0 : ct < cf)) + return false; + tmp = expand_simple_binop (mode, AND, copy_rtx (tmp), gen_int_mode (ival, mode), @@ -3795,7 +3811,13 @@ ix86_expand_int_movcc (rtx operands[]) if (new_code != UNKNOWN) { std::swap (ct, cf); - diff = (unsigned HOST_WIDE_INT) ct - (unsigned HOST_WIDE_INT) cf; + + diff = (unsigned HOST_WIDE_INT) ct - cf; + /* Make sure we can represent the difference + between the two values. */ + if ((diff > 0) != ((cf < 0) != (ct < 0) ? cf < 0 : cf < ct)) + return false; + code = new_code; } } @@ -3998,8 +4020,12 @@ ix86_expand_int_movcc (rtx operands[]) copy_rtx (out), 1, OPTAB_DIRECT); } - HOST_WIDE_INT ival = (unsigned HOST_WIDE_INT) cf - - (unsigned HOST_WIDE_INT) ct; + HOST_WIDE_INT ival = (unsigned HOST_WIDE_INT) cf - ct; + /* Make sure we can represent the difference + between the two values. */ + if ((ival > 0) != ((ct < 0) != (cf < 0) ? ct < 0 : ct < cf)) + return false; + out = expand_simple_binop (mode, AND, copy_rtx (out), gen_int_mode (ival, mode), copy_rtx (out), 1, OPTAB_DIRECT);