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

Reply via email to