This is an archive of the discontinued LLVM Phabricator instance.

[SCEV] Fix unsound reasoning in howManyLessThans
ClosedPublic

Authored by reames on Jul 13 2021, 2:56 PM.

Details

Summary

This is split from D105216, it handles only a subset of the cases in that patch.

Specifically, the issue being fixed is that the code incorrectly assumed that (Start-Stide) < End implied that the backedge was taken at least once. This is not true when e.g. Start = 4, Stride = 2, and End = 3. Note that we often do produce the right backedge taken count despite the flawed reasoning.

Diff Detail

Event Timeline

reames created this revision.Jul 13 2021, 2:56 PM
reames requested review of this revision.Jul 13 2021, 2:56 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 13 2021, 2:56 PM
reames edited the summary of this revision. (Show Details)Jul 13 2021, 3:29 PM

I think it makes sense to land this separately, if only to ensure we can bisect issues more accurately.

llvm/test/Analysis/ScalarEvolution/trip-count-unknown-stride.ll
8

We could actually handle this.

We have "%add = add nsw i32 %i.05, %s" in the IR, feeding into the backedge. We can use this to show "Start > Start - Stride": if it's false, we have poison feeding into the branch. I don't think we use this sort of reasoning anywhere at the moment, though.

I don't think we need to block this patch for that, necessarily... but we should make sure we have a testcase that can't be rescued by this sort of reasoning.

Er, there may be an issue with this. I ran my brute force checker program, and am getting results which confuse me. There's a good chance this is operator error - I'm currently brain dead - but I'll take a closer look in the morning and share refined results.

Current results seem to indicate the original code does hold for unsigned comparisons, and neither the original nor patched version holds for signed comparisons. I'm suspicious of that result, but I'll look more closely in the morning.

As I mostly expected, my concerning validation result turned out to be a bug in my brute force checker program instead. (C++ promotion rules bite again!) I have checked the logic for this transform on both signed and unsigned comparisons for all 8 bit values of start, end, and stride. The optimized form produces the same answer as both the generic n-bit ceiling logic (used in getUDivCeilSCEV) and an implementation of the N + (D - 1) /D formula using wide types.

Eli, it sounds like you're on board with me landing this. Can I get a LGTM for the record?

reames added inline comments.Jul 14 2021, 11:50 AM
llvm/test/Analysis/ScalarEvolution/trip-count-unknown-stride.ll
8

This is a good point. We don't do anything this direct, but we do reason extensively about this code about impossible paths because poison would reach a branch.

(Note: Your reasoning is only sound when this is the sole exit. Otherwise, there might be an earlier exit which exits on iteration zero.)

(It also needs to be a post increment test as well.)

Now that I think about this, I strongly suspect this is what the original code was trying to do. It just didn't account for the fact that ControlsExit does not have to be true at this point in code, and doesn't include the test for post-increment.

efriedma accepted this revision.Jul 14 2021, 5:05 PM

LGTM

But like I mentioned, I'd like to see more test coverage at some point.

llvm/test/Analysis/ScalarEvolution/trip-count-unknown-stride.ll
8

(Note: Your reasoning is only sound when this is the sole exit. Otherwise, there might be an earlier exit which exits on iteration zero.)

If there's an earlier exit which exits on iteration zero, does it matter what we return here?

This revision is now accepted and ready to land.Jul 14 2021, 5:05 PM
reames added inline comments.Jul 15 2021, 10:16 AM
llvm/test/Analysis/ScalarEvolution/trip-count-unknown-stride.ll
8

In some ways, yes. We can return any concrete value for the exit count of the exit, but we could not, for instance, return poison. At the moment, I don't think we ever actually produce poison, but a more realistic example might be a divide by possible zero. I think that the expansion code would probably prevent that biting us in practice, but we'd be walking a very thin line.

This revision was landed with ongoing or failed builds.Jul 15 2021, 10:33 AM
This revision was automatically updated to reflect the committed changes.
efriedma added inline comments.Jul 15 2021, 11:34 AM
llvm/test/Analysis/ScalarEvolution/trip-count-unknown-stride.ll
8

I suspect we need a general solution for the problem of possibly-poison trip counts. Even the simplest examples have issues. See, for example, https://web.ist.utl.pt/nuno.lopes/alive2/index.php?hash=047d8ce24c780675&test=Transforms%2FLoopUnroll%2Fruntime-loop-multiple-exits.ll

reames added inline comments.Jul 15 2021, 12:35 PM
llvm/test/Analysis/ScalarEvolution/trip-count-unknown-stride.ll
8

Eek, I hadn't realized it was quite *that* broken. Yeah, we definitely need to figure out something there. One problem at a time though. :)