Bug 110760 - slp introduces new overflow arithmetic
Summary: slp introduces new overflow arithmetic
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 14.0
: P3 normal
Target Milestone: ---
Assignee: Richard Biener
URL:
Keywords: wrong-code
Depends on:
Blocks: vectorizer 118443
  Show dependency treegraph
 
Reported: 2023-07-20 22:42 UTC by Krister Walfridsson
Modified: 2025-01-13 00:35 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2023-07-21 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Krister Walfridsson 2023-07-20 22:42:24 UTC
Consider the following function from gcc.dg/vect/bb-slp-layout-5.c:

int a[4], b[4], c[4];

void f1()
{
  a[0] = b[3] - c[3];
  a[1] = b[2] + c[2];
  a[2] = b[1] - c[1];
  a[3] = b[0] + c[0];
}

This is vectorized by slp2:
  vector(4) int vect__1.5;
  vector(4) int vect__2.8;
  vector(4) int vect__12.10;
  vector(4) int vect__3.9;
  vector(4) int _22;
  vect__1.5_18 = MEM <vector(4) int> [(int *)&b];
  vect__2.8_19 = MEM <vector(4) int> [(int *)&c];
  vect__12.10_21 = vect__1.5_18 + vect__2.8_19;
  vect__3.9_20 = vect__1.5_18 - vect__2.8_19;
  _22 = VEC_PERM_EXPR <vect__3.9_20, vect__12.10_21, { 3, 6, 1, 4 }>;
  MEM <vector(4) int> [(int *)&a] = _22;

But this introduces new calculations in the temporary vectors of the unused elements:
  b[0] - c[0];
  b[1] + c[1];
  b[2] - c[2];
  b[3] + c[3];
and these calculations may wrap for input where the original program did not wrap.
Comment 1 Andrew Pinski 2023-07-20 22:45:29 UTC
I thought we decided that vector types don't apply the overflow rules and always just wrap ...
Comment 2 Andrew Pinski 2023-07-20 22:46:42 UTC
>these calculations may wrap

You mean overflow rather than wrap. Wrapping is a defined behavior while overflow is what is considered undefined ...
Comment 3 Krister Walfridsson 2023-07-20 23:29:13 UTC
(In reply to Andrew Pinski from comment #1)
> I thought we decided that vector types don't apply the overflow rules and
> always just wrap ...

That makes sense. But on the other hand, PR 110495 is a similar issue, and that was fixed...

And TYPE_OVERFLOW_WRAPS should return true for integer vectors if they always wrap (or is it only valid for scalars? But ANY_INTEGRAL_TYPE_P is careful to handle vectors and complex numbers too, so I thought the ANY_INTEGRAL_TYPE_CHECK in TYPE_OVERFLOW_WRAPS means that it work for vectors too).
Comment 4 Andrew Pinski 2023-07-20 23:46:43 UTC
(In reply to Krister Walfridsson from comment #3)
> (In reply to Andrew Pinski from comment #1)
> > I thought we decided that vector types don't apply the overflow rules and
> > always just wrap ...
> 
> That makes sense. But on the other hand, PR 110495 is a similar issue, and
> that was fixed...
> 
> And TYPE_OVERFLOW_WRAPS should return true for integer vectors if they
> always wrap (or is it only valid for scalars? But ANY_INTEGRAL_TYPE_P is
> careful to handle vectors and complex numbers too, so I thought the
> ANY_INTEGRAL_TYPE_CHECK in TYPE_OVERFLOW_WRAPS means that it work for
> vectors too).

That is slightly different, it was introducing -2(OVF) too.
Comment 5 Richard Biener 2023-07-21 07:03:22 UTC
Vector types follow the same rules as scalar types because we eventually lower them to scalar ops.  So yes, I think this is a bug.

Now, it will be difficult to exploit since the values are not actually used.

One trick would be to CSE with a later


  tem = (unsigned)b[1] - (unsigned)c[1];

where for scalar code FRE would eliminate the above with the earlier a[2]
doing

  tem = (unsigned)a[2];

but it currently doesn't do that for vectors and as the vectorizer introduces
the wrong behavior we are not going to decompose that to scalars either.

The particular case in question should be easy to fix though.