| //===---- llvm/unittest/CodeGen/SelectionDAGPatternMatchTest.cpp ---------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "SelectionDAGTestBase.h" |
| #include "llvm/CodeGen/SDPatternMatch.h" |
| #include "llvm/IR/IntrinsicsWebAssembly.h" |
| #include "llvm/IR/IntrinsicsX86.h" |
| |
| using namespace llvm; |
| |
| class SelectionDAGPatternMatchTest : public SelectionDAGTestBase {}; |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchValueType) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| auto Float32VT = EVT::getFloatingPointVT(32); |
| auto VInt32VT = EVT::getVectorVT(Context, Int32VT, 4); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Float32VT); |
| SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(3), VInt32VT); |
| |
| using namespace SDPatternMatch; |
| EXPECT_TRUE(sd_match(Op0, m_SpecificVT(Int32VT))); |
| EXPECT_TRUE(sd_match(Op0, m_SpecificScalarVT(Int32VT))); |
| EXPECT_TRUE(sd_match(Op0, m_SpecificScalarVT(Int32VT, m_Value()))); |
| EXPECT_FALSE(sd_match(Op0, m_SpecificScalarVT(Float32VT))); |
| EXPECT_FALSE(sd_match(Op0, m_SpecificScalarVT(Float32VT, m_Value()))); |
| EXPECT_TRUE(sd_match(Op2, m_SpecificVectorElementVT(Int32VT))); |
| EXPECT_TRUE(sd_match(Op2, m_SpecificVectorElementVT(Int32VT, m_Value()))); |
| EXPECT_FALSE(sd_match(Op2, m_SpecificVectorElementVT(Float32VT))); |
| EXPECT_FALSE(sd_match(Op2, m_SpecificVectorElementVT(Float32VT, m_Value()))); |
| EVT BindVT; |
| EXPECT_TRUE(sd_match(Op1, m_VT(BindVT))); |
| EXPECT_EQ(BindVT, Float32VT); |
| EXPECT_TRUE(sd_match(Op0, m_IntegerVT())); |
| EXPECT_TRUE(sd_match(Op1, m_FloatingPointVT())); |
| EXPECT_TRUE(sd_match(Op2, m_VectorVT())); |
| EXPECT_FALSE(sd_match(Op2, m_ScalableVectorVT())); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchVecShuffle) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| auto VInt32VT = EVT::getVectorVT(Context, Int32VT, 4); |
| const std::array<int, 4> MaskData = {2, 0, 3, 1}; |
| const std::array<int, 4> OtherMaskData = {1, 2, 3, 4}; |
| ArrayRef<int> Mask; |
| |
| SDValue V0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), VInt32VT); |
| SDValue V1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), VInt32VT); |
| SDValue VecShuffleWithMask = |
| DAG->getVectorShuffle(VInt32VT, DL, V0, V1, MaskData); |
| |
| using namespace SDPatternMatch; |
| EXPECT_TRUE(sd_match(VecShuffleWithMask, m_Shuffle(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(VecShuffleWithMask, |
| m_Shuffle(m_Value(), m_Value(), m_Mask(Mask)))); |
| EXPECT_TRUE( |
| sd_match(VecShuffleWithMask, |
| m_Shuffle(m_Value(), m_Value(), m_SpecificMask(MaskData)))); |
| EXPECT_FALSE( |
| sd_match(VecShuffleWithMask, |
| m_Shuffle(m_Value(), m_Value(), m_SpecificMask(OtherMaskData)))); |
| EXPECT_TRUE( |
| std::equal(MaskData.begin(), MaskData.end(), Mask.begin(), Mask.end())); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchTernaryOp) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int32VT); |
| SDValue Op3 = DAG->getConstant(1, DL, Int32VT); |
| |
| SDValue ICMP_UGT = DAG->getSetCC(DL, MVT::i1, Op0, Op1, ISD::SETUGT); |
| SDValue ICMP_EQ01 = DAG->getSetCC(DL, MVT::i1, Op0, Op1, ISD::SETEQ); |
| SDValue ICMP_EQ10 = DAG->getSetCC(DL, MVT::i1, Op1, Op0, ISD::SETEQ); |
| |
| auto Int1VT = EVT::getIntegerVT(Context, 1); |
| SDValue Cond = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(3), Int1VT); |
| SDValue T = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(4), Int1VT); |
| SDValue F = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(5), Int1VT); |
| SDValue Select = DAG->getSelect(DL, MVT::i1, Cond, T, F); |
| |
| auto VInt32VT = EVT::getVectorVT(Context, Int32VT, 4); |
| auto SmallVInt32VT = EVT::getVectorVT(Context, Int32VT, 2); |
| auto Idx0 = DAG->getVectorIdxConstant(0, DL); |
| auto Idx3 = DAG->getVectorIdxConstant(3, DL); |
| SDValue V1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(6), VInt32VT); |
| SDValue V2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(7), VInt32VT); |
| SDValue V3 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(8), SmallVInt32VT); |
| SDValue VSelect = DAG->getNode(ISD::VSELECT, DL, VInt32VT, Cond, V1, V2); |
| SDValue InsertSubvector = |
| DAG->getNode(ISD::INSERT_SUBVECTOR, DL, VInt32VT, V2, V3, Idx0); |
| |
| SDValue ExtractELT = |
| DAG->getNode(ISD::EXTRACT_VECTOR_ELT, DL, Int32VT, V1, Op3); |
| |
| SDValue Ch = DAG->getEntryNode(); |
| SDValue BasePtr = DAG->getRegister(1, MVT::i64); |
| SDValue Offset = DAG->getUNDEF(MVT::i64); |
| MachinePointerInfo PtrInfo; |
| SDValue Load = DAG->getLoad(MVT::i32, DL, Ch, BasePtr, PtrInfo); |
| |
| using namespace SDPatternMatch; |
| ISD::CondCode CC; |
| EXPECT_TRUE(sd_match(ICMP_UGT, m_SetCC(m_Value(), m_Value(), |
| m_SpecificCondCode(ISD::SETUGT)))); |
| EXPECT_TRUE( |
| sd_match(ICMP_UGT, m_SetCC(m_Value(), m_Value(), m_CondCode(CC)))); |
| EXPECT_TRUE(CC == ISD::SETUGT); |
| EXPECT_FALSE(sd_match( |
| ICMP_UGT, m_SetCC(m_Value(), m_Value(), m_SpecificCondCode(ISD::SETLE)))); |
| |
| EXPECT_TRUE(sd_match(ICMP_EQ01, m_SetCC(m_Specific(Op0), m_Specific(Op1), |
| m_SpecificCondCode(ISD::SETEQ)))); |
| EXPECT_TRUE(sd_match(ICMP_EQ10, m_SetCC(m_Specific(Op1), m_Specific(Op0), |
| m_SpecificCondCode(ISD::SETEQ)))); |
| EXPECT_FALSE(sd_match(ICMP_EQ01, m_SetCC(m_Specific(Op1), m_Specific(Op0), |
| m_SpecificCondCode(ISD::SETEQ)))); |
| EXPECT_FALSE(sd_match(ICMP_EQ10, m_SetCC(m_Specific(Op0), m_Specific(Op1), |
| m_SpecificCondCode(ISD::SETEQ)))); |
| EXPECT_TRUE(sd_match(ICMP_EQ01, m_c_SetCC(m_Specific(Op1), m_Specific(Op0), |
| m_SpecificCondCode(ISD::SETEQ)))); |
| EXPECT_TRUE(sd_match(ICMP_EQ10, m_c_SetCC(m_Specific(Op0), m_Specific(Op1), |
| m_SpecificCondCode(ISD::SETEQ)))); |
| |
| EXPECT_TRUE(sd_match( |
| Select, m_Select(m_Specific(Cond), m_Specific(T), m_Specific(F)))); |
| EXPECT_FALSE(sd_match( |
| Select, m_Select(m_Specific(Cond), m_Specific(F), m_Specific(T)))); |
| EXPECT_FALSE(sd_match(ICMP_EQ01, m_Select(m_Specific(Op0), m_Specific(Op1), |
| m_SpecificCondCode(ISD::SETEQ)))); |
| EXPECT_TRUE(sd_match( |
| VSelect, m_VSelect(m_Specific(Cond), m_Specific(V1), m_Specific(V2)))); |
| EXPECT_FALSE(sd_match( |
| Select, m_VSelect(m_Specific(Cond), m_Specific(V1), m_Specific(V2)))); |
| |
| EXPECT_TRUE(sd_match(ExtractELT, m_ExtractElt(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(ExtractELT, m_ExtractElt(m_Value(), m_ConstInt()))); |
| EXPECT_TRUE(sd_match(ExtractELT, m_ExtractElt(m_Value(), m_SpecificInt(1)))); |
| |
| EXPECT_TRUE(sd_match(InsertSubvector, |
| m_InsertSubvector(m_Value(), m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match( |
| InsertSubvector, |
| m_InsertSubvector(m_Specific(V2), m_Specific(V3), m_Specific(Idx0)))); |
| EXPECT_TRUE(sd_match( |
| InsertSubvector, |
| m_InsertSubvector(m_Specific(V2), m_Specific(V3), m_SpecificInt(0)))); |
| EXPECT_FALSE(sd_match( |
| InsertSubvector, |
| m_InsertSubvector(m_Specific(V2), m_Specific(V3), m_Specific(Idx3)))); |
| EXPECT_FALSE(sd_match( |
| InsertSubvector, |
| m_InsertSubvector(m_Specific(V2), m_Specific(V3), m_SpecificInt(3)))); |
| |
| EXPECT_TRUE(sd_match( |
| Load, m_Load(m_Specific(Ch), m_Specific(BasePtr), m_Specific(Offset)))); |
| |
| EXPECT_FALSE( |
| sd_match(Load.getValue(1), m_Load(m_Specific(Ch), m_Specific(BasePtr), |
| m_Specific(Offset)))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchBinaryOp) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| auto Float32VT = EVT::getFloatingPointVT(32); |
| auto BigVInt32VT = EVT::getVectorVT(Context, Int32VT, 8); |
| auto VInt32VT = EVT::getVectorVT(Context, Int32VT, 4); |
| |
| SDValue V1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(6), VInt32VT); |
| auto Idx0 = DAG->getVectorIdxConstant(0, DL); |
| auto Idx1 = DAG->getVectorIdxConstant(1, DL); |
| |
| SDValue SignBit = DAG->getConstant(0x80000000u, DL, Int32VT); |
| SDValue NoSignBit = DAG->getConstant(0x7fffffffu, DL, Int32VT); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int32VT); |
| SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(3), Float32VT); |
| SDValue Op3 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(8), Int32VT); |
| SDValue Op4 = DAG->getConstant(1, DL, Int32VT); |
| |
| SDValue NonNeg0 = DAG->getNode(ISD::AND, DL, Int32VT, Op0, NoSignBit); |
| SDValue NonNeg1 = DAG->getNode(ISD::AND, DL, Int32VT, Op1, NoSignBit); |
| SDValue Neg0 = DAG->getNode(ISD::OR, DL, Int32VT, Op0, SignBit); |
| SDValue Neg1 = DAG->getNode(ISD::OR, DL, Int32VT, Op1, SignBit); |
| |
| SDValue Add = DAG->getNode(ISD::ADD, DL, Int32VT, Op0, Op1); |
| SDValue Sub = DAG->getNode(ISD::SUB, DL, Int32VT, Add, Op0); |
| SDValue Mul = DAG->getNode(ISD::MUL, DL, Int32VT, Add, Sub); |
| SDValue And = DAG->getNode(ISD::AND, DL, Int32VT, Op0, Op1); |
| SDValue Xor = DAG->getNode(ISD::XOR, DL, Int32VT, Op1, Op0); |
| SDValue Or = DAG->getNode(ISD::OR, DL, Int32VT, Op0, Op1); |
| SDValue DisOr = |
| DAG->getNode(ISD::OR, DL, Int32VT, Op0, Op3, SDNodeFlags::Disjoint); |
| SDValue SMax = DAG->getNode(ISD::SMAX, DL, Int32VT, Op0, Op1); |
| SDValue SMin = DAG->getNode(ISD::SMIN, DL, Int32VT, Op1, Op0); |
| SDValue UMax = DAG->getNode(ISD::UMAX, DL, Int32VT, Op0, Op1); |
| SDValue UMin = DAG->getNode(ISD::UMIN, DL, Int32VT, Op1, Op0); |
| SDValue Rotl = DAG->getNode(ISD::ROTL, DL, Int32VT, Op0, Op1); |
| SDValue Rotr = DAG->getNode(ISD::ROTR, DL, Int32VT, Op1, Op0); |
| |
| SDValue SMulLoHi = DAG->getNode(ISD::SMUL_LOHI, DL, |
| DAG->getVTList(Int32VT, Int32VT), Op0, Op1); |
| SDValue PartsDiff = |
| DAG->getNode(ISD::SUB, DL, Int32VT, SMulLoHi, SMulLoHi.getValue(1)); |
| |
| SDValue ICMP_GT = DAG->getSetCC(DL, MVT::i1, Op0, Op1, ISD::SETGT); |
| SDValue ICMP_GE = DAG->getSetCC(DL, MVT::i1, Op0, Op1, ISD::SETGE); |
| SDValue ICMP_UGT = DAG->getSetCC(DL, MVT::i1, Op0, Op1, ISD::SETUGT); |
| SDValue ICMP_UGE = DAG->getSetCC(DL, MVT::i1, Op0, Op1, ISD::SETUGE); |
| SDValue ICMP_LT = DAG->getSetCC(DL, MVT::i1, Op0, Op1, ISD::SETLT); |
| SDValue ICMP_LE = DAG->getSetCC(DL, MVT::i1, Op0, Op1, ISD::SETLE); |
| SDValue ICMP_ULT = DAG->getSetCC(DL, MVT::i1, Op0, Op1, ISD::SETULT); |
| SDValue ICMP_ULE = DAG->getSetCC(DL, MVT::i1, Op0, Op1, ISD::SETULE); |
| SDValue SMaxLikeGT = DAG->getSelect(DL, MVT::i32, ICMP_GT, Op0, Op1); |
| SDValue SMaxLikeGE = DAG->getSelect(DL, MVT::i32, ICMP_GE, Op0, Op1); |
| SDValue UMaxLikeUGT = DAG->getSelect(DL, MVT::i32, ICMP_UGT, Op0, Op1); |
| SDValue UMaxLikeUGE = DAG->getSelect(DL, MVT::i32, ICMP_UGE, Op0, Op1); |
| SDValue SMinLikeLT = DAG->getSelect(DL, MVT::i32, ICMP_LT, Op0, Op1); |
| SDValue SMinLikeLE = DAG->getSelect(DL, MVT::i32, ICMP_LE, Op0, Op1); |
| SDValue UMinLikeULT = DAG->getSelect(DL, MVT::i32, ICMP_ULT, Op0, Op1); |
| SDValue UMinLikeULE = DAG->getSelect(DL, MVT::i32, ICMP_ULE, Op0, Op1); |
| |
| SDValue CCSMaxLikeGT = DAG->getSelectCC(DL, Op0, Op1, Op0, Op1, ISD::SETGT); |
| SDValue CCSMaxLikeGE = DAG->getSelectCC(DL, Op0, Op1, Op0, Op1, ISD::SETGE); |
| SDValue CCSMaxLikeLT = DAG->getSelectCC(DL, Op0, Op1, Op1, Op0, ISD::SETLT); |
| SDValue CCSMaxLikeLE = DAG->getSelectCC(DL, Op0, Op1, Op1, Op0, ISD::SETLE); |
| SDValue CCUMaxLikeUGT = DAG->getSelectCC(DL, Op0, Op1, Op0, Op1, ISD::SETUGT); |
| SDValue CCUMaxLikeUGE = DAG->getSelectCC(DL, Op0, Op1, Op0, Op1, ISD::SETUGE); |
| SDValue CCUMaxLikeULT = DAG->getSelectCC(DL, Op0, Op1, Op1, Op0, ISD::SETULT); |
| SDValue CCUMaxLikeULE = DAG->getSelectCC(DL, Op0, Op1, Op1, Op0, ISD::SETULE); |
| SDValue CCSMinLikeLT = DAG->getSelectCC(DL, Op0, Op1, Op0, Op1, ISD::SETLT); |
| SDValue CCSMinLikeGT = DAG->getSelectCC(DL, Op0, Op1, Op1, Op0, ISD::SETGT); |
| SDValue CCSMinLikeLE = DAG->getSelectCC(DL, Op0, Op1, Op0, Op1, ISD::SETLE); |
| SDValue CCSMinLikeGE = DAG->getSelectCC(DL, Op0, Op1, Op1, Op0, ISD::SETGE); |
| SDValue CCUMinLikeULT = DAG->getSelectCC(DL, Op0, Op1, Op0, Op1, ISD::SETULT); |
| SDValue CCUMinLikeUGT = DAG->getSelectCC(DL, Op0, Op1, Op1, Op0, ISD::SETUGT); |
| SDValue CCUMinLikeULE = DAG->getSelectCC(DL, Op0, Op1, Op0, Op1, ISD::SETULE); |
| SDValue CCUMinLikeUGE = DAG->getSelectCC(DL, Op0, Op1, Op1, Op0, ISD::SETUGE); |
| |
| SDValue UMaxNonNeg = DAG->getNode(ISD::UMAX, DL, Int32VT, NonNeg0, NonNeg1); |
| SDValue UMinNonNeg = DAG->getNode(ISD::UMIN, DL, Int32VT, NonNeg0, NonNeg1); |
| SDValue SMaxNonNeg = DAG->getNode(ISD::SMAX, DL, Int32VT, NonNeg0, NonNeg1); |
| SDValue SMinNonNeg = DAG->getNode(ISD::SMIN, DL, Int32VT, NonNeg0, NonNeg1); |
| SDValue UMaxNeg = DAG->getNode(ISD::UMAX, DL, Int32VT, Neg0, Neg1); |
| SDValue UMinNeg = DAG->getNode(ISD::UMIN, DL, Int32VT, Neg0, Neg1); |
| SDValue SMaxNeg = DAG->getNode(ISD::SMAX, DL, Int32VT, Neg0, Neg1); |
| SDValue SMinNeg = DAG->getNode(ISD::SMIN, DL, Int32VT, Neg0, Neg1); |
| SDValue UMaxDiffSign = DAG->getNode(ISD::UMAX, DL, Int32VT, Neg0, NonNeg1); |
| SDValue UMinDiffSign = DAG->getNode(ISD::UMIN, DL, Int32VT, Neg0, NonNeg1); |
| SDValue SMaxDiffSign = DAG->getNode(ISD::SMAX, DL, Int32VT, Neg0, NonNeg1); |
| SDValue SMinDiffSign = DAG->getNode(ISD::SMIN, DL, Int32VT, Neg0, NonNeg1); |
| |
| SDValue ICMP_NN_UGT = |
| DAG->getSetCC(DL, MVT::i1, NonNeg0, NonNeg1, ISD::SETUGT); |
| SDValue ICMP_NN_ULT = |
| DAG->getSetCC(DL, MVT::i1, NonNeg0, NonNeg1, ISD::SETULT); |
| SDValue ICMP_NN_GT = DAG->getSetCC(DL, MVT::i1, NonNeg0, NonNeg1, ISD::SETGT); |
| SDValue ICMP_NN_LT = DAG->getSetCC(DL, MVT::i1, NonNeg0, NonNeg1, ISD::SETLT); |
| SDValue ICMP_N_UGT = DAG->getSetCC(DL, MVT::i1, Neg0, Neg1, ISD::SETUGT); |
| SDValue ICMP_N_ULT = DAG->getSetCC(DL, MVT::i1, Neg0, Neg1, ISD::SETULT); |
| SDValue ICMP_N_GT = DAG->getSetCC(DL, MVT::i1, Neg0, Neg1, ISD::SETGT); |
| SDValue ICMP_N_LT = DAG->getSetCC(DL, MVT::i1, Neg0, Neg1, ISD::SETLT); |
| SDValue UMaxLikeNN_UGT = |
| DAG->getSelect(DL, MVT::i32, ICMP_NN_UGT, NonNeg0, NonNeg1); |
| SDValue UMinLikeNN_ULT = |
| DAG->getSelect(DL, MVT::i32, ICMP_NN_ULT, NonNeg0, NonNeg1); |
| SDValue SMaxLikeNN_GT = |
| DAG->getSelect(DL, MVT::i32, ICMP_NN_GT, NonNeg0, NonNeg1); |
| SDValue SMinLikeNN_LT = |
| DAG->getSelect(DL, MVT::i32, ICMP_NN_LT, NonNeg0, NonNeg1); |
| SDValue UMaxLikeN_UGT = DAG->getSelect(DL, MVT::i32, ICMP_N_UGT, Neg0, Neg1); |
| SDValue UMinLikeN_ULT = DAG->getSelect(DL, MVT::i32, ICMP_N_ULT, Neg0, Neg1); |
| SDValue SMaxLikeN_GT = DAG->getSelect(DL, MVT::i32, ICMP_N_GT, Neg0, Neg1); |
| SDValue SMinLikeN_LT = DAG->getSelect(DL, MVT::i32, ICMP_N_LT, Neg0, Neg1); |
| |
| SDValue SFAdd = DAG->getNode(ISD::STRICT_FADD, DL, {Float32VT, MVT::Other}, |
| {DAG->getEntryNode(), Op2, Op2}); |
| |
| SDValue Vec = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(9), BigVInt32VT); |
| SDValue SubVec = |
| DAG->getNode(ISD::EXTRACT_SUBVECTOR, DL, VInt32VT, Vec, Idx0); |
| |
| SDValue InsertELT = |
| DAG->getNode(ISD::INSERT_VECTOR_ELT, DL, VInt32VT, V1, Op0, Op4); |
| |
| using namespace SDPatternMatch; |
| EXPECT_TRUE(sd_match(Sub, m_BinOp(ISD::SUB, m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Sub, m_Sub(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Add, m_c_BinOp(ISD::ADD, m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Add, m_Add(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Add, m_AddLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Mul, m_Mul(m_OneUse(m_SpecificOpc(ISD::SUB)), |
| m_NUses<2>(m_Specific(Add))))); |
| EXPECT_TRUE( |
| sd_match(SFAdd, m_ChainedBinOp(ISD::STRICT_FADD, m_SpecificVT(Float32VT), |
| m_SpecificVT(Float32VT)))); |
| EXPECT_FALSE(sd_match(Add, m_BitwiseLogic(m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(Sub, m_BitwiseLogic(m_Value(), m_Value()))); |
| |
| EXPECT_TRUE(sd_match(And, m_c_BinOp(ISD::AND, m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(And, m_And(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(And, m_BitwiseLogic(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Xor, m_c_BinOp(ISD::XOR, m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Xor, m_Xor(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Xor, m_BitwiseLogic(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Or, m_c_BinOp(ISD::OR, m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Or, m_Or(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Or, m_BitwiseLogic(m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(Or, m_DisjointOr(m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match( |
| Or, m_BinOp(ISD::OR, m_Value(), m_Value(), SDNodeFlags::Disjoint))); |
| EXPECT_FALSE(sd_match( |
| Or, m_c_BinOp(ISD::OR, m_Value(), m_Value(), SDNodeFlags::Disjoint))); |
| |
| EXPECT_TRUE(sd_match(DisOr, m_Or(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(DisOr, m_DisjointOr(m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(DisOr, m_Add(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(DisOr, m_AddLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match( |
| DisOr, m_BinOp(ISD::OR, m_Value(), m_Value(), SDNodeFlags::Disjoint))); |
| EXPECT_TRUE(sd_match( |
| DisOr, m_c_BinOp(ISD::OR, m_Value(), m_Value(), SDNodeFlags::Disjoint))); |
| |
| EXPECT_TRUE(sd_match(Rotl, m_Rotl(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(Rotr, m_Rotr(m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(Rotl, m_Rotr(m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(Rotr, m_Rotl(m_Value(), m_Value()))); |
| |
| EXPECT_TRUE(sd_match(SMax, m_c_BinOp(ISD::SMAX, m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(SMax, m_SMax(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(SMax, m_SMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(SMaxLikeGT, m_SMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(SMaxLikeGE, m_SMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCSMaxLikeGT, m_SMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCSMaxLikeGE, m_SMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCSMaxLikeLT, m_SMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCSMaxLikeLE, m_SMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(SMin, m_c_BinOp(ISD::SMIN, m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(SMin, m_SMin(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(SMin, m_SMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(SMinLikeLT, m_SMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(SMinLikeLE, m_SMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCSMinLikeGT, m_SMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCSMinLikeGE, m_SMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCSMinLikeLT, m_SMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCSMinLikeLE, m_SMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(UMax, m_c_BinOp(ISD::UMAX, m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(UMax, m_UMax(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(UMax, m_UMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(UMaxLikeUGT, m_UMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(UMaxLikeUGE, m_UMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCUMaxLikeUGT, m_UMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCUMaxLikeUGE, m_UMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCUMaxLikeULT, m_UMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCUMaxLikeULE, m_UMaxLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(UMin, m_c_BinOp(ISD::UMIN, m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(UMin, m_UMin(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(UMin, m_UMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(UMinLikeULT, m_UMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(UMinLikeULE, m_UMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCUMinLikeUGT, m_UMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCUMinLikeUGE, m_UMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCUMinLikeULT, m_UMinLike(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(CCUMinLikeULE, m_UMinLike(m_Value(), m_Value()))); |
| |
| EXPECT_TRUE(sd_match(UMaxNonNeg, DAG.get(), |
| m_UMaxLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| EXPECT_TRUE(sd_match(UMaxNonNeg, DAG.get(), |
| m_SMaxLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| EXPECT_TRUE(sd_match(UMinNonNeg, DAG.get(), |
| m_UMinLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| EXPECT_TRUE(sd_match(UMinNonNeg, DAG.get(), |
| m_SMinLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| |
| EXPECT_TRUE(sd_match(SMaxNonNeg, DAG.get(), |
| m_SMaxLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| EXPECT_TRUE(sd_match(SMaxNonNeg, DAG.get(), |
| m_UMaxLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| EXPECT_TRUE(sd_match(SMinNonNeg, DAG.get(), |
| m_SMinLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| EXPECT_TRUE(sd_match(SMinNonNeg, DAG.get(), |
| m_UMinLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| |
| EXPECT_TRUE(sd_match(UMaxNeg, DAG.get(), |
| m_UMaxLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| EXPECT_TRUE(sd_match(UMaxNeg, DAG.get(), |
| m_SMaxLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| EXPECT_TRUE(sd_match(UMinNeg, DAG.get(), |
| m_UMinLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| EXPECT_TRUE(sd_match(UMinNeg, DAG.get(), |
| m_SMinLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| |
| EXPECT_TRUE(sd_match(SMaxNeg, DAG.get(), |
| m_SMaxLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| EXPECT_TRUE(sd_match(SMaxNeg, DAG.get(), |
| m_UMaxLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| EXPECT_TRUE(sd_match(SMinNeg, DAG.get(), |
| m_SMinLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| EXPECT_TRUE(sd_match(SMinNeg, DAG.get(), |
| m_UMinLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| |
| EXPECT_TRUE(sd_match(UMaxLikeNN_UGT, DAG.get(), |
| m_SMaxLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| EXPECT_TRUE(sd_match(UMinLikeNN_ULT, DAG.get(), |
| m_SMinLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| EXPECT_TRUE(sd_match(SMaxLikeNN_GT, DAG.get(), |
| m_UMaxLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| EXPECT_TRUE(sd_match(SMinLikeNN_LT, DAG.get(), |
| m_UMinLike(m_Specific(NonNeg0), m_Specific(NonNeg1)))); |
| EXPECT_TRUE(sd_match(UMaxLikeN_UGT, DAG.get(), |
| m_SMaxLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| EXPECT_TRUE(sd_match(UMinLikeN_ULT, DAG.get(), |
| m_SMinLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| EXPECT_TRUE(sd_match(SMaxLikeN_GT, DAG.get(), |
| m_UMaxLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| EXPECT_TRUE(sd_match(SMinLikeN_LT, DAG.get(), |
| m_UMinLike(m_Specific(Neg0), m_Specific(Neg1)))); |
| |
| EXPECT_FALSE( |
| sd_match(UMax, DAG.get(), m_SMaxLike(m_Specific(Op0), m_Specific(Op1)))); |
| EXPECT_FALSE( |
| sd_match(UMin, DAG.get(), m_SMinLike(m_Specific(Op0), m_Specific(Op1)))); |
| EXPECT_FALSE( |
| sd_match(SMax, DAG.get(), m_UMaxLike(m_Specific(Op0), m_Specific(Op1)))); |
| EXPECT_FALSE( |
| sd_match(SMin, DAG.get(), m_UMinLike(m_Specific(Op0), m_Specific(Op1)))); |
| |
| EXPECT_FALSE(sd_match(UMaxDiffSign, DAG.get(), |
| m_SMaxLike(m_Specific(Neg0), m_Specific(NonNeg1)))); |
| EXPECT_FALSE(sd_match(UMinDiffSign, DAG.get(), |
| m_SMinLike(m_Specific(Neg0), m_Specific(NonNeg1)))); |
| EXPECT_FALSE(sd_match(SMaxDiffSign, DAG.get(), |
| m_UMaxLike(m_Specific(Neg0), m_Specific(NonNeg1)))); |
| EXPECT_FALSE(sd_match(SMinDiffSign, DAG.get(), |
| m_UMinLike(m_Specific(Neg0), m_Specific(NonNeg1)))); |
| |
| SDValue BindVal; |
| // By default, it matches any of the results. |
| EXPECT_TRUE(sd_match(PartsDiff, m_Sub(m_SpecificOpc(ISD::SMUL_LOHI), |
| m_SpecificOpc(ISD::SMUL_LOHI)))); |
| // Matching a specific result. |
| EXPECT_TRUE( |
| sd_match(PartsDiff, m_Sub(m_SpecificOpc(ISD::SMUL_LOHI), |
| m_Result<1>(m_SpecificOpc(ISD::SMUL_LOHI))))); |
| EXPECT_FALSE( |
| sd_match(PartsDiff, m_Sub(m_SpecificOpc(ISD::SMUL_LOHI), |
| m_Result<0>(m_SpecificOpc(ISD::SMUL_LOHI))))); |
| |
| // Conditionally bind the value from a certain sub-pattern. |
| EXPECT_TRUE( |
| sd_match(PartsDiff, m_Sub(m_Value(BindVal, m_SpecificOpc(ISD::SMUL_LOHI)), |
| m_SpecificOpc(ISD::SMUL_LOHI)))); |
| EXPECT_EQ(BindVal, SMulLoHi); |
| BindVal = SDValue(); |
| EXPECT_FALSE( |
| sd_match(PartsDiff, m_Sub(m_Value(BindVal, m_SpecificOpc(ISD::ADD)), |
| m_SpecificOpc(ISD::SMUL_LOHI)))); |
| EXPECT_NE(BindVal, SMulLoHi); |
| |
| BindVal = SDValue(); |
| EXPECT_TRUE(sd_match(SFAdd, m_ChainedBinOp(ISD::STRICT_FADD, m_Value(BindVal), |
| m_Deferred(BindVal)))); |
| EXPECT_FALSE(sd_match(SFAdd, m_ChainedBinOp(ISD::STRICT_FADD, m_OtherVT(), |
| m_SpecificVT(Float32VT)))); |
| BindVal = SDValue(); |
| EXPECT_TRUE( |
| sd_match(SFAdd, m_ChainedBinOp(ISD::STRICT_FADD, |
| m_Value(BindVal, m_SpecificVT(Float32VT)), |
| m_Deferred(BindVal)))); |
| BindVal = SDValue(); |
| EXPECT_FALSE(sd_match(SFAdd, m_ChainedBinOp(ISD::STRICT_FADD, |
| m_Value(BindVal, m_OtherVT()), |
| m_Deferred(BindVal)))); |
| |
| EXPECT_TRUE(sd_match(SubVec, m_ExtractSubvector(m_Value(), m_Value()))); |
| EXPECT_TRUE( |
| sd_match(SubVec, m_ExtractSubvector(m_Specific(Vec), m_Specific(Idx0)))); |
| EXPECT_TRUE( |
| sd_match(SubVec, m_ExtractSubvector(m_Specific(Vec), m_SpecificInt(0)))); |
| EXPECT_FALSE( |
| sd_match(SubVec, m_ExtractSubvector(m_Specific(Vec), m_Specific(Idx1)))); |
| EXPECT_FALSE( |
| sd_match(SubVec, m_ExtractSubvector(m_Specific(Vec), m_SpecificInt(1)))); |
| |
| EXPECT_TRUE( |
| sd_match(InsertELT, m_InsertElt(m_Value(), m_Value(), m_Value()))); |
| EXPECT_TRUE( |
| sd_match(InsertELT, m_InsertElt(m_Value(), m_Value(), m_ConstInt()))); |
| EXPECT_TRUE( |
| sd_match(InsertELT, m_InsertElt(m_Value(), m_Value(), m_SpecificInt(1)))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchSpecificFpOp) { |
| SDLoc DL; |
| APFloat Value(1.5f); |
| auto Float32VT = EVT::getFloatingPointVT(32); |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Float32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Float32VT); |
| SDValue Op2 = DAG->getConstantFP(Value, DL, Float32VT); |
| SDValue FAdd0 = DAG->getNode(ISD::FADD, DL, Float32VT, Op0, Op1); |
| SDValue FAdd1 = DAG->getNode(ISD::FADD, DL, Float32VT, Op1, Op2); |
| |
| using namespace SDPatternMatch; |
| |
| EXPECT_FALSE(sd_match(Op1, m_SpecificFP(Value))); |
| EXPECT_TRUE(sd_match(Op2, m_SpecificFP(Value))); |
| |
| EXPECT_FALSE(sd_match( |
| FAdd0, m_BinOp(ISD::FADD, m_Specific(Op0), m_SpecificFP(Value)))); |
| EXPECT_TRUE(sd_match( |
| FAdd1, m_BinOp(ISD::FADD, m_Specific(Op1), m_SpecificFP(Value)))); |
| EXPECT_TRUE(sd_match( |
| FAdd1, m_c_BinOp(ISD::FADD, m_SpecificFP(Value), m_Specific(Op1)))); |
| |
| auto VFloat32VT = EVT::getVectorVT(Context, Float32VT, 2); |
| SDValue VOp0 = DAG->getSplat(VFloat32VT, DL, Op0); |
| SDValue VOp1 = DAG->getSplat(VFloat32VT, DL, Op1); |
| SDValue VOp2 = DAG->getSplat(VFloat32VT, DL, Op2); |
| |
| EXPECT_FALSE(sd_match(VOp0, m_SpecificFP(Value))); |
| EXPECT_TRUE(sd_match(VOp2, m_SpecificFP(Value))); |
| |
| SDValue VFAdd0 = DAG->getNode(ISD::FADD, DL, VFloat32VT, VOp0, VOp1); |
| SDValue VFAdd1 = DAG->getNode(ISD::FADD, DL, VFloat32VT, VOp1, VOp2); |
| EXPECT_FALSE(sd_match( |
| VFAdd0, m_BinOp(ISD::FADD, m_Specific(VOp0), m_SpecificFP(Value)))); |
| EXPECT_TRUE(sd_match( |
| VFAdd1, m_BinOp(ISD::FADD, m_Specific(VOp1), m_SpecificFP(Value)))); |
| EXPECT_TRUE(sd_match( |
| VFAdd1, m_c_BinOp(ISD::FADD, m_SpecificFP(Value), m_Specific(VOp1)))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchGenericTernaryOp) { |
| SDLoc DL; |
| auto Float32VT = EVT::getFloatingPointVT(32); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Float32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Float32VT); |
| SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(3), Float32VT); |
| |
| SDValue FMA = DAG->getNode(ISD::FMA, DL, Float32VT, Op0, Op1, Op2); |
| SDValue FAdd = DAG->getNode(ISD::FADD, DL, Float32VT, Op0, Op1); |
| |
| using namespace SDPatternMatch; |
| SDValue A, B, C; |
| |
| EXPECT_TRUE(sd_match(FMA, m_TernaryOp(ISD::FMA, m_Specific(Op0), |
| m_Specific(Op1), m_Specific(Op2)))); |
| EXPECT_FALSE(sd_match(FMA, m_TernaryOp(ISD::FADD, m_Specific(Op0), |
| m_Specific(Op1), m_Specific(Op2)))); |
| EXPECT_FALSE( |
| sd_match(FAdd, m_TernaryOp(ISD::FMA, m_Value(), m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(FMA, m_TernaryOp(ISD::FMA, m_Specific(Op1), |
| m_Specific(Op0), m_Specific(Op2)))); |
| |
| EXPECT_TRUE( |
| sd_match(FMA, m_TernaryOp(ISD::FMA, m_Value(A), m_Value(B), m_Value(C)))); |
| EXPECT_EQ(A, Op0); |
| EXPECT_EQ(B, Op1); |
| EXPECT_EQ(C, Op2); |
| |
| A = B = C = SDValue(); |
| |
| EXPECT_TRUE(sd_match(FMA, m_c_TernaryOp(ISD::FMA, m_Specific(Op0), |
| m_Specific(Op1), m_Specific(Op2)))); |
| EXPECT_TRUE(sd_match(FMA, m_c_TernaryOp(ISD::FMA, m_Specific(Op1), |
| m_Specific(Op0), m_Specific(Op2)))); |
| |
| EXPECT_FALSE(sd_match(FMA, m_c_TernaryOp(ISD::FMA, m_Specific(Op2), |
| m_Specific(Op1), m_Specific(Op0)))); |
| EXPECT_FALSE(sd_match(FMA, m_c_TernaryOp(ISD::FMA, m_Specific(Op2), |
| m_Specific(Op0), m_Specific(Op1)))); |
| |
| EXPECT_FALSE(sd_match(FMA, m_c_TernaryOp(ISD::FMA, m_Specific(Op0), |
| m_Specific(Op2), m_Specific(Op1)))); |
| EXPECT_FALSE(sd_match(FMA, m_c_TernaryOp(ISD::FMA, m_Specific(Op1), |
| m_Specific(Op2), m_Specific(Op0)))); |
| |
| EXPECT_TRUE(sd_match( |
| FMA, m_c_TernaryOp(ISD::FMA, m_Value(A), m_Value(B), m_Value(C)))); |
| EXPECT_EQ(A, Op0); |
| EXPECT_EQ(B, Op1); |
| EXPECT_EQ(C, Op2); |
| |
| A = B = C = SDValue(); |
| EXPECT_TRUE(sd_match( |
| FMA, m_c_TernaryOp(ISD::FMA, m_Value(B), m_Value(A), m_Value(C)))); |
| EXPECT_EQ(A, Op1); |
| EXPECT_EQ(B, Op0); |
| EXPECT_EQ(C, Op2); |
| |
| A = B = C = SDValue(); |
| EXPECT_TRUE(sd_match( |
| FMA, m_c_TernaryOp(ISD::FMA, m_Value(A), m_Value(B), m_Value(C)))); |
| EXPECT_EQ(A, Op0); |
| EXPECT_EQ(B, Op1); |
| EXPECT_EQ(C, Op2); |
| |
| EXPECT_FALSE( |
| sd_match(FAdd, m_c_TernaryOp(ISD::FMA, m_Value(), m_Value(), m_Value()))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchFunnelShift) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int32VT); |
| SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(3), Int32VT); |
| SDValue C7 = DAG->getConstant(7, DL, Int32VT); |
| SDValue C24 = DAG->getConstant(24, DL, Int32VT); |
| SDValue C25 = DAG->getConstant(25, DL, Int32VT); |
| |
| SDValue FShL = DAG->getNode(ISD::FSHL, DL, Int32VT, Op0, Op1, Op2); |
| SDValue FShR = DAG->getNode(ISD::FSHR, DL, Int32VT, Op0, Op1, Op2); |
| SDValue Rotl = DAG->getNode(ISD::ROTL, DL, Int32VT, Op0, Op2); |
| SDValue Rotr = DAG->getNode(ISD::ROTR, DL, Int32VT, Op0, Op2); |
| |
| SDValue Shl7 = DAG->getNode(ISD::SHL, DL, Int32VT, Op0, C7); |
| SDValue Srl25 = DAG->getNode(ISD::SRL, DL, Int32VT, Op1, C25); |
| SDValue Srl24 = DAG->getNode(ISD::SRL, DL, Int32VT, Op1, C24); |
| SDValue OrFSh = DAG->getNode(ISD::OR, DL, Int32VT, Shl7, Srl25); |
| SDValue OrFShCommuted = DAG->getNode(ISD::OR, DL, Int32VT, Srl25, Shl7); |
| SDValue BadOrFSh = DAG->getNode(ISD::OR, DL, Int32VT, Shl7, Srl24); |
| |
| using namespace SDPatternMatch; |
| EXPECT_TRUE(sd_match( |
| FShL, m_FShL(m_Specific(Op0), m_Specific(Op1), m_Specific(Op2)))); |
| EXPECT_TRUE(sd_match( |
| FShR, m_FShR(m_Specific(Op0), m_Specific(Op1), m_Specific(Op2)))); |
| EXPECT_FALSE(sd_match(FShL, m_FShR(m_Value(), m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(FShR, m_FShL(m_Value(), m_Value(), m_Value()))); |
| |
| EXPECT_TRUE(sd_match( |
| FShL, m_FShLLike(m_Specific(Op0), m_Specific(Op1), m_Specific(Op2)))); |
| EXPECT_TRUE(sd_match( |
| FShR, m_FShRLike(m_Specific(Op0), m_Specific(Op1), m_Specific(Op2)))); |
| EXPECT_FALSE(sd_match(FShL, m_FShRLike(m_Value(), m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(FShR, m_FShLLike(m_Value(), m_Value(), m_Value()))); |
| |
| EXPECT_TRUE(sd_match( |
| Rotl, m_FShLLike(m_Specific(Op0), m_Specific(Op0), m_Specific(Op2)))); |
| EXPECT_TRUE(sd_match( |
| Rotr, m_FShRLike(m_Specific(Op0), m_Specific(Op0), m_Specific(Op2)))); |
| EXPECT_FALSE(sd_match( |
| Rotl, m_FShLLike(m_Specific(Op0), m_Specific(Op1), m_Specific(Op2)))); |
| EXPECT_FALSE(sd_match( |
| Rotr, m_FShRLike(m_Specific(Op0), m_Specific(Op1), m_Specific(Op2)))); |
| EXPECT_FALSE(sd_match(Rotl, m_FShRLike(m_Value(), m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(Rotr, m_FShLLike(m_Value(), m_Value(), m_Value()))); |
| |
| SDValue A, B, C; |
| EXPECT_TRUE(sd_match(Rotl, m_FShLLike(m_Value(A), m_Value(B), m_Value(C)))); |
| EXPECT_EQ(A, Op0); |
| EXPECT_EQ(B, Op0); |
| EXPECT_EQ(C, Op2); |
| |
| A = B = C = SDValue(); |
| EXPECT_TRUE(sd_match(Rotr, m_FShRLike(m_Value(A), m_Value(B), m_Value(C)))); |
| EXPECT_EQ(A, Op0); |
| EXPECT_EQ(B, Op0); |
| EXPECT_EQ(C, Op2); |
| |
| EXPECT_TRUE(sd_match( |
| OrFSh, m_FShLLike(m_Specific(Op0), m_Specific(Op1), m_SpecificInt(7)))); |
| EXPECT_TRUE(sd_match( |
| OrFSh, m_FShRLike(m_Specific(Op0), m_Specific(Op1), m_SpecificInt(25)))); |
| EXPECT_TRUE( |
| sd_match(OrFShCommuted, |
| m_FShLLike(m_Specific(Op0), m_Specific(Op1), m_SpecificInt(7)))); |
| EXPECT_TRUE( |
| sd_match(OrFShCommuted, m_FShRLike(m_Specific(Op0), m_Specific(Op1), |
| m_SpecificInt(25)))); |
| EXPECT_FALSE(sd_match(BadOrFSh, m_FShLLike(m_Value(), m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(BadOrFSh, m_FShRLike(m_Value(), m_Value(), m_Value()))); |
| |
| auto Int1024VT = EVT::getIntegerVT(Context, 1024); |
| auto Int8VT = EVT::getIntegerVT(Context, 8); |
| SDValue WideOp0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(4), Int1024VT); |
| SDValue WideOp1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(5), Int1024VT); |
| SDValue C0I8 = DAG->getConstant(0, DL, Int8VT); |
| SDValue WideShl = DAG->getNode(ISD::SHL, DL, Int1024VT, WideOp0, C0I8); |
| SDValue WideSrl = DAG->getNode(ISD::SRL, DL, Int1024VT, WideOp1, C0I8); |
| SDValue WideOr = DAG->getNode(ISD::OR, DL, Int1024VT, WideShl, WideSrl); |
| EXPECT_FALSE(sd_match(WideOr, m_FShLLike(m_Value(), m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(WideOr, m_FShRLike(m_Value(), m_Value(), m_Value()))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchUnaryOp) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| auto Int64VT = EVT::getIntegerVT(Context, 64); |
| auto FloatVT = EVT::getFloatingPointVT(32); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int64VT); |
| SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(3), FloatVT); |
| SDValue Op3 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(4), Int32VT); |
| |
| SDValue ZExt = DAG->getNode(ISD::ZERO_EXTEND, DL, Int64VT, Op0); |
| SDValue ZExtNNeg = |
| DAG->getNode(ISD::ZERO_EXTEND, DL, Int64VT, Op3, SDNodeFlags::NonNeg); |
| SDValue SExt = DAG->getNode(ISD::SIGN_EXTEND, DL, Int64VT, Op0); |
| SDValue Trunc = DAG->getNode(ISD::TRUNCATE, DL, Int32VT, Op1); |
| |
| SDValue Abs = DAG->getNode(ISD::ABS, DL, Int32VT, Op0); |
| |
| SDValue Sub = DAG->getNode(ISD::SUB, DL, Int32VT, Trunc, Op0); |
| SDValue Neg = DAG->getNegative(Op0, DL, Int32VT); |
| SDValue Not = DAG->getNOT(DL, Op0, Int32VT); |
| |
| SDValue VScale = DAG->getVScale(DL, Int32VT, APInt::getMaxValue(32)); |
| |
| SDValue FPToSI = DAG->getNode(ISD::FP_TO_SINT, DL, FloatVT, Op2); |
| SDValue FPToUI = DAG->getNode(ISD::FP_TO_UINT, DL, FloatVT, Op2); |
| |
| SDValue Bcast = DAG->getNode(ISD::BITCAST, DL, FloatVT, Op0); |
| SDValue Brev = DAG->getNode(ISD::BITREVERSE, DL, Int32VT, Op0); |
| SDValue Bswap = DAG->getNode(ISD::BSWAP, DL, Int32VT, Op0); |
| |
| SDValue Ctpop = DAG->getNode(ISD::CTPOP, DL, Int32VT, Op0); |
| SDValue Ctlz = DAG->getNode(ISD::CTLZ, DL, Int32VT, Op0); |
| SDValue Cttz = DAG->getNode(ISD::CTTZ, DL, Int32VT, Op0); |
| |
| SDValue SignBit = DAG->getConstant(0x80000000u, DL, Int32VT); |
| SDValue LSB = DAG->getConstant(0x00000001u, DL, Int32VT); |
| SDValue NotSignBit = DAG->getNOT(DL, SignBit, Int32VT); |
| |
| // Clear sign bit of Op0 |
| SDValue NonNegativeValue = |
| DAG->getNode(ISD::AND, DL, Int32VT, Op0, NotSignBit); |
| // Set sign bit to Op0 |
| SDValue NegativeValue = DAG->getNode(ISD::OR, DL, Int32VT, Op0, SignBit); |
| // Set LSB of Op0 |
| SDValue PositiveValue = |
| DAG->getNode(ISD::OR, DL, Int32VT, NonNegativeValue, LSB); |
| |
| using namespace SDPatternMatch; |
| EXPECT_TRUE(sd_match(ZExt, m_UnaryOp(ISD::ZERO_EXTEND, m_Value()))); |
| EXPECT_TRUE(sd_match(SExt, m_SExt(m_Value()))); |
| EXPECT_TRUE(sd_match(SExt, m_SExtLike(m_Value()))); |
| ASSERT_TRUE(ZExtNNeg->getFlags().hasNonNeg()); |
| EXPECT_FALSE(sd_match(ZExtNNeg, m_SExt(m_Value()))); |
| EXPECT_TRUE(sd_match(ZExtNNeg, m_NNegZExt(m_Value()))); |
| EXPECT_FALSE(sd_match(ZExt, m_NNegZExt(m_Value()))); |
| EXPECT_TRUE(sd_match(ZExtNNeg, m_SExtLike(m_Value()))); |
| EXPECT_FALSE(sd_match(ZExt, m_SExtLike(m_Value()))); |
| EXPECT_TRUE(sd_match(Trunc, m_Trunc(m_Specific(Op1)))); |
| |
| EXPECT_TRUE(sd_match(Abs, m_Abs(m_Specific(Op0)))); |
| EXPECT_FALSE(sd_match(Abs, m_FAbs(m_Value()))); |
| |
| SDValue FAbs = DAG->getNode(ISD::FABS, DL, FloatVT, Op2); |
| EXPECT_TRUE(sd_match(FAbs, m_FAbs(m_Specific(Op2)))); |
| EXPECT_TRUE(sd_match(FAbs, m_FAbs(m_Value()))); |
| EXPECT_FALSE(sd_match(FAbs, m_Abs(m_Value()))); |
| |
| EXPECT_TRUE(sd_match(Neg, m_Neg(m_Value()))); |
| EXPECT_TRUE(sd_match(Not, m_Not(m_Value()))); |
| EXPECT_FALSE(sd_match(ZExt, m_Neg(m_Value()))); |
| EXPECT_FALSE(sd_match(Sub, m_Neg(m_Value()))); |
| EXPECT_FALSE(sd_match(Neg, m_Not(m_Value()))); |
| |
| SDValue BindVal; |
| |
| EXPECT_FALSE(sd_match(Abs, DAG.get(), m_Negative())); |
| |
| EXPECT_FALSE( |
| sd_match(NonNegativeValue, DAG.get(), m_Negative(m_Value(BindVal)))); |
| EXPECT_NE(BindVal, NonNegativeValue); |
| EXPECT_FALSE( |
| sd_match(NonNegativeValue, DAG.get(), m_NonZero(m_Value(BindVal)))); |
| EXPECT_NE(BindVal, NonNegativeValue); |
| EXPECT_FALSE(sd_match(NonNegativeValue, DAG.get(), |
| m_StrictlyPositive(m_Value(BindVal)))); |
| EXPECT_NE(BindVal, NonNegativeValue); |
| EXPECT_FALSE( |
| sd_match(NonNegativeValue, DAG.get(), m_NonPositive(m_Value(BindVal)))); |
| EXPECT_NE(BindVal, NonNegativeValue); |
| |
| EXPECT_TRUE( |
| sd_match(NonNegativeValue, DAG.get(), m_NonNegative(m_Value(BindVal)))); |
| EXPECT_EQ(BindVal, NonNegativeValue); |
| |
| EXPECT_FALSE( |
| sd_match(NegativeValue, DAG.get(), m_NonNegative(m_Value(BindVal)))); |
| EXPECT_NE(BindVal, NegativeValue); |
| EXPECT_FALSE( |
| sd_match(NegativeValue, DAG.get(), m_StrictlyPositive(m_Value(BindVal)))); |
| EXPECT_NE(BindVal, NegativeValue); |
| |
| EXPECT_TRUE(sd_match(NegativeValue, DAG.get(), m_Negative(m_Value(BindVal)))); |
| EXPECT_EQ(BindVal, NegativeValue); |
| EXPECT_TRUE(sd_match(NegativeValue, DAG.get(), m_NonZero(m_Value(BindVal)))); |
| EXPECT_EQ(BindVal, NegativeValue); |
| EXPECT_TRUE( |
| sd_match(NegativeValue, DAG.get(), m_NonPositive(m_Value(BindVal)))); |
| EXPECT_EQ(BindVal, NegativeValue); |
| |
| EXPECT_FALSE( |
| sd_match(PositiveValue, DAG.get(), m_Negative(m_Value(BindVal)))); |
| EXPECT_NE(BindVal, PositiveValue); |
| EXPECT_FALSE( |
| sd_match(PositiveValue, DAG.get(), m_NonPositive(m_Value(BindVal)))); |
| EXPECT_NE(BindVal, PositiveValue); |
| |
| EXPECT_TRUE(sd_match(PositiveValue, DAG.get(), m_NonZero(m_Value(BindVal)))); |
| EXPECT_EQ(BindVal, PositiveValue); |
| EXPECT_TRUE( |
| sd_match(PositiveValue, DAG.get(), m_NonNegative(m_Value(BindVal)))); |
| EXPECT_EQ(BindVal, PositiveValue); |
| EXPECT_TRUE( |
| sd_match(PositiveValue, DAG.get(), m_StrictlyPositive(m_Value(BindVal)))); |
| EXPECT_EQ(BindVal, PositiveValue); |
| |
| // If DAG is not provided all matches fail regardless of the value |
| EXPECT_FALSE(sd_match(NegativeValue, m_Negative(m_Value(BindVal)))); |
| EXPECT_FALSE(sd_match(NonNegativeValue, m_NonNegative(m_Value(BindVal)))); |
| EXPECT_FALSE(sd_match(NegativeValue, m_NonZero(m_Value(BindVal)))); |
| EXPECT_FALSE(sd_match(NegativeValue, m_NonPositive(m_Value(BindVal)))); |
| EXPECT_FALSE(sd_match(PositiveValue, m_StrictlyPositive(m_Value(BindVal)))); |
| |
| EXPECT_TRUE(sd_match(VScale, m_VScale(m_Value()))); |
| |
| EXPECT_TRUE(sd_match(FPToUI, m_FPToUI(m_Value()))); |
| EXPECT_TRUE(sd_match(FPToSI, m_FPToSI(m_Value()))); |
| EXPECT_FALSE(sd_match(FPToUI, m_FPToSI(m_Value()))); |
| EXPECT_FALSE(sd_match(FPToSI, m_FPToUI(m_Value()))); |
| |
| EXPECT_TRUE(sd_match(Bcast, m_BitCast(m_Value()))); |
| EXPECT_TRUE(sd_match(Bcast, m_BitCast(m_SpecificVT(MVT::i32)))); |
| EXPECT_TRUE(sd_match(Brev, m_BitReverse(m_Value()))); |
| EXPECT_TRUE(sd_match(Bswap, m_BSwap(m_Value()))); |
| EXPECT_FALSE(sd_match(Bcast, m_BitReverse(m_Value()))); |
| EXPECT_FALSE(sd_match(Bcast, m_BitCast(m_SpecificVT(MVT::f32)))); |
| EXPECT_FALSE(sd_match(Brev, m_BSwap(m_Value()))); |
| EXPECT_FALSE(sd_match(Bswap, m_BitReverse(m_Value()))); |
| |
| EXPECT_TRUE(sd_match(Ctpop, m_Ctpop(m_Value()))); |
| EXPECT_TRUE(sd_match(Ctlz, m_Ctlz(m_Value()))); |
| EXPECT_TRUE(sd_match(Cttz, m_Cttz(m_Value()))); |
| EXPECT_FALSE(sd_match(Ctpop, m_Ctlz(m_Value()))); |
| EXPECT_FALSE(sd_match(Ctlz, m_Cttz(m_Value()))); |
| EXPECT_FALSE(sd_match(Cttz, m_Ctlz(m_Value()))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchConstants) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| auto VInt32VT = EVT::getVectorVT(Context, Int32VT, 4); |
| |
| SDValue Arg0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| |
| SDValue Const3 = DAG->getConstant(3, DL, Int32VT); |
| SDValue Const87 = DAG->getConstant(87, DL, Int32VT); |
| SDValue ConstNeg1 = DAG->getConstant(4294967295, DL, Int32VT); |
| SDValue Splat = DAG->getSplat(VInt32VT, DL, Arg0); |
| SDValue ConstSplat = DAG->getSplat(VInt32VT, DL, Const3); |
| SDValue Zero = DAG->getConstant(0, DL, Int32VT); |
| SDValue One = DAG->getConstant(1, DL, Int32VT); |
| SDValue MinusOne = DAG->getConstant( |
| APInt(Int32VT.getScalarSizeInBits(), -1, true), DL, Int32VT); |
| SDValue AllOnes = DAG->getConstant(APInt::getAllOnes(32), DL, Int32VT); |
| SDValue SetCC = DAG->getSetCC(DL, Int32VT, Arg0, Const3, ISD::SETULT); |
| |
| using namespace SDPatternMatch; |
| EXPECT_TRUE(sd_match(Const87, m_ConstInt())); |
| EXPECT_FALSE(sd_match(Arg0, m_ConstInt())); |
| APInt ConstVal; |
| EXPECT_TRUE(sd_match(ConstSplat, m_ConstInt(ConstVal))); |
| EXPECT_EQ(ConstVal, 3); |
| uint64_t ConstUnsignedInt64Val; |
| EXPECT_TRUE(sd_match(ConstNeg1, m_ConstInt(ConstUnsignedInt64Val))); |
| EXPECT_EQ(ConstUnsignedInt64Val, 4294967295ull); |
| int64_t ConstSignedInt64Val; |
| EXPECT_TRUE(sd_match(ConstNeg1, m_ConstInt(ConstSignedInt64Val))); |
| EXPECT_EQ(ConstSignedInt64Val, -1); |
| EXPECT_FALSE(sd_match(Splat, m_ConstInt())); |
| |
| EXPECT_TRUE(sd_match(Const87, m_SpecificInt(87))); |
| EXPECT_TRUE(sd_match(Const3, m_SpecificInt(ConstVal))); |
| EXPECT_TRUE(sd_match(AllOnes, m_AllOnes())); |
| |
| EXPECT_TRUE(sd_match(Zero, DAG.get(), m_False())); |
| EXPECT_TRUE(sd_match(One, DAG.get(), m_True())); |
| EXPECT_FALSE(sd_match(AllOnes, DAG.get(), m_True())); |
| |
| EXPECT_TRUE(sd_match(MinusOne, DAG.get(), m_Negative())); |
| EXPECT_FALSE(sd_match(MinusOne, DAG.get(), m_NonNegative())); |
| EXPECT_TRUE(sd_match(MinusOne, DAG.get(), m_NonZero())); |
| EXPECT_TRUE(sd_match(MinusOne, DAG.get(), m_NonPositive())); |
| EXPECT_FALSE(sd_match(MinusOne, DAG.get(), m_StrictlyPositive())); |
| |
| EXPECT_FALSE(sd_match(Zero, DAG.get(), m_Negative())); |
| EXPECT_TRUE(sd_match(Zero, DAG.get(), m_NonNegative())); |
| EXPECT_FALSE(sd_match(Zero, DAG.get(), m_NonZero())); |
| EXPECT_TRUE(sd_match(Zero, DAG.get(), m_NonPositive())); |
| EXPECT_FALSE(sd_match(Zero, DAG.get(), m_StrictlyPositive())); |
| |
| EXPECT_FALSE(sd_match(One, DAG.get(), m_Negative())); |
| EXPECT_TRUE(sd_match(One, DAG.get(), m_NonNegative())); |
| EXPECT_TRUE(sd_match(One, DAG.get(), m_NonZero())); |
| EXPECT_FALSE(sd_match(One, DAG.get(), m_NonPositive())); |
| EXPECT_TRUE(sd_match(One, DAG.get(), m_StrictlyPositive())); |
| |
| // If DAG is not provided all matches would fail |
| EXPECT_FALSE(sd_match(MinusOne, m_Negative())); |
| EXPECT_FALSE(sd_match(Zero, m_NonNegative())); |
| EXPECT_FALSE(sd_match(One, m_NonZero())); |
| EXPECT_FALSE(sd_match(Zero, m_NonPositive())); |
| EXPECT_FALSE(sd_match(One, m_StrictlyPositive())); |
| |
| ISD::CondCode CC; |
| EXPECT_TRUE(sd_match( |
| SetCC, m_Node(ISD::SETCC, m_Value(), m_Value(), m_CondCode(CC)))); |
| EXPECT_EQ(CC, ISD::SETULT); |
| EXPECT_TRUE(sd_match(SetCC, m_Node(ISD::SETCC, m_Value(), m_Value(), |
| m_SpecificCondCode(ISD::SETULT)))); |
| |
| SDValue UndefInt32VT = DAG->getUNDEF(Int32VT); |
| SDValue UndefVInt32VT = DAG->getUNDEF(VInt32VT); |
| EXPECT_TRUE(sd_match(UndefInt32VT, m_Undef())); |
| EXPECT_TRUE(sd_match(UndefVInt32VT, m_Undef())); |
| |
| SDValue PoisonInt32VT = DAG->getPOISON(Int32VT); |
| SDValue PoisonVInt32VT = DAG->getPOISON(VInt32VT); |
| EXPECT_TRUE(sd_match(PoisonInt32VT, m_Poison())); |
| EXPECT_TRUE(sd_match(PoisonVInt32VT, m_Poison())); |
| EXPECT_TRUE(sd_match(PoisonInt32VT, m_Undef())); |
| EXPECT_TRUE(sd_match(PoisonVInt32VT, m_Undef())); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, patternCombinators) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int32VT); |
| |
| SDValue Add = DAG->getNode(ISD::ADD, DL, Int32VT, Op0, Op1); |
| SDValue Sub = DAG->getNode(ISD::SUB, DL, Int32VT, Add, Op0); |
| |
| using namespace SDPatternMatch; |
| EXPECT_TRUE( |
| sd_match(Sub, m_AnyOf(m_SpecificOpc(ISD::ADD), m_SpecificOpc(ISD::SUB), |
| m_SpecificOpc(ISD::MUL)))); |
| EXPECT_TRUE(sd_match(Add, m_AllOf(m_SpecificOpc(ISD::ADD), m_OneUse()))); |
| EXPECT_TRUE(sd_match( |
| Add, m_NoneOf(m_SpecificOpc(ISD::SUB), m_SpecificOpc(ISD::MUL)))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, optionalResizing) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| auto Int64VT = EVT::getIntegerVT(Context, 64); |
| |
| SDValue Op32 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Op64 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int64VT); |
| SDValue ZExt = DAG->getNode(ISD::ZERO_EXTEND, DL, Int64VT, Op32); |
| SDValue SExt = DAG->getNode(ISD::SIGN_EXTEND, DL, Int64VT, Op32); |
| SDValue AExt = DAG->getNode(ISD::ANY_EXTEND, DL, Int64VT, Op32); |
| SDValue Trunc = DAG->getNode(ISD::TRUNCATE, DL, Int32VT, Op64); |
| |
| using namespace SDPatternMatch; |
| SDValue A; |
| EXPECT_TRUE(sd_match(Op32, m_ZExtOrSelf(m_Value(A)))); |
| EXPECT_TRUE(A == Op32); |
| EXPECT_TRUE(sd_match(ZExt, m_ZExtOrSelf(m_Value(A)))); |
| EXPECT_TRUE(A == Op32); |
| EXPECT_TRUE(sd_match(Op64, m_SExtOrSelf(m_Value(A)))); |
| EXPECT_TRUE(A == Op64); |
| EXPECT_TRUE(sd_match(SExt, m_SExtOrSelf(m_Value(A)))); |
| EXPECT_TRUE(A == Op32); |
| EXPECT_TRUE(sd_match(Op32, m_AExtOrSelf(m_Value(A)))); |
| EXPECT_TRUE(A == Op32); |
| EXPECT_TRUE(sd_match(AExt, m_AExtOrSelf(m_Value(A)))); |
| EXPECT_TRUE(A == Op32); |
| EXPECT_TRUE(sd_match(Op64, m_TruncOrSelf(m_Value(A)))); |
| EXPECT_TRUE(A == Op64); |
| EXPECT_TRUE(sd_match(Trunc, m_TruncOrSelf(m_Value(A)))); |
| EXPECT_TRUE(A == Op64); |
| |
| EXPECT_TRUE(sd_match(ZExt, DAG.get(), m_NonNegative(m_Value()))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchNode) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int32VT); |
| |
| SDValue Add = DAG->getNode(ISD::ADD, DL, Int32VT, Op0, Op1); |
| |
| using namespace SDPatternMatch; |
| EXPECT_TRUE(sd_match(Add, m_Node(ISD::ADD, m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(Add, m_Node(ISD::SUB, m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(Add, m_Node(ISD::ADD, m_Value()))); |
| EXPECT_FALSE( |
| sd_match(Add, m_Node(ISD::ADD, m_Value(), m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(Add, m_Node(ISD::ADD, m_ConstInt(), m_Value()))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchSelectLike) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| auto VInt32VT = EVT::getVectorVT(Context, Int32VT, 4); |
| |
| SDValue Cond = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(0), Int32VT); |
| SDValue TVal = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue FVal = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int32VT); |
| |
| SDValue VCond = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(4), VInt32VT); |
| SDValue VTVal = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(5), VInt32VT); |
| SDValue VFVal = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(6), VInt32VT); |
| |
| SDValue Select = DAG->getNode(ISD::SELECT, DL, Int32VT, Cond, TVal, FVal); |
| SDValue VSelect = |
| DAG->getNode(ISD::VSELECT, DL, Int32VT, VCond, VTVal, VFVal); |
| |
| using namespace SDPatternMatch; |
| EXPECT_TRUE(sd_match(Select, m_SelectLike(m_Specific(Cond), m_Specific(TVal), |
| m_Specific(FVal)))); |
| EXPECT_TRUE( |
| sd_match(VSelect, m_SelectLike(m_Specific(VCond), m_Specific(VTVal), |
| m_Specific(VFVal)))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchIntrinsicWOChain) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| auto Int64VT = EVT::getIntegerVT(Context, 64); |
| |
| SDValue WasmBitmaskIntrinsicId = |
| DAG->getConstant(Intrinsic::wasm_bitmask, DL, Int32VT); |
| SDValue X86Aadd32IntrinsicId = |
| DAG->getConstant(Intrinsic::x86_aadd32, DL, Int32VT); |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(0), Int32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int32VT); |
| SDValue PtrOp = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(3), Int64VT); |
| SDValue Op3 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(4), Int32VT); |
| |
| SDValue WasmBitmask = DAG->getNode(ISD::INTRINSIC_WO_CHAIN, DL, Int32VT, |
| WasmBitmaskIntrinsicId, Op0); |
| SDValue X86Aadd32 = DAG->getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::Other, |
| X86Aadd32IntrinsicId, PtrOp, Op1); |
| SDValue Add = DAG->getNode(ISD::ADD, DL, Int32VT, Op2, Op3); |
| |
| using namespace SDPatternMatch; |
| SDValue H0, H1, H2; |
| |
| // Intrinsic operations should match |
| EXPECT_TRUE(sd_match( |
| WasmBitmask, m_IntrinsicWOChain<Intrinsic::wasm_bitmask>(m_Value(H0)))); |
| EXPECT_TRUE(sd_match(X86Aadd32, m_IntrinsicWOChain<Intrinsic::x86_aadd32>( |
| m_Value(H1), m_Value(H2)))); |
| EXPECT_TRUE(H0 == Op0); |
| EXPECT_TRUE(H1 == PtrOp); |
| EXPECT_TRUE(H2 == Op1); |
| |
| // Intrinsic operations with incorrect IntrinsicId should not match |
| EXPECT_FALSE(sd_match(X86Aadd32, m_IntrinsicWOChain<Intrinsic::wasm_bitmask>( |
| m_Value(), m_Value()))); |
| |
| // Add operation shouldn't match |
| EXPECT_FALSE(sd_match( |
| Add, m_IntrinsicWOChain<Intrinsic::x86_aadd32>(m_Value(), m_Value()))); |
| } |
| |
| namespace { |
| struct VPMatchContext : public SDPatternMatch::BasicMatchContext { |
| using SDPatternMatch::BasicMatchContext::BasicMatchContext; |
| |
| bool match(SDValue OpVal, unsigned Opc) const { |
| if (!OpVal->isVPOpcode()) |
| return OpVal->getOpcode() == Opc; |
| |
| auto BaseOpc = ISD::getBaseOpcodeForVP(OpVal->getOpcode(), false); |
| return BaseOpc == Opc; |
| } |
| |
| unsigned getNumOperands(SDValue N) const { |
| return N->isVPOpcode() ? N->getNumOperands() - 2 : N->getNumOperands(); |
| } |
| }; |
| } // anonymous namespace |
| TEST_F(SelectionDAGPatternMatchTest, matchContext) { |
| SDLoc DL; |
| auto BoolVT = EVT::getIntegerVT(Context, 1); |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| auto VInt32VT = EVT::getVectorVT(Context, Int32VT, 4); |
| auto MaskVT = EVT::getVectorVT(Context, BoolVT, 4); |
| |
| SDValue Scalar0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Vector0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), VInt32VT); |
| SDValue Mask0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(3), MaskVT); |
| |
| SDValue VPAdd = DAG->getNode(ISD::VP_ADD, DL, VInt32VT, |
| {Vector0, Vector0, Mask0, Scalar0}); |
| SDValue VPReduceAdd = DAG->getNode(ISD::VP_REDUCE_ADD, DL, Int32VT, |
| {Scalar0, VPAdd, Mask0, Scalar0}); |
| SDValue Add = DAG->getNode(ISD::ADD, DL, VInt32VT, {Vector0, Vector0}); |
| |
| using namespace SDPatternMatch; |
| VPMatchContext VPCtx(DAG.get()); |
| EXPECT_TRUE(sd_context_match(VPAdd, VPCtx, m_SpecificOpc(ISD::ADD))); |
| EXPECT_TRUE( |
| sd_context_match(VPAdd, VPCtx, m_Node(ISD::ADD, m_Value(), m_Value()))); |
| // VPMatchContext can't match pattern using explicit VP Opcode |
| EXPECT_FALSE(sd_context_match(VPAdd, VPCtx, |
| m_Node(ISD::VP_ADD, m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_context_match( |
| VPAdd, VPCtx, |
| m_Node(ISD::VP_ADD, m_Value(), m_Value(), m_Value(), m_Value()))); |
| // Check Binary Op Pattern |
| EXPECT_TRUE(sd_context_match(VPAdd, VPCtx, m_Add(m_Value(), m_Value()))); |
| // VP_REDUCE_ADD doesn't have a based opcode, so we use a normal |
| // sd_match before switching to VPMatchContext when checking VPAdd. |
| EXPECT_TRUE( |
| sd_match(VPReduceAdd, m_Node(ISD::VP_REDUCE_ADD, m_Value(), |
| m_Context(VPCtx, m_SpecificOpc(ISD::ADD)), |
| m_Value(), m_Value()))); |
| // non-vector predicated should match too |
| EXPECT_TRUE(sd_context_match(Add, VPCtx, m_SpecificOpc(ISD::ADD))); |
| EXPECT_TRUE( |
| sd_context_match(Add, VPCtx, m_Node(ISD::ADD, m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_context_match( |
| Add, VPCtx, |
| m_Node(ISD::ADD, m_Value(), m_Value(), m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_context_match(Add, VPCtx, m_Add(m_Value(), m_Value()))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchVPWithBasicContext) { |
| SDLoc DL; |
| auto BoolVT = EVT::getIntegerVT(Context, 1); |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| auto VInt32VT = EVT::getVectorVT(Context, Int32VT, 4); |
| auto MaskVT = EVT::getVectorVT(Context, BoolVT, 4); |
| |
| SDValue Vector0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), VInt32VT); |
| SDValue Mask = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), MaskVT); |
| SDValue EL = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(3), Int32VT); |
| |
| SDValue VPAdd = |
| DAG->getNode(ISD::VP_ADD, DL, VInt32VT, Vector0, Vector0, Mask, EL); |
| |
| using namespace SDPatternMatch; |
| EXPECT_FALSE(sd_match(VPAdd, m_Node(ISD::VP_ADD, m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match( |
| VPAdd, m_Node(ISD::VP_ADD, m_Value(), m_Value(), m_Value(), m_Value()))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchAdvancedProperties) { |
| SDLoc DL; |
| auto Int16VT = EVT::getIntegerVT(Context, 16); |
| auto Int64VT = EVT::getIntegerVT(Context, 64); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int64VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int16VT); |
| |
| SDValue Add = DAG->getNode(ISD::ADD, DL, Int64VT, Op0, Op0); |
| |
| using namespace SDPatternMatch; |
| EXPECT_TRUE(sd_match(Op0, DAG.get(), m_LegalType(m_Value()))); |
| EXPECT_FALSE(sd_match(Op1, DAG.get(), m_LegalType(m_Value()))); |
| EXPECT_TRUE(sd_match(Add, DAG.get(), |
| m_LegalOp(m_IntegerVT(m_Add(m_Value(), m_Value()))))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchReassociatableOp) { |
| using namespace SDPatternMatch; |
| |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int32VT); |
| SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(3), Int32VT); |
| SDValue Op3 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(8), Int32VT); |
| |
| // (Op0 + Op1) + (Op2 + Op3) |
| SDValue ADD01 = DAG->getNode(ISD::ADD, DL, Int32VT, Op0, Op1); |
| SDValue ADD23 = DAG->getNode(ISD::ADD, DL, Int32VT, Op2, Op3); |
| SDValue ADD = DAG->getNode(ISD::ADD, DL, Int32VT, ADD01, ADD23); |
| |
| EXPECT_FALSE(sd_match(ADD01, m_ReassociatableAdd(m_Value()))); |
| EXPECT_FALSE( |
| sd_match(ADD01, m_ReassociatableAdd(m_Value(), m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(ADD01, m_ReassociatableAdd(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(ADD23, m_ReassociatableAdd(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match( |
| ADD, m_ReassociatableAdd(m_Value(), m_Value(), m_Value(), m_Value()))); |
| |
| // Op0 + (Op1 + (Op2 + Op3)) |
| SDValue ADD123 = DAG->getNode(ISD::ADD, DL, Int32VT, Op1, ADD23); |
| SDValue ADD0123 = DAG->getNode(ISD::ADD, DL, Int32VT, Op0, ADD123); |
| EXPECT_TRUE( |
| sd_match(ADD123, m_ReassociatableAdd(m_Value(), m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(ADD0123, m_ReassociatableAdd(m_Value(), m_Value(), |
| m_Value(), m_Value()))); |
| |
| // (Op0 - Op1) + (Op2 - Op3) |
| SDValue SUB01 = DAG->getNode(ISD::SUB, DL, Int32VT, Op0, Op1); |
| SDValue SUB23 = DAG->getNode(ISD::SUB, DL, Int32VT, Op2, Op3); |
| SDValue ADDS0123 = DAG->getNode(ISD::ADD, DL, Int32VT, SUB01, SUB23); |
| |
| EXPECT_FALSE(sd_match(SUB01, m_ReassociatableAdd(m_Value(), m_Value()))); |
| EXPECT_FALSE(sd_match(ADDS0123, m_ReassociatableAdd(m_Value(), m_Value(), |
| m_Value(), m_Value()))); |
| |
| // SUB + SUB matches (Op0 - Op1) + (Op2 - Op3) |
| EXPECT_TRUE( |
| sd_match(ADDS0123, m_ReassociatableAdd(m_Sub(m_Value(), m_Value()), |
| m_Sub(m_Value(), m_Value())))); |
| EXPECT_FALSE(sd_match(ADDS0123, m_ReassociatableAdd(m_Value(), m_Value(), |
| m_Value(), m_Value()))); |
| |
| // (Op0 + Op1) + Op0 binds correctly, allowing commutation on leaf nodes |
| SDValue ADD010 = DAG->getNode(ISD::ADD, DL, Int32VT, ADD01, Op0); |
| SDValue A, B; |
| EXPECT_TRUE(sd_match( |
| ADD010, m_ReassociatableAdd(m_Value(A), m_Value(B), m_Deferred(A)))); |
| EXPECT_EQ(Op0, A); |
| EXPECT_EQ(Op1, B); |
| |
| A.setNode(nullptr); |
| B.setNode(nullptr); |
| EXPECT_TRUE(sd_match( |
| ADD010, m_ReassociatableAdd(m_Value(A), m_Value(B), m_Deferred(B)))); |
| EXPECT_EQ(Op0, B); |
| EXPECT_EQ(Op1, A); |
| |
| A.setNode(nullptr); |
| B.setNode(nullptr); |
| EXPECT_TRUE(sd_match( |
| ADD010, m_ReassociatableAdd(m_Value(A), m_Deferred(A), m_Value(B)))); |
| EXPECT_EQ(Op0, A); |
| EXPECT_EQ(Op1, B); |
| |
| A.setNode(nullptr); |
| B.setNode(nullptr); |
| EXPECT_FALSE(sd_match( |
| ADD010, m_ReassociatableAdd(m_Value(A), m_Deferred(A), m_Deferred(A)))); |
| |
| A.setNode(nullptr); |
| B.setNode(nullptr); |
| EXPECT_FALSE(sd_match( |
| ADD010, m_ReassociatableAdd(m_Value(A), m_Deferred(B), m_Value(B)))); |
| |
| // (Op0 * Op1) * (Op2 * Op3) |
| SDValue MUL01 = DAG->getNode(ISD::MUL, DL, Int32VT, Op0, Op1); |
| SDValue MUL23 = DAG->getNode(ISD::MUL, DL, Int32VT, Op2, Op3); |
| SDValue MUL = DAG->getNode(ISD::MUL, DL, Int32VT, MUL01, MUL23); |
| |
| EXPECT_TRUE(sd_match(MUL01, m_ReassociatableMul(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(MUL23, m_ReassociatableMul(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match( |
| MUL, m_ReassociatableMul(m_Value(), m_Value(), m_Value(), m_Value()))); |
| |
| // Op0 * (Op1 * (Op2 * Op3)) |
| SDValue MUL123 = DAG->getNode(ISD::MUL, DL, Int32VT, Op1, MUL23); |
| SDValue MUL0123 = DAG->getNode(ISD::MUL, DL, Int32VT, Op0, MUL123); |
| EXPECT_TRUE( |
| sd_match(MUL123, m_ReassociatableMul(m_Value(), m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(MUL0123, m_ReassociatableMul(m_Value(), m_Value(), |
| m_Value(), m_Value()))); |
| |
| // (Op0 - Op1) * (Op2 - Op3) |
| SDValue MULS0123 = DAG->getNode(ISD::MUL, DL, Int32VT, SUB01, SUB23); |
| EXPECT_TRUE( |
| sd_match(MULS0123, m_ReassociatableMul(m_Sub(m_Value(), m_Value()), |
| m_Sub(m_Value(), m_Value())))); |
| EXPECT_FALSE(sd_match(MULS0123, m_ReassociatableMul(m_Value(), m_Value(), |
| m_Value(), m_Value()))); |
| |
| // (Op0 && Op1) && (Op2 && Op3) |
| SDValue AND01 = DAG->getNode(ISD::AND, DL, Int32VT, Op0, Op1); |
| SDValue AND23 = DAG->getNode(ISD::AND, DL, Int32VT, Op2, Op3); |
| SDValue AND = DAG->getNode(ISD::AND, DL, Int32VT, AND01, AND23); |
| |
| EXPECT_TRUE(sd_match(AND01, m_ReassociatableAnd(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(AND23, m_ReassociatableAnd(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match( |
| AND, m_ReassociatableAnd(m_Value(), m_Value(), m_Value(), m_Value()))); |
| |
| // Op0 && (Op1 && (Op2 && Op3)) |
| SDValue AND123 = DAG->getNode(ISD::AND, DL, Int32VT, Op1, AND23); |
| SDValue AND0123 = DAG->getNode(ISD::AND, DL, Int32VT, Op0, AND123); |
| EXPECT_TRUE( |
| sd_match(AND123, m_ReassociatableAnd(m_Value(), m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(AND0123, m_ReassociatableAnd(m_Value(), m_Value(), |
| m_Value(), m_Value()))); |
| |
| // (Op0 - Op1) && (Op2 - Op3) |
| SDValue ANDS0123 = DAG->getNode(ISD::AND, DL, Int32VT, SUB01, SUB23); |
| EXPECT_TRUE( |
| sd_match(ANDS0123, m_ReassociatableAnd(m_Sub(m_Value(), m_Value()), |
| m_Sub(m_Value(), m_Value())))); |
| EXPECT_FALSE(sd_match(ANDS0123, m_ReassociatableAnd(m_Value(), m_Value(), |
| m_Value(), m_Value()))); |
| |
| // (Op0 || Op1) || (Op2 || Op3) |
| SDValue OR01 = DAG->getNode(ISD::OR, DL, Int32VT, Op0, Op1); |
| SDValue OR23 = DAG->getNode(ISD::OR, DL, Int32VT, Op2, Op3); |
| SDValue OR = DAG->getNode(ISD::OR, DL, Int32VT, OR01, OR23); |
| |
| EXPECT_TRUE(sd_match(OR01, m_ReassociatableOr(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match(OR23, m_ReassociatableOr(m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match( |
| OR, m_ReassociatableOr(m_Value(), m_Value(), m_Value(), m_Value()))); |
| |
| // Op0 || (Op1 || (Op2 || Op3)) |
| SDValue OR123 = DAG->getNode(ISD::OR, DL, Int32VT, Op1, OR23); |
| SDValue OR0123 = DAG->getNode(ISD::OR, DL, Int32VT, Op0, OR123); |
| EXPECT_TRUE( |
| sd_match(OR123, m_ReassociatableOr(m_Value(), m_Value(), m_Value()))); |
| EXPECT_TRUE(sd_match( |
| OR0123, m_ReassociatableOr(m_Value(), m_Value(), m_Value(), m_Value()))); |
| |
| // (Op0 - Op1) || (Op2 - Op3) |
| SDValue ORS0123 = DAG->getNode(ISD::OR, DL, Int32VT, SUB01, SUB23); |
| EXPECT_TRUE( |
| sd_match(ORS0123, m_ReassociatableOr(m_Sub(m_Value(), m_Value()), |
| m_Sub(m_Value(), m_Value())))); |
| EXPECT_FALSE(sd_match( |
| ORS0123, m_ReassociatableOr(m_Value(), m_Value(), m_Value(), m_Value()))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, MatchZeroOneAllOnes) { |
| using namespace SDPatternMatch; |
| |
| SDLoc DL; |
| EVT VT = EVT::getIntegerVT(Context, 32); |
| |
| // Scalar constant 0 |
| SDValue Zero = DAG->getConstant(0, DL, VT); |
| EXPECT_TRUE(sd_match(Zero, DAG.get(), m_Zero())); |
| EXPECT_FALSE(sd_match(Zero, DAG.get(), m_One())); |
| EXPECT_FALSE(sd_match(Zero, DAG.get(), m_AllOnes())); |
| |
| // Scalar constant 1 |
| SDValue One = DAG->getConstant(1, DL, VT); |
| EXPECT_FALSE(sd_match(One, DAG.get(), m_Zero())); |
| EXPECT_TRUE(sd_match(One, DAG.get(), m_One())); |
| EXPECT_FALSE(sd_match(One, DAG.get(), m_AllOnes())); |
| |
| // Scalar constant -1 |
| SDValue AllOnes = |
| DAG->getConstant(APInt::getAllOnes(VT.getSizeInBits()), DL, VT); |
| EXPECT_FALSE(sd_match(AllOnes, DAG.get(), m_Zero())); |
| EXPECT_FALSE(sd_match(AllOnes, DAG.get(), m_One())); |
| EXPECT_TRUE(sd_match(AllOnes, DAG.get(), m_AllOnes())); |
| |
| EVT VecF32 = EVT::getVectorVT(Context, MVT::f32, 4); |
| EVT VecVT = EVT::getVectorVT(Context, MVT::i32, 4); |
| |
| // m_Zero: splat vector of 0 → bitcast |
| { |
| SDValue SplatVal = DAG->getConstant(0, DL, MVT::i32); |
| SDValue VecSplat = DAG->getSplatBuildVector(VecVT, DL, SplatVal); |
| SDValue Bitcasted = DAG->getNode(ISD::BITCAST, DL, VecF32, VecSplat); |
| EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_Zero())); |
| |
| EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_Negative())); |
| EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_NonNegative())); |
| EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_NonZero())); |
| EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_StrictlyPositive())); |
| EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_NonPositive())); |
| } |
| |
| // m_One: splat vector of 1 → bitcast |
| { |
| SDValue SplatVal = DAG->getConstant(1, DL, MVT::i32); |
| SDValue VecSplat = DAG->getSplatBuildVector(VecVT, DL, SplatVal); |
| SDValue Bitcasted = DAG->getNode(ISD::BITCAST, DL, VecF32, VecSplat); |
| EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_One())); |
| |
| EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_Negative())); |
| EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_NonNegative())); |
| EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_NonZero())); |
| EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_NonPositive())); |
| EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_StrictlyPositive())); |
| } |
| |
| // m_AllOnes: splat vector of -1 → bitcast |
| { |
| SDValue SplatVal = DAG->getConstant(APInt::getAllOnes(32), DL, MVT::i32); |
| SDValue VecSplat = DAG->getSplatBuildVector(VecVT, DL, SplatVal); |
| SDValue Bitcasted = DAG->getNode(ISD::BITCAST, DL, VecF32, VecSplat); |
| EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_AllOnes())); |
| |
| EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_Negative())); |
| EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_NonNegative())); |
| EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_NonZero())); |
| EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_NonPositive())); |
| EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_StrictlyPositive())); |
| } |
| |
| // splat vector with one undef → default should NOT match |
| SDValue Undef = DAG->getUNDEF(MVT::i32); |
| |
| { |
| // m_Zero: Undef + constant 0 |
| SDValue Zero = DAG->getConstant(0, DL, MVT::i32); |
| SmallVector<SDValue, 4> Ops(4, Zero); |
| Ops[2] = Undef; |
| SDValue Vec = DAG->getBuildVector(VecVT, DL, Ops); |
| EXPECT_FALSE(sd_match(Vec, DAG.get(), m_Zero())); |
| EXPECT_TRUE(sd_match(Vec, DAG.get(), m_Zero(true))); |
| } |
| |
| { |
| // m_One: Undef + constant 1 |
| SDValue One = DAG->getConstant(1, DL, MVT::i32); |
| SmallVector<SDValue, 4> Ops(4, One); |
| Ops[1] = Undef; |
| SDValue Vec = DAG->getBuildVector(VecVT, DL, Ops); |
| EXPECT_FALSE(sd_match(Vec, DAG.get(), m_One())); |
| EXPECT_TRUE(sd_match(Vec, DAG.get(), m_One(true))); |
| } |
| |
| { |
| // m_AllOnes: Undef + constant -1 |
| SDValue AllOnes = DAG->getConstant(APInt::getAllOnes(32), DL, MVT::i32); |
| SmallVector<SDValue, 4> Ops(4, AllOnes); |
| Ops[0] = Undef; |
| SDValue Vec = DAG->getBuildVector(VecVT, DL, Ops); |
| EXPECT_FALSE(sd_match(Vec, DAG.get(), m_AllOnes())); |
| EXPECT_TRUE(sd_match(Vec, DAG.get(), m_AllOnes(true))); |
| } |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, MatchSelectCCLike) { |
| using namespace SDPatternMatch; |
| |
| SDValue LHS = DAG->getConstant(1, SDLoc(), MVT::i32); |
| SDValue RHS = DAG->getConstant(2, SDLoc(), MVT::i32); |
| SDValue TVal = DAG->getConstant(3, SDLoc(), MVT::i32); |
| SDValue FVal = DAG->getConstant(4, SDLoc(), MVT::i32); |
| SDValue Select = DAG->getNode(ISD::SELECT_CC, SDLoc(), MVT::i32, LHS, RHS, |
| TVal, FVal, DAG->getCondCode(ISD::SETLT)); |
| |
| ISD::CondCode CC = ISD::SETLT; |
| EXPECT_TRUE(sd_match( |
| Select, m_SelectCCLike(m_Specific(LHS), m_Specific(RHS), m_Specific(TVal), |
| m_Specific(FVal), m_CondCode(CC)))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, MatchSelectCC) { |
| using namespace SDPatternMatch; |
| |
| SDValue LHS = DAG->getConstant(1, SDLoc(), MVT::i32); |
| SDValue RHS = DAG->getConstant(2, SDLoc(), MVT::i32); |
| SDValue TVal = DAG->getConstant(3, SDLoc(), MVT::i32); |
| SDValue FVal = DAG->getConstant(4, SDLoc(), MVT::i32); |
| SDValue Select = DAG->getNode(ISD::SELECT_CC, SDLoc(), MVT::i32, LHS, RHS, |
| TVal, FVal, DAG->getCondCode(ISD::SETLT)); |
| |
| ISD::CondCode CC = ISD::SETLT; |
| EXPECT_TRUE(sd_match(Select, m_SelectCC(m_Specific(LHS), m_Specific(RHS), |
| m_Specific(TVal), m_Specific(FVal), |
| m_CondCode(CC)))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, MatchSpecificNeg) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| auto VecVT = EVT::getVectorVT(Context, Int32VT, 4); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| |
| using namespace SDPatternMatch; |
| |
| SDValue Neg = DAG->getNegative(Op0, DL, Int32VT); |
| EXPECT_TRUE(sd_match(Neg, m_SpecificNeg(Op0))); |
| EXPECT_TRUE(sd_match(Neg, m_Neg(m_Specific(Op0)))); |
| |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int32VT); |
| EXPECT_FALSE(sd_match(Neg, m_SpecificNeg(Op1))); |
| |
| SDValue Const5 = DAG->getConstant(5, DL, Int32VT); |
| SDValue ConstNeg5 = DAG->getConstant(APInt(32, -5, true), DL, Int32VT); |
| EXPECT_TRUE(sd_match(ConstNeg5, m_SpecificNeg(Const5))); |
| EXPECT_TRUE(sd_match(Const5, m_SpecificNeg(ConstNeg5))); |
| |
| SDValue Const3 = DAG->getConstant(3, DL, Int32VT); |
| EXPECT_FALSE(sd_match(ConstNeg5, m_SpecificNeg(Const3))); |
| |
| SDValue VecConst5 = DAG->getSplatBuildVector(VecVT, DL, Const5); |
| SDValue VecConstNeg5 = DAG->getSplatBuildVector(VecVT, DL, ConstNeg5); |
| EXPECT_TRUE(sd_match(VecConstNeg5, m_SpecificNeg(VecConst5))); |
| EXPECT_TRUE(sd_match(VecConst5, m_SpecificNeg(VecConstNeg5))); |
| |
| SDValue Const1 = DAG->getConstant(1, DL, Int32VT); |
| SDValue Const2 = DAG->getConstant(2, DL, Int32VT); |
| SDValue ConstNeg1 = DAG->getConstant(APInt(32, -1, true), DL, Int32VT); |
| SDValue ConstNeg2 = DAG->getConstant(APInt(32, -2, true), DL, Int32VT); |
| SDValue ConstNeg3 = DAG->getConstant(APInt(32, -3, true), DL, Int32VT); |
| SDValue PosOps[] = {Const1, Const2, Const5, Const3}; |
| SDValue NegOps[] = {ConstNeg1, ConstNeg2, ConstNeg5, ConstNeg3}; |
| SDValue VecPos = DAG->getBuildVector(VecVT, DL, PosOps); |
| SDValue VecNeg = DAG->getBuildVector(VecVT, DL, NegOps); |
| EXPECT_TRUE(sd_match(VecNeg, m_SpecificNeg(VecPos))); |
| EXPECT_TRUE(sd_match(VecPos, m_SpecificNeg(VecNeg))); |
| |
| SDValue WrongOps[] = {ConstNeg1, ConstNeg2, Const5, ConstNeg5}; |
| SDValue VecWrong = DAG->getBuildVector(VecVT, DL, WrongOps); |
| EXPECT_FALSE(sd_match(VecWrong, m_SpecificNeg(VecPos))); |
| |
| auto Int16VT = EVT::getIntegerVT(Context, 16); |
| auto Vec16VT = EVT::getVectorVT(Context, Int16VT, 4); |
| SDValue Const1_16 = DAG->getConstant(1, DL, Int16VT); |
| SDValue Const2_16 = DAG->getConstant(2, DL, Int16VT); |
| SDValue Const3_16 = DAG->getConstant(3, DL, Int16VT); |
| SDValue Const5_16 = DAG->getConstant(5, DL, Int16VT); |
| SDValue PosOps16[] = {Const1_16, Const2_16, Const5_16, Const3_16}; |
| SDValue NegOps32[] = {ConstNeg1, ConstNeg2, ConstNeg5, ConstNeg3}; |
| SDValue VecPos16 = DAG->getBuildVector(Vec16VT, DL, PosOps16); |
| SDValue VecNeg32 = DAG->getBuildVector(Vec16VT, DL, NegOps32); |
| EXPECT_FALSE(sd_match(VecNeg32, m_SpecificNeg(VecPos16))); |
| |
| SDValue Zero = DAG->getConstant(0, DL, Int32VT); |
| EXPECT_TRUE(sd_match(Zero, m_SpecificNeg(Zero))); |
| } |
| |
| TEST_F(SelectionDAGPatternMatchTest, matchReassociatableFlags) { |
| SDLoc DL; |
| auto Int32VT = EVT::getIntegerVT(Context, 32); |
| |
| SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(1), Int32VT); |
| SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(2), Int32VT); |
| SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(3), Int32VT); |
| |
| SDNodeFlags NSWFlags; |
| NSWFlags.setNoSignedWrap(true); |
| |
| // (Op0 +nsw Op1) +nsw Op2 |
| SDValue Add0 = DAG->getNode(ISD::ADD, DL, Int32VT, Op0, Op1, NSWFlags); |
| SDValue Add1 = DAG->getNode(ISD::ADD, DL, Int32VT, Add0, Op2, NSWFlags); |
| |
| SDValue Op3 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(4), Int32VT); |
| SDValue Op4 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(5), Int32VT); |
| SDValue Op5 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(6), Int32VT); |
| |
| // (Op3 + Op4) +nsw Op5 |
| SDValue Add2 = DAG->getNode(ISD::ADD, DL, Int32VT, Op3, Op4); |
| SDValue Add3 = DAG->getNode(ISD::ADD, DL, Int32VT, Add2, Op5, NSWFlags); |
| |
| SDValue Op6 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(7), Int32VT); |
| SDValue Op7 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(8), Int32VT); |
| SDValue Op8 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(9), Int32VT); |
| |
| SDNodeFlags NUWFlags; |
| NUWFlags.setNoUnsignedWrap(true); |
| |
| // (Op6 +nuw Op7) +nuw Op8 |
| SDValue Add4 = DAG->getNode(ISD::ADD, DL, Int32VT, Op6, Op7, NUWFlags); |
| SDValue Add5 = DAG->getNode(ISD::ADD, DL, Int32VT, Add4, Op8, NUWFlags); |
| |
| // (Op0 +nsw+nuw Op1) +nsw+nuw Op2 |
| SDNodeFlags BothFlags; |
| BothFlags.setNoSignedWrap(true); |
| BothFlags.setNoUnsignedWrap(true); |
| |
| SDValue Op9 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(10), Int32VT); |
| SDValue Op10 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(11), Int32VT); |
| SDValue Op11 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, |
| Register::index2VirtReg(12), Int32VT); |
| |
| SDValue Add6 = DAG->getNode(ISD::ADD, DL, Int32VT, Op9, Op10, BothFlags); |
| SDValue Add7 = DAG->getNode(ISD::ADD, DL, Int32VT, Add6, Op11, BothFlags); |
| |
| using namespace SDPatternMatch; |
| |
| EXPECT_TRUE( |
| sd_match(Add1, m_ReassociatableNSWAdd(m_Specific(Op0), m_Specific(Op1), |
| m_Specific(Op2)))); |
| EXPECT_FALSE( |
| sd_match(Add3, m_ReassociatableNSWAdd(m_Specific(Op3), m_Specific(Op4), |
| m_Specific(Op5)))); |
| EXPECT_TRUE(sd_match( |
| Add3, m_ReassociatableNSWAdd(m_Specific(Add2), m_Specific(Op5)))); |
| |
| EXPECT_TRUE( |
| sd_match(Add5, m_ReassociatableNUWAdd(m_Specific(Op6), m_Specific(Op7), |
| m_Specific(Op8)))); |
| EXPECT_FALSE( |
| sd_match(Add1, m_ReassociatableNUWAdd(m_Specific(Op0), m_Specific(Op1), |
| m_Specific(Op2)))); |
| EXPECT_TRUE( |
| sd_match(Add7, m_ReassociatableNSWAdd(m_Specific(Op9), m_Specific(Op10), |
| m_Specific(Op11)))); |
| EXPECT_TRUE( |
| sd_match(Add7, m_ReassociatableNUWAdd(m_Specific(Op9), m_Specific(Op10), |
| m_Specific(Op11)))); |
| } |