forked from OSchip/llvm-project
take a big step to making aliases more general and less of a hack:
now matchables contain an explicit list of how to populate each operand in the result instruction instead of having them somehow magically be correlated to the input inst. llvm-svn: 118217
This commit is contained in:
parent
a2e098df12
commit
743081d097
|
@ -81,7 +81,6 @@
|
||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include <list>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
@ -259,6 +258,55 @@ struct MatchableInfo {
|
||||||
explicit AsmOperand(StringRef T) : Token(T), Class(0), OperandInfo(0) {}
|
explicit AsmOperand(StringRef T) : Token(T), Class(0), OperandInfo(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// ResOperand - This represents a single operand in the result instruction
|
||||||
|
/// generated by the match. In cases (like addressing modes) where a single
|
||||||
|
/// assembler operand expands to multiple MCOperands, this represents the
|
||||||
|
/// single assembler operand, not the MCOperand.
|
||||||
|
struct ResOperand {
|
||||||
|
enum {
|
||||||
|
/// RenderAsmOperand - This represents an operand result that is
|
||||||
|
/// generated by calling the render method on the assembly operand. The
|
||||||
|
/// corresponding AsmOperand is specified by AsmOperandNum.
|
||||||
|
RenderAsmOperand,
|
||||||
|
|
||||||
|
/// TiedOperand - This represents a result operand that is a duplicate of
|
||||||
|
/// a previous result operand.
|
||||||
|
TiedOperand
|
||||||
|
} Kind;
|
||||||
|
|
||||||
|
union {
|
||||||
|
/// This is the operand # in the AsmOperands list that this should be
|
||||||
|
/// copied from.
|
||||||
|
unsigned AsmOperandNum;
|
||||||
|
|
||||||
|
/// TiedOperandNum - This is the (earlier) result operand that should be
|
||||||
|
/// copied from.
|
||||||
|
unsigned TiedOperandNum;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// OpInfo - This is the information about the instruction operand that is
|
||||||
|
/// being populated.
|
||||||
|
const CGIOperandList::OperandInfo *OpInfo;
|
||||||
|
|
||||||
|
static ResOperand getRenderedOp(unsigned AsmOpNum,
|
||||||
|
const CGIOperandList::OperandInfo *Op) {
|
||||||
|
ResOperand X;
|
||||||
|
X.Kind = RenderAsmOperand;
|
||||||
|
X.AsmOperandNum = AsmOpNum;
|
||||||
|
X.OpInfo = Op;
|
||||||
|
return X;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ResOperand getTiedOp(unsigned TiedOperandNum,
|
||||||
|
const CGIOperandList::OperandInfo *Op) {
|
||||||
|
ResOperand X;
|
||||||
|
X.Kind = TiedOperand;
|
||||||
|
X.TiedOperandNum = TiedOperandNum;
|
||||||
|
X.OpInfo = Op;
|
||||||
|
return X;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// InstrName - The target name for this instruction.
|
/// InstrName - The target name for this instruction.
|
||||||
std::string InstrName;
|
std::string InstrName;
|
||||||
|
|
||||||
|
@ -266,9 +314,13 @@ struct MatchableInfo {
|
||||||
/// matchable came from.
|
/// matchable came from.
|
||||||
Record *const TheDef;
|
Record *const TheDef;
|
||||||
|
|
||||||
/// OperandList - This is the operand list that came from the (ins) and (outs)
|
// FIXME: REMOVE.
|
||||||
/// list of the alias or instruction.
|
const CGIOperandList &TheOperandList;
|
||||||
const CGIOperandList &OperandList;
|
|
||||||
|
|
||||||
|
/// ResOperands - This is the operand list that should be built for the result
|
||||||
|
/// MCInst.
|
||||||
|
std::vector<ResOperand> ResOperands;
|
||||||
|
|
||||||
/// AsmString - The assembly string for this instruction (with variants
|
/// AsmString - The assembly string for this instruction (with variants
|
||||||
/// removed), e.g. "movsx $src, $dst".
|
/// removed), e.g. "movsx $src, $dst".
|
||||||
|
@ -293,12 +345,12 @@ struct MatchableInfo {
|
||||||
std::string ConversionFnKind;
|
std::string ConversionFnKind;
|
||||||
|
|
||||||
MatchableInfo(const CodeGenInstruction &CGI)
|
MatchableInfo(const CodeGenInstruction &CGI)
|
||||||
: TheDef(CGI.TheDef), OperandList(CGI.Operands), AsmString(CGI.AsmString) {
|
: TheDef(CGI.TheDef), TheOperandList(CGI.Operands), AsmString(CGI.AsmString) {
|
||||||
InstrName = TheDef->getName();
|
InstrName = TheDef->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchableInfo(const CodeGenInstAlias *Alias)
|
MatchableInfo(const CodeGenInstAlias *Alias)
|
||||||
: TheDef(Alias->TheDef), OperandList(Alias->Operands),
|
: TheDef(Alias->TheDef), TheOperandList(Alias->Operands),
|
||||||
AsmString(Alias->AsmString) {
|
AsmString(Alias->AsmString) {
|
||||||
|
|
||||||
// FIXME: Huge hack.
|
// FIXME: Huge hack.
|
||||||
|
@ -320,6 +372,8 @@ struct MatchableInfo {
|
||||||
Record *getSingletonRegisterForAsmOperand(unsigned i,
|
Record *getSingletonRegisterForAsmOperand(unsigned i,
|
||||||
const AsmMatcherInfo &Info) const;
|
const AsmMatcherInfo &Info) const;
|
||||||
|
|
||||||
|
void BuildResultOperands();
|
||||||
|
|
||||||
/// operator< - Compare two matchables.
|
/// operator< - Compare two matchables.
|
||||||
bool operator<(const MatchableInfo &RHS) const {
|
bool operator<(const MatchableInfo &RHS) const {
|
||||||
// The primary comparator is the instruction mnemonic.
|
// The primary comparator is the instruction mnemonic.
|
||||||
|
@ -452,6 +506,9 @@ private:
|
||||||
/// operand classes.
|
/// operand classes.
|
||||||
void BuildOperandClasses();
|
void BuildOperandClasses();
|
||||||
|
|
||||||
|
void BuildInstructionOperandReference(MatchableInfo *II,
|
||||||
|
MatchableInfo::AsmOperand &Op);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AsmMatcherInfo(Record *AsmParser, CodeGenTarget &Target);
|
AsmMatcherInfo(Record *AsmParser, CodeGenTarget &Target);
|
||||||
|
|
||||||
|
@ -652,33 +709,6 @@ bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the operand list to ensure we can handle this instruction.
|
|
||||||
for (unsigned i = 0, e = OperandList.size(); i != e; ++i) {
|
|
||||||
const CGIOperandList::OperandInfo &OI = OperandList[i];
|
|
||||||
|
|
||||||
// Validate tied operands.
|
|
||||||
if (OI.getTiedRegister() != -1) {
|
|
||||||
// If we have a tied operand that consists of multiple MCOperands, reject
|
|
||||||
// it. We reject aliases and ignore instructions for now.
|
|
||||||
if (OI.MINumOperands != 1) {
|
|
||||||
if (!Hack)
|
|
||||||
throw TGError(TheDef->getLoc(),
|
|
||||||
"ERROR: tied operand '" + OI.Name +
|
|
||||||
"' has multiple MCOperands!");
|
|
||||||
|
|
||||||
// FIXME: Should reject these. The ARM backend hits this with $lane in a
|
|
||||||
// bunch of instructions. It is unclear what the right answer is.
|
|
||||||
DEBUG({
|
|
||||||
errs() << "warning: '" << InstrName << "': "
|
|
||||||
<< "ignoring instruction with multi-operand tied operand '"
|
|
||||||
<< OI.Name << "'\n";
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -944,6 +974,52 @@ AsmMatcherInfo::AsmMatcherInfo(Record *asmParser, CodeGenTarget &target)
|
||||||
RegisterPrefix(AsmParser->getValueAsString("RegisterPrefix")) {
|
RegisterPrefix(AsmParser->getValueAsString("RegisterPrefix")) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// BuildInstructionOperandReference - The specified operand is a reference to a
|
||||||
|
/// named operand such as $src. Resolve the Class and OperandInfo pointers.
|
||||||
|
void AsmMatcherInfo::
|
||||||
|
BuildInstructionOperandReference(MatchableInfo *II,
|
||||||
|
MatchableInfo::AsmOperand &Op) {
|
||||||
|
StringRef Token = Op.Token;
|
||||||
|
assert(Token[0] == '$' && "Not an operand name ref");
|
||||||
|
|
||||||
|
StringRef OperandName;
|
||||||
|
if (Token[1] == '{')
|
||||||
|
OperandName = Token.substr(2, Token.size() - 3);
|
||||||
|
else
|
||||||
|
OperandName = Token.substr(1);
|
||||||
|
|
||||||
|
const CGIOperandList &Operands = II->TheOperandList;
|
||||||
|
|
||||||
|
|
||||||
|
// Map this token to an operand. FIXME: Move elsewhere.
|
||||||
|
unsigned Idx;
|
||||||
|
if (!Operands.hasOperandNamed(OperandName, Idx))
|
||||||
|
throw TGError(II->TheDef->getLoc(), "error: unable to find operand: '" +
|
||||||
|
OperandName.str() + "'");
|
||||||
|
|
||||||
|
// FIXME: This is annoying, the named operand may be tied (e.g.,
|
||||||
|
// XCHG8rm). What we want is the untied operand, which we now have to
|
||||||
|
// grovel for. Only worry about this for single entry operands, we have to
|
||||||
|
// clean this up anyway.
|
||||||
|
const CGIOperandList::OperandInfo *OI = &Operands[Idx];
|
||||||
|
int OITied = OI->getTiedRegister();
|
||||||
|
if (OITied != -1) {
|
||||||
|
// The tied operand index is an MIOperand index, find the operand that
|
||||||
|
// contains it.
|
||||||
|
for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
|
||||||
|
if (Operands[i].MIOperandNo == unsigned(OITied)) {
|
||||||
|
OI = &Operands[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(OI && "Unable to find tied operand target!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Op.Class = getOperandClass(Token, *OI);
|
||||||
|
Op.OperandInfo = OI;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AsmMatcherInfo::BuildInfo() {
|
void AsmMatcherInfo::BuildInfo() {
|
||||||
// Build information about all of the AssemblerPredicates.
|
// Build information about all of the AssemblerPredicates.
|
||||||
|
@ -981,6 +1057,27 @@ void AsmMatcherInfo::BuildInfo() {
|
||||||
if (CGI.TheDef->getValueAsBit("isCodeGenOnly"))
|
if (CGI.TheDef->getValueAsBit("isCodeGenOnly"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Validate the operand list to ensure we can handle this instruction.
|
||||||
|
for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) {
|
||||||
|
const CGIOperandList::OperandInfo &OI = CGI.Operands[i];
|
||||||
|
|
||||||
|
// Validate tied operands.
|
||||||
|
if (OI.getTiedRegister() != -1) {
|
||||||
|
// If we have a tied operand that consists of multiple MCOperands, reject
|
||||||
|
// it. We reject aliases and ignore instructions for now.
|
||||||
|
if (OI.MINumOperands != 1) {
|
||||||
|
// FIXME: Should reject these. The ARM backend hits this with $lane
|
||||||
|
// in a bunch of instructions. It is unclear what the right answer is.
|
||||||
|
DEBUG({
|
||||||
|
errs() << "warning: '" << CGI.TheDef->getName() << "': "
|
||||||
|
<< "ignoring instruction with multi-operand tied operand '"
|
||||||
|
<< OI.Name << "'\n";
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OwningPtr<MatchableInfo> II(new MatchableInfo(CGI));
|
OwningPtr<MatchableInfo> II(new MatchableInfo(CGI));
|
||||||
|
|
||||||
II->Initialize(*this, SingletonRegisters);
|
II->Initialize(*this, SingletonRegisters);
|
||||||
|
@ -1048,46 +1145,56 @@ void AsmMatcherInfo::BuildInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise this is an operand reference.
|
// Otherwise this is an operand reference.
|
||||||
StringRef OperandName;
|
BuildInstructionOperandReference(II, Op);
|
||||||
if (Token[1] == '{')
|
|
||||||
OperandName = Token.substr(2, Token.size() - 3);
|
|
||||||
else
|
|
||||||
OperandName = Token.substr(1);
|
|
||||||
|
|
||||||
// Map this token to an operand. FIXME: Move elsewhere.
|
|
||||||
unsigned Idx;
|
|
||||||
if (!II->OperandList.hasOperandNamed(OperandName, Idx))
|
|
||||||
throw TGError(II->TheDef->getLoc(), "error: unable to find operand: '" +
|
|
||||||
OperandName.str() + "'");
|
|
||||||
|
|
||||||
// FIXME: This is annoying, the named operand may be tied (e.g.,
|
|
||||||
// XCHG8rm). What we want is the untied operand, which we now have to
|
|
||||||
// grovel for. Only worry about this for single entry operands, we have to
|
|
||||||
// clean this up anyway.
|
|
||||||
const CGIOperandList::OperandInfo *OI = &II->OperandList[Idx];
|
|
||||||
int OITied = OI->getTiedRegister();
|
|
||||||
if (OITied != -1) {
|
|
||||||
// The tied operand index is an MIOperand index, find the operand that
|
|
||||||
// contains it.
|
|
||||||
for (unsigned i = 0, e = II->OperandList.size(); i != e; ++i) {
|
|
||||||
if (II->OperandList[i].MIOperandNo == unsigned(OITied)) {
|
|
||||||
OI = &II->OperandList[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(OI && "Unable to find tied operand target!");
|
II->BuildResultOperands();
|
||||||
}
|
|
||||||
|
|
||||||
Op.Class = getOperandClass(Token, *OI);
|
|
||||||
Op.OperandInfo = OI;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reorder classes so that classes preceed super classes.
|
// Reorder classes so that classes preceed super classes.
|
||||||
std::sort(Classes.begin(), Classes.end(), less_ptr<ClassInfo>());
|
std::sort(Classes.begin(), Classes.end(), less_ptr<ClassInfo>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MatchableInfo::BuildResultOperands() {
|
||||||
|
/// OperandMap - This is a mapping from the MCInst operands (specified by the
|
||||||
|
/// II.OperandList operands) to the AsmOperands that they are filled in from.
|
||||||
|
SmallVector<int, 16> OperandMap(TheOperandList.size(), -1);
|
||||||
|
|
||||||
|
// Order the (class) operands by the order to convert them into an MCInst.
|
||||||
|
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
|
||||||
|
MatchableInfo::AsmOperand &Op = AsmOperands[i];
|
||||||
|
if (!Op.OperandInfo) continue;
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: eliminate the mapping+unmapping.
|
||||||
|
unsigned LogicalOpNum = Op.OperandInfo - &TheOperandList[0];
|
||||||
|
assert(LogicalOpNum < OperandMap.size() && "Invalid operand number");
|
||||||
|
OperandMap[LogicalOpNum] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0, e = TheOperandList.size(); i != e; ++i) {
|
||||||
|
const CGIOperandList::OperandInfo &OpInfo = TheOperandList[i];
|
||||||
|
|
||||||
|
// Find out what operand from the asmparser that this MCInst operand comes
|
||||||
|
// from.
|
||||||
|
int SrcOperand = OperandMap[i];
|
||||||
|
if (SrcOperand != -1) {
|
||||||
|
ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, &OpInfo));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, this must be a tied operand.
|
||||||
|
int TiedOp = OpInfo.getTiedRegister();
|
||||||
|
if (TiedOp == -1)
|
||||||
|
throw TGError(TheDef->getLoc(), "Instruction '" +
|
||||||
|
TheDef->getName() + "' has operand '" + OpInfo.Name +
|
||||||
|
"' that doesn't appear in asm string!");
|
||||||
|
|
||||||
|
ResOperands.push_back(ResOperand::getTiedOp(TiedOp, &OpInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void EmitConvertToMCInst(CodeGenTarget &Target,
|
static void EmitConvertToMCInst(CodeGenTarget &Target,
|
||||||
std::vector<MatchableInfo*> &Infos,
|
std::vector<MatchableInfo*> &Infos,
|
||||||
raw_ostream &OS) {
|
raw_ostream &OS) {
|
||||||
|
@ -1100,7 +1207,6 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
|
||||||
std::set<std::string> GeneratedFns;
|
std::set<std::string> GeneratedFns;
|
||||||
|
|
||||||
// Start the unified conversion function.
|
// Start the unified conversion function.
|
||||||
|
|
||||||
CvtOS << "static void ConvertToMCInst(ConversionKind Kind, MCInst &Inst, "
|
CvtOS << "static void ConvertToMCInst(ConversionKind Kind, MCInst &Inst, "
|
||||||
<< "unsigned Opcode,\n"
|
<< "unsigned Opcode,\n"
|
||||||
<< " const SmallVectorImpl<MCParsedAsmOperand*"
|
<< " const SmallVectorImpl<MCParsedAsmOperand*"
|
||||||
|
@ -1117,42 +1223,25 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
|
||||||
// TargetOperandClass - This is the target's operand class, like X86Operand.
|
// TargetOperandClass - This is the target's operand class, like X86Operand.
|
||||||
std::string TargetOperandClass = Target.getName() + "Operand";
|
std::string TargetOperandClass = Target.getName() + "Operand";
|
||||||
|
|
||||||
/// OperandMap - This is a mapping from the MCInst operands (specified by the
|
|
||||||
/// II.OperandList operands) to the AsmOperands that they filled in from.
|
|
||||||
SmallVector<int, 16> OperandMap;
|
|
||||||
|
|
||||||
for (std::vector<MatchableInfo*>::const_iterator it = Infos.begin(),
|
for (std::vector<MatchableInfo*>::const_iterator it = Infos.begin(),
|
||||||
ie = Infos.end(); it != ie; ++it) {
|
ie = Infos.end(); it != ie; ++it) {
|
||||||
MatchableInfo &II = **it;
|
MatchableInfo &II = **it;
|
||||||
|
|
||||||
OperandMap.clear();
|
|
||||||
OperandMap.resize(II.OperandList.size(), -1);
|
|
||||||
|
|
||||||
// Order the (class) operands by the order to convert them into an MCInst.
|
|
||||||
for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) {
|
|
||||||
MatchableInfo::AsmOperand &Op = II.AsmOperands[i];
|
|
||||||
if (!Op.OperandInfo) continue;
|
|
||||||
|
|
||||||
unsigned LogicalOpNum = Op.OperandInfo - &II.OperandList[0];
|
|
||||||
assert(LogicalOpNum < OperandMap.size() && "Invalid operand number");
|
|
||||||
OperandMap[LogicalOpNum] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the conversion function signature.
|
// Build the conversion function signature.
|
||||||
std::string Signature = "Convert";
|
std::string Signature = "Convert";
|
||||||
std::string CaseBody;
|
std::string CaseBody;
|
||||||
raw_string_ostream CaseOS(CaseBody);
|
raw_string_ostream CaseOS(CaseBody);
|
||||||
|
|
||||||
// Compute the convert enum and the case body.
|
// Compute the convert enum and the case body.
|
||||||
for (unsigned i = 0, e = II.OperandList.size(); i != e; ++i) {
|
for (unsigned i = 0, e = II.ResOperands.size(); i != e; ++i) {
|
||||||
const CGIOperandList::OperandInfo &OpInfo = II.OperandList[i];
|
const MatchableInfo::ResOperand &OpInfo = II.ResOperands[i];
|
||||||
|
|
||||||
// Find out what operand from the asmparser that this MCInst operand comes
|
// Generate code to populate each result operand.
|
||||||
// from.
|
switch (OpInfo.Kind) {
|
||||||
int SrcOperand = OperandMap[i];
|
default: assert(0 && "Unknown result operand kind");
|
||||||
if (SrcOperand != -1) {
|
case MatchableInfo::ResOperand::RenderAsmOperand: {
|
||||||
// Otherwise, this comes from something we parsed.
|
// This comes from something we parsed.
|
||||||
MatchableInfo::AsmOperand &Op = II.AsmOperands[SrcOperand];
|
MatchableInfo::AsmOperand &Op = II.AsmOperands[OpInfo.AsmOperandNum];
|
||||||
|
|
||||||
// Registers are always converted the same, don't duplicate the
|
// Registers are always converted the same, don't duplicate the
|
||||||
// conversion function based on them.
|
// conversion function based on them.
|
||||||
|
@ -1162,29 +1251,25 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
|
||||||
else
|
else
|
||||||
Signature += Op.Class->ClassName;
|
Signature += Op.Class->ClassName;
|
||||||
Signature += utostr(Op.OperandInfo->MINumOperands);
|
Signature += utostr(Op.OperandInfo->MINumOperands);
|
||||||
Signature += "_" + itostr(SrcOperand);
|
Signature += "_" + itostr(OpInfo.AsmOperandNum);
|
||||||
|
|
||||||
CaseOS << " ((" << TargetOperandClass << "*)Operands["
|
CaseOS << " ((" << TargetOperandClass << "*)Operands["
|
||||||
<< SrcOperand << "+1])->" << Op.Class->RenderMethod
|
<< (OpInfo.AsmOperandNum+1) << "])->" << Op.Class->RenderMethod
|
||||||
<< "(Inst, " << Op.OperandInfo->MINumOperands << ");\n";
|
<< "(Inst, " << Op.OperandInfo->MINumOperands << ");\n";
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, this must be a tied operand if not, it is something that is
|
case MatchableInfo::ResOperand::TiedOperand: {
|
||||||
// mentioned in the ins/outs list but not in the asm string.
|
// If this operand is tied to a previous one, just copy the MCInst
|
||||||
int TiedOp = OpInfo.getTiedRegister();
|
// operand from the earlier one.We can only tie single MCOperand values.
|
||||||
if (TiedOp == -1)
|
//assert(OpInfo.OpInfo->MINumOperands == 1 && "Not a singular MCOperand");
|
||||||
throw TGError(II.TheDef->getLoc(), "Instruction '" +
|
unsigned TiedOp = OpInfo.TiedOperandNum;
|
||||||
II.TheDef->getName() + "' has operand '" + OpInfo.Name +
|
assert(i > TiedOp && "Tied operand preceeds its target!");
|
||||||
"' that doesn't appear in asm string!");
|
|
||||||
|
|
||||||
// If this operand is tied to a previous one, just copy the MCInst operand
|
|
||||||
// from the earlier one.
|
|
||||||
// Copy the tied operand. We can only tie single MCOperand values.
|
|
||||||
assert(OpInfo.MINumOperands == 1 && "Not a singular MCOperand");
|
|
||||||
assert(i > unsigned(TiedOp) && "Tied operand preceeds its target!");
|
|
||||||
CaseOS << " Inst.addOperand(Inst.getOperand(" << TiedOp << "));\n";
|
CaseOS << " Inst.addOperand(Inst.getOperand(" << TiedOp << "));\n";
|
||||||
Signature += "__Tie" + itostr(TiedOp);
|
Signature += "__Tie" + utostr(TiedOp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
II.ConversionFnKind = Signature;
|
II.ConversionFnKind = Signature;
|
||||||
|
|
Loading…
Reference in New Issue