This is an archive of the discontinued LLVM Phabricator instance.

[SCEV] Add a ad-hoc pattern on isImpliedCondBalancedTypes
Changes PlannedPublic

Authored by jaykang10 on Apr 15 2021, 8:06 AM.

Details

Summary

I have seen some cases which SCEV's isImpliedCond returns false.

It looks `isImpliedCond' has no patterns for case which the FoundLHS or FoundRHS is AddRec and the LHS and RHS are not AddRec.

In order to handle this case, we can use below one.

If FoundLHS is AddRec and FoundPred is EQ, we can say

The min value of FoundRHS is AddRec's start value if and only if "AddRec == FoundRHS" is true.

It means we can use "FoundRHS >= AddRec's start value" for "AddRec == FoundRHS".

This changes helps IRCE pass handles cascaded sibling loops.

Diff Detail

Event Timeline

jaykang10 created this revision.Apr 15 2021, 8:06 AM
jaykang10 requested review of this revision.Apr 15 2021, 8:06 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 15 2021, 8:06 AM

@reames I am aiming to handle more cases on IRCE pass. If you think SCEV is not good place for this change, please let me know. I could move this change to IRCE pass.

jaykang10 edited the summary of this revision. (Show Details)Apr 15 2021, 8:21 AM
jaykang10 updated this revision to Diff 337776.Apr 15 2021, 8:25 AM

Fixed a typo

nikic requested changes to this revision.Apr 15 2021, 1:01 PM
nikic added a subscriber: nikic.
nikic added inline comments.
llvm/lib/Analysis/ScalarEvolution.cpp
10488

I find it really hard to understand this is doing based on the description. I believe the claim is that
A: Start s<= FoundRHS --> LHS s< RHS
implies
B: <Start,+,Step> == FoundRHS --> LHS s< RHS.

A sufficient condition for that to hold would be that <Start,+,Step> == FoundRHS implies Start s<= FoundRHS. I assume that was your line of reasoning.

However, this is clearly not true without further legality checks. You need to at least require that the addrec is nsw, and that the step is non-negative.

This revision now requires changes to proceed.Apr 15 2021, 1:01 PM
jaykang10 added inline comments.Apr 16 2021, 9:02 AM
llvm/lib/Analysis/ScalarEvolution.cpp
10488

I am sorry for poor description...

A sufficient condition for that to hold would be that <Start,+,Step> == FoundRHS implies Start s<= FoundRHS. I assume that was your line of reasoning.

Yep, it is exactly correct.

However, this is clearly not true without further legality checks. You need to at least require that the addrec is nsw, and that the step is non-negative.

You are right!!! Let me add legality checks with nsw and non-negative step.

jaykang10 updated this revision to Diff 338484.Apr 19 2021, 4:52 AM

Following the comment of @nikic, added checks for negative step and nsw/nuw.

jaykang10 retitled this revision from [SCEV] Add a ah-hoc pattern on isImpliedCondBalancedTypes to [SCEV] Add a ad-hoc pattern on isImpliedCondBalancedTypes.Apr 20 2021, 2:22 AM

@nikic I have run llvm-testsuite to check correctness. It seems fine.

jaykang10 updated this revision to Diff 338787.Apr 20 2021, 2:48 AM

Followed clang-format

@nikic If you need something more, please let me know.

nikic added a comment.Apr 21 2021, 2:55 PM

This needs better test coverage for the various conditions in the code, like step sign, nowrap flags, possibly predicates. Either as IR test cases, or as unit tests.

llvm/lib/Analysis/ScalarEvolution.cpp
10504

As you are working with signed predicates here, you need nsw. nuw is not enough. Of course, you could handle the analogous case with unsigned predicates, in which case you need nuw (and only nuw, the step sign doesn't matter in that case).

This needs better test coverage for the various conditions in the code, like step sign, nowrap flags, possibly predicates. Either as IR test cases, or as unit tests.

@nikic I appreciate your comments. I have updated the predicates and added unit tests for them. Please check it.

llvm/lib/Analysis/ScalarEvolution.cpp
10504

You are right! I will update it.

jaykang10 updated this revision to Diff 339540.Apr 22 2021, 2:41 AM

Following comments of @nikic, updated code and added unit tests.

nikic added inline comments.Apr 24 2021, 1:03 PM
llvm/lib/Analysis/ScalarEvolution.cpp
10506

This still isn't right: the required nowrap flag depends on the predicate. If you have NewFoundPred = ICMP_SLE, then you need nsw. If you have NewFoundPred = ICMP_ULE, then you need nuw.

jaykang10 added inline comments.Apr 26 2021, 4:07 AM
llvm/lib/Analysis/ScalarEvolution.cpp
10506

Oops! sorry, you are right! It looks the unsigned predicate with constant is transformed with SimplifyICmpOperands earlier. Let's just handle signed case.

jaykang10 updated this revision to Diff 340477.Apr 26 2021, 4:08 AM

Following comment from @nikic, updated code.

@nikic If you need something more for this change, please let me know.

Additionally, if possible, can you also review https://reviews.llvm.org/D101409 please?

nikic added inline comments.Apr 28 2021, 1:41 PM
llvm/lib/Analysis/ScalarEvolution.cpp
10497

As far as I can tell, the actual Pred is not relevant -- this should be correct independently of the used Pred, right? If so, I think it would be better to drop those checks and do something like this:

if (isa<SCEVAddRecExpr>(FoundRHS) && !isa<SCEVAddRecExpr>(FoundLHS)) {
  std::swap(FoundLHS, FoundRHS);
  std::swap(LHS, RHS);
  Pred = ICmpInst::getSwappedPredicate(Pred);
}

if (const auto *AddRec = dyn_cast<SCEVAddRecExpr>(FoundLHS)) {

Though I'm also wondering why we need to handle the case of AddRec in FoundRHS -- normally, AddRecs are canonicalized to the left-hand side. What is breaking the canonicalization here?

10506

Can you please add a test for the unsigned case? Looking at SimplifyICmpOperands, it's not really clear to me why it would already be handled.

10509

You can just return the isImpliedCondBalancedTypes result here, no need for separate return true / return false.

10511

AddRec->hasNoSignedWrap() would be more idiomatic.

llvm/test/Transforms/IRCE/sibling_loops.ll
10 ↗(On Diff #340477)

This test is over-reduced. It's best to avoid undef values, as it's very easy for tests to get broken by unrelated changes.

llvm/unittests/Analysis/ScalarEvolutionTest.cpp
1426

We should also have a negative test without nsw flag.

1473

More typically spelled ICmp...

jaykang10 added inline comments.Apr 29 2021, 9:45 AM
llvm/lib/Analysis/ScalarEvolution.cpp
10497

As far as I can tell, the actual Pred is not relevant -- this should be correct independently of the used Pred, right? If so, I think it would be better to drop those checks and do something like this:

if (isa<SCEVAddRecExpr>(FoundRHS) && !isa<SCEVAddRecExpr>(FoundLHS)) {
  std::swap(FoundLHS, FoundRHS);
  std::swap(LHS, RHS);
  Pred = ICmpInst::getSwappedPredicate(Pred);
}

if (const auto *AddRec = dyn_cast<SCEVAddRecExpr>(FoundLHS)) {

You are right.

Though I'm also wondering why we need to handle the case of AddRec in FoundRHS -- normally, AddRecs are canonicalized to the left-hand side. What is breaking the canonicalization here?

It is just conservative check. If AddRrecs is always canonicalized to the left-hand side, we do not need check FoundRHS. From below unit tests, when I call the isImpliedCond directly, I was able to see the FoundRHS is AddRec. If it is not problem, I will remove above code.

10506

Yep, I will add a unit test which is named with ImpliedCondWithAddRecNUW. You can see it on the unit test. If the unit test is wrong for unsigned, please let me know.

10509

You are right! I will update it.

10511

Yep, I will update it.

llvm/test/Transforms/IRCE/sibling_loops.ll
10 ↗(On Diff #340477)

Yep, you are right. Next time, I will be careful. This test aimed to show people the impact of IRCE pass with this SCEV change. I have started the discussion of IRCE pass so I would like to remove this test from this SCEV change now. I am sorry for inconvenience.

llvm/unittests/Analysis/ScalarEvolutionTest.cpp
1426

Yep, I will add it.

1473

Yep, I will update it.

Following comments of @nikic, updated code and added tests.

jaykang10 planned changes to this revision.Jun 2 2021, 9:25 AM