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