This is an archive of the discontinued LLVM Phabricator instance.

[SCEV] Strengthen variance condition in calculateLoopDisposition
ClosedPublic

Authored by mkazantsev on Oct 31 2017, 4:33 AM.

Details

Summary

Given loops L1 and L2 with AddRecs AR1 and AR2 varying in them respectively.
When identifying loop disposition of AR2 w.r.t. L1, we only say that it is varying if
L1 contains L2. But there is also a possible situation where L1 and L2 are
consecutive sibling loops within the parent loop. In this case, AR2 is also varying
w.r.t. L1, but we don't correctly identify it.

It can lead, for exaple, to attempt of incorrect folding. Consider:

AR1 = {a,+,b}<L1>
AR2 = {c,+,d}<L2>
EXAR2 = sext(AR1)
MUL = mul AR1, EXAR2

If we incorrectly assume that EXAR2 is invariant w.r.t. L1, we can end up trying to
construct something like: {a * {c,+,d}<L2>,+,b * {c,+,d}<L2>}<L1>, which is incorrect
because AR2 is not available on entrance of L1.

Both situations "L1 contains L2" and "L1 preceeds sibling loop L2" can be handled
with one check: "header of L1 dominates header of L2". This patch replaces the old
insufficient check with this one.

Diff Detail

Repository
rL LLVM

Event Timeline

mkazantsev created this revision.Oct 31 2017, 4:33 AM
reames edited edge metadata.Nov 7 2017, 3:58 PM

Max, I don't quite follow your discussion enough to know for sure, but I suspect there's something wrong with your framing here. A induction variable in one loop may be loop invariant with respect to sibling loop. That's normal. Is there maybe a subcase here? Or are you looking at flawed assumption in caller code?

int i;
for (i = 0; i < N; i++) { /* i is variant, j is undefined here */ }
for (int j = 0; j < M; j++) {/* i is invariant, j is varying. */ }

Max, I don't quite follow your discussion enough to know for sure, but I suspect there's something wrong with your framing here. A induction variable in one loop may be loop invariant with respect to sibling loop. That's normal. Is there maybe a subcase here? Or are you looking at flawed assumption in caller code?

int i;
for (i = 0; i < N; i++) { /* i is variant, j is undefined here */ }
for (int j = 0; j < M; j++) {/* i is invariant, j is varying. */ }

We are speaking about case /* i is variant, j is undefined here */ . We attempt to get the disposition of j w.r.t. the first loop, and we falsely return Invariant in this case. We don't have Undefined stance, so I used Variant instead of it.

I agree that i is invariant w.r.t. loop 2, but this is not the case that we cover in this patch.

mkazantsev added inline comments.Nov 10 2017, 5:07 AM
lib/Analysis/ScalarEvolution.cpp
10852 ↗(On Diff #120959)

Just to make it clear: what is meant here is "L and AR are consecutive in this order, i.e. L goes BEFORE the loop where AR is defined".

@reames the problem here is that when we try to simplify sum of i and j in getSCEVAddRecExpr, we falsely assume that j is invariant for i's loop while it should be vice versa: i is invariant for j's loop.

Updated comments in code to make it more clear what is going on.

reames requested changes to this revision.Nov 14 2017, 9:05 PM

Max and I discussed and realized this comes down to simply needing a much simpler and straight-forward comment. :) If AR is not defined on entry to L, it can't be LoopInvariant with respect to L. The distinction between L being a parent of AR->loop vs a sibling vs a nephew, cousin, etc... really doesn't contribute anything here.

The fact we use LoopVariant to represent "not defined on entry" is slightly confusing, but the code already does that for other cases.

I asked Max to update the comment and add a nephew loop example to the test.

This revision now requires changes to proceed.Nov 14 2017, 9:05 PM
mkazantsev edited edge metadata.

Changed comments, added test with nephew loop.

reames accepted this revision.Nov 21 2017, 8:21 PM

LGTM

This revision is now accepted and ready to land.Nov 21 2017, 8:21 PM
This revision was automatically updated to reflect the committed changes.