From 4f9aab2b500d3df0cc5d54f2d29c8199507af66c Mon Sep 17 00:00:00 2001 From: Pierre van Houtryve Date: Wed, 27 Mar 2024 13:53:36 +0100 Subject: [NFC][TableGen][GlobalISel] Move MIR pattern parsing out of combiner (#86789) Reland of cfa0833ccc7450a322e709583e894e4c96ce682e --- llvm/utils/TableGen/Common/CMakeLists.txt | 2 + .../TableGen/Common/GlobalISel/CombinerUtils.cpp | 23 + .../TableGen/Common/GlobalISel/CombinerUtils.h | 4 + .../TableGen/Common/GlobalISel/PatternParser.cpp | 462 ++++++++++++++++++++ .../TableGen/Common/GlobalISel/PatternParser.h | 118 +++++ llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp | 479 +-------------------- 6 files changed, 623 insertions(+), 465 deletions(-) create mode 100644 llvm/utils/TableGen/Common/GlobalISel/CombinerUtils.cpp create mode 100644 llvm/utils/TableGen/Common/GlobalISel/PatternParser.cpp create mode 100644 llvm/utils/TableGen/Common/GlobalISel/PatternParser.h diff --git a/llvm/utils/TableGen/Common/CMakeLists.txt b/llvm/utils/TableGen/Common/CMakeLists.txt index 0440f02..c31ed5a 100644 --- a/llvm/utils/TableGen/Common/CMakeLists.txt +++ b/llvm/utils/TableGen/Common/CMakeLists.txt @@ -12,10 +12,12 @@ set(LLVM_LINK_COMPONENTS add_llvm_library(LLVMTableGenCommon STATIC OBJECT EXCLUDE_FROM_ALL GlobalISel/CodeExpander.cpp + GlobalISel/CombinerUtils.cpp GlobalISel/CXXPredicates.cpp GlobalISel/GlobalISelMatchTable.cpp GlobalISel/GlobalISelMatchTableExecutorEmitter.cpp GlobalISel/MatchDataInfo.cpp + GlobalISel/PatternParser.cpp GlobalISel/Patterns.cpp AsmWriterInst.cpp diff --git a/llvm/utils/TableGen/Common/GlobalISel/CombinerUtils.cpp b/llvm/utils/TableGen/Common/GlobalISel/CombinerUtils.cpp new file mode 100644 index 0000000..37e6306 --- /dev/null +++ b/llvm/utils/TableGen/Common/GlobalISel/CombinerUtils.cpp @@ -0,0 +1,23 @@ +//===- CombinerUtils.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CombinerUtils.h" +#include "llvm/ADT/StringSet.h" + +namespace llvm { + +StringRef insertStrRef(StringRef S) { + if (S.empty()) + return {}; + + static StringSet<> Pool; + auto [It, Inserted] = Pool.insert(S); + return It->getKey(); +} + +} // namespace llvm diff --git a/llvm/utils/TableGen/Common/GlobalISel/CombinerUtils.h b/llvm/utils/TableGen/Common/GlobalISel/CombinerUtils.h index 8cb2514..82a64c6 100644 --- a/llvm/utils/TableGen/Common/GlobalISel/CombinerUtils.h +++ b/llvm/utils/TableGen/Common/GlobalISel/CombinerUtils.h @@ -65,6 +65,10 @@ inline const DagInit *getDagWithOperatorOfSubClass(const Init &N, return I; return nullptr; } + +/// Copies a StringRef into a static pool to preserve it. +StringRef insertStrRef(StringRef S); + } // namespace llvm #endif diff --git a/llvm/utils/TableGen/Common/GlobalISel/PatternParser.cpp b/llvm/utils/TableGen/Common/GlobalISel/PatternParser.cpp new file mode 100644 index 0000000..1d6c4c7 --- /dev/null +++ b/llvm/utils/TableGen/Common/GlobalISel/PatternParser.cpp @@ -0,0 +1,462 @@ +//===- PatternParser.cpp ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Common/GlobalISel/PatternParser.h" +#include "Basic/CodeGenIntrinsics.h" +#include "Common/CodeGenTarget.h" +#include "Common/GlobalISel/CombinerUtils.h" +#include "Common/GlobalISel/Patterns.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/SaveAndRestore.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" + +namespace llvm { +namespace gi { +static constexpr StringLiteral MIFlagsEnumClassName = "MIFlagEnum"; + +namespace { +class PrettyStackTraceParse : public PrettyStackTraceEntry { + const Record &Def; + +public: + PrettyStackTraceParse(const Record &Def) : Def(Def) {} + + void print(raw_ostream &OS) const override { + if (Def.isSubClassOf("GICombineRule")) + OS << "Parsing GICombineRule '" << Def.getName() << '\''; + else if (Def.isSubClassOf(PatFrag::ClassName)) + OS << "Parsing " << PatFrag::ClassName << " '" << Def.getName() << '\''; + else + OS << "Parsing '" << Def.getName() << '\''; + OS << '\n'; + } +}; +} // namespace + +bool PatternParser::parsePatternList( + const DagInit &List, + function_ref)> ParseAction, + StringRef Operator, StringRef AnonPatNamePrefix) { + if (List.getOperatorAsDef(DiagLoc)->getName() != Operator) { + PrintError(DiagLoc, "Expected " + Operator + " operator"); + return false; + } + + if (List.getNumArgs() == 0) { + PrintError(DiagLoc, Operator + " pattern list is empty"); + return false; + } + + // The match section consists of a list of matchers and predicates. Parse each + // one and add the equivalent GIMatchDag nodes, predicates, and edges. + for (unsigned I = 0; I < List.getNumArgs(); ++I) { + Init *Arg = List.getArg(I); + std::string Name = List.getArgName(I) + ? List.getArgName(I)->getValue().str() + : ("__" + AnonPatNamePrefix + "_" + Twine(I)).str(); + + if (auto Pat = parseInstructionPattern(*Arg, Name)) { + if (!ParseAction(std::move(Pat))) + return false; + continue; + } + + if (auto Pat = parseWipMatchOpcodeMatcher(*Arg, Name)) { + if (!ParseAction(std::move(Pat))) + return false; + continue; + } + + // Parse arbitrary C++ code + if (const auto *StringI = dyn_cast(Arg)) { + auto CXXPat = std::make_unique(*StringI, insertStrRef(Name)); + if (!ParseAction(std::move(CXXPat))) + return false; + continue; + } + + PrintError(DiagLoc, + "Failed to parse pattern: '" + Arg->getAsString() + '\''); + return false; + } + + return true; +} + +static const CodeGenInstruction & +getInstrForIntrinsic(const CodeGenTarget &CGT, const CodeGenIntrinsic *I) { + StringRef Opc; + if (I->isConvergent) { + Opc = I->hasSideEffects ? "G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS" + : "G_INTRINSIC_CONVERGENT"; + } else { + Opc = I->hasSideEffects ? "G_INTRINSIC_W_SIDE_EFFECTS" : "G_INTRINSIC"; + } + + RecordKeeper &RK = I->TheDef->getRecords(); + return CGT.getInstruction(RK.getDef(Opc)); +} + +static const CodeGenIntrinsic *getCodeGenIntrinsic(Record *R) { + // Intrinsics need to have a static lifetime because the match table keeps + // references to CodeGenIntrinsic objects. + static DenseMap> + AllIntrinsics; + + auto &Ptr = AllIntrinsics[R]; + if (!Ptr) + Ptr = std::make_unique(R, std::vector()); + return Ptr.get(); +} + +std::unique_ptr +PatternParser::parseInstructionPattern(const Init &Arg, StringRef Name) { + const DagInit *DagPat = dyn_cast(&Arg); + if (!DagPat) + return nullptr; + + std::unique_ptr Pat; + if (const DagInit *IP = getDagWithOperatorOfSubClass(Arg, "Instruction")) { + auto &Instr = CGT.getInstruction(IP->getOperatorAsDef(DiagLoc)); + Pat = + std::make_unique(Instr, insertStrRef(Name)); + } else if (const DagInit *IP = + getDagWithOperatorOfSubClass(Arg, "Intrinsic")) { + Record *TheDef = IP->getOperatorAsDef(DiagLoc); + const CodeGenIntrinsic *Intrin = getCodeGenIntrinsic(TheDef); + const CodeGenInstruction &Instr = getInstrForIntrinsic(CGT, Intrin); + Pat = + std::make_unique(Instr, insertStrRef(Name)); + cast(*Pat).setIntrinsic(Intrin); + } else if (const DagInit *PFP = + getDagWithOperatorOfSubClass(Arg, PatFrag::ClassName)) { + const Record *Def = PFP->getOperatorAsDef(DiagLoc); + const PatFrag *PF = parsePatFrag(Def); + if (!PF) + return nullptr; // Already diagnosed by parsePatFrag + Pat = std::make_unique(*PF, insertStrRef(Name)); + } else if (const DagInit *BP = + getDagWithOperatorOfSubClass(Arg, BuiltinPattern::ClassName)) { + Pat = std::make_unique(*BP->getOperatorAsDef(DiagLoc), + insertStrRef(Name)); + } else + return nullptr; + + for (unsigned K = 0; K < DagPat->getNumArgs(); ++K) { + Init *Arg = DagPat->getArg(K); + if (auto *DagArg = getDagWithSpecificOperator(*Arg, "MIFlags")) { + if (!parseInstructionPatternMIFlags(*Pat, DagArg)) + return nullptr; + continue; + } + + if (!parseInstructionPatternOperand(*Pat, Arg, DagPat->getArgName(K))) + return nullptr; + } + + if (!Pat->checkSemantics(DiagLoc)) + return nullptr; + + return std::move(Pat); +} + +std::unique_ptr +PatternParser::parseWipMatchOpcodeMatcher(const Init &Arg, StringRef Name) { + const DagInit *Matcher = getDagWithSpecificOperator(Arg, "wip_match_opcode"); + if (!Matcher) + return nullptr; + + if (Matcher->getNumArgs() == 0) { + PrintError(DiagLoc, "Empty wip_match_opcode"); + return nullptr; + } + + // Each argument is an opcode that can match. + auto Result = std::make_unique(insertStrRef(Name)); + for (const auto &Arg : Matcher->getArgs()) { + Record *OpcodeDef = getDefOfSubClass(*Arg, "Instruction"); + if (OpcodeDef) { + Result->addOpcode(&CGT.getInstruction(OpcodeDef)); + continue; + } + + PrintError(DiagLoc, "Arguments to wip_match_opcode must be instructions"); + return nullptr; + } + + return std::move(Result); +} + +bool PatternParser::parseInstructionPatternOperand(InstructionPattern &IP, + const Init *OpInit, + const StringInit *OpName) { + const auto ParseErr = [&]() { + PrintError(DiagLoc, + "cannot parse operand '" + OpInit->getAsUnquotedString() + "' "); + if (OpName) + PrintNote(DiagLoc, + "operand name is '" + OpName->getAsUnquotedString() + '\''); + return false; + }; + + // untyped immediate, e.g. 0 + if (const auto *IntImm = dyn_cast(OpInit)) { + std::string Name = OpName ? OpName->getAsUnquotedString() : ""; + IP.addOperand(IntImm->getValue(), insertStrRef(Name), PatternType()); + return true; + } + + // typed immediate, e.g. (i32 0) + if (const auto *DagOp = dyn_cast(OpInit)) { + if (DagOp->getNumArgs() != 1) + return ParseErr(); + + const Record *TyDef = DagOp->getOperatorAsDef(DiagLoc); + auto ImmTy = PatternType::get(DiagLoc, TyDef, + "cannot parse immediate '" + + DagOp->getAsUnquotedString() + '\''); + if (!ImmTy) + return false; + + if (!IP.hasAllDefs()) { + PrintError(DiagLoc, "out operand of '" + IP.getInstName() + + "' cannot be an immediate"); + return false; + } + + const auto *Val = dyn_cast(DagOp->getArg(0)); + if (!Val) + return ParseErr(); + + std::string Name = OpName ? OpName->getAsUnquotedString() : ""; + IP.addOperand(Val->getValue(), insertStrRef(Name), *ImmTy); + return true; + } + + // Typed operand e.g. $x/$z in (G_FNEG $x, $z) + if (auto *DefI = dyn_cast(OpInit)) { + if (!OpName) { + PrintError(DiagLoc, "expected an operand name after '" + + OpInit->getAsString() + '\''); + return false; + } + const Record *Def = DefI->getDef(); + auto Ty = PatternType::get(DiagLoc, Def, "cannot parse operand type"); + if (!Ty) + return false; + IP.addOperand(insertStrRef(OpName->getAsUnquotedString()), *Ty); + return true; + } + + // Untyped operand e.g. $x/$z in (G_FNEG $x, $z) + if (isa(OpInit)) { + assert(OpName && "Unset w/ no OpName?"); + IP.addOperand(insertStrRef(OpName->getAsUnquotedString()), PatternType()); + return true; + } + + return ParseErr(); +} + +bool PatternParser::parseInstructionPatternMIFlags(InstructionPattern &IP, + const DagInit *Op) { + auto *CGIP = dyn_cast(&IP); + if (!CGIP) { + PrintError(DiagLoc, + "matching/writing MIFlags is only allowed on CodeGenInstruction " + "patterns"); + return false; + } + + const auto CheckFlagEnum = [&](const Record *R) { + if (!R->isSubClassOf(MIFlagsEnumClassName)) { + PrintError(DiagLoc, "'" + R->getName() + "' is not a subclass of '" + + MIFlagsEnumClassName + "'"); + return false; + } + + return true; + }; + + if (CGIP->getMIFlagsInfo()) { + PrintError(DiagLoc, "MIFlags can only be present once on an instruction"); + return false; + } + + auto &FI = CGIP->getOrCreateMIFlagsInfo(); + for (unsigned K = 0; K < Op->getNumArgs(); ++K) { + const Init *Arg = Op->getArg(K); + + // Match/set a flag: (MIFlags FmNoNans) + if (const auto *Def = dyn_cast(Arg)) { + const Record *R = Def->getDef(); + if (!CheckFlagEnum(R)) + return false; + + FI.addSetFlag(R); + continue; + } + + // Do not match a flag/unset a flag: (MIFlags (not FmNoNans)) + if (const DagInit *NotDag = getDagWithSpecificOperator(*Arg, "not")) { + for (const Init *NotArg : NotDag->getArgs()) { + const DefInit *DefArg = dyn_cast(NotArg); + if (!DefArg) { + PrintError(DiagLoc, "cannot parse '" + NotArg->getAsUnquotedString() + + "': expected a '" + MIFlagsEnumClassName + + "'"); + return false; + } + + const Record *R = DefArg->getDef(); + if (!CheckFlagEnum(R)) + return false; + + FI.addUnsetFlag(R); + continue; + } + + continue; + } + + // Copy flags from a matched instruction: (MIFlags $mi) + if (isa(Arg)) { + FI.addCopyFlag(insertStrRef(Op->getArgName(K)->getAsUnquotedString())); + continue; + } + } + + return true; +} + +std::unique_ptr PatternParser::parsePatFragImpl(const Record *Def) { + auto StackTrace = PrettyStackTraceParse(*Def); + if (!Def->isSubClassOf(PatFrag::ClassName)) + return nullptr; + + const DagInit *Ins = Def->getValueAsDag("InOperands"); + if (Ins->getOperatorAsDef(Def->getLoc())->getName() != "ins") { + PrintError(Def, "expected 'ins' operator for " + PatFrag::ClassName + + " in operands list"); + return nullptr; + } + + const DagInit *Outs = Def->getValueAsDag("OutOperands"); + if (Outs->getOperatorAsDef(Def->getLoc())->getName() != "outs") { + PrintError(Def, "expected 'outs' operator for " + PatFrag::ClassName + + " out operands list"); + return nullptr; + } + + auto Result = std::make_unique(*Def); + if (!parsePatFragParamList(*Outs, [&](StringRef Name, unsigned Kind) { + Result->addOutParam(insertStrRef(Name), (PatFrag::ParamKind)Kind); + return true; + })) + return nullptr; + + if (!parsePatFragParamList(*Ins, [&](StringRef Name, unsigned Kind) { + Result->addInParam(insertStrRef(Name), (PatFrag::ParamKind)Kind); + return true; + })) + return nullptr; + + const ListInit *Alts = Def->getValueAsListInit("Alternatives"); + unsigned AltIdx = 0; + for (const Init *Alt : *Alts) { + const auto *PatDag = dyn_cast(Alt); + if (!PatDag) { + PrintError(Def, "expected dag init for PatFrag pattern alternative"); + return nullptr; + } + + PatFrag::Alternative &A = Result->addAlternative(); + const auto AddPat = [&](std::unique_ptr Pat) { + A.Pats.push_back(std::move(Pat)); + return true; + }; + + SaveAndRestore> DiagLocSAR(DiagLoc, Def->getLoc()); + if (!parsePatternList( + *PatDag, AddPat, "pattern", + /*AnonPatPrefix*/ + (Def->getName() + "_alt" + Twine(AltIdx++) + "_pattern").str())) + return nullptr; + } + + if (!Result->buildOperandsTables() || !Result->checkSemantics()) + return nullptr; + + return Result; +} + +bool PatternParser::parsePatFragParamList( + const DagInit &OpsList, + function_ref ParseAction) { + for (unsigned K = 0; K < OpsList.getNumArgs(); ++K) { + const StringInit *Name = OpsList.getArgName(K); + const Init *Ty = OpsList.getArg(K); + + if (!Name) { + PrintError(DiagLoc, "all operands must be named'"); + return false; + } + const std::string NameStr = Name->getAsUnquotedString(); + + PatFrag::ParamKind OpKind; + if (isSpecificDef(*Ty, "gi_imm")) + OpKind = PatFrag::PK_Imm; + else if (isSpecificDef(*Ty, "root")) + OpKind = PatFrag::PK_Root; + else if (isa(Ty) || + isSpecificDef(*Ty, "gi_mo")) // no type = gi_mo. + OpKind = PatFrag::PK_MachineOperand; + else { + PrintError( + DiagLoc, + '\'' + NameStr + + "' operand type was expected to be 'root', 'gi_imm' or 'gi_mo'"); + return false; + } + + if (!ParseAction(NameStr, (unsigned)OpKind)) + return false; + } + + return true; +} + +const PatFrag *PatternParser::parsePatFrag(const Record *Def) { + // Cache already parsed PatFrags to avoid doing extra work. + static DenseMap> ParsedPatFrags; + + auto It = ParsedPatFrags.find(Def); + if (It != ParsedPatFrags.end()) { + SeenPatFrags.insert(It->second.get()); + return It->second.get(); + } + + std::unique_ptr NewPatFrag = parsePatFragImpl(Def); + if (!NewPatFrag) { + PrintError(Def, "Could not parse " + PatFrag::ClassName + " '" + + Def->getName() + "'"); + // Put a nullptr in the map so we don't attempt parsing this again. + ParsedPatFrags[Def] = nullptr; + return nullptr; + } + + const auto *Res = NewPatFrag.get(); + ParsedPatFrags[Def] = std::move(NewPatFrag); + SeenPatFrags.insert(Res); + return Res; +} + +} // namespace gi +} // namespace llvm diff --git a/llvm/utils/TableGen/Common/GlobalISel/PatternParser.h b/llvm/utils/TableGen/Common/GlobalISel/PatternParser.h new file mode 100644 index 0000000..cd6f524 --- /dev/null +++ b/llvm/utils/TableGen/Common/GlobalISel/PatternParser.h @@ -0,0 +1,118 @@ +//===- PatternParser.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file Contains tools to parse MIR patterns from TableGen DAG elements. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_GLOBALISEL_PATTERNPARSER_H +#define LLVM_UTILS_GLOBALISEL_PATTERNPARSER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLFunctionalExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/SMLoc.h" +#include + +namespace llvm { +class CodeGenTarget; +class DagInit; +class Init; +class Record; +class StringRef; +class StringInit; + +namespace gi { +class InstructionPattern; +class Pattern; +class PatFrag; + +/// Helper class to parse MIR Pattern lists. +/// +/// e.g., `(match (G_FADD $x, $y, $z), (G_FNEG $y, $z))` +class PatternParser { + const CodeGenTarget &CGT; + ArrayRef DiagLoc; + + mutable SmallPtrSet SeenPatFrags; + +public: + PatternParser(const CodeGenTarget &CGT, ArrayRef DiagLoc) + : CGT(CGT), DiagLoc(DiagLoc) {} + + /// Parses a list of patterns such as: + /// (Operator (Pattern1 ...), (Pattern2 ...)) + /// \param List DagInit of the expected pattern list. + /// \param ParseAction Callback to handle a succesfully parsed pattern. + /// \param Operator The name of the operator, e.g. "match" + /// \param AnonPatNamePrefix Prefix for anonymous pattern names. + /// \return true on success, false on failure. + bool + parsePatternList(const DagInit &List, + function_ref)> ParseAction, + StringRef Operator, StringRef AnonPatNamePrefix); + + /// \returns all PatFrags encountered by this PatternParser. + const auto &getSeenPatFrags() const { return SeenPatFrags; } + +private: + /// Parse any InstructionPattern from a TableGen Init. + /// \param Arg Init to parse. + /// \param PatName Name of the pattern that will be parsed. + /// \return the parsed pattern on success, nullptr on failure. + std::unique_ptr parseInstructionPattern(const Init &Arg, + StringRef PatName); + + /// Parse a WipOpcodeMatcher from a TableGen Init. + /// \param Arg Init to parse. + /// \param PatName Name of the pattern that will be parsed. + /// \return the parsed pattern on success, nullptr on failure. + std::unique_ptr parseWipMatchOpcodeMatcher(const Init &Arg, + StringRef PatName); + + /// Parses an Operand of an InstructionPattern from a TableGen Init. + /// \param IP InstructionPattern for which we're parsing. + /// \param OpInit Init to parse. + /// \param OpName Name of the operand to parse. + /// \return true on success, false on failure. + bool parseInstructionPatternOperand(InstructionPattern &IP, + const Init *OpInit, + const StringInit *OpName); + + /// Parses a MIFlag for an InstructionPattern from a TableGen Init. + /// \param IP InstructionPattern for which we're parsing. + /// \param Op Init to parse. + /// \return true on success, false on failure. + bool parseInstructionPatternMIFlags(InstructionPattern &IP, + const DagInit *Op); + + /// (Uncached) PatFrag parsing implementation. + /// \param Def PatFrag def to parsee. + /// \return the parsed PatFrag on success, nullptr on failure. + std::unique_ptr parsePatFragImpl(const Record *Def); + + /// Parses the in or out parameter list of a PatFrag. + /// \param OpsList Init to parse. + /// \param ParseAction Callback on successful parse, with the name of + /// the parameter and its \ref PatFrag::ParamKind + /// \return true on success, false on failure. + bool + parsePatFragParamList(const DagInit &OpsList, + function_ref ParseAction); + + /// Cached PatFrag parser. This avoids duplicate work by keeping track of + /// already-parsed PatFrags. + /// \param Def PatFrag def to parsee. + /// \return the parsed PatFrag on success, nullptr on failure. + const PatFrag *parsePatFrag(const Record *Def); +}; + +} // namespace gi +} // namespace llvm + +#endif diff --git a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp index 39b9f8a..1ae6efd 100644 --- a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp @@ -36,6 +36,7 @@ #include "Common/GlobalISel/GlobalISelMatchTable.h" #include "Common/GlobalISel/GlobalISelMatchTableExecutorEmitter.h" #include "Common/GlobalISel/MatchDataInfo.h" +#include "Common/GlobalISel/PatternParser.h" #include "Common/GlobalISel/Patterns.h" #include "Common/SubtargetFeatureInfo.h" #include "llvm/ADT/APInt.h" @@ -80,7 +81,6 @@ cl::opt DebugTypeInfer("gicombiner-debug-typeinfer", constexpr StringLiteral CXXApplyPrefix = "GICXXCustomAction_CombineApply"; constexpr StringLiteral CXXPredPrefix = "GICXXPred_MI_Predicate_"; -constexpr StringLiteral MIFlagsEnumClassName = "MIFlagEnum"; //===- CodeExpansions Helpers --------------------------------------------===// @@ -109,17 +109,6 @@ void declareTempRegExpansion(CodeExpansions &CE, unsigned TempRegID, //===- Misc. Helpers -----------------------------------------------------===// -/// Copies a StringRef into a static pool to preserve it. -/// Most Pattern classes use StringRef so we need this. -StringRef insertStrRef(StringRef S) { - if (S.empty()) - return {}; - - static StringSet<> Pool; - auto [It, Inserted] = Pool.insert(S); - return It->getKey(); -} - template auto keys(Container &&C) { return map_range(C, [](auto &Entry) -> auto & { return Entry.first; }); } @@ -639,8 +628,9 @@ public: SubtargetFeatureInfoMap &SubtargetFeatures, Record &RuleDef, unsigned ID, std::vector &OutRMs) - : CGT(CGT), SubtargetFeatures(SubtargetFeatures), RuleDef(RuleDef), - RuleID(ID), OutRMs(OutRMs) {} + : Parser(CGT, RuleDef.getLoc()), CGT(CGT), + SubtargetFeatures(SubtargetFeatures), RuleDef(RuleDef), RuleID(ID), + OutRMs(OutRMs) {} /// Parses all fields in the RuleDef record. bool parseAll(); @@ -718,26 +708,6 @@ private: bool buildRuleOperandsTable(); bool parseDefs(const DagInit &Def); - bool - parsePatternList(const DagInit &List, - function_ref)> ParseAction, - StringRef Operator, ArrayRef DiagLoc, - StringRef AnonPatNamePrefix) const; - - std::unique_ptr parseInstructionPattern(const Init &Arg, - StringRef PatName) const; - std::unique_ptr parseWipMatchOpcodeMatcher(const Init &Arg, - StringRef PatName) const; - bool parseInstructionPatternOperand(InstructionPattern &IP, - const Init *OpInit, - const StringInit *OpName) const; - bool parseInstructionPatternMIFlags(InstructionPattern &IP, - const DagInit *Op) const; - std::unique_ptr parsePatFragImpl(const Record *Def) const; - bool parsePatFragParamList( - ArrayRef DiagLoc, const DagInit &OpsList, - function_ref ParseAction) const; - const PatFrag *parsePatFrag(const Record *Def) const; bool emitMatchPattern(CodeExpansions &CE, const PatternAlternatives &Alts, const InstructionPattern &IP); @@ -781,6 +751,7 @@ private: DenseSet &SeenPats, OperandDefLookupFn LookupOperandDef, OperandMapperFnRef OperandMapper = [](const auto &O) { return O; }); + PatternParser Parser; const CodeGenTarget &CGT; SubtargetFeatureInfoMap &SubtargetFeatures; Record &RuleDef; @@ -808,9 +779,6 @@ private: SmallVector MatchDatas; SmallVector PermutationsToEmit; - - // print()/debug-only members. - mutable SmallPtrSet SeenPatFrags; }; bool CombineRuleBuilder::parseAll() { @@ -819,16 +787,16 @@ bool CombineRuleBuilder::parseAll() { if (!parseDefs(*RuleDef.getValueAsDag("Defs"))) return false; - if (!parsePatternList( + if (!Parser.parsePatternList( *RuleDef.getValueAsDag("Match"), [this](auto Pat) { return addMatchPattern(std::move(Pat)); }, "match", - RuleDef.getLoc(), (RuleDef.getName() + "_match").str())) + (RuleDef.getName() + "_match").str())) return false; - if (!parsePatternList( + if (!Parser.parsePatternList( *RuleDef.getValueAsDag("Apply"), [this](auto Pat) { return addApplyPattern(std::move(Pat)); }, "apply", - RuleDef.getLoc(), (RuleDef.getName() + "_apply").str())) + (RuleDef.getName() + "_apply").str())) return false; if (!buildRuleOperandsTable() || !typecheckPatterns() || !findRoots() || @@ -884,9 +852,10 @@ void CombineRuleBuilder::print(raw_ostream &OS) const { OS << " )\n"; } - if (!SeenPatFrags.empty()) { + const auto &SeenPFs = Parser.getSeenPatFrags(); + if (!SeenPFs.empty()) { OS << " (PatFrags\n"; - for (const auto *PF : SeenPatFrags) { + for (const auto *PF : Parser.getSeenPatFrags()) { PF->print(OS, /*Indent=*/" "); OS << '\n'; } @@ -1500,426 +1469,6 @@ bool CombineRuleBuilder::parseDefs(const DagInit &Def) { return true; } -bool CombineRuleBuilder::parsePatternList( - const DagInit &List, - function_ref)> ParseAction, - StringRef Operator, ArrayRef DiagLoc, - StringRef AnonPatNamePrefix) const { - if (List.getOperatorAsDef(RuleDef.getLoc())->getName() != Operator) { - ::PrintError(DiagLoc, "Expected " + Operator + " operator"); - return false; - } - - if (List.getNumArgs() == 0) { - ::PrintError(DiagLoc, Operator + " pattern list is empty"); - return false; - } - - // The match section consists of a list of matchers and predicates. Parse each - // one and add the equivalent GIMatchDag nodes, predicates, and edges. - for (unsigned I = 0; I < List.getNumArgs(); ++I) { - Init *Arg = List.getArg(I); - std::string Name = List.getArgName(I) - ? List.getArgName(I)->getValue().str() - : ("__" + AnonPatNamePrefix + "_" + Twine(I)).str(); - - if (auto Pat = parseInstructionPattern(*Arg, Name)) { - if (!ParseAction(std::move(Pat))) - return false; - continue; - } - - if (auto Pat = parseWipMatchOpcodeMatcher(*Arg, Name)) { - if (!ParseAction(std::move(Pat))) - return false; - continue; - } - - // Parse arbitrary C++ code - if (const auto *StringI = dyn_cast(Arg)) { - auto CXXPat = std::make_unique(*StringI, insertStrRef(Name)); - if (!ParseAction(std::move(CXXPat))) - return false; - continue; - } - - ::PrintError(DiagLoc, - "Failed to parse pattern: '" + Arg->getAsString() + "'"); - return false; - } - - return true; -} - -static const CodeGenInstruction & -getInstrForIntrinsic(const CodeGenTarget &CGT, const CodeGenIntrinsic *I) { - StringRef Opc; - if (I->isConvergent) { - Opc = I->hasSideEffects ? "G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS" - : "G_INTRINSIC_CONVERGENT"; - } else { - Opc = I->hasSideEffects ? "G_INTRINSIC_W_SIDE_EFFECTS" : "G_INTRINSIC"; - } - - RecordKeeper &RK = I->TheDef->getRecords(); - return CGT.getInstruction(RK.getDef(Opc)); -} - -static const CodeGenIntrinsic *getCodeGenIntrinsic(Record *R) { - // Intrinsics need to have a static lifetime because the match table keeps - // references to CodeGenIntrinsic objects. - static DenseMap> - AllIntrinsics; - - auto &Ptr = AllIntrinsics[R]; - if (!Ptr) - Ptr = std::make_unique(R, std::vector()); - return Ptr.get(); -} - -std::unique_ptr -CombineRuleBuilder::parseInstructionPattern(const Init &Arg, - StringRef Name) const { - const DagInit *DagPat = dyn_cast(&Arg); - if (!DagPat) - return nullptr; - - std::unique_ptr Pat; - if (const DagInit *IP = getDagWithOperatorOfSubClass(Arg, "Instruction")) { - auto &Instr = CGT.getInstruction(IP->getOperatorAsDef(RuleDef.getLoc())); - Pat = - std::make_unique(Instr, insertStrRef(Name)); - } else if (const DagInit *IP = - getDagWithOperatorOfSubClass(Arg, "Intrinsic")) { - Record *TheDef = IP->getOperatorAsDef(RuleDef.getLoc()); - const CodeGenIntrinsic *Intrin = getCodeGenIntrinsic(TheDef); - const CodeGenInstruction &Instr = getInstrForIntrinsic(CGT, Intrin); - Pat = - std::make_unique(Instr, insertStrRef(Name)); - cast(*Pat).setIntrinsic(Intrin); - } else if (const DagInit *PFP = - getDagWithOperatorOfSubClass(Arg, PatFrag::ClassName)) { - const Record *Def = PFP->getOperatorAsDef(RuleDef.getLoc()); - const PatFrag *PF = parsePatFrag(Def); - if (!PF) - return nullptr; // Already diagnosed by parsePatFrag - Pat = std::make_unique(*PF, insertStrRef(Name)); - } else if (const DagInit *BP = - getDagWithOperatorOfSubClass(Arg, BuiltinPattern::ClassName)) { - Pat = std::make_unique( - *BP->getOperatorAsDef(RuleDef.getLoc()), insertStrRef(Name)); - } else - return nullptr; - - for (unsigned K = 0; K < DagPat->getNumArgs(); ++K) { - Init *Arg = DagPat->getArg(K); - if (auto *DagArg = getDagWithSpecificOperator(*Arg, "MIFlags")) { - if (!parseInstructionPatternMIFlags(*Pat, DagArg)) - return nullptr; - continue; - } - - if (!parseInstructionPatternOperand(*Pat, Arg, DagPat->getArgName(K))) - return nullptr; - } - - if (!Pat->checkSemantics(RuleDef.getLoc())) - return nullptr; - - return std::move(Pat); -} - -std::unique_ptr -CombineRuleBuilder::parseWipMatchOpcodeMatcher(const Init &Arg, - StringRef Name) const { - const DagInit *Matcher = getDagWithSpecificOperator(Arg, "wip_match_opcode"); - if (!Matcher) - return nullptr; - - if (Matcher->getNumArgs() == 0) { - PrintError("Empty wip_match_opcode"); - return nullptr; - } - - // Each argument is an opcode that can match. - auto Result = std::make_unique(insertStrRef(Name)); - for (const auto &Arg : Matcher->getArgs()) { - Record *OpcodeDef = getDefOfSubClass(*Arg, "Instruction"); - if (OpcodeDef) { - Result->addOpcode(&CGT.getInstruction(OpcodeDef)); - continue; - } - - PrintError("Arguments to wip_match_opcode must be instructions"); - return nullptr; - } - - return std::move(Result); -} - -bool CombineRuleBuilder::parseInstructionPatternOperand( - InstructionPattern &IP, const Init *OpInit, - const StringInit *OpName) const { - const auto ParseErr = [&]() { - PrintError("cannot parse operand '" + OpInit->getAsUnquotedString() + "' "); - if (OpName) - PrintNote("operand name is '" + OpName->getAsUnquotedString() + "'"); - return false; - }; - - // untyped immediate, e.g. 0 - if (const auto *IntImm = dyn_cast(OpInit)) { - std::string Name = OpName ? OpName->getAsUnquotedString() : ""; - IP.addOperand(IntImm->getValue(), insertStrRef(Name), PatternType()); - return true; - } - - // typed immediate, e.g. (i32 0) - if (const auto *DagOp = dyn_cast(OpInit)) { - if (DagOp->getNumArgs() != 1) - return ParseErr(); - - const Record *TyDef = DagOp->getOperatorAsDef(RuleDef.getLoc()); - auto ImmTy = PatternType::get(RuleDef.getLoc(), TyDef, - "cannot parse immediate '" + - DagOp->getAsUnquotedString() + "'"); - if (!ImmTy) - return false; - - if (!IP.hasAllDefs()) { - PrintError("out operand of '" + IP.getInstName() + - "' cannot be an immediate"); - return false; - } - - const auto *Val = dyn_cast(DagOp->getArg(0)); - if (!Val) - return ParseErr(); - - std::string Name = OpName ? OpName->getAsUnquotedString() : ""; - IP.addOperand(Val->getValue(), insertStrRef(Name), *ImmTy); - return true; - } - - // Typed operand e.g. $x/$z in (G_FNEG $x, $z) - if (auto *DefI = dyn_cast(OpInit)) { - if (!OpName) { - PrintError("expected an operand name after '" + OpInit->getAsString() + - "'"); - return false; - } - const Record *Def = DefI->getDef(); - auto Ty = - PatternType::get(RuleDef.getLoc(), Def, "cannot parse operand type"); - if (!Ty) - return false; - IP.addOperand(insertStrRef(OpName->getAsUnquotedString()), *Ty); - return true; - } - - // Untyped operand e.g. $x/$z in (G_FNEG $x, $z) - if (isa(OpInit)) { - assert(OpName && "Unset w/ no OpName?"); - IP.addOperand(insertStrRef(OpName->getAsUnquotedString()), PatternType()); - return true; - } - - return ParseErr(); -} - -bool CombineRuleBuilder::parseInstructionPatternMIFlags( - InstructionPattern &IP, const DagInit *Op) const { - auto *CGIP = dyn_cast(&IP); - if (!CGIP) { - PrintError("matching/writing MIFlags is only allowed on CodeGenInstruction " - "patterns"); - return false; - } - - const auto CheckFlagEnum = [&](const Record *R) { - if (!R->isSubClassOf(MIFlagsEnumClassName)) { - PrintError("'" + R->getName() + "' is not a subclass of '" + - MIFlagsEnumClassName + "'"); - return false; - } - - return true; - }; - - if (CGIP->getMIFlagsInfo()) { - PrintError("MIFlags can only be present once on an instruction"); - return false; - } - - auto &FI = CGIP->getOrCreateMIFlagsInfo(); - for (unsigned K = 0; K < Op->getNumArgs(); ++K) { - const Init *Arg = Op->getArg(K); - - // Match/set a flag: (MIFlags FmNoNans) - if (const auto *Def = dyn_cast(Arg)) { - const Record *R = Def->getDef(); - if (!CheckFlagEnum(R)) - return false; - - FI.addSetFlag(R); - continue; - } - - // Do not match a flag/unset a flag: (MIFlags (not FmNoNans)) - if (const DagInit *NotDag = getDagWithSpecificOperator(*Arg, "not")) { - for (const Init *NotArg : NotDag->getArgs()) { - const DefInit *DefArg = dyn_cast(NotArg); - if (!DefArg) { - PrintError("cannot parse '" + NotArg->getAsUnquotedString() + - "': expected a '" + MIFlagsEnumClassName + "'"); - return false; - } - - const Record *R = DefArg->getDef(); - if (!CheckFlagEnum(R)) - return false; - - FI.addUnsetFlag(R); - continue; - } - - continue; - } - - // Copy flags from a matched instruction: (MIFlags $mi) - if (isa(Arg)) { - FI.addCopyFlag(insertStrRef(Op->getArgName(K)->getAsUnquotedString())); - continue; - } - } - - return true; -} - -std::unique_ptr -CombineRuleBuilder::parsePatFragImpl(const Record *Def) const { - auto StackTrace = PrettyStackTraceParse(*Def); - if (!Def->isSubClassOf(PatFrag::ClassName)) - return nullptr; - - const DagInit *Ins = Def->getValueAsDag("InOperands"); - if (Ins->getOperatorAsDef(Def->getLoc())->getName() != "ins") { - ::PrintError(Def, "expected 'ins' operator for " + PatFrag::ClassName + - " in operands list"); - return nullptr; - } - - const DagInit *Outs = Def->getValueAsDag("OutOperands"); - if (Outs->getOperatorAsDef(Def->getLoc())->getName() != "outs") { - ::PrintError(Def, "expected 'outs' operator for " + PatFrag::ClassName + - " out operands list"); - return nullptr; - } - - auto Result = std::make_unique(*Def); - if (!parsePatFragParamList(Def->getLoc(), *Outs, - [&](StringRef Name, PatFrag::ParamKind Kind) { - Result->addOutParam(insertStrRef(Name), Kind); - return true; - })) - return nullptr; - - if (!parsePatFragParamList(Def->getLoc(), *Ins, - [&](StringRef Name, PatFrag::ParamKind Kind) { - Result->addInParam(insertStrRef(Name), Kind); - return true; - })) - return nullptr; - - const ListInit *Alts = Def->getValueAsListInit("Alternatives"); - unsigned AltIdx = 0; - for (const Init *Alt : *Alts) { - const auto *PatDag = dyn_cast(Alt); - if (!PatDag) { - ::PrintError(Def, "expected dag init for PatFrag pattern alternative"); - return nullptr; - } - - PatFrag::Alternative &A = Result->addAlternative(); - const auto AddPat = [&](std::unique_ptr Pat) { - A.Pats.push_back(std::move(Pat)); - return true; - }; - - if (!parsePatternList( - *PatDag, AddPat, "pattern", Def->getLoc(), - /*AnonPatPrefix*/ - (Def->getName() + "_alt" + Twine(AltIdx++) + "_pattern").str())) - return nullptr; - } - - if (!Result->buildOperandsTables() || !Result->checkSemantics()) - return nullptr; - - return Result; -} - -bool CombineRuleBuilder::parsePatFragParamList( - ArrayRef DiagLoc, const DagInit &OpsList, - function_ref ParseAction) const { - for (unsigned K = 0; K < OpsList.getNumArgs(); ++K) { - const StringInit *Name = OpsList.getArgName(K); - const Init *Ty = OpsList.getArg(K); - - if (!Name) { - ::PrintError(DiagLoc, "all operands must be named'"); - return false; - } - const std::string NameStr = Name->getAsUnquotedString(); - - PatFrag::ParamKind OpKind; - if (isSpecificDef(*Ty, "gi_imm")) - OpKind = PatFrag::PK_Imm; - else if (isSpecificDef(*Ty, "root")) - OpKind = PatFrag::PK_Root; - else if (isa(Ty) || - isSpecificDef(*Ty, "gi_mo")) // no type = gi_mo. - OpKind = PatFrag::PK_MachineOperand; - else { - ::PrintError( - DiagLoc, - "'" + NameStr + - "' operand type was expected to be 'root', 'gi_imm' or 'gi_mo'"); - return false; - } - - if (!ParseAction(NameStr, OpKind)) - return false; - } - - return true; -} - -const PatFrag *CombineRuleBuilder::parsePatFrag(const Record *Def) const { - // Cache already parsed PatFrags to avoid doing extra work. - static DenseMap> ParsedPatFrags; - - auto It = ParsedPatFrags.find(Def); - if (It != ParsedPatFrags.end()) { - SeenPatFrags.insert(It->second.get()); - return It->second.get(); - } - - std::unique_ptr NewPatFrag = parsePatFragImpl(Def); - if (!NewPatFrag) { - ::PrintError(Def, "Could not parse " + PatFrag::ClassName + " '" + - Def->getName() + "'"); - // Put a nullptr in the map so we don't attempt parsing this again. - ParsedPatFrags[Def] = nullptr; - return nullptr; - } - - const auto *Res = NewPatFrag.get(); - ParsedPatFrags[Def] = std::move(NewPatFrag); - SeenPatFrags.insert(Res); - return Res; -} - bool CombineRuleBuilder::emitMatchPattern(CodeExpansions &CE, const PatternAlternatives &Alts, const InstructionPattern &IP) { @@ -2956,8 +2505,8 @@ GICombinerEmitter::buildMatchTable(MutableArrayRef Rules) { const Matcher *B) { auto *L = static_cast(A); auto *R = static_cast(B); - return std::tuple(OpcodeOrder[L->getOpcode()], L->getNumOperands()) < - std::tuple(OpcodeOrder[R->getOpcode()], R->getNumOperands()); + return std::make_tuple(OpcodeOrder[L->getOpcode()], L->getNumOperands()) < + std::make_tuple(OpcodeOrder[R->getOpcode()], R->getNumOperands()); }); for (Matcher *Rule : InputRules) -- cgit v1.1