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

            Bug ID: 126594
           Summary: [16/17 Regression] Wrong code with early-break
                    vectorisation and vect_peel_nonlinear_iv_init
           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: ---

/* tree-vect-loop.cc:9066 -- vect_peel_nonlinear_iv_init switches off the
   out-of-range shift-count guard on the early-break path (the `&&
!early_exit_p`
   conjunct), so the scalar epilogue's start value for a `x >>= c` / `x <<= c`
   induction is computed as a bare `init >> (K*step)` with a *runtime* K.  Once
   K*step >= the type precision that expression is undefined in GIMPLE and on
   aarch64 it degenerates to a shift by (K*step % prec), so the epilogue starts
   from a wrong value instead of 0.


   The array must be file scope and over-aligned.  With unknown alignment the
   early break forces peeling for alignment and vect_can_peel_nonlinear_iv_p
   rejects the nonlinear IV, which masks the bug. */

int a[256] __attribute__((aligned (64)));

__attribute__((noipa)) unsigned
f_shr (void)
{
  unsigned x = 0x80000000u;
  for (int i = 0; i < 100; i++) /* constant trip count is required */
    {
      if (a[i] == 42)
        break;                  /* early exit */
      x >>= 1;                  /* vect_step_op_shr, step 1 */
    }
  return x;                     /* live out => EARLY_BRK_NEEDS_EPILOG */
}

__attribute__((noipa)) unsigned
f_shl (void)
{
  unsigned x = 1;
  for (int i = 0; i < 100; i++)
    {
      if (a[i] == 42)
        break;
      x <<= 1;                  /* vect_step_op_shl, step 1 */
    }
  return x;
}

int
main (void)
{
  for (int k = 0; k < 100; k++)
    {
      for (int i = 0; i < 256; i++)
        a[i] = 1;
      a[k] = 42;

      /* k shifts of a 32-bit unsigned: the value is 0 once k >= 32.  */
      unsigned want_shr = k >= 32 ? 0u : (0x80000000u >> k);
      unsigned got_shr = f_shr ();
      if (got_shr != want_shr)
        __builtin_abort ();

      unsigned want_shl = k >= 32 ? 0u : (1u << k);
      unsigned got_shl = f_shl ();
      if (got_shl != want_shl)
        __builtin_abort ();
    }
  return 0;
}

aborts on aarch64 at -O3 and passes without vectorisation

Reply via email to