From: Jim Grosbach Date: Thu, 19 Apr 2012 23:59:23 +0000 (+0000) Subject: TableGen support for auto-generating assembly two-operand aliases. X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=c1922c72adedadb414a3d19c3f150bfe1bc755a5;p=oota-llvm.git TableGen support for auto-generating assembly two-operand aliases. Assembly matchers for instructions with a two-operand form. ARM is full of these, for example: add {Rd}, Rn, Rm // Rd is optional and is the same as Rn if omitted. The property TwoOperandAliasConstraint on the instruction definition controls when, and if, an alias will be formed. No explicit InstAlias definitions are required. rdar://11255754 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@155172 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Target/Target.td b/include/llvm/Target/Target.td index fa1ec559452..6a321ea2cf8 100644 --- a/include/llvm/Target/Target.td +++ b/include/llvm/Target/Target.td @@ -402,6 +402,8 @@ class Instruction { string AsmMatchConverter = ""; + string TwoOperandAliasConstraint = ""; + ///@} } diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 1b7f67e83a4..a44fbe6256f 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -419,6 +419,10 @@ struct MatchableInfo { AsmString(Alias->AsmString) { } + // Two-operand aliases clone from the main matchable, but mark the second + // operand as a tied operand of the first for purposes of the assembler. + void formTwoOperandAlias(StringRef Constraint); + void initialize(const AsmMatcherInfo &Info, SmallPtrSet &SingletonRegisters, int AsmVariantNo, std::string &RegisterPrefix); @@ -650,6 +654,78 @@ void MatchableInfo::dump() { } } +static std::pair +parseTwoOperandConstraint(StringRef S, SMLoc Loc) { + // Split via the '='. + std::pair Ops = S.split('='); + if (Ops.second == "") + throw TGError(Loc, "missing '=' in two-operand alias constraint"); + // Trim whitespace and the leading '$' on the operand names. + size_t start = Ops.first.find_first_of('$'); + if (start == std::string::npos) + throw TGError(Loc, "expected '$' prefix on asm operand name"); + Ops.first = Ops.first.slice(start + 1, std::string::npos); + size_t end = Ops.first.find_last_of(" \t"); + Ops.first = Ops.first.slice(0, end); + // Now the second operand. + start = Ops.second.find_first_of('$'); + if (start == std::string::npos) + throw TGError(Loc, "expected '$' prefix on asm operand name"); + Ops.second = Ops.second.slice(start + 1, std::string::npos); + end = Ops.second.find_last_of(" \t"); + Ops.first = Ops.first.slice(0, end); + return Ops; +} + +void MatchableInfo::formTwoOperandAlias(StringRef Constraint) { + // Figure out which operands are aliased and mark them as tied. + std::pair Ops = + parseTwoOperandConstraint(Constraint, TheDef->getLoc()); + + // Find the AsmOperands that refer to the operands we're aliasing. + int SrcAsmOperand = findAsmOperandNamed(Ops.first); + int DstAsmOperand = findAsmOperandNamed(Ops.second); + if (SrcAsmOperand == -1) + throw TGError(TheDef->getLoc(), + "unknown source two-operand alias operand '" + + Ops.first.str() + "'."); + if (DstAsmOperand == -1) + throw TGError(TheDef->getLoc(), + "unknown destination two-operand alias operand '" + + Ops.second.str() + "'."); + + // Find the ResOperand that refers to the operand we're aliasing away + // and update it to refer to the combined operand instead. + for (unsigned i = 0, e = ResOperands.size(); i != e; ++i) { + ResOperand &Op = ResOperands[i]; + if (Op.Kind == ResOperand::RenderAsmOperand && + Op.AsmOperandNum == (unsigned)SrcAsmOperand) { + Op.AsmOperandNum = DstAsmOperand; + break; + } + } + // Remove the AsmOperand for the alias operand. + AsmOperands.erase(AsmOperands.begin() + SrcAsmOperand); + // Adjust the ResOperand references to any AsmOperands that followed + // the one we just deleted. + for (unsigned i = 0, e = ResOperands.size(); i != e; ++i) { + ResOperand &Op = ResOperands[i]; + switch(Op.Kind) { + default: + // Nothing to do for operands that don't reference AsmOperands. + break; + case ResOperand::RenderAsmOperand: + if (Op.AsmOperandNum > (unsigned)SrcAsmOperand) + --Op.AsmOperandNum; + break; + case ResOperand::TiedOperand: + if (Op.TiedOperandNum > (unsigned)SrcAsmOperand) + --Op.TiedOperandNum; + break; + } + } +} + void MatchableInfo::initialize(const AsmMatcherInfo &Info, SmallPtrSet &SingletonRegisters, int AsmVariantNo, std::string &RegisterPrefix) { @@ -1272,6 +1348,7 @@ void AsmMatcherInfo::buildInfo() { // Build the information about matchables, now that we have fully formed // classes. + std::vector NewMatchables; for (std::vector::iterator it = Matchables.begin(), ie = Matchables.end(); it != ie; ++it) { MatchableInfo *II = *it; @@ -1315,11 +1392,29 @@ void AsmMatcherInfo::buildInfo() { buildAliasOperandReference(II, OperandName, Op); } - if (II->DefRec.is()) + if (II->DefRec.is()) { II->buildInstructionResultOperands(); - else + // If the instruction has a two-operand alias, build up the + // matchable here. We'll add them in bulk at the end to avoid + // confusing this loop. + std::string Constraint = + II->TheDef->getValueAsString("TwoOperandAliasConstraint"); + if (Constraint != "") { + // Start by making a copy of the original matchable. + OwningPtr AliasII(new MatchableInfo(*II)); + + // Adjust it to be a two-operand alias. + AliasII->formTwoOperandAlias(Constraint); + + // Add the alias to the matchables list. + NewMatchables.push_back(AliasII.take()); + } + } else II->buildAliasResultOperands(); } + if (!NewMatchables.empty()) + Matchables.insert(Matchables.end(), NewMatchables.begin(), + NewMatchables.end()); // Process token alias definitions and set up the associated superclass // information.