diff options
author | Chris Lattner <sabre@nondot.org> | 2010-11-04 00:43:46 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2010-11-04 00:43:46 +0000 |
commit | 1d13bda737bad3e0cea28cbd65a221ab27abdb9b (patch) | |
tree | a640bf087f911abc26fcc3a86dc9e16a3f63aa7e | |
parent | 8c42f48d023c4b9164b3c39ad0513b53f1cc1e91 (diff) | |
download | external_llvm-1d13bda737bad3e0cea28cbd65a221ab27abdb9b.zip external_llvm-1d13bda737bad3e0cea28cbd65a221ab27abdb9b.tar.gz external_llvm-1d13bda737bad3e0cea28cbd65a221ab27abdb9b.tar.bz2 |
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
-rw-r--r-- | utils/TableGen/AsmMatcherEmitter.cpp | 309 |
1 files changed, 197 insertions, 112 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index aef9a3f..27a52cf 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; |