This is an archive of the discontinued LLVM Phabricator instance.

[CGP] Remove operand of llvm.assume more aggressively.
Needs ReviewPublic

Authored by skatkov on Jun 7 2023, 3:58 AM.

Details

Summary

At the moment CGP recursively removes operand of llvm.assume but
it does it only for instructions has no more than one use.

This is not enough for some induction variable which is used only
in llvm.assume.

As soon as there is no any dead code elimination passes between
CGP and instruction selector it makes sense to apply more efforts
at CGP to remove dead code.

Diff Detail

Event Timeline

skatkov created this revision.Jun 7 2023, 3:58 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 7 2023, 3:58 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
skatkov requested review of this revision.Jun 7 2023, 3:58 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 7 2023, 3:58 AM
Herald added a subscriber: wdng. · View Herald Transcript
skatkov updated this revision to Diff 529245.Jun 7 2023, 4:18 AM

Fix comments.

anna added a subscriber: anna.Jun 13 2023, 6:51 AM
anna added inline comments.
llvm/lib/CodeGen/CodeGenPrepare.cpp
807

Nit: change the order of declarations so that the comment is clearer?

814

assert that I is already in ToRemove set?

skatkov updated this revision to Diff 531604.Jun 14 2023, 9:20 PM
skatkov marked 2 inline comments as done.
anna added a comment.Jun 15 2023, 7:24 AM

LGTM (maybe wait for other reviewers for couple of days) with added tests.

llvm/test/Transforms/CodeGenPrepare/X86/delete-assume-dead-code.ll
48

Pls add couple of tests:

  • positive test: %iv2.inc is used in another cmp which feeds into another assume
  • negative test: %iv2 is used in a cmp3 which is used as a sub condition in the branch (and i1 %cmp, %cmp3)
xbolva00 added inline comments.Jun 15 2023, 7:29 AM
llvm/lib/CodeGen/CodeGenPrepare.cpp
803

Maybe extract to smaller function(s)?

Readibility if this new part is not ideal, so many nesting levels, ..

skatkov updated this revision to Diff 532083.Jun 16 2023, 4:04 AM

is it better?

Test are updated. Code re-factored. Anything I can do to land this?

arsenm added inline comments.Jun 21 2023, 5:38 PM
llvm/lib/CodeGen/CodeGenPrepare.cpp
716

sentence sounds like it's missing a word here?

720

Start with lowercase

720

I'm not sure what closure means in this context

724

Do this after the early exit?

748–749

How is this different from RecursivelyDeleteTriviallyDeadInstructions?

Thanks a lot for review. I'll update a patch as soon as we agreed on terminology (Closure) and description of FindClosureOfWouldBeTriviallyDeadInstructions function.

llvm/lib/CodeGen/CodeGenPrepare.cpp
716

Well.. Let me try to re-phrase it as follows, please review is it better?

The utility function collects all transitively reachable users of I. If all users would be trivially dead in case they
would not have users then this function returns true and Closure contains I with all found users.
Otherwise function returns false and Closure content is not specified.
For the purpose of this function llvm.assume is considered ad trivially dead instruction.

720

Will do.

Closure means transitive closure of users of instruction I In other words I, its users, users of users and so on.

Any suggestion for better term?

724

No, early exit is a simple case when there is no users, so closure consists of 1 instruction I and I should return it in Closure for further erasing.

748–749

RecursivelyDeleteTriviallyDeadInstructions will delete instruction only if has no users, while this patch will find group of instructions which is connected to each other (see tests below, induction variable case) and remove them together is none of these instructions has users outside of this group and all of them would be trivially dead.

Also this function consider llvm.assume as trivially dead instruction. This is for the case when induction variable is used in two different assumes.

skatkov updated this revision to Diff 534418.Jun 25 2023, 8:58 PM

please, take a look.

skatkov updated this revision to Diff 534421.Jun 25 2023, 9:14 PM

one more function renamed to start with lower symbol.

skatkov updated this revision to Diff 534423.Jun 25 2023, 9:15 PM

Comment update.

Friendly ping...

Our longer term plan was to stop removing assumes in CGP, so they remain available during codegen, in particular for AA purposes. Instead, we would drop assumes more aggressively earlier if they keep control flow alive.

It seems pretty likely that assumes that keep alive otherwise dead IVs are also blocking optimizations in earlier parts of the pipeline, and we would be better of dropping such assumes earlier. I'm not entirely sure what the right heuristic for that would be, but "ephemeral values of the assume include a phi node" is probably a pretty good one.

Our longer term plan was to stop removing assumes in CGP, so they remain available during codegen, in particular for AA purposes. Instead, we would drop assumes more aggressively earlier if they keep control flow alive.

It seems pretty likely that assumes that keep alive otherwise dead IVs are also blocking optimizations in earlier parts of the pipeline, and we would be better of dropping such assumes earlier. I'm not entirely sure what the right heuristic for that would be, but "ephemeral values of the assume include a phi node" is probably a pretty good one.

The current stage: remove but not everything looks the worst way. In my understanding, let's remove all the dead code together or keep it alive.
So I propose to land this up to the point CGP get rid of this code.

What do you think?

anna added a comment.Jun 28 2023, 8:43 AM

Just to give more input here - we have seen many cases where the loop vectorizer generates a lot of code with a bunch of extracts for each assume operand. Basically we do not have "vectorized assumes". We were looking at two options - we drop such assumes before loop vectorizer or teach CodeGenPrepare to be more aggressive.

The issue is knowing *which assumes* would need to be kept until end of opt at least (@nikic heuristic may work here). I believe Serguei's proposal is to use this patch as a short term fix.
As a long term approach, I think if we do plan to keep assumes in CodeGen, we would need to figure out a "drop assumes" pass with some good heuristics and appopriate position in pipeline?

We have ephemeral value trackers and other helpers, we should use those, assuming this is going forward.

We have ephemeral value trackers and other helpers, we should use those, assuming this is going forward.

EphemeralValueTracker does not recognize the group of instructions which combines to llvm.assume all together as well due to for each particular instruction it checks that all its users should be already marked as ephemeral value.
So for the tests below for phi node representing induction variable it will not recognize it as ephemeral one.

I've taken a look at CodeMetrics::collectEphemeralValues. It does not recognize loops with phi node as well. I can extend its detector, however it collects ephemeral values basing on conditions "I->mayHaveSideEffects() || I->isTerminator()".

It is less than RecursivelyDeleteTriviallyDeadInstructions which is used currently in CodeGenPrepare. For example, RDTDI can remove allocations...

So, let's decide in what direction should I move.

The idea to remove it earlier.... Not sure at what moment we should do it. It might be useful one if some one will use it properly.

We have ephemeral value trackers and other helpers, we should use those, assuming this is going forward.

Please take a look at alternative https://reviews.llvm.org/D154584.