This is an archive of the discontinued LLVM Phabricator instance.

[SCEV] Use knowledge of stride to prove loops finite for LT exit count computation
AbandonedPublic

Authored by reames on Jun 10 2021, 2:57 PM.

Details

Summary

This came up in the post commit review discussion of D103834.

The basic idea is that the general case was using a loop being finite by assumption to prove that step was non-zero. Non-zero combined with NoWrap flags in turns proves the loop must exit before overflow occurs. This change adds an explicit check for when the loop isn't known mustprogress, but we can directly prove that the step isn't zero. This will mostly help non-C/C++ family languages, though it may benefit some C language test cases as well.

Diff Detail

Event Timeline

reames created this revision.Jun 10 2021, 2:57 PM
reames requested review of this revision.Jun 10 2021, 2:57 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 10 2021, 2:57 PM

I don't see any obvious issue here. I'd like to work through the known miscompiles before we start expanding this, though.

mkazantsev accepted this revision.Jun 11 2021, 2:51 AM

Looks fine, but agreed with Eli. Please don't land it for some more days to find and fix miscompiles from underlying patches (if any).

llvm/lib/Analysis/ScalarEvolution.cpp
11479

Please refactor as

if (PredicatedIV || !NoWrap || isKnownNonPositive(Stride))
     return getCouldNotCompute();
bool StrideNonZero = loopIsFiniteByAssumption || isLoopEntryGuardedByCond ...
 if (!StrideNonZero )
     return getCouldNotCompute();

The dom tree walking is expensive, let's only do it if easy checks failed.

This revision is now accepted and ready to land.Jun 11 2021, 2:51 AM

I agree with the request to hold until latent miscompile in underlying code is addressed. I will hold this patch until that happens, and then land without further review. Max, good suggestion on condition ordering, will address in landed patch.

I agree with the request to hold until latent miscompile in underlying code is addressed. I will hold this patch until that happens, and then land without further review. Max, good suggestion on condition ordering, will address in landed patch.

I guess it will be "safe" to land this downstream meanwhile (as everyone thinks this looks good).

Out-of-curiosity. What are these known/latent miscompiles that is being referred to? Is there a bug report somewhere?

reames planned changes to this revision.Jul 15 2021, 2:19 PM

Code as posted is incorrect. A loop being finite only proves stride != 0 if the backedge is taken. If the backedge is not taken, stride may still be zero.

If the stride is zero, and RHS is invariant, the comparison feeding the backedge is invariant. If we don't exit via any other exit, that implies the backedge-taken count is either zero or infinity.

So if we know the loop is finite, the RHS is invariant, we don't exit via any other exit, and the IV doesn't overflow, we can divide strides into three cases:

  1. Stride is zero. The backedge-taken count is zero, as noted above.
  2. Stride is negative. I think we can also prove the backedge-taken count is zero here?
  3. Stride is positive. We can use the standard formula.

JFYI, this idea is on hold until some of the previous patches land. The interplay between this and some of the others is delicate and I'm worried about introducing bugs because I tried to keep too many things in my head at once. We should probably also do a bit of cleanup first - e.g. lift the RHS invariant check.

reames abandoned this revision.Nov 17 2021, 2:28 PM