https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126593
Bug ID: 126593
Summary: [13/14/15/16/17 Regression] Wrong code with complex
mul and compatible_complex_nodes_p
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: ktkachov at gcc dot gnu.org
Target Milestone: ---
/* Wrong code: tree-vect-slp-patterns.cc:805, compatible_complex_nodes_p.
The REALPART_EXPR/IMAGPART_EXPR shortcut
if ((acode == REALPART_EXPR || acode == IMAGPART_EXPR)
&& (bcode == REALPART_EXPR || bcode == IMAGPART_EXPR))
return true;
returns before the same_data_refs () test further down, so two loads that
come from two *different* _Complex arrays are accepted as the real and the
imaginary half of one complex value. complex_mul_pattern::build then emits
IFN_COMPLEX_MUL using only one of the two operand nodes, and the other array
is dropped from the computation entirely.
Here the loop mixes b and d. The vectoriser turns it into
.COMPLEX_MUL (b, a) and never loads d. */
#define N 64
_Complex float a[N], b[N], d[N], c[N];
__attribute__((noipa))
void mix (int n)
{
for (int i = 0; i < n; i++)
{
__real__ c[i] = __real__ a[i] * __real__ b[i] - __imag__ a[i] * __imag__
d[i];
__imag__ c[i] = __real__ a[i] * __imag__ b[i] + __imag__ a[i] * __real__
d[i];
}
}
int main (void)
{
for (int i = 0; i < N; i++)
{ a[i] = 1.0f + 2.0fi; b[i] = 3.0f + 4.0fi; d[i] = 5.0f + 6.0fi; }
mix (N);
/* scalar: re = 1*3 - 2*6 = -9, im = 1*4 + 2*5 = 14.
vectorised: d is dropped and a*b is computed: re = -5, im = 10. */
if (__real__ c[0] != -9.0f || __imag__ c[0] != 14.0f)
__builtin_abort ();
return 0;
}
aborts on aarch64 at -O3 -march=armv8.3-a and passes without these flags