This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] Remove computeKnownBits() fold for returns
ClosedPublic

Authored by nikic on May 22 2023, 7:14 AM.

Details

Summary

We try to fold constant computeKnownBits() with context for return instructions only. Otherwise, we rely on SimplifyDemandedBits() to fold instructions with constant known bits.

The presence of this special fold for returns is dangerous, because it makes our tests lie about what works and what doesn't. Tests are usually written by returning the result we're interested in, but will go through this separate code path that is not used for anything else. This patch removes the special fold.

This primarily regresses patterns of the style "assume(x); return x". The responsibility of handling such patterns lies with passes like EarlyCSE/GVN anyway, which will do this reliably, and not just for returns.

Diff Detail

Event Timeline

nikic created this revision.May 22 2023, 7:14 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 22 2023, 7:14 AM
nikic requested review of this revision.May 22 2023, 7:14 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 22 2023, 7:14 AM

This seems a bit counter-intuitive to the aim InstCombine, which unless I'm mistaken
is to simplify/cannonicalize IR to help other passes.
I would certainly think a constant is easier to work with than whatever expression
it came from.

nikic added a comment.May 22 2023, 9:29 AM

This seems a bit counter-intuitive to the aim InstCombine, which unless I'm mistaken
is to simplify/cannonicalize IR to help other passes.
I would certainly think a constant is easier to work with than whatever expression
it came from.

My point here is that this fold does not actually work, but its existence hides that fact because all our tests are return based. Take a look at: https://llvm.godbolt.org/z/zezhbvqhh Only the return case gets folded, but the store and br cases don't. All three cases are handled by -passes=gvn.

And yes, the aim of InstCombine is to simplify/canonicalize IR, but that does not mean that it is responsible for all possible simplifications, only a certain class of them. For example, it is not responsible for any CSE simplifications, which are under the purview of EarlyCSE and GVN.

If we do want to propagate "assume equals constant" facts in InstCombine, the way to do that would be as a combine on the assume itself, replacing the value of all dominated uses. The approach used by this code is not extensible to other cases, as it would basically require doing a separate computeKnownBits() call on every single use of every single value (to take into account different contexts). If you think handling this in InstCombine rather than GVN is important, I could look into implementing that...

For the case where the assumption is not a plain equality assumption (but e.g. that certain bits are known, and then only those bits are masked by and), we *should* be handling this via SimplifyDemandedBits -- but currently don't. This is actually how I got here in the first place. I'm trying to make sure that SimplifyDemandedBits produces the same results as computeKnownBits(). Such discrepancies are currently hidden by this return-only fold.

This seems a bit counter-intuitive to the aim InstCombine, which unless I'm mistaken
is to simplify/cannonicalize IR to help other passes.
I would certainly think a constant is easier to work with than whatever expression
it came from.

My point here is that this fold does not actually work, but its existence hides that fact because all our tests are return based. Take a look at: https://llvm.godbolt.org/z/zezhbvqhh Only the return case gets folded, but the store and br cases don't. All three cases are handled by -passes=gvn.

And yes, the aim of InstCombine is to simplify/canonicalize IR, but that does not mean that it is responsible for all possible simplifications, only a certain class of them. For example, it is not responsible for any CSE simplifications, which are under the purview of EarlyCSE and GVN.

I see what you mean about the tests and agree. Is there any situation where due to this change, we end up
propagating less simplified IR to other passes or will CSE/GVN always be in the pipeline to handle it?
If the former, I think we probably need some data from llvm-test-suite to make sure this doesn't end up
messing up other passes and maybe this change should be put in a series with the fixed for
SimplifyDemandedBits. If the latter then I have no objection to this change.

If we do want to propagate "assume equals constant" facts in InstCombine, the way to do that would be as a combine on the assume itself, replacing the value of all dominated uses. The approach used by this code is not extensible to other cases, as it would basically require doing a separate computeKnownBits() call on every single use of every single value (to take into account different contexts). If you think handling this in InstCombine rather than GVN is important, I could look into implementing that...

For the case where the assumption is not a plain equality assumption (but e.g. that certain bits are known, and then only those bits are masked by and), we *should* be handling this via SimplifyDemandedBits -- but currently don't. This is actually how I got here in the first place. I'm trying to make sure that SimplifyDemandedBits produces the same results as computeKnownBits(). Such discrepancies are currently hidden by this return-only fold.

nikic added a comment.May 24 2023, 6:45 AM

This seems a bit counter-intuitive to the aim InstCombine, which unless I'm mistaken
is to simplify/cannonicalize IR to help other passes.
I would certainly think a constant is easier to work with than whatever expression
it came from.

My point here is that this fold does not actually work, but its existence hides that fact because all our tests are return based. Take a look at: https://llvm.godbolt.org/z/zezhbvqhh Only the return case gets folded, but the store and br cases don't. All three cases are handled by -passes=gvn.

And yes, the aim of InstCombine is to simplify/canonicalize IR, but that does not mean that it is responsible for all possible simplifications, only a certain class of them. For example, it is not responsible for any CSE simplifications, which are under the purview of EarlyCSE and GVN.

I see what you mean about the tests and agree. Is there any situation where due to this change, we end up
propagating less simplified IR to other passes or will CSE/GVN always be in the pipeline to handle it?
If the former, I think we probably need some data from llvm-test-suite to make sure this doesn't end up
messing up other passes and maybe this change should be put in a series with the fixed for
SimplifyDemandedBits. If the latter then I have no objection to this change.

At least on llvm-test-suite, this patch does not result in any codegen changes (binaries are identical).

goldstein.w.n accepted this revision.May 28 2023, 9:13 AM

This seems a bit counter-intuitive to the aim InstCombine, which unless I'm mistaken
is to simplify/cannonicalize IR to help other passes.
I would certainly think a constant is easier to work with than whatever expression
it came from.

My point here is that this fold does not actually work, but its existence hides that fact because all our tests are return based. Take a look at: https://llvm.godbolt.org/z/zezhbvqhh Only the return case gets folded, but the store and br cases don't. All three cases are handled by -passes=gvn.

And yes, the aim of InstCombine is to simplify/canonicalize IR, but that does not mean that it is responsible for all possible simplifications, only a certain class of them. For example, it is not responsible for any CSE simplifications, which are under the purview of EarlyCSE and GVN.

I see what you mean about the tests and agree. Is there any situation where due to this change, we end up
propagating less simplified IR to other passes or will CSE/GVN always be in the pipeline to handle it?
If the former, I think we probably need some data from llvm-test-suite to make sure this doesn't end up
messing up other passes and maybe this change should be put in a series with the fixed for
SimplifyDemandedBits. If the latter then I have no objection to this change.

At least on llvm-test-suite, this patch does not result in any codegen changes (binaries are identical).

Okay LGTM.

This revision is now accepted and ready to land.May 28 2023, 9:13 AM
This revision was landed with ongoing or failed builds.May 30 2023, 3:17 AM
This revision was automatically updated to reflect the committed changes.