Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/Common/GlobalISel/PatternParser.cpp
35315 views
//===- PatternParser.cpp ----------------------------------------*- C++ -*-===//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 "Common/GlobalISel/PatternParser.h"9#include "Basic/CodeGenIntrinsics.h"10#include "Common/CodeGenTarget.h"11#include "Common/GlobalISel/CombinerUtils.h"12#include "Common/GlobalISel/Patterns.h"13#include "llvm/ADT/StringRef.h"14#include "llvm/Support/PrettyStackTrace.h"15#include "llvm/Support/SaveAndRestore.h"16#include "llvm/TableGen/Error.h"17#include "llvm/TableGen/Record.h"1819namespace llvm {20namespace gi {21static constexpr StringLiteral MIFlagsEnumClassName = "MIFlagEnum";2223namespace {24class PrettyStackTraceParse : public PrettyStackTraceEntry {25const Record &Def;2627public:28PrettyStackTraceParse(const Record &Def) : Def(Def) {}2930void print(raw_ostream &OS) const override {31if (Def.isSubClassOf("GICombineRule"))32OS << "Parsing GICombineRule '" << Def.getName() << '\'';33else if (Def.isSubClassOf(PatFrag::ClassName))34OS << "Parsing " << PatFrag::ClassName << " '" << Def.getName() << '\'';35else36OS << "Parsing '" << Def.getName() << '\'';37OS << '\n';38}39};40} // namespace4142bool PatternParser::parsePatternList(43const DagInit &List,44function_ref<bool(std::unique_ptr<Pattern>)> ParseAction,45StringRef Operator, StringRef AnonPatNamePrefix) {46if (List.getOperatorAsDef(DiagLoc)->getName() != Operator) {47PrintError(DiagLoc, "Expected " + Operator + " operator");48return false;49}5051if (List.getNumArgs() == 0) {52PrintError(DiagLoc, Operator + " pattern list is empty");53return false;54}5556// The match section consists of a list of matchers and predicates. Parse each57// one and add the equivalent GIMatchDag nodes, predicates, and edges.58for (unsigned I = 0; I < List.getNumArgs(); ++I) {59Init *Arg = List.getArg(I);60std::string Name = List.getArgName(I)61? List.getArgName(I)->getValue().str()62: ("__" + AnonPatNamePrefix + "_" + Twine(I)).str();6364if (auto Pat = parseInstructionPattern(*Arg, Name)) {65if (!ParseAction(std::move(Pat)))66return false;67continue;68}6970if (auto Pat = parseWipMatchOpcodeMatcher(*Arg, Name)) {71if (!ParseAction(std::move(Pat)))72return false;73continue;74}7576// Parse arbitrary C++ code77if (const auto *StringI = dyn_cast<StringInit>(Arg)) {78auto CXXPat = std::make_unique<CXXPattern>(*StringI, insertStrRef(Name));79if (!ParseAction(std::move(CXXPat)))80return false;81continue;82}8384PrintError(DiagLoc,85"Failed to parse pattern: '" + Arg->getAsString() + '\'');86return false;87}8889return true;90}9192static const CodeGenInstruction &93getInstrForIntrinsic(const CodeGenTarget &CGT, const CodeGenIntrinsic *I) {94StringRef Opc;95if (I->isConvergent) {96Opc = I->hasSideEffects ? "G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS"97: "G_INTRINSIC_CONVERGENT";98} else {99Opc = I->hasSideEffects ? "G_INTRINSIC_W_SIDE_EFFECTS" : "G_INTRINSIC";100}101102RecordKeeper &RK = I->TheDef->getRecords();103return CGT.getInstruction(RK.getDef(Opc));104}105106static const CodeGenIntrinsic *getCodeGenIntrinsic(Record *R) {107// Intrinsics need to have a static lifetime because the match table keeps108// references to CodeGenIntrinsic objects.109static DenseMap<const Record *, std::unique_ptr<CodeGenIntrinsic>>110AllIntrinsics;111112auto &Ptr = AllIntrinsics[R];113if (!Ptr)114Ptr = std::make_unique<CodeGenIntrinsic>(R, std::vector<Record *>());115return Ptr.get();116}117118std::unique_ptr<Pattern>119PatternParser::parseInstructionPattern(const Init &Arg, StringRef Name) {120const DagInit *DagPat = dyn_cast<DagInit>(&Arg);121if (!DagPat)122return nullptr;123124std::unique_ptr<InstructionPattern> Pat;125if (const DagInit *IP = getDagWithOperatorOfSubClass(Arg, "Instruction")) {126auto &Instr = CGT.getInstruction(IP->getOperatorAsDef(DiagLoc));127Pat =128std::make_unique<CodeGenInstructionPattern>(Instr, insertStrRef(Name));129} else if (const DagInit *IP =130getDagWithOperatorOfSubClass(Arg, "Intrinsic")) {131Record *TheDef = IP->getOperatorAsDef(DiagLoc);132const CodeGenIntrinsic *Intrin = getCodeGenIntrinsic(TheDef);133const CodeGenInstruction &Instr = getInstrForIntrinsic(CGT, Intrin);134Pat =135std::make_unique<CodeGenInstructionPattern>(Instr, insertStrRef(Name));136cast<CodeGenInstructionPattern>(*Pat).setIntrinsic(Intrin);137} else if (const DagInit *PFP =138getDagWithOperatorOfSubClass(Arg, PatFrag::ClassName)) {139const Record *Def = PFP->getOperatorAsDef(DiagLoc);140const PatFrag *PF = parsePatFrag(Def);141if (!PF)142return nullptr; // Already diagnosed by parsePatFrag143Pat = std::make_unique<PatFragPattern>(*PF, insertStrRef(Name));144} else if (const DagInit *BP =145getDagWithOperatorOfSubClass(Arg, BuiltinPattern::ClassName)) {146Pat = std::make_unique<BuiltinPattern>(*BP->getOperatorAsDef(DiagLoc),147insertStrRef(Name));148} else149return nullptr;150151for (unsigned K = 0; K < DagPat->getNumArgs(); ++K) {152Init *Arg = DagPat->getArg(K);153if (auto *DagArg = getDagWithSpecificOperator(*Arg, "MIFlags")) {154if (!parseInstructionPatternMIFlags(*Pat, DagArg))155return nullptr;156continue;157}158159if (!parseInstructionPatternOperand(*Pat, Arg, DagPat->getArgName(K)))160return nullptr;161}162163if (!Pat->checkSemantics(DiagLoc))164return nullptr;165166return std::move(Pat);167}168169std::unique_ptr<Pattern>170PatternParser::parseWipMatchOpcodeMatcher(const Init &Arg, StringRef Name) {171const DagInit *Matcher = getDagWithSpecificOperator(Arg, "wip_match_opcode");172if (!Matcher)173return nullptr;174175if (Matcher->getNumArgs() == 0) {176PrintError(DiagLoc, "Empty wip_match_opcode");177return nullptr;178}179180// Each argument is an opcode that can match.181auto Result = std::make_unique<AnyOpcodePattern>(insertStrRef(Name));182for (const auto &Arg : Matcher->getArgs()) {183Record *OpcodeDef = getDefOfSubClass(*Arg, "Instruction");184if (OpcodeDef) {185Result->addOpcode(&CGT.getInstruction(OpcodeDef));186continue;187}188189PrintError(DiagLoc, "Arguments to wip_match_opcode must be instructions");190return nullptr;191}192193return std::move(Result);194}195196bool PatternParser::parseInstructionPatternOperand(InstructionPattern &IP,197const Init *OpInit,198const StringInit *OpName) {199const auto ParseErr = [&]() {200PrintError(DiagLoc,201"cannot parse operand '" + OpInit->getAsUnquotedString() + "' ");202if (OpName)203PrintNote(DiagLoc,204"operand name is '" + OpName->getAsUnquotedString() + '\'');205return false;206};207208// untyped immediate, e.g. 0209if (const auto *IntImm = dyn_cast<IntInit>(OpInit)) {210std::string Name = OpName ? OpName->getAsUnquotedString() : "";211IP.addOperand(IntImm->getValue(), insertStrRef(Name), PatternType());212return true;213}214215// typed immediate, e.g. (i32 0)216if (const auto *DagOp = dyn_cast<DagInit>(OpInit)) {217if (DagOp->getNumArgs() != 1)218return ParseErr();219220const Record *TyDef = DagOp->getOperatorAsDef(DiagLoc);221auto ImmTy = PatternType::get(DiagLoc, TyDef,222"cannot parse immediate '" +223DagOp->getAsUnquotedString() + '\'');224if (!ImmTy)225return false;226227if (!IP.hasAllDefs()) {228PrintError(DiagLoc, "out operand of '" + IP.getInstName() +229"' cannot be an immediate");230return false;231}232233const auto *Val = dyn_cast<IntInit>(DagOp->getArg(0));234if (!Val)235return ParseErr();236237std::string Name = OpName ? OpName->getAsUnquotedString() : "";238IP.addOperand(Val->getValue(), insertStrRef(Name), *ImmTy);239return true;240}241242// Typed operand e.g. $x/$z in (G_FNEG $x, $z)243if (auto *DefI = dyn_cast<DefInit>(OpInit)) {244if (!OpName) {245PrintError(DiagLoc, "expected an operand name after '" +246OpInit->getAsString() + '\'');247return false;248}249const Record *Def = DefI->getDef();250auto Ty = PatternType::get(DiagLoc, Def, "cannot parse operand type");251if (!Ty)252return false;253IP.addOperand(insertStrRef(OpName->getAsUnquotedString()), *Ty);254return true;255}256257// Untyped operand e.g. $x/$z in (G_FNEG $x, $z)258if (isa<UnsetInit>(OpInit)) {259assert(OpName && "Unset w/ no OpName?");260IP.addOperand(insertStrRef(OpName->getAsUnquotedString()), PatternType());261return true;262}263264return ParseErr();265}266267bool PatternParser::parseInstructionPatternMIFlags(InstructionPattern &IP,268const DagInit *Op) {269auto *CGIP = dyn_cast<CodeGenInstructionPattern>(&IP);270if (!CGIP) {271PrintError(DiagLoc,272"matching/writing MIFlags is only allowed on CodeGenInstruction "273"patterns");274return false;275}276277const auto CheckFlagEnum = [&](const Record *R) {278if (!R->isSubClassOf(MIFlagsEnumClassName)) {279PrintError(DiagLoc, "'" + R->getName() + "' is not a subclass of '" +280MIFlagsEnumClassName + "'");281return false;282}283284return true;285};286287if (CGIP->getMIFlagsInfo()) {288PrintError(DiagLoc, "MIFlags can only be present once on an instruction");289return false;290}291292auto &FI = CGIP->getOrCreateMIFlagsInfo();293for (unsigned K = 0; K < Op->getNumArgs(); ++K) {294const Init *Arg = Op->getArg(K);295296// Match/set a flag: (MIFlags FmNoNans)297if (const auto *Def = dyn_cast<DefInit>(Arg)) {298const Record *R = Def->getDef();299if (!CheckFlagEnum(R))300return false;301302FI.addSetFlag(R);303continue;304}305306// Do not match a flag/unset a flag: (MIFlags (not FmNoNans))307if (const DagInit *NotDag = getDagWithSpecificOperator(*Arg, "not")) {308for (const Init *NotArg : NotDag->getArgs()) {309const DefInit *DefArg = dyn_cast<DefInit>(NotArg);310if (!DefArg) {311PrintError(DiagLoc, "cannot parse '" + NotArg->getAsUnquotedString() +312"': expected a '" + MIFlagsEnumClassName +313"'");314return false;315}316317const Record *R = DefArg->getDef();318if (!CheckFlagEnum(R))319return false;320321FI.addUnsetFlag(R);322continue;323}324325continue;326}327328// Copy flags from a matched instruction: (MIFlags $mi)329if (isa<UnsetInit>(Arg)) {330FI.addCopyFlag(insertStrRef(Op->getArgName(K)->getAsUnquotedString()));331continue;332}333}334335return true;336}337338std::unique_ptr<PatFrag> PatternParser::parsePatFragImpl(const Record *Def) {339auto StackTrace = PrettyStackTraceParse(*Def);340if (!Def->isSubClassOf(PatFrag::ClassName))341return nullptr;342343const DagInit *Ins = Def->getValueAsDag("InOperands");344if (Ins->getOperatorAsDef(Def->getLoc())->getName() != "ins") {345PrintError(Def, "expected 'ins' operator for " + PatFrag::ClassName +346" in operands list");347return nullptr;348}349350const DagInit *Outs = Def->getValueAsDag("OutOperands");351if (Outs->getOperatorAsDef(Def->getLoc())->getName() != "outs") {352PrintError(Def, "expected 'outs' operator for " + PatFrag::ClassName +353" out operands list");354return nullptr;355}356357auto Result = std::make_unique<PatFrag>(*Def);358if (!parsePatFragParamList(*Outs, [&](StringRef Name, unsigned Kind) {359Result->addOutParam(insertStrRef(Name), (PatFrag::ParamKind)Kind);360return true;361}))362return nullptr;363364if (!parsePatFragParamList(*Ins, [&](StringRef Name, unsigned Kind) {365Result->addInParam(insertStrRef(Name), (PatFrag::ParamKind)Kind);366return true;367}))368return nullptr;369370const ListInit *Alts = Def->getValueAsListInit("Alternatives");371unsigned AltIdx = 0;372for (const Init *Alt : *Alts) {373const auto *PatDag = dyn_cast<DagInit>(Alt);374if (!PatDag) {375PrintError(Def, "expected dag init for PatFrag pattern alternative");376return nullptr;377}378379PatFrag::Alternative &A = Result->addAlternative();380const auto AddPat = [&](std::unique_ptr<Pattern> Pat) {381A.Pats.push_back(std::move(Pat));382return true;383};384385SaveAndRestore<ArrayRef<SMLoc>> DiagLocSAR(DiagLoc, Def->getLoc());386if (!parsePatternList(387*PatDag, AddPat, "pattern",388/*AnonPatPrefix*/389(Def->getName() + "_alt" + Twine(AltIdx++) + "_pattern").str()))390return nullptr;391}392393if (!Result->buildOperandsTables() || !Result->checkSemantics())394return nullptr;395396return Result;397}398399bool PatternParser::parsePatFragParamList(400const DagInit &OpsList,401function_ref<bool(StringRef, unsigned)> ParseAction) {402for (unsigned K = 0; K < OpsList.getNumArgs(); ++K) {403const StringInit *Name = OpsList.getArgName(K);404const Init *Ty = OpsList.getArg(K);405406if (!Name) {407PrintError(DiagLoc, "all operands must be named'");408return false;409}410const std::string NameStr = Name->getAsUnquotedString();411412PatFrag::ParamKind OpKind;413if (isSpecificDef(*Ty, "gi_imm"))414OpKind = PatFrag::PK_Imm;415else if (isSpecificDef(*Ty, "root"))416OpKind = PatFrag::PK_Root;417else if (isa<UnsetInit>(Ty) ||418isSpecificDef(*Ty, "gi_mo")) // no type = gi_mo.419OpKind = PatFrag::PK_MachineOperand;420else {421PrintError(422DiagLoc,423'\'' + NameStr +424"' operand type was expected to be 'root', 'gi_imm' or 'gi_mo'");425return false;426}427428if (!ParseAction(NameStr, (unsigned)OpKind))429return false;430}431432return true;433}434435const PatFrag *PatternParser::parsePatFrag(const Record *Def) {436// Cache already parsed PatFrags to avoid doing extra work.437static DenseMap<const Record *, std::unique_ptr<PatFrag>> ParsedPatFrags;438439auto It = ParsedPatFrags.find(Def);440if (It != ParsedPatFrags.end()) {441SeenPatFrags.insert(It->second.get());442return It->second.get();443}444445std::unique_ptr<PatFrag> NewPatFrag = parsePatFragImpl(Def);446if (!NewPatFrag) {447PrintError(Def, "Could not parse " + PatFrag::ClassName + " '" +448Def->getName() + "'");449// Put a nullptr in the map so we don't attempt parsing this again.450ParsedPatFrags[Def] = nullptr;451return nullptr;452}453454const auto *Res = NewPatFrag.get();455ParsedPatFrags[Def] = std::move(NewPatFrag);456SeenPatFrags.insert(Res);457return Res;458}459460} // namespace gi461} // namespace llvm462463464