Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
35315 views
//===- GlobalISelMatchTable.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//===----------------------------------------------------------------------===//78#include "GlobalISelMatchTable.h"9#include "Common/CodeGenInstruction.h"10#include "Common/CodeGenRegisters.h"11#include "llvm/ADT/Statistic.h"12#include "llvm/Support/Debug.h"13#include "llvm/Support/LEB128.h"14#include "llvm/Support/ScopedPrinter.h"15#include "llvm/Support/raw_ostream.h"16#include "llvm/TableGen/Error.h"1718#define DEBUG_TYPE "gi-match-table"1920STATISTIC(NumPatternEmitted, "Number of patterns emitted");2122namespace llvm {23namespace gi {2425namespace {2627Error failUnsupported(const Twine &Reason) {28return make_error<StringError>(Reason, inconvertibleErrorCode());29}3031/// Get the name of the enum value used to number the predicate function.32std::string getEnumNameForPredicate(const TreePredicateFn &Predicate) {33if (Predicate.hasGISelPredicateCode())34return "GICXXPred_MI_" + Predicate.getFnName();35return "GICXXPred_" + Predicate.getImmTypeIdentifier().str() + "_" +36Predicate.getFnName();37}3839std::string getMatchOpcodeForImmPredicate(const TreePredicateFn &Predicate) {40return "GIM_Check" + Predicate.getImmTypeIdentifier().str() + "ImmPredicate";41}4243// GIMT_Encode2/4/844constexpr StringLiteral EncodeMacroName = "GIMT_Encode";4546} // namespace4748//===- Helpers ------------------------------------------------------------===//4950void emitEncodingMacrosDef(raw_ostream &OS) {51OS << "#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n"52<< "#define " << EncodeMacroName << "2(Val)"53<< " uint8_t(Val), uint8_t((uint16_t)Val >> 8)\n"54<< "#define " << EncodeMacroName << "4(Val)"55<< " uint8_t(Val), uint8_t((uint32_t)Val >> 8), "56"uint8_t((uint32_t)Val >> 16), uint8_t((uint32_t)Val >> 24)\n"57<< "#define " << EncodeMacroName << "8(Val)"58<< " uint8_t(Val), uint8_t((uint64_t)Val >> 8), "59"uint8_t((uint64_t)Val >> 16), uint8_t((uint64_t)Val >> 24), "60"uint8_t((uint64_t)Val >> 32), uint8_t((uint64_t)Val >> 40), "61"uint8_t((uint64_t)Val >> 48), uint8_t((uint64_t)Val >> 56)\n"62<< "#else\n"63<< "#define " << EncodeMacroName << "2(Val)"64<< " uint8_t((uint16_t)Val >> 8), uint8_t(Val)\n"65<< "#define " << EncodeMacroName << "4(Val)"66<< " uint8_t((uint32_t)Val >> 24), uint8_t((uint32_t)Val >> 16), "67"uint8_t((uint32_t)Val >> 8), uint8_t(Val)\n"68<< "#define " << EncodeMacroName << "8(Val)"69<< " uint8_t((uint64_t)Val >> 56), uint8_t((uint64_t)Val >> 48), "70"uint8_t((uint64_t)Val >> 40), uint8_t((uint64_t)Val >> 32), "71"uint8_t((uint64_t)Val >> 24), uint8_t((uint64_t)Val >> 16), "72"uint8_t((uint64_t)Val >> 8), uint8_t(Val)\n"73<< "#endif\n";74}7576void emitEncodingMacrosUndef(raw_ostream &OS) {77OS << "#undef " << EncodeMacroName << "2\n"78<< "#undef " << EncodeMacroName << "4\n"79<< "#undef " << EncodeMacroName << "8\n";80}8182std::string getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset,83int HwModeIdx) {84std::string Name = "GIFBS";85for (const auto &Feature : FeatureBitset)86Name += ("_" + Feature->getName()).str();87if (HwModeIdx >= 0)88Name += ("_HwMode" + std::to_string(HwModeIdx));89return Name;90}9192template <class GroupT>93std::vector<Matcher *>94optimizeRules(ArrayRef<Matcher *> Rules,95std::vector<std::unique_ptr<Matcher>> &MatcherStorage) {9697std::vector<Matcher *> OptRules;98std::unique_ptr<GroupT> CurrentGroup = std::make_unique<GroupT>();99assert(CurrentGroup->empty() && "Newly created group isn't empty!");100unsigned NumGroups = 0;101102auto ProcessCurrentGroup = [&]() {103if (CurrentGroup->empty())104// An empty group is good to be reused:105return;106107// If the group isn't large enough to provide any benefit, move all the108// added rules out of it and make sure to re-create the group to properly109// re-initialize it:110if (CurrentGroup->size() < 2)111append_range(OptRules, CurrentGroup->matchers());112else {113CurrentGroup->finalize();114OptRules.push_back(CurrentGroup.get());115MatcherStorage.emplace_back(std::move(CurrentGroup));116++NumGroups;117}118CurrentGroup = std::make_unique<GroupT>();119};120for (Matcher *Rule : Rules) {121// Greedily add as many matchers as possible to the current group:122if (CurrentGroup->addMatcher(*Rule))123continue;124125ProcessCurrentGroup();126assert(CurrentGroup->empty() && "A group wasn't properly re-initialized");127128// Try to add the pending matcher to a newly created empty group:129if (!CurrentGroup->addMatcher(*Rule))130// If we couldn't add the matcher to an empty group, that group type131// doesn't support that kind of matchers at all, so just skip it:132OptRules.push_back(Rule);133}134ProcessCurrentGroup();135136LLVM_DEBUG(dbgs() << "NumGroups: " << NumGroups << "\n");137(void)NumGroups;138assert(CurrentGroup->empty() && "The last group wasn't properly processed");139return OptRules;140}141142template std::vector<Matcher *> optimizeRules<GroupMatcher>(143ArrayRef<Matcher *> Rules,144std::vector<std::unique_ptr<Matcher>> &MatcherStorage);145146template std::vector<Matcher *> optimizeRules<SwitchMatcher>(147ArrayRef<Matcher *> Rules,148std::vector<std::unique_ptr<Matcher>> &MatcherStorage);149150static std::string getEncodedEmitStr(StringRef NamedValue, unsigned NumBytes) {151if (NumBytes == 2 || NumBytes == 4 || NumBytes == 8)152return (EncodeMacroName + Twine(NumBytes) + "(" + NamedValue + ")").str();153llvm_unreachable("Unsupported number of bytes!");154}155156//===- Global Data --------------------------------------------------------===//157158std::set<LLTCodeGen> KnownTypes;159160//===- MatchTableRecord ---------------------------------------------------===//161162void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis,163const MatchTable &Table) const {164bool UseLineComment =165LineBreakIsNextAfterThis || (Flags & MTRF_LineBreakFollows);166if (Flags & (MTRF_JumpTarget | MTRF_CommaFollows))167UseLineComment = false;168169if (Flags & MTRF_Comment)170OS << (UseLineComment ? "// " : "/*");171172if (NumElements > 1 && !(Flags & (MTRF_PreEncoded | MTRF_Comment)))173OS << getEncodedEmitStr(EmitStr, NumElements);174else175OS << EmitStr;176177if (Flags & MTRF_Label)178OS << ": @" << Table.getLabelIndex(LabelID);179180if ((Flags & MTRF_Comment) && !UseLineComment)181OS << "*/";182183if (Flags & MTRF_JumpTarget) {184if (Flags & MTRF_Comment)185OS << " ";186// TODO: Could encode this AOT to speed up build of generated file187OS << getEncodedEmitStr(llvm::to_string(Table.getLabelIndex(LabelID)),188NumElements);189}190191if (Flags & MTRF_CommaFollows) {192OS << ",";193if (!LineBreakIsNextAfterThis && !(Flags & MTRF_LineBreakFollows))194OS << " ";195}196197if (Flags & MTRF_LineBreakFollows)198OS << "\n";199}200201//===- MatchTable ---------------------------------------------------------===//202203MatchTableRecord MatchTable::LineBreak = {204std::nullopt, "" /* Emit String */, 0 /* Elements */,205MatchTableRecord::MTRF_LineBreakFollows};206207MatchTableRecord MatchTable::Comment(StringRef Comment) {208return MatchTableRecord(std::nullopt, Comment, 0,209MatchTableRecord::MTRF_Comment);210}211212MatchTableRecord MatchTable::Opcode(StringRef Opcode, int IndentAdjust) {213unsigned ExtraFlags = 0;214if (IndentAdjust > 0)215ExtraFlags |= MatchTableRecord::MTRF_Indent;216if (IndentAdjust < 0)217ExtraFlags |= MatchTableRecord::MTRF_Outdent;218219return MatchTableRecord(std::nullopt, Opcode, 1,220MatchTableRecord::MTRF_CommaFollows | ExtraFlags);221}222223MatchTableRecord MatchTable::NamedValue(unsigned NumBytes,224StringRef NamedValue) {225return MatchTableRecord(std::nullopt, NamedValue, NumBytes,226MatchTableRecord::MTRF_CommaFollows);227}228229MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef NamedValue,230int64_t RawValue) {231return MatchTableRecord(std::nullopt, NamedValue, NumBytes,232MatchTableRecord::MTRF_CommaFollows, RawValue);233}234235MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef Namespace,236StringRef NamedValue) {237return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),238NumBytes, MatchTableRecord::MTRF_CommaFollows);239}240241MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef Namespace,242StringRef NamedValue,243int64_t RawValue) {244return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),245NumBytes, MatchTableRecord::MTRF_CommaFollows,246RawValue);247}248249MatchTableRecord MatchTable::IntValue(unsigned NumBytes, int64_t IntValue) {250assert(isUIntN(NumBytes * 8, IntValue) || isIntN(NumBytes * 8, IntValue));251auto Str = llvm::to_string(IntValue);252if (NumBytes == 1 && IntValue < 0)253Str = "uint8_t(" + Str + ")";254// TODO: Could optimize this directly to save the compiler some work when255// building the file256return MatchTableRecord(std::nullopt, Str, NumBytes,257MatchTableRecord::MTRF_CommaFollows);258}259260MatchTableRecord MatchTable::ULEB128Value(uint64_t IntValue) {261uint8_t Buffer[10];262unsigned Len = encodeULEB128(IntValue, Buffer);263264// Simple case (most common)265if (Len == 1) {266return MatchTableRecord(std::nullopt, llvm::to_string((unsigned)Buffer[0]),2671, MatchTableRecord::MTRF_CommaFollows);268}269270// Print it as, e.g. /* -123456 (*/, 0xC0, 0xBB, 0x78 /*)*/271std::string Str;272raw_string_ostream OS(Str);273OS << "/* " << llvm::to_string(IntValue) << "(*/";274for (unsigned K = 0; K < Len; ++K) {275if (K)276OS << ", ";277OS << "0x" << llvm::toHex({Buffer[K]});278}279OS << "/*)*/";280return MatchTableRecord(std::nullopt, Str, Len,281MatchTableRecord::MTRF_CommaFollows |282MatchTableRecord::MTRF_PreEncoded);283}284285MatchTableRecord MatchTable::Label(unsigned LabelID) {286return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 0,287MatchTableRecord::MTRF_Label |288MatchTableRecord::MTRF_Comment |289MatchTableRecord::MTRF_LineBreakFollows);290}291292MatchTableRecord MatchTable::JumpTarget(unsigned LabelID) {293return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 4,294MatchTableRecord::MTRF_JumpTarget |295MatchTableRecord::MTRF_Comment |296MatchTableRecord::MTRF_CommaFollows);297}298299void MatchTable::emitUse(raw_ostream &OS) const { OS << "MatchTable" << ID; }300301void MatchTable::emitDeclaration(raw_ostream &OS) const {302unsigned Indentation = 4;303OS << " constexpr static uint8_t MatchTable" << ID << "[] = {";304LineBreak.emit(OS, true, *this);305OS << std::string(Indentation, ' ');306307for (auto I = Contents.begin(), E = Contents.end(); I != E; ++I) {308bool LineBreakIsNext = false;309const auto &NextI = std::next(I);310311if (NextI != E) {312if (NextI->EmitStr == "" &&313NextI->Flags == MatchTableRecord::MTRF_LineBreakFollows)314LineBreakIsNext = true;315}316317if (I->Flags & MatchTableRecord::MTRF_Indent)318Indentation += 2;319320I->emit(OS, LineBreakIsNext, *this);321if (I->Flags & MatchTableRecord::MTRF_LineBreakFollows)322OS << std::string(Indentation, ' ');323324if (I->Flags & MatchTableRecord::MTRF_Outdent)325Indentation -= 2;326}327OS << "}; // Size: " << CurrentSize << " bytes\n";328}329330MatchTable MatchTable::buildTable(ArrayRef<Matcher *> Rules, bool WithCoverage,331bool IsCombiner) {332MatchTable Table(WithCoverage, IsCombiner);333for (Matcher *Rule : Rules)334Rule->emit(Table);335336return Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;337}338339//===- LLTCodeGen ---------------------------------------------------------===//340341std::string LLTCodeGen::getCxxEnumValue() const {342std::string Str;343raw_string_ostream OS(Str);344345emitCxxEnumValue(OS);346return Str;347}348349void LLTCodeGen::emitCxxEnumValue(raw_ostream &OS) const {350if (Ty.isScalar()) {351OS << "GILLT_s" << Ty.getSizeInBits();352return;353}354if (Ty.isVector()) {355OS << (Ty.isScalable() ? "GILLT_nxv" : "GILLT_v")356<< Ty.getElementCount().getKnownMinValue() << "s"357<< Ty.getScalarSizeInBits();358return;359}360if (Ty.isPointer()) {361OS << "GILLT_p" << Ty.getAddressSpace();362if (Ty.getSizeInBits() > 0)363OS << "s" << Ty.getSizeInBits();364return;365}366llvm_unreachable("Unhandled LLT");367}368369void LLTCodeGen::emitCxxConstructorCall(raw_ostream &OS) const {370if (Ty.isScalar()) {371OS << "LLT::scalar(" << Ty.getSizeInBits() << ")";372return;373}374if (Ty.isVector()) {375OS << "LLT::vector("376<< (Ty.isScalable() ? "ElementCount::getScalable("377: "ElementCount::getFixed(")378<< Ty.getElementCount().getKnownMinValue() << "), "379<< Ty.getScalarSizeInBits() << ")";380return;381}382if (Ty.isPointer() && Ty.getSizeInBits() > 0) {383OS << "LLT::pointer(" << Ty.getAddressSpace() << ", " << Ty.getSizeInBits()384<< ")";385return;386}387llvm_unreachable("Unhandled LLT");388}389390/// This ordering is used for std::unique() and llvm::sort(). There's no391/// particular logic behind the order but either A < B or B < A must be392/// true if A != B.393bool LLTCodeGen::operator<(const LLTCodeGen &Other) const {394if (Ty.isValid() != Other.Ty.isValid())395return Ty.isValid() < Other.Ty.isValid();396if (!Ty.isValid())397return false;398399if (Ty.isVector() != Other.Ty.isVector())400return Ty.isVector() < Other.Ty.isVector();401if (Ty.isScalar() != Other.Ty.isScalar())402return Ty.isScalar() < Other.Ty.isScalar();403if (Ty.isPointer() != Other.Ty.isPointer())404return Ty.isPointer() < Other.Ty.isPointer();405406if (Ty.isPointer() && Ty.getAddressSpace() != Other.Ty.getAddressSpace())407return Ty.getAddressSpace() < Other.Ty.getAddressSpace();408409if (Ty.isVector() && Ty.getElementCount() != Other.Ty.getElementCount())410return std::tuple(Ty.isScalable(),411Ty.getElementCount().getKnownMinValue()) <412std::tuple(Other.Ty.isScalable(),413Other.Ty.getElementCount().getKnownMinValue());414415assert((!Ty.isVector() || Ty.isScalable() == Other.Ty.isScalable()) &&416"Unexpected mismatch of scalable property");417return Ty.isVector()418? std::tuple(Ty.isScalable(),419Ty.getSizeInBits().getKnownMinValue()) <420std::tuple(Other.Ty.isScalable(),421Other.Ty.getSizeInBits().getKnownMinValue())422: Ty.getSizeInBits().getFixedValue() <423Other.Ty.getSizeInBits().getFixedValue();424}425426//===- LLTCodeGen Helpers -------------------------------------------------===//427428std::optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) {429MVT VT(SVT);430431if (VT.isVector() && !VT.getVectorElementCount().isScalar())432return LLTCodeGen(433LLT::vector(VT.getVectorElementCount(), VT.getScalarSizeInBits()));434435if (VT.isInteger() || VT.isFloatingPoint())436return LLTCodeGen(LLT::scalar(VT.getSizeInBits()));437438return std::nullopt;439}440441//===- Matcher ------------------------------------------------------------===//442443void Matcher::optimize() {}444445Matcher::~Matcher() {}446447//===- GroupMatcher -------------------------------------------------------===//448449bool GroupMatcher::candidateConditionMatches(450const PredicateMatcher &Predicate) const {451452if (empty()) {453// Sharing predicates for nested instructions is not supported yet as we454// currently don't hoist the GIM_RecordInsn's properly, therefore we can455// only work on the original root instruction (InsnVarID == 0):456if (Predicate.getInsnVarID() != 0)457return false;458// ... otherwise an empty group can handle any predicate with no specific459// requirements:460return true;461}462463const Matcher &Representative = **Matchers.begin();464const auto &RepresentativeCondition = Representative.getFirstCondition();465// ... if not empty, the group can only accomodate matchers with the exact466// same first condition:467return Predicate.isIdentical(RepresentativeCondition);468}469470bool GroupMatcher::addMatcher(Matcher &Candidate) {471if (!Candidate.hasFirstCondition())472return false;473474const PredicateMatcher &Predicate = Candidate.getFirstCondition();475if (!candidateConditionMatches(Predicate))476return false;477478Matchers.push_back(&Candidate);479return true;480}481482void GroupMatcher::finalize() {483assert(Conditions.empty() && "Already finalized?");484if (empty())485return;486487Matcher &FirstRule = **Matchers.begin();488for (;;) {489// All the checks are expected to succeed during the first iteration:490for (const auto &Rule : Matchers)491if (!Rule->hasFirstCondition())492return;493const auto &FirstCondition = FirstRule.getFirstCondition();494for (unsigned I = 1, E = Matchers.size(); I < E; ++I)495if (!Matchers[I]->getFirstCondition().isIdentical(FirstCondition))496return;497498Conditions.push_back(FirstRule.popFirstCondition());499for (unsigned I = 1, E = Matchers.size(); I < E; ++I)500Matchers[I]->popFirstCondition();501}502}503504void GroupMatcher::emit(MatchTable &Table) {505unsigned LabelID = ~0U;506if (!Conditions.empty()) {507LabelID = Table.allocateLabelID();508Table << MatchTable::Opcode("GIM_Try", +1)509<< MatchTable::Comment("On fail goto")510<< MatchTable::JumpTarget(LabelID) << MatchTable::LineBreak;511}512for (auto &Condition : Conditions)513Condition->emitPredicateOpcodes(514Table, *static_cast<RuleMatcher *>(*Matchers.begin()));515516for (const auto &M : Matchers)517M->emit(Table);518519// Exit the group520if (!Conditions.empty())521Table << MatchTable::Opcode("GIM_Reject", -1) << MatchTable::LineBreak522<< MatchTable::Label(LabelID);523}524525void GroupMatcher::optimize() {526// Make sure we only sort by a specific predicate within a range of rules that527// all have that predicate checked against a specific value (not a wildcard):528auto F = Matchers.begin();529auto T = F;530auto E = Matchers.end();531while (T != E) {532while (T != E) {533auto *R = static_cast<RuleMatcher *>(*T);534if (!R->getFirstConditionAsRootType().get().isValid())535break;536++T;537}538std::stable_sort(F, T, [](Matcher *A, Matcher *B) {539auto *L = static_cast<RuleMatcher *>(A);540auto *R = static_cast<RuleMatcher *>(B);541return L->getFirstConditionAsRootType() <542R->getFirstConditionAsRootType();543});544if (T != E)545F = ++T;546}547Matchers = optimizeRules<GroupMatcher>(Matchers, MatcherStorage);548Matchers = optimizeRules<SwitchMatcher>(Matchers, MatcherStorage);549}550551//===- SwitchMatcher ------------------------------------------------------===//552553bool SwitchMatcher::isSupportedPredicateType(const PredicateMatcher &P) {554return isa<InstructionOpcodeMatcher>(P) || isa<LLTOperandMatcher>(P);555}556557bool SwitchMatcher::candidateConditionMatches(558const PredicateMatcher &Predicate) const {559560if (empty()) {561// Sharing predicates for nested instructions is not supported yet as we562// currently don't hoist the GIM_RecordInsn's properly, therefore we can563// only work on the original root instruction (InsnVarID == 0):564if (Predicate.getInsnVarID() != 0)565return false;566// ... while an attempt to add even a root matcher to an empty SwitchMatcher567// could fail as not all the types of conditions are supported:568if (!isSupportedPredicateType(Predicate))569return false;570// ... or the condition might not have a proper implementation of571// getValue() / isIdenticalDownToValue() yet:572if (!Predicate.hasValue())573return false;574// ... otherwise an empty Switch can accomodate the condition with no575// further requirements:576return true;577}578579const Matcher &CaseRepresentative = **Matchers.begin();580const auto &RepresentativeCondition = CaseRepresentative.getFirstCondition();581// Switch-cases must share the same kind of condition and path to the value it582// checks:583if (!Predicate.isIdenticalDownToValue(RepresentativeCondition))584return false;585586const auto Value = Predicate.getValue();587// ... but be unique with respect to the actual value they check:588return Values.count(Value) == 0;589}590591bool SwitchMatcher::addMatcher(Matcher &Candidate) {592if (!Candidate.hasFirstCondition())593return false;594595const PredicateMatcher &Predicate = Candidate.getFirstCondition();596if (!candidateConditionMatches(Predicate))597return false;598const auto Value = Predicate.getValue();599Values.insert(Value);600601Matchers.push_back(&Candidate);602return true;603}604605void SwitchMatcher::finalize() {606assert(Condition == nullptr && "Already finalized");607assert(Values.size() == Matchers.size() && "Broken SwitchMatcher");608if (empty())609return;610611llvm::stable_sort(Matchers, [](const Matcher *L, const Matcher *R) {612return L->getFirstCondition().getValue() <613R->getFirstCondition().getValue();614});615Condition = Matchers[0]->popFirstCondition();616for (unsigned I = 1, E = Values.size(); I < E; ++I)617Matchers[I]->popFirstCondition();618}619620void SwitchMatcher::emitPredicateSpecificOpcodes(const PredicateMatcher &P,621MatchTable &Table) {622assert(isSupportedPredicateType(P) && "Predicate type is not supported");623624if (const auto *Condition = dyn_cast<InstructionOpcodeMatcher>(&P)) {625Table << MatchTable::Opcode("GIM_SwitchOpcode") << MatchTable::Comment("MI")626<< MatchTable::ULEB128Value(Condition->getInsnVarID());627return;628}629if (const auto *Condition = dyn_cast<LLTOperandMatcher>(&P)) {630Table << MatchTable::Opcode("GIM_SwitchType") << MatchTable::Comment("MI")631<< MatchTable::ULEB128Value(Condition->getInsnVarID())632<< MatchTable::Comment("Op")633<< MatchTable::ULEB128Value(Condition->getOpIdx());634return;635}636637llvm_unreachable("emitPredicateSpecificOpcodes is broken: can not handle a "638"predicate type that is claimed to be supported");639}640641void SwitchMatcher::emit(MatchTable &Table) {642assert(Values.size() == Matchers.size() && "Broken SwitchMatcher");643if (empty())644return;645assert(Condition != nullptr &&646"Broken SwitchMatcher, hasn't been finalized?");647648std::vector<unsigned> LabelIDs(Values.size());649std::generate(LabelIDs.begin(), LabelIDs.end(),650[&Table]() { return Table.allocateLabelID(); });651const unsigned Default = Table.allocateLabelID();652653const int64_t LowerBound = Values.begin()->getRawValue();654const int64_t UpperBound = Values.rbegin()->getRawValue() + 1;655656emitPredicateSpecificOpcodes(*Condition, Table);657658Table << MatchTable::Comment("[") << MatchTable::IntValue(2, LowerBound)659<< MatchTable::IntValue(2, UpperBound) << MatchTable::Comment(")")660<< MatchTable::Comment("default:") << MatchTable::JumpTarget(Default);661662int64_t J = LowerBound;663auto VI = Values.begin();664for (unsigned I = 0, E = Values.size(); I < E; ++I) {665auto V = *VI++;666while (J++ < V.getRawValue())667Table << MatchTable::IntValue(4, 0);668V.turnIntoComment();669Table << MatchTable::LineBreak << V << MatchTable::JumpTarget(LabelIDs[I]);670}671Table << MatchTable::LineBreak;672673for (unsigned I = 0, E = Values.size(); I < E; ++I) {674Table << MatchTable::Label(LabelIDs[I]);675Matchers[I]->emit(Table);676Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;677}678Table << MatchTable::Label(Default);679}680681//===- RuleMatcher --------------------------------------------------------===//682683uint64_t RuleMatcher::NextRuleID = 0;684685StringRef RuleMatcher::getOpcode() const {686return Matchers.front()->getOpcode();687}688689unsigned RuleMatcher::getNumOperands() const {690return Matchers.front()->getNumOperands();691}692693LLTCodeGen RuleMatcher::getFirstConditionAsRootType() {694InstructionMatcher &InsnMatcher = *Matchers.front();695if (!InsnMatcher.predicates_empty())696if (const auto *TM =697dyn_cast<LLTOperandMatcher>(&**InsnMatcher.predicates_begin()))698if (TM->getInsnVarID() == 0 && TM->getOpIdx() == 0)699return TM->getTy();700return {};701}702703void RuleMatcher::optimize() {704for (auto &Item : InsnVariableIDs) {705InstructionMatcher &InsnMatcher = *Item.first;706for (auto &OM : InsnMatcher.operands()) {707// Complex Patterns are usually expensive and they relatively rarely fail708// on their own: more often we end up throwing away all the work done by a709// matching part of a complex pattern because some other part of the710// enclosing pattern didn't match. All of this makes it beneficial to711// delay complex patterns until the very end of the rule matching,712// especially for targets having lots of complex patterns.713for (auto &OP : OM->predicates())714if (isa<ComplexPatternOperandMatcher>(OP))715EpilogueMatchers.emplace_back(std::move(OP));716OM->eraseNullPredicates();717}718InsnMatcher.optimize();719}720llvm::sort(EpilogueMatchers, [](const std::unique_ptr<PredicateMatcher> &L,721const std::unique_ptr<PredicateMatcher> &R) {722return std::tuple(L->getKind(), L->getInsnVarID(), L->getOpIdx()) <723std::tuple(R->getKind(), R->getInsnVarID(), R->getOpIdx());724});725726// Deduplicate EraseInst actions, and if an EraseInst erases the root, place727// it at the end to favor generation of GIR_EraseRootFromParent_Done728DenseSet<unsigned> AlreadySeenEraseInsts;729auto EraseRootIt = Actions.end();730auto It = Actions.begin();731while (It != Actions.end()) {732if (const auto *EI = dyn_cast<EraseInstAction>(It->get())) {733unsigned InstID = EI->getInsnID();734if (!AlreadySeenEraseInsts.insert(InstID).second) {735It = Actions.erase(It);736continue;737}738739if (InstID == 0)740EraseRootIt = It;741}742743++It;744}745746if (EraseRootIt != Actions.end())747Actions.splice(Actions.end(), Actions, EraseRootIt);748}749750bool RuleMatcher::hasFirstCondition() const {751if (insnmatchers_empty())752return false;753InstructionMatcher &Matcher = insnmatchers_front();754if (!Matcher.predicates_empty())755return true;756for (auto &OM : Matcher.operands())757for (auto &OP : OM->predicates())758if (!isa<InstructionOperandMatcher>(OP))759return true;760return false;761}762763const PredicateMatcher &RuleMatcher::getFirstCondition() const {764assert(!insnmatchers_empty() &&765"Trying to get a condition from an empty RuleMatcher");766767InstructionMatcher &Matcher = insnmatchers_front();768if (!Matcher.predicates_empty())769return **Matcher.predicates_begin();770// If there is no more predicate on the instruction itself, look at its771// operands.772for (auto &OM : Matcher.operands())773for (auto &OP : OM->predicates())774if (!isa<InstructionOperandMatcher>(OP))775return *OP;776777llvm_unreachable("Trying to get a condition from an InstructionMatcher with "778"no conditions");779}780781std::unique_ptr<PredicateMatcher> RuleMatcher::popFirstCondition() {782assert(!insnmatchers_empty() &&783"Trying to pop a condition from an empty RuleMatcher");784785InstructionMatcher &Matcher = insnmatchers_front();786if (!Matcher.predicates_empty())787return Matcher.predicates_pop_front();788// If there is no more predicate on the instruction itself, look at its789// operands.790for (auto &OM : Matcher.operands())791for (auto &OP : OM->predicates())792if (!isa<InstructionOperandMatcher>(OP)) {793std::unique_ptr<PredicateMatcher> Result = std::move(OP);794OM->eraseNullPredicates();795return Result;796}797798llvm_unreachable("Trying to pop a condition from an InstructionMatcher with "799"no conditions");800}801802GISelFlags RuleMatcher::updateGISelFlag(GISelFlags CurFlags, const Record *R,803StringRef FlagName,804GISelFlags FlagBit) {805// If the value of a flag is unset, ignore it.806// If it's set, it always takes precedence over the existing value so807// clear/set the corresponding bit.808bool Unset = false;809bool Value = R->getValueAsBitOrUnset("GIIgnoreCopies", Unset);810if (!Unset)811return Value ? (CurFlags | FlagBit) : (CurFlags & ~FlagBit);812return CurFlags;813}814815SaveAndRestore<GISelFlags> RuleMatcher::setGISelFlags(const Record *R) {816if (!R || !R->isSubClassOf("GISelFlags"))817return {Flags, Flags};818819assert((R->isSubClassOf("PatFrags") || R->isSubClassOf("Pattern")) &&820"GISelFlags is only expected on Pattern/PatFrags!");821822GISelFlags NewFlags =823updateGISelFlag(Flags, R, "GIIgnoreCopies", GISF_IgnoreCopies);824return {Flags, NewFlags};825}826827Error RuleMatcher::defineComplexSubOperand(StringRef SymbolicName,828Record *ComplexPattern,829unsigned RendererID,830unsigned SubOperandID,831StringRef ParentSymbolicName) {832std::string ParentName(ParentSymbolicName);833if (ComplexSubOperands.count(SymbolicName)) {834const std::string &RecordedParentName =835ComplexSubOperandsParentName[SymbolicName];836if (RecordedParentName != ParentName)837return failUnsupported("Error: Complex suboperand " + SymbolicName +838" referenced by different operands: " +839RecordedParentName + " and " + ParentName + ".");840// Complex suboperand referenced more than once from same the operand is841// used to generate 'same operand check'. Emitting of842// GIR_ComplexSubOperandRenderer for them is already handled.843return Error::success();844}845846ComplexSubOperands[SymbolicName] =847std::tuple(ComplexPattern, RendererID, SubOperandID);848ComplexSubOperandsParentName[SymbolicName] = ParentName;849850return Error::success();851}852853InstructionMatcher &RuleMatcher::addInstructionMatcher(StringRef SymbolicName) {854Matchers.emplace_back(new InstructionMatcher(*this, SymbolicName));855MutatableInsns.insert(Matchers.back().get());856return *Matchers.back();857}858859void RuleMatcher::addRequiredSimplePredicate(StringRef PredName) {860RequiredSimplePredicates.push_back(PredName.str());861}862863const std::vector<std::string> &RuleMatcher::getRequiredSimplePredicates() {864return RequiredSimplePredicates;865}866867void RuleMatcher::addRequiredFeature(Record *Feature) {868RequiredFeatures.push_back(Feature);869}870871const std::vector<Record *> &RuleMatcher::getRequiredFeatures() const {872return RequiredFeatures;873}874875unsigned RuleMatcher::implicitlyDefineInsnVar(InstructionMatcher &Matcher) {876unsigned NewInsnVarID = NextInsnVarID++;877InsnVariableIDs[&Matcher] = NewInsnVarID;878return NewInsnVarID;879}880881unsigned RuleMatcher::getInsnVarID(InstructionMatcher &InsnMatcher) const {882const auto &I = InsnVariableIDs.find(&InsnMatcher);883if (I != InsnVariableIDs.end())884return I->second;885llvm_unreachable("Matched Insn was not captured in a local variable");886}887888void RuleMatcher::defineOperand(StringRef SymbolicName, OperandMatcher &OM) {889if (!DefinedOperands.contains(SymbolicName)) {890DefinedOperands[SymbolicName] = &OM;891return;892}893894// If the operand is already defined, then we must ensure both references in895// the matcher have the exact same node.896RuleMatcher &RM = OM.getInstructionMatcher().getRuleMatcher();897OM.addPredicate<SameOperandMatcher>(898OM.getSymbolicName(), getOperandMatcher(OM.getSymbolicName()).getOpIdx(),899RM.getGISelFlags());900}901902void RuleMatcher::definePhysRegOperand(Record *Reg, OperandMatcher &OM) {903if (!PhysRegOperands.contains(Reg)) {904PhysRegOperands[Reg] = &OM;905return;906}907}908909InstructionMatcher &910RuleMatcher::getInstructionMatcher(StringRef SymbolicName) const {911for (const auto &I : InsnVariableIDs)912if (I.first->getSymbolicName() == SymbolicName)913return *I.first;914llvm_unreachable(915("Failed to lookup instruction " + SymbolicName).str().c_str());916}917918const OperandMatcher &RuleMatcher::getPhysRegOperandMatcher(Record *Reg) const {919const auto &I = PhysRegOperands.find(Reg);920921if (I == PhysRegOperands.end()) {922PrintFatalError(SrcLoc, "Register " + Reg->getName() +923" was not declared in matcher");924}925926return *I->second;927}928929OperandMatcher &RuleMatcher::getOperandMatcher(StringRef Name) {930const auto &I = DefinedOperands.find(Name);931932if (I == DefinedOperands.end())933PrintFatalError(SrcLoc, "Operand " + Name + " was not declared in matcher");934935return *I->second;936}937938const OperandMatcher &RuleMatcher::getOperandMatcher(StringRef Name) const {939const auto &I = DefinedOperands.find(Name);940941if (I == DefinedOperands.end())942PrintFatalError(SrcLoc, "Operand " + Name + " was not declared in matcher");943944return *I->second;945}946947void RuleMatcher::emit(MatchTable &Table) {948if (Matchers.empty())949llvm_unreachable("Unexpected empty matcher!");950951// The representation supports rules that require multiple roots such as:952// %ptr(p0) = ...953// %elt0(s32) = G_LOAD %ptr954// %1(p0) = G_ADD %ptr, 4955// %elt1(s32) = G_LOAD p0 %1956// which could be usefully folded into:957// %ptr(p0) = ...958// %elt0(s32), %elt1(s32) = TGT_LOAD_PAIR %ptr959// on some targets but we don't need to make use of that yet.960assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet");961962unsigned LabelID = Table.allocateLabelID();963Table << MatchTable::Opcode("GIM_Try", +1)964<< MatchTable::Comment("On fail goto")965<< MatchTable::JumpTarget(LabelID)966<< MatchTable::Comment(("Rule ID " + Twine(RuleID) + " //").str())967<< MatchTable::LineBreak;968969if (!RequiredFeatures.empty() || HwModeIdx >= 0) {970Table << MatchTable::Opcode("GIM_CheckFeatures")971<< MatchTable::NamedValue(9722, getNameForFeatureBitset(RequiredFeatures, HwModeIdx))973<< MatchTable::LineBreak;974}975976if (!RequiredSimplePredicates.empty()) {977for (const auto &Pred : RequiredSimplePredicates) {978Table << MatchTable::Opcode("GIM_CheckSimplePredicate")979<< MatchTable::NamedValue(2, Pred) << MatchTable::LineBreak;980}981}982983Matchers.front()->emitPredicateOpcodes(Table, *this);984985// Check if it's safe to replace registers.986for (const auto &MA : Actions)987MA->emitAdditionalPredicates(Table, *this);988989// We must also check if it's safe to fold the matched instructions.990if (InsnVariableIDs.size() >= 2) {991992// FIXME: Emit checks to determine it's _actually_ safe to fold and/or993// account for unsafe cases.994//995// Example:996// MI1--> %0 = ...997// %1 = ... %0998// MI0--> %2 = ... %0999// It's not safe to erase MI1. We currently handle this by not1000// erasing %0 (even when it's dead).1001//1002// Example:1003// MI1--> %0 = load volatile @a1004// %1 = load volatile @a1005// MI0--> %2 = ... %01006// It's not safe to sink %0's def past %1. We currently handle1007// this by rejecting all loads.1008//1009// Example:1010// MI1--> %0 = load @a1011// %1 = store @a1012// MI0--> %2 = ... %01013// It's not safe to sink %0's def past %1. We currently handle1014// this by rejecting all loads.1015//1016// Example:1017// G_CONDBR %cond, @BB11018// BB0:1019// MI1--> %0 = load @a1020// G_BR @BB11021// BB1:1022// MI0--> %2 = ... %01023// It's not always safe to sink %0 across control flow. In this1024// case it may introduce a memory fault. We currentl handle1025// this by rejecting all loads.10261027Table << MatchTable::Opcode("GIM_CheckIsSafeToFold")1028<< MatchTable::Comment("NumInsns")1029<< MatchTable::IntValue(1, InsnVariableIDs.size() - 1)1030<< MatchTable::LineBreak;1031}10321033for (const auto &PM : EpilogueMatchers)1034PM->emitPredicateOpcodes(Table, *this);10351036if (!CustomCXXAction.empty()) {1037/// Handle combiners relying on custom C++ code instead of actions.1038assert(Table.isCombiner() && "CustomCXXAction is only for combiners!");1039// We cannot have actions other than debug comments.1040assert(none_of(Actions, [](auto &A) {1041return A->getKind() != MatchAction::AK_DebugComment;1042}));1043for (const auto &MA : Actions)1044MA->emitActionOpcodes(Table, *this);1045Table << MatchTable::Opcode("GIR_DoneWithCustomAction", -1)1046<< MatchTable::Comment("Fn")1047<< MatchTable::NamedValue(2, CustomCXXAction)1048<< MatchTable::LineBreak;1049} else {1050// Emit all actions except the last one, then emit coverage and emit the1051// final action.1052//1053// This is because some actions, such as GIR_EraseRootFromParent_Done, also1054// double as a GIR_Done and terminate execution of the rule.1055if (!Actions.empty()) {1056for (const auto &MA : drop_end(Actions))1057MA->emitActionOpcodes(Table, *this);1058}10591060assert((Table.isWithCoverage() ? !Table.isCombiner() : true) &&1061"Combiner tables don't support coverage!");1062if (Table.isWithCoverage())1063Table << MatchTable::Opcode("GIR_Coverage")1064<< MatchTable::IntValue(4, RuleID) << MatchTable::LineBreak;1065else if (!Table.isCombiner())1066Table << MatchTable::Comment(1067("GIR_Coverage, " + Twine(RuleID) + ",").str())1068<< MatchTable::LineBreak;10691070if (Actions.empty() ||1071!Actions.back()->emitActionOpcodesAndDone(Table, *this)) {1072Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak;1073}1074}10751076Table << MatchTable::Label(LabelID);1077++NumPatternEmitted;1078}10791080bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const {1081// Rules involving more match roots have higher priority.1082if (Matchers.size() > B.Matchers.size())1083return true;1084if (Matchers.size() < B.Matchers.size())1085return false;10861087for (auto Matcher : zip(Matchers, B.Matchers)) {1088if (std::get<0>(Matcher)->isHigherPriorityThan(*std::get<1>(Matcher)))1089return true;1090if (std::get<1>(Matcher)->isHigherPriorityThan(*std::get<0>(Matcher)))1091return false;1092}10931094return false;1095}10961097unsigned RuleMatcher::countRendererFns() const {1098return std::accumulate(1099Matchers.begin(), Matchers.end(), 0,1100[](unsigned A, const std::unique_ptr<InstructionMatcher> &Matcher) {1101return A + Matcher->countRendererFns();1102});1103}11041105//===- PredicateMatcher ---------------------------------------------------===//11061107PredicateMatcher::~PredicateMatcher() {}11081109//===- OperandPredicateMatcher --------------------------------------------===//11101111OperandPredicateMatcher::~OperandPredicateMatcher() {}11121113bool OperandPredicateMatcher::isHigherPriorityThan(1114const OperandPredicateMatcher &B) const {1115// Generally speaking, an instruction is more important than an Int or a1116// LiteralInt because it can cover more nodes but there's an exception to1117// this. G_CONSTANT's are less important than either of those two because they1118// are more permissive.11191120const auto *AOM = dyn_cast<InstructionOperandMatcher>(this);1121const auto *BOM = dyn_cast<InstructionOperandMatcher>(&B);1122bool AIsConstantInsn = AOM && AOM->getInsnMatcher().isConstantInstruction();1123bool BIsConstantInsn = BOM && BOM->getInsnMatcher().isConstantInstruction();11241125// The relative priorities between a G_CONSTANT and any other instruction1126// don't actually matter but this code is needed to ensure a strict weak1127// ordering. This is particularly important on Windows where the rules will1128// be incorrectly sorted without it.1129if (AOM && BOM)1130return !AIsConstantInsn && BIsConstantInsn;11311132if (AIsConstantInsn && (B.Kind == OPM_Int || B.Kind == OPM_LiteralInt))1133return false;1134if (BIsConstantInsn && (Kind == OPM_Int || Kind == OPM_LiteralInt))1135return true;11361137return Kind < B.Kind;1138}11391140//===- SameOperandMatcher -------------------------------------------------===//11411142void SameOperandMatcher::emitPredicateOpcodes(MatchTable &Table,1143RuleMatcher &Rule) const {1144const OperandMatcher &OtherOM = Rule.getOperandMatcher(MatchingName);1145unsigned OtherInsnVarID = Rule.getInsnVarID(OtherOM.getInstructionMatcher());1146assert(OtherInsnVarID == OtherOM.getInstructionMatcher().getInsnVarID());1147const bool IgnoreCopies = Flags & GISF_IgnoreCopies;1148Table << MatchTable::Opcode(IgnoreCopies1149? "GIM_CheckIsSameOperandIgnoreCopies"1150: "GIM_CheckIsSameOperand")1151<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1152<< MatchTable::Comment("OpIdx") << MatchTable::ULEB128Value(OpIdx)1153<< MatchTable::Comment("OtherMI")1154<< MatchTable::ULEB128Value(OtherInsnVarID)1155<< MatchTable::Comment("OtherOpIdx")1156<< MatchTable::ULEB128Value(OtherOM.getOpIdx())1157<< MatchTable::LineBreak;1158}11591160//===- LLTOperandMatcher --------------------------------------------------===//11611162std::map<LLTCodeGen, unsigned> LLTOperandMatcher::TypeIDValues;11631164MatchTableRecord LLTOperandMatcher::getValue() const {1165const auto VI = TypeIDValues.find(Ty);1166if (VI == TypeIDValues.end())1167return MatchTable::NamedValue(1, getTy().getCxxEnumValue());1168return MatchTable::NamedValue(1, getTy().getCxxEnumValue(), VI->second);1169}11701171bool LLTOperandMatcher::hasValue() const {1172if (TypeIDValues.size() != KnownTypes.size())1173initTypeIDValuesMap();1174return TypeIDValues.count(Ty);1175}11761177void LLTOperandMatcher::emitPredicateOpcodes(MatchTable &Table,1178RuleMatcher &Rule) const {1179if (InsnVarID == 0) {1180Table << MatchTable::Opcode("GIM_RootCheckType");1181} else {1182Table << MatchTable::Opcode("GIM_CheckType") << MatchTable::Comment("MI")1183<< MatchTable::ULEB128Value(InsnVarID);1184}1185Table << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)1186<< MatchTable::Comment("Type") << getValue() << MatchTable::LineBreak;1187}11881189//===- PointerToAnyOperandMatcher -----------------------------------------===//11901191void PointerToAnyOperandMatcher::emitPredicateOpcodes(MatchTable &Table,1192RuleMatcher &Rule) const {1193Table << MatchTable::Opcode("GIM_CheckPointerToAny")1194<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1195<< MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)1196<< MatchTable::Comment("SizeInBits")1197<< MatchTable::ULEB128Value(SizeInBits) << MatchTable::LineBreak;1198}11991200//===- RecordNamedOperandMatcher ------------------------------------------===//12011202void RecordNamedOperandMatcher::emitPredicateOpcodes(MatchTable &Table,1203RuleMatcher &Rule) const {1204Table << MatchTable::Opcode("GIM_RecordNamedOperand")1205<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1206<< MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)1207<< MatchTable::Comment("StoreIdx") << MatchTable::ULEB128Value(StoreIdx)1208<< MatchTable::Comment("Name : " + Name) << MatchTable::LineBreak;1209}12101211//===- RecordRegisterType ------------------------------------------===//12121213void RecordRegisterType::emitPredicateOpcodes(MatchTable &Table,1214RuleMatcher &Rule) const {1215assert(Idx < 0 && "Temp types always have negative indexes!");1216Table << MatchTable::Opcode("GIM_RecordRegType") << MatchTable::Comment("MI")1217<< MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Op")1218<< MatchTable::ULEB128Value(OpIdx) << MatchTable::Comment("TempTypeIdx")1219<< MatchTable::IntValue(1, Idx) << MatchTable::LineBreak;1220}12211222//===- ComplexPatternOperandMatcher ---------------------------------------===//12231224void ComplexPatternOperandMatcher::emitPredicateOpcodes(1225MatchTable &Table, RuleMatcher &Rule) const {1226unsigned ID = getAllocatedTemporariesBaseID();1227Table << MatchTable::Opcode("GIM_CheckComplexPattern")1228<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1229<< MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)1230<< MatchTable::Comment("Renderer") << MatchTable::IntValue(2, ID)1231<< MatchTable::NamedValue(2, ("GICP_" + TheDef.getName()).str())1232<< MatchTable::LineBreak;1233}12341235unsigned ComplexPatternOperandMatcher::getAllocatedTemporariesBaseID() const {1236return Operand.getAllocatedTemporariesBaseID();1237}12381239//===- RegisterBankOperandMatcher -----------------------------------------===//12401241bool RegisterBankOperandMatcher::isIdentical(const PredicateMatcher &B) const {1242return OperandPredicateMatcher::isIdentical(B) &&1243RC.getDef() == cast<RegisterBankOperandMatcher>(&B)->RC.getDef();1244}12451246void RegisterBankOperandMatcher::emitPredicateOpcodes(MatchTable &Table,1247RuleMatcher &Rule) const {1248if (InsnVarID == 0) {1249Table << MatchTable::Opcode("GIM_RootCheckRegBankForClass");1250} else {1251Table << MatchTable::Opcode("GIM_CheckRegBankForClass")1252<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID);1253}12541255Table << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)1256<< MatchTable::Comment("RC")1257<< MatchTable::NamedValue(2, RC.getQualifiedIdName())1258<< MatchTable::LineBreak;1259}12601261//===- MBBOperandMatcher --------------------------------------------------===//12621263void MBBOperandMatcher::emitPredicateOpcodes(MatchTable &Table,1264RuleMatcher &Rule) const {1265Table << MatchTable::Opcode("GIM_CheckIsMBB") << MatchTable::Comment("MI")1266<< MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Op")1267<< MatchTable::ULEB128Value(OpIdx) << MatchTable::LineBreak;1268}12691270//===- ImmOperandMatcher --------------------------------------------------===//12711272void ImmOperandMatcher::emitPredicateOpcodes(MatchTable &Table,1273RuleMatcher &Rule) const {1274Table << MatchTable::Opcode("GIM_CheckIsImm") << MatchTable::Comment("MI")1275<< MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Op")1276<< MatchTable::ULEB128Value(OpIdx) << MatchTable::LineBreak;1277}12781279//===- ConstantIntOperandMatcher ------------------------------------------===//12801281void ConstantIntOperandMatcher::emitPredicateOpcodes(MatchTable &Table,1282RuleMatcher &Rule) const {1283const bool IsInt8 = isInt<8>(Value);1284Table << MatchTable::Opcode(IsInt8 ? "GIM_CheckConstantInt8"1285: "GIM_CheckConstantInt")1286<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1287<< MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)1288<< MatchTable::IntValue(IsInt8 ? 1 : 8, Value) << MatchTable::LineBreak;1289}12901291//===- LiteralIntOperandMatcher -------------------------------------------===//12921293void LiteralIntOperandMatcher::emitPredicateOpcodes(MatchTable &Table,1294RuleMatcher &Rule) const {1295Table << MatchTable::Opcode("GIM_CheckLiteralInt")1296<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1297<< MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)1298<< MatchTable::IntValue(8, Value) << MatchTable::LineBreak;1299}13001301//===- CmpPredicateOperandMatcher -----------------------------------------===//13021303void CmpPredicateOperandMatcher::emitPredicateOpcodes(MatchTable &Table,1304RuleMatcher &Rule) const {1305Table << MatchTable::Opcode("GIM_CheckCmpPredicate")1306<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1307<< MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)1308<< MatchTable::Comment("Predicate")1309<< MatchTable::NamedValue(2, "CmpInst", PredName)1310<< MatchTable::LineBreak;1311}13121313//===- IntrinsicIDOperandMatcher ------------------------------------------===//13141315void IntrinsicIDOperandMatcher::emitPredicateOpcodes(MatchTable &Table,1316RuleMatcher &Rule) const {1317Table << MatchTable::Opcode("GIM_CheckIntrinsicID")1318<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1319<< MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)1320<< MatchTable::NamedValue(2, "Intrinsic::" + II->EnumName)1321<< MatchTable::LineBreak;1322}13231324//===- OperandImmPredicateMatcher -----------------------------------------===//13251326void OperandImmPredicateMatcher::emitPredicateOpcodes(MatchTable &Table,1327RuleMatcher &Rule) const {1328Table << MatchTable::Opcode("GIM_CheckImmOperandPredicate")1329<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1330<< MatchTable::Comment("MO") << MatchTable::ULEB128Value(OpIdx)1331<< MatchTable::Comment("Predicate")1332<< MatchTable::NamedValue(2, getEnumNameForPredicate(Predicate))1333<< MatchTable::LineBreak;1334}13351336//===- OperandMatcher -----------------------------------------------------===//13371338std::string OperandMatcher::getOperandExpr(unsigned InsnVarID) const {1339return "State.MIs[" + llvm::to_string(InsnVarID) + "]->getOperand(" +1340llvm::to_string(OpIdx) + ")";1341}13421343unsigned OperandMatcher::getInsnVarID() const { return Insn.getInsnVarID(); }13441345TempTypeIdx OperandMatcher::getTempTypeIdx(RuleMatcher &Rule) {1346if (TTIdx >= 0) {1347// Temp type index not assigned yet, so assign one and add the necessary1348// predicate.1349TTIdx = Rule.getNextTempTypeIdx();1350assert(TTIdx < 0);1351addPredicate<RecordRegisterType>(TTIdx);1352return TTIdx;1353}1354return TTIdx;1355}13561357void OperandMatcher::emitPredicateOpcodes(MatchTable &Table,1358RuleMatcher &Rule) {1359if (!Optimized) {1360std::string Comment;1361raw_string_ostream CommentOS(Comment);1362CommentOS << "MIs[" << getInsnVarID() << "] ";1363if (SymbolicName.empty())1364CommentOS << "Operand " << OpIdx;1365else1366CommentOS << SymbolicName;1367Table << MatchTable::Comment(Comment) << MatchTable::LineBreak;1368}13691370emitPredicateListOpcodes(Table, Rule);1371}13721373bool OperandMatcher::isHigherPriorityThan(OperandMatcher &B) {1374// Operand matchers involving more predicates have higher priority.1375if (predicates_size() > B.predicates_size())1376return true;1377if (predicates_size() < B.predicates_size())1378return false;13791380// This assumes that predicates are added in a consistent order.1381for (auto &&Predicate : zip(predicates(), B.predicates())) {1382if (std::get<0>(Predicate)->isHigherPriorityThan(*std::get<1>(Predicate)))1383return true;1384if (std::get<1>(Predicate)->isHigherPriorityThan(*std::get<0>(Predicate)))1385return false;1386}13871388return false;1389}13901391unsigned OperandMatcher::countRendererFns() {1392return std::accumulate(1393predicates().begin(), predicates().end(), 0,1394[](unsigned A,1395const std::unique_ptr<OperandPredicateMatcher> &Predicate) {1396return A + Predicate->countRendererFns();1397});1398}13991400Error OperandMatcher::addTypeCheckPredicate(const TypeSetByHwMode &VTy,1401bool OperandIsAPointer) {1402if (!VTy.isMachineValueType())1403return failUnsupported("unsupported typeset");14041405if (VTy.getMachineValueType() == MVT::iPTR && OperandIsAPointer) {1406addPredicate<PointerToAnyOperandMatcher>(0);1407return Error::success();1408}14091410auto OpTyOrNone = MVTToLLT(VTy.getMachineValueType().SimpleTy);1411if (!OpTyOrNone)1412return failUnsupported("unsupported type");14131414if (OperandIsAPointer)1415addPredicate<PointerToAnyOperandMatcher>(OpTyOrNone->get().getSizeInBits());1416else if (VTy.isPointer())1417addPredicate<LLTOperandMatcher>(1418LLT::pointer(VTy.getPtrAddrSpace(), OpTyOrNone->get().getSizeInBits()));1419else1420addPredicate<LLTOperandMatcher>(*OpTyOrNone);1421return Error::success();1422}14231424//===- InstructionOpcodeMatcher -------------------------------------------===//14251426DenseMap<const CodeGenInstruction *, unsigned>1427InstructionOpcodeMatcher::OpcodeValues;14281429MatchTableRecord1430InstructionOpcodeMatcher::getInstValue(const CodeGenInstruction *I) const {1431const auto VI = OpcodeValues.find(I);1432if (VI != OpcodeValues.end())1433return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName(),1434VI->second);1435return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName());1436}14371438void InstructionOpcodeMatcher::initOpcodeValuesMap(1439const CodeGenTarget &Target) {1440OpcodeValues.clear();14411442for (const CodeGenInstruction *I : Target.getInstructionsByEnumValue())1443OpcodeValues[I] = Target.getInstrIntValue(I->TheDef);1444}14451446MatchTableRecord InstructionOpcodeMatcher::getValue() const {1447assert(Insts.size() == 1);14481449const CodeGenInstruction *I = Insts[0];1450const auto VI = OpcodeValues.find(I);1451if (VI != OpcodeValues.end())1452return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName(),1453VI->second);1454return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName());1455}14561457void InstructionOpcodeMatcher::emitPredicateOpcodes(MatchTable &Table,1458RuleMatcher &Rule) const {1459StringRef CheckType =1460Insts.size() == 1 ? "GIM_CheckOpcode" : "GIM_CheckOpcodeIsEither";1461Table << MatchTable::Opcode(CheckType) << MatchTable::Comment("MI")1462<< MatchTable::ULEB128Value(InsnVarID);14631464for (const CodeGenInstruction *I : Insts)1465Table << getInstValue(I);1466Table << MatchTable::LineBreak;1467}14681469bool InstructionOpcodeMatcher::isHigherPriorityThan(1470const InstructionPredicateMatcher &B) const {1471if (InstructionPredicateMatcher::isHigherPriorityThan(B))1472return true;1473if (B.InstructionPredicateMatcher::isHigherPriorityThan(*this))1474return false;14751476// Prioritize opcodes for cosmetic reasons in the generated source. Although1477// this is cosmetic at the moment, we may want to drive a similar ordering1478// using instruction frequency information to improve compile time.1479if (const InstructionOpcodeMatcher *BO =1480dyn_cast<InstructionOpcodeMatcher>(&B))1481return Insts[0]->TheDef->getName() < BO->Insts[0]->TheDef->getName();14821483return false;1484}14851486bool InstructionOpcodeMatcher::isConstantInstruction() const {1487return Insts.size() == 1 && Insts[0]->TheDef->getName() == "G_CONSTANT";1488}14891490StringRef InstructionOpcodeMatcher::getOpcode() const {1491return Insts[0]->TheDef->getName();1492}14931494bool InstructionOpcodeMatcher::isVariadicNumOperands() const {1495// If one is variadic, they all should be.1496return Insts[0]->Operands.isVariadic;1497}14981499StringRef InstructionOpcodeMatcher::getOperandType(unsigned OpIdx) const {1500// Types expected to be uniform for all alternatives.1501return Insts[0]->Operands[OpIdx].OperandType;1502}15031504//===- InstructionNumOperandsMatcher --------------------------------------===//15051506void InstructionNumOperandsMatcher::emitPredicateOpcodes(1507MatchTable &Table, RuleMatcher &Rule) const {1508Table << MatchTable::Opcode("GIM_CheckNumOperands")1509<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1510<< MatchTable::Comment("Expected")1511<< MatchTable::ULEB128Value(NumOperands) << MatchTable::LineBreak;1512}15131514//===- InstructionImmPredicateMatcher -------------------------------------===//15151516bool InstructionImmPredicateMatcher::isIdentical(1517const PredicateMatcher &B) const {1518return InstructionPredicateMatcher::isIdentical(B) &&1519Predicate.getOrigPatFragRecord() ==1520cast<InstructionImmPredicateMatcher>(&B)1521->Predicate.getOrigPatFragRecord();1522}15231524void InstructionImmPredicateMatcher::emitPredicateOpcodes(1525MatchTable &Table, RuleMatcher &Rule) const {1526Table << MatchTable::Opcode(getMatchOpcodeForImmPredicate(Predicate))1527<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1528<< MatchTable::Comment("Predicate")1529<< MatchTable::NamedValue(2, getEnumNameForPredicate(Predicate))1530<< MatchTable::LineBreak;1531}15321533//===- AtomicOrderingMMOPredicateMatcher ----------------------------------===//15341535bool AtomicOrderingMMOPredicateMatcher::isIdentical(1536const PredicateMatcher &B) const {1537if (!InstructionPredicateMatcher::isIdentical(B))1538return false;1539const auto &R = *cast<AtomicOrderingMMOPredicateMatcher>(&B);1540return Order == R.Order && Comparator == R.Comparator;1541}15421543void AtomicOrderingMMOPredicateMatcher::emitPredicateOpcodes(1544MatchTable &Table, RuleMatcher &Rule) const {1545StringRef Opcode = "GIM_CheckAtomicOrdering";15461547if (Comparator == AO_OrStronger)1548Opcode = "GIM_CheckAtomicOrderingOrStrongerThan";1549if (Comparator == AO_WeakerThan)1550Opcode = "GIM_CheckAtomicOrderingWeakerThan";15511552Table << MatchTable::Opcode(Opcode) << MatchTable::Comment("MI")1553<< MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Order")1554<< MatchTable::NamedValue(1,1555("(uint8_t)AtomicOrdering::" + Order).str())1556<< MatchTable::LineBreak;1557}15581559//===- MemorySizePredicateMatcher -----------------------------------------===//15601561void MemorySizePredicateMatcher::emitPredicateOpcodes(MatchTable &Table,1562RuleMatcher &Rule) const {1563Table << MatchTable::Opcode("GIM_CheckMemorySizeEqualTo")1564<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1565<< MatchTable::Comment("MMO") << MatchTable::ULEB128Value(MMOIdx)1566<< MatchTable::Comment("Size") << MatchTable::IntValue(4, Size)1567<< MatchTable::LineBreak;1568}15691570//===- MemoryAddressSpacePredicateMatcher ---------------------------------===//15711572bool MemoryAddressSpacePredicateMatcher::isIdentical(1573const PredicateMatcher &B) const {1574if (!InstructionPredicateMatcher::isIdentical(B))1575return false;1576auto *Other = cast<MemoryAddressSpacePredicateMatcher>(&B);1577return MMOIdx == Other->MMOIdx && AddrSpaces == Other->AddrSpaces;1578}15791580void MemoryAddressSpacePredicateMatcher::emitPredicateOpcodes(1581MatchTable &Table, RuleMatcher &Rule) const {1582assert(AddrSpaces.size() < 256);1583Table << MatchTable::Opcode("GIM_CheckMemoryAddressSpace")1584<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1585<< MatchTable::Comment("MMO")1586<< MatchTable::ULEB128Value(MMOIdx)1587// Encode number of address spaces to expect.1588<< MatchTable::Comment("NumAddrSpace")1589<< MatchTable::IntValue(1, AddrSpaces.size());1590for (unsigned AS : AddrSpaces)1591Table << MatchTable::Comment("AddrSpace") << MatchTable::ULEB128Value(AS);15921593Table << MatchTable::LineBreak;1594}15951596//===- MemoryAlignmentPredicateMatcher ------------------------------------===//15971598bool MemoryAlignmentPredicateMatcher::isIdentical(1599const PredicateMatcher &B) const {1600if (!InstructionPredicateMatcher::isIdentical(B))1601return false;1602auto *Other = cast<MemoryAlignmentPredicateMatcher>(&B);1603return MMOIdx == Other->MMOIdx && MinAlign == Other->MinAlign;1604}16051606void MemoryAlignmentPredicateMatcher::emitPredicateOpcodes(1607MatchTable &Table, RuleMatcher &Rule) const {1608// TODO: we could support more, just need to emit the right opcode or switch1609// to log alignment.1610assert(MinAlign < 256);1611Table << MatchTable::Opcode("GIM_CheckMemoryAlignment")1612<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1613<< MatchTable::Comment("MMO") << MatchTable::ULEB128Value(MMOIdx)1614<< MatchTable::Comment("MinAlign") << MatchTable::IntValue(1, MinAlign)1615<< MatchTable::LineBreak;1616}16171618//===- MemoryVsLLTSizePredicateMatcher ------------------------------------===//16191620bool MemoryVsLLTSizePredicateMatcher::isIdentical(1621const PredicateMatcher &B) const {1622return InstructionPredicateMatcher::isIdentical(B) &&1623MMOIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->MMOIdx &&1624Relation == cast<MemoryVsLLTSizePredicateMatcher>(&B)->Relation &&1625OpIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->OpIdx;1626}16271628void MemoryVsLLTSizePredicateMatcher::emitPredicateOpcodes(1629MatchTable &Table, RuleMatcher &Rule) const {1630Table << MatchTable::Opcode(1631Relation == EqualTo ? "GIM_CheckMemorySizeEqualToLLT"1632: Relation == GreaterThan ? "GIM_CheckMemorySizeGreaterThanLLT"1633: "GIM_CheckMemorySizeLessThanLLT")1634<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1635<< MatchTable::Comment("MMO") << MatchTable::ULEB128Value(MMOIdx)1636<< MatchTable::Comment("OpIdx") << MatchTable::ULEB128Value(OpIdx)1637<< MatchTable::LineBreak;1638}16391640//===- VectorSplatImmPredicateMatcher -------------------------------------===//16411642void VectorSplatImmPredicateMatcher::emitPredicateOpcodes(1643MatchTable &Table, RuleMatcher &Rule) const {1644if (Kind == AllOnes)1645Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllOnes");1646else1647Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllZeros");16481649Table << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID);1650Table << MatchTable::LineBreak;1651}16521653//===- GenericInstructionPredicateMatcher ---------------------------------===//16541655GenericInstructionPredicateMatcher::GenericInstructionPredicateMatcher(1656unsigned InsnVarID, TreePredicateFn Predicate)1657: GenericInstructionPredicateMatcher(InsnVarID,1658getEnumNameForPredicate(Predicate)) {}16591660bool GenericInstructionPredicateMatcher::isIdentical(1661const PredicateMatcher &B) const {1662return InstructionPredicateMatcher::isIdentical(B) &&1663EnumVal ==1664static_cast<const GenericInstructionPredicateMatcher &>(B).EnumVal;1665}1666void GenericInstructionPredicateMatcher::emitPredicateOpcodes(1667MatchTable &Table, RuleMatcher &Rule) const {1668Table << MatchTable::Opcode("GIM_CheckCxxInsnPredicate")1669<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1670<< MatchTable::Comment("FnId") << MatchTable::NamedValue(2, EnumVal)1671<< MatchTable::LineBreak;1672}16731674//===- MIFlagsInstructionPredicateMatcher ---------------------------------===//16751676bool MIFlagsInstructionPredicateMatcher::isIdentical(1677const PredicateMatcher &B) const {1678if (!InstructionPredicateMatcher::isIdentical(B))1679return false;1680const auto &Other =1681static_cast<const MIFlagsInstructionPredicateMatcher &>(B);1682return Flags == Other.Flags && CheckNot == Other.CheckNot;1683}16841685void MIFlagsInstructionPredicateMatcher::emitPredicateOpcodes(1686MatchTable &Table, RuleMatcher &Rule) const {1687Table << MatchTable::Opcode(CheckNot ? "GIM_MIFlagsNot" : "GIM_MIFlags")1688<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)1689<< MatchTable::NamedValue(4, join(Flags, " | "))1690<< MatchTable::LineBreak;1691}16921693//===- InstructionMatcher -------------------------------------------------===//16941695OperandMatcher &1696InstructionMatcher::addOperand(unsigned OpIdx, const std::string &SymbolicName,1697unsigned AllocatedTemporariesBaseID) {1698Operands.emplace_back(new OperandMatcher(*this, OpIdx, SymbolicName,1699AllocatedTemporariesBaseID));1700if (!SymbolicName.empty())1701Rule.defineOperand(SymbolicName, *Operands.back());17021703return *Operands.back();1704}17051706OperandMatcher &InstructionMatcher::getOperand(unsigned OpIdx) {1707auto I = llvm::find_if(Operands,1708[&OpIdx](const std::unique_ptr<OperandMatcher> &X) {1709return X->getOpIdx() == OpIdx;1710});1711if (I != Operands.end())1712return **I;1713llvm_unreachable("Failed to lookup operand");1714}17151716OperandMatcher &InstructionMatcher::addPhysRegInput(Record *Reg, unsigned OpIdx,1717unsigned TempOpIdx) {1718assert(SymbolicName.empty());1719OperandMatcher *OM = new OperandMatcher(*this, OpIdx, "", TempOpIdx);1720Operands.emplace_back(OM);1721Rule.definePhysRegOperand(Reg, *OM);1722PhysRegInputs.emplace_back(Reg, OpIdx);1723return *OM;1724}17251726void InstructionMatcher::emitPredicateOpcodes(MatchTable &Table,1727RuleMatcher &Rule) {1728if (NumOperandsCheck)1729InstructionNumOperandsMatcher(InsnVarID, getNumOperands())1730.emitPredicateOpcodes(Table, Rule);17311732// First emit all instruction level predicates need to be verified before we1733// can verify operands.1734emitFilteredPredicateListOpcodes(1735[](const PredicateMatcher &P) { return !P.dependsOnOperands(); }, Table,1736Rule);17371738// Emit all operand constraints.1739for (const auto &Operand : Operands)1740Operand->emitPredicateOpcodes(Table, Rule);17411742// All of the tablegen defined predicates should now be matched. Now emit1743// any custom predicates that rely on all generated checks.1744emitFilteredPredicateListOpcodes(1745[](const PredicateMatcher &P) { return P.dependsOnOperands(); }, Table,1746Rule);1747}17481749bool InstructionMatcher::isHigherPriorityThan(InstructionMatcher &B) {1750// Instruction matchers involving more operands have higher priority.1751if (Operands.size() > B.Operands.size())1752return true;1753if (Operands.size() < B.Operands.size())1754return false;17551756for (auto &&P : zip(predicates(), B.predicates())) {1757auto L = static_cast<InstructionPredicateMatcher *>(std::get<0>(P).get());1758auto R = static_cast<InstructionPredicateMatcher *>(std::get<1>(P).get());1759if (L->isHigherPriorityThan(*R))1760return true;1761if (R->isHigherPriorityThan(*L))1762return false;1763}17641765for (auto Operand : zip(Operands, B.Operands)) {1766if (std::get<0>(Operand)->isHigherPriorityThan(*std::get<1>(Operand)))1767return true;1768if (std::get<1>(Operand)->isHigherPriorityThan(*std::get<0>(Operand)))1769return false;1770}17711772return false;1773}17741775unsigned InstructionMatcher::countRendererFns() {1776return std::accumulate(1777predicates().begin(), predicates().end(), 0,1778[](unsigned A,1779const std::unique_ptr<PredicateMatcher> &Predicate) {1780return A + Predicate->countRendererFns();1781}) +1782std::accumulate(1783Operands.begin(), Operands.end(), 0,1784[](unsigned A, const std::unique_ptr<OperandMatcher> &Operand) {1785return A + Operand->countRendererFns();1786});1787}17881789void InstructionMatcher::optimize() {1790SmallVector<std::unique_ptr<PredicateMatcher>, 8> Stash;1791const auto &OpcMatcher = getOpcodeMatcher();17921793Stash.push_back(predicates_pop_front());1794if (Stash.back().get() == &OpcMatcher) {1795if (NumOperandsCheck && OpcMatcher.isVariadicNumOperands() &&1796getNumOperands() != 0)1797Stash.emplace_back(1798new InstructionNumOperandsMatcher(InsnVarID, getNumOperands()));1799NumOperandsCheck = false;18001801for (auto &OM : Operands)1802for (auto &OP : OM->predicates())1803if (isa<IntrinsicIDOperandMatcher>(OP)) {1804Stash.push_back(std::move(OP));1805OM->eraseNullPredicates();1806break;1807}1808}18091810if (InsnVarID > 0) {1811assert(!Operands.empty() && "Nested instruction is expected to def a vreg");1812for (auto &OP : Operands[0]->predicates())1813OP.reset();1814Operands[0]->eraseNullPredicates();1815}1816for (auto &OM : Operands) {1817for (auto &OP : OM->predicates())1818if (isa<LLTOperandMatcher>(OP))1819Stash.push_back(std::move(OP));1820OM->eraseNullPredicates();1821}1822while (!Stash.empty())1823prependPredicate(Stash.pop_back_val());1824}18251826//===- InstructionOperandMatcher ------------------------------------------===//18271828void InstructionOperandMatcher::emitCaptureOpcodes(MatchTable &Table,1829RuleMatcher &Rule) const {1830const unsigned NewInsnVarID = InsnMatcher->getInsnVarID();1831const bool IgnoreCopies = Flags & GISF_IgnoreCopies;1832Table << MatchTable::Opcode(IgnoreCopies ? "GIM_RecordInsnIgnoreCopies"1833: "GIM_RecordInsn")1834<< MatchTable::Comment("DefineMI")1835<< MatchTable::ULEB128Value(NewInsnVarID) << MatchTable::Comment("MI")1836<< MatchTable::ULEB128Value(getInsnVarID())1837<< MatchTable::Comment("OpIdx") << MatchTable::ULEB128Value(getOpIdx())1838<< MatchTable::Comment("MIs[" + llvm::to_string(NewInsnVarID) + "]")1839<< MatchTable::LineBreak;1840}18411842bool InstructionOperandMatcher::isHigherPriorityThan(1843const OperandPredicateMatcher &B) const {1844if (OperandPredicateMatcher::isHigherPriorityThan(B))1845return true;1846if (B.OperandPredicateMatcher::isHigherPriorityThan(*this))1847return false;18481849if (const InstructionOperandMatcher *BP =1850dyn_cast<InstructionOperandMatcher>(&B))1851if (InsnMatcher->isHigherPriorityThan(*BP->InsnMatcher))1852return true;1853return false;1854}18551856//===- OperandRenderer ----------------------------------------------------===//18571858OperandRenderer::~OperandRenderer() {}18591860//===- CopyRenderer -------------------------------------------------------===//18611862void CopyRenderer::emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule,1863unsigned NewInsnID, unsigned OldInsnID,1864unsigned OpIdx, StringRef Name) {1865if (NewInsnID == 0 && OldInsnID == 0) {1866Table << MatchTable::Opcode("GIR_RootToRootCopy");1867} else {1868Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID")1869<< MatchTable::ULEB128Value(NewInsnID)1870<< MatchTable::Comment("OldInsnID")1871<< MatchTable::ULEB128Value(OldInsnID);1872}18731874Table << MatchTable::Comment("OpIdx") << MatchTable::ULEB128Value(OpIdx)1875<< MatchTable::Comment(Name) << MatchTable::LineBreak;1876}18771878void CopyRenderer::emitRenderOpcodes(MatchTable &Table,1879RuleMatcher &Rule) const {1880const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);1881unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());1882emitRenderOpcodes(Table, Rule, NewInsnID, OldInsnVarID, Operand.getOpIdx(),1883SymbolicName);1884}18851886//===- CopyPhysRegRenderer ------------------------------------------------===//18871888void CopyPhysRegRenderer::emitRenderOpcodes(MatchTable &Table,1889RuleMatcher &Rule) const {1890const OperandMatcher &Operand = Rule.getPhysRegOperandMatcher(PhysReg);1891unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());1892CopyRenderer::emitRenderOpcodes(Table, Rule, NewInsnID, OldInsnVarID,1893Operand.getOpIdx(), PhysReg->getName());1894}18951896//===- CopyOrAddZeroRegRenderer -------------------------------------------===//18971898void CopyOrAddZeroRegRenderer::emitRenderOpcodes(MatchTable &Table,1899RuleMatcher &Rule) const {1900const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);1901unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());1902Table << MatchTable::Opcode("GIR_CopyOrAddZeroReg")1903<< MatchTable::Comment("NewInsnID")1904<< MatchTable::ULEB128Value(NewInsnID)1905<< MatchTable::Comment("OldInsnID")1906<< MatchTable::ULEB128Value(OldInsnVarID)1907<< MatchTable::Comment("OpIdx")1908<< MatchTable::ULEB128Value(Operand.getOpIdx())1909<< MatchTable::NamedValue(19102,1911(ZeroRegisterDef->getValue("Namespace")1912? ZeroRegisterDef->getValueAsString("Namespace")1913: ""),1914ZeroRegisterDef->getName())1915<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;1916}19171918//===- CopyConstantAsImmRenderer ------------------------------------------===//19191920void CopyConstantAsImmRenderer::emitRenderOpcodes(MatchTable &Table,1921RuleMatcher &Rule) const {1922InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);1923unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);1924Table << MatchTable::Opcode(Signed ? "GIR_CopyConstantAsSImm"1925: "GIR_CopyConstantAsUImm")1926<< MatchTable::Comment("NewInsnID")1927<< MatchTable::ULEB128Value(NewInsnID)1928<< MatchTable::Comment("OldInsnID")1929<< MatchTable::ULEB128Value(OldInsnVarID)1930<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;1931}19321933//===- CopyFConstantAsFPImmRenderer ---------------------------------------===//19341935void CopyFConstantAsFPImmRenderer::emitRenderOpcodes(MatchTable &Table,1936RuleMatcher &Rule) const {1937InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);1938unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);1939Table << MatchTable::Opcode("GIR_CopyFConstantAsFPImm")1940<< MatchTable::Comment("NewInsnID")1941<< MatchTable::ULEB128Value(NewInsnID)1942<< MatchTable::Comment("OldInsnID")1943<< MatchTable::ULEB128Value(OldInsnVarID)1944<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;1945}19461947//===- CopySubRegRenderer -------------------------------------------------===//19481949void CopySubRegRenderer::emitRenderOpcodes(MatchTable &Table,1950RuleMatcher &Rule) const {1951const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);1952unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());1953Table << MatchTable::Opcode("GIR_CopySubReg")1954<< MatchTable::Comment("NewInsnID")1955<< MatchTable::ULEB128Value(NewInsnID)1956<< MatchTable::Comment("OldInsnID")1957<< MatchTable::ULEB128Value(OldInsnVarID)1958<< MatchTable::Comment("OpIdx")1959<< MatchTable::ULEB128Value(Operand.getOpIdx())1960<< MatchTable::Comment("SubRegIdx")1961<< MatchTable::IntValue(2, SubReg->EnumValue)1962<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;1963}19641965//===- AddRegisterRenderer ------------------------------------------------===//19661967void AddRegisterRenderer::emitRenderOpcodes(MatchTable &Table,1968RuleMatcher &Rule) const {1969Table << MatchTable::Opcode("GIR_AddRegister")1970<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID);1971if (RegisterDef->getName() != "zero_reg") {1972Table << MatchTable::NamedValue(19732,1974(RegisterDef->getValue("Namespace")1975? RegisterDef->getValueAsString("Namespace")1976: ""),1977RegisterDef->getName());1978} else {1979Table << MatchTable::NamedValue(2, Target.getRegNamespace(), "NoRegister");1980}1981Table << MatchTable::Comment("AddRegisterRegFlags");19821983// TODO: This is encoded as a 64-bit element, but only 16 or 32-bits are1984// really needed for a physical register reference. We can pack the1985// register and flags in a single field.1986if (IsDef)1987Table << MatchTable::NamedValue(2, "RegState::Define");1988else1989Table << MatchTable::IntValue(2, 0);1990Table << MatchTable::LineBreak;1991}19921993//===- TempRegRenderer ----------------------------------------------------===//19941995void TempRegRenderer::emitRenderOpcodes(MatchTable &Table,1996RuleMatcher &Rule) const {1997const bool NeedsFlags = (SubRegIdx || IsDef);1998if (SubRegIdx) {1999assert(!IsDef);2000Table << MatchTable::Opcode("GIR_AddTempSubRegister");2001} else2002Table << MatchTable::Opcode(NeedsFlags ? "GIR_AddTempRegister"2003: "GIR_AddSimpleTempRegister");20042005Table << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2006<< MatchTable::Comment("TempRegID")2007<< MatchTable::ULEB128Value(TempRegID);20082009if (!NeedsFlags) {2010Table << MatchTable::LineBreak;2011return;2012}20132014Table << MatchTable::Comment("TempRegFlags");2015if (IsDef) {2016SmallString<32> RegFlags;2017RegFlags += "RegState::Define";2018if (IsDead)2019RegFlags += "|RegState::Dead";2020Table << MatchTable::NamedValue(2, RegFlags);2021} else2022Table << MatchTable::IntValue(2, 0);20232024if (SubRegIdx)2025Table << MatchTable::NamedValue(2, SubRegIdx->getQualifiedName());2026Table << MatchTable::LineBreak;2027}20282029//===- ImmRenderer --------------------------------------------------------===//20302031void ImmRenderer::emitAddImm(MatchTable &Table, RuleMatcher &RM,2032unsigned InsnID, int64_t Imm, StringRef ImmName) {2033const bool IsInt8 = isInt<8>(Imm);20342035Table << MatchTable::Opcode(IsInt8 ? "GIR_AddImm8" : "GIR_AddImm")2036<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2037<< MatchTable::Comment(ImmName)2038<< MatchTable::IntValue(IsInt8 ? 1 : 8, Imm) << MatchTable::LineBreak;2039}20402041void ImmRenderer::emitRenderOpcodes(MatchTable &Table,2042RuleMatcher &Rule) const {2043if (CImmLLT) {2044assert(Table.isCombiner() &&2045"ConstantInt immediate are only for combiners!");2046Table << MatchTable::Opcode("GIR_AddCImm") << MatchTable::Comment("InsnID")2047<< MatchTable::ULEB128Value(InsnID) << MatchTable::Comment("Type")2048<< *CImmLLT << MatchTable::Comment("Imm")2049<< MatchTable::IntValue(8, Imm) << MatchTable::LineBreak;2050} else2051emitAddImm(Table, Rule, InsnID, Imm);2052}20532054//===- SubRegIndexRenderer ------------------------------------------------===//20552056void SubRegIndexRenderer::emitRenderOpcodes(MatchTable &Table,2057RuleMatcher &Rule) const {2058ImmRenderer::emitAddImm(Table, Rule, InsnID, SubRegIdx->EnumValue,2059"SubRegIndex");2060}20612062//===- RenderComplexPatternOperand ----------------------------------------===//20632064void RenderComplexPatternOperand::emitRenderOpcodes(MatchTable &Table,2065RuleMatcher &Rule) const {2066Table << MatchTable::Opcode(2067SubOperand ? (SubReg ? "GIR_ComplexSubOperandSubRegRenderer"2068: "GIR_ComplexSubOperandRenderer")2069: "GIR_ComplexRenderer")2070<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2071<< MatchTable::Comment("RendererID")2072<< MatchTable::IntValue(2, RendererID);2073if (SubOperand)2074Table << MatchTable::Comment("SubOperand")2075<< MatchTable::ULEB128Value(*SubOperand);2076if (SubReg)2077Table << MatchTable::Comment("SubRegIdx")2078<< MatchTable::IntValue(2, SubReg->EnumValue);2079Table << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;2080}20812082//===- IntrinsicIDRenderer ------------------------------------------------===//20832084void IntrinsicIDRenderer::emitRenderOpcodes(MatchTable &Table,2085RuleMatcher &Rule) const {2086Table << MatchTable::Opcode("GIR_AddIntrinsicID") << MatchTable::Comment("MI")2087<< MatchTable::ULEB128Value(InsnID)2088<< MatchTable::NamedValue(2, "Intrinsic::" + II->EnumName)2089<< MatchTable::LineBreak;2090}20912092//===- CustomRenderer -----------------------------------------------------===//20932094void CustomRenderer::emitRenderOpcodes(MatchTable &Table,2095RuleMatcher &Rule) const {2096InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);2097unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);2098Table << MatchTable::Opcode("GIR_CustomRenderer")2099<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2100<< MatchTable::Comment("OldInsnID")2101<< MatchTable::ULEB128Value(OldInsnVarID)2102<< MatchTable::Comment("Renderer")2103<< MatchTable::NamedValue(21042, "GICR_" + Renderer.getValueAsString("RendererFn").str())2105<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;2106}21072108//===- CustomOperandRenderer ----------------------------------------------===//21092110void CustomOperandRenderer::emitRenderOpcodes(MatchTable &Table,2111RuleMatcher &Rule) const {2112const OperandMatcher &OpdMatcher = Rule.getOperandMatcher(SymbolicName);2113Table << MatchTable::Opcode("GIR_CustomOperandRenderer")2114<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2115<< MatchTable::Comment("OldInsnID")2116<< MatchTable::ULEB128Value(OpdMatcher.getInsnVarID())2117<< MatchTable::Comment("OpIdx")2118<< MatchTable::ULEB128Value(OpdMatcher.getOpIdx())2119<< MatchTable::Comment("OperandRenderer")2120<< MatchTable::NamedValue(21212, "GICR_" + Renderer.getValueAsString("RendererFn").str())2122<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;2123}21242125//===- BuildMIAction ------------------------------------------------------===//21262127bool BuildMIAction::canMutate(RuleMatcher &Rule,2128const InstructionMatcher *Insn) const {2129if (!Insn)2130return false;21312132if (OperandRenderers.size() != Insn->getNumOperands())2133return false;21342135for (const auto &Renderer : enumerate(OperandRenderers)) {2136if (const auto *Copy = dyn_cast<CopyRenderer>(&*Renderer.value())) {2137const OperandMatcher &OM =2138Rule.getOperandMatcher(Copy->getSymbolicName());2139if (Insn != &OM.getInstructionMatcher() ||2140OM.getOpIdx() != Renderer.index())2141return false;2142} else2143return false;2144}21452146return true;2147}21482149void BuildMIAction::chooseInsnToMutate(RuleMatcher &Rule) {2150for (auto *MutateCandidate : Rule.mutatable_insns()) {2151if (canMutate(Rule, MutateCandidate)) {2152// Take the first one we're offered that we're able to mutate.2153Rule.reserveInsnMatcherForMutation(MutateCandidate);2154Matched = MutateCandidate;2155return;2156}2157}2158}21592160void BuildMIAction::emitActionOpcodes(MatchTable &Table,2161RuleMatcher &Rule) const {2162const auto AddMIFlags = [&]() {2163for (const InstructionMatcher *IM : CopiedFlags) {2164Table << MatchTable::Opcode("GIR_CopyMIFlags")2165<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2166<< MatchTable::Comment("OldInsnID")2167<< MatchTable::ULEB128Value(IM->getInsnVarID())2168<< MatchTable::LineBreak;2169}21702171if (!SetFlags.empty()) {2172Table << MatchTable::Opcode("GIR_SetMIFlags")2173<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2174<< MatchTable::NamedValue(4, join(SetFlags, " | "))2175<< MatchTable::LineBreak;2176}21772178if (!UnsetFlags.empty()) {2179Table << MatchTable::Opcode("GIR_UnsetMIFlags")2180<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2181<< MatchTable::NamedValue(4, join(UnsetFlags, " | "))2182<< MatchTable::LineBreak;2183}2184};21852186if (Matched) {2187assert(canMutate(Rule, Matched) &&2188"Arranged to mutate an insn that isn't mutatable");21892190unsigned RecycleInsnID = Rule.getInsnVarID(*Matched);2191Table << MatchTable::Opcode("GIR_MutateOpcode")2192<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2193<< MatchTable::Comment("RecycleInsnID")2194<< MatchTable::ULEB128Value(RecycleInsnID)2195<< MatchTable::Comment("Opcode")2196<< MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName())2197<< MatchTable::LineBreak;21982199if (!I->ImplicitDefs.empty() || !I->ImplicitUses.empty()) {2200for (auto *Def : I->ImplicitDefs) {2201auto Namespace = Def->getValue("Namespace")2202? Def->getValueAsString("Namespace")2203: "";2204const bool IsDead = DeadImplicitDefs.contains(Def);2205Table << MatchTable::Opcode("GIR_AddImplicitDef")2206<< MatchTable::Comment("InsnID")2207<< MatchTable::ULEB128Value(InsnID)2208<< MatchTable::NamedValue(2, Namespace, Def->getName())2209<< (IsDead ? MatchTable::NamedValue(2, "RegState", "Dead")2210: MatchTable::IntValue(2, 0))2211<< MatchTable::LineBreak;2212}2213for (auto *Use : I->ImplicitUses) {2214auto Namespace = Use->getValue("Namespace")2215? Use->getValueAsString("Namespace")2216: "";2217Table << MatchTable::Opcode("GIR_AddImplicitUse")2218<< MatchTable::Comment("InsnID")2219<< MatchTable::ULEB128Value(InsnID)2220<< MatchTable::NamedValue(2, Namespace, Use->getName())2221<< MatchTable::LineBreak;2222}2223}22242225AddMIFlags();22262227// Mark the mutated instruction as erased.2228Rule.tryEraseInsnID(RecycleInsnID);2229return;2230}22312232// TODO: Simple permutation looks like it could be almost as common as2233// mutation due to commutative operations.22342235if (InsnID == 0) {2236Table << MatchTable::Opcode("GIR_BuildRootMI");2237} else {2238Table << MatchTable::Opcode("GIR_BuildMI") << MatchTable::Comment("InsnID")2239<< MatchTable::ULEB128Value(InsnID);2240}22412242Table << MatchTable::Comment("Opcode")2243<< MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName())2244<< MatchTable::LineBreak;22452246for (const auto &Renderer : OperandRenderers)2247Renderer->emitRenderOpcodes(Table, Rule);22482249for (auto [OpIdx, Def] : enumerate(I->ImplicitDefs)) {2250auto Namespace =2251Def->getValue("Namespace") ? Def->getValueAsString("Namespace") : "";2252if (DeadImplicitDefs.contains(Def)) {2253Table2254<< MatchTable::Opcode("GIR_SetImplicitDefDead")2255<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2256<< MatchTable::Comment(2257("OpIdx for " + Namespace + "::" + Def->getName() + "").str())2258<< MatchTable::ULEB128Value(OpIdx) << MatchTable::LineBreak;2259}2260}22612262if (I->mayLoad || I->mayStore) {2263// Emit the ID's for all the instructions that are matched by this rule.2264// TODO: Limit this to matched instructions that mayLoad/mayStore or have2265// some other means of having a memoperand. Also limit this to2266// emitted instructions that expect to have a memoperand too. For2267// example, (G_SEXT (G_LOAD x)) that results in separate load and2268// sign-extend instructions shouldn't put the memoperand on the2269// sign-extend since it has no effect there.22702271std::vector<unsigned> MergeInsnIDs;2272for (const auto &IDMatcherPair : Rule.defined_insn_vars())2273MergeInsnIDs.push_back(IDMatcherPair.second);2274llvm::sort(MergeInsnIDs);22752276Table << MatchTable::Opcode("GIR_MergeMemOperands")2277<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2278<< MatchTable::Comment("NumInsns")2279<< MatchTable::IntValue(1, MergeInsnIDs.size())2280<< MatchTable::Comment("MergeInsnID's");2281for (const auto &MergeInsnID : MergeInsnIDs)2282Table << MatchTable::ULEB128Value(MergeInsnID);2283Table << MatchTable::LineBreak;2284}22852286AddMIFlags();2287}22882289//===- BuildConstantAction ------------------------------------------------===//22902291void BuildConstantAction::emitActionOpcodes(MatchTable &Table,2292RuleMatcher &Rule) const {2293Table << MatchTable::Opcode("GIR_BuildConstant")2294<< MatchTable::Comment("TempRegID")2295<< MatchTable::ULEB128Value(TempRegID) << MatchTable::Comment("Val")2296<< MatchTable::IntValue(8, Val) << MatchTable::LineBreak;2297}22982299//===- EraseInstAction ----------------------------------------------------===//23002301void EraseInstAction::emitActionOpcodes(MatchTable &Table,2302RuleMatcher &Rule) const {2303// Avoid erasing the same inst twice.2304if (!Rule.tryEraseInsnID(InsnID))2305return;23062307Table << MatchTable::Opcode("GIR_EraseFromParent")2308<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2309<< MatchTable::LineBreak;2310}23112312bool EraseInstAction::emitActionOpcodesAndDone(MatchTable &Table,2313RuleMatcher &Rule) const {2314if (InsnID != 0) {2315emitActionOpcodes(Table, Rule);2316return false;2317}23182319if (!Rule.tryEraseInsnID(0))2320return false;23212322Table << MatchTable::Opcode("GIR_EraseRootFromParent_Done", -1)2323<< MatchTable::LineBreak;2324return true;2325}23262327//===- ReplaceRegAction ---------------------------------------------------===//23282329void ReplaceRegAction::emitAdditionalPredicates(MatchTable &Table,2330RuleMatcher &Rule) const {2331if (TempRegID != (unsigned)-1)2332return;23332334Table << MatchTable::Opcode("GIM_CheckCanReplaceReg")2335<< MatchTable::Comment("OldInsnID")2336<< MatchTable::ULEB128Value(OldInsnID)2337<< MatchTable::Comment("OldOpIdx") << MatchTable::ULEB128Value(OldOpIdx)2338<< MatchTable::Comment("NewInsnId")2339<< MatchTable::ULEB128Value(NewInsnId)2340<< MatchTable::Comment("NewOpIdx") << MatchTable::ULEB128Value(NewOpIdx)2341<< MatchTable::LineBreak;2342}23432344void ReplaceRegAction::emitActionOpcodes(MatchTable &Table,2345RuleMatcher &Rule) const {2346if (TempRegID != (unsigned)-1) {2347Table << MatchTable::Opcode("GIR_ReplaceRegWithTempReg")2348<< MatchTable::Comment("OldInsnID")2349<< MatchTable::ULEB128Value(OldInsnID)2350<< MatchTable::Comment("OldOpIdx")2351<< MatchTable::ULEB128Value(OldOpIdx)2352<< MatchTable::Comment("TempRegID")2353<< MatchTable::ULEB128Value(TempRegID) << MatchTable::LineBreak;2354} else {2355Table << MatchTable::Opcode("GIR_ReplaceReg")2356<< MatchTable::Comment("OldInsnID")2357<< MatchTable::ULEB128Value(OldInsnID)2358<< MatchTable::Comment("OldOpIdx")2359<< MatchTable::ULEB128Value(OldOpIdx)2360<< MatchTable::Comment("NewInsnId")2361<< MatchTable::ULEB128Value(NewInsnId)2362<< MatchTable::Comment("NewOpIdx")2363<< MatchTable::ULEB128Value(NewOpIdx) << MatchTable::LineBreak;2364}2365}23662367//===- ConstrainOperandToRegClassAction -----------------------------------===//23682369void ConstrainOperandToRegClassAction::emitActionOpcodes(2370MatchTable &Table, RuleMatcher &Rule) const {2371Table << MatchTable::Opcode("GIR_ConstrainOperandRC")2372<< MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)2373<< MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)2374<< MatchTable::NamedValue(2, RC.getQualifiedIdName())2375<< MatchTable::LineBreak;2376}23772378//===- MakeTempRegisterAction ---------------------------------------------===//23792380void MakeTempRegisterAction::emitActionOpcodes(MatchTable &Table,2381RuleMatcher &Rule) const {2382Table << MatchTable::Opcode("GIR_MakeTempReg")2383<< MatchTable::Comment("TempRegID")2384<< MatchTable::ULEB128Value(TempRegID) << MatchTable::Comment("TypeID")2385<< Ty << MatchTable::LineBreak;2386}23872388} // namespace gi2389} // namespace llvm239023912392