]> git.ipfire.org Git - thirdparty/gcc.git/commit
unroll: Avoid unnecessary tail loops for constant niters
authorRichard Sandiford <richard.sandiford@arm.com>
Wed, 21 Jul 2021 06:50:20 +0000 (07:50 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Wed, 21 Jul 2021 06:50:20 +0000 (07:50 +0100)
commit62acc72a957b561462a436fcb2d6caac5b363190
tree071989b049849ee479de44719db3ecc36276eff0
parent2d9588bac5ac9e2ed778f3c7eae9ebf7bf258b44
unroll: Avoid unnecessary tail loops for constant niters

unroll and jam can decide to unroll the outer loop of a nest like:

  for (int j = 0; j < n; ++j)
    for (int i = 0; i < n; ++i)
      x[i] += __builtin_expf (y[j][i]);

It then uses a tail loop to handle any left-over iterations.

However, the code is structured so that this tail loop is always used.
If n is a multiple of the unroll factor UF, the final UF iterations will
use the tail loop rather than the unrolled loop.

“Fixing” that for variable loop counts would mean introducing another
runtime test: a branch around the tail loop if there are no more
iterations.  There's at least an argument that the overhead of doing
that test might not pay for itself.

But we use this structure even if the iteration count is provably
a multiple of UF at compile time.  E.g. with s/n/100/ and an
unroll factor of 2, the first 98 iterations use the unrolled loop
and the final 2 iterations use the original loop.

This patch makes the unroller avoid a tail loop in that case.
The end result seemed easier to follow if variables were declared
at the point of initialisation, so that it's more obvious which
ones are meaningful even when there's no tail loop.

gcc/
* tree-ssa-loop-manip.c (determine_exit_conditions): Return a null
exit condition if no tail loop is needed, and if the original exit
condition should therefore be kept as-is.
(tree_transform_and_unroll_loop): Handle that case here too.

gcc/testsuite/
* gcc.dg/unroll-9.c: New test/
gcc/testsuite/gcc.dg/unroll-9.c [new file with mode: 0644]
gcc/tree-ssa-loop-manip.c