Files
llvm-project/llvm/unittests/CodeGen/SelectionDAGPatternMatchTest.cpp
Vedant Neve 4b4aa3b791 [DAG] Add funnel-shift matchers to SDPatternMatch (Fixes #185880) (#186593)
Add new SelectionDAG pattern matchers for funnel shifts:
- m_FShL and m_FShR as ternary wrappers for ISD::FSHL/ISD::FSHR
- m_FShLLike and m_FShRLike to match:
-- direct FSHL/FSHR nodes
-- ROTL/ROTR equivalents (binding both X and Y to the same rotate operand)
-- OR(SHL(X, C), SRL(Y, BW - C)) forms (including commuted OR)

Also add unit tests covering positive and negative cases for:
- direct funnel-shif matching
- rotate equivalence matching
- OR-based funnel-shift-like patterns

Fixes #185880
2026-04-14 07:42:06 +00:00

1686 lines
77 KiB
C++

//===---- 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))));
}