This is an archive of the discontinued LLVM Phabricator instance.

Remove loop variant range check when induction variable is strictly increasing
AbandonedPublic

Authored by reames on May 14 2015, 4:55 PM.

Details

Summary

Given a range check on an induction variable, we can convert that range check to a loop invariant check against the starting value of the induction variable if the check would fail on the first iteration or not at all. This creates a check which is easily unswitched and thus effectively removes the range check from within the loop entirely.

Given C code:
for(int i = M; i < N; i++) // i is known not to overflow

if (i < 0) break;
a[i] = 0;

}
This transformation produces:
for(int i = M; i < N; i++)

if (M < 0) break;
a[i] = 0;

}
Which can be unswitched into:
if (M < 0) break;
for(int i = M; i < N; i++)

a[i] = 0;

}

I'm not entirely sure this is done in the best place. I couldn't really find a more natural fit for it, but the bit of code walking the use of each candidate induction variable didn't really seem elegant. Suggestions on a better way to structure this are very welcome.

Diff Detail

Event Timeline

reames updated this revision to Diff 25827.May 14 2015, 4:55 PM
reames retitled this revision from to Remove loop variant range check when induction variable is strictly increasing.
reames updated this object.
reames edited the test plan for this revision. (Show Details)
reames added reviewers: atrick, sanjoy, nlewycky.
reames added a subscriber: Unknown Object (MLST).
sanjoy edited edge metadata.May 14 2015, 7:24 PM

I think this is okay to commit, but I'll wait for Andy to take a look.

lib/Transforms/Utils/SimplifyIndVar.cpp
189

Might want to just assert(BI->isConditional()) here, since it uses an icmp.

194

Do you need to check / assert that BI is itself within the loop? I think you can just assert it if DominatesBackedges(BI, L, DT) since BI uses ICmp which uses an induction variable.

atrick edited edge metadata.May 18 2015, 12:21 AM

This is great.

I will say that it's not very nice to call SCEVExpander within the SimplifyIndvar utility on an arbitrary SCEV value. We can't control what SCEVExpander will do outside the loop. I think the SimplifyIndvars utility should be limited to folding instructions within the loop, and possibly cloning an IV increment, but not inserting code outside the loop. I can't think of any value in doing this inside SimplifyIndvar--it won't expose other simplification. I do agree that this optimization belongs in the indvars pass, but it could probably be a separate sub-pass over the loop's terminators.

As always, I'm nervous about using SCExpander in general. I'm not sure if we should have any checks for whether the start value can be safely or profitably materialized (see the terrible isSafeToExpand hack). It may be ok since we similary expand AddRecs and start values in WidenIV and LoopVectorize, but I can't say for sure. Just as an contrasting example implementation, if you wanted to be very conservative, you could find an existing loop phi whose initial value is your desired AddRec start with a constant offset. Then you can ask SCEVExpander to materialize that existing value wrapped in SCEVUnknown plus the offset (always safe).

At any rate, when using SCEVExpander it should be explicit and obvious at the top-level of the pass, not buried in a utility that can be called anywhere. That way it's easier to see that almost arbitrary IR rewriting may happen at that point (hopefully it's at least limited to adding new instructions, but without bounding the expression it can do some surprising things).

This has been moved to D11278

reames abandoned this revision.Jul 17 2015, 5:54 PM

Sanjoy has implemented a better version of this based on Andy's review comments over in http://reviews.llvm.org/D11278