SubOpAliases maps a sub-operand name to the respective operand's index
and the sub-operand number within this operand. The operand index is
used for the Operands array.
Currently MIOperandNo is used as the operand index, which is not
correct. For example, if there are 2 operands with 3 sub-operands each:
(ins (bdladdr12onlylen4 $B1, $D1, $L1):$BDL1,
(bdladdr12onlylen4 $B2, $D2, $L2):$BDL2)
then B2's operand index will be 3, but the correct value is 1.
Reviewed By: jyknight
Differential Revision: https://reviews.llvm.org/D155158
594 lines
23 KiB
C++
594 lines
23 KiB
C++
//===- CodeGenInstruction.cpp - CodeGen Instruction Class Wrapper ---------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the CodeGenInstruction class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CodeGenInstruction.h"
|
|
#include "CodeGenTarget.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/TableGen/Error.h"
|
|
#include "llvm/TableGen/Record.h"
|
|
#include <set>
|
|
using namespace llvm;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// CGIOperandList Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
|
|
isPredicable = false;
|
|
hasOptionalDef = false;
|
|
isVariadic = false;
|
|
|
|
DagInit *OutDI = R->getValueAsDag("OutOperandList");
|
|
|
|
if (DefInit *Init = dyn_cast<DefInit>(OutDI->getOperator())) {
|
|
if (Init->getDef()->getName() != "outs")
|
|
PrintFatalError(R->getLoc(),
|
|
R->getName() +
|
|
": invalid def name for output list: use 'outs'");
|
|
} else
|
|
PrintFatalError(R->getLoc(),
|
|
R->getName() + ": invalid output list: use 'outs'");
|
|
|
|
NumDefs = OutDI->getNumArgs();
|
|
|
|
DagInit *InDI = R->getValueAsDag("InOperandList");
|
|
if (DefInit *Init = dyn_cast<DefInit>(InDI->getOperator())) {
|
|
if (Init->getDef()->getName() != "ins")
|
|
PrintFatalError(R->getLoc(),
|
|
R->getName() +
|
|
": invalid def name for input list: use 'ins'");
|
|
} else
|
|
PrintFatalError(R->getLoc(),
|
|
R->getName() + ": invalid input list: use 'ins'");
|
|
|
|
unsigned MIOperandNo = 0;
|
|
std::set<std::string> OperandNames;
|
|
unsigned e = InDI->getNumArgs() + OutDI->getNumArgs();
|
|
OperandList.reserve(e);
|
|
bool VariadicOuts = false;
|
|
for (unsigned i = 0; i != e; ++i){
|
|
Init *ArgInit;
|
|
StringRef ArgName;
|
|
if (i < NumDefs) {
|
|
ArgInit = OutDI->getArg(i);
|
|
ArgName = OutDI->getArgNameStr(i);
|
|
} else {
|
|
ArgInit = InDI->getArg(i-NumDefs);
|
|
ArgName = InDI->getArgNameStr(i-NumDefs);
|
|
}
|
|
|
|
DagInit *SubArgDag = dyn_cast<DagInit>(ArgInit);
|
|
if (SubArgDag)
|
|
ArgInit = SubArgDag->getOperator();
|
|
|
|
DefInit *Arg = dyn_cast<DefInit>(ArgInit);
|
|
if (!Arg)
|
|
PrintFatalError(R->getLoc(), "Illegal operand for the '" + R->getName() +
|
|
"' instruction!");
|
|
|
|
Record *Rec = Arg->getDef();
|
|
std::string PrintMethod = "printOperand";
|
|
std::string EncoderMethod;
|
|
std::string OperandType = "OPERAND_UNKNOWN";
|
|
std::string OperandNamespace = "MCOI";
|
|
unsigned NumOps = 1;
|
|
DagInit *MIOpInfo = nullptr;
|
|
if (Rec->isSubClassOf("RegisterOperand")) {
|
|
PrintMethod = std::string(Rec->getValueAsString("PrintMethod"));
|
|
OperandType = std::string(Rec->getValueAsString("OperandType"));
|
|
OperandNamespace = std::string(Rec->getValueAsString("OperandNamespace"));
|
|
EncoderMethod = std::string(Rec->getValueAsString("EncoderMethod"));
|
|
} else if (Rec->isSubClassOf("Operand")) {
|
|
PrintMethod = std::string(Rec->getValueAsString("PrintMethod"));
|
|
OperandType = std::string(Rec->getValueAsString("OperandType"));
|
|
OperandNamespace = std::string(Rec->getValueAsString("OperandNamespace"));
|
|
// If there is an explicit encoder method, use it.
|
|
EncoderMethod = std::string(Rec->getValueAsString("EncoderMethod"));
|
|
MIOpInfo = Rec->getValueAsDag("MIOperandInfo");
|
|
|
|
// Verify that MIOpInfo has an 'ops' root value.
|
|
if (!isa<DefInit>(MIOpInfo->getOperator()) ||
|
|
cast<DefInit>(MIOpInfo->getOperator())->getDef()->getName() != "ops")
|
|
PrintFatalError(R->getLoc(),
|
|
"Bad value for MIOperandInfo in operand '" +
|
|
Rec->getName() + "'\n");
|
|
|
|
// If we have MIOpInfo, then we have #operands equal to number of entries
|
|
// in MIOperandInfo.
|
|
if (unsigned NumArgs = MIOpInfo->getNumArgs())
|
|
NumOps = NumArgs;
|
|
|
|
if (Rec->isSubClassOf("PredicateOp"))
|
|
isPredicable = true;
|
|
else if (Rec->isSubClassOf("OptionalDefOperand"))
|
|
hasOptionalDef = true;
|
|
} else if (Rec->getName() == "variable_ops") {
|
|
if (i < NumDefs)
|
|
VariadicOuts = true;
|
|
isVariadic = true;
|
|
continue;
|
|
} else if (Rec->isSubClassOf("RegisterClass")) {
|
|
OperandType = "OPERAND_REGISTER";
|
|
} else if (!Rec->isSubClassOf("PointerLikeRegClass") &&
|
|
!Rec->isSubClassOf("unknown_class")) {
|
|
PrintFatalError(R->getLoc(), "Unknown operand class '" + Rec->getName() +
|
|
"' in '" + R->getName() +
|
|
"' instruction!");
|
|
}
|
|
|
|
// Check that the operand has a name and that it's unique.
|
|
if (ArgName.empty())
|
|
PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +
|
|
"', operand #" + Twine(i) +
|
|
" has no name!");
|
|
if (!OperandNames.insert(std::string(ArgName)).second)
|
|
PrintFatalError(R->getLoc(),
|
|
"In instruction '" + R->getName() + "', operand #" +
|
|
Twine(i) +
|
|
" has the same name as a previous operand!");
|
|
|
|
OperandInfo &OpInfo = OperandList.emplace_back(
|
|
Rec, std::string(ArgName), std::string(PrintMethod),
|
|
OperandNamespace + "::" + OperandType, MIOperandNo, NumOps, MIOpInfo);
|
|
|
|
if (SubArgDag) {
|
|
if (SubArgDag->getNumArgs() != NumOps) {
|
|
PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +
|
|
"', operand #" + Twine(i) + " has " +
|
|
Twine(SubArgDag->getNumArgs()) +
|
|
" sub-arg names, expected " +
|
|
Twine(NumOps) + ".");
|
|
}
|
|
|
|
for (unsigned j = 0; j < NumOps; ++j) {
|
|
if (!isa<UnsetInit>(SubArgDag->getArg(j)))
|
|
PrintFatalError(R->getLoc(),
|
|
"In instruction '" + R->getName() + "', operand #" +
|
|
Twine(i) + " sub-arg #" + Twine(j) +
|
|
" has unexpected operand (expected only $name).");
|
|
|
|
StringRef SubArgName = SubArgDag->getArgNameStr(j);
|
|
if (SubArgName.empty())
|
|
PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +
|
|
"', operand #" + Twine(i) +
|
|
" has no name!");
|
|
if (!OperandNames.insert(std::string(SubArgName)).second)
|
|
PrintFatalError(R->getLoc(),
|
|
"In instruction '" + R->getName() + "', operand #" +
|
|
Twine(i) + " sub-arg #" + Twine(j) +
|
|
" has the same name as a previous operand!");
|
|
|
|
if (auto MaybeEncoderMethod =
|
|
cast<DefInit>(MIOpInfo->getArg(j))
|
|
->getDef()
|
|
->getValueAsOptionalString("EncoderMethod")) {
|
|
OpInfo.EncoderMethodNames[j] = *MaybeEncoderMethod;
|
|
}
|
|
|
|
OpInfo.SubOpNames[j] = SubArgName;
|
|
SubOpAliases[SubArgName] = std::make_pair(i, j);
|
|
}
|
|
} else if (!EncoderMethod.empty()) {
|
|
// If we have no explicit sub-op dag, but have an top-level encoder
|
|
// method, the single encoder will multiple sub-ops, itself.
|
|
OpInfo.EncoderMethodNames[0] = EncoderMethod;
|
|
for (unsigned j = 1; j < NumOps; ++j)
|
|
OpInfo.DoNotEncode[j] = true;
|
|
}
|
|
|
|
MIOperandNo += NumOps;
|
|
}
|
|
|
|
if (VariadicOuts)
|
|
--NumDefs;
|
|
}
|
|
|
|
|
|
/// getOperandNamed - Return the index of the operand with the specified
|
|
/// non-empty name. If the instruction does not have an operand with the
|
|
/// specified name, abort.
|
|
///
|
|
unsigned CGIOperandList::getOperandNamed(StringRef Name) const {
|
|
unsigned OpIdx;
|
|
if (hasOperandNamed(Name, OpIdx))
|
|
return OpIdx;
|
|
PrintFatalError(TheDef->getLoc(), "'" + TheDef->getName() +
|
|
"' does not have an operand named '$" +
|
|
Name + "'!");
|
|
}
|
|
|
|
/// hasOperandNamed - Query whether the instruction has an operand of the
|
|
/// given name. If so, return true and set OpIdx to the index of the
|
|
/// operand. Otherwise, return false.
|
|
bool CGIOperandList::hasOperandNamed(StringRef Name, unsigned &OpIdx) const {
|
|
assert(!Name.empty() && "Cannot search for operand with no name!");
|
|
for (unsigned i = 0, e = OperandList.size(); i != e; ++i)
|
|
if (OperandList[i].Name == Name) {
|
|
OpIdx = i;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CGIOperandList::hasSubOperandAlias(
|
|
StringRef Name, std::pair<unsigned, unsigned> &SubOp) const {
|
|
assert(!Name.empty() && "Cannot search for operand with no name!");
|
|
auto SubOpIter = SubOpAliases.find(Name);
|
|
if (SubOpIter != SubOpAliases.end()) {
|
|
SubOp = SubOpIter->second;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::pair<unsigned,unsigned>
|
|
CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
|
|
if (Op.empty() || Op[0] != '$')
|
|
PrintFatalError(TheDef->getLoc(),
|
|
TheDef->getName() + ": Illegal operand name: '" + Op + "'");
|
|
|
|
StringRef OpName = Op.substr(1);
|
|
StringRef SubOpName;
|
|
|
|
// Check to see if this is $foo.bar.
|
|
StringRef::size_type DotIdx = OpName.find_first_of('.');
|
|
if (DotIdx != StringRef::npos) {
|
|
SubOpName = OpName.substr(DotIdx+1);
|
|
if (SubOpName.empty())
|
|
PrintFatalError(TheDef->getLoc(),
|
|
TheDef->getName() +
|
|
": illegal empty suboperand name in '" + Op + "'");
|
|
OpName = OpName.substr(0, DotIdx);
|
|
}
|
|
|
|
unsigned OpIdx;
|
|
|
|
if (std::pair<unsigned, unsigned> SubOp; hasSubOperandAlias(OpName, SubOp)) {
|
|
// Found a name for a piece of an operand, just return it directly.
|
|
if (!SubOpName.empty()) {
|
|
PrintFatalError(
|
|
TheDef->getLoc(),
|
|
TheDef->getName() +
|
|
": Cannot use dotted suboperand name within suboperand '" +
|
|
OpName + "'");
|
|
}
|
|
return SubOp;
|
|
}
|
|
|
|
OpIdx = getOperandNamed(OpName);
|
|
|
|
if (SubOpName.empty()) { // If no suboperand name was specified:
|
|
// If one was needed, throw.
|
|
if (OperandList[OpIdx].MINumOperands > 1 && !AllowWholeOp &&
|
|
SubOpName.empty())
|
|
PrintFatalError(TheDef->getLoc(),
|
|
TheDef->getName() +
|
|
": Illegal to refer to"
|
|
" whole operand part of complex operand '" +
|
|
Op + "'");
|
|
|
|
// Otherwise, return the operand.
|
|
return std::make_pair(OpIdx, 0U);
|
|
}
|
|
|
|
// Find the suboperand number involved.
|
|
DagInit *MIOpInfo = OperandList[OpIdx].MIOperandInfo;
|
|
if (!MIOpInfo)
|
|
PrintFatalError(TheDef->getLoc(), TheDef->getName() +
|
|
": unknown suboperand name in '" +
|
|
Op + "'");
|
|
|
|
// Find the operand with the right name.
|
|
for (unsigned i = 0, e = MIOpInfo->getNumArgs(); i != e; ++i)
|
|
if (MIOpInfo->getArgNameStr(i) == SubOpName)
|
|
return std::make_pair(OpIdx, i);
|
|
|
|
// Otherwise, didn't find it!
|
|
PrintFatalError(TheDef->getLoc(), TheDef->getName() +
|
|
": unknown suboperand name in '" + Op +
|
|
"'");
|
|
return std::make_pair(0U, 0U);
|
|
}
|
|
|
|
static void ParseConstraint(StringRef CStr, CGIOperandList &Ops,
|
|
Record *Rec) {
|
|
// EARLY_CLOBBER: @early $reg
|
|
StringRef::size_type wpos = CStr.find_first_of(" \t");
|
|
StringRef::size_type start = CStr.find_first_not_of(" \t");
|
|
StringRef Tok = CStr.substr(start, wpos - start);
|
|
if (Tok == "@earlyclobber") {
|
|
StringRef Name = CStr.substr(wpos+1);
|
|
wpos = Name.find_first_not_of(" \t");
|
|
if (wpos == StringRef::npos)
|
|
PrintFatalError(
|
|
Rec->getLoc(), "Illegal format for @earlyclobber constraint in '" +
|
|
Rec->getName() + "': '" + CStr + "'");
|
|
Name = Name.substr(wpos);
|
|
std::pair<unsigned,unsigned> Op = Ops.ParseOperandName(Name, false);
|
|
|
|
// Build the string for the operand
|
|
if (!Ops[Op.first].Constraints[Op.second].isNone())
|
|
PrintFatalError(
|
|
Rec->getLoc(), "Operand '" + Name + "' of '" + Rec->getName() +
|
|
"' cannot have multiple constraints!");
|
|
Ops[Op.first].Constraints[Op.second] =
|
|
CGIOperandList::ConstraintInfo::getEarlyClobber();
|
|
return;
|
|
}
|
|
|
|
// Only other constraint is "TIED_TO" for now.
|
|
StringRef::size_type pos = CStr.find_first_of('=');
|
|
if (pos == StringRef::npos)
|
|
PrintFatalError(
|
|
Rec->getLoc(), "Unrecognized constraint '" + CStr +
|
|
"' in '" + Rec->getName() + "'");
|
|
start = CStr.find_first_not_of(" \t");
|
|
|
|
// TIED_TO: $src1 = $dst
|
|
wpos = CStr.find_first_of(" \t", start);
|
|
if (wpos == StringRef::npos || wpos > pos)
|
|
PrintFatalError(
|
|
Rec->getLoc(), "Illegal format for tied-to constraint in '" +
|
|
Rec->getName() + "': '" + CStr + "'");
|
|
StringRef LHSOpName = CStr.substr(start, wpos - start);
|
|
std::pair<unsigned,unsigned> LHSOp = Ops.ParseOperandName(LHSOpName, false);
|
|
|
|
wpos = CStr.find_first_not_of(" \t", pos + 1);
|
|
if (wpos == StringRef::npos)
|
|
PrintFatalError(
|
|
Rec->getLoc(), "Illegal format for tied-to constraint: '" + CStr + "'");
|
|
|
|
StringRef RHSOpName = CStr.substr(wpos);
|
|
std::pair<unsigned,unsigned> RHSOp = Ops.ParseOperandName(RHSOpName, false);
|
|
|
|
// Sort the operands into order, which should put the output one
|
|
// first. But keep the original order, for use in diagnostics.
|
|
bool FirstIsDest = (LHSOp < RHSOp);
|
|
std::pair<unsigned,unsigned> DestOp = (FirstIsDest ? LHSOp : RHSOp);
|
|
StringRef DestOpName = (FirstIsDest ? LHSOpName : RHSOpName);
|
|
std::pair<unsigned,unsigned> SrcOp = (FirstIsDest ? RHSOp : LHSOp);
|
|
StringRef SrcOpName = (FirstIsDest ? RHSOpName : LHSOpName);
|
|
|
|
// Ensure one operand is a def and the other is a use.
|
|
if (DestOp.first >= Ops.NumDefs)
|
|
PrintFatalError(
|
|
Rec->getLoc(), "Input operands '" + LHSOpName + "' and '" + RHSOpName +
|
|
"' of '" + Rec->getName() + "' cannot be tied!");
|
|
if (SrcOp.first < Ops.NumDefs)
|
|
PrintFatalError(
|
|
Rec->getLoc(), "Output operands '" + LHSOpName + "' and '" + RHSOpName +
|
|
"' of '" + Rec->getName() + "' cannot be tied!");
|
|
|
|
// The constraint has to go on the operand with higher index, i.e.
|
|
// the source one. Check there isn't another constraint there
|
|
// already.
|
|
if (!Ops[SrcOp.first].Constraints[SrcOp.second].isNone())
|
|
PrintFatalError(
|
|
Rec->getLoc(), "Operand '" + SrcOpName + "' of '" + Rec->getName() +
|
|
"' cannot have multiple constraints!");
|
|
|
|
unsigned DestFlatOpNo = Ops.getFlattenedOperandNumber(DestOp);
|
|
auto NewConstraint = CGIOperandList::ConstraintInfo::getTied(DestFlatOpNo);
|
|
|
|
// Check that the earlier operand is not the target of another tie
|
|
// before making it the target of this one.
|
|
for (const CGIOperandList::OperandInfo &Op : Ops) {
|
|
for (unsigned i = 0; i < Op.MINumOperands; i++)
|
|
if (Op.Constraints[i] == NewConstraint)
|
|
PrintFatalError(
|
|
Rec->getLoc(), "Operand '" + DestOpName + "' of '" + Rec->getName() +
|
|
"' cannot have multiple operands tied to it!");
|
|
}
|
|
|
|
Ops[SrcOp.first].Constraints[SrcOp.second] = NewConstraint;
|
|
}
|
|
|
|
static void ParseConstraints(StringRef CStr, CGIOperandList &Ops, Record *Rec) {
|
|
if (CStr.empty()) return;
|
|
|
|
StringRef delims(",");
|
|
StringRef::size_type bidx, eidx;
|
|
|
|
bidx = CStr.find_first_not_of(delims);
|
|
while (bidx != StringRef::npos) {
|
|
eidx = CStr.find_first_of(delims, bidx);
|
|
if (eidx == StringRef::npos)
|
|
eidx = CStr.size();
|
|
|
|
ParseConstraint(CStr.substr(bidx, eidx - bidx), Ops, Rec);
|
|
bidx = CStr.find_first_not_of(delims, eidx);
|
|
}
|
|
}
|
|
|
|
void CGIOperandList::ProcessDisableEncoding(StringRef DisableEncoding) {
|
|
while (true) {
|
|
StringRef OpName;
|
|
std::tie(OpName, DisableEncoding) = getToken(DisableEncoding, " ,\t");
|
|
if (OpName.empty()) break;
|
|
|
|
// Figure out which operand this is.
|
|
std::pair<unsigned,unsigned> Op = ParseOperandName(OpName, false);
|
|
|
|
// Mark the operand as not-to-be encoded.
|
|
OperandList[Op.first].DoNotEncode[Op.second] = true;
|
|
}
|
|
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// CodeGenInstruction Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
CodeGenInstruction::CodeGenInstruction(Record *R)
|
|
: TheDef(R), Operands(R), InferredFrom(nullptr) {
|
|
Namespace = R->getValueAsString("Namespace");
|
|
AsmString = std::string(R->getValueAsString("AsmString"));
|
|
|
|
isPreISelOpcode = R->getValueAsBit("isPreISelOpcode");
|
|
isReturn = R->getValueAsBit("isReturn");
|
|
isEHScopeReturn = R->getValueAsBit("isEHScopeReturn");
|
|
isBranch = R->getValueAsBit("isBranch");
|
|
isIndirectBranch = R->getValueAsBit("isIndirectBranch");
|
|
isCompare = R->getValueAsBit("isCompare");
|
|
isMoveImm = R->getValueAsBit("isMoveImm");
|
|
isMoveReg = R->getValueAsBit("isMoveReg");
|
|
isBitcast = R->getValueAsBit("isBitcast");
|
|
isSelect = R->getValueAsBit("isSelect");
|
|
isBarrier = R->getValueAsBit("isBarrier");
|
|
isCall = R->getValueAsBit("isCall");
|
|
isAdd = R->getValueAsBit("isAdd");
|
|
isTrap = R->getValueAsBit("isTrap");
|
|
canFoldAsLoad = R->getValueAsBit("canFoldAsLoad");
|
|
isPredicable = !R->getValueAsBit("isUnpredicable") && (
|
|
Operands.isPredicable || R->getValueAsBit("isPredicable"));
|
|
isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress");
|
|
isCommutable = R->getValueAsBit("isCommutable");
|
|
isTerminator = R->getValueAsBit("isTerminator");
|
|
isReMaterializable = R->getValueAsBit("isReMaterializable");
|
|
hasDelaySlot = R->getValueAsBit("hasDelaySlot");
|
|
usesCustomInserter = R->getValueAsBit("usesCustomInserter");
|
|
hasPostISelHook = R->getValueAsBit("hasPostISelHook");
|
|
hasCtrlDep = R->getValueAsBit("hasCtrlDep");
|
|
isNotDuplicable = R->getValueAsBit("isNotDuplicable");
|
|
isRegSequence = R->getValueAsBit("isRegSequence");
|
|
isExtractSubreg = R->getValueAsBit("isExtractSubreg");
|
|
isInsertSubreg = R->getValueAsBit("isInsertSubreg");
|
|
isConvergent = R->getValueAsBit("isConvergent");
|
|
hasNoSchedulingInfo = R->getValueAsBit("hasNoSchedulingInfo");
|
|
FastISelShouldIgnore = R->getValueAsBit("FastISelShouldIgnore");
|
|
variadicOpsAreDefs = R->getValueAsBit("variadicOpsAreDefs");
|
|
isAuthenticated = R->getValueAsBit("isAuthenticated");
|
|
|
|
bool Unset;
|
|
mayLoad = R->getValueAsBitOrUnset("mayLoad", Unset);
|
|
mayLoad_Unset = Unset;
|
|
mayStore = R->getValueAsBitOrUnset("mayStore", Unset);
|
|
mayStore_Unset = Unset;
|
|
mayRaiseFPException = R->getValueAsBit("mayRaiseFPException");
|
|
hasSideEffects = R->getValueAsBitOrUnset("hasSideEffects", Unset);
|
|
hasSideEffects_Unset = Unset;
|
|
|
|
isAsCheapAsAMove = R->getValueAsBit("isAsCheapAsAMove");
|
|
hasExtraSrcRegAllocReq = R->getValueAsBit("hasExtraSrcRegAllocReq");
|
|
hasExtraDefRegAllocReq = R->getValueAsBit("hasExtraDefRegAllocReq");
|
|
isCodeGenOnly = R->getValueAsBit("isCodeGenOnly");
|
|
isPseudo = R->getValueAsBit("isPseudo");
|
|
isMeta = R->getValueAsBit("isMeta");
|
|
ImplicitDefs = R->getValueAsListOfDefs("Defs");
|
|
ImplicitUses = R->getValueAsListOfDefs("Uses");
|
|
|
|
// This flag is only inferred from the pattern.
|
|
hasChain = false;
|
|
hasChain_Inferred = false;
|
|
|
|
// Parse Constraints.
|
|
ParseConstraints(R->getValueAsString("Constraints"), Operands, R);
|
|
|
|
// Parse the DisableEncoding field.
|
|
Operands.ProcessDisableEncoding(
|
|
R->getValueAsString("DisableEncoding"));
|
|
|
|
// First check for a ComplexDeprecationPredicate.
|
|
if (R->getValue("ComplexDeprecationPredicate")) {
|
|
HasComplexDeprecationPredicate = true;
|
|
DeprecatedReason =
|
|
std::string(R->getValueAsString("ComplexDeprecationPredicate"));
|
|
} else if (RecordVal *Dep = R->getValue("DeprecatedFeatureMask")) {
|
|
// Check if we have a Subtarget feature mask.
|
|
HasComplexDeprecationPredicate = false;
|
|
DeprecatedReason = Dep->getValue()->getAsString();
|
|
} else {
|
|
// This instruction isn't deprecated.
|
|
HasComplexDeprecationPredicate = false;
|
|
DeprecatedReason = "";
|
|
}
|
|
}
|
|
|
|
/// HasOneImplicitDefWithKnownVT - If the instruction has at least one
|
|
/// implicit def and it has a known VT, return the VT, otherwise return
|
|
/// MVT::Other.
|
|
MVT::SimpleValueType CodeGenInstruction::
|
|
HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const {
|
|
if (ImplicitDefs.empty()) return MVT::Other;
|
|
|
|
// Check to see if the first implicit def has a resolvable type.
|
|
Record *FirstImplicitDef = ImplicitDefs[0];
|
|
assert(FirstImplicitDef->isSubClassOf("Register"));
|
|
const std::vector<ValueTypeByHwMode> &RegVTs =
|
|
TargetInfo.getRegisterVTs(FirstImplicitDef);
|
|
if (RegVTs.size() == 1 && RegVTs[0].isSimple())
|
|
return RegVTs[0].getSimple().SimpleTy;
|
|
return MVT::Other;
|
|
}
|
|
|
|
|
|
/// FlattenAsmStringVariants - Flatten the specified AsmString to only
|
|
/// include text from the specified variant, returning the new string.
|
|
std::string CodeGenInstruction::
|
|
FlattenAsmStringVariants(StringRef Cur, unsigned Variant) {
|
|
std::string Res;
|
|
|
|
for (;;) {
|
|
// Find the start of the next variant string.
|
|
size_t VariantsStart = 0;
|
|
for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart)
|
|
if (Cur[VariantsStart] == '{' &&
|
|
(VariantsStart == 0 || (Cur[VariantsStart-1] != '$' &&
|
|
Cur[VariantsStart-1] != '\\')))
|
|
break;
|
|
|
|
// Add the prefix to the result.
|
|
Res += Cur.slice(0, VariantsStart);
|
|
if (VariantsStart == Cur.size())
|
|
break;
|
|
|
|
++VariantsStart; // Skip the '{'.
|
|
|
|
// Scan to the end of the variants string.
|
|
size_t VariantsEnd = VariantsStart;
|
|
unsigned NestedBraces = 1;
|
|
for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) {
|
|
if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd-1] != '\\') {
|
|
if (--NestedBraces == 0)
|
|
break;
|
|
} else if (Cur[VariantsEnd] == '{')
|
|
++NestedBraces;
|
|
}
|
|
|
|
// Select the Nth variant (or empty).
|
|
StringRef Selection = Cur.slice(VariantsStart, VariantsEnd);
|
|
for (unsigned i = 0; i != Variant; ++i)
|
|
Selection = Selection.split('|').second;
|
|
Res += Selection.split('|').first;
|
|
|
|
assert(VariantsEnd != Cur.size() &&
|
|
"Unterminated variants in assembly string!");
|
|
Cur = Cur.substr(VariantsEnd + 1);
|
|
}
|
|
|
|
return Res;
|
|
}
|
|
|
|
bool CodeGenInstruction::isOperandImpl(StringRef OpListName, unsigned i,
|
|
StringRef PropertyName) const {
|
|
DagInit *ConstraintList = TheDef->getValueAsDag(OpListName);
|
|
if (!ConstraintList || i >= ConstraintList->getNumArgs())
|
|
return false;
|
|
|
|
DefInit *Constraint = dyn_cast<DefInit>(ConstraintList->getArg(i));
|
|
if (!Constraint)
|
|
return false;
|
|
|
|
return Constraint->getDef()->isSubClassOf("TypedOperand") &&
|
|
Constraint->getDef()->getValueAsBit(PropertyName);
|
|
}
|