887 lines · cpp
1//===- Patterns.cpp --------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Patterns.h"10#include "Basic/CodeGenIntrinsics.h"11#include "CXXPredicates.h"12#include "CodeExpander.h"13#include "CodeExpansions.h"14#include "Common/CodeGenInstruction.h"15#include "llvm/ADT/StringSet.h"16#include "llvm/Support/Debug.h"17#include "llvm/Support/raw_ostream.h"18#include "llvm/TableGen/Error.h"19#include "llvm/TableGen/Record.h"20 21using namespace llvm;22using namespace gi;23 24//===- PatternType --------------------------------------------------------===//25 26std::optional<PatternType> PatternType::get(ArrayRef<SMLoc> DiagLoc,27 const Record *R, Twine DiagCtx) {28 assert(R);29 if (R->isSubClassOf("ValueType")) {30 PatternType PT(PT_ValueType);31 PT.Data.Def = R;32 return PT;33 }34 35 if (R->isSubClassOf(TypeOfClassName)) {36 auto RawOpName = R->getValueAsString("OpName");37 if (!RawOpName.starts_with("$")) {38 PrintError(DiagLoc, DiagCtx + ": invalid operand name format '" +39 RawOpName + "' in " + TypeOfClassName +40 ": expected '$' followed by an operand name");41 return std::nullopt;42 }43 44 PatternType PT(PT_TypeOf);45 PT.Data.Str = RawOpName.drop_front(1);46 return PT;47 }48 49 if (R->isSubClassOf(VariadicClassName)) {50 const int64_t Min = R->getValueAsInt("MinArgs");51 const int64_t Max = R->getValueAsInt("MaxArgs");52 53 if (Min == 0) {54 PrintError(55 DiagLoc,56 DiagCtx +57 ": minimum number of arguments must be greater than zero in " +58 VariadicClassName);59 return std::nullopt;60 }61 62 if (Max <= Min && Max != 0) {63 PrintError(DiagLoc, DiagCtx + ": maximum number of arguments (" +64 Twine(Max) +65 ") must be zero, or greater "66 "than the minimum number of arguments (" +67 Twine(Min) + ") in " + VariadicClassName);68 return std::nullopt;69 }70 71 PatternType PT(PT_VariadicPack);72 PT.Data.VPTI = {unsigned(Min), unsigned(Max)};73 return PT;74 }75 76 PrintError(DiagLoc, DiagCtx + ": unknown type '" + R->getName() + "'");77 return std::nullopt;78}79 80PatternType PatternType::getTypeOf(StringRef OpName) {81 PatternType PT(PT_TypeOf);82 PT.Data.Str = OpName;83 return PT;84}85 86StringRef PatternType::getTypeOfOpName() const {87 assert(isTypeOf());88 return Data.Str;89}90 91const Record *PatternType::getLLTRecord() const {92 assert(isLLT());93 return Data.Def;94}95 96VariadicPackTypeInfo PatternType::getVariadicPackTypeInfo() const {97 assert(isVariadicPack());98 return Data.VPTI;99}100 101bool PatternType::operator==(const PatternType &Other) const {102 if (Kind != Other.Kind)103 return false;104 105 switch (Kind) {106 case PT_None:107 return true;108 case PT_ValueType:109 return Data.Def == Other.Data.Def;110 case PT_TypeOf:111 return Data.Str == Other.Data.Str;112 case PT_VariadicPack:113 return Data.VPTI == Other.Data.VPTI;114 }115 116 llvm_unreachable("Unknown Type Kind");117}118 119std::string PatternType::str() const {120 switch (Kind) {121 case PT_None:122 return "";123 case PT_ValueType:124 return Data.Def->getName().str();125 case PT_TypeOf:126 return (TypeOfClassName + "<$" + getTypeOfOpName() + ">").str();127 case PT_VariadicPack:128 return (VariadicClassName + "<" + Twine(Data.VPTI.Min) + "," +129 Twine(Data.VPTI.Max) + ">")130 .str();131 }132 133 llvm_unreachable("Unknown type!");134}135 136//===- Pattern ------------------------------------------------------------===//137 138void Pattern::dump() const { return print(dbgs()); }139 140const char *Pattern::getKindName() const {141 switch (Kind) {142 case K_AnyOpcode:143 return "AnyOpcodePattern";144 case K_CXX:145 return "CXXPattern";146 case K_CodeGenInstruction:147 return "CodeGenInstructionPattern";148 case K_PatFrag:149 return "PatFragPattern";150 case K_Builtin:151 return "BuiltinPattern";152 }153 154 llvm_unreachable("unknown pattern kind!");155}156 157void Pattern::printImpl(raw_ostream &OS, bool PrintName,158 function_ref<void()> ContentPrinter) const {159 OS << "(" << getKindName() << " ";160 if (PrintName)161 OS << "name:" << getName() << " ";162 ContentPrinter();163 OS << ")";164}165 166//===- AnyOpcodePattern ---------------------------------------------------===//167 168void AnyOpcodePattern::print(raw_ostream &OS, bool PrintName) const {169 printImpl(OS, PrintName, [&OS, this]() {170 OS << "["171 << join(map_range(Insts, [](const auto *I) { return I->getName(); }),172 ", ")173 << "]";174 });175}176 177//===- CXXPattern ---------------------------------------------------------===//178 179CXXPattern::CXXPattern(const StringInit &Code, StringRef Name)180 : CXXPattern(Code.getAsUnquotedString(), Name) {}181 182const CXXPredicateCode &183CXXPattern::expandCode(const CodeExpansions &CE, ArrayRef<SMLoc> Locs,184 function_ref<void(raw_ostream &)> AddComment) const {185 assert(!IsApply && "'apply' CXX patterns should be handled differently!");186 187 std::string Result;188 raw_string_ostream OS(Result);189 190 if (AddComment)191 AddComment(OS);192 193 CodeExpander Expander(RawCode, CE, Locs, /*ShowExpansions*/ false);194 Expander.emit(OS);195 return CXXPredicateCode::getMatchCode(std::move(Result));196}197 198void CXXPattern::print(raw_ostream &OS, bool PrintName) const {199 printImpl(OS, PrintName, [&OS, this] {200 OS << (IsApply ? "apply" : "match") << " code:\"";201 printEscapedString(getRawCode(), OS);202 OS << "\"";203 });204}205 206//===- InstructionOperand -------------------------------------------------===//207 208std::string InstructionOperand::describe() const {209 if (!hasImmValue())210 return "MachineOperand $" + getOperandName().str() + "";211 std::string Str = "imm " + std::to_string(getImmValue());212 if (isNamedImmediate())213 Str += ":$" + getOperandName().str() + "";214 return Str;215}216 217void InstructionOperand::print(raw_ostream &OS) const {218 if (isDef())219 OS << "<def>";220 221 bool NeedsColon = true;222 if (Type) {223 if (hasImmValue())224 OS << "(" << Type.str() << " " << getImmValue() << ")";225 else226 OS << Type.str();227 } else if (hasImmValue())228 OS << getImmValue();229 else230 NeedsColon = false;231 232 if (isNamedOperand())233 OS << (NeedsColon ? ":" : "") << "$" << getOperandName();234}235 236void InstructionOperand::dump() const { return print(dbgs()); }237 238//===- InstructionPattern -------------------------------------------------===//239 240bool InstructionPattern::diagnoseAllSpecialTypes(ArrayRef<SMLoc> Loc,241 Twine Msg) const {242 bool HasDiag = false;243 for (const auto &[Idx, Op] : enumerate(operands())) {244 if (Op.getType().isSpecial()) {245 PrintError(Loc, Msg);246 PrintNote(Loc, "operand " + Twine(Idx) + " of '" + getName() +247 "' has type '" + Op.getType().str() + "'");248 HasDiag = true;249 }250 }251 return HasDiag;252}253 254void InstructionPattern::reportUnreachable(ArrayRef<SMLoc> Locs) const {255 PrintError(Locs, "pattern '" + getName() + "' ('" + getInstName() +256 "') is unreachable from the pattern root!");257}258 259bool InstructionPattern::checkSemantics(ArrayRef<SMLoc> Loc) {260 unsigned NumExpectedOperands = getNumInstOperands();261 262 if (isVariadic()) {263 if (Operands.size() < NumExpectedOperands) {264 PrintError(Loc, +"'" + getInstName() + "' expected at least " +265 Twine(NumExpectedOperands) + " operands, got " +266 Twine(Operands.size()));267 return false;268 }269 } else if (NumExpectedOperands != Operands.size()) {270 PrintError(Loc, +"'" + getInstName() + "' expected " +271 Twine(NumExpectedOperands) + " operands, got " +272 Twine(Operands.size()));273 return false;274 }275 276 unsigned OpIdx = 0;277 unsigned NumDefs = getNumInstDefs();278 for (auto &Op : Operands)279 Op.setIsDef(OpIdx++ < NumDefs);280 281 return true;282}283 284void InstructionPattern::print(raw_ostream &OS, bool PrintName) const {285 printImpl(OS, PrintName, [&OS, this] {286 OS << getInstName() << " operands:[";287 StringRef Sep;288 for (const auto &Op : Operands) {289 OS << Sep;290 Op.print(OS);291 Sep = ", ";292 }293 OS << "]";294 295 printExtras(OS);296 });297}298 299//===- OperandTable -------------------------------------------------------===//300 301bool OperandTable::addPattern(InstructionPattern *P,302 function_ref<void(StringRef)> DiagnoseRedef) {303 for (const auto &Op : P->named_operands()) {304 StringRef OpName = Op.getOperandName();305 306 // We always create an entry in the OperandTable, even for uses.307 // Uses of operands that don't have a def (= live-ins) will remain with a308 // nullptr as the Def.309 //310 // This allows us tell whether an operand exists in a pattern or not. If311 // there is no entry for it, it doesn't exist, if there is an entry, it's312 // used/def'd at least once.313 auto &Def = Table[OpName];314 315 if (!Op.isDef())316 continue;317 318 if (Def) {319 DiagnoseRedef(OpName);320 return false;321 }322 323 Def = P;324 }325 326 return true;327}328 329void OperandTable::print(raw_ostream &OS, StringRef Name,330 StringRef Indent) const {331 OS << Indent << "(OperandTable ";332 if (!Name.empty())333 OS << Name << " ";334 if (Table.empty()) {335 OS << "<empty>)\n";336 return;337 }338 339 SmallVector<StringRef, 0> Keys(Table.keys());340 sort(Keys);341 342 OS << '\n';343 for (const auto &Key : Keys) {344 const auto *Def = Table.at(Key);345 OS << Indent << " " << Key << " -> "346 << (Def ? Def->getName() : "<live-in>") << '\n';347 }348 OS << Indent << ")\n";349}350 351void OperandTable::dump() const { print(dbgs()); }352 353//===- MIFlagsInfo --------------------------------------------------------===//354 355void MIFlagsInfo::addSetFlag(const Record *R) {356 SetF.insert(R->getValueAsString("EnumName"));357}358 359void MIFlagsInfo::addUnsetFlag(const Record *R) {360 UnsetF.insert(R->getValueAsString("EnumName"));361}362 363void MIFlagsInfo::addCopyFlag(StringRef InstName) { CopyF.insert(InstName); }364 365//===- CodeGenInstructionPattern ------------------------------------------===//366 367bool CodeGenInstructionPattern::is(StringRef OpcodeName) const {368 return I.getName() == OpcodeName;369}370 371bool CodeGenInstructionPattern::isVariadic() const {372 return !isIntrinsic() && I.Operands.isVariadic;373}374 375bool CodeGenInstructionPattern::hasVariadicDefs() const {376 // Note: we cannot use variadicOpsAreDefs, it's not set for377 // GenericInstructions.378 if (!isVariadic())379 return false;380 381 if (I.variadicOpsAreDefs)382 return true;383 384 const DagInit *OutOps = I.TheDef->getValueAsDag("OutOperandList");385 if (OutOps->arg_empty())386 return false;387 388 auto *LastArgTy = dyn_cast<DefInit>(OutOps->getArg(OutOps->arg_size() - 1));389 return LastArgTy && LastArgTy->getDef()->getName() == "variable_ops";390}391 392unsigned CodeGenInstructionPattern::getNumInstDefs() const {393 if (isIntrinsic())394 return IntrinInfo->IS.RetTys.size();395 396 if (!isVariadic() || !hasVariadicDefs())397 return I.Operands.NumDefs;398 unsigned NumOuts = I.Operands.size() - I.Operands.NumDefs;399 assert(Operands.size() > NumOuts);400 return std::max<unsigned>(I.Operands.NumDefs, Operands.size() - NumOuts);401}402 403unsigned CodeGenInstructionPattern::getNumInstOperands() const {404 if (isIntrinsic())405 return IntrinInfo->IS.RetTys.size() + IntrinInfo->IS.ParamTys.size();406 407 unsigned NumCGIOps = I.Operands.size();408 return isVariadic() ? std::max<unsigned>(NumCGIOps, Operands.size())409 : NumCGIOps;410}411 412MIFlagsInfo &CodeGenInstructionPattern::getOrCreateMIFlagsInfo() {413 if (!FI)414 FI = std::make_unique<MIFlagsInfo>();415 return *FI;416}417 418StringRef CodeGenInstructionPattern::getInstName() const { return I.getName(); }419 420void CodeGenInstructionPattern::printExtras(raw_ostream &OS) const {421 if (isIntrinsic())422 OS << " intrinsic(@" << IntrinInfo->Name << ")";423 424 if (!FI)425 return;426 427 OS << " (MIFlags";428 if (!FI->set_flags().empty())429 OS << " (set " << join(FI->set_flags(), ", ") << ")";430 if (!FI->unset_flags().empty())431 OS << " (unset " << join(FI->unset_flags(), ", ") << ")";432 if (!FI->copy_flags().empty())433 OS << " (copy " << join(FI->copy_flags(), ", ") << ")";434 OS << ')';435}436 437//===- OperandTypeChecker -------------------------------------------------===//438 439bool OperandTypeChecker::check(440 InstructionPattern &P,441 std::function<bool(const PatternType &)> VerifyTypeOfOperand) {442 Pats.push_back(&P);443 444 for (auto &Op : P.operands()) {445 const auto Ty = Op.getType();446 if (!Ty)447 continue;448 449 if (Ty.isTypeOf() && !VerifyTypeOfOperand(Ty))450 return false;451 452 if (!Op.isNamedOperand())453 continue;454 455 StringRef OpName = Op.getOperandName();456 auto &Info = Types[OpName];457 if (!Info.Type) {458 Info.Type = Ty;459 Info.PrintTypeSrcNote = [this, OpName, Ty, &P]() {460 PrintSeenWithTypeIn(P, OpName, Ty);461 };462 continue;463 }464 465 if (Info.Type != Ty) {466 PrintError(DiagLoc, "conflicting types for operand '" +467 Op.getOperandName() + "': '" + Info.Type.str() +468 "' vs '" + Ty.str() + "'");469 PrintSeenWithTypeIn(P, OpName, Ty);470 Info.PrintTypeSrcNote();471 return false;472 }473 }474 475 return true;476}477 478void OperandTypeChecker::propagateTypes() {479 for (auto *Pat : Pats) {480 for (auto &Op : Pat->named_operands()) {481 if (auto &Info = Types[Op.getOperandName()]; Info.Type)482 Op.setType(Info.Type);483 }484 }485}486 487void OperandTypeChecker::PrintSeenWithTypeIn(InstructionPattern &P,488 StringRef OpName,489 PatternType Ty) const {490 PrintNote(DiagLoc, "'" + OpName + "' seen with type '" + Ty.str() + "' in '" +491 P.getName() + "'");492}493 494StringRef PatFrag::getParamKindStr(ParamKind OK) {495 switch (OK) {496 case PK_Root:497 return "root";498 case PK_MachineOperand:499 return "machine_operand";500 case PK_Imm:501 return "imm";502 }503 504 llvm_unreachable("Unknown operand kind!");505}506 507//===- PatFrag -----------------------------------------------------------===//508 509PatFrag::PatFrag(const Record &Def) : Def(Def) {510 assert(Def.isSubClassOf(ClassName));511}512 513StringRef PatFrag::getName() const { return Def.getName(); }514 515ArrayRef<SMLoc> PatFrag::getLoc() const { return Def.getLoc(); }516 517void PatFrag::addInParam(StringRef Name, ParamKind Kind) {518 Params.emplace_back(Param{Name, Kind});519}520 521iterator_range<PatFrag::ParamIt> PatFrag::in_params() const {522 return {Params.begin() + NumOutParams, Params.end()};523}524 525void PatFrag::addOutParam(StringRef Name, ParamKind Kind) {526 assert(NumOutParams == Params.size() &&527 "Adding out-param after an in-param!");528 Params.emplace_back(Param{Name, Kind});529 ++NumOutParams;530}531 532iterator_range<PatFrag::ParamIt> PatFrag::out_params() const {533 return {Params.begin(), Params.begin() + NumOutParams};534}535 536unsigned PatFrag::num_roots() const {537 return count_if(out_params(),538 [&](const auto &P) { return P.Kind == PK_Root; });539}540 541unsigned PatFrag::getParamIdx(StringRef Name) const {542 for (const auto &[Idx, Op] : enumerate(Params)) {543 if (Op.Name == Name)544 return Idx;545 }546 547 return -1;548}549 550bool PatFrag::checkSemantics() {551 for (const auto &Alt : Alts) {552 for (const auto &Pat : Alt.Pats) {553 switch (Pat->getKind()) {554 case Pattern::K_AnyOpcode:555 PrintError("wip_match_opcode cannot be used in " + ClassName);556 return false;557 case Pattern::K_Builtin:558 PrintError("Builtin instructions cannot be used in " + ClassName);559 return false;560 case Pattern::K_CXX:561 continue;562 case Pattern::K_CodeGenInstruction:563 // TODO: Allow VarArgs?564 if (cast<CodeGenInstructionPattern>(Pat.get())->diagnoseAllSpecialTypes(565 Def.getLoc(), PatternType::SpecialTyClassName +566 " is not supported in " + ClassName))567 return false;568 continue;569 case Pattern::K_PatFrag:570 // TODO: It's just that the emitter doesn't handle it but technically571 // there is no reason why we can't. We just have to be careful with572 // operand mappings, it could get complex.573 PrintError("nested " + ClassName + " are not supported");574 return false;575 }576 }577 }578 579 StringSet<> SeenOps;580 for (const auto &Op : in_params()) {581 if (SeenOps.contains(Op.Name)) {582 PrintError("duplicate parameter '" + Op.Name + "'");583 return false;584 }585 586 // Check this operand is NOT defined in any alternative's patterns.587 for (const auto &Alt : Alts) {588 if (Alt.OpTable.lookup(Op.Name).Def) {589 PrintError("input parameter '" + Op.Name + "' cannot be redefined!");590 return false;591 }592 }593 594 if (Op.Kind == PK_Root) {595 PrintError("input parameterr '" + Op.Name + "' cannot be a root!");596 return false;597 }598 599 SeenOps.insert(Op.Name);600 }601 602 for (const auto &Op : out_params()) {603 if (Op.Kind != PK_Root && Op.Kind != PK_MachineOperand) {604 PrintError("output parameter '" + Op.Name +605 "' must be 'root' or 'gi_mo'");606 return false;607 }608 609 if (SeenOps.contains(Op.Name)) {610 PrintError("duplicate parameter '" + Op.Name + "'");611 return false;612 }613 614 // Check this operand is defined in all alternative's patterns.615 for (const auto &Alt : Alts) {616 const auto *OpDef = Alt.OpTable.getDef(Op.Name);617 if (!OpDef) {618 PrintError("output parameter '" + Op.Name +619 "' must be defined by all alternative patterns in '" +620 Def.getName() + "'");621 return false;622 }623 624 if (Op.Kind == PK_Root && OpDef->getNumInstDefs() != 1) {625 // The instruction that defines the root must have a single def.626 // Otherwise we'd need to support multiple roots and it gets messy.627 //628 // e.g. this is not supported:629 // (pattern (G_UNMERGE_VALUES $x, $root, $vec))630 PrintError("all instructions that define root '" + Op.Name + "' in '" +631 Def.getName() + "' can only have a single output operand");632 return false;633 }634 }635 636 SeenOps.insert(Op.Name);637 }638 639 if (num_out_params() != 0 && num_roots() == 0) {640 PrintError(ClassName + " must have one root in its 'out' operands");641 return false;642 }643 644 if (num_roots() > 1) {645 PrintError(ClassName + " can only have one root");646 return false;647 }648 649 // TODO: find unused params650 651 const auto CheckTypeOf = [&](const PatternType &) -> bool {652 llvm_unreachable("GITypeOf should have been rejected earlier!");653 };654 655 // Now, typecheck all alternatives.656 for (auto &Alt : Alts) {657 OperandTypeChecker OTC(Def.getLoc());658 for (auto &Pat : Alt.Pats) {659 if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {660 if (!OTC.check(*IP, CheckTypeOf))661 return false;662 }663 }664 OTC.propagateTypes();665 }666 667 return true;668}669 670bool PatFrag::handleUnboundInParam(StringRef ParamName, StringRef ArgName,671 ArrayRef<SMLoc> DiagLoc) const {672 // The parameter must be a live-in of all alternatives for this to work.673 // Otherwise, we risk having unbound parameters being used (= crashes).674 //675 // Examples:676 //677 // in (ins $y), (patterns (G_FNEG $dst, $y), "return matchFnegOp(${y})")678 // even if $y is unbound, we'll lazily bind it when emitting the G_FNEG.679 //680 // in (ins $y), (patterns "return matchFnegOp(${y})")681 // if $y is unbound when this fragment is emitted, C++ code expansion will682 // fail.683 for (const auto &Alt : Alts) {684 auto &OT = Alt.OpTable;685 if (!OT.lookup(ParamName).Found) {686 llvm::PrintError(DiagLoc, "operand '" + ArgName + "' (for parameter '" +687 ParamName + "' of '" + getName() +688 "') cannot be unbound");689 PrintNote(690 DiagLoc,691 "one or more alternatives of '" + getName() + "' do not bind '" +692 ParamName +693 "' to an instruction operand; either use a bound operand or "694 "ensure '" +695 Def.getName() + "' binds '" + ParamName +696 "' in all alternatives");697 return false;698 }699 }700 701 return true;702}703 704bool PatFrag::buildOperandsTables() {705 // enumerate(...) doesn't seem to allow lvalues so we need to count the old706 // way.707 unsigned Idx = 0;708 709 const auto DiagnoseRedef = [this, &Idx](StringRef OpName) {710 PrintError("Operand '" + OpName +711 "' is defined multiple times in patterns of alternative #" +712 std::to_string(Idx));713 };714 715 for (auto &Alt : Alts) {716 for (auto &Pat : Alt.Pats) {717 auto *IP = dyn_cast<InstructionPattern>(Pat.get());718 if (!IP)719 continue;720 721 if (!Alt.OpTable.addPattern(IP, DiagnoseRedef))722 return false;723 }724 725 ++Idx;726 }727 728 return true;729}730 731void PatFrag::print(raw_ostream &OS, StringRef Indent) const {732 OS << Indent << "(PatFrag name:" << getName() << '\n';733 if (!in_params().empty()) {734 OS << Indent << " (ins ";735 printParamsList(OS, in_params());736 OS << ")\n";737 }738 739 if (!out_params().empty()) {740 OS << Indent << " (outs ";741 printParamsList(OS, out_params());742 OS << ")\n";743 }744 745 // TODO: Dump OperandTable as well.746 OS << Indent << " (alternatives [\n";747 for (const auto &Alt : Alts) {748 OS << Indent << " [\n";749 for (const auto &Pat : Alt.Pats) {750 OS << Indent << " ";751 Pat->print(OS, /*PrintName=*/true);752 OS << ",\n";753 }754 OS << Indent << " ],\n";755 }756 OS << Indent << " ])\n";757 758 OS << Indent << ')';759}760 761void PatFrag::dump() const { print(dbgs()); }762 763void PatFrag::printParamsList(raw_ostream &OS, iterator_range<ParamIt> Params) {764 OS << '['765 << join(map_range(Params,766 [](auto &O) {767 return (O.Name + ":" + getParamKindStr(O.Kind)).str();768 }),769 ", ")770 << ']';771}772 773void PatFrag::PrintError(Twine Msg) const { llvm::PrintError(&Def, Msg); }774 775ArrayRef<InstructionOperand> PatFragPattern::getApplyDefsNeeded() const {776 assert(PF.num_roots() == 1);777 // Only roots need to be redef.778 for (auto [Idx, Param] : enumerate(PF.out_params())) {779 if (Param.Kind == PatFrag::PK_Root)780 return getOperand(Idx);781 }782 llvm_unreachable("root not found!");783}784 785//===- PatFragPattern -----------------------------------------------------===//786 787bool PatFragPattern::checkSemantics(ArrayRef<SMLoc> DiagLoc) {788 if (!InstructionPattern::checkSemantics(DiagLoc))789 return false;790 791 for (const auto &[Idx, Op] : enumerate(Operands)) {792 switch (PF.getParam(Idx).Kind) {793 case PatFrag::PK_Imm:794 if (!Op.hasImmValue()) {795 PrintError(DiagLoc, "expected operand " + std::to_string(Idx) +796 " of '" + getInstName() +797 "' to be an immediate; got " + Op.describe());798 return false;799 }800 if (Op.isNamedImmediate()) {801 PrintError(DiagLoc, "operand " + std::to_string(Idx) + " of '" +802 getInstName() +803 "' cannot be a named immediate");804 return false;805 }806 break;807 case PatFrag::PK_Root:808 case PatFrag::PK_MachineOperand:809 if (!Op.isNamedOperand() || Op.isNamedImmediate()) {810 PrintError(DiagLoc, "expected operand " + std::to_string(Idx) +811 " of '" + getInstName() +812 "' to be a MachineOperand; got " +813 Op.describe());814 return false;815 }816 break;817 }818 }819 820 return true;821}822 823bool PatFragPattern::mapInputCodeExpansions(const CodeExpansions &ParentCEs,824 CodeExpansions &PatFragCEs,825 ArrayRef<SMLoc> DiagLoc) const {826 for (const auto &[Idx, Op] : enumerate(operands())) {827 StringRef ParamName = PF.getParam(Idx).Name;828 829 // Operands to a PFP can only be named, or be an immediate, but not a named830 // immediate.831 assert(!Op.isNamedImmediate());832 833 if (Op.isNamedOperand()) {834 StringRef ArgName = Op.getOperandName();835 // Map it only if it's been defined.836 auto It = ParentCEs.find(ArgName);837 if (It == ParentCEs.end()) {838 if (!PF.handleUnboundInParam(ParamName, ArgName, DiagLoc))839 return false;840 } else {841 PatFragCEs.declare(ParamName, It->second);842 }843 continue;844 }845 846 if (Op.hasImmValue()) {847 PatFragCEs.declare(ParamName, std::to_string(Op.getImmValue()));848 continue;849 }850 851 llvm_unreachable("Unknown Operand Type!");852 }853 854 return true;855}856 857//===- BuiltinPattern -----------------------------------------------------===//858 859BuiltinPattern::BuiltinInfo BuiltinPattern::getBuiltinInfo(const Record &Def) {860 assert(Def.isSubClassOf(ClassName));861 862 StringRef Name = Def.getName();863 for (const auto &KBI : KnownBuiltins) {864 if (KBI.DefName == Name)865 return KBI;866 }867 868 PrintFatalError(Def.getLoc(),869 "Unimplemented " + ClassName + " def '" + Name + "'");870}871 872bool BuiltinPattern::checkSemantics(ArrayRef<SMLoc> Loc) {873 if (!InstructionPattern::checkSemantics(Loc))874 return false;875 876 // For now all builtins just take names, no immediates.877 for (const auto &[Idx, Op] : enumerate(operands())) {878 if (!Op.isNamedOperand() || Op.isNamedImmediate()) {879 PrintError(Loc, "expected operand " + std::to_string(Idx) + " of '" +880 getInstName() + "' to be a name");881 return false;882 }883 }884 885 return true;886}887