[PATCH] D17201: [SCEV] Introduce a guarded backedge taken count and use it in LAA and LV

silviu.baranga@arm.com via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 29 05:31:31 PDT 2016


sbaranga added inline comments.

================
Comment at: lib/Analysis/ScalarEvolutionExpander.cpp:2007
@@ -2006,2 +2006,3 @@
 
-  const SCEV *ExitCount = SE.getBackedgeTakenCount(AR->getLoop());
+  SCEVUnionPredicate Pred;
+  const SCEV *ExitCount =
----------------
sanjoy wrote:
> sbaranga wrote:
> > sanjoy wrote:
> > > This part is a significant semantic change that I unfortunately hadn't
> > > (but really should have) noticed in earlier revisions.  While I don't
> > > yet have a specific example given the current state of the code, I
> > > think it is possible to end up with a circular logic fallacy here.
> > > 
> > > Earlier, the invariant was: given a no-overflow predicate, we would
> > > write a loop entry predicate `EP` (a function of the backedge count)
> > > that, when `true`, would imply no overflow.  Formally, `EP => NoOverflow`.
> > > However, now we're doing something different.  Now we
> > > have: `EP => (Backedge taken count is BE => NoOverflow)` (this part is
> > > the same as earlier), but `Backedge taken count is BE` is not
> > > axiomatically true -- it is true under the `NoOverflow`
> > > condition.  In other words, the set of logical equations we have are
> > > 
> > > ```
> > > EP => (Backedge taken count is BE => NoOverflow)
> > > NoOverflow => Backedge taken count is BE
> > > ```
> > > 
> > > Now we check `EP` at runtime, so it is known to be `true`.  Given
> > > that, there are two solutions to the above: {`Backedge taken count is
> > > BE` is `true`, `NoOverflow` is `true`}; or {`Backedge taken count is
> > > BE` is `false`, `NoOverflow` is `false`}.  The latter solution is
> > > problematic.
> > > 
> > > One problematic case that won't happen today, but illustrates what I'm
> > > talking about:
> > > 
> > > ```
> > >   for (u32 i = 0; ; i++)
> > >     store volatile (GEP a, i), 0
> > > ```
> > > 
> > > The above loop can run forever (assuming `u32` 's overflow is well
> > > defined), but let's say we decide to predicate the increment to an
> > > NUSW increment.  Given that, we know the loop won't run more than `-1`
> > > times (since otherwise we will have a side effect that uses poison).
> > > Howver, the predicate that you'll compute in SCEVExpander in such a
> > > case is `-1 == -1`, which is trivially true, and now the loop is
> > > miscompiled (instead of running forever, it'll just run `-1` times).
> > > 
> > > Now, I'll note that I've so far not have been able to come with a
> > > problematic case that will break in the current version of the patch,
> > > so it is possible that there is some deeper invariant here that is
> > > obvious.
> > Thanks! That is a very good point and we should be really careful here. I think this change is still correct:
> > 
> > Let's say that we return a symbolic answer X, and the correct answer is Y. The problem is when X != Y and we pass the predicate check.
> > 
> > Because the answer is wrong, some overflow must happen. Since we are passing the NoOverflow check, we need to have X < Y (otherwise we wouldn't be passing the check).
> > 
> > Note that for the first X iterations our predicate holds. I think what makes this correct is the fact that we're using the predicates in HowManyGreaterThans/HowManyLessThans, which means that we need to stop at iteration X.
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> So, to rephrase what I understood, by "with the predicate (IsNoWrap
> AR) the trip count of the loop is N", PSE really means "if the add
> recurrence AR does not overflow in the first N iterations, then the
> loop's count is N".  In particular, for the loop
> 
> ```
> for (unsigned i; ; i++)
>   side_effect_use(i);
> ```
> 
> predicating `i++` as NUSW does *not* let you conclude that the trip
> count of the loop is `UINT_MAX`, since just because `i++` does not
> overflow the in first `UINT_MAX` iterations does not guarantee that
> the loop will exit or have UB in the ``UINT_MAX+1` th iteration.
> 
> This is a subtle invariant, so at the very least this needs to be
> documented explicitly; and the places where we add predicates
> `HowManyLessThans` etc. need to be audited carefully (it sounds like
> you already have done most of that?).
> 
> Finally, if possible, it will be great if we can structure the code in
> a way that will make (accidentally) breaking this invariant difficult;
> though I don't have anything concrete in mind right now.
Yes, this is a very good description of the logic!

Indeed, this is subtle so it needs documenting. I did audit the places where we've added the predicates, but I'd like to have another look.


http://reviews.llvm.org/D17201





More information about the llvm-commits mailing list