mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-03 00:47:07 +00:00
[TableGen][AsmMatcherEmitter] Allow tied operands of different classes in aliases.
Allow a tied operand of a different operand class in InstAliases, so that the operand can be printed (and added to the MC instruction) as the appropriate register. For example, 'GPR64as32', which would be printed/parsed as a 32bit register and should match a tied 64bit register operand, where the former is a sub-register of the latter. This patch also generalizes the constraint checking to an overrideable method in MCTargetAsmParser, so that target asmparsers can specify whether a given operand satisfies the tied register constraint. Reviewers: olista01, rengolin, fhahn, SjoerdMeijer, samparker, dsanders, craig.topper Reviewed By: fhahn Differential Revision: https://reviews.llvm.org/D47714 llvm-svn: 334942
This commit is contained in:
parent
600459b595
commit
df252ecda0
@ -14,6 +14,7 @@
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCParser/MCAsmLexer.h"
|
||||
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
||||
#include "llvm/MC/MCParser/MCAsmParserExtension.h"
|
||||
#include "llvm/MC/MCTargetOptions.h"
|
||||
#include "llvm/Support/SMLoc.h"
|
||||
@ -453,6 +454,15 @@ public:
|
||||
virtual void convertToMapAndConstraints(unsigned Kind,
|
||||
const OperandVector &Operands) = 0;
|
||||
|
||||
/// Returns whether two registers are equal and is used by the tied-operands
|
||||
/// checks in the AsmMatcher. This method can be overridden allow e.g. a
|
||||
/// sub- or super-register as the tied operand.
|
||||
virtual bool regsEqual(const MCParsedAsmOperand &Op1,
|
||||
const MCParsedAsmOperand &Op2) const {
|
||||
assert(Op1.isReg() && Op2.isReg() && "Operands not all regs");
|
||||
return Op1.getReg() == Op2.getReg();
|
||||
}
|
||||
|
||||
// Return whether this parser uses assignment statements with equals tokens
|
||||
virtual bool equalIsAsmAssignment() { return true; };
|
||||
// Return whether this start of statement identifier is a label
|
||||
|
@ -1855,8 +1855,22 @@ void MatchableInfo::buildAliasResultOperands(bool AliasConstraintsAreChecked) {
|
||||
SrcOp2 = (SrcOp2 == (unsigned)-1) ? SrcOp1 : SrcOp2;
|
||||
}
|
||||
|
||||
ResOperands.push_back(ResOperand::getTiedOp(TiedOp, SrcOp1, SrcOp2));
|
||||
continue;
|
||||
// If the alias operand is of a different operand class, we only want
|
||||
// to benefit from the tied-operands check and just match the operand
|
||||
// as a normal, but not copy the original (TiedOp) to the result
|
||||
// instruction. We do this by passing -1 as the tied operand to copy.
|
||||
if (ResultInst->Operands[i].Rec->getName() !=
|
||||
ResultInst->Operands[TiedOp].Rec->getName()) {
|
||||
SrcOp1 = ResOperands[TiedOp].AsmOperandNum;
|
||||
int SubIdx = CGA.ResultInstOperandIndex[AliasOpNo].second;
|
||||
StringRef Name = CGA.ResultOperands[AliasOpNo].getName();
|
||||
SrcOp2 = findAsmOperand(Name, SubIdx);
|
||||
ResOperands.push_back(
|
||||
ResOperand::getTiedOp((unsigned)-1, SrcOp1, SrcOp2));
|
||||
} else {
|
||||
ResOperands.push_back(ResOperand::getTiedOp(TiedOp, SrcOp1, SrcOp2));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle all the suboperands for this operand.
|
||||
@ -1986,7 +2000,8 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
|
||||
CvtOS << " std::begin(TiedAsmOperandTable)) &&\n";
|
||||
CvtOS << " \"Tied operand not found\");\n";
|
||||
CvtOS << " unsigned TiedResOpnd = TiedAsmOperandTable[OpIdx][0];\n";
|
||||
CvtOS << " Inst.addOperand(Inst.getOperand(TiedResOpnd));\n";
|
||||
CvtOS << " if (TiedResOpnd != (uint8_t) -1)\n";
|
||||
CvtOS << " Inst.addOperand(Inst.getOperand(TiedResOpnd));\n";
|
||||
CvtOS << " break;\n";
|
||||
CvtOS << " }\n";
|
||||
|
||||
@ -2020,7 +2035,7 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
|
||||
enum { CVT_Done, CVT_Reg, CVT_Tied };
|
||||
|
||||
// Map of e.g. <0, 2, 3> -> "Tie_0_2_3" enum label.
|
||||
std::map<std::tuple<unsigned, unsigned, unsigned>, std::string>
|
||||
std::map<std::tuple<uint8_t, uint8_t, uint8_t>, std::string>
|
||||
TiedOperandsEnumMap;
|
||||
|
||||
for (auto &II : Infos) {
|
||||
@ -2143,10 +2158,13 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
|
||||
// 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.MINumOperands == 1 && "Not a singular MCOperand");
|
||||
unsigned TiedOp = OpInfo.TiedOperands.ResOpnd;
|
||||
unsigned SrcOp1 = OpInfo.TiedOperands.SrcOpnd1Idx + HasMnemonicFirst;
|
||||
unsigned SrcOp2 = OpInfo.TiedOperands.SrcOpnd2Idx + HasMnemonicFirst;
|
||||
assert(i > TiedOp && "Tied operand precedes its target!");
|
||||
uint8_t TiedOp = OpInfo.TiedOperands.ResOpnd;
|
||||
uint8_t SrcOp1 =
|
||||
OpInfo.TiedOperands.SrcOpnd1Idx + HasMnemonicFirst;
|
||||
uint8_t SrcOp2 =
|
||||
OpInfo.TiedOperands.SrcOpnd2Idx + HasMnemonicFirst;
|
||||
assert((i > TiedOp || TiedOp == (uint8_t)-1) &&
|
||||
"Tied operand precedes its target!");
|
||||
auto TiedTupleName = std::string("Tie") + utostr(TiedOp) + '_' +
|
||||
utostr(SrcOp1) + '_' + utostr(SrcOp2);
|
||||
Signature += "__" + TiedTupleName;
|
||||
@ -2246,9 +2264,10 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
|
||||
if (TiedOperandsEnumMap.size()) {
|
||||
// The number of tied operand combinations will be small in practice,
|
||||
// but just add the assert to be sure.
|
||||
assert(TiedOperandsEnumMap.size() <= 255 &&
|
||||
assert(TiedOperandsEnumMap.size() <= 254 &&
|
||||
"Too many tied-operand combinations to reference with "
|
||||
"an 8bit offset from the conversion table");
|
||||
"an 8bit offset from the conversion table, where index "
|
||||
"'255' is reserved as operand not to be copied.");
|
||||
|
||||
OS << "enum {\n";
|
||||
for (auto &KV : TiedOperandsEnumMap) {
|
||||
@ -2256,15 +2275,17 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
|
||||
}
|
||||
OS << "};\n\n";
|
||||
|
||||
OS << "const char TiedAsmOperandTable[][3] = {\n";
|
||||
OS << "const uint8_t TiedAsmOperandTable[][3] = {\n";
|
||||
for (auto &KV : TiedOperandsEnumMap) {
|
||||
OS << " /* " << KV.second << " */ { " << std::get<0>(KV.first) << ", "
|
||||
<< std::get<1>(KV.first) << ", " << std::get<2>(KV.first) << " },\n";
|
||||
OS << " /* " << KV.second << " */ { "
|
||||
<< utostr(std::get<0>(KV.first)) << ", "
|
||||
<< utostr(std::get<1>(KV.first)) << ", "
|
||||
<< utostr(std::get<2>(KV.first)) << " },\n";
|
||||
}
|
||||
OS << "};\n\n";
|
||||
} else
|
||||
OS << "const char TiedAsmOperandTable[][3] = { /* empty */ {0, 0, 0} "
|
||||
"};\n\n";
|
||||
OS << "const uint8_t TiedAsmOperandTable[][3] = "
|
||||
"{ /* empty */ {0, 0, 0} };\n\n";
|
||||
|
||||
OS << "namespace {\n";
|
||||
|
||||
@ -2303,9 +2324,9 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
|
||||
// For a tied operand, emit a reference to the TiedAsmOperandTable
|
||||
// that contains the operand to copy, and the parsed operands to
|
||||
// check for their tied constraints.
|
||||
auto Key = std::make_tuple((unsigned)ConversionTable[Row][i + 1],
|
||||
(unsigned)ConversionTable[Row][i + 2],
|
||||
(unsigned)ConversionTable[Row][i + 3]);
|
||||
auto Key = std::make_tuple((uint8_t)ConversionTable[Row][i + 1],
|
||||
(uint8_t)ConversionTable[Row][i + 2],
|
||||
(uint8_t)ConversionTable[Row][i + 3]);
|
||||
auto TiedOpndEnum = TiedOperandsEnumMap.find(Key);
|
||||
assert(TiedOpndEnum != TiedOperandsEnumMap.end() &&
|
||||
"No record for tied operand pair");
|
||||
@ -2978,8 +2999,12 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
|
||||
static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
|
||||
AsmMatcherInfo &Info,
|
||||
raw_ostream &OS) {
|
||||
std::string AsmParserName =
|
||||
Info.AsmParser->getValueAsString("AsmParserClassName");
|
||||
OS << "static bool ";
|
||||
OS << "checkAsmTiedOperandConstraints(unsigned Kind,\n";
|
||||
OS << "checkAsmTiedOperandConstraints(const " << Target.getName()
|
||||
<< AsmParserName << "&AsmParser,\n";
|
||||
OS << " unsigned Kind,\n";
|
||||
OS << " const OperandVector &Operands,\n";
|
||||
OS << " uint64_t &ErrorInfo) {\n";
|
||||
OS << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n";
|
||||
@ -2996,10 +3021,11 @@ static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
|
||||
OS << " if (OpndNum1 != OpndNum2) {\n";
|
||||
OS << " auto &SrcOp1 = Operands[OpndNum1];\n";
|
||||
OS << " auto &SrcOp2 = Operands[OpndNum2];\n";
|
||||
OS << " if (SrcOp1->isReg() && SrcOp2->isReg() &&\n";
|
||||
OS << " SrcOp1->getReg() != SrcOp2->getReg()) {\n";
|
||||
OS << " ErrorInfo = OpndNum2;\n";
|
||||
OS << " return false;\n";
|
||||
OS << " if (SrcOp1->isReg() && SrcOp2->isReg()) {\n";
|
||||
OS << " if (!AsmParser.regsEqual(*SrcOp1, *SrcOp2)) {\n";
|
||||
OS << " ErrorInfo = OpndNum2;\n";
|
||||
OS << " return false;\n";
|
||||
OS << " }\n";
|
||||
OS << " }\n";
|
||||
OS << " }\n";
|
||||
OS << " break;\n";
|
||||
@ -3686,7 +3712,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
OS << " if (matchingInlineAsm) {\n";
|
||||
OS << " convertToMapAndConstraints(it->ConvertFn, Operands);\n";
|
||||
if (!ReportMultipleNearMisses) {
|
||||
OS << " if (!checkAsmTiedOperandConstraints(it->ConvertFn, Operands, ErrorInfo))\n";
|
||||
OS << " if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
|
||||
"Operands, ErrorInfo))\n";
|
||||
OS << " return Match_InvalidTiedOperand;\n";
|
||||
OS << "\n";
|
||||
}
|
||||
@ -3765,7 +3792,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
|
||||
}
|
||||
|
||||
if (!ReportMultipleNearMisses) {
|
||||
OS << " if (!checkAsmTiedOperandConstraints(it->ConvertFn, Operands, ErrorInfo))\n";
|
||||
OS << " if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
|
||||
"Operands, ErrorInfo))\n";
|
||||
OS << " return Match_InvalidTiedOperand;\n";
|
||||
OS << "\n";
|
||||
}
|
||||
|
@ -630,8 +630,14 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T)
|
||||
// of a complex operand, in which case we include them anyways, as we
|
||||
// don't have any other way to specify the whole operand.
|
||||
if (ResultInst->Operands[i].MINumOperands == 1 &&
|
||||
ResultInst->Operands[i].getTiedRegister() != -1)
|
||||
continue;
|
||||
ResultInst->Operands[i].getTiedRegister() != -1) {
|
||||
// Tied operands of different RegisterClass should be explicit within an
|
||||
// instruction's syntax and so cannot be skipped.
|
||||
int TiedOpNum = ResultInst->Operands[i].getTiedRegister();
|
||||
if (ResultInst->Operands[i].Rec->getName() ==
|
||||
ResultInst->Operands[TiedOpNum].Rec->getName())
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AliasOpNo >= Result->getNumArgs())
|
||||
PrintFatalError(R->getLoc(), "not enough arguments for instruction!");
|
||||
|
Loading…
Reference in New Issue
Block a user