llvm.org GIT mirror llvm / 6ab5bbc
Add support for pattern matching MachineInsts. https://reviews.llvm.org/D42439 Add Instcombine like matchers for MachineInstructions. There are only globalISel matchers for now. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@323400 91177308-0d34-0410-b5e6-96231b3b80d8 Aditya Nandakumar 2 years ago
4 changed file(s) with 628 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
0 //== ----- llvm/CodeGen/GlobalISel/MIPatternMatch.h --------------------- == //
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// Contains matchers for matching SSA Machine Instructions.
10 //
11 //===----------------------------------------------------------------------===//
12 #ifndef LLVM_GMIR_PATTERNMATCH_H
13 #define LLVM_GMIR_PATTERNMATCH_H
14
15 #include "llvm/ADT/APFloat.h"
16 #include "llvm/ADT/APInt.h"
17 #include "llvm/CodeGen/GlobalISel/Utils.h"
18 #include "llvm/CodeGen/MachineRegisterInfo.h"
19
20 namespace llvm {
21 namespace MIPatternMatch {
22
23 template
24 bool mi_match(Reg R, MachineRegisterInfo &MRI, Pattern &&P) {
25 return P.match(MRI, R);
26 }
27
28 // TODO: Extend for N use.
29 template struct OneUse_match {
30 SubPatternT SubPat;
31 OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
32
33 template
34 bool match(const MachineRegisterInfo &MRI, unsigned Reg) {
35 return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
36 }
37 };
38
39 template
40 inline OneUse_match m_OneUse(const SubPat &SP) {
41 return SP;
42 }
43
44 struct ConstantMatch {
45 uint64_t &CR;
46 ConstantMatch(uint64_t &C) : CR(C) {}
47 bool match(const MachineRegisterInfo &MRI, unsigned Reg) {
48 if (auto MaybeCst = getConstantVRegVal(Reg, MRI)) {
49 CR = *MaybeCst;
50 return true;
51 }
52 return false;
53 }
54 };
55
56 ConstantMatch m_ICst(uint64_t &Cst) { return ConstantMatch(Cst); }
57
58 // TODO: Rework this for different kinds of MachineOperand.
59 // Currently assumes the Src for a match is a register.
60 // We might want to support taking in some MachineOperands and call getReg on
61 // that.
62
63 struct operand_type_match {
64 bool match(const MachineRegisterInfo &MRI, unsigned Reg) { return true; }
65 bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
66 return MO->isReg();
67 }
68 };
69
70 operand_type_match m_Reg() { return operand_type_match(); }
71
72 /// Matching combinators.
73 template struct And {
74 template
75 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
76 return true;
77 }
78 };
79
80 template
81 struct And : And {
82 Pred P;
83 And(Pred &&p, Preds &&... preds)
84 : And(std::forward(preds)...), P(std::forward(p)) {
85 }
86 template
87 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
88 return P.match(MRI, src) && And::match(MRI, src);
89 }
90 };
91
92 template struct Or {
93 template
94 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
95 return true;
96 }
97 };
98
99 template
100 struct Or : Or {
101 Pred P;
102 Or(Pred &&p, Preds &&... preds)
103 : Or(std::forward(preds)...), P(std::forward(p)) {}
104 template
105 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
106 return P.match(MRI, src) || Or::match(MRI, src);
107 }
108 };
109
110 template And m_all_of(Preds &&... preds) {
111 return And(std::forward(preds)...);
112 }
113
114 template Or m_any_of(Preds &&... preds) {
115 return Or(std::forward(preds)...);
116 }
117
118 template struct bind_helper {
119 static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
120 VR = V;
121 return true;
122 }
123 };
124
125 template <> struct bind_helper {
126 static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
127 unsigned Reg) {
128 MI = MRI.getVRegDef(Reg);
129 if (MI)
130 return true;
131 return false;
132 }
133 };
134
135 template <> struct bind_helper {
136 static bool bind(const MachineRegisterInfo &MRI, LLT &Ty, unsigned Reg) {
137 Ty = MRI.getType(Reg);
138 if (Ty.isValid())
139 return true;
140 return false;
141 }
142 };
143
144 template struct bind_ty {
145 Class &VR;
146
147 bind_ty(Class &V) : VR(V) {}
148
149 template bool match(const MachineRegisterInfo &MRI, ITy &&V) {
150 return bind_helper::bind(MRI, VR, V);
151 }
152 };
153
154 inline bind_ty m_Reg(unsigned &R) { return R; }
155 inline bind_ty m_MInstr(MachineInstr *&MI) { return MI; }
156 inline bind_ty m_Type(LLT &Ty) { return Ty; }
157
158 // General helper for all the binary generic MI such as G_ADD/G_SUB etc
159 template
160 bool Commutable = false>
161 struct BinaryOp_match {
162 LHS_P L;
163 RHS_P R;
164
165 BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
166 template bool match(MachineRegisterInfo &MRI, OpTy &&Op) {
167 MachineInstr *TmpMI;
168 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
169 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
170 return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
171 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
172 (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
173 L.match(MRI, TmpMI->getOperand(2).getReg())));
174 }
175 }
176 return false;
177 }
178 };
179
180 template
181 inline BinaryOp_match
182 m_GAdd(const LHS &L, const RHS &R) {
183 return BinaryOp_match(L, R);
184 }
185
186 template
187 inline BinaryOp_match m_GSub(const LHS &L,
188 const RHS &R) {
189 return BinaryOp_match(L, R);
190 }
191
192 template
193 inline BinaryOp_match
194 m_GMul(const LHS &L, const RHS &R) {
195 return BinaryOp_match(L, R);
196 }
197
198 template
199 inline BinaryOp_match m_GFAdd(const LHS &L,
200 const RHS &R) {
201 return BinaryOp_match(L, R);
202 }
203
204 // Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
205 template struct UnaryOp_match {
206 SrcTy L;
207
208 UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
209 template bool match(MachineRegisterInfo &MRI, OpTy &&Op) {
210 MachineInstr *TmpMI;
211 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
212 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
213 return L.match(MRI, TmpMI->getOperand(1).getReg());
214 }
215 }
216 return false;
217 }
218 };
219
220 template
221 inline UnaryOp_match
222 m_GAnyExt(const SrcTy &Src) {
223 return UnaryOp_match(Src);
224 }
225
226 template
227 inline UnaryOp_match m_GSExt(const SrcTy &Src) {
228 return UnaryOp_match(Src);
229 }
230
231 template
232 inline UnaryOp_match m_GZExt(const SrcTy &Src) {
233 return UnaryOp_match(Src);
234 }
235
236 template
237 inline UnaryOp_match m_GFPExt(const SrcTy &Src) {
238 return UnaryOp_match(Src);
239 }
240
241 template
242 inline UnaryOp_match m_GTrunc(const SrcTy &Src) {
243 return UnaryOp_match(Src);
244 }
245
246 template
247 inline UnaryOp_match
248 m_GFPTrunc(const SrcTy &Src) {
249 return UnaryOp_match(Src);
250 }
251
252 template
253 inline UnaryOp_match m_Copy(SrcTy &&Src) {
254 return UnaryOp_match(std::forward(Src));
255 }
256
257 // Helper for checking if a Reg is of specific type.
258 struct CheckType {
259 LLT Ty;
260 CheckType(const LLT &Ty) : Ty(Ty) {}
261
262 bool match(MachineRegisterInfo &MRI, unsigned Reg) {
263 return MRI.getType(Reg) == Ty;
264 }
265 };
266
267 inline CheckType m_SpecificType(LLT Ty) { return Ty; }
268
269 } // namespace GMIPatternMatch
270 } // namespace llvm
271
272 #endif
254254 /// with the same (scalar or vector) type).
255255 ///
256256 /// \return a MachineInstrBuilder for the newly created instruction.
257 template
258 MachineInstrBuilder buildSub(DstTy &&Ty, UseArgsTy &&... UseArgs) {
259 unsigned Res = getDestFromArg(Ty);
260 return buildSub(Res, (getRegFromArg(UseArgs))...);
261 }
257262 MachineInstrBuilder buildSub(unsigned Res, unsigned Op0,
258263 unsigned Op1);
259264
267272 /// with the same (scalar or vector) type).
268273 ///
269274 /// \return a MachineInstrBuilder for the newly created instruction.
275 template
276 MachineInstrBuilder buildMul(DstTy &&Ty, UseArgsTy &&... UseArgs) {
277 unsigned Res = getDestFromArg(Ty);
278 return buildMul(Res, (getRegFromArg(UseArgs))...);
279 }
270280 MachineInstrBuilder buildMul(unsigned Res, unsigned Op0,
271281 unsigned Op1);
272282
398408 /// \pre \p Op must be smaller than \p Res
399409 ///
400410 /// \return The newly created instruction.
411 template
412 MachineInstrBuilder buildSExt(DstType &&Res, ArgType &&Arg) {
413 return buildSExt(getDestFromArg(Res), getRegFromArg(Arg));
414 }
401415 MachineInstrBuilder buildSExt(unsigned Res, unsigned Op);
402416
403417 /// Build and insert \p Res = G_ZEXT \p Op
412426 /// \pre \p Op must be smaller than \p Res
413427 ///
414428 /// \return The newly created instruction.
429 template
430 MachineInstrBuilder buildZExt(DstType &&Res, ArgType &&Arg) {
431 return buildZExt(getDestFromArg(Res), getRegFromArg(Arg));
432 }
415433 MachineInstrBuilder buildZExt(unsigned Res, unsigned Op);
416434
417435 /// Build and insert \p Res = G_SEXT \p Op, \p Res = G_TRUNC \p Op, or
0 set(LLVM_LINK_COMPONENTS
1 ${LLVM_TARGETS_TO_BUILD}
2 CodeGen
3 Core
14 GlobalISel
2 CodeGen
5 MC
6 MIRParser
7 Support
8 Target
39 )
410
511 add_llvm_unittest(GlobalISelTests
612 LegalizerInfoTest.cpp
13 PatternMatchTest.cpp
714 )
0 //===- PatternMatchTest.cpp -----------------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
10 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
11 #include "llvm/CodeGen/GlobalISel/Utils.h"
12 #include "llvm/CodeGen/MIRParser/MIRParser.h"
13 #include "llvm/CodeGen/MachineFunction.h"
14 #include "llvm/CodeGen/MachineModuleInfo.h"
15 #include "llvm/CodeGen/TargetFrameLowering.h"
16 #include "llvm/CodeGen/TargetInstrInfo.h"
17 #include "llvm/CodeGen/TargetLowering.h"
18 #include "llvm/CodeGen/TargetSubtargetInfo.h"
19 #include "llvm/Support/SourceMgr.h"
20 #include "llvm/Support/TargetRegistry.h"
21 #include "llvm/Support/TargetSelect.h"
22 #include "llvm/Target/TargetMachine.h"
23 #include "llvm/Target/TargetOptions.h"
24 #include "gtest/gtest.h"
25
26 using namespace llvm;
27 using namespace MIPatternMatch;
28
29 namespace {
30
31 void initLLVM() {
32 InitializeAllTargets();
33 InitializeAllTargetMCs();
34 InitializeAllAsmPrinters();
35 InitializeAllAsmParsers();
36
37 PassRegistry *Registry = PassRegistry::getPassRegistry();
38 initializeCore(*Registry);
39 initializeCodeGen(*Registry);
40 }
41
42 /// Create a TargetMachine. As we lack a dedicated always available target for
43 /// unittests, we go for "AArch64".
44 std::unique_ptr createTargetMachine() {
45 Triple TargetTriple("aarch64--");
46 std::string Error;
47 const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
48 if (!T)
49 return nullptr;
50
51 TargetOptions Options;
52 return std::unique_ptr(T->createTargetMachine(
53 "AArch64", "", "", Options, None, None, CodeGenOpt::Aggressive));
54 }
55
56 std::unique_ptr parseMIR(LLVMContext &Context,
57 std::unique_ptr &MIR,
58 const TargetMachine &TM, StringRef MIRCode,
59 const char *FuncName, MachineModuleInfo &MMI) {
60 SMDiagnostic Diagnostic;
61 std::unique_ptr MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
62 MIR = createMIRParser(std::move(MBuffer), Context);
63 if (!MIR)
64 return nullptr;
65
66 std::unique_ptr M = MIR->parseIRModule();
67 if (!M)
68 return nullptr;
69
70 M->setDataLayout(TM.createDataLayout());
71
72 if (MIR->parseMachineFunctions(*M, MMI))
73 return nullptr;
74
75 return M;
76 }
77
78 std::pair, std::unique_ptr>
79 createDummyModule(LLVMContext &Context, const TargetMachine &TM,
80 StringRef MIRFunc) {
81 SmallString<512> S;
82 StringRef MIRString = (Twine(R"MIR(
83 ---
84 ...
85 name: func
86 registers:
87 - { id: 0, class: _ }
88 - { id: 1, class: _ }
89 - { id: 2, class: _ }
90 - { id: 3, class: _ }
91 body: |
92 bb.1:
93 %0(s64) = COPY %x0
94 %1(s64) = COPY %x1
95 %2(s64) = COPY %x2
96 )MIR") + Twine(MIRFunc) + Twine("...\n"))
97 .toNullTerminatedStringRef(S);
98 std::unique_ptr MIR;
99 auto MMI = make_unique(&TM);
100 std::unique_ptr M =
101 parseMIR(Context, MIR, TM, MIRString, "func", *MMI);
102 return make_pair(std::move(M), std::move(MMI));
103 }
104
105 static MachineFunction *getMFFromMMI(const Module *M,
106 const MachineModuleInfo *MMI) {
107 Function *F = M->getFunction("func");
108 auto *MF = MMI->getMachineFunction(*F);
109 return MF;
110 }
111
112 static void collectCopies(SmallVectorImpl &Copies,
113 MachineFunction *MF) {
114 for (auto &MBB : *MF)
115 for (MachineInstr &MI : MBB) {
116 if (MI.getOpcode() == TargetOpcode::COPY)
117 Copies.push_back(MI.getOperand(0).getReg());
118 }
119 }
120
121 TEST(PatternMatchInstr, MatchIntConstant) {
122 LLVMContext Context;
123 std::unique_ptr TM = createTargetMachine();
124 if (!TM)
125 return;
126 auto ModuleMMIPair = createDummyModule(Context, *TM, "");
127 MachineFunction *MF =
128 getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
129 SmallVector Copies;
130 collectCopies(Copies, MF);
131 MachineBasicBlock *EntryMBB = &*MF->begin();
132 MachineIRBuilder B(*MF);
133 MachineRegisterInfo &MRI = MF->getRegInfo();
134 B.setInsertPt(*EntryMBB, EntryMBB->end());
135 auto MIBCst = B.buildConstant(LLT::scalar(64), 42);
136 uint64_t Cst;
137 bool match = mi_match(MIBCst->getOperand(0).getReg(), MRI, m_ICst(Cst));
138 ASSERT_TRUE(match);
139 ASSERT_EQ(Cst, (uint64_t)42);
140 }
141
142 TEST(PatternMatchInstr, MatchBinaryOp) {
143 LLVMContext Context;
144 std::unique_ptr TM = createTargetMachine();
145 if (!TM)
146 return;
147 auto ModuleMMIPair = createDummyModule(Context, *TM, "");
148 MachineFunction *MF =
149 getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
150 SmallVector Copies;
151 collectCopies(Copies, MF);
152 MachineBasicBlock *EntryMBB = &*MF->begin();
153 MachineIRBuilder B(*MF);
154 MachineRegisterInfo &MRI = MF->getRegInfo();
155 B.setInsertPt(*EntryMBB, EntryMBB->end());
156 LLT s64 = LLT::scalar(64);
157 auto MIBAdd = B.buildAdd(s64, Copies[0], Copies[1]);
158 // Test case for no bind.
159 bool match =
160 mi_match(MIBAdd->getOperand(0).getReg(), MRI, m_GAdd(m_Reg(), m_Reg()));
161 ASSERT_TRUE(match);
162 unsigned Src0, Src1, Src2;
163 match = mi_match(MIBAdd->getOperand(0).getReg(), MRI,
164 m_GAdd(m_Reg(Src0), m_Reg(Src1)));
165 ASSERT_TRUE(match);
166 ASSERT_EQ(Src0, Copies[0]);
167 ASSERT_EQ(Src1, Copies[1]);
168
169 // Build MUL(ADD %0, %1), %2
170 auto MIBMul = B.buildMul(s64, MIBAdd, Copies[2]);
171
172 // Try to match MUL.
173 match = mi_match(MIBMul->getOperand(0).getReg(), MRI,
174 m_GMul(m_Reg(Src0), m_Reg(Src1)));
175 ASSERT_TRUE(match);
176 ASSERT_EQ(Src0, MIBAdd->getOperand(0).getReg());
177 ASSERT_EQ(Src1, Copies[2]);
178
179 // Try to match MUL(ADD)
180 match = mi_match(MIBMul->getOperand(0).getReg(), MRI,
181 m_GMul(m_GAdd(m_Reg(Src0), m_Reg(Src1)), m_Reg(Src2)));
182 ASSERT_TRUE(match);
183 ASSERT_EQ(Src0, Copies[0]);
184 ASSERT_EQ(Src1, Copies[1]);
185 ASSERT_EQ(Src2, Copies[2]);
186
187 // Test Commutativity.
188 auto MIBMul2 = B.buildMul(s64, Copies[0], B.buildConstant(s64, 42));
189 // Try to match MUL(Cst, Reg) on src of MUL(Reg, Cst) to validate
190 // commutativity.
191 uint64_t Cst;
192 match = mi_match(MIBMul2->getOperand(0).getReg(), MRI,
193 m_GMul(m_ICst(Cst), m_Reg(Src0)));
194 ASSERT_TRUE(match);
195 ASSERT_EQ(Cst, (uint64_t)42);
196 ASSERT_EQ(Src0, Copies[0]);
197
198 // Make sure commutative doesn't work with something like SUB.
199 auto MIBSub = B.buildSub(s64, Copies[0], B.buildConstant(s64, 42));
200 match = mi_match(MIBSub->getOperand(0).getReg(), MRI,
201 m_GSub(m_ICst(Cst), m_Reg(Src0)));
202 ASSERT_FALSE(match);
203 }
204
205 TEST(PatternMatchInstr, MatchExtendsTrunc) {
206 LLVMContext Context;
207 std::unique_ptr TM = createTargetMachine();
208 if (!TM)
209 return;
210 auto ModuleMMIPair = createDummyModule(Context, *TM, "");
211 MachineFunction *MF =
212 getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
213 SmallVector Copies;
214 collectCopies(Copies, MF);
215 MachineBasicBlock *EntryMBB = &*MF->begin();
216 MachineIRBuilder B(*MF);
217 MachineRegisterInfo &MRI = MF->getRegInfo();
218 B.setInsertPt(*EntryMBB, EntryMBB->end());
219 LLT s64 = LLT::scalar(64);
220 LLT s32 = LLT::scalar(32);
221
222 auto MIBTrunc = B.buildTrunc(s32, Copies[0]);
223 auto MIBAExt = B.buildAnyExt(s64, MIBTrunc);
224 auto MIBZExt = B.buildZExt(s64, MIBTrunc);
225 auto MIBSExt = B.buildSExt(s64, MIBTrunc);
226 unsigned Src0;
227 bool match =
228 mi_match(MIBTrunc->getOperand(0).getReg(), MRI, m_GTrunc(m_Reg(Src0)));
229 ASSERT_TRUE(match);
230 ASSERT_EQ(Src0, Copies[0]);
231 match =
232 mi_match(MIBAExt->getOperand(0).getReg(), MRI, m_GAnyExt(m_Reg(Src0)));
233 ASSERT_TRUE(match);
234 ASSERT_EQ(Src0, MIBTrunc->getOperand(0).getReg());
235
236 match = mi_match(MIBSExt->getOperand(0).getReg(), MRI, m_GSExt(m_Reg(Src0)));
237 ASSERT_TRUE(match);
238 ASSERT_EQ(Src0, MIBTrunc->getOperand(0).getReg());
239
240 match = mi_match(MIBZExt->getOperand(0).getReg(), MRI, m_GZExt(m_Reg(Src0)));
241 ASSERT_TRUE(match);
242 ASSERT_EQ(Src0, MIBTrunc->getOperand(0).getReg());
243
244 // Match ext(trunc src)
245 match = mi_match(MIBAExt->getOperand(0).getReg(), MRI,
246 m_GAnyExt(m_GTrunc(m_Reg(Src0))));
247 ASSERT_TRUE(match);
248 ASSERT_EQ(Src0, Copies[0]);
249
250 match = mi_match(MIBSExt->getOperand(0).getReg(), MRI,
251 m_GSExt(m_GTrunc(m_Reg(Src0))));
252 ASSERT_TRUE(match);
253 ASSERT_EQ(Src0, Copies[0]);
254
255 match = mi_match(MIBZExt->getOperand(0).getReg(), MRI,
256 m_GZExt(m_GTrunc(m_Reg(Src0))));
257 ASSERT_TRUE(match);
258 ASSERT_EQ(Src0, Copies[0]);
259 }
260
261 TEST(PatternMatchInstr, MatchSpecificType) {
262 LLVMContext Context;
263 std::unique_ptr TM = createTargetMachine();
264 if (!TM)
265 return;
266 auto ModuleMMIPair = createDummyModule(Context, *TM, "");
267 MachineFunction *MF =
268 getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
269 SmallVector Copies;
270 collectCopies(Copies, MF);
271 MachineBasicBlock *EntryMBB = &*MF->begin();
272 MachineIRBuilder B(*MF);
273 MachineRegisterInfo &MRI = MF->getRegInfo();
274 B.setInsertPt(*EntryMBB, EntryMBB->end());
275 LLT s64 = LLT::scalar(64);
276 LLT s32 = LLT::scalar(32);
277 auto MIBAdd = B.buildAdd(s64, Copies[0], Copies[1]);
278
279 // Try to match a 64bit add.
280 ASSERT_FALSE(mi_match(MIBAdd->getOperand(0).getReg(), MRI,
281 m_GAdd(m_SpecificType(s32), m_Reg())));
282 ASSERT_TRUE(mi_match(MIBAdd->getOperand(0).getReg(), MRI,
283 m_GAdd(m_SpecificType(s64), m_Reg())));
284 }
285
286 TEST(PatternMatchInstr, MatchCombinators) {
287 LLVMContext Context;
288 std::unique_ptr TM = createTargetMachine();
289 if (!TM)
290 return;
291 auto ModuleMMIPair = createDummyModule(Context, *TM, "");
292 MachineFunction *MF =
293 getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
294 SmallVector Copies;
295 collectCopies(Copies, MF);
296 MachineBasicBlock *EntryMBB = &*MF->begin();
297 MachineIRBuilder B(*MF);
298 MachineRegisterInfo &MRI = MF->getRegInfo();
299 B.setInsertPt(*EntryMBB, EntryMBB->end());
300 LLT s64 = LLT::scalar(64);
301 LLT s32 = LLT::scalar(32);
302 auto MIBAdd = B.buildAdd(s64, Copies[0], Copies[1]);
303 unsigned Src0, Src1;
304 bool match =
305 mi_match(MIBAdd->getOperand(0).getReg(), MRI,
306 m_all_of(m_SpecificType(s64), m_GAdd(m_Reg(Src0), m_Reg(Src1))));
307 ASSERT_TRUE(match);
308 ASSERT_EQ(Src0, Copies[0]);
309 ASSERT_EQ(Src1, Copies[1]);
310 // Check for s32 (which should fail).
311 match =
312 mi_match(MIBAdd->getOperand(0).getReg(), MRI,
313 m_all_of(m_SpecificType(s32), m_GAdd(m_Reg(Src0), m_Reg(Src1))));
314 ASSERT_FALSE(match);
315 match =
316 mi_match(MIBAdd->getOperand(0).getReg(), MRI,
317 m_any_of(m_SpecificType(s32), m_GAdd(m_Reg(Src0), m_Reg(Src1))));
318 ASSERT_TRUE(match);
319 ASSERT_EQ(Src0, Copies[0]);
320 ASSERT_EQ(Src1, Copies[1]);
321 }
322 } // namespace
323
324 int main(int argc, char **argv) {
325 ::testing::InitGoogleTest(&argc, argv);
326 initLLVM();
327 return RUN_ALL_TESTS();
328 }