[GlobalISel] Add commutative matchers for compares.

This adds:

* `m_c_GICmp`
* `m_c_GFCmp`

These work the same way as the standard matchers, but will also try to commute
the LHS and RHS of a compare to get a match.

E.g.

```
m_c_GICmp(m_Pred(...), m_GAdd(...), m_GSub(...))
```

Can match either of

```
icmp cc (add x, y), (sub a, b)
icmp swapped_cc (sub a, b), (add x, y)
```

Differential Revision: https://reviews.llvm.org/D135415
This commit is contained in:
Jessica Paquette 2022-10-07 12:19:33 -07:00
parent 9e80add2cf
commit 45b9c6b01f
2 changed files with 98 additions and 4 deletions

View File

@ -636,7 +636,8 @@ inline UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT> m_GFSqrt(const SrcTy &Src) {
// General helper for generic MI compares, i.e. G_ICMP and G_FCMP
// TODO: Allow checking a specific predicate.
template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode>
template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode,
bool Commutable = false>
struct CompareOp_match {
Pred_P P;
LHS_P L;
@ -655,9 +656,14 @@ struct CompareOp_match {
static_cast<CmpInst::Predicate>(TmpMI->getOperand(1).getPredicate());
if (!P.match(MRI, TmpPred))
return false;
return L.match(MRI, TmpMI->getOperand(2).getReg()) &&
R.match(MRI, TmpMI->getOperand(3).getReg());
Register LHS = TmpMI->getOperand(2).getReg();
Register RHS = TmpMI->getOperand(3).getReg();
if (L.match(MRI, LHS) && R.match(MRI, RHS))
return true;
if (Commutable && L.match(MRI, RHS) && R.match(MRI, LHS) &&
P.match(MRI, CmpInst::getSwappedPredicate(TmpPred)))
return true;
return false;
}
};
@ -673,6 +679,36 @@ m_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>(P, L, R);
}
/// G_ICMP matcher that also matches commuted compares.
/// E.g.
///
/// m_c_GICmp(m_Pred(...), m_GAdd(...), m_GSub(...))
///
/// Could match both of:
///
/// icmp ugt (add x, y) (sub a, b)
/// icmp ult (sub a, b) (add x, y)
template <typename Pred, typename LHS, typename RHS>
inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true>
m_c_GICmp(const Pred &P, const LHS &L, const RHS &R) {
return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true>(P, L, R);
}
/// G_FCMP matcher that also matches commuted compares.
/// E.g.
///
/// m_c_GFCmp(m_Pred(...), m_FAdd(...), m_GFMul(...))
///
/// Could match both of:
///
/// fcmp ogt (fadd x, y) (fmul a, b)
/// fcmp olt (fmul a, b) (fadd x, y)
template <typename Pred, typename LHS, typename RHS>
inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>
m_c_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>(P, L, R);
}
// Helper for checking if a Reg is of specific type.
struct CheckType {
LLT Ty;

View File

@ -323,6 +323,64 @@ TEST_F(AArch64GISelMITest, MatchFCmp) {
EXPECT_EQ(Copies[1], Reg1);
}
TEST_F(AArch64GISelMITest, MatcCommutativeICmp) {
setUp();
if (!TM)
return;
const LLT s1 = LLT::scalar(1);
Register LHS = Copies[0];
Register RHS = Copies[1];
CmpInst::Predicate MatchedPred;
bool Match = false;
for (unsigned P = CmpInst::Predicate::FIRST_ICMP_PREDICATE;
P < CmpInst::Predicate::LAST_ICMP_PREDICATE; ++P) {
auto CurrPred = static_cast<CmpInst::Predicate>(P);
auto Cmp = B.buildICmp(CurrPred, s1, LHS, RHS);
// Basic matching.
Match = mi_match(
Cmp.getReg(0), *MRI,
m_c_GICmp(m_Pred(MatchedPred), m_SpecificReg(LHS), m_SpecificReg(RHS)));
EXPECT_TRUE(Match);
EXPECT_EQ(MatchedPred, CurrPred);
// Commuting operands should still match, but the predicate should be
// swapped.
Match = mi_match(
Cmp.getReg(0), *MRI,
m_c_GICmp(m_Pred(MatchedPred), m_SpecificReg(RHS), m_SpecificReg(LHS)));
EXPECT_TRUE(Match);
EXPECT_EQ(MatchedPred, CmpInst::getSwappedPredicate(CurrPred));
}
}
TEST_F(AArch64GISelMITest, MatcCommutativeFCmp) {
setUp();
if (!TM)
return;
const LLT s1 = LLT::scalar(1);
Register LHS = Copies[0];
Register RHS = Copies[1];
CmpInst::Predicate MatchedPred;
bool Match = false;
for (unsigned P = CmpInst::Predicate::FIRST_FCMP_PREDICATE;
P < CmpInst::Predicate::LAST_FCMP_PREDICATE; ++P) {
auto CurrPred = static_cast<CmpInst::Predicate>(P);
auto Cmp = B.buildFCmp(CurrPred, s1, LHS, RHS);
// Basic matching.
Match = mi_match(
Cmp.getReg(0), *MRI,
m_c_GFCmp(m_Pred(MatchedPred), m_SpecificReg(LHS), m_SpecificReg(RHS)));
EXPECT_TRUE(Match);
EXPECT_EQ(MatchedPred, CurrPred);
// Commuting operands should still match, but the predicate should be
// swapped.
Match = mi_match(
Cmp.getReg(0), *MRI,
m_c_GFCmp(m_Pred(MatchedPred), m_SpecificReg(RHS), m_SpecificReg(LHS)));
EXPECT_TRUE(Match);
EXPECT_EQ(MatchedPred, CmpInst::getSwappedPredicate(CurrPred));
}
}
TEST_F(AArch64GISelMITest, MatchFPUnaryOp) {
setUp();
if (!TM)