brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.8 KiB · 62a7b54 Raw
578 lines · cpp
1//===- CodeGenInstruction.cpp - CodeGen Instruction Class Wrapper ---------===//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// This file implements the CodeGenInstruction class.10//11//===----------------------------------------------------------------------===//12 13#include "CodeGenInstruction.h"14#include "CodeGenTarget.h"15#include "llvm/ADT/StringExtras.h"16#include "llvm/TableGen/Error.h"17#include "llvm/TableGen/Record.h"18#include <set>19using namespace llvm;20 21//===----------------------------------------------------------------------===//22// CGIOperandList Implementation23//===----------------------------------------------------------------------===//24 25CGIOperandList::CGIOperandList(const Record *R) : TheDef(R) {26  isPredicable = false;27  hasOptionalDef = false;28  isVariadic = false;29 30  const DagInit *OutDI = R->getValueAsDag("OutOperandList");31 32  if (const DefInit *Init = dyn_cast<DefInit>(OutDI->getOperator())) {33    if (Init->getDef()->getName() != "outs")34      PrintFatalError(R->getLoc(),35                      R->getName() +36                          ": invalid def name for output list: use 'outs'");37  } else {38    PrintFatalError(R->getLoc(),39                    R->getName() + ": invalid output list: use 'outs'");40  }41 42  NumDefs = OutDI->getNumArgs();43 44  const DagInit *InDI = R->getValueAsDag("InOperandList");45  if (const DefInit *Init = dyn_cast<DefInit>(InDI->getOperator())) {46    if (Init->getDef()->getName() != "ins")47      PrintFatalError(R->getLoc(),48                      R->getName() +49                          ": invalid def name for input list: use 'ins'");50  } else {51    PrintFatalError(R->getLoc(),52                    R->getName() + ": invalid input list: use 'ins'");53  }54 55  unsigned MIOperandNo = 0;56  std::set<std::string> OperandNames;57  unsigned e = InDI->getNumArgs() + OutDI->getNumArgs();58  OperandList.reserve(e);59  bool VariadicOuts = false;60  for (unsigned i = 0; i != e; ++i) {61    const Init *ArgInit;62    StringRef ArgName;63    if (i < NumDefs) {64      ArgInit = OutDI->getArg(i);65      ArgName = OutDI->getArgNameStr(i);66    } else {67      ArgInit = InDI->getArg(i - NumDefs);68      ArgName = InDI->getArgNameStr(i - NumDefs);69    }70 71    const DagInit *SubArgDag = dyn_cast<DagInit>(ArgInit);72    if (SubArgDag)73      ArgInit = SubArgDag->getOperator();74 75    const DefInit *Arg = dyn_cast<DefInit>(ArgInit);76    if (!Arg)77      PrintFatalError(R->getLoc(), "Illegal operand for the '" + R->getName() +78                                       "' instruction!");79 80    const Record *Rec = Arg->getDef();81    StringRef PrintMethod = "printOperand";82    StringRef EncoderMethod;83    std::string OperandType = "OPERAND_UNKNOWN";84    std::string OperandNamespace = "MCOI";85    unsigned NumOps = 1;86    const DagInit *MIOpInfo = nullptr;87    if (Rec->isSubClassOf("RegisterOperand")) {88      PrintMethod = Rec->getValueAsString("PrintMethod");89      OperandType = Rec->getValueAsString("OperandType").str();90      OperandNamespace = Rec->getValueAsString("OperandNamespace").str();91      EncoderMethod = Rec->getValueAsString("EncoderMethod");92    } else if (Rec->isSubClassOf("Operand")) {93      PrintMethod = Rec->getValueAsString("PrintMethod");94      OperandType = Rec->getValueAsString("OperandType").str();95      OperandNamespace = Rec->getValueAsString("OperandNamespace").str();96      // If there is an explicit encoder method, use it.97      EncoderMethod = Rec->getValueAsString("EncoderMethod");98      MIOpInfo = Rec->getValueAsDag("MIOperandInfo");99 100      // Verify that MIOpInfo has an 'ops' root value.101      if (!isa<DefInit>(MIOpInfo->getOperator()) ||102          cast<DefInit>(MIOpInfo->getOperator())->getDef()->getName() != "ops")103        PrintFatalError(R->getLoc(),104                        "Bad value for MIOperandInfo in operand '" +105                            Rec->getName() + "'\n");106 107      // If we have MIOpInfo, then we have #operands equal to number of entries108      // in MIOperandInfo.109      if (unsigned NumArgs = MIOpInfo->getNumArgs())110        NumOps = NumArgs;111 112      if (Rec->isSubClassOf("PredicateOp"))113        isPredicable = true;114      else if (Rec->isSubClassOf("OptionalDefOperand"))115        hasOptionalDef = true;116    } else if (Rec->getName() == "variable_ops") {117      if (i < NumDefs)118        VariadicOuts = true;119      isVariadic = true;120      continue;121    } else if (Rec->isSubClassOf("RegisterClassLike")) {122      OperandType = "OPERAND_REGISTER";123    } else if (!Rec->isSubClassOf("PointerLikeRegClass") &&124               !Rec->isSubClassOf("unknown_class")) {125      PrintFatalError(R->getLoc(), "Unknown operand class '" + Rec->getName() +126                                       "' in '" + R->getName() +127                                       "' instruction!");128    }129 130    // Check that the operand has a name and that it's unique.131    if (ArgName.empty())132      PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +133                                       "', operand #" + Twine(i) +134                                       " has no name!");135    if (!OperandNames.insert(ArgName.str()).second)136      PrintFatalError(R->getLoc(),137                      "In instruction '" + R->getName() + "', operand #" +138                          Twine(i) +139                          " has the same name as a previous operand!");140 141    OperandInfo &OpInfo = OperandList.emplace_back(142        Rec, ArgName, PrintMethod, OperandNamespace + "::" + OperandType,143        MIOperandNo, NumOps, MIOpInfo);144 145    if (SubArgDag) {146      if (!MIOpInfo) {147        PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +148                                         "', operand #" + Twine(i) + " has " +149                                         Twine(SubArgDag->getNumArgs()) +150                                         " sub-arg names, but no sub-operands");151      }152 153      unsigned NumSubArgs = SubArgDag->getNumArgs();154      unsigned NumSubOps = MIOpInfo->getNumArgs();155      if (NumSubArgs != NumSubOps) {156        PrintFatalError(R->getLoc(),157                        "In instruction '" + R->getName() + "', operand #" +158                            Twine(i) + " has " + Twine(NumSubArgs) +159                            " sub-arg names, expected " + Twine(NumSubOps));160      }161 162      for (unsigned j = 0; j < NumOps; ++j) {163        if (!isa<UnsetInit>(SubArgDag->getArg(j)))164          PrintFatalError(R->getLoc(),165                          "In instruction '" + R->getName() + "', operand #" +166                              Twine(i) + " sub-arg #" + Twine(j) +167                              " has unexpected operand (expected only $name).");168 169        StringRef SubArgName = SubArgDag->getArgNameStr(j);170        if (SubArgName.empty())171          PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +172                                           "', operand #" + Twine(i) +173                                           " has no name!");174        if (!OperandNames.insert(SubArgName.str()).second)175          PrintFatalError(R->getLoc(),176                          "In instruction '" + R->getName() + "', operand #" +177                              Twine(i) + " sub-arg #" + Twine(j) +178                              " has the same name as a previous operand!");179 180        if (auto MaybeEncoderMethod =181                cast<DefInit>(MIOpInfo->getArg(j))182                    ->getDef()183                    ->getValueAsOptionalString("EncoderMethod")) {184          OpInfo.EncoderMethodNames[j] = *MaybeEncoderMethod;185        }186 187        OpInfo.SubOpNames[j] = SubArgName;188        SubOpAliases[SubArgName] = {i, j};189      }190    } else if (!EncoderMethod.empty()) {191      // If we have no explicit sub-op dag, but have an top-level encoder192      // method, the single encoder will multiple sub-ops, itself.193      OpInfo.EncoderMethodNames[0] = EncoderMethod;194    }195 196    MIOperandNo += NumOps;197  }198 199  if (VariadicOuts)200    --NumDefs;201}202 203/// getOperandNamed - Return the index of the operand with the specified204/// non-empty name.  If the instruction does not have an operand with the205/// specified name, abort.206///207unsigned CGIOperandList::getOperandNamed(StringRef Name) const {208  std::optional<unsigned> OpIdx = findOperandNamed(Name);209  if (OpIdx)210    return *OpIdx;211  PrintFatalError(TheDef->getLoc(), "'" + TheDef->getName() +212                                        "' does not have an operand named '$" +213                                        Name + "'!");214}215 216/// findOperandNamed - Query whether the instruction has an operand of the217/// given name. If so, the index of the operand. Otherwise, return std::nullopt.218std::optional<unsigned> CGIOperandList::findOperandNamed(StringRef Name) const {219  assert(!Name.empty() && "Cannot search for operand with no name!");220  for (const auto &[Index, Opnd] : enumerate(OperandList))221    if (Opnd.Name == Name)222      return Index;223  return std::nullopt;224}225 226std::optional<std::pair<unsigned, unsigned>>227CGIOperandList::findSubOperandAlias(StringRef Name) const {228  assert(!Name.empty() && "Cannot search for operand with no name!");229  auto SubOpIter = SubOpAliases.find(Name);230  if (SubOpIter != SubOpAliases.end())231    return SubOpIter->second;232  return std::nullopt;233}234 235std::pair<unsigned, unsigned>236CGIOperandList::parseOperandName(StringRef Op, bool AllowWholeOp) const {237  if (!Op.starts_with("$"))238    PrintFatalError(TheDef->getLoc(),239                    TheDef->getName() + ": Illegal operand name: '" + Op + "'");240 241  StringRef OpName = Op.substr(1);242  StringRef SubOpName;243 244  // Check to see if this is $foo.bar.245  StringRef::size_type DotIdx = OpName.find_first_of('.');246  if (DotIdx != StringRef::npos) {247    SubOpName = OpName.substr(DotIdx + 1);248    if (SubOpName.empty())249      PrintFatalError(TheDef->getLoc(),250                      TheDef->getName() +251                          ": illegal empty suboperand name in '" + Op + "'");252    OpName = OpName.substr(0, DotIdx);253  }254 255  if (auto SubOp = findSubOperandAlias(OpName)) {256    // Found a name for a piece of an operand, just return it directly.257    if (!SubOpName.empty()) {258      PrintFatalError(259          TheDef->getLoc(),260          TheDef->getName() +261              ": Cannot use dotted suboperand name within suboperand '" +262              OpName + "'");263    }264    return *SubOp;265  }266 267  unsigned OpIdx = getOperandNamed(OpName);268 269  if (SubOpName.empty()) { // If no suboperand name was specified:270    // If one was needed, throw.271    if (OperandList[OpIdx].MINumOperands > 1 && !AllowWholeOp &&272        SubOpName.empty())273      PrintFatalError(TheDef->getLoc(),274                      TheDef->getName() +275                          ": Illegal to refer to"276                          " whole operand part of complex operand '" +277                          Op + "'");278 279    // Otherwise, return the operand.280    return {OpIdx, 0U};281  }282 283  // Find the suboperand number involved.284  const DagInit *MIOpInfo = OperandList[OpIdx].MIOperandInfo;285  if (!MIOpInfo)286    PrintFatalError(TheDef->getLoc(), TheDef->getName() +287                                          ": unknown suboperand name in '" +288                                          Op + "'");289 290  // Find the operand with the right name.291  for (unsigned i = 0, e = MIOpInfo->getNumArgs(); i != e; ++i)292    if (MIOpInfo->getArgNameStr(i) == SubOpName)293      return {OpIdx, i};294 295  // Otherwise, didn't find it!296  PrintFatalError(TheDef->getLoc(), TheDef->getName() +297                                        ": unknown suboperand name in '" + Op +298                                        "'");299  return {0U, 0U};300}301 302static void ParseConstraint(StringRef CStr, CGIOperandList &Ops,303                            const Record *Rec) {304  // EARLY_CLOBBER: @early $reg305  StringRef::size_type wpos = CStr.find_first_of(" \t");306  StringRef::size_type start = CStr.find_first_not_of(" \t");307  StringRef Tok = CStr.substr(start, wpos - start);308  if (Tok == "@earlyclobber") {309    StringRef Name = CStr.substr(wpos + 1);310    wpos = Name.find_first_not_of(" \t");311    if (wpos == StringRef::npos)312      PrintFatalError(Rec->getLoc(),313                      "Illegal format for @earlyclobber constraint in '" +314                          Rec->getName() + "': '" + CStr + "'");315    Name = Name.substr(wpos);316    std::pair<unsigned, unsigned> Op = Ops.parseOperandName(Name, false);317 318    // Build the string for the operand319    if (!Ops[Op.first].Constraints[Op.second].isNone())320      PrintFatalError(Rec->getLoc(), "Operand '" + Name + "' of '" +321                                         Rec->getName() +322                                         "' cannot have multiple constraints!");323    Ops[Op.first].Constraints[Op.second] =324        CGIOperandList::ConstraintInfo::getEarlyClobber();325    return;326  }327 328  // Only other constraint is "TIED_TO" for now.329  StringRef::size_type pos = CStr.find_first_of('=');330  if (pos == StringRef::npos || pos == 0 ||331      CStr.find_first_of(" \t", pos) != (pos + 1) ||332      CStr.find_last_of(" \t", pos) != (pos - 1))333    PrintFatalError(Rec->getLoc(), "Unrecognized constraint '" + CStr +334                                       "' in '" + Rec->getName() + "'");335  start = CStr.find_first_not_of(" \t");336 337  // TIED_TO: $src1 = $dst338  wpos = CStr.find_first_of(" \t", start);339  if (wpos == StringRef::npos || wpos > pos)340    PrintFatalError(Rec->getLoc(),341                    "Illegal format for tied-to constraint in '" +342                        Rec->getName() + "': '" + CStr + "'");343  StringRef LHSOpName = CStr.substr(start, wpos - start);344  std::pair<unsigned, unsigned> LHSOp = Ops.parseOperandName(LHSOpName, false);345 346  wpos = CStr.find_first_not_of(" \t", pos + 1);347  if (wpos == StringRef::npos)348    PrintFatalError(Rec->getLoc(),349                    "Illegal format for tied-to constraint: '" + CStr + "'");350 351  StringRef RHSOpName = CStr.substr(wpos);352  std::pair<unsigned, unsigned> RHSOp = Ops.parseOperandName(RHSOpName, false);353 354  // Sort the operands into order, which should put the output one355  // first. But keep the original order, for use in diagnostics.356  bool FirstIsDest = (LHSOp < RHSOp);357  std::pair<unsigned, unsigned> DestOp = (FirstIsDest ? LHSOp : RHSOp);358  StringRef DestOpName = (FirstIsDest ? LHSOpName : RHSOpName);359  std::pair<unsigned, unsigned> SrcOp = (FirstIsDest ? RHSOp : LHSOp);360  StringRef SrcOpName = (FirstIsDest ? RHSOpName : LHSOpName);361 362  // Ensure one operand is a def and the other is a use.363  if (DestOp.first >= Ops.NumDefs)364    PrintFatalError(Rec->getLoc(), "Input operands '" + LHSOpName + "' and '" +365                                       RHSOpName + "' of '" + Rec->getName() +366                                       "' cannot be tied!");367  if (SrcOp.first < Ops.NumDefs)368    PrintFatalError(Rec->getLoc(), "Output operands '" + LHSOpName + "' and '" +369                                       RHSOpName + "' of '" + Rec->getName() +370                                       "' cannot be tied!");371 372  // The constraint has to go on the operand with higher index, i.e.373  // the source one. Check there isn't another constraint there374  // already.375  if (!Ops[SrcOp.first].Constraints[SrcOp.second].isNone())376    PrintFatalError(Rec->getLoc(), "Operand '" + SrcOpName + "' of '" +377                                       Rec->getName() +378                                       "' cannot have multiple constraints!");379 380  unsigned DestFlatOpNo = Ops.getFlattenedOperandNumber(DestOp);381  auto NewConstraint = CGIOperandList::ConstraintInfo::getTied(DestFlatOpNo);382 383  // Check that the earlier operand is not the target of another tie384  // before making it the target of this one.385  for (const CGIOperandList::OperandInfo &Op : Ops) {386    for (unsigned i = 0; i < Op.MINumOperands; i++)387      if (Op.Constraints[i] == NewConstraint)388        PrintFatalError(Rec->getLoc(),389                        "Operand '" + DestOpName + "' of '" + Rec->getName() +390                            "' cannot have multiple operands tied to it!");391  }392 393  Ops[SrcOp.first].Constraints[SrcOp.second] = NewConstraint;394}395 396static void ParseConstraints(StringRef CStr, CGIOperandList &Ops,397                             const Record *Rec) {398  if (CStr.empty())399    return;400 401  StringRef delims(",");402  StringRef::size_type bidx, eidx;403 404  bidx = CStr.find_first_not_of(delims);405  while (bidx != StringRef::npos) {406    eidx = CStr.find_first_of(delims, bidx);407    if (eidx == StringRef::npos)408      eidx = CStr.size();409 410    ParseConstraint(CStr.substr(bidx, eidx - bidx), Ops, Rec);411    bidx = CStr.find_first_not_of(delims, eidx);412  }413}414 415//===----------------------------------------------------------------------===//416// CodeGenInstruction Implementation417//===----------------------------------------------------------------------===//418 419CodeGenInstruction::CodeGenInstruction(const Record *R)420    : TheDef(R), Operands(R), InferredFrom(nullptr) {421  Namespace = R->getValueAsString("Namespace");422  AsmString = R->getValueAsString("AsmString");423 424  isPreISelOpcode = R->getValueAsBit("isPreISelOpcode");425  isReturn = R->getValueAsBit("isReturn");426  isEHScopeReturn = R->getValueAsBit("isEHScopeReturn");427  isBranch = R->getValueAsBit("isBranch");428  isIndirectBranch = R->getValueAsBit("isIndirectBranch");429  isCompare = R->getValueAsBit("isCompare");430  isMoveImm = R->getValueAsBit("isMoveImm");431  isMoveReg = R->getValueAsBit("isMoveReg");432  isBitcast = R->getValueAsBit("isBitcast");433  isSelect = R->getValueAsBit("isSelect");434  isBarrier = R->getValueAsBit("isBarrier");435  isCall = R->getValueAsBit("isCall");436  isAdd = R->getValueAsBit("isAdd");437  isTrap = R->getValueAsBit("isTrap");438  canFoldAsLoad = R->getValueAsBit("canFoldAsLoad");439  isPredicable = !R->getValueAsBit("isUnpredicable") &&440                 (Operands.isPredicable || R->getValueAsBit("isPredicable"));441  isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress");442  isCommutable = R->getValueAsBit("isCommutable");443  isTerminator = R->getValueAsBit("isTerminator");444  isReMaterializable = R->getValueAsBit("isReMaterializable");445  hasDelaySlot = R->getValueAsBit("hasDelaySlot");446  usesCustomInserter = R->getValueAsBit("usesCustomInserter");447  hasPostISelHook = R->getValueAsBit("hasPostISelHook");448  hasCtrlDep = R->getValueAsBit("hasCtrlDep");449  isNotDuplicable = R->getValueAsBit("isNotDuplicable");450  isRegSequence = R->getValueAsBit("isRegSequence");451  isExtractSubreg = R->getValueAsBit("isExtractSubreg");452  isInsertSubreg = R->getValueAsBit("isInsertSubreg");453  isConvergent = R->getValueAsBit("isConvergent");454  hasNoSchedulingInfo = R->getValueAsBit("hasNoSchedulingInfo");455  FastISelShouldIgnore = R->getValueAsBit("FastISelShouldIgnore");456  variadicOpsAreDefs = R->getValueAsBit("variadicOpsAreDefs");457  isAuthenticated = R->getValueAsBit("isAuthenticated");458 459  bool Unset;460  mayLoad = R->getValueAsBitOrUnset("mayLoad", Unset);461  mayLoad_Unset = Unset;462  mayStore = R->getValueAsBitOrUnset("mayStore", Unset);463  mayStore_Unset = Unset;464  mayRaiseFPException = R->getValueAsBit("mayRaiseFPException");465  hasSideEffects = R->getValueAsBitOrUnset("hasSideEffects", Unset);466  hasSideEffects_Unset = Unset;467 468  isAsCheapAsAMove = R->getValueAsBit("isAsCheapAsAMove");469  hasExtraSrcRegAllocReq = R->getValueAsBit("hasExtraSrcRegAllocReq");470  hasExtraDefRegAllocReq = R->getValueAsBit("hasExtraDefRegAllocReq");471  isCodeGenOnly = R->getValueAsBit("isCodeGenOnly");472  isPseudo = R->getValueAsBit("isPseudo");473  isMeta = R->getValueAsBit("isMeta");474  ImplicitDefs = R->getValueAsListOfDefs("Defs");475  ImplicitUses = R->getValueAsListOfDefs("Uses");476 477  // This flag is only inferred from the pattern.478  hasChain = false;479  hasChain_Inferred = false;480 481  // Parse Constraints.482  ParseConstraints(R->getValueAsString("Constraints"), Operands, R);483 484  // First check for a ComplexDeprecationPredicate.485  if (R->getValue("ComplexDeprecationPredicate")) {486    HasComplexDeprecationPredicate = true;487    DeprecatedReason = R->getValueAsString("ComplexDeprecationPredicate").str();488  } else if (const RecordVal *Dep = R->getValue("DeprecatedFeatureMask")) {489    // Check if we have a Subtarget feature mask.490    HasComplexDeprecationPredicate = false;491    DeprecatedReason = Dep->getValue()->getAsString();492  } else {493    // This instruction isn't deprecated.494    HasComplexDeprecationPredicate = false;495    DeprecatedReason = "";496  }497}498 499/// HasOneImplicitDefWithKnownVT - If the instruction has at least one500/// implicit def and it has a known VT, return the VT, otherwise return501/// MVT::Other.502MVT CodeGenInstruction::HasOneImplicitDefWithKnownVT(503    const CodeGenTarget &TargetInfo) const {504  if (ImplicitDefs.empty())505    return MVT::Other;506 507  // Check to see if the first implicit def has a resolvable type.508  const Record *FirstImplicitDef = ImplicitDefs[0];509  assert(FirstImplicitDef->isSubClassOf("Register"));510  const std::vector<ValueTypeByHwMode> &RegVTs =511      TargetInfo.getRegisterVTs(FirstImplicitDef);512  if (RegVTs.size() == 1 && RegVTs[0].isSimple())513    return RegVTs[0].getSimple();514  return MVT::Other;515}516 517/// FlattenAsmStringVariants - Flatten the specified AsmString to only518/// include text from the specified variant, returning the new string.519std::string CodeGenInstruction::FlattenAsmStringVariants(StringRef Cur,520                                                         unsigned Variant) {521  std::string Res;522 523  for (;;) {524    // Find the start of the next variant string.525    size_t VariantsStart = 0;526    for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart)527      if (Cur[VariantsStart] == '{' &&528          (VariantsStart == 0 ||529           (Cur[VariantsStart - 1] != '$' && Cur[VariantsStart - 1] != '\\')))530        break;531 532    // Add the prefix to the result.533    Res += Cur.slice(0, VariantsStart);534    if (VariantsStart == Cur.size())535      break;536 537    ++VariantsStart; // Skip the '{'.538 539    // Scan to the end of the variants string.540    size_t VariantsEnd = VariantsStart;541    unsigned NestedBraces = 1;542    for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) {543      if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd - 1] != '\\') {544        if (--NestedBraces == 0)545          break;546      } else if (Cur[VariantsEnd] == '{')547        ++NestedBraces;548    }549 550    // Select the Nth variant (or empty).551    StringRef Selection =552        Cur.substr(VariantsStart, VariantsEnd - VariantsStart);553    for (unsigned i = 0; i != Variant; ++i)554      Selection = Selection.split('|').second;555    Res += Selection.split('|').first;556 557    assert(VariantsEnd != Cur.size() &&558           "Unterminated variants in assembly string!");559    Cur = Cur.substr(VariantsEnd + 1);560  }561 562  return Res;563}564 565bool CodeGenInstruction::isOperandImpl(StringRef OpListName, unsigned i,566                                       StringRef PropertyName) const {567  const DagInit *ConstraintList = TheDef->getValueAsDag(OpListName);568  if (!ConstraintList || i >= ConstraintList->getNumArgs())569    return false;570 571  const DefInit *Constraint = dyn_cast<DefInit>(ConstraintList->getArg(i));572  if (!Constraint)573    return false;574 575  return Constraint->getDef()->isSubClassOf("TypedOperand") &&576         Constraint->getDef()->getValueAsBit(PropertyName);577}578