aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-30 16:33:32 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-30 16:33:32 +0000
commit51315c45ff5643a27f9c84b816db54ee870ba29b (patch)
tree1d87443fa0e53d3e6b315ce25787e64be0906bf7 /contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp
parent6dfd050075216be8538ae375a22d30db72916f7e (diff)
parenteb11fae6d08f479c0799db45860a98af528fa6e7 (diff)
Merge llvm trunk r338150, and resolve conflicts.
Notes
Notes: svn path=/projects/clang700-import/; revision=336916
Diffstat (limited to 'contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp')
-rw-r--r--contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp317
1 files changed, 270 insertions, 47 deletions
diff --git a/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index f2d304bfcf5b..e808661b7a51 100644
--- a/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/contrib/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -105,6 +105,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
@@ -272,9 +273,17 @@ public:
return true;
// ... or if any of its super classes are a subset of RHS.
- for (const ClassInfo *CI : SuperClasses)
- if (CI->isSubsetOf(RHS))
+ SmallVector<const ClassInfo *, 16> Worklist(SuperClasses.begin(),
+ SuperClasses.end());
+ SmallPtrSet<const ClassInfo *, 16> Visited;
+ while (!Worklist.empty()) {
+ auto *CI = Worklist.pop_back_val();
+ if (CI == &RHS)
return true;
+ for (auto *Super : CI->SuperClasses)
+ if (Visited.insert(Super).second)
+ Worklist.push_back(Super);
+ }
return false;
}
@@ -378,6 +387,9 @@ struct MatchableInfo {
/// The operand name this is, if anything.
StringRef SrcOpName;
+ /// The operand name this is, before renaming for tied operands.
+ StringRef OrigSrcOpName;
+
/// The suboperand index within SrcOpName, or -1 for the entire operand.
int SubOpIdx;
@@ -416,14 +428,22 @@ struct MatchableInfo {
RegOperand
} Kind;
+ /// Tuple containing the index of the (earlier) result operand that should
+ /// be copied from, as well as the indices of the corresponding (parsed)
+ /// operands in the asm string.
+ struct TiedOperandsTuple {
+ unsigned ResOpnd;
+ unsigned SrcOpnd1Idx;
+ unsigned SrcOpnd2Idx;
+ };
+
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;
+ /// Description of tied operands.
+ TiedOperandsTuple TiedOperands;
/// ImmVal - This is the immediate value added to the instruction.
int64_t ImmVal;
@@ -444,10 +464,11 @@ struct MatchableInfo {
return X;
}
- static ResOperand getTiedOp(unsigned TiedOperandNum) {
+ static ResOperand getTiedOp(unsigned TiedOperandNum, unsigned SrcOperand1,
+ unsigned SrcOperand2) {
ResOperand X;
X.Kind = TiedOperand;
- X.TiedOperandNum = TiedOperandNum;
+ X.TiedOperands = { TiedOperandNum, SrcOperand1, SrcOperand2 };
X.MINumOperands = 1;
return X;
}
@@ -560,7 +581,7 @@ struct MatchableInfo {
/// validate - Return true if this matchable is a valid thing to match against
/// and perform a bunch of validity checking.
- bool validate(StringRef CommentDelimiter, bool Hack) const;
+ bool validate(StringRef CommentDelimiter, bool IsAlias) const;
/// findAsmOperand - Find the AsmOperand with the specified name and
/// suboperand index.
@@ -573,14 +594,21 @@ struct MatchableInfo {
/// findAsmOperandNamed - Find the first AsmOperand with the specified name.
/// This does not check the suboperand index.
- int findAsmOperandNamed(StringRef N) const {
- auto I = find_if(AsmOperands,
+ int findAsmOperandNamed(StringRef N, int LastIdx = -1) const {
+ auto I = std::find_if(AsmOperands.begin() + LastIdx + 1, AsmOperands.end(),
[&](const AsmOperand &Op) { return Op.SrcOpName == N; });
return (I != AsmOperands.end()) ? I - AsmOperands.begin() : -1;
}
+ int findAsmOperandOriginallyNamed(StringRef N) const {
+ auto I =
+ find_if(AsmOperands,
+ [&](const AsmOperand &Op) { return Op.OrigSrcOpName == N; });
+ return (I != AsmOperands.end()) ? I - AsmOperands.begin() : -1;
+ }
+
void buildInstructionResultOperands();
- void buildAliasResultOperands();
+ void buildAliasResultOperands(bool AliasConstraintsAreChecked);
/// operator< - Compare two matchables.
bool operator<(const MatchableInfo &RHS) const {
@@ -620,6 +648,10 @@ struct MatchableInfo {
if (Mnemonic != RHS.Mnemonic)
return false;
+ // Different variants can't conflict.
+ if (AsmVariantID != RHS.AsmVariantID)
+ return false;
+
// The number of operands is unambiguous.
if (AsmOperands.size() != RHS.AsmOperands.size())
return false;
@@ -770,6 +802,8 @@ public:
LLVM_DUMP_METHOD void MatchableInfo::dump() const {
errs() << TheDef->getName() << " -- " << "flattened:\"" << AsmString <<"\"\n";
+ errs() << " variant: " << AsmVariantID << "\n";
+
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
const AsmOperand &Op = AsmOperands[i];
errs() << " op[" << i << "] = " << Op.Class->ClassName << " - ";
@@ -840,10 +874,6 @@ void MatchableInfo::formTwoOperandAlias(StringRef Constraint) {
if (Op.AsmOperandNum > (unsigned)SrcAsmOperand)
--Op.AsmOperandNum;
break;
- case ResOperand::TiedOperand:
- if (Op.TiedOperandNum > (unsigned)SrcAsmOperand)
- --Op.TiedOperandNum;
- break;
}
}
}
@@ -1019,7 +1049,7 @@ void MatchableInfo::tokenizeAsmString(const AsmMatcherInfo &Info,
addAsmOperand(String.substr(Prev), IsIsolatedToken);
}
-bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const {
+bool MatchableInfo::validate(StringRef CommentDelimiter, bool IsAlias) const {
// Reject matchables with no .s string.
if (AsmString.empty())
PrintFatalError(TheDef->getLoc(), "instruction with empty asm string");
@@ -1052,17 +1082,10 @@ bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const {
PrintFatalError(TheDef->getLoc(),
"matchable with operand modifier '" + Tok +
"' not supported by asm matcher. Mark isCodeGenOnly!");
-
// Verify that any operand is only mentioned once.
// We reject aliases and ignore instructions for now.
- if (Tok[0] == '$' && !OperandNames.insert(Tok).second) {
- if (!Hack)
- PrintFatalError(TheDef->getLoc(),
- "ERROR: matchable with tied operand '" + Tok +
- "' can never be matched!");
- // 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({
+ if (!IsAlias && Tok[0] == '$' && !OperandNames.insert(Tok).second) {
+ LLVM_DEBUG({
errs() << "warning: '" << TheDef->getName() << "': "
<< "ignoring instruction with tied operand '"
<< Tok << "'\n";
@@ -1448,11 +1471,13 @@ void AsmMatcherInfo::buildInfo() {
SubtargetFeaturePairs.end());
#ifndef NDEBUG
for (const auto &Pair : SubtargetFeatures)
- DEBUG(Pair.second.dump());
+ LLVM_DEBUG(Pair.second.dump());
#endif // NDEBUG
assert(SubtargetFeatures.size() <= 64 && "Too many subtarget features!");
bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst");
+ bool ReportMultipleNearMisses =
+ AsmParser->getValueAsBit("ReportMultipleNearMisses");
// Parse the instructions; we need to do this first so that we can gather the
// singleton register classes.
@@ -1495,7 +1520,7 @@ void AsmMatcherInfo::buildInfo() {
// Ignore instructions which shouldn't be matched and diagnose invalid
// instruction definitions with an error.
- if (!II->validate(CommentDelimiter, true))
+ if (!II->validate(CommentDelimiter, false))
continue;
Matchables.push_back(std::move(II));
@@ -1507,7 +1532,6 @@ void AsmMatcherInfo::buildInfo() {
Records.getAllDerivedDefinitions("InstAlias");
for (unsigned i = 0, e = AllInstAliases.size(); i != e; ++i) {
auto Alias = llvm::make_unique<CodeGenInstAlias>(AllInstAliases[i],
- Variant.AsmVariantNo,
Target);
// If the tblgen -match-prefix option is specified (for tblgen hackers),
@@ -1526,7 +1550,7 @@ void AsmMatcherInfo::buildInfo() {
II->initialize(*this, SingletonRegisters, Variant, HasMnemonicFirst);
// Validate the alias definitions.
- II->validate(CommentDelimiter, false);
+ II->validate(CommentDelimiter, true);
Matchables.push_back(std::move(II));
}
@@ -1599,7 +1623,12 @@ void AsmMatcherInfo::buildInfo() {
NewMatchables.push_back(std::move(AliasII));
}
} else
- II->buildAliasResultOperands();
+ // FIXME: The tied operands checking is not yet integrated with the
+ // framework for reporting multiple near misses. To prevent invalid
+ // formats from being matched with an alias if a tied-operands check
+ // would otherwise have disallowed it, we just disallow such constructs
+ // in TableGen completely.
+ II->buildAliasResultOperands(!ReportMultipleNearMisses);
}
if (!NewMatchables.empty())
Matchables.insert(Matchables.end(),
@@ -1672,6 +1701,7 @@ buildInstructionOperandReference(MatchableInfo *II,
// Set up the operand class.
Op->Class = getOperandClass(Operands[Idx], Op->SubOpIdx);
+ Op->OrigSrcOpName = OperandName;
// If the named operand is tied, canonicalize it to the untied operand.
// For example, something like:
@@ -1716,6 +1746,7 @@ void AsmMatcherInfo::buildAliasOperandReference(MatchableInfo *II,
Op.Class = getOperandClass(CGA.ResultOperands[i].getRecord(),
Op.SubOpIdx);
Op.SrcOpName = OperandName;
+ Op.OrigSrcOpName = OperandName;
return;
}
@@ -1734,11 +1765,16 @@ void MatchableInfo::buildInstructionResultOperands() {
if (OpInfo.MINumOperands == 1)
TiedOp = OpInfo.getTiedRegister();
if (TiedOp != -1) {
- ResOperands.push_back(ResOperand::getTiedOp(TiedOp));
+ int TiedSrcOperand = findAsmOperandOriginallyNamed(OpInfo.Name);
+ if (TiedSrcOperand != -1 &&
+ ResOperands[TiedOp].Kind == ResOperand::RenderAsmOperand)
+ ResOperands.push_back(ResOperand::getTiedOp(
+ TiedOp, ResOperands[TiedOp].AsmOperandNum, TiedSrcOperand));
+ else
+ ResOperands.push_back(ResOperand::getTiedOp(TiedOp, 0, 0));
continue;
}
- // Find out what operand from the asmparser this MCInst operand comes from.
int SrcOperand = findAsmOperandNamed(OpInfo.Name);
if (OpInfo.Name.empty() || SrcOperand == -1) {
// This may happen for operands that are tied to a suboperand of a
@@ -1767,10 +1803,16 @@ void MatchableInfo::buildInstructionResultOperands() {
}
}
-void MatchableInfo::buildAliasResultOperands() {
+void MatchableInfo::buildAliasResultOperands(bool AliasConstraintsAreChecked) {
const CodeGenInstAlias &CGA = *DefRec.get<const CodeGenInstAlias*>();
const CodeGenInstruction *ResultInst = getResultInst();
+ // Map of: $reg -> #lastref
+ // where $reg is the name of the operand in the asm string
+ // where #lastref is the last processed index where $reg was referenced in
+ // the asm string.
+ SmallDenseMap<StringRef, int> OperandRefs;
+
// Loop over all operands of the result instruction, determining how to
// populate them.
unsigned AliasOpNo = 0;
@@ -1783,8 +1825,46 @@ void MatchableInfo::buildAliasResultOperands() {
if (OpInfo->MINumOperands == 1)
TiedOp = OpInfo->getTiedRegister();
if (TiedOp != -1) {
- ResOperands.push_back(ResOperand::getTiedOp(TiedOp));
- continue;
+ unsigned SrcOp1 = 0;
+ unsigned SrcOp2 = 0;
+
+ // If an operand has been specified twice in the asm string,
+ // add the two source operand's indices to the TiedOp so that
+ // at runtime the 'tied' constraint is checked.
+ if (ResOperands[TiedOp].Kind == ResOperand::RenderAsmOperand) {
+ SrcOp1 = ResOperands[TiedOp].AsmOperandNum;
+
+ // Find the next operand (similarly named operand) in the string.
+ StringRef Name = AsmOperands[SrcOp1].SrcOpName;
+ auto Insert = OperandRefs.try_emplace(Name, SrcOp1);
+ SrcOp2 = findAsmOperandNamed(Name, Insert.first->second);
+
+ // Not updating the record in OperandRefs will cause TableGen
+ // to fail with an error at the end of this function.
+ if (AliasConstraintsAreChecked)
+ Insert.first->second = SrcOp2;
+
+ // In case it only has one reference in the asm string,
+ // it doesn't need to be checked for tied constraints.
+ SrcOp2 = (SrcOp2 == (unsigned)-1) ? SrcOp1 : SrcOp2;
+ }
+
+ // 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.
@@ -1803,6 +1883,11 @@ void MatchableInfo::buildAliasResultOperands() {
PrintFatalError(TheDef->getLoc(), "Instruction '" +
TheDef->getName() + "' has operand '" + OpName +
"' that doesn't appear in asm string!");
+
+ // Add it to the operand references. If it is added a second time, the
+ // record won't be updated and it will fail later on.
+ OperandRefs.try_emplace(Name, SrcOperand);
+
unsigned NumOperands = (SubIdx == -1 ? OpInfo->MINumOperands : 1);
ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand,
NumOperands));
@@ -1821,6 +1906,13 @@ void MatchableInfo::buildAliasResultOperands() {
}
}
}
+
+ // Check that operands are not repeated more times than is supported.
+ for (auto &T : OperandRefs) {
+ if (T.second != -1 && findAsmOperandNamed(T.first, T.second) != -1)
+ PrintFatalError(TheDef->getLoc(),
+ "Operand '" + T.first + "' can never be matched");
+ }
}
static unsigned
@@ -1897,9 +1989,15 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
CvtOS << " static_cast<" << TargetOperandClass
<< "&>(*Operands[OpIdx]).addRegOperands(Inst, 1);\n";
CvtOS << " break;\n";
- CvtOS << " case CVT_Tied:\n";
- CvtOS << " Inst.addOperand(Inst.getOperand(OpIdx));\n";
+ CvtOS << " case CVT_Tied: {\n";
+ CvtOS << " assert(OpIdx < (size_t)(std::end(TiedAsmOperandTable) -\n";
+ CvtOS << " std::begin(TiedAsmOperandTable)) &&\n";
+ CvtOS << " \"Tied operand not found\");\n";
+ CvtOS << " unsigned TiedResOpnd = TiedAsmOperandTable[OpIdx][0];\n";
+ CvtOS << " if (TiedResOpnd != (uint8_t) -1)\n";
+ CvtOS << " Inst.addOperand(Inst.getOperand(TiedResOpnd));\n";
CvtOS << " break;\n";
+ CvtOS << " }\n";
std::string OperandFnBody;
raw_string_ostream OpOS(OperandFnBody);
@@ -1930,6 +2028,10 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
OperandConversionKinds.insert(CachedHashString("CVT_Tied"));
enum { CVT_Done, CVT_Reg, CVT_Tied };
+ // Map of e.g. <0, 2, 3> -> "Tie_0_2_3" enum label.
+ std::map<std::tuple<uint8_t, uint8_t, uint8_t>, std::string>
+ TiedOperandsEnumMap;
+
for (auto &II : Infos) {
// Check if we have a custom match function.
StringRef AsmMatchConverter =
@@ -2050,11 +2152,24 @@ 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.TiedOperandNum;
- assert(i > TiedOp && "Tied operand precedes its target!");
- Signature += "__Tie" + utostr(TiedOp);
+ 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;
ConversionRow.push_back(CVT_Tied);
ConversionRow.push_back(TiedOp);
+ ConversionRow.push_back(SrcOp1);
+ ConversionRow.push_back(SrcOp2);
+
+ // Also create an 'enum' for this combination of tied operands.
+ auto Key = std::make_tuple(TiedOp, SrcOp1, SrcOp2);
+ TiedOperandsEnumMap.emplace(Key, TiedTupleName);
break;
}
case MatchableInfo::ResOperand::ImmOperand: {
@@ -2139,6 +2254,33 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
// Finish up the operand number lookup function.
OpOS << " }\n }\n}\n\n";
+ // Output a static table for tied operands.
+ 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() <= 254 &&
+ "Too many tied-operand combinations to reference with "
+ "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) {
+ OS << " " << KV.second << ",\n";
+ }
+ OS << "};\n\n";
+
+ OS << "static const uint8_t TiedAsmOperandTable[][3] = {\n";
+ for (auto &KV : TiedOperandsEnumMap) {
+ 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 << "static const uint8_t TiedAsmOperandTable[][3] = "
+ "{ /* empty */ {0, 0, 0} };\n\n";
+
OS << "namespace {\n";
// Output the operand conversion kind enum.
@@ -2165,9 +2307,26 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
assert(ConversionTable[Row].size() % 2 == 0 && "bad conversion row!");
OS << " // " << InstructionConversionKinds[Row] << "\n";
OS << " { ";
- for (unsigned i = 0, e = ConversionTable[Row].size(); i != e; i += 2)
- OS << OperandConversionKinds[ConversionTable[Row][i]] << ", "
- << (unsigned)(ConversionTable[Row][i + 1]) << ", ";
+ for (unsigned i = 0, e = ConversionTable[Row].size(); i != e; i += 2) {
+ OS << OperandConversionKinds[ConversionTable[Row][i]] << ", ";
+ if (OperandConversionKinds[ConversionTable[Row][i]] !=
+ CachedHashString("CVT_Tied")) {
+ OS << (unsigned)(ConversionTable[Row][i + 1]) << ", ";
+ continue;
+ }
+
+ // 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((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");
+ OS << TiedOpndEnum->second << ", ";
+ i += 2;
+ }
OS << "CVT_Done },\n";
}
@@ -2307,14 +2466,20 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info,
continue;
OS << " // '" << CI.ClassName << "' class\n";
- OS << " case " << CI.Name << ":\n";
- OS << " if (Operand." << CI.PredicateMethod << "())\n";
+ OS << " case " << CI.Name << ": {\n";
+ OS << " DiagnosticPredicate DP(Operand." << CI.PredicateMethod
+ << "());\n";
+ OS << " if (DP.isMatch())\n";
OS << " return MCTargetAsmParser::Match_Success;\n";
- if (!CI.DiagnosticType.empty())
- OS << " return " << Info.Target.getName() << "AsmParser::Match_"
+ if (!CI.DiagnosticType.empty()) {
+ OS << " if (DP.isNearMatch())\n";
+ OS << " return " << Info.Target.getName() << "AsmParser::Match_"
<< CI.DiagnosticType << ";\n";
+ OS << " break;\n";
+ }
else
OS << " break;\n";
+ OS << " }\n";
}
OS << " } // end switch (Kind)\n\n";
@@ -2825,6 +2990,48 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
OS << "}\n\n";
}
+static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
+ AsmMatcherInfo &Info,
+ raw_ostream &OS) {
+ std::string AsmParserName =
+ Info.AsmParser->getValueAsString("AsmParserClassName");
+ OS << "static bool ";
+ 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";
+ OS << " const uint8_t *Converter = ConversionTable[Kind];\n";
+ OS << " for (const uint8_t *p = Converter; *p; p+= 2) {\n";
+ OS << " switch (*p) {\n";
+ OS << " case CVT_Tied: {\n";
+ OS << " unsigned OpIdx = *(p+1);\n";
+ OS << " assert(OpIdx < (size_t)(std::end(TiedAsmOperandTable) -\n";
+ OS << " std::begin(TiedAsmOperandTable)) &&\n";
+ OS << " \"Tied operand not found\");\n";
+ OS << " unsigned OpndNum1 = TiedAsmOperandTable[OpIdx][1];\n";
+ OS << " unsigned OpndNum2 = TiedAsmOperandTable[OpIdx][2];\n";
+ 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 << " if (!AsmParser.regsEqual(*SrcOp1, *SrcOp2)) {\n";
+ OS << " ErrorInfo = OpndNum2;\n";
+ OS << " return false;\n";
+ OS << " }\n";
+ OS << " }\n";
+ OS << " }\n";
+ OS << " break;\n";
+ OS << " }\n";
+ OS << " default:\n";
+ OS << " break;\n";
+ OS << " }\n";
+ OS << " }\n";
+ OS << " return true;\n";
+ OS << "}\n\n";
+}
+
static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target,
unsigned VariantCount) {
OS << "static std::string " << Target.getName()
@@ -3072,6 +3279,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
Info.Target.getName(), ClassName, "ComputeAvailableFeatures",
Info.SubtargetFeatures, OS);
+ if (!ReportMultipleNearMisses)
+ emitAsmTiedOperandConstraints(Target, Info, OS);
+
StringToOffsetTable StringTable;
size_t MaxNumOperands = 0;
@@ -3495,6 +3705,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " if (matchingInlineAsm) {\n";
OS << " convertToMapAndConstraints(it->ConvertFn, Operands);\n";
+ if (!ReportMultipleNearMisses) {
+ OS << " if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
+ "Operands, ErrorInfo))\n";
+ OS << " return Match_InvalidTiedOperand;\n";
+ OS << "\n";
+ }
OS << " return Match_Success;\n";
OS << " }\n\n";
OS << " // We have selected a definite instruction, convert the parsed\n"
@@ -3569,6 +3785,13 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " }\n";
}
+ if (!ReportMultipleNearMisses) {
+ OS << " if (!checkAsmTiedOperandConstraints(*this, it->ConvertFn, "
+ "Operands, ErrorInfo))\n";
+ OS << " return Match_InvalidTiedOperand;\n";
+ OS << "\n";
+ }
+
OS << " DEBUG_WITH_TYPE(\n";
OS << " \"asm-matcher\",\n";
OS << " dbgs() << \"Opcode result: complete match, selecting this opcode\\n\");\n";