aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-11-04 00:43:46 +0000
committerChris Lattner <sabre@nondot.org>2010-11-04 00:43:46 +0000
commit1d13bda737bad3e0cea28cbd65a221ab27abdb9b (patch)
treea640bf087f911abc26fcc3a86dc9e16a3f63aa7e /utils
parent8c42f48d023c4b9164b3c39ad0513b53f1cc1e91 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@118217 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils')
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp309
1 files changed, 197 insertions, 112 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index aef9a3f161..27a52cfe58 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -81,7 +81,6 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
-#include <list>
#include <map>
#include <set>
using namespace llvm;
@@ -258,6 +257,55 @@ struct MatchableInfo {
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.
std::string InstrName;
@@ -266,9 +314,13 @@ struct MatchableInfo {
/// matchable came from.
Record *const TheDef;
- /// OperandList - This is the operand list that came from the (ins) and (outs)
- /// list of the alias or instruction.
- const CGIOperandList &OperandList;
+ // FIXME: REMOVE.
+ const CGIOperandList &TheOperandList;
+
+
+ /// 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
/// removed), e.g. "movsx $src, $dst".
@@ -293,12 +345,12 @@ struct MatchableInfo {
std::string ConversionFnKind;
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();
}
MatchableInfo(const CodeGenInstAlias *Alias)
- : TheDef(Alias->TheDef), OperandList(Alias->Operands),
+ : TheDef(Alias->TheDef), TheOperandList(Alias->Operands),
AsmString(Alias->AsmString) {
// FIXME: Huge hack.
@@ -320,6 +372,8 @@ struct MatchableInfo {
Record *getSingletonRegisterForAsmOperand(unsigned i,
const AsmMatcherInfo &Info) const;
+ void BuildResultOperands();
+
/// operator< - Compare two matchables.
bool operator<(const MatchableInfo &RHS) const {
// The primary comparator is the instruction mnemonic.
@@ -452,6 +506,9 @@ private:
/// operand classes.
void BuildOperandClasses();
+ void BuildInstructionOperandReference(MatchableInfo *II,
+ MatchableInfo::AsmOperand &Op);
+
public:
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;
}
@@ -944,6 +974,52 @@ AsmMatcherInfo::AsmMatcherInfo(Record *asmParser, CodeGenTarget &target)
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() {
// Build information about all of the AssemblerPredicates.
@@ -981,6 +1057,27 @@ void AsmMatcherInfo::BuildInfo() {
if (CGI.TheDef->getValueAsBit("isCodeGenOnly"))
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));
II->Initialize(*this, SingletonRegisters);
@@ -1048,46 +1145,56 @@ void AsmMatcherInfo::BuildInfo() {
}
// Otherwise this is an operand reference.
- StringRef OperandName;
- 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!");
- }
-
- Op.Class = getOperandClass(Token, *OI);
- Op.OperandInfo = OI;
+ BuildInstructionOperandReference(II, Op);
}
+
+ II->BuildResultOperands();
}
// Reorder classes so that classes preceed super classes.
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,
std::vector<MatchableInfo*> &Infos,
raw_ostream &OS) {
@@ -1100,7 +1207,6 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
std::set<std::string> GeneratedFns;
// Start the unified conversion function.
-
CvtOS << "static void ConvertToMCInst(ConversionKind Kind, MCInst &Inst, "
<< "unsigned Opcode,\n"
<< " const SmallVectorImpl<MCParsedAsmOperand*"
@@ -1117,42 +1223,25 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
// TargetOperandClass - This is the target's operand class, like X86Operand.
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(),
ie = Infos.end(); it != ie; ++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.
std::string Signature = "Convert";
std::string CaseBody;
raw_string_ostream CaseOS(CaseBody);
// Compute the convert enum and the case body.
- for (unsigned i = 0, e = II.OperandList.size(); i != e; ++i) {
- const CGIOperandList::OperandInfo &OpInfo = II.OperandList[i];
-
- // Find out what operand from the asmparser that this MCInst operand comes
- // from.
- int SrcOperand = OperandMap[i];
- if (SrcOperand != -1) {
- // Otherwise, this comes from something we parsed.
- MatchableInfo::AsmOperand &Op = II.AsmOperands[SrcOperand];
+ for (unsigned i = 0, e = II.ResOperands.size(); i != e; ++i) {
+ const MatchableInfo::ResOperand &OpInfo = II.ResOperands[i];
+
+ // Generate code to populate each result operand.
+ switch (OpInfo.Kind) {
+ default: assert(0 && "Unknown result operand kind");
+ case MatchableInfo::ResOperand::RenderAsmOperand: {
+ // This comes from something we parsed.
+ MatchableInfo::AsmOperand &Op = II.AsmOperands[OpInfo.AsmOperandNum];
// Registers are always converted the same, don't duplicate the
// conversion function based on them.
@@ -1162,29 +1251,25 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
else
Signature += Op.Class->ClassName;
Signature += utostr(Op.OperandInfo->MINumOperands);
- Signature += "_" + itostr(SrcOperand);
+ Signature += "_" + itostr(OpInfo.AsmOperandNum);
CaseOS << " ((" << TargetOperandClass << "*)Operands["
- << SrcOperand << "+1])->" << Op.Class->RenderMethod
+ << (OpInfo.AsmOperandNum+1) << "])->" << Op.Class->RenderMethod
<< "(Inst, " << Op.OperandInfo->MINumOperands << ");\n";
- continue;
+ break;
+ }
+
+ case MatchableInfo::ResOperand::TiedOperand: {
+ // If this operand is tied to a previous one, just copy the MCInst
+ // operand from the earlier one.We can only tie single MCOperand values.
+ //assert(OpInfo.OpInfo->MINumOperands == 1 && "Not a singular MCOperand");
+ unsigned TiedOp = OpInfo.TiedOperandNum;
+ assert(i > TiedOp && "Tied operand preceeds its target!");
+ CaseOS << " Inst.addOperand(Inst.getOperand(" << TiedOp << "));\n";
+ Signature += "__Tie" + utostr(TiedOp);
+ break;
+ }
}
-
- // Otherwise, this must be a tied operand if not, it is something that is
- // mentioned in the ins/outs list but not in the asm string.
- int TiedOp = OpInfo.getTiedRegister();
- if (TiedOp == -1)
- throw TGError(II.TheDef->getLoc(), "Instruction '" +
- II.TheDef->getName() + "' has operand '" + OpInfo.Name +
- "' 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";
- Signature += "__Tie" + itostr(TiedOp);
}
II.ConversionFnKind = Signature;