xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
15f757f3fSDimitry Andric //===- GlobalISelCombinerMatchTableEmitter.cpp - --------------------------===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric //
95f757f3fSDimitry Andric /// \file Generate a combiner implementation for GlobalISel from a declarative
105f757f3fSDimitry Andric /// syntax using GlobalISelMatchTable.
115f757f3fSDimitry Andric ///
125f757f3fSDimitry Andric /// Usually, TableGen backends use "assert is an error" as a means to report
135f757f3fSDimitry Andric /// invalid input. They try to diagnose common case but don't try very hard and
145f757f3fSDimitry Andric /// crashes can be common. This backend aims to behave closer to how a language
155f757f3fSDimitry Andric /// compiler frontend would behave: we try extra hard to diagnose invalid inputs
165f757f3fSDimitry Andric /// early, and any crash should be considered a bug (= a feature or diagnostic
175f757f3fSDimitry Andric /// is missing).
185f757f3fSDimitry Andric ///
195f757f3fSDimitry Andric /// While this can make the backend a bit more complex than it needs to be, it
205f757f3fSDimitry Andric /// pays off because MIR patterns can get complicated. Giving useful error
215f757f3fSDimitry Andric /// messages to combine writers can help boost their productivity.
225f757f3fSDimitry Andric ///
235f757f3fSDimitry Andric /// As with anything, a good balance has to be found. We also don't want to
245f757f3fSDimitry Andric /// write hundreds of lines of code to detect edge cases. In practice, crashing
255f757f3fSDimitry Andric /// very occasionally, or giving poor errors in some rare instances, is fine.
265f757f3fSDimitry Andric ///
275f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
285f757f3fSDimitry Andric 
295f757f3fSDimitry Andric #include "CodeGenInstruction.h"
305f757f3fSDimitry Andric #include "CodeGenTarget.h"
315f757f3fSDimitry Andric #include "GlobalISel/CXXPredicates.h"
325f757f3fSDimitry Andric #include "GlobalISel/CodeExpander.h"
335f757f3fSDimitry Andric #include "GlobalISel/CodeExpansions.h"
345f757f3fSDimitry Andric #include "GlobalISel/CombinerUtils.h"
355f757f3fSDimitry Andric #include "GlobalISel/MatchDataInfo.h"
365f757f3fSDimitry Andric #include "GlobalISel/Patterns.h"
375f757f3fSDimitry Andric #include "GlobalISelMatchTable.h"
385f757f3fSDimitry Andric #include "GlobalISelMatchTableExecutorEmitter.h"
395f757f3fSDimitry Andric #include "SubtargetFeatureInfo.h"
405f757f3fSDimitry Andric #include "llvm/ADT/APInt.h"
415f757f3fSDimitry Andric #include "llvm/ADT/EquivalenceClasses.h"
425f757f3fSDimitry Andric #include "llvm/ADT/Hashing.h"
435f757f3fSDimitry Andric #include "llvm/ADT/MapVector.h"
445f757f3fSDimitry Andric #include "llvm/ADT/SetVector.h"
455f757f3fSDimitry Andric #include "llvm/ADT/Statistic.h"
465f757f3fSDimitry Andric #include "llvm/ADT/StringSet.h"
475f757f3fSDimitry Andric #include "llvm/Support/CommandLine.h"
485f757f3fSDimitry Andric #include "llvm/Support/Debug.h"
495f757f3fSDimitry Andric #include "llvm/Support/PrettyStackTrace.h"
505f757f3fSDimitry Andric #include "llvm/Support/ScopedPrinter.h"
515f757f3fSDimitry Andric #include "llvm/TableGen/Error.h"
525f757f3fSDimitry Andric #include "llvm/TableGen/Record.h"
535f757f3fSDimitry Andric #include "llvm/TableGen/StringMatcher.h"
545f757f3fSDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
555f757f3fSDimitry Andric #include <cstdint>
565f757f3fSDimitry Andric 
575f757f3fSDimitry Andric using namespace llvm;
585f757f3fSDimitry Andric using namespace llvm::gi;
595f757f3fSDimitry Andric 
605f757f3fSDimitry Andric #define DEBUG_TYPE "gicombiner-emitter"
615f757f3fSDimitry Andric 
625f757f3fSDimitry Andric namespace {
635f757f3fSDimitry Andric cl::OptionCategory
645f757f3fSDimitry Andric     GICombinerEmitterCat("Options for -gen-global-isel-combiner");
655f757f3fSDimitry Andric cl::opt<bool> StopAfterParse(
665f757f3fSDimitry Andric     "gicombiner-stop-after-parse",
675f757f3fSDimitry Andric     cl::desc("Stop processing after parsing rules and dump state"),
685f757f3fSDimitry Andric     cl::cat(GICombinerEmitterCat));
695f757f3fSDimitry Andric cl::list<std::string>
705f757f3fSDimitry Andric     SelectedCombiners("combiners", cl::desc("Emit the specified combiners"),
715f757f3fSDimitry Andric                       cl::cat(GICombinerEmitterCat), cl::CommaSeparated);
725f757f3fSDimitry Andric cl::opt<bool> DebugCXXPreds(
735f757f3fSDimitry Andric     "gicombiner-debug-cxxpreds",
745f757f3fSDimitry Andric     cl::desc("Add Contextual/Debug comments to all C++ predicates"),
755f757f3fSDimitry Andric     cl::cat(GICombinerEmitterCat));
765f757f3fSDimitry Andric cl::opt<bool> DebugTypeInfer("gicombiner-debug-typeinfer",
775f757f3fSDimitry Andric                              cl::desc("Print type inference debug logs"),
785f757f3fSDimitry Andric                              cl::cat(GICombinerEmitterCat));
795f757f3fSDimitry Andric 
805f757f3fSDimitry Andric constexpr StringLiteral CXXApplyPrefix = "GICXXCustomAction_CombineApply";
815f757f3fSDimitry Andric constexpr StringLiteral CXXPredPrefix = "GICXXPred_MI_Predicate_";
825f757f3fSDimitry Andric constexpr StringLiteral MIFlagsEnumClassName = "MIFlagEnum";
835f757f3fSDimitry Andric 
845f757f3fSDimitry Andric //===- CodeExpansions Helpers  --------------------------------------------===//
855f757f3fSDimitry Andric 
865f757f3fSDimitry Andric void declareInstExpansion(CodeExpansions &CE, const InstructionMatcher &IM,
875f757f3fSDimitry Andric                           StringRef Name) {
885f757f3fSDimitry Andric   CE.declare(Name, "State.MIs[" + to_string(IM.getInsnVarID()) + "]");
895f757f3fSDimitry Andric }
905f757f3fSDimitry Andric 
915f757f3fSDimitry Andric void declareInstExpansion(CodeExpansions &CE, const BuildMIAction &A,
925f757f3fSDimitry Andric                           StringRef Name) {
935f757f3fSDimitry Andric   // Note: we use redeclare here because this may overwrite a matcher inst
945f757f3fSDimitry Andric   // expansion.
955f757f3fSDimitry Andric   CE.redeclare(Name, "OutMIs[" + to_string(A.getInsnID()) + "]");
965f757f3fSDimitry Andric }
975f757f3fSDimitry Andric 
985f757f3fSDimitry Andric void declareOperandExpansion(CodeExpansions &CE, const OperandMatcher &OM,
995f757f3fSDimitry Andric                              StringRef Name) {
1005f757f3fSDimitry Andric   CE.declare(Name, "State.MIs[" + to_string(OM.getInsnVarID()) +
1015f757f3fSDimitry Andric                        "]->getOperand(" + to_string(OM.getOpIdx()) + ")");
1025f757f3fSDimitry Andric }
1035f757f3fSDimitry Andric 
1045f757f3fSDimitry Andric void declareTempRegExpansion(CodeExpansions &CE, unsigned TempRegID,
1055f757f3fSDimitry Andric                              StringRef Name) {
1065f757f3fSDimitry Andric   CE.declare(Name, "State.TempRegisters[" + to_string(TempRegID) + "]");
1075f757f3fSDimitry Andric }
1085f757f3fSDimitry Andric 
1095f757f3fSDimitry Andric //===- Misc. Helpers  -----------------------------------------------------===//
1105f757f3fSDimitry Andric 
1115f757f3fSDimitry Andric /// Copies a StringRef into a static pool to preserve it.
1125f757f3fSDimitry Andric /// Most Pattern classes use StringRef so we need this.
1135f757f3fSDimitry Andric StringRef insertStrRef(StringRef S) {
1145f757f3fSDimitry Andric   if (S.empty())
1155f757f3fSDimitry Andric     return {};
1165f757f3fSDimitry Andric 
1175f757f3fSDimitry Andric   static StringSet<> Pool;
1185f757f3fSDimitry Andric   auto [It, Inserted] = Pool.insert(S);
1195f757f3fSDimitry Andric   return It->getKey();
1205f757f3fSDimitry Andric }
1215f757f3fSDimitry Andric 
1225f757f3fSDimitry Andric template <typename Container> auto keys(Container &&C) {
1235f757f3fSDimitry Andric   return map_range(C, [](auto &Entry) -> auto & { return Entry.first; });
1245f757f3fSDimitry Andric }
1255f757f3fSDimitry Andric 
1265f757f3fSDimitry Andric template <typename Container> auto values(Container &&C) {
1275f757f3fSDimitry Andric   return map_range(C, [](auto &Entry) -> auto & { return Entry.second; });
1285f757f3fSDimitry Andric }
1295f757f3fSDimitry Andric 
1305f757f3fSDimitry Andric std::string getIsEnabledPredicateEnumName(unsigned CombinerRuleID) {
1315f757f3fSDimitry Andric   return "GICXXPred_Simple_IsRule" + to_string(CombinerRuleID) + "Enabled";
1325f757f3fSDimitry Andric }
1335f757f3fSDimitry Andric 
1345f757f3fSDimitry Andric //===- MatchTable Helpers  ------------------------------------------------===//
1355f757f3fSDimitry Andric 
1365f757f3fSDimitry Andric LLTCodeGen getLLTCodeGen(const PatternType &PT) {
1375f757f3fSDimitry Andric   return *MVTToLLT(getValueType(PT.getLLTRecord()));
1385f757f3fSDimitry Andric }
1395f757f3fSDimitry Andric 
1405f757f3fSDimitry Andric LLTCodeGenOrTempType getLLTCodeGenOrTempType(const PatternType &PT,
1415f757f3fSDimitry Andric                                              RuleMatcher &RM) {
1425f757f3fSDimitry Andric   assert(!PT.isNone());
1435f757f3fSDimitry Andric 
1445f757f3fSDimitry Andric   if (PT.isLLT())
1455f757f3fSDimitry Andric     return getLLTCodeGen(PT);
1465f757f3fSDimitry Andric 
1475f757f3fSDimitry Andric   assert(PT.isTypeOf());
1485f757f3fSDimitry Andric   auto &OM = RM.getOperandMatcher(PT.getTypeOfOpName());
1495f757f3fSDimitry Andric   return OM.getTempTypeIdx(RM);
1505f757f3fSDimitry Andric }
1515f757f3fSDimitry Andric 
1525f757f3fSDimitry Andric //===- PrettyStackTrace Helpers  ------------------------------------------===//
1535f757f3fSDimitry Andric 
1545f757f3fSDimitry Andric class PrettyStackTraceParse : public PrettyStackTraceEntry {
1555f757f3fSDimitry Andric   const Record &Def;
1565f757f3fSDimitry Andric 
1575f757f3fSDimitry Andric public:
1585f757f3fSDimitry Andric   PrettyStackTraceParse(const Record &Def) : Def(Def) {}
1595f757f3fSDimitry Andric 
1605f757f3fSDimitry Andric   void print(raw_ostream &OS) const override {
1615f757f3fSDimitry Andric     if (Def.isSubClassOf("GICombineRule"))
1625f757f3fSDimitry Andric       OS << "Parsing GICombineRule '" << Def.getName() << "'";
1635f757f3fSDimitry Andric     else if (Def.isSubClassOf(PatFrag::ClassName))
1645f757f3fSDimitry Andric       OS << "Parsing " << PatFrag::ClassName << " '" << Def.getName() << "'";
1655f757f3fSDimitry Andric     else
1665f757f3fSDimitry Andric       OS << "Parsing '" << Def.getName() << "'";
1675f757f3fSDimitry Andric     OS << '\n';
1685f757f3fSDimitry Andric   }
1695f757f3fSDimitry Andric };
1705f757f3fSDimitry Andric 
1715f757f3fSDimitry Andric class PrettyStackTraceEmit : public PrettyStackTraceEntry {
1725f757f3fSDimitry Andric   const Record &Def;
1735f757f3fSDimitry Andric   const Pattern *Pat = nullptr;
1745f757f3fSDimitry Andric 
1755f757f3fSDimitry Andric public:
1765f757f3fSDimitry Andric   PrettyStackTraceEmit(const Record &Def, const Pattern *Pat = nullptr)
1775f757f3fSDimitry Andric       : Def(Def), Pat(Pat) {}
1785f757f3fSDimitry Andric 
1795f757f3fSDimitry Andric   void print(raw_ostream &OS) const override {
1805f757f3fSDimitry Andric     if (Def.isSubClassOf("GICombineRule"))
1815f757f3fSDimitry Andric       OS << "Emitting GICombineRule '" << Def.getName() << "'";
1825f757f3fSDimitry Andric     else if (Def.isSubClassOf(PatFrag::ClassName))
1835f757f3fSDimitry Andric       OS << "Emitting " << PatFrag::ClassName << " '" << Def.getName() << "'";
1845f757f3fSDimitry Andric     else
1855f757f3fSDimitry Andric       OS << "Emitting '" << Def.getName() << "'";
1865f757f3fSDimitry Andric 
1875f757f3fSDimitry Andric     if (Pat)
1885f757f3fSDimitry Andric       OS << " [" << Pat->getKindName() << " '" << Pat->getName() << "']";
1895f757f3fSDimitry Andric     OS << '\n';
1905f757f3fSDimitry Andric   }
1915f757f3fSDimitry Andric };
1925f757f3fSDimitry Andric 
1935f757f3fSDimitry Andric //===- CombineRuleOperandTypeChecker --------------------------------------===//
1945f757f3fSDimitry Andric 
1955f757f3fSDimitry Andric /// This is a wrapper around OperandTypeChecker specialized for Combiner Rules.
1965f757f3fSDimitry Andric /// On top of doing the same things as OperandTypeChecker, this also attempts to
1975f757f3fSDimitry Andric /// infer as many types as possible for temporary register defs & immediates in
1985f757f3fSDimitry Andric /// apply patterns.
1995f757f3fSDimitry Andric ///
2005f757f3fSDimitry Andric /// The inference is trivial and leverages the MCOI OperandTypes encoded in
2015f757f3fSDimitry Andric /// CodeGenInstructions to infer types across patterns in a CombineRule. It's
2025f757f3fSDimitry Andric /// thus very limited and only supports CodeGenInstructions (but that's the main
2035f757f3fSDimitry Andric /// use case so it's fine).
2045f757f3fSDimitry Andric ///
2055f757f3fSDimitry Andric /// We only try to infer untyped operands in apply patterns when they're temp
2065f757f3fSDimitry Andric /// reg defs, or immediates. Inference always outputs a `TypeOf<$x>` where $x is
2075f757f3fSDimitry Andric /// a named operand from a match pattern.
2085f757f3fSDimitry Andric class CombineRuleOperandTypeChecker : private OperandTypeChecker {
2095f757f3fSDimitry Andric public:
2105f757f3fSDimitry Andric   CombineRuleOperandTypeChecker(const Record &RuleDef,
2115f757f3fSDimitry Andric                                 const OperandTable &MatchOpTable)
2125f757f3fSDimitry Andric       : OperandTypeChecker(RuleDef.getLoc()), RuleDef(RuleDef),
2135f757f3fSDimitry Andric         MatchOpTable(MatchOpTable) {}
2145f757f3fSDimitry Andric 
2155f757f3fSDimitry Andric   /// Records and checks a 'match' pattern.
2165f757f3fSDimitry Andric   bool processMatchPattern(InstructionPattern &P);
2175f757f3fSDimitry Andric 
2185f757f3fSDimitry Andric   /// Records and checks an 'apply' pattern.
2195f757f3fSDimitry Andric   bool processApplyPattern(InstructionPattern &P);
2205f757f3fSDimitry Andric 
2215f757f3fSDimitry Andric   /// Propagates types, then perform type inference and do a second round of
2225f757f3fSDimitry Andric   /// propagation in the apply patterns only if any types were inferred.
2235f757f3fSDimitry Andric   void propagateAndInferTypes();
2245f757f3fSDimitry Andric 
2255f757f3fSDimitry Andric private:
2265f757f3fSDimitry Andric   /// TypeEquivalenceClasses are groups of operands of an instruction that share
2275f757f3fSDimitry Andric   /// a common type.
2285f757f3fSDimitry Andric   ///
2295f757f3fSDimitry Andric   /// e.g. [[a, b], [c, d]] means a and b have the same type, and c and
2305f757f3fSDimitry Andric   /// d have the same type too. b/c and a/d don't have to have the same type,
2315f757f3fSDimitry Andric   /// though.
2325f757f3fSDimitry Andric   using TypeEquivalenceClasses = EquivalenceClasses<StringRef>;
2335f757f3fSDimitry Andric 
2345f757f3fSDimitry Andric   /// \returns true for `OPERAND_GENERIC_` 0 through 5.
2355f757f3fSDimitry Andric   /// These are the MCOI types that can be registers. The other MCOI types are
2365f757f3fSDimitry Andric   /// either immediates, or fancier operands used only post-ISel, so we don't
2375f757f3fSDimitry Andric   /// care about them for combiners.
2385f757f3fSDimitry Andric   static bool canMCOIOperandTypeBeARegister(StringRef MCOIType) {
2395f757f3fSDimitry Andric     // Assume OPERAND_GENERIC_0 through 5 can be registers. The other MCOI
2405f757f3fSDimitry Andric     // OperandTypes are either never used in gMIR, or not relevant (e.g.
2415f757f3fSDimitry Andric     // OPERAND_GENERIC_IMM, which is definitely never a register).
2425f757f3fSDimitry Andric     return MCOIType.drop_back(1).ends_with("OPERAND_GENERIC_");
2435f757f3fSDimitry Andric   }
2445f757f3fSDimitry Andric 
2455f757f3fSDimitry Andric   /// Finds the "MCOI::"" operand types for each operand of \p CGP.
2465f757f3fSDimitry Andric   ///
2475f757f3fSDimitry Andric   /// This is a bit trickier than it looks because we need to handle variadic
2485f757f3fSDimitry Andric   /// in/outs.
2495f757f3fSDimitry Andric   ///
2505f757f3fSDimitry Andric   /// e.g. for
2515f757f3fSDimitry Andric   ///   (G_BUILD_VECTOR $vec, $x, $y) ->
2525f757f3fSDimitry Andric   ///   [MCOI::OPERAND_GENERIC_0, MCOI::OPERAND_GENERIC_1,
2535f757f3fSDimitry Andric   ///    MCOI::OPERAND_GENERIC_1]
2545f757f3fSDimitry Andric   ///
2555f757f3fSDimitry Andric   /// For unknown types (which can happen in variadics where varargs types are
2565f757f3fSDimitry Andric   /// inconsistent), a unique name is given, e.g. "unknown_type_0".
2575f757f3fSDimitry Andric   static std::vector<std::string>
2585f757f3fSDimitry Andric   getMCOIOperandTypes(const CodeGenInstructionPattern &CGP);
2595f757f3fSDimitry Andric 
2605f757f3fSDimitry Andric   /// Adds the TypeEquivalenceClasses for \p P in \p OutTECs.
2615f757f3fSDimitry Andric   void getInstEqClasses(const InstructionPattern &P,
2625f757f3fSDimitry Andric                         TypeEquivalenceClasses &OutTECs) const;
2635f757f3fSDimitry Andric 
2645f757f3fSDimitry Andric   /// Calls `getInstEqClasses` on all patterns of the rule to produce the whole
2655f757f3fSDimitry Andric   /// rule's TypeEquivalenceClasses.
2665f757f3fSDimitry Andric   TypeEquivalenceClasses getRuleEqClasses() const;
2675f757f3fSDimitry Andric 
2685f757f3fSDimitry Andric   /// Tries to infer the type of the \p ImmOpIdx -th operand of \p IP using \p
2695f757f3fSDimitry Andric   /// TECs.
2705f757f3fSDimitry Andric   ///
2715f757f3fSDimitry Andric   /// This is achieved by trying to find a named operand in \p IP that shares
2725f757f3fSDimitry Andric   /// the same type as \p ImmOpIdx, and using \ref inferNamedOperandType on that
2735f757f3fSDimitry Andric   /// operand instead.
2745f757f3fSDimitry Andric   ///
2755f757f3fSDimitry Andric   /// \returns the inferred type or an empty PatternType if inference didn't
2765f757f3fSDimitry Andric   /// succeed.
2775f757f3fSDimitry Andric   PatternType inferImmediateType(const InstructionPattern &IP,
2785f757f3fSDimitry Andric                                  unsigned ImmOpIdx,
2795f757f3fSDimitry Andric                                  const TypeEquivalenceClasses &TECs) const;
2805f757f3fSDimitry Andric 
2815f757f3fSDimitry Andric   /// Looks inside \p TECs to infer \p OpName's type.
2825f757f3fSDimitry Andric   ///
2835f757f3fSDimitry Andric   /// \returns the inferred type or an empty PatternType if inference didn't
2845f757f3fSDimitry Andric   /// succeed.
2855f757f3fSDimitry Andric   PatternType inferNamedOperandType(const InstructionPattern &IP,
2865f757f3fSDimitry Andric                                     StringRef OpName,
2871db9f3b2SDimitry Andric                                     const TypeEquivalenceClasses &TECs,
2881db9f3b2SDimitry Andric                                     bool AllowSelf = false) const;
2895f757f3fSDimitry Andric 
2905f757f3fSDimitry Andric   const Record &RuleDef;
2915f757f3fSDimitry Andric   SmallVector<InstructionPattern *, 8> MatchPats;
2925f757f3fSDimitry Andric   SmallVector<InstructionPattern *, 8> ApplyPats;
2935f757f3fSDimitry Andric 
2945f757f3fSDimitry Andric   const OperandTable &MatchOpTable;
2955f757f3fSDimitry Andric };
2965f757f3fSDimitry Andric 
2975f757f3fSDimitry Andric bool CombineRuleOperandTypeChecker::processMatchPattern(InstructionPattern &P) {
2985f757f3fSDimitry Andric   MatchPats.push_back(&P);
2995f757f3fSDimitry Andric   return check(P, /*CheckTypeOf*/ [](const auto &) {
3005f757f3fSDimitry Andric     // GITypeOf in 'match' is currently always rejected by the
3015f757f3fSDimitry Andric     // CombineRuleBuilder after inference is done.
3025f757f3fSDimitry Andric     return true;
3035f757f3fSDimitry Andric   });
3045f757f3fSDimitry Andric }
3055f757f3fSDimitry Andric 
3065f757f3fSDimitry Andric bool CombineRuleOperandTypeChecker::processApplyPattern(InstructionPattern &P) {
3075f757f3fSDimitry Andric   ApplyPats.push_back(&P);
3085f757f3fSDimitry Andric   return check(P, /*CheckTypeOf*/ [&](const PatternType &Ty) {
3095f757f3fSDimitry Andric     // GITypeOf<"$x"> can only be used if "$x" is a matched operand.
3105f757f3fSDimitry Andric     const auto OpName = Ty.getTypeOfOpName();
3115f757f3fSDimitry Andric     if (MatchOpTable.lookup(OpName).Found)
3125f757f3fSDimitry Andric       return true;
3135f757f3fSDimitry Andric 
3145f757f3fSDimitry Andric     PrintError(RuleDef.getLoc(), "'" + OpName + "' ('" + Ty.str() +
3155f757f3fSDimitry Andric                                      "') does not refer to a matched operand!");
3165f757f3fSDimitry Andric     return false;
3175f757f3fSDimitry Andric   });
3185f757f3fSDimitry Andric }
3195f757f3fSDimitry Andric 
3205f757f3fSDimitry Andric void CombineRuleOperandTypeChecker::propagateAndInferTypes() {
3215f757f3fSDimitry Andric   /// First step here is to propagate types using the OperandTypeChecker. That
3225f757f3fSDimitry Andric   /// way we ensure all uses of a given register have consistent types.
3235f757f3fSDimitry Andric   propagateTypes();
3245f757f3fSDimitry Andric 
3255f757f3fSDimitry Andric   /// Build the TypeEquivalenceClasses for the whole rule.
3265f757f3fSDimitry Andric   const TypeEquivalenceClasses TECs = getRuleEqClasses();
3275f757f3fSDimitry Andric 
3285f757f3fSDimitry Andric   /// Look at the apply patterns and find operands that need to be
3295f757f3fSDimitry Andric   /// inferred. We then try to find an equivalence class that they're a part of
3305f757f3fSDimitry Andric   /// and select the best operand to use for the `GITypeOf` type. We prioritize
3315f757f3fSDimitry Andric   /// defs of matched instructions because those are guaranteed to be registers.
3325f757f3fSDimitry Andric   bool InferredAny = false;
3335f757f3fSDimitry Andric   for (auto *Pat : ApplyPats) {
3345f757f3fSDimitry Andric     for (unsigned K = 0; K < Pat->operands_size(); ++K) {
3355f757f3fSDimitry Andric       auto &Op = Pat->getOperand(K);
3365f757f3fSDimitry Andric 
3375f757f3fSDimitry Andric       // We only want to take a look at untyped defs or immediates.
3385f757f3fSDimitry Andric       if ((!Op.isDef() && !Op.hasImmValue()) || Op.getType())
3395f757f3fSDimitry Andric         continue;
3405f757f3fSDimitry Andric 
3415f757f3fSDimitry Andric       // Infer defs & named immediates.
3425f757f3fSDimitry Andric       if (Op.isDef() || Op.isNamedImmediate()) {
3435f757f3fSDimitry Andric         // Check it's not a redefinition of a matched operand.
3445f757f3fSDimitry Andric         // In such cases, inference is not necessary because we just copy
3455f757f3fSDimitry Andric         // operands and don't create temporary registers.
3465f757f3fSDimitry Andric         if (MatchOpTable.lookup(Op.getOperandName()).Found)
3475f757f3fSDimitry Andric           continue;
3485f757f3fSDimitry Andric 
3495f757f3fSDimitry Andric         // Inference is needed here, so try to do it.
3505f757f3fSDimitry Andric         if (PatternType Ty =
3515f757f3fSDimitry Andric                 inferNamedOperandType(*Pat, Op.getOperandName(), TECs)) {
3525f757f3fSDimitry Andric           if (DebugTypeInfer)
3535f757f3fSDimitry Andric             errs() << "INFER: " << Op.describe() << " -> " << Ty.str() << '\n';
3545f757f3fSDimitry Andric           Op.setType(Ty);
3555f757f3fSDimitry Andric           InferredAny = true;
3565f757f3fSDimitry Andric         }
3575f757f3fSDimitry Andric 
3585f757f3fSDimitry Andric         continue;
3595f757f3fSDimitry Andric       }
3605f757f3fSDimitry Andric 
3615f757f3fSDimitry Andric       // Infer immediates
3625f757f3fSDimitry Andric       if (Op.hasImmValue()) {
3635f757f3fSDimitry Andric         if (PatternType Ty = inferImmediateType(*Pat, K, TECs)) {
3645f757f3fSDimitry Andric           if (DebugTypeInfer)
3655f757f3fSDimitry Andric             errs() << "INFER: " << Op.describe() << " -> " << Ty.str() << '\n';
3665f757f3fSDimitry Andric           Op.setType(Ty);
3675f757f3fSDimitry Andric           InferredAny = true;
3685f757f3fSDimitry Andric         }
3695f757f3fSDimitry Andric         continue;
3705f757f3fSDimitry Andric       }
3715f757f3fSDimitry Andric     }
3725f757f3fSDimitry Andric   }
3735f757f3fSDimitry Andric 
3745f757f3fSDimitry Andric   // If we've inferred any types, we want to propagate them across the apply
3755f757f3fSDimitry Andric   // patterns. Type inference only adds GITypeOf types that point to Matched
3765f757f3fSDimitry Andric   // operands, so we definitely don't want to propagate types into the match
3775f757f3fSDimitry Andric   // patterns as well, otherwise bad things happen.
3785f757f3fSDimitry Andric   if (InferredAny) {
3795f757f3fSDimitry Andric     OperandTypeChecker OTC(RuleDef.getLoc());
3805f757f3fSDimitry Andric     for (auto *Pat : ApplyPats) {
3815f757f3fSDimitry Andric       if (!OTC.check(*Pat, [&](const auto &) { return true; }))
3825f757f3fSDimitry Andric         PrintFatalError(RuleDef.getLoc(),
3835f757f3fSDimitry Andric                         "OperandTypeChecker unexpectedly failed on '" +
3845f757f3fSDimitry Andric                             Pat->getName() + "' during Type Inference");
3855f757f3fSDimitry Andric     }
3865f757f3fSDimitry Andric     OTC.propagateTypes();
3875f757f3fSDimitry Andric 
3885f757f3fSDimitry Andric     if (DebugTypeInfer) {
3895f757f3fSDimitry Andric       errs() << "Apply patterns for rule " << RuleDef.getName()
3905f757f3fSDimitry Andric              << " after inference:\n";
3915f757f3fSDimitry Andric       for (auto *Pat : ApplyPats) {
3925f757f3fSDimitry Andric         errs() << "  ";
3935f757f3fSDimitry Andric         Pat->print(errs(), /*PrintName*/ true);
3945f757f3fSDimitry Andric         errs() << '\n';
3955f757f3fSDimitry Andric       }
3965f757f3fSDimitry Andric       errs() << '\n';
3975f757f3fSDimitry Andric     }
3985f757f3fSDimitry Andric   }
3995f757f3fSDimitry Andric }
4005f757f3fSDimitry Andric 
4015f757f3fSDimitry Andric PatternType CombineRuleOperandTypeChecker::inferImmediateType(
4025f757f3fSDimitry Andric     const InstructionPattern &IP, unsigned ImmOpIdx,
4035f757f3fSDimitry Andric     const TypeEquivalenceClasses &TECs) const {
4045f757f3fSDimitry Andric   // We can only infer CGPs.
4055f757f3fSDimitry Andric   const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&IP);
4065f757f3fSDimitry Andric   if (!CGP)
4075f757f3fSDimitry Andric     return {};
4085f757f3fSDimitry Andric 
4095f757f3fSDimitry Andric   // For CGPs, we try to infer immediates by trying to infer another named
4105f757f3fSDimitry Andric   // operand that shares its type.
4115f757f3fSDimitry Andric   //
4125f757f3fSDimitry Andric   // e.g.
4135f757f3fSDimitry Andric   //    Pattern: G_BUILD_VECTOR $x, $y, 0
4145f757f3fSDimitry Andric   //    MCOIs:   [MCOI::OPERAND_GENERIC_0, MCOI::OPERAND_GENERIC_1,
4155f757f3fSDimitry Andric   //              MCOI::OPERAND_GENERIC_1]
4165f757f3fSDimitry Andric   //    $y has the same type as 0, so we can infer $y and get the type 0 should
4175f757f3fSDimitry Andric   //    have.
4185f757f3fSDimitry Andric 
4195f757f3fSDimitry Andric   // We infer immediates by looking for a named operand that shares the same
4205f757f3fSDimitry Andric   // MCOI type.
4215f757f3fSDimitry Andric   const auto MCOITypes = getMCOIOperandTypes(*CGP);
4225f757f3fSDimitry Andric   StringRef ImmOpTy = MCOITypes[ImmOpIdx];
4235f757f3fSDimitry Andric 
4245f757f3fSDimitry Andric   for (const auto &[Idx, Ty] : enumerate(MCOITypes)) {
4255f757f3fSDimitry Andric     if (Idx != ImmOpIdx && Ty == ImmOpTy) {
4265f757f3fSDimitry Andric       const auto &Op = IP.getOperand(Idx);
4275f757f3fSDimitry Andric       if (!Op.isNamedOperand())
4285f757f3fSDimitry Andric         continue;
4295f757f3fSDimitry Andric 
4305f757f3fSDimitry Andric       // Named operand with the same name, try to infer that.
4311db9f3b2SDimitry Andric       if (PatternType InferTy = inferNamedOperandType(IP, Op.getOperandName(),
4321db9f3b2SDimitry Andric                                                       TECs, /*AllowSelf=*/true))
4335f757f3fSDimitry Andric         return InferTy;
4345f757f3fSDimitry Andric     }
4355f757f3fSDimitry Andric   }
4365f757f3fSDimitry Andric 
4375f757f3fSDimitry Andric   return {};
4385f757f3fSDimitry Andric }
4395f757f3fSDimitry Andric 
4405f757f3fSDimitry Andric PatternType CombineRuleOperandTypeChecker::inferNamedOperandType(
4415f757f3fSDimitry Andric     const InstructionPattern &IP, StringRef OpName,
4421db9f3b2SDimitry Andric     const TypeEquivalenceClasses &TECs, bool AllowSelf) const {
4435f757f3fSDimitry Andric   // This is the simplest possible case, we just need to find a TEC that
4441db9f3b2SDimitry Andric   // contains OpName. Look at all operands in equivalence class and try to
4451db9f3b2SDimitry Andric   // find a suitable one. If `AllowSelf` is true, the operand itself is also
4461db9f3b2SDimitry Andric   // considered suitable.
4475f757f3fSDimitry Andric 
4485f757f3fSDimitry Andric   // Check for a def of a matched pattern. This is guaranteed to always
4495f757f3fSDimitry Andric   // be a register so we can blindly use that.
4505f757f3fSDimitry Andric   StringRef GoodOpName;
4515f757f3fSDimitry Andric   for (auto It = TECs.findLeader(OpName); It != TECs.member_end(); ++It) {
4521db9f3b2SDimitry Andric     if (!AllowSelf && *It == OpName)
4535f757f3fSDimitry Andric       continue;
4545f757f3fSDimitry Andric 
4555f757f3fSDimitry Andric     const auto LookupRes = MatchOpTable.lookup(*It);
4565f757f3fSDimitry Andric     if (LookupRes.Def) // Favor defs
4575f757f3fSDimitry Andric       return PatternType::getTypeOf(*It);
4585f757f3fSDimitry Andric 
4595f757f3fSDimitry Andric     // Otherwise just save this in case we don't find any def.
4605f757f3fSDimitry Andric     if (GoodOpName.empty() && LookupRes.Found)
4615f757f3fSDimitry Andric       GoodOpName = *It;
4625f757f3fSDimitry Andric   }
4635f757f3fSDimitry Andric 
4645f757f3fSDimitry Andric   if (!GoodOpName.empty())
4655f757f3fSDimitry Andric     return PatternType::getTypeOf(GoodOpName);
4665f757f3fSDimitry Andric 
4675f757f3fSDimitry Andric   // No good operand found, give up.
4685f757f3fSDimitry Andric   return {};
4695f757f3fSDimitry Andric }
4705f757f3fSDimitry Andric 
4715f757f3fSDimitry Andric std::vector<std::string> CombineRuleOperandTypeChecker::getMCOIOperandTypes(
4725f757f3fSDimitry Andric     const CodeGenInstructionPattern &CGP) {
4735f757f3fSDimitry Andric   // FIXME?: Should we cache this? We call it twice when inferring immediates.
4745f757f3fSDimitry Andric 
4755f757f3fSDimitry Andric   static unsigned UnknownTypeIdx = 0;
4765f757f3fSDimitry Andric 
4775f757f3fSDimitry Andric   std::vector<std::string> OpTypes;
4785f757f3fSDimitry Andric   auto &CGI = CGP.getInst();
4795f757f3fSDimitry Andric   Record *VarArgsTy = CGI.TheDef->isSubClassOf("GenericInstruction")
4805f757f3fSDimitry Andric                           ? CGI.TheDef->getValueAsOptionalDef("variadicOpsType")
4815f757f3fSDimitry Andric                           : nullptr;
4825f757f3fSDimitry Andric   std::string VarArgsTyName =
4835f757f3fSDimitry Andric       VarArgsTy ? ("MCOI::" + VarArgsTy->getValueAsString("OperandType")).str()
4845f757f3fSDimitry Andric                 : ("unknown_type_" + Twine(UnknownTypeIdx++)).str();
4855f757f3fSDimitry Andric 
4865f757f3fSDimitry Andric   // First, handle defs.
4875f757f3fSDimitry Andric   for (unsigned K = 0; K < CGI.Operands.NumDefs; ++K)
4885f757f3fSDimitry Andric     OpTypes.push_back(CGI.Operands[K].OperandType);
4895f757f3fSDimitry Andric 
4905f757f3fSDimitry Andric   // Then, handle variadic defs if there are any.
4915f757f3fSDimitry Andric   if (CGP.hasVariadicDefs()) {
4925f757f3fSDimitry Andric     for (unsigned K = CGI.Operands.NumDefs; K < CGP.getNumInstDefs(); ++K)
4935f757f3fSDimitry Andric       OpTypes.push_back(VarArgsTyName);
4945f757f3fSDimitry Andric   }
4955f757f3fSDimitry Andric 
4965f757f3fSDimitry Andric   // If we had variadic defs, the op idx in the pattern won't match the op idx
4975f757f3fSDimitry Andric   // in the CGI anymore.
4985f757f3fSDimitry Andric   int CGIOpOffset = int(CGI.Operands.NumDefs) - CGP.getNumInstDefs();
4995f757f3fSDimitry Andric   assert(CGP.hasVariadicDefs() ? (CGIOpOffset <= 0) : (CGIOpOffset == 0));
5005f757f3fSDimitry Andric 
5015f757f3fSDimitry Andric   // Handle all remaining use operands, including variadic ones.
5025f757f3fSDimitry Andric   for (unsigned K = CGP.getNumInstDefs(); K < CGP.getNumInstOperands(); ++K) {
5035f757f3fSDimitry Andric     unsigned CGIOpIdx = K + CGIOpOffset;
5045f757f3fSDimitry Andric     if (CGIOpIdx >= CGI.Operands.size()) {
5055f757f3fSDimitry Andric       assert(CGP.isVariadic());
5065f757f3fSDimitry Andric       OpTypes.push_back(VarArgsTyName);
5075f757f3fSDimitry Andric     } else {
5085f757f3fSDimitry Andric       OpTypes.push_back(CGI.Operands[CGIOpIdx].OperandType);
5095f757f3fSDimitry Andric     }
5105f757f3fSDimitry Andric   }
5115f757f3fSDimitry Andric 
5125f757f3fSDimitry Andric   assert(OpTypes.size() == CGP.operands_size());
5135f757f3fSDimitry Andric   return OpTypes;
5145f757f3fSDimitry Andric }
5155f757f3fSDimitry Andric 
5165f757f3fSDimitry Andric void CombineRuleOperandTypeChecker::getInstEqClasses(
5175f757f3fSDimitry Andric     const InstructionPattern &P, TypeEquivalenceClasses &OutTECs) const {
5185f757f3fSDimitry Andric   // Determine the TypeEquivalenceClasses by:
5195f757f3fSDimitry Andric   //    - Getting the MCOI Operand Types.
5205f757f3fSDimitry Andric   //    - Creating a Map of MCOI Type -> [Operand Indexes]
5215f757f3fSDimitry Andric   //    - Iterating over the map, filtering types we don't like, and just adding
5225f757f3fSDimitry Andric   //      the array of Operand Indexes to \p OutTECs.
5235f757f3fSDimitry Andric 
5245f757f3fSDimitry Andric   // We can only do this on CodeGenInstructions. Other InstructionPatterns have
5255f757f3fSDimitry Andric   // no type inference information associated with them.
5265f757f3fSDimitry Andric   // TODO: Could we add some inference information to builtins at least? e.g.
5275f757f3fSDimitry Andric   // ReplaceReg should always replace with a reg of the same type, for instance.
5285f757f3fSDimitry Andric   // Though, those patterns are often used alone so it might not be worth the
5295f757f3fSDimitry Andric   // trouble to infer their types.
5305f757f3fSDimitry Andric   auto *CGP = dyn_cast<CodeGenInstructionPattern>(&P);
5315f757f3fSDimitry Andric   if (!CGP)
5325f757f3fSDimitry Andric     return;
5335f757f3fSDimitry Andric 
5345f757f3fSDimitry Andric   const auto MCOITypes = getMCOIOperandTypes(*CGP);
5355f757f3fSDimitry Andric   assert(MCOITypes.size() == P.operands_size());
5365f757f3fSDimitry Andric 
5375f757f3fSDimitry Andric   DenseMap<StringRef, std::vector<unsigned>> TyToOpIdx;
5385f757f3fSDimitry Andric   for (const auto &[Idx, Ty] : enumerate(MCOITypes))
5395f757f3fSDimitry Andric     TyToOpIdx[Ty].push_back(Idx);
5405f757f3fSDimitry Andric 
5415f757f3fSDimitry Andric   if (DebugTypeInfer)
5425f757f3fSDimitry Andric     errs() << "\tGroups for " << P.getName() << ":\t";
5435f757f3fSDimitry Andric 
5445f757f3fSDimitry Andric   for (const auto &[Ty, Idxs] : TyToOpIdx) {
5455f757f3fSDimitry Andric     if (!canMCOIOperandTypeBeARegister(Ty))
5465f757f3fSDimitry Andric       continue;
5475f757f3fSDimitry Andric 
5485f757f3fSDimitry Andric     if (DebugTypeInfer)
5495f757f3fSDimitry Andric       errs() << '[';
5505f757f3fSDimitry Andric     StringRef Sep = "";
5515f757f3fSDimitry Andric 
5525f757f3fSDimitry Andric     // We only collect named operands.
5535f757f3fSDimitry Andric     StringRef Leader;
5545f757f3fSDimitry Andric     for (unsigned Idx : Idxs) {
5555f757f3fSDimitry Andric       const auto &Op = P.getOperand(Idx);
5565f757f3fSDimitry Andric       if (!Op.isNamedOperand())
5575f757f3fSDimitry Andric         continue;
5585f757f3fSDimitry Andric 
5595f757f3fSDimitry Andric       const auto OpName = Op.getOperandName();
5605f757f3fSDimitry Andric       if (DebugTypeInfer) {
5615f757f3fSDimitry Andric         errs() << Sep << OpName;
5625f757f3fSDimitry Andric         Sep = ", ";
5635f757f3fSDimitry Andric       }
5645f757f3fSDimitry Andric 
5655f757f3fSDimitry Andric       if (Leader.empty())
5665f757f3fSDimitry Andric         OutTECs.insert((Leader = OpName));
5675f757f3fSDimitry Andric       else
5685f757f3fSDimitry Andric         OutTECs.unionSets(Leader, OpName);
5695f757f3fSDimitry Andric     }
5705f757f3fSDimitry Andric 
5715f757f3fSDimitry Andric     if (DebugTypeInfer)
5725f757f3fSDimitry Andric       errs() << "] ";
5735f757f3fSDimitry Andric   }
5745f757f3fSDimitry Andric 
5755f757f3fSDimitry Andric   if (DebugTypeInfer)
5765f757f3fSDimitry Andric     errs() << '\n';
5775f757f3fSDimitry Andric }
5785f757f3fSDimitry Andric 
5795f757f3fSDimitry Andric CombineRuleOperandTypeChecker::TypeEquivalenceClasses
5805f757f3fSDimitry Andric CombineRuleOperandTypeChecker::getRuleEqClasses() const {
5815f757f3fSDimitry Andric   StringMap<unsigned> OpNameToEqClassIdx;
5825f757f3fSDimitry Andric   TypeEquivalenceClasses TECs;
5835f757f3fSDimitry Andric 
5845f757f3fSDimitry Andric   if (DebugTypeInfer)
5855f757f3fSDimitry Andric     errs() << "Rule Operand Type Equivalence Classes for " << RuleDef.getName()
5865f757f3fSDimitry Andric            << ":\n";
5875f757f3fSDimitry Andric 
5885f757f3fSDimitry Andric   for (const auto *Pat : MatchPats)
5895f757f3fSDimitry Andric     getInstEqClasses(*Pat, TECs);
5905f757f3fSDimitry Andric   for (const auto *Pat : ApplyPats)
5915f757f3fSDimitry Andric     getInstEqClasses(*Pat, TECs);
5925f757f3fSDimitry Andric 
5935f757f3fSDimitry Andric   if (DebugTypeInfer) {
5945f757f3fSDimitry Andric     errs() << "Final Type Equivalence Classes: ";
5955f757f3fSDimitry Andric     for (auto ClassIt = TECs.begin(); ClassIt != TECs.end(); ++ClassIt) {
5965f757f3fSDimitry Andric       // only print non-empty classes.
5975f757f3fSDimitry Andric       if (auto MembIt = TECs.member_begin(ClassIt);
5985f757f3fSDimitry Andric           MembIt != TECs.member_end()) {
5995f757f3fSDimitry Andric         errs() << '[';
6005f757f3fSDimitry Andric         StringRef Sep = "";
6015f757f3fSDimitry Andric         for (; MembIt != TECs.member_end(); ++MembIt) {
6025f757f3fSDimitry Andric           errs() << Sep << *MembIt;
6035f757f3fSDimitry Andric           Sep = ", ";
6045f757f3fSDimitry Andric         }
6055f757f3fSDimitry Andric         errs() << "] ";
6065f757f3fSDimitry Andric       }
6075f757f3fSDimitry Andric     }
6085f757f3fSDimitry Andric     errs() << '\n';
6095f757f3fSDimitry Andric   }
6105f757f3fSDimitry Andric 
6115f757f3fSDimitry Andric   return TECs;
6125f757f3fSDimitry Andric }
6135f757f3fSDimitry Andric 
6145f757f3fSDimitry Andric //===- CombineRuleBuilder -------------------------------------------------===//
6155f757f3fSDimitry Andric 
6165f757f3fSDimitry Andric /// Parses combine rule and builds a small intermediate representation to tie
6175f757f3fSDimitry Andric /// patterns together and emit RuleMatchers to match them. This may emit more
6185f757f3fSDimitry Andric /// than one RuleMatcher, e.g. for `wip_match_opcode`.
6195f757f3fSDimitry Andric ///
6205f757f3fSDimitry Andric /// Memory management for `Pattern` objects is done through `std::unique_ptr`.
6215f757f3fSDimitry Andric /// In most cases, there are two stages to a pattern's lifetime:
6225f757f3fSDimitry Andric ///   - Creation in a `parse` function
6235f757f3fSDimitry Andric ///     - The unique_ptr is stored in a variable, and may be destroyed if the
6245f757f3fSDimitry Andric ///       pattern is found to be semantically invalid.
6255f757f3fSDimitry Andric ///   - Ownership transfer into a `PatternMap`
6265f757f3fSDimitry Andric ///     - Once a pattern is moved into either the map of Match or Apply
6275f757f3fSDimitry Andric ///       patterns, it is known to be valid and it never moves back.
6285f757f3fSDimitry Andric class CombineRuleBuilder {
6295f757f3fSDimitry Andric public:
6305f757f3fSDimitry Andric   using PatternMap = MapVector<StringRef, std::unique_ptr<Pattern>>;
6315f757f3fSDimitry Andric   using PatternAlternatives = DenseMap<const Pattern *, unsigned>;
6325f757f3fSDimitry Andric 
6335f757f3fSDimitry Andric   CombineRuleBuilder(const CodeGenTarget &CGT,
6345f757f3fSDimitry Andric                      SubtargetFeatureInfoMap &SubtargetFeatures,
6355f757f3fSDimitry Andric                      Record &RuleDef, unsigned ID,
6365f757f3fSDimitry Andric                      std::vector<RuleMatcher> &OutRMs)
6375f757f3fSDimitry Andric       : CGT(CGT), SubtargetFeatures(SubtargetFeatures), RuleDef(RuleDef),
6385f757f3fSDimitry Andric         RuleID(ID), OutRMs(OutRMs) {}
6395f757f3fSDimitry Andric 
6405f757f3fSDimitry Andric   /// Parses all fields in the RuleDef record.
6415f757f3fSDimitry Andric   bool parseAll();
6425f757f3fSDimitry Andric 
6435f757f3fSDimitry Andric   /// Emits all RuleMatchers into the vector of RuleMatchers passed in the
6445f757f3fSDimitry Andric   /// constructor.
6455f757f3fSDimitry Andric   bool emitRuleMatchers();
6465f757f3fSDimitry Andric 
6475f757f3fSDimitry Andric   void print(raw_ostream &OS) const;
6485f757f3fSDimitry Andric   void dump() const { print(dbgs()); }
6495f757f3fSDimitry Andric 
6505f757f3fSDimitry Andric   /// Debug-only verification of invariants.
6515f757f3fSDimitry Andric #ifndef NDEBUG
6525f757f3fSDimitry Andric   void verify() const;
6535f757f3fSDimitry Andric #endif
6545f757f3fSDimitry Andric 
6555f757f3fSDimitry Andric private:
6565f757f3fSDimitry Andric   const CodeGenInstruction &getGConstant() const {
6575f757f3fSDimitry Andric     return CGT.getInstruction(RuleDef.getRecords().getDef("G_CONSTANT"));
6585f757f3fSDimitry Andric   }
6595f757f3fSDimitry Andric 
6605f757f3fSDimitry Andric   void PrintError(Twine Msg) const { ::PrintError(&RuleDef, Msg); }
6615f757f3fSDimitry Andric   void PrintWarning(Twine Msg) const { ::PrintWarning(RuleDef.getLoc(), Msg); }
6625f757f3fSDimitry Andric   void PrintNote(Twine Msg) const { ::PrintNote(RuleDef.getLoc(), Msg); }
6635f757f3fSDimitry Andric 
6645f757f3fSDimitry Andric   void print(raw_ostream &OS, const PatternAlternatives &Alts) const;
6655f757f3fSDimitry Andric 
6665f757f3fSDimitry Andric   bool addApplyPattern(std::unique_ptr<Pattern> Pat);
6675f757f3fSDimitry Andric   bool addMatchPattern(std::unique_ptr<Pattern> Pat);
6685f757f3fSDimitry Andric 
6695f757f3fSDimitry Andric   /// Adds the expansions from \see MatchDatas to \p CE.
6705f757f3fSDimitry Andric   void declareAllMatchDatasExpansions(CodeExpansions &CE) const;
6715f757f3fSDimitry Andric 
6725f757f3fSDimitry Andric   /// Adds a matcher \p P to \p IM, expanding its code using \p CE.
6735f757f3fSDimitry Andric   /// Note that the predicate is added on the last InstructionMatcher.
6745f757f3fSDimitry Andric   ///
6755f757f3fSDimitry Andric   /// \p Alts is only used if DebugCXXPreds is enabled.
6765f757f3fSDimitry Andric   void addCXXPredicate(RuleMatcher &M, const CodeExpansions &CE,
6775f757f3fSDimitry Andric                        const CXXPattern &P, const PatternAlternatives &Alts);
6785f757f3fSDimitry Andric 
6795f757f3fSDimitry Andric   /// Adds an apply \p P to \p IM, expanding its code using \p CE.
6805f757f3fSDimitry Andric   void addCXXAction(RuleMatcher &M, const CodeExpansions &CE,
6815f757f3fSDimitry Andric                     const CXXPattern &P);
6825f757f3fSDimitry Andric 
6835f757f3fSDimitry Andric   bool hasOnlyCXXApplyPatterns() const;
6845f757f3fSDimitry Andric   bool hasEraseRoot() const;
6855f757f3fSDimitry Andric 
6865f757f3fSDimitry Andric   // Infer machine operand types and check their consistency.
6875f757f3fSDimitry Andric   bool typecheckPatterns();
6885f757f3fSDimitry Andric 
6895f757f3fSDimitry Andric   /// For all PatFragPatterns, add a new entry in PatternAlternatives for each
6905f757f3fSDimitry Andric   /// PatternList it contains. This is multiplicative, so if we have 2
6915f757f3fSDimitry Andric   /// PatFrags with 3 alternatives each, we get 2*3 permutations added to
6925f757f3fSDimitry Andric   /// PermutationsToEmit. The "MaxPermutations" field controls how many
6935f757f3fSDimitry Andric   /// permutations are allowed before an error is emitted and this function
6945f757f3fSDimitry Andric   /// returns false. This is a simple safeguard to prevent combination of
6955f757f3fSDimitry Andric   /// PatFrags from generating enormous amounts of rules.
6965f757f3fSDimitry Andric   bool buildPermutationsToEmit();
6975f757f3fSDimitry Andric 
6985f757f3fSDimitry Andric   /// Checks additional semantics of the Patterns.
6995f757f3fSDimitry Andric   bool checkSemantics();
7005f757f3fSDimitry Andric 
7015f757f3fSDimitry Andric   /// Creates a new RuleMatcher with some boilerplate
7025f757f3fSDimitry Andric   /// settings/actions/predicates, and and adds it to \p OutRMs.
7035f757f3fSDimitry Andric   /// \see addFeaturePredicates too.
7045f757f3fSDimitry Andric   ///
7055f757f3fSDimitry Andric   /// \param Alts Current set of alternatives, for debug comment.
7065f757f3fSDimitry Andric   /// \param AdditionalComment Comment string to be added to the
7075f757f3fSDimitry Andric   ///        `DebugCommentAction`.
7085f757f3fSDimitry Andric   RuleMatcher &addRuleMatcher(const PatternAlternatives &Alts,
7095f757f3fSDimitry Andric                               Twine AdditionalComment = "");
7105f757f3fSDimitry Andric   bool addFeaturePredicates(RuleMatcher &M);
7115f757f3fSDimitry Andric 
7125f757f3fSDimitry Andric   bool findRoots();
7135f757f3fSDimitry Andric   bool buildRuleOperandsTable();
7145f757f3fSDimitry Andric 
7155f757f3fSDimitry Andric   bool parseDefs(const DagInit &Def);
7165f757f3fSDimitry Andric   bool
7175f757f3fSDimitry Andric   parsePatternList(const DagInit &List,
7185f757f3fSDimitry Andric                    function_ref<bool(std::unique_ptr<Pattern>)> ParseAction,
7195f757f3fSDimitry Andric                    StringRef Operator, ArrayRef<SMLoc> DiagLoc,
7205f757f3fSDimitry Andric                    StringRef AnonPatNamePrefix) const;
7215f757f3fSDimitry Andric 
7225f757f3fSDimitry Andric   std::unique_ptr<Pattern> parseInstructionPattern(const Init &Arg,
7235f757f3fSDimitry Andric                                                    StringRef PatName) const;
7245f757f3fSDimitry Andric   std::unique_ptr<Pattern> parseWipMatchOpcodeMatcher(const Init &Arg,
7255f757f3fSDimitry Andric                                                       StringRef PatName) const;
7265f757f3fSDimitry Andric   bool parseInstructionPatternOperand(InstructionPattern &IP,
7275f757f3fSDimitry Andric                                       const Init *OpInit,
7285f757f3fSDimitry Andric                                       const StringInit *OpName) const;
7295f757f3fSDimitry Andric   bool parseInstructionPatternMIFlags(InstructionPattern &IP,
7305f757f3fSDimitry Andric                                       const DagInit *Op) const;
7315f757f3fSDimitry Andric   std::unique_ptr<PatFrag> parsePatFragImpl(const Record *Def) const;
7325f757f3fSDimitry Andric   bool parsePatFragParamList(
7335f757f3fSDimitry Andric       ArrayRef<SMLoc> DiagLoc, const DagInit &OpsList,
7345f757f3fSDimitry Andric       function_ref<bool(StringRef, PatFrag::ParamKind)> ParseAction) const;
7355f757f3fSDimitry Andric   const PatFrag *parsePatFrag(const Record *Def) const;
7365f757f3fSDimitry Andric 
7375f757f3fSDimitry Andric   bool emitMatchPattern(CodeExpansions &CE, const PatternAlternatives &Alts,
7385f757f3fSDimitry Andric                         const InstructionPattern &IP);
7395f757f3fSDimitry Andric   bool emitMatchPattern(CodeExpansions &CE, const PatternAlternatives &Alts,
7405f757f3fSDimitry Andric                         const AnyOpcodePattern &AOP);
7415f757f3fSDimitry Andric 
7425f757f3fSDimitry Andric   bool emitPatFragMatchPattern(CodeExpansions &CE,
7435f757f3fSDimitry Andric                                const PatternAlternatives &Alts, RuleMatcher &RM,
7445f757f3fSDimitry Andric                                InstructionMatcher *IM,
7455f757f3fSDimitry Andric                                const PatFragPattern &PFP,
7465f757f3fSDimitry Andric                                DenseSet<const Pattern *> &SeenPats);
7475f757f3fSDimitry Andric 
7485f757f3fSDimitry Andric   bool emitApplyPatterns(CodeExpansions &CE, RuleMatcher &M);
7495f757f3fSDimitry Andric 
7505f757f3fSDimitry Andric   // Recursively visits InstructionPatterns from P to build up the
7515f757f3fSDimitry Andric   // RuleMatcher actions.
7525f757f3fSDimitry Andric   bool emitInstructionApplyPattern(CodeExpansions &CE, RuleMatcher &M,
7535f757f3fSDimitry Andric                                    const InstructionPattern &P,
7545f757f3fSDimitry Andric                                    DenseSet<const Pattern *> &SeenPats,
7555f757f3fSDimitry Andric                                    StringMap<unsigned> &OperandToTempRegID);
7565f757f3fSDimitry Andric 
7575f757f3fSDimitry Andric   bool emitCodeGenInstructionApplyImmOperand(RuleMatcher &M,
7585f757f3fSDimitry Andric                                              BuildMIAction &DstMI,
7595f757f3fSDimitry Andric                                              const CodeGenInstructionPattern &P,
7605f757f3fSDimitry Andric                                              const InstructionOperand &O);
7615f757f3fSDimitry Andric 
7625f757f3fSDimitry Andric   bool emitBuiltinApplyPattern(CodeExpansions &CE, RuleMatcher &M,
7635f757f3fSDimitry Andric                                const BuiltinPattern &P,
7645f757f3fSDimitry Andric                                StringMap<unsigned> &OperandToTempRegID);
7655f757f3fSDimitry Andric 
7665f757f3fSDimitry Andric   // Recursively visits CodeGenInstructionPattern from P to build up the
7675f757f3fSDimitry Andric   // RuleMatcher/InstructionMatcher. May create new InstructionMatchers as
7685f757f3fSDimitry Andric   // needed.
7695f757f3fSDimitry Andric   using OperandMapperFnRef =
7705f757f3fSDimitry Andric       function_ref<InstructionOperand(const InstructionOperand &)>;
7715f757f3fSDimitry Andric   using OperandDefLookupFn =
7725f757f3fSDimitry Andric       function_ref<const InstructionPattern *(StringRef)>;
7735f757f3fSDimitry Andric   bool emitCodeGenInstructionMatchPattern(
7745f757f3fSDimitry Andric       CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &M,
7755f757f3fSDimitry Andric       InstructionMatcher &IM, const CodeGenInstructionPattern &P,
7765f757f3fSDimitry Andric       DenseSet<const Pattern *> &SeenPats, OperandDefLookupFn LookupOperandDef,
7775f757f3fSDimitry Andric       OperandMapperFnRef OperandMapper = [](const auto &O) { return O; });
7785f757f3fSDimitry Andric 
7795f757f3fSDimitry Andric   const CodeGenTarget &CGT;
7805f757f3fSDimitry Andric   SubtargetFeatureInfoMap &SubtargetFeatures;
7815f757f3fSDimitry Andric   Record &RuleDef;
7825f757f3fSDimitry Andric   const unsigned RuleID;
7835f757f3fSDimitry Andric   std::vector<RuleMatcher> &OutRMs;
7845f757f3fSDimitry Andric 
7855f757f3fSDimitry Andric   // For InstructionMatcher::addOperand
7865f757f3fSDimitry Andric   unsigned AllocatedTemporariesBaseID = 0;
7875f757f3fSDimitry Andric 
7885f757f3fSDimitry Andric   /// The root of the pattern.
7895f757f3fSDimitry Andric   StringRef RootName;
7905f757f3fSDimitry Andric 
7915f757f3fSDimitry Andric   /// These maps have ownership of the actual Pattern objects.
7925f757f3fSDimitry Andric   /// They both map a Pattern's name to the Pattern instance.
7935f757f3fSDimitry Andric   PatternMap MatchPats;
7945f757f3fSDimitry Andric   PatternMap ApplyPats;
7955f757f3fSDimitry Andric 
7965f757f3fSDimitry Andric   /// Operand tables to tie match/apply patterns together.
7975f757f3fSDimitry Andric   OperandTable MatchOpTable;
7985f757f3fSDimitry Andric   OperandTable ApplyOpTable;
7995f757f3fSDimitry Andric 
8005f757f3fSDimitry Andric   /// Set by findRoots.
8015f757f3fSDimitry Andric   Pattern *MatchRoot = nullptr;
8025f757f3fSDimitry Andric   SmallDenseSet<InstructionPattern *, 2> ApplyRoots;
8035f757f3fSDimitry Andric 
8045f757f3fSDimitry Andric   SmallVector<MatchDataInfo, 2> MatchDatas;
8055f757f3fSDimitry Andric   SmallVector<PatternAlternatives, 1> PermutationsToEmit;
8065f757f3fSDimitry Andric 
8075f757f3fSDimitry Andric   // print()/debug-only members.
8085f757f3fSDimitry Andric   mutable SmallPtrSet<const PatFrag *, 2> SeenPatFrags;
8095f757f3fSDimitry Andric };
8105f757f3fSDimitry Andric 
8115f757f3fSDimitry Andric bool CombineRuleBuilder::parseAll() {
8125f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceParse(RuleDef);
8135f757f3fSDimitry Andric 
8145f757f3fSDimitry Andric   if (!parseDefs(*RuleDef.getValueAsDag("Defs")))
8155f757f3fSDimitry Andric     return false;
8165f757f3fSDimitry Andric 
8175f757f3fSDimitry Andric   if (!parsePatternList(
8185f757f3fSDimitry Andric           *RuleDef.getValueAsDag("Match"),
8195f757f3fSDimitry Andric           [this](auto Pat) { return addMatchPattern(std::move(Pat)); }, "match",
8205f757f3fSDimitry Andric           RuleDef.getLoc(), (RuleDef.getName() + "_match").str()))
8215f757f3fSDimitry Andric     return false;
8225f757f3fSDimitry Andric 
8235f757f3fSDimitry Andric   if (!parsePatternList(
8245f757f3fSDimitry Andric           *RuleDef.getValueAsDag("Apply"),
8255f757f3fSDimitry Andric           [this](auto Pat) { return addApplyPattern(std::move(Pat)); }, "apply",
8265f757f3fSDimitry Andric           RuleDef.getLoc(), (RuleDef.getName() + "_apply").str()))
8275f757f3fSDimitry Andric     return false;
8285f757f3fSDimitry Andric 
8295f757f3fSDimitry Andric   if (!buildRuleOperandsTable() || !typecheckPatterns() || !findRoots() ||
8305f757f3fSDimitry Andric       !checkSemantics() || !buildPermutationsToEmit())
8315f757f3fSDimitry Andric     return false;
8325f757f3fSDimitry Andric   LLVM_DEBUG(verify());
8335f757f3fSDimitry Andric   return true;
8345f757f3fSDimitry Andric }
8355f757f3fSDimitry Andric 
8365f757f3fSDimitry Andric bool CombineRuleBuilder::emitRuleMatchers() {
8375f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef);
8385f757f3fSDimitry Andric 
8395f757f3fSDimitry Andric   assert(MatchRoot);
8405f757f3fSDimitry Andric   CodeExpansions CE;
8415f757f3fSDimitry Andric   declareAllMatchDatasExpansions(CE);
8425f757f3fSDimitry Andric 
8435f757f3fSDimitry Andric   assert(!PermutationsToEmit.empty());
8445f757f3fSDimitry Andric   for (const auto &Alts : PermutationsToEmit) {
8455f757f3fSDimitry Andric     switch (MatchRoot->getKind()) {
8465f757f3fSDimitry Andric     case Pattern::K_AnyOpcode: {
8475f757f3fSDimitry Andric       if (!emitMatchPattern(CE, Alts, *cast<AnyOpcodePattern>(MatchRoot)))
8485f757f3fSDimitry Andric         return false;
8495f757f3fSDimitry Andric       break;
8505f757f3fSDimitry Andric     }
8515f757f3fSDimitry Andric     case Pattern::K_PatFrag:
8525f757f3fSDimitry Andric     case Pattern::K_Builtin:
8535f757f3fSDimitry Andric     case Pattern::K_CodeGenInstruction:
8545f757f3fSDimitry Andric       if (!emitMatchPattern(CE, Alts, *cast<InstructionPattern>(MatchRoot)))
8555f757f3fSDimitry Andric         return false;
8565f757f3fSDimitry Andric       break;
8575f757f3fSDimitry Andric     case Pattern::K_CXX:
8585f757f3fSDimitry Andric       PrintError("C++ code cannot be the root of a rule!");
8595f757f3fSDimitry Andric       return false;
8605f757f3fSDimitry Andric     default:
8615f757f3fSDimitry Andric       llvm_unreachable("unknown pattern kind!");
8625f757f3fSDimitry Andric     }
8635f757f3fSDimitry Andric   }
8645f757f3fSDimitry Andric 
8655f757f3fSDimitry Andric   return true;
8665f757f3fSDimitry Andric }
8675f757f3fSDimitry Andric 
8685f757f3fSDimitry Andric void CombineRuleBuilder::print(raw_ostream &OS) const {
8695f757f3fSDimitry Andric   OS << "(CombineRule name:" << RuleDef.getName() << " id:" << RuleID
8705f757f3fSDimitry Andric      << " root:" << RootName << '\n';
8715f757f3fSDimitry Andric 
8725f757f3fSDimitry Andric   if (!MatchDatas.empty()) {
8735f757f3fSDimitry Andric     OS << "  (MatchDatas\n";
8745f757f3fSDimitry Andric     for (const auto &MD : MatchDatas) {
8755f757f3fSDimitry Andric       OS << "    ";
8765f757f3fSDimitry Andric       MD.print(OS);
8775f757f3fSDimitry Andric       OS << '\n';
8785f757f3fSDimitry Andric     }
8795f757f3fSDimitry Andric     OS << "  )\n";
8805f757f3fSDimitry Andric   }
8815f757f3fSDimitry Andric 
8825f757f3fSDimitry Andric   if (!SeenPatFrags.empty()) {
8835f757f3fSDimitry Andric     OS << "  (PatFrags\n";
8845f757f3fSDimitry Andric     for (const auto *PF : SeenPatFrags) {
8855f757f3fSDimitry Andric       PF->print(OS, /*Indent=*/"    ");
8865f757f3fSDimitry Andric       OS << '\n';
8875f757f3fSDimitry Andric     }
8885f757f3fSDimitry Andric     OS << "  )\n";
8895f757f3fSDimitry Andric   }
8905f757f3fSDimitry Andric 
8915f757f3fSDimitry Andric   const auto DumpPats = [&](StringRef Name, const PatternMap &Pats) {
8925f757f3fSDimitry Andric     OS << "  (" << Name << " ";
8935f757f3fSDimitry Andric     if (Pats.empty()) {
8945f757f3fSDimitry Andric       OS << "<empty>)\n";
8955f757f3fSDimitry Andric       return;
8965f757f3fSDimitry Andric     }
8975f757f3fSDimitry Andric 
8985f757f3fSDimitry Andric     OS << '\n';
8995f757f3fSDimitry Andric     for (const auto &[Name, Pat] : Pats) {
9005f757f3fSDimitry Andric       OS << "    ";
9015f757f3fSDimitry Andric       if (Pat.get() == MatchRoot)
9025f757f3fSDimitry Andric         OS << "<match_root>";
9035f757f3fSDimitry Andric       if (isa<InstructionPattern>(Pat.get()) &&
9045f757f3fSDimitry Andric           ApplyRoots.contains(cast<InstructionPattern>(Pat.get())))
9055f757f3fSDimitry Andric         OS << "<apply_root>";
9065f757f3fSDimitry Andric       OS << Name << ":";
9075f757f3fSDimitry Andric       Pat->print(OS, /*PrintName=*/false);
9085f757f3fSDimitry Andric       OS << '\n';
9095f757f3fSDimitry Andric     }
9105f757f3fSDimitry Andric     OS << "  )\n";
9115f757f3fSDimitry Andric   };
9125f757f3fSDimitry Andric 
9135f757f3fSDimitry Andric   DumpPats("MatchPats", MatchPats);
9145f757f3fSDimitry Andric   DumpPats("ApplyPats", ApplyPats);
9155f757f3fSDimitry Andric 
9165f757f3fSDimitry Andric   MatchOpTable.print(OS, "MatchPats", /*Indent*/ "  ");
9175f757f3fSDimitry Andric   ApplyOpTable.print(OS, "ApplyPats", /*Indent*/ "  ");
9185f757f3fSDimitry Andric 
9195f757f3fSDimitry Andric   if (PermutationsToEmit.size() > 1) {
9205f757f3fSDimitry Andric     OS << "  (PermutationsToEmit\n";
9215f757f3fSDimitry Andric     for (const auto &Perm : PermutationsToEmit) {
9225f757f3fSDimitry Andric       OS << "    ";
9235f757f3fSDimitry Andric       print(OS, Perm);
9245f757f3fSDimitry Andric       OS << ",\n";
9255f757f3fSDimitry Andric     }
9265f757f3fSDimitry Andric     OS << "  )\n";
9275f757f3fSDimitry Andric   }
9285f757f3fSDimitry Andric 
9295f757f3fSDimitry Andric   OS << ")\n";
9305f757f3fSDimitry Andric }
9315f757f3fSDimitry Andric 
9325f757f3fSDimitry Andric #ifndef NDEBUG
9335f757f3fSDimitry Andric void CombineRuleBuilder::verify() const {
9345f757f3fSDimitry Andric   const auto VerifyPats = [&](const PatternMap &Pats) {
9355f757f3fSDimitry Andric     for (const auto &[Name, Pat] : Pats) {
9365f757f3fSDimitry Andric       if (!Pat)
9375f757f3fSDimitry Andric         PrintFatalError("null pattern in pattern map!");
9385f757f3fSDimitry Andric 
9395f757f3fSDimitry Andric       if (Name != Pat->getName()) {
9405f757f3fSDimitry Andric         Pat->dump();
9415f757f3fSDimitry Andric         PrintFatalError("Pattern name mismatch! Map name: " + Name +
9425f757f3fSDimitry Andric                         ", Pat name: " + Pat->getName());
9435f757f3fSDimitry Andric       }
9445f757f3fSDimitry Andric 
9455f757f3fSDimitry Andric       // Sanity check: the map should point to the same data as the Pattern.
9465f757f3fSDimitry Andric       // Both strings are allocated in the pool using insertStrRef.
9475f757f3fSDimitry Andric       if (Name.data() != Pat->getName().data()) {
9485f757f3fSDimitry Andric         dbgs() << "Map StringRef: '" << Name << "' @ "
9495f757f3fSDimitry Andric                << (const void *)Name.data() << '\n';
9505f757f3fSDimitry Andric         dbgs() << "Pat String: '" << Pat->getName() << "' @ "
9515f757f3fSDimitry Andric                << (const void *)Pat->getName().data() << '\n';
9525f757f3fSDimitry Andric         PrintFatalError("StringRef stored in the PatternMap is not referencing "
9535f757f3fSDimitry Andric                         "the same string as its Pattern!");
9545f757f3fSDimitry Andric       }
9555f757f3fSDimitry Andric     }
9565f757f3fSDimitry Andric   };
9575f757f3fSDimitry Andric 
9585f757f3fSDimitry Andric   VerifyPats(MatchPats);
9595f757f3fSDimitry Andric   VerifyPats(ApplyPats);
9605f757f3fSDimitry Andric 
9615f757f3fSDimitry Andric   // Check there are no wip_match_opcode patterns in the "apply" patterns.
9625f757f3fSDimitry Andric   if (any_of(ApplyPats,
9635f757f3fSDimitry Andric              [&](auto &E) { return isa<AnyOpcodePattern>(E.second.get()); })) {
9645f757f3fSDimitry Andric     dump();
9655f757f3fSDimitry Andric     PrintFatalError(
9665f757f3fSDimitry Andric         "illegal wip_match_opcode pattern in the 'apply' patterns!");
9675f757f3fSDimitry Andric   }
9685f757f3fSDimitry Andric 
9695f757f3fSDimitry Andric   // Check there are no nullptrs in ApplyRoots.
9705f757f3fSDimitry Andric   if (ApplyRoots.contains(nullptr)) {
9715f757f3fSDimitry Andric     PrintFatalError(
9725f757f3fSDimitry Andric         "CombineRuleBuilder's ApplyRoots set contains a null pointer!");
9735f757f3fSDimitry Andric   }
9745f757f3fSDimitry Andric }
9755f757f3fSDimitry Andric #endif
9765f757f3fSDimitry Andric 
9775f757f3fSDimitry Andric void CombineRuleBuilder::print(raw_ostream &OS,
9785f757f3fSDimitry Andric                                const PatternAlternatives &Alts) const {
9795f757f3fSDimitry Andric   SmallVector<std::string, 1> Strings(
9805f757f3fSDimitry Andric       map_range(Alts, [](const auto &PatAndPerm) {
9815f757f3fSDimitry Andric         return PatAndPerm.first->getName().str() + "[" +
9825f757f3fSDimitry Andric                to_string(PatAndPerm.second) + "]";
9835f757f3fSDimitry Andric       }));
9845f757f3fSDimitry Andric   // Sort so output is deterministic for tests. Otherwise it's sorted by pointer
9855f757f3fSDimitry Andric   // values.
9865f757f3fSDimitry Andric   sort(Strings);
9875f757f3fSDimitry Andric   OS << "[" << join(Strings, ", ") << "]";
9885f757f3fSDimitry Andric }
9895f757f3fSDimitry Andric 
9905f757f3fSDimitry Andric bool CombineRuleBuilder::addApplyPattern(std::unique_ptr<Pattern> Pat) {
9915f757f3fSDimitry Andric   StringRef Name = Pat->getName();
9925f757f3fSDimitry Andric   if (ApplyPats.contains(Name)) {
9935f757f3fSDimitry Andric     PrintError("'" + Name + "' apply pattern defined more than once!");
9945f757f3fSDimitry Andric     return false;
9955f757f3fSDimitry Andric   }
9965f757f3fSDimitry Andric 
9975f757f3fSDimitry Andric   if (isa<AnyOpcodePattern>(Pat.get())) {
9985f757f3fSDimitry Andric     PrintError("'" + Name +
9995f757f3fSDimitry Andric                "': wip_match_opcode is not supported in apply patterns");
10005f757f3fSDimitry Andric     return false;
10015f757f3fSDimitry Andric   }
10025f757f3fSDimitry Andric 
10035f757f3fSDimitry Andric   if (isa<PatFragPattern>(Pat.get())) {
10045f757f3fSDimitry Andric     PrintError("'" + Name + "': using " + PatFrag::ClassName +
10055f757f3fSDimitry Andric                " is not supported in apply patterns");
10065f757f3fSDimitry Andric     return false;
10075f757f3fSDimitry Andric   }
10085f757f3fSDimitry Andric 
10095f757f3fSDimitry Andric   if (auto *CXXPat = dyn_cast<CXXPattern>(Pat.get()))
10105f757f3fSDimitry Andric     CXXPat->setIsApply();
10115f757f3fSDimitry Andric 
10125f757f3fSDimitry Andric   ApplyPats[Name] = std::move(Pat);
10135f757f3fSDimitry Andric   return true;
10145f757f3fSDimitry Andric }
10155f757f3fSDimitry Andric 
10165f757f3fSDimitry Andric bool CombineRuleBuilder::addMatchPattern(std::unique_ptr<Pattern> Pat) {
10175f757f3fSDimitry Andric   StringRef Name = Pat->getName();
10185f757f3fSDimitry Andric   if (MatchPats.contains(Name)) {
10195f757f3fSDimitry Andric     PrintError("'" + Name + "' match pattern defined more than once!");
10205f757f3fSDimitry Andric     return false;
10215f757f3fSDimitry Andric   }
10225f757f3fSDimitry Andric 
10235f757f3fSDimitry Andric   // For now, none of the builtins can appear in 'match'.
10245f757f3fSDimitry Andric   if (const auto *BP = dyn_cast<BuiltinPattern>(Pat.get())) {
10255f757f3fSDimitry Andric     PrintError("'" + BP->getInstName() +
10265f757f3fSDimitry Andric                "' cannot be used in a 'match' pattern");
10275f757f3fSDimitry Andric     return false;
10285f757f3fSDimitry Andric   }
10295f757f3fSDimitry Andric 
10305f757f3fSDimitry Andric   MatchPats[Name] = std::move(Pat);
10315f757f3fSDimitry Andric   return true;
10325f757f3fSDimitry Andric }
10335f757f3fSDimitry Andric 
10345f757f3fSDimitry Andric void CombineRuleBuilder::declareAllMatchDatasExpansions(
10355f757f3fSDimitry Andric     CodeExpansions &CE) const {
10365f757f3fSDimitry Andric   for (const auto &MD : MatchDatas)
10375f757f3fSDimitry Andric     CE.declare(MD.getPatternSymbol(), MD.getQualifiedVariableName());
10385f757f3fSDimitry Andric }
10395f757f3fSDimitry Andric 
10405f757f3fSDimitry Andric void CombineRuleBuilder::addCXXPredicate(RuleMatcher &M,
10415f757f3fSDimitry Andric                                          const CodeExpansions &CE,
10425f757f3fSDimitry Andric                                          const CXXPattern &P,
10435f757f3fSDimitry Andric                                          const PatternAlternatives &Alts) {
10445f757f3fSDimitry Andric   // FIXME: Hack so C++ code is executed last. May not work for more complex
10455f757f3fSDimitry Andric   // patterns.
10465f757f3fSDimitry Andric   auto &IM = *std::prev(M.insnmatchers().end());
10475f757f3fSDimitry Andric   auto Loc = RuleDef.getLoc();
10485f757f3fSDimitry Andric   const auto AddComment = [&](raw_ostream &OS) {
10495f757f3fSDimitry Andric     OS << "// Pattern Alternatives: ";
10505f757f3fSDimitry Andric     print(OS, Alts);
10515f757f3fSDimitry Andric     OS << '\n';
10525f757f3fSDimitry Andric   };
10535f757f3fSDimitry Andric   const auto &ExpandedCode =
10545f757f3fSDimitry Andric       DebugCXXPreds ? P.expandCode(CE, Loc, AddComment) : P.expandCode(CE, Loc);
10555f757f3fSDimitry Andric   IM->addPredicate<GenericInstructionPredicateMatcher>(
10565f757f3fSDimitry Andric       ExpandedCode.getEnumNameWithPrefix(CXXPredPrefix));
10575f757f3fSDimitry Andric }
10585f757f3fSDimitry Andric 
10595f757f3fSDimitry Andric void CombineRuleBuilder::addCXXAction(RuleMatcher &M, const CodeExpansions &CE,
10605f757f3fSDimitry Andric                                       const CXXPattern &P) {
10615f757f3fSDimitry Andric   const auto &ExpandedCode = P.expandCode(CE, RuleDef.getLoc());
10625f757f3fSDimitry Andric   M.addAction<CustomCXXAction>(
10635f757f3fSDimitry Andric       ExpandedCode.getEnumNameWithPrefix(CXXApplyPrefix));
10645f757f3fSDimitry Andric }
10655f757f3fSDimitry Andric 
10665f757f3fSDimitry Andric bool CombineRuleBuilder::hasOnlyCXXApplyPatterns() const {
10675f757f3fSDimitry Andric   return all_of(ApplyPats, [&](auto &Entry) {
10685f757f3fSDimitry Andric     return isa<CXXPattern>(Entry.second.get());
10695f757f3fSDimitry Andric   });
10705f757f3fSDimitry Andric }
10715f757f3fSDimitry Andric 
10725f757f3fSDimitry Andric bool CombineRuleBuilder::hasEraseRoot() const {
10735f757f3fSDimitry Andric   return any_of(ApplyPats, [&](auto &Entry) {
10745f757f3fSDimitry Andric     if (const auto *BP = dyn_cast<BuiltinPattern>(Entry.second.get()))
10755f757f3fSDimitry Andric       return BP->getBuiltinKind() == BI_EraseRoot;
10765f757f3fSDimitry Andric     return false;
10775f757f3fSDimitry Andric   });
10785f757f3fSDimitry Andric }
10795f757f3fSDimitry Andric 
10805f757f3fSDimitry Andric bool CombineRuleBuilder::typecheckPatterns() {
10815f757f3fSDimitry Andric   CombineRuleOperandTypeChecker OTC(RuleDef, MatchOpTable);
10825f757f3fSDimitry Andric 
10835f757f3fSDimitry Andric   for (auto &Pat : values(MatchPats)) {
10845f757f3fSDimitry Andric     if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
10855f757f3fSDimitry Andric       if (!OTC.processMatchPattern(*IP))
10865f757f3fSDimitry Andric         return false;
10875f757f3fSDimitry Andric     }
10885f757f3fSDimitry Andric   }
10895f757f3fSDimitry Andric 
10905f757f3fSDimitry Andric   for (auto &Pat : values(ApplyPats)) {
10915f757f3fSDimitry Andric     if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
10925f757f3fSDimitry Andric       if (!OTC.processApplyPattern(*IP))
10935f757f3fSDimitry Andric         return false;
10945f757f3fSDimitry Andric     }
10955f757f3fSDimitry Andric   }
10965f757f3fSDimitry Andric 
10975f757f3fSDimitry Andric   OTC.propagateAndInferTypes();
10985f757f3fSDimitry Andric 
10995f757f3fSDimitry Andric   // Always check this after in case inference adds some special types to the
11005f757f3fSDimitry Andric   // match patterns.
11015f757f3fSDimitry Andric   for (auto &Pat : values(MatchPats)) {
11025f757f3fSDimitry Andric     if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
11035f757f3fSDimitry Andric       if (IP->diagnoseAllSpecialTypes(
11045f757f3fSDimitry Andric               RuleDef.getLoc(), PatternType::SpecialTyClassName +
11055f757f3fSDimitry Andric                                     " is not supported in 'match' patterns")) {
11065f757f3fSDimitry Andric         return false;
11075f757f3fSDimitry Andric       }
11085f757f3fSDimitry Andric     }
11095f757f3fSDimitry Andric   }
11105f757f3fSDimitry Andric   return true;
11115f757f3fSDimitry Andric }
11125f757f3fSDimitry Andric 
11135f757f3fSDimitry Andric bool CombineRuleBuilder::buildPermutationsToEmit() {
11145f757f3fSDimitry Andric   PermutationsToEmit.clear();
11155f757f3fSDimitry Andric 
11165f757f3fSDimitry Andric   // Start with one empty set of alternatives.
11175f757f3fSDimitry Andric   PermutationsToEmit.emplace_back();
11185f757f3fSDimitry Andric   for (const auto &Pat : values(MatchPats)) {
11195f757f3fSDimitry Andric     unsigned NumAlts = 0;
11205f757f3fSDimitry Andric     // Note: technically, AnyOpcodePattern also needs permutations, but:
11215f757f3fSDimitry Andric     //    - We only allow a single one of them in the root.
11225f757f3fSDimitry Andric     //    - They cannot be mixed with any other pattern other than C++ code.
11235f757f3fSDimitry Andric     // So we don't really need to take them into account here. We could, but
11245f757f3fSDimitry Andric     // that pattern is a hack anyway and the less it's involved, the better.
11255f757f3fSDimitry Andric     if (const auto *PFP = dyn_cast<PatFragPattern>(Pat.get()))
11265f757f3fSDimitry Andric       NumAlts = PFP->getPatFrag().num_alternatives();
11275f757f3fSDimitry Andric     else
11285f757f3fSDimitry Andric       continue;
11295f757f3fSDimitry Andric 
11305f757f3fSDimitry Andric     // For each pattern that needs permutations, multiply the current set of
11315f757f3fSDimitry Andric     // alternatives.
11325f757f3fSDimitry Andric     auto CurPerms = PermutationsToEmit;
11335f757f3fSDimitry Andric     PermutationsToEmit.clear();
11345f757f3fSDimitry Andric 
11355f757f3fSDimitry Andric     for (const auto &Perm : CurPerms) {
11365f757f3fSDimitry Andric       assert(!Perm.count(Pat.get()) && "Pattern already emitted?");
11375f757f3fSDimitry Andric       for (unsigned K = 0; K < NumAlts; ++K) {
11385f757f3fSDimitry Andric         PatternAlternatives NewPerm = Perm;
11395f757f3fSDimitry Andric         NewPerm[Pat.get()] = K;
11405f757f3fSDimitry Andric         PermutationsToEmit.emplace_back(std::move(NewPerm));
11415f757f3fSDimitry Andric       }
11425f757f3fSDimitry Andric     }
11435f757f3fSDimitry Andric   }
11445f757f3fSDimitry Andric 
11455f757f3fSDimitry Andric   if (int64_t MaxPerms = RuleDef.getValueAsInt("MaxPermutations");
11465f757f3fSDimitry Andric       MaxPerms > 0) {
11475f757f3fSDimitry Andric     if ((int64_t)PermutationsToEmit.size() > MaxPerms) {
11485f757f3fSDimitry Andric       PrintError("cannot emit rule '" + RuleDef.getName() + "'; " +
11495f757f3fSDimitry Andric                  Twine(PermutationsToEmit.size()) +
11505f757f3fSDimitry Andric                  " permutations would be emitted, but the max is " +
11515f757f3fSDimitry Andric                  Twine(MaxPerms));
11525f757f3fSDimitry Andric       return false;
11535f757f3fSDimitry Andric     }
11545f757f3fSDimitry Andric   }
11555f757f3fSDimitry Andric 
11565f757f3fSDimitry Andric   // Ensure we always have a single empty entry, it simplifies the emission
11575f757f3fSDimitry Andric   // logic so it doesn't need to handle the case where there are no perms.
11585f757f3fSDimitry Andric   if (PermutationsToEmit.empty()) {
11595f757f3fSDimitry Andric     PermutationsToEmit.emplace_back();
11605f757f3fSDimitry Andric     return true;
11615f757f3fSDimitry Andric   }
11625f757f3fSDimitry Andric 
11635f757f3fSDimitry Andric   return true;
11645f757f3fSDimitry Andric }
11655f757f3fSDimitry Andric 
11665f757f3fSDimitry Andric bool CombineRuleBuilder::checkSemantics() {
11675f757f3fSDimitry Andric   assert(MatchRoot && "Cannot call this before findRoots()");
11685f757f3fSDimitry Andric 
11695f757f3fSDimitry Andric   bool UsesWipMatchOpcode = false;
11705f757f3fSDimitry Andric   for (const auto &Match : MatchPats) {
11715f757f3fSDimitry Andric     const auto *Pat = Match.second.get();
11725f757f3fSDimitry Andric 
11735f757f3fSDimitry Andric     if (const auto *CXXPat = dyn_cast<CXXPattern>(Pat)) {
11745f757f3fSDimitry Andric       if (!CXXPat->getRawCode().contains("return "))
11755f757f3fSDimitry Andric         PrintWarning("'match' C++ code does not seem to return!");
11765f757f3fSDimitry Andric       continue;
11775f757f3fSDimitry Andric     }
11785f757f3fSDimitry Andric 
11795f757f3fSDimitry Andric     // MIFlags in match cannot use the following syntax: (MIFlags $mi)
11805f757f3fSDimitry Andric     if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(Pat)) {
11815f757f3fSDimitry Andric       if (auto *FI = CGP->getMIFlagsInfo()) {
11825f757f3fSDimitry Andric         if (!FI->copy_flags().empty()) {
11835f757f3fSDimitry Andric           PrintError(
11845f757f3fSDimitry Andric               "'match' patterns cannot refer to flags from other instructions");
11855f757f3fSDimitry Andric           PrintNote("MIFlags in '" + CGP->getName() +
11865f757f3fSDimitry Andric                     "' refer to: " + join(FI->copy_flags(), ", "));
11875f757f3fSDimitry Andric           return false;
11885f757f3fSDimitry Andric         }
11895f757f3fSDimitry Andric       }
11905f757f3fSDimitry Andric     }
11915f757f3fSDimitry Andric 
11925f757f3fSDimitry Andric     const auto *AOP = dyn_cast<AnyOpcodePattern>(Pat);
11935f757f3fSDimitry Andric     if (!AOP)
11945f757f3fSDimitry Andric       continue;
11955f757f3fSDimitry Andric 
11965f757f3fSDimitry Andric     if (UsesWipMatchOpcode) {
11975f757f3fSDimitry Andric       PrintError("wip_opcode_match can only be present once");
11985f757f3fSDimitry Andric       return false;
11995f757f3fSDimitry Andric     }
12005f757f3fSDimitry Andric 
12015f757f3fSDimitry Andric     UsesWipMatchOpcode = true;
12025f757f3fSDimitry Andric   }
12035f757f3fSDimitry Andric 
12045f757f3fSDimitry Andric   for (const auto &Apply : ApplyPats) {
12055f757f3fSDimitry Andric     assert(Apply.second.get());
12065f757f3fSDimitry Andric     const auto *IP = dyn_cast<InstructionPattern>(Apply.second.get());
12075f757f3fSDimitry Andric     if (!IP)
12085f757f3fSDimitry Andric       continue;
12095f757f3fSDimitry Andric 
12105f757f3fSDimitry Andric     if (UsesWipMatchOpcode) {
12115f757f3fSDimitry Andric       PrintError("cannot use wip_match_opcode in combination with apply "
12125f757f3fSDimitry Andric                  "instruction patterns!");
12135f757f3fSDimitry Andric       return false;
12145f757f3fSDimitry Andric     }
12155f757f3fSDimitry Andric 
12165f757f3fSDimitry Andric     // Check that the insts mentioned in copy_flags exist.
12175f757f3fSDimitry Andric     if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(IP)) {
12185f757f3fSDimitry Andric       if (auto *FI = CGP->getMIFlagsInfo()) {
12195f757f3fSDimitry Andric         for (auto InstName : FI->copy_flags()) {
12205f757f3fSDimitry Andric           auto It = MatchPats.find(InstName);
12215f757f3fSDimitry Andric           if (It == MatchPats.end()) {
12225f757f3fSDimitry Andric             PrintError("unknown instruction '$" + InstName +
12235f757f3fSDimitry Andric                        "' referenced in MIFlags of '" + CGP->getName() + "'");
12245f757f3fSDimitry Andric             return false;
12255f757f3fSDimitry Andric           }
12265f757f3fSDimitry Andric 
12275f757f3fSDimitry Andric           if (!isa<CodeGenInstructionPattern>(It->second.get())) {
12285f757f3fSDimitry Andric             PrintError(
12295f757f3fSDimitry Andric                 "'$" + InstName +
12305f757f3fSDimitry Andric                 "' does not refer to a CodeGenInstruction in MIFlags of '" +
12315f757f3fSDimitry Andric                 CGP->getName() + "'");
12325f757f3fSDimitry Andric             return false;
12335f757f3fSDimitry Andric           }
12345f757f3fSDimitry Andric         }
12355f757f3fSDimitry Andric       }
12365f757f3fSDimitry Andric     }
12375f757f3fSDimitry Andric 
12385f757f3fSDimitry Andric     const auto *BIP = dyn_cast<BuiltinPattern>(IP);
12395f757f3fSDimitry Andric     if (!BIP)
12405f757f3fSDimitry Andric       continue;
12415f757f3fSDimitry Andric     StringRef Name = BIP->getInstName();
12425f757f3fSDimitry Andric 
12435f757f3fSDimitry Andric     // (GIEraseInst) has to be the only apply pattern, or it can not be used at
12445f757f3fSDimitry Andric     // all. The root cannot have any defs either.
12455f757f3fSDimitry Andric     switch (BIP->getBuiltinKind()) {
12465f757f3fSDimitry Andric     case BI_EraseRoot: {
12475f757f3fSDimitry Andric       if (ApplyPats.size() > 1) {
12485f757f3fSDimitry Andric         PrintError(Name + " must be the only 'apply' pattern");
12495f757f3fSDimitry Andric         return false;
12505f757f3fSDimitry Andric       }
12515f757f3fSDimitry Andric 
12525f757f3fSDimitry Andric       const auto *IRoot = dyn_cast<CodeGenInstructionPattern>(MatchRoot);
12535f757f3fSDimitry Andric       if (!IRoot) {
12545f757f3fSDimitry Andric         PrintError(Name +
12555f757f3fSDimitry Andric                    " can only be used if the root is a CodeGenInstruction");
12565f757f3fSDimitry Andric         return false;
12575f757f3fSDimitry Andric       }
12585f757f3fSDimitry Andric 
12595f757f3fSDimitry Andric       if (IRoot->getNumInstDefs() != 0) {
12605f757f3fSDimitry Andric         PrintError(Name + " can only be used if on roots that do "
12615f757f3fSDimitry Andric                           "not have any output operand");
12625f757f3fSDimitry Andric         PrintNote("'" + IRoot->getInstName() + "' has " +
12635f757f3fSDimitry Andric                   Twine(IRoot->getNumInstDefs()) + " output operands");
12645f757f3fSDimitry Andric         return false;
12655f757f3fSDimitry Andric       }
12665f757f3fSDimitry Andric       break;
12675f757f3fSDimitry Andric     }
12685f757f3fSDimitry Andric     case BI_ReplaceReg: {
12695f757f3fSDimitry Andric       // (GIReplaceReg can only be used on the root instruction)
12705f757f3fSDimitry Andric       // TODO: When we allow rewriting non-root instructions, also allow this.
12715f757f3fSDimitry Andric       StringRef OldRegName = BIP->getOperand(0).getOperandName();
12725f757f3fSDimitry Andric       auto *Def = MatchOpTable.getDef(OldRegName);
12735f757f3fSDimitry Andric       if (!Def) {
12745f757f3fSDimitry Andric         PrintError(Name + " cannot find a matched pattern that defines '" +
12755f757f3fSDimitry Andric                    OldRegName + "'");
12765f757f3fSDimitry Andric         return false;
12775f757f3fSDimitry Andric       }
12785f757f3fSDimitry Andric       if (MatchOpTable.getDef(OldRegName) != MatchRoot) {
12795f757f3fSDimitry Andric         PrintError(Name + " cannot replace '" + OldRegName +
12805f757f3fSDimitry Andric                    "': this builtin can only replace a register defined by the "
12815f757f3fSDimitry Andric                    "match root");
12825f757f3fSDimitry Andric         return false;
12835f757f3fSDimitry Andric       }
12845f757f3fSDimitry Andric       break;
12855f757f3fSDimitry Andric     }
12865f757f3fSDimitry Andric     }
12875f757f3fSDimitry Andric   }
12885f757f3fSDimitry Andric 
12895f757f3fSDimitry Andric   return true;
12905f757f3fSDimitry Andric }
12915f757f3fSDimitry Andric 
12925f757f3fSDimitry Andric RuleMatcher &CombineRuleBuilder::addRuleMatcher(const PatternAlternatives &Alts,
12935f757f3fSDimitry Andric                                                 Twine AdditionalComment) {
12945f757f3fSDimitry Andric   auto &RM = OutRMs.emplace_back(RuleDef.getLoc());
12955f757f3fSDimitry Andric   addFeaturePredicates(RM);
12965f757f3fSDimitry Andric   RM.setPermanentGISelFlags(GISF_IgnoreCopies);
12975f757f3fSDimitry Andric   RM.addRequiredSimplePredicate(getIsEnabledPredicateEnumName(RuleID));
12985f757f3fSDimitry Andric 
12995f757f3fSDimitry Andric   std::string Comment;
13005f757f3fSDimitry Andric   raw_string_ostream CommentOS(Comment);
13015f757f3fSDimitry Andric   CommentOS << "Combiner Rule #" << RuleID << ": " << RuleDef.getName();
13025f757f3fSDimitry Andric   if (!Alts.empty()) {
13035f757f3fSDimitry Andric     CommentOS << " @ ";
13045f757f3fSDimitry Andric     print(CommentOS, Alts);
13055f757f3fSDimitry Andric   }
13065f757f3fSDimitry Andric   if (!AdditionalComment.isTriviallyEmpty())
13075f757f3fSDimitry Andric     CommentOS << "; " << AdditionalComment;
13085f757f3fSDimitry Andric   RM.addAction<DebugCommentAction>(Comment);
13095f757f3fSDimitry Andric   return RM;
13105f757f3fSDimitry Andric }
13115f757f3fSDimitry Andric 
13125f757f3fSDimitry Andric bool CombineRuleBuilder::addFeaturePredicates(RuleMatcher &M) {
13135f757f3fSDimitry Andric   if (!RuleDef.getValue("Predicates"))
13145f757f3fSDimitry Andric     return true;
13155f757f3fSDimitry Andric 
13165f757f3fSDimitry Andric   ListInit *Preds = RuleDef.getValueAsListInit("Predicates");
13175f757f3fSDimitry Andric   for (Init *PI : Preds->getValues()) {
13185f757f3fSDimitry Andric     DefInit *Pred = dyn_cast<DefInit>(PI);
13195f757f3fSDimitry Andric     if (!Pred)
13205f757f3fSDimitry Andric       continue;
13215f757f3fSDimitry Andric 
13225f757f3fSDimitry Andric     Record *Def = Pred->getDef();
13235f757f3fSDimitry Andric     if (!Def->isSubClassOf("Predicate")) {
13245f757f3fSDimitry Andric       ::PrintError(Def, "Unknown 'Predicate' Type");
13255f757f3fSDimitry Andric       return false;
13265f757f3fSDimitry Andric     }
13275f757f3fSDimitry Andric 
13285f757f3fSDimitry Andric     if (Def->getValueAsString("CondString").empty())
13295f757f3fSDimitry Andric       continue;
13305f757f3fSDimitry Andric 
13315f757f3fSDimitry Andric     if (SubtargetFeatures.count(Def) == 0) {
13325f757f3fSDimitry Andric       SubtargetFeatures.emplace(
13335f757f3fSDimitry Andric           Def, SubtargetFeatureInfo(Def, SubtargetFeatures.size()));
13345f757f3fSDimitry Andric     }
13355f757f3fSDimitry Andric 
13365f757f3fSDimitry Andric     M.addRequiredFeature(Def);
13375f757f3fSDimitry Andric   }
13385f757f3fSDimitry Andric 
13395f757f3fSDimitry Andric   return true;
13405f757f3fSDimitry Andric }
13415f757f3fSDimitry Andric 
13425f757f3fSDimitry Andric bool CombineRuleBuilder::findRoots() {
13435f757f3fSDimitry Andric   const auto Finish = [&]() {
13445f757f3fSDimitry Andric     assert(MatchRoot);
13455f757f3fSDimitry Andric 
13465f757f3fSDimitry Andric     if (hasOnlyCXXApplyPatterns() || hasEraseRoot())
13475f757f3fSDimitry Andric       return true;
13485f757f3fSDimitry Andric 
13495f757f3fSDimitry Andric     auto *IPRoot = dyn_cast<InstructionPattern>(MatchRoot);
13505f757f3fSDimitry Andric     if (!IPRoot)
13515f757f3fSDimitry Andric       return true;
13525f757f3fSDimitry Andric 
13535f757f3fSDimitry Andric     if (IPRoot->getNumInstDefs() == 0) {
13545f757f3fSDimitry Andric       // No defs to work with -> find the root using the pattern name.
13555f757f3fSDimitry Andric       auto It = ApplyPats.find(RootName);
13565f757f3fSDimitry Andric       if (It == ApplyPats.end()) {
13575f757f3fSDimitry Andric         PrintError("Cannot find root '" + RootName + "' in apply patterns!");
13585f757f3fSDimitry Andric         return false;
13595f757f3fSDimitry Andric       }
13605f757f3fSDimitry Andric 
13615f757f3fSDimitry Andric       auto *ApplyRoot = dyn_cast<InstructionPattern>(It->second.get());
13625f757f3fSDimitry Andric       if (!ApplyRoot) {
13635f757f3fSDimitry Andric         PrintError("apply pattern root '" + RootName +
13645f757f3fSDimitry Andric                    "' must be an instruction pattern");
13655f757f3fSDimitry Andric         return false;
13665f757f3fSDimitry Andric       }
13675f757f3fSDimitry Andric 
13685f757f3fSDimitry Andric       ApplyRoots.insert(ApplyRoot);
13695f757f3fSDimitry Andric       return true;
13705f757f3fSDimitry Andric     }
13715f757f3fSDimitry Andric 
13725f757f3fSDimitry Andric     // Collect all redefinitions of the MatchRoot's defs and put them in
13735f757f3fSDimitry Andric     // ApplyRoots.
13745f757f3fSDimitry Andric     const auto DefsNeeded = IPRoot->getApplyDefsNeeded();
13755f757f3fSDimitry Andric     for (auto &Op : DefsNeeded) {
13765f757f3fSDimitry Andric       assert(Op.isDef() && Op.isNamedOperand());
13775f757f3fSDimitry Andric       StringRef Name = Op.getOperandName();
13785f757f3fSDimitry Andric 
13795f757f3fSDimitry Andric       auto *ApplyRedef = ApplyOpTable.getDef(Name);
13805f757f3fSDimitry Andric       if (!ApplyRedef) {
13815f757f3fSDimitry Andric         PrintError("'" + Name + "' must be redefined in the 'apply' pattern");
13825f757f3fSDimitry Andric         return false;
13835f757f3fSDimitry Andric       }
13845f757f3fSDimitry Andric 
13855f757f3fSDimitry Andric       ApplyRoots.insert((InstructionPattern *)ApplyRedef);
13865f757f3fSDimitry Andric     }
13875f757f3fSDimitry Andric 
13885f757f3fSDimitry Andric     if (auto It = ApplyPats.find(RootName); It != ApplyPats.end()) {
13895f757f3fSDimitry Andric       if (find(ApplyRoots, It->second.get()) == ApplyRoots.end()) {
13905f757f3fSDimitry Andric         PrintError("apply pattern '" + RootName +
13915f757f3fSDimitry Andric                    "' is supposed to be a root but it does not redefine any of "
13925f757f3fSDimitry Andric                    "the defs of the match root");
13935f757f3fSDimitry Andric         return false;
13945f757f3fSDimitry Andric       }
13955f757f3fSDimitry Andric     }
13965f757f3fSDimitry Andric 
13975f757f3fSDimitry Andric     return true;
13985f757f3fSDimitry Andric   };
13995f757f3fSDimitry Andric 
14005f757f3fSDimitry Andric   // Look by pattern name, e.g.
14015f757f3fSDimitry Andric   //    (G_FNEG $x, $y):$root
14025f757f3fSDimitry Andric   if (auto MatchPatIt = MatchPats.find(RootName);
14035f757f3fSDimitry Andric       MatchPatIt != MatchPats.end()) {
14045f757f3fSDimitry Andric     MatchRoot = MatchPatIt->second.get();
14055f757f3fSDimitry Andric     return Finish();
14065f757f3fSDimitry Andric   }
14075f757f3fSDimitry Andric 
14085f757f3fSDimitry Andric   // Look by def:
14095f757f3fSDimitry Andric   //    (G_FNEG $root, $y)
14105f757f3fSDimitry Andric   auto LookupRes = MatchOpTable.lookup(RootName);
14115f757f3fSDimitry Andric   if (!LookupRes.Found) {
14125f757f3fSDimitry Andric     PrintError("Cannot find root '" + RootName + "' in match patterns!");
14135f757f3fSDimitry Andric     return false;
14145f757f3fSDimitry Andric   }
14155f757f3fSDimitry Andric 
14165f757f3fSDimitry Andric   MatchRoot = LookupRes.Def;
14175f757f3fSDimitry Andric   if (!MatchRoot) {
14185f757f3fSDimitry Andric     PrintError("Cannot use live-in operand '" + RootName +
14195f757f3fSDimitry Andric                "' as match pattern root!");
14205f757f3fSDimitry Andric     return false;
14215f757f3fSDimitry Andric   }
14225f757f3fSDimitry Andric 
14235f757f3fSDimitry Andric   return Finish();
14245f757f3fSDimitry Andric }
14255f757f3fSDimitry Andric 
14265f757f3fSDimitry Andric bool CombineRuleBuilder::buildRuleOperandsTable() {
14275f757f3fSDimitry Andric   const auto DiagnoseRedefMatch = [&](StringRef OpName) {
14285f757f3fSDimitry Andric     PrintError("Operand '" + OpName +
14295f757f3fSDimitry Andric                "' is defined multiple times in the 'match' patterns");
14305f757f3fSDimitry Andric   };
14315f757f3fSDimitry Andric 
14325f757f3fSDimitry Andric   const auto DiagnoseRedefApply = [&](StringRef OpName) {
14335f757f3fSDimitry Andric     PrintError("Operand '" + OpName +
14345f757f3fSDimitry Andric                "' is defined multiple times in the 'apply' patterns");
14355f757f3fSDimitry Andric   };
14365f757f3fSDimitry Andric 
14375f757f3fSDimitry Andric   for (auto &Pat : values(MatchPats)) {
14385f757f3fSDimitry Andric     auto *IP = dyn_cast<InstructionPattern>(Pat.get());
14395f757f3fSDimitry Andric     if (IP && !MatchOpTable.addPattern(IP, DiagnoseRedefMatch))
14405f757f3fSDimitry Andric       return false;
14415f757f3fSDimitry Andric   }
14425f757f3fSDimitry Andric 
14435f757f3fSDimitry Andric   for (auto &Pat : values(ApplyPats)) {
14445f757f3fSDimitry Andric     auto *IP = dyn_cast<InstructionPattern>(Pat.get());
14455f757f3fSDimitry Andric     if (IP && !ApplyOpTable.addPattern(IP, DiagnoseRedefApply))
14465f757f3fSDimitry Andric       return false;
14475f757f3fSDimitry Andric   }
14485f757f3fSDimitry Andric 
14495f757f3fSDimitry Andric   return true;
14505f757f3fSDimitry Andric }
14515f757f3fSDimitry Andric 
14525f757f3fSDimitry Andric bool CombineRuleBuilder::parseDefs(const DagInit &Def) {
14535f757f3fSDimitry Andric   if (Def.getOperatorAsDef(RuleDef.getLoc())->getName() != "defs") {
14545f757f3fSDimitry Andric     PrintError("Expected defs operator");
14555f757f3fSDimitry Andric     return false;
14565f757f3fSDimitry Andric   }
14575f757f3fSDimitry Andric 
14585f757f3fSDimitry Andric   SmallVector<StringRef> Roots;
14595f757f3fSDimitry Andric   for (unsigned I = 0, E = Def.getNumArgs(); I < E; ++I) {
14605f757f3fSDimitry Andric     if (isSpecificDef(*Def.getArg(I), "root")) {
14615f757f3fSDimitry Andric       Roots.emplace_back(Def.getArgNameStr(I));
14625f757f3fSDimitry Andric       continue;
14635f757f3fSDimitry Andric     }
14645f757f3fSDimitry Andric 
14655f757f3fSDimitry Andric     // Subclasses of GIDefMatchData should declare that this rule needs to pass
14665f757f3fSDimitry Andric     // data from the match stage to the apply stage, and ensure that the
14675f757f3fSDimitry Andric     // generated matcher has a suitable variable for it to do so.
14685f757f3fSDimitry Andric     if (Record *MatchDataRec =
14695f757f3fSDimitry Andric             getDefOfSubClass(*Def.getArg(I), "GIDefMatchData")) {
14705f757f3fSDimitry Andric       MatchDatas.emplace_back(Def.getArgNameStr(I),
14715f757f3fSDimitry Andric                               MatchDataRec->getValueAsString("Type"));
14725f757f3fSDimitry Andric       continue;
14735f757f3fSDimitry Andric     }
14745f757f3fSDimitry Andric 
14755f757f3fSDimitry Andric     // Otherwise emit an appropriate error message.
14765f757f3fSDimitry Andric     if (getDefOfSubClass(*Def.getArg(I), "GIDefKind"))
14775f757f3fSDimitry Andric       PrintError("This GIDefKind not implemented in tablegen");
14785f757f3fSDimitry Andric     else if (getDefOfSubClass(*Def.getArg(I), "GIDefKindWithArgs"))
14795f757f3fSDimitry Andric       PrintError("This GIDefKindWithArgs not implemented in tablegen");
14805f757f3fSDimitry Andric     else
14815f757f3fSDimitry Andric       PrintError("Expected a subclass of GIDefKind or a sub-dag whose "
14825f757f3fSDimitry Andric                  "operator is of type GIDefKindWithArgs");
14835f757f3fSDimitry Andric     return false;
14845f757f3fSDimitry Andric   }
14855f757f3fSDimitry Andric 
14865f757f3fSDimitry Andric   if (Roots.size() != 1) {
14875f757f3fSDimitry Andric     PrintError("Combine rules must have exactly one root");
14885f757f3fSDimitry Andric     return false;
14895f757f3fSDimitry Andric   }
14905f757f3fSDimitry Andric 
14915f757f3fSDimitry Andric   RootName = Roots.front();
14925f757f3fSDimitry Andric 
14935f757f3fSDimitry Andric   // Assign variables to all MatchDatas.
14945f757f3fSDimitry Andric   AssignMatchDataVariables(MatchDatas);
14955f757f3fSDimitry Andric   return true;
14965f757f3fSDimitry Andric }
14975f757f3fSDimitry Andric 
14985f757f3fSDimitry Andric bool CombineRuleBuilder::parsePatternList(
14995f757f3fSDimitry Andric     const DagInit &List,
15005f757f3fSDimitry Andric     function_ref<bool(std::unique_ptr<Pattern>)> ParseAction,
15015f757f3fSDimitry Andric     StringRef Operator, ArrayRef<SMLoc> DiagLoc,
15025f757f3fSDimitry Andric     StringRef AnonPatNamePrefix) const {
15035f757f3fSDimitry Andric   if (List.getOperatorAsDef(RuleDef.getLoc())->getName() != Operator) {
15045f757f3fSDimitry Andric     ::PrintError(DiagLoc, "Expected " + Operator + " operator");
15055f757f3fSDimitry Andric     return false;
15065f757f3fSDimitry Andric   }
15075f757f3fSDimitry Andric 
15085f757f3fSDimitry Andric   if (List.getNumArgs() == 0) {
15095f757f3fSDimitry Andric     ::PrintError(DiagLoc, Operator + " pattern list is empty");
15105f757f3fSDimitry Andric     return false;
15115f757f3fSDimitry Andric   }
15125f757f3fSDimitry Andric 
15135f757f3fSDimitry Andric   // The match section consists of a list of matchers and predicates. Parse each
15145f757f3fSDimitry Andric   // one and add the equivalent GIMatchDag nodes, predicates, and edges.
15155f757f3fSDimitry Andric   for (unsigned I = 0; I < List.getNumArgs(); ++I) {
15165f757f3fSDimitry Andric     Init *Arg = List.getArg(I);
15175f757f3fSDimitry Andric     std::string Name = List.getArgName(I)
15185f757f3fSDimitry Andric                            ? List.getArgName(I)->getValue().str()
15195f757f3fSDimitry Andric                            : ("__" + AnonPatNamePrefix + "_" + Twine(I)).str();
15205f757f3fSDimitry Andric 
15215f757f3fSDimitry Andric     if (auto Pat = parseInstructionPattern(*Arg, Name)) {
15225f757f3fSDimitry Andric       if (!ParseAction(std::move(Pat)))
15235f757f3fSDimitry Andric         return false;
15245f757f3fSDimitry Andric       continue;
15255f757f3fSDimitry Andric     }
15265f757f3fSDimitry Andric 
15275f757f3fSDimitry Andric     if (auto Pat = parseWipMatchOpcodeMatcher(*Arg, Name)) {
15285f757f3fSDimitry Andric       if (!ParseAction(std::move(Pat)))
15295f757f3fSDimitry Andric         return false;
15305f757f3fSDimitry Andric       continue;
15315f757f3fSDimitry Andric     }
15325f757f3fSDimitry Andric 
15335f757f3fSDimitry Andric     // Parse arbitrary C++ code
15345f757f3fSDimitry Andric     if (const auto *StringI = dyn_cast<StringInit>(Arg)) {
15355f757f3fSDimitry Andric       auto CXXPat = std::make_unique<CXXPattern>(*StringI, insertStrRef(Name));
15365f757f3fSDimitry Andric       if (!ParseAction(std::move(CXXPat)))
15375f757f3fSDimitry Andric         return false;
15385f757f3fSDimitry Andric       continue;
15395f757f3fSDimitry Andric     }
15405f757f3fSDimitry Andric 
15415f757f3fSDimitry Andric     ::PrintError(DiagLoc,
15425f757f3fSDimitry Andric                  "Failed to parse pattern: '" + Arg->getAsString() + "'");
15435f757f3fSDimitry Andric     return false;
15445f757f3fSDimitry Andric   }
15455f757f3fSDimitry Andric 
15465f757f3fSDimitry Andric   return true;
15475f757f3fSDimitry Andric }
15485f757f3fSDimitry Andric 
15495f757f3fSDimitry Andric std::unique_ptr<Pattern>
15505f757f3fSDimitry Andric CombineRuleBuilder::parseInstructionPattern(const Init &Arg,
15515f757f3fSDimitry Andric                                             StringRef Name) const {
15525f757f3fSDimitry Andric   const DagInit *DagPat = dyn_cast<DagInit>(&Arg);
15535f757f3fSDimitry Andric   if (!DagPat)
15545f757f3fSDimitry Andric     return nullptr;
15555f757f3fSDimitry Andric 
15565f757f3fSDimitry Andric   std::unique_ptr<InstructionPattern> Pat;
15575f757f3fSDimitry Andric   if (const DagInit *IP = getDagWithOperatorOfSubClass(Arg, "Instruction")) {
15585f757f3fSDimitry Andric     auto &Instr = CGT.getInstruction(IP->getOperatorAsDef(RuleDef.getLoc()));
15595f757f3fSDimitry Andric     Pat =
15605f757f3fSDimitry Andric         std::make_unique<CodeGenInstructionPattern>(Instr, insertStrRef(Name));
15615f757f3fSDimitry Andric   } else if (const DagInit *PFP =
15625f757f3fSDimitry Andric                  getDagWithOperatorOfSubClass(Arg, PatFrag::ClassName)) {
15635f757f3fSDimitry Andric     const Record *Def = PFP->getOperatorAsDef(RuleDef.getLoc());
15645f757f3fSDimitry Andric     const PatFrag *PF = parsePatFrag(Def);
15655f757f3fSDimitry Andric     if (!PF)
15665f757f3fSDimitry Andric       return nullptr; // Already diagnosed by parsePatFrag
15675f757f3fSDimitry Andric     Pat = std::make_unique<PatFragPattern>(*PF, insertStrRef(Name));
15685f757f3fSDimitry Andric   } else if (const DagInit *BP =
15695f757f3fSDimitry Andric                  getDagWithOperatorOfSubClass(Arg, BuiltinPattern::ClassName)) {
15705f757f3fSDimitry Andric     Pat = std::make_unique<BuiltinPattern>(
15715f757f3fSDimitry Andric         *BP->getOperatorAsDef(RuleDef.getLoc()), insertStrRef(Name));
15725f757f3fSDimitry Andric   } else {
15735f757f3fSDimitry Andric     return nullptr;
15745f757f3fSDimitry Andric   }
15755f757f3fSDimitry Andric 
15765f757f3fSDimitry Andric   for (unsigned K = 0; K < DagPat->getNumArgs(); ++K) {
15775f757f3fSDimitry Andric     Init *Arg = DagPat->getArg(K);
15785f757f3fSDimitry Andric     if (auto *DagArg = getDagWithSpecificOperator(*Arg, "MIFlags")) {
15795f757f3fSDimitry Andric       if (!parseInstructionPatternMIFlags(*Pat, DagArg))
15805f757f3fSDimitry Andric         return nullptr;
15815f757f3fSDimitry Andric       continue;
15825f757f3fSDimitry Andric     }
15835f757f3fSDimitry Andric 
15845f757f3fSDimitry Andric     if (!parseInstructionPatternOperand(*Pat, Arg, DagPat->getArgName(K)))
15855f757f3fSDimitry Andric       return nullptr;
15865f757f3fSDimitry Andric   }
15875f757f3fSDimitry Andric 
15885f757f3fSDimitry Andric   if (!Pat->checkSemantics(RuleDef.getLoc()))
15895f757f3fSDimitry Andric     return nullptr;
15905f757f3fSDimitry Andric 
15915f757f3fSDimitry Andric   return std::move(Pat);
15925f757f3fSDimitry Andric }
15935f757f3fSDimitry Andric 
15945f757f3fSDimitry Andric std::unique_ptr<Pattern>
15955f757f3fSDimitry Andric CombineRuleBuilder::parseWipMatchOpcodeMatcher(const Init &Arg,
15965f757f3fSDimitry Andric                                                StringRef Name) const {
15975f757f3fSDimitry Andric   const DagInit *Matcher = getDagWithSpecificOperator(Arg, "wip_match_opcode");
15985f757f3fSDimitry Andric   if (!Matcher)
15995f757f3fSDimitry Andric     return nullptr;
16005f757f3fSDimitry Andric 
16015f757f3fSDimitry Andric   if (Matcher->getNumArgs() == 0) {
16025f757f3fSDimitry Andric     PrintError("Empty wip_match_opcode");
16035f757f3fSDimitry Andric     return nullptr;
16045f757f3fSDimitry Andric   }
16055f757f3fSDimitry Andric 
16065f757f3fSDimitry Andric   // Each argument is an opcode that can match.
16075f757f3fSDimitry Andric   auto Result = std::make_unique<AnyOpcodePattern>(insertStrRef(Name));
16085f757f3fSDimitry Andric   for (const auto &Arg : Matcher->getArgs()) {
16095f757f3fSDimitry Andric     Record *OpcodeDef = getDefOfSubClass(*Arg, "Instruction");
16105f757f3fSDimitry Andric     if (OpcodeDef) {
16115f757f3fSDimitry Andric       Result->addOpcode(&CGT.getInstruction(OpcodeDef));
16125f757f3fSDimitry Andric       continue;
16135f757f3fSDimitry Andric     }
16145f757f3fSDimitry Andric 
16155f757f3fSDimitry Andric     PrintError("Arguments to wip_match_opcode must be instructions");
16165f757f3fSDimitry Andric     return nullptr;
16175f757f3fSDimitry Andric   }
16185f757f3fSDimitry Andric 
16195f757f3fSDimitry Andric   return std::move(Result);
16205f757f3fSDimitry Andric }
16215f757f3fSDimitry Andric 
16225f757f3fSDimitry Andric bool CombineRuleBuilder::parseInstructionPatternOperand(
16235f757f3fSDimitry Andric     InstructionPattern &IP, const Init *OpInit,
16245f757f3fSDimitry Andric     const StringInit *OpName) const {
16255f757f3fSDimitry Andric   const auto ParseErr = [&]() {
16265f757f3fSDimitry Andric     PrintError("cannot parse operand '" + OpInit->getAsUnquotedString() + "' ");
16275f757f3fSDimitry Andric     if (OpName)
16285f757f3fSDimitry Andric       PrintNote("operand name is '" + OpName->getAsUnquotedString() + "'");
16295f757f3fSDimitry Andric     return false;
16305f757f3fSDimitry Andric   };
16315f757f3fSDimitry Andric 
16325f757f3fSDimitry Andric   // untyped immediate, e.g. 0
16335f757f3fSDimitry Andric   if (const auto *IntImm = dyn_cast<IntInit>(OpInit)) {
16345f757f3fSDimitry Andric     std::string Name = OpName ? OpName->getAsUnquotedString() : "";
16355f757f3fSDimitry Andric     IP.addOperand(IntImm->getValue(), insertStrRef(Name), PatternType());
16365f757f3fSDimitry Andric     return true;
16375f757f3fSDimitry Andric   }
16385f757f3fSDimitry Andric 
16395f757f3fSDimitry Andric   // typed immediate, e.g. (i32 0)
16405f757f3fSDimitry Andric   if (const auto *DagOp = dyn_cast<DagInit>(OpInit)) {
16415f757f3fSDimitry Andric     if (DagOp->getNumArgs() != 1)
16425f757f3fSDimitry Andric       return ParseErr();
16435f757f3fSDimitry Andric 
16445f757f3fSDimitry Andric     const Record *TyDef = DagOp->getOperatorAsDef(RuleDef.getLoc());
16455f757f3fSDimitry Andric     auto ImmTy = PatternType::get(RuleDef.getLoc(), TyDef,
16465f757f3fSDimitry Andric                                   "cannot parse immediate '" +
16475f757f3fSDimitry Andric                                       DagOp->getAsUnquotedString() + "'");
16485f757f3fSDimitry Andric     if (!ImmTy)
16495f757f3fSDimitry Andric       return false;
16505f757f3fSDimitry Andric 
16515f757f3fSDimitry Andric     if (!IP.hasAllDefs()) {
16525f757f3fSDimitry Andric       PrintError("out operand of '" + IP.getInstName() +
16535f757f3fSDimitry Andric                  "' cannot be an immediate");
16545f757f3fSDimitry Andric       return false;
16555f757f3fSDimitry Andric     }
16565f757f3fSDimitry Andric 
16575f757f3fSDimitry Andric     const auto *Val = dyn_cast<IntInit>(DagOp->getArg(0));
16585f757f3fSDimitry Andric     if (!Val)
16595f757f3fSDimitry Andric       return ParseErr();
16605f757f3fSDimitry Andric 
16615f757f3fSDimitry Andric     std::string Name = OpName ? OpName->getAsUnquotedString() : "";
16625f757f3fSDimitry Andric     IP.addOperand(Val->getValue(), insertStrRef(Name), *ImmTy);
16635f757f3fSDimitry Andric     return true;
16645f757f3fSDimitry Andric   }
16655f757f3fSDimitry Andric 
16665f757f3fSDimitry Andric   // Typed operand e.g. $x/$z in (G_FNEG $x, $z)
16675f757f3fSDimitry Andric   if (auto *DefI = dyn_cast<DefInit>(OpInit)) {
16685f757f3fSDimitry Andric     if (!OpName) {
16695f757f3fSDimitry Andric       PrintError("expected an operand name after '" + OpInit->getAsString() +
16705f757f3fSDimitry Andric                  "'");
16715f757f3fSDimitry Andric       return false;
16725f757f3fSDimitry Andric     }
16735f757f3fSDimitry Andric     const Record *Def = DefI->getDef();
16745f757f3fSDimitry Andric     auto Ty =
16755f757f3fSDimitry Andric         PatternType::get(RuleDef.getLoc(), Def, "cannot parse operand type");
16765f757f3fSDimitry Andric     if (!Ty)
16775f757f3fSDimitry Andric       return false;
16785f757f3fSDimitry Andric     IP.addOperand(insertStrRef(OpName->getAsUnquotedString()), *Ty);
16795f757f3fSDimitry Andric     return true;
16805f757f3fSDimitry Andric   }
16815f757f3fSDimitry Andric 
16825f757f3fSDimitry Andric   // Untyped operand e.g. $x/$z in (G_FNEG $x, $z)
16835f757f3fSDimitry Andric   if (isa<UnsetInit>(OpInit)) {
16845f757f3fSDimitry Andric     assert(OpName && "Unset w/ no OpName?");
16855f757f3fSDimitry Andric     IP.addOperand(insertStrRef(OpName->getAsUnquotedString()), PatternType());
16865f757f3fSDimitry Andric     return true;
16875f757f3fSDimitry Andric   }
16885f757f3fSDimitry Andric 
16895f757f3fSDimitry Andric   return ParseErr();
16905f757f3fSDimitry Andric }
16915f757f3fSDimitry Andric 
16925f757f3fSDimitry Andric bool CombineRuleBuilder::parseInstructionPatternMIFlags(
16935f757f3fSDimitry Andric     InstructionPattern &IP, const DagInit *Op) const {
16945f757f3fSDimitry Andric   auto *CGIP = dyn_cast<CodeGenInstructionPattern>(&IP);
16955f757f3fSDimitry Andric   if (!CGIP) {
16965f757f3fSDimitry Andric     PrintError("matching/writing MIFlags is only allowed on CodeGenInstruction "
16975f757f3fSDimitry Andric                "patterns");
16985f757f3fSDimitry Andric     return false;
16995f757f3fSDimitry Andric   }
17005f757f3fSDimitry Andric 
17015f757f3fSDimitry Andric   const auto CheckFlagEnum = [&](const Record *R) {
17025f757f3fSDimitry Andric     if (!R->isSubClassOf(MIFlagsEnumClassName)) {
17035f757f3fSDimitry Andric       PrintError("'" + R->getName() + "' is not a subclass of '" +
17045f757f3fSDimitry Andric                  MIFlagsEnumClassName + "'");
17055f757f3fSDimitry Andric       return false;
17065f757f3fSDimitry Andric     }
17075f757f3fSDimitry Andric 
17085f757f3fSDimitry Andric     return true;
17095f757f3fSDimitry Andric   };
17105f757f3fSDimitry Andric 
17115f757f3fSDimitry Andric   if (CGIP->getMIFlagsInfo()) {
17125f757f3fSDimitry Andric     PrintError("MIFlags can only be present once on an instruction");
17135f757f3fSDimitry Andric     return false;
17145f757f3fSDimitry Andric   }
17155f757f3fSDimitry Andric 
17165f757f3fSDimitry Andric   auto &FI = CGIP->getOrCreateMIFlagsInfo();
17175f757f3fSDimitry Andric   for (unsigned K = 0; K < Op->getNumArgs(); ++K) {
17185f757f3fSDimitry Andric     const Init *Arg = Op->getArg(K);
17195f757f3fSDimitry Andric 
17205f757f3fSDimitry Andric     // Match/set a flag: (MIFlags FmNoNans)
17215f757f3fSDimitry Andric     if (const auto *Def = dyn_cast<DefInit>(Arg)) {
17225f757f3fSDimitry Andric       const Record *R = Def->getDef();
17235f757f3fSDimitry Andric       if (!CheckFlagEnum(R))
17245f757f3fSDimitry Andric         return false;
17255f757f3fSDimitry Andric 
17265f757f3fSDimitry Andric       FI.addSetFlag(R);
17275f757f3fSDimitry Andric       continue;
17285f757f3fSDimitry Andric     }
17295f757f3fSDimitry Andric 
17305f757f3fSDimitry Andric     // Do not match a flag/unset a flag: (MIFlags (not FmNoNans))
17315f757f3fSDimitry Andric     if (const DagInit *NotDag = getDagWithSpecificOperator(*Arg, "not")) {
17325f757f3fSDimitry Andric       for (const Init *NotArg : NotDag->getArgs()) {
17335f757f3fSDimitry Andric         const DefInit *DefArg = dyn_cast<DefInit>(NotArg);
17345f757f3fSDimitry Andric         if (!DefArg) {
17355f757f3fSDimitry Andric           PrintError("cannot parse '" + NotArg->getAsUnquotedString() +
17365f757f3fSDimitry Andric                      "': expected a '" + MIFlagsEnumClassName + "'");
17375f757f3fSDimitry Andric           return false;
17385f757f3fSDimitry Andric         }
17395f757f3fSDimitry Andric 
17405f757f3fSDimitry Andric         const Record *R = DefArg->getDef();
17415f757f3fSDimitry Andric         if (!CheckFlagEnum(R))
17425f757f3fSDimitry Andric           return false;
17435f757f3fSDimitry Andric 
17445f757f3fSDimitry Andric         FI.addUnsetFlag(R);
17455f757f3fSDimitry Andric         continue;
17465f757f3fSDimitry Andric       }
17475f757f3fSDimitry Andric 
17485f757f3fSDimitry Andric       continue;
17495f757f3fSDimitry Andric     }
17505f757f3fSDimitry Andric 
17515f757f3fSDimitry Andric     // Copy flags from a matched instruction: (MIFlags $mi)
17525f757f3fSDimitry Andric     if (isa<UnsetInit>(Arg)) {
17535f757f3fSDimitry Andric       FI.addCopyFlag(insertStrRef(Op->getArgName(K)->getAsUnquotedString()));
17545f757f3fSDimitry Andric       continue;
17555f757f3fSDimitry Andric     }
17565f757f3fSDimitry Andric   }
17575f757f3fSDimitry Andric 
17585f757f3fSDimitry Andric   return true;
17595f757f3fSDimitry Andric }
17605f757f3fSDimitry Andric 
17615f757f3fSDimitry Andric std::unique_ptr<PatFrag>
17625f757f3fSDimitry Andric CombineRuleBuilder::parsePatFragImpl(const Record *Def) const {
17635f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceParse(*Def);
17645f757f3fSDimitry Andric   if (!Def->isSubClassOf(PatFrag::ClassName))
17655f757f3fSDimitry Andric     return nullptr;
17665f757f3fSDimitry Andric 
17675f757f3fSDimitry Andric   const DagInit *Ins = Def->getValueAsDag("InOperands");
17685f757f3fSDimitry Andric   if (Ins->getOperatorAsDef(Def->getLoc())->getName() != "ins") {
17695f757f3fSDimitry Andric     ::PrintError(Def, "expected 'ins' operator for " + PatFrag::ClassName +
17705f757f3fSDimitry Andric                           " in operands list");
17715f757f3fSDimitry Andric     return nullptr;
17725f757f3fSDimitry Andric   }
17735f757f3fSDimitry Andric 
17745f757f3fSDimitry Andric   const DagInit *Outs = Def->getValueAsDag("OutOperands");
17755f757f3fSDimitry Andric   if (Outs->getOperatorAsDef(Def->getLoc())->getName() != "outs") {
17765f757f3fSDimitry Andric     ::PrintError(Def, "expected 'outs' operator for " + PatFrag::ClassName +
17775f757f3fSDimitry Andric                           " out operands list");
17785f757f3fSDimitry Andric     return nullptr;
17795f757f3fSDimitry Andric   }
17805f757f3fSDimitry Andric 
17815f757f3fSDimitry Andric   auto Result = std::make_unique<PatFrag>(*Def);
17825f757f3fSDimitry Andric   if (!parsePatFragParamList(Def->getLoc(), *Outs,
17835f757f3fSDimitry Andric                              [&](StringRef Name, PatFrag::ParamKind Kind) {
17845f757f3fSDimitry Andric                                Result->addOutParam(insertStrRef(Name), Kind);
17855f757f3fSDimitry Andric                                return true;
17865f757f3fSDimitry Andric                              }))
17875f757f3fSDimitry Andric     return nullptr;
17885f757f3fSDimitry Andric 
17895f757f3fSDimitry Andric   if (!parsePatFragParamList(Def->getLoc(), *Ins,
17905f757f3fSDimitry Andric                              [&](StringRef Name, PatFrag::ParamKind Kind) {
17915f757f3fSDimitry Andric                                Result->addInParam(insertStrRef(Name), Kind);
17925f757f3fSDimitry Andric                                return true;
17935f757f3fSDimitry Andric                              }))
17945f757f3fSDimitry Andric     return nullptr;
17955f757f3fSDimitry Andric 
17965f757f3fSDimitry Andric   const ListInit *Alts = Def->getValueAsListInit("Alternatives");
17975f757f3fSDimitry Andric   unsigned AltIdx = 0;
17985f757f3fSDimitry Andric   for (const Init *Alt : *Alts) {
17995f757f3fSDimitry Andric     const auto *PatDag = dyn_cast<DagInit>(Alt);
18005f757f3fSDimitry Andric     if (!PatDag) {
18015f757f3fSDimitry Andric       ::PrintError(Def, "expected dag init for PatFrag pattern alternative");
18025f757f3fSDimitry Andric       return nullptr;
18035f757f3fSDimitry Andric     }
18045f757f3fSDimitry Andric 
18055f757f3fSDimitry Andric     PatFrag::Alternative &A = Result->addAlternative();
18065f757f3fSDimitry Andric     const auto AddPat = [&](std::unique_ptr<Pattern> Pat) {
18075f757f3fSDimitry Andric       A.Pats.push_back(std::move(Pat));
18085f757f3fSDimitry Andric       return true;
18095f757f3fSDimitry Andric     };
18105f757f3fSDimitry Andric 
18115f757f3fSDimitry Andric     if (!parsePatternList(
18125f757f3fSDimitry Andric             *PatDag, AddPat, "pattern", Def->getLoc(),
18135f757f3fSDimitry Andric             /*AnonPatPrefix*/
18145f757f3fSDimitry Andric             (Def->getName() + "_alt" + Twine(AltIdx++) + "_pattern").str()))
18155f757f3fSDimitry Andric       return nullptr;
18165f757f3fSDimitry Andric   }
18175f757f3fSDimitry Andric 
18185f757f3fSDimitry Andric   if (!Result->buildOperandsTables() || !Result->checkSemantics())
18195f757f3fSDimitry Andric     return nullptr;
18205f757f3fSDimitry Andric 
18215f757f3fSDimitry Andric   return Result;
18225f757f3fSDimitry Andric }
18235f757f3fSDimitry Andric 
18245f757f3fSDimitry Andric bool CombineRuleBuilder::parsePatFragParamList(
18255f757f3fSDimitry Andric     ArrayRef<SMLoc> DiagLoc, const DagInit &OpsList,
18265f757f3fSDimitry Andric     function_ref<bool(StringRef, PatFrag::ParamKind)> ParseAction) const {
18275f757f3fSDimitry Andric   for (unsigned K = 0; K < OpsList.getNumArgs(); ++K) {
18285f757f3fSDimitry Andric     const StringInit *Name = OpsList.getArgName(K);
18295f757f3fSDimitry Andric     const Init *Ty = OpsList.getArg(K);
18305f757f3fSDimitry Andric 
18315f757f3fSDimitry Andric     if (!Name) {
18325f757f3fSDimitry Andric       ::PrintError(DiagLoc, "all operands must be named'");
18335f757f3fSDimitry Andric       return false;
18345f757f3fSDimitry Andric     }
18355f757f3fSDimitry Andric     const std::string NameStr = Name->getAsUnquotedString();
18365f757f3fSDimitry Andric 
18375f757f3fSDimitry Andric     PatFrag::ParamKind OpKind;
18385f757f3fSDimitry Andric     if (isSpecificDef(*Ty, "gi_imm"))
18395f757f3fSDimitry Andric       OpKind = PatFrag::PK_Imm;
18405f757f3fSDimitry Andric     else if (isSpecificDef(*Ty, "root"))
18415f757f3fSDimitry Andric       OpKind = PatFrag::PK_Root;
18425f757f3fSDimitry Andric     else if (isa<UnsetInit>(Ty) ||
18435f757f3fSDimitry Andric              isSpecificDef(*Ty, "gi_mo")) // no type = gi_mo.
18445f757f3fSDimitry Andric       OpKind = PatFrag::PK_MachineOperand;
18455f757f3fSDimitry Andric     else {
18465f757f3fSDimitry Andric       ::PrintError(
18475f757f3fSDimitry Andric           DiagLoc,
18485f757f3fSDimitry Andric           "'" + NameStr +
18495f757f3fSDimitry Andric               "' operand type was expected to be 'root', 'gi_imm' or 'gi_mo'");
18505f757f3fSDimitry Andric       return false;
18515f757f3fSDimitry Andric     }
18525f757f3fSDimitry Andric 
18535f757f3fSDimitry Andric     if (!ParseAction(NameStr, OpKind))
18545f757f3fSDimitry Andric       return false;
18555f757f3fSDimitry Andric   }
18565f757f3fSDimitry Andric 
18575f757f3fSDimitry Andric   return true;
18585f757f3fSDimitry Andric }
18595f757f3fSDimitry Andric 
18605f757f3fSDimitry Andric const PatFrag *CombineRuleBuilder::parsePatFrag(const Record *Def) const {
18615f757f3fSDimitry Andric   // Cache already parsed PatFrags to avoid doing extra work.
18625f757f3fSDimitry Andric   static DenseMap<const Record *, std::unique_ptr<PatFrag>> ParsedPatFrags;
18635f757f3fSDimitry Andric 
18645f757f3fSDimitry Andric   auto It = ParsedPatFrags.find(Def);
18655f757f3fSDimitry Andric   if (It != ParsedPatFrags.end()) {
18665f757f3fSDimitry Andric     SeenPatFrags.insert(It->second.get());
18675f757f3fSDimitry Andric     return It->second.get();
18685f757f3fSDimitry Andric   }
18695f757f3fSDimitry Andric 
18705f757f3fSDimitry Andric   std::unique_ptr<PatFrag> NewPatFrag = parsePatFragImpl(Def);
18715f757f3fSDimitry Andric   if (!NewPatFrag) {
18725f757f3fSDimitry Andric     ::PrintError(Def, "Could not parse " + PatFrag::ClassName + " '" +
18735f757f3fSDimitry Andric                           Def->getName() + "'");
18745f757f3fSDimitry Andric     // Put a nullptr in the map so we don't attempt parsing this again.
18755f757f3fSDimitry Andric     ParsedPatFrags[Def] = nullptr;
18765f757f3fSDimitry Andric     return nullptr;
18775f757f3fSDimitry Andric   }
18785f757f3fSDimitry Andric 
18795f757f3fSDimitry Andric   const auto *Res = NewPatFrag.get();
18805f757f3fSDimitry Andric   ParsedPatFrags[Def] = std::move(NewPatFrag);
18815f757f3fSDimitry Andric   SeenPatFrags.insert(Res);
18825f757f3fSDimitry Andric   return Res;
18835f757f3fSDimitry Andric }
18845f757f3fSDimitry Andric 
18855f757f3fSDimitry Andric bool CombineRuleBuilder::emitMatchPattern(CodeExpansions &CE,
18865f757f3fSDimitry Andric                                           const PatternAlternatives &Alts,
18875f757f3fSDimitry Andric                                           const InstructionPattern &IP) {
18885f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef, &IP);
18895f757f3fSDimitry Andric 
18905f757f3fSDimitry Andric   auto &M = addRuleMatcher(Alts);
18915f757f3fSDimitry Andric   InstructionMatcher &IM = M.addInstructionMatcher(IP.getName());
18925f757f3fSDimitry Andric   declareInstExpansion(CE, IM, IP.getName());
18935f757f3fSDimitry Andric 
18945f757f3fSDimitry Andric   DenseSet<const Pattern *> SeenPats;
18955f757f3fSDimitry Andric 
18965f757f3fSDimitry Andric   const auto FindOperandDef = [&](StringRef Op) -> InstructionPattern * {
18975f757f3fSDimitry Andric     return MatchOpTable.getDef(Op);
18985f757f3fSDimitry Andric   };
18995f757f3fSDimitry Andric 
19005f757f3fSDimitry Andric   if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&IP)) {
19015f757f3fSDimitry Andric     if (!emitCodeGenInstructionMatchPattern(CE, Alts, M, IM, *CGP, SeenPats,
19025f757f3fSDimitry Andric                                             FindOperandDef))
19035f757f3fSDimitry Andric       return false;
19045f757f3fSDimitry Andric   } else if (const auto *PFP = dyn_cast<PatFragPattern>(&IP)) {
19055f757f3fSDimitry Andric     if (!PFP->getPatFrag().canBeMatchRoot()) {
19065f757f3fSDimitry Andric       PrintError("cannot use '" + PFP->getInstName() + " as match root");
19075f757f3fSDimitry Andric       return false;
19085f757f3fSDimitry Andric     }
19095f757f3fSDimitry Andric 
19105f757f3fSDimitry Andric     if (!emitPatFragMatchPattern(CE, Alts, M, &IM, *PFP, SeenPats))
19115f757f3fSDimitry Andric       return false;
19125f757f3fSDimitry Andric   } else if (isa<BuiltinPattern>(&IP)) {
19135f757f3fSDimitry Andric     llvm_unreachable("No match builtins known!");
19145f757f3fSDimitry Andric   } else
19155f757f3fSDimitry Andric     llvm_unreachable("Unknown kind of InstructionPattern!");
19165f757f3fSDimitry Andric 
19175f757f3fSDimitry Andric   // Emit remaining patterns
19185f757f3fSDimitry Andric   for (auto &Pat : values(MatchPats)) {
19195f757f3fSDimitry Andric     if (SeenPats.contains(Pat.get()))
19205f757f3fSDimitry Andric       continue;
19215f757f3fSDimitry Andric 
19225f757f3fSDimitry Andric     switch (Pat->getKind()) {
19235f757f3fSDimitry Andric     case Pattern::K_AnyOpcode:
19245f757f3fSDimitry Andric       PrintError("wip_match_opcode can not be used with instruction patterns!");
19255f757f3fSDimitry Andric       return false;
19265f757f3fSDimitry Andric     case Pattern::K_PatFrag: {
19275f757f3fSDimitry Andric       if (!emitPatFragMatchPattern(CE, Alts, M, /*IM*/ nullptr,
19285f757f3fSDimitry Andric                                    *cast<PatFragPattern>(Pat.get()), SeenPats))
19295f757f3fSDimitry Andric         return false;
19305f757f3fSDimitry Andric       continue;
19315f757f3fSDimitry Andric     }
19325f757f3fSDimitry Andric     case Pattern::K_Builtin:
19335f757f3fSDimitry Andric       PrintError("No known match builtins");
19345f757f3fSDimitry Andric       return false;
19355f757f3fSDimitry Andric     case Pattern::K_CodeGenInstruction:
19365f757f3fSDimitry Andric       cast<InstructionPattern>(Pat.get())->reportUnreachable(RuleDef.getLoc());
19375f757f3fSDimitry Andric       return false;
19385f757f3fSDimitry Andric     case Pattern::K_CXX: {
19395f757f3fSDimitry Andric       addCXXPredicate(M, CE, *cast<CXXPattern>(Pat.get()), Alts);
19405f757f3fSDimitry Andric       continue;
19415f757f3fSDimitry Andric     }
19425f757f3fSDimitry Andric     default:
19435f757f3fSDimitry Andric       llvm_unreachable("unknown pattern kind!");
19445f757f3fSDimitry Andric     }
19455f757f3fSDimitry Andric   }
19465f757f3fSDimitry Andric 
19475f757f3fSDimitry Andric   return emitApplyPatterns(CE, M);
19485f757f3fSDimitry Andric }
19495f757f3fSDimitry Andric 
19505f757f3fSDimitry Andric bool CombineRuleBuilder::emitMatchPattern(CodeExpansions &CE,
19515f757f3fSDimitry Andric                                           const PatternAlternatives &Alts,
19525f757f3fSDimitry Andric                                           const AnyOpcodePattern &AOP) {
19535f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef, &AOP);
19545f757f3fSDimitry Andric 
19555f757f3fSDimitry Andric   for (const CodeGenInstruction *CGI : AOP.insts()) {
19565f757f3fSDimitry Andric     auto &M = addRuleMatcher(Alts, "wip_match_opcode '" +
19575f757f3fSDimitry Andric                                        CGI->TheDef->getName() + "'");
19585f757f3fSDimitry Andric 
19595f757f3fSDimitry Andric     InstructionMatcher &IM = M.addInstructionMatcher(AOP.getName());
19605f757f3fSDimitry Andric     declareInstExpansion(CE, IM, AOP.getName());
19615f757f3fSDimitry Andric     // declareInstExpansion needs to be identical, otherwise we need to create a
19625f757f3fSDimitry Andric     // CodeExpansions object here instead.
19635f757f3fSDimitry Andric     assert(IM.getInsnVarID() == 0);
19645f757f3fSDimitry Andric 
19655f757f3fSDimitry Andric     IM.addPredicate<InstructionOpcodeMatcher>(CGI);
19665f757f3fSDimitry Andric 
19675f757f3fSDimitry Andric     // Emit remaining patterns.
19685f757f3fSDimitry Andric     for (auto &Pat : values(MatchPats)) {
19695f757f3fSDimitry Andric       if (Pat.get() == &AOP)
19705f757f3fSDimitry Andric         continue;
19715f757f3fSDimitry Andric 
19725f757f3fSDimitry Andric       switch (Pat->getKind()) {
19735f757f3fSDimitry Andric       case Pattern::K_AnyOpcode:
19745f757f3fSDimitry Andric         PrintError("wip_match_opcode can only be present once!");
19755f757f3fSDimitry Andric         return false;
19765f757f3fSDimitry Andric       case Pattern::K_PatFrag: {
19775f757f3fSDimitry Andric         DenseSet<const Pattern *> SeenPats;
19785f757f3fSDimitry Andric         if (!emitPatFragMatchPattern(CE, Alts, M, /*IM*/ nullptr,
19795f757f3fSDimitry Andric                                      *cast<PatFragPattern>(Pat.get()),
19805f757f3fSDimitry Andric                                      SeenPats))
19815f757f3fSDimitry Andric           return false;
19825f757f3fSDimitry Andric         continue;
19835f757f3fSDimitry Andric       }
19845f757f3fSDimitry Andric       case Pattern::K_Builtin:
19855f757f3fSDimitry Andric         PrintError("No known match builtins");
19865f757f3fSDimitry Andric         return false;
19875f757f3fSDimitry Andric       case Pattern::K_CodeGenInstruction:
19885f757f3fSDimitry Andric         cast<InstructionPattern>(Pat.get())->reportUnreachable(
19895f757f3fSDimitry Andric             RuleDef.getLoc());
19905f757f3fSDimitry Andric         return false;
19915f757f3fSDimitry Andric       case Pattern::K_CXX: {
19925f757f3fSDimitry Andric         addCXXPredicate(M, CE, *cast<CXXPattern>(Pat.get()), Alts);
19935f757f3fSDimitry Andric         break;
19945f757f3fSDimitry Andric       }
19955f757f3fSDimitry Andric       default:
19965f757f3fSDimitry Andric         llvm_unreachable("unknown pattern kind!");
19975f757f3fSDimitry Andric       }
19985f757f3fSDimitry Andric     }
19995f757f3fSDimitry Andric 
20005f757f3fSDimitry Andric     if (!emitApplyPatterns(CE, M))
20015f757f3fSDimitry Andric       return false;
20025f757f3fSDimitry Andric   }
20035f757f3fSDimitry Andric 
20045f757f3fSDimitry Andric   return true;
20055f757f3fSDimitry Andric }
20065f757f3fSDimitry Andric 
20075f757f3fSDimitry Andric bool CombineRuleBuilder::emitPatFragMatchPattern(
20085f757f3fSDimitry Andric     CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &RM,
20095f757f3fSDimitry Andric     InstructionMatcher *IM, const PatFragPattern &PFP,
20105f757f3fSDimitry Andric     DenseSet<const Pattern *> &SeenPats) {
20115f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef, &PFP);
20125f757f3fSDimitry Andric 
20135f757f3fSDimitry Andric   if (SeenPats.contains(&PFP))
20145f757f3fSDimitry Andric     return true;
20155f757f3fSDimitry Andric   SeenPats.insert(&PFP);
20165f757f3fSDimitry Andric 
20175f757f3fSDimitry Andric   const auto &PF = PFP.getPatFrag();
20185f757f3fSDimitry Andric 
20195f757f3fSDimitry Andric   if (!IM) {
20205f757f3fSDimitry Andric     // When we don't have an IM, this means this PatFrag isn't reachable from
20215f757f3fSDimitry Andric     // the root. This is only acceptable if it doesn't define anything (e.g. a
20225f757f3fSDimitry Andric     // pure C++ PatFrag).
20235f757f3fSDimitry Andric     if (PF.num_out_params() != 0) {
20245f757f3fSDimitry Andric       PFP.reportUnreachable(RuleDef.getLoc());
20255f757f3fSDimitry Andric       return false;
20265f757f3fSDimitry Andric     }
20275f757f3fSDimitry Andric   } else {
20285f757f3fSDimitry Andric     // When an IM is provided, this is reachable from the root, and we're
20295f757f3fSDimitry Andric     // expecting to have output operands.
20305f757f3fSDimitry Andric     // TODO: If we want to allow for multiple roots we'll need a map of IMs
20315f757f3fSDimitry Andric     // then, and emission becomes a bit more complicated.
20325f757f3fSDimitry Andric     assert(PF.num_roots() == 1);
20335f757f3fSDimitry Andric   }
20345f757f3fSDimitry Andric 
20355f757f3fSDimitry Andric   CodeExpansions PatFragCEs;
20365f757f3fSDimitry Andric   if (!PFP.mapInputCodeExpansions(CE, PatFragCEs, RuleDef.getLoc()))
20375f757f3fSDimitry Andric     return false;
20385f757f3fSDimitry Andric 
20395f757f3fSDimitry Andric   // List of {ParamName, ArgName}.
20405f757f3fSDimitry Andric   // When all patterns have been emitted, find expansions in PatFragCEs named
20415f757f3fSDimitry Andric   // ArgName and add their expansion to CE using ParamName as the key.
20425f757f3fSDimitry Andric   SmallVector<std::pair<std::string, std::string>, 4> CEsToImport;
20435f757f3fSDimitry Andric 
20445f757f3fSDimitry Andric   // Map parameter names to the actual argument.
20455f757f3fSDimitry Andric   const auto OperandMapper =
20465f757f3fSDimitry Andric       [&](const InstructionOperand &O) -> InstructionOperand {
20475f757f3fSDimitry Andric     if (!O.isNamedOperand())
20485f757f3fSDimitry Andric       return O;
20495f757f3fSDimitry Andric 
20505f757f3fSDimitry Andric     StringRef ParamName = O.getOperandName();
20515f757f3fSDimitry Andric 
20525f757f3fSDimitry Andric     // Not sure what to do with those tbh. They should probably never be here.
20535f757f3fSDimitry Andric     assert(!O.isNamedImmediate() && "TODO: handle named imms");
20545f757f3fSDimitry Andric     unsigned PIdx = PF.getParamIdx(ParamName);
20555f757f3fSDimitry Andric 
20565f757f3fSDimitry Andric     // Map parameters to the argument values.
20575f757f3fSDimitry Andric     if (PIdx == (unsigned)-1) {
20585f757f3fSDimitry Andric       // This is a temp of the PatFragPattern, prefix the name to avoid
20595f757f3fSDimitry Andric       // conflicts.
20605f757f3fSDimitry Andric       return O.withNewName(
20615f757f3fSDimitry Andric           insertStrRef((PFP.getName() + "." + ParamName).str()));
20625f757f3fSDimitry Andric     }
20635f757f3fSDimitry Andric 
20645f757f3fSDimitry Andric     // The operand will be added to PatFragCEs's code expansions using the
20655f757f3fSDimitry Andric     // parameter's name. If it's bound to some operand during emission of the
20665f757f3fSDimitry Andric     // patterns, we'll want to add it to CE.
20675f757f3fSDimitry Andric     auto ArgOp = PFP.getOperand(PIdx);
20685f757f3fSDimitry Andric     if (ArgOp.isNamedOperand())
20695f757f3fSDimitry Andric       CEsToImport.emplace_back(ArgOp.getOperandName().str(), ParamName);
20705f757f3fSDimitry Andric 
20715f757f3fSDimitry Andric     if (ArgOp.getType() && O.getType() && ArgOp.getType() != O.getType()) {
20725f757f3fSDimitry Andric       StringRef PFName = PF.getName();
20735f757f3fSDimitry Andric       PrintWarning("impossible type constraints: operand " + Twine(PIdx) +
20745f757f3fSDimitry Andric                    " of '" + PFP.getName() + "' has type '" +
20755f757f3fSDimitry Andric                    ArgOp.getType().str() + "', but '" + PFName +
20765f757f3fSDimitry Andric                    "' constrains it to '" + O.getType().str() + "'");
20775f757f3fSDimitry Andric       if (ArgOp.isNamedOperand())
20785f757f3fSDimitry Andric         PrintNote("operand " + Twine(PIdx) + " of '" + PFP.getName() +
20795f757f3fSDimitry Andric                   "' is '" + ArgOp.getOperandName() + "'");
20805f757f3fSDimitry Andric       if (O.isNamedOperand())
20815f757f3fSDimitry Andric         PrintNote("argument " + Twine(PIdx) + " of '" + PFName + "' is '" +
20825f757f3fSDimitry Andric                   ParamName + "'");
20835f757f3fSDimitry Andric     }
20845f757f3fSDimitry Andric 
20855f757f3fSDimitry Andric     return ArgOp;
20865f757f3fSDimitry Andric   };
20875f757f3fSDimitry Andric 
20885f757f3fSDimitry Andric   // PatFragPatterns are only made of InstructionPatterns or CXXPatterns.
20895f757f3fSDimitry Andric   // Emit instructions from the root.
20905f757f3fSDimitry Andric   const auto &FragAlt = PF.getAlternative(Alts.lookup(&PFP));
20915f757f3fSDimitry Andric   const auto &FragAltOT = FragAlt.OpTable;
20925f757f3fSDimitry Andric   const auto LookupOperandDef =
20935f757f3fSDimitry Andric       [&](StringRef Op) -> const InstructionPattern * {
20945f757f3fSDimitry Andric     return FragAltOT.getDef(Op);
20955f757f3fSDimitry Andric   };
20965f757f3fSDimitry Andric 
20975f757f3fSDimitry Andric   DenseSet<const Pattern *> PatFragSeenPats;
20985f757f3fSDimitry Andric   for (const auto &[Idx, InOp] : enumerate(PF.out_params())) {
20995f757f3fSDimitry Andric     if (InOp.Kind != PatFrag::PK_Root)
21005f757f3fSDimitry Andric       continue;
21015f757f3fSDimitry Andric 
21025f757f3fSDimitry Andric     StringRef ParamName = InOp.Name;
21035f757f3fSDimitry Andric     const auto *Def = FragAltOT.getDef(ParamName);
21045f757f3fSDimitry Andric     assert(Def && "PatFrag::checkSemantics should have emitted an error if "
21055f757f3fSDimitry Andric                   "an out operand isn't defined!");
21065f757f3fSDimitry Andric     assert(isa<CodeGenInstructionPattern>(Def) &&
21075f757f3fSDimitry Andric            "Nested PatFrags not supported yet");
21085f757f3fSDimitry Andric 
21095f757f3fSDimitry Andric     if (!emitCodeGenInstructionMatchPattern(
21105f757f3fSDimitry Andric             PatFragCEs, Alts, RM, *IM, *cast<CodeGenInstructionPattern>(Def),
21115f757f3fSDimitry Andric             PatFragSeenPats, LookupOperandDef, OperandMapper))
21125f757f3fSDimitry Andric       return false;
21135f757f3fSDimitry Andric   }
21145f757f3fSDimitry Andric 
21155f757f3fSDimitry Andric   // Emit leftovers.
21165f757f3fSDimitry Andric   for (const auto &Pat : FragAlt.Pats) {
21175f757f3fSDimitry Andric     if (PatFragSeenPats.contains(Pat.get()))
21185f757f3fSDimitry Andric       continue;
21195f757f3fSDimitry Andric 
21205f757f3fSDimitry Andric     if (const auto *CXXPat = dyn_cast<CXXPattern>(Pat.get())) {
21215f757f3fSDimitry Andric       addCXXPredicate(RM, PatFragCEs, *CXXPat, Alts);
21225f757f3fSDimitry Andric       continue;
21235f757f3fSDimitry Andric     }
21245f757f3fSDimitry Andric 
21255f757f3fSDimitry Andric     if (const auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
21265f757f3fSDimitry Andric       IP->reportUnreachable(PF.getLoc());
21275f757f3fSDimitry Andric       return false;
21285f757f3fSDimitry Andric     }
21295f757f3fSDimitry Andric 
21305f757f3fSDimitry Andric     llvm_unreachable("Unexpected pattern kind in PatFrag");
21315f757f3fSDimitry Andric   }
21325f757f3fSDimitry Andric 
21335f757f3fSDimitry Andric   for (const auto &[ParamName, ArgName] : CEsToImport) {
21345f757f3fSDimitry Andric     // Note: we're find if ParamName already exists. It just means it's been
21355f757f3fSDimitry Andric     // bound before, so we prefer to keep the first binding.
21365f757f3fSDimitry Andric     CE.declare(ParamName, PatFragCEs.lookup(ArgName));
21375f757f3fSDimitry Andric   }
21385f757f3fSDimitry Andric 
21395f757f3fSDimitry Andric   return true;
21405f757f3fSDimitry Andric }
21415f757f3fSDimitry Andric 
21425f757f3fSDimitry Andric bool CombineRuleBuilder::emitApplyPatterns(CodeExpansions &CE, RuleMatcher &M) {
21435f757f3fSDimitry Andric   if (hasOnlyCXXApplyPatterns()) {
21445f757f3fSDimitry Andric     for (auto &Pat : values(ApplyPats))
21455f757f3fSDimitry Andric       addCXXAction(M, CE, *cast<CXXPattern>(Pat.get()));
21465f757f3fSDimitry Andric     return true;
21475f757f3fSDimitry Andric   }
21485f757f3fSDimitry Andric 
21495f757f3fSDimitry Andric   DenseSet<const Pattern *> SeenPats;
21505f757f3fSDimitry Andric   StringMap<unsigned> OperandToTempRegID;
21515f757f3fSDimitry Andric 
21525f757f3fSDimitry Andric   for (auto *ApplyRoot : ApplyRoots) {
21535f757f3fSDimitry Andric     assert(isa<InstructionPattern>(ApplyRoot) &&
21545f757f3fSDimitry Andric            "Root can only be a InstructionPattern!");
21555f757f3fSDimitry Andric     if (!emitInstructionApplyPattern(CE, M,
21565f757f3fSDimitry Andric                                      cast<InstructionPattern>(*ApplyRoot),
21575f757f3fSDimitry Andric                                      SeenPats, OperandToTempRegID))
21585f757f3fSDimitry Andric       return false;
21595f757f3fSDimitry Andric   }
21605f757f3fSDimitry Andric 
21615f757f3fSDimitry Andric   for (auto &Pat : values(ApplyPats)) {
21625f757f3fSDimitry Andric     if (SeenPats.contains(Pat.get()))
21635f757f3fSDimitry Andric       continue;
21645f757f3fSDimitry Andric 
21655f757f3fSDimitry Andric     switch (Pat->getKind()) {
21665f757f3fSDimitry Andric     case Pattern::K_AnyOpcode:
21675f757f3fSDimitry Andric       llvm_unreachable("Unexpected pattern in apply!");
21685f757f3fSDimitry Andric     case Pattern::K_PatFrag:
21695f757f3fSDimitry Andric       // TODO: We could support pure C++ PatFrags as a temporary thing.
21705f757f3fSDimitry Andric       llvm_unreachable("Unexpected pattern in apply!");
21715f757f3fSDimitry Andric     case Pattern::K_Builtin:
21725f757f3fSDimitry Andric       if (!emitInstructionApplyPattern(CE, M, cast<BuiltinPattern>(*Pat),
21735f757f3fSDimitry Andric                                        SeenPats, OperandToTempRegID))
21745f757f3fSDimitry Andric         return false;
21755f757f3fSDimitry Andric       break;
21765f757f3fSDimitry Andric     case Pattern::K_CodeGenInstruction:
21775f757f3fSDimitry Andric       cast<CodeGenInstructionPattern>(*Pat).reportUnreachable(RuleDef.getLoc());
21785f757f3fSDimitry Andric       return false;
21795f757f3fSDimitry Andric     case Pattern::K_CXX: {
21805f757f3fSDimitry Andric       addCXXAction(M, CE, *cast<CXXPattern>(Pat.get()));
21815f757f3fSDimitry Andric       continue;
21825f757f3fSDimitry Andric     }
21835f757f3fSDimitry Andric     default:
21845f757f3fSDimitry Andric       llvm_unreachable("unknown pattern kind!");
21855f757f3fSDimitry Andric     }
21865f757f3fSDimitry Andric   }
21875f757f3fSDimitry Andric 
2188*7a6dacacSDimitry Andric   // Erase the root.
2189*7a6dacacSDimitry Andric   unsigned RootInsnID =
2190*7a6dacacSDimitry Andric       M.getInsnVarID(M.getInstructionMatcher(MatchRoot->getName()));
2191*7a6dacacSDimitry Andric   M.addAction<EraseInstAction>(RootInsnID);
2192*7a6dacacSDimitry Andric 
21935f757f3fSDimitry Andric   return true;
21945f757f3fSDimitry Andric }
21955f757f3fSDimitry Andric 
21965f757f3fSDimitry Andric bool CombineRuleBuilder::emitInstructionApplyPattern(
21975f757f3fSDimitry Andric     CodeExpansions &CE, RuleMatcher &M, const InstructionPattern &P,
21985f757f3fSDimitry Andric     DenseSet<const Pattern *> &SeenPats,
21995f757f3fSDimitry Andric     StringMap<unsigned> &OperandToTempRegID) {
22005f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef, &P);
22015f757f3fSDimitry Andric 
22025f757f3fSDimitry Andric   if (SeenPats.contains(&P))
22035f757f3fSDimitry Andric     return true;
22045f757f3fSDimitry Andric 
22055f757f3fSDimitry Andric   SeenPats.insert(&P);
22065f757f3fSDimitry Andric 
22075f757f3fSDimitry Andric   // First, render the uses.
22085f757f3fSDimitry Andric   for (auto &Op : P.named_operands()) {
22095f757f3fSDimitry Andric     if (Op.isDef())
22105f757f3fSDimitry Andric       continue;
22115f757f3fSDimitry Andric 
22125f757f3fSDimitry Andric     StringRef OpName = Op.getOperandName();
22135f757f3fSDimitry Andric     if (const auto *DefPat = ApplyOpTable.getDef(OpName)) {
22145f757f3fSDimitry Andric       if (!emitInstructionApplyPattern(CE, M, *DefPat, SeenPats,
22155f757f3fSDimitry Andric                                        OperandToTempRegID))
22165f757f3fSDimitry Andric         return false;
22175f757f3fSDimitry Andric     } else {
22185f757f3fSDimitry Andric       // If we have no def, check this exists in the MatchRoot.
22195f757f3fSDimitry Andric       if (!Op.isNamedImmediate() && !MatchOpTable.lookup(OpName).Found) {
22205f757f3fSDimitry Andric         PrintError("invalid output operand '" + OpName +
22215f757f3fSDimitry Andric                    "': operand is not a live-in of the match pattern, and it "
22225f757f3fSDimitry Andric                    "has no definition");
22235f757f3fSDimitry Andric         return false;
22245f757f3fSDimitry Andric       }
22255f757f3fSDimitry Andric     }
22265f757f3fSDimitry Andric   }
22275f757f3fSDimitry Andric 
22285f757f3fSDimitry Andric   if (const auto *BP = dyn_cast<BuiltinPattern>(&P))
22295f757f3fSDimitry Andric     return emitBuiltinApplyPattern(CE, M, *BP, OperandToTempRegID);
22305f757f3fSDimitry Andric 
22315f757f3fSDimitry Andric   if (isa<PatFragPattern>(&P))
22325f757f3fSDimitry Andric     llvm_unreachable("PatFragPatterns is not supported in 'apply'!");
22335f757f3fSDimitry Andric 
22345f757f3fSDimitry Andric   auto &CGIP = cast<CodeGenInstructionPattern>(P);
22355f757f3fSDimitry Andric 
22365f757f3fSDimitry Andric   // Now render this inst.
22375f757f3fSDimitry Andric   auto &DstMI =
22385f757f3fSDimitry Andric       M.addAction<BuildMIAction>(M.allocateOutputInsnID(), &CGIP.getInst());
22395f757f3fSDimitry Andric 
22405f757f3fSDimitry Andric   for (auto &Op : P.operands()) {
22415f757f3fSDimitry Andric     if (Op.isNamedImmediate()) {
22425f757f3fSDimitry Andric       PrintError("invalid output operand '" + Op.getOperandName() +
22435f757f3fSDimitry Andric                  "': output immediates cannot be named");
22445f757f3fSDimitry Andric       PrintNote("while emitting pattern '" + P.getName() + "' (" +
22455f757f3fSDimitry Andric                 P.getInstName() + ")");
22465f757f3fSDimitry Andric       return false;
22475f757f3fSDimitry Andric     }
22485f757f3fSDimitry Andric 
22495f757f3fSDimitry Andric     if (Op.hasImmValue()) {
22505f757f3fSDimitry Andric       if (!emitCodeGenInstructionApplyImmOperand(M, DstMI, CGIP, Op))
22515f757f3fSDimitry Andric         return false;
22525f757f3fSDimitry Andric       continue;
22535f757f3fSDimitry Andric     }
22545f757f3fSDimitry Andric 
22555f757f3fSDimitry Andric     StringRef OpName = Op.getOperandName();
22565f757f3fSDimitry Andric 
22575f757f3fSDimitry Andric     // Uses of operand.
22585f757f3fSDimitry Andric     if (!Op.isDef()) {
22595f757f3fSDimitry Andric       if (auto It = OperandToTempRegID.find(OpName);
22605f757f3fSDimitry Andric           It != OperandToTempRegID.end()) {
22615f757f3fSDimitry Andric         assert(!MatchOpTable.lookup(OpName).Found &&
22625f757f3fSDimitry Andric                "Temp reg is also from match pattern?");
22635f757f3fSDimitry Andric         DstMI.addRenderer<TempRegRenderer>(It->second);
22645f757f3fSDimitry Andric       } else {
22655f757f3fSDimitry Andric         // This should be a match live in or a redef of a matched instr.
22665f757f3fSDimitry Andric         // If it's a use of a temporary register, then we messed up somewhere -
22675f757f3fSDimitry Andric         // the previous condition should have passed.
22685f757f3fSDimitry Andric         assert(MatchOpTable.lookup(OpName).Found &&
22695f757f3fSDimitry Andric                !ApplyOpTable.getDef(OpName) && "Temp reg not emitted yet!");
22705f757f3fSDimitry Andric         DstMI.addRenderer<CopyRenderer>(OpName);
22715f757f3fSDimitry Andric       }
22725f757f3fSDimitry Andric       continue;
22735f757f3fSDimitry Andric     }
22745f757f3fSDimitry Andric 
22755f757f3fSDimitry Andric     // Determine what we're dealing with. Are we replace a matched instruction?
22765f757f3fSDimitry Andric     // Creating a new one?
22775f757f3fSDimitry Andric     auto OpLookupRes = MatchOpTable.lookup(OpName);
22785f757f3fSDimitry Andric     if (OpLookupRes.Found) {
22795f757f3fSDimitry Andric       if (OpLookupRes.isLiveIn()) {
22805f757f3fSDimitry Andric         // live-in of the match pattern.
22815f757f3fSDimitry Andric         PrintError("Cannot define live-in operand '" + OpName +
22825f757f3fSDimitry Andric                    "' in the 'apply' pattern");
22835f757f3fSDimitry Andric         return false;
22845f757f3fSDimitry Andric       }
22855f757f3fSDimitry Andric       assert(OpLookupRes.Def);
22865f757f3fSDimitry Andric 
22875f757f3fSDimitry Andric       // TODO: Handle this. We need to mutate the instr, or delete the old
22885f757f3fSDimitry Andric       // one.
22895f757f3fSDimitry Andric       //       Likewise, we also need to ensure we redef everything, if the
22905f757f3fSDimitry Andric       //       instr has more than one def, we need to redef all or nothing.
22915f757f3fSDimitry Andric       if (OpLookupRes.Def != MatchRoot) {
22925f757f3fSDimitry Andric         PrintError("redefining an instruction other than the root is not "
22935f757f3fSDimitry Andric                    "supported (operand '" +
22945f757f3fSDimitry Andric                    OpName + "')");
22955f757f3fSDimitry Andric         return false;
22965f757f3fSDimitry Andric       }
22975f757f3fSDimitry Andric       // redef of a match
22985f757f3fSDimitry Andric       DstMI.addRenderer<CopyRenderer>(OpName);
22995f757f3fSDimitry Andric       continue;
23005f757f3fSDimitry Andric     }
23015f757f3fSDimitry Andric 
23025f757f3fSDimitry Andric     // Define a new register unique to the apply patterns (AKA a "temp"
23035f757f3fSDimitry Andric     // register).
23045f757f3fSDimitry Andric     unsigned TempRegID;
23055f757f3fSDimitry Andric     if (auto It = OperandToTempRegID.find(OpName);
23065f757f3fSDimitry Andric         It != OperandToTempRegID.end()) {
23075f757f3fSDimitry Andric       TempRegID = It->second;
23085f757f3fSDimitry Andric     } else {
23095f757f3fSDimitry Andric       // This is a brand new register.
23105f757f3fSDimitry Andric       TempRegID = M.allocateTempRegID();
23115f757f3fSDimitry Andric       OperandToTempRegID[OpName] = TempRegID;
23125f757f3fSDimitry Andric       const auto Ty = Op.getType();
23135f757f3fSDimitry Andric       if (!Ty) {
23145f757f3fSDimitry Andric         PrintError("def of a new register '" + OpName +
23155f757f3fSDimitry Andric                    "' in the apply patterns must have a type");
23165f757f3fSDimitry Andric         return false;
23175f757f3fSDimitry Andric       }
23185f757f3fSDimitry Andric 
23195f757f3fSDimitry Andric       declareTempRegExpansion(CE, TempRegID, OpName);
23205f757f3fSDimitry Andric       // Always insert the action at the beginning, otherwise we may end up
23215f757f3fSDimitry Andric       // using the temp reg before it's available.
23225f757f3fSDimitry Andric       M.insertAction<MakeTempRegisterAction>(
23235f757f3fSDimitry Andric           M.actions_begin(), getLLTCodeGenOrTempType(Ty, M), TempRegID);
23245f757f3fSDimitry Andric     }
23255f757f3fSDimitry Andric 
2326297eecfbSDimitry Andric     DstMI.addRenderer<TempRegRenderer>(TempRegID, /*IsDef=*/true);
23275f757f3fSDimitry Andric   }
23285f757f3fSDimitry Andric 
23295f757f3fSDimitry Andric   // Render MIFlags
23305f757f3fSDimitry Andric   if (const auto *FI = CGIP.getMIFlagsInfo()) {
23315f757f3fSDimitry Andric     for (StringRef InstName : FI->copy_flags())
23325f757f3fSDimitry Andric       DstMI.addCopiedMIFlags(M.getInstructionMatcher(InstName));
23335f757f3fSDimitry Andric     for (StringRef F : FI->set_flags())
23345f757f3fSDimitry Andric       DstMI.addSetMIFlags(F);
23355f757f3fSDimitry Andric     for (StringRef F : FI->unset_flags())
23365f757f3fSDimitry Andric       DstMI.addUnsetMIFlags(F);
23375f757f3fSDimitry Andric   }
23385f757f3fSDimitry Andric 
23395f757f3fSDimitry Andric   // Don't allow mutating opcodes for GISel combiners. We want a more precise
23405f757f3fSDimitry Andric   // handling of MIFlags so we require them to be explicitly preserved.
23415f757f3fSDimitry Andric   //
23425f757f3fSDimitry Andric   // TODO: We don't mutate very often, if at all in combiners, but it'd be nice
23435f757f3fSDimitry Andric   // to re-enable this. We'd then need to always clear MIFlags when mutating
23445f757f3fSDimitry Andric   // opcodes, and never mutate an inst that we copy flags from.
23455f757f3fSDimitry Andric   // DstMI.chooseInsnToMutate(M);
23465f757f3fSDimitry Andric   declareInstExpansion(CE, DstMI, P.getName());
23475f757f3fSDimitry Andric 
23485f757f3fSDimitry Andric   return true;
23495f757f3fSDimitry Andric }
23505f757f3fSDimitry Andric 
23515f757f3fSDimitry Andric bool CombineRuleBuilder::emitCodeGenInstructionApplyImmOperand(
23525f757f3fSDimitry Andric     RuleMatcher &M, BuildMIAction &DstMI, const CodeGenInstructionPattern &P,
23535f757f3fSDimitry Andric     const InstructionOperand &O) {
23545f757f3fSDimitry Andric   // If we have a type, we implicitly emit a G_CONSTANT, except for G_CONSTANT
23555f757f3fSDimitry Andric   // itself where we emit a CImm.
23565f757f3fSDimitry Andric   //
23575f757f3fSDimitry Andric   // No type means we emit a simple imm.
23585f757f3fSDimitry Andric   // G_CONSTANT is a special case and needs a CImm though so this is likely a
23595f757f3fSDimitry Andric   // mistake.
23605f757f3fSDimitry Andric   const bool isGConstant = P.is("G_CONSTANT");
23615f757f3fSDimitry Andric   const auto Ty = O.getType();
23625f757f3fSDimitry Andric   if (!Ty) {
23635f757f3fSDimitry Andric     if (isGConstant) {
23645f757f3fSDimitry Andric       PrintError("'G_CONSTANT' immediate must be typed!");
23655f757f3fSDimitry Andric       PrintNote("while emitting pattern '" + P.getName() + "' (" +
23665f757f3fSDimitry Andric                 P.getInstName() + ")");
23675f757f3fSDimitry Andric       return false;
23685f757f3fSDimitry Andric     }
23695f757f3fSDimitry Andric 
23705f757f3fSDimitry Andric     DstMI.addRenderer<ImmRenderer>(O.getImmValue());
23715f757f3fSDimitry Andric     return true;
23725f757f3fSDimitry Andric   }
23735f757f3fSDimitry Andric 
23745f757f3fSDimitry Andric   auto ImmTy = getLLTCodeGenOrTempType(Ty, M);
23755f757f3fSDimitry Andric 
23765f757f3fSDimitry Andric   if (isGConstant) {
23775f757f3fSDimitry Andric     DstMI.addRenderer<ImmRenderer>(O.getImmValue(), ImmTy);
23785f757f3fSDimitry Andric     return true;
23795f757f3fSDimitry Andric   }
23805f757f3fSDimitry Andric 
23815f757f3fSDimitry Andric   unsigned TempRegID = M.allocateTempRegID();
23825f757f3fSDimitry Andric   // Ensure MakeTempReg & the BuildConstantAction occur at the beginning.
23835f757f3fSDimitry Andric   auto InsertIt = M.insertAction<MakeTempRegisterAction>(M.actions_begin(),
23845f757f3fSDimitry Andric                                                          ImmTy, TempRegID);
23855f757f3fSDimitry Andric   M.insertAction<BuildConstantAction>(++InsertIt, TempRegID, O.getImmValue());
23865f757f3fSDimitry Andric   DstMI.addRenderer<TempRegRenderer>(TempRegID);
23875f757f3fSDimitry Andric   return true;
23885f757f3fSDimitry Andric }
23895f757f3fSDimitry Andric 
23905f757f3fSDimitry Andric bool CombineRuleBuilder::emitBuiltinApplyPattern(
23915f757f3fSDimitry Andric     CodeExpansions &CE, RuleMatcher &M, const BuiltinPattern &P,
23925f757f3fSDimitry Andric     StringMap<unsigned> &OperandToTempRegID) {
23935f757f3fSDimitry Andric   const auto Error = [&](Twine Reason) {
23945f757f3fSDimitry Andric     PrintError("cannot emit '" + P.getInstName() + "' builtin: " + Reason);
23955f757f3fSDimitry Andric     return false;
23965f757f3fSDimitry Andric   };
23975f757f3fSDimitry Andric 
23985f757f3fSDimitry Andric   switch (P.getBuiltinKind()) {
23995f757f3fSDimitry Andric   case BI_EraseRoot: {
24005f757f3fSDimitry Andric     // Root is always inst 0.
24015f757f3fSDimitry Andric     M.addAction<EraseInstAction>(/*InsnID*/ 0);
24025f757f3fSDimitry Andric     return true;
24035f757f3fSDimitry Andric   }
24045f757f3fSDimitry Andric   case BI_ReplaceReg: {
24055f757f3fSDimitry Andric     StringRef Old = P.getOperand(0).getOperandName();
24065f757f3fSDimitry Andric     StringRef New = P.getOperand(1).getOperandName();
24075f757f3fSDimitry Andric 
24085f757f3fSDimitry Andric     if (!ApplyOpTable.lookup(New).Found && !MatchOpTable.lookup(New).Found)
24095f757f3fSDimitry Andric       return Error("unknown operand '" + Old + "'");
24105f757f3fSDimitry Andric 
24115f757f3fSDimitry Andric     auto &OldOM = M.getOperandMatcher(Old);
24125f757f3fSDimitry Andric     if (auto It = OperandToTempRegID.find(New);
24135f757f3fSDimitry Andric         It != OperandToTempRegID.end()) {
24145f757f3fSDimitry Andric       // Replace with temp reg.
24155f757f3fSDimitry Andric       M.addAction<ReplaceRegAction>(OldOM.getInsnVarID(), OldOM.getOpIdx(),
24165f757f3fSDimitry Andric                                     It->second);
24175f757f3fSDimitry Andric     } else {
24185f757f3fSDimitry Andric       // Replace with matched reg.
24195f757f3fSDimitry Andric       auto &NewOM = M.getOperandMatcher(New);
24205f757f3fSDimitry Andric       M.addAction<ReplaceRegAction>(OldOM.getInsnVarID(), OldOM.getOpIdx(),
24215f757f3fSDimitry Andric                                     NewOM.getInsnVarID(), NewOM.getOpIdx());
24225f757f3fSDimitry Andric     }
24235f757f3fSDimitry Andric     // checkSemantics should have ensured that we can only rewrite the root.
24245f757f3fSDimitry Andric     // Ensure we're deleting it.
24255f757f3fSDimitry Andric     assert(MatchOpTable.getDef(Old) == MatchRoot);
24265f757f3fSDimitry Andric     return true;
24275f757f3fSDimitry Andric   }
24285f757f3fSDimitry Andric   }
24295f757f3fSDimitry Andric 
24305f757f3fSDimitry Andric   llvm_unreachable("Unknown BuiltinKind!");
24315f757f3fSDimitry Andric }
24325f757f3fSDimitry Andric 
24335f757f3fSDimitry Andric bool isLiteralImm(const InstructionPattern &P, unsigned OpIdx) {
24345f757f3fSDimitry Andric   if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&P)) {
24355f757f3fSDimitry Andric     StringRef InstName = CGP->getInst().TheDef->getName();
24365f757f3fSDimitry Andric     return (InstName == "G_CONSTANT" || InstName == "G_FCONSTANT") &&
24375f757f3fSDimitry Andric            OpIdx == 1;
24385f757f3fSDimitry Andric   }
24395f757f3fSDimitry Andric 
24405f757f3fSDimitry Andric   llvm_unreachable("TODO");
24415f757f3fSDimitry Andric }
24425f757f3fSDimitry Andric 
24435f757f3fSDimitry Andric bool CombineRuleBuilder::emitCodeGenInstructionMatchPattern(
24445f757f3fSDimitry Andric     CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &M,
24455f757f3fSDimitry Andric     InstructionMatcher &IM, const CodeGenInstructionPattern &P,
24465f757f3fSDimitry Andric     DenseSet<const Pattern *> &SeenPats, OperandDefLookupFn LookupOperandDef,
24475f757f3fSDimitry Andric     OperandMapperFnRef OperandMapper) {
24485f757f3fSDimitry Andric   auto StackTrace = PrettyStackTraceEmit(RuleDef, &P);
24495f757f3fSDimitry Andric 
24505f757f3fSDimitry Andric   if (SeenPats.contains(&P))
24515f757f3fSDimitry Andric     return true;
24525f757f3fSDimitry Andric 
24535f757f3fSDimitry Andric   SeenPats.insert(&P);
24545f757f3fSDimitry Andric 
24555f757f3fSDimitry Andric   IM.addPredicate<InstructionOpcodeMatcher>(&P.getInst());
24565f757f3fSDimitry Andric   declareInstExpansion(CE, IM, P.getName());
24575f757f3fSDimitry Andric 
24585f757f3fSDimitry Andric   // Check flags if needed.
24595f757f3fSDimitry Andric   if (const auto *FI = P.getMIFlagsInfo()) {
24605f757f3fSDimitry Andric     assert(FI->copy_flags().empty());
24615f757f3fSDimitry Andric 
24625f757f3fSDimitry Andric     if (const auto &SetF = FI->set_flags(); !SetF.empty())
24635f757f3fSDimitry Andric       IM.addPredicate<MIFlagsInstructionPredicateMatcher>(SetF.getArrayRef());
24645f757f3fSDimitry Andric     if (const auto &UnsetF = FI->unset_flags(); !UnsetF.empty())
24655f757f3fSDimitry Andric       IM.addPredicate<MIFlagsInstructionPredicateMatcher>(UnsetF.getArrayRef(),
24665f757f3fSDimitry Andric                                                           /*CheckNot=*/true);
24675f757f3fSDimitry Andric   }
24685f757f3fSDimitry Andric 
24695f757f3fSDimitry Andric   for (const auto &[Idx, OriginalO] : enumerate(P.operands())) {
24705f757f3fSDimitry Andric     // Remap the operand. This is used when emitting InstructionPatterns inside
24715f757f3fSDimitry Andric     // PatFrags, so it can remap them to the arguments passed to the pattern.
24725f757f3fSDimitry Andric     //
24735f757f3fSDimitry Andric     // We use the remapped operand to emit immediates, and for the symbolic
24745f757f3fSDimitry Andric     // operand names (in IM.addOperand). CodeExpansions and OperandTable lookups
24755f757f3fSDimitry Andric     // still use the original name.
24765f757f3fSDimitry Andric     //
24775f757f3fSDimitry Andric     // The "def" flag on the remapped operand is always ignored.
24785f757f3fSDimitry Andric     auto RemappedO = OperandMapper(OriginalO);
24795f757f3fSDimitry Andric     assert(RemappedO.isNamedOperand() == OriginalO.isNamedOperand() &&
24805f757f3fSDimitry Andric            "Cannot remap an unnamed operand to a named one!");
24815f757f3fSDimitry Andric 
24825f757f3fSDimitry Andric     const auto OpName =
24835f757f3fSDimitry Andric         RemappedO.isNamedOperand() ? RemappedO.getOperandName().str() : "";
24845f757f3fSDimitry Andric     OperandMatcher &OM =
24855f757f3fSDimitry Andric         IM.addOperand(Idx, OpName, AllocatedTemporariesBaseID++);
24865f757f3fSDimitry Andric     if (!OpName.empty())
24875f757f3fSDimitry Andric       declareOperandExpansion(CE, OM, OriginalO.getOperandName());
24885f757f3fSDimitry Andric 
24895f757f3fSDimitry Andric     // Handle immediates.
24905f757f3fSDimitry Andric     if (RemappedO.hasImmValue()) {
24915f757f3fSDimitry Andric       if (isLiteralImm(P, Idx))
24925f757f3fSDimitry Andric         OM.addPredicate<LiteralIntOperandMatcher>(RemappedO.getImmValue());
24935f757f3fSDimitry Andric       else
24945f757f3fSDimitry Andric         OM.addPredicate<ConstantIntOperandMatcher>(RemappedO.getImmValue());
24955f757f3fSDimitry Andric     }
24965f757f3fSDimitry Andric 
24975f757f3fSDimitry Andric     // Handle typed operands, but only bother to check if it hasn't been done
24985f757f3fSDimitry Andric     // before.
24995f757f3fSDimitry Andric     //
25005f757f3fSDimitry Andric     // getOperandMatcher will always return the first OM to have been created
25015f757f3fSDimitry Andric     // for that Operand. "OM" here is always a new OperandMatcher.
25025f757f3fSDimitry Andric     //
25035f757f3fSDimitry Andric     // Always emit a check for unnamed operands.
25045f757f3fSDimitry Andric     if (OpName.empty() ||
25055f757f3fSDimitry Andric         !M.getOperandMatcher(OpName).contains<LLTOperandMatcher>()) {
25065f757f3fSDimitry Andric       if (const auto Ty = RemappedO.getType()) {
25075f757f3fSDimitry Andric         // TODO: We could support GITypeOf here on the condition that the
25085f757f3fSDimitry Andric         // OperandMatcher exists already. Though it's clunky to make this work
25095f757f3fSDimitry Andric         // and isn't all that useful so it's just rejected in typecheckPatterns
25105f757f3fSDimitry Andric         // at this time.
25115f757f3fSDimitry Andric         assert(Ty.isLLT() && "Only LLTs are supported in match patterns!");
25125f757f3fSDimitry Andric         OM.addPredicate<LLTOperandMatcher>(getLLTCodeGen(Ty));
25135f757f3fSDimitry Andric       }
25145f757f3fSDimitry Andric     }
25155f757f3fSDimitry Andric 
25165f757f3fSDimitry Andric     // Stop here if the operand is a def, or if it had no name.
25175f757f3fSDimitry Andric     if (OriginalO.isDef() || !OriginalO.isNamedOperand())
25185f757f3fSDimitry Andric       continue;
25195f757f3fSDimitry Andric 
25205f757f3fSDimitry Andric     const auto *DefPat = LookupOperandDef(OriginalO.getOperandName());
25215f757f3fSDimitry Andric     if (!DefPat)
25225f757f3fSDimitry Andric       continue;
25235f757f3fSDimitry Andric 
25245f757f3fSDimitry Andric     if (OriginalO.hasImmValue()) {
25255f757f3fSDimitry Andric       assert(!OpName.empty());
25265f757f3fSDimitry Andric       // This is a named immediate that also has a def, that's not okay.
25275f757f3fSDimitry Andric       // e.g.
25285f757f3fSDimitry Andric       //    (G_SEXT $y, (i32 0))
25295f757f3fSDimitry Andric       //    (COPY $x, 42:$y)
25305f757f3fSDimitry Andric       PrintError("'" + OpName +
25315f757f3fSDimitry Andric                  "' is a named immediate, it cannot be defined by another "
25325f757f3fSDimitry Andric                  "instruction");
25335f757f3fSDimitry Andric       PrintNote("'" + OpName + "' is defined by '" + DefPat->getName() + "'");
25345f757f3fSDimitry Andric       return false;
25355f757f3fSDimitry Andric     }
25365f757f3fSDimitry Andric 
25375f757f3fSDimitry Andric     // From here we know that the operand defines an instruction, and we need to
25385f757f3fSDimitry Andric     // emit it.
25395f757f3fSDimitry Andric     auto InstOpM =
25405f757f3fSDimitry Andric         OM.addPredicate<InstructionOperandMatcher>(M, DefPat->getName());
25415f757f3fSDimitry Andric     if (!InstOpM) {
25425f757f3fSDimitry Andric       // TODO: copy-pasted from GlobalISelEmitter.cpp. Is it still relevant
25435f757f3fSDimitry Andric       // here?
25445f757f3fSDimitry Andric       PrintError("Nested instruction '" + DefPat->getName() +
25455f757f3fSDimitry Andric                  "' cannot be the same as another operand '" +
25465f757f3fSDimitry Andric                  OriginalO.getOperandName() + "'");
25475f757f3fSDimitry Andric       return false;
25485f757f3fSDimitry Andric     }
25495f757f3fSDimitry Andric 
25505f757f3fSDimitry Andric     auto &IM = (*InstOpM)->getInsnMatcher();
25515f757f3fSDimitry Andric     if (const auto *CGIDef = dyn_cast<CodeGenInstructionPattern>(DefPat)) {
25525f757f3fSDimitry Andric       if (!emitCodeGenInstructionMatchPattern(CE, Alts, M, IM, *CGIDef,
25535f757f3fSDimitry Andric                                               SeenPats, LookupOperandDef,
25545f757f3fSDimitry Andric                                               OperandMapper))
25555f757f3fSDimitry Andric         return false;
25565f757f3fSDimitry Andric       continue;
25575f757f3fSDimitry Andric     }
25585f757f3fSDimitry Andric 
25595f757f3fSDimitry Andric     if (const auto *PFPDef = dyn_cast<PatFragPattern>(DefPat)) {
25605f757f3fSDimitry Andric       if (!emitPatFragMatchPattern(CE, Alts, M, &IM, *PFPDef, SeenPats))
25615f757f3fSDimitry Andric         return false;
25625f757f3fSDimitry Andric       continue;
25635f757f3fSDimitry Andric     }
25645f757f3fSDimitry Andric 
25655f757f3fSDimitry Andric     llvm_unreachable("unknown type of InstructionPattern");
25665f757f3fSDimitry Andric   }
25675f757f3fSDimitry Andric 
25685f757f3fSDimitry Andric   return true;
25695f757f3fSDimitry Andric }
25705f757f3fSDimitry Andric 
25715f757f3fSDimitry Andric //===- GICombinerEmitter --------------------------------------------------===//
25725f757f3fSDimitry Andric 
25735f757f3fSDimitry Andric /// Main implementation class. This emits the tablegenerated output.
25745f757f3fSDimitry Andric ///
25755f757f3fSDimitry Andric /// It collects rules, uses `CombineRuleBuilder` to parse them and accumulate
25765f757f3fSDimitry Andric /// RuleMatchers, then takes all the necessary state/data from the various
25775f757f3fSDimitry Andric /// static storage pools and wires them together to emit the match table &
25785f757f3fSDimitry Andric /// associated function/data structures.
25795f757f3fSDimitry Andric class GICombinerEmitter final : public GlobalISelMatchTableExecutorEmitter {
25805f757f3fSDimitry Andric   RecordKeeper &Records;
25815f757f3fSDimitry Andric   StringRef Name;
25825f757f3fSDimitry Andric   const CodeGenTarget &Target;
25835f757f3fSDimitry Andric   Record *Combiner;
25845f757f3fSDimitry Andric   unsigned NextRuleID = 0;
25855f757f3fSDimitry Andric 
25865f757f3fSDimitry Andric   // List all combine rules (ID, name) imported.
25875f757f3fSDimitry Andric   // Note that the combiner rule ID is different from the RuleMatcher ID. The
25885f757f3fSDimitry Andric   // latter is internal to the MatchTable, the former is the canonical ID of the
25895f757f3fSDimitry Andric   // combine rule used to disable/enable it.
25905f757f3fSDimitry Andric   std::vector<std::pair<unsigned, std::string>> AllCombineRules;
25915f757f3fSDimitry Andric 
25925f757f3fSDimitry Andric   // Keep track of all rules we've seen so far to ensure we don't process
25935f757f3fSDimitry Andric   // the same rule twice.
25945f757f3fSDimitry Andric   StringSet<> RulesSeen;
25955f757f3fSDimitry Andric 
25965f757f3fSDimitry Andric   MatchTable buildMatchTable(MutableArrayRef<RuleMatcher> Rules);
25975f757f3fSDimitry Andric 
25985f757f3fSDimitry Andric   void emitRuleConfigImpl(raw_ostream &OS);
25995f757f3fSDimitry Andric 
26005f757f3fSDimitry Andric   void emitAdditionalImpl(raw_ostream &OS) override;
26015f757f3fSDimitry Andric 
26025f757f3fSDimitry Andric   void emitMIPredicateFns(raw_ostream &OS) override;
26035f757f3fSDimitry Andric   void emitI64ImmPredicateFns(raw_ostream &OS) override;
26045f757f3fSDimitry Andric   void emitAPFloatImmPredicateFns(raw_ostream &OS) override;
26055f757f3fSDimitry Andric   void emitAPIntImmPredicateFns(raw_ostream &OS) override;
26065f757f3fSDimitry Andric   void emitTestSimplePredicate(raw_ostream &OS) override;
26075f757f3fSDimitry Andric   void emitRunCustomAction(raw_ostream &OS) override;
26085f757f3fSDimitry Andric 
26095f757f3fSDimitry Andric   void emitAdditionalTemporariesDecl(raw_ostream &OS,
26105f757f3fSDimitry Andric                                      StringRef Indent) override;
26115f757f3fSDimitry Andric 
26125f757f3fSDimitry Andric   const CodeGenTarget &getTarget() const override { return Target; }
26135f757f3fSDimitry Andric   StringRef getClassName() const override {
26145f757f3fSDimitry Andric     return Combiner->getValueAsString("Classname");
26155f757f3fSDimitry Andric   }
26165f757f3fSDimitry Andric 
26175f757f3fSDimitry Andric   StringRef getCombineAllMethodName() const {
26185f757f3fSDimitry Andric     return Combiner->getValueAsString("CombineAllMethodName");
26195f757f3fSDimitry Andric   }
26205f757f3fSDimitry Andric 
26215f757f3fSDimitry Andric   std::string getRuleConfigClassName() const {
26225f757f3fSDimitry Andric     return getClassName().str() + "RuleConfig";
26235f757f3fSDimitry Andric   }
26245f757f3fSDimitry Andric 
26255f757f3fSDimitry Andric   void gatherRules(std::vector<RuleMatcher> &Rules,
26265f757f3fSDimitry Andric                    const std::vector<Record *> &&RulesAndGroups);
26275f757f3fSDimitry Andric 
26285f757f3fSDimitry Andric public:
26295f757f3fSDimitry Andric   explicit GICombinerEmitter(RecordKeeper &RK, const CodeGenTarget &Target,
26305f757f3fSDimitry Andric                              StringRef Name, Record *Combiner);
26315f757f3fSDimitry Andric   ~GICombinerEmitter() {}
26325f757f3fSDimitry Andric 
26335f757f3fSDimitry Andric   void run(raw_ostream &OS);
26345f757f3fSDimitry Andric };
26355f757f3fSDimitry Andric 
26365f757f3fSDimitry Andric void GICombinerEmitter::emitRuleConfigImpl(raw_ostream &OS) {
26375f757f3fSDimitry Andric   OS << "struct " << getRuleConfigClassName() << " {\n"
26385f757f3fSDimitry Andric      << "  SparseBitVector<> DisabledRules;\n\n"
26395f757f3fSDimitry Andric      << "  bool isRuleEnabled(unsigned RuleID) const;\n"
26405f757f3fSDimitry Andric      << "  bool parseCommandLineOption();\n"
26415f757f3fSDimitry Andric      << "  bool setRuleEnabled(StringRef RuleIdentifier);\n"
26425f757f3fSDimitry Andric      << "  bool setRuleDisabled(StringRef RuleIdentifier);\n"
26435f757f3fSDimitry Andric      << "};\n\n";
26445f757f3fSDimitry Andric 
26455f757f3fSDimitry Andric   std::vector<std::pair<std::string, std::string>> Cases;
26465f757f3fSDimitry Andric   Cases.reserve(AllCombineRules.size());
26475f757f3fSDimitry Andric 
26485f757f3fSDimitry Andric   for (const auto &[ID, Name] : AllCombineRules)
26495f757f3fSDimitry Andric     Cases.emplace_back(Name, "return " + to_string(ID) + ";\n");
26505f757f3fSDimitry Andric 
26515f757f3fSDimitry Andric   OS << "static std::optional<uint64_t> getRuleIdxForIdentifier(StringRef "
26525f757f3fSDimitry Andric         "RuleIdentifier) {\n"
26535f757f3fSDimitry Andric      << "  uint64_t I;\n"
26545f757f3fSDimitry Andric      << "  // getAtInteger(...) returns false on success\n"
26555f757f3fSDimitry Andric      << "  bool Parsed = !RuleIdentifier.getAsInteger(0, I);\n"
26565f757f3fSDimitry Andric      << "  if (Parsed)\n"
26575f757f3fSDimitry Andric      << "    return I;\n\n"
26585f757f3fSDimitry Andric      << "#ifndef NDEBUG\n";
26595f757f3fSDimitry Andric   StringMatcher Matcher("RuleIdentifier", Cases, OS);
26605f757f3fSDimitry Andric   Matcher.Emit();
26615f757f3fSDimitry Andric   OS << "#endif // ifndef NDEBUG\n\n"
26625f757f3fSDimitry Andric      << "  return std::nullopt;\n"
26635f757f3fSDimitry Andric      << "}\n";
26645f757f3fSDimitry Andric 
26655f757f3fSDimitry Andric   OS << "static std::optional<std::pair<uint64_t, uint64_t>> "
26665f757f3fSDimitry Andric         "getRuleRangeForIdentifier(StringRef RuleIdentifier) {\n"
26675f757f3fSDimitry Andric      << "  std::pair<StringRef, StringRef> RangePair = "
26685f757f3fSDimitry Andric         "RuleIdentifier.split('-');\n"
26695f757f3fSDimitry Andric      << "  if (!RangePair.second.empty()) {\n"
26705f757f3fSDimitry Andric      << "    const auto First = "
26715f757f3fSDimitry Andric         "getRuleIdxForIdentifier(RangePair.first);\n"
26725f757f3fSDimitry Andric      << "    const auto Last = "
26735f757f3fSDimitry Andric         "getRuleIdxForIdentifier(RangePair.second);\n"
26745f757f3fSDimitry Andric      << "    if (!First || !Last)\n"
26755f757f3fSDimitry Andric      << "      return std::nullopt;\n"
26765f757f3fSDimitry Andric      << "    if (First >= Last)\n"
26775f757f3fSDimitry Andric      << "      report_fatal_error(\"Beginning of range should be before "
26785f757f3fSDimitry Andric         "end of range\");\n"
26795f757f3fSDimitry Andric      << "    return {{*First, *Last + 1}};\n"
26805f757f3fSDimitry Andric      << "  }\n"
26815f757f3fSDimitry Andric      << "  if (RangePair.first == \"*\") {\n"
26825f757f3fSDimitry Andric      << "    return {{0, " << AllCombineRules.size() << "}};\n"
26835f757f3fSDimitry Andric      << "  }\n"
26845f757f3fSDimitry Andric      << "  const auto I = getRuleIdxForIdentifier(RangePair.first);\n"
26855f757f3fSDimitry Andric      << "  if (!I)\n"
26865f757f3fSDimitry Andric      << "    return std::nullopt;\n"
26875f757f3fSDimitry Andric      << "  return {{*I, *I + 1}};\n"
26885f757f3fSDimitry Andric      << "}\n\n";
26895f757f3fSDimitry Andric 
26905f757f3fSDimitry Andric   for (bool Enabled : {true, false}) {
26915f757f3fSDimitry Andric     OS << "bool " << getRuleConfigClassName() << "::setRule"
26925f757f3fSDimitry Andric        << (Enabled ? "Enabled" : "Disabled") << "(StringRef RuleIdentifier) {\n"
26935f757f3fSDimitry Andric        << "  auto MaybeRange = getRuleRangeForIdentifier(RuleIdentifier);\n"
26945f757f3fSDimitry Andric        << "  if (!MaybeRange)\n"
26955f757f3fSDimitry Andric        << "    return false;\n"
26965f757f3fSDimitry Andric        << "  for (auto I = MaybeRange->first; I < MaybeRange->second; ++I)\n"
26975f757f3fSDimitry Andric        << "    DisabledRules." << (Enabled ? "reset" : "set") << "(I);\n"
26985f757f3fSDimitry Andric        << "  return true;\n"
26995f757f3fSDimitry Andric        << "}\n\n";
27005f757f3fSDimitry Andric   }
27015f757f3fSDimitry Andric 
27025f757f3fSDimitry Andric   OS << "static std::vector<std::string> " << Name << "Option;\n"
27035f757f3fSDimitry Andric      << "static cl::list<std::string> " << Name << "DisableOption(\n"
27045f757f3fSDimitry Andric      << "    \"" << Name.lower() << "-disable-rule\",\n"
27055f757f3fSDimitry Andric      << "    cl::desc(\"Disable one or more combiner rules temporarily in "
27065f757f3fSDimitry Andric      << "the " << Name << " pass\"),\n"
27075f757f3fSDimitry Andric      << "    cl::CommaSeparated,\n"
27085f757f3fSDimitry Andric      << "    cl::Hidden,\n"
27095f757f3fSDimitry Andric      << "    cl::cat(GICombinerOptionCategory),\n"
27105f757f3fSDimitry Andric      << "    cl::callback([](const std::string &Str) {\n"
27115f757f3fSDimitry Andric      << "      " << Name << "Option.push_back(Str);\n"
27125f757f3fSDimitry Andric      << "    }));\n"
27135f757f3fSDimitry Andric      << "static cl::list<std::string> " << Name << "OnlyEnableOption(\n"
27145f757f3fSDimitry Andric      << "    \"" << Name.lower() << "-only-enable-rule\",\n"
27155f757f3fSDimitry Andric      << "    cl::desc(\"Disable all rules in the " << Name
27165f757f3fSDimitry Andric      << " pass then re-enable the specified ones\"),\n"
27175f757f3fSDimitry Andric      << "    cl::Hidden,\n"
27185f757f3fSDimitry Andric      << "    cl::cat(GICombinerOptionCategory),\n"
27195f757f3fSDimitry Andric      << "    cl::callback([](const std::string &CommaSeparatedArg) {\n"
27205f757f3fSDimitry Andric      << "      StringRef Str = CommaSeparatedArg;\n"
27215f757f3fSDimitry Andric      << "      " << Name << "Option.push_back(\"*\");\n"
27225f757f3fSDimitry Andric      << "      do {\n"
27235f757f3fSDimitry Andric      << "        auto X = Str.split(\",\");\n"
27245f757f3fSDimitry Andric      << "        " << Name << "Option.push_back((\"!\" + X.first).str());\n"
27255f757f3fSDimitry Andric      << "        Str = X.second;\n"
27265f757f3fSDimitry Andric      << "      } while (!Str.empty());\n"
27275f757f3fSDimitry Andric      << "    }));\n"
27285f757f3fSDimitry Andric      << "\n\n"
27295f757f3fSDimitry Andric      << "bool " << getRuleConfigClassName()
27305f757f3fSDimitry Andric      << "::isRuleEnabled(unsigned RuleID) const {\n"
27315f757f3fSDimitry Andric      << "    return  !DisabledRules.test(RuleID);\n"
27325f757f3fSDimitry Andric      << "}\n"
27335f757f3fSDimitry Andric      << "bool " << getRuleConfigClassName() << "::parseCommandLineOption() {\n"
27345f757f3fSDimitry Andric      << "  for (StringRef Identifier : " << Name << "Option) {\n"
27355f757f3fSDimitry Andric      << "    bool Enabled = Identifier.consume_front(\"!\");\n"
27365f757f3fSDimitry Andric      << "    if (Enabled && !setRuleEnabled(Identifier))\n"
27375f757f3fSDimitry Andric      << "      return false;\n"
27385f757f3fSDimitry Andric      << "    if (!Enabled && !setRuleDisabled(Identifier))\n"
27395f757f3fSDimitry Andric      << "      return false;\n"
27405f757f3fSDimitry Andric      << "  }\n"
27415f757f3fSDimitry Andric      << "  return true;\n"
27425f757f3fSDimitry Andric      << "}\n\n";
27435f757f3fSDimitry Andric }
27445f757f3fSDimitry Andric 
27455f757f3fSDimitry Andric void GICombinerEmitter::emitAdditionalImpl(raw_ostream &OS) {
27465f757f3fSDimitry Andric   OS << "bool " << getClassName() << "::" << getCombineAllMethodName()
27475f757f3fSDimitry Andric      << "(MachineInstr &I) const {\n"
27485f757f3fSDimitry Andric      << "  const TargetSubtargetInfo &ST = MF.getSubtarget();\n"
27495f757f3fSDimitry Andric      << "  const PredicateBitset AvailableFeatures = "
27505f757f3fSDimitry Andric         "getAvailableFeatures();\n"
27515f757f3fSDimitry Andric      << "  B.setInstrAndDebugLoc(I);\n"
27525f757f3fSDimitry Andric      << "  State.MIs.clear();\n"
27535f757f3fSDimitry Andric      << "  State.MIs.push_back(&I);\n"
27545f757f3fSDimitry Andric      << "  " << MatchDataInfo::StructName << " = "
27555f757f3fSDimitry Andric      << MatchDataInfo::StructTypeName << "();\n\n"
27565f757f3fSDimitry Andric      << "  if (executeMatchTable(*this, State, ExecInfo, B"
27575f757f3fSDimitry Andric      << ", getMatchTable(), *ST.getInstrInfo(), MRI, "
27585f757f3fSDimitry Andric         "*MRI.getTargetRegisterInfo(), *ST.getRegBankInfo(), AvailableFeatures"
27595f757f3fSDimitry Andric      << ", /*CoverageInfo*/ nullptr)) {\n"
27605f757f3fSDimitry Andric      << "    return true;\n"
27615f757f3fSDimitry Andric      << "  }\n\n"
27625f757f3fSDimitry Andric      << "  return false;\n"
27635f757f3fSDimitry Andric      << "}\n\n";
27645f757f3fSDimitry Andric }
27655f757f3fSDimitry Andric 
27665f757f3fSDimitry Andric void GICombinerEmitter::emitMIPredicateFns(raw_ostream &OS) {
27675f757f3fSDimitry Andric   auto MatchCode = CXXPredicateCode::getAllMatchCode();
27685f757f3fSDimitry Andric   emitMIPredicateFnsImpl<const CXXPredicateCode *>(
27695f757f3fSDimitry Andric       OS, "", ArrayRef<const CXXPredicateCode *>(MatchCode),
27705f757f3fSDimitry Andric       [](const CXXPredicateCode *C) -> StringRef { return C->BaseEnumName; },
27715f757f3fSDimitry Andric       [](const CXXPredicateCode *C) -> StringRef { return C->Code; });
27725f757f3fSDimitry Andric }
27735f757f3fSDimitry Andric 
27745f757f3fSDimitry Andric void GICombinerEmitter::emitI64ImmPredicateFns(raw_ostream &OS) {
27755f757f3fSDimitry Andric   // Unused, but still needs to be called.
27765f757f3fSDimitry Andric   emitImmPredicateFnsImpl<unsigned>(
27775f757f3fSDimitry Andric       OS, "I64", "int64_t", {}, [](unsigned) { return ""; },
27785f757f3fSDimitry Andric       [](unsigned) { return ""; });
27795f757f3fSDimitry Andric }
27805f757f3fSDimitry Andric 
27815f757f3fSDimitry Andric void GICombinerEmitter::emitAPFloatImmPredicateFns(raw_ostream &OS) {
27825f757f3fSDimitry Andric   // Unused, but still needs to be called.
27835f757f3fSDimitry Andric   emitImmPredicateFnsImpl<unsigned>(
27845f757f3fSDimitry Andric       OS, "APFloat", "const APFloat &", {}, [](unsigned) { return ""; },
27855f757f3fSDimitry Andric       [](unsigned) { return ""; });
27865f757f3fSDimitry Andric }
27875f757f3fSDimitry Andric 
27885f757f3fSDimitry Andric void GICombinerEmitter::emitAPIntImmPredicateFns(raw_ostream &OS) {
27895f757f3fSDimitry Andric   // Unused, but still needs to be called.
27905f757f3fSDimitry Andric   emitImmPredicateFnsImpl<unsigned>(
27915f757f3fSDimitry Andric       OS, "APInt", "const APInt &", {}, [](unsigned) { return ""; },
27925f757f3fSDimitry Andric       [](unsigned) { return ""; });
27935f757f3fSDimitry Andric }
27945f757f3fSDimitry Andric 
27955f757f3fSDimitry Andric void GICombinerEmitter::emitTestSimplePredicate(raw_ostream &OS) {
27965f757f3fSDimitry Andric   if (!AllCombineRules.empty()) {
27975f757f3fSDimitry Andric     OS << "enum {\n";
27985f757f3fSDimitry Andric     std::string EnumeratorSeparator = " = GICXXPred_Invalid + 1,\n";
27995f757f3fSDimitry Andric     // To avoid emitting a switch, we expect that all those rules are in order.
28005f757f3fSDimitry Andric     // That way we can just get the RuleID from the enum by subtracting
28015f757f3fSDimitry Andric     // (GICXXPred_Invalid + 1).
28025f757f3fSDimitry Andric     unsigned ExpectedID = 0;
28035f757f3fSDimitry Andric     (void)ExpectedID;
28045f757f3fSDimitry Andric     for (const auto &ID : keys(AllCombineRules)) {
28055f757f3fSDimitry Andric       assert(ExpectedID++ == ID && "combine rules are not ordered!");
28065f757f3fSDimitry Andric       OS << "  " << getIsEnabledPredicateEnumName(ID) << EnumeratorSeparator;
28075f757f3fSDimitry Andric       EnumeratorSeparator = ",\n";
28085f757f3fSDimitry Andric     }
28095f757f3fSDimitry Andric     OS << "};\n\n";
28105f757f3fSDimitry Andric   }
28115f757f3fSDimitry Andric 
28125f757f3fSDimitry Andric   OS << "bool " << getClassName()
28135f757f3fSDimitry Andric      << "::testSimplePredicate(unsigned Predicate) const {\n"
28145f757f3fSDimitry Andric      << "    return RuleConfig.isRuleEnabled(Predicate - "
28155f757f3fSDimitry Andric         "GICXXPred_Invalid - "
28165f757f3fSDimitry Andric         "1);\n"
28175f757f3fSDimitry Andric      << "}\n";
28185f757f3fSDimitry Andric }
28195f757f3fSDimitry Andric 
28205f757f3fSDimitry Andric void GICombinerEmitter::emitRunCustomAction(raw_ostream &OS) {
28215f757f3fSDimitry Andric   const auto ApplyCode = CXXPredicateCode::getAllApplyCode();
28225f757f3fSDimitry Andric 
28235f757f3fSDimitry Andric   if (!ApplyCode.empty()) {
28245f757f3fSDimitry Andric     OS << "enum {\n";
28255f757f3fSDimitry Andric     std::string EnumeratorSeparator = " = GICXXCustomAction_Invalid + 1,\n";
28265f757f3fSDimitry Andric     for (const auto &Apply : ApplyCode) {
28275f757f3fSDimitry Andric       OS << "  " << Apply->getEnumNameWithPrefix(CXXApplyPrefix)
28285f757f3fSDimitry Andric          << EnumeratorSeparator;
28295f757f3fSDimitry Andric       EnumeratorSeparator = ",\n";
28305f757f3fSDimitry Andric     }
28315f757f3fSDimitry Andric     OS << "};\n";
28325f757f3fSDimitry Andric   }
28335f757f3fSDimitry Andric 
28345f757f3fSDimitry Andric   OS << "void " << getClassName()
28355f757f3fSDimitry Andric      << "::runCustomAction(unsigned ApplyID, const MatcherState &State, "
28365f757f3fSDimitry Andric         "NewMIVector &OutMIs) const "
28375f757f3fSDimitry Andric         "{\n";
28385f757f3fSDimitry Andric   if (!ApplyCode.empty()) {
28395f757f3fSDimitry Andric     OS << "  switch(ApplyID) {\n";
28405f757f3fSDimitry Andric     for (const auto &Apply : ApplyCode) {
28415f757f3fSDimitry Andric       OS << "  case " << Apply->getEnumNameWithPrefix(CXXApplyPrefix) << ":{\n"
28425f757f3fSDimitry Andric          << "    " << join(split(Apply->Code, '\n'), "\n    ") << '\n'
28435f757f3fSDimitry Andric          << "    return;\n";
28445f757f3fSDimitry Andric       OS << "  }\n";
28455f757f3fSDimitry Andric     }
28465f757f3fSDimitry Andric     OS << "}\n";
28475f757f3fSDimitry Andric   }
28485f757f3fSDimitry Andric   OS << "  llvm_unreachable(\"Unknown Apply Action\");\n"
28495f757f3fSDimitry Andric      << "}\n";
28505f757f3fSDimitry Andric }
28515f757f3fSDimitry Andric 
28525f757f3fSDimitry Andric void GICombinerEmitter::emitAdditionalTemporariesDecl(raw_ostream &OS,
28535f757f3fSDimitry Andric                                                       StringRef Indent) {
28545f757f3fSDimitry Andric   OS << Indent << "struct " << MatchDataInfo::StructTypeName << " {\n";
28555f757f3fSDimitry Andric   for (const auto &[Type, VarNames] : AllMatchDataVars) {
28565f757f3fSDimitry Andric     assert(!VarNames.empty() && "Cannot have no vars for this type!");
28575f757f3fSDimitry Andric     OS << Indent << "  " << Type << " " << join(VarNames, ", ") << ";\n";
28585f757f3fSDimitry Andric   }
28595f757f3fSDimitry Andric   OS << Indent << "};\n"
28605f757f3fSDimitry Andric      << Indent << "mutable " << MatchDataInfo::StructTypeName << " "
28615f757f3fSDimitry Andric      << MatchDataInfo::StructName << ";\n\n";
28625f757f3fSDimitry Andric }
28635f757f3fSDimitry Andric 
28645f757f3fSDimitry Andric GICombinerEmitter::GICombinerEmitter(RecordKeeper &RK,
28655f757f3fSDimitry Andric                                      const CodeGenTarget &Target,
28665f757f3fSDimitry Andric                                      StringRef Name, Record *Combiner)
28675f757f3fSDimitry Andric     : Records(RK), Name(Name), Target(Target), Combiner(Combiner) {}
28685f757f3fSDimitry Andric 
28695f757f3fSDimitry Andric MatchTable
28705f757f3fSDimitry Andric GICombinerEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules) {
28715f757f3fSDimitry Andric   std::vector<Matcher *> InputRules;
28725f757f3fSDimitry Andric   for (Matcher &Rule : Rules)
28735f757f3fSDimitry Andric     InputRules.push_back(&Rule);
28745f757f3fSDimitry Andric 
28755f757f3fSDimitry Andric   unsigned CurrentOrdering = 0;
28765f757f3fSDimitry Andric   StringMap<unsigned> OpcodeOrder;
28775f757f3fSDimitry Andric   for (RuleMatcher &Rule : Rules) {
28785f757f3fSDimitry Andric     const StringRef Opcode = Rule.getOpcode();
28795f757f3fSDimitry Andric     assert(!Opcode.empty() && "Didn't expect an undefined opcode");
28805f757f3fSDimitry Andric     if (OpcodeOrder.count(Opcode) == 0)
28815f757f3fSDimitry Andric       OpcodeOrder[Opcode] = CurrentOrdering++;
28825f757f3fSDimitry Andric   }
28835f757f3fSDimitry Andric 
28845f757f3fSDimitry Andric   llvm::stable_sort(InputRules, [&OpcodeOrder](const Matcher *A,
28855f757f3fSDimitry Andric                                                const Matcher *B) {
28865f757f3fSDimitry Andric     auto *L = static_cast<const RuleMatcher *>(A);
28875f757f3fSDimitry Andric     auto *R = static_cast<const RuleMatcher *>(B);
28885f757f3fSDimitry Andric     return std::make_tuple(OpcodeOrder[L->getOpcode()], L->getNumOperands()) <
28895f757f3fSDimitry Andric            std::make_tuple(OpcodeOrder[R->getOpcode()], R->getNumOperands());
28905f757f3fSDimitry Andric   });
28915f757f3fSDimitry Andric 
28925f757f3fSDimitry Andric   for (Matcher *Rule : InputRules)
28935f757f3fSDimitry Andric     Rule->optimize();
28945f757f3fSDimitry Andric 
28955f757f3fSDimitry Andric   std::vector<std::unique_ptr<Matcher>> MatcherStorage;
28965f757f3fSDimitry Andric   std::vector<Matcher *> OptRules =
28975f757f3fSDimitry Andric       optimizeRules<GroupMatcher>(InputRules, MatcherStorage);
28985f757f3fSDimitry Andric 
28995f757f3fSDimitry Andric   for (Matcher *Rule : OptRules)
29005f757f3fSDimitry Andric     Rule->optimize();
29015f757f3fSDimitry Andric 
29025f757f3fSDimitry Andric   OptRules = optimizeRules<SwitchMatcher>(OptRules, MatcherStorage);
29035f757f3fSDimitry Andric 
29045f757f3fSDimitry Andric   return MatchTable::buildTable(OptRules, /*WithCoverage*/ false,
29055f757f3fSDimitry Andric                                 /*IsCombiner*/ true);
29065f757f3fSDimitry Andric }
29075f757f3fSDimitry Andric 
29085f757f3fSDimitry Andric /// Recurse into GICombineGroup's and flatten the ruleset into a simple list.
29095f757f3fSDimitry Andric void GICombinerEmitter::gatherRules(
29105f757f3fSDimitry Andric     std::vector<RuleMatcher> &ActiveRules,
29115f757f3fSDimitry Andric     const std::vector<Record *> &&RulesAndGroups) {
29125f757f3fSDimitry Andric   for (Record *Rec : RulesAndGroups) {
29135f757f3fSDimitry Andric     if (!Rec->isValueUnset("Rules")) {
29145f757f3fSDimitry Andric       gatherRules(ActiveRules, Rec->getValueAsListOfDefs("Rules"));
29155f757f3fSDimitry Andric       continue;
29165f757f3fSDimitry Andric     }
29175f757f3fSDimitry Andric 
29185f757f3fSDimitry Andric     StringRef RuleName = Rec->getName();
29195f757f3fSDimitry Andric     if (!RulesSeen.insert(RuleName).second) {
29205f757f3fSDimitry Andric       PrintWarning(Rec->getLoc(),
29215f757f3fSDimitry Andric                    "skipping rule '" + Rec->getName() +
29225f757f3fSDimitry Andric                        "' because it has already been processed");
29235f757f3fSDimitry Andric       continue;
29245f757f3fSDimitry Andric     }
29255f757f3fSDimitry Andric 
29265f757f3fSDimitry Andric     AllCombineRules.emplace_back(NextRuleID, Rec->getName().str());
29275f757f3fSDimitry Andric     CombineRuleBuilder CRB(Target, SubtargetFeatures, *Rec, NextRuleID++,
29285f757f3fSDimitry Andric                            ActiveRules);
29295f757f3fSDimitry Andric 
29305f757f3fSDimitry Andric     if (!CRB.parseAll()) {
29315f757f3fSDimitry Andric       assert(ErrorsPrinted && "Parsing failed without errors!");
29325f757f3fSDimitry Andric       continue;
29335f757f3fSDimitry Andric     }
29345f757f3fSDimitry Andric 
29355f757f3fSDimitry Andric     if (StopAfterParse) {
29365f757f3fSDimitry Andric       CRB.print(outs());
29375f757f3fSDimitry Andric       continue;
29385f757f3fSDimitry Andric     }
29395f757f3fSDimitry Andric 
29405f757f3fSDimitry Andric     if (!CRB.emitRuleMatchers()) {
29415f757f3fSDimitry Andric       assert(ErrorsPrinted && "Emission failed without errors!");
29425f757f3fSDimitry Andric       continue;
29435f757f3fSDimitry Andric     }
29445f757f3fSDimitry Andric   }
29455f757f3fSDimitry Andric }
29465f757f3fSDimitry Andric 
29475f757f3fSDimitry Andric void GICombinerEmitter::run(raw_ostream &OS) {
29485f757f3fSDimitry Andric   InstructionOpcodeMatcher::initOpcodeValuesMap(Target);
29495f757f3fSDimitry Andric   LLTOperandMatcher::initTypeIDValuesMap();
29505f757f3fSDimitry Andric 
29515f757f3fSDimitry Andric   Records.startTimer("Gather rules");
29525f757f3fSDimitry Andric   std::vector<RuleMatcher> Rules;
29535f757f3fSDimitry Andric   gatherRules(Rules, Combiner->getValueAsListOfDefs("Rules"));
29545f757f3fSDimitry Andric   if (ErrorsPrinted)
29555f757f3fSDimitry Andric     PrintFatalError(Combiner->getLoc(), "Failed to parse one or more rules");
29565f757f3fSDimitry Andric 
29575f757f3fSDimitry Andric   if (StopAfterParse)
29585f757f3fSDimitry Andric     return;
29595f757f3fSDimitry Andric 
29605f757f3fSDimitry Andric   Records.startTimer("Creating Match Table");
29615f757f3fSDimitry Andric   unsigned MaxTemporaries = 0;
29625f757f3fSDimitry Andric   for (const auto &Rule : Rules)
29635f757f3fSDimitry Andric     MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());
29645f757f3fSDimitry Andric 
29655f757f3fSDimitry Andric   llvm::stable_sort(Rules, [&](const RuleMatcher &A, const RuleMatcher &B) {
29665f757f3fSDimitry Andric     if (A.isHigherPriorityThan(B)) {
29675f757f3fSDimitry Andric       assert(!B.isHigherPriorityThan(A) && "Cannot be more important "
29685f757f3fSDimitry Andric                                            "and less important at "
29695f757f3fSDimitry Andric                                            "the same time");
29705f757f3fSDimitry Andric       return true;
29715f757f3fSDimitry Andric     }
29725f757f3fSDimitry Andric     return false;
29735f757f3fSDimitry Andric   });
29745f757f3fSDimitry Andric 
29755f757f3fSDimitry Andric   const MatchTable Table = buildMatchTable(Rules);
29765f757f3fSDimitry Andric 
29775f757f3fSDimitry Andric   Records.startTimer("Emit combiner");
29785f757f3fSDimitry Andric 
29795f757f3fSDimitry Andric   emitSourceFileHeader(getClassName().str() + " Combiner Match Table", OS);
29805f757f3fSDimitry Andric 
29815f757f3fSDimitry Andric   // Unused
29825f757f3fSDimitry Andric   std::vector<StringRef> CustomRendererFns;
29835f757f3fSDimitry Andric   // Unused
29845f757f3fSDimitry Andric   std::vector<Record *> ComplexPredicates;
29855f757f3fSDimitry Andric 
29865f757f3fSDimitry Andric   SmallVector<LLTCodeGen, 16> TypeObjects;
29875f757f3fSDimitry Andric   append_range(TypeObjects, KnownTypes);
29885f757f3fSDimitry Andric   llvm::sort(TypeObjects);
29895f757f3fSDimitry Andric 
29905f757f3fSDimitry Andric   // Hack: Avoid empty declarator.
29915f757f3fSDimitry Andric   if (TypeObjects.empty())
29925f757f3fSDimitry Andric     TypeObjects.push_back(LLT::scalar(1));
29935f757f3fSDimitry Andric 
29945f757f3fSDimitry Andric   // GET_GICOMBINER_DEPS, which pulls in extra dependencies.
29955f757f3fSDimitry Andric   OS << "#ifdef GET_GICOMBINER_DEPS\n"
29965f757f3fSDimitry Andric      << "#include \"llvm/ADT/SparseBitVector.h\"\n"
29975f757f3fSDimitry Andric      << "namespace llvm {\n"
29985f757f3fSDimitry Andric      << "extern cl::OptionCategory GICombinerOptionCategory;\n"
29995f757f3fSDimitry Andric      << "} // end namespace llvm\n"
30005f757f3fSDimitry Andric      << "#endif // ifdef GET_GICOMBINER_DEPS\n\n";
30015f757f3fSDimitry Andric 
30025f757f3fSDimitry Andric   // GET_GICOMBINER_TYPES, which needs to be included before the declaration of
30035f757f3fSDimitry Andric   // the class.
30045f757f3fSDimitry Andric   OS << "#ifdef GET_GICOMBINER_TYPES\n";
30055f757f3fSDimitry Andric   emitRuleConfigImpl(OS);
30065f757f3fSDimitry Andric   OS << "#endif // ifdef GET_GICOMBINER_TYPES\n\n";
30075f757f3fSDimitry Andric   emitPredicateBitset(OS, "GET_GICOMBINER_TYPES");
30085f757f3fSDimitry Andric 
30095f757f3fSDimitry Andric   // GET_GICOMBINER_CLASS_MEMBERS, which need to be included inside the class.
30105f757f3fSDimitry Andric   emitPredicatesDecl(OS, "GET_GICOMBINER_CLASS_MEMBERS");
30115f757f3fSDimitry Andric   emitTemporariesDecl(OS, "GET_GICOMBINER_CLASS_MEMBERS");
30125f757f3fSDimitry Andric 
30135f757f3fSDimitry Andric   // GET_GICOMBINER_IMPL, which needs to be included outside the class.
30145f757f3fSDimitry Andric   emitExecutorImpl(OS, Table, TypeObjects, Rules, ComplexPredicates,
30155f757f3fSDimitry Andric                    CustomRendererFns, "GET_GICOMBINER_IMPL");
30165f757f3fSDimitry Andric 
30175f757f3fSDimitry Andric   // GET_GICOMBINER_CONSTRUCTOR_INITS, which are in the constructor's
30185f757f3fSDimitry Andric   // initializer list.
30195f757f3fSDimitry Andric   emitPredicatesInit(OS, "GET_GICOMBINER_CONSTRUCTOR_INITS");
30205f757f3fSDimitry Andric   emitTemporariesInit(OS, MaxTemporaries, "GET_GICOMBINER_CONSTRUCTOR_INITS");
30215f757f3fSDimitry Andric }
30225f757f3fSDimitry Andric 
30235f757f3fSDimitry Andric } // end anonymous namespace
30245f757f3fSDimitry Andric 
30255f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
30265f757f3fSDimitry Andric 
30275f757f3fSDimitry Andric static void EmitGICombiner(RecordKeeper &RK, raw_ostream &OS) {
30285f757f3fSDimitry Andric   EnablePrettyStackTrace();
30295f757f3fSDimitry Andric   CodeGenTarget Target(RK);
30305f757f3fSDimitry Andric 
30315f757f3fSDimitry Andric   if (SelectedCombiners.empty())
30325f757f3fSDimitry Andric     PrintFatalError("No combiners selected with -combiners");
30335f757f3fSDimitry Andric   for (const auto &Combiner : SelectedCombiners) {
30345f757f3fSDimitry Andric     Record *CombinerDef = RK.getDef(Combiner);
30355f757f3fSDimitry Andric     if (!CombinerDef)
30365f757f3fSDimitry Andric       PrintFatalError("Could not find " + Combiner);
30375f757f3fSDimitry Andric     GICombinerEmitter(RK, Target, Combiner, CombinerDef).run(OS);
30385f757f3fSDimitry Andric   }
30395f757f3fSDimitry Andric }
30405f757f3fSDimitry Andric 
30415f757f3fSDimitry Andric static TableGen::Emitter::Opt X("gen-global-isel-combiner", EmitGICombiner,
30425f757f3fSDimitry Andric                                 "Generate GlobalISel Combiner");
3043