Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 031d9c6

Browse files
dsandersllvmahmedbougacha
authored andcommitted
[globalisel] Re-factor ISel matchers into a hierarchy. NFC
Summary: This should make it possible to easily add everything needed to import all the existing SelectionDAG rules. It should also serve the likely kinds of GlobalISel rules (some of which are not currently representable in SelectionDAG) once we've nailed down the tablegen definition for that. The hierarchy is as follows: MatcherRule - A matching rule. Currently used to emit C++ ISel code but will | also be used to emit test cases and tablegen definitions in the | near future. |- Instruction(s) - Represents the instruction to be matched. |- Instruction Predicate(s) - Test the opcode, arithmetic flags, etc. of an | instruction. \- Operand(s) - Represents a particular operand of the instruction. In the | future, there may be subclasses to test the same predicates | on multiple operands (including for variadic instructions). \ Operand Predicate(s) - Test the type, register bank, etc. of an operand. This is where the ComplexPattern equivalent will be represented. It's also nested-instruction matching will live as a predicate that follows the DefUse chain to the Def and tests a MatcherRule from that position. Support for multiple instruction matchers in a rule has been retained from the existing code but has been adjusted to assert when it is used. Previously it would silently drop all but the first instruction matcher. The tablegen-erated file is not functionally changed but has more parentheses and no longer attempts to format the if-statements since keeping track of the indentation is tricky in the presence of the matcher hierarchy. It would be nice to have CMakes tablegen() run the output through clang-format (when available) so we don't have to complicate TableGen with pretty-printing. It's also worth mentioning that this hierarchy will also be able to emit TableGen definitions and test cases in the near future. This is the reason for favouring explicit emit*() calls rather than the << operator. Reviewers: aditya_nandakumar, rovka, t.p.northover, qcolombet, ab Reviewed By: ab Subscribers: igorb, dberris, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D28942 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@293172 91177308-0d34-0410-b5e6-96231b3b80d8 (cherry picked from commit 2b464c4)
1 parent 681026e commit 031d9c6

File tree

1 file changed

+226
-48
lines changed

1 file changed

+226
-48
lines changed

utils/TableGen/GlobalISelEmitter.cpp

Lines changed: 226 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,6 @@ static bool isTrivialOperatorNode(const TreePatternNode *N) {
110110

111111
//===- Matchers -----------------------------------------------------------===//
112112

113-
struct Matcher {
114-
virtual ~Matcher() {}
115-
virtual void emit(raw_ostream &OS) const = 0;
116-
};
117-
118-
raw_ostream &operator<<(raw_ostream &S, const Matcher &M) {
119-
M.emit(S);
120-
return S;
121-
}
122-
123113
struct MatchAction {
124114
virtual ~MatchAction() {}
125115
virtual void emit(raw_ostream &OS) const = 0;
@@ -130,46 +120,211 @@ raw_ostream &operator<<(raw_ostream &S, const MatchAction &A) {
130120
return S;
131121
}
132122

133-
struct MatchOpcode : public Matcher {
134-
MatchOpcode(const CodeGenInstruction *I) : I(I) {}
135-
const CodeGenInstruction *I;
123+
template <class PredicateTy> class PredicateListMatcher {
124+
private:
125+
typedef std::vector<std::unique_ptr<PredicateTy>> PredicateVec;
126+
PredicateVec Predicates;
136127

137-
virtual void emit(raw_ostream &OS) const {
138-
OS << "I.getOpcode() == " << I->Namespace << "::" << I->TheDef->getName();
128+
public:
129+
/// Construct a new operand predicate and add it to the matcher.
130+
template <class Kind, class... Args>
131+
Kind &addPredicate(Args&&... args) {
132+
Predicates.emplace_back(make_unique<Kind>(std::forward<Args...>(args)...));
133+
return *static_cast<Kind *>(Predicates.back().get());
134+
}
135+
136+
typename PredicateVec::const_iterator predicates_begin() const { return Predicates.begin(); }
137+
typename PredicateVec::const_iterator predicates_end() const { return Predicates.end(); }
138+
iterator_range<typename PredicateVec::const_iterator> predicates() const {
139+
return make_range(predicates_begin(), predicates_end());
139140
}
141+
142+
#if 0
143+
/// Emit a C++ expression that tests whether all the predicates are met.
144+
template <class... Args>
145+
void emitCxxPredicatesExpr(raw_ostream &OS, Args&&... args) const {
146+
if (Predicates.empty()) {
147+
OS << "true";
148+
return;
149+
}
150+
151+
StringRef Separator = "";
152+
for (const auto &Predicate : predicates()) {
153+
OS << Separator << "(";
154+
Predicate->emitCxxPredicateExpr(OS, std::forward<Args...>(args)...);
155+
OS << ")";
156+
Separator = " && ";
157+
}
158+
}
159+
#else
160+
/// Emit a C++ expression that tests whether all the predicates are met.
161+
template <class Arg1>
162+
void emitCxxPredicatesExpr(raw_ostream &OS, Arg1&& arg1) const {
163+
if (Predicates.empty()) {
164+
OS << "true";
165+
return;
166+
}
167+
168+
StringRef Separator = "";
169+
for (const auto &Predicate : predicates()) {
170+
OS << Separator << "(";
171+
Predicate->emitCxxPredicateExpr(OS, std::forward<Arg1>(arg1));
172+
OS << ")";
173+
Separator = " && ";
174+
}
175+
}
176+
177+
template <class Arg1, class Arg2>
178+
void emitCxxPredicatesExpr(raw_ostream &OS, Arg1&& arg1, Arg2&& arg2) const {
179+
if (Predicates.empty()) {
180+
OS << "true";
181+
return;
182+
}
183+
184+
StringRef Separator = "";
185+
for (const auto &Predicate : predicates()) {
186+
OS << Separator << "(";
187+
Predicate->emitCxxPredicateExpr(OS, std::forward<Arg1>(arg1),
188+
std::forward<Arg2>(arg2));
189+
OS << ")";
190+
Separator = " && ";
191+
}
192+
}
193+
#endif
140194
};
141195

142-
struct MatchRegOpType : public Matcher {
143-
MatchRegOpType(unsigned OpIdx, std::string Ty)
144-
: OpIdx(OpIdx), Ty(Ty) {}
145-
unsigned OpIdx;
196+
/// Generates code to check a predicate of an operand.
197+
///
198+
/// Typical predicates include:
199+
/// * Operand is a particular register.
200+
/// * Operand is assigned a particular register bank.
201+
/// * Operand is an MBB.
202+
class OperandPredicateMatcher {
203+
public:
204+
virtual ~OperandPredicateMatcher() {}
205+
206+
/// Emit a C++ expression that checks the predicate for the OpIdx operand of
207+
/// the instruction given in InsnVarName.
208+
virtual void emitCxxPredicateExpr(raw_ostream &OS,
209+
const StringRef InsnVarName,
210+
unsigned OpIdx) const = 0;
211+
};
212+
213+
/// Generates code to check that an operand is a particular LLT.
214+
class LLTOperandMatcher : public OperandPredicateMatcher {
215+
protected:
146216
std::string Ty;
147217

148-
virtual void emit(raw_ostream &OS) const {
149-
OS << "MRI.getType(I.getOperand(" << OpIdx << ").getReg()) == (" << Ty
150-
<< ")";
218+
public:
219+
LLTOperandMatcher(std::string Ty) : Ty(Ty) {}
220+
221+
void emitCxxPredicateExpr(raw_ostream &OS, const StringRef InsnVarName,
222+
unsigned OpIdx) const override {
223+
OS << "MRI.getType(" << InsnVarName << ".getOperand(" << OpIdx
224+
<< ").getReg()) == (" << Ty << ")";
151225
}
152226
};
153227

154-
struct MatchRegOpBank : public Matcher {
155-
MatchRegOpBank(unsigned OpIdx, const CodeGenRegisterClass &RC)
156-
: OpIdx(OpIdx), RC(RC) {}
157-
unsigned OpIdx;
228+
/// Generates code to check that an operand is in a particular register bank.
229+
class RegisterBankOperandMatcher : public OperandPredicateMatcher {
230+
protected:
158231
const CodeGenRegisterClass &RC;
159232

160-
virtual void emit(raw_ostream &OS) const {
233+
public:
234+
RegisterBankOperandMatcher(const CodeGenRegisterClass &RC) : RC(RC) {}
235+
236+
void emitCxxPredicateExpr(raw_ostream &OS, const StringRef InsnVarName,
237+
unsigned OpIdx) const override {
161238
OS << "(&RBI.getRegBankFromRegClass(" << RC.getQualifiedName()
162-
<< "RegClass) == RBI.getRegBank(I.getOperand(" << OpIdx
163-
<< ").getReg(), MRI, TRI))";
239+
<< "RegClass) == RBI.getRegBank(" << InsnVarName << ".getOperand("
240+
<< OpIdx << ").getReg(), MRI, TRI))";
164241
}
165242
};
166243

167-
struct MatchMBBOp : public Matcher {
168-
MatchMBBOp(unsigned OpIdx) : OpIdx(OpIdx) {}
244+
/// Generates code to check that an operand is a basic block.
245+
class MBBOperandMatcher : public OperandPredicateMatcher {
246+
public:
247+
void emitCxxPredicateExpr(raw_ostream &OS, const StringRef InsnVarName,
248+
unsigned OpIdx) const override {
249+
OS << InsnVarName << ".getOperand(" << OpIdx << ").isMBB()";
250+
}
251+
};
252+
253+
/// Generates code to check that a set of predicates match for a particular
254+
/// operand.
255+
class OperandMatcher : public PredicateListMatcher<OperandPredicateMatcher> {
256+
protected:
169257
unsigned OpIdx;
170258

171-
virtual void emit(raw_ostream &OS) const {
172-
OS << "I.getOperand(" << OpIdx << ").isMBB()";
259+
public:
260+
OperandMatcher(unsigned OpIdx) : OpIdx(OpIdx) {}
261+
262+
/// Emit a C++ expression that tests whether the instruction named in
263+
/// InsnVarName matches all the predicate and all the operands.
264+
void emitCxxPredicateExpr(raw_ostream &OS, const StringRef InsnVarName) const {
265+
OS << "(";
266+
emitCxxPredicatesExpr(OS, InsnVarName, OpIdx);
267+
OS << ")";
268+
}
269+
};
270+
271+
/// Generates code to check a predicate on an instruction.
272+
///
273+
/// Typical predicates include:
274+
/// * The opcode of the instruction is a particular value.
275+
/// * The nsw/nuw flag is/isn't set.
276+
class InstructionPredicateMatcher {
277+
public:
278+
virtual ~InstructionPredicateMatcher() {}
279+
280+
/// Emit a C++ expression that tests whether the instruction named in
281+
/// InsnVarName matches the predicate.
282+
virtual void emitCxxPredicateExpr(raw_ostream &OS,
283+
const StringRef InsnVarName) const = 0;
284+
};
285+
286+
/// Generates code to check the opcode of an instruction.
287+
class InstructionOpcodeMatcher : public InstructionPredicateMatcher {
288+
protected:
289+
const CodeGenInstruction *I;
290+
291+
public:
292+
InstructionOpcodeMatcher(const CodeGenInstruction *I) : I(I) {}
293+
294+
void emitCxxPredicateExpr(raw_ostream &OS,
295+
const StringRef InsnVarName) const override {
296+
OS << InsnVarName << ".getOpcode() == " << I->Namespace
297+
<< "::" << I->TheDef->getName();
298+
}
299+
};
300+
301+
/// Generates code to check that a set of predicates and operands match for a
302+
/// particular instruction.
303+
///
304+
/// Typical predicates include:
305+
/// * Has a specific opcode.
306+
/// * Has an nsw/nuw flag or doesn't.
307+
class InstructionMatcher
308+
: public PredicateListMatcher<InstructionPredicateMatcher> {
309+
protected:
310+
std::vector<OperandMatcher> Operands;
311+
312+
public:
313+
/// Add an operand to the matcher.
314+
OperandMatcher &addOperand(unsigned OpIdx) {
315+
Operands.emplace_back(OpIdx);
316+
return Operands.back();
317+
}
318+
319+
/// Emit a C++ expression that tests whether the instruction named in
320+
/// InsnVarName matches all the predicates and all the operands.
321+
void emitCxxPredicateExpr(raw_ostream &OS, const StringRef InsnVarName) const {
322+
emitCxxPredicatesExpr(OS, InsnVarName);
323+
for (const auto &Operand : Operands) {
324+
OS << " && (";
325+
Operand.emitCxxPredicateExpr(OS, InsnVarName);
326+
OS << ")";
327+
}
173328
}
174329
};
175330

@@ -183,14 +338,25 @@ struct MutateOpcode : public MatchAction {
183338
}
184339
};
185340

186-
class MatcherEmitter {
341+
/// Generates code to check that a match rule matches.
342+
///
343+
/// This currently supports a single match position but could be extended to
344+
/// support multiple positions to support div/rem fusion or load-multiple
345+
/// instructions.
346+
class RuleMatcher {
187347
const PatternToMatch &P;
188348

349+
std::vector<std::unique_ptr<InstructionMatcher>> Matchers;
350+
189351
public:
190-
std::vector<std::unique_ptr<Matcher>> Matchers;
191352
std::vector<std::unique_ptr<MatchAction>> Actions;
192353

193-
MatcherEmitter(const PatternToMatch &P) : P(P) {}
354+
RuleMatcher(const PatternToMatch &P) : P(P) {}
355+
356+
InstructionMatcher &addInstructionMatcher() {
357+
Matchers.emplace_back(new InstructionMatcher());
358+
return *Matchers.back();
359+
}
194360

195361
void emit(raw_ostream &OS) {
196362
if (Matchers.empty())
@@ -199,9 +365,18 @@ class MatcherEmitter {
199365
OS << " // Src: " << *P.getSrcPattern() << "\n"
200366
<< " // Dst: " << *P.getDstPattern() << "\n";
201367

202-
OS << " if ((" << *Matchers.front() << ")";
203-
for (auto &MA : makeArrayRef(Matchers).drop_front())
204-
OS << " &&\n (" << *MA << ")";
368+
// The representation supports rules that require multiple roots such as:
369+
// %ptr(p0) = ...
370+
// %elt0(s32) = G_LOAD %ptr
371+
// %1(p0) = G_ADD %ptr, 4
372+
// %elt1(s32) = G_LOAD p0 %1
373+
// which could be usefully folded into:
374+
// %ptr(p0) = ...
375+
// %elt0(s32), %elt1(s32) = TGT_LOAD_PAIR %ptr
376+
// on some targets but we don't need to make use of that yet.
377+
assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet");
378+
OS << " if (";
379+
Matchers.front()->emitCxxPredicateExpr(OS, "I");
205380
OS << ") {\n";
206381

207382
for (auto &MA : Actions)
@@ -235,7 +410,7 @@ Optional<GlobalISelEmitter::SkipReason>
235410
GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
236411

237412
// Keep track of the matchers and actions to emit.
238-
MatcherEmitter M(P);
413+
RuleMatcher M(P);
239414

240415
// First, analyze the whole pattern.
241416
// If the entire pattern has a predicate (e.g., target features), ignore it.
@@ -268,7 +443,8 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
268443
auto &SrcGI = *SrcGIOrNull;
269444

270445
// The operators look good: match the opcode and mutate it to the new one.
271-
M.Matchers.emplace_back(new MatchOpcode(&SrcGI));
446+
InstructionMatcher &InsnMatcher = M.addInstructionMatcher();
447+
InsnMatcher.addPredicate<InstructionOpcodeMatcher>(&SrcGI);
272448
M.Actions.emplace_back(new MutateOpcode(&DstI));
273449

274450
// Next, analyze the children, only accepting patterns that don't require
@@ -291,9 +467,10 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
291467
if (!OpTyOrNone)
292468
return SkipReason{"Dst operand has an unsupported type"};
293469

294-
M.Matchers.emplace_back(new MatchRegOpType(OpIdx, *OpTyOrNone));
295-
M.Matchers.emplace_back(
296-
new MatchRegOpBank(OpIdx, Target.getRegisterClass(DstIOpRec)));
470+
OperandMatcher &OM = InsnMatcher.addOperand(OpIdx);
471+
OM.addPredicate<LLTOperandMatcher>(*OpTyOrNone);
472+
OM.addPredicate<RegisterBankOperandMatcher>(
473+
Target.getRegisterClass(DstIOpRec));
297474
++OpIdx;
298475
}
299476

@@ -316,7 +493,7 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
316493
if (SrcChild->getOperator()->isSubClassOf("SDNode")) {
317494
auto &ChildSDNI = CGP.getSDNodeInfo(SrcChild->getOperator());
318495
if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") {
319-
M.Matchers.emplace_back(new MatchMBBOp(OpIdx++));
496+
InsnMatcher.addOperand(OpIdx++).addPredicate<MBBOperandMatcher>();
320497
continue;
321498
}
322499
}
@@ -341,9 +518,10 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
341518
if (!OpTyOrNone)
342519
return SkipReason{"Src operand has an unsupported type"};
343520

344-
M.Matchers.emplace_back(new MatchRegOpType(OpIdx, *OpTyOrNone));
345-
M.Matchers.emplace_back(
346-
new MatchRegOpBank(OpIdx, Target.getRegisterClass(ChildRec)));
521+
OperandMatcher &OM = InsnMatcher.addOperand(OpIdx);
522+
OM.addPredicate<LLTOperandMatcher>(*OpTyOrNone);
523+
OM.addPredicate<RegisterBankOperandMatcher>(
524+
Target.getRegisterClass(ChildRec));
347525
++OpIdx;
348526
}
349527

0 commit comments

Comments
 (0)