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
29*0fca6ea1SDimitry Andric #include "Basic/CodeGenIntrinsics.h"
30*0fca6ea1SDimitry Andric #include "Common/CodeGenInstruction.h"
31*0fca6ea1SDimitry Andric #include "Common/CodeGenTarget.h"
32*0fca6ea1SDimitry Andric #include "Common/GlobalISel/CXXPredicates.h"
33*0fca6ea1SDimitry Andric #include "Common/GlobalISel/CodeExpander.h"
34*0fca6ea1SDimitry Andric #include "Common/GlobalISel/CodeExpansions.h"
35*0fca6ea1SDimitry Andric #include "Common/GlobalISel/CombinerUtils.h"
36*0fca6ea1SDimitry Andric #include "Common/GlobalISel/GlobalISelMatchTable.h"
37*0fca6ea1SDimitry Andric #include "Common/GlobalISel/GlobalISelMatchTableExecutorEmitter.h"
38*0fca6ea1SDimitry Andric #include "Common/GlobalISel/PatternParser.h"
39*0fca6ea1SDimitry Andric #include "Common/GlobalISel/Patterns.h"
40*0fca6ea1SDimitry Andric #include "Common/SubtargetFeatureInfo.h"
415f757f3fSDimitry Andric #include "llvm/ADT/APInt.h"
425f757f3fSDimitry Andric #include "llvm/ADT/EquivalenceClasses.h"
435f757f3fSDimitry Andric #include "llvm/ADT/Hashing.h"
445f757f3fSDimitry Andric #include "llvm/ADT/MapVector.h"
455f757f3fSDimitry Andric #include "llvm/ADT/SetVector.h"
465f757f3fSDimitry Andric #include "llvm/ADT/Statistic.h"
47*0fca6ea1SDimitry Andric #include "llvm/ADT/StringExtras.h"
485f757f3fSDimitry Andric #include "llvm/ADT/StringSet.h"
495f757f3fSDimitry Andric #include "llvm/Support/CommandLine.h"
505f757f3fSDimitry Andric #include "llvm/Support/Debug.h"
515f757f3fSDimitry Andric #include "llvm/Support/PrettyStackTrace.h"
525f757f3fSDimitry Andric #include "llvm/Support/ScopedPrinter.h"
535f757f3fSDimitry Andric #include "llvm/TableGen/Error.h"
545f757f3fSDimitry Andric #include "llvm/TableGen/Record.h"
555f757f3fSDimitry Andric #include "llvm/TableGen/StringMatcher.h"
565f757f3fSDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
575f757f3fSDimitry Andric #include <cstdint>
585f757f3fSDimitry Andric
595f757f3fSDimitry Andric using namespace llvm;
605f757f3fSDimitry Andric using namespace llvm::gi;
615f757f3fSDimitry Andric
625f757f3fSDimitry Andric #define DEBUG_TYPE "gicombiner-emitter"
635f757f3fSDimitry Andric
645f757f3fSDimitry Andric namespace {
655f757f3fSDimitry Andric cl::OptionCategory
665f757f3fSDimitry Andric GICombinerEmitterCat("Options for -gen-global-isel-combiner");
675f757f3fSDimitry Andric cl::opt<bool> StopAfterParse(
685f757f3fSDimitry Andric "gicombiner-stop-after-parse",
695f757f3fSDimitry Andric cl::desc("Stop processing after parsing rules and dump state"),
705f757f3fSDimitry Andric cl::cat(GICombinerEmitterCat));
715f757f3fSDimitry Andric cl::list<std::string>
725f757f3fSDimitry Andric SelectedCombiners("combiners", cl::desc("Emit the specified combiners"),
735f757f3fSDimitry Andric cl::cat(GICombinerEmitterCat), cl::CommaSeparated);
745f757f3fSDimitry Andric cl::opt<bool> DebugCXXPreds(
755f757f3fSDimitry Andric "gicombiner-debug-cxxpreds",
765f757f3fSDimitry Andric cl::desc("Add Contextual/Debug comments to all C++ predicates"),
775f757f3fSDimitry Andric cl::cat(GICombinerEmitterCat));
785f757f3fSDimitry Andric cl::opt<bool> DebugTypeInfer("gicombiner-debug-typeinfer",
795f757f3fSDimitry Andric cl::desc("Print type inference debug logs"),
805f757f3fSDimitry Andric cl::cat(GICombinerEmitterCat));
815f757f3fSDimitry Andric
82*0fca6ea1SDimitry Andric constexpr StringLiteral CXXCustomActionPrefix = "GICXXCustomAction_";
835f757f3fSDimitry Andric constexpr StringLiteral CXXPredPrefix = "GICXXPred_MI_Predicate_";
84*0fca6ea1SDimitry Andric constexpr StringLiteral MatchDataClassName = "GIDefMatchData";
855f757f3fSDimitry Andric
865f757f3fSDimitry Andric //===- CodeExpansions Helpers --------------------------------------------===//
875f757f3fSDimitry Andric
declareInstExpansion(CodeExpansions & CE,const InstructionMatcher & IM,StringRef Name)885f757f3fSDimitry Andric void declareInstExpansion(CodeExpansions &CE, const InstructionMatcher &IM,
895f757f3fSDimitry Andric StringRef Name) {
905f757f3fSDimitry Andric CE.declare(Name, "State.MIs[" + to_string(IM.getInsnVarID()) + "]");
915f757f3fSDimitry Andric }
925f757f3fSDimitry Andric
declareInstExpansion(CodeExpansions & CE,const BuildMIAction & A,StringRef Name)935f757f3fSDimitry Andric void declareInstExpansion(CodeExpansions &CE, const BuildMIAction &A,
945f757f3fSDimitry Andric StringRef Name) {
955f757f3fSDimitry Andric // Note: we use redeclare here because this may overwrite a matcher inst
965f757f3fSDimitry Andric // expansion.
975f757f3fSDimitry Andric CE.redeclare(Name, "OutMIs[" + to_string(A.getInsnID()) + "]");
985f757f3fSDimitry Andric }
995f757f3fSDimitry Andric
declareOperandExpansion(CodeExpansions & CE,const OperandMatcher & OM,StringRef Name)1005f757f3fSDimitry Andric void declareOperandExpansion(CodeExpansions &CE, const OperandMatcher &OM,
1015f757f3fSDimitry Andric StringRef Name) {
1025f757f3fSDimitry Andric CE.declare(Name, "State.MIs[" + to_string(OM.getInsnVarID()) +
1035f757f3fSDimitry Andric "]->getOperand(" + to_string(OM.getOpIdx()) + ")");
1045f757f3fSDimitry Andric }
1055f757f3fSDimitry Andric
declareTempRegExpansion(CodeExpansions & CE,unsigned TempRegID,StringRef Name)1065f757f3fSDimitry Andric void declareTempRegExpansion(CodeExpansions &CE, unsigned TempRegID,
1075f757f3fSDimitry Andric StringRef Name) {
1085f757f3fSDimitry Andric CE.declare(Name, "State.TempRegisters[" + to_string(TempRegID) + "]");
1095f757f3fSDimitry Andric }
1105f757f3fSDimitry Andric
1115f757f3fSDimitry Andric //===- Misc. Helpers -----------------------------------------------------===//
1125f757f3fSDimitry Andric
keys(Container && C)1135f757f3fSDimitry Andric template <typename Container> auto keys(Container &&C) {
1145f757f3fSDimitry Andric return map_range(C, [](auto &Entry) -> auto & { return Entry.first; });
1155f757f3fSDimitry Andric }
1165f757f3fSDimitry Andric
values(Container && C)1175f757f3fSDimitry Andric template <typename Container> auto values(Container &&C) {
1185f757f3fSDimitry Andric return map_range(C, [](auto &Entry) -> auto & { return Entry.second; });
1195f757f3fSDimitry Andric }
1205f757f3fSDimitry Andric
getIsEnabledPredicateEnumName(unsigned CombinerRuleID)1215f757f3fSDimitry Andric std::string getIsEnabledPredicateEnumName(unsigned CombinerRuleID) {
1225f757f3fSDimitry Andric return "GICXXPred_Simple_IsRule" + to_string(CombinerRuleID) + "Enabled";
1235f757f3fSDimitry Andric }
1245f757f3fSDimitry Andric
1255f757f3fSDimitry Andric //===- MatchTable Helpers ------------------------------------------------===//
1265f757f3fSDimitry Andric
getLLTCodeGen(const PatternType & PT)1275f757f3fSDimitry Andric LLTCodeGen getLLTCodeGen(const PatternType &PT) {
1285f757f3fSDimitry Andric return *MVTToLLT(getValueType(PT.getLLTRecord()));
1295f757f3fSDimitry Andric }
1305f757f3fSDimitry Andric
getLLTCodeGenOrTempType(const PatternType & PT,RuleMatcher & RM)1315f757f3fSDimitry Andric LLTCodeGenOrTempType getLLTCodeGenOrTempType(const PatternType &PT,
1325f757f3fSDimitry Andric RuleMatcher &RM) {
1335f757f3fSDimitry Andric assert(!PT.isNone());
1345f757f3fSDimitry Andric
1355f757f3fSDimitry Andric if (PT.isLLT())
1365f757f3fSDimitry Andric return getLLTCodeGen(PT);
1375f757f3fSDimitry Andric
1385f757f3fSDimitry Andric assert(PT.isTypeOf());
1395f757f3fSDimitry Andric auto &OM = RM.getOperandMatcher(PT.getTypeOfOpName());
1405f757f3fSDimitry Andric return OM.getTempTypeIdx(RM);
1415f757f3fSDimitry Andric }
1425f757f3fSDimitry Andric
1435f757f3fSDimitry Andric //===- PrettyStackTrace Helpers ------------------------------------------===//
1445f757f3fSDimitry Andric
1455f757f3fSDimitry Andric class PrettyStackTraceParse : public PrettyStackTraceEntry {
1465f757f3fSDimitry Andric const Record &Def;
1475f757f3fSDimitry Andric
1485f757f3fSDimitry Andric public:
PrettyStackTraceParse(const Record & Def)1495f757f3fSDimitry Andric PrettyStackTraceParse(const Record &Def) : Def(Def) {}
1505f757f3fSDimitry Andric
print(raw_ostream & OS) const1515f757f3fSDimitry Andric void print(raw_ostream &OS) const override {
1525f757f3fSDimitry Andric if (Def.isSubClassOf("GICombineRule"))
1535f757f3fSDimitry Andric OS << "Parsing GICombineRule '" << Def.getName() << "'";
1545f757f3fSDimitry Andric else if (Def.isSubClassOf(PatFrag::ClassName))
1555f757f3fSDimitry Andric OS << "Parsing " << PatFrag::ClassName << " '" << Def.getName() << "'";
1565f757f3fSDimitry Andric else
1575f757f3fSDimitry Andric OS << "Parsing '" << Def.getName() << "'";
1585f757f3fSDimitry Andric OS << '\n';
1595f757f3fSDimitry Andric }
1605f757f3fSDimitry Andric };
1615f757f3fSDimitry Andric
1625f757f3fSDimitry Andric class PrettyStackTraceEmit : public PrettyStackTraceEntry {
1635f757f3fSDimitry Andric const Record &Def;
1645f757f3fSDimitry Andric const Pattern *Pat = nullptr;
1655f757f3fSDimitry Andric
1665f757f3fSDimitry Andric public:
PrettyStackTraceEmit(const Record & Def,const Pattern * Pat=nullptr)1675f757f3fSDimitry Andric PrettyStackTraceEmit(const Record &Def, const Pattern *Pat = nullptr)
1685f757f3fSDimitry Andric : Def(Def), Pat(Pat) {}
1695f757f3fSDimitry Andric
print(raw_ostream & OS) const1705f757f3fSDimitry Andric void print(raw_ostream &OS) const override {
1715f757f3fSDimitry Andric if (Def.isSubClassOf("GICombineRule"))
1725f757f3fSDimitry Andric OS << "Emitting GICombineRule '" << Def.getName() << "'";
1735f757f3fSDimitry Andric else if (Def.isSubClassOf(PatFrag::ClassName))
1745f757f3fSDimitry Andric OS << "Emitting " << PatFrag::ClassName << " '" << Def.getName() << "'";
1755f757f3fSDimitry Andric else
1765f757f3fSDimitry Andric OS << "Emitting '" << Def.getName() << "'";
1775f757f3fSDimitry Andric
1785f757f3fSDimitry Andric if (Pat)
1795f757f3fSDimitry Andric OS << " [" << Pat->getKindName() << " '" << Pat->getName() << "']";
1805f757f3fSDimitry Andric OS << '\n';
1815f757f3fSDimitry Andric }
1825f757f3fSDimitry Andric };
1835f757f3fSDimitry Andric
1845f757f3fSDimitry Andric //===- CombineRuleOperandTypeChecker --------------------------------------===//
1855f757f3fSDimitry Andric
1865f757f3fSDimitry Andric /// This is a wrapper around OperandTypeChecker specialized for Combiner Rules.
1875f757f3fSDimitry Andric /// On top of doing the same things as OperandTypeChecker, this also attempts to
1885f757f3fSDimitry Andric /// infer as many types as possible for temporary register defs & immediates in
1895f757f3fSDimitry Andric /// apply patterns.
1905f757f3fSDimitry Andric ///
1915f757f3fSDimitry Andric /// The inference is trivial and leverages the MCOI OperandTypes encoded in
1925f757f3fSDimitry Andric /// CodeGenInstructions to infer types across patterns in a CombineRule. It's
1935f757f3fSDimitry Andric /// thus very limited and only supports CodeGenInstructions (but that's the main
1945f757f3fSDimitry Andric /// use case so it's fine).
1955f757f3fSDimitry Andric ///
1965f757f3fSDimitry Andric /// We only try to infer untyped operands in apply patterns when they're temp
1975f757f3fSDimitry Andric /// reg defs, or immediates. Inference always outputs a `TypeOf<$x>` where $x is
1985f757f3fSDimitry Andric /// a named operand from a match pattern.
1995f757f3fSDimitry Andric class CombineRuleOperandTypeChecker : private OperandTypeChecker {
2005f757f3fSDimitry Andric public:
CombineRuleOperandTypeChecker(const Record & RuleDef,const OperandTable & MatchOpTable)2015f757f3fSDimitry Andric CombineRuleOperandTypeChecker(const Record &RuleDef,
2025f757f3fSDimitry Andric const OperandTable &MatchOpTable)
2035f757f3fSDimitry Andric : OperandTypeChecker(RuleDef.getLoc()), RuleDef(RuleDef),
2045f757f3fSDimitry Andric MatchOpTable(MatchOpTable) {}
2055f757f3fSDimitry Andric
2065f757f3fSDimitry Andric /// Records and checks a 'match' pattern.
2075f757f3fSDimitry Andric bool processMatchPattern(InstructionPattern &P);
2085f757f3fSDimitry Andric
2095f757f3fSDimitry Andric /// Records and checks an 'apply' pattern.
2105f757f3fSDimitry Andric bool processApplyPattern(InstructionPattern &P);
2115f757f3fSDimitry Andric
2125f757f3fSDimitry Andric /// Propagates types, then perform type inference and do a second round of
2135f757f3fSDimitry Andric /// propagation in the apply patterns only if any types were inferred.
2145f757f3fSDimitry Andric void propagateAndInferTypes();
2155f757f3fSDimitry Andric
2165f757f3fSDimitry Andric private:
2175f757f3fSDimitry Andric /// TypeEquivalenceClasses are groups of operands of an instruction that share
2185f757f3fSDimitry Andric /// a common type.
2195f757f3fSDimitry Andric ///
2205f757f3fSDimitry Andric /// e.g. [[a, b], [c, d]] means a and b have the same type, and c and
2215f757f3fSDimitry Andric /// d have the same type too. b/c and a/d don't have to have the same type,
2225f757f3fSDimitry Andric /// though.
2235f757f3fSDimitry Andric using TypeEquivalenceClasses = EquivalenceClasses<StringRef>;
2245f757f3fSDimitry Andric
2255f757f3fSDimitry Andric /// \returns true for `OPERAND_GENERIC_` 0 through 5.
2265f757f3fSDimitry Andric /// These are the MCOI types that can be registers. The other MCOI types are
2275f757f3fSDimitry Andric /// either immediates, or fancier operands used only post-ISel, so we don't
2285f757f3fSDimitry Andric /// care about them for combiners.
canMCOIOperandTypeBeARegister(StringRef MCOIType)2295f757f3fSDimitry Andric static bool canMCOIOperandTypeBeARegister(StringRef MCOIType) {
2305f757f3fSDimitry Andric // Assume OPERAND_GENERIC_0 through 5 can be registers. The other MCOI
2315f757f3fSDimitry Andric // OperandTypes are either never used in gMIR, or not relevant (e.g.
2325f757f3fSDimitry Andric // OPERAND_GENERIC_IMM, which is definitely never a register).
2335f757f3fSDimitry Andric return MCOIType.drop_back(1).ends_with("OPERAND_GENERIC_");
2345f757f3fSDimitry Andric }
2355f757f3fSDimitry Andric
2365f757f3fSDimitry Andric /// Finds the "MCOI::"" operand types for each operand of \p CGP.
2375f757f3fSDimitry Andric ///
2385f757f3fSDimitry Andric /// This is a bit trickier than it looks because we need to handle variadic
2395f757f3fSDimitry Andric /// in/outs.
2405f757f3fSDimitry Andric ///
2415f757f3fSDimitry Andric /// e.g. for
2425f757f3fSDimitry Andric /// (G_BUILD_VECTOR $vec, $x, $y) ->
2435f757f3fSDimitry Andric /// [MCOI::OPERAND_GENERIC_0, MCOI::OPERAND_GENERIC_1,
2445f757f3fSDimitry Andric /// MCOI::OPERAND_GENERIC_1]
2455f757f3fSDimitry Andric ///
2465f757f3fSDimitry Andric /// For unknown types (which can happen in variadics where varargs types are
2475f757f3fSDimitry Andric /// inconsistent), a unique name is given, e.g. "unknown_type_0".
2485f757f3fSDimitry Andric static std::vector<std::string>
2495f757f3fSDimitry Andric getMCOIOperandTypes(const CodeGenInstructionPattern &CGP);
2505f757f3fSDimitry Andric
2515f757f3fSDimitry Andric /// Adds the TypeEquivalenceClasses for \p P in \p OutTECs.
2525f757f3fSDimitry Andric void getInstEqClasses(const InstructionPattern &P,
2535f757f3fSDimitry Andric TypeEquivalenceClasses &OutTECs) const;
2545f757f3fSDimitry Andric
2555f757f3fSDimitry Andric /// Calls `getInstEqClasses` on all patterns of the rule to produce the whole
2565f757f3fSDimitry Andric /// rule's TypeEquivalenceClasses.
2575f757f3fSDimitry Andric TypeEquivalenceClasses getRuleEqClasses() const;
2585f757f3fSDimitry Andric
2595f757f3fSDimitry Andric /// Tries to infer the type of the \p ImmOpIdx -th operand of \p IP using \p
2605f757f3fSDimitry Andric /// TECs.
2615f757f3fSDimitry Andric ///
2625f757f3fSDimitry Andric /// This is achieved by trying to find a named operand in \p IP that shares
2635f757f3fSDimitry Andric /// the same type as \p ImmOpIdx, and using \ref inferNamedOperandType on that
2645f757f3fSDimitry Andric /// operand instead.
2655f757f3fSDimitry Andric ///
2665f757f3fSDimitry Andric /// \returns the inferred type or an empty PatternType if inference didn't
2675f757f3fSDimitry Andric /// succeed.
2685f757f3fSDimitry Andric PatternType inferImmediateType(const InstructionPattern &IP,
2695f757f3fSDimitry Andric unsigned ImmOpIdx,
2705f757f3fSDimitry Andric const TypeEquivalenceClasses &TECs) const;
2715f757f3fSDimitry Andric
2725f757f3fSDimitry Andric /// Looks inside \p TECs to infer \p OpName's type.
2735f757f3fSDimitry Andric ///
2745f757f3fSDimitry Andric /// \returns the inferred type or an empty PatternType if inference didn't
2755f757f3fSDimitry Andric /// succeed.
2765f757f3fSDimitry Andric PatternType inferNamedOperandType(const InstructionPattern &IP,
2775f757f3fSDimitry Andric StringRef OpName,
2781db9f3b2SDimitry Andric const TypeEquivalenceClasses &TECs,
2791db9f3b2SDimitry Andric bool AllowSelf = false) const;
2805f757f3fSDimitry Andric
2815f757f3fSDimitry Andric const Record &RuleDef;
2825f757f3fSDimitry Andric SmallVector<InstructionPattern *, 8> MatchPats;
2835f757f3fSDimitry Andric SmallVector<InstructionPattern *, 8> ApplyPats;
2845f757f3fSDimitry Andric
2855f757f3fSDimitry Andric const OperandTable &MatchOpTable;
2865f757f3fSDimitry Andric };
2875f757f3fSDimitry Andric
processMatchPattern(InstructionPattern & P)2885f757f3fSDimitry Andric bool CombineRuleOperandTypeChecker::processMatchPattern(InstructionPattern &P) {
2895f757f3fSDimitry Andric MatchPats.push_back(&P);
2905f757f3fSDimitry Andric return check(P, /*CheckTypeOf*/ [](const auto &) {
2915f757f3fSDimitry Andric // GITypeOf in 'match' is currently always rejected by the
2925f757f3fSDimitry Andric // CombineRuleBuilder after inference is done.
2935f757f3fSDimitry Andric return true;
2945f757f3fSDimitry Andric });
2955f757f3fSDimitry Andric }
2965f757f3fSDimitry Andric
processApplyPattern(InstructionPattern & P)2975f757f3fSDimitry Andric bool CombineRuleOperandTypeChecker::processApplyPattern(InstructionPattern &P) {
2985f757f3fSDimitry Andric ApplyPats.push_back(&P);
2995f757f3fSDimitry Andric return check(P, /*CheckTypeOf*/ [&](const PatternType &Ty) {
3005f757f3fSDimitry Andric // GITypeOf<"$x"> can only be used if "$x" is a matched operand.
3015f757f3fSDimitry Andric const auto OpName = Ty.getTypeOfOpName();
3025f757f3fSDimitry Andric if (MatchOpTable.lookup(OpName).Found)
3035f757f3fSDimitry Andric return true;
3045f757f3fSDimitry Andric
3055f757f3fSDimitry Andric PrintError(RuleDef.getLoc(), "'" + OpName + "' ('" + Ty.str() +
3065f757f3fSDimitry Andric "') does not refer to a matched operand!");
3075f757f3fSDimitry Andric return false;
3085f757f3fSDimitry Andric });
3095f757f3fSDimitry Andric }
3105f757f3fSDimitry Andric
propagateAndInferTypes()3115f757f3fSDimitry Andric void CombineRuleOperandTypeChecker::propagateAndInferTypes() {
3125f757f3fSDimitry Andric /// First step here is to propagate types using the OperandTypeChecker. That
3135f757f3fSDimitry Andric /// way we ensure all uses of a given register have consistent types.
3145f757f3fSDimitry Andric propagateTypes();
3155f757f3fSDimitry Andric
3165f757f3fSDimitry Andric /// Build the TypeEquivalenceClasses for the whole rule.
3175f757f3fSDimitry Andric const TypeEquivalenceClasses TECs = getRuleEqClasses();
3185f757f3fSDimitry Andric
3195f757f3fSDimitry Andric /// Look at the apply patterns and find operands that need to be
3205f757f3fSDimitry Andric /// inferred. We then try to find an equivalence class that they're a part of
3215f757f3fSDimitry Andric /// and select the best operand to use for the `GITypeOf` type. We prioritize
3225f757f3fSDimitry Andric /// defs of matched instructions because those are guaranteed to be registers.
3235f757f3fSDimitry Andric bool InferredAny = false;
3245f757f3fSDimitry Andric for (auto *Pat : ApplyPats) {
3255f757f3fSDimitry Andric for (unsigned K = 0; K < Pat->operands_size(); ++K) {
3265f757f3fSDimitry Andric auto &Op = Pat->getOperand(K);
3275f757f3fSDimitry Andric
3285f757f3fSDimitry Andric // We only want to take a look at untyped defs or immediates.
3295f757f3fSDimitry Andric if ((!Op.isDef() && !Op.hasImmValue()) || Op.getType())
3305f757f3fSDimitry Andric continue;
3315f757f3fSDimitry Andric
3325f757f3fSDimitry Andric // Infer defs & named immediates.
3335f757f3fSDimitry Andric if (Op.isDef() || Op.isNamedImmediate()) {
3345f757f3fSDimitry Andric // Check it's not a redefinition of a matched operand.
3355f757f3fSDimitry Andric // In such cases, inference is not necessary because we just copy
3365f757f3fSDimitry Andric // operands and don't create temporary registers.
3375f757f3fSDimitry Andric if (MatchOpTable.lookup(Op.getOperandName()).Found)
3385f757f3fSDimitry Andric continue;
3395f757f3fSDimitry Andric
3405f757f3fSDimitry Andric // Inference is needed here, so try to do it.
3415f757f3fSDimitry Andric if (PatternType Ty =
3425f757f3fSDimitry Andric inferNamedOperandType(*Pat, Op.getOperandName(), TECs)) {
3435f757f3fSDimitry Andric if (DebugTypeInfer)
3445f757f3fSDimitry Andric errs() << "INFER: " << Op.describe() << " -> " << Ty.str() << '\n';
3455f757f3fSDimitry Andric Op.setType(Ty);
3465f757f3fSDimitry Andric InferredAny = true;
3475f757f3fSDimitry Andric }
3485f757f3fSDimitry Andric
3495f757f3fSDimitry Andric continue;
3505f757f3fSDimitry Andric }
3515f757f3fSDimitry Andric
3525f757f3fSDimitry Andric // Infer immediates
3535f757f3fSDimitry Andric if (Op.hasImmValue()) {
3545f757f3fSDimitry Andric if (PatternType Ty = inferImmediateType(*Pat, K, TECs)) {
3555f757f3fSDimitry Andric if (DebugTypeInfer)
3565f757f3fSDimitry Andric errs() << "INFER: " << Op.describe() << " -> " << Ty.str() << '\n';
3575f757f3fSDimitry Andric Op.setType(Ty);
3585f757f3fSDimitry Andric InferredAny = true;
3595f757f3fSDimitry Andric }
3605f757f3fSDimitry Andric continue;
3615f757f3fSDimitry Andric }
3625f757f3fSDimitry Andric }
3635f757f3fSDimitry Andric }
3645f757f3fSDimitry Andric
3655f757f3fSDimitry Andric // If we've inferred any types, we want to propagate them across the apply
3665f757f3fSDimitry Andric // patterns. Type inference only adds GITypeOf types that point to Matched
3675f757f3fSDimitry Andric // operands, so we definitely don't want to propagate types into the match
3685f757f3fSDimitry Andric // patterns as well, otherwise bad things happen.
3695f757f3fSDimitry Andric if (InferredAny) {
3705f757f3fSDimitry Andric OperandTypeChecker OTC(RuleDef.getLoc());
3715f757f3fSDimitry Andric for (auto *Pat : ApplyPats) {
3725f757f3fSDimitry Andric if (!OTC.check(*Pat, [&](const auto &) { return true; }))
3735f757f3fSDimitry Andric PrintFatalError(RuleDef.getLoc(),
3745f757f3fSDimitry Andric "OperandTypeChecker unexpectedly failed on '" +
3755f757f3fSDimitry Andric Pat->getName() + "' during Type Inference");
3765f757f3fSDimitry Andric }
3775f757f3fSDimitry Andric OTC.propagateTypes();
3785f757f3fSDimitry Andric
3795f757f3fSDimitry Andric if (DebugTypeInfer) {
3805f757f3fSDimitry Andric errs() << "Apply patterns for rule " << RuleDef.getName()
3815f757f3fSDimitry Andric << " after inference:\n";
3825f757f3fSDimitry Andric for (auto *Pat : ApplyPats) {
3835f757f3fSDimitry Andric errs() << " ";
3845f757f3fSDimitry Andric Pat->print(errs(), /*PrintName*/ true);
3855f757f3fSDimitry Andric errs() << '\n';
3865f757f3fSDimitry Andric }
3875f757f3fSDimitry Andric errs() << '\n';
3885f757f3fSDimitry Andric }
3895f757f3fSDimitry Andric }
3905f757f3fSDimitry Andric }
3915f757f3fSDimitry Andric
inferImmediateType(const InstructionPattern & IP,unsigned ImmOpIdx,const TypeEquivalenceClasses & TECs) const3925f757f3fSDimitry Andric PatternType CombineRuleOperandTypeChecker::inferImmediateType(
3935f757f3fSDimitry Andric const InstructionPattern &IP, unsigned ImmOpIdx,
3945f757f3fSDimitry Andric const TypeEquivalenceClasses &TECs) const {
395*0fca6ea1SDimitry Andric // We can only infer CGPs (except intrinsics).
3965f757f3fSDimitry Andric const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&IP);
397*0fca6ea1SDimitry Andric if (!CGP || CGP->isIntrinsic())
3985f757f3fSDimitry Andric return {};
3995f757f3fSDimitry Andric
4005f757f3fSDimitry Andric // For CGPs, we try to infer immediates by trying to infer another named
4015f757f3fSDimitry Andric // operand that shares its type.
4025f757f3fSDimitry Andric //
4035f757f3fSDimitry Andric // e.g.
4045f757f3fSDimitry Andric // Pattern: G_BUILD_VECTOR $x, $y, 0
4055f757f3fSDimitry Andric // MCOIs: [MCOI::OPERAND_GENERIC_0, MCOI::OPERAND_GENERIC_1,
4065f757f3fSDimitry Andric // MCOI::OPERAND_GENERIC_1]
4075f757f3fSDimitry Andric // $y has the same type as 0, so we can infer $y and get the type 0 should
4085f757f3fSDimitry Andric // have.
4095f757f3fSDimitry Andric
4105f757f3fSDimitry Andric // We infer immediates by looking for a named operand that shares the same
4115f757f3fSDimitry Andric // MCOI type.
4125f757f3fSDimitry Andric const auto MCOITypes = getMCOIOperandTypes(*CGP);
4135f757f3fSDimitry Andric StringRef ImmOpTy = MCOITypes[ImmOpIdx];
4145f757f3fSDimitry Andric
4155f757f3fSDimitry Andric for (const auto &[Idx, Ty] : enumerate(MCOITypes)) {
4165f757f3fSDimitry Andric if (Idx != ImmOpIdx && Ty == ImmOpTy) {
4175f757f3fSDimitry Andric const auto &Op = IP.getOperand(Idx);
4185f757f3fSDimitry Andric if (!Op.isNamedOperand())
4195f757f3fSDimitry Andric continue;
4205f757f3fSDimitry Andric
4215f757f3fSDimitry Andric // Named operand with the same name, try to infer that.
4221db9f3b2SDimitry Andric if (PatternType InferTy = inferNamedOperandType(IP, Op.getOperandName(),
4231db9f3b2SDimitry Andric TECs, /*AllowSelf=*/true))
4245f757f3fSDimitry Andric return InferTy;
4255f757f3fSDimitry Andric }
4265f757f3fSDimitry Andric }
4275f757f3fSDimitry Andric
4285f757f3fSDimitry Andric return {};
4295f757f3fSDimitry Andric }
4305f757f3fSDimitry Andric
inferNamedOperandType(const InstructionPattern & IP,StringRef OpName,const TypeEquivalenceClasses & TECs,bool AllowSelf) const4315f757f3fSDimitry Andric PatternType CombineRuleOperandTypeChecker::inferNamedOperandType(
4325f757f3fSDimitry Andric const InstructionPattern &IP, StringRef OpName,
4331db9f3b2SDimitry Andric const TypeEquivalenceClasses &TECs, bool AllowSelf) const {
4345f757f3fSDimitry Andric // This is the simplest possible case, we just need to find a TEC that
4351db9f3b2SDimitry Andric // contains OpName. Look at all operands in equivalence class and try to
4361db9f3b2SDimitry Andric // find a suitable one. If `AllowSelf` is true, the operand itself is also
4371db9f3b2SDimitry Andric // considered suitable.
4385f757f3fSDimitry Andric
4395f757f3fSDimitry Andric // Check for a def of a matched pattern. This is guaranteed to always
4405f757f3fSDimitry Andric // be a register so we can blindly use that.
4415f757f3fSDimitry Andric StringRef GoodOpName;
4425f757f3fSDimitry Andric for (auto It = TECs.findLeader(OpName); It != TECs.member_end(); ++It) {
4431db9f3b2SDimitry Andric if (!AllowSelf && *It == OpName)
4445f757f3fSDimitry Andric continue;
4455f757f3fSDimitry Andric
4465f757f3fSDimitry Andric const auto LookupRes = MatchOpTable.lookup(*It);
4475f757f3fSDimitry Andric if (LookupRes.Def) // Favor defs
4485f757f3fSDimitry Andric return PatternType::getTypeOf(*It);
4495f757f3fSDimitry Andric
4505f757f3fSDimitry Andric // Otherwise just save this in case we don't find any def.
4515f757f3fSDimitry Andric if (GoodOpName.empty() && LookupRes.Found)
4525f757f3fSDimitry Andric GoodOpName = *It;
4535f757f3fSDimitry Andric }
4545f757f3fSDimitry Andric
4555f757f3fSDimitry Andric if (!GoodOpName.empty())
4565f757f3fSDimitry Andric return PatternType::getTypeOf(GoodOpName);
4575f757f3fSDimitry Andric
4585f757f3fSDimitry Andric // No good operand found, give up.
4595f757f3fSDimitry Andric return {};
4605f757f3fSDimitry Andric }
4615f757f3fSDimitry Andric
getMCOIOperandTypes(const CodeGenInstructionPattern & CGP)4625f757f3fSDimitry Andric std::vector<std::string> CombineRuleOperandTypeChecker::getMCOIOperandTypes(
4635f757f3fSDimitry Andric const CodeGenInstructionPattern &CGP) {
4645f757f3fSDimitry Andric // FIXME?: Should we cache this? We call it twice when inferring immediates.
4655f757f3fSDimitry Andric
4665f757f3fSDimitry Andric static unsigned UnknownTypeIdx = 0;
4675f757f3fSDimitry Andric
4685f757f3fSDimitry Andric std::vector<std::string> OpTypes;
4695f757f3fSDimitry Andric auto &CGI = CGP.getInst();
4705f757f3fSDimitry Andric Record *VarArgsTy = CGI.TheDef->isSubClassOf("GenericInstruction")
4715f757f3fSDimitry Andric ? CGI.TheDef->getValueAsOptionalDef("variadicOpsType")
4725f757f3fSDimitry Andric : nullptr;
4735f757f3fSDimitry Andric std::string VarArgsTyName =
4745f757f3fSDimitry Andric VarArgsTy ? ("MCOI::" + VarArgsTy->getValueAsString("OperandType")).str()
4755f757f3fSDimitry Andric : ("unknown_type_" + Twine(UnknownTypeIdx++)).str();
4765f757f3fSDimitry Andric
4775f757f3fSDimitry Andric // First, handle defs.
4785f757f3fSDimitry Andric for (unsigned K = 0; K < CGI.Operands.NumDefs; ++K)
4795f757f3fSDimitry Andric OpTypes.push_back(CGI.Operands[K].OperandType);
4805f757f3fSDimitry Andric
4815f757f3fSDimitry Andric // Then, handle variadic defs if there are any.
4825f757f3fSDimitry Andric if (CGP.hasVariadicDefs()) {
4835f757f3fSDimitry Andric for (unsigned K = CGI.Operands.NumDefs; K < CGP.getNumInstDefs(); ++K)
4845f757f3fSDimitry Andric OpTypes.push_back(VarArgsTyName);
4855f757f3fSDimitry Andric }
4865f757f3fSDimitry Andric
4875f757f3fSDimitry Andric // If we had variadic defs, the op idx in the pattern won't match the op idx
4885f757f3fSDimitry Andric // in the CGI anymore.
4895f757f3fSDimitry Andric int CGIOpOffset = int(CGI.Operands.NumDefs) - CGP.getNumInstDefs();
4905f757f3fSDimitry Andric assert(CGP.hasVariadicDefs() ? (CGIOpOffset <= 0) : (CGIOpOffset == 0));
4915f757f3fSDimitry Andric
4925f757f3fSDimitry Andric // Handle all remaining use operands, including variadic ones.
4935f757f3fSDimitry Andric for (unsigned K = CGP.getNumInstDefs(); K < CGP.getNumInstOperands(); ++K) {
4945f757f3fSDimitry Andric unsigned CGIOpIdx = K + CGIOpOffset;
4955f757f3fSDimitry Andric if (CGIOpIdx >= CGI.Operands.size()) {
4965f757f3fSDimitry Andric assert(CGP.isVariadic());
4975f757f3fSDimitry Andric OpTypes.push_back(VarArgsTyName);
4985f757f3fSDimitry Andric } else {
4995f757f3fSDimitry Andric OpTypes.push_back(CGI.Operands[CGIOpIdx].OperandType);
5005f757f3fSDimitry Andric }
5015f757f3fSDimitry Andric }
5025f757f3fSDimitry Andric
5035f757f3fSDimitry Andric assert(OpTypes.size() == CGP.operands_size());
5045f757f3fSDimitry Andric return OpTypes;
5055f757f3fSDimitry Andric }
5065f757f3fSDimitry Andric
getInstEqClasses(const InstructionPattern & P,TypeEquivalenceClasses & OutTECs) const5075f757f3fSDimitry Andric void CombineRuleOperandTypeChecker::getInstEqClasses(
5085f757f3fSDimitry Andric const InstructionPattern &P, TypeEquivalenceClasses &OutTECs) const {
5095f757f3fSDimitry Andric // Determine the TypeEquivalenceClasses by:
5105f757f3fSDimitry Andric // - Getting the MCOI Operand Types.
5115f757f3fSDimitry Andric // - Creating a Map of MCOI Type -> [Operand Indexes]
5125f757f3fSDimitry Andric // - Iterating over the map, filtering types we don't like, and just adding
5135f757f3fSDimitry Andric // the array of Operand Indexes to \p OutTECs.
5145f757f3fSDimitry Andric
515*0fca6ea1SDimitry Andric // We can only do this on CodeGenInstructions that aren't intrinsics. Other
516*0fca6ea1SDimitry Andric // InstructionPatterns have no type inference information associated with
517*0fca6ea1SDimitry Andric // them.
518*0fca6ea1SDimitry Andric // TODO: We could try to extract some info from CodeGenIntrinsic to
519*0fca6ea1SDimitry Andric // guide inference.
520*0fca6ea1SDimitry Andric
5215f757f3fSDimitry Andric // TODO: Could we add some inference information to builtins at least? e.g.
5225f757f3fSDimitry Andric // ReplaceReg should always replace with a reg of the same type, for instance.
5235f757f3fSDimitry Andric // Though, those patterns are often used alone so it might not be worth the
5245f757f3fSDimitry Andric // trouble to infer their types.
5255f757f3fSDimitry Andric auto *CGP = dyn_cast<CodeGenInstructionPattern>(&P);
526*0fca6ea1SDimitry Andric if (!CGP || CGP->isIntrinsic())
5275f757f3fSDimitry Andric return;
5285f757f3fSDimitry Andric
5295f757f3fSDimitry Andric const auto MCOITypes = getMCOIOperandTypes(*CGP);
5305f757f3fSDimitry Andric assert(MCOITypes.size() == P.operands_size());
5315f757f3fSDimitry Andric
532*0fca6ea1SDimitry Andric MapVector<StringRef, SmallVector<unsigned, 0>> TyToOpIdx;
5335f757f3fSDimitry Andric for (const auto &[Idx, Ty] : enumerate(MCOITypes))
5345f757f3fSDimitry Andric TyToOpIdx[Ty].push_back(Idx);
5355f757f3fSDimitry Andric
5365f757f3fSDimitry Andric if (DebugTypeInfer)
5375f757f3fSDimitry Andric errs() << "\tGroups for " << P.getName() << ":\t";
5385f757f3fSDimitry Andric
5395f757f3fSDimitry Andric for (const auto &[Ty, Idxs] : TyToOpIdx) {
5405f757f3fSDimitry Andric if (!canMCOIOperandTypeBeARegister(Ty))
5415f757f3fSDimitry Andric continue;
5425f757f3fSDimitry Andric
5435f757f3fSDimitry Andric if (DebugTypeInfer)
5445f757f3fSDimitry Andric errs() << '[';
5455f757f3fSDimitry Andric StringRef Sep = "";
5465f757f3fSDimitry Andric
5475f757f3fSDimitry Andric // We only collect named operands.
5485f757f3fSDimitry Andric StringRef Leader;
5495f757f3fSDimitry Andric for (unsigned Idx : Idxs) {
5505f757f3fSDimitry Andric const auto &Op = P.getOperand(Idx);
5515f757f3fSDimitry Andric if (!Op.isNamedOperand())
5525f757f3fSDimitry Andric continue;
5535f757f3fSDimitry Andric
5545f757f3fSDimitry Andric const auto OpName = Op.getOperandName();
5555f757f3fSDimitry Andric if (DebugTypeInfer) {
5565f757f3fSDimitry Andric errs() << Sep << OpName;
5575f757f3fSDimitry Andric Sep = ", ";
5585f757f3fSDimitry Andric }
5595f757f3fSDimitry Andric
5605f757f3fSDimitry Andric if (Leader.empty())
5615f757f3fSDimitry Andric OutTECs.insert((Leader = OpName));
5625f757f3fSDimitry Andric else
5635f757f3fSDimitry Andric OutTECs.unionSets(Leader, OpName);
5645f757f3fSDimitry Andric }
5655f757f3fSDimitry Andric
5665f757f3fSDimitry Andric if (DebugTypeInfer)
5675f757f3fSDimitry Andric errs() << "] ";
5685f757f3fSDimitry Andric }
5695f757f3fSDimitry Andric
5705f757f3fSDimitry Andric if (DebugTypeInfer)
5715f757f3fSDimitry Andric errs() << '\n';
5725f757f3fSDimitry Andric }
5735f757f3fSDimitry Andric
5745f757f3fSDimitry Andric CombineRuleOperandTypeChecker::TypeEquivalenceClasses
getRuleEqClasses() const5755f757f3fSDimitry Andric CombineRuleOperandTypeChecker::getRuleEqClasses() const {
5765f757f3fSDimitry Andric StringMap<unsigned> OpNameToEqClassIdx;
5775f757f3fSDimitry Andric TypeEquivalenceClasses TECs;
5785f757f3fSDimitry Andric
5795f757f3fSDimitry Andric if (DebugTypeInfer)
5805f757f3fSDimitry Andric errs() << "Rule Operand Type Equivalence Classes for " << RuleDef.getName()
5815f757f3fSDimitry Andric << ":\n";
5825f757f3fSDimitry Andric
5835f757f3fSDimitry Andric for (const auto *Pat : MatchPats)
5845f757f3fSDimitry Andric getInstEqClasses(*Pat, TECs);
5855f757f3fSDimitry Andric for (const auto *Pat : ApplyPats)
5865f757f3fSDimitry Andric getInstEqClasses(*Pat, TECs);
5875f757f3fSDimitry Andric
5885f757f3fSDimitry Andric if (DebugTypeInfer) {
5895f757f3fSDimitry Andric errs() << "Final Type Equivalence Classes: ";
5905f757f3fSDimitry Andric for (auto ClassIt = TECs.begin(); ClassIt != TECs.end(); ++ClassIt) {
5915f757f3fSDimitry Andric // only print non-empty classes.
5925f757f3fSDimitry Andric if (auto MembIt = TECs.member_begin(ClassIt);
5935f757f3fSDimitry Andric MembIt != TECs.member_end()) {
5945f757f3fSDimitry Andric errs() << '[';
5955f757f3fSDimitry Andric StringRef Sep = "";
5965f757f3fSDimitry Andric for (; MembIt != TECs.member_end(); ++MembIt) {
5975f757f3fSDimitry Andric errs() << Sep << *MembIt;
5985f757f3fSDimitry Andric Sep = ", ";
5995f757f3fSDimitry Andric }
6005f757f3fSDimitry Andric errs() << "] ";
6015f757f3fSDimitry Andric }
6025f757f3fSDimitry Andric }
6035f757f3fSDimitry Andric errs() << '\n';
6045f757f3fSDimitry Andric }
6055f757f3fSDimitry Andric
6065f757f3fSDimitry Andric return TECs;
6075f757f3fSDimitry Andric }
6085f757f3fSDimitry Andric
609*0fca6ea1SDimitry Andric //===- MatchData Handling -------------------------------------------------===//
610*0fca6ea1SDimitry Andric struct MatchDataDef {
MatchDataDef__anon569e2aa20111::MatchDataDef611*0fca6ea1SDimitry Andric MatchDataDef(StringRef Symbol, StringRef Type) : Symbol(Symbol), Type(Type) {}
612*0fca6ea1SDimitry Andric
613*0fca6ea1SDimitry Andric StringRef Symbol;
614*0fca6ea1SDimitry Andric StringRef Type;
615*0fca6ea1SDimitry Andric
616*0fca6ea1SDimitry Andric /// \returns the desired variable name for this MatchData.
getVarName__anon569e2aa20111::MatchDataDef617*0fca6ea1SDimitry Andric std::string getVarName() const {
618*0fca6ea1SDimitry Andric // Add a prefix in case the symbol name is very generic and conflicts with
619*0fca6ea1SDimitry Andric // something else.
620*0fca6ea1SDimitry Andric return "GIMatchData_" + Symbol.str();
621*0fca6ea1SDimitry Andric }
622*0fca6ea1SDimitry Andric };
623*0fca6ea1SDimitry Andric
6245f757f3fSDimitry Andric //===- CombineRuleBuilder -------------------------------------------------===//
6255f757f3fSDimitry Andric
6265f757f3fSDimitry Andric /// Parses combine rule and builds a small intermediate representation to tie
6275f757f3fSDimitry Andric /// patterns together and emit RuleMatchers to match them. This may emit more
6285f757f3fSDimitry Andric /// than one RuleMatcher, e.g. for `wip_match_opcode`.
6295f757f3fSDimitry Andric ///
6305f757f3fSDimitry Andric /// Memory management for `Pattern` objects is done through `std::unique_ptr`.
6315f757f3fSDimitry Andric /// In most cases, there are two stages to a pattern's lifetime:
6325f757f3fSDimitry Andric /// - Creation in a `parse` function
6335f757f3fSDimitry Andric /// - The unique_ptr is stored in a variable, and may be destroyed if the
6345f757f3fSDimitry Andric /// pattern is found to be semantically invalid.
6355f757f3fSDimitry Andric /// - Ownership transfer into a `PatternMap`
6365f757f3fSDimitry Andric /// - Once a pattern is moved into either the map of Match or Apply
6375f757f3fSDimitry Andric /// patterns, it is known to be valid and it never moves back.
6385f757f3fSDimitry Andric class CombineRuleBuilder {
6395f757f3fSDimitry Andric public:
6405f757f3fSDimitry Andric using PatternMap = MapVector<StringRef, std::unique_ptr<Pattern>>;
6415f757f3fSDimitry Andric using PatternAlternatives = DenseMap<const Pattern *, unsigned>;
6425f757f3fSDimitry Andric
CombineRuleBuilder(const CodeGenTarget & CGT,SubtargetFeatureInfoMap & SubtargetFeatures,Record & RuleDef,unsigned ID,std::vector<RuleMatcher> & OutRMs)6435f757f3fSDimitry Andric CombineRuleBuilder(const CodeGenTarget &CGT,
6445f757f3fSDimitry Andric SubtargetFeatureInfoMap &SubtargetFeatures,
6455f757f3fSDimitry Andric Record &RuleDef, unsigned ID,
6465f757f3fSDimitry Andric std::vector<RuleMatcher> &OutRMs)
647*0fca6ea1SDimitry Andric : Parser(CGT, RuleDef.getLoc()), CGT(CGT),
648*0fca6ea1SDimitry Andric SubtargetFeatures(SubtargetFeatures), RuleDef(RuleDef), RuleID(ID),
649*0fca6ea1SDimitry Andric OutRMs(OutRMs) {}
6505f757f3fSDimitry Andric
6515f757f3fSDimitry Andric /// Parses all fields in the RuleDef record.
6525f757f3fSDimitry Andric bool parseAll();
6535f757f3fSDimitry Andric
6545f757f3fSDimitry Andric /// Emits all RuleMatchers into the vector of RuleMatchers passed in the
6555f757f3fSDimitry Andric /// constructor.
6565f757f3fSDimitry Andric bool emitRuleMatchers();
6575f757f3fSDimitry Andric
6585f757f3fSDimitry Andric void print(raw_ostream &OS) const;
dump() const6595f757f3fSDimitry Andric void dump() const { print(dbgs()); }
6605f757f3fSDimitry Andric
6615f757f3fSDimitry Andric /// Debug-only verification of invariants.
6625f757f3fSDimitry Andric #ifndef NDEBUG
6635f757f3fSDimitry Andric void verify() const;
6645f757f3fSDimitry Andric #endif
6655f757f3fSDimitry Andric
6665f757f3fSDimitry Andric private:
getGConstant() const6675f757f3fSDimitry Andric const CodeGenInstruction &getGConstant() const {
6685f757f3fSDimitry Andric return CGT.getInstruction(RuleDef.getRecords().getDef("G_CONSTANT"));
6695f757f3fSDimitry Andric }
6705f757f3fSDimitry Andric
PrintError(Twine Msg) const6715f757f3fSDimitry Andric void PrintError(Twine Msg) const { ::PrintError(&RuleDef, Msg); }
PrintWarning(Twine Msg) const6725f757f3fSDimitry Andric void PrintWarning(Twine Msg) const { ::PrintWarning(RuleDef.getLoc(), Msg); }
PrintNote(Twine Msg) const6735f757f3fSDimitry Andric void PrintNote(Twine Msg) const { ::PrintNote(RuleDef.getLoc(), Msg); }
6745f757f3fSDimitry Andric
6755f757f3fSDimitry Andric void print(raw_ostream &OS, const PatternAlternatives &Alts) const;
6765f757f3fSDimitry Andric
6775f757f3fSDimitry Andric bool addApplyPattern(std::unique_ptr<Pattern> Pat);
6785f757f3fSDimitry Andric bool addMatchPattern(std::unique_ptr<Pattern> Pat);
6795f757f3fSDimitry Andric
6805f757f3fSDimitry Andric /// Adds the expansions from \see MatchDatas to \p CE.
6815f757f3fSDimitry Andric void declareAllMatchDatasExpansions(CodeExpansions &CE) const;
6825f757f3fSDimitry Andric
6835f757f3fSDimitry Andric /// Adds a matcher \p P to \p IM, expanding its code using \p CE.
6845f757f3fSDimitry Andric /// Note that the predicate is added on the last InstructionMatcher.
6855f757f3fSDimitry Andric ///
6865f757f3fSDimitry Andric /// \p Alts is only used if DebugCXXPreds is enabled.
6875f757f3fSDimitry Andric void addCXXPredicate(RuleMatcher &M, const CodeExpansions &CE,
6885f757f3fSDimitry Andric const CXXPattern &P, const PatternAlternatives &Alts);
6895f757f3fSDimitry Andric
6905f757f3fSDimitry Andric bool hasOnlyCXXApplyPatterns() const;
6915f757f3fSDimitry Andric bool hasEraseRoot() const;
6925f757f3fSDimitry Andric
6935f757f3fSDimitry Andric // Infer machine operand types and check their consistency.
6945f757f3fSDimitry Andric bool typecheckPatterns();
6955f757f3fSDimitry Andric
6965f757f3fSDimitry Andric /// For all PatFragPatterns, add a new entry in PatternAlternatives for each
6975f757f3fSDimitry Andric /// PatternList it contains. This is multiplicative, so if we have 2
6985f757f3fSDimitry Andric /// PatFrags with 3 alternatives each, we get 2*3 permutations added to
6995f757f3fSDimitry Andric /// PermutationsToEmit. The "MaxPermutations" field controls how many
7005f757f3fSDimitry Andric /// permutations are allowed before an error is emitted and this function
7015f757f3fSDimitry Andric /// returns false. This is a simple safeguard to prevent combination of
7025f757f3fSDimitry Andric /// PatFrags from generating enormous amounts of rules.
7035f757f3fSDimitry Andric bool buildPermutationsToEmit();
7045f757f3fSDimitry Andric
7055f757f3fSDimitry Andric /// Checks additional semantics of the Patterns.
7065f757f3fSDimitry Andric bool checkSemantics();
7075f757f3fSDimitry Andric
7085f757f3fSDimitry Andric /// Creates a new RuleMatcher with some boilerplate
7095f757f3fSDimitry Andric /// settings/actions/predicates, and and adds it to \p OutRMs.
7105f757f3fSDimitry Andric /// \see addFeaturePredicates too.
7115f757f3fSDimitry Andric ///
7125f757f3fSDimitry Andric /// \param Alts Current set of alternatives, for debug comment.
7135f757f3fSDimitry Andric /// \param AdditionalComment Comment string to be added to the
7145f757f3fSDimitry Andric /// `DebugCommentAction`.
7155f757f3fSDimitry Andric RuleMatcher &addRuleMatcher(const PatternAlternatives &Alts,
7165f757f3fSDimitry Andric Twine AdditionalComment = "");
7175f757f3fSDimitry Andric bool addFeaturePredicates(RuleMatcher &M);
7185f757f3fSDimitry Andric
7195f757f3fSDimitry Andric bool findRoots();
7205f757f3fSDimitry Andric bool buildRuleOperandsTable();
7215f757f3fSDimitry Andric
7225f757f3fSDimitry Andric bool parseDefs(const DagInit &Def);
7235f757f3fSDimitry Andric
7245f757f3fSDimitry Andric bool emitMatchPattern(CodeExpansions &CE, const PatternAlternatives &Alts,
7255f757f3fSDimitry Andric const InstructionPattern &IP);
7265f757f3fSDimitry Andric bool emitMatchPattern(CodeExpansions &CE, const PatternAlternatives &Alts,
7275f757f3fSDimitry Andric const AnyOpcodePattern &AOP);
7285f757f3fSDimitry Andric
7295f757f3fSDimitry Andric bool emitPatFragMatchPattern(CodeExpansions &CE,
7305f757f3fSDimitry Andric const PatternAlternatives &Alts, RuleMatcher &RM,
7315f757f3fSDimitry Andric InstructionMatcher *IM,
7325f757f3fSDimitry Andric const PatFragPattern &PFP,
7335f757f3fSDimitry Andric DenseSet<const Pattern *> &SeenPats);
7345f757f3fSDimitry Andric
7355f757f3fSDimitry Andric bool emitApplyPatterns(CodeExpansions &CE, RuleMatcher &M);
736*0fca6ea1SDimitry Andric bool emitCXXMatchApply(CodeExpansions &CE, RuleMatcher &M,
737*0fca6ea1SDimitry Andric ArrayRef<CXXPattern *> Matchers);
7385f757f3fSDimitry Andric
7395f757f3fSDimitry Andric // Recursively visits InstructionPatterns from P to build up the
7405f757f3fSDimitry Andric // RuleMatcher actions.
7415f757f3fSDimitry Andric bool emitInstructionApplyPattern(CodeExpansions &CE, RuleMatcher &M,
7425f757f3fSDimitry Andric const InstructionPattern &P,
7435f757f3fSDimitry Andric DenseSet<const Pattern *> &SeenPats,
7445f757f3fSDimitry Andric StringMap<unsigned> &OperandToTempRegID);
7455f757f3fSDimitry Andric
7465f757f3fSDimitry Andric bool emitCodeGenInstructionApplyImmOperand(RuleMatcher &M,
7475f757f3fSDimitry Andric BuildMIAction &DstMI,
7485f757f3fSDimitry Andric const CodeGenInstructionPattern &P,
7495f757f3fSDimitry Andric const InstructionOperand &O);
7505f757f3fSDimitry Andric
7515f757f3fSDimitry Andric bool emitBuiltinApplyPattern(CodeExpansions &CE, RuleMatcher &M,
7525f757f3fSDimitry Andric const BuiltinPattern &P,
7535f757f3fSDimitry Andric StringMap<unsigned> &OperandToTempRegID);
7545f757f3fSDimitry Andric
7555f757f3fSDimitry Andric // Recursively visits CodeGenInstructionPattern from P to build up the
7565f757f3fSDimitry Andric // RuleMatcher/InstructionMatcher. May create new InstructionMatchers as
7575f757f3fSDimitry Andric // needed.
7585f757f3fSDimitry Andric using OperandMapperFnRef =
7595f757f3fSDimitry Andric function_ref<InstructionOperand(const InstructionOperand &)>;
7605f757f3fSDimitry Andric using OperandDefLookupFn =
7615f757f3fSDimitry Andric function_ref<const InstructionPattern *(StringRef)>;
7625f757f3fSDimitry Andric bool emitCodeGenInstructionMatchPattern(
7635f757f3fSDimitry Andric CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &M,
7645f757f3fSDimitry Andric InstructionMatcher &IM, const CodeGenInstructionPattern &P,
7655f757f3fSDimitry Andric DenseSet<const Pattern *> &SeenPats, OperandDefLookupFn LookupOperandDef,
__anon569e2aa20702(const auto &O) 7665f757f3fSDimitry Andric OperandMapperFnRef OperandMapper = [](const auto &O) { return O; });
7675f757f3fSDimitry Andric
768*0fca6ea1SDimitry Andric PatternParser Parser;
7695f757f3fSDimitry Andric const CodeGenTarget &CGT;
7705f757f3fSDimitry Andric SubtargetFeatureInfoMap &SubtargetFeatures;
7715f757f3fSDimitry Andric Record &RuleDef;
7725f757f3fSDimitry Andric const unsigned RuleID;
7735f757f3fSDimitry Andric std::vector<RuleMatcher> &OutRMs;
7745f757f3fSDimitry Andric
7755f757f3fSDimitry Andric // For InstructionMatcher::addOperand
7765f757f3fSDimitry Andric unsigned AllocatedTemporariesBaseID = 0;
7775f757f3fSDimitry Andric
7785f757f3fSDimitry Andric /// The root of the pattern.
7795f757f3fSDimitry Andric StringRef RootName;
7805f757f3fSDimitry Andric
7815f757f3fSDimitry Andric /// These maps have ownership of the actual Pattern objects.
7825f757f3fSDimitry Andric /// They both map a Pattern's name to the Pattern instance.
7835f757f3fSDimitry Andric PatternMap MatchPats;
7845f757f3fSDimitry Andric PatternMap ApplyPats;
7855f757f3fSDimitry Andric
7865f757f3fSDimitry Andric /// Operand tables to tie match/apply patterns together.
7875f757f3fSDimitry Andric OperandTable MatchOpTable;
7885f757f3fSDimitry Andric OperandTable ApplyOpTable;
7895f757f3fSDimitry Andric
7905f757f3fSDimitry Andric /// Set by findRoots.
7915f757f3fSDimitry Andric Pattern *MatchRoot = nullptr;
7925f757f3fSDimitry Andric SmallDenseSet<InstructionPattern *, 2> ApplyRoots;
7935f757f3fSDimitry Andric
794*0fca6ea1SDimitry Andric SmallVector<MatchDataDef, 2> MatchDatas;
7955f757f3fSDimitry Andric SmallVector<PatternAlternatives, 1> PermutationsToEmit;
7965f757f3fSDimitry Andric };
7975f757f3fSDimitry Andric
parseAll()7985f757f3fSDimitry Andric bool CombineRuleBuilder::parseAll() {
7995f757f3fSDimitry Andric auto StackTrace = PrettyStackTraceParse(RuleDef);
8005f757f3fSDimitry Andric
8015f757f3fSDimitry Andric if (!parseDefs(*RuleDef.getValueAsDag("Defs")))
8025f757f3fSDimitry Andric return false;
8035f757f3fSDimitry Andric
804*0fca6ea1SDimitry Andric if (!Parser.parsePatternList(
8055f757f3fSDimitry Andric *RuleDef.getValueAsDag("Match"),
8065f757f3fSDimitry Andric [this](auto Pat) { return addMatchPattern(std::move(Pat)); }, "match",
807*0fca6ea1SDimitry Andric (RuleDef.getName() + "_match").str()))
8085f757f3fSDimitry Andric return false;
8095f757f3fSDimitry Andric
810*0fca6ea1SDimitry Andric if (!Parser.parsePatternList(
8115f757f3fSDimitry Andric *RuleDef.getValueAsDag("Apply"),
8125f757f3fSDimitry Andric [this](auto Pat) { return addApplyPattern(std::move(Pat)); }, "apply",
813*0fca6ea1SDimitry Andric (RuleDef.getName() + "_apply").str()))
8145f757f3fSDimitry Andric return false;
8155f757f3fSDimitry Andric
8165f757f3fSDimitry Andric if (!buildRuleOperandsTable() || !typecheckPatterns() || !findRoots() ||
8175f757f3fSDimitry Andric !checkSemantics() || !buildPermutationsToEmit())
8185f757f3fSDimitry Andric return false;
8195f757f3fSDimitry Andric LLVM_DEBUG(verify());
8205f757f3fSDimitry Andric return true;
8215f757f3fSDimitry Andric }
8225f757f3fSDimitry Andric
emitRuleMatchers()8235f757f3fSDimitry Andric bool CombineRuleBuilder::emitRuleMatchers() {
8245f757f3fSDimitry Andric auto StackTrace = PrettyStackTraceEmit(RuleDef);
8255f757f3fSDimitry Andric
8265f757f3fSDimitry Andric assert(MatchRoot);
8275f757f3fSDimitry Andric CodeExpansions CE;
8285f757f3fSDimitry Andric
8295f757f3fSDimitry Andric assert(!PermutationsToEmit.empty());
8305f757f3fSDimitry Andric for (const auto &Alts : PermutationsToEmit) {
8315f757f3fSDimitry Andric switch (MatchRoot->getKind()) {
8325f757f3fSDimitry Andric case Pattern::K_AnyOpcode: {
8335f757f3fSDimitry Andric if (!emitMatchPattern(CE, Alts, *cast<AnyOpcodePattern>(MatchRoot)))
8345f757f3fSDimitry Andric return false;
8355f757f3fSDimitry Andric break;
8365f757f3fSDimitry Andric }
8375f757f3fSDimitry Andric case Pattern::K_PatFrag:
8385f757f3fSDimitry Andric case Pattern::K_Builtin:
8395f757f3fSDimitry Andric case Pattern::K_CodeGenInstruction:
8405f757f3fSDimitry Andric if (!emitMatchPattern(CE, Alts, *cast<InstructionPattern>(MatchRoot)))
8415f757f3fSDimitry Andric return false;
8425f757f3fSDimitry Andric break;
8435f757f3fSDimitry Andric case Pattern::K_CXX:
8445f757f3fSDimitry Andric PrintError("C++ code cannot be the root of a rule!");
8455f757f3fSDimitry Andric return false;
8465f757f3fSDimitry Andric default:
8475f757f3fSDimitry Andric llvm_unreachable("unknown pattern kind!");
8485f757f3fSDimitry Andric }
8495f757f3fSDimitry Andric }
8505f757f3fSDimitry Andric
8515f757f3fSDimitry Andric return true;
8525f757f3fSDimitry Andric }
8535f757f3fSDimitry Andric
print(raw_ostream & OS) const8545f757f3fSDimitry Andric void CombineRuleBuilder::print(raw_ostream &OS) const {
8555f757f3fSDimitry Andric OS << "(CombineRule name:" << RuleDef.getName() << " id:" << RuleID
8565f757f3fSDimitry Andric << " root:" << RootName << '\n';
8575f757f3fSDimitry Andric
8585f757f3fSDimitry Andric if (!MatchDatas.empty()) {
8595f757f3fSDimitry Andric OS << " (MatchDatas\n";
8605f757f3fSDimitry Andric for (const auto &MD : MatchDatas) {
861*0fca6ea1SDimitry Andric OS << " (MatchDataDef symbol:" << MD.Symbol << " type:" << MD.Type
862*0fca6ea1SDimitry Andric << ")\n";
8635f757f3fSDimitry Andric }
8645f757f3fSDimitry Andric OS << " )\n";
8655f757f3fSDimitry Andric }
8665f757f3fSDimitry Andric
867*0fca6ea1SDimitry Andric const auto &SeenPFs = Parser.getSeenPatFrags();
868*0fca6ea1SDimitry Andric if (!SeenPFs.empty()) {
8695f757f3fSDimitry Andric OS << " (PatFrags\n";
870*0fca6ea1SDimitry Andric for (const auto *PF : Parser.getSeenPatFrags()) {
8715f757f3fSDimitry Andric PF->print(OS, /*Indent=*/" ");
8725f757f3fSDimitry Andric OS << '\n';
8735f757f3fSDimitry Andric }
8745f757f3fSDimitry Andric OS << " )\n";
8755f757f3fSDimitry Andric }
8765f757f3fSDimitry Andric
8775f757f3fSDimitry Andric const auto DumpPats = [&](StringRef Name, const PatternMap &Pats) {
8785f757f3fSDimitry Andric OS << " (" << Name << " ";
8795f757f3fSDimitry Andric if (Pats.empty()) {
8805f757f3fSDimitry Andric OS << "<empty>)\n";
8815f757f3fSDimitry Andric return;
8825f757f3fSDimitry Andric }
8835f757f3fSDimitry Andric
8845f757f3fSDimitry Andric OS << '\n';
8855f757f3fSDimitry Andric for (const auto &[Name, Pat] : Pats) {
8865f757f3fSDimitry Andric OS << " ";
8875f757f3fSDimitry Andric if (Pat.get() == MatchRoot)
8885f757f3fSDimitry Andric OS << "<match_root>";
8895f757f3fSDimitry Andric if (isa<InstructionPattern>(Pat.get()) &&
8905f757f3fSDimitry Andric ApplyRoots.contains(cast<InstructionPattern>(Pat.get())))
8915f757f3fSDimitry Andric OS << "<apply_root>";
8925f757f3fSDimitry Andric OS << Name << ":";
8935f757f3fSDimitry Andric Pat->print(OS, /*PrintName=*/false);
8945f757f3fSDimitry Andric OS << '\n';
8955f757f3fSDimitry Andric }
8965f757f3fSDimitry Andric OS << " )\n";
8975f757f3fSDimitry Andric };
8985f757f3fSDimitry Andric
8995f757f3fSDimitry Andric DumpPats("MatchPats", MatchPats);
9005f757f3fSDimitry Andric DumpPats("ApplyPats", ApplyPats);
9015f757f3fSDimitry Andric
9025f757f3fSDimitry Andric MatchOpTable.print(OS, "MatchPats", /*Indent*/ " ");
9035f757f3fSDimitry Andric ApplyOpTable.print(OS, "ApplyPats", /*Indent*/ " ");
9045f757f3fSDimitry Andric
9055f757f3fSDimitry Andric if (PermutationsToEmit.size() > 1) {
9065f757f3fSDimitry Andric OS << " (PermutationsToEmit\n";
9075f757f3fSDimitry Andric for (const auto &Perm : PermutationsToEmit) {
9085f757f3fSDimitry Andric OS << " ";
9095f757f3fSDimitry Andric print(OS, Perm);
9105f757f3fSDimitry Andric OS << ",\n";
9115f757f3fSDimitry Andric }
9125f757f3fSDimitry Andric OS << " )\n";
9135f757f3fSDimitry Andric }
9145f757f3fSDimitry Andric
9155f757f3fSDimitry Andric OS << ")\n";
9165f757f3fSDimitry Andric }
9175f757f3fSDimitry Andric
9185f757f3fSDimitry Andric #ifndef NDEBUG
verify() const9195f757f3fSDimitry Andric void CombineRuleBuilder::verify() const {
9205f757f3fSDimitry Andric const auto VerifyPats = [&](const PatternMap &Pats) {
9215f757f3fSDimitry Andric for (const auto &[Name, Pat] : Pats) {
9225f757f3fSDimitry Andric if (!Pat)
9235f757f3fSDimitry Andric PrintFatalError("null pattern in pattern map!");
9245f757f3fSDimitry Andric
9255f757f3fSDimitry Andric if (Name != Pat->getName()) {
9265f757f3fSDimitry Andric Pat->dump();
9275f757f3fSDimitry Andric PrintFatalError("Pattern name mismatch! Map name: " + Name +
9285f757f3fSDimitry Andric ", Pat name: " + Pat->getName());
9295f757f3fSDimitry Andric }
9305f757f3fSDimitry Andric
9315f757f3fSDimitry Andric // Sanity check: the map should point to the same data as the Pattern.
9325f757f3fSDimitry Andric // Both strings are allocated in the pool using insertStrRef.
9335f757f3fSDimitry Andric if (Name.data() != Pat->getName().data()) {
9345f757f3fSDimitry Andric dbgs() << "Map StringRef: '" << Name << "' @ "
9355f757f3fSDimitry Andric << (const void *)Name.data() << '\n';
9365f757f3fSDimitry Andric dbgs() << "Pat String: '" << Pat->getName() << "' @ "
9375f757f3fSDimitry Andric << (const void *)Pat->getName().data() << '\n';
9385f757f3fSDimitry Andric PrintFatalError("StringRef stored in the PatternMap is not referencing "
9395f757f3fSDimitry Andric "the same string as its Pattern!");
9405f757f3fSDimitry Andric }
9415f757f3fSDimitry Andric }
9425f757f3fSDimitry Andric };
9435f757f3fSDimitry Andric
9445f757f3fSDimitry Andric VerifyPats(MatchPats);
9455f757f3fSDimitry Andric VerifyPats(ApplyPats);
9465f757f3fSDimitry Andric
9475f757f3fSDimitry Andric // Check there are no wip_match_opcode patterns in the "apply" patterns.
9485f757f3fSDimitry Andric if (any_of(ApplyPats,
9495f757f3fSDimitry Andric [&](auto &E) { return isa<AnyOpcodePattern>(E.second.get()); })) {
9505f757f3fSDimitry Andric dump();
9515f757f3fSDimitry Andric PrintFatalError(
9525f757f3fSDimitry Andric "illegal wip_match_opcode pattern in the 'apply' patterns!");
9535f757f3fSDimitry Andric }
9545f757f3fSDimitry Andric
9555f757f3fSDimitry Andric // Check there are no nullptrs in ApplyRoots.
9565f757f3fSDimitry Andric if (ApplyRoots.contains(nullptr)) {
9575f757f3fSDimitry Andric PrintFatalError(
9585f757f3fSDimitry Andric "CombineRuleBuilder's ApplyRoots set contains a null pointer!");
9595f757f3fSDimitry Andric }
9605f757f3fSDimitry Andric }
9615f757f3fSDimitry Andric #endif
9625f757f3fSDimitry Andric
print(raw_ostream & OS,const PatternAlternatives & Alts) const9635f757f3fSDimitry Andric void CombineRuleBuilder::print(raw_ostream &OS,
9645f757f3fSDimitry Andric const PatternAlternatives &Alts) const {
9655f757f3fSDimitry Andric SmallVector<std::string, 1> Strings(
9665f757f3fSDimitry Andric map_range(Alts, [](const auto &PatAndPerm) {
9675f757f3fSDimitry Andric return PatAndPerm.first->getName().str() + "[" +
9685f757f3fSDimitry Andric to_string(PatAndPerm.second) + "]";
9695f757f3fSDimitry Andric }));
9705f757f3fSDimitry Andric // Sort so output is deterministic for tests. Otherwise it's sorted by pointer
9715f757f3fSDimitry Andric // values.
9725f757f3fSDimitry Andric sort(Strings);
9735f757f3fSDimitry Andric OS << "[" << join(Strings, ", ") << "]";
9745f757f3fSDimitry Andric }
9755f757f3fSDimitry Andric
addApplyPattern(std::unique_ptr<Pattern> Pat)9765f757f3fSDimitry Andric bool CombineRuleBuilder::addApplyPattern(std::unique_ptr<Pattern> Pat) {
9775f757f3fSDimitry Andric StringRef Name = Pat->getName();
9785f757f3fSDimitry Andric if (ApplyPats.contains(Name)) {
9795f757f3fSDimitry Andric PrintError("'" + Name + "' apply pattern defined more than once!");
9805f757f3fSDimitry Andric return false;
9815f757f3fSDimitry Andric }
9825f757f3fSDimitry Andric
9835f757f3fSDimitry Andric if (isa<AnyOpcodePattern>(Pat.get())) {
9845f757f3fSDimitry Andric PrintError("'" + Name +
9855f757f3fSDimitry Andric "': wip_match_opcode is not supported in apply patterns");
9865f757f3fSDimitry Andric return false;
9875f757f3fSDimitry Andric }
9885f757f3fSDimitry Andric
9895f757f3fSDimitry Andric if (isa<PatFragPattern>(Pat.get())) {
9905f757f3fSDimitry Andric PrintError("'" + Name + "': using " + PatFrag::ClassName +
9915f757f3fSDimitry Andric " is not supported in apply patterns");
9925f757f3fSDimitry Andric return false;
9935f757f3fSDimitry Andric }
9945f757f3fSDimitry Andric
9955f757f3fSDimitry Andric if (auto *CXXPat = dyn_cast<CXXPattern>(Pat.get()))
9965f757f3fSDimitry Andric CXXPat->setIsApply();
9975f757f3fSDimitry Andric
9985f757f3fSDimitry Andric ApplyPats[Name] = std::move(Pat);
9995f757f3fSDimitry Andric return true;
10005f757f3fSDimitry Andric }
10015f757f3fSDimitry Andric
addMatchPattern(std::unique_ptr<Pattern> Pat)10025f757f3fSDimitry Andric bool CombineRuleBuilder::addMatchPattern(std::unique_ptr<Pattern> Pat) {
10035f757f3fSDimitry Andric StringRef Name = Pat->getName();
10045f757f3fSDimitry Andric if (MatchPats.contains(Name)) {
10055f757f3fSDimitry Andric PrintError("'" + Name + "' match pattern defined more than once!");
10065f757f3fSDimitry Andric return false;
10075f757f3fSDimitry Andric }
10085f757f3fSDimitry Andric
10095f757f3fSDimitry Andric // For now, none of the builtins can appear in 'match'.
10105f757f3fSDimitry Andric if (const auto *BP = dyn_cast<BuiltinPattern>(Pat.get())) {
10115f757f3fSDimitry Andric PrintError("'" + BP->getInstName() +
10125f757f3fSDimitry Andric "' cannot be used in a 'match' pattern");
10135f757f3fSDimitry Andric return false;
10145f757f3fSDimitry Andric }
10155f757f3fSDimitry Andric
10165f757f3fSDimitry Andric MatchPats[Name] = std::move(Pat);
10175f757f3fSDimitry Andric return true;
10185f757f3fSDimitry Andric }
10195f757f3fSDimitry Andric
declareAllMatchDatasExpansions(CodeExpansions & CE) const10205f757f3fSDimitry Andric void CombineRuleBuilder::declareAllMatchDatasExpansions(
10215f757f3fSDimitry Andric CodeExpansions &CE) const {
10225f757f3fSDimitry Andric for (const auto &MD : MatchDatas)
1023*0fca6ea1SDimitry Andric CE.declare(MD.Symbol, MD.getVarName());
10245f757f3fSDimitry Andric }
10255f757f3fSDimitry Andric
addCXXPredicate(RuleMatcher & M,const CodeExpansions & CE,const CXXPattern & P,const PatternAlternatives & Alts)10265f757f3fSDimitry Andric void CombineRuleBuilder::addCXXPredicate(RuleMatcher &M,
10275f757f3fSDimitry Andric const CodeExpansions &CE,
10285f757f3fSDimitry Andric const CXXPattern &P,
10295f757f3fSDimitry Andric const PatternAlternatives &Alts) {
10305f757f3fSDimitry Andric // FIXME: Hack so C++ code is executed last. May not work for more complex
10315f757f3fSDimitry Andric // patterns.
10325f757f3fSDimitry Andric auto &IM = *std::prev(M.insnmatchers().end());
10335f757f3fSDimitry Andric auto Loc = RuleDef.getLoc();
10345f757f3fSDimitry Andric const auto AddComment = [&](raw_ostream &OS) {
10355f757f3fSDimitry Andric OS << "// Pattern Alternatives: ";
10365f757f3fSDimitry Andric print(OS, Alts);
10375f757f3fSDimitry Andric OS << '\n';
10385f757f3fSDimitry Andric };
10395f757f3fSDimitry Andric const auto &ExpandedCode =
10405f757f3fSDimitry Andric DebugCXXPreds ? P.expandCode(CE, Loc, AddComment) : P.expandCode(CE, Loc);
10415f757f3fSDimitry Andric IM->addPredicate<GenericInstructionPredicateMatcher>(
10425f757f3fSDimitry Andric ExpandedCode.getEnumNameWithPrefix(CXXPredPrefix));
10435f757f3fSDimitry Andric }
10445f757f3fSDimitry Andric
hasOnlyCXXApplyPatterns() const10455f757f3fSDimitry Andric bool CombineRuleBuilder::hasOnlyCXXApplyPatterns() const {
10465f757f3fSDimitry Andric return all_of(ApplyPats, [&](auto &Entry) {
10475f757f3fSDimitry Andric return isa<CXXPattern>(Entry.second.get());
10485f757f3fSDimitry Andric });
10495f757f3fSDimitry Andric }
10505f757f3fSDimitry Andric
hasEraseRoot() const10515f757f3fSDimitry Andric bool CombineRuleBuilder::hasEraseRoot() const {
10525f757f3fSDimitry Andric return any_of(ApplyPats, [&](auto &Entry) {
10535f757f3fSDimitry Andric if (const auto *BP = dyn_cast<BuiltinPattern>(Entry.second.get()))
10545f757f3fSDimitry Andric return BP->getBuiltinKind() == BI_EraseRoot;
10555f757f3fSDimitry Andric return false;
10565f757f3fSDimitry Andric });
10575f757f3fSDimitry Andric }
10585f757f3fSDimitry Andric
typecheckPatterns()10595f757f3fSDimitry Andric bool CombineRuleBuilder::typecheckPatterns() {
10605f757f3fSDimitry Andric CombineRuleOperandTypeChecker OTC(RuleDef, MatchOpTable);
10615f757f3fSDimitry Andric
10625f757f3fSDimitry Andric for (auto &Pat : values(MatchPats)) {
10635f757f3fSDimitry Andric if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
10645f757f3fSDimitry Andric if (!OTC.processMatchPattern(*IP))
10655f757f3fSDimitry Andric return false;
10665f757f3fSDimitry Andric }
10675f757f3fSDimitry Andric }
10685f757f3fSDimitry Andric
10695f757f3fSDimitry Andric for (auto &Pat : values(ApplyPats)) {
10705f757f3fSDimitry Andric if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
10715f757f3fSDimitry Andric if (!OTC.processApplyPattern(*IP))
10725f757f3fSDimitry Andric return false;
10735f757f3fSDimitry Andric }
10745f757f3fSDimitry Andric }
10755f757f3fSDimitry Andric
10765f757f3fSDimitry Andric OTC.propagateAndInferTypes();
10775f757f3fSDimitry Andric
10785f757f3fSDimitry Andric // Always check this after in case inference adds some special types to the
10795f757f3fSDimitry Andric // match patterns.
10805f757f3fSDimitry Andric for (auto &Pat : values(MatchPats)) {
10815f757f3fSDimitry Andric if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
10825f757f3fSDimitry Andric if (IP->diagnoseAllSpecialTypes(
10835f757f3fSDimitry Andric RuleDef.getLoc(), PatternType::SpecialTyClassName +
10845f757f3fSDimitry Andric " is not supported in 'match' patterns")) {
10855f757f3fSDimitry Andric return false;
10865f757f3fSDimitry Andric }
10875f757f3fSDimitry Andric }
10885f757f3fSDimitry Andric }
10895f757f3fSDimitry Andric return true;
10905f757f3fSDimitry Andric }
10915f757f3fSDimitry Andric
buildPermutationsToEmit()10925f757f3fSDimitry Andric bool CombineRuleBuilder::buildPermutationsToEmit() {
10935f757f3fSDimitry Andric PermutationsToEmit.clear();
10945f757f3fSDimitry Andric
10955f757f3fSDimitry Andric // Start with one empty set of alternatives.
10965f757f3fSDimitry Andric PermutationsToEmit.emplace_back();
10975f757f3fSDimitry Andric for (const auto &Pat : values(MatchPats)) {
10985f757f3fSDimitry Andric unsigned NumAlts = 0;
10995f757f3fSDimitry Andric // Note: technically, AnyOpcodePattern also needs permutations, but:
11005f757f3fSDimitry Andric // - We only allow a single one of them in the root.
11015f757f3fSDimitry Andric // - They cannot be mixed with any other pattern other than C++ code.
11025f757f3fSDimitry Andric // So we don't really need to take them into account here. We could, but
11035f757f3fSDimitry Andric // that pattern is a hack anyway and the less it's involved, the better.
11045f757f3fSDimitry Andric if (const auto *PFP = dyn_cast<PatFragPattern>(Pat.get()))
11055f757f3fSDimitry Andric NumAlts = PFP->getPatFrag().num_alternatives();
11065f757f3fSDimitry Andric else
11075f757f3fSDimitry Andric continue;
11085f757f3fSDimitry Andric
11095f757f3fSDimitry Andric // For each pattern that needs permutations, multiply the current set of
11105f757f3fSDimitry Andric // alternatives.
11115f757f3fSDimitry Andric auto CurPerms = PermutationsToEmit;
11125f757f3fSDimitry Andric PermutationsToEmit.clear();
11135f757f3fSDimitry Andric
11145f757f3fSDimitry Andric for (const auto &Perm : CurPerms) {
11155f757f3fSDimitry Andric assert(!Perm.count(Pat.get()) && "Pattern already emitted?");
11165f757f3fSDimitry Andric for (unsigned K = 0; K < NumAlts; ++K) {
11175f757f3fSDimitry Andric PatternAlternatives NewPerm = Perm;
11185f757f3fSDimitry Andric NewPerm[Pat.get()] = K;
11195f757f3fSDimitry Andric PermutationsToEmit.emplace_back(std::move(NewPerm));
11205f757f3fSDimitry Andric }
11215f757f3fSDimitry Andric }
11225f757f3fSDimitry Andric }
11235f757f3fSDimitry Andric
11245f757f3fSDimitry Andric if (int64_t MaxPerms = RuleDef.getValueAsInt("MaxPermutations");
11255f757f3fSDimitry Andric MaxPerms > 0) {
11265f757f3fSDimitry Andric if ((int64_t)PermutationsToEmit.size() > MaxPerms) {
11275f757f3fSDimitry Andric PrintError("cannot emit rule '" + RuleDef.getName() + "'; " +
11285f757f3fSDimitry Andric Twine(PermutationsToEmit.size()) +
11295f757f3fSDimitry Andric " permutations would be emitted, but the max is " +
11305f757f3fSDimitry Andric Twine(MaxPerms));
11315f757f3fSDimitry Andric return false;
11325f757f3fSDimitry Andric }
11335f757f3fSDimitry Andric }
11345f757f3fSDimitry Andric
11355f757f3fSDimitry Andric // Ensure we always have a single empty entry, it simplifies the emission
11365f757f3fSDimitry Andric // logic so it doesn't need to handle the case where there are no perms.
11375f757f3fSDimitry Andric if (PermutationsToEmit.empty()) {
11385f757f3fSDimitry Andric PermutationsToEmit.emplace_back();
11395f757f3fSDimitry Andric return true;
11405f757f3fSDimitry Andric }
11415f757f3fSDimitry Andric
11425f757f3fSDimitry Andric return true;
11435f757f3fSDimitry Andric }
11445f757f3fSDimitry Andric
checkSemantics()11455f757f3fSDimitry Andric bool CombineRuleBuilder::checkSemantics() {
11465f757f3fSDimitry Andric assert(MatchRoot && "Cannot call this before findRoots()");
11475f757f3fSDimitry Andric
11485f757f3fSDimitry Andric bool UsesWipMatchOpcode = false;
11495f757f3fSDimitry Andric for (const auto &Match : MatchPats) {
11505f757f3fSDimitry Andric const auto *Pat = Match.second.get();
11515f757f3fSDimitry Andric
11525f757f3fSDimitry Andric if (const auto *CXXPat = dyn_cast<CXXPattern>(Pat)) {
11535f757f3fSDimitry Andric if (!CXXPat->getRawCode().contains("return "))
11545f757f3fSDimitry Andric PrintWarning("'match' C++ code does not seem to return!");
11555f757f3fSDimitry Andric continue;
11565f757f3fSDimitry Andric }
11575f757f3fSDimitry Andric
11585f757f3fSDimitry Andric // MIFlags in match cannot use the following syntax: (MIFlags $mi)
11595f757f3fSDimitry Andric if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(Pat)) {
11605f757f3fSDimitry Andric if (auto *FI = CGP->getMIFlagsInfo()) {
11615f757f3fSDimitry Andric if (!FI->copy_flags().empty()) {
11625f757f3fSDimitry Andric PrintError(
11635f757f3fSDimitry Andric "'match' patterns cannot refer to flags from other instructions");
11645f757f3fSDimitry Andric PrintNote("MIFlags in '" + CGP->getName() +
11655f757f3fSDimitry Andric "' refer to: " + join(FI->copy_flags(), ", "));
11665f757f3fSDimitry Andric return false;
11675f757f3fSDimitry Andric }
11685f757f3fSDimitry Andric }
11695f757f3fSDimitry Andric }
11705f757f3fSDimitry Andric
11715f757f3fSDimitry Andric const auto *AOP = dyn_cast<AnyOpcodePattern>(Pat);
11725f757f3fSDimitry Andric if (!AOP)
11735f757f3fSDimitry Andric continue;
11745f757f3fSDimitry Andric
11755f757f3fSDimitry Andric if (UsesWipMatchOpcode) {
11765f757f3fSDimitry Andric PrintError("wip_opcode_match can only be present once");
11775f757f3fSDimitry Andric return false;
11785f757f3fSDimitry Andric }
11795f757f3fSDimitry Andric
11805f757f3fSDimitry Andric UsesWipMatchOpcode = true;
11815f757f3fSDimitry Andric }
11825f757f3fSDimitry Andric
1183*0fca6ea1SDimitry Andric std::optional<bool> IsUsingCXXPatterns;
11845f757f3fSDimitry Andric for (const auto &Apply : ApplyPats) {
1185*0fca6ea1SDimitry Andric Pattern *Pat = Apply.second.get();
1186*0fca6ea1SDimitry Andric if (IsUsingCXXPatterns) {
1187*0fca6ea1SDimitry Andric if (*IsUsingCXXPatterns != isa<CXXPattern>(Pat)) {
1188*0fca6ea1SDimitry Andric PrintError("'apply' patterns cannot mix C++ code with other types of "
1189*0fca6ea1SDimitry Andric "patterns");
1190*0fca6ea1SDimitry Andric return false;
1191*0fca6ea1SDimitry Andric }
1192*0fca6ea1SDimitry Andric } else
1193*0fca6ea1SDimitry Andric IsUsingCXXPatterns = isa<CXXPattern>(Pat);
1194*0fca6ea1SDimitry Andric
1195*0fca6ea1SDimitry Andric assert(Pat);
1196*0fca6ea1SDimitry Andric const auto *IP = dyn_cast<InstructionPattern>(Pat);
11975f757f3fSDimitry Andric if (!IP)
11985f757f3fSDimitry Andric continue;
11995f757f3fSDimitry Andric
12005f757f3fSDimitry Andric if (UsesWipMatchOpcode) {
12015f757f3fSDimitry Andric PrintError("cannot use wip_match_opcode in combination with apply "
12025f757f3fSDimitry Andric "instruction patterns!");
12035f757f3fSDimitry Andric return false;
12045f757f3fSDimitry Andric }
12055f757f3fSDimitry Andric
12065f757f3fSDimitry Andric // Check that the insts mentioned in copy_flags exist.
12075f757f3fSDimitry Andric if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(IP)) {
12085f757f3fSDimitry Andric if (auto *FI = CGP->getMIFlagsInfo()) {
12095f757f3fSDimitry Andric for (auto InstName : FI->copy_flags()) {
12105f757f3fSDimitry Andric auto It = MatchPats.find(InstName);
12115f757f3fSDimitry Andric if (It == MatchPats.end()) {
12125f757f3fSDimitry Andric PrintError("unknown instruction '$" + InstName +
12135f757f3fSDimitry Andric "' referenced in MIFlags of '" + CGP->getName() + "'");
12145f757f3fSDimitry Andric return false;
12155f757f3fSDimitry Andric }
12165f757f3fSDimitry Andric
12175f757f3fSDimitry Andric if (!isa<CodeGenInstructionPattern>(It->second.get())) {
12185f757f3fSDimitry Andric PrintError(
12195f757f3fSDimitry Andric "'$" + InstName +
12205f757f3fSDimitry Andric "' does not refer to a CodeGenInstruction in MIFlags of '" +
12215f757f3fSDimitry Andric CGP->getName() + "'");
12225f757f3fSDimitry Andric return false;
12235f757f3fSDimitry Andric }
12245f757f3fSDimitry Andric }
12255f757f3fSDimitry Andric }
12265f757f3fSDimitry Andric }
12275f757f3fSDimitry Andric
12285f757f3fSDimitry Andric const auto *BIP = dyn_cast<BuiltinPattern>(IP);
12295f757f3fSDimitry Andric if (!BIP)
12305f757f3fSDimitry Andric continue;
12315f757f3fSDimitry Andric StringRef Name = BIP->getInstName();
12325f757f3fSDimitry Andric
12335f757f3fSDimitry Andric // (GIEraseInst) has to be the only apply pattern, or it can not be used at
12345f757f3fSDimitry Andric // all. The root cannot have any defs either.
12355f757f3fSDimitry Andric switch (BIP->getBuiltinKind()) {
12365f757f3fSDimitry Andric case BI_EraseRoot: {
12375f757f3fSDimitry Andric if (ApplyPats.size() > 1) {
12385f757f3fSDimitry Andric PrintError(Name + " must be the only 'apply' pattern");
12395f757f3fSDimitry Andric return false;
12405f757f3fSDimitry Andric }
12415f757f3fSDimitry Andric
12425f757f3fSDimitry Andric const auto *IRoot = dyn_cast<CodeGenInstructionPattern>(MatchRoot);
12435f757f3fSDimitry Andric if (!IRoot) {
1244*0fca6ea1SDimitry Andric PrintError(Name + " can only be used if the root is a "
1245*0fca6ea1SDimitry Andric "CodeGenInstruction or Intrinsic");
12465f757f3fSDimitry Andric return false;
12475f757f3fSDimitry Andric }
12485f757f3fSDimitry Andric
12495f757f3fSDimitry Andric if (IRoot->getNumInstDefs() != 0) {
12505f757f3fSDimitry Andric PrintError(Name + " can only be used if on roots that do "
12515f757f3fSDimitry Andric "not have any output operand");
12525f757f3fSDimitry Andric PrintNote("'" + IRoot->getInstName() + "' has " +
12535f757f3fSDimitry Andric Twine(IRoot->getNumInstDefs()) + " output operands");
12545f757f3fSDimitry Andric return false;
12555f757f3fSDimitry Andric }
12565f757f3fSDimitry Andric break;
12575f757f3fSDimitry Andric }
12585f757f3fSDimitry Andric case BI_ReplaceReg: {
12595f757f3fSDimitry Andric // (GIReplaceReg can only be used on the root instruction)
12605f757f3fSDimitry Andric // TODO: When we allow rewriting non-root instructions, also allow this.
12615f757f3fSDimitry Andric StringRef OldRegName = BIP->getOperand(0).getOperandName();
12625f757f3fSDimitry Andric auto *Def = MatchOpTable.getDef(OldRegName);
12635f757f3fSDimitry Andric if (!Def) {
12645f757f3fSDimitry Andric PrintError(Name + " cannot find a matched pattern that defines '" +
12655f757f3fSDimitry Andric OldRegName + "'");
12665f757f3fSDimitry Andric return false;
12675f757f3fSDimitry Andric }
12685f757f3fSDimitry Andric if (MatchOpTable.getDef(OldRegName) != MatchRoot) {
12695f757f3fSDimitry Andric PrintError(Name + " cannot replace '" + OldRegName +
12705f757f3fSDimitry Andric "': this builtin can only replace a register defined by the "
12715f757f3fSDimitry Andric "match root");
12725f757f3fSDimitry Andric return false;
12735f757f3fSDimitry Andric }
12745f757f3fSDimitry Andric break;
12755f757f3fSDimitry Andric }
12765f757f3fSDimitry Andric }
12775f757f3fSDimitry Andric }
12785f757f3fSDimitry Andric
1279*0fca6ea1SDimitry Andric if (!hasOnlyCXXApplyPatterns() && !MatchDatas.empty()) {
1280*0fca6ea1SDimitry Andric PrintError(MatchDataClassName +
1281*0fca6ea1SDimitry Andric " can only be used if 'apply' in entirely written in C++");
1282*0fca6ea1SDimitry Andric return false;
1283*0fca6ea1SDimitry Andric }
1284*0fca6ea1SDimitry Andric
12855f757f3fSDimitry Andric return true;
12865f757f3fSDimitry Andric }
12875f757f3fSDimitry Andric
addRuleMatcher(const PatternAlternatives & Alts,Twine AdditionalComment)12885f757f3fSDimitry Andric RuleMatcher &CombineRuleBuilder::addRuleMatcher(const PatternAlternatives &Alts,
12895f757f3fSDimitry Andric Twine AdditionalComment) {
12905f757f3fSDimitry Andric auto &RM = OutRMs.emplace_back(RuleDef.getLoc());
12915f757f3fSDimitry Andric addFeaturePredicates(RM);
12925f757f3fSDimitry Andric RM.setPermanentGISelFlags(GISF_IgnoreCopies);
12935f757f3fSDimitry Andric RM.addRequiredSimplePredicate(getIsEnabledPredicateEnumName(RuleID));
12945f757f3fSDimitry Andric
12955f757f3fSDimitry Andric std::string Comment;
12965f757f3fSDimitry Andric raw_string_ostream CommentOS(Comment);
12975f757f3fSDimitry Andric CommentOS << "Combiner Rule #" << RuleID << ": " << RuleDef.getName();
12985f757f3fSDimitry Andric if (!Alts.empty()) {
12995f757f3fSDimitry Andric CommentOS << " @ ";
13005f757f3fSDimitry Andric print(CommentOS, Alts);
13015f757f3fSDimitry Andric }
13025f757f3fSDimitry Andric if (!AdditionalComment.isTriviallyEmpty())
13035f757f3fSDimitry Andric CommentOS << "; " << AdditionalComment;
13045f757f3fSDimitry Andric RM.addAction<DebugCommentAction>(Comment);
13055f757f3fSDimitry Andric return RM;
13065f757f3fSDimitry Andric }
13075f757f3fSDimitry Andric
addFeaturePredicates(RuleMatcher & M)13085f757f3fSDimitry Andric bool CombineRuleBuilder::addFeaturePredicates(RuleMatcher &M) {
13095f757f3fSDimitry Andric if (!RuleDef.getValue("Predicates"))
13105f757f3fSDimitry Andric return true;
13115f757f3fSDimitry Andric
13125f757f3fSDimitry Andric ListInit *Preds = RuleDef.getValueAsListInit("Predicates");
13135f757f3fSDimitry Andric for (Init *PI : Preds->getValues()) {
13145f757f3fSDimitry Andric DefInit *Pred = dyn_cast<DefInit>(PI);
13155f757f3fSDimitry Andric if (!Pred)
13165f757f3fSDimitry Andric continue;
13175f757f3fSDimitry Andric
13185f757f3fSDimitry Andric Record *Def = Pred->getDef();
13195f757f3fSDimitry Andric if (!Def->isSubClassOf("Predicate")) {
13205f757f3fSDimitry Andric ::PrintError(Def, "Unknown 'Predicate' Type");
13215f757f3fSDimitry Andric return false;
13225f757f3fSDimitry Andric }
13235f757f3fSDimitry Andric
13245f757f3fSDimitry Andric if (Def->getValueAsString("CondString").empty())
13255f757f3fSDimitry Andric continue;
13265f757f3fSDimitry Andric
13275f757f3fSDimitry Andric if (SubtargetFeatures.count(Def) == 0) {
13285f757f3fSDimitry Andric SubtargetFeatures.emplace(
13295f757f3fSDimitry Andric Def, SubtargetFeatureInfo(Def, SubtargetFeatures.size()));
13305f757f3fSDimitry Andric }
13315f757f3fSDimitry Andric
13325f757f3fSDimitry Andric M.addRequiredFeature(Def);
13335f757f3fSDimitry Andric }
13345f757f3fSDimitry Andric
13355f757f3fSDimitry Andric return true;
13365f757f3fSDimitry Andric }
13375f757f3fSDimitry Andric
findRoots()13385f757f3fSDimitry Andric bool CombineRuleBuilder::findRoots() {
13395f757f3fSDimitry Andric const auto Finish = [&]() {
13405f757f3fSDimitry Andric assert(MatchRoot);
13415f757f3fSDimitry Andric
13425f757f3fSDimitry Andric if (hasOnlyCXXApplyPatterns() || hasEraseRoot())
13435f757f3fSDimitry Andric return true;
13445f757f3fSDimitry Andric
13455f757f3fSDimitry Andric auto *IPRoot = dyn_cast<InstructionPattern>(MatchRoot);
13465f757f3fSDimitry Andric if (!IPRoot)
13475f757f3fSDimitry Andric return true;
13485f757f3fSDimitry Andric
13495f757f3fSDimitry Andric if (IPRoot->getNumInstDefs() == 0) {
13505f757f3fSDimitry Andric // No defs to work with -> find the root using the pattern name.
13515f757f3fSDimitry Andric auto It = ApplyPats.find(RootName);
13525f757f3fSDimitry Andric if (It == ApplyPats.end()) {
13535f757f3fSDimitry Andric PrintError("Cannot find root '" + RootName + "' in apply patterns!");
13545f757f3fSDimitry Andric return false;
13555f757f3fSDimitry Andric }
13565f757f3fSDimitry Andric
13575f757f3fSDimitry Andric auto *ApplyRoot = dyn_cast<InstructionPattern>(It->second.get());
13585f757f3fSDimitry Andric if (!ApplyRoot) {
13595f757f3fSDimitry Andric PrintError("apply pattern root '" + RootName +
13605f757f3fSDimitry Andric "' must be an instruction pattern");
13615f757f3fSDimitry Andric return false;
13625f757f3fSDimitry Andric }
13635f757f3fSDimitry Andric
13645f757f3fSDimitry Andric ApplyRoots.insert(ApplyRoot);
13655f757f3fSDimitry Andric return true;
13665f757f3fSDimitry Andric }
13675f757f3fSDimitry Andric
13685f757f3fSDimitry Andric // Collect all redefinitions of the MatchRoot's defs and put them in
13695f757f3fSDimitry Andric // ApplyRoots.
13705f757f3fSDimitry Andric const auto DefsNeeded = IPRoot->getApplyDefsNeeded();
13715f757f3fSDimitry Andric for (auto &Op : DefsNeeded) {
13725f757f3fSDimitry Andric assert(Op.isDef() && Op.isNamedOperand());
13735f757f3fSDimitry Andric StringRef Name = Op.getOperandName();
13745f757f3fSDimitry Andric
13755f757f3fSDimitry Andric auto *ApplyRedef = ApplyOpTable.getDef(Name);
13765f757f3fSDimitry Andric if (!ApplyRedef) {
13775f757f3fSDimitry Andric PrintError("'" + Name + "' must be redefined in the 'apply' pattern");
13785f757f3fSDimitry Andric return false;
13795f757f3fSDimitry Andric }
13805f757f3fSDimitry Andric
13815f757f3fSDimitry Andric ApplyRoots.insert((InstructionPattern *)ApplyRedef);
13825f757f3fSDimitry Andric }
13835f757f3fSDimitry Andric
13845f757f3fSDimitry Andric if (auto It = ApplyPats.find(RootName); It != ApplyPats.end()) {
13855f757f3fSDimitry Andric if (find(ApplyRoots, It->second.get()) == ApplyRoots.end()) {
13865f757f3fSDimitry Andric PrintError("apply pattern '" + RootName +
13875f757f3fSDimitry Andric "' is supposed to be a root but it does not redefine any of "
13885f757f3fSDimitry Andric "the defs of the match root");
13895f757f3fSDimitry Andric return false;
13905f757f3fSDimitry Andric }
13915f757f3fSDimitry Andric }
13925f757f3fSDimitry Andric
13935f757f3fSDimitry Andric return true;
13945f757f3fSDimitry Andric };
13955f757f3fSDimitry Andric
13965f757f3fSDimitry Andric // Look by pattern name, e.g.
13975f757f3fSDimitry Andric // (G_FNEG $x, $y):$root
13985f757f3fSDimitry Andric if (auto MatchPatIt = MatchPats.find(RootName);
13995f757f3fSDimitry Andric MatchPatIt != MatchPats.end()) {
14005f757f3fSDimitry Andric MatchRoot = MatchPatIt->second.get();
14015f757f3fSDimitry Andric return Finish();
14025f757f3fSDimitry Andric }
14035f757f3fSDimitry Andric
14045f757f3fSDimitry Andric // Look by def:
14055f757f3fSDimitry Andric // (G_FNEG $root, $y)
14065f757f3fSDimitry Andric auto LookupRes = MatchOpTable.lookup(RootName);
14075f757f3fSDimitry Andric if (!LookupRes.Found) {
14085f757f3fSDimitry Andric PrintError("Cannot find root '" + RootName + "' in match patterns!");
14095f757f3fSDimitry Andric return false;
14105f757f3fSDimitry Andric }
14115f757f3fSDimitry Andric
14125f757f3fSDimitry Andric MatchRoot = LookupRes.Def;
14135f757f3fSDimitry Andric if (!MatchRoot) {
14145f757f3fSDimitry Andric PrintError("Cannot use live-in operand '" + RootName +
14155f757f3fSDimitry Andric "' as match pattern root!");
14165f757f3fSDimitry Andric return false;
14175f757f3fSDimitry Andric }
14185f757f3fSDimitry Andric
14195f757f3fSDimitry Andric return Finish();
14205f757f3fSDimitry Andric }
14215f757f3fSDimitry Andric
buildRuleOperandsTable()14225f757f3fSDimitry Andric bool CombineRuleBuilder::buildRuleOperandsTable() {
14235f757f3fSDimitry Andric const auto DiagnoseRedefMatch = [&](StringRef OpName) {
14245f757f3fSDimitry Andric PrintError("Operand '" + OpName +
14255f757f3fSDimitry Andric "' is defined multiple times in the 'match' patterns");
14265f757f3fSDimitry Andric };
14275f757f3fSDimitry Andric
14285f757f3fSDimitry Andric const auto DiagnoseRedefApply = [&](StringRef OpName) {
14295f757f3fSDimitry Andric PrintError("Operand '" + OpName +
14305f757f3fSDimitry Andric "' is defined multiple times in the 'apply' patterns");
14315f757f3fSDimitry Andric };
14325f757f3fSDimitry Andric
14335f757f3fSDimitry Andric for (auto &Pat : values(MatchPats)) {
14345f757f3fSDimitry Andric auto *IP = dyn_cast<InstructionPattern>(Pat.get());
14355f757f3fSDimitry Andric if (IP && !MatchOpTable.addPattern(IP, DiagnoseRedefMatch))
14365f757f3fSDimitry Andric return false;
14375f757f3fSDimitry Andric }
14385f757f3fSDimitry Andric
14395f757f3fSDimitry Andric for (auto &Pat : values(ApplyPats)) {
14405f757f3fSDimitry Andric auto *IP = dyn_cast<InstructionPattern>(Pat.get());
14415f757f3fSDimitry Andric if (IP && !ApplyOpTable.addPattern(IP, DiagnoseRedefApply))
14425f757f3fSDimitry Andric return false;
14435f757f3fSDimitry Andric }
14445f757f3fSDimitry Andric
14455f757f3fSDimitry Andric return true;
14465f757f3fSDimitry Andric }
14475f757f3fSDimitry Andric
parseDefs(const DagInit & Def)14485f757f3fSDimitry Andric bool CombineRuleBuilder::parseDefs(const DagInit &Def) {
14495f757f3fSDimitry Andric if (Def.getOperatorAsDef(RuleDef.getLoc())->getName() != "defs") {
14505f757f3fSDimitry Andric PrintError("Expected defs operator");
14515f757f3fSDimitry Andric return false;
14525f757f3fSDimitry Andric }
14535f757f3fSDimitry Andric
14545f757f3fSDimitry Andric SmallVector<StringRef> Roots;
14555f757f3fSDimitry Andric for (unsigned I = 0, E = Def.getNumArgs(); I < E; ++I) {
14565f757f3fSDimitry Andric if (isSpecificDef(*Def.getArg(I), "root")) {
14575f757f3fSDimitry Andric Roots.emplace_back(Def.getArgNameStr(I));
14585f757f3fSDimitry Andric continue;
14595f757f3fSDimitry Andric }
14605f757f3fSDimitry Andric
14615f757f3fSDimitry Andric // Subclasses of GIDefMatchData should declare that this rule needs to pass
14625f757f3fSDimitry Andric // data from the match stage to the apply stage, and ensure that the
14635f757f3fSDimitry Andric // generated matcher has a suitable variable for it to do so.
14645f757f3fSDimitry Andric if (Record *MatchDataRec =
1465*0fca6ea1SDimitry Andric getDefOfSubClass(*Def.getArg(I), MatchDataClassName)) {
14665f757f3fSDimitry Andric MatchDatas.emplace_back(Def.getArgNameStr(I),
14675f757f3fSDimitry Andric MatchDataRec->getValueAsString("Type"));
14685f757f3fSDimitry Andric continue;
14695f757f3fSDimitry Andric }
14705f757f3fSDimitry Andric
14715f757f3fSDimitry Andric // Otherwise emit an appropriate error message.
14725f757f3fSDimitry Andric if (getDefOfSubClass(*Def.getArg(I), "GIDefKind"))
14735f757f3fSDimitry Andric PrintError("This GIDefKind not implemented in tablegen");
14745f757f3fSDimitry Andric else if (getDefOfSubClass(*Def.getArg(I), "GIDefKindWithArgs"))
14755f757f3fSDimitry Andric PrintError("This GIDefKindWithArgs not implemented in tablegen");
14765f757f3fSDimitry Andric else
14775f757f3fSDimitry Andric PrintError("Expected a subclass of GIDefKind or a sub-dag whose "
14785f757f3fSDimitry Andric "operator is of type GIDefKindWithArgs");
14795f757f3fSDimitry Andric return false;
14805f757f3fSDimitry Andric }
14815f757f3fSDimitry Andric
14825f757f3fSDimitry Andric if (Roots.size() != 1) {
14835f757f3fSDimitry Andric PrintError("Combine rules must have exactly one root");
14845f757f3fSDimitry Andric return false;
14855f757f3fSDimitry Andric }
14865f757f3fSDimitry Andric
14875f757f3fSDimitry Andric RootName = Roots.front();
14885f757f3fSDimitry Andric return true;
14895f757f3fSDimitry Andric }
14905f757f3fSDimitry Andric
emitMatchPattern(CodeExpansions & CE,const PatternAlternatives & Alts,const InstructionPattern & IP)14915f757f3fSDimitry Andric bool CombineRuleBuilder::emitMatchPattern(CodeExpansions &CE,
14925f757f3fSDimitry Andric const PatternAlternatives &Alts,
14935f757f3fSDimitry Andric const InstructionPattern &IP) {
14945f757f3fSDimitry Andric auto StackTrace = PrettyStackTraceEmit(RuleDef, &IP);
14955f757f3fSDimitry Andric
14965f757f3fSDimitry Andric auto &M = addRuleMatcher(Alts);
14975f757f3fSDimitry Andric InstructionMatcher &IM = M.addInstructionMatcher(IP.getName());
14985f757f3fSDimitry Andric declareInstExpansion(CE, IM, IP.getName());
14995f757f3fSDimitry Andric
15005f757f3fSDimitry Andric DenseSet<const Pattern *> SeenPats;
15015f757f3fSDimitry Andric
15025f757f3fSDimitry Andric const auto FindOperandDef = [&](StringRef Op) -> InstructionPattern * {
15035f757f3fSDimitry Andric return MatchOpTable.getDef(Op);
15045f757f3fSDimitry Andric };
15055f757f3fSDimitry Andric
15065f757f3fSDimitry Andric if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&IP)) {
15075f757f3fSDimitry Andric if (!emitCodeGenInstructionMatchPattern(CE, Alts, M, IM, *CGP, SeenPats,
15085f757f3fSDimitry Andric FindOperandDef))
15095f757f3fSDimitry Andric return false;
15105f757f3fSDimitry Andric } else if (const auto *PFP = dyn_cast<PatFragPattern>(&IP)) {
15115f757f3fSDimitry Andric if (!PFP->getPatFrag().canBeMatchRoot()) {
15125f757f3fSDimitry Andric PrintError("cannot use '" + PFP->getInstName() + " as match root");
15135f757f3fSDimitry Andric return false;
15145f757f3fSDimitry Andric }
15155f757f3fSDimitry Andric
15165f757f3fSDimitry Andric if (!emitPatFragMatchPattern(CE, Alts, M, &IM, *PFP, SeenPats))
15175f757f3fSDimitry Andric return false;
15185f757f3fSDimitry Andric } else if (isa<BuiltinPattern>(&IP)) {
15195f757f3fSDimitry Andric llvm_unreachable("No match builtins known!");
15205f757f3fSDimitry Andric } else
15215f757f3fSDimitry Andric llvm_unreachable("Unknown kind of InstructionPattern!");
15225f757f3fSDimitry Andric
15235f757f3fSDimitry Andric // Emit remaining patterns
1524*0fca6ea1SDimitry Andric const bool IsUsingCustomCXXAction = hasOnlyCXXApplyPatterns();
1525*0fca6ea1SDimitry Andric SmallVector<CXXPattern *, 2> CXXMatchers;
15265f757f3fSDimitry Andric for (auto &Pat : values(MatchPats)) {
15275f757f3fSDimitry Andric if (SeenPats.contains(Pat.get()))
15285f757f3fSDimitry Andric continue;
15295f757f3fSDimitry Andric
15305f757f3fSDimitry Andric switch (Pat->getKind()) {
15315f757f3fSDimitry Andric case Pattern::K_AnyOpcode:
15325f757f3fSDimitry Andric PrintError("wip_match_opcode can not be used with instruction patterns!");
15335f757f3fSDimitry Andric return false;
15345f757f3fSDimitry Andric case Pattern::K_PatFrag: {
15355f757f3fSDimitry Andric if (!emitPatFragMatchPattern(CE, Alts, M, /*IM*/ nullptr,
15365f757f3fSDimitry Andric *cast<PatFragPattern>(Pat.get()), SeenPats))
15375f757f3fSDimitry Andric return false;
15385f757f3fSDimitry Andric continue;
15395f757f3fSDimitry Andric }
15405f757f3fSDimitry Andric case Pattern::K_Builtin:
15415f757f3fSDimitry Andric PrintError("No known match builtins");
15425f757f3fSDimitry Andric return false;
15435f757f3fSDimitry Andric case Pattern::K_CodeGenInstruction:
15445f757f3fSDimitry Andric cast<InstructionPattern>(Pat.get())->reportUnreachable(RuleDef.getLoc());
15455f757f3fSDimitry Andric return false;
15465f757f3fSDimitry Andric case Pattern::K_CXX: {
1547*0fca6ea1SDimitry Andric // Delay emission for top-level C++ matchers (which can use MatchDatas).
1548*0fca6ea1SDimitry Andric if (IsUsingCustomCXXAction)
1549*0fca6ea1SDimitry Andric CXXMatchers.push_back(cast<CXXPattern>(Pat.get()));
1550*0fca6ea1SDimitry Andric else
15515f757f3fSDimitry Andric addCXXPredicate(M, CE, *cast<CXXPattern>(Pat.get()), Alts);
15525f757f3fSDimitry Andric continue;
15535f757f3fSDimitry Andric }
15545f757f3fSDimitry Andric default:
15555f757f3fSDimitry Andric llvm_unreachable("unknown pattern kind!");
15565f757f3fSDimitry Andric }
15575f757f3fSDimitry Andric }
15585f757f3fSDimitry Andric
1559*0fca6ea1SDimitry Andric return IsUsingCustomCXXAction ? emitCXXMatchApply(CE, M, CXXMatchers)
1560*0fca6ea1SDimitry Andric : emitApplyPatterns(CE, M);
15615f757f3fSDimitry Andric }
15625f757f3fSDimitry Andric
emitMatchPattern(CodeExpansions & CE,const PatternAlternatives & Alts,const AnyOpcodePattern & AOP)15635f757f3fSDimitry Andric bool CombineRuleBuilder::emitMatchPattern(CodeExpansions &CE,
15645f757f3fSDimitry Andric const PatternAlternatives &Alts,
15655f757f3fSDimitry Andric const AnyOpcodePattern &AOP) {
15665f757f3fSDimitry Andric auto StackTrace = PrettyStackTraceEmit(RuleDef, &AOP);
15675f757f3fSDimitry Andric
1568*0fca6ea1SDimitry Andric const bool IsUsingCustomCXXAction = hasOnlyCXXApplyPatterns();
15695f757f3fSDimitry Andric for (const CodeGenInstruction *CGI : AOP.insts()) {
15705f757f3fSDimitry Andric auto &M = addRuleMatcher(Alts, "wip_match_opcode '" +
15715f757f3fSDimitry Andric CGI->TheDef->getName() + "'");
15725f757f3fSDimitry Andric
15735f757f3fSDimitry Andric InstructionMatcher &IM = M.addInstructionMatcher(AOP.getName());
15745f757f3fSDimitry Andric declareInstExpansion(CE, IM, AOP.getName());
15755f757f3fSDimitry Andric // declareInstExpansion needs to be identical, otherwise we need to create a
15765f757f3fSDimitry Andric // CodeExpansions object here instead.
15775f757f3fSDimitry Andric assert(IM.getInsnVarID() == 0);
15785f757f3fSDimitry Andric
15795f757f3fSDimitry Andric IM.addPredicate<InstructionOpcodeMatcher>(CGI);
15805f757f3fSDimitry Andric
15815f757f3fSDimitry Andric // Emit remaining patterns.
1582*0fca6ea1SDimitry Andric SmallVector<CXXPattern *, 2> CXXMatchers;
15835f757f3fSDimitry Andric for (auto &Pat : values(MatchPats)) {
15845f757f3fSDimitry Andric if (Pat.get() == &AOP)
15855f757f3fSDimitry Andric continue;
15865f757f3fSDimitry Andric
15875f757f3fSDimitry Andric switch (Pat->getKind()) {
15885f757f3fSDimitry Andric case Pattern::K_AnyOpcode:
15895f757f3fSDimitry Andric PrintError("wip_match_opcode can only be present once!");
15905f757f3fSDimitry Andric return false;
15915f757f3fSDimitry Andric case Pattern::K_PatFrag: {
15925f757f3fSDimitry Andric DenseSet<const Pattern *> SeenPats;
15935f757f3fSDimitry Andric if (!emitPatFragMatchPattern(CE, Alts, M, /*IM*/ nullptr,
15945f757f3fSDimitry Andric *cast<PatFragPattern>(Pat.get()),
15955f757f3fSDimitry Andric SeenPats))
15965f757f3fSDimitry Andric return false;
15975f757f3fSDimitry Andric continue;
15985f757f3fSDimitry Andric }
15995f757f3fSDimitry Andric case Pattern::K_Builtin:
16005f757f3fSDimitry Andric PrintError("No known match builtins");
16015f757f3fSDimitry Andric return false;
16025f757f3fSDimitry Andric case Pattern::K_CodeGenInstruction:
16035f757f3fSDimitry Andric cast<InstructionPattern>(Pat.get())->reportUnreachable(
16045f757f3fSDimitry Andric RuleDef.getLoc());
16055f757f3fSDimitry Andric return false;
16065f757f3fSDimitry Andric case Pattern::K_CXX: {
1607*0fca6ea1SDimitry Andric // Delay emission for top-level C++ matchers (which can use MatchDatas).
1608*0fca6ea1SDimitry Andric if (IsUsingCustomCXXAction)
1609*0fca6ea1SDimitry Andric CXXMatchers.push_back(cast<CXXPattern>(Pat.get()));
1610*0fca6ea1SDimitry Andric else
16115f757f3fSDimitry Andric addCXXPredicate(M, CE, *cast<CXXPattern>(Pat.get()), Alts);
16125f757f3fSDimitry Andric break;
16135f757f3fSDimitry Andric }
16145f757f3fSDimitry Andric default:
16155f757f3fSDimitry Andric llvm_unreachable("unknown pattern kind!");
16165f757f3fSDimitry Andric }
16175f757f3fSDimitry Andric }
16185f757f3fSDimitry Andric
1619*0fca6ea1SDimitry Andric const bool Res = IsUsingCustomCXXAction
1620*0fca6ea1SDimitry Andric ? emitCXXMatchApply(CE, M, CXXMatchers)
1621*0fca6ea1SDimitry Andric : emitApplyPatterns(CE, M);
1622*0fca6ea1SDimitry Andric if (!Res)
16235f757f3fSDimitry Andric return false;
16245f757f3fSDimitry Andric }
16255f757f3fSDimitry Andric
16265f757f3fSDimitry Andric return true;
16275f757f3fSDimitry Andric }
16285f757f3fSDimitry Andric
emitPatFragMatchPattern(CodeExpansions & CE,const PatternAlternatives & Alts,RuleMatcher & RM,InstructionMatcher * IM,const PatFragPattern & PFP,DenseSet<const Pattern * > & SeenPats)16295f757f3fSDimitry Andric bool CombineRuleBuilder::emitPatFragMatchPattern(
16305f757f3fSDimitry Andric CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &RM,
16315f757f3fSDimitry Andric InstructionMatcher *IM, const PatFragPattern &PFP,
16325f757f3fSDimitry Andric DenseSet<const Pattern *> &SeenPats) {
16335f757f3fSDimitry Andric auto StackTrace = PrettyStackTraceEmit(RuleDef, &PFP);
16345f757f3fSDimitry Andric
16355f757f3fSDimitry Andric if (SeenPats.contains(&PFP))
16365f757f3fSDimitry Andric return true;
16375f757f3fSDimitry Andric SeenPats.insert(&PFP);
16385f757f3fSDimitry Andric
16395f757f3fSDimitry Andric const auto &PF = PFP.getPatFrag();
16405f757f3fSDimitry Andric
16415f757f3fSDimitry Andric if (!IM) {
16425f757f3fSDimitry Andric // When we don't have an IM, this means this PatFrag isn't reachable from
16435f757f3fSDimitry Andric // the root. This is only acceptable if it doesn't define anything (e.g. a
16445f757f3fSDimitry Andric // pure C++ PatFrag).
16455f757f3fSDimitry Andric if (PF.num_out_params() != 0) {
16465f757f3fSDimitry Andric PFP.reportUnreachable(RuleDef.getLoc());
16475f757f3fSDimitry Andric return false;
16485f757f3fSDimitry Andric }
16495f757f3fSDimitry Andric } else {
16505f757f3fSDimitry Andric // When an IM is provided, this is reachable from the root, and we're
16515f757f3fSDimitry Andric // expecting to have output operands.
16525f757f3fSDimitry Andric // TODO: If we want to allow for multiple roots we'll need a map of IMs
16535f757f3fSDimitry Andric // then, and emission becomes a bit more complicated.
16545f757f3fSDimitry Andric assert(PF.num_roots() == 1);
16555f757f3fSDimitry Andric }
16565f757f3fSDimitry Andric
16575f757f3fSDimitry Andric CodeExpansions PatFragCEs;
16585f757f3fSDimitry Andric if (!PFP.mapInputCodeExpansions(CE, PatFragCEs, RuleDef.getLoc()))
16595f757f3fSDimitry Andric return false;
16605f757f3fSDimitry Andric
16615f757f3fSDimitry Andric // List of {ParamName, ArgName}.
16625f757f3fSDimitry Andric // When all patterns have been emitted, find expansions in PatFragCEs named
16635f757f3fSDimitry Andric // ArgName and add their expansion to CE using ParamName as the key.
16645f757f3fSDimitry Andric SmallVector<std::pair<std::string, std::string>, 4> CEsToImport;
16655f757f3fSDimitry Andric
16665f757f3fSDimitry Andric // Map parameter names to the actual argument.
16675f757f3fSDimitry Andric const auto OperandMapper =
16685f757f3fSDimitry Andric [&](const InstructionOperand &O) -> InstructionOperand {
16695f757f3fSDimitry Andric if (!O.isNamedOperand())
16705f757f3fSDimitry Andric return O;
16715f757f3fSDimitry Andric
16725f757f3fSDimitry Andric StringRef ParamName = O.getOperandName();
16735f757f3fSDimitry Andric
16745f757f3fSDimitry Andric // Not sure what to do with those tbh. They should probably never be here.
16755f757f3fSDimitry Andric assert(!O.isNamedImmediate() && "TODO: handle named imms");
16765f757f3fSDimitry Andric unsigned PIdx = PF.getParamIdx(ParamName);
16775f757f3fSDimitry Andric
16785f757f3fSDimitry Andric // Map parameters to the argument values.
16795f757f3fSDimitry Andric if (PIdx == (unsigned)-1) {
16805f757f3fSDimitry Andric // This is a temp of the PatFragPattern, prefix the name to avoid
16815f757f3fSDimitry Andric // conflicts.
16825f757f3fSDimitry Andric return O.withNewName(
16835f757f3fSDimitry Andric insertStrRef((PFP.getName() + "." + ParamName).str()));
16845f757f3fSDimitry Andric }
16855f757f3fSDimitry Andric
16865f757f3fSDimitry Andric // The operand will be added to PatFragCEs's code expansions using the
16875f757f3fSDimitry Andric // parameter's name. If it's bound to some operand during emission of the
16885f757f3fSDimitry Andric // patterns, we'll want to add it to CE.
16895f757f3fSDimitry Andric auto ArgOp = PFP.getOperand(PIdx);
16905f757f3fSDimitry Andric if (ArgOp.isNamedOperand())
16915f757f3fSDimitry Andric CEsToImport.emplace_back(ArgOp.getOperandName().str(), ParamName);
16925f757f3fSDimitry Andric
16935f757f3fSDimitry Andric if (ArgOp.getType() && O.getType() && ArgOp.getType() != O.getType()) {
16945f757f3fSDimitry Andric StringRef PFName = PF.getName();
16955f757f3fSDimitry Andric PrintWarning("impossible type constraints: operand " + Twine(PIdx) +
16965f757f3fSDimitry Andric " of '" + PFP.getName() + "' has type '" +
16975f757f3fSDimitry Andric ArgOp.getType().str() + "', but '" + PFName +
16985f757f3fSDimitry Andric "' constrains it to '" + O.getType().str() + "'");
16995f757f3fSDimitry Andric if (ArgOp.isNamedOperand())
17005f757f3fSDimitry Andric PrintNote("operand " + Twine(PIdx) + " of '" + PFP.getName() +
17015f757f3fSDimitry Andric "' is '" + ArgOp.getOperandName() + "'");
17025f757f3fSDimitry Andric if (O.isNamedOperand())
17035f757f3fSDimitry Andric PrintNote("argument " + Twine(PIdx) + " of '" + PFName + "' is '" +
17045f757f3fSDimitry Andric ParamName + "'");
17055f757f3fSDimitry Andric }
17065f757f3fSDimitry Andric
17075f757f3fSDimitry Andric return ArgOp;
17085f757f3fSDimitry Andric };
17095f757f3fSDimitry Andric
17105f757f3fSDimitry Andric // PatFragPatterns are only made of InstructionPatterns or CXXPatterns.
17115f757f3fSDimitry Andric // Emit instructions from the root.
17125f757f3fSDimitry Andric const auto &FragAlt = PF.getAlternative(Alts.lookup(&PFP));
17135f757f3fSDimitry Andric const auto &FragAltOT = FragAlt.OpTable;
17145f757f3fSDimitry Andric const auto LookupOperandDef =
17155f757f3fSDimitry Andric [&](StringRef Op) -> const InstructionPattern * {
17165f757f3fSDimitry Andric return FragAltOT.getDef(Op);
17175f757f3fSDimitry Andric };
17185f757f3fSDimitry Andric
17195f757f3fSDimitry Andric DenseSet<const Pattern *> PatFragSeenPats;
17205f757f3fSDimitry Andric for (const auto &[Idx, InOp] : enumerate(PF.out_params())) {
17215f757f3fSDimitry Andric if (InOp.Kind != PatFrag::PK_Root)
17225f757f3fSDimitry Andric continue;
17235f757f3fSDimitry Andric
17245f757f3fSDimitry Andric StringRef ParamName = InOp.Name;
17255f757f3fSDimitry Andric const auto *Def = FragAltOT.getDef(ParamName);
17265f757f3fSDimitry Andric assert(Def && "PatFrag::checkSemantics should have emitted an error if "
17275f757f3fSDimitry Andric "an out operand isn't defined!");
17285f757f3fSDimitry Andric assert(isa<CodeGenInstructionPattern>(Def) &&
17295f757f3fSDimitry Andric "Nested PatFrags not supported yet");
17305f757f3fSDimitry Andric
17315f757f3fSDimitry Andric if (!emitCodeGenInstructionMatchPattern(
17325f757f3fSDimitry Andric PatFragCEs, Alts, RM, *IM, *cast<CodeGenInstructionPattern>(Def),
17335f757f3fSDimitry Andric PatFragSeenPats, LookupOperandDef, OperandMapper))
17345f757f3fSDimitry Andric return false;
17355f757f3fSDimitry Andric }
17365f757f3fSDimitry Andric
17375f757f3fSDimitry Andric // Emit leftovers.
17385f757f3fSDimitry Andric for (const auto &Pat : FragAlt.Pats) {
17395f757f3fSDimitry Andric if (PatFragSeenPats.contains(Pat.get()))
17405f757f3fSDimitry Andric continue;
17415f757f3fSDimitry Andric
17425f757f3fSDimitry Andric if (const auto *CXXPat = dyn_cast<CXXPattern>(Pat.get())) {
17435f757f3fSDimitry Andric addCXXPredicate(RM, PatFragCEs, *CXXPat, Alts);
17445f757f3fSDimitry Andric continue;
17455f757f3fSDimitry Andric }
17465f757f3fSDimitry Andric
17475f757f3fSDimitry Andric if (const auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
17485f757f3fSDimitry Andric IP->reportUnreachable(PF.getLoc());
17495f757f3fSDimitry Andric return false;
17505f757f3fSDimitry Andric }
17515f757f3fSDimitry Andric
17525f757f3fSDimitry Andric llvm_unreachable("Unexpected pattern kind in PatFrag");
17535f757f3fSDimitry Andric }
17545f757f3fSDimitry Andric
17555f757f3fSDimitry Andric for (const auto &[ParamName, ArgName] : CEsToImport) {
17565f757f3fSDimitry Andric // Note: we're find if ParamName already exists. It just means it's been
17575f757f3fSDimitry Andric // bound before, so we prefer to keep the first binding.
17585f757f3fSDimitry Andric CE.declare(ParamName, PatFragCEs.lookup(ArgName));
17595f757f3fSDimitry Andric }
17605f757f3fSDimitry Andric
17615f757f3fSDimitry Andric return true;
17625f757f3fSDimitry Andric }
17635f757f3fSDimitry Andric
emitApplyPatterns(CodeExpansions & CE,RuleMatcher & M)17645f757f3fSDimitry Andric bool CombineRuleBuilder::emitApplyPatterns(CodeExpansions &CE, RuleMatcher &M) {
1765*0fca6ea1SDimitry Andric assert(MatchDatas.empty());
17665f757f3fSDimitry Andric
17675f757f3fSDimitry Andric DenseSet<const Pattern *> SeenPats;
17685f757f3fSDimitry Andric StringMap<unsigned> OperandToTempRegID;
17695f757f3fSDimitry Andric
17705f757f3fSDimitry Andric for (auto *ApplyRoot : ApplyRoots) {
17715f757f3fSDimitry Andric assert(isa<InstructionPattern>(ApplyRoot) &&
17725f757f3fSDimitry Andric "Root can only be a InstructionPattern!");
17735f757f3fSDimitry Andric if (!emitInstructionApplyPattern(CE, M,
17745f757f3fSDimitry Andric cast<InstructionPattern>(*ApplyRoot),
17755f757f3fSDimitry Andric SeenPats, OperandToTempRegID))
17765f757f3fSDimitry Andric return false;
17775f757f3fSDimitry Andric }
17785f757f3fSDimitry Andric
17795f757f3fSDimitry Andric for (auto &Pat : values(ApplyPats)) {
17805f757f3fSDimitry Andric if (SeenPats.contains(Pat.get()))
17815f757f3fSDimitry Andric continue;
17825f757f3fSDimitry Andric
17835f757f3fSDimitry Andric switch (Pat->getKind()) {
17845f757f3fSDimitry Andric case Pattern::K_AnyOpcode:
17855f757f3fSDimitry Andric llvm_unreachable("Unexpected pattern in apply!");
17865f757f3fSDimitry Andric case Pattern::K_PatFrag:
17875f757f3fSDimitry Andric // TODO: We could support pure C++ PatFrags as a temporary thing.
17885f757f3fSDimitry Andric llvm_unreachable("Unexpected pattern in apply!");
17895f757f3fSDimitry Andric case Pattern::K_Builtin:
17905f757f3fSDimitry Andric if (!emitInstructionApplyPattern(CE, M, cast<BuiltinPattern>(*Pat),
17915f757f3fSDimitry Andric SeenPats, OperandToTempRegID))
17925f757f3fSDimitry Andric return false;
17935f757f3fSDimitry Andric break;
17945f757f3fSDimitry Andric case Pattern::K_CodeGenInstruction:
17955f757f3fSDimitry Andric cast<CodeGenInstructionPattern>(*Pat).reportUnreachable(RuleDef.getLoc());
17965f757f3fSDimitry Andric return false;
17975f757f3fSDimitry Andric case Pattern::K_CXX: {
1798*0fca6ea1SDimitry Andric llvm_unreachable(
1799*0fca6ea1SDimitry Andric "CXX Pattern Emission should have been handled earlier!");
18005f757f3fSDimitry Andric }
18015f757f3fSDimitry Andric default:
18025f757f3fSDimitry Andric llvm_unreachable("unknown pattern kind!");
18035f757f3fSDimitry Andric }
18045f757f3fSDimitry Andric }
18055f757f3fSDimitry Andric
18067a6dacacSDimitry Andric // Erase the root.
18077a6dacacSDimitry Andric unsigned RootInsnID =
18087a6dacacSDimitry Andric M.getInsnVarID(M.getInstructionMatcher(MatchRoot->getName()));
18097a6dacacSDimitry Andric M.addAction<EraseInstAction>(RootInsnID);
18107a6dacacSDimitry Andric
18115f757f3fSDimitry Andric return true;
18125f757f3fSDimitry Andric }
18135f757f3fSDimitry Andric
emitCXXMatchApply(CodeExpansions & CE,RuleMatcher & M,ArrayRef<CXXPattern * > Matchers)1814*0fca6ea1SDimitry Andric bool CombineRuleBuilder::emitCXXMatchApply(CodeExpansions &CE, RuleMatcher &M,
1815*0fca6ea1SDimitry Andric ArrayRef<CXXPattern *> Matchers) {
1816*0fca6ea1SDimitry Andric assert(hasOnlyCXXApplyPatterns());
1817*0fca6ea1SDimitry Andric declareAllMatchDatasExpansions(CE);
1818*0fca6ea1SDimitry Andric
1819*0fca6ea1SDimitry Andric std::string CodeStr;
1820*0fca6ea1SDimitry Andric raw_string_ostream OS(CodeStr);
1821*0fca6ea1SDimitry Andric
1822*0fca6ea1SDimitry Andric for (auto &MD : MatchDatas)
1823*0fca6ea1SDimitry Andric OS << MD.Type << " " << MD.getVarName() << ";\n";
1824*0fca6ea1SDimitry Andric
1825*0fca6ea1SDimitry Andric if (!Matchers.empty()) {
1826*0fca6ea1SDimitry Andric OS << "// Match Patterns\n";
1827*0fca6ea1SDimitry Andric for (auto *M : Matchers) {
1828*0fca6ea1SDimitry Andric OS << "if(![&](){";
1829*0fca6ea1SDimitry Andric CodeExpander Expander(M->getRawCode(), CE, RuleDef.getLoc(),
1830*0fca6ea1SDimitry Andric /*ShowExpansions=*/false);
1831*0fca6ea1SDimitry Andric Expander.emit(OS);
1832*0fca6ea1SDimitry Andric OS << "}()) {\n"
1833*0fca6ea1SDimitry Andric << " return false;\n}\n";
1834*0fca6ea1SDimitry Andric }
1835*0fca6ea1SDimitry Andric }
1836*0fca6ea1SDimitry Andric
1837*0fca6ea1SDimitry Andric OS << "// Apply Patterns\n";
1838*0fca6ea1SDimitry Andric ListSeparator LS("\n");
1839*0fca6ea1SDimitry Andric for (auto &Pat : ApplyPats) {
1840*0fca6ea1SDimitry Andric auto *CXXPat = cast<CXXPattern>(Pat.second.get());
1841*0fca6ea1SDimitry Andric CodeExpander Expander(CXXPat->getRawCode(), CE, RuleDef.getLoc(),
1842*0fca6ea1SDimitry Andric /*ShowExpansions=*/ false);
1843*0fca6ea1SDimitry Andric OS << LS;
1844*0fca6ea1SDimitry Andric Expander.emit(OS);
1845*0fca6ea1SDimitry Andric }
1846*0fca6ea1SDimitry Andric
1847*0fca6ea1SDimitry Andric const auto &Code = CXXPredicateCode::getCustomActionCode(CodeStr);
1848*0fca6ea1SDimitry Andric M.setCustomCXXAction(Code.getEnumNameWithPrefix(CXXCustomActionPrefix));
1849*0fca6ea1SDimitry Andric return true;
1850*0fca6ea1SDimitry Andric }
1851*0fca6ea1SDimitry Andric
emitInstructionApplyPattern(CodeExpansions & CE,RuleMatcher & M,const InstructionPattern & P,DenseSet<const Pattern * > & SeenPats,StringMap<unsigned> & OperandToTempRegID)18525f757f3fSDimitry Andric bool CombineRuleBuilder::emitInstructionApplyPattern(
18535f757f3fSDimitry Andric CodeExpansions &CE, RuleMatcher &M, const InstructionPattern &P,
18545f757f3fSDimitry Andric DenseSet<const Pattern *> &SeenPats,
18555f757f3fSDimitry Andric StringMap<unsigned> &OperandToTempRegID) {
18565f757f3fSDimitry Andric auto StackTrace = PrettyStackTraceEmit(RuleDef, &P);
18575f757f3fSDimitry Andric
18585f757f3fSDimitry Andric if (SeenPats.contains(&P))
18595f757f3fSDimitry Andric return true;
18605f757f3fSDimitry Andric
18615f757f3fSDimitry Andric SeenPats.insert(&P);
18625f757f3fSDimitry Andric
18635f757f3fSDimitry Andric // First, render the uses.
18645f757f3fSDimitry Andric for (auto &Op : P.named_operands()) {
18655f757f3fSDimitry Andric if (Op.isDef())
18665f757f3fSDimitry Andric continue;
18675f757f3fSDimitry Andric
18685f757f3fSDimitry Andric StringRef OpName = Op.getOperandName();
18695f757f3fSDimitry Andric if (const auto *DefPat = ApplyOpTable.getDef(OpName)) {
18705f757f3fSDimitry Andric if (!emitInstructionApplyPattern(CE, M, *DefPat, SeenPats,
18715f757f3fSDimitry Andric OperandToTempRegID))
18725f757f3fSDimitry Andric return false;
18735f757f3fSDimitry Andric } else {
18745f757f3fSDimitry Andric // If we have no def, check this exists in the MatchRoot.
18755f757f3fSDimitry Andric if (!Op.isNamedImmediate() && !MatchOpTable.lookup(OpName).Found) {
18765f757f3fSDimitry Andric PrintError("invalid output operand '" + OpName +
18775f757f3fSDimitry Andric "': operand is not a live-in of the match pattern, and it "
18785f757f3fSDimitry Andric "has no definition");
18795f757f3fSDimitry Andric return false;
18805f757f3fSDimitry Andric }
18815f757f3fSDimitry Andric }
18825f757f3fSDimitry Andric }
18835f757f3fSDimitry Andric
18845f757f3fSDimitry Andric if (const auto *BP = dyn_cast<BuiltinPattern>(&P))
18855f757f3fSDimitry Andric return emitBuiltinApplyPattern(CE, M, *BP, OperandToTempRegID);
18865f757f3fSDimitry Andric
18875f757f3fSDimitry Andric if (isa<PatFragPattern>(&P))
18885f757f3fSDimitry Andric llvm_unreachable("PatFragPatterns is not supported in 'apply'!");
18895f757f3fSDimitry Andric
18905f757f3fSDimitry Andric auto &CGIP = cast<CodeGenInstructionPattern>(P);
18915f757f3fSDimitry Andric
18925f757f3fSDimitry Andric // Now render this inst.
18935f757f3fSDimitry Andric auto &DstMI =
18945f757f3fSDimitry Andric M.addAction<BuildMIAction>(M.allocateOutputInsnID(), &CGIP.getInst());
18955f757f3fSDimitry Andric
1896*0fca6ea1SDimitry Andric bool HasEmittedIntrinsicID = false;
1897*0fca6ea1SDimitry Andric const auto EmitIntrinsicID = [&]() {
1898*0fca6ea1SDimitry Andric assert(CGIP.isIntrinsic());
1899*0fca6ea1SDimitry Andric DstMI.addRenderer<IntrinsicIDRenderer>(CGIP.getIntrinsic());
1900*0fca6ea1SDimitry Andric HasEmittedIntrinsicID = true;
1901*0fca6ea1SDimitry Andric };
1902*0fca6ea1SDimitry Andric
19035f757f3fSDimitry Andric for (auto &Op : P.operands()) {
1904*0fca6ea1SDimitry Andric // Emit the intrinsic ID after the last def.
1905*0fca6ea1SDimitry Andric if (CGIP.isIntrinsic() && !Op.isDef() && !HasEmittedIntrinsicID)
1906*0fca6ea1SDimitry Andric EmitIntrinsicID();
1907*0fca6ea1SDimitry Andric
19085f757f3fSDimitry Andric if (Op.isNamedImmediate()) {
19095f757f3fSDimitry Andric PrintError("invalid output operand '" + Op.getOperandName() +
19105f757f3fSDimitry Andric "': output immediates cannot be named");
19115f757f3fSDimitry Andric PrintNote("while emitting pattern '" + P.getName() + "' (" +
19125f757f3fSDimitry Andric P.getInstName() + ")");
19135f757f3fSDimitry Andric return false;
19145f757f3fSDimitry Andric }
19155f757f3fSDimitry Andric
19165f757f3fSDimitry Andric if (Op.hasImmValue()) {
19175f757f3fSDimitry Andric if (!emitCodeGenInstructionApplyImmOperand(M, DstMI, CGIP, Op))
19185f757f3fSDimitry Andric return false;
19195f757f3fSDimitry Andric continue;
19205f757f3fSDimitry Andric }
19215f757f3fSDimitry Andric
19225f757f3fSDimitry Andric StringRef OpName = Op.getOperandName();
19235f757f3fSDimitry Andric
19245f757f3fSDimitry Andric // Uses of operand.
19255f757f3fSDimitry Andric if (!Op.isDef()) {
19265f757f3fSDimitry Andric if (auto It = OperandToTempRegID.find(OpName);
19275f757f3fSDimitry Andric It != OperandToTempRegID.end()) {
19285f757f3fSDimitry Andric assert(!MatchOpTable.lookup(OpName).Found &&
19295f757f3fSDimitry Andric "Temp reg is also from match pattern?");
19305f757f3fSDimitry Andric DstMI.addRenderer<TempRegRenderer>(It->second);
19315f757f3fSDimitry Andric } else {
19325f757f3fSDimitry Andric // This should be a match live in or a redef of a matched instr.
19335f757f3fSDimitry Andric // If it's a use of a temporary register, then we messed up somewhere -
19345f757f3fSDimitry Andric // the previous condition should have passed.
19355f757f3fSDimitry Andric assert(MatchOpTable.lookup(OpName).Found &&
19365f757f3fSDimitry Andric !ApplyOpTable.getDef(OpName) && "Temp reg not emitted yet!");
19375f757f3fSDimitry Andric DstMI.addRenderer<CopyRenderer>(OpName);
19385f757f3fSDimitry Andric }
19395f757f3fSDimitry Andric continue;
19405f757f3fSDimitry Andric }
19415f757f3fSDimitry Andric
19425f757f3fSDimitry Andric // Determine what we're dealing with. Are we replace a matched instruction?
19435f757f3fSDimitry Andric // Creating a new one?
19445f757f3fSDimitry Andric auto OpLookupRes = MatchOpTable.lookup(OpName);
19455f757f3fSDimitry Andric if (OpLookupRes.Found) {
19465f757f3fSDimitry Andric if (OpLookupRes.isLiveIn()) {
19475f757f3fSDimitry Andric // live-in of the match pattern.
19485f757f3fSDimitry Andric PrintError("Cannot define live-in operand '" + OpName +
19495f757f3fSDimitry Andric "' in the 'apply' pattern");
19505f757f3fSDimitry Andric return false;
19515f757f3fSDimitry Andric }
19525f757f3fSDimitry Andric assert(OpLookupRes.Def);
19535f757f3fSDimitry Andric
19545f757f3fSDimitry Andric // TODO: Handle this. We need to mutate the instr, or delete the old
19555f757f3fSDimitry Andric // one.
19565f757f3fSDimitry Andric // Likewise, we also need to ensure we redef everything, if the
19575f757f3fSDimitry Andric // instr has more than one def, we need to redef all or nothing.
19585f757f3fSDimitry Andric if (OpLookupRes.Def != MatchRoot) {
19595f757f3fSDimitry Andric PrintError("redefining an instruction other than the root is not "
19605f757f3fSDimitry Andric "supported (operand '" +
19615f757f3fSDimitry Andric OpName + "')");
19625f757f3fSDimitry Andric return false;
19635f757f3fSDimitry Andric }
19645f757f3fSDimitry Andric // redef of a match
19655f757f3fSDimitry Andric DstMI.addRenderer<CopyRenderer>(OpName);
19665f757f3fSDimitry Andric continue;
19675f757f3fSDimitry Andric }
19685f757f3fSDimitry Andric
19695f757f3fSDimitry Andric // Define a new register unique to the apply patterns (AKA a "temp"
19705f757f3fSDimitry Andric // register).
19715f757f3fSDimitry Andric unsigned TempRegID;
19725f757f3fSDimitry Andric if (auto It = OperandToTempRegID.find(OpName);
19735f757f3fSDimitry Andric It != OperandToTempRegID.end()) {
19745f757f3fSDimitry Andric TempRegID = It->second;
19755f757f3fSDimitry Andric } else {
19765f757f3fSDimitry Andric // This is a brand new register.
19775f757f3fSDimitry Andric TempRegID = M.allocateTempRegID();
19785f757f3fSDimitry Andric OperandToTempRegID[OpName] = TempRegID;
19795f757f3fSDimitry Andric const auto Ty = Op.getType();
19805f757f3fSDimitry Andric if (!Ty) {
19815f757f3fSDimitry Andric PrintError("def of a new register '" + OpName +
19825f757f3fSDimitry Andric "' in the apply patterns must have a type");
19835f757f3fSDimitry Andric return false;
19845f757f3fSDimitry Andric }
19855f757f3fSDimitry Andric
19865f757f3fSDimitry Andric declareTempRegExpansion(CE, TempRegID, OpName);
19875f757f3fSDimitry Andric // Always insert the action at the beginning, otherwise we may end up
19885f757f3fSDimitry Andric // using the temp reg before it's available.
19895f757f3fSDimitry Andric M.insertAction<MakeTempRegisterAction>(
19905f757f3fSDimitry Andric M.actions_begin(), getLLTCodeGenOrTempType(Ty, M), TempRegID);
19915f757f3fSDimitry Andric }
19925f757f3fSDimitry Andric
1993297eecfbSDimitry Andric DstMI.addRenderer<TempRegRenderer>(TempRegID, /*IsDef=*/true);
19945f757f3fSDimitry Andric }
19955f757f3fSDimitry Andric
1996*0fca6ea1SDimitry Andric // Some intrinsics have no in operands, ensure the ID is still emitted in such
1997*0fca6ea1SDimitry Andric // cases.
1998*0fca6ea1SDimitry Andric if (CGIP.isIntrinsic() && !HasEmittedIntrinsicID)
1999*0fca6ea1SDimitry Andric EmitIntrinsicID();
2000*0fca6ea1SDimitry Andric
20015f757f3fSDimitry Andric // Render MIFlags
20025f757f3fSDimitry Andric if (const auto *FI = CGIP.getMIFlagsInfo()) {
20035f757f3fSDimitry Andric for (StringRef InstName : FI->copy_flags())
20045f757f3fSDimitry Andric DstMI.addCopiedMIFlags(M.getInstructionMatcher(InstName));
20055f757f3fSDimitry Andric for (StringRef F : FI->set_flags())
20065f757f3fSDimitry Andric DstMI.addSetMIFlags(F);
20075f757f3fSDimitry Andric for (StringRef F : FI->unset_flags())
20085f757f3fSDimitry Andric DstMI.addUnsetMIFlags(F);
20095f757f3fSDimitry Andric }
20105f757f3fSDimitry Andric
20115f757f3fSDimitry Andric // Don't allow mutating opcodes for GISel combiners. We want a more precise
20125f757f3fSDimitry Andric // handling of MIFlags so we require them to be explicitly preserved.
20135f757f3fSDimitry Andric //
20145f757f3fSDimitry Andric // TODO: We don't mutate very often, if at all in combiners, but it'd be nice
20155f757f3fSDimitry Andric // to re-enable this. We'd then need to always clear MIFlags when mutating
20165f757f3fSDimitry Andric // opcodes, and never mutate an inst that we copy flags from.
20175f757f3fSDimitry Andric // DstMI.chooseInsnToMutate(M);
20185f757f3fSDimitry Andric declareInstExpansion(CE, DstMI, P.getName());
20195f757f3fSDimitry Andric
20205f757f3fSDimitry Andric return true;
20215f757f3fSDimitry Andric }
20225f757f3fSDimitry Andric
emitCodeGenInstructionApplyImmOperand(RuleMatcher & M,BuildMIAction & DstMI,const CodeGenInstructionPattern & P,const InstructionOperand & O)20235f757f3fSDimitry Andric bool CombineRuleBuilder::emitCodeGenInstructionApplyImmOperand(
20245f757f3fSDimitry Andric RuleMatcher &M, BuildMIAction &DstMI, const CodeGenInstructionPattern &P,
20255f757f3fSDimitry Andric const InstructionOperand &O) {
20265f757f3fSDimitry Andric // If we have a type, we implicitly emit a G_CONSTANT, except for G_CONSTANT
20275f757f3fSDimitry Andric // itself where we emit a CImm.
20285f757f3fSDimitry Andric //
20295f757f3fSDimitry Andric // No type means we emit a simple imm.
20305f757f3fSDimitry Andric // G_CONSTANT is a special case and needs a CImm though so this is likely a
20315f757f3fSDimitry Andric // mistake.
20325f757f3fSDimitry Andric const bool isGConstant = P.is("G_CONSTANT");
20335f757f3fSDimitry Andric const auto Ty = O.getType();
20345f757f3fSDimitry Andric if (!Ty) {
20355f757f3fSDimitry Andric if (isGConstant) {
20365f757f3fSDimitry Andric PrintError("'G_CONSTANT' immediate must be typed!");
20375f757f3fSDimitry Andric PrintNote("while emitting pattern '" + P.getName() + "' (" +
20385f757f3fSDimitry Andric P.getInstName() + ")");
20395f757f3fSDimitry Andric return false;
20405f757f3fSDimitry Andric }
20415f757f3fSDimitry Andric
20425f757f3fSDimitry Andric DstMI.addRenderer<ImmRenderer>(O.getImmValue());
20435f757f3fSDimitry Andric return true;
20445f757f3fSDimitry Andric }
20455f757f3fSDimitry Andric
20465f757f3fSDimitry Andric auto ImmTy = getLLTCodeGenOrTempType(Ty, M);
20475f757f3fSDimitry Andric
20485f757f3fSDimitry Andric if (isGConstant) {
20495f757f3fSDimitry Andric DstMI.addRenderer<ImmRenderer>(O.getImmValue(), ImmTy);
20505f757f3fSDimitry Andric return true;
20515f757f3fSDimitry Andric }
20525f757f3fSDimitry Andric
20535f757f3fSDimitry Andric unsigned TempRegID = M.allocateTempRegID();
20545f757f3fSDimitry Andric // Ensure MakeTempReg & the BuildConstantAction occur at the beginning.
20555f757f3fSDimitry Andric auto InsertIt = M.insertAction<MakeTempRegisterAction>(M.actions_begin(),
20565f757f3fSDimitry Andric ImmTy, TempRegID);
20575f757f3fSDimitry Andric M.insertAction<BuildConstantAction>(++InsertIt, TempRegID, O.getImmValue());
20585f757f3fSDimitry Andric DstMI.addRenderer<TempRegRenderer>(TempRegID);
20595f757f3fSDimitry Andric return true;
20605f757f3fSDimitry Andric }
20615f757f3fSDimitry Andric
emitBuiltinApplyPattern(CodeExpansions & CE,RuleMatcher & M,const BuiltinPattern & P,StringMap<unsigned> & OperandToTempRegID)20625f757f3fSDimitry Andric bool CombineRuleBuilder::emitBuiltinApplyPattern(
20635f757f3fSDimitry Andric CodeExpansions &CE, RuleMatcher &M, const BuiltinPattern &P,
20645f757f3fSDimitry Andric StringMap<unsigned> &OperandToTempRegID) {
20655f757f3fSDimitry Andric const auto Error = [&](Twine Reason) {
20665f757f3fSDimitry Andric PrintError("cannot emit '" + P.getInstName() + "' builtin: " + Reason);
20675f757f3fSDimitry Andric return false;
20685f757f3fSDimitry Andric };
20695f757f3fSDimitry Andric
20705f757f3fSDimitry Andric switch (P.getBuiltinKind()) {
20715f757f3fSDimitry Andric case BI_EraseRoot: {
20725f757f3fSDimitry Andric // Root is always inst 0.
20735f757f3fSDimitry Andric M.addAction<EraseInstAction>(/*InsnID*/ 0);
20745f757f3fSDimitry Andric return true;
20755f757f3fSDimitry Andric }
20765f757f3fSDimitry Andric case BI_ReplaceReg: {
20775f757f3fSDimitry Andric StringRef Old = P.getOperand(0).getOperandName();
20785f757f3fSDimitry Andric StringRef New = P.getOperand(1).getOperandName();
20795f757f3fSDimitry Andric
20805f757f3fSDimitry Andric if (!ApplyOpTable.lookup(New).Found && !MatchOpTable.lookup(New).Found)
20815f757f3fSDimitry Andric return Error("unknown operand '" + Old + "'");
20825f757f3fSDimitry Andric
20835f757f3fSDimitry Andric auto &OldOM = M.getOperandMatcher(Old);
20845f757f3fSDimitry Andric if (auto It = OperandToTempRegID.find(New);
20855f757f3fSDimitry Andric It != OperandToTempRegID.end()) {
20865f757f3fSDimitry Andric // Replace with temp reg.
20875f757f3fSDimitry Andric M.addAction<ReplaceRegAction>(OldOM.getInsnVarID(), OldOM.getOpIdx(),
20885f757f3fSDimitry Andric It->second);
20895f757f3fSDimitry Andric } else {
20905f757f3fSDimitry Andric // Replace with matched reg.
20915f757f3fSDimitry Andric auto &NewOM = M.getOperandMatcher(New);
20925f757f3fSDimitry Andric M.addAction<ReplaceRegAction>(OldOM.getInsnVarID(), OldOM.getOpIdx(),
20935f757f3fSDimitry Andric NewOM.getInsnVarID(), NewOM.getOpIdx());
20945f757f3fSDimitry Andric }
20955f757f3fSDimitry Andric // checkSemantics should have ensured that we can only rewrite the root.
20965f757f3fSDimitry Andric // Ensure we're deleting it.
20975f757f3fSDimitry Andric assert(MatchOpTable.getDef(Old) == MatchRoot);
20985f757f3fSDimitry Andric return true;
20995f757f3fSDimitry Andric }
21005f757f3fSDimitry Andric }
21015f757f3fSDimitry Andric
21025f757f3fSDimitry Andric llvm_unreachable("Unknown BuiltinKind!");
21035f757f3fSDimitry Andric }
21045f757f3fSDimitry Andric
isLiteralImm(const InstructionPattern & P,unsigned OpIdx)21055f757f3fSDimitry Andric bool isLiteralImm(const InstructionPattern &P, unsigned OpIdx) {
21065f757f3fSDimitry Andric if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&P)) {
21075f757f3fSDimitry Andric StringRef InstName = CGP->getInst().TheDef->getName();
21085f757f3fSDimitry Andric return (InstName == "G_CONSTANT" || InstName == "G_FCONSTANT") &&
21095f757f3fSDimitry Andric OpIdx == 1;
21105f757f3fSDimitry Andric }
21115f757f3fSDimitry Andric
21125f757f3fSDimitry Andric llvm_unreachable("TODO");
21135f757f3fSDimitry Andric }
21145f757f3fSDimitry Andric
emitCodeGenInstructionMatchPattern(CodeExpansions & CE,const PatternAlternatives & Alts,RuleMatcher & M,InstructionMatcher & IM,const CodeGenInstructionPattern & P,DenseSet<const Pattern * > & SeenPats,OperandDefLookupFn LookupOperandDef,OperandMapperFnRef OperandMapper)21155f757f3fSDimitry Andric bool CombineRuleBuilder::emitCodeGenInstructionMatchPattern(
21165f757f3fSDimitry Andric CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &M,
21175f757f3fSDimitry Andric InstructionMatcher &IM, const CodeGenInstructionPattern &P,
21185f757f3fSDimitry Andric DenseSet<const Pattern *> &SeenPats, OperandDefLookupFn LookupOperandDef,
21195f757f3fSDimitry Andric OperandMapperFnRef OperandMapper) {
21205f757f3fSDimitry Andric auto StackTrace = PrettyStackTraceEmit(RuleDef, &P);
21215f757f3fSDimitry Andric
21225f757f3fSDimitry Andric if (SeenPats.contains(&P))
21235f757f3fSDimitry Andric return true;
21245f757f3fSDimitry Andric
21255f757f3fSDimitry Andric SeenPats.insert(&P);
21265f757f3fSDimitry Andric
21275f757f3fSDimitry Andric IM.addPredicate<InstructionOpcodeMatcher>(&P.getInst());
21285f757f3fSDimitry Andric declareInstExpansion(CE, IM, P.getName());
21295f757f3fSDimitry Andric
2130*0fca6ea1SDimitry Andric // If this is an intrinsic, check the intrinsic ID.
2131*0fca6ea1SDimitry Andric if (P.isIntrinsic()) {
2132*0fca6ea1SDimitry Andric // The IntrinsicID's operand is the first operand after the defs.
2133*0fca6ea1SDimitry Andric OperandMatcher &OM = IM.addOperand(P.getNumInstDefs(), "$intrinsic_id",
2134*0fca6ea1SDimitry Andric AllocatedTemporariesBaseID++);
2135*0fca6ea1SDimitry Andric OM.addPredicate<IntrinsicIDOperandMatcher>(P.getIntrinsic());
2136*0fca6ea1SDimitry Andric }
2137*0fca6ea1SDimitry Andric
21385f757f3fSDimitry Andric // Check flags if needed.
21395f757f3fSDimitry Andric if (const auto *FI = P.getMIFlagsInfo()) {
21405f757f3fSDimitry Andric assert(FI->copy_flags().empty());
21415f757f3fSDimitry Andric
21425f757f3fSDimitry Andric if (const auto &SetF = FI->set_flags(); !SetF.empty())
21435f757f3fSDimitry Andric IM.addPredicate<MIFlagsInstructionPredicateMatcher>(SetF.getArrayRef());
21445f757f3fSDimitry Andric if (const auto &UnsetF = FI->unset_flags(); !UnsetF.empty())
21455f757f3fSDimitry Andric IM.addPredicate<MIFlagsInstructionPredicateMatcher>(UnsetF.getArrayRef(),
21465f757f3fSDimitry Andric /*CheckNot=*/true);
21475f757f3fSDimitry Andric }
21485f757f3fSDimitry Andric
2149*0fca6ea1SDimitry Andric for (auto [Idx, OriginalO] : enumerate(P.operands())) {
21505f757f3fSDimitry Andric // Remap the operand. This is used when emitting InstructionPatterns inside
21515f757f3fSDimitry Andric // PatFrags, so it can remap them to the arguments passed to the pattern.
21525f757f3fSDimitry Andric //
21535f757f3fSDimitry Andric // We use the remapped operand to emit immediates, and for the symbolic
21545f757f3fSDimitry Andric // operand names (in IM.addOperand). CodeExpansions and OperandTable lookups
21555f757f3fSDimitry Andric // still use the original name.
21565f757f3fSDimitry Andric //
21575f757f3fSDimitry Andric // The "def" flag on the remapped operand is always ignored.
21585f757f3fSDimitry Andric auto RemappedO = OperandMapper(OriginalO);
21595f757f3fSDimitry Andric assert(RemappedO.isNamedOperand() == OriginalO.isNamedOperand() &&
21605f757f3fSDimitry Andric "Cannot remap an unnamed operand to a named one!");
21615f757f3fSDimitry Andric
21625f757f3fSDimitry Andric const auto OpName =
21635f757f3fSDimitry Andric RemappedO.isNamedOperand() ? RemappedO.getOperandName().str() : "";
2164*0fca6ea1SDimitry Andric
2165*0fca6ea1SDimitry Andric // For intrinsics, the first use operand is the intrinsic id, so the true
2166*0fca6ea1SDimitry Andric // operand index is shifted by 1.
2167*0fca6ea1SDimitry Andric //
2168*0fca6ea1SDimitry Andric // From now on:
2169*0fca6ea1SDimitry Andric // Idx = index in the pattern operand list.
2170*0fca6ea1SDimitry Andric // RealIdx = expected index in the MachineInstr.
2171*0fca6ea1SDimitry Andric const unsigned RealIdx =
2172*0fca6ea1SDimitry Andric (P.isIntrinsic() && !OriginalO.isDef()) ? (Idx + 1) : Idx;
21735f757f3fSDimitry Andric OperandMatcher &OM =
2174*0fca6ea1SDimitry Andric IM.addOperand(RealIdx, OpName, AllocatedTemporariesBaseID++);
21755f757f3fSDimitry Andric if (!OpName.empty())
21765f757f3fSDimitry Andric declareOperandExpansion(CE, OM, OriginalO.getOperandName());
21775f757f3fSDimitry Andric
21785f757f3fSDimitry Andric // Handle immediates.
21795f757f3fSDimitry Andric if (RemappedO.hasImmValue()) {
21805f757f3fSDimitry Andric if (isLiteralImm(P, Idx))
21815f757f3fSDimitry Andric OM.addPredicate<LiteralIntOperandMatcher>(RemappedO.getImmValue());
21825f757f3fSDimitry Andric else
21835f757f3fSDimitry Andric OM.addPredicate<ConstantIntOperandMatcher>(RemappedO.getImmValue());
21845f757f3fSDimitry Andric }
21855f757f3fSDimitry Andric
21865f757f3fSDimitry Andric // Handle typed operands, but only bother to check if it hasn't been done
21875f757f3fSDimitry Andric // before.
21885f757f3fSDimitry Andric //
21895f757f3fSDimitry Andric // getOperandMatcher will always return the first OM to have been created
21905f757f3fSDimitry Andric // for that Operand. "OM" here is always a new OperandMatcher.
21915f757f3fSDimitry Andric //
21925f757f3fSDimitry Andric // Always emit a check for unnamed operands.
21935f757f3fSDimitry Andric if (OpName.empty() ||
21945f757f3fSDimitry Andric !M.getOperandMatcher(OpName).contains<LLTOperandMatcher>()) {
21955f757f3fSDimitry Andric if (const auto Ty = RemappedO.getType()) {
21965f757f3fSDimitry Andric // TODO: We could support GITypeOf here on the condition that the
21975f757f3fSDimitry Andric // OperandMatcher exists already. Though it's clunky to make this work
21985f757f3fSDimitry Andric // and isn't all that useful so it's just rejected in typecheckPatterns
21995f757f3fSDimitry Andric // at this time.
22005f757f3fSDimitry Andric assert(Ty.isLLT() && "Only LLTs are supported in match patterns!");
22015f757f3fSDimitry Andric OM.addPredicate<LLTOperandMatcher>(getLLTCodeGen(Ty));
22025f757f3fSDimitry Andric }
22035f757f3fSDimitry Andric }
22045f757f3fSDimitry Andric
22055f757f3fSDimitry Andric // Stop here if the operand is a def, or if it had no name.
22065f757f3fSDimitry Andric if (OriginalO.isDef() || !OriginalO.isNamedOperand())
22075f757f3fSDimitry Andric continue;
22085f757f3fSDimitry Andric
22095f757f3fSDimitry Andric const auto *DefPat = LookupOperandDef(OriginalO.getOperandName());
22105f757f3fSDimitry Andric if (!DefPat)
22115f757f3fSDimitry Andric continue;
22125f757f3fSDimitry Andric
22135f757f3fSDimitry Andric if (OriginalO.hasImmValue()) {
22145f757f3fSDimitry Andric assert(!OpName.empty());
22155f757f3fSDimitry Andric // This is a named immediate that also has a def, that's not okay.
22165f757f3fSDimitry Andric // e.g.
22175f757f3fSDimitry Andric // (G_SEXT $y, (i32 0))
22185f757f3fSDimitry Andric // (COPY $x, 42:$y)
22195f757f3fSDimitry Andric PrintError("'" + OpName +
22205f757f3fSDimitry Andric "' is a named immediate, it cannot be defined by another "
22215f757f3fSDimitry Andric "instruction");
22225f757f3fSDimitry Andric PrintNote("'" + OpName + "' is defined by '" + DefPat->getName() + "'");
22235f757f3fSDimitry Andric return false;
22245f757f3fSDimitry Andric }
22255f757f3fSDimitry Andric
22265f757f3fSDimitry Andric // From here we know that the operand defines an instruction, and we need to
22275f757f3fSDimitry Andric // emit it.
22285f757f3fSDimitry Andric auto InstOpM =
22295f757f3fSDimitry Andric OM.addPredicate<InstructionOperandMatcher>(M, DefPat->getName());
22305f757f3fSDimitry Andric if (!InstOpM) {
22315f757f3fSDimitry Andric // TODO: copy-pasted from GlobalISelEmitter.cpp. Is it still relevant
22325f757f3fSDimitry Andric // here?
22335f757f3fSDimitry Andric PrintError("Nested instruction '" + DefPat->getName() +
22345f757f3fSDimitry Andric "' cannot be the same as another operand '" +
22355f757f3fSDimitry Andric OriginalO.getOperandName() + "'");
22365f757f3fSDimitry Andric return false;
22375f757f3fSDimitry Andric }
22385f757f3fSDimitry Andric
22395f757f3fSDimitry Andric auto &IM = (*InstOpM)->getInsnMatcher();
22405f757f3fSDimitry Andric if (const auto *CGIDef = dyn_cast<CodeGenInstructionPattern>(DefPat)) {
22415f757f3fSDimitry Andric if (!emitCodeGenInstructionMatchPattern(CE, Alts, M, IM, *CGIDef,
22425f757f3fSDimitry Andric SeenPats, LookupOperandDef,
22435f757f3fSDimitry Andric OperandMapper))
22445f757f3fSDimitry Andric return false;
22455f757f3fSDimitry Andric continue;
22465f757f3fSDimitry Andric }
22475f757f3fSDimitry Andric
22485f757f3fSDimitry Andric if (const auto *PFPDef = dyn_cast<PatFragPattern>(DefPat)) {
22495f757f3fSDimitry Andric if (!emitPatFragMatchPattern(CE, Alts, M, &IM, *PFPDef, SeenPats))
22505f757f3fSDimitry Andric return false;
22515f757f3fSDimitry Andric continue;
22525f757f3fSDimitry Andric }
22535f757f3fSDimitry Andric
22545f757f3fSDimitry Andric llvm_unreachable("unknown type of InstructionPattern");
22555f757f3fSDimitry Andric }
22565f757f3fSDimitry Andric
22575f757f3fSDimitry Andric return true;
22585f757f3fSDimitry Andric }
22595f757f3fSDimitry Andric
22605f757f3fSDimitry Andric //===- GICombinerEmitter --------------------------------------------------===//
22615f757f3fSDimitry Andric
22625f757f3fSDimitry Andric /// Main implementation class. This emits the tablegenerated output.
22635f757f3fSDimitry Andric ///
22645f757f3fSDimitry Andric /// It collects rules, uses `CombineRuleBuilder` to parse them and accumulate
22655f757f3fSDimitry Andric /// RuleMatchers, then takes all the necessary state/data from the various
22665f757f3fSDimitry Andric /// static storage pools and wires them together to emit the match table &
22675f757f3fSDimitry Andric /// associated function/data structures.
22685f757f3fSDimitry Andric class GICombinerEmitter final : public GlobalISelMatchTableExecutorEmitter {
22695f757f3fSDimitry Andric RecordKeeper &Records;
22705f757f3fSDimitry Andric StringRef Name;
22715f757f3fSDimitry Andric const CodeGenTarget &Target;
22725f757f3fSDimitry Andric Record *Combiner;
22735f757f3fSDimitry Andric unsigned NextRuleID = 0;
22745f757f3fSDimitry Andric
22755f757f3fSDimitry Andric // List all combine rules (ID, name) imported.
22765f757f3fSDimitry Andric // Note that the combiner rule ID is different from the RuleMatcher ID. The
22775f757f3fSDimitry Andric // latter is internal to the MatchTable, the former is the canonical ID of the
22785f757f3fSDimitry Andric // combine rule used to disable/enable it.
22795f757f3fSDimitry Andric std::vector<std::pair<unsigned, std::string>> AllCombineRules;
22805f757f3fSDimitry Andric
22815f757f3fSDimitry Andric // Keep track of all rules we've seen so far to ensure we don't process
22825f757f3fSDimitry Andric // the same rule twice.
22835f757f3fSDimitry Andric StringSet<> RulesSeen;
22845f757f3fSDimitry Andric
22855f757f3fSDimitry Andric MatchTable buildMatchTable(MutableArrayRef<RuleMatcher> Rules);
22865f757f3fSDimitry Andric
22875f757f3fSDimitry Andric void emitRuleConfigImpl(raw_ostream &OS);
22885f757f3fSDimitry Andric
22895f757f3fSDimitry Andric void emitAdditionalImpl(raw_ostream &OS) override;
22905f757f3fSDimitry Andric
22915f757f3fSDimitry Andric void emitMIPredicateFns(raw_ostream &OS) override;
22925f757f3fSDimitry Andric void emitI64ImmPredicateFns(raw_ostream &OS) override;
22935f757f3fSDimitry Andric void emitAPFloatImmPredicateFns(raw_ostream &OS) override;
22945f757f3fSDimitry Andric void emitAPIntImmPredicateFns(raw_ostream &OS) override;
22955f757f3fSDimitry Andric void emitTestSimplePredicate(raw_ostream &OS) override;
22965f757f3fSDimitry Andric void emitRunCustomAction(raw_ostream &OS) override;
22975f757f3fSDimitry Andric
getTarget() const22985f757f3fSDimitry Andric const CodeGenTarget &getTarget() const override { return Target; }
getClassName() const22995f757f3fSDimitry Andric StringRef getClassName() const override {
23005f757f3fSDimitry Andric return Combiner->getValueAsString("Classname");
23015f757f3fSDimitry Andric }
23025f757f3fSDimitry Andric
getCombineAllMethodName() const23035f757f3fSDimitry Andric StringRef getCombineAllMethodName() const {
23045f757f3fSDimitry Andric return Combiner->getValueAsString("CombineAllMethodName");
23055f757f3fSDimitry Andric }
23065f757f3fSDimitry Andric
getRuleConfigClassName() const23075f757f3fSDimitry Andric std::string getRuleConfigClassName() const {
23085f757f3fSDimitry Andric return getClassName().str() + "RuleConfig";
23095f757f3fSDimitry Andric }
23105f757f3fSDimitry Andric
23115f757f3fSDimitry Andric void gatherRules(std::vector<RuleMatcher> &Rules,
23125f757f3fSDimitry Andric const std::vector<Record *> &&RulesAndGroups);
23135f757f3fSDimitry Andric
23145f757f3fSDimitry Andric public:
23155f757f3fSDimitry Andric explicit GICombinerEmitter(RecordKeeper &RK, const CodeGenTarget &Target,
23165f757f3fSDimitry Andric StringRef Name, Record *Combiner);
~GICombinerEmitter()23175f757f3fSDimitry Andric ~GICombinerEmitter() {}
23185f757f3fSDimitry Andric
23195f757f3fSDimitry Andric void run(raw_ostream &OS);
23205f757f3fSDimitry Andric };
23215f757f3fSDimitry Andric
emitRuleConfigImpl(raw_ostream & OS)23225f757f3fSDimitry Andric void GICombinerEmitter::emitRuleConfigImpl(raw_ostream &OS) {
23235f757f3fSDimitry Andric OS << "struct " << getRuleConfigClassName() << " {\n"
23245f757f3fSDimitry Andric << " SparseBitVector<> DisabledRules;\n\n"
23255f757f3fSDimitry Andric << " bool isRuleEnabled(unsigned RuleID) const;\n"
23265f757f3fSDimitry Andric << " bool parseCommandLineOption();\n"
23275f757f3fSDimitry Andric << " bool setRuleEnabled(StringRef RuleIdentifier);\n"
23285f757f3fSDimitry Andric << " bool setRuleDisabled(StringRef RuleIdentifier);\n"
23295f757f3fSDimitry Andric << "};\n\n";
23305f757f3fSDimitry Andric
23315f757f3fSDimitry Andric std::vector<std::pair<std::string, std::string>> Cases;
23325f757f3fSDimitry Andric Cases.reserve(AllCombineRules.size());
23335f757f3fSDimitry Andric
23345f757f3fSDimitry Andric for (const auto &[ID, Name] : AllCombineRules)
23355f757f3fSDimitry Andric Cases.emplace_back(Name, "return " + to_string(ID) + ";\n");
23365f757f3fSDimitry Andric
23375f757f3fSDimitry Andric OS << "static std::optional<uint64_t> getRuleIdxForIdentifier(StringRef "
23385f757f3fSDimitry Andric "RuleIdentifier) {\n"
23395f757f3fSDimitry Andric << " uint64_t I;\n"
23405f757f3fSDimitry Andric << " // getAtInteger(...) returns false on success\n"
23415f757f3fSDimitry Andric << " bool Parsed = !RuleIdentifier.getAsInteger(0, I);\n"
23425f757f3fSDimitry Andric << " if (Parsed)\n"
23435f757f3fSDimitry Andric << " return I;\n\n"
23445f757f3fSDimitry Andric << "#ifndef NDEBUG\n";
23455f757f3fSDimitry Andric StringMatcher Matcher("RuleIdentifier", Cases, OS);
23465f757f3fSDimitry Andric Matcher.Emit();
23475f757f3fSDimitry Andric OS << "#endif // ifndef NDEBUG\n\n"
23485f757f3fSDimitry Andric << " return std::nullopt;\n"
23495f757f3fSDimitry Andric << "}\n";
23505f757f3fSDimitry Andric
23515f757f3fSDimitry Andric OS << "static std::optional<std::pair<uint64_t, uint64_t>> "
23525f757f3fSDimitry Andric "getRuleRangeForIdentifier(StringRef RuleIdentifier) {\n"
23535f757f3fSDimitry Andric << " std::pair<StringRef, StringRef> RangePair = "
23545f757f3fSDimitry Andric "RuleIdentifier.split('-');\n"
23555f757f3fSDimitry Andric << " if (!RangePair.second.empty()) {\n"
23565f757f3fSDimitry Andric << " const auto First = "
23575f757f3fSDimitry Andric "getRuleIdxForIdentifier(RangePair.first);\n"
23585f757f3fSDimitry Andric << " const auto Last = "
23595f757f3fSDimitry Andric "getRuleIdxForIdentifier(RangePair.second);\n"
23605f757f3fSDimitry Andric << " if (!First || !Last)\n"
23615f757f3fSDimitry Andric << " return std::nullopt;\n"
23625f757f3fSDimitry Andric << " if (First >= Last)\n"
23635f757f3fSDimitry Andric << " report_fatal_error(\"Beginning of range should be before "
23645f757f3fSDimitry Andric "end of range\");\n"
23655f757f3fSDimitry Andric << " return {{*First, *Last + 1}};\n"
23665f757f3fSDimitry Andric << " }\n"
23675f757f3fSDimitry Andric << " if (RangePair.first == \"*\") {\n"
23685f757f3fSDimitry Andric << " return {{0, " << AllCombineRules.size() << "}};\n"
23695f757f3fSDimitry Andric << " }\n"
23705f757f3fSDimitry Andric << " const auto I = getRuleIdxForIdentifier(RangePair.first);\n"
23715f757f3fSDimitry Andric << " if (!I)\n"
23725f757f3fSDimitry Andric << " return std::nullopt;\n"
23735f757f3fSDimitry Andric << " return {{*I, *I + 1}};\n"
23745f757f3fSDimitry Andric << "}\n\n";
23755f757f3fSDimitry Andric
23765f757f3fSDimitry Andric for (bool Enabled : {true, false}) {
23775f757f3fSDimitry Andric OS << "bool " << getRuleConfigClassName() << "::setRule"
23785f757f3fSDimitry Andric << (Enabled ? "Enabled" : "Disabled") << "(StringRef RuleIdentifier) {\n"
23795f757f3fSDimitry Andric << " auto MaybeRange = getRuleRangeForIdentifier(RuleIdentifier);\n"
23805f757f3fSDimitry Andric << " if (!MaybeRange)\n"
23815f757f3fSDimitry Andric << " return false;\n"
23825f757f3fSDimitry Andric << " for (auto I = MaybeRange->first; I < MaybeRange->second; ++I)\n"
23835f757f3fSDimitry Andric << " DisabledRules." << (Enabled ? "reset" : "set") << "(I);\n"
23845f757f3fSDimitry Andric << " return true;\n"
23855f757f3fSDimitry Andric << "}\n\n";
23865f757f3fSDimitry Andric }
23875f757f3fSDimitry Andric
23885f757f3fSDimitry Andric OS << "static std::vector<std::string> " << Name << "Option;\n"
23895f757f3fSDimitry Andric << "static cl::list<std::string> " << Name << "DisableOption(\n"
23905f757f3fSDimitry Andric << " \"" << Name.lower() << "-disable-rule\",\n"
23915f757f3fSDimitry Andric << " cl::desc(\"Disable one or more combiner rules temporarily in "
23925f757f3fSDimitry Andric << "the " << Name << " pass\"),\n"
23935f757f3fSDimitry Andric << " cl::CommaSeparated,\n"
23945f757f3fSDimitry Andric << " cl::Hidden,\n"
23955f757f3fSDimitry Andric << " cl::cat(GICombinerOptionCategory),\n"
23965f757f3fSDimitry Andric << " cl::callback([](const std::string &Str) {\n"
23975f757f3fSDimitry Andric << " " << Name << "Option.push_back(Str);\n"
23985f757f3fSDimitry Andric << " }));\n"
23995f757f3fSDimitry Andric << "static cl::list<std::string> " << Name << "OnlyEnableOption(\n"
24005f757f3fSDimitry Andric << " \"" << Name.lower() << "-only-enable-rule\",\n"
24015f757f3fSDimitry Andric << " cl::desc(\"Disable all rules in the " << Name
24025f757f3fSDimitry Andric << " pass then re-enable the specified ones\"),\n"
24035f757f3fSDimitry Andric << " cl::Hidden,\n"
24045f757f3fSDimitry Andric << " cl::cat(GICombinerOptionCategory),\n"
24055f757f3fSDimitry Andric << " cl::callback([](const std::string &CommaSeparatedArg) {\n"
24065f757f3fSDimitry Andric << " StringRef Str = CommaSeparatedArg;\n"
24075f757f3fSDimitry Andric << " " << Name << "Option.push_back(\"*\");\n"
24085f757f3fSDimitry Andric << " do {\n"
24095f757f3fSDimitry Andric << " auto X = Str.split(\",\");\n"
24105f757f3fSDimitry Andric << " " << Name << "Option.push_back((\"!\" + X.first).str());\n"
24115f757f3fSDimitry Andric << " Str = X.second;\n"
24125f757f3fSDimitry Andric << " } while (!Str.empty());\n"
24135f757f3fSDimitry Andric << " }));\n"
24145f757f3fSDimitry Andric << "\n\n"
24155f757f3fSDimitry Andric << "bool " << getRuleConfigClassName()
24165f757f3fSDimitry Andric << "::isRuleEnabled(unsigned RuleID) const {\n"
24175f757f3fSDimitry Andric << " return !DisabledRules.test(RuleID);\n"
24185f757f3fSDimitry Andric << "}\n"
24195f757f3fSDimitry Andric << "bool " << getRuleConfigClassName() << "::parseCommandLineOption() {\n"
24205f757f3fSDimitry Andric << " for (StringRef Identifier : " << Name << "Option) {\n"
24215f757f3fSDimitry Andric << " bool Enabled = Identifier.consume_front(\"!\");\n"
24225f757f3fSDimitry Andric << " if (Enabled && !setRuleEnabled(Identifier))\n"
24235f757f3fSDimitry Andric << " return false;\n"
24245f757f3fSDimitry Andric << " if (!Enabled && !setRuleDisabled(Identifier))\n"
24255f757f3fSDimitry Andric << " return false;\n"
24265f757f3fSDimitry Andric << " }\n"
24275f757f3fSDimitry Andric << " return true;\n"
24285f757f3fSDimitry Andric << "}\n\n";
24295f757f3fSDimitry Andric }
24305f757f3fSDimitry Andric
emitAdditionalImpl(raw_ostream & OS)24315f757f3fSDimitry Andric void GICombinerEmitter::emitAdditionalImpl(raw_ostream &OS) {
24325f757f3fSDimitry Andric OS << "bool " << getClassName() << "::" << getCombineAllMethodName()
24335f757f3fSDimitry Andric << "(MachineInstr &I) const {\n"
24345f757f3fSDimitry Andric << " const TargetSubtargetInfo &ST = MF.getSubtarget();\n"
24355f757f3fSDimitry Andric << " const PredicateBitset AvailableFeatures = "
24365f757f3fSDimitry Andric "getAvailableFeatures();\n"
24375f757f3fSDimitry Andric << " B.setInstrAndDebugLoc(I);\n"
24385f757f3fSDimitry Andric << " State.MIs.clear();\n"
24395f757f3fSDimitry Andric << " State.MIs.push_back(&I);\n"
24405f757f3fSDimitry Andric << " if (executeMatchTable(*this, State, ExecInfo, B"
24415f757f3fSDimitry Andric << ", getMatchTable(), *ST.getInstrInfo(), MRI, "
24425f757f3fSDimitry Andric "*MRI.getTargetRegisterInfo(), *ST.getRegBankInfo(), AvailableFeatures"
24435f757f3fSDimitry Andric << ", /*CoverageInfo*/ nullptr)) {\n"
24445f757f3fSDimitry Andric << " return true;\n"
24455f757f3fSDimitry Andric << " }\n\n"
24465f757f3fSDimitry Andric << " return false;\n"
24475f757f3fSDimitry Andric << "}\n\n";
24485f757f3fSDimitry Andric }
24495f757f3fSDimitry Andric
emitMIPredicateFns(raw_ostream & OS)24505f757f3fSDimitry Andric void GICombinerEmitter::emitMIPredicateFns(raw_ostream &OS) {
24515f757f3fSDimitry Andric auto MatchCode = CXXPredicateCode::getAllMatchCode();
24525f757f3fSDimitry Andric emitMIPredicateFnsImpl<const CXXPredicateCode *>(
24535f757f3fSDimitry Andric OS, "", ArrayRef<const CXXPredicateCode *>(MatchCode),
24545f757f3fSDimitry Andric [](const CXXPredicateCode *C) -> StringRef { return C->BaseEnumName; },
24555f757f3fSDimitry Andric [](const CXXPredicateCode *C) -> StringRef { return C->Code; });
24565f757f3fSDimitry Andric }
24575f757f3fSDimitry Andric
emitI64ImmPredicateFns(raw_ostream & OS)24585f757f3fSDimitry Andric void GICombinerEmitter::emitI64ImmPredicateFns(raw_ostream &OS) {
24595f757f3fSDimitry Andric // Unused, but still needs to be called.
24605f757f3fSDimitry Andric emitImmPredicateFnsImpl<unsigned>(
24615f757f3fSDimitry Andric OS, "I64", "int64_t", {}, [](unsigned) { return ""; },
24625f757f3fSDimitry Andric [](unsigned) { return ""; });
24635f757f3fSDimitry Andric }
24645f757f3fSDimitry Andric
emitAPFloatImmPredicateFns(raw_ostream & OS)24655f757f3fSDimitry Andric void GICombinerEmitter::emitAPFloatImmPredicateFns(raw_ostream &OS) {
24665f757f3fSDimitry Andric // Unused, but still needs to be called.
24675f757f3fSDimitry Andric emitImmPredicateFnsImpl<unsigned>(
24685f757f3fSDimitry Andric OS, "APFloat", "const APFloat &", {}, [](unsigned) { return ""; },
24695f757f3fSDimitry Andric [](unsigned) { return ""; });
24705f757f3fSDimitry Andric }
24715f757f3fSDimitry Andric
emitAPIntImmPredicateFns(raw_ostream & OS)24725f757f3fSDimitry Andric void GICombinerEmitter::emitAPIntImmPredicateFns(raw_ostream &OS) {
24735f757f3fSDimitry Andric // Unused, but still needs to be called.
24745f757f3fSDimitry Andric emitImmPredicateFnsImpl<unsigned>(
24755f757f3fSDimitry Andric OS, "APInt", "const APInt &", {}, [](unsigned) { return ""; },
24765f757f3fSDimitry Andric [](unsigned) { return ""; });
24775f757f3fSDimitry Andric }
24785f757f3fSDimitry Andric
emitTestSimplePredicate(raw_ostream & OS)24795f757f3fSDimitry Andric void GICombinerEmitter::emitTestSimplePredicate(raw_ostream &OS) {
24805f757f3fSDimitry Andric if (!AllCombineRules.empty()) {
24815f757f3fSDimitry Andric OS << "enum {\n";
24825f757f3fSDimitry Andric std::string EnumeratorSeparator = " = GICXXPred_Invalid + 1,\n";
24835f757f3fSDimitry Andric // To avoid emitting a switch, we expect that all those rules are in order.
24845f757f3fSDimitry Andric // That way we can just get the RuleID from the enum by subtracting
24855f757f3fSDimitry Andric // (GICXXPred_Invalid + 1).
24865f757f3fSDimitry Andric unsigned ExpectedID = 0;
24875f757f3fSDimitry Andric (void)ExpectedID;
24885f757f3fSDimitry Andric for (const auto &ID : keys(AllCombineRules)) {
24895f757f3fSDimitry Andric assert(ExpectedID++ == ID && "combine rules are not ordered!");
24905f757f3fSDimitry Andric OS << " " << getIsEnabledPredicateEnumName(ID) << EnumeratorSeparator;
24915f757f3fSDimitry Andric EnumeratorSeparator = ",\n";
24925f757f3fSDimitry Andric }
24935f757f3fSDimitry Andric OS << "};\n\n";
24945f757f3fSDimitry Andric }
24955f757f3fSDimitry Andric
24965f757f3fSDimitry Andric OS << "bool " << getClassName()
24975f757f3fSDimitry Andric << "::testSimplePredicate(unsigned Predicate) const {\n"
24985f757f3fSDimitry Andric << " return RuleConfig.isRuleEnabled(Predicate - "
24995f757f3fSDimitry Andric "GICXXPred_Invalid - "
25005f757f3fSDimitry Andric "1);\n"
25015f757f3fSDimitry Andric << "}\n";
25025f757f3fSDimitry Andric }
25035f757f3fSDimitry Andric
emitRunCustomAction(raw_ostream & OS)25045f757f3fSDimitry Andric void GICombinerEmitter::emitRunCustomAction(raw_ostream &OS) {
2505*0fca6ea1SDimitry Andric const auto CustomActionsCode = CXXPredicateCode::getAllCustomActionsCode();
25065f757f3fSDimitry Andric
2507*0fca6ea1SDimitry Andric if (!CustomActionsCode.empty()) {
25085f757f3fSDimitry Andric OS << "enum {\n";
25095f757f3fSDimitry Andric std::string EnumeratorSeparator = " = GICXXCustomAction_Invalid + 1,\n";
2510*0fca6ea1SDimitry Andric for (const auto &CA : CustomActionsCode) {
2511*0fca6ea1SDimitry Andric OS << " " << CA->getEnumNameWithPrefix(CXXCustomActionPrefix)
25125f757f3fSDimitry Andric << EnumeratorSeparator;
25135f757f3fSDimitry Andric EnumeratorSeparator = ",\n";
25145f757f3fSDimitry Andric }
25155f757f3fSDimitry Andric OS << "};\n";
25165f757f3fSDimitry Andric }
25175f757f3fSDimitry Andric
2518*0fca6ea1SDimitry Andric OS << "bool " << getClassName()
25195f757f3fSDimitry Andric << "::runCustomAction(unsigned ApplyID, const MatcherState &State, "
25205f757f3fSDimitry Andric "NewMIVector &OutMIs) const "
2521*0fca6ea1SDimitry Andric "{\n Helper.getBuilder().setInstrAndDebugLoc(*State.MIs[0]);\n";
2522*0fca6ea1SDimitry Andric if (!CustomActionsCode.empty()) {
25235f757f3fSDimitry Andric OS << " switch(ApplyID) {\n";
2524*0fca6ea1SDimitry Andric for (const auto &CA : CustomActionsCode) {
2525*0fca6ea1SDimitry Andric OS << " case " << CA->getEnumNameWithPrefix(CXXCustomActionPrefix)
2526*0fca6ea1SDimitry Andric << ":{\n"
2527*0fca6ea1SDimitry Andric << " " << join(split(CA->Code, '\n'), "\n ") << '\n'
2528*0fca6ea1SDimitry Andric << " return true;\n";
25295f757f3fSDimitry Andric OS << " }\n";
25305f757f3fSDimitry Andric }
25315f757f3fSDimitry Andric OS << " }\n";
25325f757f3fSDimitry Andric }
25335f757f3fSDimitry Andric OS << " llvm_unreachable(\"Unknown Apply Action\");\n"
25345f757f3fSDimitry Andric << "}\n";
25355f757f3fSDimitry Andric }
25365f757f3fSDimitry Andric
GICombinerEmitter(RecordKeeper & RK,const CodeGenTarget & Target,StringRef Name,Record * Combiner)25375f757f3fSDimitry Andric GICombinerEmitter::GICombinerEmitter(RecordKeeper &RK,
25385f757f3fSDimitry Andric const CodeGenTarget &Target,
25395f757f3fSDimitry Andric StringRef Name, Record *Combiner)
25405f757f3fSDimitry Andric : Records(RK), Name(Name), Target(Target), Combiner(Combiner) {}
25415f757f3fSDimitry Andric
25425f757f3fSDimitry Andric MatchTable
buildMatchTable(MutableArrayRef<RuleMatcher> Rules)25435f757f3fSDimitry Andric GICombinerEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules) {
25445f757f3fSDimitry Andric std::vector<Matcher *> InputRules;
25455f757f3fSDimitry Andric for (Matcher &Rule : Rules)
25465f757f3fSDimitry Andric InputRules.push_back(&Rule);
25475f757f3fSDimitry Andric
25485f757f3fSDimitry Andric unsigned CurrentOrdering = 0;
25495f757f3fSDimitry Andric StringMap<unsigned> OpcodeOrder;
25505f757f3fSDimitry Andric for (RuleMatcher &Rule : Rules) {
25515f757f3fSDimitry Andric const StringRef Opcode = Rule.getOpcode();
25525f757f3fSDimitry Andric assert(!Opcode.empty() && "Didn't expect an undefined opcode");
25535f757f3fSDimitry Andric if (OpcodeOrder.count(Opcode) == 0)
25545f757f3fSDimitry Andric OpcodeOrder[Opcode] = CurrentOrdering++;
25555f757f3fSDimitry Andric }
25565f757f3fSDimitry Andric
25575f757f3fSDimitry Andric llvm::stable_sort(InputRules, [&OpcodeOrder](const Matcher *A,
25585f757f3fSDimitry Andric const Matcher *B) {
25595f757f3fSDimitry Andric auto *L = static_cast<const RuleMatcher *>(A);
25605f757f3fSDimitry Andric auto *R = static_cast<const RuleMatcher *>(B);
25615f757f3fSDimitry Andric return std::make_tuple(OpcodeOrder[L->getOpcode()], L->getNumOperands()) <
25625f757f3fSDimitry Andric std::make_tuple(OpcodeOrder[R->getOpcode()], R->getNumOperands());
25635f757f3fSDimitry Andric });
25645f757f3fSDimitry Andric
25655f757f3fSDimitry Andric for (Matcher *Rule : InputRules)
25665f757f3fSDimitry Andric Rule->optimize();
25675f757f3fSDimitry Andric
25685f757f3fSDimitry Andric std::vector<std::unique_ptr<Matcher>> MatcherStorage;
25695f757f3fSDimitry Andric std::vector<Matcher *> OptRules =
25705f757f3fSDimitry Andric optimizeRules<GroupMatcher>(InputRules, MatcherStorage);
25715f757f3fSDimitry Andric
25725f757f3fSDimitry Andric for (Matcher *Rule : OptRules)
25735f757f3fSDimitry Andric Rule->optimize();
25745f757f3fSDimitry Andric
25755f757f3fSDimitry Andric OptRules = optimizeRules<SwitchMatcher>(OptRules, MatcherStorage);
25765f757f3fSDimitry Andric
25775f757f3fSDimitry Andric return MatchTable::buildTable(OptRules, /*WithCoverage*/ false,
25785f757f3fSDimitry Andric /*IsCombiner*/ true);
25795f757f3fSDimitry Andric }
25805f757f3fSDimitry Andric
25815f757f3fSDimitry Andric /// Recurse into GICombineGroup's and flatten the ruleset into a simple list.
gatherRules(std::vector<RuleMatcher> & ActiveRules,const std::vector<Record * > && RulesAndGroups)25825f757f3fSDimitry Andric void GICombinerEmitter::gatherRules(
25835f757f3fSDimitry Andric std::vector<RuleMatcher> &ActiveRules,
25845f757f3fSDimitry Andric const std::vector<Record *> &&RulesAndGroups) {
25855f757f3fSDimitry Andric for (Record *Rec : RulesAndGroups) {
25865f757f3fSDimitry Andric if (!Rec->isValueUnset("Rules")) {
25875f757f3fSDimitry Andric gatherRules(ActiveRules, Rec->getValueAsListOfDefs("Rules"));
25885f757f3fSDimitry Andric continue;
25895f757f3fSDimitry Andric }
25905f757f3fSDimitry Andric
25915f757f3fSDimitry Andric StringRef RuleName = Rec->getName();
25925f757f3fSDimitry Andric if (!RulesSeen.insert(RuleName).second) {
25935f757f3fSDimitry Andric PrintWarning(Rec->getLoc(),
25945f757f3fSDimitry Andric "skipping rule '" + Rec->getName() +
25955f757f3fSDimitry Andric "' because it has already been processed");
25965f757f3fSDimitry Andric continue;
25975f757f3fSDimitry Andric }
25985f757f3fSDimitry Andric
25995f757f3fSDimitry Andric AllCombineRules.emplace_back(NextRuleID, Rec->getName().str());
26005f757f3fSDimitry Andric CombineRuleBuilder CRB(Target, SubtargetFeatures, *Rec, NextRuleID++,
26015f757f3fSDimitry Andric ActiveRules);
26025f757f3fSDimitry Andric
26035f757f3fSDimitry Andric if (!CRB.parseAll()) {
26045f757f3fSDimitry Andric assert(ErrorsPrinted && "Parsing failed without errors!");
26055f757f3fSDimitry Andric continue;
26065f757f3fSDimitry Andric }
26075f757f3fSDimitry Andric
26085f757f3fSDimitry Andric if (StopAfterParse) {
26095f757f3fSDimitry Andric CRB.print(outs());
26105f757f3fSDimitry Andric continue;
26115f757f3fSDimitry Andric }
26125f757f3fSDimitry Andric
26135f757f3fSDimitry Andric if (!CRB.emitRuleMatchers()) {
26145f757f3fSDimitry Andric assert(ErrorsPrinted && "Emission failed without errors!");
26155f757f3fSDimitry Andric continue;
26165f757f3fSDimitry Andric }
26175f757f3fSDimitry Andric }
26185f757f3fSDimitry Andric }
26195f757f3fSDimitry Andric
run(raw_ostream & OS)26205f757f3fSDimitry Andric void GICombinerEmitter::run(raw_ostream &OS) {
26215f757f3fSDimitry Andric InstructionOpcodeMatcher::initOpcodeValuesMap(Target);
26225f757f3fSDimitry Andric LLTOperandMatcher::initTypeIDValuesMap();
26235f757f3fSDimitry Andric
26245f757f3fSDimitry Andric Records.startTimer("Gather rules");
26255f757f3fSDimitry Andric std::vector<RuleMatcher> Rules;
26265f757f3fSDimitry Andric gatherRules(Rules, Combiner->getValueAsListOfDefs("Rules"));
26275f757f3fSDimitry Andric if (ErrorsPrinted)
26285f757f3fSDimitry Andric PrintFatalError(Combiner->getLoc(), "Failed to parse one or more rules");
26295f757f3fSDimitry Andric
26305f757f3fSDimitry Andric if (StopAfterParse)
26315f757f3fSDimitry Andric return;
26325f757f3fSDimitry Andric
26335f757f3fSDimitry Andric Records.startTimer("Creating Match Table");
26345f757f3fSDimitry Andric unsigned MaxTemporaries = 0;
26355f757f3fSDimitry Andric for (const auto &Rule : Rules)
26365f757f3fSDimitry Andric MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());
26375f757f3fSDimitry Andric
26385f757f3fSDimitry Andric llvm::stable_sort(Rules, [&](const RuleMatcher &A, const RuleMatcher &B) {
26395f757f3fSDimitry Andric if (A.isHigherPriorityThan(B)) {
26405f757f3fSDimitry Andric assert(!B.isHigherPriorityThan(A) && "Cannot be more important "
26415f757f3fSDimitry Andric "and less important at "
26425f757f3fSDimitry Andric "the same time");
26435f757f3fSDimitry Andric return true;
26445f757f3fSDimitry Andric }
26455f757f3fSDimitry Andric return false;
26465f757f3fSDimitry Andric });
26475f757f3fSDimitry Andric
26485f757f3fSDimitry Andric const MatchTable Table = buildMatchTable(Rules);
26495f757f3fSDimitry Andric
26505f757f3fSDimitry Andric Records.startTimer("Emit combiner");
26515f757f3fSDimitry Andric
26525f757f3fSDimitry Andric emitSourceFileHeader(getClassName().str() + " Combiner Match Table", OS);
26535f757f3fSDimitry Andric
26545f757f3fSDimitry Andric // Unused
26555f757f3fSDimitry Andric std::vector<StringRef> CustomRendererFns;
26565f757f3fSDimitry Andric // Unused
26575f757f3fSDimitry Andric std::vector<Record *> ComplexPredicates;
26585f757f3fSDimitry Andric
26595f757f3fSDimitry Andric SmallVector<LLTCodeGen, 16> TypeObjects;
26605f757f3fSDimitry Andric append_range(TypeObjects, KnownTypes);
26615f757f3fSDimitry Andric llvm::sort(TypeObjects);
26625f757f3fSDimitry Andric
26635f757f3fSDimitry Andric // Hack: Avoid empty declarator.
26645f757f3fSDimitry Andric if (TypeObjects.empty())
26655f757f3fSDimitry Andric TypeObjects.push_back(LLT::scalar(1));
26665f757f3fSDimitry Andric
26675f757f3fSDimitry Andric // GET_GICOMBINER_DEPS, which pulls in extra dependencies.
26685f757f3fSDimitry Andric OS << "#ifdef GET_GICOMBINER_DEPS\n"
26695f757f3fSDimitry Andric << "#include \"llvm/ADT/SparseBitVector.h\"\n"
26705f757f3fSDimitry Andric << "namespace llvm {\n"
26715f757f3fSDimitry Andric << "extern cl::OptionCategory GICombinerOptionCategory;\n"
26725f757f3fSDimitry Andric << "} // end namespace llvm\n"
26735f757f3fSDimitry Andric << "#endif // ifdef GET_GICOMBINER_DEPS\n\n";
26745f757f3fSDimitry Andric
26755f757f3fSDimitry Andric // GET_GICOMBINER_TYPES, which needs to be included before the declaration of
26765f757f3fSDimitry Andric // the class.
26775f757f3fSDimitry Andric OS << "#ifdef GET_GICOMBINER_TYPES\n";
26785f757f3fSDimitry Andric emitRuleConfigImpl(OS);
26795f757f3fSDimitry Andric OS << "#endif // ifdef GET_GICOMBINER_TYPES\n\n";
26805f757f3fSDimitry Andric emitPredicateBitset(OS, "GET_GICOMBINER_TYPES");
26815f757f3fSDimitry Andric
26825f757f3fSDimitry Andric // GET_GICOMBINER_CLASS_MEMBERS, which need to be included inside the class.
26835f757f3fSDimitry Andric emitPredicatesDecl(OS, "GET_GICOMBINER_CLASS_MEMBERS");
26845f757f3fSDimitry Andric emitTemporariesDecl(OS, "GET_GICOMBINER_CLASS_MEMBERS");
26855f757f3fSDimitry Andric
26865f757f3fSDimitry Andric // GET_GICOMBINER_IMPL, which needs to be included outside the class.
26875f757f3fSDimitry Andric emitExecutorImpl(OS, Table, TypeObjects, Rules, ComplexPredicates,
26885f757f3fSDimitry Andric CustomRendererFns, "GET_GICOMBINER_IMPL");
26895f757f3fSDimitry Andric
26905f757f3fSDimitry Andric // GET_GICOMBINER_CONSTRUCTOR_INITS, which are in the constructor's
26915f757f3fSDimitry Andric // initializer list.
26925f757f3fSDimitry Andric emitPredicatesInit(OS, "GET_GICOMBINER_CONSTRUCTOR_INITS");
26935f757f3fSDimitry Andric emitTemporariesInit(OS, MaxTemporaries, "GET_GICOMBINER_CONSTRUCTOR_INITS");
26945f757f3fSDimitry Andric }
26955f757f3fSDimitry Andric
26965f757f3fSDimitry Andric } // end anonymous namespace
26975f757f3fSDimitry Andric
26985f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
26995f757f3fSDimitry Andric
EmitGICombiner(RecordKeeper & RK,raw_ostream & OS)27005f757f3fSDimitry Andric static void EmitGICombiner(RecordKeeper &RK, raw_ostream &OS) {
27015f757f3fSDimitry Andric EnablePrettyStackTrace();
27025f757f3fSDimitry Andric CodeGenTarget Target(RK);
27035f757f3fSDimitry Andric
27045f757f3fSDimitry Andric if (SelectedCombiners.empty())
27055f757f3fSDimitry Andric PrintFatalError("No combiners selected with -combiners");
27065f757f3fSDimitry Andric for (const auto &Combiner : SelectedCombiners) {
27075f757f3fSDimitry Andric Record *CombinerDef = RK.getDef(Combiner);
27085f757f3fSDimitry Andric if (!CombinerDef)
27095f757f3fSDimitry Andric PrintFatalError("Could not find " + Combiner);
27105f757f3fSDimitry Andric GICombinerEmitter(RK, Target, Combiner, CombinerDef).run(OS);
27115f757f3fSDimitry Andric }
27125f757f3fSDimitry Andric }
27135f757f3fSDimitry Andric
27145f757f3fSDimitry Andric static TableGen::Emitter::Opt X("gen-global-isel-combiner", EmitGICombiner,
27155f757f3fSDimitry Andric "Generate GlobalISel Combiner");
2716