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