This is an archive of the discontinued LLVM Phabricator instance.

[ValueTracking] Use `select` condition to help determine if `select` is non-zero
ClosedPublic

Authored by goldstein.w.n on Apr 9 2023, 5:15 PM.

Details

Summary

In select c, x, y the condition c dominates the resulting x or
y chosen by the select. This adds logic to isKnownNonZero to try
and use the icmp for the c condition to see if it implies the
select x or y are known non-zero.

For example in:

%c = icmp ugt i8 %x, %C
%r = select i1 %c, i8 %x, i8 %y
```
The true arm of select `%x` is non-zero (when "returned" by the
`select`) because `%c` being true implies `%x` is non-zero.

Alive2 Links (with x {pred} C):

Diff Detail

Event Timeline

goldstein.w.n created this revision.Apr 9 2023, 5:15 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 9 2023, 5:15 PM
goldstein.w.n requested review of this revision.Apr 9 2023, 5:15 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 9 2023, 5:15 PM

Can you please base this on cmpExcludesZero() instead? I don't think there's need to handle cases here that we don't handle for assumes or branches.

nikic added a comment.Apr 12 2023, 1:17 PM

Can you please base this on cmpExcludesZero() instead? I don't think there's need to handle cases here that we don't handle for assumes or branches.

(I realized this might be ambiguous, so to clarify: What I mean is to use cmpExcludesZero() with its current set of supported functionality, not to generalize it to handle additional cases.)

goldstein.w.n added a comment.EditedApr 12 2023, 1:29 PM

Can you please base this on cmpExcludesZero() instead? I don't think there's need to handle cases here that we don't handle for assumes or branches.

(I realized this might be ambiguous, so to clarify: What I mean is to use cmpExcludesZero() with its current set of supported functionality, not to generalize it to handle additional cases.)

Oh okay. Open to a future patch to expand cmpExcludesZero?
Although seems somewhat a shame to miss very handable cases.

goldstein.w.n added a comment.EditedApr 12 2023, 1:50 PM

Can you please base this on cmpExcludesZero() instead? I don't think there's need to handle cases here that we don't handle for assumes or branches.

Any chance you are okay leaving this as a todo. i.e
"TODO: Integrate these cases in cmpExcludesZero"
Edit: Maybe a second version like cmpExcludesZeroRecursive for use
outside loops (maybe could get away with it in the assume loop).

Personally don't like leaving known missed-optimizations on the table :(

Also feels like a different circumstance. Other uses of cmpExcludesZero are in
loops so there is a case for skipping the over-analysis. This, on the otherhand
is capped at +2 recursive calls (only for ICMP_SGE, the rest +1/+0).

ultimately up to you, so LMK.

use cmpExcludesZero

nikic added inline comments.May 21 2023, 2:02 PM
llvm/lib/Analysis/ValueTracking.cpp
586

possible -> possibly

2913

I'd factor this differently, so that you keep the general structure of the previous code (i.e. short circuit if one operand is not known non-zero). Basically move the isKnownNonZero() check into the lambda as well.

2926–2933
2940

Redundant with the TODO on cmpExcludesZero.

goldstein.w.n marked 4 inline comments as done.May 21 2023, 2:55 PM
nikic added inline comments.May 22 2023, 1:06 PM
llvm/lib/Analysis/ValueTracking.cpp
2948–2949

I have a hard time following the logic here at the end. What I expected to see was something like this:

auto SelectArmIsNonZero = [&](bool IsTrueArm) {
  Value *Op = IsTrueArm ? I->getOperand(1) : I->getOperand(2);
  if (isKnownNonZero(Op, DemandedElts, Depth, Q))
    return true;

  // The condition of the select dominates the true/false arm. Check if the
  // condition implies that a given arm is non-zero.
  Value *X;
  CmpInst::Predicate Pred;
  if (!match(I->getOperand(0), m_c_ICmp(Pred, m_Specific(Op), m_Value(X))))
    return false;

  if (!IsTrueArm)
    Pred = ICmpInst::getInversePredicate(Pred);

  return cmpExcludesZero(Pred, X);
};

if (SelectArmIsNonZero(/* IsTrueArm */ true) &&
    SelectArmIsNonZero(/* IsTrueArm */ false))
  return true;
goldstein.w.n marked an inline comment as done.May 22 2023, 1:26 PM
goldstein.w.n added inline comments.
llvm/lib/Analysis/ValueTracking.cpp
2948–2949

Ah, that is indeed much clearer.

goldstein.w.n marked an inline comment as done.

Cleanup as @nikic suggests

nikic accepted this revision.May 22 2023, 1:53 PM

LGTM

This revision is now accepted and ready to land.May 22 2023, 1:53 PM