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