cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
952 lines
42 KiB
C++
952 lines
42 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 "llvm/Analysis/OptimizationRemarkEmitter.h"
|
|
#include "llvm/Analysis/TargetTransformInfo.h"
|
|
#include "llvm/AsmParser/Parser.h"
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
|
#include "llvm/CodeGen/SDPatternMatch.h"
|
|
#include "llvm/CodeGen/TargetLowering.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/MC/TargetRegistry.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/Support/TargetSelect.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
class SelectionDAGPatternMatchTest : public testing::Test {
|
|
protected:
|
|
static void SetUpTestCase() {
|
|
InitializeAllTargets();
|
|
InitializeAllTargetMCs();
|
|
}
|
|
|
|
void SetUp() override {
|
|
StringRef Assembly = "@g = global i32 0\n"
|
|
"@g_alias = alias i32, i32* @g\n"
|
|
"define i32 @f() {\n"
|
|
" %1 = load i32, i32* @g\n"
|
|
" ret i32 %1\n"
|
|
"}";
|
|
|
|
Triple TargetTriple("riscv64--");
|
|
std::string Error;
|
|
const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
|
|
// FIXME: These tests do not depend on RISCV specifically, but we have to
|
|
// initialize a target. A skeleton Target for unittests would allow us to
|
|
// always run these tests.
|
|
if (!T)
|
|
GTEST_SKIP();
|
|
|
|
TargetOptions Options;
|
|
TM = std::unique_ptr<TargetMachine>(T->createTargetMachine(
|
|
TargetTriple, "", "+m,+f,+d,+v", Options, std::nullopt, std::nullopt,
|
|
CodeGenOptLevel::Aggressive));
|
|
if (!TM)
|
|
GTEST_SKIP();
|
|
|
|
SMDiagnostic SMError;
|
|
M = parseAssemblyString(Assembly, SMError, Context);
|
|
if (!M)
|
|
report_fatal_error(SMError.getMessage());
|
|
M->setDataLayout(TM->createDataLayout());
|
|
|
|
F = M->getFunction("f");
|
|
if (!F)
|
|
report_fatal_error("F?");
|
|
G = M->getGlobalVariable("g");
|
|
if (!G)
|
|
report_fatal_error("G?");
|
|
AliasedG = M->getNamedAlias("g_alias");
|
|
if (!AliasedG)
|
|
report_fatal_error("AliasedG?");
|
|
|
|
MachineModuleInfo MMI(TM.get());
|
|
|
|
MF = std::make_unique<MachineFunction>(*F, *TM, *TM->getSubtargetImpl(*F),
|
|
MMI.getContext(), 0);
|
|
|
|
DAG = std::make_unique<SelectionDAG>(*TM, CodeGenOptLevel::None);
|
|
if (!DAG)
|
|
report_fatal_error("DAG?");
|
|
OptimizationRemarkEmitter ORE(F);
|
|
FunctionAnalysisManager FAM;
|
|
FAM.registerPass([&] { return TM->getTargetIRAnalysis(); });
|
|
|
|
TargetTransformInfo TTI = TM->getTargetIRAnalysis().run(*F, FAM);
|
|
DAG->init(*MF, ORE, nullptr, nullptr, nullptr, nullptr, nullptr, MMI,
|
|
nullptr, TTI.hasBranchDivergence(F));
|
|
}
|
|
|
|
TargetLoweringBase::LegalizeTypeAction getTypeAction(EVT VT) {
|
|
return DAG->getTargetLoweringInfo().getTypeAction(Context, VT);
|
|
}
|
|
|
|
EVT getTypeToTransformTo(EVT VT) {
|
|
return DAG->getTargetLoweringInfo().getTypeToTransformTo(Context, VT);
|
|
}
|
|
|
|
LLVMContext Context;
|
|
std::unique_ptr<TargetMachine> TM;
|
|
std::unique_ptr<Module> M;
|
|
Function *F;
|
|
GlobalVariable *G;
|
|
GlobalAlias *AliasedG;
|
|
std::unique_ptr<MachineFunction> MF;
|
|
std::unique_ptr<SelectionDAG> DAG;
|
|
};
|
|
|
|
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, 1, Int32VT);
|
|
SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 2, Float32VT);
|
|
SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 2, 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, 1, VInt32VT);
|
|
SDValue V1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 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, 1, Int32VT);
|
|
SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 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, 3, Int1VT);
|
|
SDValue T = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 4, Int1VT);
|
|
SDValue F = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 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, 6, VInt32VT);
|
|
SDValue V2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 7, VInt32VT);
|
|
SDValue V3 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 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, 6, VInt32VT);
|
|
auto Idx0 = DAG->getVectorIdxConstant(0, DL);
|
|
auto Idx1 = DAG->getVectorIdxConstant(1, DL);
|
|
|
|
SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 1, Int32VT);
|
|
SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 2, Int32VT);
|
|
SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 3, Float32VT);
|
|
SDValue Op3 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 8, Int32VT);
|
|
SDValue Op4 = DAG->getConstant(1, DL, Int32VT);
|
|
|
|
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 SFAdd = DAG->getNode(ISD::STRICT_FADD, DL, {Float32VT, MVT::Other},
|
|
{DAG->getEntryNode(), Op2, Op2});
|
|
|
|
SDValue Vec = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 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_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(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())));
|
|
|
|
// 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)))));
|
|
|
|
SDValue BindVal;
|
|
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))));
|
|
|
|
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, 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, 1, Int32VT);
|
|
SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 1, Int64VT);
|
|
SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 1, FloatVT);
|
|
SDValue Op3 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 3, 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);
|
|
|
|
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_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())));
|
|
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, 1, Int32VT);
|
|
|
|
SDValue Const3 = DAG->getConstant(3, DL, Int32VT);
|
|
SDValue Const87 = DAG->getConstant(87, 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 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);
|
|
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()));
|
|
|
|
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()));
|
|
}
|
|
|
|
TEST_F(SelectionDAGPatternMatchTest, patternCombinators) {
|
|
SDLoc DL;
|
|
auto Int32VT = EVT::getIntegerVT(Context, 32);
|
|
|
|
SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 1, Int32VT);
|
|
SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 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, 1, Int32VT);
|
|
SDValue Op64 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 1, 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);
|
|
}
|
|
|
|
TEST_F(SelectionDAGPatternMatchTest, matchNode) {
|
|
SDLoc DL;
|
|
auto Int32VT = EVT::getIntegerVT(Context, 32);
|
|
|
|
SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 1, Int32VT);
|
|
SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 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())));
|
|
}
|
|
|
|
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, 1, Int32VT);
|
|
SDValue Vector0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 2, VInt32VT);
|
|
SDValue Mask0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 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, 1, VInt32VT);
|
|
SDValue Mask = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 2, MaskVT);
|
|
SDValue EL = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 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, 1, Int64VT);
|
|
SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 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, 1, Int32VT);
|
|
SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 2, Int32VT);
|
|
SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 3, Int32VT);
|
|
SDValue Op3 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 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_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) * (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()));
|
|
}
|
|
|
|
// 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()));
|
|
}
|
|
|
|
// 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()));
|
|
}
|
|
|
|
// 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)));
|
|
}
|
|
}
|