[llvm] r323400 - Add support for pattern matching MachineInsts.
Aditya Nandakumar via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 24 18:53:06 PST 2018
Author: aditya_nandakumar
Date: Wed Jan 24 18:53:06 2018
New Revision: 323400
URL: http://llvm.org/viewvc/llvm-project?rev=323400&view=rev
Log:
Add support for pattern matching MachineInsts.
https://reviews.llvm.org/D42439
Add Instcombine like matchers for MachineInstructions. There are only
globalISel matchers for now.
Added:
llvm/trunk/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
llvm/trunk/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp
Modified:
llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt
Added: llvm/trunk/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h?rev=323400&view=auto
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h (added)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h Wed Jan 24 18:53:06 2018
@@ -0,0 +1,273 @@
+//== ----- llvm/CodeGen/GlobalISel/MIPatternMatch.h --------------------- == //
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// Contains matchers for matching SSA Machine Instructions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_GMIR_PATTERNMATCH_H
+#define LLVM_GMIR_PATTERNMATCH_H
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/CodeGen/GlobalISel/Utils.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+
+namespace llvm {
+namespace MIPatternMatch {
+
+template <typename Reg, typename Pattern>
+bool mi_match(Reg R, MachineRegisterInfo &MRI, Pattern &&P) {
+ return P.match(MRI, R);
+}
+
+// TODO: Extend for N use.
+template <typename SubPatternT> struct OneUse_match {
+ SubPatternT SubPat;
+ OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
+
+ template <typename OpTy>
+ bool match(const MachineRegisterInfo &MRI, unsigned Reg) {
+ return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
+ }
+};
+
+template <typename SubPat>
+inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) {
+ return SP;
+}
+
+struct ConstantMatch {
+ uint64_t &CR;
+ ConstantMatch(uint64_t &C) : CR(C) {}
+ bool match(const MachineRegisterInfo &MRI, unsigned Reg) {
+ if (auto MaybeCst = getConstantVRegVal(Reg, MRI)) {
+ CR = *MaybeCst;
+ return true;
+ }
+ return false;
+ }
+};
+
+ConstantMatch m_ICst(uint64_t &Cst) { return ConstantMatch(Cst); }
+
+// TODO: Rework this for different kinds of MachineOperand.
+// Currently assumes the Src for a match is a register.
+// We might want to support taking in some MachineOperands and call getReg on
+// that.
+
+struct operand_type_match {
+ bool match(const MachineRegisterInfo &MRI, unsigned Reg) { return true; }
+ bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
+ return MO->isReg();
+ }
+};
+
+operand_type_match m_Reg() { return operand_type_match(); }
+
+/// Matching combinators.
+template <typename... Preds> struct And {
+ template <typename MatchSrc>
+ bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
+ return true;
+ }
+};
+
+template <typename Pred, typename... Preds>
+struct And<Pred, Preds...> : And<Preds...> {
+ Pred P;
+ And(Pred &&p, Preds &&... preds)
+ : And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {
+ }
+ template <typename MatchSrc>
+ bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
+ return P.match(MRI, src) && And<Preds...>::match(MRI, src);
+ }
+};
+
+template <typename... Preds> struct Or {
+ template <typename MatchSrc>
+ bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
+ return true;
+ }
+};
+
+template <typename Pred, typename... Preds>
+struct Or<Pred, Preds...> : Or<Preds...> {
+ Pred P;
+ Or(Pred &&p, Preds &&... preds)
+ : Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {}
+ template <typename MatchSrc>
+ bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
+ return P.match(MRI, src) || Or<Preds...>::match(MRI, src);
+ }
+};
+
+template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) {
+ return And<Preds...>(std::forward<Preds>(preds)...);
+}
+
+template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) {
+ return Or<Preds...>(std::forward<Preds>(preds)...);
+}
+
+template <typename BindTy> struct bind_helper {
+ static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
+ VR = V;
+ return true;
+ }
+};
+
+template <> struct bind_helper<MachineInstr *> {
+ static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
+ unsigned Reg) {
+ MI = MRI.getVRegDef(Reg);
+ if (MI)
+ return true;
+ return false;
+ }
+};
+
+template <> struct bind_helper<LLT> {
+ static bool bind(const MachineRegisterInfo &MRI, LLT &Ty, unsigned Reg) {
+ Ty = MRI.getType(Reg);
+ if (Ty.isValid())
+ return true;
+ return false;
+ }
+};
+
+template <typename Class> struct bind_ty {
+ Class &VR;
+
+ bind_ty(Class &V) : VR(V) {}
+
+ template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
+ return bind_helper<Class>::bind(MRI, VR, V);
+ }
+};
+
+inline bind_ty<unsigned> m_Reg(unsigned &R) { return R; }
+inline bind_ty<MachineInstr *> m_MInstr(MachineInstr *&MI) { return MI; }
+inline bind_ty<LLT> m_Type(LLT &Ty) { return Ty; }
+
+// General helper for all the binary generic MI such as G_ADD/G_SUB etc
+template <typename LHS_P, typename RHS_P, unsigned Opcode,
+ bool Commutable = false>
+struct BinaryOp_match {
+ LHS_P L;
+ RHS_P R;
+
+ BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
+ template <typename OpTy> bool match(MachineRegisterInfo &MRI, OpTy &&Op) {
+ MachineInstr *TmpMI;
+ if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
+ if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
+ return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
+ R.match(MRI, TmpMI->getOperand(2).getReg())) ||
+ (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
+ L.match(MRI, TmpMI->getOperand(2).getReg())));
+ }
+ }
+ return false;
+ }
+};
+
+template <typename LHS, typename RHS>
+inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>
+m_GAdd(const LHS &L, const RHS &R) {
+ return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R);
+}
+
+template <typename LHS, typename RHS>
+inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L,
+ const RHS &R) {
+ return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R);
+}
+
+template <typename LHS, typename RHS>
+inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>
+m_GMul(const LHS &L, const RHS &R) {
+ return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R);
+}
+
+template <typename LHS, typename RHS>
+inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD> m_GFAdd(const LHS &L,
+ const RHS &R) {
+ return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD>(L, R);
+}
+
+// Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
+template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
+ SrcTy L;
+
+ UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
+ template <typename OpTy> bool match(MachineRegisterInfo &MRI, OpTy &&Op) {
+ MachineInstr *TmpMI;
+ if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
+ if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
+ return L.match(MRI, TmpMI->getOperand(1).getReg());
+ }
+ }
+ return false;
+ }
+};
+
+template <typename SrcTy>
+inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>
+m_GAnyExt(const SrcTy &Src) {
+ return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src);
+}
+
+template <typename SrcTy>
+inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) {
+ return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src);
+}
+
+template <typename SrcTy>
+inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) {
+ return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src);
+}
+
+template <typename SrcTy>
+inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) {
+ return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src);
+}
+
+template <typename SrcTy>
+inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) {
+ return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src);
+}
+
+template <typename SrcTy>
+inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>
+m_GFPTrunc(const SrcTy &Src) {
+ return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src);
+}
+
+template <typename SrcTy>
+inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) {
+ return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src));
+}
+
+// Helper for checking if a Reg is of specific type.
+struct CheckType {
+ LLT Ty;
+ CheckType(const LLT &Ty) : Ty(Ty) {}
+
+ bool match(MachineRegisterInfo &MRI, unsigned Reg) {
+ return MRI.getType(Reg) == Ty;
+ }
+};
+
+inline CheckType m_SpecificType(LLT Ty) { return Ty; }
+
+} // namespace GMIPatternMatch
+} // namespace llvm
+
+#endif
Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h?rev=323400&r1=323399&r2=323400&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h Wed Jan 24 18:53:06 2018
@@ -255,6 +255,11 @@ public:
/// with the same (scalar or vector) type).
///
/// \return a MachineInstrBuilder for the newly created instruction.
+ template <typename DstTy, typename... UseArgsTy>
+ MachineInstrBuilder buildSub(DstTy &&Ty, UseArgsTy &&... UseArgs) {
+ unsigned Res = getDestFromArg(Ty);
+ return buildSub(Res, (getRegFromArg(UseArgs))...);
+ }
MachineInstrBuilder buildSub(unsigned Res, unsigned Op0,
unsigned Op1);
@@ -268,6 +273,11 @@ public:
/// with the same (scalar or vector) type).
///
/// \return a MachineInstrBuilder for the newly created instruction.
+ template <typename DstTy, typename... UseArgsTy>
+ MachineInstrBuilder buildMul(DstTy &&Ty, UseArgsTy &&... UseArgs) {
+ unsigned Res = getDestFromArg(Ty);
+ return buildMul(Res, (getRegFromArg(UseArgs))...);
+ }
MachineInstrBuilder buildMul(unsigned Res, unsigned Op0,
unsigned Op1);
@@ -399,6 +409,10 @@ public:
/// \pre \p Op must be smaller than \p Res
///
/// \return The newly created instruction.
+ template <typename DstType, typename ArgType>
+ MachineInstrBuilder buildSExt(DstType &&Res, ArgType &&Arg) {
+ return buildSExt(getDestFromArg(Res), getRegFromArg(Arg));
+ }
MachineInstrBuilder buildSExt(unsigned Res, unsigned Op);
/// Build and insert \p Res = G_ZEXT \p Op
@@ -413,6 +427,10 @@ public:
/// \pre \p Op must be smaller than \p Res
///
/// \return The newly created instruction.
+ template <typename DstType, typename ArgType>
+ MachineInstrBuilder buildZExt(DstType &&Res, ArgType &&Arg) {
+ return buildZExt(getDestFromArg(Res), getRegFromArg(Arg));
+ }
MachineInstrBuilder buildZExt(unsigned Res, unsigned Op);
/// Build and insert \p Res = G_SEXT \p Op, \p Res = G_TRUNC \p Op, or
Modified: llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt?rev=323400&r1=323399&r2=323400&view=diff
==============================================================================
--- llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt (original)
+++ llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt Wed Jan 24 18:53:06 2018
@@ -1,8 +1,15 @@
set(LLVM_LINK_COMPONENTS
- GlobalISel
+ ${LLVM_TARGETS_TO_BUILD}
CodeGen
+ Core
+ GlobalISel
+ MC
+ MIRParser
+ Support
+ Target
)
add_llvm_unittest(GlobalISelTests
LegalizerInfoTest.cpp
+ PatternMatchTest.cpp
)
Added: llvm/trunk/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp?rev=323400&view=auto
==============================================================================
--- llvm/trunk/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp (added)
+++ llvm/trunk/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp Wed Jan 24 18:53:06 2018
@@ -0,0 +1,329 @@
+//===- PatternMatchTest.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/GlobalISel/Utils.h"
+#include "llvm/CodeGen/MIRParser/MIRParser.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/TargetFrameLowering.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace MIPatternMatch;
+
+namespace {
+
+void initLLVM() {
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+
+ PassRegistry *Registry = PassRegistry::getPassRegistry();
+ initializeCore(*Registry);
+ initializeCodeGen(*Registry);
+}
+
+/// Create a TargetMachine. As we lack a dedicated always available target for
+/// unittests, we go for "AArch64".
+std::unique_ptr<TargetMachine> createTargetMachine() {
+ Triple TargetTriple("aarch64--");
+ std::string Error;
+ const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
+ if (!T)
+ return nullptr;
+
+ TargetOptions Options;
+ return std::unique_ptr<TargetMachine>(T->createTargetMachine(
+ "AArch64", "", "", Options, None, None, CodeGenOpt::Aggressive));
+}
+
+std::unique_ptr<Module> parseMIR(LLVMContext &Context,
+ std::unique_ptr<MIRParser> &MIR,
+ const TargetMachine &TM, StringRef MIRCode,
+ const char *FuncName, MachineModuleInfo &MMI) {
+ SMDiagnostic Diagnostic;
+ std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
+ MIR = createMIRParser(std::move(MBuffer), Context);
+ if (!MIR)
+ return nullptr;
+
+ std::unique_ptr<Module> M = MIR->parseIRModule();
+ if (!M)
+ return nullptr;
+
+ M->setDataLayout(TM.createDataLayout());
+
+ if (MIR->parseMachineFunctions(*M, MMI))
+ return nullptr;
+
+ return M;
+}
+
+std::pair<std::unique_ptr<Module>, std::unique_ptr<MachineModuleInfo>>
+createDummyModule(LLVMContext &Context, const TargetMachine &TM,
+ StringRef MIRFunc) {
+ SmallString<512> S;
+ StringRef MIRString = (Twine(R"MIR(
+---
+...
+name: func
+registers:
+ - { id: 0, class: _ }
+ - { id: 1, class: _ }
+ - { id: 2, class: _ }
+ - { id: 3, class: _ }
+body: |
+ bb.1:
+ %0(s64) = COPY %x0
+ %1(s64) = COPY %x1
+ %2(s64) = COPY %x2
+)MIR") + Twine(MIRFunc) + Twine("...\n"))
+ .toNullTerminatedStringRef(S);
+ std::unique_ptr<MIRParser> MIR;
+ auto MMI = make_unique<MachineModuleInfo>(&TM);
+ std::unique_ptr<Module> M =
+ parseMIR(Context, MIR, TM, MIRString, "func", *MMI);
+ return make_pair(std::move(M), std::move(MMI));
+}
+
+static MachineFunction *getMFFromMMI(const Module *M,
+ const MachineModuleInfo *MMI) {
+ Function *F = M->getFunction("func");
+ auto *MF = MMI->getMachineFunction(*F);
+ return MF;
+}
+
+static void collectCopies(SmallVectorImpl<unsigned> &Copies,
+ MachineFunction *MF) {
+ for (auto &MBB : *MF)
+ for (MachineInstr &MI : MBB) {
+ if (MI.getOpcode() == TargetOpcode::COPY)
+ Copies.push_back(MI.getOperand(0).getReg());
+ }
+}
+
+TEST(PatternMatchInstr, MatchIntConstant) {
+ LLVMContext Context;
+ std::unique_ptr<TargetMachine> TM = createTargetMachine();
+ if (!TM)
+ return;
+ auto ModuleMMIPair = createDummyModule(Context, *TM, "");
+ MachineFunction *MF =
+ getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
+ SmallVector<unsigned, 4> Copies;
+ collectCopies(Copies, MF);
+ MachineBasicBlock *EntryMBB = &*MF->begin();
+ MachineIRBuilder B(*MF);
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+ B.setInsertPt(*EntryMBB, EntryMBB->end());
+ auto MIBCst = B.buildConstant(LLT::scalar(64), 42);
+ uint64_t Cst;
+ bool match = mi_match(MIBCst->getOperand(0).getReg(), MRI, m_ICst(Cst));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Cst, (uint64_t)42);
+}
+
+TEST(PatternMatchInstr, MatchBinaryOp) {
+ LLVMContext Context;
+ std::unique_ptr<TargetMachine> TM = createTargetMachine();
+ if (!TM)
+ return;
+ auto ModuleMMIPair = createDummyModule(Context, *TM, "");
+ MachineFunction *MF =
+ getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
+ SmallVector<unsigned, 4> Copies;
+ collectCopies(Copies, MF);
+ MachineBasicBlock *EntryMBB = &*MF->begin();
+ MachineIRBuilder B(*MF);
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+ B.setInsertPt(*EntryMBB, EntryMBB->end());
+ LLT s64 = LLT::scalar(64);
+ auto MIBAdd = B.buildAdd(s64, Copies[0], Copies[1]);
+ // Test case for no bind.
+ bool match =
+ mi_match(MIBAdd->getOperand(0).getReg(), MRI, m_GAdd(m_Reg(), m_Reg()));
+ ASSERT_TRUE(match);
+ unsigned Src0, Src1, Src2;
+ match = mi_match(MIBAdd->getOperand(0).getReg(), MRI,
+ m_GAdd(m_Reg(Src0), m_Reg(Src1)));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, Copies[0]);
+ ASSERT_EQ(Src1, Copies[1]);
+
+ // Build MUL(ADD %0, %1), %2
+ auto MIBMul = B.buildMul(s64, MIBAdd, Copies[2]);
+
+ // Try to match MUL.
+ match = mi_match(MIBMul->getOperand(0).getReg(), MRI,
+ m_GMul(m_Reg(Src0), m_Reg(Src1)));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, MIBAdd->getOperand(0).getReg());
+ ASSERT_EQ(Src1, Copies[2]);
+
+ // Try to match MUL(ADD)
+ match = mi_match(MIBMul->getOperand(0).getReg(), MRI,
+ m_GMul(m_GAdd(m_Reg(Src0), m_Reg(Src1)), m_Reg(Src2)));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, Copies[0]);
+ ASSERT_EQ(Src1, Copies[1]);
+ ASSERT_EQ(Src2, Copies[2]);
+
+ // Test Commutativity.
+ auto MIBMul2 = B.buildMul(s64, Copies[0], B.buildConstant(s64, 42));
+ // Try to match MUL(Cst, Reg) on src of MUL(Reg, Cst) to validate
+ // commutativity.
+ uint64_t Cst;
+ match = mi_match(MIBMul2->getOperand(0).getReg(), MRI,
+ m_GMul(m_ICst(Cst), m_Reg(Src0)));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Cst, (uint64_t)42);
+ ASSERT_EQ(Src0, Copies[0]);
+
+ // Make sure commutative doesn't work with something like SUB.
+ auto MIBSub = B.buildSub(s64, Copies[0], B.buildConstant(s64, 42));
+ match = mi_match(MIBSub->getOperand(0).getReg(), MRI,
+ m_GSub(m_ICst(Cst), m_Reg(Src0)));
+ ASSERT_FALSE(match);
+}
+
+TEST(PatternMatchInstr, MatchExtendsTrunc) {
+ LLVMContext Context;
+ std::unique_ptr<TargetMachine> TM = createTargetMachine();
+ if (!TM)
+ return;
+ auto ModuleMMIPair = createDummyModule(Context, *TM, "");
+ MachineFunction *MF =
+ getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
+ SmallVector<unsigned, 4> Copies;
+ collectCopies(Copies, MF);
+ MachineBasicBlock *EntryMBB = &*MF->begin();
+ MachineIRBuilder B(*MF);
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+ B.setInsertPt(*EntryMBB, EntryMBB->end());
+ LLT s64 = LLT::scalar(64);
+ LLT s32 = LLT::scalar(32);
+
+ auto MIBTrunc = B.buildTrunc(s32, Copies[0]);
+ auto MIBAExt = B.buildAnyExt(s64, MIBTrunc);
+ auto MIBZExt = B.buildZExt(s64, MIBTrunc);
+ auto MIBSExt = B.buildSExt(s64, MIBTrunc);
+ unsigned Src0;
+ bool match =
+ mi_match(MIBTrunc->getOperand(0).getReg(), MRI, m_GTrunc(m_Reg(Src0)));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, Copies[0]);
+ match =
+ mi_match(MIBAExt->getOperand(0).getReg(), MRI, m_GAnyExt(m_Reg(Src0)));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, MIBTrunc->getOperand(0).getReg());
+
+ match = mi_match(MIBSExt->getOperand(0).getReg(), MRI, m_GSExt(m_Reg(Src0)));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, MIBTrunc->getOperand(0).getReg());
+
+ match = mi_match(MIBZExt->getOperand(0).getReg(), MRI, m_GZExt(m_Reg(Src0)));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, MIBTrunc->getOperand(0).getReg());
+
+ // Match ext(trunc src)
+ match = mi_match(MIBAExt->getOperand(0).getReg(), MRI,
+ m_GAnyExt(m_GTrunc(m_Reg(Src0))));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, Copies[0]);
+
+ match = mi_match(MIBSExt->getOperand(0).getReg(), MRI,
+ m_GSExt(m_GTrunc(m_Reg(Src0))));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, Copies[0]);
+
+ match = mi_match(MIBZExt->getOperand(0).getReg(), MRI,
+ m_GZExt(m_GTrunc(m_Reg(Src0))));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, Copies[0]);
+}
+
+TEST(PatternMatchInstr, MatchSpecificType) {
+ LLVMContext Context;
+ std::unique_ptr<TargetMachine> TM = createTargetMachine();
+ if (!TM)
+ return;
+ auto ModuleMMIPair = createDummyModule(Context, *TM, "");
+ MachineFunction *MF =
+ getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
+ SmallVector<unsigned, 4> Copies;
+ collectCopies(Copies, MF);
+ MachineBasicBlock *EntryMBB = &*MF->begin();
+ MachineIRBuilder B(*MF);
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+ B.setInsertPt(*EntryMBB, EntryMBB->end());
+ LLT s64 = LLT::scalar(64);
+ LLT s32 = LLT::scalar(32);
+ auto MIBAdd = B.buildAdd(s64, Copies[0], Copies[1]);
+
+ // Try to match a 64bit add.
+ ASSERT_FALSE(mi_match(MIBAdd->getOperand(0).getReg(), MRI,
+ m_GAdd(m_SpecificType(s32), m_Reg())));
+ ASSERT_TRUE(mi_match(MIBAdd->getOperand(0).getReg(), MRI,
+ m_GAdd(m_SpecificType(s64), m_Reg())));
+}
+
+TEST(PatternMatchInstr, MatchCombinators) {
+ LLVMContext Context;
+ std::unique_ptr<TargetMachine> TM = createTargetMachine();
+ if (!TM)
+ return;
+ auto ModuleMMIPair = createDummyModule(Context, *TM, "");
+ MachineFunction *MF =
+ getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
+ SmallVector<unsigned, 4> Copies;
+ collectCopies(Copies, MF);
+ MachineBasicBlock *EntryMBB = &*MF->begin();
+ MachineIRBuilder B(*MF);
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+ B.setInsertPt(*EntryMBB, EntryMBB->end());
+ LLT s64 = LLT::scalar(64);
+ LLT s32 = LLT::scalar(32);
+ auto MIBAdd = B.buildAdd(s64, Copies[0], Copies[1]);
+ unsigned Src0, Src1;
+ bool match =
+ mi_match(MIBAdd->getOperand(0).getReg(), MRI,
+ m_all_of(m_SpecificType(s64), m_GAdd(m_Reg(Src0), m_Reg(Src1))));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, Copies[0]);
+ ASSERT_EQ(Src1, Copies[1]);
+ // Check for s32 (which should fail).
+ match =
+ mi_match(MIBAdd->getOperand(0).getReg(), MRI,
+ m_all_of(m_SpecificType(s32), m_GAdd(m_Reg(Src0), m_Reg(Src1))));
+ ASSERT_FALSE(match);
+ match =
+ mi_match(MIBAdd->getOperand(0).getReg(), MRI,
+ m_any_of(m_SpecificType(s32), m_GAdd(m_Reg(Src0), m_Reg(Src1))));
+ ASSERT_TRUE(match);
+ ASSERT_EQ(Src0, Copies[0]);
+ ASSERT_EQ(Src1, Copies[1]);
+}
+} // namespace
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ initLLVM();
+ return RUN_ALL_TESTS();
+}
More information about the llvm-commits
mailing list