Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
35258 views
//===- GlobalISelCombinerMatchTableEmitter.cpp - --------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8/// \file Generate a combiner implementation for GlobalISel from a declarative9/// syntax using GlobalISelMatchTable.10///11/// Usually, TableGen backends use "assert is an error" as a means to report12/// invalid input. They try to diagnose common case but don't try very hard and13/// crashes can be common. This backend aims to behave closer to how a language14/// compiler frontend would behave: we try extra hard to diagnose invalid inputs15/// early, and any crash should be considered a bug (= a feature or diagnostic16/// is missing).17///18/// While this can make the backend a bit more complex than it needs to be, it19/// pays off because MIR patterns can get complicated. Giving useful error20/// messages to combine writers can help boost their productivity.21///22/// As with anything, a good balance has to be found. We also don't want to23/// write hundreds of lines of code to detect edge cases. In practice, crashing24/// very occasionally, or giving poor errors in some rare instances, is fine.25///26//===----------------------------------------------------------------------===//2728#include "Basic/CodeGenIntrinsics.h"29#include "Common/CodeGenInstruction.h"30#include "Common/CodeGenTarget.h"31#include "Common/GlobalISel/CXXPredicates.h"32#include "Common/GlobalISel/CodeExpander.h"33#include "Common/GlobalISel/CodeExpansions.h"34#include "Common/GlobalISel/CombinerUtils.h"35#include "Common/GlobalISel/GlobalISelMatchTable.h"36#include "Common/GlobalISel/GlobalISelMatchTableExecutorEmitter.h"37#include "Common/GlobalISel/PatternParser.h"38#include "Common/GlobalISel/Patterns.h"39#include "Common/SubtargetFeatureInfo.h"40#include "llvm/ADT/APInt.h"41#include "llvm/ADT/EquivalenceClasses.h"42#include "llvm/ADT/Hashing.h"43#include "llvm/ADT/MapVector.h"44#include "llvm/ADT/SetVector.h"45#include "llvm/ADT/Statistic.h"46#include "llvm/ADT/StringExtras.h"47#include "llvm/ADT/StringSet.h"48#include "llvm/Support/CommandLine.h"49#include "llvm/Support/Debug.h"50#include "llvm/Support/PrettyStackTrace.h"51#include "llvm/Support/ScopedPrinter.h"52#include "llvm/TableGen/Error.h"53#include "llvm/TableGen/Record.h"54#include "llvm/TableGen/StringMatcher.h"55#include "llvm/TableGen/TableGenBackend.h"56#include <cstdint>5758using namespace llvm;59using namespace llvm::gi;6061#define DEBUG_TYPE "gicombiner-emitter"6263namespace {64cl::OptionCategory65GICombinerEmitterCat("Options for -gen-global-isel-combiner");66cl::opt<bool> StopAfterParse(67"gicombiner-stop-after-parse",68cl::desc("Stop processing after parsing rules and dump state"),69cl::cat(GICombinerEmitterCat));70cl::list<std::string>71SelectedCombiners("combiners", cl::desc("Emit the specified combiners"),72cl::cat(GICombinerEmitterCat), cl::CommaSeparated);73cl::opt<bool> DebugCXXPreds(74"gicombiner-debug-cxxpreds",75cl::desc("Add Contextual/Debug comments to all C++ predicates"),76cl::cat(GICombinerEmitterCat));77cl::opt<bool> DebugTypeInfer("gicombiner-debug-typeinfer",78cl::desc("Print type inference debug logs"),79cl::cat(GICombinerEmitterCat));8081constexpr StringLiteral CXXCustomActionPrefix = "GICXXCustomAction_";82constexpr StringLiteral CXXPredPrefix = "GICXXPred_MI_Predicate_";83constexpr StringLiteral MatchDataClassName = "GIDefMatchData";8485//===- CodeExpansions Helpers --------------------------------------------===//8687void declareInstExpansion(CodeExpansions &CE, const InstructionMatcher &IM,88StringRef Name) {89CE.declare(Name, "State.MIs[" + to_string(IM.getInsnVarID()) + "]");90}9192void declareInstExpansion(CodeExpansions &CE, const BuildMIAction &A,93StringRef Name) {94// Note: we use redeclare here because this may overwrite a matcher inst95// expansion.96CE.redeclare(Name, "OutMIs[" + to_string(A.getInsnID()) + "]");97}9899void declareOperandExpansion(CodeExpansions &CE, const OperandMatcher &OM,100StringRef Name) {101CE.declare(Name, "State.MIs[" + to_string(OM.getInsnVarID()) +102"]->getOperand(" + to_string(OM.getOpIdx()) + ")");103}104105void declareTempRegExpansion(CodeExpansions &CE, unsigned TempRegID,106StringRef Name) {107CE.declare(Name, "State.TempRegisters[" + to_string(TempRegID) + "]");108}109110//===- Misc. Helpers -----------------------------------------------------===//111112template <typename Container> auto keys(Container &&C) {113return map_range(C, [](auto &Entry) -> auto & { return Entry.first; });114}115116template <typename Container> auto values(Container &&C) {117return map_range(C, [](auto &Entry) -> auto & { return Entry.second; });118}119120std::string getIsEnabledPredicateEnumName(unsigned CombinerRuleID) {121return "GICXXPred_Simple_IsRule" + to_string(CombinerRuleID) + "Enabled";122}123124//===- MatchTable Helpers ------------------------------------------------===//125126LLTCodeGen getLLTCodeGen(const PatternType &PT) {127return *MVTToLLT(getValueType(PT.getLLTRecord()));128}129130LLTCodeGenOrTempType getLLTCodeGenOrTempType(const PatternType &PT,131RuleMatcher &RM) {132assert(!PT.isNone());133134if (PT.isLLT())135return getLLTCodeGen(PT);136137assert(PT.isTypeOf());138auto &OM = RM.getOperandMatcher(PT.getTypeOfOpName());139return OM.getTempTypeIdx(RM);140}141142//===- PrettyStackTrace Helpers ------------------------------------------===//143144class PrettyStackTraceParse : public PrettyStackTraceEntry {145const Record &Def;146147public:148PrettyStackTraceParse(const Record &Def) : Def(Def) {}149150void print(raw_ostream &OS) const override {151if (Def.isSubClassOf("GICombineRule"))152OS << "Parsing GICombineRule '" << Def.getName() << "'";153else if (Def.isSubClassOf(PatFrag::ClassName))154OS << "Parsing " << PatFrag::ClassName << " '" << Def.getName() << "'";155else156OS << "Parsing '" << Def.getName() << "'";157OS << '\n';158}159};160161class PrettyStackTraceEmit : public PrettyStackTraceEntry {162const Record &Def;163const Pattern *Pat = nullptr;164165public:166PrettyStackTraceEmit(const Record &Def, const Pattern *Pat = nullptr)167: Def(Def), Pat(Pat) {}168169void print(raw_ostream &OS) const override {170if (Def.isSubClassOf("GICombineRule"))171OS << "Emitting GICombineRule '" << Def.getName() << "'";172else if (Def.isSubClassOf(PatFrag::ClassName))173OS << "Emitting " << PatFrag::ClassName << " '" << Def.getName() << "'";174else175OS << "Emitting '" << Def.getName() << "'";176177if (Pat)178OS << " [" << Pat->getKindName() << " '" << Pat->getName() << "']";179OS << '\n';180}181};182183//===- CombineRuleOperandTypeChecker --------------------------------------===//184185/// This is a wrapper around OperandTypeChecker specialized for Combiner Rules.186/// On top of doing the same things as OperandTypeChecker, this also attempts to187/// infer as many types as possible for temporary register defs & immediates in188/// apply patterns.189///190/// The inference is trivial and leverages the MCOI OperandTypes encoded in191/// CodeGenInstructions to infer types across patterns in a CombineRule. It's192/// thus very limited and only supports CodeGenInstructions (but that's the main193/// use case so it's fine).194///195/// We only try to infer untyped operands in apply patterns when they're temp196/// reg defs, or immediates. Inference always outputs a `TypeOf<$x>` where $x is197/// a named operand from a match pattern.198class CombineRuleOperandTypeChecker : private OperandTypeChecker {199public:200CombineRuleOperandTypeChecker(const Record &RuleDef,201const OperandTable &MatchOpTable)202: OperandTypeChecker(RuleDef.getLoc()), RuleDef(RuleDef),203MatchOpTable(MatchOpTable) {}204205/// Records and checks a 'match' pattern.206bool processMatchPattern(InstructionPattern &P);207208/// Records and checks an 'apply' pattern.209bool processApplyPattern(InstructionPattern &P);210211/// Propagates types, then perform type inference and do a second round of212/// propagation in the apply patterns only if any types were inferred.213void propagateAndInferTypes();214215private:216/// TypeEquivalenceClasses are groups of operands of an instruction that share217/// a common type.218///219/// e.g. [[a, b], [c, d]] means a and b have the same type, and c and220/// d have the same type too. b/c and a/d don't have to have the same type,221/// though.222using TypeEquivalenceClasses = EquivalenceClasses<StringRef>;223224/// \returns true for `OPERAND_GENERIC_` 0 through 5.225/// These are the MCOI types that can be registers. The other MCOI types are226/// either immediates, or fancier operands used only post-ISel, so we don't227/// care about them for combiners.228static bool canMCOIOperandTypeBeARegister(StringRef MCOIType) {229// Assume OPERAND_GENERIC_0 through 5 can be registers. The other MCOI230// OperandTypes are either never used in gMIR, or not relevant (e.g.231// OPERAND_GENERIC_IMM, which is definitely never a register).232return MCOIType.drop_back(1).ends_with("OPERAND_GENERIC_");233}234235/// Finds the "MCOI::"" operand types for each operand of \p CGP.236///237/// This is a bit trickier than it looks because we need to handle variadic238/// in/outs.239///240/// e.g. for241/// (G_BUILD_VECTOR $vec, $x, $y) ->242/// [MCOI::OPERAND_GENERIC_0, MCOI::OPERAND_GENERIC_1,243/// MCOI::OPERAND_GENERIC_1]244///245/// For unknown types (which can happen in variadics where varargs types are246/// inconsistent), a unique name is given, e.g. "unknown_type_0".247static std::vector<std::string>248getMCOIOperandTypes(const CodeGenInstructionPattern &CGP);249250/// Adds the TypeEquivalenceClasses for \p P in \p OutTECs.251void getInstEqClasses(const InstructionPattern &P,252TypeEquivalenceClasses &OutTECs) const;253254/// Calls `getInstEqClasses` on all patterns of the rule to produce the whole255/// rule's TypeEquivalenceClasses.256TypeEquivalenceClasses getRuleEqClasses() const;257258/// Tries to infer the type of the \p ImmOpIdx -th operand of \p IP using \p259/// TECs.260///261/// This is achieved by trying to find a named operand in \p IP that shares262/// the same type as \p ImmOpIdx, and using \ref inferNamedOperandType on that263/// operand instead.264///265/// \returns the inferred type or an empty PatternType if inference didn't266/// succeed.267PatternType inferImmediateType(const InstructionPattern &IP,268unsigned ImmOpIdx,269const TypeEquivalenceClasses &TECs) const;270271/// Looks inside \p TECs to infer \p OpName's type.272///273/// \returns the inferred type or an empty PatternType if inference didn't274/// succeed.275PatternType inferNamedOperandType(const InstructionPattern &IP,276StringRef OpName,277const TypeEquivalenceClasses &TECs,278bool AllowSelf = false) const;279280const Record &RuleDef;281SmallVector<InstructionPattern *, 8> MatchPats;282SmallVector<InstructionPattern *, 8> ApplyPats;283284const OperandTable &MatchOpTable;285};286287bool CombineRuleOperandTypeChecker::processMatchPattern(InstructionPattern &P) {288MatchPats.push_back(&P);289return check(P, /*CheckTypeOf*/ [](const auto &) {290// GITypeOf in 'match' is currently always rejected by the291// CombineRuleBuilder after inference is done.292return true;293});294}295296bool CombineRuleOperandTypeChecker::processApplyPattern(InstructionPattern &P) {297ApplyPats.push_back(&P);298return check(P, /*CheckTypeOf*/ [&](const PatternType &Ty) {299// GITypeOf<"$x"> can only be used if "$x" is a matched operand.300const auto OpName = Ty.getTypeOfOpName();301if (MatchOpTable.lookup(OpName).Found)302return true;303304PrintError(RuleDef.getLoc(), "'" + OpName + "' ('" + Ty.str() +305"') does not refer to a matched operand!");306return false;307});308}309310void CombineRuleOperandTypeChecker::propagateAndInferTypes() {311/// First step here is to propagate types using the OperandTypeChecker. That312/// way we ensure all uses of a given register have consistent types.313propagateTypes();314315/// Build the TypeEquivalenceClasses for the whole rule.316const TypeEquivalenceClasses TECs = getRuleEqClasses();317318/// Look at the apply patterns and find operands that need to be319/// inferred. We then try to find an equivalence class that they're a part of320/// and select the best operand to use for the `GITypeOf` type. We prioritize321/// defs of matched instructions because those are guaranteed to be registers.322bool InferredAny = false;323for (auto *Pat : ApplyPats) {324for (unsigned K = 0; K < Pat->operands_size(); ++K) {325auto &Op = Pat->getOperand(K);326327// We only want to take a look at untyped defs or immediates.328if ((!Op.isDef() && !Op.hasImmValue()) || Op.getType())329continue;330331// Infer defs & named immediates.332if (Op.isDef() || Op.isNamedImmediate()) {333// Check it's not a redefinition of a matched operand.334// In such cases, inference is not necessary because we just copy335// operands and don't create temporary registers.336if (MatchOpTable.lookup(Op.getOperandName()).Found)337continue;338339// Inference is needed here, so try to do it.340if (PatternType Ty =341inferNamedOperandType(*Pat, Op.getOperandName(), TECs)) {342if (DebugTypeInfer)343errs() << "INFER: " << Op.describe() << " -> " << Ty.str() << '\n';344Op.setType(Ty);345InferredAny = true;346}347348continue;349}350351// Infer immediates352if (Op.hasImmValue()) {353if (PatternType Ty = inferImmediateType(*Pat, K, TECs)) {354if (DebugTypeInfer)355errs() << "INFER: " << Op.describe() << " -> " << Ty.str() << '\n';356Op.setType(Ty);357InferredAny = true;358}359continue;360}361}362}363364// If we've inferred any types, we want to propagate them across the apply365// patterns. Type inference only adds GITypeOf types that point to Matched366// operands, so we definitely don't want to propagate types into the match367// patterns as well, otherwise bad things happen.368if (InferredAny) {369OperandTypeChecker OTC(RuleDef.getLoc());370for (auto *Pat : ApplyPats) {371if (!OTC.check(*Pat, [&](const auto &) { return true; }))372PrintFatalError(RuleDef.getLoc(),373"OperandTypeChecker unexpectedly failed on '" +374Pat->getName() + "' during Type Inference");375}376OTC.propagateTypes();377378if (DebugTypeInfer) {379errs() << "Apply patterns for rule " << RuleDef.getName()380<< " after inference:\n";381for (auto *Pat : ApplyPats) {382errs() << " ";383Pat->print(errs(), /*PrintName*/ true);384errs() << '\n';385}386errs() << '\n';387}388}389}390391PatternType CombineRuleOperandTypeChecker::inferImmediateType(392const InstructionPattern &IP, unsigned ImmOpIdx,393const TypeEquivalenceClasses &TECs) const {394// We can only infer CGPs (except intrinsics).395const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&IP);396if (!CGP || CGP->isIntrinsic())397return {};398399// For CGPs, we try to infer immediates by trying to infer another named400// operand that shares its type.401//402// e.g.403// Pattern: G_BUILD_VECTOR $x, $y, 0404// MCOIs: [MCOI::OPERAND_GENERIC_0, MCOI::OPERAND_GENERIC_1,405// MCOI::OPERAND_GENERIC_1]406// $y has the same type as 0, so we can infer $y and get the type 0 should407// have.408409// We infer immediates by looking for a named operand that shares the same410// MCOI type.411const auto MCOITypes = getMCOIOperandTypes(*CGP);412StringRef ImmOpTy = MCOITypes[ImmOpIdx];413414for (const auto &[Idx, Ty] : enumerate(MCOITypes)) {415if (Idx != ImmOpIdx && Ty == ImmOpTy) {416const auto &Op = IP.getOperand(Idx);417if (!Op.isNamedOperand())418continue;419420// Named operand with the same name, try to infer that.421if (PatternType InferTy = inferNamedOperandType(IP, Op.getOperandName(),422TECs, /*AllowSelf=*/true))423return InferTy;424}425}426427return {};428}429430PatternType CombineRuleOperandTypeChecker::inferNamedOperandType(431const InstructionPattern &IP, StringRef OpName,432const TypeEquivalenceClasses &TECs, bool AllowSelf) const {433// This is the simplest possible case, we just need to find a TEC that434// contains OpName. Look at all operands in equivalence class and try to435// find a suitable one. If `AllowSelf` is true, the operand itself is also436// considered suitable.437438// Check for a def of a matched pattern. This is guaranteed to always439// be a register so we can blindly use that.440StringRef GoodOpName;441for (auto It = TECs.findLeader(OpName); It != TECs.member_end(); ++It) {442if (!AllowSelf && *It == OpName)443continue;444445const auto LookupRes = MatchOpTable.lookup(*It);446if (LookupRes.Def) // Favor defs447return PatternType::getTypeOf(*It);448449// Otherwise just save this in case we don't find any def.450if (GoodOpName.empty() && LookupRes.Found)451GoodOpName = *It;452}453454if (!GoodOpName.empty())455return PatternType::getTypeOf(GoodOpName);456457// No good operand found, give up.458return {};459}460461std::vector<std::string> CombineRuleOperandTypeChecker::getMCOIOperandTypes(462const CodeGenInstructionPattern &CGP) {463// FIXME?: Should we cache this? We call it twice when inferring immediates.464465static unsigned UnknownTypeIdx = 0;466467std::vector<std::string> OpTypes;468auto &CGI = CGP.getInst();469Record *VarArgsTy = CGI.TheDef->isSubClassOf("GenericInstruction")470? CGI.TheDef->getValueAsOptionalDef("variadicOpsType")471: nullptr;472std::string VarArgsTyName =473VarArgsTy ? ("MCOI::" + VarArgsTy->getValueAsString("OperandType")).str()474: ("unknown_type_" + Twine(UnknownTypeIdx++)).str();475476// First, handle defs.477for (unsigned K = 0; K < CGI.Operands.NumDefs; ++K)478OpTypes.push_back(CGI.Operands[K].OperandType);479480// Then, handle variadic defs if there are any.481if (CGP.hasVariadicDefs()) {482for (unsigned K = CGI.Operands.NumDefs; K < CGP.getNumInstDefs(); ++K)483OpTypes.push_back(VarArgsTyName);484}485486// If we had variadic defs, the op idx in the pattern won't match the op idx487// in the CGI anymore.488int CGIOpOffset = int(CGI.Operands.NumDefs) - CGP.getNumInstDefs();489assert(CGP.hasVariadicDefs() ? (CGIOpOffset <= 0) : (CGIOpOffset == 0));490491// Handle all remaining use operands, including variadic ones.492for (unsigned K = CGP.getNumInstDefs(); K < CGP.getNumInstOperands(); ++K) {493unsigned CGIOpIdx = K + CGIOpOffset;494if (CGIOpIdx >= CGI.Operands.size()) {495assert(CGP.isVariadic());496OpTypes.push_back(VarArgsTyName);497} else {498OpTypes.push_back(CGI.Operands[CGIOpIdx].OperandType);499}500}501502assert(OpTypes.size() == CGP.operands_size());503return OpTypes;504}505506void CombineRuleOperandTypeChecker::getInstEqClasses(507const InstructionPattern &P, TypeEquivalenceClasses &OutTECs) const {508// Determine the TypeEquivalenceClasses by:509// - Getting the MCOI Operand Types.510// - Creating a Map of MCOI Type -> [Operand Indexes]511// - Iterating over the map, filtering types we don't like, and just adding512// the array of Operand Indexes to \p OutTECs.513514// We can only do this on CodeGenInstructions that aren't intrinsics. Other515// InstructionPatterns have no type inference information associated with516// them.517// TODO: We could try to extract some info from CodeGenIntrinsic to518// guide inference.519520// TODO: Could we add some inference information to builtins at least? e.g.521// ReplaceReg should always replace with a reg of the same type, for instance.522// Though, those patterns are often used alone so it might not be worth the523// trouble to infer their types.524auto *CGP = dyn_cast<CodeGenInstructionPattern>(&P);525if (!CGP || CGP->isIntrinsic())526return;527528const auto MCOITypes = getMCOIOperandTypes(*CGP);529assert(MCOITypes.size() == P.operands_size());530531MapVector<StringRef, SmallVector<unsigned, 0>> TyToOpIdx;532for (const auto &[Idx, Ty] : enumerate(MCOITypes))533TyToOpIdx[Ty].push_back(Idx);534535if (DebugTypeInfer)536errs() << "\tGroups for " << P.getName() << ":\t";537538for (const auto &[Ty, Idxs] : TyToOpIdx) {539if (!canMCOIOperandTypeBeARegister(Ty))540continue;541542if (DebugTypeInfer)543errs() << '[';544StringRef Sep = "";545546// We only collect named operands.547StringRef Leader;548for (unsigned Idx : Idxs) {549const auto &Op = P.getOperand(Idx);550if (!Op.isNamedOperand())551continue;552553const auto OpName = Op.getOperandName();554if (DebugTypeInfer) {555errs() << Sep << OpName;556Sep = ", ";557}558559if (Leader.empty())560OutTECs.insert((Leader = OpName));561else562OutTECs.unionSets(Leader, OpName);563}564565if (DebugTypeInfer)566errs() << "] ";567}568569if (DebugTypeInfer)570errs() << '\n';571}572573CombineRuleOperandTypeChecker::TypeEquivalenceClasses574CombineRuleOperandTypeChecker::getRuleEqClasses() const {575StringMap<unsigned> OpNameToEqClassIdx;576TypeEquivalenceClasses TECs;577578if (DebugTypeInfer)579errs() << "Rule Operand Type Equivalence Classes for " << RuleDef.getName()580<< ":\n";581582for (const auto *Pat : MatchPats)583getInstEqClasses(*Pat, TECs);584for (const auto *Pat : ApplyPats)585getInstEqClasses(*Pat, TECs);586587if (DebugTypeInfer) {588errs() << "Final Type Equivalence Classes: ";589for (auto ClassIt = TECs.begin(); ClassIt != TECs.end(); ++ClassIt) {590// only print non-empty classes.591if (auto MembIt = TECs.member_begin(ClassIt);592MembIt != TECs.member_end()) {593errs() << '[';594StringRef Sep = "";595for (; MembIt != TECs.member_end(); ++MembIt) {596errs() << Sep << *MembIt;597Sep = ", ";598}599errs() << "] ";600}601}602errs() << '\n';603}604605return TECs;606}607608//===- MatchData Handling -------------------------------------------------===//609struct MatchDataDef {610MatchDataDef(StringRef Symbol, StringRef Type) : Symbol(Symbol), Type(Type) {}611612StringRef Symbol;613StringRef Type;614615/// \returns the desired variable name for this MatchData.616std::string getVarName() const {617// Add a prefix in case the symbol name is very generic and conflicts with618// something else.619return "GIMatchData_" + Symbol.str();620}621};622623//===- CombineRuleBuilder -------------------------------------------------===//624625/// Parses combine rule and builds a small intermediate representation to tie626/// patterns together and emit RuleMatchers to match them. This may emit more627/// than one RuleMatcher, e.g. for `wip_match_opcode`.628///629/// Memory management for `Pattern` objects is done through `std::unique_ptr`.630/// In most cases, there are two stages to a pattern's lifetime:631/// - Creation in a `parse` function632/// - The unique_ptr is stored in a variable, and may be destroyed if the633/// pattern is found to be semantically invalid.634/// - Ownership transfer into a `PatternMap`635/// - Once a pattern is moved into either the map of Match or Apply636/// patterns, it is known to be valid and it never moves back.637class CombineRuleBuilder {638public:639using PatternMap = MapVector<StringRef, std::unique_ptr<Pattern>>;640using PatternAlternatives = DenseMap<const Pattern *, unsigned>;641642CombineRuleBuilder(const CodeGenTarget &CGT,643SubtargetFeatureInfoMap &SubtargetFeatures,644Record &RuleDef, unsigned ID,645std::vector<RuleMatcher> &OutRMs)646: Parser(CGT, RuleDef.getLoc()), CGT(CGT),647SubtargetFeatures(SubtargetFeatures), RuleDef(RuleDef), RuleID(ID),648OutRMs(OutRMs) {}649650/// Parses all fields in the RuleDef record.651bool parseAll();652653/// Emits all RuleMatchers into the vector of RuleMatchers passed in the654/// constructor.655bool emitRuleMatchers();656657void print(raw_ostream &OS) const;658void dump() const { print(dbgs()); }659660/// Debug-only verification of invariants.661#ifndef NDEBUG662void verify() const;663#endif664665private:666const CodeGenInstruction &getGConstant() const {667return CGT.getInstruction(RuleDef.getRecords().getDef("G_CONSTANT"));668}669670void PrintError(Twine Msg) const { ::PrintError(&RuleDef, Msg); }671void PrintWarning(Twine Msg) const { ::PrintWarning(RuleDef.getLoc(), Msg); }672void PrintNote(Twine Msg) const { ::PrintNote(RuleDef.getLoc(), Msg); }673674void print(raw_ostream &OS, const PatternAlternatives &Alts) const;675676bool addApplyPattern(std::unique_ptr<Pattern> Pat);677bool addMatchPattern(std::unique_ptr<Pattern> Pat);678679/// Adds the expansions from \see MatchDatas to \p CE.680void declareAllMatchDatasExpansions(CodeExpansions &CE) const;681682/// Adds a matcher \p P to \p IM, expanding its code using \p CE.683/// Note that the predicate is added on the last InstructionMatcher.684///685/// \p Alts is only used if DebugCXXPreds is enabled.686void addCXXPredicate(RuleMatcher &M, const CodeExpansions &CE,687const CXXPattern &P, const PatternAlternatives &Alts);688689bool hasOnlyCXXApplyPatterns() const;690bool hasEraseRoot() const;691692// Infer machine operand types and check their consistency.693bool typecheckPatterns();694695/// For all PatFragPatterns, add a new entry in PatternAlternatives for each696/// PatternList it contains. This is multiplicative, so if we have 2697/// PatFrags with 3 alternatives each, we get 2*3 permutations added to698/// PermutationsToEmit. The "MaxPermutations" field controls how many699/// permutations are allowed before an error is emitted and this function700/// returns false. This is a simple safeguard to prevent combination of701/// PatFrags from generating enormous amounts of rules.702bool buildPermutationsToEmit();703704/// Checks additional semantics of the Patterns.705bool checkSemantics();706707/// Creates a new RuleMatcher with some boilerplate708/// settings/actions/predicates, and and adds it to \p OutRMs.709/// \see addFeaturePredicates too.710///711/// \param Alts Current set of alternatives, for debug comment.712/// \param AdditionalComment Comment string to be added to the713/// `DebugCommentAction`.714RuleMatcher &addRuleMatcher(const PatternAlternatives &Alts,715Twine AdditionalComment = "");716bool addFeaturePredicates(RuleMatcher &M);717718bool findRoots();719bool buildRuleOperandsTable();720721bool parseDefs(const DagInit &Def);722723bool emitMatchPattern(CodeExpansions &CE, const PatternAlternatives &Alts,724const InstructionPattern &IP);725bool emitMatchPattern(CodeExpansions &CE, const PatternAlternatives &Alts,726const AnyOpcodePattern &AOP);727728bool emitPatFragMatchPattern(CodeExpansions &CE,729const PatternAlternatives &Alts, RuleMatcher &RM,730InstructionMatcher *IM,731const PatFragPattern &PFP,732DenseSet<const Pattern *> &SeenPats);733734bool emitApplyPatterns(CodeExpansions &CE, RuleMatcher &M);735bool emitCXXMatchApply(CodeExpansions &CE, RuleMatcher &M,736ArrayRef<CXXPattern *> Matchers);737738// Recursively visits InstructionPatterns from P to build up the739// RuleMatcher actions.740bool emitInstructionApplyPattern(CodeExpansions &CE, RuleMatcher &M,741const InstructionPattern &P,742DenseSet<const Pattern *> &SeenPats,743StringMap<unsigned> &OperandToTempRegID);744745bool emitCodeGenInstructionApplyImmOperand(RuleMatcher &M,746BuildMIAction &DstMI,747const CodeGenInstructionPattern &P,748const InstructionOperand &O);749750bool emitBuiltinApplyPattern(CodeExpansions &CE, RuleMatcher &M,751const BuiltinPattern &P,752StringMap<unsigned> &OperandToTempRegID);753754// Recursively visits CodeGenInstructionPattern from P to build up the755// RuleMatcher/InstructionMatcher. May create new InstructionMatchers as756// needed.757using OperandMapperFnRef =758function_ref<InstructionOperand(const InstructionOperand &)>;759using OperandDefLookupFn =760function_ref<const InstructionPattern *(StringRef)>;761bool emitCodeGenInstructionMatchPattern(762CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &M,763InstructionMatcher &IM, const CodeGenInstructionPattern &P,764DenseSet<const Pattern *> &SeenPats, OperandDefLookupFn LookupOperandDef,765OperandMapperFnRef OperandMapper = [](const auto &O) { return O; });766767PatternParser Parser;768const CodeGenTarget &CGT;769SubtargetFeatureInfoMap &SubtargetFeatures;770Record &RuleDef;771const unsigned RuleID;772std::vector<RuleMatcher> &OutRMs;773774// For InstructionMatcher::addOperand775unsigned AllocatedTemporariesBaseID = 0;776777/// The root of the pattern.778StringRef RootName;779780/// These maps have ownership of the actual Pattern objects.781/// They both map a Pattern's name to the Pattern instance.782PatternMap MatchPats;783PatternMap ApplyPats;784785/// Operand tables to tie match/apply patterns together.786OperandTable MatchOpTable;787OperandTable ApplyOpTable;788789/// Set by findRoots.790Pattern *MatchRoot = nullptr;791SmallDenseSet<InstructionPattern *, 2> ApplyRoots;792793SmallVector<MatchDataDef, 2> MatchDatas;794SmallVector<PatternAlternatives, 1> PermutationsToEmit;795};796797bool CombineRuleBuilder::parseAll() {798auto StackTrace = PrettyStackTraceParse(RuleDef);799800if (!parseDefs(*RuleDef.getValueAsDag("Defs")))801return false;802803if (!Parser.parsePatternList(804*RuleDef.getValueAsDag("Match"),805[this](auto Pat) { return addMatchPattern(std::move(Pat)); }, "match",806(RuleDef.getName() + "_match").str()))807return false;808809if (!Parser.parsePatternList(810*RuleDef.getValueAsDag("Apply"),811[this](auto Pat) { return addApplyPattern(std::move(Pat)); }, "apply",812(RuleDef.getName() + "_apply").str()))813return false;814815if (!buildRuleOperandsTable() || !typecheckPatterns() || !findRoots() ||816!checkSemantics() || !buildPermutationsToEmit())817return false;818LLVM_DEBUG(verify());819return true;820}821822bool CombineRuleBuilder::emitRuleMatchers() {823auto StackTrace = PrettyStackTraceEmit(RuleDef);824825assert(MatchRoot);826CodeExpansions CE;827828assert(!PermutationsToEmit.empty());829for (const auto &Alts : PermutationsToEmit) {830switch (MatchRoot->getKind()) {831case Pattern::K_AnyOpcode: {832if (!emitMatchPattern(CE, Alts, *cast<AnyOpcodePattern>(MatchRoot)))833return false;834break;835}836case Pattern::K_PatFrag:837case Pattern::K_Builtin:838case Pattern::K_CodeGenInstruction:839if (!emitMatchPattern(CE, Alts, *cast<InstructionPattern>(MatchRoot)))840return false;841break;842case Pattern::K_CXX:843PrintError("C++ code cannot be the root of a rule!");844return false;845default:846llvm_unreachable("unknown pattern kind!");847}848}849850return true;851}852853void CombineRuleBuilder::print(raw_ostream &OS) const {854OS << "(CombineRule name:" << RuleDef.getName() << " id:" << RuleID855<< " root:" << RootName << '\n';856857if (!MatchDatas.empty()) {858OS << " (MatchDatas\n";859for (const auto &MD : MatchDatas) {860OS << " (MatchDataDef symbol:" << MD.Symbol << " type:" << MD.Type861<< ")\n";862}863OS << " )\n";864}865866const auto &SeenPFs = Parser.getSeenPatFrags();867if (!SeenPFs.empty()) {868OS << " (PatFrags\n";869for (const auto *PF : Parser.getSeenPatFrags()) {870PF->print(OS, /*Indent=*/" ");871OS << '\n';872}873OS << " )\n";874}875876const auto DumpPats = [&](StringRef Name, const PatternMap &Pats) {877OS << " (" << Name << " ";878if (Pats.empty()) {879OS << "<empty>)\n";880return;881}882883OS << '\n';884for (const auto &[Name, Pat] : Pats) {885OS << " ";886if (Pat.get() == MatchRoot)887OS << "<match_root>";888if (isa<InstructionPattern>(Pat.get()) &&889ApplyRoots.contains(cast<InstructionPattern>(Pat.get())))890OS << "<apply_root>";891OS << Name << ":";892Pat->print(OS, /*PrintName=*/false);893OS << '\n';894}895OS << " )\n";896};897898DumpPats("MatchPats", MatchPats);899DumpPats("ApplyPats", ApplyPats);900901MatchOpTable.print(OS, "MatchPats", /*Indent*/ " ");902ApplyOpTable.print(OS, "ApplyPats", /*Indent*/ " ");903904if (PermutationsToEmit.size() > 1) {905OS << " (PermutationsToEmit\n";906for (const auto &Perm : PermutationsToEmit) {907OS << " ";908print(OS, Perm);909OS << ",\n";910}911OS << " )\n";912}913914OS << ")\n";915}916917#ifndef NDEBUG918void CombineRuleBuilder::verify() const {919const auto VerifyPats = [&](const PatternMap &Pats) {920for (const auto &[Name, Pat] : Pats) {921if (!Pat)922PrintFatalError("null pattern in pattern map!");923924if (Name != Pat->getName()) {925Pat->dump();926PrintFatalError("Pattern name mismatch! Map name: " + Name +927", Pat name: " + Pat->getName());928}929930// Sanity check: the map should point to the same data as the Pattern.931// Both strings are allocated in the pool using insertStrRef.932if (Name.data() != Pat->getName().data()) {933dbgs() << "Map StringRef: '" << Name << "' @ "934<< (const void *)Name.data() << '\n';935dbgs() << "Pat String: '" << Pat->getName() << "' @ "936<< (const void *)Pat->getName().data() << '\n';937PrintFatalError("StringRef stored in the PatternMap is not referencing "938"the same string as its Pattern!");939}940}941};942943VerifyPats(MatchPats);944VerifyPats(ApplyPats);945946// Check there are no wip_match_opcode patterns in the "apply" patterns.947if (any_of(ApplyPats,948[&](auto &E) { return isa<AnyOpcodePattern>(E.second.get()); })) {949dump();950PrintFatalError(951"illegal wip_match_opcode pattern in the 'apply' patterns!");952}953954// Check there are no nullptrs in ApplyRoots.955if (ApplyRoots.contains(nullptr)) {956PrintFatalError(957"CombineRuleBuilder's ApplyRoots set contains a null pointer!");958}959}960#endif961962void CombineRuleBuilder::print(raw_ostream &OS,963const PatternAlternatives &Alts) const {964SmallVector<std::string, 1> Strings(965map_range(Alts, [](const auto &PatAndPerm) {966return PatAndPerm.first->getName().str() + "[" +967to_string(PatAndPerm.second) + "]";968}));969// Sort so output is deterministic for tests. Otherwise it's sorted by pointer970// values.971sort(Strings);972OS << "[" << join(Strings, ", ") << "]";973}974975bool CombineRuleBuilder::addApplyPattern(std::unique_ptr<Pattern> Pat) {976StringRef Name = Pat->getName();977if (ApplyPats.contains(Name)) {978PrintError("'" + Name + "' apply pattern defined more than once!");979return false;980}981982if (isa<AnyOpcodePattern>(Pat.get())) {983PrintError("'" + Name +984"': wip_match_opcode is not supported in apply patterns");985return false;986}987988if (isa<PatFragPattern>(Pat.get())) {989PrintError("'" + Name + "': using " + PatFrag::ClassName +990" is not supported in apply patterns");991return false;992}993994if (auto *CXXPat = dyn_cast<CXXPattern>(Pat.get()))995CXXPat->setIsApply();996997ApplyPats[Name] = std::move(Pat);998return true;999}10001001bool CombineRuleBuilder::addMatchPattern(std::unique_ptr<Pattern> Pat) {1002StringRef Name = Pat->getName();1003if (MatchPats.contains(Name)) {1004PrintError("'" + Name + "' match pattern defined more than once!");1005return false;1006}10071008// For now, none of the builtins can appear in 'match'.1009if (const auto *BP = dyn_cast<BuiltinPattern>(Pat.get())) {1010PrintError("'" + BP->getInstName() +1011"' cannot be used in a 'match' pattern");1012return false;1013}10141015MatchPats[Name] = std::move(Pat);1016return true;1017}10181019void CombineRuleBuilder::declareAllMatchDatasExpansions(1020CodeExpansions &CE) const {1021for (const auto &MD : MatchDatas)1022CE.declare(MD.Symbol, MD.getVarName());1023}10241025void CombineRuleBuilder::addCXXPredicate(RuleMatcher &M,1026const CodeExpansions &CE,1027const CXXPattern &P,1028const PatternAlternatives &Alts) {1029// FIXME: Hack so C++ code is executed last. May not work for more complex1030// patterns.1031auto &IM = *std::prev(M.insnmatchers().end());1032auto Loc = RuleDef.getLoc();1033const auto AddComment = [&](raw_ostream &OS) {1034OS << "// Pattern Alternatives: ";1035print(OS, Alts);1036OS << '\n';1037};1038const auto &ExpandedCode =1039DebugCXXPreds ? P.expandCode(CE, Loc, AddComment) : P.expandCode(CE, Loc);1040IM->addPredicate<GenericInstructionPredicateMatcher>(1041ExpandedCode.getEnumNameWithPrefix(CXXPredPrefix));1042}10431044bool CombineRuleBuilder::hasOnlyCXXApplyPatterns() const {1045return all_of(ApplyPats, [&](auto &Entry) {1046return isa<CXXPattern>(Entry.second.get());1047});1048}10491050bool CombineRuleBuilder::hasEraseRoot() const {1051return any_of(ApplyPats, [&](auto &Entry) {1052if (const auto *BP = dyn_cast<BuiltinPattern>(Entry.second.get()))1053return BP->getBuiltinKind() == BI_EraseRoot;1054return false;1055});1056}10571058bool CombineRuleBuilder::typecheckPatterns() {1059CombineRuleOperandTypeChecker OTC(RuleDef, MatchOpTable);10601061for (auto &Pat : values(MatchPats)) {1062if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {1063if (!OTC.processMatchPattern(*IP))1064return false;1065}1066}10671068for (auto &Pat : values(ApplyPats)) {1069if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {1070if (!OTC.processApplyPattern(*IP))1071return false;1072}1073}10741075OTC.propagateAndInferTypes();10761077// Always check this after in case inference adds some special types to the1078// match patterns.1079for (auto &Pat : values(MatchPats)) {1080if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {1081if (IP->diagnoseAllSpecialTypes(1082RuleDef.getLoc(), PatternType::SpecialTyClassName +1083" is not supported in 'match' patterns")) {1084return false;1085}1086}1087}1088return true;1089}10901091bool CombineRuleBuilder::buildPermutationsToEmit() {1092PermutationsToEmit.clear();10931094// Start with one empty set of alternatives.1095PermutationsToEmit.emplace_back();1096for (const auto &Pat : values(MatchPats)) {1097unsigned NumAlts = 0;1098// Note: technically, AnyOpcodePattern also needs permutations, but:1099// - We only allow a single one of them in the root.1100// - They cannot be mixed with any other pattern other than C++ code.1101// So we don't really need to take them into account here. We could, but1102// that pattern is a hack anyway and the less it's involved, the better.1103if (const auto *PFP = dyn_cast<PatFragPattern>(Pat.get()))1104NumAlts = PFP->getPatFrag().num_alternatives();1105else1106continue;11071108// For each pattern that needs permutations, multiply the current set of1109// alternatives.1110auto CurPerms = PermutationsToEmit;1111PermutationsToEmit.clear();11121113for (const auto &Perm : CurPerms) {1114assert(!Perm.count(Pat.get()) && "Pattern already emitted?");1115for (unsigned K = 0; K < NumAlts; ++K) {1116PatternAlternatives NewPerm = Perm;1117NewPerm[Pat.get()] = K;1118PermutationsToEmit.emplace_back(std::move(NewPerm));1119}1120}1121}11221123if (int64_t MaxPerms = RuleDef.getValueAsInt("MaxPermutations");1124MaxPerms > 0) {1125if ((int64_t)PermutationsToEmit.size() > MaxPerms) {1126PrintError("cannot emit rule '" + RuleDef.getName() + "'; " +1127Twine(PermutationsToEmit.size()) +1128" permutations would be emitted, but the max is " +1129Twine(MaxPerms));1130return false;1131}1132}11331134// Ensure we always have a single empty entry, it simplifies the emission1135// logic so it doesn't need to handle the case where there are no perms.1136if (PermutationsToEmit.empty()) {1137PermutationsToEmit.emplace_back();1138return true;1139}11401141return true;1142}11431144bool CombineRuleBuilder::checkSemantics() {1145assert(MatchRoot && "Cannot call this before findRoots()");11461147bool UsesWipMatchOpcode = false;1148for (const auto &Match : MatchPats) {1149const auto *Pat = Match.second.get();11501151if (const auto *CXXPat = dyn_cast<CXXPattern>(Pat)) {1152if (!CXXPat->getRawCode().contains("return "))1153PrintWarning("'match' C++ code does not seem to return!");1154continue;1155}11561157// MIFlags in match cannot use the following syntax: (MIFlags $mi)1158if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(Pat)) {1159if (auto *FI = CGP->getMIFlagsInfo()) {1160if (!FI->copy_flags().empty()) {1161PrintError(1162"'match' patterns cannot refer to flags from other instructions");1163PrintNote("MIFlags in '" + CGP->getName() +1164"' refer to: " + join(FI->copy_flags(), ", "));1165return false;1166}1167}1168}11691170const auto *AOP = dyn_cast<AnyOpcodePattern>(Pat);1171if (!AOP)1172continue;11731174if (UsesWipMatchOpcode) {1175PrintError("wip_opcode_match can only be present once");1176return false;1177}11781179UsesWipMatchOpcode = true;1180}11811182std::optional<bool> IsUsingCXXPatterns;1183for (const auto &Apply : ApplyPats) {1184Pattern *Pat = Apply.second.get();1185if (IsUsingCXXPatterns) {1186if (*IsUsingCXXPatterns != isa<CXXPattern>(Pat)) {1187PrintError("'apply' patterns cannot mix C++ code with other types of "1188"patterns");1189return false;1190}1191} else1192IsUsingCXXPatterns = isa<CXXPattern>(Pat);11931194assert(Pat);1195const auto *IP = dyn_cast<InstructionPattern>(Pat);1196if (!IP)1197continue;11981199if (UsesWipMatchOpcode) {1200PrintError("cannot use wip_match_opcode in combination with apply "1201"instruction patterns!");1202return false;1203}12041205// Check that the insts mentioned in copy_flags exist.1206if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(IP)) {1207if (auto *FI = CGP->getMIFlagsInfo()) {1208for (auto InstName : FI->copy_flags()) {1209auto It = MatchPats.find(InstName);1210if (It == MatchPats.end()) {1211PrintError("unknown instruction '$" + InstName +1212"' referenced in MIFlags of '" + CGP->getName() + "'");1213return false;1214}12151216if (!isa<CodeGenInstructionPattern>(It->second.get())) {1217PrintError(1218"'$" + InstName +1219"' does not refer to a CodeGenInstruction in MIFlags of '" +1220CGP->getName() + "'");1221return false;1222}1223}1224}1225}12261227const auto *BIP = dyn_cast<BuiltinPattern>(IP);1228if (!BIP)1229continue;1230StringRef Name = BIP->getInstName();12311232// (GIEraseInst) has to be the only apply pattern, or it can not be used at1233// all. The root cannot have any defs either.1234switch (BIP->getBuiltinKind()) {1235case BI_EraseRoot: {1236if (ApplyPats.size() > 1) {1237PrintError(Name + " must be the only 'apply' pattern");1238return false;1239}12401241const auto *IRoot = dyn_cast<CodeGenInstructionPattern>(MatchRoot);1242if (!IRoot) {1243PrintError(Name + " can only be used if the root is a "1244"CodeGenInstruction or Intrinsic");1245return false;1246}12471248if (IRoot->getNumInstDefs() != 0) {1249PrintError(Name + " can only be used if on roots that do "1250"not have any output operand");1251PrintNote("'" + IRoot->getInstName() + "' has " +1252Twine(IRoot->getNumInstDefs()) + " output operands");1253return false;1254}1255break;1256}1257case BI_ReplaceReg: {1258// (GIReplaceReg can only be used on the root instruction)1259// TODO: When we allow rewriting non-root instructions, also allow this.1260StringRef OldRegName = BIP->getOperand(0).getOperandName();1261auto *Def = MatchOpTable.getDef(OldRegName);1262if (!Def) {1263PrintError(Name + " cannot find a matched pattern that defines '" +1264OldRegName + "'");1265return false;1266}1267if (MatchOpTable.getDef(OldRegName) != MatchRoot) {1268PrintError(Name + " cannot replace '" + OldRegName +1269"': this builtin can only replace a register defined by the "1270"match root");1271return false;1272}1273break;1274}1275}1276}12771278if (!hasOnlyCXXApplyPatterns() && !MatchDatas.empty()) {1279PrintError(MatchDataClassName +1280" can only be used if 'apply' in entirely written in C++");1281return false;1282}12831284return true;1285}12861287RuleMatcher &CombineRuleBuilder::addRuleMatcher(const PatternAlternatives &Alts,1288Twine AdditionalComment) {1289auto &RM = OutRMs.emplace_back(RuleDef.getLoc());1290addFeaturePredicates(RM);1291RM.setPermanentGISelFlags(GISF_IgnoreCopies);1292RM.addRequiredSimplePredicate(getIsEnabledPredicateEnumName(RuleID));12931294std::string Comment;1295raw_string_ostream CommentOS(Comment);1296CommentOS << "Combiner Rule #" << RuleID << ": " << RuleDef.getName();1297if (!Alts.empty()) {1298CommentOS << " @ ";1299print(CommentOS, Alts);1300}1301if (!AdditionalComment.isTriviallyEmpty())1302CommentOS << "; " << AdditionalComment;1303RM.addAction<DebugCommentAction>(Comment);1304return RM;1305}13061307bool CombineRuleBuilder::addFeaturePredicates(RuleMatcher &M) {1308if (!RuleDef.getValue("Predicates"))1309return true;13101311ListInit *Preds = RuleDef.getValueAsListInit("Predicates");1312for (Init *PI : Preds->getValues()) {1313DefInit *Pred = dyn_cast<DefInit>(PI);1314if (!Pred)1315continue;13161317Record *Def = Pred->getDef();1318if (!Def->isSubClassOf("Predicate")) {1319::PrintError(Def, "Unknown 'Predicate' Type");1320return false;1321}13221323if (Def->getValueAsString("CondString").empty())1324continue;13251326if (SubtargetFeatures.count(Def) == 0) {1327SubtargetFeatures.emplace(1328Def, SubtargetFeatureInfo(Def, SubtargetFeatures.size()));1329}13301331M.addRequiredFeature(Def);1332}13331334return true;1335}13361337bool CombineRuleBuilder::findRoots() {1338const auto Finish = [&]() {1339assert(MatchRoot);13401341if (hasOnlyCXXApplyPatterns() || hasEraseRoot())1342return true;13431344auto *IPRoot = dyn_cast<InstructionPattern>(MatchRoot);1345if (!IPRoot)1346return true;13471348if (IPRoot->getNumInstDefs() == 0) {1349// No defs to work with -> find the root using the pattern name.1350auto It = ApplyPats.find(RootName);1351if (It == ApplyPats.end()) {1352PrintError("Cannot find root '" + RootName + "' in apply patterns!");1353return false;1354}13551356auto *ApplyRoot = dyn_cast<InstructionPattern>(It->second.get());1357if (!ApplyRoot) {1358PrintError("apply pattern root '" + RootName +1359"' must be an instruction pattern");1360return false;1361}13621363ApplyRoots.insert(ApplyRoot);1364return true;1365}13661367// Collect all redefinitions of the MatchRoot's defs and put them in1368// ApplyRoots.1369const auto DefsNeeded = IPRoot->getApplyDefsNeeded();1370for (auto &Op : DefsNeeded) {1371assert(Op.isDef() && Op.isNamedOperand());1372StringRef Name = Op.getOperandName();13731374auto *ApplyRedef = ApplyOpTable.getDef(Name);1375if (!ApplyRedef) {1376PrintError("'" + Name + "' must be redefined in the 'apply' pattern");1377return false;1378}13791380ApplyRoots.insert((InstructionPattern *)ApplyRedef);1381}13821383if (auto It = ApplyPats.find(RootName); It != ApplyPats.end()) {1384if (find(ApplyRoots, It->second.get()) == ApplyRoots.end()) {1385PrintError("apply pattern '" + RootName +1386"' is supposed to be a root but it does not redefine any of "1387"the defs of the match root");1388return false;1389}1390}13911392return true;1393};13941395// Look by pattern name, e.g.1396// (G_FNEG $x, $y):$root1397if (auto MatchPatIt = MatchPats.find(RootName);1398MatchPatIt != MatchPats.end()) {1399MatchRoot = MatchPatIt->second.get();1400return Finish();1401}14021403// Look by def:1404// (G_FNEG $root, $y)1405auto LookupRes = MatchOpTable.lookup(RootName);1406if (!LookupRes.Found) {1407PrintError("Cannot find root '" + RootName + "' in match patterns!");1408return false;1409}14101411MatchRoot = LookupRes.Def;1412if (!MatchRoot) {1413PrintError("Cannot use live-in operand '" + RootName +1414"' as match pattern root!");1415return false;1416}14171418return Finish();1419}14201421bool CombineRuleBuilder::buildRuleOperandsTable() {1422const auto DiagnoseRedefMatch = [&](StringRef OpName) {1423PrintError("Operand '" + OpName +1424"' is defined multiple times in the 'match' patterns");1425};14261427const auto DiagnoseRedefApply = [&](StringRef OpName) {1428PrintError("Operand '" + OpName +1429"' is defined multiple times in the 'apply' patterns");1430};14311432for (auto &Pat : values(MatchPats)) {1433auto *IP = dyn_cast<InstructionPattern>(Pat.get());1434if (IP && !MatchOpTable.addPattern(IP, DiagnoseRedefMatch))1435return false;1436}14371438for (auto &Pat : values(ApplyPats)) {1439auto *IP = dyn_cast<InstructionPattern>(Pat.get());1440if (IP && !ApplyOpTable.addPattern(IP, DiagnoseRedefApply))1441return false;1442}14431444return true;1445}14461447bool CombineRuleBuilder::parseDefs(const DagInit &Def) {1448if (Def.getOperatorAsDef(RuleDef.getLoc())->getName() != "defs") {1449PrintError("Expected defs operator");1450return false;1451}14521453SmallVector<StringRef> Roots;1454for (unsigned I = 0, E = Def.getNumArgs(); I < E; ++I) {1455if (isSpecificDef(*Def.getArg(I), "root")) {1456Roots.emplace_back(Def.getArgNameStr(I));1457continue;1458}14591460// Subclasses of GIDefMatchData should declare that this rule needs to pass1461// data from the match stage to the apply stage, and ensure that the1462// generated matcher has a suitable variable for it to do so.1463if (Record *MatchDataRec =1464getDefOfSubClass(*Def.getArg(I), MatchDataClassName)) {1465MatchDatas.emplace_back(Def.getArgNameStr(I),1466MatchDataRec->getValueAsString("Type"));1467continue;1468}14691470// Otherwise emit an appropriate error message.1471if (getDefOfSubClass(*Def.getArg(I), "GIDefKind"))1472PrintError("This GIDefKind not implemented in tablegen");1473else if (getDefOfSubClass(*Def.getArg(I), "GIDefKindWithArgs"))1474PrintError("This GIDefKindWithArgs not implemented in tablegen");1475else1476PrintError("Expected a subclass of GIDefKind or a sub-dag whose "1477"operator is of type GIDefKindWithArgs");1478return false;1479}14801481if (Roots.size() != 1) {1482PrintError("Combine rules must have exactly one root");1483return false;1484}14851486RootName = Roots.front();1487return true;1488}14891490bool CombineRuleBuilder::emitMatchPattern(CodeExpansions &CE,1491const PatternAlternatives &Alts,1492const InstructionPattern &IP) {1493auto StackTrace = PrettyStackTraceEmit(RuleDef, &IP);14941495auto &M = addRuleMatcher(Alts);1496InstructionMatcher &IM = M.addInstructionMatcher(IP.getName());1497declareInstExpansion(CE, IM, IP.getName());14981499DenseSet<const Pattern *> SeenPats;15001501const auto FindOperandDef = [&](StringRef Op) -> InstructionPattern * {1502return MatchOpTable.getDef(Op);1503};15041505if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&IP)) {1506if (!emitCodeGenInstructionMatchPattern(CE, Alts, M, IM, *CGP, SeenPats,1507FindOperandDef))1508return false;1509} else if (const auto *PFP = dyn_cast<PatFragPattern>(&IP)) {1510if (!PFP->getPatFrag().canBeMatchRoot()) {1511PrintError("cannot use '" + PFP->getInstName() + " as match root");1512return false;1513}15141515if (!emitPatFragMatchPattern(CE, Alts, M, &IM, *PFP, SeenPats))1516return false;1517} else if (isa<BuiltinPattern>(&IP)) {1518llvm_unreachable("No match builtins known!");1519} else1520llvm_unreachable("Unknown kind of InstructionPattern!");15211522// Emit remaining patterns1523const bool IsUsingCustomCXXAction = hasOnlyCXXApplyPatterns();1524SmallVector<CXXPattern *, 2> CXXMatchers;1525for (auto &Pat : values(MatchPats)) {1526if (SeenPats.contains(Pat.get()))1527continue;15281529switch (Pat->getKind()) {1530case Pattern::K_AnyOpcode:1531PrintError("wip_match_opcode can not be used with instruction patterns!");1532return false;1533case Pattern::K_PatFrag: {1534if (!emitPatFragMatchPattern(CE, Alts, M, /*IM*/ nullptr,1535*cast<PatFragPattern>(Pat.get()), SeenPats))1536return false;1537continue;1538}1539case Pattern::K_Builtin:1540PrintError("No known match builtins");1541return false;1542case Pattern::K_CodeGenInstruction:1543cast<InstructionPattern>(Pat.get())->reportUnreachable(RuleDef.getLoc());1544return false;1545case Pattern::K_CXX: {1546// Delay emission for top-level C++ matchers (which can use MatchDatas).1547if (IsUsingCustomCXXAction)1548CXXMatchers.push_back(cast<CXXPattern>(Pat.get()));1549else1550addCXXPredicate(M, CE, *cast<CXXPattern>(Pat.get()), Alts);1551continue;1552}1553default:1554llvm_unreachable("unknown pattern kind!");1555}1556}15571558return IsUsingCustomCXXAction ? emitCXXMatchApply(CE, M, CXXMatchers)1559: emitApplyPatterns(CE, M);1560}15611562bool CombineRuleBuilder::emitMatchPattern(CodeExpansions &CE,1563const PatternAlternatives &Alts,1564const AnyOpcodePattern &AOP) {1565auto StackTrace = PrettyStackTraceEmit(RuleDef, &AOP);15661567const bool IsUsingCustomCXXAction = hasOnlyCXXApplyPatterns();1568for (const CodeGenInstruction *CGI : AOP.insts()) {1569auto &M = addRuleMatcher(Alts, "wip_match_opcode '" +1570CGI->TheDef->getName() + "'");15711572InstructionMatcher &IM = M.addInstructionMatcher(AOP.getName());1573declareInstExpansion(CE, IM, AOP.getName());1574// declareInstExpansion needs to be identical, otherwise we need to create a1575// CodeExpansions object here instead.1576assert(IM.getInsnVarID() == 0);15771578IM.addPredicate<InstructionOpcodeMatcher>(CGI);15791580// Emit remaining patterns.1581SmallVector<CXXPattern *, 2> CXXMatchers;1582for (auto &Pat : values(MatchPats)) {1583if (Pat.get() == &AOP)1584continue;15851586switch (Pat->getKind()) {1587case Pattern::K_AnyOpcode:1588PrintError("wip_match_opcode can only be present once!");1589return false;1590case Pattern::K_PatFrag: {1591DenseSet<const Pattern *> SeenPats;1592if (!emitPatFragMatchPattern(CE, Alts, M, /*IM*/ nullptr,1593*cast<PatFragPattern>(Pat.get()),1594SeenPats))1595return false;1596continue;1597}1598case Pattern::K_Builtin:1599PrintError("No known match builtins");1600return false;1601case Pattern::K_CodeGenInstruction:1602cast<InstructionPattern>(Pat.get())->reportUnreachable(1603RuleDef.getLoc());1604return false;1605case Pattern::K_CXX: {1606// Delay emission for top-level C++ matchers (which can use MatchDatas).1607if (IsUsingCustomCXXAction)1608CXXMatchers.push_back(cast<CXXPattern>(Pat.get()));1609else1610addCXXPredicate(M, CE, *cast<CXXPattern>(Pat.get()), Alts);1611break;1612}1613default:1614llvm_unreachable("unknown pattern kind!");1615}1616}16171618const bool Res = IsUsingCustomCXXAction1619? emitCXXMatchApply(CE, M, CXXMatchers)1620: emitApplyPatterns(CE, M);1621if (!Res)1622return false;1623}16241625return true;1626}16271628bool CombineRuleBuilder::emitPatFragMatchPattern(1629CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &RM,1630InstructionMatcher *IM, const PatFragPattern &PFP,1631DenseSet<const Pattern *> &SeenPats) {1632auto StackTrace = PrettyStackTraceEmit(RuleDef, &PFP);16331634if (SeenPats.contains(&PFP))1635return true;1636SeenPats.insert(&PFP);16371638const auto &PF = PFP.getPatFrag();16391640if (!IM) {1641// When we don't have an IM, this means this PatFrag isn't reachable from1642// the root. This is only acceptable if it doesn't define anything (e.g. a1643// pure C++ PatFrag).1644if (PF.num_out_params() != 0) {1645PFP.reportUnreachable(RuleDef.getLoc());1646return false;1647}1648} else {1649// When an IM is provided, this is reachable from the root, and we're1650// expecting to have output operands.1651// TODO: If we want to allow for multiple roots we'll need a map of IMs1652// then, and emission becomes a bit more complicated.1653assert(PF.num_roots() == 1);1654}16551656CodeExpansions PatFragCEs;1657if (!PFP.mapInputCodeExpansions(CE, PatFragCEs, RuleDef.getLoc()))1658return false;16591660// List of {ParamName, ArgName}.1661// When all patterns have been emitted, find expansions in PatFragCEs named1662// ArgName and add their expansion to CE using ParamName as the key.1663SmallVector<std::pair<std::string, std::string>, 4> CEsToImport;16641665// Map parameter names to the actual argument.1666const auto OperandMapper =1667[&](const InstructionOperand &O) -> InstructionOperand {1668if (!O.isNamedOperand())1669return O;16701671StringRef ParamName = O.getOperandName();16721673// Not sure what to do with those tbh. They should probably never be here.1674assert(!O.isNamedImmediate() && "TODO: handle named imms");1675unsigned PIdx = PF.getParamIdx(ParamName);16761677// Map parameters to the argument values.1678if (PIdx == (unsigned)-1) {1679// This is a temp of the PatFragPattern, prefix the name to avoid1680// conflicts.1681return O.withNewName(1682insertStrRef((PFP.getName() + "." + ParamName).str()));1683}16841685// The operand will be added to PatFragCEs's code expansions using the1686// parameter's name. If it's bound to some operand during emission of the1687// patterns, we'll want to add it to CE.1688auto ArgOp = PFP.getOperand(PIdx);1689if (ArgOp.isNamedOperand())1690CEsToImport.emplace_back(ArgOp.getOperandName().str(), ParamName);16911692if (ArgOp.getType() && O.getType() && ArgOp.getType() != O.getType()) {1693StringRef PFName = PF.getName();1694PrintWarning("impossible type constraints: operand " + Twine(PIdx) +1695" of '" + PFP.getName() + "' has type '" +1696ArgOp.getType().str() + "', but '" + PFName +1697"' constrains it to '" + O.getType().str() + "'");1698if (ArgOp.isNamedOperand())1699PrintNote("operand " + Twine(PIdx) + " of '" + PFP.getName() +1700"' is '" + ArgOp.getOperandName() + "'");1701if (O.isNamedOperand())1702PrintNote("argument " + Twine(PIdx) + " of '" + PFName + "' is '" +1703ParamName + "'");1704}17051706return ArgOp;1707};17081709// PatFragPatterns are only made of InstructionPatterns or CXXPatterns.1710// Emit instructions from the root.1711const auto &FragAlt = PF.getAlternative(Alts.lookup(&PFP));1712const auto &FragAltOT = FragAlt.OpTable;1713const auto LookupOperandDef =1714[&](StringRef Op) -> const InstructionPattern * {1715return FragAltOT.getDef(Op);1716};17171718DenseSet<const Pattern *> PatFragSeenPats;1719for (const auto &[Idx, InOp] : enumerate(PF.out_params())) {1720if (InOp.Kind != PatFrag::PK_Root)1721continue;17221723StringRef ParamName = InOp.Name;1724const auto *Def = FragAltOT.getDef(ParamName);1725assert(Def && "PatFrag::checkSemantics should have emitted an error if "1726"an out operand isn't defined!");1727assert(isa<CodeGenInstructionPattern>(Def) &&1728"Nested PatFrags not supported yet");17291730if (!emitCodeGenInstructionMatchPattern(1731PatFragCEs, Alts, RM, *IM, *cast<CodeGenInstructionPattern>(Def),1732PatFragSeenPats, LookupOperandDef, OperandMapper))1733return false;1734}17351736// Emit leftovers.1737for (const auto &Pat : FragAlt.Pats) {1738if (PatFragSeenPats.contains(Pat.get()))1739continue;17401741if (const auto *CXXPat = dyn_cast<CXXPattern>(Pat.get())) {1742addCXXPredicate(RM, PatFragCEs, *CXXPat, Alts);1743continue;1744}17451746if (const auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {1747IP->reportUnreachable(PF.getLoc());1748return false;1749}17501751llvm_unreachable("Unexpected pattern kind in PatFrag");1752}17531754for (const auto &[ParamName, ArgName] : CEsToImport) {1755// Note: we're find if ParamName already exists. It just means it's been1756// bound before, so we prefer to keep the first binding.1757CE.declare(ParamName, PatFragCEs.lookup(ArgName));1758}17591760return true;1761}17621763bool CombineRuleBuilder::emitApplyPatterns(CodeExpansions &CE, RuleMatcher &M) {1764assert(MatchDatas.empty());17651766DenseSet<const Pattern *> SeenPats;1767StringMap<unsigned> OperandToTempRegID;17681769for (auto *ApplyRoot : ApplyRoots) {1770assert(isa<InstructionPattern>(ApplyRoot) &&1771"Root can only be a InstructionPattern!");1772if (!emitInstructionApplyPattern(CE, M,1773cast<InstructionPattern>(*ApplyRoot),1774SeenPats, OperandToTempRegID))1775return false;1776}17771778for (auto &Pat : values(ApplyPats)) {1779if (SeenPats.contains(Pat.get()))1780continue;17811782switch (Pat->getKind()) {1783case Pattern::K_AnyOpcode:1784llvm_unreachable("Unexpected pattern in apply!");1785case Pattern::K_PatFrag:1786// TODO: We could support pure C++ PatFrags as a temporary thing.1787llvm_unreachable("Unexpected pattern in apply!");1788case Pattern::K_Builtin:1789if (!emitInstructionApplyPattern(CE, M, cast<BuiltinPattern>(*Pat),1790SeenPats, OperandToTempRegID))1791return false;1792break;1793case Pattern::K_CodeGenInstruction:1794cast<CodeGenInstructionPattern>(*Pat).reportUnreachable(RuleDef.getLoc());1795return false;1796case Pattern::K_CXX: {1797llvm_unreachable(1798"CXX Pattern Emission should have been handled earlier!");1799}1800default:1801llvm_unreachable("unknown pattern kind!");1802}1803}18041805// Erase the root.1806unsigned RootInsnID =1807M.getInsnVarID(M.getInstructionMatcher(MatchRoot->getName()));1808M.addAction<EraseInstAction>(RootInsnID);18091810return true;1811}18121813bool CombineRuleBuilder::emitCXXMatchApply(CodeExpansions &CE, RuleMatcher &M,1814ArrayRef<CXXPattern *> Matchers) {1815assert(hasOnlyCXXApplyPatterns());1816declareAllMatchDatasExpansions(CE);18171818std::string CodeStr;1819raw_string_ostream OS(CodeStr);18201821for (auto &MD : MatchDatas)1822OS << MD.Type << " " << MD.getVarName() << ";\n";18231824if (!Matchers.empty()) {1825OS << "// Match Patterns\n";1826for (auto *M : Matchers) {1827OS << "if(![&](){";1828CodeExpander Expander(M->getRawCode(), CE, RuleDef.getLoc(),1829/*ShowExpansions=*/false);1830Expander.emit(OS);1831OS << "}()) {\n"1832<< " return false;\n}\n";1833}1834}18351836OS << "// Apply Patterns\n";1837ListSeparator LS("\n");1838for (auto &Pat : ApplyPats) {1839auto *CXXPat = cast<CXXPattern>(Pat.second.get());1840CodeExpander Expander(CXXPat->getRawCode(), CE, RuleDef.getLoc(),1841/*ShowExpansions=*/ false);1842OS << LS;1843Expander.emit(OS);1844}18451846const auto &Code = CXXPredicateCode::getCustomActionCode(CodeStr);1847M.setCustomCXXAction(Code.getEnumNameWithPrefix(CXXCustomActionPrefix));1848return true;1849}18501851bool CombineRuleBuilder::emitInstructionApplyPattern(1852CodeExpansions &CE, RuleMatcher &M, const InstructionPattern &P,1853DenseSet<const Pattern *> &SeenPats,1854StringMap<unsigned> &OperandToTempRegID) {1855auto StackTrace = PrettyStackTraceEmit(RuleDef, &P);18561857if (SeenPats.contains(&P))1858return true;18591860SeenPats.insert(&P);18611862// First, render the uses.1863for (auto &Op : P.named_operands()) {1864if (Op.isDef())1865continue;18661867StringRef OpName = Op.getOperandName();1868if (const auto *DefPat = ApplyOpTable.getDef(OpName)) {1869if (!emitInstructionApplyPattern(CE, M, *DefPat, SeenPats,1870OperandToTempRegID))1871return false;1872} else {1873// If we have no def, check this exists in the MatchRoot.1874if (!Op.isNamedImmediate() && !MatchOpTable.lookup(OpName).Found) {1875PrintError("invalid output operand '" + OpName +1876"': operand is not a live-in of the match pattern, and it "1877"has no definition");1878return false;1879}1880}1881}18821883if (const auto *BP = dyn_cast<BuiltinPattern>(&P))1884return emitBuiltinApplyPattern(CE, M, *BP, OperandToTempRegID);18851886if (isa<PatFragPattern>(&P))1887llvm_unreachable("PatFragPatterns is not supported in 'apply'!");18881889auto &CGIP = cast<CodeGenInstructionPattern>(P);18901891// Now render this inst.1892auto &DstMI =1893M.addAction<BuildMIAction>(M.allocateOutputInsnID(), &CGIP.getInst());18941895bool HasEmittedIntrinsicID = false;1896const auto EmitIntrinsicID = [&]() {1897assert(CGIP.isIntrinsic());1898DstMI.addRenderer<IntrinsicIDRenderer>(CGIP.getIntrinsic());1899HasEmittedIntrinsicID = true;1900};19011902for (auto &Op : P.operands()) {1903// Emit the intrinsic ID after the last def.1904if (CGIP.isIntrinsic() && !Op.isDef() && !HasEmittedIntrinsicID)1905EmitIntrinsicID();19061907if (Op.isNamedImmediate()) {1908PrintError("invalid output operand '" + Op.getOperandName() +1909"': output immediates cannot be named");1910PrintNote("while emitting pattern '" + P.getName() + "' (" +1911P.getInstName() + ")");1912return false;1913}19141915if (Op.hasImmValue()) {1916if (!emitCodeGenInstructionApplyImmOperand(M, DstMI, CGIP, Op))1917return false;1918continue;1919}19201921StringRef OpName = Op.getOperandName();19221923// Uses of operand.1924if (!Op.isDef()) {1925if (auto It = OperandToTempRegID.find(OpName);1926It != OperandToTempRegID.end()) {1927assert(!MatchOpTable.lookup(OpName).Found &&1928"Temp reg is also from match pattern?");1929DstMI.addRenderer<TempRegRenderer>(It->second);1930} else {1931// This should be a match live in or a redef of a matched instr.1932// If it's a use of a temporary register, then we messed up somewhere -1933// the previous condition should have passed.1934assert(MatchOpTable.lookup(OpName).Found &&1935!ApplyOpTable.getDef(OpName) && "Temp reg not emitted yet!");1936DstMI.addRenderer<CopyRenderer>(OpName);1937}1938continue;1939}19401941// Determine what we're dealing with. Are we replace a matched instruction?1942// Creating a new one?1943auto OpLookupRes = MatchOpTable.lookup(OpName);1944if (OpLookupRes.Found) {1945if (OpLookupRes.isLiveIn()) {1946// live-in of the match pattern.1947PrintError("Cannot define live-in operand '" + OpName +1948"' in the 'apply' pattern");1949return false;1950}1951assert(OpLookupRes.Def);19521953// TODO: Handle this. We need to mutate the instr, or delete the old1954// one.1955// Likewise, we also need to ensure we redef everything, if the1956// instr has more than one def, we need to redef all or nothing.1957if (OpLookupRes.Def != MatchRoot) {1958PrintError("redefining an instruction other than the root is not "1959"supported (operand '" +1960OpName + "')");1961return false;1962}1963// redef of a match1964DstMI.addRenderer<CopyRenderer>(OpName);1965continue;1966}19671968// Define a new register unique to the apply patterns (AKA a "temp"1969// register).1970unsigned TempRegID;1971if (auto It = OperandToTempRegID.find(OpName);1972It != OperandToTempRegID.end()) {1973TempRegID = It->second;1974} else {1975// This is a brand new register.1976TempRegID = M.allocateTempRegID();1977OperandToTempRegID[OpName] = TempRegID;1978const auto Ty = Op.getType();1979if (!Ty) {1980PrintError("def of a new register '" + OpName +1981"' in the apply patterns must have a type");1982return false;1983}19841985declareTempRegExpansion(CE, TempRegID, OpName);1986// Always insert the action at the beginning, otherwise we may end up1987// using the temp reg before it's available.1988M.insertAction<MakeTempRegisterAction>(1989M.actions_begin(), getLLTCodeGenOrTempType(Ty, M), TempRegID);1990}19911992DstMI.addRenderer<TempRegRenderer>(TempRegID, /*IsDef=*/true);1993}19941995// Some intrinsics have no in operands, ensure the ID is still emitted in such1996// cases.1997if (CGIP.isIntrinsic() && !HasEmittedIntrinsicID)1998EmitIntrinsicID();19992000// Render MIFlags2001if (const auto *FI = CGIP.getMIFlagsInfo()) {2002for (StringRef InstName : FI->copy_flags())2003DstMI.addCopiedMIFlags(M.getInstructionMatcher(InstName));2004for (StringRef F : FI->set_flags())2005DstMI.addSetMIFlags(F);2006for (StringRef F : FI->unset_flags())2007DstMI.addUnsetMIFlags(F);2008}20092010// Don't allow mutating opcodes for GISel combiners. We want a more precise2011// handling of MIFlags so we require them to be explicitly preserved.2012//2013// TODO: We don't mutate very often, if at all in combiners, but it'd be nice2014// to re-enable this. We'd then need to always clear MIFlags when mutating2015// opcodes, and never mutate an inst that we copy flags from.2016// DstMI.chooseInsnToMutate(M);2017declareInstExpansion(CE, DstMI, P.getName());20182019return true;2020}20212022bool CombineRuleBuilder::emitCodeGenInstructionApplyImmOperand(2023RuleMatcher &M, BuildMIAction &DstMI, const CodeGenInstructionPattern &P,2024const InstructionOperand &O) {2025// If we have a type, we implicitly emit a G_CONSTANT, except for G_CONSTANT2026// itself where we emit a CImm.2027//2028// No type means we emit a simple imm.2029// G_CONSTANT is a special case and needs a CImm though so this is likely a2030// mistake.2031const bool isGConstant = P.is("G_CONSTANT");2032const auto Ty = O.getType();2033if (!Ty) {2034if (isGConstant) {2035PrintError("'G_CONSTANT' immediate must be typed!");2036PrintNote("while emitting pattern '" + P.getName() + "' (" +2037P.getInstName() + ")");2038return false;2039}20402041DstMI.addRenderer<ImmRenderer>(O.getImmValue());2042return true;2043}20442045auto ImmTy = getLLTCodeGenOrTempType(Ty, M);20462047if (isGConstant) {2048DstMI.addRenderer<ImmRenderer>(O.getImmValue(), ImmTy);2049return true;2050}20512052unsigned TempRegID = M.allocateTempRegID();2053// Ensure MakeTempReg & the BuildConstantAction occur at the beginning.2054auto InsertIt = M.insertAction<MakeTempRegisterAction>(M.actions_begin(),2055ImmTy, TempRegID);2056M.insertAction<BuildConstantAction>(++InsertIt, TempRegID, O.getImmValue());2057DstMI.addRenderer<TempRegRenderer>(TempRegID);2058return true;2059}20602061bool CombineRuleBuilder::emitBuiltinApplyPattern(2062CodeExpansions &CE, RuleMatcher &M, const BuiltinPattern &P,2063StringMap<unsigned> &OperandToTempRegID) {2064const auto Error = [&](Twine Reason) {2065PrintError("cannot emit '" + P.getInstName() + "' builtin: " + Reason);2066return false;2067};20682069switch (P.getBuiltinKind()) {2070case BI_EraseRoot: {2071// Root is always inst 0.2072M.addAction<EraseInstAction>(/*InsnID*/ 0);2073return true;2074}2075case BI_ReplaceReg: {2076StringRef Old = P.getOperand(0).getOperandName();2077StringRef New = P.getOperand(1).getOperandName();20782079if (!ApplyOpTable.lookup(New).Found && !MatchOpTable.lookup(New).Found)2080return Error("unknown operand '" + Old + "'");20812082auto &OldOM = M.getOperandMatcher(Old);2083if (auto It = OperandToTempRegID.find(New);2084It != OperandToTempRegID.end()) {2085// Replace with temp reg.2086M.addAction<ReplaceRegAction>(OldOM.getInsnVarID(), OldOM.getOpIdx(),2087It->second);2088} else {2089// Replace with matched reg.2090auto &NewOM = M.getOperandMatcher(New);2091M.addAction<ReplaceRegAction>(OldOM.getInsnVarID(), OldOM.getOpIdx(),2092NewOM.getInsnVarID(), NewOM.getOpIdx());2093}2094// checkSemantics should have ensured that we can only rewrite the root.2095// Ensure we're deleting it.2096assert(MatchOpTable.getDef(Old) == MatchRoot);2097return true;2098}2099}21002101llvm_unreachable("Unknown BuiltinKind!");2102}21032104bool isLiteralImm(const InstructionPattern &P, unsigned OpIdx) {2105if (const auto *CGP = dyn_cast<CodeGenInstructionPattern>(&P)) {2106StringRef InstName = CGP->getInst().TheDef->getName();2107return (InstName == "G_CONSTANT" || InstName == "G_FCONSTANT") &&2108OpIdx == 1;2109}21102111llvm_unreachable("TODO");2112}21132114bool CombineRuleBuilder::emitCodeGenInstructionMatchPattern(2115CodeExpansions &CE, const PatternAlternatives &Alts, RuleMatcher &M,2116InstructionMatcher &IM, const CodeGenInstructionPattern &P,2117DenseSet<const Pattern *> &SeenPats, OperandDefLookupFn LookupOperandDef,2118OperandMapperFnRef OperandMapper) {2119auto StackTrace = PrettyStackTraceEmit(RuleDef, &P);21202121if (SeenPats.contains(&P))2122return true;21232124SeenPats.insert(&P);21252126IM.addPredicate<InstructionOpcodeMatcher>(&P.getInst());2127declareInstExpansion(CE, IM, P.getName());21282129// If this is an intrinsic, check the intrinsic ID.2130if (P.isIntrinsic()) {2131// The IntrinsicID's operand is the first operand after the defs.2132OperandMatcher &OM = IM.addOperand(P.getNumInstDefs(), "$intrinsic_id",2133AllocatedTemporariesBaseID++);2134OM.addPredicate<IntrinsicIDOperandMatcher>(P.getIntrinsic());2135}21362137// Check flags if needed.2138if (const auto *FI = P.getMIFlagsInfo()) {2139assert(FI->copy_flags().empty());21402141if (const auto &SetF = FI->set_flags(); !SetF.empty())2142IM.addPredicate<MIFlagsInstructionPredicateMatcher>(SetF.getArrayRef());2143if (const auto &UnsetF = FI->unset_flags(); !UnsetF.empty())2144IM.addPredicate<MIFlagsInstructionPredicateMatcher>(UnsetF.getArrayRef(),2145/*CheckNot=*/true);2146}21472148for (auto [Idx, OriginalO] : enumerate(P.operands())) {2149// Remap the operand. This is used when emitting InstructionPatterns inside2150// PatFrags, so it can remap them to the arguments passed to the pattern.2151//2152// We use the remapped operand to emit immediates, and for the symbolic2153// operand names (in IM.addOperand). CodeExpansions and OperandTable lookups2154// still use the original name.2155//2156// The "def" flag on the remapped operand is always ignored.2157auto RemappedO = OperandMapper(OriginalO);2158assert(RemappedO.isNamedOperand() == OriginalO.isNamedOperand() &&2159"Cannot remap an unnamed operand to a named one!");21602161const auto OpName =2162RemappedO.isNamedOperand() ? RemappedO.getOperandName().str() : "";21632164// For intrinsics, the first use operand is the intrinsic id, so the true2165// operand index is shifted by 1.2166//2167// From now on:2168// Idx = index in the pattern operand list.2169// RealIdx = expected index in the MachineInstr.2170const unsigned RealIdx =2171(P.isIntrinsic() && !OriginalO.isDef()) ? (Idx + 1) : Idx;2172OperandMatcher &OM =2173IM.addOperand(RealIdx, OpName, AllocatedTemporariesBaseID++);2174if (!OpName.empty())2175declareOperandExpansion(CE, OM, OriginalO.getOperandName());21762177// Handle immediates.2178if (RemappedO.hasImmValue()) {2179if (isLiteralImm(P, Idx))2180OM.addPredicate<LiteralIntOperandMatcher>(RemappedO.getImmValue());2181else2182OM.addPredicate<ConstantIntOperandMatcher>(RemappedO.getImmValue());2183}21842185// Handle typed operands, but only bother to check if it hasn't been done2186// before.2187//2188// getOperandMatcher will always return the first OM to have been created2189// for that Operand. "OM" here is always a new OperandMatcher.2190//2191// Always emit a check for unnamed operands.2192if (OpName.empty() ||2193!M.getOperandMatcher(OpName).contains<LLTOperandMatcher>()) {2194if (const auto Ty = RemappedO.getType()) {2195// TODO: We could support GITypeOf here on the condition that the2196// OperandMatcher exists already. Though it's clunky to make this work2197// and isn't all that useful so it's just rejected in typecheckPatterns2198// at this time.2199assert(Ty.isLLT() && "Only LLTs are supported in match patterns!");2200OM.addPredicate<LLTOperandMatcher>(getLLTCodeGen(Ty));2201}2202}22032204// Stop here if the operand is a def, or if it had no name.2205if (OriginalO.isDef() || !OriginalO.isNamedOperand())2206continue;22072208const auto *DefPat = LookupOperandDef(OriginalO.getOperandName());2209if (!DefPat)2210continue;22112212if (OriginalO.hasImmValue()) {2213assert(!OpName.empty());2214// This is a named immediate that also has a def, that's not okay.2215// e.g.2216// (G_SEXT $y, (i32 0))2217// (COPY $x, 42:$y)2218PrintError("'" + OpName +2219"' is a named immediate, it cannot be defined by another "2220"instruction");2221PrintNote("'" + OpName + "' is defined by '" + DefPat->getName() + "'");2222return false;2223}22242225// From here we know that the operand defines an instruction, and we need to2226// emit it.2227auto InstOpM =2228OM.addPredicate<InstructionOperandMatcher>(M, DefPat->getName());2229if (!InstOpM) {2230// TODO: copy-pasted from GlobalISelEmitter.cpp. Is it still relevant2231// here?2232PrintError("Nested instruction '" + DefPat->getName() +2233"' cannot be the same as another operand '" +2234OriginalO.getOperandName() + "'");2235return false;2236}22372238auto &IM = (*InstOpM)->getInsnMatcher();2239if (const auto *CGIDef = dyn_cast<CodeGenInstructionPattern>(DefPat)) {2240if (!emitCodeGenInstructionMatchPattern(CE, Alts, M, IM, *CGIDef,2241SeenPats, LookupOperandDef,2242OperandMapper))2243return false;2244continue;2245}22462247if (const auto *PFPDef = dyn_cast<PatFragPattern>(DefPat)) {2248if (!emitPatFragMatchPattern(CE, Alts, M, &IM, *PFPDef, SeenPats))2249return false;2250continue;2251}22522253llvm_unreachable("unknown type of InstructionPattern");2254}22552256return true;2257}22582259//===- GICombinerEmitter --------------------------------------------------===//22602261/// Main implementation class. This emits the tablegenerated output.2262///2263/// It collects rules, uses `CombineRuleBuilder` to parse them and accumulate2264/// RuleMatchers, then takes all the necessary state/data from the various2265/// static storage pools and wires them together to emit the match table &2266/// associated function/data structures.2267class GICombinerEmitter final : public GlobalISelMatchTableExecutorEmitter {2268RecordKeeper &Records;2269StringRef Name;2270const CodeGenTarget &Target;2271Record *Combiner;2272unsigned NextRuleID = 0;22732274// List all combine rules (ID, name) imported.2275// Note that the combiner rule ID is different from the RuleMatcher ID. The2276// latter is internal to the MatchTable, the former is the canonical ID of the2277// combine rule used to disable/enable it.2278std::vector<std::pair<unsigned, std::string>> AllCombineRules;22792280// Keep track of all rules we've seen so far to ensure we don't process2281// the same rule twice.2282StringSet<> RulesSeen;22832284MatchTable buildMatchTable(MutableArrayRef<RuleMatcher> Rules);22852286void emitRuleConfigImpl(raw_ostream &OS);22872288void emitAdditionalImpl(raw_ostream &OS) override;22892290void emitMIPredicateFns(raw_ostream &OS) override;2291void emitI64ImmPredicateFns(raw_ostream &OS) override;2292void emitAPFloatImmPredicateFns(raw_ostream &OS) override;2293void emitAPIntImmPredicateFns(raw_ostream &OS) override;2294void emitTestSimplePredicate(raw_ostream &OS) override;2295void emitRunCustomAction(raw_ostream &OS) override;22962297const CodeGenTarget &getTarget() const override { return Target; }2298StringRef getClassName() const override {2299return Combiner->getValueAsString("Classname");2300}23012302StringRef getCombineAllMethodName() const {2303return Combiner->getValueAsString("CombineAllMethodName");2304}23052306std::string getRuleConfigClassName() const {2307return getClassName().str() + "RuleConfig";2308}23092310void gatherRules(std::vector<RuleMatcher> &Rules,2311const std::vector<Record *> &&RulesAndGroups);23122313public:2314explicit GICombinerEmitter(RecordKeeper &RK, const CodeGenTarget &Target,2315StringRef Name, Record *Combiner);2316~GICombinerEmitter() {}23172318void run(raw_ostream &OS);2319};23202321void GICombinerEmitter::emitRuleConfigImpl(raw_ostream &OS) {2322OS << "struct " << getRuleConfigClassName() << " {\n"2323<< " SparseBitVector<> DisabledRules;\n\n"2324<< " bool isRuleEnabled(unsigned RuleID) const;\n"2325<< " bool parseCommandLineOption();\n"2326<< " bool setRuleEnabled(StringRef RuleIdentifier);\n"2327<< " bool setRuleDisabled(StringRef RuleIdentifier);\n"2328<< "};\n\n";23292330std::vector<std::pair<std::string, std::string>> Cases;2331Cases.reserve(AllCombineRules.size());23322333for (const auto &[ID, Name] : AllCombineRules)2334Cases.emplace_back(Name, "return " + to_string(ID) + ";\n");23352336OS << "static std::optional<uint64_t> getRuleIdxForIdentifier(StringRef "2337"RuleIdentifier) {\n"2338<< " uint64_t I;\n"2339<< " // getAtInteger(...) returns false on success\n"2340<< " bool Parsed = !RuleIdentifier.getAsInteger(0, I);\n"2341<< " if (Parsed)\n"2342<< " return I;\n\n"2343<< "#ifndef NDEBUG\n";2344StringMatcher Matcher("RuleIdentifier", Cases, OS);2345Matcher.Emit();2346OS << "#endif // ifndef NDEBUG\n\n"2347<< " return std::nullopt;\n"2348<< "}\n";23492350OS << "static std::optional<std::pair<uint64_t, uint64_t>> "2351"getRuleRangeForIdentifier(StringRef RuleIdentifier) {\n"2352<< " std::pair<StringRef, StringRef> RangePair = "2353"RuleIdentifier.split('-');\n"2354<< " if (!RangePair.second.empty()) {\n"2355<< " const auto First = "2356"getRuleIdxForIdentifier(RangePair.first);\n"2357<< " const auto Last = "2358"getRuleIdxForIdentifier(RangePair.second);\n"2359<< " if (!First || !Last)\n"2360<< " return std::nullopt;\n"2361<< " if (First >= Last)\n"2362<< " report_fatal_error(\"Beginning of range should be before "2363"end of range\");\n"2364<< " return {{*First, *Last + 1}};\n"2365<< " }\n"2366<< " if (RangePair.first == \"*\") {\n"2367<< " return {{0, " << AllCombineRules.size() << "}};\n"2368<< " }\n"2369<< " const auto I = getRuleIdxForIdentifier(RangePair.first);\n"2370<< " if (!I)\n"2371<< " return std::nullopt;\n"2372<< " return {{*I, *I + 1}};\n"2373<< "}\n\n";23742375for (bool Enabled : {true, false}) {2376OS << "bool " << getRuleConfigClassName() << "::setRule"2377<< (Enabled ? "Enabled" : "Disabled") << "(StringRef RuleIdentifier) {\n"2378<< " auto MaybeRange = getRuleRangeForIdentifier(RuleIdentifier);\n"2379<< " if (!MaybeRange)\n"2380<< " return false;\n"2381<< " for (auto I = MaybeRange->first; I < MaybeRange->second; ++I)\n"2382<< " DisabledRules." << (Enabled ? "reset" : "set") << "(I);\n"2383<< " return true;\n"2384<< "}\n\n";2385}23862387OS << "static std::vector<std::string> " << Name << "Option;\n"2388<< "static cl::list<std::string> " << Name << "DisableOption(\n"2389<< " \"" << Name.lower() << "-disable-rule\",\n"2390<< " cl::desc(\"Disable one or more combiner rules temporarily in "2391<< "the " << Name << " pass\"),\n"2392<< " cl::CommaSeparated,\n"2393<< " cl::Hidden,\n"2394<< " cl::cat(GICombinerOptionCategory),\n"2395<< " cl::callback([](const std::string &Str) {\n"2396<< " " << Name << "Option.push_back(Str);\n"2397<< " }));\n"2398<< "static cl::list<std::string> " << Name << "OnlyEnableOption(\n"2399<< " \"" << Name.lower() << "-only-enable-rule\",\n"2400<< " cl::desc(\"Disable all rules in the " << Name2401<< " pass then re-enable the specified ones\"),\n"2402<< " cl::Hidden,\n"2403<< " cl::cat(GICombinerOptionCategory),\n"2404<< " cl::callback([](const std::string &CommaSeparatedArg) {\n"2405<< " StringRef Str = CommaSeparatedArg;\n"2406<< " " << Name << "Option.push_back(\"*\");\n"2407<< " do {\n"2408<< " auto X = Str.split(\",\");\n"2409<< " " << Name << "Option.push_back((\"!\" + X.first).str());\n"2410<< " Str = X.second;\n"2411<< " } while (!Str.empty());\n"2412<< " }));\n"2413<< "\n\n"2414<< "bool " << getRuleConfigClassName()2415<< "::isRuleEnabled(unsigned RuleID) const {\n"2416<< " return !DisabledRules.test(RuleID);\n"2417<< "}\n"2418<< "bool " << getRuleConfigClassName() << "::parseCommandLineOption() {\n"2419<< " for (StringRef Identifier : " << Name << "Option) {\n"2420<< " bool Enabled = Identifier.consume_front(\"!\");\n"2421<< " if (Enabled && !setRuleEnabled(Identifier))\n"2422<< " return false;\n"2423<< " if (!Enabled && !setRuleDisabled(Identifier))\n"2424<< " return false;\n"2425<< " }\n"2426<< " return true;\n"2427<< "}\n\n";2428}24292430void GICombinerEmitter::emitAdditionalImpl(raw_ostream &OS) {2431OS << "bool " << getClassName() << "::" << getCombineAllMethodName()2432<< "(MachineInstr &I) const {\n"2433<< " const TargetSubtargetInfo &ST = MF.getSubtarget();\n"2434<< " const PredicateBitset AvailableFeatures = "2435"getAvailableFeatures();\n"2436<< " B.setInstrAndDebugLoc(I);\n"2437<< " State.MIs.clear();\n"2438<< " State.MIs.push_back(&I);\n"2439<< " if (executeMatchTable(*this, State, ExecInfo, B"2440<< ", getMatchTable(), *ST.getInstrInfo(), MRI, "2441"*MRI.getTargetRegisterInfo(), *ST.getRegBankInfo(), AvailableFeatures"2442<< ", /*CoverageInfo*/ nullptr)) {\n"2443<< " return true;\n"2444<< " }\n\n"2445<< " return false;\n"2446<< "}\n\n";2447}24482449void GICombinerEmitter::emitMIPredicateFns(raw_ostream &OS) {2450auto MatchCode = CXXPredicateCode::getAllMatchCode();2451emitMIPredicateFnsImpl<const CXXPredicateCode *>(2452OS, "", ArrayRef<const CXXPredicateCode *>(MatchCode),2453[](const CXXPredicateCode *C) -> StringRef { return C->BaseEnumName; },2454[](const CXXPredicateCode *C) -> StringRef { return C->Code; });2455}24562457void GICombinerEmitter::emitI64ImmPredicateFns(raw_ostream &OS) {2458// Unused, but still needs to be called.2459emitImmPredicateFnsImpl<unsigned>(2460OS, "I64", "int64_t", {}, [](unsigned) { return ""; },2461[](unsigned) { return ""; });2462}24632464void GICombinerEmitter::emitAPFloatImmPredicateFns(raw_ostream &OS) {2465// Unused, but still needs to be called.2466emitImmPredicateFnsImpl<unsigned>(2467OS, "APFloat", "const APFloat &", {}, [](unsigned) { return ""; },2468[](unsigned) { return ""; });2469}24702471void GICombinerEmitter::emitAPIntImmPredicateFns(raw_ostream &OS) {2472// Unused, but still needs to be called.2473emitImmPredicateFnsImpl<unsigned>(2474OS, "APInt", "const APInt &", {}, [](unsigned) { return ""; },2475[](unsigned) { return ""; });2476}24772478void GICombinerEmitter::emitTestSimplePredicate(raw_ostream &OS) {2479if (!AllCombineRules.empty()) {2480OS << "enum {\n";2481std::string EnumeratorSeparator = " = GICXXPred_Invalid + 1,\n";2482// To avoid emitting a switch, we expect that all those rules are in order.2483// That way we can just get the RuleID from the enum by subtracting2484// (GICXXPred_Invalid + 1).2485unsigned ExpectedID = 0;2486(void)ExpectedID;2487for (const auto &ID : keys(AllCombineRules)) {2488assert(ExpectedID++ == ID && "combine rules are not ordered!");2489OS << " " << getIsEnabledPredicateEnumName(ID) << EnumeratorSeparator;2490EnumeratorSeparator = ",\n";2491}2492OS << "};\n\n";2493}24942495OS << "bool " << getClassName()2496<< "::testSimplePredicate(unsigned Predicate) const {\n"2497<< " return RuleConfig.isRuleEnabled(Predicate - "2498"GICXXPred_Invalid - "2499"1);\n"2500<< "}\n";2501}25022503void GICombinerEmitter::emitRunCustomAction(raw_ostream &OS) {2504const auto CustomActionsCode = CXXPredicateCode::getAllCustomActionsCode();25052506if (!CustomActionsCode.empty()) {2507OS << "enum {\n";2508std::string EnumeratorSeparator = " = GICXXCustomAction_Invalid + 1,\n";2509for (const auto &CA : CustomActionsCode) {2510OS << " " << CA->getEnumNameWithPrefix(CXXCustomActionPrefix)2511<< EnumeratorSeparator;2512EnumeratorSeparator = ",\n";2513}2514OS << "};\n";2515}25162517OS << "bool " << getClassName()2518<< "::runCustomAction(unsigned ApplyID, const MatcherState &State, "2519"NewMIVector &OutMIs) const "2520"{\n Helper.getBuilder().setInstrAndDebugLoc(*State.MIs[0]);\n";2521if (!CustomActionsCode.empty()) {2522OS << " switch(ApplyID) {\n";2523for (const auto &CA : CustomActionsCode) {2524OS << " case " << CA->getEnumNameWithPrefix(CXXCustomActionPrefix)2525<< ":{\n"2526<< " " << join(split(CA->Code, '\n'), "\n ") << '\n'2527<< " return true;\n";2528OS << " }\n";2529}2530OS << " }\n";2531}2532OS << " llvm_unreachable(\"Unknown Apply Action\");\n"2533<< "}\n";2534}25352536GICombinerEmitter::GICombinerEmitter(RecordKeeper &RK,2537const CodeGenTarget &Target,2538StringRef Name, Record *Combiner)2539: Records(RK), Name(Name), Target(Target), Combiner(Combiner) {}25402541MatchTable2542GICombinerEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules) {2543std::vector<Matcher *> InputRules;2544for (Matcher &Rule : Rules)2545InputRules.push_back(&Rule);25462547unsigned CurrentOrdering = 0;2548StringMap<unsigned> OpcodeOrder;2549for (RuleMatcher &Rule : Rules) {2550const StringRef Opcode = Rule.getOpcode();2551assert(!Opcode.empty() && "Didn't expect an undefined opcode");2552if (OpcodeOrder.count(Opcode) == 0)2553OpcodeOrder[Opcode] = CurrentOrdering++;2554}25552556llvm::stable_sort(InputRules, [&OpcodeOrder](const Matcher *A,2557const Matcher *B) {2558auto *L = static_cast<const RuleMatcher *>(A);2559auto *R = static_cast<const RuleMatcher *>(B);2560return std::make_tuple(OpcodeOrder[L->getOpcode()], L->getNumOperands()) <2561std::make_tuple(OpcodeOrder[R->getOpcode()], R->getNumOperands());2562});25632564for (Matcher *Rule : InputRules)2565Rule->optimize();25662567std::vector<std::unique_ptr<Matcher>> MatcherStorage;2568std::vector<Matcher *> OptRules =2569optimizeRules<GroupMatcher>(InputRules, MatcherStorage);25702571for (Matcher *Rule : OptRules)2572Rule->optimize();25732574OptRules = optimizeRules<SwitchMatcher>(OptRules, MatcherStorage);25752576return MatchTable::buildTable(OptRules, /*WithCoverage*/ false,2577/*IsCombiner*/ true);2578}25792580/// Recurse into GICombineGroup's and flatten the ruleset into a simple list.2581void GICombinerEmitter::gatherRules(2582std::vector<RuleMatcher> &ActiveRules,2583const std::vector<Record *> &&RulesAndGroups) {2584for (Record *Rec : RulesAndGroups) {2585if (!Rec->isValueUnset("Rules")) {2586gatherRules(ActiveRules, Rec->getValueAsListOfDefs("Rules"));2587continue;2588}25892590StringRef RuleName = Rec->getName();2591if (!RulesSeen.insert(RuleName).second) {2592PrintWarning(Rec->getLoc(),2593"skipping rule '" + Rec->getName() +2594"' because it has already been processed");2595continue;2596}25972598AllCombineRules.emplace_back(NextRuleID, Rec->getName().str());2599CombineRuleBuilder CRB(Target, SubtargetFeatures, *Rec, NextRuleID++,2600ActiveRules);26012602if (!CRB.parseAll()) {2603assert(ErrorsPrinted && "Parsing failed without errors!");2604continue;2605}26062607if (StopAfterParse) {2608CRB.print(outs());2609continue;2610}26112612if (!CRB.emitRuleMatchers()) {2613assert(ErrorsPrinted && "Emission failed without errors!");2614continue;2615}2616}2617}26182619void GICombinerEmitter::run(raw_ostream &OS) {2620InstructionOpcodeMatcher::initOpcodeValuesMap(Target);2621LLTOperandMatcher::initTypeIDValuesMap();26222623Records.startTimer("Gather rules");2624std::vector<RuleMatcher> Rules;2625gatherRules(Rules, Combiner->getValueAsListOfDefs("Rules"));2626if (ErrorsPrinted)2627PrintFatalError(Combiner->getLoc(), "Failed to parse one or more rules");26282629if (StopAfterParse)2630return;26312632Records.startTimer("Creating Match Table");2633unsigned MaxTemporaries = 0;2634for (const auto &Rule : Rules)2635MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());26362637llvm::stable_sort(Rules, [&](const RuleMatcher &A, const RuleMatcher &B) {2638if (A.isHigherPriorityThan(B)) {2639assert(!B.isHigherPriorityThan(A) && "Cannot be more important "2640"and less important at "2641"the same time");2642return true;2643}2644return false;2645});26462647const MatchTable Table = buildMatchTable(Rules);26482649Records.startTimer("Emit combiner");26502651emitSourceFileHeader(getClassName().str() + " Combiner Match Table", OS);26522653// Unused2654std::vector<StringRef> CustomRendererFns;2655// Unused2656std::vector<Record *> ComplexPredicates;26572658SmallVector<LLTCodeGen, 16> TypeObjects;2659append_range(TypeObjects, KnownTypes);2660llvm::sort(TypeObjects);26612662// Hack: Avoid empty declarator.2663if (TypeObjects.empty())2664TypeObjects.push_back(LLT::scalar(1));26652666// GET_GICOMBINER_DEPS, which pulls in extra dependencies.2667OS << "#ifdef GET_GICOMBINER_DEPS\n"2668<< "#include \"llvm/ADT/SparseBitVector.h\"\n"2669<< "namespace llvm {\n"2670<< "extern cl::OptionCategory GICombinerOptionCategory;\n"2671<< "} // end namespace llvm\n"2672<< "#endif // ifdef GET_GICOMBINER_DEPS\n\n";26732674// GET_GICOMBINER_TYPES, which needs to be included before the declaration of2675// the class.2676OS << "#ifdef GET_GICOMBINER_TYPES\n";2677emitRuleConfigImpl(OS);2678OS << "#endif // ifdef GET_GICOMBINER_TYPES\n\n";2679emitPredicateBitset(OS, "GET_GICOMBINER_TYPES");26802681// GET_GICOMBINER_CLASS_MEMBERS, which need to be included inside the class.2682emitPredicatesDecl(OS, "GET_GICOMBINER_CLASS_MEMBERS");2683emitTemporariesDecl(OS, "GET_GICOMBINER_CLASS_MEMBERS");26842685// GET_GICOMBINER_IMPL, which needs to be included outside the class.2686emitExecutorImpl(OS, Table, TypeObjects, Rules, ComplexPredicates,2687CustomRendererFns, "GET_GICOMBINER_IMPL");26882689// GET_GICOMBINER_CONSTRUCTOR_INITS, which are in the constructor's2690// initializer list.2691emitPredicatesInit(OS, "GET_GICOMBINER_CONSTRUCTOR_INITS");2692emitTemporariesInit(OS, MaxTemporaries, "GET_GICOMBINER_CONSTRUCTOR_INITS");2693}26942695} // end anonymous namespace26962697//===----------------------------------------------------------------------===//26982699static void EmitGICombiner(RecordKeeper &RK, raw_ostream &OS) {2700EnablePrettyStackTrace();2701CodeGenTarget Target(RK);27022703if (SelectedCombiners.empty())2704PrintFatalError("No combiners selected with -combiners");2705for (const auto &Combiner : SelectedCombiners) {2706Record *CombinerDef = RK.getDef(Combiner);2707if (!CombinerDef)2708PrintFatalError("Could not find " + Combiner);2709GICombinerEmitter(RK, Target, Combiner, CombinerDef).run(OS);2710}2711}27122713static TableGen::Emitter::Opt X("gen-global-isel-combiner", EmitGICombiner,2714"Generate GlobalISel Combiner");271527162717