brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.4 KiB · dfd37fd Raw
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