llvm-project/llvm/unittests/CodeGen/SelectionDAGPatternMatchTest.cpp
Craig Topper 1e676e7edb
[SelectionDAG] Use virtual registers instead of arbitrary physical registers in unit tests. NFC (#183205)
These tests use constants in the physical register space. These will
correspond to different registers on different targets and aren't
stable.

Using virtual registers makes more sense here. This will print in a
coherent way if you anyone were to dump the DAG created by these tests.
2026-02-25 08:52:45 -08:00

1588 lines
73 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_Opc(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_Opc(ISD::SMUL_LOHI), m_Opc(ISD::SMUL_LOHI))));
// Matching a specific result.
EXPECT_TRUE(sd_match(PartsDiff, m_Sub(m_Opc(ISD::SMUL_LOHI),
m_Result<1>(m_Opc(ISD::SMUL_LOHI)))));
EXPECT_FALSE(sd_match(PartsDiff, m_Sub(m_Opc(ISD::SMUL_LOHI),
m_Result<0>(m_Opc(ISD::SMUL_LOHI)))));
// Conditionally bind the value from a certain sub-pattern.
EXPECT_TRUE(sd_match(PartsDiff, m_Sub(m_Value(BindVal, m_Opc(ISD::SMUL_LOHI)),
m_Opc(ISD::SMUL_LOHI))));
EXPECT_EQ(BindVal, SMulLoHi);
BindVal = SDValue();
EXPECT_FALSE(sd_match(PartsDiff, m_Sub(m_Value(BindVal, m_Opc(ISD::ADD)),
m_Opc(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, 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_Opc(ISD::ADD), m_Opc(ISD::SUB), m_Opc(ISD::MUL))));
EXPECT_TRUE(sd_match(Add, m_AllOf(m_Opc(ISD::ADD), m_OneUse())));
EXPECT_TRUE(sd_match(Add, m_NoneOf(m_Opc(ISD::SUB), m_Opc(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_Opc(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_Opc(ISD::ADD)),
m_Value(), m_Value())));
// non-vector predicated should match too
EXPECT_TRUE(sd_context_match(Add, VPCtx, m_Opc(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))));
}