Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/Common/CodeGenInstruction.cpp
35290 views
//===- CodeGenInstruction.cpp - CodeGen Instruction Class Wrapper ---------===//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//===----------------------------------------------------------------------===//7//8// This file implements the CodeGenInstruction class.9//10//===----------------------------------------------------------------------===//1112#include "CodeGenInstruction.h"13#include "CodeGenTarget.h"14#include "llvm/ADT/StringExtras.h"15#include "llvm/TableGen/Error.h"16#include "llvm/TableGen/Record.h"17#include <set>18using namespace llvm;1920//===----------------------------------------------------------------------===//21// CGIOperandList Implementation22//===----------------------------------------------------------------------===//2324CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {25isPredicable = false;26hasOptionalDef = false;27isVariadic = false;2829DagInit *OutDI = R->getValueAsDag("OutOperandList");3031if (DefInit *Init = dyn_cast<DefInit>(OutDI->getOperator())) {32if (Init->getDef()->getName() != "outs")33PrintFatalError(R->getLoc(),34R->getName() +35": invalid def name for output list: use 'outs'");36} else37PrintFatalError(R->getLoc(),38R->getName() + ": invalid output list: use 'outs'");3940NumDefs = OutDI->getNumArgs();4142DagInit *InDI = R->getValueAsDag("InOperandList");43if (DefInit *Init = dyn_cast<DefInit>(InDI->getOperator())) {44if (Init->getDef()->getName() != "ins")45PrintFatalError(R->getLoc(),46R->getName() +47": invalid def name for input list: use 'ins'");48} else49PrintFatalError(R->getLoc(),50R->getName() + ": invalid input list: use 'ins'");5152unsigned MIOperandNo = 0;53std::set<std::string> OperandNames;54unsigned e = InDI->getNumArgs() + OutDI->getNumArgs();55OperandList.reserve(e);56bool VariadicOuts = false;57for (unsigned i = 0; i != e; ++i) {58Init *ArgInit;59StringRef ArgName;60if (i < NumDefs) {61ArgInit = OutDI->getArg(i);62ArgName = OutDI->getArgNameStr(i);63} else {64ArgInit = InDI->getArg(i - NumDefs);65ArgName = InDI->getArgNameStr(i - NumDefs);66}6768DagInit *SubArgDag = dyn_cast<DagInit>(ArgInit);69if (SubArgDag)70ArgInit = SubArgDag->getOperator();7172DefInit *Arg = dyn_cast<DefInit>(ArgInit);73if (!Arg)74PrintFatalError(R->getLoc(), "Illegal operand for the '" + R->getName() +75"' instruction!");7677Record *Rec = Arg->getDef();78std::string PrintMethod = "printOperand";79std::string EncoderMethod;80std::string OperandType = "OPERAND_UNKNOWN";81std::string OperandNamespace = "MCOI";82unsigned NumOps = 1;83DagInit *MIOpInfo = nullptr;84if (Rec->isSubClassOf("RegisterOperand")) {85PrintMethod = std::string(Rec->getValueAsString("PrintMethod"));86OperandType = std::string(Rec->getValueAsString("OperandType"));87OperandNamespace = std::string(Rec->getValueAsString("OperandNamespace"));88EncoderMethod = std::string(Rec->getValueAsString("EncoderMethod"));89} else if (Rec->isSubClassOf("Operand")) {90PrintMethod = std::string(Rec->getValueAsString("PrintMethod"));91OperandType = std::string(Rec->getValueAsString("OperandType"));92OperandNamespace = std::string(Rec->getValueAsString("OperandNamespace"));93// If there is an explicit encoder method, use it.94EncoderMethod = std::string(Rec->getValueAsString("EncoderMethod"));95MIOpInfo = Rec->getValueAsDag("MIOperandInfo");9697// Verify that MIOpInfo has an 'ops' root value.98if (!isa<DefInit>(MIOpInfo->getOperator()) ||99cast<DefInit>(MIOpInfo->getOperator())->getDef()->getName() != "ops")100PrintFatalError(R->getLoc(),101"Bad value for MIOperandInfo in operand '" +102Rec->getName() + "'\n");103104// If we have MIOpInfo, then we have #operands equal to number of entries105// in MIOperandInfo.106if (unsigned NumArgs = MIOpInfo->getNumArgs())107NumOps = NumArgs;108109if (Rec->isSubClassOf("PredicateOp"))110isPredicable = true;111else if (Rec->isSubClassOf("OptionalDefOperand"))112hasOptionalDef = true;113} else if (Rec->getName() == "variable_ops") {114if (i < NumDefs)115VariadicOuts = true;116isVariadic = true;117continue;118} else if (Rec->isSubClassOf("RegisterClass")) {119OperandType = "OPERAND_REGISTER";120} else if (!Rec->isSubClassOf("PointerLikeRegClass") &&121!Rec->isSubClassOf("unknown_class")) {122PrintFatalError(R->getLoc(), "Unknown operand class '" + Rec->getName() +123"' in '" + R->getName() +124"' instruction!");125}126127// Check that the operand has a name and that it's unique.128if (ArgName.empty())129PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +130"', operand #" + Twine(i) +131" has no name!");132if (!OperandNames.insert(std::string(ArgName)).second)133PrintFatalError(R->getLoc(),134"In instruction '" + R->getName() + "', operand #" +135Twine(i) +136" has the same name as a previous operand!");137138OperandInfo &OpInfo = OperandList.emplace_back(139Rec, std::string(ArgName), std::string(PrintMethod),140OperandNamespace + "::" + OperandType, MIOperandNo, NumOps, MIOpInfo);141142if (SubArgDag) {143if (SubArgDag->getNumArgs() != NumOps) {144PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +145"', operand #" + Twine(i) + " has " +146Twine(SubArgDag->getNumArgs()) +147" sub-arg names, expected " +148Twine(NumOps) + ".");149}150151for (unsigned j = 0; j < NumOps; ++j) {152if (!isa<UnsetInit>(SubArgDag->getArg(j)))153PrintFatalError(R->getLoc(),154"In instruction '" + R->getName() + "', operand #" +155Twine(i) + " sub-arg #" + Twine(j) +156" has unexpected operand (expected only $name).");157158StringRef SubArgName = SubArgDag->getArgNameStr(j);159if (SubArgName.empty())160PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +161"', operand #" + Twine(i) +162" has no name!");163if (!OperandNames.insert(std::string(SubArgName)).second)164PrintFatalError(R->getLoc(),165"In instruction '" + R->getName() + "', operand #" +166Twine(i) + " sub-arg #" + Twine(j) +167" has the same name as a previous operand!");168169if (auto MaybeEncoderMethod =170cast<DefInit>(MIOpInfo->getArg(j))171->getDef()172->getValueAsOptionalString("EncoderMethod")) {173OpInfo.EncoderMethodNames[j] = *MaybeEncoderMethod;174}175176OpInfo.SubOpNames[j] = SubArgName;177SubOpAliases[SubArgName] = std::pair(i, j);178}179} else if (!EncoderMethod.empty()) {180// If we have no explicit sub-op dag, but have an top-level encoder181// method, the single encoder will multiple sub-ops, itself.182OpInfo.EncoderMethodNames[0] = EncoderMethod;183for (unsigned j = 1; j < NumOps; ++j)184OpInfo.DoNotEncode[j] = true;185}186187MIOperandNo += NumOps;188}189190if (VariadicOuts)191--NumDefs;192}193194/// getOperandNamed - Return the index of the operand with the specified195/// non-empty name. If the instruction does not have an operand with the196/// specified name, abort.197///198unsigned CGIOperandList::getOperandNamed(StringRef Name) const {199unsigned OpIdx;200if (hasOperandNamed(Name, OpIdx))201return OpIdx;202PrintFatalError(TheDef->getLoc(), "'" + TheDef->getName() +203"' does not have an operand named '$" +204Name + "'!");205}206207/// hasOperandNamed - Query whether the instruction has an operand of the208/// given name. If so, return true and set OpIdx to the index of the209/// operand. Otherwise, return false.210bool CGIOperandList::hasOperandNamed(StringRef Name, unsigned &OpIdx) const {211assert(!Name.empty() && "Cannot search for operand with no name!");212for (unsigned i = 0, e = OperandList.size(); i != e; ++i)213if (OperandList[i].Name == Name) {214OpIdx = i;215return true;216}217return false;218}219220bool CGIOperandList::hasSubOperandAlias(221StringRef Name, std::pair<unsigned, unsigned> &SubOp) const {222assert(!Name.empty() && "Cannot search for operand with no name!");223auto SubOpIter = SubOpAliases.find(Name);224if (SubOpIter != SubOpAliases.end()) {225SubOp = SubOpIter->second;226return true;227}228return false;229}230231std::pair<unsigned, unsigned>232CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {233if (!Op.starts_with("$"))234PrintFatalError(TheDef->getLoc(),235TheDef->getName() + ": Illegal operand name: '" + Op + "'");236237StringRef OpName = Op.substr(1);238StringRef SubOpName;239240// Check to see if this is $foo.bar.241StringRef::size_type DotIdx = OpName.find_first_of('.');242if (DotIdx != StringRef::npos) {243SubOpName = OpName.substr(DotIdx + 1);244if (SubOpName.empty())245PrintFatalError(TheDef->getLoc(),246TheDef->getName() +247": illegal empty suboperand name in '" + Op + "'");248OpName = OpName.substr(0, DotIdx);249}250251unsigned OpIdx;252253if (std::pair<unsigned, unsigned> SubOp; hasSubOperandAlias(OpName, SubOp)) {254// Found a name for a piece of an operand, just return it directly.255if (!SubOpName.empty()) {256PrintFatalError(257TheDef->getLoc(),258TheDef->getName() +259": Cannot use dotted suboperand name within suboperand '" +260OpName + "'");261}262return SubOp;263}264265OpIdx = getOperandNamed(OpName);266267if (SubOpName.empty()) { // If no suboperand name was specified:268// If one was needed, throw.269if (OperandList[OpIdx].MINumOperands > 1 && !AllowWholeOp &&270SubOpName.empty())271PrintFatalError(TheDef->getLoc(),272TheDef->getName() +273": Illegal to refer to"274" whole operand part of complex operand '" +275Op + "'");276277// Otherwise, return the operand.278return std::pair(OpIdx, 0U);279}280281// Find the suboperand number involved.282DagInit *MIOpInfo = OperandList[OpIdx].MIOperandInfo;283if (!MIOpInfo)284PrintFatalError(TheDef->getLoc(), TheDef->getName() +285": unknown suboperand name in '" +286Op + "'");287288// Find the operand with the right name.289for (unsigned i = 0, e = MIOpInfo->getNumArgs(); i != e; ++i)290if (MIOpInfo->getArgNameStr(i) == SubOpName)291return std::pair(OpIdx, i);292293// Otherwise, didn't find it!294PrintFatalError(TheDef->getLoc(), TheDef->getName() +295": unknown suboperand name in '" + Op +296"'");297return std::pair(0U, 0U);298}299300static void ParseConstraint(StringRef CStr, CGIOperandList &Ops, Record *Rec) {301// EARLY_CLOBBER: @early $reg302StringRef::size_type wpos = CStr.find_first_of(" \t");303StringRef::size_type start = CStr.find_first_not_of(" \t");304StringRef Tok = CStr.substr(start, wpos - start);305if (Tok == "@earlyclobber") {306StringRef Name = CStr.substr(wpos + 1);307wpos = Name.find_first_not_of(" \t");308if (wpos == StringRef::npos)309PrintFatalError(Rec->getLoc(),310"Illegal format for @earlyclobber constraint in '" +311Rec->getName() + "': '" + CStr + "'");312Name = Name.substr(wpos);313std::pair<unsigned, unsigned> Op = Ops.ParseOperandName(Name, false);314315// Build the string for the operand316if (!Ops[Op.first].Constraints[Op.second].isNone())317PrintFatalError(Rec->getLoc(), "Operand '" + Name + "' of '" +318Rec->getName() +319"' cannot have multiple constraints!");320Ops[Op.first].Constraints[Op.second] =321CGIOperandList::ConstraintInfo::getEarlyClobber();322return;323}324325// Only other constraint is "TIED_TO" for now.326StringRef::size_type pos = CStr.find_first_of('=');327if (pos == StringRef::npos || pos == 0 ||328CStr.find_first_of(" \t", pos) != (pos + 1) ||329CStr.find_last_of(" \t", pos) != (pos - 1))330PrintFatalError(Rec->getLoc(), "Unrecognized constraint '" + CStr +331"' in '" + Rec->getName() + "'");332start = CStr.find_first_not_of(" \t");333334// TIED_TO: $src1 = $dst335wpos = CStr.find_first_of(" \t", start);336if (wpos == StringRef::npos || wpos > pos)337PrintFatalError(Rec->getLoc(),338"Illegal format for tied-to constraint in '" +339Rec->getName() + "': '" + CStr + "'");340StringRef LHSOpName = CStr.substr(start, wpos - start);341std::pair<unsigned, unsigned> LHSOp = Ops.ParseOperandName(LHSOpName, false);342343wpos = CStr.find_first_not_of(" \t", pos + 1);344if (wpos == StringRef::npos)345PrintFatalError(Rec->getLoc(),346"Illegal format for tied-to constraint: '" + CStr + "'");347348StringRef RHSOpName = CStr.substr(wpos);349std::pair<unsigned, unsigned> RHSOp = Ops.ParseOperandName(RHSOpName, false);350351// Sort the operands into order, which should put the output one352// first. But keep the original order, for use in diagnostics.353bool FirstIsDest = (LHSOp < RHSOp);354std::pair<unsigned, unsigned> DestOp = (FirstIsDest ? LHSOp : RHSOp);355StringRef DestOpName = (FirstIsDest ? LHSOpName : RHSOpName);356std::pair<unsigned, unsigned> SrcOp = (FirstIsDest ? RHSOp : LHSOp);357StringRef SrcOpName = (FirstIsDest ? RHSOpName : LHSOpName);358359// Ensure one operand is a def and the other is a use.360if (DestOp.first >= Ops.NumDefs)361PrintFatalError(Rec->getLoc(), "Input operands '" + LHSOpName + "' and '" +362RHSOpName + "' of '" + Rec->getName() +363"' cannot be tied!");364if (SrcOp.first < Ops.NumDefs)365PrintFatalError(Rec->getLoc(), "Output operands '" + LHSOpName + "' and '" +366RHSOpName + "' of '" + Rec->getName() +367"' cannot be tied!");368369// The constraint has to go on the operand with higher index, i.e.370// the source one. Check there isn't another constraint there371// already.372if (!Ops[SrcOp.first].Constraints[SrcOp.second].isNone())373PrintFatalError(Rec->getLoc(), "Operand '" + SrcOpName + "' of '" +374Rec->getName() +375"' cannot have multiple constraints!");376377unsigned DestFlatOpNo = Ops.getFlattenedOperandNumber(DestOp);378auto NewConstraint = CGIOperandList::ConstraintInfo::getTied(DestFlatOpNo);379380// Check that the earlier operand is not the target of another tie381// before making it the target of this one.382for (const CGIOperandList::OperandInfo &Op : Ops) {383for (unsigned i = 0; i < Op.MINumOperands; i++)384if (Op.Constraints[i] == NewConstraint)385PrintFatalError(Rec->getLoc(),386"Operand '" + DestOpName + "' of '" + Rec->getName() +387"' cannot have multiple operands tied to it!");388}389390Ops[SrcOp.first].Constraints[SrcOp.second] = NewConstraint;391}392393static void ParseConstraints(StringRef CStr, CGIOperandList &Ops, Record *Rec) {394if (CStr.empty())395return;396397StringRef delims(",");398StringRef::size_type bidx, eidx;399400bidx = CStr.find_first_not_of(delims);401while (bidx != StringRef::npos) {402eidx = CStr.find_first_of(delims, bidx);403if (eidx == StringRef::npos)404eidx = CStr.size();405406ParseConstraint(CStr.substr(bidx, eidx - bidx), Ops, Rec);407bidx = CStr.find_first_not_of(delims, eidx);408}409}410411void CGIOperandList::ProcessDisableEncoding(StringRef DisableEncoding) {412while (true) {413StringRef OpName;414std::tie(OpName, DisableEncoding) = getToken(DisableEncoding, " ,\t");415if (OpName.empty())416break;417418// Figure out which operand this is.419std::pair<unsigned, unsigned> Op = ParseOperandName(OpName, false);420421// Mark the operand as not-to-be encoded.422OperandList[Op.first].DoNotEncode[Op.second] = true;423}424}425426//===----------------------------------------------------------------------===//427// CodeGenInstruction Implementation428//===----------------------------------------------------------------------===//429430CodeGenInstruction::CodeGenInstruction(Record *R)431: TheDef(R), Operands(R), InferredFrom(nullptr) {432Namespace = R->getValueAsString("Namespace");433AsmString = std::string(R->getValueAsString("AsmString"));434435isPreISelOpcode = R->getValueAsBit("isPreISelOpcode");436isReturn = R->getValueAsBit("isReturn");437isEHScopeReturn = R->getValueAsBit("isEHScopeReturn");438isBranch = R->getValueAsBit("isBranch");439isIndirectBranch = R->getValueAsBit("isIndirectBranch");440isCompare = R->getValueAsBit("isCompare");441isMoveImm = R->getValueAsBit("isMoveImm");442isMoveReg = R->getValueAsBit("isMoveReg");443isBitcast = R->getValueAsBit("isBitcast");444isSelect = R->getValueAsBit("isSelect");445isBarrier = R->getValueAsBit("isBarrier");446isCall = R->getValueAsBit("isCall");447isAdd = R->getValueAsBit("isAdd");448isTrap = R->getValueAsBit("isTrap");449canFoldAsLoad = R->getValueAsBit("canFoldAsLoad");450isPredicable = !R->getValueAsBit("isUnpredicable") &&451(Operands.isPredicable || R->getValueAsBit("isPredicable"));452isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress");453isCommutable = R->getValueAsBit("isCommutable");454isTerminator = R->getValueAsBit("isTerminator");455isReMaterializable = R->getValueAsBit("isReMaterializable");456hasDelaySlot = R->getValueAsBit("hasDelaySlot");457usesCustomInserter = R->getValueAsBit("usesCustomInserter");458hasPostISelHook = R->getValueAsBit("hasPostISelHook");459hasCtrlDep = R->getValueAsBit("hasCtrlDep");460isNotDuplicable = R->getValueAsBit("isNotDuplicable");461isRegSequence = R->getValueAsBit("isRegSequence");462isExtractSubreg = R->getValueAsBit("isExtractSubreg");463isInsertSubreg = R->getValueAsBit("isInsertSubreg");464isConvergent = R->getValueAsBit("isConvergent");465hasNoSchedulingInfo = R->getValueAsBit("hasNoSchedulingInfo");466FastISelShouldIgnore = R->getValueAsBit("FastISelShouldIgnore");467variadicOpsAreDefs = R->getValueAsBit("variadicOpsAreDefs");468isAuthenticated = R->getValueAsBit("isAuthenticated");469470bool Unset;471mayLoad = R->getValueAsBitOrUnset("mayLoad", Unset);472mayLoad_Unset = Unset;473mayStore = R->getValueAsBitOrUnset("mayStore", Unset);474mayStore_Unset = Unset;475mayRaiseFPException = R->getValueAsBit("mayRaiseFPException");476hasSideEffects = R->getValueAsBitOrUnset("hasSideEffects", Unset);477hasSideEffects_Unset = Unset;478479isAsCheapAsAMove = R->getValueAsBit("isAsCheapAsAMove");480hasExtraSrcRegAllocReq = R->getValueAsBit("hasExtraSrcRegAllocReq");481hasExtraDefRegAllocReq = R->getValueAsBit("hasExtraDefRegAllocReq");482isCodeGenOnly = R->getValueAsBit("isCodeGenOnly");483isPseudo = R->getValueAsBit("isPseudo");484isMeta = R->getValueAsBit("isMeta");485ImplicitDefs = R->getValueAsListOfDefs("Defs");486ImplicitUses = R->getValueAsListOfDefs("Uses");487488// This flag is only inferred from the pattern.489hasChain = false;490hasChain_Inferred = false;491492// Parse Constraints.493ParseConstraints(R->getValueAsString("Constraints"), Operands, R);494495// Parse the DisableEncoding field.496Operands.ProcessDisableEncoding(R->getValueAsString("DisableEncoding"));497498// First check for a ComplexDeprecationPredicate.499if (R->getValue("ComplexDeprecationPredicate")) {500HasComplexDeprecationPredicate = true;501DeprecatedReason =502std::string(R->getValueAsString("ComplexDeprecationPredicate"));503} else if (RecordVal *Dep = R->getValue("DeprecatedFeatureMask")) {504// Check if we have a Subtarget feature mask.505HasComplexDeprecationPredicate = false;506DeprecatedReason = Dep->getValue()->getAsString();507} else {508// This instruction isn't deprecated.509HasComplexDeprecationPredicate = false;510DeprecatedReason = "";511}512}513514/// HasOneImplicitDefWithKnownVT - If the instruction has at least one515/// implicit def and it has a known VT, return the VT, otherwise return516/// MVT::Other.517MVT::SimpleValueType CodeGenInstruction::HasOneImplicitDefWithKnownVT(518const CodeGenTarget &TargetInfo) const {519if (ImplicitDefs.empty())520return MVT::Other;521522// Check to see if the first implicit def has a resolvable type.523Record *FirstImplicitDef = ImplicitDefs[0];524assert(FirstImplicitDef->isSubClassOf("Register"));525const std::vector<ValueTypeByHwMode> &RegVTs =526TargetInfo.getRegisterVTs(FirstImplicitDef);527if (RegVTs.size() == 1 && RegVTs[0].isSimple())528return RegVTs[0].getSimple().SimpleTy;529return MVT::Other;530}531532/// FlattenAsmStringVariants - Flatten the specified AsmString to only533/// include text from the specified variant, returning the new string.534std::string CodeGenInstruction::FlattenAsmStringVariants(StringRef Cur,535unsigned Variant) {536std::string Res;537538for (;;) {539// Find the start of the next variant string.540size_t VariantsStart = 0;541for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart)542if (Cur[VariantsStart] == '{' &&543(VariantsStart == 0 ||544(Cur[VariantsStart - 1] != '$' && Cur[VariantsStart - 1] != '\\')))545break;546547// Add the prefix to the result.548Res += Cur.slice(0, VariantsStart);549if (VariantsStart == Cur.size())550break;551552++VariantsStart; // Skip the '{'.553554// Scan to the end of the variants string.555size_t VariantsEnd = VariantsStart;556unsigned NestedBraces = 1;557for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) {558if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd - 1] != '\\') {559if (--NestedBraces == 0)560break;561} else if (Cur[VariantsEnd] == '{')562++NestedBraces;563}564565// Select the Nth variant (or empty).566StringRef Selection = Cur.slice(VariantsStart, VariantsEnd);567for (unsigned i = 0; i != Variant; ++i)568Selection = Selection.split('|').second;569Res += Selection.split('|').first;570571assert(VariantsEnd != Cur.size() &&572"Unterminated variants in assembly string!");573Cur = Cur.substr(VariantsEnd + 1);574}575576return Res;577}578579bool CodeGenInstruction::isOperandImpl(StringRef OpListName, unsigned i,580StringRef PropertyName) const {581DagInit *ConstraintList = TheDef->getValueAsDag(OpListName);582if (!ConstraintList || i >= ConstraintList->getNumArgs())583return false;584585DefInit *Constraint = dyn_cast<DefInit>(ConstraintList->getArg(i));586if (!Constraint)587return false;588589return Constraint->getDef()->isSubClassOf("TypedOperand") &&590Constraint->getDef()->getValueAsBit(PropertyName);591}592593594