llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.36k stars 12.14k forks source link

Scalar Evolution fails to find constant trip count #28803

Open cddouma-arm opened 8 years ago

cddouma-arm commented 8 years ago
Bugzilla Link 28429
Version trunk
OS All
CC @hfinkel,@sanjoy
cddouma-arm commented 8 years ago

The following loop is not unrolled because the trip count is not simple constant:

void foo(int x, int *p) { x += 2; //any value bigger than 1 for (int i = x; i <= x+1; ++i) p[i] = i; }

The attached IR is generated compiling the above source with: ./bin/clang --target=aarch64-arm-none-eabi -mllvm -debug-only=loop-unroll -O3

SCEV find the trip count as: (-2 + (-1 * %x) + ((2 + %x) smax (3 + %x)))

This expression can be simplified into a constant if the arguments of smax are not wrapping. But while the original source has non-wrapping expressions, they are not marked as such by SCEV. Reason is that SCEV considers these expressions possible poison values and marks them as wrapping. This seem to be a limitation in the llvm::ScalarEvolution::isSCEVExprNeverPoison function.

Analysis so far: The actual add instructions have the nsw flags and reside in a basic block just before the loop body. The isSCEVExprNeverPoison function is called on them but assumes the instruction must be part of a loop. If the instruction is not part of any loop it is reported as a possible poison value.

A possible fix would be to assume the instruction is loop independent if it is not part of any loop. But I am not sure if the loop information is complete (does absence of loop info on a basic block means there is no loop in the code in the scalar evolution pass?). With such a fix the resulting expression would be: (-2 + (-1 * %x) + ((2 + %x) smax (3 + %x))

This is foldable, although the current folding expression constructors don’t handle this case yet.

cddouma-arm commented 8 years ago

IR of reproducer that loop-unroll operates on