llvm.org GIT mirror llvm / cb6c95b
[TableGen][AsmMatcherEmitter] Fix tied-constraint checking for InstAliases Summary: This is a bit of a reimplementation the work done in https://reviews.llvm.org/D41446, since that patch only really works for tied operands of instructions, not aliases. Instead of checking the constraints based on the matched instruction's opcode, this patch uses the match-info's convert function to check the operand constraints for that specific instruction/alias. This is based on the matched operands for the instruction, not the resulting opcode of the MCInst. This patch adds the following enum/table to the *GenAsmMatcher.inc file: enum { Tie0_1_1, Tie0_1_2, Tie0_1_5, ... }; const char TiedAsmOperandTable[][3] = { /* Tie0_1_1 */ { 0, 1, 1 }, /* Tie0_1_2 */ { 0, 1, 2 }, /* Tie0_1_5 */ { 0, 1, 5 }, ... }; And it is referenced directly in the ConversionTable, like this: static const uint8_t ConversionTable[CVT_NUM_SIGNATURES][13] = { ... { CVT_95_addRegOperands, 1, CVT_95_addRegOperands, 2, CVT_Tied, Tie0_1_5, CVT_95_addRegOperands, 6, CVT_Done }, ... The Tie0_1_5 (and corresponding table) encodes that: * Result operand 0 is the operand to copy (which is e.g. done when building up the operands to the MCInst in convertToMCInst()) * Asm operands 1 and 5 should be the same operands (which is checked in checkAsmTiedOperandConstraints()). Reviewers: olista01, rengolin, fhahn, craig.topper, echristo, apazos, dsanders Reviewed By: olista01 Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D42293 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@324196 91177308-0d34-0410-b5e6-96231b3b80d8 Sander de Smalen 2 years ago
1 changed file(s) with 188 addition(s) and 154 deletion(s). Raw diff Collapse all Expand all
377377 /// The operand name this is, if anything.
378378 StringRef SrcOpName;
379379
380 /// The operand name this is, before renaming for tied operands.
381 StringRef OrigSrcOpName;
382
380383 /// The suboperand index within SrcOpName, or -1 for the entire operand.
381384 int SubOpIdx;
382385
415418 RegOperand
416419 } Kind;
417420
421 /// Tuple containing the index of the (earlier) result operand that should
422 /// be copied from, as well as the indices of the corresponding (parsed)
423 /// operands in the asm string.
424 struct TiedOperandsTuple {
425 unsigned ResOpnd;
426 unsigned SrcOpnd1Idx;
427 unsigned SrcOpnd2Idx;
428 };
429
418430 union {
419431 /// This is the operand # in the AsmOperands list that this should be
420432 /// copied from.
421433 unsigned AsmOperandNum;
422434
423 /// TiedOperandNum - This is the (earlier) result operand that should be
424 /// copied from.
425 unsigned TiedOperandNum;
435 /// Description of tied operands.
436 TiedOperandsTuple TiedOperands;
426437
427438 /// ImmVal - This is the immediate value added to the instruction.
428439 int64_t ImmVal;
443454 return X;
444455 }
445456
446 static ResOperand getTiedOp(unsigned TiedOperandNum) {
457 static ResOperand getTiedOp(unsigned TiedOperandNum, unsigned SrcOperand1,
458 unsigned SrcOperand2) {
447459 ResOperand X;
448460 X.Kind = TiedOperand;
449 X.TiedOperandNum = TiedOperandNum;
461 X.TiedOperands = { TiedOperandNum, SrcOperand1, SrcOperand2 };
450462 X.MINumOperands = 1;
451463 return X;
452464 }
573585
574586 /// validate - Return true if this matchable is a valid thing to match against
575587 /// and perform a bunch of validity checking.
576 bool validate(StringRef CommentDelimiter, bool Hack) const;
588 bool validate(StringRef CommentDelimiter, bool IsAlias) const;
577589
578590 /// findAsmOperand - Find the AsmOperand with the specified name and
579591 /// suboperand index.
586598
587599 /// findAsmOperandNamed - Find the first AsmOperand with the specified name.
588600 /// This does not check the suboperand index.
589 int findAsmOperandNamed(StringRef N) const {
590 auto I = find_if(AsmOperands,
601 int findAsmOperandNamed(StringRef N, int LastIdx = -1) const {
602 auto I = std::find_if(AsmOperands.begin() + LastIdx + 1, AsmOperands.end(),
591603 [&](const AsmOperand &Op) { return Op.SrcOpName == N; });
592604 return (I != AsmOperands.end()) ? I - AsmOperands.begin() : -1;
593605 }
594606
607 int findAsmOperandOriginallyNamed(StringRef N) const {
608 auto I =
609 find_if(AsmOperands,
610 [&](const AsmOperand &Op) { return Op.OrigSrcOpName == N; });
611 return (I != AsmOperands.end()) ? I - AsmOperands.begin() : -1;
612 }
613
595614 void buildInstructionResultOperands();
596 void buildAliasResultOperands();
615 void buildAliasResultOperands(bool AliasConstraintsAreChecked);
597616
598617 /// operator< - Compare two matchables.
599618 bool operator<(const MatchableInfo &RHS) const {
859878 if (Op.AsmOperandNum > (unsigned)SrcAsmOperand)
860879 --Op.AsmOperandNum;
861880 break;
862 case ResOperand::TiedOperand:
863 if (Op.TiedOperandNum > (unsigned)SrcAsmOperand)
864 --Op.TiedOperandNum;
865 break;
866881 }
867882 }
868883 }
896911
897912 // If there is no register prefix (i.e. "%" in "%eax"), then this may
898913 // be some random non-register token, just ignore it.
899 }
900
901 static Optional
902 getAsmOperandIdx(const SmallVectorImpl &AsmOperands,
903 std::string Name) {
904 const auto SymbolicName = std::string("$") + Name;
905 const auto Pos =
906 std::find_if(AsmOperands.begin(), AsmOperands.end(),
907 [&SymbolicName](const MatchableInfo::AsmOperand &A) {
908 return A.Token == SymbolicName;
909 });
910
911 if (Pos == AsmOperands.end())
912 return Optional();
913
914 return Optional(std::distance(AsmOperands.begin(), Pos));
915914 }
916915
917916 void MatchableInfo::initialize(const AsmMatcherInfo &Info,
962961
963962 HasDeprecation =
964963 DepMask ? !DepMask->getValue()->getAsUnquotedString().empty() : false;
965
966 // Do not generate tied operand info if the instruction does not
967 // use the default AsmMatchConverter.
968 if (TheDef->getValue("AsmMatchConverter") &&
969 !TheDef->getValueAsString("AsmMatchConverter").empty())
970 return;
971
972 // Generate tied operand contraints info.
973 const auto &CGIOperands = getResultInst()->Operands;
974 for (const auto &CGIOp : CGIOperands) {
975 int TiedReg = CGIOp.getTiedRegister();
976 if (TiedReg == -1)
977 continue;
978
979 Optional LHSIdx = getAsmOperandIdx(AsmOperands, CGIOp.Name);
980 Optional RHSIdx =
981 getAsmOperandIdx(AsmOperands, CGIOperands[TiedReg].Name);
982 // Skipping operands with constraint but no reference in the
983 // AsmString. No need to throw a warning, as it's normal to have
984 // a $dst operand in the outs dag that is constrained to a $src
985 // operand in the ins dag but that does not appear in the AsmString.
986 if (!LHSIdx || !RHSIdx)
987 continue;
988
989 // Add the constraint. Using min/max as we consider constraint
990 // pair {A,B} and {B,A} the same
991 size_t AddMnemonicIdx = HasMnemonicFirst;
992 AsmOperandTiedConstraints.emplace_back(
993 std::min(*LHSIdx, *RHSIdx) + AddMnemonicIdx,
994 std::max(*LHSIdx, *RHSIdx) + AddMnemonicIdx);
995 }
996964 }
997965
998966 /// Append an AsmOperand for the given substring of AsmString.
10851053 addAsmOperand(String.substr(Prev), IsIsolatedToken);
10861054 }
10871055
1088 bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const {
1056 bool MatchableInfo::validate(StringRef CommentDelimiter, bool IsAlias) const {
10891057 // Reject matchables with no .s string.
10901058 if (AsmString.empty())
10911059 PrintFatalError(TheDef->getLoc(), "instruction with empty asm string");
11181086 PrintFatalError(TheDef->getLoc(),
11191087 "matchable with operand modifier '" + Tok +
11201088 "' not supported by asm matcher. Mark isCodeGenOnly!");
1121
11221089 // Verify that any operand is only mentioned once.
11231090 // We reject aliases and ignore instructions for now.
1124 if (Tok[0] == '$' && !OperandNames.insert(Tok).second) {
1125 if (!Hack)
1126 PrintFatalError(TheDef->getLoc(),
1127 "ERROR: matchable with tied operand '" + Tok +
1128 "' can never be matched!");
1129 // FIXME: Should reject these. The ARM backend hits this with $lane in a
1130 // bunch of instructions. It is unclear what the right answer is.
1091 if (!IsAlias && Tok[0] == '$' && !OperandNames.insert(Tok).second) {
11311092 DEBUG({
11321093 errs() << "warning: '" << TheDef->getName() << "': "
11331094 << "ignoring instruction with tied operand '"
15191480 assert(SubtargetFeatures.size() <= 64 && "Too many subtarget features!");
15201481
15211482 bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst");
1483 bool ReportMultipleNearMisses =
1484 AsmParser->getValueAsBit("ReportMultipleNearMisses");
15221485
15231486 // Parse the instructions; we need to do this first so that we can gather the
15241487 // singleton register classes.
15611524
15621525 // Ignore instructions which shouldn't be matched and diagnose invalid
15631526 // instruction definitions with an error.
1564 if (!II->validate(CommentDelimiter, true))
1527 if (!II->validate(CommentDelimiter, false))
15651528 continue;
15661529
15671530 Matchables.push_back(std::move(II));
15921555 II->initialize(*this, SingletonRegisters, Variant, HasMnemonicFirst);
15931556
15941557 // Validate the alias definitions.
1595 II->validate(CommentDelimiter, false);
1558 II->validate(CommentDelimiter, true);
15961559
15971560 Matchables.push_back(std::move(II));
15981561 }
16651628 NewMatchables.push_back(std::move(AliasII));
16661629 }
16671630 } else
1668 II->buildAliasResultOperands();
1631 // FIXME: The tied operands checking is not yet integrated with the
1632 // framework for reporting multiple near misses. To prevent invalid
1633 // formats from being matched with an alias if a tied-operands check
1634 // would otherwise have disallowed it, we just disallow such constructs
1635 // in TableGen completely.
1636 II->buildAliasResultOperands(!ReportMultipleNearMisses);
16691637 }
16701638 if (!NewMatchables.empty())
16711639 Matchables.insert(Matchables.end(),
17381706
17391707 // Set up the operand class.
17401708 Op->Class = getOperandClass(Operands[Idx], Op->SubOpIdx);
1709 Op->OrigSrcOpName = OperandName;
17411710
17421711 // If the named operand is tied, canonicalize it to the untied operand.
17431712 // For example, something like:
17821751 Op.Class = getOperandClass(CGA.ResultOperands[i].getRecord(),
17831752 Op.SubOpIdx);
17841753 Op.SrcOpName = OperandName;
1754 Op.OrigSrcOpName = OperandName;
17851755 return;
17861756 }
17871757
18001770 if (OpInfo.MINumOperands == 1)
18011771 TiedOp = OpInfo.getTiedRegister();
18021772 if (TiedOp != -1) {
1803 ResOperands.push_back(ResOperand::getTiedOp(TiedOp));
1773 int TiedSrcOperand = findAsmOperandOriginallyNamed(OpInfo.Name);
1774 if (TiedSrcOperand != -1 &&
1775 ResOperands[TiedOp].Kind == ResOperand::RenderAsmOperand)
1776 ResOperands.push_back(ResOperand::getTiedOp(
1777 TiedOp, ResOperands[TiedOp].AsmOperandNum, TiedSrcOperand));
1778 else
1779 ResOperands.push_back(ResOperand::getTiedOp(TiedOp, 0, 0));
18041780 continue;
18051781 }
18061782
1807 // Find out what operand from the asmparser this MCInst operand comes from.
18081783 int SrcOperand = findAsmOperandNamed(OpInfo.Name);
18091784 if (OpInfo.Name.empty() || SrcOperand == -1) {
18101785 // This may happen for operands that are tied to a suboperand of a
18331808 }
18341809 }
18351810
1836 void MatchableInfo::buildAliasResultOperands() {
1811 void MatchableInfo::buildAliasResultOperands(bool AliasConstraintsAreChecked) {
18371812 const CodeGenInstAlias &CGA = *DefRec.get();
18381813 const CodeGenInstruction *ResultInst = getResultInst();
1814
1815 // Map of: $reg -> #lastref
1816 // where $reg is the name of the operand in the asm string
1817 // where #lastref is the last processed index where $reg was referenced in
1818 // the asm string.
1819 SmallDenseMap OperandRefs;
18391820
18401821 // Loop over all operands of the result instruction, determining how to
18411822 // populate them.
18491830 if (OpInfo->MINumOperands == 1)
18501831 TiedOp = OpInfo->getTiedRegister();
18511832 if (TiedOp != -1) {
1852 ResOperands.push_back(ResOperand::getTiedOp(TiedOp));
1833 unsigned SrcOp1 = 0;
1834 unsigned SrcOp2 = 0;
1835
1836 // If an operand has been specified twice in the asm string,
1837 // add the two source operand's indices to the TiedOp so that
1838 // at runtime the 'tied' constraint is checked.
1839 if (ResOperands[TiedOp].Kind == ResOperand::RenderAsmOperand) {
1840 SrcOp1 = ResOperands[TiedOp].AsmOperandNum;
1841
1842 // Find the next operand (similarly named operand) in the string.
1843 StringRef Name = AsmOperands[SrcOp1].SrcOpName;
1844 auto Insert = OperandRefs.try_emplace(Name, SrcOp1);
1845 SrcOp2 = findAsmOperandNamed(Name, Insert.first->second);
1846
1847 // Not updating the record in OperandRefs will cause TableGen
1848 // to fail with an error at the end of this function.
1849 if (AliasConstraintsAreChecked)
1850 Insert.first->second = SrcOp2;
1851
1852 // In case it only has one reference in the asm string,
1853 // it doesn't need to be checked for tied constraints.
1854 SrcOp2 = (SrcOp2 == (unsigned)-1) ? SrcOp1 : SrcOp2;
1855 }
1856
1857 ResOperands.push_back(ResOperand::getTiedOp(TiedOp, SrcOp1, SrcOp2));
18531858 continue;
18541859 }
18551860
18691874 PrintFatalError(TheDef->getLoc(), "Instruction '" +
18701875 TheDef->getName() + "' has operand '" + OpName +
18711876 "' that doesn't appear in asm string!");
1877
1878 // Add it to the operand references. If it is added a second time, the
1879 // record won't be updated and it will fail later on.
1880 OperandRefs.try_emplace(Name, SrcOperand);
1881
18721882 unsigned NumOperands = (SubIdx == -1 ? OpInfo->MINumOperands : 1);
18731883 ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand,
18741884 NumOperands));
18861896 }
18871897 }
18881898 }
1899 }
1900
1901 // Check that operands are not repeated more times than is supported.
1902 for (auto &T : OperandRefs) {
1903 if (T.second != -1 && findAsmOperandNamed(T.first, T.second) != -1)
1904 PrintFatalError(TheDef->getLoc(),
1905 "Operand '" + T.first + "' can never be matched");
18891906 }
18901907 }
18911908
19631980 CvtOS << " static_cast<" << TargetOperandClass
19641981 << "&>(*Operands[OpIdx]).addRegOperands(Inst, 1);\n";
19651982 CvtOS << " break;\n";
1966 CvtOS << " case CVT_Tied:\n";
1967 CvtOS << " Inst.addOperand(Inst.getOperand(OpIdx));\n";
1983 CvtOS << " case CVT_Tied: {\n";
1984 CvtOS << " assert(OpIdx < (std::end(TiedAsmOperandTable) -\n";
1985 CvtOS << " std::begin(TiedAsmOperandTable)) &&\n";
1986 CvtOS << " \"Tied operand not found\");\n";
1987 CvtOS << " unsigned TiedResOpnd = TiedAsmOperandTable[OpIdx][0];\n";
1988 CvtOS << " Inst.addOperand(Inst.getOperand(TiedResOpnd));\n";
19681989 CvtOS << " break;\n";
1990 CvtOS << " }\n";
19691991
19701992 std::string OperandFnBody;
19711993 raw_string_ostream OpOS(OperandFnBody);
19952017 OperandConversionKinds.insert(CachedHashString("CVT_Reg"));
19962018 OperandConversionKinds.insert(CachedHashString("CVT_Tied"));
19972019 enum { CVT_Done, CVT_Reg, CVT_Tied };
2020
2021 // Map of e.g. <0, 2, 3> -> "Tie_0_2_3" enum label.
2022 std::map, std::string>
2023 TiedOperandsEnumMap;
19982024
19992025 for (auto &II : Infos) {
20002026 // Check if we have a custom match function.
21162142 // If this operand is tied to a previous one, just copy the MCInst
21172143 // operand from the earlier one.We can only tie single MCOperand values.
21182144 assert(OpInfo.MINumOperands == 1 && "Not a singular MCOperand");
2119 unsigned TiedOp = OpInfo.TiedOperandNum;
2145 unsigned TiedOp = OpInfo.TiedOperands.ResOpnd;
2146 unsigned SrcOp1 = OpInfo.TiedOperands.SrcOpnd1Idx + HasMnemonicFirst;
2147 unsigned SrcOp2 = OpInfo.TiedOperands.SrcOpnd2Idx + HasMnemonicFirst;
21202148 assert(i > TiedOp && "Tied operand precedes its target!");
2121 Signature += "__Tie" + utostr(TiedOp);
2149 auto TiedTupleName = std::string("Tie") + utostr(TiedOp) + '_' +
2150 utostr(SrcOp1) + '_' + utostr(SrcOp2);
2151 Signature += "__" + TiedTupleName;
21222152 ConversionRow.push_back(CVT_Tied);
21232153 ConversionRow.push_back(TiedOp);
2154 ConversionRow.push_back(SrcOp1);
2155 ConversionRow.push_back(SrcOp2);
2156
2157 // Also create an 'enum' for this combination of tied operands.
2158 auto Key = std::make_tuple(TiedOp, SrcOp1, SrcOp2);
2159 TiedOperandsEnumMap.emplace(Key, TiedTupleName);
21242160 break;
21252161 }
21262162 case MatchableInfo::ResOperand::ImmOperand: {
22052241 // Finish up the operand number lookup function.
22062242 OpOS << " }\n }\n}\n\n";
22072243
2244 // Output a static table for tied operands.
2245 if (TiedOperandsEnumMap.size()) {
2246 // The number of tied operand combinations will be small in practice,
2247 // but just add the assert to be sure.
2248 assert(TiedOperandsEnumMap.size() <= 255 &&
2249 "Too many tied-operand combinations to reference with "
2250 "an 8bit offset from the conversion table");
2251
2252 OS << "enum {\n";
2253 for (auto &KV : TiedOperandsEnumMap) {
2254 OS << " " << KV.second << ",\n";
2255 }
2256 OS << "};\n\n";
2257
2258 OS << "const char TiedAsmOperandTable[][3] = {\n";
2259 for (auto &KV : TiedOperandsEnumMap) {
2260 OS << " /* " << KV.second << " */ { " << std::get<0>(KV.first) << ", "
2261 << std::get<1>(KV.first) << ", " << std::get<2>(KV.first) << " },\n";
2262 }
2263 OS << "};\n\n";
2264 } else
2265 OS << "const char TiedAsmOperandTable[][3] = { /* empty */ {0, 0, 0} "
2266 "};\n\n";
2267
22082268 OS << "namespace {\n";
22092269
22102270 // Output the operand conversion kind enum.
22312291 assert(ConversionTable[Row].size() % 2 == 0 && "bad conversion row!");
22322292 OS << " // " << InstructionConversionKinds[Row] << "\n";
22332293 OS << " { ";
2234 for (unsigned i = 0, e = ConversionTable[Row].size(); i != e; i += 2)
2235 OS << OperandConversionKinds[ConversionTable[Row][i]] << ", "
2236 << (unsigned)(ConversionTable[Row][i + 1]) << ", ";
2294 for (unsigned i = 0, e = ConversionTable[Row].size(); i != e; i += 2) {
2295 OS << OperandConversionKinds[ConversionTable[Row][i]] << ", ";
2296 if (OperandConversionKinds[ConversionTable[Row][i]] !=
2297 CachedHashString("CVT_Tied")) {
2298 OS << (unsigned)(ConversionTable[Row][i + 1]) << ", ";
2299 continue;
2300 }
2301
2302 // For a tied operand, emit a reference to the TiedAsmOperandTable
2303 // that contains the operand to copy, and the parsed operands to
2304 // check for their tied constraints.
2305 auto Key = std::make_tuple((unsigned)ConversionTable[Row][i + 1],
2306 (unsigned)ConversionTable[Row][i + 2],
2307 (unsigned)ConversionTable[Row][i + 3]);
2308 auto TiedOpndEnum = TiedOperandsEnumMap.find(Key);
2309 assert(TiedOpndEnum != TiedOperandsEnumMap.end() &&
2310 "No record for tied operand pair");
2311 OS << TiedOpndEnum->second << ", ";
2312 i += 2;
2313 }
22372314 OS << "CVT_Done },\n";
22382315 }
22392316
28942971 static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
28952972 AsmMatcherInfo &Info,
28962973 raw_ostream &OS) {
2897 std::string Buf;
2898 raw_string_ostream TmpOS(Buf);
2899 TmpOS << "namespace {\n";
2900 TmpOS << " struct TiedAsmOpndPair {\n";
2901 TmpOS << " unsigned Opcode;\n";
2902 TmpOS << " unsigned Opnd1;\n";
2903 TmpOS << " unsigned Opnd2;\n";
2904 TmpOS << " TiedAsmOpndPair(unsigned Opcode, unsigned Opnd1, unsigned "
2905 "Opnd2)\n";
2906 TmpOS << " : Opcode(Opcode), Opnd1(Opnd1), Opnd2(Opnd2) {}\n";
2907 TmpOS << " };\n";
2908 TmpOS << "} // end anonymous namespace\n\n";
2909 TmpOS << "static const TiedAsmOpndPair TiedAsmOperandsTable[] = {\n";
2910 bool TableEmpty = true;
2911 for (const auto &Inst : Target.getInstructionsByEnumValue()) {
2912 auto It = std::find_if(Info.Matchables.begin(), Info.Matchables.end(),
2913 [&Inst](const std::unique_ptr &MI) {
2914 return (MI->TheDef->getID() == Inst->TheDef->getID());
2915 });
2916
2917 if (It == Info.Matchables.end())
2918 continue;
2919
2920 auto &Constraints = (**It).AsmOperandTiedConstraints;
2921 if (Constraints.empty())
2922 continue;
2923
2924 std::string Namespace = Inst->TheDef->getValueAsString("Namespace");
2925
2926 for (const auto &C : Constraints) {
2927 TableEmpty = false;
2928 TmpOS << " {";
2929 TmpOS << Namespace << "::"<< (**It).TheDef->getName() << ", ";
2930 TmpOS << C.first << ", " << C.second;
2931 TmpOS << "},\n";
2932 }
2933 }
2934 TmpOS << "};\n\n";
2935 if (!TableEmpty)
2936 OS << TmpOS.str();
2937
29382974 OS << "static bool ";
2939 OS << "checkAsmTiedOperandConstraints(const MCInst &Inst,\n";
2975 OS << "checkAsmTiedOperandConstraints(unsigned Kind,\n";
29402976 OS << " const OperandVector &Operands,\n";
2941 OS << " SMLoc &Loc) {\n";
2942
2943 if (TableEmpty) {
2944 OS << "return true;\n}\n\n";
2945 return;
2946 }
2947
2948 OS << " const TiedAsmOpndPair SearchValue(Inst.getOpcode(), 0, 0);\n";
2949 OS << " const auto Range = std::equal_range(\n";
2950 OS << " std::begin(TiedAsmOperandsTable), std::end(TiedAsmOperandsTable),\n";
2951 OS << " SearchValue, [](const TiedAsmOpndPair &a,\n";
2952 OS << " const TiedAsmOpndPair &b) {\n";
2953 OS << " return (a.Opcode < b.Opcode);\n";
2954 OS << " });\n\n";
2955 OS << " for (auto Item = Range.first; Item != Range.second; ++Item) {\n";
2956 OS << " MCParsedAsmOperand &Op1 = *Operands[Item->Opnd1];\n";
2957 OS << " MCParsedAsmOperand &Op2 = *Operands[Item->Opnd2];\n";
2958 OS << " if ((Op1.isReg() && Op2.isReg()) &&\n";
2959 OS << " (Op1.getReg() != Op2.getReg())) {\n";
2960 OS << " Loc = Op2.getStartLoc();\n";
2961 OS << " return false;\n";
2977 OS << " uint64_t &ErrorInfo) {\n";
2978 OS << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n";
2979 OS << " const uint8_t *Converter = ConversionTable[Kind];\n";
2980 OS << " for (const uint8_t *p = Converter; *p; p+= 2) {\n";
2981 OS << " switch (*p) {\n";
2982 OS << " case CVT_Tied: {\n";
2983 OS << " unsigned OpIdx = *(p+1);\n";
2984 OS << " assert(OpIdx < (std::end(TiedAsmOperandTable) -\n";
2985 OS << " std::begin(TiedAsmOperandTable)) &&\n";
2986 OS << " \"Tied operand not found\");\n";
2987 OS << " unsigned OpndNum1 = TiedAsmOperandTable[OpIdx][1];\n";
2988 OS << " unsigned OpndNum2 = TiedAsmOperandTable[OpIdx][2];\n";
2989 OS << " if (OpndNum1 != OpndNum2) {\n";
2990 OS << " auto &SrcOp1 = Operands[OpndNum1];\n";
2991 OS << " auto &SrcOp2 = Operands[OpndNum2];\n";
2992 OS << " if (SrcOp1->isReg() && SrcOp2->isReg() &&\n";
2993 OS << " SrcOp1->getReg() != SrcOp2->getReg()) {\n";
2994 OS << " ErrorInfo = OpndNum2;\n";
2995 OS << " return false;\n";
2996 OS << " }\n";
2997 OS << " }\n";
2998 OS << " break;\n";
2999 OS << " }\n";
3000 OS << " default:\n";
3001 OS << " break;\n";
29623002 OS << " }\n";
29633003 OS << " }\n";
29643004 OS << " return true;\n";
36393679 OS << " if (matchingInlineAsm) {\n";
36403680 OS << " convertToMapAndConstraints(it->ConvertFn, Operands);\n";
36413681 if (!ReportMultipleNearMisses) {
3642 OS << " SMLoc Loc;\n";
3643 OS << " if (!checkAsmTiedOperandConstraints(Inst, Operands, Loc)) {\n";
3644 OS << " ErrorInfo = " << (HasMnemonicFirst ? "1" : "SIndex") << ";\n";
3682 OS << " if (!checkAsmTiedOperandConstraints(it->ConvertFn, Operands, ErrorInfo))\n";
36453683 OS << " return Match_InvalidTiedOperand;\n";
3646 OS << " }\n";
36473684 OS << "\n";
36483685 }
36493686 OS << " return Match_Success;\n";
37213758 }
37223759
37233760 if (!ReportMultipleNearMisses) {
3724 OS << " SMLoc Loc;\n";
3725 OS << " if (!checkAsmTiedOperandConstraints(Inst, Operands, Loc)) {\n";
3726 OS << " ErrorInfo = " << (HasMnemonicFirst ? "1" : "SIndex") << ";\n";
3761 OS << " if (!checkAsmTiedOperandConstraints(it->ConvertFn, Operands, ErrorInfo))\n";
37273762 OS << " return Match_InvalidTiedOperand;\n";
3728 OS << " }\n";
37293763 OS << "\n";
37303764 }
37313765