This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] Fold Select with AND/OR condition
ClosedPublic

Authored by xbolva00 on Jul 27 2018, 9:25 AM.

Details

Summary

Fold

%A = icmp ne i8 %X, %V1
%B = icmp ne i8 %X, %V2
%C = or i1 %A, %B
%D = select i1 %C, i8 %X, i8 %V1
ret i8 %D
  =>
ret i8 %X

Fixes https://bugs.llvm.org/show_bug.cgi?id=38334
Proof: https://rise4fun.com/Alive/plI8

Diff Detail

Repository
rL LLVM

Event Timeline

xbolva00 created this revision.Jul 27 2018, 9:25 AM

This should be in InstSimplify, as you don't create any new instructions.

There should be an opposite version with and instead of or and the compare condition inverted. We should handle that too.

Ok, I will look on it.

lebedev.ri added inline comments.Jul 27 2018, 10:04 AM
lib/Transforms/InstCombine/InstCombineSelect.cpp
65–87 ↗(On Diff #157701)

One more thing - this is slightly too verbose. I suspect it may miss some commutative cases, too.
Please make better use of pattern matchers.

How about:

Value *foldSelectInstBinaryOp(SelectInst &Sel) {
  Value *X, *V1, *V2;
  CmpInst::Predicate Pred1, Pred2;
  if (!match(&Sel, m_Select(m_c_Or(m_ICmp(Pred1, m_Value(X), m_Value(V1)),
                                   m_c_ICmp(Pred2, m_Deferred(X), m_Value(V2))),
                            m_Deferred(X), m_Deferred(V1))) ||
      !(Pred1 == Pred2 && Pred1 == ICmpInst::ICMP_NE))
    return nullptr;
  return X;
}
lebedev.ri added inline comments.Jul 27 2018, 10:08 AM
lib/Transforms/InstCombine/InstCombineSelect.cpp
65–87 ↗(On Diff #157701)

Actually, you won't even need V2 right now, i think, so,

static Value *foldSelectInstBinaryOp(SelectInst &Sel) {
  Value *X, *V1;
  CmpInst::Predicate Pred1, Pred2;
  if (!match(&Sel, m_Select(m_c_Or(m_ICmp(Pred1, m_Value(X), m_Value(V1)),
                                   m_c_ICmp(Pred2, m_Deferred(X), m_Value())),
                            m_Deferred(X), m_Deferred(V1))) ||
      !(Pred1 == Pred2 && Pred1 == ICmpInst::ICMP_NE))
    return nullptr;
  return X;
}
lebedev.ri edited the summary of this revision. (Show Details)Jul 27 2018, 10:22 AM
xbolva00 added inline comments.Jul 27 2018, 10:46 AM
lib/Transforms/InstCombine/InstCombineSelect.cpp
65–87 ↗(On Diff #157701)

Wow, nice simplification :) Thanks

xbolva00 updated this revision to Diff 157709.Jul 27 2018, 10:57 AM
  • Added AND variant
  • Addressed review comments
xbolva00 retitled this revision from [InstCombine] Fold Select with OR condition to [InstCombine] Fold Select with AND/OR condition.Jul 27 2018, 10:58 AM
xbolva00 added a comment.EditedJul 27 2018, 11:05 AM

Can we handle even more cases? Any ideas how to easily extend this patch to handle them?
https://godbolt.org/g/kKhQ3s

Nevermind, maybe for now TODO. Let's do this simple case.

lebedev.ri added inline comments.Jul 27 2018, 11:25 AM
lib/Analysis/InstructionSimplify.cpp
78–93 ↗(On Diff #157709)

Nice.
Then i'd suggest something a bit more flatter:

static Value *foldSelectWithBinaryOp(Value *Cond, Value *TrueVal,
                                     Value *FalseVal) {
  BinaryOperator::BinaryOps BinOpCode;
  if (auto *BO = dyn_cast<BinaryOperator>(Cond))
    BinOpCode = BO->getOpcode();
  else
    return nullptr;

  CmpInst::Predicate ExpectedPred;
  if (BinOpCode == BinaryOperator::Or) {
    ExpectedPred = ICmpInst::ICMP_NE;
  } else if (BinOpCode == BinaryOperator::And) {
    ExpectedPred = ICmpInst::ICMP_EQ;
    std::swap(TrueVal, FalseVal);
  } else
    return nullptr;

  CmpInst::Predicate Pred1, Pred2;
  if (!match(
          Cond,
          m_c_BinOp(m_c_ICmp(Pred1, m_Specific(TrueVal), m_Specific(FalseVal)),
                    m_c_ICmp(Pred2, m_Specific(TrueVal), m_Value()))) ||
      Pred1 != Pred2 || Pred1 != ExpectedPred)
    return nullptr;

  return TrueVal;
}
test/Transforms/InstCombine/select-or-cmp.ll
56 ↗(On Diff #157709)

Please split this into two different test case files, i.e. the tests for and variant should go into the new file.

xbolva00 updated this revision to Diff 157725.Jul 27 2018, 11:43 AM
  • Improved matching
xbolva00 marked 2 inline comments as done.Jul 27 2018, 11:44 AM

In general, looks ok, but i would like to see better test coverage
(the both test files should be identical other than or vs. and and ne vs. eq)

  1. A positive test with <2 x i32> vector
  2. Negative tests:
    • wrong (opposite) predicate (one and/or both, i.e. ideally 3 tests?)
    • Some other TrueVal of the select - a some new argument %k
    • Some other FalseVal of the select - a some new argument %k
lib/Analysis/InstructionSimplify.cpp
102–106 ↗(On Diff #157725)

Hmm, ok, i think that would work too. https://rise4fun.com/Alive/wYX
But maybe

return BinOpCode == BinaryOperator::Or ? TrueVal : FalseVal;

to not anyone else wonder about this being done after the match.

  1. Negative tests:

+

  • wrong (opposite) binary operation - or instead of and
  1. Negative tests:

+

  • %x replaced with some other new argument in one of the icmp's

Not sure what other cases would be valuable to check against.

xbolva00 updated this revision to Diff 157745.EditedJul 27 2018, 12:49 PM
  • Tests

replaced with some other new argument in one of the icmp's

Ok, i will do.

xbolva00 marked an inline comment as done.Jul 27 2018, 12:49 PM
xbolva00 updated this revision to Diff 157746.Jul 27 2018, 12:55 PM
  • Added more negative tests
  • Added more negative tests

Thank you.
Tests look good (i only looked at the select-and-cmp.ll, i assume the other one is fully identical/symmetrical).
Please commit the tests now, and rebase.

xbolva00 updated this revision to Diff 157755.Jul 27 2018, 1:31 PM
lebedev.ri accepted this revision.Jul 27 2018, 1:54 PM

Ok, i think this looks good, other than nits.
Please wait a bit (1 day?) before committing in case others want to comment.

lib/Analysis/InstructionSimplify.cpp
68–77 ↗(On Diff #157755)

Maybe something like

/// Fold
///   %A = icmp ne/eq i8 %X, %V1
///   %B = icmp ne/eq i8 %X, %V2
///   %C = or/and i1 %A, %B
///   %D = select i1 %C, i8 %X, i8 %V1
/// To
///   %X/%V1
3792 ↗(On Diff #157755)

Can we come up with more descriptive name?
I don't have any good ideas here.

This revision is now accepted and ready to land.Jul 27 2018, 1:54 PM
xbolva00 updated this revision to Diff 157768.Jul 27 2018, 2:30 PM
  • Updated comment
This revision was automatically updated to reflect the committed changes.
spatel added inline comments.Jul 28 2018, 6:15 AM
llvm/trunk/test/Transforms/InstCombine/select-and-cmp.ll
2

The code was moved to instsimplify, but the tests remained in instcombine. The files should be moved, and the RUN lines should be changed to only use "-instsimplify".

xbolva00 added inline comments.Jul 28 2018, 6:21 AM
llvm/trunk/test/Transforms/InstCombine/select-and-cmp.ll
2

Move them directly to test/Analysis? There are many inner folders - is there any folder which is more suitable for this tests?

spatel added inline comments.Jul 28 2018, 6:31 AM
llvm/trunk/test/Transforms/InstCombine/select-and-cmp.ll
2

instsimplify tests are under:
test/Transforms/InstSimplify

I think that's because instsimplify can be used as either an analysis or a transform pass.