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

            Bug ID: 126590
           Summary: [16/17 Regression] Wrong code with
                    vect_gen_vector_loop_niters and non-pow2 VF
           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: ---

/* Candidate: tree-vect-loop-manip.cc:3077 (vect_gen_vector_loop_niters).

   vect_gen_vector_loop_niters, !niters_no_overflow path, guards only on
   "const_vf > 1" instead of pow2p_hwi (const_vf) before using
   exact_log2 (const_vf) as a wi::rshift amount.  exact_log2 returns -1 for a
   non-power-of-two VF, wi::lrshift treats the -1 shift amount as >= precision
   and yields 0, so the recorded upper bound collapses to 0 + 1 == 1 and the
   vector-loop trip count SSA name "bnd" gets the global range [1, 1].  The
   vector loop is then provably single-trip, so all but the first VF elements
   are dropped.

   "#pragma GCC unroll 12" with an assumed VF of 4 makes
   tree-vect-loop.cc give suggested_unroll_factor = 3 and
   LOOP_VINFO_VECT_FACTOR = 12, a non-power-of-two constant VF.
   -march=armv8-a (generic tuning, no simd_issue_info) makes aarch64's own
   determine_suggested_unroll_factor return 1, so the user-pragma path is the
   one that sets the unroll factor and it is not rounded up to a power of two.
   The do-while with "!=" lets niters wrap (n == 0 means 2^32 iterations), so
   loop_niters_no_overflow () is false and the buggy branch is taken.

   Dump evidence (-fdump-tree-vect-details):
     optimized: loop vectorized using 16 byte vectors and unroll factor 12
     Global Exported: bnd.7_28 = [irange] unsigned int [1, 1]
   With "unroll 8" or "unroll 16" the same dump instead shows
   [1, 536870912] / [1, 268435456] and the program is correct, which pins the
   fault on the non-power-of-two shift amount.

   Observed: only a[0..21] are incremented, a[22..999] stay 0.  */

__attribute__((noipa))
void f (unsigned int *a, unsigned int n)
{
  unsigned int i = 0;
  unsigned int *p = a;
#pragma GCC unroll 12
  do
    *p++ += 1;
  while (++i != n);
}

int
main (void)
{
  static unsigned int a[1000];
  f (a, 1000);
  for (unsigned int i = 0; i < 1000; i++)
    if (a[i] != 1)
      __builtin_abort ();
  return 0;
}

Aborts on aarch64 at -O3 and passes at -O1

Reply via email to