[PATCH] D17201: [SCEV] Introduce a guarded backedge taken count and use it in LAA and LV
Sanjoy Das via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 28 17:42:50 PDT 2016
sanjoy 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 =
----------------
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.
http://reviews.llvm.org/D17201
More information about the llvm-commits
mailing list