wide-int adds some code to div_if_zero_remainder to handle mismatched signs. I think it's trying to make sure that we do the division to "infinite" precision, extending each operand according to its own sign. We can do that more easily using wi::to_widest. Using to::widest should also be chaper.
Tested on powerpc64-linux-gnu and by rerunning the assembly comparison. OK to install? Thanks, Richard Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c 2013-11-09 09:39:28.207810833 +0000 +++ gcc/fold-const.c 2013-11-09 09:39:29.198817531 +0000 @@ -170,31 +170,10 @@ protected_set_expr_location_unshare (tre tree div_if_zero_remainder (const_tree arg1, const_tree arg2) { - wide_int quo; - wide_int warg1 = arg1; - wide_int warg2 = arg2; - signop sgn = TYPE_SIGN (TREE_TYPE (arg1)); - signop sgn2 = TYPE_SIGN (TREE_TYPE (arg2)); + widest_int quo; - if (sgn != sgn2) - { - /* When signedness mismatches, we promote the unsigned value to - a signed value. We preserve the value by extending the - precision by 1 bit, iff the top bit is set. */ - if (sgn == UNSIGNED) - { - if (wi::neg_p (warg1)) - warg1 = wide_int::from (warg1, warg1.get_precision () + 1, sgn); - sgn = SIGNED; - } - else - { - if (wi::neg_p (warg2)) - warg2 = wide_int::from (warg2, warg2.get_precision () + 1, sgn2); - } - } - - if (wi::multiple_of_p (warg1, warg2, sgn, &quo)) + if (wi::multiple_of_p (wi::to_widest (arg1), wi::to_widest (arg2), + SIGNED, &quo)) return wide_int_to_tree (TREE_TYPE (arg1), quo); return NULL_TREE;