This is an archive of the discontinued LLVM Phabricator instance.

[SCEV] Canonicalize ext(min/max(x, y)) to min/max(ext(x), ext(y))
ClosedPublic

Authored by mkazantsev on Jan 11 2023, 4:42 AM.

Details

Summary

I stumbled over this when trying to improve our exit count work. These expressions
are equivalent for complementary signed/unsigned ext and min/max (including umin_seq),
but they are not canonicalized and SCEV cannot recognize them as the same.

The benefit of this canonicalization is that SCEV can prove some new equivalences which
it coudln't prove because of different forms. There is 1 test where trip count seems pessimized,
I could not directly figure out why, but it just seems an unrelated issue that we can fix.
Other changes seem neutral to me.

Diff Detail

Event Timeline

mkazantsev created this revision.Jan 11 2023, 4:42 AM
mkazantsev requested review of this revision.Jan 11 2023, 4:42 AM
Herald added a project: Restricted Project. · View Herald TranscriptJan 11 2023, 4:42 AM
mkazantsev added inline comments.Jan 11 2023, 5:11 AM
llvm/test/Analysis/ScalarEvolution/fold.ll
78

There are even some improvements from it.

nikic added inline comments.Jan 31 2023, 5:29 AM
llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info-rewrite-expressions.ll
47

Why does this regress?

mkazantsev planned changes to this revision.Feb 1 2023, 2:15 AM
mkazantsev added inline comments.
llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info-rewrite-expressions.ll
47

Investigating.

mkazantsev requested review of this revision.Feb 1 2023, 3:25 AM
mkazantsev added inline comments.
llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info-rewrite-expressions.ll
47

I digged as deep as that inside of howFarToZero, there is code

if (Exact != getCouldNotCompute()) {
  APInt MaxInt = getUnsignedRangeMax(applyLoopGuards(Exact, L));
  ConstantMax =
      getConstant(APIntOps::umin(MaxInt, getUnsignedRangeMax(Exact)));
}

and here is the numbers are coming from. Good case:

Exact = ((-4 + (4 * ((zext i32 (16 umin %N) to i64) /u 4))<nuw><nsw>)<nsw> /u 4), ConstantMax = 3

Bad case:

Exact = ((-4 + (4 * ((16 umin (zext i32 %N to i64)) /u 4))<nuw><nsw>)<nsw> /u 4), ConstantMax = 4611686018427387903

I didn't go deep enough to understand what exactly was missing on range computation. Looks like that one of dozens of ad-hoc ways to compute it has failed. I could theoretically go deeper and try to understand this. I'm pretty sure this SCEV can be constructed with same result even now, just no test that would expose the problem.

Question is: do we care enough to be blocked on this? What the patch did makes perfect sense, it's just another heuristic missing somewhere. I can assign someone to take a look a bit later, unless this is a serious problem.

How much are you concerned by this?

nikic added inline comments.Feb 1 2023, 6:11 AM
llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info-rewrite-expressions.ll
47

Maybe it's related to the fact that applyLoopGuards rewriting supports zext but not umin? https://github.com/llvm/llvm-project/blob/c05ace1067bd21abf504d75f1efb5cf0e1c3fb51/llvm/lib/Analysis/ScalarEvolution.cpp#L14956

How much are you concerned by this?

Based on the comment above, it looks like this is a motivating case for the applyLoopGuards() logic, not just artificial test coverage, so it would be nice to not regress it.

Ok, I'll see what I can do...

mkazantsev updated this revision to Diff 494588.EditedFeb 3 2023, 4:39 AM

Rebased and updated.

Short summary:

  1. With improvements in SCEVLoopGuardRewriter, all old regressions are fixed.
  2. I've added a bunch of new tests and two of them start working with D143259 but regress with this canonicalization back to the prior state. I don't know why exactly.
  3. The whole thing with divisibility is raw and fragile, and this fragility is spiralling out of scope, this time the problem seems to be outside of SCEVLoopGuardRewriter.
  4. Rather than doing all these crazy rewritings, I'd just prefer to have getRangeAtScope and it seems to solve all problems we've faced so far.

I'll try to find some time to take a look into it later myself or ask someone of my colleagues to investigate, but I absolutely don't want to be blocked on these new tests. They never worked, they don't work again, this is fine.

mkazantsev added inline comments.Feb 3 2023, 4:48 AM
llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info-rewrite-expressions.ll
111

This is a new test, improved by D143259 and regressed back by this due to some fragile algorithms somewhere.

255

Same

nikic accepted this revision.Feb 19 2023, 11:19 PM

LGTM

This revision is now accepted and ready to land.Feb 19 2023, 11:19 PM
This revision was landed with ongoing or failed builds.Feb 20 2023, 1:13 AM
This revision was automatically updated to reflect the committed changes.
This comment was removed by efriedma.

Nevermind, ignore me, I somehow got it backwards; the given example gets improved.