Hi!

When val_so_far is signed, we can end up in UB in various places, e.g.
for the multiplication by 0x7fffffffffffffff, which is done as << 63 shift
followed by subtracting one.

Fixed by computing this in UHWI instead, and only cast at the end to SHWI.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-08-16  Jakub Jelinek  <ja...@redhat.com>

        PR middle-end/67485
        * expmed.c (expand_mult_const): Change val_so_far's type to UHWI,
        only cast it to SHWI for the final comparison.

        * gcc.c-torture/compile/pr67485.c: New test.

--- gcc/expmed.c.jj     2016-08-12 17:33:46.000000000 +0200
+++ gcc/expmed.c        2016-08-15 13:45:59.197300977 +0200
@@ -3055,7 +3055,7 @@ expand_mult_const (machine_mode mode, rt
                   rtx target, const struct algorithm *alg,
                   enum mult_variant variant)
 {
-  HOST_WIDE_INT val_so_far;
+  unsigned HOST_WIDE_INT val_so_far;
   rtx_insn *insn;
   rtx accum, tem;
   int opno;
@@ -3105,14 +3105,14 @@ expand_mult_const (machine_mode mode, rt
          tem = expand_shift (LSHIFT_EXPR, mode, op0, log, NULL_RTX, 0);
          accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
                                 add_target ? add_target : accum_target);
-         val_so_far += HOST_WIDE_INT_1 << log;
+         val_so_far += HOST_WIDE_INT_1U << log;
          break;
 
        case alg_sub_t_m2:
          tem = expand_shift (LSHIFT_EXPR, mode, op0, log, NULL_RTX, 0);
          accum = force_operand (gen_rtx_MINUS (mode, accum, tem),
                                 add_target ? add_target : accum_target);
-         val_so_far -= HOST_WIDE_INT_1 << log;
+         val_so_far -= HOST_WIDE_INT_1U << log;
          break;
 
        case alg_add_t2_m:
@@ -3188,7 +3188,7 @@ expand_mult_const (machine_mode mode, rt
   nmode = GET_MODE_INNER (mode);
   val &= GET_MODE_MASK (nmode);
   val_so_far &= GET_MODE_MASK (nmode);
-  gcc_assert (val == val_so_far);
+  gcc_assert (val == (HOST_WIDE_INT) val_so_far);
 
   return accum;
 }
--- gcc/testsuite/gcc.c-torture/compile/pr67485.c.jj    2016-08-15 
13:48:13.747639954 +0200
+++ gcc/testsuite/gcc.c-torture/compile/pr67485.c       2016-08-15 
13:48:17.113598401 +0200
@@ -0,0 +1,7 @@
+/* PR middle-end/67485 */
+
+long int
+foo (long int x)
+{
+  return x * __LONG_MAX__;
+}

        Jakub

Reply via email to