Let GetMinTrailingZeros() make better use of assumptions by taking an optional context instruction.
The context defaults to null, keeping the API backward-compatible. If a context is provided, the method will neither use nor update the trailing zeros cache.
The context argument is then used by the loop vectorizer and by SCEV::getSmallConstantTripMultiple() to set the context at their given loop.
Details
- Reviewers
fhahn nikic lebedev.ri
Diff Detail
Event Timeline
llvm/lib/Analysis/ScalarEvolution.cpp | ||
---|---|---|
6893 | No reason, actually. Will change to first instruction in the header. | |
llvm/test/Transforms/LoopUnroll/runtime-unroll-assume-no-remainder.ll | ||
8 | Ah, good catch on LV (but I better do this separately to keep this patch's changes clear). |
Rebased on top of 7ddbe0cb905ec62d37b284a2e8daf54887a35f94 (merge ..-assume-divisible-TC.ll into ..-divisible-TC.ll)
I would expect that the SCEV change could be testable with just the scev itselfs (-analyze -scalar-evolution), is it not?
llvm/lib/Analysis/ScalarEvolution.cpp | ||
---|---|---|
5611–5615 | Doesn't this defy the point of the cache? |
I think the fix makes sense in isolation, but I am wondering if we could generalize this to automatically apply in more cases. Would it be possible to 'apply' the information from the loop guard directly to the SCEV expression? Like we do for some conditions already: https://github.com/llvm/llvm-project/blob/master/llvm/lib/Analysis/ScalarEvolution.cpp#L13241 ?
Right, will add a unit test for this API.
Will take a look at that. Thanks!
llvm/lib/Analysis/ScalarEvolution.cpp | ||
---|---|---|
5611–5615 |
This API seems to be used extensively. Since (for now) only the unroller and vectorizer would be providing a non-null context I wasn't sure caching those calls was worth the added space/time of extending the key.
Will do. |
Trying to apply Florian's suggestion in D95521 (only for powers of 2 as a first step). This handles the power-of-two case added by PR47904.
llvm/lib/Analysis/ScalarEvolution.cpp | ||
---|---|---|
5611–5615 | Thinking about this, it's not even so much that it's pessimising the cache, it's actually straight-up upsafe to do. x = y if(!(x & 0b1)) f(x); // x has at least one trailing bit if we first ask GetMinTrailingZeros(X, "f(x)"), we'll get 1, |
llvm/lib/Analysis/ScalarEvolution.cpp | ||
---|---|---|
5611–5615 | Not sure I follow. If a context is provided the cache is neither queried nor updated, so the call GetMinTrailingZeros(X, "f(x)") shouldn't affect a later GetMinTrailingZeros(X, "x = y") call (or a later GetMinTrailingZeros(X) call). Am I missing something? |
llvm/lib/Analysis/ScalarEvolution.cpp | ||
---|---|---|
5611–5615 | Err, nope. |
Doesn't this defy the point of the cache?
I think MinTrailingZerosCache's key should be changed to be a std::pair<SCEV*,CxtI*>