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 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 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 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 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 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 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 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 1275f757f3fSDimitry Andric LLTCodeGen getLLTCodeGen(const PatternType &PT) { 1285f757f3fSDimitry Andric return *MVTToLLT(getValueType(PT.getLLTRecord())); 1295f757f3fSDimitry Andric } 1305f757f3fSDimitry Andric 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: 1495f757f3fSDimitry Andric PrettyStackTraceParse(const Record &Def) : Def(Def) {} 1505f757f3fSDimitry Andric 1515f757f3fSDimitry 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: 1675f757f3fSDimitry Andric PrettyStackTraceEmit(const Record &Def, const Pattern *Pat = nullptr) 1685f757f3fSDimitry Andric : Def(Def), Pat(Pat) {} 1695f757f3fSDimitry Andric 1705f757f3fSDimitry 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: 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. 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 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 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 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 3925f757f3fSDimitry 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 4315f757f3fSDimitry 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 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 5075f757f3fSDimitry 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 5755f757f3fSDimitry 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 { 611*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. 617*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 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; 6595f757f3fSDimitry 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: 6675f757f3fSDimitry Andric const CodeGenInstruction &getGConstant() const { 6685f757f3fSDimitry Andric return CGT.getInstruction(RuleDef.getRecords().getDef("G_CONSTANT")); 6695f757f3fSDimitry Andric } 6705f757f3fSDimitry Andric 6715f757f3fSDimitry Andric void PrintError(Twine Msg) const { ::PrintError(&RuleDef, Msg); } 6725f757f3fSDimitry Andric void PrintWarning(Twine Msg) const { ::PrintWarning(RuleDef.getLoc(), Msg); } 6735f757f3fSDimitry 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, 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 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 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 8545f757f3fSDimitry 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 9195f757f3fSDimitry 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 9635f757f3fSDimitry 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 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 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 10205f757f3fSDimitry 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 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 10455f757f3fSDimitry 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 10515f757f3fSDimitry 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 22985f757f3fSDimitry Andric const CodeGenTarget &getTarget() const override { return Target; } 22995f757f3fSDimitry Andric StringRef getClassName() const override { 23005f757f3fSDimitry Andric return Combiner->getValueAsString("Classname"); 23015f757f3fSDimitry Andric } 23025f757f3fSDimitry Andric 23035f757f3fSDimitry Andric StringRef getCombineAllMethodName() const { 23045f757f3fSDimitry Andric return Combiner->getValueAsString("CombineAllMethodName"); 23055f757f3fSDimitry Andric } 23065f757f3fSDimitry Andric 23075f757f3fSDimitry 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); 23175f757f3fSDimitry Andric ~GICombinerEmitter() {} 23185f757f3fSDimitry Andric 23195f757f3fSDimitry Andric void run(raw_ostream &OS); 23205f757f3fSDimitry Andric }; 23215f757f3fSDimitry Andric 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 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 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 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 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 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 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 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 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 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. 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 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 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