brintos

brintos / llvm-project-archived public Read only

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