https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98069

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |rsandifo at gcc dot gnu.org

--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> ---
So before vectorization we have

  var_3.0_1 = var_3;
  iftmp.3_10 = var_3.0_1 != 0 ? -2147483648 : 0;
  _2 = (int) iftmp.3_10;
  d_11 = -2147483648 - _2;

which should compute to 0.  Now somewhere (split_constant_offset I'd bet)
things go wrong and we produce in dataref analysis

        base_address: &arr_165
        offset from base address: (ssizetype) ((sizetype) -_2 * 2)
        constant offset from base address: -4294967296
        step: 2
        base alignment: 32
        base misalignment: 0
        offset alignment: 2
        step alignment: 2
        base_object: arr_165
        Access function 0: {d_11, +, 1}_2

from { ((sizetype) d_21) * 2, +, 2 }_2 as offset IV which split_constant_offset
makes into { (sizetype) -_2 * 2, +, 2 }_2 + -4294967296.

The logic is that we can dive into the (sizetype) extension from int since
the operation on int cannot overflow (undefined behavior).  We then
strip the -2147483648 constant, thinking we can associate this as
(sizetype)(0 - _2) + -2147483648 but of course 0 - _2 now overflows
and we happily fold it to -_2.  So here:

static bool
split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1,
                         tree *var, tree *off,
                         hash_map<tree, std::pair<tree, tree> > &cache,
                         unsigned *limit)
{
...
    case PLUS_EXPR:
    case MINUS_EXPR:
      if (TREE_CODE (op1) == INTEGER_CST)
        {
          split_constant_offset (op0, &var0, &off0, cache, limit);
          *var = var0;
          *off = size_binop (ocode, off0, fold_convert (ssizetype, op1));
          return true;
        }
      split_constant_offset (op0, &var0, &off0, cache, limit);
      split_constant_offset (op1, &var1, &off1, cache, limit);
      *var = fold_build2 (code, type, var0, var1);

we have to make sure that the expression we fold cannot overflow or
use unsigned arithmetic.  In fact, using unsigned arithmetic looks like
the only reasonable thing since splitting out any constant is not
trivially valid.  We're doing

 (var0 + off0) +- (var1 + off1) -> (var0 +- var1) + (off0 + off1)

where we know the left side doesn't overflow.

This makes associating across the multiplication invalid where we do

 ((sizetype) (A +- B)) * 2 -> ((sizetype) A) * 2 +- B * 2

and thus from 0 * 2 we go to -2147483648 * 2 + -4294967296.  Using
unsigned arithmetic to make the inner op no longer undefined doesn't
help here.

So it looks like we cannot use TYPE_OVERFLOW_UNDEFINED to validate
looking across widening conversions.  Which points to the same area
as PR97960.

Reply via email to