This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] sub(add(X,Y),umin(Y,Z)) --> add(X,usub.sat(Y,Z))
ClosedPublic

Authored by Chenbing.Zheng on Apr 26 2022, 11:29 PM.

Diff Detail

Event Timeline

Herald added a project: Restricted Project. · View Herald TranscriptApr 26 2022, 11:29 PM
Herald added a subscriber: hiraditya. · View Herald Transcript
Chenbing.Zheng requested review of this revision.Apr 26 2022, 11:29 PM
RKSimon added inline comments.Apr 27 2022, 3:02 AM
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
2043

Is it worth putting the fold within the dyn_cast<MinMaxIntrinsic>(Op1) check above?

llvm/test/Transforms/InstCombine/sub-minmax.ll
734

(style) Don't enumerate tests - use the name to describe the actual test (commutations etc).

767

vector tests?
you probably want negative tests for where the m_Specific() match fails as well

address comment

RKSimon added inline comments.May 5 2022, 2:20 AM
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
2038

I meant - can you incorporate these tests under the existing dyn_cast<MinMaxIntrinsic> check at Line 2021?

Chenbing.Zheng added inline comments.May 5 2022, 2:52 AM
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
2038

I try to do it, but the code doesn't get much cleaner and it breaks readability.

RKSimon added inline comments.May 5 2022, 3:03 AM
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
2038

At the very least the isa<MinMaxIntrinsic>(Op1) check should be at the top, not inside a loop in which its invariant.

if (isa<MinMaxIntrinsic>(Op1)) {
  Value *X, *Y, *Z;
  Type *Ty = I.getType();
  for (bool Swap : {false, true}) {
    ....
  }
}

address comment

A couple of minors

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
2029

(style) Move this inside braces (and the same for the new fold):

{
    Value *X = II->getLHS();
    Value *Y = II->getRHS();
    if (match(Op0, m_c_Add(m_Specific(X), m_Specific(Y))) &&
        (Op0->hasOneUse() || Op1->hasOneUse())) {
      Intrinsic::ID InvID = getInverseMinMaxIntrinsic(II->getIntrinsicID());
      Value *InvMaxMin = Builder.CreateBinaryIntrinsic(InvID, X, Y);
      return replaceInstUsesWith(I, InvMaxMin);
    }
}
2036

Maybe move the "for (bool Swap : {false, true})" loop inside the match to avoid performing the match twice?

address comments

RKSimon added inline comments.May 6 2022, 4:24 AM
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
2042

Do we have a m_c_UMin that we can use instead?

spatel added inline comments.May 6 2022, 5:18 AM
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
2042

We do have that matcher, but this would be easier if we match the umin first and then find the common operand in the add?

// sub(add(X,Y),umin(Y,Z)) --> add(X,usub.sat(Y,Z))
// sub(add(X,Z),umin(Y,Z)) --> add(X,usub.sat(Y,Z))
Value *X, *Y, *Z;
if (match(Op1, m_OneUse(m_UMin(m_Value(Y), m_Value(Z)))) &&
    (match(Op0, m_OneUse(m_c_Add(m_Specific(Y), m_Value(X)))) ||
     match(Op0, m_OneUse(m_c_Add(m_Specific(Z), m_Value(X)))))) {
  Value *USub =
      Builder.CreateIntrinsic(Intrinsic::usub_sat, I.getType(), {Y, Z});
  return BinaryOperator::CreateAdd(X, USub);
}

According to spatel's suggestion.

RKSimon accepted this revision.May 7 2022, 1:19 AM

LGTM

This revision is now accepted and ready to land.May 7 2022, 1:19 AM
This revision was landed with ongoing or failed builds.May 7 2022, 2:20 AM
This revision was automatically updated to reflect the committed changes.