xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1*5f757f3fSDimitry Andric //===- GlobalISelCombinerMatchTableEmitter.cpp - --------------------------===//
2*5f757f3fSDimitry Andric //
3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5f757f3fSDimitry Andric //
7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
8*5f757f3fSDimitry Andric //
9*5f757f3fSDimitry Andric /// \file Generate a combiner implementation for GlobalISel from a declarative
10*5f757f3fSDimitry Andric /// syntax using GlobalISelMatchTable.
11*5f757f3fSDimitry Andric ///
12*5f757f3fSDimitry Andric /// Usually, TableGen backends use "assert is an error" as a means to report
13*5f757f3fSDimitry Andric /// invalid input. They try to diagnose common case but don't try very hard and
14*5f757f3fSDimitry Andric /// crashes can be common. This backend aims to behave closer to how a language
15*5f757f3fSDimitry Andric /// compiler frontend would behave: we try extra hard to diagnose invalid inputs
16*5f757f3fSDimitry Andric /// early, and any crash should be considered a bug (= a feature or diagnostic
17*5f757f3fSDimitry Andric /// is missing).
18*5f757f3fSDimitry Andric ///
19*5f757f3fSDimitry Andric /// While this can make the backend a bit more complex than it needs to be, it
20*5f757f3fSDimitry Andric /// pays off because MIR patterns can get complicated. Giving useful error
21*5f757f3fSDimitry Andric /// messages to combine writers can help boost their productivity.
22*5f757f3fSDimitry Andric ///
23*5f757f3fSDimitry Andric /// As with anything, a good balance has to be found. We also don't want to
24*5f757f3fSDimitry Andric /// write hundreds of lines of code to detect edge cases. In practice, crashing
25*5f757f3fSDimitry Andric /// very occasionally, or giving poor errors in some rare instances, is fine.
26*5f757f3fSDimitry Andric ///
27*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
28*5f757f3fSDimitry Andric 
29*5f757f3fSDimitry Andric #include "CodeGenInstruction.h"
30*5f757f3fSDimitry Andric #include "CodeGenTarget.h"
31*5f757f3fSDimitry Andric #include "GlobalISel/CXXPredicates.h"
32*5f757f3fSDimitry Andric #include "GlobalISel/CodeExpander.h"
33*5f757f3fSDimitry Andric #include "GlobalISel/CodeExpansions.h"
34*5f757f3fSDimitry Andric #include "GlobalISel/CombinerUtils.h"
35*5f757f3fSDimitry Andric #include "GlobalISel/MatchDataInfo.h"
36*5f757f3fSDimitry Andric #include "GlobalISel/Patterns.h"
37*5f757f3fSDimitry Andric #include "GlobalISelMatchTable.h"
38*5f757f3fSDimitry Andric #include "GlobalISelMatchTableExecutorEmitter.h"
39*5f757f3fSDimitry Andric #include "SubtargetFeatureInfo.h"
40*5f757f3fSDimitry Andric #include "llvm/ADT/APInt.h"
41*5f757f3fSDimitry Andric #include "llvm/ADT/EquivalenceClasses.h"
42*5f757f3fSDimitry Andric #include "llvm/ADT/Hashing.h"
43*5f757f3fSDimitry Andric #include "llvm/ADT/MapVector.h"
44*5f757f3fSDimitry Andric #include "llvm/ADT/SetVector.h"
45*5f757f3fSDimitry Andric #include "llvm/ADT/Statistic.h"
46*5f757f3fSDimitry Andric #include "llvm/ADT/StringSet.h"
47*5f757f3fSDimitry Andric #include "llvm/Support/CommandLine.h"
48*5f757f3fSDimitry Andric #include "llvm/Support/Debug.h"
49*5f757f3fSDimitry Andric #include "llvm/Support/PrettyStackTrace.h"
50*5f757f3fSDimitry Andric #include "llvm/Support/ScopedPrinter.h"
51*5f757f3fSDimitry Andric #include "llvm/TableGen/Error.h"
52*5f757f3fSDimitry Andric #include "llvm/TableGen/Record.h"
53*5f757f3fSDimitry Andric #include "llvm/TableGen/StringMatcher.h"
54*5f757f3fSDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
55*5f757f3fSDimitry Andric #include <cstdint>
56*5f757f3fSDimitry Andric 
57*5f757f3fSDimitry Andric using namespace llvm;
58*5f757f3fSDimitry Andric using namespace llvm::gi;
59*5f757f3fSDimitry Andric 
60*5f757f3fSDimitry Andric #define DEBUG_TYPE "gicombiner-emitter"
61*5f757f3fSDimitry Andric 
62*5f757f3fSDimitry Andric namespace {
63*5f757f3fSDimitry Andric cl::OptionCategory
64*5f757f3fSDimitry Andric     GICombinerEmitterCat("Options for -gen-global-isel-combiner");
65*5f757f3fSDimitry Andric cl::opt<bool> StopAfterParse(
66*5f757f3fSDimitry Andric     "gicombiner-stop-after-parse",
67*5f757f3fSDimitry Andric     cl::desc("Stop processing after parsing rules and dump state"),
68*5f757f3fSDimitry Andric     cl::cat(GICombinerEmitterCat));
69*5f757f3fSDimitry Andric cl::list<std::string>
70*5f757f3fSDimitry Andric     SelectedCombiners("combiners", cl::desc("Emit the specified combiners"),
71*5f757f3fSDimitry Andric                       cl::cat(GICombinerEmitterCat), cl::CommaSeparated);
72*5f757f3fSDimitry Andric cl::opt<bool> DebugCXXPreds(
73*5f757f3fSDimitry Andric     "gicombiner-debug-cxxpreds",
74*5f757f3fSDimitry Andric     cl::desc("Add Contextual/Debug comments to all C++ predicates"),
75*5f757f3fSDimitry Andric     cl::cat(GICombinerEmitterCat));
76*5f757f3fSDimitry Andric cl::opt<bool> DebugTypeInfer("gicombiner-debug-typeinfer",
77*5f757f3fSDimitry Andric                              cl::desc("Print type inference debug logs"),
78*5f757f3fSDimitry Andric                              cl::cat(GICombinerEmitterCat));
79*5f757f3fSDimitry Andric 
80*5f757f3fSDimitry Andric constexpr StringLiteral CXXApplyPrefix = "GICXXCustomAction_CombineApply";
81*5f757f3fSDimitry Andric constexpr StringLiteral CXXPredPrefix = "GICXXPred_MI_Predicate_";
82*5f757f3fSDimitry Andric constexpr StringLiteral MIFlagsEnumClassName = "MIFlagEnum";
83*5f757f3fSDimitry Andric 
84*5f757f3fSDimitry Andric //===- CodeExpansions Helpers  --------------------------------------------===//
85*5f757f3fSDimitry Andric 
86*5f757f3fSDimitry Andric void declareInstExpansion(CodeExpansions &CE, const InstructionMatcher &IM,
87*5f757f3fSDimitry Andric                           StringRef Name) {
88*5f757f3fSDimitry Andric   CE.declare(Name, "State.MIs[" + to_string(IM.getInsnVarID()) + "]");
89*5f757f3fSDimitry Andric }
90*5f757f3fSDimitry Andric 
91*5f757f3fSDimitry Andric void declareInstExpansion(CodeExpansions &CE, const BuildMIAction &A,
92*5f757f3fSDimitry Andric                           StringRef Name) {
93*5f757f3fSDimitry Andric   // Note: we use redeclare here because this may overwrite a matcher inst
94*5f757f3fSDimitry Andric   // expansion.
95*5f757f3fSDimitry Andric   CE.redeclare(Name, "OutMIs[" + to_string(A.getInsnID()) + "]");
96*5f757f3fSDimitry Andric }
97*5f757f3fSDimitry Andric 
98*5f757f3fSDimitry Andric void declareOperandExpansion(CodeExpansions &CE, const OperandMatcher &OM,
99*5f757f3fSDimitry Andric                              StringRef Name) {
100*5f757f3fSDimitry Andric   CE.declare(Name, "State.MIs[" + to_string(OM.getInsnVarID()) +
101*5f757f3fSDimitry Andric                        "]->getOperand(" + to_string(OM.getOpIdx()) + ")");
102*5f757f3fSDimitry Andric }
103*5f757f3fSDimitry Andric 
104*5f757f3fSDimitry Andric void declareTempRegExpansion(CodeExpansions &CE, unsigned TempRegID,
105*5f757f3fSDimitry Andric                              StringRef Name) {
106*5f757f3fSDimitry Andric   CE.declare(Name, "State.TempRegisters[" + to_string(TempRegID) + "]");
107*5f757f3fSDimitry Andric }
108*5f757f3fSDimitry Andric 
109*5f757f3fSDimitry Andric //===- Misc. Helpers  -----------------------------------------------------===//
110*5f757f3fSDimitry Andric 
111*5f757f3fSDimitry Andric /// Copies a StringRef into a static pool to preserve it.
112*5f757f3fSDimitry Andric /// Most Pattern classes use StringRef so we need this.
113*5f757f3fSDimitry Andric StringRef insertStrRef(StringRef S) {
114*5f757f3fSDimitry Andric   if (S.empty())
115*5f757f3fSDimitry Andric     return {};
116*5f757f3fSDimitry Andric 
117*5f757f3fSDimitry Andric   static StringSet<> Pool;
118*5f757f3fSDimitry Andric   auto [It, Inserted] = Pool.insert(S);
119*5f757f3fSDimitry Andric   return It->getKey();
120*5f757f3fSDimitry Andric }
121*5f757f3fSDimitry Andric 
122*5f757f3fSDimitry Andric template <typename Container> auto keys(Container &&C) {
123*5f757f3fSDimitry Andric   return map_range(C, [](auto &Entry) -> auto & { return Entry.first; });
124*5f757f3fSDimitry Andric }
125*5f757f3fSDimitry Andric 
126*5f757f3fSDimitry Andric template <typename Container> auto values(Container &&C) {
127*5f757f3fSDimitry Andric   return map_range(C, [](auto &Entry) -> auto & { return Entry.second; });
128*5f757f3fSDimitry Andric }
129*5f757f3fSDimitry Andric 
130*5f757f3fSDimitry Andric std::string getIsEnabledPredicateEnumName(unsigned CombinerRuleID) {
131*5f757f3fSDimitry Andric   return "GICXXPred_Simple_IsRule" + to_string(CombinerRuleID) + "Enabled";
132*5f757f3fSDimitry Andric }
133*5f757f3fSDimitry Andric 
134*5f757f3fSDimitry Andric //===- MatchTable Helpers  ------------------------------------------------===//
135*5f757f3fSDimitry Andric 
136*5f757f3fSDimitry Andric LLTCodeGen getLLTCodeGen(const PatternType &PT) {
137*5f757f3fSDimitry Andric   return *MVTToLLT(getValueType(PT.getLLTRecord()));
138*5f757f3fSDimitry Andric }
139*5f757f3fSDimitry Andric 
140*5f757f3fSDimitry Andric LLTCodeGenOrTempType getLLTCodeGenOrTempType(const PatternType &PT,
141*5f757f3fSDimitry Andric                                              RuleMatcher &RM) {
142*5f757f3fSDimitry Andric   assert(!PT.isNone());
143*5f757f3fSDimitry Andric 
144*5f757f3fSDimitry Andric   if (PT.isLLT())
145*5f757f3fSDimitry Andric     return getLLTCodeGen(PT);
146*5f757f3fSDimitry Andric 
147*5f757f3fSDimitry Andric   assert(PT.isTypeOf());
148*5f757f3fSDimitry Andric   auto &OM = RM.getOperandMatcher(PT.getTypeOfOpName());
149*5f757f3fSDimitry Andric   return OM.getTempTypeIdx(RM);
150*5f757f3fSDimitry Andric }
151*5f757f3fSDimitry Andric 
152*5f757f3fSDimitry Andric //===- PrettyStackTrace Helpers  ------------------------------------------===//
153*5f757f3fSDimitry Andric 
154*5f757f3fSDimitry Andric class PrettyStackTraceParse : public PrettyStackTraceEntry {
155*5f757f3fSDimitry Andric   const Record &Def;
156*5f757f3fSDimitry Andric 
157*5f757f3fSDimitry Andric public:
158*5f757f3fSDimitry Andric   PrettyStackTraceParse(const Record &Def) : Def(Def) {}
159*5f757f3fSDimitry Andric 
160*5f757f3fSDimitry Andric   void print(raw_ostream &OS) const override {
161*5f757f3fSDimitry Andric     if (Def.isSubClassOf("GICombineRule"))
162*5f757f3fSDimitry Andric       OS << "Parsing GICombineRule '" << Def.getName() << "'";
163*5f757f3fSDimitry Andric     else if (Def.isSubClassOf(PatFrag::ClassName))
164*5f757f3fSDimitry Andric       OS << "Parsing " << PatFrag::ClassName << " '" << Def.getName() << "'";
165*5f757f3fSDimitry Andric     else
166*5f757f3fSDimitry Andric       OS << "Parsing '" << Def.getName() << "'";
167*5f757f3fSDimitry Andric     OS << '\n';
168*5f757f3fSDimitry Andric   }
169*5f757f3fSDimitry Andric };
170*5f757f3fSDimitry Andric 
171*5f757f3fSDimitry Andric class PrettyStackTraceEmit : public PrettyStackTraceEntry {
172*5f757f3fSDimitry Andric   const Record &Def;
173*5f757f3fSDimitry Andric   const Pattern *Pat = nullptr;
174*5f757f3fSDimitry Andric 
175*5f757f3fSDimitry Andric public:
176*5f757f3fSDimitry Andric   PrettyStackTraceEmit(const Record &Def, const Pattern *Pat = nullptr)
177*5f757f3fSDimitry Andric       : Def(Def), Pat(Pat) {}
178*5f757f3fSDimitry Andric 
179*5f757f3fSDimitry Andric   void print(raw_ostream &OS) const override {
180*5f757f3fSDimitry Andric     if (Def.isSubClassOf("GICombineRule"))
181*5f757f3fSDimitry Andric       OS << "Emitting GICombineRule '" << Def.getName() << "'";
182*5f757f3fSDimitry Andric     else if (Def.isSubClassOf(PatFrag::ClassName))
183*5f757f3fSDimitry Andric       OS << "Emitting " << PatFrag::ClassName << " '" << Def.getName() << "'";
184*5f757f3fSDimitry Andric     else
185*5f757f3fSDimitry Andric       OS << "Emitting '" << Def.getName() << "'";
186*5f757f3fSDimitry Andric 
187*5f757f3fSDimitry Andric     if (Pat)
188*5f757f3fSDimitry Andric       OS << " [" << Pat->getKindName() << " '" << Pat->getName() << "']";
189*5f757f3fSDimitry Andric     OS << '\n';
190*5f757f3fSDimitry Andric   }
191*5f757f3fSDimitry Andric };
192*5f757f3fSDimitry Andric 
193*5f757f3fSDimitry Andric //===- CombineRuleOperandTypeChecker --------------------------------------===//
194*5f757f3fSDimitry Andric 
195*5f757f3fSDimitry Andric /// This is a wrapper around OperandTypeChecker specialized for Combiner Rules.
196*5f757f3fSDimitry Andric /// On top of doing the same things as OperandTypeChecker, this also attempts to
197*5f757f3fSDimitry Andric /// infer as many types as possible for temporary register defs & immediates in
198*5f757f3fSDimitry Andric /// apply patterns.
199*5f757f3fSDimitry Andric ///
200*5f757f3fSDimitry Andric /// The inference is trivial and leverages the MCOI OperandTypes encoded in
201*5f757f3fSDimitry Andric /// CodeGenInstructions to infer types across patterns in a CombineRule. It's
202*5f757f3fSDimitry Andric /// thus very limited and only supports CodeGenInstructions (but that's the main
203*5f757f3fSDimitry Andric /// use case so it's fine).
204*5f757f3fSDimitry Andric ///
205*5f757f3fSDimitry Andric /// We only try to infer untyped operands in apply patterns when they're temp
206*5f757f3fSDimitry Andric /// reg defs, or immediates. Inference always outputs a `TypeOf<$x>` where $x is
207*5f757f3fSDimitry Andric /// a named operand from a match pattern.
208*5f757f3fSDimitry Andric class CombineRuleOperandTypeChecker : private OperandTypeChecker {
209*5f757f3fSDimitry Andric public:
210*5f757f3fSDimitry Andric   CombineRuleOperandTypeChecker(const Record &RuleDef,
211*5f757f3fSDimitry Andric                                 const OperandTable &MatchOpTable)
212*5f757f3fSDimitry Andric       : OperandTypeChecker(RuleDef.getLoc()), RuleDef(RuleDef),
213*5f757f3fSDimitry Andric         MatchOpTable(MatchOpTable) {}
214*5f757f3fSDimitry Andric 
215*5f757f3fSDimitry Andric   /// Records and checks a 'match' pattern.
216*5f757f3fSDimitry Andric   bool processMatchPattern(InstructionPattern &P);
217*5f757f3fSDimitry Andric 
218*5f757f3fSDimitry Andric   /// Records and checks an 'apply' pattern.
219*5f757f3fSDimitry Andric   bool processApplyPattern(InstructionPattern &P);
220*5f757f3fSDimitry Andric 
221*5f757f3fSDimitry Andric   /// Propagates types, then perform type inference and do a second round of
222*5f757f3fSDimitry Andric   /// propagation in the apply patterns only if any types were inferred.
223*5f757f3fSDimitry Andric   void propagateAndInferTypes();
224*5f757f3fSDimitry Andric 
225*5f757f3fSDimitry Andric private:
226*5f757f3fSDimitry Andric   /// TypeEquivalenceClasses are groups of operands of an instruction that share
227*5f757f3fSDimitry Andric   /// a common type.
228*5f757f3fSDimitry Andric   ///
229*5f757f3fSDimitry Andric   /// e.g. [[a, b], [c, d]] means a and b have the same type, and c and
230*5f757f3fSDimitry Andric   /// d have the same type too. b/c and a/d don't have to have the same type,
231*5f757f3fSDimitry Andric   /// though.
232*5f757f3fSDimitry Andric   using TypeEquivalenceClasses = EquivalenceClasses<StringRef>;
233*5f757f3fSDimitry Andric 
234*5f757f3fSDimitry Andric   /// \returns true for `OPERAND_GENERIC_` 0 through 5.
235*5f757f3fSDimitry Andric   /// These are the MCOI types that can be registers. The other MCOI types are
236*5f757f3fSDimitry Andric   /// either immediates, or fancier operands used only post-ISel, so we don't
237*5f757f3fSDimitry Andric   /// care about them for combiners.
238*5f757f3fSDimitry Andric   static bool canMCOIOperandTypeBeARegister(StringRef MCOIType) {
239*5f757f3fSDimitry Andric     // Assume OPERAND_GENERIC_0 through 5 can be registers. The other MCOI
240*5f757f3fSDimitry Andric     // OperandTypes are either never used in gMIR, or not relevant (e.g.
241*5f757f3fSDimitry Andric     // OPERAND_GENERIC_IMM, which is definitely never a register).
242*5f757f3fSDimitry Andric     return MCOIType.drop_back(1).ends_with("OPERAND_GENERIC_");
243*5f757f3fSDimitry Andric   }
244*5f757f3fSDimitry Andric 
245*5f757f3fSDimitry Andric   /// Finds the "MCOI::"" operand types for each operand of \p CGP.
246*5f757f3fSDimitry Andric   ///
247*5f757f3fSDimitry Andric   /// This is a bit trickier than it looks because we need to handle variadic
248*5f757f3fSDimitry Andric   /// in/outs.
249*5f757f3fSDimitry Andric   ///
250*5f757f3fSDimitry Andric   /// e.g. for
251*5f757f3fSDimitry Andric   ///   (G_BUILD_VECTOR $vec, $x, $y) ->
252*5f757f3fSDimitry Andric   ///   [MCOI::OPERAND_GENERIC_0, MCOI::OPERAND_GENERIC_1,
253*5f757f3fSDimitry Andric   ///    MCOI::OPERAND_GENERIC_1]
254*5f757f3fSDimitry Andric   ///
255*5f757f3fSDimitry Andric   /// For unknown types (which can happen in variadics where varargs types are
256*5f757f3fSDimitry Andric   /// inconsistent), a unique name is given, e.g. "unknown_type_0".
257*5f757f3fSDimitry Andric   static std::vector<std::string>
258*5f757f3fSDimitry Andric   getMCOIOperandTypes(const CodeGenInstructionPattern &CGP);
259*5f757f3fSDimitry Andric 
260*5f757f3fSDimitry Andric   /// Adds the TypeEquivalenceClasses for \p P in \p OutTECs.
261*5f757f3fSDimitry Andric   void getInstEqClasses(const InstructionPattern &P,
262*5f757f3fSDimitry Andric                         TypeEquivalenceClasses &OutTECs) const;
263*5f757f3fSDimitry Andric 
264*5f757f3fSDimitry Andric   /// Calls `getInstEqClasses` on all patterns of the rule to produce the whole
265*5f757f3fSDimitry Andric   /// rule's TypeEquivalenceClasses.
266*5f757f3fSDimitry Andric   TypeEquivalenceClasses getRuleEqClasses() const;
267*5f757f3fSDimitry Andric 
268*5f757f3fSDimitry Andric   /// Tries to infer the type of the \p ImmOpIdx -th operand of \p IP using \p
269*5f757f3fSDimitry Andric   /// TECs.
270*5f757f3fSDimitry Andric   ///
271*5f757f3fSDimitry Andric   /// This is achieved by trying to find a named operand in \p IP that shares
272*5f757f3fSDimitry Andric   /// the same type as \p ImmOpIdx, and using \ref inferNamedOperandType on that
273*5f757f3fSDimitry Andric   /// operand instead.
274*5f757f3fSDimitry Andric   ///
275*5f757f3fSDimitry Andric   /// \returns the inferred type or an empty PatternType if inference didn't
276*5f757f3fSDimitry Andric   /// succeed.
277*5f757f3fSDimitry Andric   PatternType inferImmediateType(const InstructionPattern &IP,
278*5f757f3fSDimitry Andric                                  unsigned ImmOpIdx,
279*5f757f3fSDimitry Andric                                  const TypeEquivalenceClasses &TECs) const;
280*5f757f3fSDimitry Andric 
281*5f757f3fSDimitry Andric   /// Looks inside \p TECs to infer \p OpName's type.
282*5f757f3fSDimitry Andric   ///
283*5f757f3fSDimitry Andric   /// \returns the inferred type or an empty PatternType if inference didn't
284*5f757f3fSDimitry Andric   /// succeed.
285*5f757f3fSDimitry Andric   PatternType inferNamedOperandType(const InstructionPattern &IP,
286*5f757f3fSDimitry Andric                                     StringRef OpName,
287*5f757f3fSDimitry Andric                                     const TypeEquivalenceClasses &TECs) const;
288*5f757f3fSDimitry Andric 
289*5f757f3fSDimitry Andric   const Record &RuleDef;
290*5f757f3fSDimitry Andric   SmallVector<InstructionPattern *, 8> MatchPats;
291*5f757f3fSDimitry Andric   SmallVector<InstructionPattern *, 8> ApplyPats;
292*5f757f3fSDimitry Andric 
293*5f757f3fSDimitry Andric   const OperandTable &MatchOpTable;
294*5f757f3fSDimitry Andric };
295*5f757f3fSDimitry Andric 
296*5f757f3fSDimitry Andric bool CombineRuleOperandTypeChecker::processMatchPattern(InstructionPattern &P) {
297*5f757f3fSDimitry Andric   MatchPats.push_back(&P);
298*5f757f3fSDimitry Andric   return check(P, /*CheckTypeOf*/ [](const auto &) {
299*5f757f3fSDimitry Andric     // GITypeOf in 'match' is currently always rejected by the
300*5f757f3fSDimitry Andric     // CombineRuleBuilder after inference is done.
301*5f757f3fSDimitry Andric     return true;
302*5f757f3fSDimitry Andric   });
303*5f757f3fSDimitry Andric }
304*5f757f3fSDimitry Andric 
305*5f757f3fSDimitry Andric bool CombineRuleOperandTypeChecker::processApplyPattern(InstructionPattern &P) {
306*5f757f3fSDimitry Andric   ApplyPats.push_back(&P);
307*5f757f3fSDimitry Andric   return check(P, /*CheckTypeOf*/ [&](const PatternType &Ty) {
308*5f757f3fSDimitry Andric     // GITypeOf<"$x"> can only be used if "$x" is a matched operand.
309*5f757f3fSDimitry Andric     const auto OpName = Ty.getTypeOfOpName();
310*5f757f3fSDimitry Andric     if (MatchOpTable.lookup(OpName).Found)
311*5f757f3fSDimitry Andric       return true;
312*5f757f3fSDimitry Andric 
313*5f757f3fSDimitry Andric     PrintError(RuleDef.getLoc(), "'" + OpName + "' ('" + Ty.str() +
314*5f757f3fSDimitry Andric                                      "') does not refer to a matched operand!");
315*5f757f3fSDimitry Andric     return false;
316*5f757f3fSDimitry Andric   });
317*5f757f3fSDimitry Andric }
318*5f757f3fSDimitry Andric 
319*5f757f3fSDimitry Andric void CombineRuleOperandTypeChecker::propagateAndInferTypes() {
320*5f757f3fSDimitry Andric   /// First step here is to propagate types using the OperandTypeChecker. That
321*5f757f3fSDimitry Andric   /// way we ensure all uses of a given register have consistent types.
322*5f757f3fSDimitry Andric   propagateTypes();
323*5f757f3fSDimitry Andric 
324*5f757f3fSDimitry Andric   /// Build the TypeEquivalenceClasses for the whole rule.
325*5f757f3fSDimitry Andric   const TypeEquivalenceClasses TECs = getRuleEqClasses();
326*5f757f3fSDimitry Andric 
327*5f757f3fSDimitry Andric   /// Look at the apply patterns and find operands that need to be
328*5f757f3fSDimitry Andric   /// inferred. We then try to find an equivalence class that they're a part of
329*5f757f3fSDimitry Andric   /// and select the best operand to use for the `GITypeOf` type. We prioritize
330*5f757f3fSDimitry Andric   /// defs of matched instructions because those are guaranteed to be registers.
331*5f757f3fSDimitry Andric   bool InferredAny = false;
332*5f757f3fSDimitry Andric   for (auto *Pat : ApplyPats) {
333*5f757f3fSDimitry Andric     for (unsigned K = 0; K < Pat->operands_size(); ++K) {
334*5f757f3fSDimitry Andric       auto &Op = Pat->getOperand(K);
335*5f757f3fSDimitry Andric 
336*5f757f3fSDimitry Andric       // We only want to take a look at untyped defs or immediates.
337*5f757f3fSDimitry Andric       if ((!Op.isDef() && !Op.hasImmValue()) || Op.getType())
338*5f757f3fSDimitry Andric         continue;
339*5f757f3fSDimitry Andric 
340*5f757f3fSDimitry Andric       // Infer defs & named immediates.
341*5f757f3fSDimitry Andric       if (Op.isDef() || Op.isNamedImmediate()) {
342*5f757f3fSDimitry Andric         // Check it's not a redefinition of a matched operand.
343*5f757f3fSDimitry Andric         // In such cases, inference is not necessary because we just copy
344*5f757f3fSDimitry Andric         // operands and don't create temporary registers.
345*5f757f3fSDimitry Andric         if (MatchOpTable.lookup(Op.getOperandName()).Found)
346*5f757f3fSDimitry Andric           continue;
347*5f757f3fSDimitry Andric 
348*5f757f3fSDimitry Andric         // Inference is needed here, so try to do it.
349*5f757f3fSDimitry Andric         if (PatternType Ty =
350*5f757f3fSDimitry Andric                 inferNamedOperandType(*Pat, Op.getOperandName(), TECs)) {
351*5f757f3fSDimitry Andric           if (DebugTypeInfer)
352*5f757f3fSDimitry Andric             errs() << "INFER: " << Op.describe() << " -> " << Ty.str() << '\n';
353*5f757f3fSDimitry Andric           Op.setType(Ty);
354*5f757f3fSDimitry Andric           InferredAny = true;
355*5f757f3fSDimitry Andric         }
356*5f757f3fSDimitry Andric 
357*5f757f3fSDimitry Andric         continue;
358*5f757f3fSDimitry Andric       }
359*5f757f3fSDimitry Andric 
360*5f757f3fSDimitry Andric       // Infer immediates
361*5f757f3fSDimitry Andric       if (Op.hasImmValue()) {
362*5f757f3fSDimitry Andric         if (PatternType Ty = inferImmediateType(*Pat, K, TECs)) {
363*5f757f3fSDimitry Andric           if (DebugTypeInfer)
364*5f757f3fSDimitry Andric             errs() << "INFER: " << Op.describe() << " -> " << Ty.str() << '\n';
365*5f757f3fSDimitry Andric           Op.setType(Ty);
366*5f757f3fSDimitry Andric           InferredAny = true;
367*5f757f3fSDimitry Andric         }
368*5f757f3fSDimitry Andric         continue;
369*5f757f3fSDimitry Andric       }
370*5f757f3fSDimitry Andric     }
371*5f757f3fSDimitry Andric   }
372*5f757f3fSDimitry Andric 
373*5f757f3fSDimitry Andric   // If we've inferred any types, we want to propagate them across the apply
374*5f757f3fSDimitry Andric   // patterns. Type inference only adds GITypeOf types that point to Matched
375*5f757f3fSDimitry Andric   // operands, so we definitely don't want to propagate types into the match
376*5f757f3fSDimitry Andric   // patterns as well, otherwise bad things happen.
377*5f757f3fSDimitry Andric   if (InferredAny) {
378*5f757f3fSDimitry Andric     OperandTypeChecker OTC(RuleDef.getLoc());
379*5f757f3fSDimitry Andric     for (auto *Pat : ApplyPats) {
380*5f757f3fSDimitry Andric       if (!OTC.check(*Pat, [&](const auto &) { return true; }))
381*5f757f3fSDimitry Andric         PrintFatalError(RuleDef.getLoc(),
382*5f757f3fSDimitry Andric                         "OperandTypeChecker unexpectedly failed on '" +
383*5f757f3fSDimitry Andric                             Pat->getName() + "' during Type Inference");
384*5f757f3fSDimitry Andric     }
385*5f757f3fSDimitry Andric     OTC.propagateTypes();
386*5f757f3fSDimitry Andric 
387*5f757f3fSDimitry Andric     if (DebugTypeInfer) {
388*5f757f3fSDimitry Andric       errs() << "Apply patterns for rule " << RuleDef.getName()
389*5f757f3fSDimitry Andric              << " after inference:\n";
390*5f757f3fSDimitry Andric       for (auto *Pat : ApplyPats) {
391*5f757f3fSDimitry Andric         errs() << "  ";
392*5f757f3fSDimitry Andric         Pat->print(errs(), /*PrintName*/ true);
393*5f757f3fSDimitry Andric         errs() << '\n';
394*5f757f3fSDimitry Andric       }
395*5f757f3fSDimitry Andric       errs() << '\n';
396*5f757f3fSDimitry Andric     }
397*5f757f3fSDimitry Andric   }
398*5f757f3fSDimitry Andric }
399*5f757f3fSDimitry Andric 
400*5f757f3fSDimitry Andric PatternType CombineRuleOperandTypeChecker::inferImmediateType(
401*5f757f3fSDimitry Andric     const InstructionPattern &IP, unsigned ImmOpIdx,
402*5f757f3fSDimitry Andric     const TypeEquivalenceClasses &TECs) const {
403*5f757f3fSDimitry Andric   // We can only infer CGPs.
404*5f757f3fSDimitry Andric   const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&IP);
405*5f757f3fSDimitry Andric   if (!CGP)
406*5f757f3fSDimitry Andric     return {};
407*5f757f3fSDimitry Andric 
408*5f757f3fSDimitry Andric   // For CGPs, we try to infer immediates by trying to infer another named
409*5f757f3fSDimitry Andric   // operand that shares its type.
410*5f757f3fSDimitry Andric   //
411*5f757f3fSDimitry Andric   // e.g.
412*5f757f3fSDimitry Andric   //    Pattern: G_BUILD_VECTOR $x, $y, 0
413*5f757f3fSDimitry Andric   //    MCOIs:   [MCOI::OPERAND_GENERIC_0, MCOI::OPERAND_GENERIC_1,
414*5f757f3fSDimitry Andric   //              MCOI::OPERAND_GENERIC_1]
415*5f757f3fSDimitry Andric   //    $y has the same type as 0, so we can infer $y and get the type 0 should
416*5f757f3fSDimitry Andric   //    have.
417*5f757f3fSDimitry Andric 
418*5f757f3fSDimitry Andric   // We infer immediates by looking for a named operand that shares the same
419*5f757f3fSDimitry Andric   // MCOI type.
420*5f757f3fSDimitry Andric   const auto MCOITypes = getMCOIOperandTypes(*CGP);
421*5f757f3fSDimitry Andric   StringRef ImmOpTy = MCOITypes[ImmOpIdx];
422*5f757f3fSDimitry Andric 
423*5f757f3fSDimitry Andric   for (const auto &[Idx, Ty] : enumerate(MCOITypes)) {
424*5f757f3fSDimitry Andric     if (Idx != ImmOpIdx && Ty == ImmOpTy) {
425*5f757f3fSDimitry Andric       const auto &Op = IP.getOperand(Idx);
426*5f757f3fSDimitry Andric       if (!Op.isNamedOperand())
427*5f757f3fSDimitry Andric         continue;
428*5f757f3fSDimitry Andric 
429*5f757f3fSDimitry Andric       // Named operand with the same name, try to infer that.
430*5f757f3fSDimitry Andric       if (PatternType InferTy =
431*5f757f3fSDimitry Andric               inferNamedOperandType(IP, Op.getOperandName(), TECs))
432*5f757f3fSDimitry Andric         return InferTy;
433*5f757f3fSDimitry Andric     }
434*5f757f3fSDimitry Andric   }
435*5f757f3fSDimitry Andric 
436*5f757f3fSDimitry Andric   return {};
437*5f757f3fSDimitry Andric }
438*5f757f3fSDimitry Andric 
439*5f757f3fSDimitry Andric PatternType CombineRuleOperandTypeChecker::inferNamedOperandType(
440*5f757f3fSDimitry Andric     const InstructionPattern &IP, StringRef OpName,
441*5f757f3fSDimitry Andric     const TypeEquivalenceClasses &TECs) const {
442*5f757f3fSDimitry Andric   // This is the simplest possible case, we just need to find a TEC that
443*5f757f3fSDimitry Andric   // contains OpName. Look at all other operands in equivalence class and try to
444*5f757f3fSDimitry Andric   // find a suitable one.
445*5f757f3fSDimitry Andric 
446*5f757f3fSDimitry Andric   // Check for a def of a matched pattern. This is guaranteed to always
447*5f757f3fSDimitry Andric   // be a register so we can blindly use that.
448*5f757f3fSDimitry Andric   StringRef GoodOpName;
449*5f757f3fSDimitry Andric   for (auto It = TECs.findLeader(OpName); It != TECs.member_end(); ++It) {
450*5f757f3fSDimitry Andric     if (*It == OpName)
451*5f757f3fSDimitry Andric       continue;
452*5f757f3fSDimitry Andric 
453*5f757f3fSDimitry Andric     const auto LookupRes = MatchOpTable.lookup(*It);
454*5f757f3fSDimitry Andric     if (LookupRes.Def) // Favor defs
455*5f757f3fSDimitry Andric       return PatternType::getTypeOf(*It);
456*5f757f3fSDimitry Andric 
457*5f757f3fSDimitry Andric     // Otherwise just save this in case we don't find any def.
458*5f757f3fSDimitry Andric     if (GoodOpName.empty() && LookupRes.Found)
459*5f757f3fSDimitry Andric       GoodOpName = *It;
460*5f757f3fSDimitry Andric   }
461*5f757f3fSDimitry Andric 
462*5f757f3fSDimitry Andric   if (!GoodOpName.empty())
463*5f757f3fSDimitry Andric     return PatternType::getTypeOf(GoodOpName);
464*5f757f3fSDimitry Andric 
465*5f757f3fSDimitry Andric   // No good operand found, give up.
466*5f757f3fSDimitry Andric   return {};
467*5f757f3fSDimitry Andric }
468*5f757f3fSDimitry Andric 
469*5f757f3fSDimitry Andric std::vector<std::string> CombineRuleOperandTypeChecker::getMCOIOperandTypes(
470*5f757f3fSDimitry Andric     const CodeGenInstructionPattern &CGP) {
471*5f757f3fSDimitry Andric   // FIXME?: Should we cache this? We call it twice when inferring immediates.
472*5f757f3fSDimitry Andric 
473*5f757f3fSDimitry Andric   static unsigned UnknownTypeIdx = 0;
474*5f757f3fSDimitry Andric 
475*5f757f3fSDimitry Andric   std::vector<std::string> OpTypes;
476*5f757f3fSDimitry Andric   auto &CGI = CGP.getInst();
477*5f757f3fSDimitry Andric   Record *VarArgsTy = CGI.TheDef->isSubClassOf("GenericInstruction")
478*5f757f3fSDimitry Andric                           ? CGI.TheDef->getValueAsOptionalDef("variadicOpsType")
479*5f757f3fSDimitry Andric                           : nullptr;
480*5f757f3fSDimitry Andric   std::string VarArgsTyName =
481*5f757f3fSDimitry Andric       VarArgsTy ? ("MCOI::" + VarArgsTy->getValueAsString("OperandType")).str()
482*5f757f3fSDimitry Andric                 : ("unknown_type_" + Twine(UnknownTypeIdx++)).str();
483*5f757f3fSDimitry Andric 
484*5f757f3fSDimitry Andric   // First, handle defs.
485*5f757f3fSDimitry Andric   for (unsigned K = 0; K < CGI.Operands.NumDefs; ++K)
486*5f757f3fSDimitry Andric     OpTypes.push_back(CGI.Operands[K].OperandType);
487*5f757f3fSDimitry Andric 
488*5f757f3fSDimitry Andric   // Then, handle variadic defs if there are any.
489*5f757f3fSDimitry Andric   if (CGP.hasVariadicDefs()) {
490*5f757f3fSDimitry Andric     for (unsigned K = CGI.Operands.NumDefs; K < CGP.getNumInstDefs(); ++K)
491*5f757f3fSDimitry Andric       OpTypes.push_back(VarArgsTyName);
492*5f757f3fSDimitry Andric   }
493*5f757f3fSDimitry Andric 
494*5f757f3fSDimitry Andric   // If we had variadic defs, the op idx in the pattern won't match the op idx
495*5f757f3fSDimitry Andric   // in the CGI anymore.
496*5f757f3fSDimitry Andric   int CGIOpOffset = int(CGI.Operands.NumDefs) - CGP.getNumInstDefs();
497*5f757f3fSDimitry Andric   assert(CGP.hasVariadicDefs() ? (CGIOpOffset <= 0) : (CGIOpOffset == 0));
498*5f757f3fSDimitry Andric 
499*5f757f3fSDimitry Andric   // Handle all remaining use operands, including variadic ones.
500*5f757f3fSDimitry Andric   for (unsigned K = CGP.getNumInstDefs(); K < CGP.getNumInstOperands(); ++K) {
501*5f757f3fSDimitry Andric     unsigned CGIOpIdx = K + CGIOpOffset;
502*5f757f3fSDimitry Andric     if (CGIOpIdx >= CGI.Operands.size()) {
503*5f757f3fSDimitry Andric       assert(CGP.isVariadic());
504*5f757f3fSDimitry Andric       OpTypes.push_back(VarArgsTyName);
505*5f757f3fSDimitry Andric     } else {
506*5f757f3fSDimitry Andric       OpTypes.push_back(CGI.Operands[CGIOpIdx].OperandType);
507*5f757f3fSDimitry Andric     }
508*5f757f3fSDimitry Andric   }
509*5f757f3fSDimitry Andric 
510*5f757f3fSDimitry Andric   assert(OpTypes.size() == CGP.operands_size());
511*5f757f3fSDimitry Andric   return OpTypes;
512*5f757f3fSDimitry Andric }
513*5f757f3fSDimitry Andric 
514*5f757f3fSDimitry Andric void CombineRuleOperandTypeChecker::getInstEqClasses(
515*5f757f3fSDimitry Andric     const InstructionPattern &P, TypeEquivalenceClasses &OutTECs) const {
516*5f757f3fSDimitry Andric   // Determine the TypeEquivalenceClasses by:
517*5f757f3fSDimitry Andric   //    - Getting the MCOI Operand Types.
518*5f757f3fSDimitry Andric   //    - Creating a Map of MCOI Type -> [Operand Indexes]
519*5f757f3fSDimitry Andric   //    - Iterating over the map, filtering types we don't like, and just adding
520*5f757f3fSDimitry Andric   //      the array of Operand Indexes to \p OutTECs.
521*5f757f3fSDimitry Andric 
522*5f757f3fSDimitry Andric   // We can only do this on CodeGenInstructions. Other InstructionPatterns have
523*5f757f3fSDimitry Andric   // no type inference information associated with them.
524*5f757f3fSDimitry Andric   // TODO: Could we add some inference information to builtins at least? e.g.
525*5f757f3fSDimitry Andric   // ReplaceReg should always replace with a reg of the same type, for instance.
526*5f757f3fSDimitry Andric   // Though, those patterns are often used alone so it might not be worth the
527*5f757f3fSDimitry Andric   // trouble to infer their types.
528*5f757f3fSDimitry Andric   auto *CGP = dyn_cast<CodeGenInstructionPattern>(&P);
529*5f757f3fSDimitry Andric   if (!CGP)
530*5f757f3fSDimitry Andric     return;
531*5f757f3fSDimitry Andric 
532*5f757f3fSDimitry Andric   const auto MCOITypes = getMCOIOperandTypes(*CGP);
533*5f757f3fSDimitry Andric   assert(MCOITypes.size() == P.operands_size());
534*5f757f3fSDimitry Andric 
535*5f757f3fSDimitry Andric   DenseMap<StringRef, std::vector<unsigned>> TyToOpIdx;
536*5f757f3fSDimitry Andric   for (const auto &[Idx, Ty] : enumerate(MCOITypes))
537*5f757f3fSDimitry Andric     TyToOpIdx[Ty].push_back(Idx);
538*5f757f3fSDimitry Andric 
539*5f757f3fSDimitry Andric   if (DebugTypeInfer)
540*5f757f3fSDimitry Andric     errs() << "\tGroups for " << P.getName() << ":\t";
541*5f757f3fSDimitry Andric 
542*5f757f3fSDimitry Andric   for (const auto &[Ty, Idxs] : TyToOpIdx) {
543*5f757f3fSDimitry Andric     if (!canMCOIOperandTypeBeARegister(Ty))
544*5f757f3fSDimitry Andric       continue;
545*5f757f3fSDimitry Andric 
546*5f757f3fSDimitry Andric     if (DebugTypeInfer)
547*5f757f3fSDimitry Andric       errs() << '[';
548*5f757f3fSDimitry Andric     StringRef Sep = "";
549*5f757f3fSDimitry Andric 
550*5f757f3fSDimitry Andric     // We only collect named operands.
551*5f757f3fSDimitry Andric     StringRef Leader;
552*5f757f3fSDimitry Andric     for (unsigned Idx : Idxs) {
553*5f757f3fSDimitry Andric       const auto &Op = P.getOperand(Idx);
554*5f757f3fSDimitry Andric       if (!Op.isNamedOperand())
555*5f757f3fSDimitry Andric         continue;
556*5f757f3fSDimitry Andric 
557*5f757f3fSDimitry Andric       const auto OpName = Op.getOperandName();
558*5f757f3fSDimitry Andric       if (DebugTypeInfer) {
559*5f757f3fSDimitry Andric         errs() << Sep << OpName;
560*5f757f3fSDimitry Andric         Sep = ", ";
561*5f757f3fSDimitry Andric       }
562*5f757f3fSDimitry Andric 
563*5f757f3fSDimitry Andric       if (Leader.empty())
564*5f757f3fSDimitry Andric         OutTECs.insert((Leader = OpName));
565*5f757f3fSDimitry Andric       else
566*5f757f3fSDimitry Andric         OutTECs.unionSets(Leader, OpName);
567*5f757f3fSDimitry Andric     }
568*5f757f3fSDimitry Andric 
569*5f757f3fSDimitry Andric     if (DebugTypeInfer)
570*5f757f3fSDimitry Andric       errs() << "] ";
571*5f757f3fSDimitry Andric   }
572*5f757f3fSDimitry Andric 
573*5f757f3fSDimitry Andric   if (DebugTypeInfer)
574*5f757f3fSDimitry Andric     errs() << '\n';
575*5f757f3fSDimitry Andric }
576*5f757f3fSDimitry Andric 
577*5f757f3fSDimitry Andric CombineRuleOperandTypeChecker::TypeEquivalenceClasses
578*5f757f3fSDimitry Andric CombineRuleOperandTypeChecker::getRuleEqClasses() const {
579*5f757f3fSDimitry Andric   StringMap<unsigned> OpNameToEqClassIdx;
580*5f757f3fSDimitry Andric   TypeEquivalenceClasses TECs;
581*5f757f3fSDimitry Andric 
582*5f757f3fSDimitry Andric   if (DebugTypeInfer)
583*5f757f3fSDimitry Andric     errs() << "Rule Operand Type Equivalence Classes for " << RuleDef.getName()
584*5f757f3fSDimitry Andric            << ":\n";
585*5f757f3fSDimitry Andric 
586*5f757f3fSDimitry Andric   for (const auto *Pat : MatchPats)
587*5f757f3fSDimitry Andric     getInstEqClasses(*Pat, TECs);
588*5f757f3fSDimitry Andric   for (const auto *Pat : ApplyPats)
589*5f757f3fSDimitry Andric     getInstEqClasses(*Pat, TECs);
590*5f757f3fSDimitry Andric 
591*5f757f3fSDimitry Andric   if (DebugTypeInfer) {
592*5f757f3fSDimitry Andric     errs() << "Final Type Equivalence Classes: ";
593*5f757f3fSDimitry Andric     for (auto ClassIt = TECs.begin(); ClassIt != TECs.end(); ++ClassIt) {
594*5f757f3fSDimitry Andric       // only print non-empty classes.
595*5f757f3fSDimitry Andric       if (auto MembIt = TECs.member_begin(ClassIt);
596*5f757f3fSDimitry Andric           MembIt != TECs.member_end()) {
597*5f757f3fSDimitry Andric         errs() << '[';
598*5f757f3fSDimitry Andric         StringRef Sep = "";
599*5f757f3fSDimitry Andric         for (; MembIt != TECs.member_end(); ++MembIt) {
600*5f757f3fSDimitry Andric           errs() << Sep << *MembIt;
601*5f757f3fSDimitry Andric           Sep = ", ";
602*5f757f3fSDimitry Andric         }
603*5f757f3fSDimitry Andric         errs() << "] ";
604*5f757f3fSDimitry Andric       }
605*5f757f3fSDimitry Andric     }
606*5f757f3fSDimitry Andric     errs() << '\n';
607*5f757f3fSDimitry Andric   }
608*5f757f3fSDimitry Andric 
609*5f757f3fSDimitry Andric   return TECs;
610*5f757f3fSDimitry Andric }
611*5f757f3fSDimitry Andric 
612*5f757f3fSDimitry Andric //===- CombineRuleBuilder -------------------------------------------------===//
613*5f757f3fSDimitry Andric 
614*5f757f3fSDimitry Andric /// Parses combine rule and builds a small intermediate representation to tie
615*5f757f3fSDimitry Andric /// patterns together and emit RuleMatchers to match them. This may emit more
616*5f757f3fSDimitry Andric /// than one RuleMatcher, e.g. for `wip_match_opcode`.
617*5f757f3fSDimitry Andric ///
618*5f757f3fSDimitry Andric /// Memory management for `Pattern` objects is done through `std::unique_ptr`.
619*5f757f3fSDimitry Andric /// In most cases, there are two stages to a pattern's lifetime:
620*5f757f3fSDimitry Andric ///   - Creation in a `parse` function
621*5f757f3fSDimitry Andric ///     - The unique_ptr is stored in a variable, and may be destroyed if the
622*5f757f3fSDimitry Andric ///       pattern is found to be semantically invalid.
623*5f757f3fSDimitry Andric ///   - Ownership transfer into a `PatternMap`
624*5f757f3fSDimitry Andric ///     - Once a pattern is moved into either the map of Match or Apply
625*5f757f3fSDimitry Andric ///       patterns, it is known to be valid and it never moves back.
626*5f757f3fSDimitry Andric class CombineRuleBuilder {
627*5f757f3fSDimitry Andric public:
628*5f757f3fSDimitry Andric   using PatternMap = MapVector<StringRef, std::unique_ptr<Pattern>>;
629*5f757f3fSDimitry Andric   using PatternAlternatives = DenseMap<const Pattern *, unsigned>;
630*5f757f3fSDimitry Andric 
631*5f757f3fSDimitry Andric   CombineRuleBuilder(const CodeGenTarget &CGT,
632*5f757f3fSDimitry Andric                      SubtargetFeatureInfoMap &SubtargetFeatures,
633*5f757f3fSDimitry Andric                      Record &RuleDef, unsigned ID,
634*5f757f3fSDimitry Andric                      std::vector<RuleMatcher> &OutRMs)
635*5f757f3fSDimitry Andric       : CGT(CGT), SubtargetFeatures(SubtargetFeatures), RuleDef(RuleDef),
636*5f757f3fSDimitry Andric         RuleID(ID), OutRMs(OutRMs) {}
637*5f757f3fSDimitry Andric 
638*5f757f3fSDimitry Andric   /// Parses all fields in the RuleDef record.
639*5f757f3fSDimitry Andric   bool parseAll();
640*5f757f3fSDimitry Andric 
641*5f757f3fSDimitry Andric   /// Emits all RuleMatchers into the vector of RuleMatchers passed in the
642*5f757f3fSDimitry Andric   /// constructor.
643*5f757f3fSDimitry Andric   bool emitRuleMatchers();
644*5f757f3fSDimitry Andric 
645*5f757f3fSDimitry Andric   void print(raw_ostream &OS) const;
646*5f757f3fSDimitry Andric   void dump() const { print(dbgs()); }
647*5f757f3fSDimitry Andric 
648*5f757f3fSDimitry Andric   /// Debug-only verification of invariants.
649*5f757f3fSDimitry Andric #ifndef NDEBUG
650*5f757f3fSDimitry Andric   void verify() const;
651*5f757f3fSDimitry Andric #endif
652*5f757f3fSDimitry Andric 
653*5f757f3fSDimitry Andric private:
654*5f757f3fSDimitry Andric   const CodeGenInstruction &getGConstant() const {
655*5f757f3fSDimitry Andric     return CGT.getInstruction(RuleDef.getRecords().getDef("G_CONSTANT"));
656*5f757f3fSDimitry Andric   }
657*5f757f3fSDimitry Andric 
658*5f757f3fSDimitry Andric   void PrintError(Twine Msg) const { ::PrintError(&RuleDef, Msg); }
659*5f757f3fSDimitry Andric   void PrintWarning(Twine Msg) const { ::PrintWarning(RuleDef.getLoc(), Msg); }
660*5f757f3fSDimitry Andric   void PrintNote(Twine Msg) const { ::PrintNote(RuleDef.getLoc(), Msg); }
661*5f757f3fSDimitry Andric 
662*5f757f3fSDimitry Andric   void print(raw_ostream &OS, const PatternAlternatives &Alts) const;
663*5f757f3fSDimitry Andric 
664*5f757f3fSDimitry Andric   bool addApplyPattern(std::unique_ptr<Pattern> Pat);
665*5f757f3fSDimitry Andric   bool addMatchPattern(std::unique_ptr<Pattern> Pat);
666*5f757f3fSDimitry Andric 
667*5f757f3fSDimitry Andric   /// Adds the expansions from \see MatchDatas to \p CE.
668*5f757f3fSDimitry Andric   void declareAllMatchDatasExpansions(CodeExpansions &CE) const;
669*5f757f3fSDimitry Andric 
670*5f757f3fSDimitry Andric   /// Adds a matcher \p P to \p IM, expanding its code using \p CE.
671*5f757f3fSDimitry Andric   /// Note that the predicate is added on the last InstructionMatcher.
672*5f757f3fSDimitry Andric   ///
673*5f757f3fSDimitry Andric   /// \p Alts is only used if DebugCXXPreds is enabled.
674*5f757f3fSDimitry Andric   void addCXXPredicate(RuleMatcher &M, const CodeExpansions &CE,
675*5f757f3fSDimitry Andric                        const CXXPattern &P, const PatternAlternatives &Alts);
676*5f757f3fSDimitry Andric 
677*5f757f3fSDimitry Andric   /// Adds an apply \p P to \p IM, expanding its code using \p CE.
678*5f757f3fSDimitry Andric   void addCXXAction(RuleMatcher &M, const CodeExpansions &CE,
679*5f757f3fSDimitry Andric                     const CXXPattern &P);
680*5f757f3fSDimitry Andric 
681*5f757f3fSDimitry Andric   bool hasOnlyCXXApplyPatterns() const;
682*5f757f3fSDimitry Andric   bool hasEraseRoot() const;
683*5f757f3fSDimitry Andric 
684*5f757f3fSDimitry Andric   // Infer machine operand types and check their consistency.
685*5f757f3fSDimitry Andric   bool typecheckPatterns();
686*5f757f3fSDimitry Andric 
687*5f757f3fSDimitry Andric   /// For all PatFragPatterns, add a new entry in PatternAlternatives for each
688*5f757f3fSDimitry Andric   /// PatternList it contains. This is multiplicative, so if we have 2
689*5f757f3fSDimitry Andric   /// PatFrags with 3 alternatives each, we get 2*3 permutations added to
690*5f757f3fSDimitry Andric   /// PermutationsToEmit. The "MaxPermutations" field controls how many
691*5f757f3fSDimitry Andric   /// permutations are allowed before an error is emitted and this function
692*5f757f3fSDimitry Andric   /// returns false. This is a simple safeguard to prevent combination of
693*5f757f3fSDimitry Andric   /// PatFrags from generating enormous amounts of rules.
694*5f757f3fSDimitry Andric   bool buildPermutationsToEmit();
695*5f757f3fSDimitry Andric 
696*5f757f3fSDimitry Andric   /// Checks additional semantics of the Patterns.
697*5f757f3fSDimitry Andric   bool checkSemantics();
698*5f757f3fSDimitry Andric 
699*5f757f3fSDimitry Andric   /// Creates a new RuleMatcher with some boilerplate
700*5f757f3fSDimitry Andric   /// settings/actions/predicates, and and adds it to \p OutRMs.
701*5f757f3fSDimitry Andric   /// \see addFeaturePredicates too.
702*5f757f3fSDimitry Andric   ///
703*5f757f3fSDimitry Andric   /// \param Alts Current set of alternatives, for debug comment.
704*5f757f3fSDimitry Andric   /// \param AdditionalComment Comment string to be added to the
705*5f757f3fSDimitry Andric   ///        `DebugCommentAction`.
706*5f757f3fSDimitry Andric   RuleMatcher &addRuleMatcher(const PatternAlternatives &Alts,
707*5f757f3fSDimitry Andric                               Twine AdditionalComment = "");
708*5f757f3fSDimitry Andric   bool addFeaturePredicates(RuleMatcher &M);
709*5f757f3fSDimitry Andric 
710*5f757f3fSDimitry Andric   bool findRoots();
711*5f757f3fSDimitry Andric   bool buildRuleOperandsTable();
712*5f757f3fSDimitry Andric 
713*5f757f3fSDimitry Andric   bool parseDefs(const DagInit &Def);
714*5f757f3fSDimitry Andric   bool
715*5f757f3fSDimitry Andric   parsePatternList(const DagInit &List,
716*5f757f3fSDimitry Andric                    function_ref<bool(std::unique_ptr<Pattern>)> ParseAction,
717*5f757f3fSDimitry Andric                    StringRef Operator, ArrayRef<SMLoc> DiagLoc,
718*5f757f3fSDimitry Andric                    StringRef AnonPatNamePrefix) const;
719*5f757f3fSDimitry Andric 
720*5f757f3fSDimitry Andric   std::unique_ptr<Pattern> parseInstructionPattern(const Init &Arg,
721*5f757f3fSDimitry Andric                                                    StringRef PatName) const;
722*5f757f3fSDimitry Andric   std::unique_ptr<Pattern> parseWipMatchOpcodeMatcher(const Init &Arg,
723*5f757f3fSDimitry Andric                                                       StringRef PatName) const;
724*5f757f3fSDimitry Andric   bool parseInstructionPatternOperand(InstructionPattern &IP,
725*5f757f3fSDimitry Andric                                       const Init *OpInit,
726*5f757f3fSDimitry Andric                                       const StringInit *OpName) const;
727*5f757f3fSDimitry Andric   bool parseInstructionPatternMIFlags(InstructionPattern &IP,
728*5f757f3fSDimitry Andric                                       const DagInit *Op) const;
729*5f757f3fSDimitry Andric   std::unique_ptr<PatFrag> parsePatFragImpl(const Record *Def) const;
730*5f757f3fSDimitry Andric   bool parsePatFragParamList(
731*5f757f3fSDimitry Andric       ArrayRef<SMLoc> DiagLoc, const DagInit &OpsList,
732*5f757f3fSDimitry Andric       function_ref<bool(StringRef, PatFrag::ParamKind)> ParseAction) const;
733*5f757f3fSDimitry Andric   const PatFrag *parsePatFrag(const Record *Def) const;
734*5f757f3fSDimitry Andric 
735*5f757f3fSDimitry Andric   bool emitMatchPattern(CodeExpansions &CE, const PatternAlternatives &Alts,
736*5f757f3fSDimitry Andric                         const InstructionPattern &IP);
737*5f757f3fSDimitry Andric   bool emitMatchPattern(CodeExpansions &CE, const PatternAlternatives &Alts,
738*5f757f3fSDimitry Andric                         const AnyOpcodePattern &AOP);
739*5f757f3fSDimitry Andric 
740*5f757f3fSDimitry Andric   bool emitPatFragMatchPattern(CodeExpansions &CE,
741*5f757f3fSDimitry Andric                                const PatternAlternatives &Alts, RuleMatcher &RM,
742*5f757f3fSDimitry Andric                                InstructionMatcher *IM,
743*5f757f3fSDimitry Andric                                const PatFragPattern &PFP,
744*5f757f3fSDimitry Andric                                DenseSet<const Pattern *> &SeenPats);
745*5f757f3fSDimitry Andric 
746*5f757f3fSDimitry Andric   bool emitApplyPatterns(CodeExpansions &CE, RuleMatcher &M);
747*5f757f3fSDimitry Andric 
748*5f757f3fSDimitry Andric   // Recursively visits InstructionPatterns from P to build up the
749*5f757f3fSDimitry Andric   // RuleMatcher actions.
750*5f757f3fSDimitry Andric   bool emitInstructionApplyPattern(CodeExpansions &CE, RuleMatcher &M,
751*5f757f3fSDimitry Andric                                    const InstructionPattern &P,
752*5f757f3fSDimitry Andric                                    DenseSet<const Pattern *> &SeenPats,
753*5f757f3fSDimitry Andric                                    StringMap<unsigned> &OperandToTempRegID);
754*5f757f3fSDimitry Andric 
755*5f757f3fSDimitry Andric   bool emitCodeGenInstructionApplyImmOperand(RuleMatcher &M,
756*5f757f3fSDimitry Andric                                              BuildMIAction &DstMI,
757*5f757f3fSDimitry Andric                                              const CodeGenInstructionPattern &P,
758*5f757f3fSDimitry Andric                                              const InstructionOperand &O);
759*5f757f3fSDimitry Andric 
760*5f757f3fSDimitry Andric   bool emitBuiltinApplyPattern(CodeExpansions &CE, RuleMatcher &M,
761*5f757f3fSDimitry Andric                                const BuiltinPattern &P,
762*5f757f3fSDimitry Andric                                StringMap<unsigned> &OperandToTempRegID);
763*5f757f3fSDimitry Andric 
764*5f757f3fSDimitry Andric   // Recursively visits CodeGenInstructionPattern from P to build up the
765*5f757f3fSDimitry Andric   // RuleMatcher/InstructionMatcher. May create new InstructionMatchers as
766*5f757f3fSDimitry Andric   // needed.
767*5f757f3fSDimitry Andric   using OperandMapperFnRef =
768*5f757f3fSDimitry Andric       function_ref<InstructionOperand(const InstructionOperand &)>;
769*5f757f3fSDimitry Andric   using OperandDefLookupFn =
770*5f757f3fSDimitry Andric       function_ref<const InstructionPattern *(StringRef)>;
771*5f757f3fSDimitry Andric   bool emitCodeGenInstructionMatchPattern(
772*5f757f3fSDimitry Andric       CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &M,
773*5f757f3fSDimitry Andric       InstructionMatcher &IM, const CodeGenInstructionPattern &P,
774*5f757f3fSDimitry Andric       DenseSet<const Pattern *> &SeenPats, OperandDefLookupFn LookupOperandDef,
775*5f757f3fSDimitry Andric       OperandMapperFnRef OperandMapper = [](const auto &O) { return O; });
776*5f757f3fSDimitry Andric 
777*5f757f3fSDimitry Andric   const CodeGenTarget &CGT;
778*5f757f3fSDimitry Andric   SubtargetFeatureInfoMap &SubtargetFeatures;
779*5f757f3fSDimitry Andric   Record &RuleDef;
780*5f757f3fSDimitry Andric   const unsigned RuleID;
781*5f757f3fSDimitry Andric   std::vector<RuleMatcher> &OutRMs;
782*5f757f3fSDimitry Andric 
783*5f757f3fSDimitry Andric   // For InstructionMatcher::addOperand
784*5f757f3fSDimitry Andric   unsigned AllocatedTemporariesBaseID = 0;
785*5f757f3fSDimitry Andric 
786*5f757f3fSDimitry Andric   /// The root of the pattern.
787*5f757f3fSDimitry Andric   StringRef RootName;
788*5f757f3fSDimitry Andric 
789*5f757f3fSDimitry Andric   /// These maps have ownership of the actual Pattern objects.
790*5f757f3fSDimitry Andric   /// They both map a Pattern's name to the Pattern instance.
791*5f757f3fSDimitry Andric   PatternMap MatchPats;
792*5f757f3fSDimitry Andric   PatternMap ApplyPats;
793*5f757f3fSDimitry Andric 
794*5f757f3fSDimitry Andric   /// Operand tables to tie match/apply patterns together.
795*5f757f3fSDimitry Andric   OperandTable MatchOpTable;
796*5f757f3fSDimitry Andric   OperandTable ApplyOpTable;
797*5f757f3fSDimitry Andric 
798*5f757f3fSDimitry Andric   /// Set by findRoots.
799*5f757f3fSDimitry Andric   Pattern *MatchRoot = nullptr;
800*5f757f3fSDimitry Andric   SmallDenseSet<InstructionPattern *, 2> ApplyRoots;
801*5f757f3fSDimitry Andric 
802*5f757f3fSDimitry Andric   SmallVector<MatchDataInfo, 2> MatchDatas;
803*5f757f3fSDimitry Andric   SmallVector<PatternAlternatives, 1> PermutationsToEmit;
804*5f757f3fSDimitry Andric 
805*5f757f3fSDimitry Andric   // print()/debug-only members.
806*5f757f3fSDimitry Andric   mutable SmallPtrSet<const PatFrag *, 2> SeenPatFrags;
807*5f757f3fSDimitry Andric };
808*5f757f3fSDimitry Andric 
809*5f757f3fSDimitry Andric bool CombineRuleBuilder::parseAll() {
810*5f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceParse(RuleDef);
811*5f757f3fSDimitry Andric 
812*5f757f3fSDimitry Andric   if (!parseDefs(*RuleDef.getValueAsDag("Defs")))
813*5f757f3fSDimitry Andric     return false;
814*5f757f3fSDimitry Andric 
815*5f757f3fSDimitry Andric   if (!parsePatternList(
816*5f757f3fSDimitry Andric           *RuleDef.getValueAsDag("Match"),
817*5f757f3fSDimitry Andric           [this](auto Pat) { return addMatchPattern(std::move(Pat)); }, "match",
818*5f757f3fSDimitry Andric           RuleDef.getLoc(), (RuleDef.getName() + "_match").str()))
819*5f757f3fSDimitry Andric     return false;
820*5f757f3fSDimitry Andric 
821*5f757f3fSDimitry Andric   if (!parsePatternList(
822*5f757f3fSDimitry Andric           *RuleDef.getValueAsDag("Apply"),
823*5f757f3fSDimitry Andric           [this](auto Pat) { return addApplyPattern(std::move(Pat)); }, "apply",
824*5f757f3fSDimitry Andric           RuleDef.getLoc(), (RuleDef.getName() + "_apply").str()))
825*5f757f3fSDimitry Andric     return false;
826*5f757f3fSDimitry Andric 
827*5f757f3fSDimitry Andric   if (!buildRuleOperandsTable() || !typecheckPatterns() || !findRoots() ||
828*5f757f3fSDimitry Andric       !checkSemantics() || !buildPermutationsToEmit())
829*5f757f3fSDimitry Andric     return false;
830*5f757f3fSDimitry Andric   LLVM_DEBUG(verify());
831*5f757f3fSDimitry Andric   return true;
832*5f757f3fSDimitry Andric }
833*5f757f3fSDimitry Andric 
834*5f757f3fSDimitry Andric bool CombineRuleBuilder::emitRuleMatchers() {
835*5f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef);
836*5f757f3fSDimitry Andric 
837*5f757f3fSDimitry Andric   assert(MatchRoot);
838*5f757f3fSDimitry Andric   CodeExpansions CE;
839*5f757f3fSDimitry Andric   declareAllMatchDatasExpansions(CE);
840*5f757f3fSDimitry Andric 
841*5f757f3fSDimitry Andric   assert(!PermutationsToEmit.empty());
842*5f757f3fSDimitry Andric   for (const auto &Alts : PermutationsToEmit) {
843*5f757f3fSDimitry Andric     switch (MatchRoot->getKind()) {
844*5f757f3fSDimitry Andric     case Pattern::K_AnyOpcode: {
845*5f757f3fSDimitry Andric       if (!emitMatchPattern(CE, Alts, *cast<AnyOpcodePattern>(MatchRoot)))
846*5f757f3fSDimitry Andric         return false;
847*5f757f3fSDimitry Andric       break;
848*5f757f3fSDimitry Andric     }
849*5f757f3fSDimitry Andric     case Pattern::K_PatFrag:
850*5f757f3fSDimitry Andric     case Pattern::K_Builtin:
851*5f757f3fSDimitry Andric     case Pattern::K_CodeGenInstruction:
852*5f757f3fSDimitry Andric       if (!emitMatchPattern(CE, Alts, *cast<InstructionPattern>(MatchRoot)))
853*5f757f3fSDimitry Andric         return false;
854*5f757f3fSDimitry Andric       break;
855*5f757f3fSDimitry Andric     case Pattern::K_CXX:
856*5f757f3fSDimitry Andric       PrintError("C++ code cannot be the root of a rule!");
857*5f757f3fSDimitry Andric       return false;
858*5f757f3fSDimitry Andric     default:
859*5f757f3fSDimitry Andric       llvm_unreachable("unknown pattern kind!");
860*5f757f3fSDimitry Andric     }
861*5f757f3fSDimitry Andric   }
862*5f757f3fSDimitry Andric 
863*5f757f3fSDimitry Andric   return true;
864*5f757f3fSDimitry Andric }
865*5f757f3fSDimitry Andric 
866*5f757f3fSDimitry Andric void CombineRuleBuilder::print(raw_ostream &OS) const {
867*5f757f3fSDimitry Andric   OS << "(CombineRule name:" << RuleDef.getName() << " id:" << RuleID
868*5f757f3fSDimitry Andric      << " root:" << RootName << '\n';
869*5f757f3fSDimitry Andric 
870*5f757f3fSDimitry Andric   if (!MatchDatas.empty()) {
871*5f757f3fSDimitry Andric     OS << "  (MatchDatas\n";
872*5f757f3fSDimitry Andric     for (const auto &MD : MatchDatas) {
873*5f757f3fSDimitry Andric       OS << "    ";
874*5f757f3fSDimitry Andric       MD.print(OS);
875*5f757f3fSDimitry Andric       OS << '\n';
876*5f757f3fSDimitry Andric     }
877*5f757f3fSDimitry Andric     OS << "  )\n";
878*5f757f3fSDimitry Andric   }
879*5f757f3fSDimitry Andric 
880*5f757f3fSDimitry Andric   if (!SeenPatFrags.empty()) {
881*5f757f3fSDimitry Andric     OS << "  (PatFrags\n";
882*5f757f3fSDimitry Andric     for (const auto *PF : SeenPatFrags) {
883*5f757f3fSDimitry Andric       PF->print(OS, /*Indent=*/"    ");
884*5f757f3fSDimitry Andric       OS << '\n';
885*5f757f3fSDimitry Andric     }
886*5f757f3fSDimitry Andric     OS << "  )\n";
887*5f757f3fSDimitry Andric   }
888*5f757f3fSDimitry Andric 
889*5f757f3fSDimitry Andric   const auto DumpPats = [&](StringRef Name, const PatternMap &Pats) {
890*5f757f3fSDimitry Andric     OS << "  (" << Name << " ";
891*5f757f3fSDimitry Andric     if (Pats.empty()) {
892*5f757f3fSDimitry Andric       OS << "<empty>)\n";
893*5f757f3fSDimitry Andric       return;
894*5f757f3fSDimitry Andric     }
895*5f757f3fSDimitry Andric 
896*5f757f3fSDimitry Andric     OS << '\n';
897*5f757f3fSDimitry Andric     for (const auto &[Name, Pat] : Pats) {
898*5f757f3fSDimitry Andric       OS << "    ";
899*5f757f3fSDimitry Andric       if (Pat.get() == MatchRoot)
900*5f757f3fSDimitry Andric         OS << "<match_root>";
901*5f757f3fSDimitry Andric       if (isa<InstructionPattern>(Pat.get()) &&
902*5f757f3fSDimitry Andric           ApplyRoots.contains(cast<InstructionPattern>(Pat.get())))
903*5f757f3fSDimitry Andric         OS << "<apply_root>";
904*5f757f3fSDimitry Andric       OS << Name << ":";
905*5f757f3fSDimitry Andric       Pat->print(OS, /*PrintName=*/false);
906*5f757f3fSDimitry Andric       OS << '\n';
907*5f757f3fSDimitry Andric     }
908*5f757f3fSDimitry Andric     OS << "  )\n";
909*5f757f3fSDimitry Andric   };
910*5f757f3fSDimitry Andric 
911*5f757f3fSDimitry Andric   DumpPats("MatchPats", MatchPats);
912*5f757f3fSDimitry Andric   DumpPats("ApplyPats", ApplyPats);
913*5f757f3fSDimitry Andric 
914*5f757f3fSDimitry Andric   MatchOpTable.print(OS, "MatchPats", /*Indent*/ "  ");
915*5f757f3fSDimitry Andric   ApplyOpTable.print(OS, "ApplyPats", /*Indent*/ "  ");
916*5f757f3fSDimitry Andric 
917*5f757f3fSDimitry Andric   if (PermutationsToEmit.size() > 1) {
918*5f757f3fSDimitry Andric     OS << "  (PermutationsToEmit\n";
919*5f757f3fSDimitry Andric     for (const auto &Perm : PermutationsToEmit) {
920*5f757f3fSDimitry Andric       OS << "    ";
921*5f757f3fSDimitry Andric       print(OS, Perm);
922*5f757f3fSDimitry Andric       OS << ",\n";
923*5f757f3fSDimitry Andric     }
924*5f757f3fSDimitry Andric     OS << "  )\n";
925*5f757f3fSDimitry Andric   }
926*5f757f3fSDimitry Andric 
927*5f757f3fSDimitry Andric   OS << ")\n";
928*5f757f3fSDimitry Andric }
929*5f757f3fSDimitry Andric 
930*5f757f3fSDimitry Andric #ifndef NDEBUG
931*5f757f3fSDimitry Andric void CombineRuleBuilder::verify() const {
932*5f757f3fSDimitry Andric   const auto VerifyPats = [&](const PatternMap &Pats) {
933*5f757f3fSDimitry Andric     for (const auto &[Name, Pat] : Pats) {
934*5f757f3fSDimitry Andric       if (!Pat)
935*5f757f3fSDimitry Andric         PrintFatalError("null pattern in pattern map!");
936*5f757f3fSDimitry Andric 
937*5f757f3fSDimitry Andric       if (Name != Pat->getName()) {
938*5f757f3fSDimitry Andric         Pat->dump();
939*5f757f3fSDimitry Andric         PrintFatalError("Pattern name mismatch! Map name: " + Name +
940*5f757f3fSDimitry Andric                         ", Pat name: " + Pat->getName());
941*5f757f3fSDimitry Andric       }
942*5f757f3fSDimitry Andric 
943*5f757f3fSDimitry Andric       // Sanity check: the map should point to the same data as the Pattern.
944*5f757f3fSDimitry Andric       // Both strings are allocated in the pool using insertStrRef.
945*5f757f3fSDimitry Andric       if (Name.data() != Pat->getName().data()) {
946*5f757f3fSDimitry Andric         dbgs() << "Map StringRef: '" << Name << "' @ "
947*5f757f3fSDimitry Andric                << (const void *)Name.data() << '\n';
948*5f757f3fSDimitry Andric         dbgs() << "Pat String: '" << Pat->getName() << "' @ "
949*5f757f3fSDimitry Andric                << (const void *)Pat->getName().data() << '\n';
950*5f757f3fSDimitry Andric         PrintFatalError("StringRef stored in the PatternMap is not referencing "
951*5f757f3fSDimitry Andric                         "the same string as its Pattern!");
952*5f757f3fSDimitry Andric       }
953*5f757f3fSDimitry Andric     }
954*5f757f3fSDimitry Andric   };
955*5f757f3fSDimitry Andric 
956*5f757f3fSDimitry Andric   VerifyPats(MatchPats);
957*5f757f3fSDimitry Andric   VerifyPats(ApplyPats);
958*5f757f3fSDimitry Andric 
959*5f757f3fSDimitry Andric   // Check there are no wip_match_opcode patterns in the "apply" patterns.
960*5f757f3fSDimitry Andric   if (any_of(ApplyPats,
961*5f757f3fSDimitry Andric              [&](auto &E) { return isa<AnyOpcodePattern>(E.second.get()); })) {
962*5f757f3fSDimitry Andric     dump();
963*5f757f3fSDimitry Andric     PrintFatalError(
964*5f757f3fSDimitry Andric         "illegal wip_match_opcode pattern in the 'apply' patterns!");
965*5f757f3fSDimitry Andric   }
966*5f757f3fSDimitry Andric 
967*5f757f3fSDimitry Andric   // Check there are no nullptrs in ApplyRoots.
968*5f757f3fSDimitry Andric   if (ApplyRoots.contains(nullptr)) {
969*5f757f3fSDimitry Andric     PrintFatalError(
970*5f757f3fSDimitry Andric         "CombineRuleBuilder's ApplyRoots set contains a null pointer!");
971*5f757f3fSDimitry Andric   }
972*5f757f3fSDimitry Andric }
973*5f757f3fSDimitry Andric #endif
974*5f757f3fSDimitry Andric 
975*5f757f3fSDimitry Andric void CombineRuleBuilder::print(raw_ostream &OS,
976*5f757f3fSDimitry Andric                                const PatternAlternatives &Alts) const {
977*5f757f3fSDimitry Andric   SmallVector<std::string, 1> Strings(
978*5f757f3fSDimitry Andric       map_range(Alts, [](const auto &PatAndPerm) {
979*5f757f3fSDimitry Andric         return PatAndPerm.first->getName().str() + "[" +
980*5f757f3fSDimitry Andric                to_string(PatAndPerm.second) + "]";
981*5f757f3fSDimitry Andric       }));
982*5f757f3fSDimitry Andric   // Sort so output is deterministic for tests. Otherwise it's sorted by pointer
983*5f757f3fSDimitry Andric   // values.
984*5f757f3fSDimitry Andric   sort(Strings);
985*5f757f3fSDimitry Andric   OS << "[" << join(Strings, ", ") << "]";
986*5f757f3fSDimitry Andric }
987*5f757f3fSDimitry Andric 
988*5f757f3fSDimitry Andric bool CombineRuleBuilder::addApplyPattern(std::unique_ptr<Pattern> Pat) {
989*5f757f3fSDimitry Andric   StringRef Name = Pat->getName();
990*5f757f3fSDimitry Andric   if (ApplyPats.contains(Name)) {
991*5f757f3fSDimitry Andric     PrintError("'" + Name + "' apply pattern defined more than once!");
992*5f757f3fSDimitry Andric     return false;
993*5f757f3fSDimitry Andric   }
994*5f757f3fSDimitry Andric 
995*5f757f3fSDimitry Andric   if (isa<AnyOpcodePattern>(Pat.get())) {
996*5f757f3fSDimitry Andric     PrintError("'" + Name +
997*5f757f3fSDimitry Andric                "': wip_match_opcode is not supported in apply patterns");
998*5f757f3fSDimitry Andric     return false;
999*5f757f3fSDimitry Andric   }
1000*5f757f3fSDimitry Andric 
1001*5f757f3fSDimitry Andric   if (isa<PatFragPattern>(Pat.get())) {
1002*5f757f3fSDimitry Andric     PrintError("'" + Name + "': using " + PatFrag::ClassName +
1003*5f757f3fSDimitry Andric                " is not supported in apply patterns");
1004*5f757f3fSDimitry Andric     return false;
1005*5f757f3fSDimitry Andric   }
1006*5f757f3fSDimitry Andric 
1007*5f757f3fSDimitry Andric   if (auto *CXXPat = dyn_cast<CXXPattern>(Pat.get()))
1008*5f757f3fSDimitry Andric     CXXPat->setIsApply();
1009*5f757f3fSDimitry Andric 
1010*5f757f3fSDimitry Andric   ApplyPats[Name] = std::move(Pat);
1011*5f757f3fSDimitry Andric   return true;
1012*5f757f3fSDimitry Andric }
1013*5f757f3fSDimitry Andric 
1014*5f757f3fSDimitry Andric bool CombineRuleBuilder::addMatchPattern(std::unique_ptr<Pattern> Pat) {
1015*5f757f3fSDimitry Andric   StringRef Name = Pat->getName();
1016*5f757f3fSDimitry Andric   if (MatchPats.contains(Name)) {
1017*5f757f3fSDimitry Andric     PrintError("'" + Name + "' match pattern defined more than once!");
1018*5f757f3fSDimitry Andric     return false;
1019*5f757f3fSDimitry Andric   }
1020*5f757f3fSDimitry Andric 
1021*5f757f3fSDimitry Andric   // For now, none of the builtins can appear in 'match'.
1022*5f757f3fSDimitry Andric   if (const auto *BP = dyn_cast<BuiltinPattern>(Pat.get())) {
1023*5f757f3fSDimitry Andric     PrintError("'" + BP->getInstName() +
1024*5f757f3fSDimitry Andric                "' cannot be used in a 'match' pattern");
1025*5f757f3fSDimitry Andric     return false;
1026*5f757f3fSDimitry Andric   }
1027*5f757f3fSDimitry Andric 
1028*5f757f3fSDimitry Andric   MatchPats[Name] = std::move(Pat);
1029*5f757f3fSDimitry Andric   return true;
1030*5f757f3fSDimitry Andric }
1031*5f757f3fSDimitry Andric 
1032*5f757f3fSDimitry Andric void CombineRuleBuilder::declareAllMatchDatasExpansions(
1033*5f757f3fSDimitry Andric     CodeExpansions &CE) const {
1034*5f757f3fSDimitry Andric   for (const auto &MD : MatchDatas)
1035*5f757f3fSDimitry Andric     CE.declare(MD.getPatternSymbol(), MD.getQualifiedVariableName());
1036*5f757f3fSDimitry Andric }
1037*5f757f3fSDimitry Andric 
1038*5f757f3fSDimitry Andric void CombineRuleBuilder::addCXXPredicate(RuleMatcher &M,
1039*5f757f3fSDimitry Andric                                          const CodeExpansions &CE,
1040*5f757f3fSDimitry Andric                                          const CXXPattern &P,
1041*5f757f3fSDimitry Andric                                          const PatternAlternatives &Alts) {
1042*5f757f3fSDimitry Andric   // FIXME: Hack so C++ code is executed last. May not work for more complex
1043*5f757f3fSDimitry Andric   // patterns.
1044*5f757f3fSDimitry Andric   auto &IM = *std::prev(M.insnmatchers().end());
1045*5f757f3fSDimitry Andric   auto Loc = RuleDef.getLoc();
1046*5f757f3fSDimitry Andric   const auto AddComment = [&](raw_ostream &OS) {
1047*5f757f3fSDimitry Andric     OS << "// Pattern Alternatives: ";
1048*5f757f3fSDimitry Andric     print(OS, Alts);
1049*5f757f3fSDimitry Andric     OS << '\n';
1050*5f757f3fSDimitry Andric   };
1051*5f757f3fSDimitry Andric   const auto &ExpandedCode =
1052*5f757f3fSDimitry Andric       DebugCXXPreds ? P.expandCode(CE, Loc, AddComment) : P.expandCode(CE, Loc);
1053*5f757f3fSDimitry Andric   IM->addPredicate<GenericInstructionPredicateMatcher>(
1054*5f757f3fSDimitry Andric       ExpandedCode.getEnumNameWithPrefix(CXXPredPrefix));
1055*5f757f3fSDimitry Andric }
1056*5f757f3fSDimitry Andric 
1057*5f757f3fSDimitry Andric void CombineRuleBuilder::addCXXAction(RuleMatcher &M, const CodeExpansions &CE,
1058*5f757f3fSDimitry Andric                                       const CXXPattern &P) {
1059*5f757f3fSDimitry Andric   const auto &ExpandedCode = P.expandCode(CE, RuleDef.getLoc());
1060*5f757f3fSDimitry Andric   M.addAction<CustomCXXAction>(
1061*5f757f3fSDimitry Andric       ExpandedCode.getEnumNameWithPrefix(CXXApplyPrefix));
1062*5f757f3fSDimitry Andric }
1063*5f757f3fSDimitry Andric 
1064*5f757f3fSDimitry Andric bool CombineRuleBuilder::hasOnlyCXXApplyPatterns() const {
1065*5f757f3fSDimitry Andric   return all_of(ApplyPats, [&](auto &Entry) {
1066*5f757f3fSDimitry Andric     return isa<CXXPattern>(Entry.second.get());
1067*5f757f3fSDimitry Andric   });
1068*5f757f3fSDimitry Andric }
1069*5f757f3fSDimitry Andric 
1070*5f757f3fSDimitry Andric bool CombineRuleBuilder::hasEraseRoot() const {
1071*5f757f3fSDimitry Andric   return any_of(ApplyPats, [&](auto &Entry) {
1072*5f757f3fSDimitry Andric     if (const auto *BP = dyn_cast<BuiltinPattern>(Entry.second.get()))
1073*5f757f3fSDimitry Andric       return BP->getBuiltinKind() == BI_EraseRoot;
1074*5f757f3fSDimitry Andric     return false;
1075*5f757f3fSDimitry Andric   });
1076*5f757f3fSDimitry Andric }
1077*5f757f3fSDimitry Andric 
1078*5f757f3fSDimitry Andric bool CombineRuleBuilder::typecheckPatterns() {
1079*5f757f3fSDimitry Andric   CombineRuleOperandTypeChecker OTC(RuleDef, MatchOpTable);
1080*5f757f3fSDimitry Andric 
1081*5f757f3fSDimitry Andric   for (auto &Pat : values(MatchPats)) {
1082*5f757f3fSDimitry Andric     if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
1083*5f757f3fSDimitry Andric       if (!OTC.processMatchPattern(*IP))
1084*5f757f3fSDimitry Andric         return false;
1085*5f757f3fSDimitry Andric     }
1086*5f757f3fSDimitry Andric   }
1087*5f757f3fSDimitry Andric 
1088*5f757f3fSDimitry Andric   for (auto &Pat : values(ApplyPats)) {
1089*5f757f3fSDimitry Andric     if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
1090*5f757f3fSDimitry Andric       if (!OTC.processApplyPattern(*IP))
1091*5f757f3fSDimitry Andric         return false;
1092*5f757f3fSDimitry Andric     }
1093*5f757f3fSDimitry Andric   }
1094*5f757f3fSDimitry Andric 
1095*5f757f3fSDimitry Andric   OTC.propagateAndInferTypes();
1096*5f757f3fSDimitry Andric 
1097*5f757f3fSDimitry Andric   // Always check this after in case inference adds some special types to the
1098*5f757f3fSDimitry Andric   // match patterns.
1099*5f757f3fSDimitry Andric   for (auto &Pat : values(MatchPats)) {
1100*5f757f3fSDimitry Andric     if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
1101*5f757f3fSDimitry Andric       if (IP->diagnoseAllSpecialTypes(
1102*5f757f3fSDimitry Andric               RuleDef.getLoc(), PatternType::SpecialTyClassName +
1103*5f757f3fSDimitry Andric                                     " is not supported in 'match' patterns")) {
1104*5f757f3fSDimitry Andric         return false;
1105*5f757f3fSDimitry Andric       }
1106*5f757f3fSDimitry Andric     }
1107*5f757f3fSDimitry Andric   }
1108*5f757f3fSDimitry Andric   return true;
1109*5f757f3fSDimitry Andric }
1110*5f757f3fSDimitry Andric 
1111*5f757f3fSDimitry Andric bool CombineRuleBuilder::buildPermutationsToEmit() {
1112*5f757f3fSDimitry Andric   PermutationsToEmit.clear();
1113*5f757f3fSDimitry Andric 
1114*5f757f3fSDimitry Andric   // Start with one empty set of alternatives.
1115*5f757f3fSDimitry Andric   PermutationsToEmit.emplace_back();
1116*5f757f3fSDimitry Andric   for (const auto &Pat : values(MatchPats)) {
1117*5f757f3fSDimitry Andric     unsigned NumAlts = 0;
1118*5f757f3fSDimitry Andric     // Note: technically, AnyOpcodePattern also needs permutations, but:
1119*5f757f3fSDimitry Andric     //    - We only allow a single one of them in the root.
1120*5f757f3fSDimitry Andric     //    - They cannot be mixed with any other pattern other than C++ code.
1121*5f757f3fSDimitry Andric     // So we don't really need to take them into account here. We could, but
1122*5f757f3fSDimitry Andric     // that pattern is a hack anyway and the less it's involved, the better.
1123*5f757f3fSDimitry Andric     if (const auto *PFP = dyn_cast<PatFragPattern>(Pat.get()))
1124*5f757f3fSDimitry Andric       NumAlts = PFP->getPatFrag().num_alternatives();
1125*5f757f3fSDimitry Andric     else
1126*5f757f3fSDimitry Andric       continue;
1127*5f757f3fSDimitry Andric 
1128*5f757f3fSDimitry Andric     // For each pattern that needs permutations, multiply the current set of
1129*5f757f3fSDimitry Andric     // alternatives.
1130*5f757f3fSDimitry Andric     auto CurPerms = PermutationsToEmit;
1131*5f757f3fSDimitry Andric     PermutationsToEmit.clear();
1132*5f757f3fSDimitry Andric 
1133*5f757f3fSDimitry Andric     for (const auto &Perm : CurPerms) {
1134*5f757f3fSDimitry Andric       assert(!Perm.count(Pat.get()) && "Pattern already emitted?");
1135*5f757f3fSDimitry Andric       for (unsigned K = 0; K < NumAlts; ++K) {
1136*5f757f3fSDimitry Andric         PatternAlternatives NewPerm = Perm;
1137*5f757f3fSDimitry Andric         NewPerm[Pat.get()] = K;
1138*5f757f3fSDimitry Andric         PermutationsToEmit.emplace_back(std::move(NewPerm));
1139*5f757f3fSDimitry Andric       }
1140*5f757f3fSDimitry Andric     }
1141*5f757f3fSDimitry Andric   }
1142*5f757f3fSDimitry Andric 
1143*5f757f3fSDimitry Andric   if (int64_t MaxPerms = RuleDef.getValueAsInt("MaxPermutations");
1144*5f757f3fSDimitry Andric       MaxPerms > 0) {
1145*5f757f3fSDimitry Andric     if ((int64_t)PermutationsToEmit.size() > MaxPerms) {
1146*5f757f3fSDimitry Andric       PrintError("cannot emit rule '" + RuleDef.getName() + "'; " +
1147*5f757f3fSDimitry Andric                  Twine(PermutationsToEmit.size()) +
1148*5f757f3fSDimitry Andric                  " permutations would be emitted, but the max is " +
1149*5f757f3fSDimitry Andric                  Twine(MaxPerms));
1150*5f757f3fSDimitry Andric       return false;
1151*5f757f3fSDimitry Andric     }
1152*5f757f3fSDimitry Andric   }
1153*5f757f3fSDimitry Andric 
1154*5f757f3fSDimitry Andric   // Ensure we always have a single empty entry, it simplifies the emission
1155*5f757f3fSDimitry Andric   // logic so it doesn't need to handle the case where there are no perms.
1156*5f757f3fSDimitry Andric   if (PermutationsToEmit.empty()) {
1157*5f757f3fSDimitry Andric     PermutationsToEmit.emplace_back();
1158*5f757f3fSDimitry Andric     return true;
1159*5f757f3fSDimitry Andric   }
1160*5f757f3fSDimitry Andric 
1161*5f757f3fSDimitry Andric   return true;
1162*5f757f3fSDimitry Andric }
1163*5f757f3fSDimitry Andric 
1164*5f757f3fSDimitry Andric bool CombineRuleBuilder::checkSemantics() {
1165*5f757f3fSDimitry Andric   assert(MatchRoot && "Cannot call this before findRoots()");
1166*5f757f3fSDimitry Andric 
1167*5f757f3fSDimitry Andric   bool UsesWipMatchOpcode = false;
1168*5f757f3fSDimitry Andric   for (const auto &Match : MatchPats) {
1169*5f757f3fSDimitry Andric     const auto *Pat = Match.second.get();
1170*5f757f3fSDimitry Andric 
1171*5f757f3fSDimitry Andric     if (const auto *CXXPat = dyn_cast<CXXPattern>(Pat)) {
1172*5f757f3fSDimitry Andric       if (!CXXPat->getRawCode().contains("return "))
1173*5f757f3fSDimitry Andric         PrintWarning("'match' C++ code does not seem to return!");
1174*5f757f3fSDimitry Andric       continue;
1175*5f757f3fSDimitry Andric     }
1176*5f757f3fSDimitry Andric 
1177*5f757f3fSDimitry Andric     // MIFlags in match cannot use the following syntax: (MIFlags $mi)
1178*5f757f3fSDimitry Andric     if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(Pat)) {
1179*5f757f3fSDimitry Andric       if (auto *FI = CGP->getMIFlagsInfo()) {
1180*5f757f3fSDimitry Andric         if (!FI->copy_flags().empty()) {
1181*5f757f3fSDimitry Andric           PrintError(
1182*5f757f3fSDimitry Andric               "'match' patterns cannot refer to flags from other instructions");
1183*5f757f3fSDimitry Andric           PrintNote("MIFlags in '" + CGP->getName() +
1184*5f757f3fSDimitry Andric                     "' refer to: " + join(FI->copy_flags(), ", "));
1185*5f757f3fSDimitry Andric           return false;
1186*5f757f3fSDimitry Andric         }
1187*5f757f3fSDimitry Andric       }
1188*5f757f3fSDimitry Andric     }
1189*5f757f3fSDimitry Andric 
1190*5f757f3fSDimitry Andric     const auto *AOP = dyn_cast<AnyOpcodePattern>(Pat);
1191*5f757f3fSDimitry Andric     if (!AOP)
1192*5f757f3fSDimitry Andric       continue;
1193*5f757f3fSDimitry Andric 
1194*5f757f3fSDimitry Andric     if (UsesWipMatchOpcode) {
1195*5f757f3fSDimitry Andric       PrintError("wip_opcode_match can only be present once");
1196*5f757f3fSDimitry Andric       return false;
1197*5f757f3fSDimitry Andric     }
1198*5f757f3fSDimitry Andric 
1199*5f757f3fSDimitry Andric     UsesWipMatchOpcode = true;
1200*5f757f3fSDimitry Andric   }
1201*5f757f3fSDimitry Andric 
1202*5f757f3fSDimitry Andric   for (const auto &Apply : ApplyPats) {
1203*5f757f3fSDimitry Andric     assert(Apply.second.get());
1204*5f757f3fSDimitry Andric     const auto *IP = dyn_cast<InstructionPattern>(Apply.second.get());
1205*5f757f3fSDimitry Andric     if (!IP)
1206*5f757f3fSDimitry Andric       continue;
1207*5f757f3fSDimitry Andric 
1208*5f757f3fSDimitry Andric     if (UsesWipMatchOpcode) {
1209*5f757f3fSDimitry Andric       PrintError("cannot use wip_match_opcode in combination with apply "
1210*5f757f3fSDimitry Andric                  "instruction patterns!");
1211*5f757f3fSDimitry Andric       return false;
1212*5f757f3fSDimitry Andric     }
1213*5f757f3fSDimitry Andric 
1214*5f757f3fSDimitry Andric     // Check that the insts mentioned in copy_flags exist.
1215*5f757f3fSDimitry Andric     if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(IP)) {
1216*5f757f3fSDimitry Andric       if (auto *FI = CGP->getMIFlagsInfo()) {
1217*5f757f3fSDimitry Andric         for (auto InstName : FI->copy_flags()) {
1218*5f757f3fSDimitry Andric           auto It = MatchPats.find(InstName);
1219*5f757f3fSDimitry Andric           if (It == MatchPats.end()) {
1220*5f757f3fSDimitry Andric             PrintError("unknown instruction '$" + InstName +
1221*5f757f3fSDimitry Andric                        "' referenced in MIFlags of '" + CGP->getName() + "'");
1222*5f757f3fSDimitry Andric             return false;
1223*5f757f3fSDimitry Andric           }
1224*5f757f3fSDimitry Andric 
1225*5f757f3fSDimitry Andric           if (!isa<CodeGenInstructionPattern>(It->second.get())) {
1226*5f757f3fSDimitry Andric             PrintError(
1227*5f757f3fSDimitry Andric                 "'$" + InstName +
1228*5f757f3fSDimitry Andric                 "' does not refer to a CodeGenInstruction in MIFlags of '" +
1229*5f757f3fSDimitry Andric                 CGP->getName() + "'");
1230*5f757f3fSDimitry Andric             return false;
1231*5f757f3fSDimitry Andric           }
1232*5f757f3fSDimitry Andric         }
1233*5f757f3fSDimitry Andric       }
1234*5f757f3fSDimitry Andric     }
1235*5f757f3fSDimitry Andric 
1236*5f757f3fSDimitry Andric     const auto *BIP = dyn_cast<BuiltinPattern>(IP);
1237*5f757f3fSDimitry Andric     if (!BIP)
1238*5f757f3fSDimitry Andric       continue;
1239*5f757f3fSDimitry Andric     StringRef Name = BIP->getInstName();
1240*5f757f3fSDimitry Andric 
1241*5f757f3fSDimitry Andric     // (GIEraseInst) has to be the only apply pattern, or it can not be used at
1242*5f757f3fSDimitry Andric     // all. The root cannot have any defs either.
1243*5f757f3fSDimitry Andric     switch (BIP->getBuiltinKind()) {
1244*5f757f3fSDimitry Andric     case BI_EraseRoot: {
1245*5f757f3fSDimitry Andric       if (ApplyPats.size() > 1) {
1246*5f757f3fSDimitry Andric         PrintError(Name + " must be the only 'apply' pattern");
1247*5f757f3fSDimitry Andric         return false;
1248*5f757f3fSDimitry Andric       }
1249*5f757f3fSDimitry Andric 
1250*5f757f3fSDimitry Andric       const auto *IRoot = dyn_cast<CodeGenInstructionPattern>(MatchRoot);
1251*5f757f3fSDimitry Andric       if (!IRoot) {
1252*5f757f3fSDimitry Andric         PrintError(Name +
1253*5f757f3fSDimitry Andric                    " can only be used if the root is a CodeGenInstruction");
1254*5f757f3fSDimitry Andric         return false;
1255*5f757f3fSDimitry Andric       }
1256*5f757f3fSDimitry Andric 
1257*5f757f3fSDimitry Andric       if (IRoot->getNumInstDefs() != 0) {
1258*5f757f3fSDimitry Andric         PrintError(Name + " can only be used if on roots that do "
1259*5f757f3fSDimitry Andric                           "not have any output operand");
1260*5f757f3fSDimitry Andric         PrintNote("'" + IRoot->getInstName() + "' has " +
1261*5f757f3fSDimitry Andric                   Twine(IRoot->getNumInstDefs()) + " output operands");
1262*5f757f3fSDimitry Andric         return false;
1263*5f757f3fSDimitry Andric       }
1264*5f757f3fSDimitry Andric       break;
1265*5f757f3fSDimitry Andric     }
1266*5f757f3fSDimitry Andric     case BI_ReplaceReg: {
1267*5f757f3fSDimitry Andric       // (GIReplaceReg can only be used on the root instruction)
1268*5f757f3fSDimitry Andric       // TODO: When we allow rewriting non-root instructions, also allow this.
1269*5f757f3fSDimitry Andric       StringRef OldRegName = BIP->getOperand(0).getOperandName();
1270*5f757f3fSDimitry Andric       auto *Def = MatchOpTable.getDef(OldRegName);
1271*5f757f3fSDimitry Andric       if (!Def) {
1272*5f757f3fSDimitry Andric         PrintError(Name + " cannot find a matched pattern that defines '" +
1273*5f757f3fSDimitry Andric                    OldRegName + "'");
1274*5f757f3fSDimitry Andric         return false;
1275*5f757f3fSDimitry Andric       }
1276*5f757f3fSDimitry Andric       if (MatchOpTable.getDef(OldRegName) != MatchRoot) {
1277*5f757f3fSDimitry Andric         PrintError(Name + " cannot replace '" + OldRegName +
1278*5f757f3fSDimitry Andric                    "': this builtin can only replace a register defined by the "
1279*5f757f3fSDimitry Andric                    "match root");
1280*5f757f3fSDimitry Andric         return false;
1281*5f757f3fSDimitry Andric       }
1282*5f757f3fSDimitry Andric       break;
1283*5f757f3fSDimitry Andric     }
1284*5f757f3fSDimitry Andric     }
1285*5f757f3fSDimitry Andric   }
1286*5f757f3fSDimitry Andric 
1287*5f757f3fSDimitry Andric   return true;
1288*5f757f3fSDimitry Andric }
1289*5f757f3fSDimitry Andric 
1290*5f757f3fSDimitry Andric RuleMatcher &CombineRuleBuilder::addRuleMatcher(const PatternAlternatives &Alts,
1291*5f757f3fSDimitry Andric                                                 Twine AdditionalComment) {
1292*5f757f3fSDimitry Andric   auto &RM = OutRMs.emplace_back(RuleDef.getLoc());
1293*5f757f3fSDimitry Andric   addFeaturePredicates(RM);
1294*5f757f3fSDimitry Andric   RM.setPermanentGISelFlags(GISF_IgnoreCopies);
1295*5f757f3fSDimitry Andric   RM.addRequiredSimplePredicate(getIsEnabledPredicateEnumName(RuleID));
1296*5f757f3fSDimitry Andric 
1297*5f757f3fSDimitry Andric   std::string Comment;
1298*5f757f3fSDimitry Andric   raw_string_ostream CommentOS(Comment);
1299*5f757f3fSDimitry Andric   CommentOS << "Combiner Rule #" << RuleID << ": " << RuleDef.getName();
1300*5f757f3fSDimitry Andric   if (!Alts.empty()) {
1301*5f757f3fSDimitry Andric     CommentOS << " @ ";
1302*5f757f3fSDimitry Andric     print(CommentOS, Alts);
1303*5f757f3fSDimitry Andric   }
1304*5f757f3fSDimitry Andric   if (!AdditionalComment.isTriviallyEmpty())
1305*5f757f3fSDimitry Andric     CommentOS << "; " << AdditionalComment;
1306*5f757f3fSDimitry Andric   RM.addAction<DebugCommentAction>(Comment);
1307*5f757f3fSDimitry Andric   return RM;
1308*5f757f3fSDimitry Andric }
1309*5f757f3fSDimitry Andric 
1310*5f757f3fSDimitry Andric bool CombineRuleBuilder::addFeaturePredicates(RuleMatcher &M) {
1311*5f757f3fSDimitry Andric   if (!RuleDef.getValue("Predicates"))
1312*5f757f3fSDimitry Andric     return true;
1313*5f757f3fSDimitry Andric 
1314*5f757f3fSDimitry Andric   ListInit *Preds = RuleDef.getValueAsListInit("Predicates");
1315*5f757f3fSDimitry Andric   for (Init *PI : Preds->getValues()) {
1316*5f757f3fSDimitry Andric     DefInit *Pred = dyn_cast<DefInit>(PI);
1317*5f757f3fSDimitry Andric     if (!Pred)
1318*5f757f3fSDimitry Andric       continue;
1319*5f757f3fSDimitry Andric 
1320*5f757f3fSDimitry Andric     Record *Def = Pred->getDef();
1321*5f757f3fSDimitry Andric     if (!Def->isSubClassOf("Predicate")) {
1322*5f757f3fSDimitry Andric       ::PrintError(Def, "Unknown 'Predicate' Type");
1323*5f757f3fSDimitry Andric       return false;
1324*5f757f3fSDimitry Andric     }
1325*5f757f3fSDimitry Andric 
1326*5f757f3fSDimitry Andric     if (Def->getValueAsString("CondString").empty())
1327*5f757f3fSDimitry Andric       continue;
1328*5f757f3fSDimitry Andric 
1329*5f757f3fSDimitry Andric     if (SubtargetFeatures.count(Def) == 0) {
1330*5f757f3fSDimitry Andric       SubtargetFeatures.emplace(
1331*5f757f3fSDimitry Andric           Def, SubtargetFeatureInfo(Def, SubtargetFeatures.size()));
1332*5f757f3fSDimitry Andric     }
1333*5f757f3fSDimitry Andric 
1334*5f757f3fSDimitry Andric     M.addRequiredFeature(Def);
1335*5f757f3fSDimitry Andric   }
1336*5f757f3fSDimitry Andric 
1337*5f757f3fSDimitry Andric   return true;
1338*5f757f3fSDimitry Andric }
1339*5f757f3fSDimitry Andric 
1340*5f757f3fSDimitry Andric bool CombineRuleBuilder::findRoots() {
1341*5f757f3fSDimitry Andric   const auto Finish = [&]() {
1342*5f757f3fSDimitry Andric     assert(MatchRoot);
1343*5f757f3fSDimitry Andric 
1344*5f757f3fSDimitry Andric     if (hasOnlyCXXApplyPatterns() || hasEraseRoot())
1345*5f757f3fSDimitry Andric       return true;
1346*5f757f3fSDimitry Andric 
1347*5f757f3fSDimitry Andric     auto *IPRoot = dyn_cast<InstructionPattern>(MatchRoot);
1348*5f757f3fSDimitry Andric     if (!IPRoot)
1349*5f757f3fSDimitry Andric       return true;
1350*5f757f3fSDimitry Andric 
1351*5f757f3fSDimitry Andric     if (IPRoot->getNumInstDefs() == 0) {
1352*5f757f3fSDimitry Andric       // No defs to work with -> find the root using the pattern name.
1353*5f757f3fSDimitry Andric       auto It = ApplyPats.find(RootName);
1354*5f757f3fSDimitry Andric       if (It == ApplyPats.end()) {
1355*5f757f3fSDimitry Andric         PrintError("Cannot find root '" + RootName + "' in apply patterns!");
1356*5f757f3fSDimitry Andric         return false;
1357*5f757f3fSDimitry Andric       }
1358*5f757f3fSDimitry Andric 
1359*5f757f3fSDimitry Andric       auto *ApplyRoot = dyn_cast<InstructionPattern>(It->second.get());
1360*5f757f3fSDimitry Andric       if (!ApplyRoot) {
1361*5f757f3fSDimitry Andric         PrintError("apply pattern root '" + RootName +
1362*5f757f3fSDimitry Andric                    "' must be an instruction pattern");
1363*5f757f3fSDimitry Andric         return false;
1364*5f757f3fSDimitry Andric       }
1365*5f757f3fSDimitry Andric 
1366*5f757f3fSDimitry Andric       ApplyRoots.insert(ApplyRoot);
1367*5f757f3fSDimitry Andric       return true;
1368*5f757f3fSDimitry Andric     }
1369*5f757f3fSDimitry Andric 
1370*5f757f3fSDimitry Andric     // Collect all redefinitions of the MatchRoot's defs and put them in
1371*5f757f3fSDimitry Andric     // ApplyRoots.
1372*5f757f3fSDimitry Andric     const auto DefsNeeded = IPRoot->getApplyDefsNeeded();
1373*5f757f3fSDimitry Andric     for (auto &Op : DefsNeeded) {
1374*5f757f3fSDimitry Andric       assert(Op.isDef() && Op.isNamedOperand());
1375*5f757f3fSDimitry Andric       StringRef Name = Op.getOperandName();
1376*5f757f3fSDimitry Andric 
1377*5f757f3fSDimitry Andric       auto *ApplyRedef = ApplyOpTable.getDef(Name);
1378*5f757f3fSDimitry Andric       if (!ApplyRedef) {
1379*5f757f3fSDimitry Andric         PrintError("'" + Name + "' must be redefined in the 'apply' pattern");
1380*5f757f3fSDimitry Andric         return false;
1381*5f757f3fSDimitry Andric       }
1382*5f757f3fSDimitry Andric 
1383*5f757f3fSDimitry Andric       ApplyRoots.insert((InstructionPattern *)ApplyRedef);
1384*5f757f3fSDimitry Andric     }
1385*5f757f3fSDimitry Andric 
1386*5f757f3fSDimitry Andric     if (auto It = ApplyPats.find(RootName); It != ApplyPats.end()) {
1387*5f757f3fSDimitry Andric       if (find(ApplyRoots, It->second.get()) == ApplyRoots.end()) {
1388*5f757f3fSDimitry Andric         PrintError("apply pattern '" + RootName +
1389*5f757f3fSDimitry Andric                    "' is supposed to be a root but it does not redefine any of "
1390*5f757f3fSDimitry Andric                    "the defs of the match root");
1391*5f757f3fSDimitry Andric         return false;
1392*5f757f3fSDimitry Andric       }
1393*5f757f3fSDimitry Andric     }
1394*5f757f3fSDimitry Andric 
1395*5f757f3fSDimitry Andric     return true;
1396*5f757f3fSDimitry Andric   };
1397*5f757f3fSDimitry Andric 
1398*5f757f3fSDimitry Andric   // Look by pattern name, e.g.
1399*5f757f3fSDimitry Andric   //    (G_FNEG $x, $y):$root
1400*5f757f3fSDimitry Andric   if (auto MatchPatIt = MatchPats.find(RootName);
1401*5f757f3fSDimitry Andric       MatchPatIt != MatchPats.end()) {
1402*5f757f3fSDimitry Andric     MatchRoot = MatchPatIt->second.get();
1403*5f757f3fSDimitry Andric     return Finish();
1404*5f757f3fSDimitry Andric   }
1405*5f757f3fSDimitry Andric 
1406*5f757f3fSDimitry Andric   // Look by def:
1407*5f757f3fSDimitry Andric   //    (G_FNEG $root, $y)
1408*5f757f3fSDimitry Andric   auto LookupRes = MatchOpTable.lookup(RootName);
1409*5f757f3fSDimitry Andric   if (!LookupRes.Found) {
1410*5f757f3fSDimitry Andric     PrintError("Cannot find root '" + RootName + "' in match patterns!");
1411*5f757f3fSDimitry Andric     return false;
1412*5f757f3fSDimitry Andric   }
1413*5f757f3fSDimitry Andric 
1414*5f757f3fSDimitry Andric   MatchRoot = LookupRes.Def;
1415*5f757f3fSDimitry Andric   if (!MatchRoot) {
1416*5f757f3fSDimitry Andric     PrintError("Cannot use live-in operand '" + RootName +
1417*5f757f3fSDimitry Andric                "' as match pattern root!");
1418*5f757f3fSDimitry Andric     return false;
1419*5f757f3fSDimitry Andric   }
1420*5f757f3fSDimitry Andric 
1421*5f757f3fSDimitry Andric   return Finish();
1422*5f757f3fSDimitry Andric }
1423*5f757f3fSDimitry Andric 
1424*5f757f3fSDimitry Andric bool CombineRuleBuilder::buildRuleOperandsTable() {
1425*5f757f3fSDimitry Andric   const auto DiagnoseRedefMatch = [&](StringRef OpName) {
1426*5f757f3fSDimitry Andric     PrintError("Operand '" + OpName +
1427*5f757f3fSDimitry Andric                "' is defined multiple times in the 'match' patterns");
1428*5f757f3fSDimitry Andric   };
1429*5f757f3fSDimitry Andric 
1430*5f757f3fSDimitry Andric   const auto DiagnoseRedefApply = [&](StringRef OpName) {
1431*5f757f3fSDimitry Andric     PrintError("Operand '" + OpName +
1432*5f757f3fSDimitry Andric                "' is defined multiple times in the 'apply' patterns");
1433*5f757f3fSDimitry Andric   };
1434*5f757f3fSDimitry Andric 
1435*5f757f3fSDimitry Andric   for (auto &Pat : values(MatchPats)) {
1436*5f757f3fSDimitry Andric     auto *IP = dyn_cast<InstructionPattern>(Pat.get());
1437*5f757f3fSDimitry Andric     if (IP && !MatchOpTable.addPattern(IP, DiagnoseRedefMatch))
1438*5f757f3fSDimitry Andric       return false;
1439*5f757f3fSDimitry Andric   }
1440*5f757f3fSDimitry Andric 
1441*5f757f3fSDimitry Andric   for (auto &Pat : values(ApplyPats)) {
1442*5f757f3fSDimitry Andric     auto *IP = dyn_cast<InstructionPattern>(Pat.get());
1443*5f757f3fSDimitry Andric     if (IP && !ApplyOpTable.addPattern(IP, DiagnoseRedefApply))
1444*5f757f3fSDimitry Andric       return false;
1445*5f757f3fSDimitry Andric   }
1446*5f757f3fSDimitry Andric 
1447*5f757f3fSDimitry Andric   return true;
1448*5f757f3fSDimitry Andric }
1449*5f757f3fSDimitry Andric 
1450*5f757f3fSDimitry Andric bool CombineRuleBuilder::parseDefs(const DagInit &Def) {
1451*5f757f3fSDimitry Andric   if (Def.getOperatorAsDef(RuleDef.getLoc())->getName() != "defs") {
1452*5f757f3fSDimitry Andric     PrintError("Expected defs operator");
1453*5f757f3fSDimitry Andric     return false;
1454*5f757f3fSDimitry Andric   }
1455*5f757f3fSDimitry Andric 
1456*5f757f3fSDimitry Andric   SmallVector<StringRef> Roots;
1457*5f757f3fSDimitry Andric   for (unsigned I = 0, E = Def.getNumArgs(); I < E; ++I) {
1458*5f757f3fSDimitry Andric     if (isSpecificDef(*Def.getArg(I), "root")) {
1459*5f757f3fSDimitry Andric       Roots.emplace_back(Def.getArgNameStr(I));
1460*5f757f3fSDimitry Andric       continue;
1461*5f757f3fSDimitry Andric     }
1462*5f757f3fSDimitry Andric 
1463*5f757f3fSDimitry Andric     // Subclasses of GIDefMatchData should declare that this rule needs to pass
1464*5f757f3fSDimitry Andric     // data from the match stage to the apply stage, and ensure that the
1465*5f757f3fSDimitry Andric     // generated matcher has a suitable variable for it to do so.
1466*5f757f3fSDimitry Andric     if (Record *MatchDataRec =
1467*5f757f3fSDimitry Andric             getDefOfSubClass(*Def.getArg(I), "GIDefMatchData")) {
1468*5f757f3fSDimitry Andric       MatchDatas.emplace_back(Def.getArgNameStr(I),
1469*5f757f3fSDimitry Andric                               MatchDataRec->getValueAsString("Type"));
1470*5f757f3fSDimitry Andric       continue;
1471*5f757f3fSDimitry Andric     }
1472*5f757f3fSDimitry Andric 
1473*5f757f3fSDimitry Andric     // Otherwise emit an appropriate error message.
1474*5f757f3fSDimitry Andric     if (getDefOfSubClass(*Def.getArg(I), "GIDefKind"))
1475*5f757f3fSDimitry Andric       PrintError("This GIDefKind not implemented in tablegen");
1476*5f757f3fSDimitry Andric     else if (getDefOfSubClass(*Def.getArg(I), "GIDefKindWithArgs"))
1477*5f757f3fSDimitry Andric       PrintError("This GIDefKindWithArgs not implemented in tablegen");
1478*5f757f3fSDimitry Andric     else
1479*5f757f3fSDimitry Andric       PrintError("Expected a subclass of GIDefKind or a sub-dag whose "
1480*5f757f3fSDimitry Andric                  "operator is of type GIDefKindWithArgs");
1481*5f757f3fSDimitry Andric     return false;
1482*5f757f3fSDimitry Andric   }
1483*5f757f3fSDimitry Andric 
1484*5f757f3fSDimitry Andric   if (Roots.size() != 1) {
1485*5f757f3fSDimitry Andric     PrintError("Combine rules must have exactly one root");
1486*5f757f3fSDimitry Andric     return false;
1487*5f757f3fSDimitry Andric   }
1488*5f757f3fSDimitry Andric 
1489*5f757f3fSDimitry Andric   RootName = Roots.front();
1490*5f757f3fSDimitry Andric 
1491*5f757f3fSDimitry Andric   // Assign variables to all MatchDatas.
1492*5f757f3fSDimitry Andric   AssignMatchDataVariables(MatchDatas);
1493*5f757f3fSDimitry Andric   return true;
1494*5f757f3fSDimitry Andric }
1495*5f757f3fSDimitry Andric 
1496*5f757f3fSDimitry Andric bool CombineRuleBuilder::parsePatternList(
1497*5f757f3fSDimitry Andric     const DagInit &List,
1498*5f757f3fSDimitry Andric     function_ref<bool(std::unique_ptr<Pattern>)> ParseAction,
1499*5f757f3fSDimitry Andric     StringRef Operator, ArrayRef<SMLoc> DiagLoc,
1500*5f757f3fSDimitry Andric     StringRef AnonPatNamePrefix) const {
1501*5f757f3fSDimitry Andric   if (List.getOperatorAsDef(RuleDef.getLoc())->getName() != Operator) {
1502*5f757f3fSDimitry Andric     ::PrintError(DiagLoc, "Expected " + Operator + " operator");
1503*5f757f3fSDimitry Andric     return false;
1504*5f757f3fSDimitry Andric   }
1505*5f757f3fSDimitry Andric 
1506*5f757f3fSDimitry Andric   if (List.getNumArgs() == 0) {
1507*5f757f3fSDimitry Andric     ::PrintError(DiagLoc, Operator + " pattern list is empty");
1508*5f757f3fSDimitry Andric     return false;
1509*5f757f3fSDimitry Andric   }
1510*5f757f3fSDimitry Andric 
1511*5f757f3fSDimitry Andric   // The match section consists of a list of matchers and predicates. Parse each
1512*5f757f3fSDimitry Andric   // one and add the equivalent GIMatchDag nodes, predicates, and edges.
1513*5f757f3fSDimitry Andric   for (unsigned I = 0; I < List.getNumArgs(); ++I) {
1514*5f757f3fSDimitry Andric     Init *Arg = List.getArg(I);
1515*5f757f3fSDimitry Andric     std::string Name = List.getArgName(I)
1516*5f757f3fSDimitry Andric                            ? List.getArgName(I)->getValue().str()
1517*5f757f3fSDimitry Andric                            : ("__" + AnonPatNamePrefix + "_" + Twine(I)).str();
1518*5f757f3fSDimitry Andric 
1519*5f757f3fSDimitry Andric     if (auto Pat = parseInstructionPattern(*Arg, Name)) {
1520*5f757f3fSDimitry Andric       if (!ParseAction(std::move(Pat)))
1521*5f757f3fSDimitry Andric         return false;
1522*5f757f3fSDimitry Andric       continue;
1523*5f757f3fSDimitry Andric     }
1524*5f757f3fSDimitry Andric 
1525*5f757f3fSDimitry Andric     if (auto Pat = parseWipMatchOpcodeMatcher(*Arg, Name)) {
1526*5f757f3fSDimitry Andric       if (!ParseAction(std::move(Pat)))
1527*5f757f3fSDimitry Andric         return false;
1528*5f757f3fSDimitry Andric       continue;
1529*5f757f3fSDimitry Andric     }
1530*5f757f3fSDimitry Andric 
1531*5f757f3fSDimitry Andric     // Parse arbitrary C++ code
1532*5f757f3fSDimitry Andric     if (const auto *StringI = dyn_cast<StringInit>(Arg)) {
1533*5f757f3fSDimitry Andric       auto CXXPat = std::make_unique<CXXPattern>(*StringI, insertStrRef(Name));
1534*5f757f3fSDimitry Andric       if (!ParseAction(std::move(CXXPat)))
1535*5f757f3fSDimitry Andric         return false;
1536*5f757f3fSDimitry Andric       continue;
1537*5f757f3fSDimitry Andric     }
1538*5f757f3fSDimitry Andric 
1539*5f757f3fSDimitry Andric     ::PrintError(DiagLoc,
1540*5f757f3fSDimitry Andric                  "Failed to parse pattern: '" + Arg->getAsString() + "'");
1541*5f757f3fSDimitry Andric     return false;
1542*5f757f3fSDimitry Andric   }
1543*5f757f3fSDimitry Andric 
1544*5f757f3fSDimitry Andric   return true;
1545*5f757f3fSDimitry Andric }
1546*5f757f3fSDimitry Andric 
1547*5f757f3fSDimitry Andric std::unique_ptr<Pattern>
1548*5f757f3fSDimitry Andric CombineRuleBuilder::parseInstructionPattern(const Init &Arg,
1549*5f757f3fSDimitry Andric                                             StringRef Name) const {
1550*5f757f3fSDimitry Andric   const DagInit *DagPat = dyn_cast<DagInit>(&Arg);
1551*5f757f3fSDimitry Andric   if (!DagPat)
1552*5f757f3fSDimitry Andric     return nullptr;
1553*5f757f3fSDimitry Andric 
1554*5f757f3fSDimitry Andric   std::unique_ptr<InstructionPattern> Pat;
1555*5f757f3fSDimitry Andric   if (const DagInit *IP = getDagWithOperatorOfSubClass(Arg, "Instruction")) {
1556*5f757f3fSDimitry Andric     auto &Instr = CGT.getInstruction(IP->getOperatorAsDef(RuleDef.getLoc()));
1557*5f757f3fSDimitry Andric     Pat =
1558*5f757f3fSDimitry Andric         std::make_unique<CodeGenInstructionPattern>(Instr, insertStrRef(Name));
1559*5f757f3fSDimitry Andric   } else if (const DagInit *PFP =
1560*5f757f3fSDimitry Andric                  getDagWithOperatorOfSubClass(Arg, PatFrag::ClassName)) {
1561*5f757f3fSDimitry Andric     const Record *Def = PFP->getOperatorAsDef(RuleDef.getLoc());
1562*5f757f3fSDimitry Andric     const PatFrag *PF = parsePatFrag(Def);
1563*5f757f3fSDimitry Andric     if (!PF)
1564*5f757f3fSDimitry Andric       return nullptr; // Already diagnosed by parsePatFrag
1565*5f757f3fSDimitry Andric     Pat = std::make_unique<PatFragPattern>(*PF, insertStrRef(Name));
1566*5f757f3fSDimitry Andric   } else if (const DagInit *BP =
1567*5f757f3fSDimitry Andric                  getDagWithOperatorOfSubClass(Arg, BuiltinPattern::ClassName)) {
1568*5f757f3fSDimitry Andric     Pat = std::make_unique<BuiltinPattern>(
1569*5f757f3fSDimitry Andric         *BP->getOperatorAsDef(RuleDef.getLoc()), insertStrRef(Name));
1570*5f757f3fSDimitry Andric   } else {
1571*5f757f3fSDimitry Andric     return nullptr;
1572*5f757f3fSDimitry Andric   }
1573*5f757f3fSDimitry Andric 
1574*5f757f3fSDimitry Andric   for (unsigned K = 0; K < DagPat->getNumArgs(); ++K) {
1575*5f757f3fSDimitry Andric     Init *Arg = DagPat->getArg(K);
1576*5f757f3fSDimitry Andric     if (auto *DagArg = getDagWithSpecificOperator(*Arg, "MIFlags")) {
1577*5f757f3fSDimitry Andric       if (!parseInstructionPatternMIFlags(*Pat, DagArg))
1578*5f757f3fSDimitry Andric         return nullptr;
1579*5f757f3fSDimitry Andric       continue;
1580*5f757f3fSDimitry Andric     }
1581*5f757f3fSDimitry Andric 
1582*5f757f3fSDimitry Andric     if (!parseInstructionPatternOperand(*Pat, Arg, DagPat->getArgName(K)))
1583*5f757f3fSDimitry Andric       return nullptr;
1584*5f757f3fSDimitry Andric   }
1585*5f757f3fSDimitry Andric 
1586*5f757f3fSDimitry Andric   if (!Pat->checkSemantics(RuleDef.getLoc()))
1587*5f757f3fSDimitry Andric     return nullptr;
1588*5f757f3fSDimitry Andric 
1589*5f757f3fSDimitry Andric   return std::move(Pat);
1590*5f757f3fSDimitry Andric }
1591*5f757f3fSDimitry Andric 
1592*5f757f3fSDimitry Andric std::unique_ptr<Pattern>
1593*5f757f3fSDimitry Andric CombineRuleBuilder::parseWipMatchOpcodeMatcher(const Init &Arg,
1594*5f757f3fSDimitry Andric                                                StringRef Name) const {
1595*5f757f3fSDimitry Andric   const DagInit *Matcher = getDagWithSpecificOperator(Arg, "wip_match_opcode");
1596*5f757f3fSDimitry Andric   if (!Matcher)
1597*5f757f3fSDimitry Andric     return nullptr;
1598*5f757f3fSDimitry Andric 
1599*5f757f3fSDimitry Andric   if (Matcher->getNumArgs() == 0) {
1600*5f757f3fSDimitry Andric     PrintError("Empty wip_match_opcode");
1601*5f757f3fSDimitry Andric     return nullptr;
1602*5f757f3fSDimitry Andric   }
1603*5f757f3fSDimitry Andric 
1604*5f757f3fSDimitry Andric   // Each argument is an opcode that can match.
1605*5f757f3fSDimitry Andric   auto Result = std::make_unique<AnyOpcodePattern>(insertStrRef(Name));
1606*5f757f3fSDimitry Andric   for (const auto &Arg : Matcher->getArgs()) {
1607*5f757f3fSDimitry Andric     Record *OpcodeDef = getDefOfSubClass(*Arg, "Instruction");
1608*5f757f3fSDimitry Andric     if (OpcodeDef) {
1609*5f757f3fSDimitry Andric       Result->addOpcode(&CGT.getInstruction(OpcodeDef));
1610*5f757f3fSDimitry Andric       continue;
1611*5f757f3fSDimitry Andric     }
1612*5f757f3fSDimitry Andric 
1613*5f757f3fSDimitry Andric     PrintError("Arguments to wip_match_opcode must be instructions");
1614*5f757f3fSDimitry Andric     return nullptr;
1615*5f757f3fSDimitry Andric   }
1616*5f757f3fSDimitry Andric 
1617*5f757f3fSDimitry Andric   return std::move(Result);
1618*5f757f3fSDimitry Andric }
1619*5f757f3fSDimitry Andric 
1620*5f757f3fSDimitry Andric bool CombineRuleBuilder::parseInstructionPatternOperand(
1621*5f757f3fSDimitry Andric     InstructionPattern &IP, const Init *OpInit,
1622*5f757f3fSDimitry Andric     const StringInit *OpName) const {
1623*5f757f3fSDimitry Andric   const auto ParseErr = [&]() {
1624*5f757f3fSDimitry Andric     PrintError("cannot parse operand '" + OpInit->getAsUnquotedString() + "' ");
1625*5f757f3fSDimitry Andric     if (OpName)
1626*5f757f3fSDimitry Andric       PrintNote("operand name is '" + OpName->getAsUnquotedString() + "'");
1627*5f757f3fSDimitry Andric     return false;
1628*5f757f3fSDimitry Andric   };
1629*5f757f3fSDimitry Andric 
1630*5f757f3fSDimitry Andric   // untyped immediate, e.g. 0
1631*5f757f3fSDimitry Andric   if (const auto *IntImm = dyn_cast<IntInit>(OpInit)) {
1632*5f757f3fSDimitry Andric     std::string Name = OpName ? OpName->getAsUnquotedString() : "";
1633*5f757f3fSDimitry Andric     IP.addOperand(IntImm->getValue(), insertStrRef(Name), PatternType());
1634*5f757f3fSDimitry Andric     return true;
1635*5f757f3fSDimitry Andric   }
1636*5f757f3fSDimitry Andric 
1637*5f757f3fSDimitry Andric   // typed immediate, e.g. (i32 0)
1638*5f757f3fSDimitry Andric   if (const auto *DagOp = dyn_cast<DagInit>(OpInit)) {
1639*5f757f3fSDimitry Andric     if (DagOp->getNumArgs() != 1)
1640*5f757f3fSDimitry Andric       return ParseErr();
1641*5f757f3fSDimitry Andric 
1642*5f757f3fSDimitry Andric     const Record *TyDef = DagOp->getOperatorAsDef(RuleDef.getLoc());
1643*5f757f3fSDimitry Andric     auto ImmTy = PatternType::get(RuleDef.getLoc(), TyDef,
1644*5f757f3fSDimitry Andric                                   "cannot parse immediate '" +
1645*5f757f3fSDimitry Andric                                       DagOp->getAsUnquotedString() + "'");
1646*5f757f3fSDimitry Andric     if (!ImmTy)
1647*5f757f3fSDimitry Andric       return false;
1648*5f757f3fSDimitry Andric 
1649*5f757f3fSDimitry Andric     if (!IP.hasAllDefs()) {
1650*5f757f3fSDimitry Andric       PrintError("out operand of '" + IP.getInstName() +
1651*5f757f3fSDimitry Andric                  "' cannot be an immediate");
1652*5f757f3fSDimitry Andric       return false;
1653*5f757f3fSDimitry Andric     }
1654*5f757f3fSDimitry Andric 
1655*5f757f3fSDimitry Andric     const auto *Val = dyn_cast<IntInit>(DagOp->getArg(0));
1656*5f757f3fSDimitry Andric     if (!Val)
1657*5f757f3fSDimitry Andric       return ParseErr();
1658*5f757f3fSDimitry Andric 
1659*5f757f3fSDimitry Andric     std::string Name = OpName ? OpName->getAsUnquotedString() : "";
1660*5f757f3fSDimitry Andric     IP.addOperand(Val->getValue(), insertStrRef(Name), *ImmTy);
1661*5f757f3fSDimitry Andric     return true;
1662*5f757f3fSDimitry Andric   }
1663*5f757f3fSDimitry Andric 
1664*5f757f3fSDimitry Andric   // Typed operand e.g. $x/$z in (G_FNEG $x, $z)
1665*5f757f3fSDimitry Andric   if (auto *DefI = dyn_cast<DefInit>(OpInit)) {
1666*5f757f3fSDimitry Andric     if (!OpName) {
1667*5f757f3fSDimitry Andric       PrintError("expected an operand name after '" + OpInit->getAsString() +
1668*5f757f3fSDimitry Andric                  "'");
1669*5f757f3fSDimitry Andric       return false;
1670*5f757f3fSDimitry Andric     }
1671*5f757f3fSDimitry Andric     const Record *Def = DefI->getDef();
1672*5f757f3fSDimitry Andric     auto Ty =
1673*5f757f3fSDimitry Andric         PatternType::get(RuleDef.getLoc(), Def, "cannot parse operand type");
1674*5f757f3fSDimitry Andric     if (!Ty)
1675*5f757f3fSDimitry Andric       return false;
1676*5f757f3fSDimitry Andric     IP.addOperand(insertStrRef(OpName->getAsUnquotedString()), *Ty);
1677*5f757f3fSDimitry Andric     return true;
1678*5f757f3fSDimitry Andric   }
1679*5f757f3fSDimitry Andric 
1680*5f757f3fSDimitry Andric   // Untyped operand e.g. $x/$z in (G_FNEG $x, $z)
1681*5f757f3fSDimitry Andric   if (isa<UnsetInit>(OpInit)) {
1682*5f757f3fSDimitry Andric     assert(OpName && "Unset w/ no OpName?");
1683*5f757f3fSDimitry Andric     IP.addOperand(insertStrRef(OpName->getAsUnquotedString()), PatternType());
1684*5f757f3fSDimitry Andric     return true;
1685*5f757f3fSDimitry Andric   }
1686*5f757f3fSDimitry Andric 
1687*5f757f3fSDimitry Andric   return ParseErr();
1688*5f757f3fSDimitry Andric }
1689*5f757f3fSDimitry Andric 
1690*5f757f3fSDimitry Andric bool CombineRuleBuilder::parseInstructionPatternMIFlags(
1691*5f757f3fSDimitry Andric     InstructionPattern &IP, const DagInit *Op) const {
1692*5f757f3fSDimitry Andric   auto *CGIP = dyn_cast<CodeGenInstructionPattern>(&IP);
1693*5f757f3fSDimitry Andric   if (!CGIP) {
1694*5f757f3fSDimitry Andric     PrintError("matching/writing MIFlags is only allowed on CodeGenInstruction "
1695*5f757f3fSDimitry Andric                "patterns");
1696*5f757f3fSDimitry Andric     return false;
1697*5f757f3fSDimitry Andric   }
1698*5f757f3fSDimitry Andric 
1699*5f757f3fSDimitry Andric   const auto CheckFlagEnum = [&](const Record *R) {
1700*5f757f3fSDimitry Andric     if (!R->isSubClassOf(MIFlagsEnumClassName)) {
1701*5f757f3fSDimitry Andric       PrintError("'" + R->getName() + "' is not a subclass of '" +
1702*5f757f3fSDimitry Andric                  MIFlagsEnumClassName + "'");
1703*5f757f3fSDimitry Andric       return false;
1704*5f757f3fSDimitry Andric     }
1705*5f757f3fSDimitry Andric 
1706*5f757f3fSDimitry Andric     return true;
1707*5f757f3fSDimitry Andric   };
1708*5f757f3fSDimitry Andric 
1709*5f757f3fSDimitry Andric   if (CGIP->getMIFlagsInfo()) {
1710*5f757f3fSDimitry Andric     PrintError("MIFlags can only be present once on an instruction");
1711*5f757f3fSDimitry Andric     return false;
1712*5f757f3fSDimitry Andric   }
1713*5f757f3fSDimitry Andric 
1714*5f757f3fSDimitry Andric   auto &FI = CGIP->getOrCreateMIFlagsInfo();
1715*5f757f3fSDimitry Andric   for (unsigned K = 0; K < Op->getNumArgs(); ++K) {
1716*5f757f3fSDimitry Andric     const Init *Arg = Op->getArg(K);
1717*5f757f3fSDimitry Andric 
1718*5f757f3fSDimitry Andric     // Match/set a flag: (MIFlags FmNoNans)
1719*5f757f3fSDimitry Andric     if (const auto *Def = dyn_cast<DefInit>(Arg)) {
1720*5f757f3fSDimitry Andric       const Record *R = Def->getDef();
1721*5f757f3fSDimitry Andric       if (!CheckFlagEnum(R))
1722*5f757f3fSDimitry Andric         return false;
1723*5f757f3fSDimitry Andric 
1724*5f757f3fSDimitry Andric       FI.addSetFlag(R);
1725*5f757f3fSDimitry Andric       continue;
1726*5f757f3fSDimitry Andric     }
1727*5f757f3fSDimitry Andric 
1728*5f757f3fSDimitry Andric     // Do not match a flag/unset a flag: (MIFlags (not FmNoNans))
1729*5f757f3fSDimitry Andric     if (const DagInit *NotDag = getDagWithSpecificOperator(*Arg, "not")) {
1730*5f757f3fSDimitry Andric       for (const Init *NotArg : NotDag->getArgs()) {
1731*5f757f3fSDimitry Andric         const DefInit *DefArg = dyn_cast<DefInit>(NotArg);
1732*5f757f3fSDimitry Andric         if (!DefArg) {
1733*5f757f3fSDimitry Andric           PrintError("cannot parse '" + NotArg->getAsUnquotedString() +
1734*5f757f3fSDimitry Andric                      "': expected a '" + MIFlagsEnumClassName + "'");
1735*5f757f3fSDimitry Andric           return false;
1736*5f757f3fSDimitry Andric         }
1737*5f757f3fSDimitry Andric 
1738*5f757f3fSDimitry Andric         const Record *R = DefArg->getDef();
1739*5f757f3fSDimitry Andric         if (!CheckFlagEnum(R))
1740*5f757f3fSDimitry Andric           return false;
1741*5f757f3fSDimitry Andric 
1742*5f757f3fSDimitry Andric         FI.addUnsetFlag(R);
1743*5f757f3fSDimitry Andric         continue;
1744*5f757f3fSDimitry Andric       }
1745*5f757f3fSDimitry Andric 
1746*5f757f3fSDimitry Andric       continue;
1747*5f757f3fSDimitry Andric     }
1748*5f757f3fSDimitry Andric 
1749*5f757f3fSDimitry Andric     // Copy flags from a matched instruction: (MIFlags $mi)
1750*5f757f3fSDimitry Andric     if (isa<UnsetInit>(Arg)) {
1751*5f757f3fSDimitry Andric       FI.addCopyFlag(insertStrRef(Op->getArgName(K)->getAsUnquotedString()));
1752*5f757f3fSDimitry Andric       continue;
1753*5f757f3fSDimitry Andric     }
1754*5f757f3fSDimitry Andric   }
1755*5f757f3fSDimitry Andric 
1756*5f757f3fSDimitry Andric   return true;
1757*5f757f3fSDimitry Andric }
1758*5f757f3fSDimitry Andric 
1759*5f757f3fSDimitry Andric std::unique_ptr<PatFrag>
1760*5f757f3fSDimitry Andric CombineRuleBuilder::parsePatFragImpl(const Record *Def) const {
1761*5f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceParse(*Def);
1762*5f757f3fSDimitry Andric   if (!Def->isSubClassOf(PatFrag::ClassName))
1763*5f757f3fSDimitry Andric     return nullptr;
1764*5f757f3fSDimitry Andric 
1765*5f757f3fSDimitry Andric   const DagInit *Ins = Def->getValueAsDag("InOperands");
1766*5f757f3fSDimitry Andric   if (Ins->getOperatorAsDef(Def->getLoc())->getName() != "ins") {
1767*5f757f3fSDimitry Andric     ::PrintError(Def, "expected 'ins' operator for " + PatFrag::ClassName +
1768*5f757f3fSDimitry Andric                           " in operands list");
1769*5f757f3fSDimitry Andric     return nullptr;
1770*5f757f3fSDimitry Andric   }
1771*5f757f3fSDimitry Andric 
1772*5f757f3fSDimitry Andric   const DagInit *Outs = Def->getValueAsDag("OutOperands");
1773*5f757f3fSDimitry Andric   if (Outs->getOperatorAsDef(Def->getLoc())->getName() != "outs") {
1774*5f757f3fSDimitry Andric     ::PrintError(Def, "expected 'outs' operator for " + PatFrag::ClassName +
1775*5f757f3fSDimitry Andric                           " out operands list");
1776*5f757f3fSDimitry Andric     return nullptr;
1777*5f757f3fSDimitry Andric   }
1778*5f757f3fSDimitry Andric 
1779*5f757f3fSDimitry Andric   auto Result = std::make_unique<PatFrag>(*Def);
1780*5f757f3fSDimitry Andric   if (!parsePatFragParamList(Def->getLoc(), *Outs,
1781*5f757f3fSDimitry Andric                              [&](StringRef Name, PatFrag::ParamKind Kind) {
1782*5f757f3fSDimitry Andric                                Result->addOutParam(insertStrRef(Name), Kind);
1783*5f757f3fSDimitry Andric                                return true;
1784*5f757f3fSDimitry Andric                              }))
1785*5f757f3fSDimitry Andric     return nullptr;
1786*5f757f3fSDimitry Andric 
1787*5f757f3fSDimitry Andric   if (!parsePatFragParamList(Def->getLoc(), *Ins,
1788*5f757f3fSDimitry Andric                              [&](StringRef Name, PatFrag::ParamKind Kind) {
1789*5f757f3fSDimitry Andric                                Result->addInParam(insertStrRef(Name), Kind);
1790*5f757f3fSDimitry Andric                                return true;
1791*5f757f3fSDimitry Andric                              }))
1792*5f757f3fSDimitry Andric     return nullptr;
1793*5f757f3fSDimitry Andric 
1794*5f757f3fSDimitry Andric   const ListInit *Alts = Def->getValueAsListInit("Alternatives");
1795*5f757f3fSDimitry Andric   unsigned AltIdx = 0;
1796*5f757f3fSDimitry Andric   for (const Init *Alt : *Alts) {
1797*5f757f3fSDimitry Andric     const auto *PatDag = dyn_cast<DagInit>(Alt);
1798*5f757f3fSDimitry Andric     if (!PatDag) {
1799*5f757f3fSDimitry Andric       ::PrintError(Def, "expected dag init for PatFrag pattern alternative");
1800*5f757f3fSDimitry Andric       return nullptr;
1801*5f757f3fSDimitry Andric     }
1802*5f757f3fSDimitry Andric 
1803*5f757f3fSDimitry Andric     PatFrag::Alternative &A = Result->addAlternative();
1804*5f757f3fSDimitry Andric     const auto AddPat = [&](std::unique_ptr<Pattern> Pat) {
1805*5f757f3fSDimitry Andric       A.Pats.push_back(std::move(Pat));
1806*5f757f3fSDimitry Andric       return true;
1807*5f757f3fSDimitry Andric     };
1808*5f757f3fSDimitry Andric 
1809*5f757f3fSDimitry Andric     if (!parsePatternList(
1810*5f757f3fSDimitry Andric             *PatDag, AddPat, "pattern", Def->getLoc(),
1811*5f757f3fSDimitry Andric             /*AnonPatPrefix*/
1812*5f757f3fSDimitry Andric             (Def->getName() + "_alt" + Twine(AltIdx++) + "_pattern").str()))
1813*5f757f3fSDimitry Andric       return nullptr;
1814*5f757f3fSDimitry Andric   }
1815*5f757f3fSDimitry Andric 
1816*5f757f3fSDimitry Andric   if (!Result->buildOperandsTables() || !Result->checkSemantics())
1817*5f757f3fSDimitry Andric     return nullptr;
1818*5f757f3fSDimitry Andric 
1819*5f757f3fSDimitry Andric   return Result;
1820*5f757f3fSDimitry Andric }
1821*5f757f3fSDimitry Andric 
1822*5f757f3fSDimitry Andric bool CombineRuleBuilder::parsePatFragParamList(
1823*5f757f3fSDimitry Andric     ArrayRef<SMLoc> DiagLoc, const DagInit &OpsList,
1824*5f757f3fSDimitry Andric     function_ref<bool(StringRef, PatFrag::ParamKind)> ParseAction) const {
1825*5f757f3fSDimitry Andric   for (unsigned K = 0; K < OpsList.getNumArgs(); ++K) {
1826*5f757f3fSDimitry Andric     const StringInit *Name = OpsList.getArgName(K);
1827*5f757f3fSDimitry Andric     const Init *Ty = OpsList.getArg(K);
1828*5f757f3fSDimitry Andric 
1829*5f757f3fSDimitry Andric     if (!Name) {
1830*5f757f3fSDimitry Andric       ::PrintError(DiagLoc, "all operands must be named'");
1831*5f757f3fSDimitry Andric       return false;
1832*5f757f3fSDimitry Andric     }
1833*5f757f3fSDimitry Andric     const std::string NameStr = Name->getAsUnquotedString();
1834*5f757f3fSDimitry Andric 
1835*5f757f3fSDimitry Andric     PatFrag::ParamKind OpKind;
1836*5f757f3fSDimitry Andric     if (isSpecificDef(*Ty, "gi_imm"))
1837*5f757f3fSDimitry Andric       OpKind = PatFrag::PK_Imm;
1838*5f757f3fSDimitry Andric     else if (isSpecificDef(*Ty, "root"))
1839*5f757f3fSDimitry Andric       OpKind = PatFrag::PK_Root;
1840*5f757f3fSDimitry Andric     else if (isa<UnsetInit>(Ty) ||
1841*5f757f3fSDimitry Andric              isSpecificDef(*Ty, "gi_mo")) // no type = gi_mo.
1842*5f757f3fSDimitry Andric       OpKind = PatFrag::PK_MachineOperand;
1843*5f757f3fSDimitry Andric     else {
1844*5f757f3fSDimitry Andric       ::PrintError(
1845*5f757f3fSDimitry Andric           DiagLoc,
1846*5f757f3fSDimitry Andric           "'" + NameStr +
1847*5f757f3fSDimitry Andric               "' operand type was expected to be 'root', 'gi_imm' or 'gi_mo'");
1848*5f757f3fSDimitry Andric       return false;
1849*5f757f3fSDimitry Andric     }
1850*5f757f3fSDimitry Andric 
1851*5f757f3fSDimitry Andric     if (!ParseAction(NameStr, OpKind))
1852*5f757f3fSDimitry Andric       return false;
1853*5f757f3fSDimitry Andric   }
1854*5f757f3fSDimitry Andric 
1855*5f757f3fSDimitry Andric   return true;
1856*5f757f3fSDimitry Andric }
1857*5f757f3fSDimitry Andric 
1858*5f757f3fSDimitry Andric const PatFrag *CombineRuleBuilder::parsePatFrag(const Record *Def) const {
1859*5f757f3fSDimitry Andric   // Cache already parsed PatFrags to avoid doing extra work.
1860*5f757f3fSDimitry Andric   static DenseMap<const Record *, std::unique_ptr<PatFrag>> ParsedPatFrags;
1861*5f757f3fSDimitry Andric 
1862*5f757f3fSDimitry Andric   auto It = ParsedPatFrags.find(Def);
1863*5f757f3fSDimitry Andric   if (It != ParsedPatFrags.end()) {
1864*5f757f3fSDimitry Andric     SeenPatFrags.insert(It->second.get());
1865*5f757f3fSDimitry Andric     return It->second.get();
1866*5f757f3fSDimitry Andric   }
1867*5f757f3fSDimitry Andric 
1868*5f757f3fSDimitry Andric   std::unique_ptr<PatFrag> NewPatFrag = parsePatFragImpl(Def);
1869*5f757f3fSDimitry Andric   if (!NewPatFrag) {
1870*5f757f3fSDimitry Andric     ::PrintError(Def, "Could not parse " + PatFrag::ClassName + " '" +
1871*5f757f3fSDimitry Andric                           Def->getName() + "'");
1872*5f757f3fSDimitry Andric     // Put a nullptr in the map so we don't attempt parsing this again.
1873*5f757f3fSDimitry Andric     ParsedPatFrags[Def] = nullptr;
1874*5f757f3fSDimitry Andric     return nullptr;
1875*5f757f3fSDimitry Andric   }
1876*5f757f3fSDimitry Andric 
1877*5f757f3fSDimitry Andric   const auto *Res = NewPatFrag.get();
1878*5f757f3fSDimitry Andric   ParsedPatFrags[Def] = std::move(NewPatFrag);
1879*5f757f3fSDimitry Andric   SeenPatFrags.insert(Res);
1880*5f757f3fSDimitry Andric   return Res;
1881*5f757f3fSDimitry Andric }
1882*5f757f3fSDimitry Andric 
1883*5f757f3fSDimitry Andric bool CombineRuleBuilder::emitMatchPattern(CodeExpansions &CE,
1884*5f757f3fSDimitry Andric                                           const PatternAlternatives &Alts,
1885*5f757f3fSDimitry Andric                                           const InstructionPattern &IP) {
1886*5f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef, &IP);
1887*5f757f3fSDimitry Andric 
1888*5f757f3fSDimitry Andric   auto &M = addRuleMatcher(Alts);
1889*5f757f3fSDimitry Andric   InstructionMatcher &IM = M.addInstructionMatcher(IP.getName());
1890*5f757f3fSDimitry Andric   declareInstExpansion(CE, IM, IP.getName());
1891*5f757f3fSDimitry Andric 
1892*5f757f3fSDimitry Andric   DenseSet<const Pattern *> SeenPats;
1893*5f757f3fSDimitry Andric 
1894*5f757f3fSDimitry Andric   const auto FindOperandDef = [&](StringRef Op) -> InstructionPattern * {
1895*5f757f3fSDimitry Andric     return MatchOpTable.getDef(Op);
1896*5f757f3fSDimitry Andric   };
1897*5f757f3fSDimitry Andric 
1898*5f757f3fSDimitry Andric   if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&IP)) {
1899*5f757f3fSDimitry Andric     if (!emitCodeGenInstructionMatchPattern(CE, Alts, M, IM, *CGP, SeenPats,
1900*5f757f3fSDimitry Andric                                             FindOperandDef))
1901*5f757f3fSDimitry Andric       return false;
1902*5f757f3fSDimitry Andric   } else if (const auto *PFP = dyn_cast<PatFragPattern>(&IP)) {
1903*5f757f3fSDimitry Andric     if (!PFP->getPatFrag().canBeMatchRoot()) {
1904*5f757f3fSDimitry Andric       PrintError("cannot use '" + PFP->getInstName() + " as match root");
1905*5f757f3fSDimitry Andric       return false;
1906*5f757f3fSDimitry Andric     }
1907*5f757f3fSDimitry Andric 
1908*5f757f3fSDimitry Andric     if (!emitPatFragMatchPattern(CE, Alts, M, &IM, *PFP, SeenPats))
1909*5f757f3fSDimitry Andric       return false;
1910*5f757f3fSDimitry Andric   } else if (isa<BuiltinPattern>(&IP)) {
1911*5f757f3fSDimitry Andric     llvm_unreachable("No match builtins known!");
1912*5f757f3fSDimitry Andric   } else
1913*5f757f3fSDimitry Andric     llvm_unreachable("Unknown kind of InstructionPattern!");
1914*5f757f3fSDimitry Andric 
1915*5f757f3fSDimitry Andric   // Emit remaining patterns
1916*5f757f3fSDimitry Andric   for (auto &Pat : values(MatchPats)) {
1917*5f757f3fSDimitry Andric     if (SeenPats.contains(Pat.get()))
1918*5f757f3fSDimitry Andric       continue;
1919*5f757f3fSDimitry Andric 
1920*5f757f3fSDimitry Andric     switch (Pat->getKind()) {
1921*5f757f3fSDimitry Andric     case Pattern::K_AnyOpcode:
1922*5f757f3fSDimitry Andric       PrintError("wip_match_opcode can not be used with instruction patterns!");
1923*5f757f3fSDimitry Andric       return false;
1924*5f757f3fSDimitry Andric     case Pattern::K_PatFrag: {
1925*5f757f3fSDimitry Andric       if (!emitPatFragMatchPattern(CE, Alts, M, /*IM*/ nullptr,
1926*5f757f3fSDimitry Andric                                    *cast<PatFragPattern>(Pat.get()), SeenPats))
1927*5f757f3fSDimitry Andric         return false;
1928*5f757f3fSDimitry Andric       continue;
1929*5f757f3fSDimitry Andric     }
1930*5f757f3fSDimitry Andric     case Pattern::K_Builtin:
1931*5f757f3fSDimitry Andric       PrintError("No known match builtins");
1932*5f757f3fSDimitry Andric       return false;
1933*5f757f3fSDimitry Andric     case Pattern::K_CodeGenInstruction:
1934*5f757f3fSDimitry Andric       cast<InstructionPattern>(Pat.get())->reportUnreachable(RuleDef.getLoc());
1935*5f757f3fSDimitry Andric       return false;
1936*5f757f3fSDimitry Andric     case Pattern::K_CXX: {
1937*5f757f3fSDimitry Andric       addCXXPredicate(M, CE, *cast<CXXPattern>(Pat.get()), Alts);
1938*5f757f3fSDimitry Andric       continue;
1939*5f757f3fSDimitry Andric     }
1940*5f757f3fSDimitry Andric     default:
1941*5f757f3fSDimitry Andric       llvm_unreachable("unknown pattern kind!");
1942*5f757f3fSDimitry Andric     }
1943*5f757f3fSDimitry Andric   }
1944*5f757f3fSDimitry Andric 
1945*5f757f3fSDimitry Andric   return emitApplyPatterns(CE, M);
1946*5f757f3fSDimitry Andric }
1947*5f757f3fSDimitry Andric 
1948*5f757f3fSDimitry Andric bool CombineRuleBuilder::emitMatchPattern(CodeExpansions &CE,
1949*5f757f3fSDimitry Andric                                           const PatternAlternatives &Alts,
1950*5f757f3fSDimitry Andric                                           const AnyOpcodePattern &AOP) {
1951*5f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef, &AOP);
1952*5f757f3fSDimitry Andric 
1953*5f757f3fSDimitry Andric   for (const CodeGenInstruction *CGI : AOP.insts()) {
1954*5f757f3fSDimitry Andric     auto &M = addRuleMatcher(Alts, "wip_match_opcode '" +
1955*5f757f3fSDimitry Andric                                        CGI->TheDef->getName() + "'");
1956*5f757f3fSDimitry Andric 
1957*5f757f3fSDimitry Andric     InstructionMatcher &IM = M.addInstructionMatcher(AOP.getName());
1958*5f757f3fSDimitry Andric     declareInstExpansion(CE, IM, AOP.getName());
1959*5f757f3fSDimitry Andric     // declareInstExpansion needs to be identical, otherwise we need to create a
1960*5f757f3fSDimitry Andric     // CodeExpansions object here instead.
1961*5f757f3fSDimitry Andric     assert(IM.getInsnVarID() == 0);
1962*5f757f3fSDimitry Andric 
1963*5f757f3fSDimitry Andric     IM.addPredicate<InstructionOpcodeMatcher>(CGI);
1964*5f757f3fSDimitry Andric 
1965*5f757f3fSDimitry Andric     // Emit remaining patterns.
1966*5f757f3fSDimitry Andric     for (auto &Pat : values(MatchPats)) {
1967*5f757f3fSDimitry Andric       if (Pat.get() == &AOP)
1968*5f757f3fSDimitry Andric         continue;
1969*5f757f3fSDimitry Andric 
1970*5f757f3fSDimitry Andric       switch (Pat->getKind()) {
1971*5f757f3fSDimitry Andric       case Pattern::K_AnyOpcode:
1972*5f757f3fSDimitry Andric         PrintError("wip_match_opcode can only be present once!");
1973*5f757f3fSDimitry Andric         return false;
1974*5f757f3fSDimitry Andric       case Pattern::K_PatFrag: {
1975*5f757f3fSDimitry Andric         DenseSet<const Pattern *> SeenPats;
1976*5f757f3fSDimitry Andric         if (!emitPatFragMatchPattern(CE, Alts, M, /*IM*/ nullptr,
1977*5f757f3fSDimitry Andric                                      *cast<PatFragPattern>(Pat.get()),
1978*5f757f3fSDimitry Andric                                      SeenPats))
1979*5f757f3fSDimitry Andric           return false;
1980*5f757f3fSDimitry Andric         continue;
1981*5f757f3fSDimitry Andric       }
1982*5f757f3fSDimitry Andric       case Pattern::K_Builtin:
1983*5f757f3fSDimitry Andric         PrintError("No known match builtins");
1984*5f757f3fSDimitry Andric         return false;
1985*5f757f3fSDimitry Andric       case Pattern::K_CodeGenInstruction:
1986*5f757f3fSDimitry Andric         cast<InstructionPattern>(Pat.get())->reportUnreachable(
1987*5f757f3fSDimitry Andric             RuleDef.getLoc());
1988*5f757f3fSDimitry Andric         return false;
1989*5f757f3fSDimitry Andric       case Pattern::K_CXX: {
1990*5f757f3fSDimitry Andric         addCXXPredicate(M, CE, *cast<CXXPattern>(Pat.get()), Alts);
1991*5f757f3fSDimitry Andric         break;
1992*5f757f3fSDimitry Andric       }
1993*5f757f3fSDimitry Andric       default:
1994*5f757f3fSDimitry Andric         llvm_unreachable("unknown pattern kind!");
1995*5f757f3fSDimitry Andric       }
1996*5f757f3fSDimitry Andric     }
1997*5f757f3fSDimitry Andric 
1998*5f757f3fSDimitry Andric     if (!emitApplyPatterns(CE, M))
1999*5f757f3fSDimitry Andric       return false;
2000*5f757f3fSDimitry Andric   }
2001*5f757f3fSDimitry Andric 
2002*5f757f3fSDimitry Andric   return true;
2003*5f757f3fSDimitry Andric }
2004*5f757f3fSDimitry Andric 
2005*5f757f3fSDimitry Andric bool CombineRuleBuilder::emitPatFragMatchPattern(
2006*5f757f3fSDimitry Andric     CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &RM,
2007*5f757f3fSDimitry Andric     InstructionMatcher *IM, const PatFragPattern &PFP,
2008*5f757f3fSDimitry Andric     DenseSet<const Pattern *> &SeenPats) {
2009*5f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef, &PFP);
2010*5f757f3fSDimitry Andric 
2011*5f757f3fSDimitry Andric   if (SeenPats.contains(&PFP))
2012*5f757f3fSDimitry Andric     return true;
2013*5f757f3fSDimitry Andric   SeenPats.insert(&PFP);
2014*5f757f3fSDimitry Andric 
2015*5f757f3fSDimitry Andric   const auto &PF = PFP.getPatFrag();
2016*5f757f3fSDimitry Andric 
2017*5f757f3fSDimitry Andric   if (!IM) {
2018*5f757f3fSDimitry Andric     // When we don't have an IM, this means this PatFrag isn't reachable from
2019*5f757f3fSDimitry Andric     // the root. This is only acceptable if it doesn't define anything (e.g. a
2020*5f757f3fSDimitry Andric     // pure C++ PatFrag).
2021*5f757f3fSDimitry Andric     if (PF.num_out_params() != 0) {
2022*5f757f3fSDimitry Andric       PFP.reportUnreachable(RuleDef.getLoc());
2023*5f757f3fSDimitry Andric       return false;
2024*5f757f3fSDimitry Andric     }
2025*5f757f3fSDimitry Andric   } else {
2026*5f757f3fSDimitry Andric     // When an IM is provided, this is reachable from the root, and we're
2027*5f757f3fSDimitry Andric     // expecting to have output operands.
2028*5f757f3fSDimitry Andric     // TODO: If we want to allow for multiple roots we'll need a map of IMs
2029*5f757f3fSDimitry Andric     // then, and emission becomes a bit more complicated.
2030*5f757f3fSDimitry Andric     assert(PF.num_roots() == 1);
2031*5f757f3fSDimitry Andric   }
2032*5f757f3fSDimitry Andric 
2033*5f757f3fSDimitry Andric   CodeExpansions PatFragCEs;
2034*5f757f3fSDimitry Andric   if (!PFP.mapInputCodeExpansions(CE, PatFragCEs, RuleDef.getLoc()))
2035*5f757f3fSDimitry Andric     return false;
2036*5f757f3fSDimitry Andric 
2037*5f757f3fSDimitry Andric   // List of {ParamName, ArgName}.
2038*5f757f3fSDimitry Andric   // When all patterns have been emitted, find expansions in PatFragCEs named
2039*5f757f3fSDimitry Andric   // ArgName and add their expansion to CE using ParamName as the key.
2040*5f757f3fSDimitry Andric   SmallVector<std::pair<std::string, std::string>, 4> CEsToImport;
2041*5f757f3fSDimitry Andric 
2042*5f757f3fSDimitry Andric   // Map parameter names to the actual argument.
2043*5f757f3fSDimitry Andric   const auto OperandMapper =
2044*5f757f3fSDimitry Andric       [&](const InstructionOperand &O) -> InstructionOperand {
2045*5f757f3fSDimitry Andric     if (!O.isNamedOperand())
2046*5f757f3fSDimitry Andric       return O;
2047*5f757f3fSDimitry Andric 
2048*5f757f3fSDimitry Andric     StringRef ParamName = O.getOperandName();
2049*5f757f3fSDimitry Andric 
2050*5f757f3fSDimitry Andric     // Not sure what to do with those tbh. They should probably never be here.
2051*5f757f3fSDimitry Andric     assert(!O.isNamedImmediate() && "TODO: handle named imms");
2052*5f757f3fSDimitry Andric     unsigned PIdx = PF.getParamIdx(ParamName);
2053*5f757f3fSDimitry Andric 
2054*5f757f3fSDimitry Andric     // Map parameters to the argument values.
2055*5f757f3fSDimitry Andric     if (PIdx == (unsigned)-1) {
2056*5f757f3fSDimitry Andric       // This is a temp of the PatFragPattern, prefix the name to avoid
2057*5f757f3fSDimitry Andric       // conflicts.
2058*5f757f3fSDimitry Andric       return O.withNewName(
2059*5f757f3fSDimitry Andric           insertStrRef((PFP.getName() + "." + ParamName).str()));
2060*5f757f3fSDimitry Andric     }
2061*5f757f3fSDimitry Andric 
2062*5f757f3fSDimitry Andric     // The operand will be added to PatFragCEs's code expansions using the
2063*5f757f3fSDimitry Andric     // parameter's name. If it's bound to some operand during emission of the
2064*5f757f3fSDimitry Andric     // patterns, we'll want to add it to CE.
2065*5f757f3fSDimitry Andric     auto ArgOp = PFP.getOperand(PIdx);
2066*5f757f3fSDimitry Andric     if (ArgOp.isNamedOperand())
2067*5f757f3fSDimitry Andric       CEsToImport.emplace_back(ArgOp.getOperandName().str(), ParamName);
2068*5f757f3fSDimitry Andric 
2069*5f757f3fSDimitry Andric     if (ArgOp.getType() && O.getType() && ArgOp.getType() != O.getType()) {
2070*5f757f3fSDimitry Andric       StringRef PFName = PF.getName();
2071*5f757f3fSDimitry Andric       PrintWarning("impossible type constraints: operand " + Twine(PIdx) +
2072*5f757f3fSDimitry Andric                    " of '" + PFP.getName() + "' has type '" +
2073*5f757f3fSDimitry Andric                    ArgOp.getType().str() + "', but '" + PFName +
2074*5f757f3fSDimitry Andric                    "' constrains it to '" + O.getType().str() + "'");
2075*5f757f3fSDimitry Andric       if (ArgOp.isNamedOperand())
2076*5f757f3fSDimitry Andric         PrintNote("operand " + Twine(PIdx) + " of '" + PFP.getName() +
2077*5f757f3fSDimitry Andric                   "' is '" + ArgOp.getOperandName() + "'");
2078*5f757f3fSDimitry Andric       if (O.isNamedOperand())
2079*5f757f3fSDimitry Andric         PrintNote("argument " + Twine(PIdx) + " of '" + PFName + "' is '" +
2080*5f757f3fSDimitry Andric                   ParamName + "'");
2081*5f757f3fSDimitry Andric     }
2082*5f757f3fSDimitry Andric 
2083*5f757f3fSDimitry Andric     return ArgOp;
2084*5f757f3fSDimitry Andric   };
2085*5f757f3fSDimitry Andric 
2086*5f757f3fSDimitry Andric   // PatFragPatterns are only made of InstructionPatterns or CXXPatterns.
2087*5f757f3fSDimitry Andric   // Emit instructions from the root.
2088*5f757f3fSDimitry Andric   const auto &FragAlt = PF.getAlternative(Alts.lookup(&PFP));
2089*5f757f3fSDimitry Andric   const auto &FragAltOT = FragAlt.OpTable;
2090*5f757f3fSDimitry Andric   const auto LookupOperandDef =
2091*5f757f3fSDimitry Andric       [&](StringRef Op) -> const InstructionPattern * {
2092*5f757f3fSDimitry Andric     return FragAltOT.getDef(Op);
2093*5f757f3fSDimitry Andric   };
2094*5f757f3fSDimitry Andric 
2095*5f757f3fSDimitry Andric   DenseSet<const Pattern *> PatFragSeenPats;
2096*5f757f3fSDimitry Andric   for (const auto &[Idx, InOp] : enumerate(PF.out_params())) {
2097*5f757f3fSDimitry Andric     if (InOp.Kind != PatFrag::PK_Root)
2098*5f757f3fSDimitry Andric       continue;
2099*5f757f3fSDimitry Andric 
2100*5f757f3fSDimitry Andric     StringRef ParamName = InOp.Name;
2101*5f757f3fSDimitry Andric     const auto *Def = FragAltOT.getDef(ParamName);
2102*5f757f3fSDimitry Andric     assert(Def && "PatFrag::checkSemantics should have emitted an error if "
2103*5f757f3fSDimitry Andric                   "an out operand isn't defined!");
2104*5f757f3fSDimitry Andric     assert(isa<CodeGenInstructionPattern>(Def) &&
2105*5f757f3fSDimitry Andric            "Nested PatFrags not supported yet");
2106*5f757f3fSDimitry Andric 
2107*5f757f3fSDimitry Andric     if (!emitCodeGenInstructionMatchPattern(
2108*5f757f3fSDimitry Andric             PatFragCEs, Alts, RM, *IM, *cast<CodeGenInstructionPattern>(Def),
2109*5f757f3fSDimitry Andric             PatFragSeenPats, LookupOperandDef, OperandMapper))
2110*5f757f3fSDimitry Andric       return false;
2111*5f757f3fSDimitry Andric   }
2112*5f757f3fSDimitry Andric 
2113*5f757f3fSDimitry Andric   // Emit leftovers.
2114*5f757f3fSDimitry Andric   for (const auto &Pat : FragAlt.Pats) {
2115*5f757f3fSDimitry Andric     if (PatFragSeenPats.contains(Pat.get()))
2116*5f757f3fSDimitry Andric       continue;
2117*5f757f3fSDimitry Andric 
2118*5f757f3fSDimitry Andric     if (const auto *CXXPat = dyn_cast<CXXPattern>(Pat.get())) {
2119*5f757f3fSDimitry Andric       addCXXPredicate(RM, PatFragCEs, *CXXPat, Alts);
2120*5f757f3fSDimitry Andric       continue;
2121*5f757f3fSDimitry Andric     }
2122*5f757f3fSDimitry Andric 
2123*5f757f3fSDimitry Andric     if (const auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
2124*5f757f3fSDimitry Andric       IP->reportUnreachable(PF.getLoc());
2125*5f757f3fSDimitry Andric       return false;
2126*5f757f3fSDimitry Andric     }
2127*5f757f3fSDimitry Andric 
2128*5f757f3fSDimitry Andric     llvm_unreachable("Unexpected pattern kind in PatFrag");
2129*5f757f3fSDimitry Andric   }
2130*5f757f3fSDimitry Andric 
2131*5f757f3fSDimitry Andric   for (const auto &[ParamName, ArgName] : CEsToImport) {
2132*5f757f3fSDimitry Andric     // Note: we're find if ParamName already exists. It just means it's been
2133*5f757f3fSDimitry Andric     // bound before, so we prefer to keep the first binding.
2134*5f757f3fSDimitry Andric     CE.declare(ParamName, PatFragCEs.lookup(ArgName));
2135*5f757f3fSDimitry Andric   }
2136*5f757f3fSDimitry Andric 
2137*5f757f3fSDimitry Andric   return true;
2138*5f757f3fSDimitry Andric }
2139*5f757f3fSDimitry Andric 
2140*5f757f3fSDimitry Andric bool CombineRuleBuilder::emitApplyPatterns(CodeExpansions &CE, RuleMatcher &M) {
2141*5f757f3fSDimitry Andric   if (hasOnlyCXXApplyPatterns()) {
2142*5f757f3fSDimitry Andric     for (auto &Pat : values(ApplyPats))
2143*5f757f3fSDimitry Andric       addCXXAction(M, CE, *cast<CXXPattern>(Pat.get()));
2144*5f757f3fSDimitry Andric     return true;
2145*5f757f3fSDimitry Andric   }
2146*5f757f3fSDimitry Andric 
2147*5f757f3fSDimitry Andric   DenseSet<const Pattern *> SeenPats;
2148*5f757f3fSDimitry Andric   StringMap<unsigned> OperandToTempRegID;
2149*5f757f3fSDimitry Andric 
2150*5f757f3fSDimitry Andric   for (auto *ApplyRoot : ApplyRoots) {
2151*5f757f3fSDimitry Andric     assert(isa<InstructionPattern>(ApplyRoot) &&
2152*5f757f3fSDimitry Andric            "Root can only be a InstructionPattern!");
2153*5f757f3fSDimitry Andric     if (!emitInstructionApplyPattern(CE, M,
2154*5f757f3fSDimitry Andric                                      cast<InstructionPattern>(*ApplyRoot),
2155*5f757f3fSDimitry Andric                                      SeenPats, OperandToTempRegID))
2156*5f757f3fSDimitry Andric       return false;
2157*5f757f3fSDimitry Andric   }
2158*5f757f3fSDimitry Andric 
2159*5f757f3fSDimitry Andric   for (auto &Pat : values(ApplyPats)) {
2160*5f757f3fSDimitry Andric     if (SeenPats.contains(Pat.get()))
2161*5f757f3fSDimitry Andric       continue;
2162*5f757f3fSDimitry Andric 
2163*5f757f3fSDimitry Andric     switch (Pat->getKind()) {
2164*5f757f3fSDimitry Andric     case Pattern::K_AnyOpcode:
2165*5f757f3fSDimitry Andric       llvm_unreachable("Unexpected pattern in apply!");
2166*5f757f3fSDimitry Andric     case Pattern::K_PatFrag:
2167*5f757f3fSDimitry Andric       // TODO: We could support pure C++ PatFrags as a temporary thing.
2168*5f757f3fSDimitry Andric       llvm_unreachable("Unexpected pattern in apply!");
2169*5f757f3fSDimitry Andric     case Pattern::K_Builtin:
2170*5f757f3fSDimitry Andric       if (!emitInstructionApplyPattern(CE, M, cast<BuiltinPattern>(*Pat),
2171*5f757f3fSDimitry Andric                                        SeenPats, OperandToTempRegID))
2172*5f757f3fSDimitry Andric         return false;
2173*5f757f3fSDimitry Andric       break;
2174*5f757f3fSDimitry Andric     case Pattern::K_CodeGenInstruction:
2175*5f757f3fSDimitry Andric       cast<CodeGenInstructionPattern>(*Pat).reportUnreachable(RuleDef.getLoc());
2176*5f757f3fSDimitry Andric       return false;
2177*5f757f3fSDimitry Andric     case Pattern::K_CXX: {
2178*5f757f3fSDimitry Andric       addCXXAction(M, CE, *cast<CXXPattern>(Pat.get()));
2179*5f757f3fSDimitry Andric       continue;
2180*5f757f3fSDimitry Andric     }
2181*5f757f3fSDimitry Andric     default:
2182*5f757f3fSDimitry Andric       llvm_unreachable("unknown pattern kind!");
2183*5f757f3fSDimitry Andric     }
2184*5f757f3fSDimitry Andric   }
2185*5f757f3fSDimitry Andric 
2186*5f757f3fSDimitry Andric   return true;
2187*5f757f3fSDimitry Andric }
2188*5f757f3fSDimitry Andric 
2189*5f757f3fSDimitry Andric bool CombineRuleBuilder::emitInstructionApplyPattern(
2190*5f757f3fSDimitry Andric     CodeExpansions &CE, RuleMatcher &M, const InstructionPattern &P,
2191*5f757f3fSDimitry Andric     DenseSet<const Pattern *> &SeenPats,
2192*5f757f3fSDimitry Andric     StringMap<unsigned> &OperandToTempRegID) {
2193*5f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef, &P);
2194*5f757f3fSDimitry Andric 
2195*5f757f3fSDimitry Andric   if (SeenPats.contains(&P))
2196*5f757f3fSDimitry Andric     return true;
2197*5f757f3fSDimitry Andric 
2198*5f757f3fSDimitry Andric   SeenPats.insert(&P);
2199*5f757f3fSDimitry Andric 
2200*5f757f3fSDimitry Andric   // First, render the uses.
2201*5f757f3fSDimitry Andric   for (auto &Op : P.named_operands()) {
2202*5f757f3fSDimitry Andric     if (Op.isDef())
2203*5f757f3fSDimitry Andric       continue;
2204*5f757f3fSDimitry Andric 
2205*5f757f3fSDimitry Andric     StringRef OpName = Op.getOperandName();
2206*5f757f3fSDimitry Andric     if (const auto *DefPat = ApplyOpTable.getDef(OpName)) {
2207*5f757f3fSDimitry Andric       if (!emitInstructionApplyPattern(CE, M, *DefPat, SeenPats,
2208*5f757f3fSDimitry Andric                                        OperandToTempRegID))
2209*5f757f3fSDimitry Andric         return false;
2210*5f757f3fSDimitry Andric     } else {
2211*5f757f3fSDimitry Andric       // If we have no def, check this exists in the MatchRoot.
2212*5f757f3fSDimitry Andric       if (!Op.isNamedImmediate() && !MatchOpTable.lookup(OpName).Found) {
2213*5f757f3fSDimitry Andric         PrintError("invalid output operand '" + OpName +
2214*5f757f3fSDimitry Andric                    "': operand is not a live-in of the match pattern, and it "
2215*5f757f3fSDimitry Andric                    "has no definition");
2216*5f757f3fSDimitry Andric         return false;
2217*5f757f3fSDimitry Andric       }
2218*5f757f3fSDimitry Andric     }
2219*5f757f3fSDimitry Andric   }
2220*5f757f3fSDimitry Andric 
2221*5f757f3fSDimitry Andric   if (const auto *BP = dyn_cast<BuiltinPattern>(&P))
2222*5f757f3fSDimitry Andric     return emitBuiltinApplyPattern(CE, M, *BP, OperandToTempRegID);
2223*5f757f3fSDimitry Andric 
2224*5f757f3fSDimitry Andric   if (isa<PatFragPattern>(&P))
2225*5f757f3fSDimitry Andric     llvm_unreachable("PatFragPatterns is not supported in 'apply'!");
2226*5f757f3fSDimitry Andric 
2227*5f757f3fSDimitry Andric   auto &CGIP = cast<CodeGenInstructionPattern>(P);
2228*5f757f3fSDimitry Andric 
2229*5f757f3fSDimitry Andric   // Now render this inst.
2230*5f757f3fSDimitry Andric   auto &DstMI =
2231*5f757f3fSDimitry Andric       M.addAction<BuildMIAction>(M.allocateOutputInsnID(), &CGIP.getInst());
2232*5f757f3fSDimitry Andric 
2233*5f757f3fSDimitry Andric   for (auto &Op : P.operands()) {
2234*5f757f3fSDimitry Andric     if (Op.isNamedImmediate()) {
2235*5f757f3fSDimitry Andric       PrintError("invalid output operand '" + Op.getOperandName() +
2236*5f757f3fSDimitry Andric                  "': output immediates cannot be named");
2237*5f757f3fSDimitry Andric       PrintNote("while emitting pattern '" + P.getName() + "' (" +
2238*5f757f3fSDimitry Andric                 P.getInstName() + ")");
2239*5f757f3fSDimitry Andric       return false;
2240*5f757f3fSDimitry Andric     }
2241*5f757f3fSDimitry Andric 
2242*5f757f3fSDimitry Andric     if (Op.hasImmValue()) {
2243*5f757f3fSDimitry Andric       if (!emitCodeGenInstructionApplyImmOperand(M, DstMI, CGIP, Op))
2244*5f757f3fSDimitry Andric         return false;
2245*5f757f3fSDimitry Andric       continue;
2246*5f757f3fSDimitry Andric     }
2247*5f757f3fSDimitry Andric 
2248*5f757f3fSDimitry Andric     StringRef OpName = Op.getOperandName();
2249*5f757f3fSDimitry Andric 
2250*5f757f3fSDimitry Andric     // Uses of operand.
2251*5f757f3fSDimitry Andric     if (!Op.isDef()) {
2252*5f757f3fSDimitry Andric       if (auto It = OperandToTempRegID.find(OpName);
2253*5f757f3fSDimitry Andric           It != OperandToTempRegID.end()) {
2254*5f757f3fSDimitry Andric         assert(!MatchOpTable.lookup(OpName).Found &&
2255*5f757f3fSDimitry Andric                "Temp reg is also from match pattern?");
2256*5f757f3fSDimitry Andric         DstMI.addRenderer<TempRegRenderer>(It->second);
2257*5f757f3fSDimitry Andric       } else {
2258*5f757f3fSDimitry Andric         // This should be a match live in or a redef of a matched instr.
2259*5f757f3fSDimitry Andric         // If it's a use of a temporary register, then we messed up somewhere -
2260*5f757f3fSDimitry Andric         // the previous condition should have passed.
2261*5f757f3fSDimitry Andric         assert(MatchOpTable.lookup(OpName).Found &&
2262*5f757f3fSDimitry Andric                !ApplyOpTable.getDef(OpName) && "Temp reg not emitted yet!");
2263*5f757f3fSDimitry Andric         DstMI.addRenderer<CopyRenderer>(OpName);
2264*5f757f3fSDimitry Andric       }
2265*5f757f3fSDimitry Andric       continue;
2266*5f757f3fSDimitry Andric     }
2267*5f757f3fSDimitry Andric 
2268*5f757f3fSDimitry Andric     // Determine what we're dealing with. Are we replace a matched instruction?
2269*5f757f3fSDimitry Andric     // Creating a new one?
2270*5f757f3fSDimitry Andric     auto OpLookupRes = MatchOpTable.lookup(OpName);
2271*5f757f3fSDimitry Andric     if (OpLookupRes.Found) {
2272*5f757f3fSDimitry Andric       if (OpLookupRes.isLiveIn()) {
2273*5f757f3fSDimitry Andric         // live-in of the match pattern.
2274*5f757f3fSDimitry Andric         PrintError("Cannot define live-in operand '" + OpName +
2275*5f757f3fSDimitry Andric                    "' in the 'apply' pattern");
2276*5f757f3fSDimitry Andric         return false;
2277*5f757f3fSDimitry Andric       }
2278*5f757f3fSDimitry Andric       assert(OpLookupRes.Def);
2279*5f757f3fSDimitry Andric 
2280*5f757f3fSDimitry Andric       // TODO: Handle this. We need to mutate the instr, or delete the old
2281*5f757f3fSDimitry Andric       // one.
2282*5f757f3fSDimitry Andric       //       Likewise, we also need to ensure we redef everything, if the
2283*5f757f3fSDimitry Andric       //       instr has more than one def, we need to redef all or nothing.
2284*5f757f3fSDimitry Andric       if (OpLookupRes.Def != MatchRoot) {
2285*5f757f3fSDimitry Andric         PrintError("redefining an instruction other than the root is not "
2286*5f757f3fSDimitry Andric                    "supported (operand '" +
2287*5f757f3fSDimitry Andric                    OpName + "')");
2288*5f757f3fSDimitry Andric         return false;
2289*5f757f3fSDimitry Andric       }
2290*5f757f3fSDimitry Andric       // redef of a match
2291*5f757f3fSDimitry Andric       DstMI.addRenderer<CopyRenderer>(OpName);
2292*5f757f3fSDimitry Andric       continue;
2293*5f757f3fSDimitry Andric     }
2294*5f757f3fSDimitry Andric 
2295*5f757f3fSDimitry Andric     // Define a new register unique to the apply patterns (AKA a "temp"
2296*5f757f3fSDimitry Andric     // register).
2297*5f757f3fSDimitry Andric     unsigned TempRegID;
2298*5f757f3fSDimitry Andric     if (auto It = OperandToTempRegID.find(OpName);
2299*5f757f3fSDimitry Andric         It != OperandToTempRegID.end()) {
2300*5f757f3fSDimitry Andric       TempRegID = It->second;
2301*5f757f3fSDimitry Andric     } else {
2302*5f757f3fSDimitry Andric       // This is a brand new register.
2303*5f757f3fSDimitry Andric       TempRegID = M.allocateTempRegID();
2304*5f757f3fSDimitry Andric       OperandToTempRegID[OpName] = TempRegID;
2305*5f757f3fSDimitry Andric       const auto Ty = Op.getType();
2306*5f757f3fSDimitry Andric       if (!Ty) {
2307*5f757f3fSDimitry Andric         PrintError("def of a new register '" + OpName +
2308*5f757f3fSDimitry Andric                    "' in the apply patterns must have a type");
2309*5f757f3fSDimitry Andric         return false;
2310*5f757f3fSDimitry Andric       }
2311*5f757f3fSDimitry Andric 
2312*5f757f3fSDimitry Andric       declareTempRegExpansion(CE, TempRegID, OpName);
2313*5f757f3fSDimitry Andric       // Always insert the action at the beginning, otherwise we may end up
2314*5f757f3fSDimitry Andric       // using the temp reg before it's available.
2315*5f757f3fSDimitry Andric       M.insertAction<MakeTempRegisterAction>(
2316*5f757f3fSDimitry Andric           M.actions_begin(), getLLTCodeGenOrTempType(Ty, M), TempRegID);
2317*5f757f3fSDimitry Andric     }
2318*5f757f3fSDimitry Andric 
2319*5f757f3fSDimitry Andric     DstMI.addRenderer<TempRegRenderer>(TempRegID);
2320*5f757f3fSDimitry Andric   }
2321*5f757f3fSDimitry Andric 
2322*5f757f3fSDimitry Andric   // Render MIFlags
2323*5f757f3fSDimitry Andric   if (const auto *FI = CGIP.getMIFlagsInfo()) {
2324*5f757f3fSDimitry Andric     for (StringRef InstName : FI->copy_flags())
2325*5f757f3fSDimitry Andric       DstMI.addCopiedMIFlags(M.getInstructionMatcher(InstName));
2326*5f757f3fSDimitry Andric     for (StringRef F : FI->set_flags())
2327*5f757f3fSDimitry Andric       DstMI.addSetMIFlags(F);
2328*5f757f3fSDimitry Andric     for (StringRef F : FI->unset_flags())
2329*5f757f3fSDimitry Andric       DstMI.addUnsetMIFlags(F);
2330*5f757f3fSDimitry Andric   }
2331*5f757f3fSDimitry Andric 
2332*5f757f3fSDimitry Andric   // Don't allow mutating opcodes for GISel combiners. We want a more precise
2333*5f757f3fSDimitry Andric   // handling of MIFlags so we require them to be explicitly preserved.
2334*5f757f3fSDimitry Andric   //
2335*5f757f3fSDimitry Andric   // TODO: We don't mutate very often, if at all in combiners, but it'd be nice
2336*5f757f3fSDimitry Andric   // to re-enable this. We'd then need to always clear MIFlags when mutating
2337*5f757f3fSDimitry Andric   // opcodes, and never mutate an inst that we copy flags from.
2338*5f757f3fSDimitry Andric   // DstMI.chooseInsnToMutate(M);
2339*5f757f3fSDimitry Andric   declareInstExpansion(CE, DstMI, P.getName());
2340*5f757f3fSDimitry Andric 
2341*5f757f3fSDimitry Andric   return true;
2342*5f757f3fSDimitry Andric }
2343*5f757f3fSDimitry Andric 
2344*5f757f3fSDimitry Andric bool CombineRuleBuilder::emitCodeGenInstructionApplyImmOperand(
2345*5f757f3fSDimitry Andric     RuleMatcher &M, BuildMIAction &DstMI, const CodeGenInstructionPattern &P,
2346*5f757f3fSDimitry Andric     const InstructionOperand &O) {
2347*5f757f3fSDimitry Andric   // If we have a type, we implicitly emit a G_CONSTANT, except for G_CONSTANT
2348*5f757f3fSDimitry Andric   // itself where we emit a CImm.
2349*5f757f3fSDimitry Andric   //
2350*5f757f3fSDimitry Andric   // No type means we emit a simple imm.
2351*5f757f3fSDimitry Andric   // G_CONSTANT is a special case and needs a CImm though so this is likely a
2352*5f757f3fSDimitry Andric   // mistake.
2353*5f757f3fSDimitry Andric   const bool isGConstant = P.is("G_CONSTANT");
2354*5f757f3fSDimitry Andric   const auto Ty = O.getType();
2355*5f757f3fSDimitry Andric   if (!Ty) {
2356*5f757f3fSDimitry Andric     if (isGConstant) {
2357*5f757f3fSDimitry Andric       PrintError("'G_CONSTANT' immediate must be typed!");
2358*5f757f3fSDimitry Andric       PrintNote("while emitting pattern '" + P.getName() + "' (" +
2359*5f757f3fSDimitry Andric                 P.getInstName() + ")");
2360*5f757f3fSDimitry Andric       return false;
2361*5f757f3fSDimitry Andric     }
2362*5f757f3fSDimitry Andric 
2363*5f757f3fSDimitry Andric     DstMI.addRenderer<ImmRenderer>(O.getImmValue());
2364*5f757f3fSDimitry Andric     return true;
2365*5f757f3fSDimitry Andric   }
2366*5f757f3fSDimitry Andric 
2367*5f757f3fSDimitry Andric   auto ImmTy = getLLTCodeGenOrTempType(Ty, M);
2368*5f757f3fSDimitry Andric 
2369*5f757f3fSDimitry Andric   if (isGConstant) {
2370*5f757f3fSDimitry Andric     DstMI.addRenderer<ImmRenderer>(O.getImmValue(), ImmTy);
2371*5f757f3fSDimitry Andric     return true;
2372*5f757f3fSDimitry Andric   }
2373*5f757f3fSDimitry Andric 
2374*5f757f3fSDimitry Andric   unsigned TempRegID = M.allocateTempRegID();
2375*5f757f3fSDimitry Andric   // Ensure MakeTempReg & the BuildConstantAction occur at the beginning.
2376*5f757f3fSDimitry Andric   auto InsertIt = M.insertAction<MakeTempRegisterAction>(M.actions_begin(),
2377*5f757f3fSDimitry Andric                                                          ImmTy, TempRegID);
2378*5f757f3fSDimitry Andric   M.insertAction<BuildConstantAction>(++InsertIt, TempRegID, O.getImmValue());
2379*5f757f3fSDimitry Andric   DstMI.addRenderer<TempRegRenderer>(TempRegID);
2380*5f757f3fSDimitry Andric   return true;
2381*5f757f3fSDimitry Andric }
2382*5f757f3fSDimitry Andric 
2383*5f757f3fSDimitry Andric bool CombineRuleBuilder::emitBuiltinApplyPattern(
2384*5f757f3fSDimitry Andric     CodeExpansions &CE, RuleMatcher &M, const BuiltinPattern &P,
2385*5f757f3fSDimitry Andric     StringMap<unsigned> &OperandToTempRegID) {
2386*5f757f3fSDimitry Andric   const auto Error = [&](Twine Reason) {
2387*5f757f3fSDimitry Andric     PrintError("cannot emit '" + P.getInstName() + "' builtin: " + Reason);
2388*5f757f3fSDimitry Andric     return false;
2389*5f757f3fSDimitry Andric   };
2390*5f757f3fSDimitry Andric 
2391*5f757f3fSDimitry Andric   switch (P.getBuiltinKind()) {
2392*5f757f3fSDimitry Andric   case BI_EraseRoot: {
2393*5f757f3fSDimitry Andric     // Root is always inst 0.
2394*5f757f3fSDimitry Andric     M.addAction<EraseInstAction>(/*InsnID*/ 0);
2395*5f757f3fSDimitry Andric     return true;
2396*5f757f3fSDimitry Andric   }
2397*5f757f3fSDimitry Andric   case BI_ReplaceReg: {
2398*5f757f3fSDimitry Andric     StringRef Old = P.getOperand(0).getOperandName();
2399*5f757f3fSDimitry Andric     StringRef New = P.getOperand(1).getOperandName();
2400*5f757f3fSDimitry Andric 
2401*5f757f3fSDimitry Andric     if (!ApplyOpTable.lookup(New).Found && !MatchOpTable.lookup(New).Found)
2402*5f757f3fSDimitry Andric       return Error("unknown operand '" + Old + "'");
2403*5f757f3fSDimitry Andric 
2404*5f757f3fSDimitry Andric     auto &OldOM = M.getOperandMatcher(Old);
2405*5f757f3fSDimitry Andric     if (auto It = OperandToTempRegID.find(New);
2406*5f757f3fSDimitry Andric         It != OperandToTempRegID.end()) {
2407*5f757f3fSDimitry Andric       // Replace with temp reg.
2408*5f757f3fSDimitry Andric       M.addAction<ReplaceRegAction>(OldOM.getInsnVarID(), OldOM.getOpIdx(),
2409*5f757f3fSDimitry Andric                                     It->second);
2410*5f757f3fSDimitry Andric     } else {
2411*5f757f3fSDimitry Andric       // Replace with matched reg.
2412*5f757f3fSDimitry Andric       auto &NewOM = M.getOperandMatcher(New);
2413*5f757f3fSDimitry Andric       M.addAction<ReplaceRegAction>(OldOM.getInsnVarID(), OldOM.getOpIdx(),
2414*5f757f3fSDimitry Andric                                     NewOM.getInsnVarID(), NewOM.getOpIdx());
2415*5f757f3fSDimitry Andric     }
2416*5f757f3fSDimitry Andric     // checkSemantics should have ensured that we can only rewrite the root.
2417*5f757f3fSDimitry Andric     // Ensure we're deleting it.
2418*5f757f3fSDimitry Andric     assert(MatchOpTable.getDef(Old) == MatchRoot);
2419*5f757f3fSDimitry Andric     // TODO: We could avoid adding the action again if it's already in. The
2420*5f757f3fSDimitry Andric     // MatchTable is smart enough to only emit one opcode even if
2421*5f757f3fSDimitry Andric     // EraseInstAction is present multiple times. I think searching for a copy
2422*5f757f3fSDimitry Andric     // is more expensive than just blindly adding it though.
2423*5f757f3fSDimitry Andric     M.addAction<EraseInstAction>(/*InsnID*/ 0);
2424*5f757f3fSDimitry Andric 
2425*5f757f3fSDimitry Andric     return true;
2426*5f757f3fSDimitry Andric   }
2427*5f757f3fSDimitry Andric   }
2428*5f757f3fSDimitry Andric 
2429*5f757f3fSDimitry Andric   llvm_unreachable("Unknown BuiltinKind!");
2430*5f757f3fSDimitry Andric }
2431*5f757f3fSDimitry Andric 
2432*5f757f3fSDimitry Andric bool isLiteralImm(const InstructionPattern &P, unsigned OpIdx) {
2433*5f757f3fSDimitry Andric   if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&P)) {
2434*5f757f3fSDimitry Andric     StringRef InstName = CGP->getInst().TheDef->getName();
2435*5f757f3fSDimitry Andric     return (InstName == "G_CONSTANT" || InstName == "G_FCONSTANT") &&
2436*5f757f3fSDimitry Andric            OpIdx == 1;
2437*5f757f3fSDimitry Andric   }
2438*5f757f3fSDimitry Andric 
2439*5f757f3fSDimitry Andric   llvm_unreachable("TODO");
2440*5f757f3fSDimitry Andric }
2441*5f757f3fSDimitry Andric 
2442*5f757f3fSDimitry Andric bool CombineRuleBuilder::emitCodeGenInstructionMatchPattern(
2443*5f757f3fSDimitry Andric     CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &M,
2444*5f757f3fSDimitry Andric     InstructionMatcher &IM, const CodeGenInstructionPattern &P,
2445*5f757f3fSDimitry Andric     DenseSet<const Pattern *> &SeenPats, OperandDefLookupFn LookupOperandDef,
2446*5f757f3fSDimitry Andric     OperandMapperFnRef OperandMapper) {
2447*5f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef, &P);
2448*5f757f3fSDimitry Andric 
2449*5f757f3fSDimitry Andric   if (SeenPats.contains(&P))
2450*5f757f3fSDimitry Andric     return true;
2451*5f757f3fSDimitry Andric 
2452*5f757f3fSDimitry Andric   SeenPats.insert(&P);
2453*5f757f3fSDimitry Andric 
2454*5f757f3fSDimitry Andric   IM.addPredicate<InstructionOpcodeMatcher>(&P.getInst());
2455*5f757f3fSDimitry Andric   declareInstExpansion(CE, IM, P.getName());
2456*5f757f3fSDimitry Andric 
2457*5f757f3fSDimitry Andric   // Check flags if needed.
2458*5f757f3fSDimitry Andric   if (const auto *FI = P.getMIFlagsInfo()) {
2459*5f757f3fSDimitry Andric     assert(FI->copy_flags().empty());
2460*5f757f3fSDimitry Andric 
2461*5f757f3fSDimitry Andric     if (const auto &SetF = FI->set_flags(); !SetF.empty())
2462*5f757f3fSDimitry Andric       IM.addPredicate<MIFlagsInstructionPredicateMatcher>(SetF.getArrayRef());
2463*5f757f3fSDimitry Andric     if (const auto &UnsetF = FI->unset_flags(); !UnsetF.empty())
2464*5f757f3fSDimitry Andric       IM.addPredicate<MIFlagsInstructionPredicateMatcher>(UnsetF.getArrayRef(),
2465*5f757f3fSDimitry Andric                                                           /*CheckNot=*/true);
2466*5f757f3fSDimitry Andric   }
2467*5f757f3fSDimitry Andric 
2468*5f757f3fSDimitry Andric   for (const auto &[Idx, OriginalO] : enumerate(P.operands())) {
2469*5f757f3fSDimitry Andric     // Remap the operand. This is used when emitting InstructionPatterns inside
2470*5f757f3fSDimitry Andric     // PatFrags, so it can remap them to the arguments passed to the pattern.
2471*5f757f3fSDimitry Andric     //
2472*5f757f3fSDimitry Andric     // We use the remapped operand to emit immediates, and for the symbolic
2473*5f757f3fSDimitry Andric     // operand names (in IM.addOperand). CodeExpansions and OperandTable lookups
2474*5f757f3fSDimitry Andric     // still use the original name.
2475*5f757f3fSDimitry Andric     //
2476*5f757f3fSDimitry Andric     // The "def" flag on the remapped operand is always ignored.
2477*5f757f3fSDimitry Andric     auto RemappedO = OperandMapper(OriginalO);
2478*5f757f3fSDimitry Andric     assert(RemappedO.isNamedOperand() == OriginalO.isNamedOperand() &&
2479*5f757f3fSDimitry Andric            "Cannot remap an unnamed operand to a named one!");
2480*5f757f3fSDimitry Andric 
2481*5f757f3fSDimitry Andric     const auto OpName =
2482*5f757f3fSDimitry Andric         RemappedO.isNamedOperand() ? RemappedO.getOperandName().str() : "";
2483*5f757f3fSDimitry Andric     OperandMatcher &OM =
2484*5f757f3fSDimitry Andric         IM.addOperand(Idx, OpName, AllocatedTemporariesBaseID++);
2485*5f757f3fSDimitry Andric     if (!OpName.empty())
2486*5f757f3fSDimitry Andric       declareOperandExpansion(CE, OM, OriginalO.getOperandName());
2487*5f757f3fSDimitry Andric 
2488*5f757f3fSDimitry Andric     // Handle immediates.
2489*5f757f3fSDimitry Andric     if (RemappedO.hasImmValue()) {
2490*5f757f3fSDimitry Andric       if (isLiteralImm(P, Idx))
2491*5f757f3fSDimitry Andric         OM.addPredicate<LiteralIntOperandMatcher>(RemappedO.getImmValue());
2492*5f757f3fSDimitry Andric       else
2493*5f757f3fSDimitry Andric         OM.addPredicate<ConstantIntOperandMatcher>(RemappedO.getImmValue());
2494*5f757f3fSDimitry Andric     }
2495*5f757f3fSDimitry Andric 
2496*5f757f3fSDimitry Andric     // Handle typed operands, but only bother to check if it hasn't been done
2497*5f757f3fSDimitry Andric     // before.
2498*5f757f3fSDimitry Andric     //
2499*5f757f3fSDimitry Andric     // getOperandMatcher will always return the first OM to have been created
2500*5f757f3fSDimitry Andric     // for that Operand. "OM" here is always a new OperandMatcher.
2501*5f757f3fSDimitry Andric     //
2502*5f757f3fSDimitry Andric     // Always emit a check for unnamed operands.
2503*5f757f3fSDimitry Andric     if (OpName.empty() ||
2504*5f757f3fSDimitry Andric         !M.getOperandMatcher(OpName).contains<LLTOperandMatcher>()) {
2505*5f757f3fSDimitry Andric       if (const auto Ty = RemappedO.getType()) {
2506*5f757f3fSDimitry Andric         // TODO: We could support GITypeOf here on the condition that the
2507*5f757f3fSDimitry Andric         // OperandMatcher exists already. Though it's clunky to make this work
2508*5f757f3fSDimitry Andric         // and isn't all that useful so it's just rejected in typecheckPatterns
2509*5f757f3fSDimitry Andric         // at this time.
2510*5f757f3fSDimitry Andric         assert(Ty.isLLT() && "Only LLTs are supported in match patterns!");
2511*5f757f3fSDimitry Andric         OM.addPredicate<LLTOperandMatcher>(getLLTCodeGen(Ty));
2512*5f757f3fSDimitry Andric       }
2513*5f757f3fSDimitry Andric     }
2514*5f757f3fSDimitry Andric 
2515*5f757f3fSDimitry Andric     // Stop here if the operand is a def, or if it had no name.
2516*5f757f3fSDimitry Andric     if (OriginalO.isDef() || !OriginalO.isNamedOperand())
2517*5f757f3fSDimitry Andric       continue;
2518*5f757f3fSDimitry Andric 
2519*5f757f3fSDimitry Andric     const auto *DefPat = LookupOperandDef(OriginalO.getOperandName());
2520*5f757f3fSDimitry Andric     if (!DefPat)
2521*5f757f3fSDimitry Andric       continue;
2522*5f757f3fSDimitry Andric 
2523*5f757f3fSDimitry Andric     if (OriginalO.hasImmValue()) {
2524*5f757f3fSDimitry Andric       assert(!OpName.empty());
2525*5f757f3fSDimitry Andric       // This is a named immediate that also has a def, that's not okay.
2526*5f757f3fSDimitry Andric       // e.g.
2527*5f757f3fSDimitry Andric       //    (G_SEXT $y, (i32 0))
2528*5f757f3fSDimitry Andric       //    (COPY $x, 42:$y)
2529*5f757f3fSDimitry Andric       PrintError("'" + OpName +
2530*5f757f3fSDimitry Andric                  "' is a named immediate, it cannot be defined by another "
2531*5f757f3fSDimitry Andric                  "instruction");
2532*5f757f3fSDimitry Andric       PrintNote("'" + OpName + "' is defined by '" + DefPat->getName() + "'");
2533*5f757f3fSDimitry Andric       return false;
2534*5f757f3fSDimitry Andric     }
2535*5f757f3fSDimitry Andric 
2536*5f757f3fSDimitry Andric     // From here we know that the operand defines an instruction, and we need to
2537*5f757f3fSDimitry Andric     // emit it.
2538*5f757f3fSDimitry Andric     auto InstOpM =
2539*5f757f3fSDimitry Andric         OM.addPredicate<InstructionOperandMatcher>(M, DefPat->getName());
2540*5f757f3fSDimitry Andric     if (!InstOpM) {
2541*5f757f3fSDimitry Andric       // TODO: copy-pasted from GlobalISelEmitter.cpp. Is it still relevant
2542*5f757f3fSDimitry Andric       // here?
2543*5f757f3fSDimitry Andric       PrintError("Nested instruction '" + DefPat->getName() +
2544*5f757f3fSDimitry Andric                  "' cannot be the same as another operand '" +
2545*5f757f3fSDimitry Andric                  OriginalO.getOperandName() + "'");
2546*5f757f3fSDimitry Andric       return false;
2547*5f757f3fSDimitry Andric     }
2548*5f757f3fSDimitry Andric 
2549*5f757f3fSDimitry Andric     auto &IM = (*InstOpM)->getInsnMatcher();
2550*5f757f3fSDimitry Andric     if (const auto *CGIDef = dyn_cast<CodeGenInstructionPattern>(DefPat)) {
2551*5f757f3fSDimitry Andric       if (!emitCodeGenInstructionMatchPattern(CE, Alts, M, IM, *CGIDef,
2552*5f757f3fSDimitry Andric                                               SeenPats, LookupOperandDef,
2553*5f757f3fSDimitry Andric                                               OperandMapper))
2554*5f757f3fSDimitry Andric         return false;
2555*5f757f3fSDimitry Andric       continue;
2556*5f757f3fSDimitry Andric     }
2557*5f757f3fSDimitry Andric 
2558*5f757f3fSDimitry Andric     if (const auto *PFPDef = dyn_cast<PatFragPattern>(DefPat)) {
2559*5f757f3fSDimitry Andric       if (!emitPatFragMatchPattern(CE, Alts, M, &IM, *PFPDef, SeenPats))
2560*5f757f3fSDimitry Andric         return false;
2561*5f757f3fSDimitry Andric       continue;
2562*5f757f3fSDimitry Andric     }
2563*5f757f3fSDimitry Andric 
2564*5f757f3fSDimitry Andric     llvm_unreachable("unknown type of InstructionPattern");
2565*5f757f3fSDimitry Andric   }
2566*5f757f3fSDimitry Andric 
2567*5f757f3fSDimitry Andric   return true;
2568*5f757f3fSDimitry Andric }
2569*5f757f3fSDimitry Andric 
2570*5f757f3fSDimitry Andric //===- GICombinerEmitter --------------------------------------------------===//
2571*5f757f3fSDimitry Andric 
2572*5f757f3fSDimitry Andric /// Main implementation class. This emits the tablegenerated output.
2573*5f757f3fSDimitry Andric ///
2574*5f757f3fSDimitry Andric /// It collects rules, uses `CombineRuleBuilder` to parse them and accumulate
2575*5f757f3fSDimitry Andric /// RuleMatchers, then takes all the necessary state/data from the various
2576*5f757f3fSDimitry Andric /// static storage pools and wires them together to emit the match table &
2577*5f757f3fSDimitry Andric /// associated function/data structures.
2578*5f757f3fSDimitry Andric class GICombinerEmitter final : public GlobalISelMatchTableExecutorEmitter {
2579*5f757f3fSDimitry Andric   RecordKeeper &Records;
2580*5f757f3fSDimitry Andric   StringRef Name;
2581*5f757f3fSDimitry Andric   const CodeGenTarget &Target;
2582*5f757f3fSDimitry Andric   Record *Combiner;
2583*5f757f3fSDimitry Andric   unsigned NextRuleID = 0;
2584*5f757f3fSDimitry Andric 
2585*5f757f3fSDimitry Andric   // List all combine rules (ID, name) imported.
2586*5f757f3fSDimitry Andric   // Note that the combiner rule ID is different from the RuleMatcher ID. The
2587*5f757f3fSDimitry Andric   // latter is internal to the MatchTable, the former is the canonical ID of the
2588*5f757f3fSDimitry Andric   // combine rule used to disable/enable it.
2589*5f757f3fSDimitry Andric   std::vector<std::pair<unsigned, std::string>> AllCombineRules;
2590*5f757f3fSDimitry Andric 
2591*5f757f3fSDimitry Andric   // Keep track of all rules we've seen so far to ensure we don't process
2592*5f757f3fSDimitry Andric   // the same rule twice.
2593*5f757f3fSDimitry Andric   StringSet<> RulesSeen;
2594*5f757f3fSDimitry Andric 
2595*5f757f3fSDimitry Andric   MatchTable buildMatchTable(MutableArrayRef<RuleMatcher> Rules);
2596*5f757f3fSDimitry Andric 
2597*5f757f3fSDimitry Andric   void emitRuleConfigImpl(raw_ostream &OS);
2598*5f757f3fSDimitry Andric 
2599*5f757f3fSDimitry Andric   void emitAdditionalImpl(raw_ostream &OS) override;
2600*5f757f3fSDimitry Andric 
2601*5f757f3fSDimitry Andric   void emitMIPredicateFns(raw_ostream &OS) override;
2602*5f757f3fSDimitry Andric   void emitI64ImmPredicateFns(raw_ostream &OS) override;
2603*5f757f3fSDimitry Andric   void emitAPFloatImmPredicateFns(raw_ostream &OS) override;
2604*5f757f3fSDimitry Andric   void emitAPIntImmPredicateFns(raw_ostream &OS) override;
2605*5f757f3fSDimitry Andric   void emitTestSimplePredicate(raw_ostream &OS) override;
2606*5f757f3fSDimitry Andric   void emitRunCustomAction(raw_ostream &OS) override;
2607*5f757f3fSDimitry Andric 
2608*5f757f3fSDimitry Andric   void emitAdditionalTemporariesDecl(raw_ostream &OS,
2609*5f757f3fSDimitry Andric                                      StringRef Indent) override;
2610*5f757f3fSDimitry Andric 
2611*5f757f3fSDimitry Andric   const CodeGenTarget &getTarget() const override { return Target; }
2612*5f757f3fSDimitry Andric   StringRef getClassName() const override {
2613*5f757f3fSDimitry Andric     return Combiner->getValueAsString("Classname");
2614*5f757f3fSDimitry Andric   }
2615*5f757f3fSDimitry Andric 
2616*5f757f3fSDimitry Andric   StringRef getCombineAllMethodName() const {
2617*5f757f3fSDimitry Andric     return Combiner->getValueAsString("CombineAllMethodName");
2618*5f757f3fSDimitry Andric   }
2619*5f757f3fSDimitry Andric 
2620*5f757f3fSDimitry Andric   std::string getRuleConfigClassName() const {
2621*5f757f3fSDimitry Andric     return getClassName().str() + "RuleConfig";
2622*5f757f3fSDimitry Andric   }
2623*5f757f3fSDimitry Andric 
2624*5f757f3fSDimitry Andric   void gatherRules(std::vector<RuleMatcher> &Rules,
2625*5f757f3fSDimitry Andric                    const std::vector<Record *> &&RulesAndGroups);
2626*5f757f3fSDimitry Andric 
2627*5f757f3fSDimitry Andric public:
2628*5f757f3fSDimitry Andric   explicit GICombinerEmitter(RecordKeeper &RK, const CodeGenTarget &Target,
2629*5f757f3fSDimitry Andric                              StringRef Name, Record *Combiner);
2630*5f757f3fSDimitry Andric   ~GICombinerEmitter() {}
2631*5f757f3fSDimitry Andric 
2632*5f757f3fSDimitry Andric   void run(raw_ostream &OS);
2633*5f757f3fSDimitry Andric };
2634*5f757f3fSDimitry Andric 
2635*5f757f3fSDimitry Andric void GICombinerEmitter::emitRuleConfigImpl(raw_ostream &OS) {
2636*5f757f3fSDimitry Andric   OS << "struct " << getRuleConfigClassName() << " {\n"
2637*5f757f3fSDimitry Andric      << "  SparseBitVector<> DisabledRules;\n\n"
2638*5f757f3fSDimitry Andric      << "  bool isRuleEnabled(unsigned RuleID) const;\n"
2639*5f757f3fSDimitry Andric      << "  bool parseCommandLineOption();\n"
2640*5f757f3fSDimitry Andric      << "  bool setRuleEnabled(StringRef RuleIdentifier);\n"
2641*5f757f3fSDimitry Andric      << "  bool setRuleDisabled(StringRef RuleIdentifier);\n"
2642*5f757f3fSDimitry Andric      << "};\n\n";
2643*5f757f3fSDimitry Andric 
2644*5f757f3fSDimitry Andric   std::vector<std::pair<std::string, std::string>> Cases;
2645*5f757f3fSDimitry Andric   Cases.reserve(AllCombineRules.size());
2646*5f757f3fSDimitry Andric 
2647*5f757f3fSDimitry Andric   for (const auto &[ID, Name] : AllCombineRules)
2648*5f757f3fSDimitry Andric     Cases.emplace_back(Name, "return " + to_string(ID) + ";\n");
2649*5f757f3fSDimitry Andric 
2650*5f757f3fSDimitry Andric   OS << "static std::optional<uint64_t> getRuleIdxForIdentifier(StringRef "
2651*5f757f3fSDimitry Andric         "RuleIdentifier) {\n"
2652*5f757f3fSDimitry Andric      << "  uint64_t I;\n"
2653*5f757f3fSDimitry Andric      << "  // getAtInteger(...) returns false on success\n"
2654*5f757f3fSDimitry Andric      << "  bool Parsed = !RuleIdentifier.getAsInteger(0, I);\n"
2655*5f757f3fSDimitry Andric      << "  if (Parsed)\n"
2656*5f757f3fSDimitry Andric      << "    return I;\n\n"
2657*5f757f3fSDimitry Andric      << "#ifndef NDEBUG\n";
2658*5f757f3fSDimitry Andric   StringMatcher Matcher("RuleIdentifier", Cases, OS);
2659*5f757f3fSDimitry Andric   Matcher.Emit();
2660*5f757f3fSDimitry Andric   OS << "#endif // ifndef NDEBUG\n\n"
2661*5f757f3fSDimitry Andric      << "  return std::nullopt;\n"
2662*5f757f3fSDimitry Andric      << "}\n";
2663*5f757f3fSDimitry Andric 
2664*5f757f3fSDimitry Andric   OS << "static std::optional<std::pair<uint64_t, uint64_t>> "
2665*5f757f3fSDimitry Andric         "getRuleRangeForIdentifier(StringRef RuleIdentifier) {\n"
2666*5f757f3fSDimitry Andric      << "  std::pair<StringRef, StringRef> RangePair = "
2667*5f757f3fSDimitry Andric         "RuleIdentifier.split('-');\n"
2668*5f757f3fSDimitry Andric      << "  if (!RangePair.second.empty()) {\n"
2669*5f757f3fSDimitry Andric      << "    const auto First = "
2670*5f757f3fSDimitry Andric         "getRuleIdxForIdentifier(RangePair.first);\n"
2671*5f757f3fSDimitry Andric      << "    const auto Last = "
2672*5f757f3fSDimitry Andric         "getRuleIdxForIdentifier(RangePair.second);\n"
2673*5f757f3fSDimitry Andric      << "    if (!First || !Last)\n"
2674*5f757f3fSDimitry Andric      << "      return std::nullopt;\n"
2675*5f757f3fSDimitry Andric      << "    if (First >= Last)\n"
2676*5f757f3fSDimitry Andric      << "      report_fatal_error(\"Beginning of range should be before "
2677*5f757f3fSDimitry Andric         "end of range\");\n"
2678*5f757f3fSDimitry Andric      << "    return {{*First, *Last + 1}};\n"
2679*5f757f3fSDimitry Andric      << "  }\n"
2680*5f757f3fSDimitry Andric      << "  if (RangePair.first == \"*\") {\n"
2681*5f757f3fSDimitry Andric      << "    return {{0, " << AllCombineRules.size() << "}};\n"
2682*5f757f3fSDimitry Andric      << "  }\n"
2683*5f757f3fSDimitry Andric      << "  const auto I = getRuleIdxForIdentifier(RangePair.first);\n"
2684*5f757f3fSDimitry Andric      << "  if (!I)\n"
2685*5f757f3fSDimitry Andric      << "    return std::nullopt;\n"
2686*5f757f3fSDimitry Andric      << "  return {{*I, *I + 1}};\n"
2687*5f757f3fSDimitry Andric      << "}\n\n";
2688*5f757f3fSDimitry Andric 
2689*5f757f3fSDimitry Andric   for (bool Enabled : {true, false}) {
2690*5f757f3fSDimitry Andric     OS << "bool " << getRuleConfigClassName() << "::setRule"
2691*5f757f3fSDimitry Andric        << (Enabled ? "Enabled" : "Disabled") << "(StringRef RuleIdentifier) {\n"
2692*5f757f3fSDimitry Andric        << "  auto MaybeRange = getRuleRangeForIdentifier(RuleIdentifier);\n"
2693*5f757f3fSDimitry Andric        << "  if (!MaybeRange)\n"
2694*5f757f3fSDimitry Andric        << "    return false;\n"
2695*5f757f3fSDimitry Andric        << "  for (auto I = MaybeRange->first; I < MaybeRange->second; ++I)\n"
2696*5f757f3fSDimitry Andric        << "    DisabledRules." << (Enabled ? "reset" : "set") << "(I);\n"
2697*5f757f3fSDimitry Andric        << "  return true;\n"
2698*5f757f3fSDimitry Andric        << "}\n\n";
2699*5f757f3fSDimitry Andric   }
2700*5f757f3fSDimitry Andric 
2701*5f757f3fSDimitry Andric   OS << "static std::vector<std::string> " << Name << "Option;\n"
2702*5f757f3fSDimitry Andric      << "static cl::list<std::string> " << Name << "DisableOption(\n"
2703*5f757f3fSDimitry Andric      << "    \"" << Name.lower() << "-disable-rule\",\n"
2704*5f757f3fSDimitry Andric      << "    cl::desc(\"Disable one or more combiner rules temporarily in "
2705*5f757f3fSDimitry Andric      << "the " << Name << " pass\"),\n"
2706*5f757f3fSDimitry Andric      << "    cl::CommaSeparated,\n"
2707*5f757f3fSDimitry Andric      << "    cl::Hidden,\n"
2708*5f757f3fSDimitry Andric      << "    cl::cat(GICombinerOptionCategory),\n"
2709*5f757f3fSDimitry Andric      << "    cl::callback([](const std::string &Str) {\n"
2710*5f757f3fSDimitry Andric      << "      " << Name << "Option.push_back(Str);\n"
2711*5f757f3fSDimitry Andric      << "    }));\n"
2712*5f757f3fSDimitry Andric      << "static cl::list<std::string> " << Name << "OnlyEnableOption(\n"
2713*5f757f3fSDimitry Andric      << "    \"" << Name.lower() << "-only-enable-rule\",\n"
2714*5f757f3fSDimitry Andric      << "    cl::desc(\"Disable all rules in the " << Name
2715*5f757f3fSDimitry Andric      << " pass then re-enable the specified ones\"),\n"
2716*5f757f3fSDimitry Andric      << "    cl::Hidden,\n"
2717*5f757f3fSDimitry Andric      << "    cl::cat(GICombinerOptionCategory),\n"
2718*5f757f3fSDimitry Andric      << "    cl::callback([](const std::string &CommaSeparatedArg) {\n"
2719*5f757f3fSDimitry Andric      << "      StringRef Str = CommaSeparatedArg;\n"
2720*5f757f3fSDimitry Andric      << "      " << Name << "Option.push_back(\"*\");\n"
2721*5f757f3fSDimitry Andric      << "      do {\n"
2722*5f757f3fSDimitry Andric      << "        auto X = Str.split(\",\");\n"
2723*5f757f3fSDimitry Andric      << "        " << Name << "Option.push_back((\"!\" + X.first).str());\n"
2724*5f757f3fSDimitry Andric      << "        Str = X.second;\n"
2725*5f757f3fSDimitry Andric      << "      } while (!Str.empty());\n"
2726*5f757f3fSDimitry Andric      << "    }));\n"
2727*5f757f3fSDimitry Andric      << "\n\n"
2728*5f757f3fSDimitry Andric      << "bool " << getRuleConfigClassName()
2729*5f757f3fSDimitry Andric      << "::isRuleEnabled(unsigned RuleID) const {\n"
2730*5f757f3fSDimitry Andric      << "    return  !DisabledRules.test(RuleID);\n"
2731*5f757f3fSDimitry Andric      << "}\n"
2732*5f757f3fSDimitry Andric      << "bool " << getRuleConfigClassName() << "::parseCommandLineOption() {\n"
2733*5f757f3fSDimitry Andric      << "  for (StringRef Identifier : " << Name << "Option) {\n"
2734*5f757f3fSDimitry Andric      << "    bool Enabled = Identifier.consume_front(\"!\");\n"
2735*5f757f3fSDimitry Andric      << "    if (Enabled && !setRuleEnabled(Identifier))\n"
2736*5f757f3fSDimitry Andric      << "      return false;\n"
2737*5f757f3fSDimitry Andric      << "    if (!Enabled && !setRuleDisabled(Identifier))\n"
2738*5f757f3fSDimitry Andric      << "      return false;\n"
2739*5f757f3fSDimitry Andric      << "  }\n"
2740*5f757f3fSDimitry Andric      << "  return true;\n"
2741*5f757f3fSDimitry Andric      << "}\n\n";
2742*5f757f3fSDimitry Andric }
2743*5f757f3fSDimitry Andric 
2744*5f757f3fSDimitry Andric void GICombinerEmitter::emitAdditionalImpl(raw_ostream &OS) {
2745*5f757f3fSDimitry Andric   OS << "bool " << getClassName() << "::" << getCombineAllMethodName()
2746*5f757f3fSDimitry Andric      << "(MachineInstr &I) const {\n"
2747*5f757f3fSDimitry Andric      << "  const TargetSubtargetInfo &ST = MF.getSubtarget();\n"
2748*5f757f3fSDimitry Andric      << "  const PredicateBitset AvailableFeatures = "
2749*5f757f3fSDimitry Andric         "getAvailableFeatures();\n"
2750*5f757f3fSDimitry Andric      << "  B.setInstrAndDebugLoc(I);\n"
2751*5f757f3fSDimitry Andric      << "  State.MIs.clear();\n"
2752*5f757f3fSDimitry Andric      << "  State.MIs.push_back(&I);\n"
2753*5f757f3fSDimitry Andric      << "  " << MatchDataInfo::StructName << " = "
2754*5f757f3fSDimitry Andric      << MatchDataInfo::StructTypeName << "();\n\n"
2755*5f757f3fSDimitry Andric      << "  if (executeMatchTable(*this, State, ExecInfo, B"
2756*5f757f3fSDimitry Andric      << ", getMatchTable(), *ST.getInstrInfo(), MRI, "
2757*5f757f3fSDimitry Andric         "*MRI.getTargetRegisterInfo(), *ST.getRegBankInfo(), AvailableFeatures"
2758*5f757f3fSDimitry Andric      << ", /*CoverageInfo*/ nullptr)) {\n"
2759*5f757f3fSDimitry Andric      << "    return true;\n"
2760*5f757f3fSDimitry Andric      << "  }\n\n"
2761*5f757f3fSDimitry Andric      << "  return false;\n"
2762*5f757f3fSDimitry Andric      << "}\n\n";
2763*5f757f3fSDimitry Andric }
2764*5f757f3fSDimitry Andric 
2765*5f757f3fSDimitry Andric void GICombinerEmitter::emitMIPredicateFns(raw_ostream &OS) {
2766*5f757f3fSDimitry Andric   auto MatchCode = CXXPredicateCode::getAllMatchCode();
2767*5f757f3fSDimitry Andric   emitMIPredicateFnsImpl<const CXXPredicateCode *>(
2768*5f757f3fSDimitry Andric       OS, "", ArrayRef<const CXXPredicateCode *>(MatchCode),
2769*5f757f3fSDimitry Andric       [](const CXXPredicateCode *C) -> StringRef { return C->BaseEnumName; },
2770*5f757f3fSDimitry Andric       [](const CXXPredicateCode *C) -> StringRef { return C->Code; });
2771*5f757f3fSDimitry Andric }
2772*5f757f3fSDimitry Andric 
2773*5f757f3fSDimitry Andric void GICombinerEmitter::emitI64ImmPredicateFns(raw_ostream &OS) {
2774*5f757f3fSDimitry Andric   // Unused, but still needs to be called.
2775*5f757f3fSDimitry Andric   emitImmPredicateFnsImpl<unsigned>(
2776*5f757f3fSDimitry Andric       OS, "I64", "int64_t", {}, [](unsigned) { return ""; },
2777*5f757f3fSDimitry Andric       [](unsigned) { return ""; });
2778*5f757f3fSDimitry Andric }
2779*5f757f3fSDimitry Andric 
2780*5f757f3fSDimitry Andric void GICombinerEmitter::emitAPFloatImmPredicateFns(raw_ostream &OS) {
2781*5f757f3fSDimitry Andric   // Unused, but still needs to be called.
2782*5f757f3fSDimitry Andric   emitImmPredicateFnsImpl<unsigned>(
2783*5f757f3fSDimitry Andric       OS, "APFloat", "const APFloat &", {}, [](unsigned) { return ""; },
2784*5f757f3fSDimitry Andric       [](unsigned) { return ""; });
2785*5f757f3fSDimitry Andric }
2786*5f757f3fSDimitry Andric 
2787*5f757f3fSDimitry Andric void GICombinerEmitter::emitAPIntImmPredicateFns(raw_ostream &OS) {
2788*5f757f3fSDimitry Andric   // Unused, but still needs to be called.
2789*5f757f3fSDimitry Andric   emitImmPredicateFnsImpl<unsigned>(
2790*5f757f3fSDimitry Andric       OS, "APInt", "const APInt &", {}, [](unsigned) { return ""; },
2791*5f757f3fSDimitry Andric       [](unsigned) { return ""; });
2792*5f757f3fSDimitry Andric }
2793*5f757f3fSDimitry Andric 
2794*5f757f3fSDimitry Andric void GICombinerEmitter::emitTestSimplePredicate(raw_ostream &OS) {
2795*5f757f3fSDimitry Andric   if (!AllCombineRules.empty()) {
2796*5f757f3fSDimitry Andric     OS << "enum {\n";
2797*5f757f3fSDimitry Andric     std::string EnumeratorSeparator = " = GICXXPred_Invalid + 1,\n";
2798*5f757f3fSDimitry Andric     // To avoid emitting a switch, we expect that all those rules are in order.
2799*5f757f3fSDimitry Andric     // That way we can just get the RuleID from the enum by subtracting
2800*5f757f3fSDimitry Andric     // (GICXXPred_Invalid + 1).
2801*5f757f3fSDimitry Andric     unsigned ExpectedID = 0;
2802*5f757f3fSDimitry Andric     (void)ExpectedID;
2803*5f757f3fSDimitry Andric     for (const auto &ID : keys(AllCombineRules)) {
2804*5f757f3fSDimitry Andric       assert(ExpectedID++ == ID && "combine rules are not ordered!");
2805*5f757f3fSDimitry Andric       OS << "  " << getIsEnabledPredicateEnumName(ID) << EnumeratorSeparator;
2806*5f757f3fSDimitry Andric       EnumeratorSeparator = ",\n";
2807*5f757f3fSDimitry Andric     }
2808*5f757f3fSDimitry Andric     OS << "};\n\n";
2809*5f757f3fSDimitry Andric   }
2810*5f757f3fSDimitry Andric 
2811*5f757f3fSDimitry Andric   OS << "bool " << getClassName()
2812*5f757f3fSDimitry Andric      << "::testSimplePredicate(unsigned Predicate) const {\n"
2813*5f757f3fSDimitry Andric      << "    return RuleConfig.isRuleEnabled(Predicate - "
2814*5f757f3fSDimitry Andric         "GICXXPred_Invalid - "
2815*5f757f3fSDimitry Andric         "1);\n"
2816*5f757f3fSDimitry Andric      << "}\n";
2817*5f757f3fSDimitry Andric }
2818*5f757f3fSDimitry Andric 
2819*5f757f3fSDimitry Andric void GICombinerEmitter::emitRunCustomAction(raw_ostream &OS) {
2820*5f757f3fSDimitry Andric   const auto ApplyCode = CXXPredicateCode::getAllApplyCode();
2821*5f757f3fSDimitry Andric 
2822*5f757f3fSDimitry Andric   if (!ApplyCode.empty()) {
2823*5f757f3fSDimitry Andric     OS << "enum {\n";
2824*5f757f3fSDimitry Andric     std::string EnumeratorSeparator = " = GICXXCustomAction_Invalid + 1,\n";
2825*5f757f3fSDimitry Andric     for (const auto &Apply : ApplyCode) {
2826*5f757f3fSDimitry Andric       OS << "  " << Apply->getEnumNameWithPrefix(CXXApplyPrefix)
2827*5f757f3fSDimitry Andric          << EnumeratorSeparator;
2828*5f757f3fSDimitry Andric       EnumeratorSeparator = ",\n";
2829*5f757f3fSDimitry Andric     }
2830*5f757f3fSDimitry Andric     OS << "};\n";
2831*5f757f3fSDimitry Andric   }
2832*5f757f3fSDimitry Andric 
2833*5f757f3fSDimitry Andric   OS << "void " << getClassName()
2834*5f757f3fSDimitry Andric      << "::runCustomAction(unsigned ApplyID, const MatcherState &State, "
2835*5f757f3fSDimitry Andric         "NewMIVector &OutMIs) const "
2836*5f757f3fSDimitry Andric         "{\n";
2837*5f757f3fSDimitry Andric   if (!ApplyCode.empty()) {
2838*5f757f3fSDimitry Andric     OS << "  switch(ApplyID) {\n";
2839*5f757f3fSDimitry Andric     for (const auto &Apply : ApplyCode) {
2840*5f757f3fSDimitry Andric       OS << "  case " << Apply->getEnumNameWithPrefix(CXXApplyPrefix) << ":{\n"
2841*5f757f3fSDimitry Andric          << "    " << join(split(Apply->Code, '\n'), "\n    ") << '\n'
2842*5f757f3fSDimitry Andric          << "    return;\n";
2843*5f757f3fSDimitry Andric       OS << "  }\n";
2844*5f757f3fSDimitry Andric     }
2845*5f757f3fSDimitry Andric     OS << "}\n";
2846*5f757f3fSDimitry Andric   }
2847*5f757f3fSDimitry Andric   OS << "  llvm_unreachable(\"Unknown Apply Action\");\n"
2848*5f757f3fSDimitry Andric      << "}\n";
2849*5f757f3fSDimitry Andric }
2850*5f757f3fSDimitry Andric 
2851*5f757f3fSDimitry Andric void GICombinerEmitter::emitAdditionalTemporariesDecl(raw_ostream &OS,
2852*5f757f3fSDimitry Andric                                                       StringRef Indent) {
2853*5f757f3fSDimitry Andric   OS << Indent << "struct " << MatchDataInfo::StructTypeName << " {\n";
2854*5f757f3fSDimitry Andric   for (const auto &[Type, VarNames] : AllMatchDataVars) {
2855*5f757f3fSDimitry Andric     assert(!VarNames.empty() && "Cannot have no vars for this type!");
2856*5f757f3fSDimitry Andric     OS << Indent << "  " << Type << " " << join(VarNames, ", ") << ";\n";
2857*5f757f3fSDimitry Andric   }
2858*5f757f3fSDimitry Andric   OS << Indent << "};\n"
2859*5f757f3fSDimitry Andric      << Indent << "mutable " << MatchDataInfo::StructTypeName << " "
2860*5f757f3fSDimitry Andric      << MatchDataInfo::StructName << ";\n\n";
2861*5f757f3fSDimitry Andric }
2862*5f757f3fSDimitry Andric 
2863*5f757f3fSDimitry Andric GICombinerEmitter::GICombinerEmitter(RecordKeeper &RK,
2864*5f757f3fSDimitry Andric                                      const CodeGenTarget &Target,
2865*5f757f3fSDimitry Andric                                      StringRef Name, Record *Combiner)
2866*5f757f3fSDimitry Andric     : Records(RK), Name(Name), Target(Target), Combiner(Combiner) {}
2867*5f757f3fSDimitry Andric 
2868*5f757f3fSDimitry Andric MatchTable
2869*5f757f3fSDimitry Andric GICombinerEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules) {
2870*5f757f3fSDimitry Andric   std::vector<Matcher *> InputRules;
2871*5f757f3fSDimitry Andric   for (Matcher &Rule : Rules)
2872*5f757f3fSDimitry Andric     InputRules.push_back(&Rule);
2873*5f757f3fSDimitry Andric 
2874*5f757f3fSDimitry Andric   unsigned CurrentOrdering = 0;
2875*5f757f3fSDimitry Andric   StringMap<unsigned> OpcodeOrder;
2876*5f757f3fSDimitry Andric   for (RuleMatcher &Rule : Rules) {
2877*5f757f3fSDimitry Andric     const StringRef Opcode = Rule.getOpcode();
2878*5f757f3fSDimitry Andric     assert(!Opcode.empty() && "Didn't expect an undefined opcode");
2879*5f757f3fSDimitry Andric     if (OpcodeOrder.count(Opcode) == 0)
2880*5f757f3fSDimitry Andric       OpcodeOrder[Opcode] = CurrentOrdering++;
2881*5f757f3fSDimitry Andric   }
2882*5f757f3fSDimitry Andric 
2883*5f757f3fSDimitry Andric   llvm::stable_sort(InputRules, [&OpcodeOrder](const Matcher *A,
2884*5f757f3fSDimitry Andric                                                const Matcher *B) {
2885*5f757f3fSDimitry Andric     auto *L = static_cast<const RuleMatcher *>(A);
2886*5f757f3fSDimitry Andric     auto *R = static_cast<const RuleMatcher *>(B);
2887*5f757f3fSDimitry Andric     return std::make_tuple(OpcodeOrder[L->getOpcode()], L->getNumOperands()) <
2888*5f757f3fSDimitry Andric            std::make_tuple(OpcodeOrder[R->getOpcode()], R->getNumOperands());
2889*5f757f3fSDimitry Andric   });
2890*5f757f3fSDimitry Andric 
2891*5f757f3fSDimitry Andric   for (Matcher *Rule : InputRules)
2892*5f757f3fSDimitry Andric     Rule->optimize();
2893*5f757f3fSDimitry Andric 
2894*5f757f3fSDimitry Andric   std::vector<std::unique_ptr<Matcher>> MatcherStorage;
2895*5f757f3fSDimitry Andric   std::vector<Matcher *> OptRules =
2896*5f757f3fSDimitry Andric       optimizeRules<GroupMatcher>(InputRules, MatcherStorage);
2897*5f757f3fSDimitry Andric 
2898*5f757f3fSDimitry Andric   for (Matcher *Rule : OptRules)
2899*5f757f3fSDimitry Andric     Rule->optimize();
2900*5f757f3fSDimitry Andric 
2901*5f757f3fSDimitry Andric   OptRules = optimizeRules<SwitchMatcher>(OptRules, MatcherStorage);
2902*5f757f3fSDimitry Andric 
2903*5f757f3fSDimitry Andric   return MatchTable::buildTable(OptRules, /*WithCoverage*/ false,
2904*5f757f3fSDimitry Andric                                 /*IsCombiner*/ true);
2905*5f757f3fSDimitry Andric }
2906*5f757f3fSDimitry Andric 
2907*5f757f3fSDimitry Andric /// Recurse into GICombineGroup's and flatten the ruleset into a simple list.
2908*5f757f3fSDimitry Andric void GICombinerEmitter::gatherRules(
2909*5f757f3fSDimitry Andric     std::vector<RuleMatcher> &ActiveRules,
2910*5f757f3fSDimitry Andric     const std::vector<Record *> &&RulesAndGroups) {
2911*5f757f3fSDimitry Andric   for (Record *Rec : RulesAndGroups) {
2912*5f757f3fSDimitry Andric     if (!Rec->isValueUnset("Rules")) {
2913*5f757f3fSDimitry Andric       gatherRules(ActiveRules, Rec->getValueAsListOfDefs("Rules"));
2914*5f757f3fSDimitry Andric       continue;
2915*5f757f3fSDimitry Andric     }
2916*5f757f3fSDimitry Andric 
2917*5f757f3fSDimitry Andric     StringRef RuleName = Rec->getName();
2918*5f757f3fSDimitry Andric     if (!RulesSeen.insert(RuleName).second) {
2919*5f757f3fSDimitry Andric       PrintWarning(Rec->getLoc(),
2920*5f757f3fSDimitry Andric                    "skipping rule '" + Rec->getName() +
2921*5f757f3fSDimitry Andric                        "' because it has already been processed");
2922*5f757f3fSDimitry Andric       continue;
2923*5f757f3fSDimitry Andric     }
2924*5f757f3fSDimitry Andric 
2925*5f757f3fSDimitry Andric     AllCombineRules.emplace_back(NextRuleID, Rec->getName().str());
2926*5f757f3fSDimitry Andric     CombineRuleBuilder CRB(Target, SubtargetFeatures, *Rec, NextRuleID++,
2927*5f757f3fSDimitry Andric                            ActiveRules);
2928*5f757f3fSDimitry Andric 
2929*5f757f3fSDimitry Andric     if (!CRB.parseAll()) {
2930*5f757f3fSDimitry Andric       assert(ErrorsPrinted && "Parsing failed without errors!");
2931*5f757f3fSDimitry Andric       continue;
2932*5f757f3fSDimitry Andric     }
2933*5f757f3fSDimitry Andric 
2934*5f757f3fSDimitry Andric     if (StopAfterParse) {
2935*5f757f3fSDimitry Andric       CRB.print(outs());
2936*5f757f3fSDimitry Andric       continue;
2937*5f757f3fSDimitry Andric     }
2938*5f757f3fSDimitry Andric 
2939*5f757f3fSDimitry Andric     if (!CRB.emitRuleMatchers()) {
2940*5f757f3fSDimitry Andric       assert(ErrorsPrinted && "Emission failed without errors!");
2941*5f757f3fSDimitry Andric       continue;
2942*5f757f3fSDimitry Andric     }
2943*5f757f3fSDimitry Andric   }
2944*5f757f3fSDimitry Andric }
2945*5f757f3fSDimitry Andric 
2946*5f757f3fSDimitry Andric void GICombinerEmitter::run(raw_ostream &OS) {
2947*5f757f3fSDimitry Andric   InstructionOpcodeMatcher::initOpcodeValuesMap(Target);
2948*5f757f3fSDimitry Andric   LLTOperandMatcher::initTypeIDValuesMap();
2949*5f757f3fSDimitry Andric 
2950*5f757f3fSDimitry Andric   Records.startTimer("Gather rules");
2951*5f757f3fSDimitry Andric   std::vector<RuleMatcher> Rules;
2952*5f757f3fSDimitry Andric   gatherRules(Rules, Combiner->getValueAsListOfDefs("Rules"));
2953*5f757f3fSDimitry Andric   if (ErrorsPrinted)
2954*5f757f3fSDimitry Andric     PrintFatalError(Combiner->getLoc(), "Failed to parse one or more rules");
2955*5f757f3fSDimitry Andric 
2956*5f757f3fSDimitry Andric   if (StopAfterParse)
2957*5f757f3fSDimitry Andric     return;
2958*5f757f3fSDimitry Andric 
2959*5f757f3fSDimitry Andric   Records.startTimer("Creating Match Table");
2960*5f757f3fSDimitry Andric   unsigned MaxTemporaries = 0;
2961*5f757f3fSDimitry Andric   for (const auto &Rule : Rules)
2962*5f757f3fSDimitry Andric     MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());
2963*5f757f3fSDimitry Andric 
2964*5f757f3fSDimitry Andric   llvm::stable_sort(Rules, [&](const RuleMatcher &A, const RuleMatcher &B) {
2965*5f757f3fSDimitry Andric     if (A.isHigherPriorityThan(B)) {
2966*5f757f3fSDimitry Andric       assert(!B.isHigherPriorityThan(A) && "Cannot be more important "
2967*5f757f3fSDimitry Andric                                            "and less important at "
2968*5f757f3fSDimitry Andric                                            "the same time");
2969*5f757f3fSDimitry Andric       return true;
2970*5f757f3fSDimitry Andric     }
2971*5f757f3fSDimitry Andric     return false;
2972*5f757f3fSDimitry Andric   });
2973*5f757f3fSDimitry Andric 
2974*5f757f3fSDimitry Andric   const MatchTable Table = buildMatchTable(Rules);
2975*5f757f3fSDimitry Andric 
2976*5f757f3fSDimitry Andric   Records.startTimer("Emit combiner");
2977*5f757f3fSDimitry Andric 
2978*5f757f3fSDimitry Andric   emitSourceFileHeader(getClassName().str() + " Combiner Match Table", OS);
2979*5f757f3fSDimitry Andric 
2980*5f757f3fSDimitry Andric   // Unused
2981*5f757f3fSDimitry Andric   std::vector<StringRef> CustomRendererFns;
2982*5f757f3fSDimitry Andric   // Unused
2983*5f757f3fSDimitry Andric   std::vector<Record *> ComplexPredicates;
2984*5f757f3fSDimitry Andric 
2985*5f757f3fSDimitry Andric   SmallVector<LLTCodeGen, 16> TypeObjects;
2986*5f757f3fSDimitry Andric   append_range(TypeObjects, KnownTypes);
2987*5f757f3fSDimitry Andric   llvm::sort(TypeObjects);
2988*5f757f3fSDimitry Andric 
2989*5f757f3fSDimitry Andric   // Hack: Avoid empty declarator.
2990*5f757f3fSDimitry Andric   if (TypeObjects.empty())
2991*5f757f3fSDimitry Andric     TypeObjects.push_back(LLT::scalar(1));
2992*5f757f3fSDimitry Andric 
2993*5f757f3fSDimitry Andric   // GET_GICOMBINER_DEPS, which pulls in extra dependencies.
2994*5f757f3fSDimitry Andric   OS << "#ifdef GET_GICOMBINER_DEPS\n"
2995*5f757f3fSDimitry Andric      << "#include \"llvm/ADT/SparseBitVector.h\"\n"
2996*5f757f3fSDimitry Andric      << "namespace llvm {\n"
2997*5f757f3fSDimitry Andric      << "extern cl::OptionCategory GICombinerOptionCategory;\n"
2998*5f757f3fSDimitry Andric      << "} // end namespace llvm\n"
2999*5f757f3fSDimitry Andric      << "#endif // ifdef GET_GICOMBINER_DEPS\n\n";
3000*5f757f3fSDimitry Andric 
3001*5f757f3fSDimitry Andric   // GET_GICOMBINER_TYPES, which needs to be included before the declaration of
3002*5f757f3fSDimitry Andric   // the class.
3003*5f757f3fSDimitry Andric   OS << "#ifdef GET_GICOMBINER_TYPES\n";
3004*5f757f3fSDimitry Andric   emitRuleConfigImpl(OS);
3005*5f757f3fSDimitry Andric   OS << "#endif // ifdef GET_GICOMBINER_TYPES\n\n";
3006*5f757f3fSDimitry Andric   emitPredicateBitset(OS, "GET_GICOMBINER_TYPES");
3007*5f757f3fSDimitry Andric 
3008*5f757f3fSDimitry Andric   // GET_GICOMBINER_CLASS_MEMBERS, which need to be included inside the class.
3009*5f757f3fSDimitry Andric   emitPredicatesDecl(OS, "GET_GICOMBINER_CLASS_MEMBERS");
3010*5f757f3fSDimitry Andric   emitTemporariesDecl(OS, "GET_GICOMBINER_CLASS_MEMBERS");
3011*5f757f3fSDimitry Andric 
3012*5f757f3fSDimitry Andric   // GET_GICOMBINER_IMPL, which needs to be included outside the class.
3013*5f757f3fSDimitry Andric   emitExecutorImpl(OS, Table, TypeObjects, Rules, ComplexPredicates,
3014*5f757f3fSDimitry Andric                    CustomRendererFns, "GET_GICOMBINER_IMPL");
3015*5f757f3fSDimitry Andric 
3016*5f757f3fSDimitry Andric   // GET_GICOMBINER_CONSTRUCTOR_INITS, which are in the constructor's
3017*5f757f3fSDimitry Andric   // initializer list.
3018*5f757f3fSDimitry Andric   emitPredicatesInit(OS, "GET_GICOMBINER_CONSTRUCTOR_INITS");
3019*5f757f3fSDimitry Andric   emitTemporariesInit(OS, MaxTemporaries, "GET_GICOMBINER_CONSTRUCTOR_INITS");
3020*5f757f3fSDimitry Andric }
3021*5f757f3fSDimitry Andric 
3022*5f757f3fSDimitry Andric } // end anonymous namespace
3023*5f757f3fSDimitry Andric 
3024*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
3025*5f757f3fSDimitry Andric 
3026*5f757f3fSDimitry Andric static void EmitGICombiner(RecordKeeper &RK, raw_ostream &OS) {
3027*5f757f3fSDimitry Andric   EnablePrettyStackTrace();
3028*5f757f3fSDimitry Andric   CodeGenTarget Target(RK);
3029*5f757f3fSDimitry Andric 
3030*5f757f3fSDimitry Andric   if (SelectedCombiners.empty())
3031*5f757f3fSDimitry Andric     PrintFatalError("No combiners selected with -combiners");
3032*5f757f3fSDimitry Andric   for (const auto &Combiner : SelectedCombiners) {
3033*5f757f3fSDimitry Andric     Record *CombinerDef = RK.getDef(Combiner);
3034*5f757f3fSDimitry Andric     if (!CombinerDef)
3035*5f757f3fSDimitry Andric       PrintFatalError("Could not find " + Combiner);
3036*5f757f3fSDimitry Andric     GICombinerEmitter(RK, Target, Combiner, CombinerDef).run(OS);
3037*5f757f3fSDimitry Andric   }
3038*5f757f3fSDimitry Andric }
3039*5f757f3fSDimitry Andric 
3040*5f757f3fSDimitry Andric static TableGen::Emitter::Opt X("gen-global-isel-combiner", EmitGICombiner,
3041*5f757f3fSDimitry Andric                                 "Generate GlobalISel Combiner");
3042