diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
| commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
| tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /utils/TableGen | |
| parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) | |
Notes
Diffstat (limited to 'utils/TableGen')
52 files changed, 6100 insertions, 2510 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index f2d304bfcf5b..e808661b7a51 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/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"; diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index 723c0cd773f7..3c4c9c8e5c6e 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -351,8 +351,8 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { // If we don't have enough bits for this operand, don't include it. if (NumBits > BitsLeft) { - DEBUG(errs() << "Not enough bits to densely encode " << NumBits - << " more bits\n"); + LLVM_DEBUG(errs() << "Not enough bits to densely encode " << NumBits + << " more bits\n"); break; } @@ -727,10 +727,6 @@ public: } // end anonymous namespace static unsigned CountNumOperands(StringRef AsmString, unsigned Variant) { - std::string FlatAsmString = - CodeGenInstruction::FlattenAsmStringVariants(AsmString, Variant); - AsmString = FlatAsmString; - return AsmString.count(' ') + AsmString.count('\t'); } @@ -782,7 +778,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { const DagInit *DI = R->getValueAsDag("ResultInst"); const DefInit *Op = cast<DefInit>(DI->getOperator()); AliasMap[getQualifiedName(Op->getDef())].insert( - std::make_pair(CodeGenInstAlias(R, Variant, Target), Priority)); + std::make_pair(CodeGenInstAlias(R, Target), Priority)); } // A map of which conditions need to be met for each instruction operand @@ -799,14 +795,20 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { for (auto &Alias : Aliases.second) { const CodeGenInstAlias &CGA = Alias.first; unsigned LastOpNo = CGA.ResultInstOperandIndex.size(); - unsigned NumResultOps = - CountNumOperands(CGA.ResultInst->AsmString, Variant); + std::string FlatInstAsmString = + CodeGenInstruction::FlattenAsmStringVariants(CGA.ResultInst->AsmString, + Variant); + unsigned NumResultOps = CountNumOperands(FlatInstAsmString, Variant); + + std::string FlatAliasAsmString = + CodeGenInstruction::FlattenAsmStringVariants(CGA.AsmString, + Variant); // Don't emit the alias if it has more operands than what it's aliasing. - if (NumResultOps < CountNumOperands(CGA.AsmString, Variant)) + if (NumResultOps < CountNumOperands(FlatAliasAsmString, Variant)) continue; - IAPrinter IAP(CGA.Result->getAsString(), CGA.AsmString); + IAPrinter IAP(CGA.Result->getAsString(), FlatAliasAsmString); StringRef Namespace = Target.getName(); std::vector<Record *> ReqFeatures; diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index 0944d54a4273..0428249f9179 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -29,7 +29,9 @@ add_tablegen(llvm-tblgen LLVM InstrDocsEmitter.cpp IntrinsicEmitter.cpp OptParserEmitter.cpp + PredicateExpander.cpp PseudoLoweringEmitter.cpp + RISCVCompressInstEmitter.cpp RegisterBankEmitter.cpp RegisterInfoEmitter.cpp SDNodeProperties.cpp @@ -43,6 +45,7 @@ add_tablegen(llvm-tblgen LLVM X86FoldTablesEmitter.cpp X86ModRMFilters.cpp X86RecognizableInstr.cpp + WebAssemblyDisassemblerEmitter.cpp CTagsEmitter.cpp ) set_target_properties(llvm-tblgen PROPERTIES FOLDER "Tablegenning") diff --git a/utils/TableGen/CTagsEmitter.cpp b/utils/TableGen/CTagsEmitter.cpp index 5213cd904462..a0f83f1c9910 100644 --- a/utils/TableGen/CTagsEmitter.cpp +++ b/utils/TableGen/CTagsEmitter.cpp @@ -73,7 +73,7 @@ void CTagsEmitter::run(raw_ostream &OS) { for (const auto &D : Defs) Tags.push_back(Tag(D.first, locate(D.second.get()))); // Emit tags. - std::sort(Tags.begin(), Tags.end()); + llvm::sort(Tags.begin(), Tags.end()); OS << "!_TAG_FILE_FORMAT\t1\t/original ctags format/\n"; OS << "!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/\n"; for (const Tag &T : Tags) diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index 64cf23314497..1abe3a88bfbf 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -808,7 +808,7 @@ TypeSetByHwMode TypeInfer::getLegalTypes() { #ifndef NDEBUG TypeInfer::ValidateOnExit::~ValidateOnExit() { - if (!VTS.validate()) { + if (Infer.Validate && !VTS.validate()) { dbgs() << "Type set is empty for each HW mode:\n" "possible type contradiction in the pattern below " "(use -print-records with llvm-tblgen to see all " @@ -1134,6 +1134,14 @@ Record *TreePredicateFn::getScalarMemoryVT() const { return nullptr; return R->getValueAsDef("ScalarMemoryVT"); } +bool TreePredicateFn::hasGISelPredicateCode() const { + return !PatFragRec->getRecord() + ->getValueAsString("GISelPredicateCode") + .empty(); +} +std::string TreePredicateFn::getGISelPredicateCode() const { + return PatFragRec->getRecord()->getValueAsString("GISelPredicateCode"); +} StringRef TreePredicateFn::getImmType() const { if (immCodeUsesAPInt()) @@ -1305,7 +1313,7 @@ std::string PatternToMatch::getPredicateCheck() const { SmallVector<const Predicate*,4> PredList; for (const Predicate &P : Predicates) PredList.push_back(&P); - std::sort(PredList.begin(), PredList.end(), deref<llvm::less>()); + llvm::sort(PredList.begin(), PredList.end(), deref<llvm::less>()); std::string Check; for (unsigned i = 0, e = PredList.size(); i != e; ++i) { @@ -1564,7 +1572,7 @@ bool TreePatternNode::hasProperTypeByHwMode() const { for (const TypeSetByHwMode &S : Types) if (!S.isDefaultOnly()) return true; - for (TreePatternNode *C : Children) + for (const TreePatternNodePtr &C : Children) if (C->hasProperTypeByHwMode()) return true; return false; @@ -1574,7 +1582,7 @@ bool TreePatternNode::hasPossibleType() const { for (const TypeSetByHwMode &S : Types) if (!S.isPossible()) return false; - for (TreePatternNode *C : Children) + for (const TreePatternNodePtr &C : Children) if (!C->hasPossibleType()) return false; return true; @@ -1587,7 +1595,7 @@ bool TreePatternNode::setDefaultMode(unsigned Mode) { if (S.get(DefaultMode).empty()) return false; } - for (TreePatternNode *C : Children) + for (const TreePatternNodePtr &C : Children) if (!C->setDefaultMode(Mode)) return false; return true; @@ -1644,13 +1652,6 @@ MVT::SimpleValueType SDNodeInfo::getKnownType(unsigned ResNo) const { // TreePatternNode implementation // -TreePatternNode::~TreePatternNode() { -#if 0 // FIXME: implement refcounted tree nodes! - for (unsigned i = 0, e = getNumChildren(); i != e; ++i) - delete getChild(i); -#endif -} - static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) { if (Operator->getName() == "set" || Operator->getName() == "implicit") @@ -1662,21 +1663,31 @@ static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) { if (Operator->isSubClassOf("SDNode")) return CDP.getSDNodeInfo(Operator).getNumResults(); - if (Operator->isSubClassOf("PatFrag")) { + if (Operator->isSubClassOf("PatFrags")) { // If we've already parsed this pattern fragment, get it. Otherwise, handle // the forward reference case where one pattern fragment references another // before it is processed. - if (TreePattern *PFRec = CDP.getPatternFragmentIfRead(Operator)) - return PFRec->getOnlyTree()->getNumTypes(); + if (TreePattern *PFRec = CDP.getPatternFragmentIfRead(Operator)) { + // The number of results of a fragment with alternative records is the + // maximum number of results across all alternatives. + unsigned NumResults = 0; + for (auto T : PFRec->getTrees()) + NumResults = std::max(NumResults, T->getNumTypes()); + return NumResults; + } - // Get the result tree. - DagInit *Tree = Operator->getValueAsDag("Fragment"); - Record *Op = nullptr; - if (Tree) - if (DefInit *DI = dyn_cast<DefInit>(Tree->getOperator())) - Op = DI->getDef(); - assert(Op && "Invalid Fragment"); - return GetNumNodeResults(Op, CDP); + ListInit *LI = Operator->getValueAsListInit("Fragments"); + assert(LI && "Invalid Fragment"); + unsigned NumResults = 0; + for (Init *I : LI->getValues()) { + Record *Op = nullptr; + if (DagInit *Dag = dyn_cast<DagInit>(I)) + if (DefInit *DI = dyn_cast<DefInit>(Dag->getOperator())) + Op = DI->getDef(); + assert(Op && "Invalid Fragment"); + NumResults = std::max(NumResults, GetNumNodeResults(Op, CDP)); + } + return NumResults; } if (Operator->isSubClassOf("Instruction")) { @@ -1783,16 +1794,17 @@ bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N, /// clone - Make a copy of this tree and all of its children. /// -TreePatternNode *TreePatternNode::clone() const { - TreePatternNode *New; +TreePatternNodePtr TreePatternNode::clone() const { + TreePatternNodePtr New; if (isLeaf()) { - New = new TreePatternNode(getLeafValue(), getNumTypes()); + New = std::make_shared<TreePatternNode>(getLeafValue(), getNumTypes()); } else { - std::vector<TreePatternNode*> CChildren; + std::vector<TreePatternNodePtr> CChildren; CChildren.reserve(Children.size()); for (unsigned i = 0, e = getNumChildren(); i != e; ++i) CChildren.push_back(getChild(i)->clone()); - New = new TreePatternNode(getOperator(), CChildren, getNumTypes()); + New = std::make_shared<TreePatternNode>(getOperator(), std::move(CChildren), + getNumTypes()); } New->setName(getName()); New->Types = Types; @@ -1813,8 +1825,8 @@ void TreePatternNode::RemoveAllTypes() { /// SubstituteFormalArguments - Replace the formal arguments in this tree /// with actual values specified by ArgMap. -void TreePatternNode:: -SubstituteFormalArguments(std::map<std::string, TreePatternNode*> &ArgMap) { +void TreePatternNode::SubstituteFormalArguments( + std::map<std::string, TreePatternNodePtr> &ArgMap) { if (isLeaf()) return; for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { @@ -1826,12 +1838,12 @@ SubstituteFormalArguments(std::map<std::string, TreePatternNode*> &ArgMap) { if (isa<UnsetInit>(Val) || (isa<DefInit>(Val) && cast<DefInit>(Val)->getDef()->getName() == "node")) { // We found a use of a formal argument, replace it with its value. - TreePatternNode *NewChild = ArgMap[Child->getName()]; + TreePatternNodePtr NewChild = ArgMap[Child->getName()]; assert(NewChild && "Couldn't find formal argument!"); assert((Child->getPredicateFns().empty() || NewChild->getPredicateFns() == Child->getPredicateFns()) && "Non-empty child predicate clobbered!"); - setChild(i, NewChild); + setChild(i, std::move(NewChild)); } } else { getChild(i)->SubstituteFormalArguments(ArgMap); @@ -1841,29 +1853,81 @@ SubstituteFormalArguments(std::map<std::string, TreePatternNode*> &ArgMap) { /// InlinePatternFragments - If this pattern refers to any pattern -/// fragments, inline them into place, giving us a pattern without any -/// PatFrag references. -TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { +/// fragments, return the set of inlined versions (this can be more than +/// one if a PatFrags record has multiple alternatives). +void TreePatternNode::InlinePatternFragments( + TreePatternNodePtr T, TreePattern &TP, + std::vector<TreePatternNodePtr> &OutAlternatives) { + if (TP.hasError()) - return nullptr; + return; + + if (isLeaf()) { + OutAlternatives.push_back(T); // nothing to do. + return; + } - if (isLeaf()) - return this; // nothing to do. Record *Op = getOperator(); - if (!Op->isSubClassOf("PatFrag")) { - // Just recursively inline children nodes. - for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { - TreePatternNode *Child = getChild(i); - TreePatternNode *NewChild = Child->InlinePatternFragments(TP); + if (!Op->isSubClassOf("PatFrags")) { + if (getNumChildren() == 0) { + OutAlternatives.push_back(T); + return; + } - assert((Child->getPredicateFns().empty() || - NewChild->getPredicateFns() == Child->getPredicateFns()) && - "Non-empty child predicate clobbered!"); + // Recursively inline children nodes. + std::vector<std::vector<TreePatternNodePtr> > ChildAlternatives; + ChildAlternatives.resize(getNumChildren()); + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { + TreePatternNodePtr Child = getChildShared(i); + Child->InlinePatternFragments(Child, TP, ChildAlternatives[i]); + // If there are no alternatives for any child, there are no + // alternatives for this expression as whole. + if (ChildAlternatives[i].empty()) + return; - setChild(i, NewChild); + for (auto NewChild : ChildAlternatives[i]) + assert((Child->getPredicateFns().empty() || + NewChild->getPredicateFns() == Child->getPredicateFns()) && + "Non-empty child predicate clobbered!"); } - return this; + + // The end result is an all-pairs construction of the resultant pattern. + std::vector<unsigned> Idxs; + Idxs.resize(ChildAlternatives.size()); + bool NotDone; + do { + // Create the variant and add it to the output list. + std::vector<TreePatternNodePtr> NewChildren; + for (unsigned i = 0, e = ChildAlternatives.size(); i != e; ++i) + NewChildren.push_back(ChildAlternatives[i][Idxs[i]]); + TreePatternNodePtr R = std::make_shared<TreePatternNode>( + getOperator(), std::move(NewChildren), getNumTypes()); + + // Copy over properties. + R->setName(getName()); + R->setPredicateFns(getPredicateFns()); + R->setTransformFn(getTransformFn()); + for (unsigned i = 0, e = getNumTypes(); i != e; ++i) + R->setType(i, getExtType(i)); + + // Register alternative. + OutAlternatives.push_back(R); + + // Increment indices to the next permutation by incrementing the + // indices from last index backward, e.g., generate the sequence + // [0, 0], [0, 1], [1, 0], [1, 1]. + int IdxsIdx; + for (IdxsIdx = Idxs.size() - 1; IdxsIdx >= 0; --IdxsIdx) { + if (++Idxs[IdxsIdx] == ChildAlternatives[IdxsIdx].size()) + Idxs[IdxsIdx] = 0; + else + break; + } + NotDone = (IdxsIdx >= 0); + } while (NotDone); + + return; } // Otherwise, we found a reference to a fragment. First, look up its @@ -1874,39 +1938,42 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { if (Frag->getNumArgs() != Children.size()) { TP.error("'" + Op->getName() + "' fragment requires " + Twine(Frag->getNumArgs()) + " operands!"); - return nullptr; + return; } - TreePatternNode *FragTree = Frag->getOnlyTree()->clone(); - - TreePredicateFn PredFn(Frag); - if (!PredFn.isAlwaysTrue()) - FragTree->addPredicateFn(PredFn); + // Compute the map of formal to actual arguments. + std::map<std::string, TreePatternNodePtr> ArgMap; + for (unsigned i = 0, e = Frag->getNumArgs(); i != e; ++i) { + const TreePatternNodePtr &Child = getChildShared(i); + ArgMap[Frag->getArgName(i)] = Child; + } - // Resolve formal arguments to their actual value. - if (Frag->getNumArgs()) { - // Compute the map of formal to actual arguments. - std::map<std::string, TreePatternNode*> ArgMap; - for (unsigned i = 0, e = Frag->getNumArgs(); i != e; ++i) - ArgMap[Frag->getArgName(i)] = getChild(i)->InlinePatternFragments(TP); + // Loop over all fragment alternatives. + for (auto Alternative : Frag->getTrees()) { + TreePatternNodePtr FragTree = Alternative->clone(); - FragTree->SubstituteFormalArguments(ArgMap); - } + TreePredicateFn PredFn(Frag); + if (!PredFn.isAlwaysTrue()) + FragTree->addPredicateFn(PredFn); - FragTree->setName(getName()); - for (unsigned i = 0, e = Types.size(); i != e; ++i) - FragTree->UpdateNodeType(i, getExtType(i), TP); + // Resolve formal arguments to their actual value. + if (Frag->getNumArgs()) + FragTree->SubstituteFormalArguments(ArgMap); - // Transfer in the old predicates. - for (const TreePredicateFn &Pred : getPredicateFns()) - FragTree->addPredicateFn(Pred); + // Transfer types. Note that the resolved alternative may have fewer + // (but not more) results than the PatFrags node. + FragTree->setName(getName()); + for (unsigned i = 0, e = FragTree->getNumTypes(); i != e; ++i) + FragTree->UpdateNodeType(i, getExtType(i), TP); - // Get a new copy of this fragment to stitch into here. - //delete this; // FIXME: implement refcounting! + // Transfer in the old predicates. + for (const TreePredicateFn &Pred : getPredicateFns()) + FragTree->addPredicateFn(Pred); - // The fragment we inlined could have recursive inlining that is needed. See - // if there are any pattern fragments in it and inline them as needed. - return FragTree->InlinePatternFragments(TP); + // The fragment we inlined could have recursive inlining that is needed. See + // if there are any pattern fragments in it and inline them as needed. + FragTree->InlinePatternFragments(FragTree, TP, OutAlternatives); + } } /// getImplicitType - Check to see if the specified record has an implicit @@ -1953,7 +2020,7 @@ static TypeSetByHwMode getImplicitType(Record *R, unsigned ResNo, return TypeSetByHwMode(T.getRegisterClass(R).getValueTypes()); } - if (R->isSubClassOf("PatFrag")) { + if (R->isSubClassOf("PatFrags")) { assert(ResNo == 0 && "FIXME: PatFrag with multiple results?"); // Pattern fragment types will be resolved when they are inlined. return TypeSetByHwMode(); // Unknown. @@ -2205,35 +2272,6 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { return false; } - // special handling for set, which isn't really an SDNode. - if (getOperator()->getName() == "set") { - assert(getNumTypes() == 0 && "Set doesn't produce a value"); - assert(getNumChildren() >= 2 && "Missing RHS of a set?"); - unsigned NC = getNumChildren(); - - TreePatternNode *SetVal = getChild(NC-1); - bool MadeChange = SetVal->ApplyTypeConstraints(TP, NotRegisters); - - for (unsigned i = 0; i < NC-1; ++i) { - TreePatternNode *Child = getChild(i); - MadeChange |= Child->ApplyTypeConstraints(TP, NotRegisters); - - // Types of operands must match. - MadeChange |= Child->UpdateNodeType(0, SetVal->getExtType(i), TP); - MadeChange |= SetVal->UpdateNodeType(i, Child->getExtType(0), TP); - } - return MadeChange; - } - - if (getOperator()->getName() == "implicit") { - assert(getNumTypes() == 0 && "Node doesn't produce a value"); - - bool MadeChange = false; - for (unsigned i = 0; i < getNumChildren(); ++i) - MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters); - return MadeChange; - } - if (const CodeGenIntrinsic *Int = getIntrinsicInfo(CDP)) { bool MadeChange = false; @@ -2508,10 +2546,10 @@ TreePattern::TreePattern(Record *TheRec, DagInit *Pat, bool isInput, Trees.push_back(ParseTreePattern(Pat, "")); } -TreePattern::TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput, - CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp), - isInputPattern(isInput), HasError(false), - Infer(*this) { +TreePattern::TreePattern(Record *TheRec, TreePatternNodePtr Pat, bool isInput, + CodeGenDAGPatterns &cdp) + : TheRecord(TheRec), CDP(cdp), isInputPattern(isInput), HasError(false), + Infer(*this) { Trees.push_back(Pat); } @@ -2524,8 +2562,8 @@ void TreePattern::error(const Twine &Msg) { } void TreePattern::ComputeNamedNodes() { - for (TreePatternNode *Tree : Trees) - ComputeNamedNodes(Tree); + for (TreePatternNodePtr &Tree : Trees) + ComputeNamedNodes(Tree.get()); } void TreePattern::ComputeNamedNodes(TreePatternNode *N) { @@ -2536,22 +2574,22 @@ void TreePattern::ComputeNamedNodes(TreePatternNode *N) { ComputeNamedNodes(N->getChild(i)); } - -TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ +TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit, + StringRef OpName) { if (DefInit *DI = dyn_cast<DefInit>(TheInit)) { Record *R = DI->getDef(); // Direct reference to a leaf DagNode or PatFrag? Turn it into a // TreePatternNode of its own. For example: /// (foo GPR, imm) -> (foo GPR, (imm)) - if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrag")) + if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrags")) return ParseTreePattern( DagInit::get(DI, nullptr, std::vector<std::pair<Init*, StringInit*> >()), OpName); // Input argument? - TreePatternNode *Res = new TreePatternNode(DI, 1); + TreePatternNodePtr Res = std::make_shared<TreePatternNode>(DI, 1); if (R->getName() == "node" && !OpName.empty()) { if (OpName.empty()) error("'node' argument requires a name to match with operand list"); @@ -2566,16 +2604,18 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ if (isa<UnsetInit>(TheInit)) { if (OpName.empty()) error("'?' argument requires a name to match with operand list"); - TreePatternNode *Res = new TreePatternNode(TheInit, 1); + TreePatternNodePtr Res = std::make_shared<TreePatternNode>(TheInit, 1); Args.push_back(OpName); Res->setName(OpName); return Res; } - if (IntInit *II = dyn_cast<IntInit>(TheInit)) { + if (isa<IntInit>(TheInit) || isa<BitInit>(TheInit)) { if (!OpName.empty()) - error("Constant int argument should not have a name!"); - return new TreePatternNode(II, 1); + error("Constant int or bit argument should not have a name!"); + if (isa<BitInit>(TheInit)) + TheInit = TheInit->convertInitializerTo(IntRecTy::get()); + return std::make_shared<TreePatternNode>(TheInit, 1); } if (BitsInit *BI = dyn_cast<BitsInit>(TheInit)) { @@ -2601,8 +2641,8 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ if (Dag->getNumArgs() != 1) error("Type cast only takes one operand!"); - TreePatternNode *New = ParseTreePattern(Dag->getArg(0), - Dag->getArgNameStr(0)); + TreePatternNodePtr New = + ParseTreePattern(Dag->getArg(0), Dag->getArgNameStr(0)); // Apply the type cast. assert(New->getNumTypes() == 1 && "FIXME: Unhandled"); @@ -2615,7 +2655,7 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ } // Verify that this is something that makes sense for an operator. - if (!Operator->isSubClassOf("PatFrag") && + if (!Operator->isSubClassOf("PatFrags") && !Operator->isSubClassOf("SDNode") && !Operator->isSubClassOf("Instruction") && !Operator->isSubClassOf("SDNodeXForm") && @@ -2650,13 +2690,17 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ error("Cannot use '" + Operator->getName() + "' in an output pattern!"); } - std::vector<TreePatternNode*> Children; + std::vector<TreePatternNodePtr> Children; // Parse all the operands. for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) Children.push_back(ParseTreePattern(Dag->getArg(i), Dag->getArgNameStr(i))); - // If the operator is an intrinsic, then this is just syntactic sugar for for + // Get the actual number of results before Operator is converted to an intrinsic + // node (which is hard-coded to have either zero or one result). + unsigned NumResults = GetNumNodeResults(Operator, CDP); + + // If the operator is an intrinsic, then this is just syntactic sugar for // (intrinsic_* <number>, ..children..). Pick the right intrinsic node, and // convert the intrinsic name to a number. if (Operator->isSubClassOf("Intrinsic")) { @@ -2673,13 +2717,13 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ else // Otherwise, no chain. Operator = getDAGPatterns().get_intrinsic_wo_chain_sdnode(); - TreePatternNode *IIDNode = new TreePatternNode(IntInit::get(IID), 1); - Children.insert(Children.begin(), IIDNode); + Children.insert(Children.begin(), + std::make_shared<TreePatternNode>(IntInit::get(IID), 1)); } if (Operator->isSubClassOf("ComplexPattern")) { for (unsigned i = 0; i < Children.size(); ++i) { - TreePatternNode *Child = Children[i]; + TreePatternNodePtr Child = Children[i]; if (Child->getName().empty()) error("All arguments to a ComplexPattern must be named"); @@ -2698,8 +2742,9 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ } } - unsigned NumResults = GetNumNodeResults(Operator, CDP); - TreePatternNode *Result = new TreePatternNode(Operator, Children, NumResults); + TreePatternNodePtr Result = + std::make_shared<TreePatternNode>(Operator, std::move(Children), + NumResults); Result->setName(OpName); if (Dag->getName()) { @@ -2715,7 +2760,7 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ /// more type generic things and have useless type casts fold away. /// /// This returns true if any change is made. -static bool SimplifyTree(TreePatternNode *&N) { +static bool SimplifyTree(TreePatternNodePtr &N) { if (N->isLeaf()) return false; @@ -2725,7 +2770,7 @@ static bool SimplifyTree(TreePatternNode *&N) { N->getExtType(0).isValueTypeByHwMode(false) && N->getExtType(0) == N->getChild(0)->getExtType(0) && N->getName().empty()) { - N = N->getChild(0); + N = N->getChildShared(0); SimplifyTree(N); return true; } @@ -2733,9 +2778,9 @@ static bool SimplifyTree(TreePatternNode *&N) { // Walk all children. bool MadeChange = false; for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) { - TreePatternNode *Child = N->getChild(i); + TreePatternNodePtr Child = N->getChildShared(i); MadeChange |= SimplifyTree(Child); - N->setChild(i, Child); + N->setChild(i, std::move(Child)); } return MadeChange; } @@ -2753,7 +2798,7 @@ InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) { bool MadeChange = true; while (MadeChange) { MadeChange = false; - for (TreePatternNode *&Tree : Trees) { + for (TreePatternNodePtr &Tree : Trees) { MadeChange |= Tree->ApplyTypeConstraints(*this, false); MadeChange |= SimplifyTree(Tree); } @@ -2781,7 +2826,7 @@ InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) { // changing the type of the input register in this case. This allows // us to match things like: // def : Pat<(v1i64 (bitconvert(v2i32 DPR:$src))), (v1i64 DPR:$src)>; - if (Node == Trees[0] && Node->isLeaf()) { + if (Node == Trees[0].get() && Node->isLeaf()) { DefInit *DI = dyn_cast<DefInit>(Node->getLeafValue()); if (DI && (DI->getDef()->isSubClassOf("RegisterClass") || DI->getDef()->isSubClassOf("RegisterOperand"))) @@ -2812,7 +2857,7 @@ InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) { } bool HasUnresolvedTypes = false; - for (const TreePatternNode *Tree : Trees) + for (const TreePatternNodePtr &Tree : Trees) HasUnresolvedTypes |= Tree->ContainsUnresolvedType(*this); return !HasUnresolvedTypes; } @@ -2829,7 +2874,7 @@ void TreePattern::print(raw_ostream &OS) const { if (Trees.size() > 1) OS << "[\n"; - for (const TreePatternNode *Tree : Trees) { + for (const TreePatternNodePtr &Tree : Trees) { OS << "\t"; Tree->print(OS); OS << "\n"; @@ -2933,17 +2978,17 @@ void CodeGenDAGPatterns::ParseComplexPatterns() { /// inside a pattern fragment to a pattern fragment. /// void CodeGenDAGPatterns::ParsePatternFragments(bool OutFrags) { - std::vector<Record*> Fragments = Records.getAllDerivedDefinitions("PatFrag"); + std::vector<Record*> Fragments = Records.getAllDerivedDefinitions("PatFrags"); // First step, parse all of the fragments. for (Record *Frag : Fragments) { if (OutFrags != Frag->isSubClassOf("OutPatFrag")) continue; - DagInit *Tree = Frag->getValueAsDag("Fragment"); + ListInit *LI = Frag->getValueAsListInit("Fragments"); TreePattern *P = (PatternFragments[Frag] = llvm::make_unique<TreePattern>( - Frag, Tree, !Frag->isSubClassOf("OutPatFrag"), + Frag, LI, !Frag->isSubClassOf("OutPatFrag"), *this)).get(); // Validate the argument list, converting it to set, to discard duplicates. @@ -2991,13 +3036,15 @@ void CodeGenDAGPatterns::ParsePatternFragments(bool OutFrags) { // this fragment uses it. TreePredicateFn PredFn(P); if (!PredFn.isAlwaysTrue()) - P->getOnlyTree()->addPredicateFn(PredFn); + for (auto T : P->getTrees()) + T->addPredicateFn(PredFn); // If there is a node transformation corresponding to this, keep track of // it. Record *Transform = Frag->getValueAsDef("OperandTransform"); if (!getSDNodeTransform(Transform).second.empty()) // not noop xform? - P->getOnlyTree()->setTransformFn(Transform); + for (auto T : P->getTrees()) + T->setTransformFn(Transform); } // Now that we've parsed all of the tree fragments, do a closure on them so @@ -3010,12 +3057,18 @@ void CodeGenDAGPatterns::ParsePatternFragments(bool OutFrags) { ThePat.InlinePatternFragments(); // Infer as many types as possible. Don't worry about it if we don't infer - // all of them, some may depend on the inputs of the pattern. - ThePat.InferAllTypes(); - ThePat.resetError(); + // all of them, some may depend on the inputs of the pattern. Also, don't + // validate type sets; validation may cause spurious failures e.g. if a + // fragment needs floating-point types but the current target does not have + // any (this is only an error if that fragment is ever used!). + { + TypeInfer::SuppressValidation SV(ThePat.getInfer()); + ThePat.InferAllTypes(); + ThePat.resetError(); + } // If debugging, print out the pattern fragment result. - DEBUG(ThePat.dump()); + LLVM_DEBUG(ThePat.dump()); } } @@ -3045,9 +3098,9 @@ void CodeGenDAGPatterns::ParseDefaultOperands() { // Copy the operands over into a DAGDefaultOperand. DAGDefaultOperand DefaultOpInfo; - TreePatternNode *T = P.getTree(0); + const TreePatternNodePtr &T = P.getTree(0); for (unsigned op = 0, e = T->getNumChildren(); op != e; ++op) { - TreePatternNode *TPN = T->getChild(op); + TreePatternNodePtr TPN = T->getChildShared(op); while (TPN->ApplyTypeConstraints(P, false)) /* Resolve all types */; @@ -3056,7 +3109,7 @@ void CodeGenDAGPatterns::ParseDefaultOperands() { DefaultOps[i]->getName() + "' doesn't have a concrete type!"); } - DefaultOpInfo.DefaultOps.push_back(TPN); + DefaultOpInfo.DefaultOps.push_back(std::move(TPN)); } // Insert it into the DefaultOperands map so we can find it later. @@ -3066,15 +3119,15 @@ void CodeGenDAGPatterns::ParseDefaultOperands() { /// HandleUse - Given "Pat" a leaf in the pattern, check to see if it is an /// instruction input. Return true if this is a real use. -static bool HandleUse(TreePattern *I, TreePatternNode *Pat, - std::map<std::string, TreePatternNode*> &InstInputs) { +static bool HandleUse(TreePattern &I, TreePatternNodePtr Pat, + std::map<std::string, TreePatternNodePtr> &InstInputs) { // No name -> not interesting. if (Pat->getName().empty()) { if (Pat->isLeaf()) { DefInit *DI = dyn_cast<DefInit>(Pat->getLeafValue()); if (DI && (DI->getDef()->isSubClassOf("RegisterClass") || DI->getDef()->isSubClassOf("RegisterOperand"))) - I->error("Input " + DI->getDef()->getName() + " must be named!"); + I.error("Input " + DI->getDef()->getName() + " must be named!"); } return false; } @@ -3082,7 +3135,8 @@ static bool HandleUse(TreePattern *I, TreePatternNode *Pat, Record *Rec; if (Pat->isLeaf()) { DefInit *DI = dyn_cast<DefInit>(Pat->getLeafValue()); - if (!DI) I->error("Input $" + Pat->getName() + " must be an identifier!"); + if (!DI) + I.error("Input $" + Pat->getName() + " must be an identifier!"); Rec = DI->getDef(); } else { Rec = Pat->getOperator(); @@ -3092,7 +3146,7 @@ static bool HandleUse(TreePattern *I, TreePatternNode *Pat, if (Rec->getName() == "srcvalue") return false; - TreePatternNode *&Slot = InstInputs[Pat->getName()]; + TreePatternNodePtr &Slot = InstInputs[Pat->getName()]; if (!Slot) { Slot = Pat; return true; @@ -3107,24 +3161,38 @@ static bool HandleUse(TreePattern *I, TreePatternNode *Pat, // Ensure that the inputs agree if we've already seen this input. if (Rec != SlotRec) - I->error("All $" + Pat->getName() + " inputs must agree with each other"); + I.error("All $" + Pat->getName() + " inputs must agree with each other"); + // Ensure that the types can agree as well. + Slot->UpdateNodeType(0, Pat->getExtType(0), I); + Pat->UpdateNodeType(0, Slot->getExtType(0), I); if (Slot->getExtTypes() != Pat->getExtTypes()) - I->error("All $" + Pat->getName() + " inputs must agree with each other"); + I.error("All $" + Pat->getName() + " inputs must agree with each other"); return true; } /// FindPatternInputsAndOutputs - Scan the specified TreePatternNode (which is /// part of "I", the instruction), computing the set of inputs and outputs of /// the pattern. Report errors if we see anything naughty. -void CodeGenDAGPatterns:: -FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, - std::map<std::string, TreePatternNode*> &InstInputs, - std::map<std::string, TreePatternNode*>&InstResults, - std::vector<Record*> &InstImpResults) { +void CodeGenDAGPatterns::FindPatternInputsAndOutputs( + TreePattern &I, TreePatternNodePtr Pat, + std::map<std::string, TreePatternNodePtr> &InstInputs, + std::map<std::string, TreePatternNodePtr> &InstResults, + std::vector<Record *> &InstImpResults) { + + // The instruction pattern still has unresolved fragments. For *named* + // nodes we must resolve those here. This may not result in multiple + // alternatives. + if (!Pat->getName().empty()) { + TreePattern SrcPattern(I.getRecord(), Pat, true, *this); + SrcPattern.InlinePatternFragments(); + SrcPattern.InferAllTypes(); + Pat = SrcPattern.getOnlyTree(); + } + if (Pat->isLeaf()) { bool isUse = HandleUse(I, Pat, InstInputs); if (!isUse && Pat->getTransformFn()) - I->error("Cannot specify a transform function for a non-input value!"); + I.error("Cannot specify a transform function for a non-input value!"); return; } @@ -3132,11 +3200,11 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i) { TreePatternNode *Dest = Pat->getChild(i); if (!Dest->isLeaf()) - I->error("implicitly defined value should be a register!"); + I.error("implicitly defined value should be a register!"); DefInit *Val = dyn_cast<DefInit>(Dest->getLeafValue()); if (!Val || !Val->getDef()->isSubClassOf("Register")) - I->error("implicitly defined value should be a register!"); + I.error("implicitly defined value should be a register!"); InstImpResults.push_back(Val->getDef()); } return; @@ -3147,9 +3215,9 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, // and recurse. for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i) { if (Pat->getChild(i)->getNumTypes() == 0) - I->error("Cannot have void nodes inside of patterns!"); - FindPatternInputsAndOutputs(I, Pat->getChild(i), InstInputs, InstResults, - InstImpResults); + I.error("Cannot have void nodes inside of patterns!"); + FindPatternInputsAndOutputs(I, Pat->getChildShared(i), InstInputs, + InstResults, InstImpResults); } // If this is a non-leaf node with no children, treat it basically as if @@ -3157,27 +3225,33 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, bool isUse = HandleUse(I, Pat, InstInputs); if (!isUse && Pat->getTransformFn()) - I->error("Cannot specify a transform function for a non-input value!"); + I.error("Cannot specify a transform function for a non-input value!"); return; } // Otherwise, this is a set, validate and collect instruction results. if (Pat->getNumChildren() == 0) - I->error("set requires operands!"); + I.error("set requires operands!"); if (Pat->getTransformFn()) - I->error("Cannot specify a transform function on a set node!"); + I.error("Cannot specify a transform function on a set node!"); // Check the set destinations. unsigned NumDests = Pat->getNumChildren()-1; for (unsigned i = 0; i != NumDests; ++i) { - TreePatternNode *Dest = Pat->getChild(i); + TreePatternNodePtr Dest = Pat->getChildShared(i); + // For set destinations we also must resolve fragments here. + TreePattern DestPattern(I.getRecord(), Dest, false, *this); + DestPattern.InlinePatternFragments(); + DestPattern.InferAllTypes(); + Dest = DestPattern.getOnlyTree(); + if (!Dest->isLeaf()) - I->error("set destination should be a register!"); + I.error("set destination should be a register!"); DefInit *Val = dyn_cast<DefInit>(Dest->getLeafValue()); if (!Val) { - I->error("set destination should be a register!"); + I.error("set destination should be a register!"); continue; } @@ -3186,20 +3260,20 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, Val->getDef()->isSubClassOf("RegisterOperand") || Val->getDef()->isSubClassOf("PointerLikeRegClass")) { if (Dest->getName().empty()) - I->error("set destination must have a name!"); + I.error("set destination must have a name!"); if (InstResults.count(Dest->getName())) - I->error("cannot set '" + Dest->getName() +"' multiple times"); + I.error("cannot set '" + Dest->getName() + "' multiple times"); InstResults[Dest->getName()] = Dest; } else if (Val->getDef()->isSubClassOf("Register")) { InstImpResults.push_back(Val->getDef()); } else { - I->error("set destination should be a register!"); + I.error("set destination should be a register!"); } } // Verify and collect info from the computation. - FindPatternInputsAndOutputs(I, Pat->getChild(NumDests), - InstInputs, InstResults, InstImpResults); + FindPatternInputsAndOutputs(I, Pat->getChildShared(NumDests), InstInputs, + InstResults, InstImpResults); } //===----------------------------------------------------------------------===// @@ -3214,18 +3288,17 @@ public: bool mayLoad; bool isBitcast; bool isVariadic; + bool hasChain; InstAnalyzer(const CodeGenDAGPatterns &cdp) : CDP(cdp), hasSideEffects(false), mayStore(false), mayLoad(false), - isBitcast(false), isVariadic(false) {} - - void Analyze(const TreePattern *Pat) { - // Assume only the first tree is the pattern. The others are clobber nodes. - AnalyzeNode(Pat->getTree(0)); - } + isBitcast(false), isVariadic(false), hasChain(false) {} void Analyze(const PatternToMatch &Pat) { - AnalyzeNode(Pat.getSrcPattern()); + const TreePatternNode *N = Pat.getSrcPattern(); + AnalyzeNode(N); + // These properties are detected only on the root node. + isBitcast = IsNodeBitcast(N); } private: @@ -3233,20 +3306,12 @@ private: if (hasSideEffects || mayLoad || mayStore || isVariadic) return false; - if (N->getNumChildren() != 2) + if (N->isLeaf()) return false; - - const TreePatternNode *N0 = N->getChild(0); - if (!N0->isLeaf() || !isa<DefInit>(N0->getLeafValue())) + if (N->getNumChildren() != 1 || !N->getChild(0)->isLeaf()) return false; - const TreePatternNode *N1 = N->getChild(1); - if (N1->isLeaf()) - return false; - if (N1->getNumChildren() != 1 || !N1->getChild(0)->isLeaf()) - return false; - - const SDNodeInfo &OpInfo = CDP.getSDNodeInfo(N1->getOperator()); + const SDNodeInfo &OpInfo = CDP.getSDNodeInfo(N->getOperator()); if (OpInfo.getNumResults() != 1 || OpInfo.getNumOperands() != 1) return false; return OpInfo.getEnumName() == "ISD::BITCAST"; @@ -3272,17 +3337,12 @@ public: for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) AnalyzeNode(N->getChild(i)); - // Ignore set nodes, which are not SDNodes. - if (N->getOperator()->getName() == "set") { - isBitcast = IsNodeBitcast(N); - return; - } - // Notice properties of the node. if (N->NodeHasProperty(SDNPMayStore, CDP)) mayStore = true; if (N->NodeHasProperty(SDNPMayLoad, CDP)) mayLoad = true; if (N->NodeHasProperty(SDNPSideEffect, CDP)) hasSideEffects = true; if (N->NodeHasProperty(SDNPVariadic, CDP)) isVariadic = true; + if (N->NodeHasProperty(SDNPHasChain, CDP)) hasChain = true; if (const CodeGenIntrinsic *IntInfo = N->getIntrinsicInfo(CDP)) { // If this is an intrinsic, analyze it. @@ -3345,7 +3405,13 @@ static bool InferFromPattern(CodeGenInstruction &InstInfo, InstInfo.mayLoad |= PatInfo.mayLoad; // These flags are silently added without any verification. - InstInfo.isBitcast |= PatInfo.isBitcast; + // FIXME: To match historical behavior of TableGen, for now add those flags + // only when we're inferring from the primary instruction pattern. + if (PatDef->isSubClassOf("Instruction")) { + InstInfo.isBitcast |= PatInfo.isBitcast; + InstInfo.hasChain |= PatInfo.hasChain; + InstInfo.hasChain_Inferred = true; + } // Don't infer isVariadic. This flag means something different on SDNodes and // instructions. For example, a CALL SDNode is variadic because it has the @@ -3416,37 +3482,30 @@ static bool checkOperandClass(CGIOperandList::OperandInfo &OI, return false; } -const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern( +void CodeGenDAGPatterns::parseInstructionPattern( CodeGenInstruction &CGI, ListInit *Pat, DAGInstMap &DAGInsts) { assert(!DAGInsts.count(CGI.TheDef) && "Instruction already parsed!"); // Parse the instruction. - TreePattern *I = new TreePattern(CGI.TheDef, Pat, true, *this); - // Inline pattern fragments into it. - I->InlinePatternFragments(); - - // Infer as many types as possible. If we cannot infer all of them, we can - // never do anything with this instruction pattern: report it to the user. - if (!I->InferAllTypes()) - I->error("Could not infer all types in pattern!"); + TreePattern I(CGI.TheDef, Pat, true, *this); // InstInputs - Keep track of all of the inputs of the instruction, along // with the record they are declared as. - std::map<std::string, TreePatternNode*> InstInputs; + std::map<std::string, TreePatternNodePtr> InstInputs; // InstResults - Keep track of all the virtual registers that are 'set' // in the instruction, including what reg class they are. - std::map<std::string, TreePatternNode*> InstResults; + std::map<std::string, TreePatternNodePtr> InstResults; std::vector<Record*> InstImpResults; // Verify that the top-level forms in the instruction are of void type, and // fill in the InstResults map. SmallString<32> TypesString; - for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) { + for (unsigned j = 0, e = I.getNumTrees(); j != e; ++j) { TypesString.clear(); - TreePatternNode *Pat = I->getTree(j); + TreePatternNodePtr Pat = I.getTree(j); if (Pat->getNumTypes() != 0) { raw_svector_ostream OS(TypesString); for (unsigned k = 0, ke = Pat->getNumTypes(); k != ke; ++k) { @@ -3454,7 +3513,7 @@ const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern( OS << ", "; Pat->getExtType(k).writeToStream(OS); } - I->error("Top-level forms in instruction pattern should have" + I.error("Top-level forms in instruction pattern should have" " void types, has types " + OS.str()); } @@ -3470,31 +3529,31 @@ const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern( unsigned NumResults = InstResults.size(); // Parse the operands list from the (ops) list, validating it. - assert(I->getArgList().empty() && "Args list should still be empty here!"); + assert(I.getArgList().empty() && "Args list should still be empty here!"); // Check that all of the results occur first in the list. std::vector<Record*> Results; - SmallVector<TreePatternNode *, 2> ResNodes; + SmallVector<TreePatternNodePtr, 2> ResNodes; for (unsigned i = 0; i != NumResults; ++i) { if (i == CGI.Operands.size()) - I->error("'" + InstResults.begin()->first + + I.error("'" + InstResults.begin()->first + "' set but does not appear in operand list!"); const std::string &OpName = CGI.Operands[i].Name; // Check that it exists in InstResults. - TreePatternNode *RNode = InstResults[OpName]; + TreePatternNodePtr RNode = InstResults[OpName]; if (!RNode) - I->error("Operand $" + OpName + " does not exist in operand list!"); + I.error("Operand $" + OpName + " does not exist in operand list!"); - ResNodes.push_back(RNode); Record *R = cast<DefInit>(RNode->getLeafValue())->getDef(); + ResNodes.push_back(std::move(RNode)); if (!R) - I->error("Operand $" + OpName + " should be a set destination: all " + I.error("Operand $" + OpName + " should be a set destination: all " "outputs must occur before inputs in operand list!"); if (!checkOperandClass(CGI.Operands[i], R)) - I->error("Operand $" + OpName + " class mismatch!"); + I.error("Operand $" + OpName + " class mismatch!"); // Remember the return type. Results.push_back(CGI.Operands[i].Rec); @@ -3503,19 +3562,16 @@ const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern( InstResults.erase(OpName); } - // Loop over the inputs next. Make a copy of InstInputs so we can destroy - // the copy while we're checking the inputs. - std::map<std::string, TreePatternNode*> InstInputsCheck(InstInputs); - - std::vector<TreePatternNode*> ResultNodeOperands; + // Loop over the inputs next. + std::vector<TreePatternNodePtr> ResultNodeOperands; std::vector<Record*> Operands; for (unsigned i = NumResults, e = CGI.Operands.size(); i != e; ++i) { CGIOperandList::OperandInfo &Op = CGI.Operands[i]; const std::string &OpName = Op.Name; if (OpName.empty()) - I->error("Operand #" + Twine(i) + " in operands list has no name!"); + I.error("Operand #" + Twine(i) + " in operands list has no name!"); - if (!InstInputsCheck.count(OpName)) { + if (!InstInputs.count(OpName)) { // If this is an operand with a DefaultOps set filled in, we can ignore // this. When we codegen it, we will do so as always executed. if (Op.Rec->isSubClassOf("OperandWithDefaultOps")) { @@ -3524,22 +3580,22 @@ const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern( if (!getDefaultOperand(Op.Rec).DefaultOps.empty()) continue; } - I->error("Operand $" + OpName + + I.error("Operand $" + OpName + " does not appear in the instruction pattern"); } - TreePatternNode *InVal = InstInputsCheck[OpName]; - InstInputsCheck.erase(OpName); // It occurred, remove from map. + TreePatternNodePtr InVal = InstInputs[OpName]; + InstInputs.erase(OpName); // It occurred, remove from map. if (InVal->isLeaf() && isa<DefInit>(InVal->getLeafValue())) { Record *InRec = static_cast<DefInit*>(InVal->getLeafValue())->getDef(); if (!checkOperandClass(Op, InRec)) - I->error("Operand $" + OpName + "'s register class disagrees" + I.error("Operand $" + OpName + "'s register class disagrees" " between the operand and pattern"); } Operands.push_back(Op.Rec); // Construct the result for the dest-pattern operand list. - TreePatternNode *OpNode = InVal->clone(); + TreePatternNodePtr OpNode = InVal->clone(); // No predicate is useful on the result. OpNode->clearPredicateFns(); @@ -3547,42 +3603,47 @@ const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern( // Promote the xform function to be an explicit node if set. if (Record *Xform = OpNode->getTransformFn()) { OpNode->setTransformFn(nullptr); - std::vector<TreePatternNode*> Children; + std::vector<TreePatternNodePtr> Children; Children.push_back(OpNode); - OpNode = new TreePatternNode(Xform, Children, OpNode->getNumTypes()); + OpNode = std::make_shared<TreePatternNode>(Xform, std::move(Children), + OpNode->getNumTypes()); } - ResultNodeOperands.push_back(OpNode); + ResultNodeOperands.push_back(std::move(OpNode)); } - if (!InstInputsCheck.empty()) - I->error("Input operand $" + InstInputsCheck.begin()->first + - " occurs in pattern but not in operands list!"); + if (!InstInputs.empty()) + I.error("Input operand $" + InstInputs.begin()->first + + " occurs in pattern but not in operands list!"); - TreePatternNode *ResultPattern = - new TreePatternNode(I->getRecord(), ResultNodeOperands, - GetNumNodeResults(I->getRecord(), *this)); + TreePatternNodePtr ResultPattern = std::make_shared<TreePatternNode>( + I.getRecord(), std::move(ResultNodeOperands), + GetNumNodeResults(I.getRecord(), *this)); // Copy fully inferred output node types to instruction result pattern. for (unsigned i = 0; i != NumResults; ++i) { assert(ResNodes[i]->getNumTypes() == 1 && "FIXME: Unhandled"); ResultPattern->setType(i, ResNodes[i]->getExtType(0)); } + // FIXME: Assume only the first tree is the pattern. The others are clobber + // nodes. + TreePatternNodePtr Pattern = I.getTree(0); + TreePatternNodePtr SrcPattern; + if (Pattern->getOperator()->getName() == "set") { + SrcPattern = Pattern->getChild(Pattern->getNumChildren()-1)->clone(); + } else{ + // Not a set (store or something?) + SrcPattern = Pattern; + } + // Create and insert the instruction. // FIXME: InstImpResults should not be part of DAGInstruction. - DAGInstruction TheInst(I, Results, Operands, InstImpResults); - DAGInsts.insert(std::make_pair(I->getRecord(), TheInst)); - - // Use a temporary tree pattern to infer all types and make sure that the - // constructed result is correct. This depends on the instruction already - // being inserted into the DAGInsts map. - TreePattern Temp(I->getRecord(), ResultPattern, false, *this); - Temp.InferAllTypes(&I->getNamedNodesMap()); + Record *R = I.getRecord(); + DAGInsts.emplace(std::piecewise_construct, std::forward_as_tuple(R), + std::forward_as_tuple(Results, Operands, InstImpResults, + SrcPattern, ResultPattern)); - DAGInstruction &TheInsertedInst = DAGInsts.find(I->getRecord())->second; - TheInsertedInst.setResultPattern(Temp.getOnlyTree()); - - return TheInsertedInst; + LLVM_DEBUG(I.dump()); } /// ParseInstructions - Parse all of the instructions, inlining and resolving @@ -3622,51 +3683,32 @@ void CodeGenDAGPatterns::ParseInstructions() { // Create and insert the instruction. std::vector<Record*> ImpResults; Instructions.insert(std::make_pair(Instr, - DAGInstruction(nullptr, Results, Operands, ImpResults))); + DAGInstruction(Results, Operands, ImpResults))); continue; // no pattern. } CodeGenInstruction &CGI = Target.getInstruction(Instr); - const DAGInstruction &DI = parseInstructionPattern(CGI, LI, Instructions); - - (void)DI; - DEBUG(DI.getPattern()->dump()); + parseInstructionPattern(CGI, LI, Instructions); } // If we can, convert the instructions to be patterns that are matched! for (auto &Entry : Instructions) { + Record *Instr = Entry.first; DAGInstruction &TheInst = Entry.second; - TreePattern *I = TheInst.getPattern(); - if (!I) continue; // No pattern. - - if (PatternRewriter) - PatternRewriter(I); - // FIXME: Assume only the first tree is the pattern. The others are clobber - // nodes. - TreePatternNode *Pattern = I->getTree(0); - TreePatternNode *SrcPattern; - if (Pattern->getOperator()->getName() == "set") { - SrcPattern = Pattern->getChild(Pattern->getNumChildren()-1)->clone(); - } else{ - // Not a set (store or something?) - SrcPattern = Pattern; - } + TreePatternNodePtr SrcPattern = TheInst.getSrcPattern(); + TreePatternNodePtr ResultPattern = TheInst.getResultPattern(); - Record *Instr = Entry.first; - ListInit *Preds = Instr->getValueAsListInit("Predicates"); - int Complexity = Instr->getValueAsInt("AddedComplexity"); - AddPatternToMatch( - I, - PatternToMatch(Instr, makePredList(Preds), SrcPattern, - TheInst.getResultPattern(), TheInst.getImpResults(), - Complexity, Instr->getID())); + if (SrcPattern && ResultPattern) { + TreePattern Pattern(Instr, SrcPattern, true, *this); + TreePattern Result(Instr, ResultPattern, false, *this); + ParseOnePattern(Instr, Pattern, Result, TheInst.getImpResults()); + } } } +typedef std::pair<TreePatternNode *, unsigned> NameRecord; -typedef std::pair<const TreePatternNode*, unsigned> NameRecord; - -static void FindNames(const TreePatternNode *P, +static void FindNames(TreePatternNode *P, std::map<std::string, NameRecord> &Names, TreePattern *PatternTop) { if (!P->getName().empty()) { @@ -3695,7 +3737,7 @@ std::vector<Predicate> CodeGenDAGPatterns::makePredList(ListInit *L) { } // Sort so that different orders get canonicalized to the same string. - std::sort(Preds.begin(), Preds.end()); + llvm::sort(Preds.begin(), Preds.end()); return Preds; } @@ -3739,34 +3781,18 @@ void CodeGenDAGPatterns::AddPatternToMatch(TreePattern *Pattern, SrcNames[Entry.first].second == 1) Pattern->error("Pattern has dead named input: $" + Entry.first); - PatternsToMatch.push_back(std::move(PTM)); + PatternsToMatch.push_back(PTM); } void CodeGenDAGPatterns::InferInstructionFlags() { ArrayRef<const CodeGenInstruction*> Instructions = Target.getInstructionsByEnumValue(); - // First try to infer flags from the primary instruction pattern, if any. - SmallVector<CodeGenInstruction*, 8> Revisit; unsigned Errors = 0; - for (unsigned i = 0, e = Instructions.size(); i != e; ++i) { - CodeGenInstruction &InstInfo = - const_cast<CodeGenInstruction &>(*Instructions[i]); - - // Get the primary instruction pattern. - const TreePattern *Pattern = getInstruction(InstInfo.TheDef).getPattern(); - if (!Pattern) { - if (InstInfo.hasUndefFlags()) - Revisit.push_back(&InstInfo); - continue; - } - InstAnalyzer PatInfo(*this); - PatInfo.Analyze(Pattern); - Errors += InferFromPattern(InstInfo, PatInfo, InstInfo.TheDef); - } - // Second, look for single-instruction patterns defined outside the - // instruction. + // Try to infer flags from all patterns in PatternToMatch. These include + // both the primary instruction patterns (which always come first) and + // patterns defined outside the instruction. for (const PatternToMatch &PTM : ptms()) { // We can only infer from single-instruction patterns, otherwise we won't // know which instruction should get the flags. @@ -3790,9 +3816,11 @@ void CodeGenDAGPatterns::InferInstructionFlags() { if (Errors) PrintFatalError("pattern conflicts"); - // Revisit instructions with undefined flags and no pattern. + // If requested by the target, guess any undefined properties. if (Target.guessInstructionProperties()) { - for (CodeGenInstruction *InstInfo : Revisit) { + for (unsigned i = 0, e = Instructions.size(); i != e; ++i) { + CodeGenInstruction *InstInfo = + const_cast<CodeGenInstruction *>(Instructions[i]); if (InstInfo->InferredFrom) continue; // The mayLoad and mayStore flags default to false. @@ -3804,7 +3832,9 @@ void CodeGenDAGPatterns::InferInstructionFlags() { } // Complain about any flags that are still undefined. - for (CodeGenInstruction *InstInfo : Revisit) { + for (unsigned i = 0, e = Instructions.size(); i != e; ++i) { + CodeGenInstruction *InstInfo = + const_cast<CodeGenInstruction *>(Instructions[i]); if (InstInfo->InferredFrom) continue; if (InstInfo->hasSideEffects_Unset) @@ -3916,6 +3946,122 @@ static bool ForceArbitraryInstResultType(TreePatternNode *N, TreePattern &TP) { return false; } +void CodeGenDAGPatterns::ParseOnePattern(Record *TheDef, + TreePattern &Pattern, TreePattern &Result, + const std::vector<Record *> &InstImpResults) { + + // Inline pattern fragments and expand multiple alternatives. + Pattern.InlinePatternFragments(); + Result.InlinePatternFragments(); + + if (Result.getNumTrees() != 1) + Result.error("Cannot use multi-alternative fragments in result pattern!"); + + // Infer types. + bool IterateInference; + bool InferredAllPatternTypes, InferredAllResultTypes; + do { + // Infer as many types as possible. If we cannot infer all of them, we + // can never do anything with this pattern: report it to the user. + InferredAllPatternTypes = + Pattern.InferAllTypes(&Pattern.getNamedNodesMap()); + + // Infer as many types as possible. If we cannot infer all of them, we + // can never do anything with this pattern: report it to the user. + InferredAllResultTypes = + Result.InferAllTypes(&Pattern.getNamedNodesMap()); + + IterateInference = false; + + // Apply the type of the result to the source pattern. This helps us + // resolve cases where the input type is known to be a pointer type (which + // is considered resolved), but the result knows it needs to be 32- or + // 64-bits. Infer the other way for good measure. + for (auto T : Pattern.getTrees()) + for (unsigned i = 0, e = std::min(Result.getOnlyTree()->getNumTypes(), + T->getNumTypes()); + i != e; ++i) { + IterateInference |= T->UpdateNodeType( + i, Result.getOnlyTree()->getExtType(i), Result); + IterateInference |= Result.getOnlyTree()->UpdateNodeType( + i, T->getExtType(i), Result); + } + + // If our iteration has converged and the input pattern's types are fully + // resolved but the result pattern is not fully resolved, we may have a + // situation where we have two instructions in the result pattern and + // the instructions require a common register class, but don't care about + // what actual MVT is used. This is actually a bug in our modelling: + // output patterns should have register classes, not MVTs. + // + // In any case, to handle this, we just go through and disambiguate some + // arbitrary types to the result pattern's nodes. + if (!IterateInference && InferredAllPatternTypes && + !InferredAllResultTypes) + IterateInference = + ForceArbitraryInstResultType(Result.getTree(0).get(), Result); + } while (IterateInference); + + // Verify that we inferred enough types that we can do something with the + // pattern and result. If these fire the user has to add type casts. + if (!InferredAllPatternTypes) + Pattern.error("Could not infer all types in pattern!"); + if (!InferredAllResultTypes) { + Pattern.dump(); + Result.error("Could not infer all types in pattern result!"); + } + + // Promote the xform function to be an explicit node if set. + const TreePatternNodePtr &DstPattern = Result.getOnlyTree(); + std::vector<TreePatternNodePtr> ResultNodeOperands; + for (unsigned ii = 0, ee = DstPattern->getNumChildren(); ii != ee; ++ii) { + TreePatternNodePtr OpNode = DstPattern->getChildShared(ii); + if (Record *Xform = OpNode->getTransformFn()) { + OpNode->setTransformFn(nullptr); + std::vector<TreePatternNodePtr> Children; + Children.push_back(OpNode); + OpNode = std::make_shared<TreePatternNode>(Xform, std::move(Children), + OpNode->getNumTypes()); + } + ResultNodeOperands.push_back(OpNode); + } + + TreePatternNodePtr DstShared = + DstPattern->isLeaf() + ? DstPattern + : std::make_shared<TreePatternNode>(DstPattern->getOperator(), + std::move(ResultNodeOperands), + DstPattern->getNumTypes()); + + for (unsigned i = 0, e = Result.getOnlyTree()->getNumTypes(); i != e; ++i) + DstShared->setType(i, Result.getOnlyTree()->getExtType(i)); + + TreePattern Temp(Result.getRecord(), DstShared, false, *this); + Temp.InferAllTypes(); + + ListInit *Preds = TheDef->getValueAsListInit("Predicates"); + int Complexity = TheDef->getValueAsInt("AddedComplexity"); + + if (PatternRewriter) + PatternRewriter(&Pattern); + + // A pattern may end up with an "impossible" type, i.e. a situation + // where all types have been eliminated for some node in this pattern. + // This could occur for intrinsics that only make sense for a specific + // value type, and use a specific register class. If, for some mode, + // that register class does not accept that type, the type inference + // will lead to a contradiction, which is not an error however, but + // a sign that this pattern will simply never match. + if (Temp.getOnlyTree()->hasPossibleType()) + for (auto T : Pattern.getTrees()) + if (T->hasPossibleType()) + AddPatternToMatch(&Pattern, + PatternToMatch(TheDef, makePredList(Preds), + T, Temp.getOnlyTree(), + InstImpResults, Complexity, + TheDef->getID())); +} + void CodeGenDAGPatterns::ParsePatterns() { std::vector<Record*> Patterns = Records.getAllDerivedDefinitions("Pattern"); @@ -3926,10 +4072,7 @@ void CodeGenDAGPatterns::ParsePatterns() { if (hasNullFragReference(Tree)) continue; - TreePattern *Pattern = new TreePattern(CurPattern, Tree, true, *this); - - // Inline pattern fragments into it. - Pattern->InlinePatternFragments(); + TreePattern Pattern(CurPattern, Tree, true, *this); ListInit *LI = CurPattern->getValueAsListInit("ResultInstrs"); if (LI->empty()) continue; // no pattern. @@ -3937,119 +4080,19 @@ void CodeGenDAGPatterns::ParsePatterns() { // Parse the instruction. TreePattern Result(CurPattern, LI, false, *this); - // Inline pattern fragments into it. - Result.InlinePatternFragments(); - if (Result.getNumTrees() != 1) Result.error("Cannot handle instructions producing instructions " "with temporaries yet!"); - bool IterateInference; - bool InferredAllPatternTypes, InferredAllResultTypes; - do { - // Infer as many types as possible. If we cannot infer all of them, we - // can never do anything with this pattern: report it to the user. - InferredAllPatternTypes = - Pattern->InferAllTypes(&Pattern->getNamedNodesMap()); - - // Infer as many types as possible. If we cannot infer all of them, we - // can never do anything with this pattern: report it to the user. - InferredAllResultTypes = - Result.InferAllTypes(&Pattern->getNamedNodesMap()); - - IterateInference = false; - - // Apply the type of the result to the source pattern. This helps us - // resolve cases where the input type is known to be a pointer type (which - // is considered resolved), but the result knows it needs to be 32- or - // 64-bits. Infer the other way for good measure. - for (unsigned i = 0, e = std::min(Result.getTree(0)->getNumTypes(), - Pattern->getTree(0)->getNumTypes()); - i != e; ++i) { - IterateInference = Pattern->getTree(0)->UpdateNodeType( - i, Result.getTree(0)->getExtType(i), Result); - IterateInference |= Result.getTree(0)->UpdateNodeType( - i, Pattern->getTree(0)->getExtType(i), Result); - } - - // If our iteration has converged and the input pattern's types are fully - // resolved but the result pattern is not fully resolved, we may have a - // situation where we have two instructions in the result pattern and - // the instructions require a common register class, but don't care about - // what actual MVT is used. This is actually a bug in our modelling: - // output patterns should have register classes, not MVTs. - // - // In any case, to handle this, we just go through and disambiguate some - // arbitrary types to the result pattern's nodes. - if (!IterateInference && InferredAllPatternTypes && - !InferredAllResultTypes) - IterateInference = - ForceArbitraryInstResultType(Result.getTree(0), Result); - } while (IterateInference); - - // Verify that we inferred enough types that we can do something with the - // pattern and result. If these fire the user has to add type casts. - if (!InferredAllPatternTypes) - Pattern->error("Could not infer all types in pattern!"); - if (!InferredAllResultTypes) { - Pattern->dump(); - Result.error("Could not infer all types in pattern result!"); - } - // Validate that the input pattern is correct. - std::map<std::string, TreePatternNode*> InstInputs; - std::map<std::string, TreePatternNode*> InstResults; + std::map<std::string, TreePatternNodePtr> InstInputs; + std::map<std::string, TreePatternNodePtr> InstResults; std::vector<Record*> InstImpResults; - for (unsigned j = 0, ee = Pattern->getNumTrees(); j != ee; ++j) - FindPatternInputsAndOutputs(Pattern, Pattern->getTree(j), - InstInputs, InstResults, - InstImpResults); + for (unsigned j = 0, ee = Pattern.getNumTrees(); j != ee; ++j) + FindPatternInputsAndOutputs(Pattern, Pattern.getTree(j), InstInputs, + InstResults, InstImpResults); - // Promote the xform function to be an explicit node if set. - TreePatternNode *DstPattern = Result.getOnlyTree(); - std::vector<TreePatternNode*> ResultNodeOperands; - for (unsigned ii = 0, ee = DstPattern->getNumChildren(); ii != ee; ++ii) { - TreePatternNode *OpNode = DstPattern->getChild(ii); - if (Record *Xform = OpNode->getTransformFn()) { - OpNode->setTransformFn(nullptr); - std::vector<TreePatternNode*> Children; - Children.push_back(OpNode); - OpNode = new TreePatternNode(Xform, Children, OpNode->getNumTypes()); - } - ResultNodeOperands.push_back(OpNode); - } - DstPattern = Result.getOnlyTree(); - if (!DstPattern->isLeaf()) - DstPattern = new TreePatternNode(DstPattern->getOperator(), - ResultNodeOperands, - DstPattern->getNumTypes()); - - for (unsigned i = 0, e = Result.getOnlyTree()->getNumTypes(); i != e; ++i) - DstPattern->setType(i, Result.getOnlyTree()->getExtType(i)); - - TreePattern Temp(Result.getRecord(), DstPattern, false, *this); - Temp.InferAllTypes(); - - // A pattern may end up with an "impossible" type, i.e. a situation - // where all types have been eliminated for some node in this pattern. - // This could occur for intrinsics that only make sense for a specific - // value type, and use a specific register class. If, for some mode, - // that register class does not accept that type, the type inference - // will lead to a contradiction, which is not an error however, but - // a sign that this pattern will simply never match. - if (Pattern->getTree(0)->hasPossibleType() && - Temp.getOnlyTree()->hasPossibleType()) { - ListInit *Preds = CurPattern->getValueAsListInit("Predicates"); - int Complexity = CurPattern->getValueAsInt("AddedComplexity"); - if (PatternRewriter) - PatternRewriter(Pattern); - AddPatternToMatch( - Pattern, - PatternToMatch( - CurPattern, makePredList(Preds), Pattern->getTree(0), - Temp.getOnlyTree(), std::move(InstImpResults), Complexity, - CurPattern->getID())); - } + ParseOnePattern(CurPattern, Pattern, Result, InstImpResults); } } @@ -4068,25 +4111,24 @@ void CodeGenDAGPatterns::ExpandHwModeBasedTypes() { std::vector<PatternToMatch> Copy = PatternsToMatch; PatternsToMatch.clear(); - auto AppendPattern = [this,&ModeChecks](PatternToMatch &P, unsigned Mode) { - TreePatternNode *NewSrc = P.SrcPattern->clone(); - TreePatternNode *NewDst = P.DstPattern->clone(); + auto AppendPattern = [this, &ModeChecks](PatternToMatch &P, unsigned Mode) { + TreePatternNodePtr NewSrc = P.SrcPattern->clone(); + TreePatternNodePtr NewDst = P.DstPattern->clone(); if (!NewSrc->setDefaultMode(Mode) || !NewDst->setDefaultMode(Mode)) { - delete NewSrc; - delete NewDst; return; } std::vector<Predicate> Preds = P.Predicates; const std::vector<Predicate> &MC = ModeChecks[Mode]; Preds.insert(Preds.end(), MC.begin(), MC.end()); - PatternsToMatch.emplace_back(P.getSrcRecord(), Preds, NewSrc, NewDst, - P.getDstRegs(), P.getAddedComplexity(), - Record::getNewUID(), Mode); + PatternsToMatch.emplace_back(P.getSrcRecord(), Preds, std::move(NewSrc), + std::move(NewDst), P.getDstRegs(), + P.getAddedComplexity(), Record::getNewUID(), + Mode); }; for (PatternToMatch &P : Copy) { - TreePatternNode *SrcP = nullptr, *DstP = nullptr; + TreePatternNodePtr SrcP = nullptr, DstP = nullptr; if (P.SrcPattern->hasProperTypeByHwMode()) SrcP = P.SrcPattern; if (P.DstPattern->hasProperTypeByHwMode()) @@ -4098,9 +4140,9 @@ void CodeGenDAGPatterns::ExpandHwModeBasedTypes() { std::set<unsigned> Modes; if (SrcP) - collectModes(Modes, SrcP); + collectModes(Modes, SrcP.get()); if (DstP) - collectModes(Modes, DstP); + collectModes(Modes, DstP.get()); // The predicate for the default mode needs to be constructed for each // pattern separately. @@ -4168,13 +4210,13 @@ static void FindDepVars(TreePatternNode *N, MultipleUseVarSet &DepVars) { /// Dump the dependent variable set: static void DumpDepVars(MultipleUseVarSet &DepVars) { if (DepVars.empty()) { - DEBUG(errs() << "<empty set>"); + LLVM_DEBUG(errs() << "<empty set>"); } else { - DEBUG(errs() << "[ "); + LLVM_DEBUG(errs() << "[ "); for (const auto &DepVar : DepVars) { - DEBUG(errs() << DepVar.getKey() << " "); + LLVM_DEBUG(errs() << DepVar.getKey() << " "); } - DEBUG(errs() << "]"); + LLVM_DEBUG(errs() << "]"); } } #endif @@ -4182,11 +4224,11 @@ static void DumpDepVars(MultipleUseVarSet &DepVars) { /// CombineChildVariants - Given a bunch of permutations of each child of the /// 'operator' node, put them together in all possible ways. -static void CombineChildVariants(TreePatternNode *Orig, - const std::vector<std::vector<TreePatternNode*> > &ChildVariants, - std::vector<TreePatternNode*> &OutVariants, - CodeGenDAGPatterns &CDP, - const MultipleUseVarSet &DepVars) { +static void CombineChildVariants( + TreePatternNodePtr Orig, + const std::vector<std::vector<TreePatternNodePtr>> &ChildVariants, + std::vector<TreePatternNodePtr> &OutVariants, CodeGenDAGPatterns &CDP, + const MultipleUseVarSet &DepVars) { // Make sure that each operand has at least one variant to choose from. for (const auto &Variants : ChildVariants) if (Variants.empty()) @@ -4198,20 +4240,20 @@ static void CombineChildVariants(TreePatternNode *Orig, bool NotDone; do { #ifndef NDEBUG - DEBUG(if (!Idxs.empty()) { - errs() << Orig->getOperator()->getName() << ": Idxs = [ "; - for (unsigned Idx : Idxs) { - errs() << Idx << " "; - } - errs() << "]\n"; - }); + LLVM_DEBUG(if (!Idxs.empty()) { + errs() << Orig->getOperator()->getName() << ": Idxs = [ "; + for (unsigned Idx : Idxs) { + errs() << Idx << " "; + } + errs() << "]\n"; + }); #endif // Create the variant and add it to the output list. - std::vector<TreePatternNode*> NewChildren; + std::vector<TreePatternNodePtr> NewChildren; for (unsigned i = 0, e = ChildVariants.size(); i != e; ++i) NewChildren.push_back(ChildVariants[i][Idxs[i]]); - auto R = llvm::make_unique<TreePatternNode>( - Orig->getOperator(), NewChildren, Orig->getNumTypes()); + TreePatternNodePtr R = std::make_shared<TreePatternNode>( + Orig->getOperator(), std::move(NewChildren), Orig->getNumTypes()); // Copy over properties. R->setName(Orig->getName()); @@ -4227,10 +4269,10 @@ static void CombineChildVariants(TreePatternNode *Orig, // (and GPRC:$a, GPRC:$b) -> (and GPRC:$b, GPRC:$a) // which are the same pattern. Ignore the dups. if (R->canPatternMatch(ErrString, CDP) && - none_of(OutVariants, [&](TreePatternNode *Variant) { - return R->isIsomorphicTo(Variant, DepVars); + none_of(OutVariants, [&](TreePatternNodePtr Variant) { + return R->isIsomorphicTo(Variant.get(), DepVars); })) - OutVariants.push_back(R.release()); + OutVariants.push_back(R); // Increment indices to the next permutation by incrementing the // indices from last index backward, e.g., generate the sequence @@ -4248,21 +4290,21 @@ static void CombineChildVariants(TreePatternNode *Orig, /// CombineChildVariants - A helper function for binary operators. /// -static void CombineChildVariants(TreePatternNode *Orig, - const std::vector<TreePatternNode*> &LHS, - const std::vector<TreePatternNode*> &RHS, - std::vector<TreePatternNode*> &OutVariants, +static void CombineChildVariants(TreePatternNodePtr Orig, + const std::vector<TreePatternNodePtr> &LHS, + const std::vector<TreePatternNodePtr> &RHS, + std::vector<TreePatternNodePtr> &OutVariants, CodeGenDAGPatterns &CDP, const MultipleUseVarSet &DepVars) { - std::vector<std::vector<TreePatternNode*> > ChildVariants; + std::vector<std::vector<TreePatternNodePtr>> ChildVariants; ChildVariants.push_back(LHS); ChildVariants.push_back(RHS); CombineChildVariants(Orig, ChildVariants, OutVariants, CDP, DepVars); } - -static void GatherChildrenOfAssociativeOpcode(TreePatternNode *N, - std::vector<TreePatternNode *> &Children) { +static void +GatherChildrenOfAssociativeOpcode(TreePatternNodePtr N, + std::vector<TreePatternNodePtr> &Children) { assert(N->getNumChildren()==2 &&"Associative but doesn't have 2 children!"); Record *Operator = N->getOperator(); @@ -4274,21 +4316,21 @@ static void GatherChildrenOfAssociativeOpcode(TreePatternNode *N, } if (N->getChild(0)->isLeaf() || N->getChild(0)->getOperator() != Operator) - Children.push_back(N->getChild(0)); + Children.push_back(N->getChildShared(0)); else - GatherChildrenOfAssociativeOpcode(N->getChild(0), Children); + GatherChildrenOfAssociativeOpcode(N->getChildShared(0), Children); if (N->getChild(1)->isLeaf() || N->getChild(1)->getOperator() != Operator) - Children.push_back(N->getChild(1)); + Children.push_back(N->getChildShared(1)); else - GatherChildrenOfAssociativeOpcode(N->getChild(1), Children); + GatherChildrenOfAssociativeOpcode(N->getChildShared(1), Children); } /// GenerateVariantsOf - Given a pattern N, generate all permutations we can of /// the (potentially recursive) pattern by using algebraic laws. /// -static void GenerateVariantsOf(TreePatternNode *N, - std::vector<TreePatternNode*> &OutVariants, +static void GenerateVariantsOf(TreePatternNodePtr N, + std::vector<TreePatternNodePtr> &OutVariants, CodeGenDAGPatterns &CDP, const MultipleUseVarSet &DepVars) { // We cannot permute leaves or ComplexPattern uses. @@ -4303,14 +4345,14 @@ static void GenerateVariantsOf(TreePatternNode *N, // If this node is associative, re-associate. if (NodeInfo.hasProperty(SDNPAssociative)) { // Re-associate by pulling together all of the linked operators - std::vector<TreePatternNode*> MaximalChildren; + std::vector<TreePatternNodePtr> MaximalChildren; GatherChildrenOfAssociativeOpcode(N, MaximalChildren); // Only handle child sizes of 3. Otherwise we'll end up trying too many // permutations. if (MaximalChildren.size() == 3) { // Find the variants of all of our maximal children. - std::vector<TreePatternNode*> AVariants, BVariants, CVariants; + std::vector<TreePatternNodePtr> AVariants, BVariants, CVariants; GenerateVariantsOf(MaximalChildren[0], AVariants, CDP, DepVars); GenerateVariantsOf(MaximalChildren[1], BVariants, CDP, DepVars); GenerateVariantsOf(MaximalChildren[2], CVariants, CDP, DepVars); @@ -4320,12 +4362,12 @@ static void GenerateVariantsOf(TreePatternNode *N, // Within these forms, we can also permute A/B/C. // Generate legal pair permutations of A/B/C. - std::vector<TreePatternNode*> ABVariants; - std::vector<TreePatternNode*> BAVariants; - std::vector<TreePatternNode*> ACVariants; - std::vector<TreePatternNode*> CAVariants; - std::vector<TreePatternNode*> BCVariants; - std::vector<TreePatternNode*> CBVariants; + std::vector<TreePatternNodePtr> ABVariants; + std::vector<TreePatternNodePtr> BAVariants; + std::vector<TreePatternNodePtr> ACVariants; + std::vector<TreePatternNodePtr> CAVariants; + std::vector<TreePatternNodePtr> BCVariants; + std::vector<TreePatternNodePtr> CBVariants; CombineChildVariants(N, AVariants, BVariants, ABVariants, CDP, DepVars); CombineChildVariants(N, BVariants, AVariants, BAVariants, CDP, DepVars); CombineChildVariants(N, AVariants, CVariants, ACVariants, CDP, DepVars); @@ -4353,10 +4395,10 @@ static void GenerateVariantsOf(TreePatternNode *N, } // Compute permutations of all children. - std::vector<std::vector<TreePatternNode*> > ChildVariants; + std::vector<std::vector<TreePatternNodePtr>> ChildVariants; ChildVariants.resize(N->getNumChildren()); for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) - GenerateVariantsOf(N->getChild(i), ChildVariants[i], CDP, DepVars); + GenerateVariantsOf(N->getChildShared(i), ChildVariants[i], CDP, DepVars); // Build all permutations based on how the children were formed. CombineChildVariants(N, ChildVariants, OutVariants, CDP, DepVars); @@ -4385,19 +4427,19 @@ static void GenerateVariantsOf(TreePatternNode *N, // after those. assert(NC >= 3 && "Commutative intrinsic should have at least 3 children!"); - std::vector<std::vector<TreePatternNode*> > Variants; - Variants.push_back(ChildVariants[0]); // Intrinsic id. - Variants.push_back(ChildVariants[2]); - Variants.push_back(ChildVariants[1]); + std::vector<std::vector<TreePatternNodePtr>> Variants; + Variants.push_back(std::move(ChildVariants[0])); // Intrinsic id. + Variants.push_back(std::move(ChildVariants[2])); + Variants.push_back(std::move(ChildVariants[1])); for (unsigned i = 3; i != NC; ++i) - Variants.push_back(ChildVariants[i]); + Variants.push_back(std::move(ChildVariants[i])); CombineChildVariants(N, Variants, OutVariants, CDP, DepVars); } else if (NC == N->getNumChildren()) { - std::vector<std::vector<TreePatternNode*> > Variants; - Variants.push_back(ChildVariants[1]); - Variants.push_back(ChildVariants[0]); + std::vector<std::vector<TreePatternNodePtr>> Variants; + Variants.push_back(std::move(ChildVariants[1])); + Variants.push_back(std::move(ChildVariants[0])); for (unsigned i = 2; i != NC; ++i) - Variants.push_back(ChildVariants[i]); + Variants.push_back(std::move(ChildVariants[i])); CombineChildVariants(N, Variants, OutVariants, CDP, DepVars); } } @@ -4407,7 +4449,7 @@ static void GenerateVariantsOf(TreePatternNode *N, // GenerateVariants - Generate variants. For example, commutative patterns can // match multiple ways. Add them to PatternsToMatch as well. void CodeGenDAGPatterns::GenerateVariants() { - DEBUG(errs() << "Generating instruction variants.\n"); + LLVM_DEBUG(errs() << "Generating instruction variants.\n"); // Loop over all of the patterns we've collected, checking to see if we can // generate variants of the instruction, through the exploitation of @@ -4420,28 +4462,26 @@ void CodeGenDAGPatterns::GenerateVariants() { // for (unsigned i = 0, e = PatternsToMatch.size(); i != e; ++i) { MultipleUseVarSet DepVars; - std::vector<TreePatternNode*> Variants; + std::vector<TreePatternNodePtr> Variants; FindDepVars(PatternsToMatch[i].getSrcPattern(), DepVars); - DEBUG(errs() << "Dependent/multiply used variables: "); - DEBUG(DumpDepVars(DepVars)); - DEBUG(errs() << "\n"); - GenerateVariantsOf(PatternsToMatch[i].getSrcPattern(), Variants, *this, - DepVars); + LLVM_DEBUG(errs() << "Dependent/multiply used variables: "); + LLVM_DEBUG(DumpDepVars(DepVars)); + LLVM_DEBUG(errs() << "\n"); + GenerateVariantsOf(PatternsToMatch[i].getSrcPatternShared(), Variants, + *this, DepVars); assert(!Variants.empty() && "Must create at least original variant!"); if (Variants.size() == 1) // No additional variants for this pattern. continue; - DEBUG(errs() << "FOUND VARIANTS OF: "; - PatternsToMatch[i].getSrcPattern()->dump(); - errs() << "\n"); + LLVM_DEBUG(errs() << "FOUND VARIANTS OF: "; + PatternsToMatch[i].getSrcPattern()->dump(); errs() << "\n"); for (unsigned v = 0, e = Variants.size(); v != e; ++v) { - TreePatternNode *Variant = Variants[v]; + TreePatternNodePtr Variant = Variants[v]; - DEBUG(errs() << " VAR#" << v << ": "; - Variant->dump(); - errs() << "\n"); + LLVM_DEBUG(errs() << " VAR#" << v << ": "; Variant->dump(); + errs() << "\n"); // Scan to see if an instruction or explicit pattern already matches this. bool AlreadyExists = false; @@ -4453,7 +4493,7 @@ void CodeGenDAGPatterns::GenerateVariants() { // Check to see if this variant already exists. if (Variant->isIsomorphicTo(PatternsToMatch[p].getSrcPattern(), DepVars)) { - DEBUG(errs() << " *** ALREADY EXISTS, ignoring variant.\n"); + LLVM_DEBUG(errs() << " *** ALREADY EXISTS, ignoring variant.\n"); AlreadyExists = true; break; } @@ -4464,11 +4504,11 @@ void CodeGenDAGPatterns::GenerateVariants() { // Otherwise, add it to the list of patterns we have. PatternsToMatch.push_back(PatternToMatch( PatternsToMatch[i].getSrcRecord(), PatternsToMatch[i].getPredicates(), - Variant, PatternsToMatch[i].getDstPattern(), + Variant, PatternsToMatch[i].getDstPatternShared(), PatternsToMatch[i].getDstRegs(), PatternsToMatch[i].getAddedComplexity(), Record::getNewUID())); } - DEBUG(errs() << "\n"); + LLVM_DEBUG(errs() << "\n"); } } diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h index 8a8132c7f894..9be3816cc7fc 100644 --- a/utils/TableGen/CodeGenDAGPatterns.h +++ b/utils/TableGen/CodeGenDAGPatterns.h @@ -43,6 +43,9 @@ class TreePatternNode; class CodeGenDAGPatterns; class ComplexPattern; +/// Shared pointer for TreePatternNode. +using TreePatternNodePtr = std::shared_ptr<TreePatternNode>; + /// This represents a set of MVTs. Since the underlying type for the MVT /// is uint8_t, there are at most 256 values. To reduce the number of memory /// allocations and deallocations, represent the set as a sequence of bits. @@ -330,9 +333,21 @@ struct TypeInfer { TypeSetByHwMode &VTS; }; + struct SuppressValidation { + SuppressValidation(TypeInfer &TI) : Infer(TI), SavedValidate(TI.Validate) { + Infer.Validate = false; + } + ~SuppressValidation() { + Infer.Validate = SavedValidate; + } + TypeInfer &Infer; + bool SavedValidate; + }; + TreePattern &TP; unsigned ForceMode; // Mode to use when set. bool CodeGen = false; // Set during generation of matcher code. + bool Validate = true; // Indicate whether to validate types. private: TypeSetByHwMode getLegalTypes(); @@ -540,6 +555,10 @@ public: /// ValueType record for the memory VT. Record *getScalarMemoryVT() const; + // If true, indicates that GlobalISel-based C++ code was supplied. + bool hasGISelPredicateCode() const; + std::string getGISelPredicateCode() const; + private: bool hasPredCode() const; bool hasImmCode() const; @@ -552,9 +571,6 @@ private: }; -/// FIXME: TreePatternNode's can be shared in some cases (due to dag-shaped -/// patterns), and as such should be ref counted. We currently just leak all -/// TreePatternNode objects! class TreePatternNode { /// The type of each node result. Before and during type inference, each /// result may be a set of possible types. After (successful) type inference, @@ -581,18 +597,19 @@ class TreePatternNode { /// it can be substituted into the resulting instruction on a pattern match. Record *TransformFn; - std::vector<TreePatternNode*> Children; + std::vector<TreePatternNodePtr> Children; + public: - TreePatternNode(Record *Op, const std::vector<TreePatternNode*> &Ch, + TreePatternNode(Record *Op, std::vector<TreePatternNodePtr> Ch, unsigned NumResults) - : Operator(Op), Val(nullptr), TransformFn(nullptr), Children(Ch) { + : Operator(Op), Val(nullptr), TransformFn(nullptr), + Children(std::move(Ch)) { Types.resize(NumResults); } TreePatternNode(Init *val, unsigned NumResults) // leaf ctor : Operator(nullptr), Val(val), TransformFn(nullptr) { Types.resize(NumResults); } - ~TreePatternNode(); bool hasName() const { return !Name.empty(); } const std::string &getName() const { return Name; } @@ -626,15 +643,17 @@ public: Record *getOperator() const { assert(!isLeaf()); return Operator; } unsigned getNumChildren() const { return Children.size(); } - TreePatternNode *getChild(unsigned N) const { return Children[N]; } - void setChild(unsigned i, TreePatternNode *N) { - Children[i] = N; + TreePatternNode *getChild(unsigned N) const { return Children[N].get(); } + const TreePatternNodePtr &getChildShared(unsigned N) const { + return Children[N]; } + void setChild(unsigned i, TreePatternNodePtr N) { Children[i] = N; } /// hasChild - Return true if N is any of our children. bool hasChild(const TreePatternNode *N) const { for (unsigned i = 0, e = Children.size(); i != e; ++i) - if (Children[i] == N) return true; + if (Children[i].get() == N) + return true; return false; } @@ -694,7 +713,7 @@ public: // Higher level manipulation routines. /// clone - Return a new copy of this tree. /// - TreePatternNode *clone() const; + TreePatternNodePtr clone() const; /// RemoveAllTypes - Recursively strip all the types of this tree. void RemoveAllTypes(); @@ -708,13 +727,15 @@ public: // Higher level manipulation routines. /// SubstituteFormalArguments - Replace the formal arguments in this tree /// with actual values specified by ArgMap. - void SubstituteFormalArguments(std::map<std::string, - TreePatternNode*> &ArgMap); + void + SubstituteFormalArguments(std::map<std::string, TreePatternNodePtr> &ArgMap); /// InlinePatternFragments - If this pattern refers to any pattern - /// fragments, inline them into place, giving us a pattern without any - /// PatFrag references. - TreePatternNode *InlinePatternFragments(TreePattern &TP); + /// fragments, return the set of inlined versions (this can be more than + /// one if a PatFrags record has multiple alternatives). + void InlinePatternFragments(TreePatternNodePtr T, + TreePattern &TP, + std::vector<TreePatternNodePtr> &OutAlternatives); /// ApplyTypeConstraints - Apply all of the type constraints relevant to /// this node and its children in the tree. This returns true if it makes a @@ -759,11 +780,11 @@ class TreePattern { /// Trees - The list of pattern trees which corresponds to this pattern. /// Note that PatFrag's only have a single tree. /// - std::vector<TreePatternNode*> Trees; + std::vector<TreePatternNodePtr> Trees; /// NamedNodes - This is all of the nodes that have names in the trees in this /// pattern. - StringMap<SmallVector<TreePatternNode*,1> > NamedNodes; + StringMap<SmallVector<TreePatternNode *, 1>> NamedNodes; /// TheRecord - The actual TableGen record corresponding to this pattern. /// @@ -802,21 +823,21 @@ public: CodeGenDAGPatterns &ise); TreePattern(Record *TheRec, DagInit *Pat, bool isInput, CodeGenDAGPatterns &ise); - TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput, + TreePattern(Record *TheRec, TreePatternNodePtr Pat, bool isInput, CodeGenDAGPatterns &ise); /// getTrees - Return the tree patterns which corresponds to this pattern. /// - const std::vector<TreePatternNode*> &getTrees() const { return Trees; } + const std::vector<TreePatternNodePtr> &getTrees() const { return Trees; } unsigned getNumTrees() const { return Trees.size(); } - TreePatternNode *getTree(unsigned i) const { return Trees[i]; } - void setTree(unsigned i, TreePatternNode *Tree) { Trees[i] = Tree; } - TreePatternNode *getOnlyTree() const { + const TreePatternNodePtr &getTree(unsigned i) const { return Trees[i]; } + void setTree(unsigned i, TreePatternNodePtr Tree) { Trees[i] = Tree; } + const TreePatternNodePtr &getOnlyTree() const { assert(Trees.size() == 1 && "Doesn't have exactly one pattern!"); return Trees[0]; } - const StringMap<SmallVector<TreePatternNode*,1> > &getNamedNodesMap() { + const StringMap<SmallVector<TreePatternNode *, 1>> &getNamedNodesMap() { if (NamedNodes.empty()) ComputeNamedNodes(); return NamedNodes; @@ -838,17 +859,20 @@ public: /// InlinePatternFragments - If this pattern refers to any pattern /// fragments, inline them into place, giving us a pattern without any - /// PatFrag references. + /// PatFrags references. This may increase the number of trees in the + /// pattern if a PatFrags has multiple alternatives. void InlinePatternFragments() { - for (unsigned i = 0, e = Trees.size(); i != e; ++i) - Trees[i] = Trees[i]->InlinePatternFragments(*this); + std::vector<TreePatternNodePtr> Copy = Trees; + Trees.clear(); + for (unsigned i = 0, e = Copy.size(); i != e; ++i) + Copy[i]->InlinePatternFragments(Copy[i], *this, Trees); } /// InferAllTypes - Infer/propagate as many types throughout the expression /// patterns as possible. Return true if all types are inferred, false /// otherwise. Bail out if a type contradiction is found. - bool InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > - *NamedTypes=nullptr); + bool InferAllTypes( + const StringMap<SmallVector<TreePatternNode *, 1>> *NamedTypes = nullptr); /// error - If this is the first error in the current resolution step, /// print it and set the error flag. Otherwise, continue silently. @@ -866,7 +890,7 @@ public: void dump() const; private: - TreePatternNode *ParseTreePattern(Init *DI, StringRef OpName); + TreePatternNodePtr ParseTreePattern(Init *DI, StringRef OpName); void ComputeNamedNodes(); void ComputeNamedNodes(TreePatternNode *N); }; @@ -900,31 +924,30 @@ inline bool TreePatternNode::UpdateNodeType(unsigned ResNo, /// DAGDefaultOperand - One of these is created for each OperandWithDefaultOps /// that has a set ExecuteAlways / DefaultOps field. struct DAGDefaultOperand { - std::vector<TreePatternNode*> DefaultOps; + std::vector<TreePatternNodePtr> DefaultOps; }; class DAGInstruction { - TreePattern *Pattern; std::vector<Record*> Results; std::vector<Record*> Operands; std::vector<Record*> ImpResults; - TreePatternNode *ResultPattern; + TreePatternNodePtr SrcPattern; + TreePatternNodePtr ResultPattern; + public: - DAGInstruction(TreePattern *TP, - const std::vector<Record*> &results, + DAGInstruction(const std::vector<Record*> &results, const std::vector<Record*> &operands, - const std::vector<Record*> &impresults) - : Pattern(TP), Results(results), Operands(operands), - ImpResults(impresults), ResultPattern(nullptr) {} + const std::vector<Record*> &impresults, + TreePatternNodePtr srcpattern = nullptr, + TreePatternNodePtr resultpattern = nullptr) + : Results(results), Operands(operands), ImpResults(impresults), + SrcPattern(srcpattern), ResultPattern(resultpattern) {} - TreePattern *getPattern() const { return Pattern; } unsigned getNumResults() const { return Results.size(); } unsigned getNumOperands() const { return Operands.size(); } unsigned getNumImpResults() const { return ImpResults.size(); } const std::vector<Record*>& getImpResults() const { return ImpResults; } - void setResultPattern(TreePatternNode *R) { ResultPattern = R; } - Record *getResult(unsigned RN) const { assert(RN < Results.size()); return Results[RN]; @@ -940,7 +963,8 @@ public: return ImpResults[RN]; } - TreePatternNode *getResultPattern() const { return ResultPattern; } + TreePatternNodePtr getSrcPattern() const { return SrcPattern; } + TreePatternNodePtr getResultPattern() const { return ResultPattern; } }; /// This class represents a condition that has to be satisfied for a pattern @@ -994,25 +1018,17 @@ public: /// processed to produce isel. class PatternToMatch { public: - PatternToMatch(Record *srcrecord, const std::vector<Predicate> &preds, - TreePatternNode *src, TreePatternNode *dst, - const std::vector<Record*> &dstregs, - int complexity, unsigned uid, unsigned setmode = 0) - : SrcRecord(srcrecord), SrcPattern(src), DstPattern(dst), - Predicates(preds), Dstregs(std::move(dstregs)), - AddedComplexity(complexity), ID(uid), ForceMode(setmode) {} - - PatternToMatch(Record *srcrecord, std::vector<Predicate> &&preds, - TreePatternNode *src, TreePatternNode *dst, - std::vector<Record*> &&dstregs, - int complexity, unsigned uid, unsigned setmode = 0) - : SrcRecord(srcrecord), SrcPattern(src), DstPattern(dst), - Predicates(preds), Dstregs(std::move(dstregs)), - AddedComplexity(complexity), ID(uid), ForceMode(setmode) {} + PatternToMatch(Record *srcrecord, std::vector<Predicate> preds, + TreePatternNodePtr src, TreePatternNodePtr dst, + std::vector<Record *> dstregs, int complexity, + unsigned uid, unsigned setmode = 0) + : SrcRecord(srcrecord), SrcPattern(src), DstPattern(dst), + Predicates(std::move(preds)), Dstregs(std::move(dstregs)), + AddedComplexity(complexity), ID(uid), ForceMode(setmode) {} Record *SrcRecord; // Originating Record for the pattern. - TreePatternNode *SrcPattern; // Source pattern to match. - TreePatternNode *DstPattern; // Resulting pattern. + TreePatternNodePtr SrcPattern; // Source pattern to match. + TreePatternNodePtr DstPattern; // Resulting pattern. std::vector<Predicate> Predicates; // Top level predicate conditions // to match. std::vector<Record*> Dstregs; // Physical register defs being matched. @@ -1021,8 +1037,10 @@ public: unsigned ForceMode; // Force this mode in type inference when set. Record *getSrcRecord() const { return SrcRecord; } - TreePatternNode *getSrcPattern() const { return SrcPattern; } - TreePatternNode *getDstPattern() const { return DstPattern; } + TreePatternNode *getSrcPattern() const { return SrcPattern.get(); } + TreePatternNodePtr getSrcPatternShared() const { return SrcPattern; } + TreePatternNode *getDstPattern() const { return DstPattern.get(); } + TreePatternNodePtr getDstPatternShared() const { return DstPattern; } const std::vector<Record*> &getDstRegs() const { return Dstregs; } int getAddedComplexity() const { return AddedComplexity; } const std::vector<Predicate> &getPredicates() const { return Predicates; } @@ -1156,7 +1174,7 @@ public: /// Parse the Pattern for an instruction, and insert the result in DAGInsts. typedef std::map<Record*, DAGInstruction, LessRecordByID> DAGInstMap; - const DAGInstruction &parseInstructionPattern( + void parseInstructionPattern( CodeGenInstruction &CGI, ListInit *Pattern, DAGInstMap &DAGInsts); @@ -1193,13 +1211,15 @@ private: std::vector<Predicate> makePredList(ListInit *L); + void ParseOnePattern(Record *TheDef, + TreePattern &Pattern, TreePattern &Result, + const std::vector<Record *> &InstImpResults); void AddPatternToMatch(TreePattern *Pattern, PatternToMatch &&PTM); - void FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, - std::map<std::string, - TreePatternNode*> &InstInputs, - std::map<std::string, - TreePatternNode*> &InstResults, - std::vector<Record*> &InstImpResults); + void FindPatternInputsAndOutputs( + TreePattern &I, TreePatternNodePtr Pat, + std::map<std::string, TreePatternNodePtr> &InstInputs, + std::map<std::string, TreePatternNodePtr> &InstResults, + std::vector<Record *> &InstImpResults); }; diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp index 44ee16f6fd74..eb35020d3d3a 100644 --- a/utils/TableGen/CodeGenInstruction.cpp +++ b/utils/TableGen/CodeGenInstruction.cpp @@ -306,11 +306,13 @@ CodeGenInstruction::CodeGenInstruction(Record *R) isIndirectBranch = R->getValueAsBit("isIndirectBranch"); isCompare = R->getValueAsBit("isCompare"); isMoveImm = R->getValueAsBit("isMoveImm"); + isMoveReg = R->getValueAsBit("isMoveReg"); isBitcast = R->getValueAsBit("isBitcast"); isSelect = R->getValueAsBit("isSelect"); isBarrier = R->getValueAsBit("isBarrier"); isCall = R->getValueAsBit("isCall"); isAdd = R->getValueAsBit("isAdd"); + isTrap = R->getValueAsBit("isTrap"); canFoldAsLoad = R->getValueAsBit("canFoldAsLoad"); isPredicable = Operands.isPredicable || R->getValueAsBit("isPredicable"); isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress"); @@ -327,6 +329,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R) isInsertSubreg = R->getValueAsBit("isInsertSubreg"); isConvergent = R->getValueAsBit("isConvergent"); hasNoSchedulingInfo = R->getValueAsBit("hasNoSchedulingInfo"); + FastISelShouldIgnore = R->getValueAsBit("FastISelShouldIgnore"); bool Unset; mayLoad = R->getValueAsBitOrUnset("mayLoad", Unset); @@ -344,6 +347,10 @@ CodeGenInstruction::CodeGenInstruction(Record *R) ImplicitDefs = R->getValueAsListOfDefs("Defs"); ImplicitUses = R->getValueAsListOfDefs("Uses"); + // This flag is only inferred from the pattern. + hasChain = false; + hasChain_Inferred = false; + // Parse Constraints. ParseConstraints(R->getValueAsString("Constraints"), Operands); @@ -588,12 +595,10 @@ unsigned CodeGenInstAlias::ResultOperand::getMINumOperands() const { return MIOpInfo->getNumArgs(); } -CodeGenInstAlias::CodeGenInstAlias(Record *R, unsigned Variant, - CodeGenTarget &T) +CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) { Result = R->getValueAsDag("ResultInst"); AsmString = R->getValueAsString("AsmString"); - AsmString = CodeGenInstruction::FlattenAsmStringVariants(AsmString, Variant); // Verify that the root of the result is an instruction. @@ -630,8 +635,14 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, unsigned Variant, // 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!"); diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h index 9cff95b1247f..a50c3e60e6e7 100644 --- a/utils/TableGen/CodeGenInstruction.h +++ b/utils/TableGen/CodeGenInstruction.h @@ -15,7 +15,7 @@ #define LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H #include "llvm/ADT/StringRef.h" -#include "llvm/CodeGen/MachineValueType.h" +#include "llvm/Support/MachineValueType.h" #include "llvm/Support/SMLoc.h" #include <string> #include <utility> @@ -226,11 +226,13 @@ template <typename T> class ArrayRef; bool isIndirectBranch : 1; bool isCompare : 1; bool isMoveImm : 1; + bool isMoveReg : 1; bool isBitcast : 1; bool isSelect : 1; bool isBarrier : 1; bool isCall : 1; bool isAdd : 1; + bool isTrap : 1; bool canFoldAsLoad : 1; bool mayLoad : 1; bool mayLoad_Unset : 1; @@ -258,6 +260,9 @@ template <typename T> class ArrayRef; bool isInsertSubreg : 1; bool isConvergent : 1; bool hasNoSchedulingInfo : 1; + bool FastISelShouldIgnore : 1; + bool hasChain : 1; + bool hasChain_Inferred : 1; std::string DeprecatedReason; bool HasComplexDeprecationPredicate; @@ -350,7 +355,7 @@ template <typename T> class ArrayRef; /// of them are matched by the operand, the second value should be -1. std::vector<std::pair<unsigned, int> > ResultInstOperandIndex; - CodeGenInstAlias(Record *R, unsigned Variant, CodeGenTarget &T); + CodeGenInstAlias(Record *R, CodeGenTarget &T); bool tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, Record *InstOpRec, bool hasSubOps, ArrayRef<SMLoc> Loc, diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h index 91305034dc24..5d0715959120 100644 --- a/utils/TableGen/CodeGenIntrinsics.h +++ b/utils/TableGen/CodeGenIntrinsics.h @@ -15,7 +15,7 @@ #define LLVM_UTILS_TABLEGEN_CODEGENINTRINSICS_H #include "SDNodeProperties.h" -#include "llvm/CodeGen/MachineValueType.h" +#include "llvm/Support/MachineValueType.h" #include <string> #include <vector> diff --git a/utils/TableGen/CodeGenMapTable.cpp b/utils/TableGen/CodeGenMapTable.cpp index 43348b622a74..e5b0426cdcc3 100644 --- a/utils/TableGen/CodeGenMapTable.cpp +++ b/utils/TableGen/CodeGenMapTable.cpp @@ -243,7 +243,12 @@ void MapTableEmitter::buildRowInstrMap() { std::vector<Init*> KeyValue; ListInit *RowFields = InstrMapDesc.getRowFields(); for (Init *RowField : RowFields->getValues()) { - Init *CurInstrVal = CurInstr->getValue(RowField)->getValue(); + RecordVal *RecVal = CurInstr->getValue(RowField); + if (RecVal == nullptr) + PrintFatalError(CurInstr->getLoc(), "No value " + + RowField->getAsString() + " found in \"" + + CurInstr->getName() + "\" instruction description."); + Init *CurInstrVal = RecVal->getValue(); KeyValue.push_back(CurInstrVal); } diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp index a6b0a4beb8ea..b0d13b7d38f3 100644 --- a/utils/TableGen/CodeGenRegisters.cpp +++ b/utils/TableGen/CodeGenRegisters.cpp @@ -21,7 +21,6 @@ #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/SparseBitVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" @@ -52,7 +51,7 @@ using namespace llvm; //===----------------------------------------------------------------------===// CodeGenSubRegIndex::CodeGenSubRegIndex(Record *R, unsigned Enum) - : TheDef(R), EnumValue(Enum), AllSuperRegsCovered(true) { + : TheDef(R), EnumValue(Enum), AllSuperRegsCovered(true), Artificial(true) { Name = R->getName(); if (R->getValue("Namespace")) Namespace = R->getValueAsString("Namespace"); @@ -63,7 +62,7 @@ CodeGenSubRegIndex::CodeGenSubRegIndex(Record *R, unsigned Enum) CodeGenSubRegIndex::CodeGenSubRegIndex(StringRef N, StringRef Nspace, unsigned Enum) : TheDef(nullptr), Name(N), Namespace(Nspace), Size(-1), Offset(-1), - EnumValue(Enum), AllSuperRegsCovered(true) { + EnumValue(Enum), AllSuperRegsCovered(true), Artificial(true) { } std::string CodeGenSubRegIndex::getQualifiedName() const { @@ -162,8 +161,9 @@ CodeGenRegister::CodeGenRegister(Record *R, unsigned Enum) HasDisjunctSubRegs(false), SubRegsComplete(false), SuperRegsComplete(false), - TopoSig(~0u) -{} + TopoSig(~0u) { + Artificial = R->getValueAsBit("isArtificial"); +} void CodeGenRegister::buildObjectGraph(CodeGenRegBank &RegBank) { std::vector<Record*> SRIs = TheDef->getValueAsListOfDefs("SubRegIndices"); @@ -276,6 +276,8 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) { CodeGenRegister *SR = ExplicitSubRegs[i]; CodeGenSubRegIndex *Idx = ExplicitSubRegIndices[i]; + if (!SR->Artificial) + Idx->Artificial = false; if (!SubRegs.insert(std::make_pair(Idx, SR)).second) PrintFatalError(TheDef->getLoc(), "SubRegIndex " + Idx->getName() + " appears twice in Register " + getName()); @@ -386,13 +388,17 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { // user already specified. for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) { CodeGenRegister *SR = ExplicitSubRegs[i]; - if (!SR->CoveredBySubRegs || SR->ExplicitSubRegs.size() <= 1) + if (!SR->CoveredBySubRegs || SR->ExplicitSubRegs.size() <= 1 || + SR->Artificial) continue; // SR is composed of multiple sub-regs. Find their names in this register. SmallVector<CodeGenSubRegIndex*, 8> Parts; - for (unsigned j = 0, e = SR->ExplicitSubRegs.size(); j != e; ++j) - Parts.push_back(getSubRegIndex(SR->ExplicitSubRegs[j])); + for (unsigned j = 0, e = SR->ExplicitSubRegs.size(); j != e; ++j) { + CodeGenSubRegIndex &I = *SR->ExplicitSubRegIndices[j]; + if (!I.Artificial) + Parts.push_back(getSubRegIndex(SR->ExplicitSubRegs[j])); + } // Offer this as an existing spelling for the concatenation of Parts. CodeGenSubRegIndex &Idx = *ExplicitSubRegIndices[i]; @@ -602,6 +608,13 @@ unsigned CodeGenRegister::getWeight(const CodeGenRegBank &RegBank) const { namespace { struct TupleExpander : SetTheory::Expander { + // Reference to SynthDefs in the containing CodeGenRegBank, to keep track of + // the synthesized definitions for their lifetime. + std::vector<std::unique_ptr<Record>> &SynthDefs; + + TupleExpander(std::vector<std::unique_ptr<Record>> &SynthDefs) + : SynthDefs(SynthDefs) {} + void expand(SetTheory &ST, Record *Def, SetTheory::RecSet &Elts) override { std::vector<Record*> Indices = Def->getValueAsListOfDefs("SubRegIndices"); unsigned Dim = Indices.size(); @@ -646,7 +659,9 @@ struct TupleExpander : SetTheory::Expander { // Create a new Record representing the synthesized register. This record // is only for consumption by CodeGenRegister, it is not added to the // RecordKeeper. - Record *NewReg = new Record(Name, Def->getLoc(), Def->getRecords()); + SynthDefs.emplace_back( + llvm::make_unique<Record>(Name, Def->getLoc(), Def->getRecords())); + Record *NewReg = SynthDefs.back().get(); Elts.insert(NewReg); // Copy Proto super-classes. @@ -710,7 +725,7 @@ struct TupleExpander : SetTheory::Expander { //===----------------------------------------------------------------------===// static void sortAndUniqueRegisters(CodeGenRegister::Vec &M) { - std::sort(M.begin(), M.end(), deref<llvm::less>()); + llvm::sort(M.begin(), M.end(), deref<llvm::less>()); M.erase(std::unique(M.begin(), M.end(), deref<llvm::equal>()), M.end()); } @@ -736,10 +751,12 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) Orders.resize(1 + AltOrders->size()); // Default allocation order always contains all registers. + Artificial = true; for (unsigned i = 0, e = Elements->size(); i != e; ++i) { Orders[0].push_back((*Elements)[i]); const CodeGenRegister *Reg = RegBank.getReg((*Elements)[i]); Members.push_back(Reg); + Artificial &= Reg->Artificial; TopoSigs.set(Reg->getTopoSig()); } sortAndUniqueRegisters(Members); @@ -798,8 +815,11 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, CopyCost(0), Allocatable(true), AllocationPriority(0) { - for (const auto R : Members) + Artificial = true; + for (const auto R : Members) { TopoSigs.set(R->getTopoSig()); + Artificial &= R->Artificial; + } } // Compute inherited propertied for a synthesized register class. @@ -915,6 +935,8 @@ void CodeGenRegisterClass::computeSubClasses(CodeGenRegBank &RegBank) { CodeGenRegisterClass &RC = *I; RC.SubClasses.resize(RegClasses.size()); RC.SubClasses.set(RC.EnumValue); + if (RC.Artificial) + continue; // Normally, all subclasses have IDs >= rci, unless RC is part of a clique. for (auto I2 = I.base(), E2 = RegClasses.end(); I2 != E2; ++I2) { @@ -975,7 +997,7 @@ CodeGenRegisterClass::getMatchingSubClassWithSubRegs( for (auto &RC : RegClasses) if (SuperRegRCsBV[RC.EnumValue]) SuperRegRCs.emplace_back(&RC); - std::sort(SuperRegRCs.begin(), SuperRegRCs.end(), SizeOrder); + llvm::sort(SuperRegRCs.begin(), SuperRegRCs.end(), SizeOrder); assert(SuperRegRCs.front() == BiggestSuperRegRC && "Biggest class wasn't first"); // Find all the subreg classes and order them by size too. @@ -986,11 +1008,11 @@ CodeGenRegisterClass::getMatchingSubClassWithSubRegs( if (SuperRegClassesBV.any()) SuperRegClasses.push_back(std::make_pair(&RC, SuperRegClassesBV)); } - std::sort(SuperRegClasses.begin(), SuperRegClasses.end(), - [&](const std::pair<CodeGenRegisterClass *, BitVector> &A, - const std::pair<CodeGenRegisterClass *, BitVector> &B) { - return SizeOrder(A.first, B.first); - }); + llvm::sort(SuperRegClasses.begin(), SuperRegClasses.end(), + [&](const std::pair<CodeGenRegisterClass *, BitVector> &A, + const std::pair<CodeGenRegisterClass *, BitVector> &B) { + return SizeOrder(A.first, B.first); + }); // Find the biggest subclass and subreg class such that R:subidx is in the // subreg class for all R in subclass. @@ -1043,12 +1065,15 @@ void CodeGenRegisterClass::getSuperRegClasses(const CodeGenSubRegIndex *SubIdx, } // Populate a unique sorted list of units from a register set. -void CodeGenRegisterClass::buildRegUnitSet( +void CodeGenRegisterClass::buildRegUnitSet(const CodeGenRegBank &RegBank, std::vector<unsigned> &RegUnits) const { std::vector<unsigned> TmpUnits; - for (RegUnitIterator UnitI(Members); UnitI.isValid(); ++UnitI) - TmpUnits.push_back(*UnitI); - std::sort(TmpUnits.begin(), TmpUnits.end()); + for (RegUnitIterator UnitI(Members); UnitI.isValid(); ++UnitI) { + const RegUnit &RU = RegBank.getRegUnit(*UnitI); + if (!RU.Artificial) + TmpUnits.push_back(*UnitI); + } + llvm::sort(TmpUnits.begin(), TmpUnits.end()); std::unique_copy(TmpUnits.begin(), TmpUnits.end(), std::back_inserter(RegUnits)); } @@ -1062,12 +1087,13 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records, // Configure register Sets to understand register classes and tuples. Sets.addFieldExpander("RegisterClass", "MemberList"); Sets.addFieldExpander("CalleeSavedRegs", "SaveList"); - Sets.addExpander("RegisterTuples", llvm::make_unique<TupleExpander>()); + Sets.addExpander("RegisterTuples", + llvm::make_unique<TupleExpander>(SynthDefs)); // Read in the user-defined (named) sub-register indices. // More indices will be synthesized later. std::vector<Record*> SRIs = Records.getAllDerivedDefinitions("SubRegIndex"); - std::sort(SRIs.begin(), SRIs.end(), LessRecord()); + llvm::sort(SRIs.begin(), SRIs.end(), LessRecord()); for (unsigned i = 0, e = SRIs.size(); i != e; ++i) getSubRegIdx(SRIs[i]); // Build composite maps from ComposedOf fields. @@ -1076,7 +1102,7 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records, // Read in the register definitions. std::vector<Record*> Regs = Records.getAllDerivedDefinitions("Register"); - std::sort(Regs.begin(), Regs.end(), LessRecordRegister()); + llvm::sort(Regs.begin(), Regs.end(), LessRecordRegister()); // Assign the enumeration values. for (unsigned i = 0, e = Regs.size(); i != e; ++i) getReg(Regs[i]); @@ -1087,7 +1113,7 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records, for (Record *R : Tups) { std::vector<Record *> TupRegs = *Sets.expand(R); - std::sort(TupRegs.begin(), TupRegs.end(), LessRecordRegister()); + llvm::sort(TupRegs.begin(), TupRegs.end(), LessRecordRegister()); for (Record *RC : TupRegs) getReg(RC); } @@ -1131,6 +1157,18 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records, for (auto &Reg : Registers) Reg.computeSuperRegs(*this); + // For each pair of Reg:SR, if both are non-artificial, mark the + // corresponding sub-register index as non-artificial. + for (auto &Reg : Registers) { + if (Reg.Artificial) + continue; + for (auto P : Reg.getSubRegs()) { + const CodeGenRegister *SR = P.second; + if (!SR->Artificial) + P.first->Artificial = false; + } + } + // Native register units are associated with a leaf register. They've all been // discovered now. NumNativeRegUnits = RegUnits.size(); @@ -1141,9 +1179,11 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records, PrintFatalError("No 'RegisterClass' subclasses defined!"); // Allocate user-defined register classes. - for (auto *RC : RCs) { - RegClasses.emplace_back(*this, RC); - addToMaps(&RegClasses.back()); + for (auto *R : RCs) { + RegClasses.emplace_back(*this, R); + CodeGenRegisterClass &RC = RegClasses.back(); + if (!RC.Artificial) + addToMaps(&RC); } // Infer missing classes to create a full algebra. @@ -1554,21 +1594,24 @@ static void computeUberWeights(std::vector<UberRegSet> &UberSets, Reg = UnitI.getReg(); Weight = 0; } - unsigned UWeight = RegBank.getRegUnit(*UnitI).Weight; - if (!UWeight) { - UWeight = 1; - RegBank.increaseRegUnitWeight(*UnitI, UWeight); + if (!RegBank.getRegUnit(*UnitI).Artificial) { + unsigned UWeight = RegBank.getRegUnit(*UnitI).Weight; + if (!UWeight) { + UWeight = 1; + RegBank.increaseRegUnitWeight(*UnitI, UWeight); + } + Weight += UWeight; } - Weight += UWeight; } if (Weight > MaxWeight) MaxWeight = Weight; if (I->Weight != MaxWeight) { - DEBUG( - dbgs() << "UberSet " << I - UberSets.begin() << " Weight " << MaxWeight; - for (auto &Unit : I->Regs) - dbgs() << " " << Unit->getName(); - dbgs() << "\n"); + LLVM_DEBUG(dbgs() << "UberSet " << I - UberSets.begin() << " Weight " + << MaxWeight; + for (auto &Unit + : I->Regs) dbgs() + << " " << Unit->getName(); + dbgs() << "\n"); // Update the set weight. I->Weight = MaxWeight; } @@ -1595,9 +1638,10 @@ static void computeUberWeights(std::vector<UberRegSet> &UberSets, static bool normalizeWeight(CodeGenRegister *Reg, std::vector<UberRegSet> &UberSets, std::vector<UberRegSet*> &RegSets, - SparseBitVector<> &NormalRegs, + BitVector &NormalRegs, CodeGenRegister::RegUnitList &NormalUnits, CodeGenRegBank &RegBank) { + NormalRegs.resize(std::max(Reg->EnumValue + 1, NormalRegs.size())); if (NormalRegs.test(Reg->EnumValue)) return false; NormalRegs.set(Reg->EnumValue); @@ -1637,7 +1681,8 @@ static bool normalizeWeight(CodeGenRegister *Reg, } else { // Adjust the existing single unit. - RegBank.increaseRegUnitWeight(AdjustUnit, UberSet->Weight - RegWeight); + if (!RegBank.getRegUnit(AdjustUnit).Artificial) + RegBank.increaseRegUnitWeight(AdjustUnit, UberSet->Weight - RegWeight); // The unit may be shared among sets and registers within this set. computeUberWeights(UberSets, RegBank); } @@ -1670,7 +1715,7 @@ void CodeGenRegBank::computeRegUnitWeights() { Changed = false; for (auto &Reg : Registers) { CodeGenRegister::RegUnitList NormalUnits; - SparseBitVector<> NormalRegs; + BitVector NormalRegs; Changed |= normalizeWeight(&Reg, UberSets, RegSets, NormalRegs, NormalUnits, *this); } @@ -1734,8 +1779,8 @@ void CodeGenRegBank::pruneUnitSets() { && (SubSet.Units.size() + 3 > SuperSet.Units.size()) && UnitWeight == RegUnits[SuperSet.Units[0]].Weight && UnitWeight == RegUnits[SuperSet.Units.back()].Weight) { - DEBUG(dbgs() << "UnitSet " << SubIdx << " subsumed by " << SuperIdx - << "\n"); + LLVM_DEBUG(dbgs() << "UnitSet " << SubIdx << " subsumed by " << SuperIdx + << "\n"); // We can pick any of the set names for the merged set. Go for the // shortest one to avoid picking the name of one of the classes that are // artificially created by tablegen. So "FPR128_lo" instead of @@ -1771,7 +1816,7 @@ void CodeGenRegBank::computeRegUnitSets() { // Compute a unique RegUnitSet for each RegClass. auto &RegClasses = getRegClasses(); for (auto &RC : RegClasses) { - if (!RC.Allocatable) + if (!RC.Allocatable || RC.Artificial) continue; // Speculatively grow the RegUnitSets to hold the new set. @@ -1779,7 +1824,7 @@ void CodeGenRegBank::computeRegUnitSets() { RegUnitSets.back().Name = RC.getName(); // Compute a sorted list of units in this class. - RC.buildRegUnitSet(RegUnitSets.back().Units); + RC.buildRegUnitSet(*this, RegUnitSets.back().Units); // Find an existing RegUnitSet. std::vector<RegUnitSet>::const_iterator SetI = @@ -1788,29 +1833,26 @@ void CodeGenRegBank::computeRegUnitSets() { RegUnitSets.pop_back(); } - DEBUG(dbgs() << "\nBefore pruning:\n"; - for (unsigned USIdx = 0, USEnd = RegUnitSets.size(); - USIdx < USEnd; ++USIdx) { - dbgs() << "UnitSet " << USIdx << " " << RegUnitSets[USIdx].Name - << ":"; - for (auto &U : RegUnitSets[USIdx].Units) - printRegUnitName(U); - dbgs() << "\n"; - }); + LLVM_DEBUG(dbgs() << "\nBefore pruning:\n"; for (unsigned USIdx = 0, + USEnd = RegUnitSets.size(); + USIdx < USEnd; ++USIdx) { + dbgs() << "UnitSet " << USIdx << " " << RegUnitSets[USIdx].Name << ":"; + for (auto &U : RegUnitSets[USIdx].Units) + printRegUnitName(U); + dbgs() << "\n"; + }); // Iteratively prune unit sets. pruneUnitSets(); - DEBUG(dbgs() << "\nBefore union:\n"; - for (unsigned USIdx = 0, USEnd = RegUnitSets.size(); - USIdx < USEnd; ++USIdx) { - dbgs() << "UnitSet " << USIdx << " " << RegUnitSets[USIdx].Name - << ":"; - for (auto &U : RegUnitSets[USIdx].Units) - printRegUnitName(U); - dbgs() << "\n"; - } - dbgs() << "\nUnion sets:\n"); + LLVM_DEBUG(dbgs() << "\nBefore union:\n"; for (unsigned USIdx = 0, + USEnd = RegUnitSets.size(); + USIdx < USEnd; ++USIdx) { + dbgs() << "UnitSet " << USIdx << " " << RegUnitSets[USIdx].Name << ":"; + for (auto &U : RegUnitSets[USIdx].Units) + printRegUnitName(U); + dbgs() << "\n"; + } dbgs() << "\nUnion sets:\n"); // Iterate over all unit sets, including new ones added by this loop. unsigned NumRegUnitSubSets = RegUnitSets.size(); @@ -1850,11 +1892,11 @@ void CodeGenRegBank::computeRegUnitSets() { if (SetI != std::prev(RegUnitSets.end())) RegUnitSets.pop_back(); else { - DEBUG(dbgs() << "UnitSet " << RegUnitSets.size()-1 - << " " << RegUnitSets.back().Name << ":"; - for (auto &U : RegUnitSets.back().Units) - printRegUnitName(U); - dbgs() << "\n";); + LLVM_DEBUG(dbgs() << "UnitSet " << RegUnitSets.size() - 1 << " " + << RegUnitSets.back().Name << ":"; + for (auto &U + : RegUnitSets.back().Units) printRegUnitName(U); + dbgs() << "\n";); } } } @@ -1862,15 +1904,14 @@ void CodeGenRegBank::computeRegUnitSets() { // Iteratively prune unit sets after inferring supersets. pruneUnitSets(); - DEBUG(dbgs() << "\n"; - for (unsigned USIdx = 0, USEnd = RegUnitSets.size(); - USIdx < USEnd; ++USIdx) { - dbgs() << "UnitSet " << USIdx << " " << RegUnitSets[USIdx].Name - << ":"; - for (auto &U : RegUnitSets[USIdx].Units) - printRegUnitName(U); - dbgs() << "\n"; - }); + LLVM_DEBUG( + dbgs() << "\n"; for (unsigned USIdx = 0, USEnd = RegUnitSets.size(); + USIdx < USEnd; ++USIdx) { + dbgs() << "UnitSet " << USIdx << " " << RegUnitSets[USIdx].Name << ":"; + for (auto &U : RegUnitSets[USIdx].Units) + printRegUnitName(U); + dbgs() << "\n"; + }); // For each register class, list the UnitSets that are supersets. RegClassUnitSets.resize(RegClasses.size()); @@ -1882,26 +1923,26 @@ void CodeGenRegBank::computeRegUnitSets() { // Recompute the sorted list of units in this class. std::vector<unsigned> RCRegUnits; - RC.buildRegUnitSet(RCRegUnits); + RC.buildRegUnitSet(*this, RCRegUnits); // Don't increase pressure for unallocatable regclasses. if (RCRegUnits.empty()) continue; - DEBUG(dbgs() << "RC " << RC.getName() << " Units: \n"; - for (auto U : RCRegUnits) - printRegUnitName(U); - dbgs() << "\n UnitSetIDs:"); + LLVM_DEBUG(dbgs() << "RC " << RC.getName() << " Units: \n"; + for (auto U + : RCRegUnits) printRegUnitName(U); + dbgs() << "\n UnitSetIDs:"); // Find all supersets. for (unsigned USIdx = 0, USEnd = RegUnitSets.size(); USIdx != USEnd; ++USIdx) { if (isRegUnitSubSet(RCRegUnits, RegUnitSets[USIdx].Units)) { - DEBUG(dbgs() << " " << USIdx); + LLVM_DEBUG(dbgs() << " " << USIdx); RegClassUnitSets[RCIdx].push_back(USIdx); } } - DEBUG(dbgs() << "\n"); + LLVM_DEBUG(dbgs() << "\n"); assert(!RegClassUnitSets[RCIdx].empty() && "missing unit set for regclass"); } @@ -2069,10 +2110,14 @@ void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) { // Compute the set of registers supporting each SubRegIndex. SubReg2SetMap SRSets; for (const auto R : RC->getMembers()) { + if (R->Artificial) + continue; const CodeGenRegister::SubRegMap &SRM = R->getSubRegs(); for (CodeGenRegister::SubRegMap::const_iterator I = SRM.begin(), - E = SRM.end(); I != E; ++I) - SRSets[I->first].push_back(R); + E = SRM.end(); I != E; ++I) { + if (!I->first->Artificial) + SRSets[I->first].push_back(R); + } } for (auto I : SRSets) @@ -2081,6 +2126,8 @@ void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) { // Find matching classes for all SRSets entries. Iterate in SubRegIndex // numerical order to visit synthetic indices last. for (const auto &SubIdx : SubRegIndices) { + if (SubIdx.Artificial) + continue; SubReg2SetMap::const_iterator I = SRSets.find(&SubIdx); // Unsupported SubRegIndex. Skip it. if (I == SRSets.end()) @@ -2137,6 +2184,8 @@ void CodeGenRegBank::inferMatchingSuperRegClass(CodeGenRegisterClass *RC, for (auto I = FirstSubRegRC, E = std::prev(RegClasses.end()); I != std::next(E); ++I) { CodeGenRegisterClass &SubRC = *I; + if (SubRC.Artificial) + continue; // Topological shortcut: SubRC members have the wrong shape. if (!TopoSigs.anyCommon(SubRC.getTopoSigs())) continue; @@ -2182,6 +2231,8 @@ void CodeGenRegBank::computeInferredRegisterClasses() { // Watch out for iterator invalidation here. for (auto I = RegClasses.begin(), E = RegClasses.end(); I != E; ++I) { CodeGenRegisterClass *RC = &*I; + if (RC->Artificial) + continue; // Synthesize answers for getSubClassWithSubReg(). inferSubClassWithSubReg(RC); diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h index f2f1e6971af9..32aa33c80b3a 100644 --- a/utils/TableGen/CodeGenRegisters.h +++ b/utils/TableGen/CodeGenRegisters.h @@ -19,16 +19,16 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SparseBitVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/CodeGen/MachineValueType.h" #include "llvm/MC/LaneBitmask.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MachineValueType.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/SetTheory.h" #include <cassert> @@ -80,6 +80,10 @@ namespace llvm { // Are all super-registers containing this SubRegIndex covered by their // sub-registers? bool AllSuperRegsCovered; + // A subregister index is "artificial" if every subregister obtained + // from applying this index is artificial. Artificial subregister + // indexes are not used to create new register classes. + bool Artificial; CodeGenSubRegIndex(Record *R, unsigned Enum); CodeGenSubRegIndex(StringRef N, StringRef Nspace, unsigned Enum); @@ -150,6 +154,7 @@ namespace llvm { unsigned CostPerUse; bool CoveredBySubRegs; bool HasDisjunctSubRegs; + bool Artificial; // Map SubRegIndex -> Register. typedef std::map<CodeGenSubRegIndex *, CodeGenRegister *, deref<llvm::less>> @@ -331,6 +336,8 @@ namespace llvm { /// True if there are at least 2 subregisters which do not interfere. bool HasDisjunctSubRegs; bool CoveredBySubRegs; + /// A register class is artificial if all its members are artificial. + bool Artificial; // Return the Record that defined this class, or NULL if the class was // created by TableGen. @@ -427,7 +434,8 @@ namespace llvm { const BitVector &getTopoSigs() const { return TopoSigs; } // Populate a unique sorted list of units from a register set. - void buildRegUnitSet(std::vector<unsigned> &RegUnits) const; + void buildRegUnitSet(const CodeGenRegBank &RegBank, + std::vector<unsigned> &RegUnits) const; CodeGenRegisterClass(CodeGenRegBank&, Record *R); @@ -475,8 +483,11 @@ namespace llvm { // Index into RegClassUnitSets where we can find the list of UnitSets that // contain this unit. unsigned RegClassUnitSetsIdx; + // A register unit is artificial if at least one of its roots is + // artificial. + bool Artificial; - RegUnit() : Weight(0), RegClassUnitSetsIdx(0) { + RegUnit() : Weight(0), RegClassUnitSetsIdx(0), Artificial(false) { Roots[0] = Roots[1] = nullptr; } @@ -551,6 +562,9 @@ namespace llvm { // Give each register unit set an order based on sorting criteria. std::vector<unsigned> RegUnitSetOrder; + // Keep track of synthesized definitions generated in TupleExpander. + std::vector<std::unique_ptr<Record>> SynthDefs; + // Add RC to *2RC maps. void addToMaps(CodeGenRegisterClass*); @@ -648,8 +662,12 @@ namespace llvm { // registers. unsigned newRegUnit(CodeGenRegister *R0, CodeGenRegister *R1 = nullptr) { RegUnits.resize(RegUnits.size() + 1); - RegUnits.back().Roots[0] = R0; - RegUnits.back().Roots[1] = R1; + RegUnit &RU = RegUnits.back(); + RU.Roots[0] = R0; + RU.Roots[1] = R1; + RU.Artificial = R0->Artificial; + if (R1) + RU.Artificial |= R1->Artificial; return RegUnits.size() - 1; } diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index b753e19a5443..9331fadf4099 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -12,17 +12,18 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenInstruction.h" #include "CodeGenSchedule.h" +#include "CodeGenInstruction.h" #include "CodeGenTarget.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" #include <algorithm> #include <iterator> @@ -50,38 +51,113 @@ struct InstrsOp : public SetTheory::Operator { }; // (instregex "OpcPat",...) Find all instructions matching an opcode pattern. -// -// TODO: Since this is a prefix match, perform a binary search over the -// instruction names using lower_bound. Note that the predefined instrs must be -// scanned linearly first. However, this is only safe if the regex pattern has -// no top-level bars. The DAG already has a list of patterns, so there's no -// reason to use top-level bars, but we need a way to verify they don't exist -// before implementing the optimization. struct InstRegexOp : public SetTheory::Operator { const CodeGenTarget &Target; InstRegexOp(const CodeGenTarget &t): Target(t) {} + /// Remove any text inside of parentheses from S. + static std::string removeParens(llvm::StringRef S) { + std::string Result; + unsigned Paren = 0; + // NB: We don't care about escaped parens here. + for (char C : S) { + switch (C) { + case '(': + ++Paren; + break; + case ')': + --Paren; + break; + default: + if (Paren == 0) + Result += C; + } + } + return Result; + } + void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, ArrayRef<SMLoc> Loc) override { - SmallVector<Regex, 4> RegexList; + ArrayRef<const CodeGenInstruction *> Instructions = + Target.getInstructionsByEnumValue(); + + unsigned NumGeneric = Target.getNumFixedInstructions(); + unsigned NumPseudos = Target.getNumPseudoInstructions(); + auto Generics = Instructions.slice(0, NumGeneric); + auto Pseudos = Instructions.slice(NumGeneric, NumPseudos); + auto NonPseudos = Instructions.slice(NumGeneric + NumPseudos); + for (Init *Arg : make_range(Expr->arg_begin(), Expr->arg_end())) { StringInit *SI = dyn_cast<StringInit>(Arg); if (!SI) - PrintFatalError(Loc, "instregex requires pattern string: " - + Expr->getAsString()); - std::string pat = SI->getValue(); - // Implement a python-style prefix match. - if (pat[0] != '^') { - pat.insert(0, "^("); - pat.insert(pat.end(), ')'); + PrintFatalError(Loc, "instregex requires pattern string: " + + Expr->getAsString()); + StringRef Original = SI->getValue(); + + // Extract a prefix that we can binary search on. + static const char RegexMetachars[] = "()^$|*+?.[]\\{}"; + auto FirstMeta = Original.find_first_of(RegexMetachars); + + // Look for top-level | or ?. We cannot optimize them to binary search. + if (removeParens(Original).find_first_of("|?") != std::string::npos) + FirstMeta = 0; + + Optional<Regex> Regexpr = None; + StringRef Prefix = Original.substr(0, FirstMeta); + StringRef PatStr = Original.substr(FirstMeta); + if (!PatStr.empty()) { + // For the rest use a python-style prefix match. + std::string pat = PatStr; + if (pat[0] != '^') { + pat.insert(0, "^("); + pat.insert(pat.end(), ')'); + } + Regexpr = Regex(pat); } - RegexList.push_back(Regex(pat)); - } - for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { - for (auto &R : RegexList) { - if (R.match(Inst->TheDef->getName())) + + int NumMatches = 0; + + // The generic opcodes are unsorted, handle them manually. + for (auto *Inst : Generics) { + StringRef InstName = Inst->TheDef->getName(); + if (InstName.startswith(Prefix) && + (!Regexpr || Regexpr->match(InstName.substr(Prefix.size())))) { Elts.insert(Inst->TheDef); + NumMatches++; + } } + + // Target instructions are split into two ranges: pseudo instructions + // first, than non-pseudos. Each range is in lexicographical order + // sorted by name. Find the sub-ranges that start with our prefix. + struct Comp { + bool operator()(const CodeGenInstruction *LHS, StringRef RHS) { + return LHS->TheDef->getName() < RHS; + } + bool operator()(StringRef LHS, const CodeGenInstruction *RHS) { + return LHS < RHS->TheDef->getName() && + !RHS->TheDef->getName().startswith(LHS); + } + }; + auto Range1 = + std::equal_range(Pseudos.begin(), Pseudos.end(), Prefix, Comp()); + auto Range2 = std::equal_range(NonPseudos.begin(), NonPseudos.end(), + Prefix, Comp()); + + // For these ranges we know that instruction names start with the prefix. + // Check if there's a regex that needs to be checked. + const auto HandleNonGeneric = [&](const CodeGenInstruction *Inst) { + StringRef InstName = Inst->TheDef->getName(); + if (!Regexpr || Regexpr->match(InstName.substr(Prefix.size()))) { + Elts.insert(Inst->TheDef); + NumMatches++; + } + }; + std::for_each(Range1.first, Range1.second, HandleNonGeneric); + std::for_each(Range2.first, Range2.second, HandleNonGeneric); + + if (0 == NumMatches) + PrintFatalError(Loc, "instregex has no matches: " + Original); } } }; @@ -139,16 +215,49 @@ CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, // Populate each CodeGenProcModel's WriteResDefs, ReadAdvanceDefs, and // ProcResourceDefs. - DEBUG(dbgs() << "\n+++ RESOURCE DEFINITIONS (collectProcResources) +++\n"); + LLVM_DEBUG( + dbgs() << "\n+++ RESOURCE DEFINITIONS (collectProcResources) +++\n"); collectProcResources(); + // Collect optional processor description. + collectOptionalProcessorInfo(); + + checkCompleteness(); +} + +void CodeGenSchedModels::collectRetireControlUnits() { + RecVec Units = Records.getAllDerivedDefinitions("RetireControlUnit"); + + for (Record *RCU : Units) { + CodeGenProcModel &PM = getProcModel(RCU->getValueAsDef("SchedModel")); + if (PM.RetireControlUnit) { + PrintError(RCU->getLoc(), + "Expected a single RetireControlUnit definition"); + PrintNote(PM.RetireControlUnit->getLoc(), + "Previous definition of RetireControlUnit was here"); + } + PM.RetireControlUnit = RCU; + } +} + +/// Collect optional processor information. +void CodeGenSchedModels::collectOptionalProcessorInfo() { + // Find register file definitions for each processor. + collectRegisterFiles(); + + // Collect processor RetireControlUnit descriptors if available. + collectRetireControlUnits(); + + // Find pfm counter definitions for each processor. + collectPfmCounters(); + checkCompleteness(); } /// Gather all processor models. void CodeGenSchedModels::collectProcModels() { RecVec ProcRecords = Records.getAllDerivedDefinitions("Processor"); - std::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName()); + llvm::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName()); // Reserve space because we can. Reallocation would be ok. ProcModels.reserve(ProcRecords.size()+1); @@ -160,7 +269,7 @@ void CodeGenSchedModels::collectProcModels() { ProcModelMap[NoModelDef] = 0; // For each processor, find a unique machine model. - DEBUG(dbgs() << "+++ PROCESSOR MODELs (addProcModel) +++\n"); + LLVM_DEBUG(dbgs() << "+++ PROCESSOR MODELs (addProcModel) +++\n"); for (Record *ProcRecord : ProcRecords) addProcModel(ProcRecord); } @@ -184,7 +293,7 @@ void CodeGenSchedModels::addProcModel(Record *ProcDef) { ProcModels.emplace_back(ProcModels.size(), Name, ProcDef->getValueAsDef("SchedModel"), ModelKey); } - DEBUG(ProcModels.back().dump()); + LLVM_DEBUG(ProcModels.back().dump()); } // Recursively find all reachable SchedReadWrite records. @@ -267,7 +376,7 @@ void CodeGenSchedModels::collectSchedRW() { // Find all ReadWrites referenced by SchedAlias. AliasDefs needs to be sorted // for the loop below that initializes Alias vectors. RecVec AliasDefs = Records.getAllDerivedDefinitions("SchedAlias"); - std::sort(AliasDefs.begin(), AliasDefs.end(), LessRecord()); + llvm::sort(AliasDefs.begin(), AliasDefs.end(), LessRecord()); for (Record *ADef : AliasDefs) { Record *MatchDef = ADef->getValueAsDef("MatchRW"); Record *AliasDef = ADef->getValueAsDef("AliasRW"); @@ -285,12 +394,12 @@ void CodeGenSchedModels::collectSchedRW() { } // Sort and add the SchedReadWrites directly referenced by instructions or // itinerary resources. Index reads and writes in separate domains. - std::sort(SWDefs.begin(), SWDefs.end(), LessRecord()); + llvm::sort(SWDefs.begin(), SWDefs.end(), LessRecord()); for (Record *SWDef : SWDefs) { assert(!getSchedRWIdx(SWDef, /*IsRead=*/false) && "duplicate SchedWrite"); SchedWrites.emplace_back(SchedWrites.size(), SWDef); } - std::sort(SRDefs.begin(), SRDefs.end(), LessRecord()); + llvm::sort(SRDefs.begin(), SRDefs.end(), LessRecord()); for (Record *SRDef : SRDefs) { assert(!getSchedRWIdx(SRDef, /*IsRead-*/true) && "duplicate SchedWrite"); SchedReads.emplace_back(SchedReads.size(), SRDef); @@ -312,26 +421,26 @@ void CodeGenSchedModels::collectSchedRW() { PrintFatalError(ADef->getLoc(), "Cannot Alias an Alias"); RW.Aliases.push_back(ADef); } - DEBUG( - dbgs() << "\n+++ SCHED READS and WRITES (collectSchedRW) +++\n"; - for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) { - dbgs() << WIdx << ": "; - SchedWrites[WIdx].dump(); - dbgs() << '\n'; - } - for (unsigned RIdx = 0, REnd = SchedReads.size(); RIdx != REnd; ++RIdx) { - dbgs() << RIdx << ": "; - SchedReads[RIdx].dump(); - dbgs() << '\n'; - } - RecVec RWDefs = Records.getAllDerivedDefinitions("SchedReadWrite"); - for (Record *RWDef : RWDefs) { - if (!getSchedRWIdx(RWDef, RWDef->isSubClassOf("SchedRead"))) { - const std::string &Name = RWDef->getName(); - if (Name != "NoWrite" && Name != "ReadDefault") - dbgs() << "Unused SchedReadWrite " << RWDef->getName() << '\n'; - } - }); + LLVM_DEBUG( + dbgs() << "\n+++ SCHED READS and WRITES (collectSchedRW) +++\n"; + for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) { + dbgs() << WIdx << ": "; + SchedWrites[WIdx].dump(); + dbgs() << '\n'; + } for (unsigned RIdx = 0, REnd = SchedReads.size(); RIdx != REnd; + ++RIdx) { + dbgs() << RIdx << ": "; + SchedReads[RIdx].dump(); + dbgs() << '\n'; + } RecVec RWDefs = Records.getAllDerivedDefinitions("SchedReadWrite"); + for (Record *RWDef + : RWDefs) { + if (!getSchedRWIdx(RWDef, RWDef->isSubClassOf("SchedRead"))) { + StringRef Name = RWDef->getName(); + if (Name != "NoWrite" && Name != "ReadDefault") + dbgs() << "Unused SchedReadWrite " << Name << '\n'; + } + }); } /// Compute a SchedWrite name from a sequence of writes. @@ -346,16 +455,12 @@ std::string CodeGenSchedModels::genRWName(ArrayRef<unsigned> Seq, bool IsRead) { return Name; } -unsigned CodeGenSchedModels::getSchedRWIdx(Record *Def, bool IsRead, - unsigned After) const { +unsigned CodeGenSchedModels::getSchedRWIdx(const Record *Def, + bool IsRead) const { const std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; - assert(After < RWVec.size() && "start position out of bounds"); - for (std::vector<CodeGenSchedRW>::const_iterator I = RWVec.begin() + After, - E = RWVec.end(); I != E; ++I) { - if (I->TheDef == Def) - return I - RWVec.begin(); - } - return 0; + const auto I = find_if( + RWVec, [Def](const CodeGenSchedRW &RW) { return RW.TheDef == Def; }); + return I == RWVec.end() ? 0 : std::distance(RWVec.begin(), I); } bool CodeGenSchedModels::hasReadOfWrite(Record *WriteDef) const { @@ -372,10 +477,8 @@ bool CodeGenSchedModels::hasReadOfWrite(Record *WriteDef) const { return false; } -namespace llvm { - -void splitSchedReadWrites(const RecVec &RWDefs, - RecVec &WriteDefs, RecVec &ReadDefs) { +static void splitSchedReadWrites(const RecVec &RWDefs, + RecVec &WriteDefs, RecVec &ReadDefs) { for (Record *RWDef : RWDefs) { if (RWDef->isSubClassOf("SchedWrite")) WriteDefs.push_back(RWDef); @@ -386,16 +489,14 @@ void splitSchedReadWrites(const RecVec &RWDefs, } } -} // end namespace llvm - // Split the SchedReadWrites defs and call findRWs for each list. void CodeGenSchedModels::findRWs(const RecVec &RWDefs, IdxVec &Writes, IdxVec &Reads) const { - RecVec WriteDefs; - RecVec ReadDefs; - splitSchedReadWrites(RWDefs, WriteDefs, ReadDefs); - findRWs(WriteDefs, Writes, false); - findRWs(ReadDefs, Reads, true); + RecVec WriteDefs; + RecVec ReadDefs; + splitSchedReadWrites(RWDefs, WriteDefs, ReadDefs); + findRWs(WriteDefs, Writes, false); + findRWs(ReadDefs, Reads, true); } // Call getSchedRWIdx for all elements in a sequence of SchedRW defs. @@ -432,11 +533,10 @@ void CodeGenSchedModels::expandRWSeqForProc( const CodeGenSchedRW &SchedWrite = getSchedRW(RWIdx, IsRead); Record *AliasDef = nullptr; - for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end(); - AI != AE; ++AI) { - const CodeGenSchedRW &AliasRW = getSchedRW((*AI)->getValueAsDef("AliasRW")); - if ((*AI)->getValueInit("SchedModel")->isComplete()) { - Record *ModelDef = (*AI)->getValueAsDef("SchedModel"); + for (const Record *Rec : SchedWrite.Aliases) { + const CodeGenSchedRW &AliasRW = getSchedRW(Rec->getValueAsDef("AliasRW")); + if (Rec->getValueInit("SchedModel")->isComplete()) { + Record *ModelDef = Rec->getValueAsDef("SchedModel"); if (&getProcModel(ModelDef) != &ProcModel) continue; } @@ -457,9 +557,9 @@ void CodeGenSchedModels::expandRWSeqForProc( } int Repeat = SchedWrite.TheDef ? SchedWrite.TheDef->getValueAsInt("Repeat") : 1; - for (int i = 0; i < Repeat; ++i) { - for (unsigned I : SchedWrite.Sequence) { - expandRWSeqForProc(I, RWSeq, IsRead, ProcModel); + for (int I = 0, E = Repeat; I < E; ++I) { + for (unsigned Idx : SchedWrite.Sequence) { + expandRWSeqForProc(Idx, RWSeq, IsRead, ProcModel); } } } @@ -469,13 +569,11 @@ unsigned CodeGenSchedModels::findRWForSequence(ArrayRef<unsigned> Seq, bool IsRead) { std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; - for (std::vector<CodeGenSchedRW>::iterator I = RWVec.begin(), E = RWVec.end(); - I != E; ++I) { - if (makeArrayRef(I->Sequence) == Seq) - return I - RWVec.begin(); - } + auto I = find_if(RWVec, [Seq](CodeGenSchedRW &RW) { + return makeArrayRef(RW.Sequence) == Seq; + }); // Index zero reserved for invalid RW. - return 0; + return I == RWVec.end() ? 0 : std::distance(RWVec.begin(), I); } /// Add this ReadWrite if it doesn't already exist. @@ -489,12 +587,10 @@ unsigned CodeGenSchedModels::findOrInsertRW(ArrayRef<unsigned> Seq, if (Idx) return Idx; - unsigned RWIdx = IsRead ? SchedReads.size() : SchedWrites.size(); + std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; + unsigned RWIdx = RWVec.size(); CodeGenSchedRW SchedRW(RWIdx, IsRead, Seq, genRWName(Seq, IsRead)); - if (IsRead) - SchedReads.push_back(SchedRW); - else - SchedWrites.push_back(SchedRW); + RWVec.push_back(SchedRW); return RWIdx; } @@ -504,10 +600,9 @@ unsigned CodeGenSchedModels::findOrInsertRW(ArrayRef<unsigned> Seq, void CodeGenSchedModels::collectSchedClasses() { // NoItinerary is always the first class at Idx=0 - SchedClasses.resize(1); - SchedClasses.back().Index = 0; - SchedClasses.back().Name = "NoInstrModel"; - SchedClasses.back().ItinClassDef = Records.getDef("NoItinerary"); + assert(SchedClasses.empty() && "Expected empty sched class"); + SchedClasses.emplace_back(0, "NoInstrModel", + Records.getDef("NoItinerary")); SchedClasses.back().ProcIndices.push_back(0); // Create a SchedClass for each unique combination of itinerary class and @@ -519,32 +614,34 @@ void CodeGenSchedModels::collectSchedClasses() { findRWs(Inst->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); // ProcIdx == 0 indicates the class applies to all processors. - IdxVec ProcIndices(1, 0); - - unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, ProcIndices); + unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, /*ProcIndices*/{0}); InstrClassMap[Inst->TheDef] = SCIdx; } // Create classes for InstRW defs. RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); - std::sort(InstRWDefs.begin(), InstRWDefs.end(), LessRecord()); - DEBUG(dbgs() << "\n+++ SCHED CLASSES (createInstRWClass) +++\n"); + llvm::sort(InstRWDefs.begin(), InstRWDefs.end(), LessRecord()); + LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (createInstRWClass) +++\n"); for (Record *RWDef : InstRWDefs) createInstRWClass(RWDef); NumInstrSchedClasses = SchedClasses.size(); bool EnableDump = false; - DEBUG(EnableDump = true); + LLVM_DEBUG(EnableDump = true); if (!EnableDump) return; - dbgs() << "\n+++ ITINERARIES and/or MACHINE MODELS (collectSchedClasses) +++\n"; + LLVM_DEBUG( + dbgs() + << "\n+++ ITINERARIES and/or MACHINE MODELS (collectSchedClasses) +++\n"); for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { StringRef InstName = Inst->TheDef->getName(); - unsigned SCIdx = InstrClassMap.lookup(Inst->TheDef); + unsigned SCIdx = getSchedClassIdx(*Inst); if (!SCIdx) { - if (!Inst->hasNoSchedulingInfo) - dbgs() << "No machine model for " << Inst->TheDef->getName() << '\n'; + LLVM_DEBUG({ + if (!Inst->hasNoSchedulingInfo) + dbgs() << "No machine model for " << Inst->TheDef->getName() << '\n'; + }); continue; } CodeGenSchedClass &SC = getSchedClass(SCIdx); @@ -560,58 +657,51 @@ void CodeGenSchedModels::collectSchedClasses() { } if (!SC.Writes.empty()) { ProcIndices.push_back(0); - dbgs() << "SchedRW machine model for " << InstName; - for (IdxIter WI = SC.Writes.begin(), WE = SC.Writes.end(); WI != WE; ++WI) - dbgs() << " " << SchedWrites[*WI].Name; - for (IdxIter RI = SC.Reads.begin(), RE = SC.Reads.end(); RI != RE; ++RI) - dbgs() << " " << SchedReads[*RI].Name; - dbgs() << '\n'; + LLVM_DEBUG({ + dbgs() << "SchedRW machine model for " << InstName; + for (IdxIter WI = SC.Writes.begin(), WE = SC.Writes.end(); WI != WE; + ++WI) + dbgs() << " " << SchedWrites[*WI].Name; + for (IdxIter RI = SC.Reads.begin(), RE = SC.Reads.end(); RI != RE; ++RI) + dbgs() << " " << SchedReads[*RI].Name; + dbgs() << '\n'; + }); } const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs; for (Record *RWDef : RWDefs) { const CodeGenProcModel &ProcModel = - getProcModel(RWDef->getValueAsDef("SchedModel")); + getProcModel(RWDef->getValueAsDef("SchedModel")); ProcIndices.push_back(ProcModel.Index); - dbgs() << "InstRW on " << ProcModel.ModelName << " for " << InstName; + LLVM_DEBUG(dbgs() << "InstRW on " << ProcModel.ModelName << " for " + << InstName); IdxVec Writes; IdxVec Reads; findRWs(RWDef->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); - for (unsigned WIdx : Writes) - dbgs() << " " << SchedWrites[WIdx].Name; - for (unsigned RIdx : Reads) - dbgs() << " " << SchedReads[RIdx].Name; - dbgs() << '\n'; + LLVM_DEBUG({ + for (unsigned WIdx : Writes) + dbgs() << " " << SchedWrites[WIdx].Name; + for (unsigned RIdx : Reads) + dbgs() << " " << SchedReads[RIdx].Name; + dbgs() << '\n'; + }); } // If ProcIndices contains zero, the class applies to all processors. - if (!std::count(ProcIndices.begin(), ProcIndices.end(), 0)) { - for (const CodeGenProcModel &PM : ProcModels) { - if (!std::count(ProcIndices.begin(), ProcIndices.end(), PM.Index)) - dbgs() << "No machine model for " << Inst->TheDef->getName() - << " on processor " << PM.ModelName << '\n'; + LLVM_DEBUG({ + if (!std::count(ProcIndices.begin(), ProcIndices.end(), 0)) { + for (const CodeGenProcModel &PM : ProcModels) { + if (!std::count(ProcIndices.begin(), ProcIndices.end(), PM.Index)) + dbgs() << "No machine model for " << Inst->TheDef->getName() + << " on processor " << PM.ModelName << '\n'; + } } - } - } -} - -/// Find an SchedClass that has been inferred from a per-operand list of -/// SchedWrites and SchedReads. -unsigned CodeGenSchedModels::findSchedClassIdx(Record *ItinClassDef, - ArrayRef<unsigned> Writes, - ArrayRef<unsigned> Reads) const { - for (SchedClassIter I = schedClassBegin(), E = schedClassEnd(); I != E; ++I) { - if (I->ItinClassDef == ItinClassDef && makeArrayRef(I->Writes) == Writes && - makeArrayRef(I->Reads) == Reads) { - return I - schedClassBegin(); - } + }); } - return 0; } // Get the SchedClass index for an instruction. -unsigned CodeGenSchedModels::getSchedClassIdx( - const CodeGenInstruction &Inst) const { - +unsigned +CodeGenSchedModels::getSchedClassIdx(const CodeGenInstruction &Inst) const { return InstrClassMap.lookup(Inst.TheDef); } @@ -655,22 +745,27 @@ unsigned CodeGenSchedModels::addSchedClass(Record *ItinClassDef, ArrayRef<unsigned> ProcIndices) { assert(!ProcIndices.empty() && "expect at least one ProcIdx"); - unsigned Idx = findSchedClassIdx(ItinClassDef, OperWrites, OperReads); + auto IsKeyEqual = [=](const CodeGenSchedClass &SC) { + return SC.isKeyEqual(ItinClassDef, OperWrites, OperReads); + }; + + auto I = find_if(make_range(schedClassBegin(), schedClassEnd()), IsKeyEqual); + unsigned Idx = I == schedClassEnd() ? 0 : std::distance(schedClassBegin(), I); if (Idx || SchedClasses[0].isKeyEqual(ItinClassDef, OperWrites, OperReads)) { IdxVec PI; std::set_union(SchedClasses[Idx].ProcIndices.begin(), SchedClasses[Idx].ProcIndices.end(), ProcIndices.begin(), ProcIndices.end(), std::back_inserter(PI)); - SchedClasses[Idx].ProcIndices.swap(PI); + SchedClasses[Idx].ProcIndices = std::move(PI); return Idx; } Idx = SchedClasses.size(); - SchedClasses.resize(Idx+1); + SchedClasses.emplace_back(Idx, + createSchedClassName(ItinClassDef, OperWrites, + OperReads), + ItinClassDef); CodeGenSchedClass &SC = SchedClasses.back(); - SC.Index = Idx; - SC.Name = createSchedClassName(ItinClassDef, OperWrites, OperReads); - SC.ItinClassDef = ItinClassDef; SC.Writes = OperWrites; SC.Reads = OperReads; SC.ProcIndices = ProcIndices; @@ -685,106 +780,104 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { // intersects with an existing class via a previous InstRWDef. Instrs that do // not intersect with an existing class refer back to their former class as // determined from ItinDef or SchedRW. - SmallVector<std::pair<unsigned, SmallVector<Record *, 8>>, 4> ClassInstrs; + SmallMapVector<unsigned, SmallVector<Record *, 8>, 4> ClassInstrs; // Sort Instrs into sets. const RecVec *InstDefs = Sets.expand(InstRWDef); if (InstDefs->empty()) PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes"); - for (Record *InstDef : make_range(InstDefs->begin(), InstDefs->end())) { + for (Record *InstDef : *InstDefs) { InstClassMapTy::const_iterator Pos = InstrClassMap.find(InstDef); if (Pos == InstrClassMap.end()) PrintFatalError(InstDef->getLoc(), "No sched class for instruction."); unsigned SCIdx = Pos->second; - unsigned CIdx = 0, CEnd = ClassInstrs.size(); - for (; CIdx != CEnd; ++CIdx) { - if (ClassInstrs[CIdx].first == SCIdx) - break; - } - if (CIdx == CEnd) { - ClassInstrs.resize(CEnd + 1); - ClassInstrs[CIdx].first = SCIdx; - } - ClassInstrs[CIdx].second.push_back(InstDef); + ClassInstrs[SCIdx].push_back(InstDef); } // For each set of Instrs, create a new class if necessary, and map or remap // the Instrs to it. - unsigned CIdx = 0, CEnd = ClassInstrs.size(); - for (; CIdx != CEnd; ++CIdx) { - unsigned OldSCIdx = ClassInstrs[CIdx].first; - ArrayRef<Record*> InstDefs = ClassInstrs[CIdx].second; + for (auto &Entry : ClassInstrs) { + unsigned OldSCIdx = Entry.first; + ArrayRef<Record*> InstDefs = Entry.second; // If the all instrs in the current class are accounted for, then leave // them mapped to their old class. if (OldSCIdx) { const RecVec &RWDefs = SchedClasses[OldSCIdx].InstRWs; if (!RWDefs.empty()) { const RecVec *OrigInstDefs = Sets.expand(RWDefs[0]); - unsigned OrigNumInstrs = 0; - for (Record *OIDef : make_range(OrigInstDefs->begin(), OrigInstDefs->end())) { - if (InstrClassMap[OIDef] == OldSCIdx) - ++OrigNumInstrs; - } + unsigned OrigNumInstrs = + count_if(*OrigInstDefs, [&](Record *OIDef) { + return InstrClassMap[OIDef] == OldSCIdx; + }); if (OrigNumInstrs == InstDefs.size()) { assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 && "expected a generic SchedClass"); - DEBUG(dbgs() << "InstRW: Reuse SC " << OldSCIdx << ":" - << SchedClasses[OldSCIdx].Name << " on " - << InstRWDef->getValueAsDef("SchedModel")->getName() << "\n"); + Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); + // Make sure we didn't already have a InstRW containing this + // instruction on this model. + for (Record *RWD : RWDefs) { + if (RWD->getValueAsDef("SchedModel") == RWModelDef && + RWModelDef->getValueAsBit("FullInstRWOverlapCheck")) { + for (Record *Inst : InstDefs) { + PrintFatalError(InstRWDef->getLoc(), "Overlapping InstRW def " + + Inst->getName() + " also matches " + + RWD->getValue("Instrs")->getValue()->getAsString()); + } + } + } + LLVM_DEBUG(dbgs() << "InstRW: Reuse SC " << OldSCIdx << ":" + << SchedClasses[OldSCIdx].Name << " on " + << RWModelDef->getName() << "\n"); SchedClasses[OldSCIdx].InstRWs.push_back(InstRWDef); continue; } } } unsigned SCIdx = SchedClasses.size(); - SchedClasses.resize(SCIdx+1); + SchedClasses.emplace_back(SCIdx, createSchedClassName(InstDefs), nullptr); CodeGenSchedClass &SC = SchedClasses.back(); - SC.Index = SCIdx; - SC.Name = createSchedClassName(InstDefs); - DEBUG(dbgs() << "InstRW: New SC " << SCIdx << ":" << SC.Name << " on " - << InstRWDef->getValueAsDef("SchedModel")->getName() << "\n"); + LLVM_DEBUG(dbgs() << "InstRW: New SC " << SCIdx << ":" << SC.Name << " on " + << InstRWDef->getValueAsDef("SchedModel")->getName() + << "\n"); // Preserve ItinDef and Writes/Reads for processors without an InstRW entry. SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef; SC.Writes = SchedClasses[OldSCIdx].Writes; SC.Reads = SchedClasses[OldSCIdx].Reads; SC.ProcIndices.push_back(0); - // Map each Instr to this new class. - // Note that InstDefs may be a smaller list than InstRWDef's "Instrs". - Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); - SmallSet<unsigned, 4> RemappedClassIDs; - for (ArrayRef<Record*>::const_iterator - II = InstDefs.begin(), IE = InstDefs.end(); II != IE; ++II) { - unsigned OldSCIdx = InstrClassMap[*II]; - if (OldSCIdx && RemappedClassIDs.insert(OldSCIdx).second) { - for (RecIter RI = SchedClasses[OldSCIdx].InstRWs.begin(), - RE = SchedClasses[OldSCIdx].InstRWs.end(); RI != RE; ++RI) { - if ((*RI)->getValueAsDef("SchedModel") == RWModelDef) { - PrintFatalError(InstRWDef->getLoc(), "Overlapping InstRW def " + - (*II)->getName() + " also matches " + - (*RI)->getValue("Instrs")->getValue()->getAsString()); + // If we had an old class, copy it's InstRWs to this new class. + if (OldSCIdx) { + Record *RWModelDef = InstRWDef->getValueAsDef("SchedModel"); + for (Record *OldRWDef : SchedClasses[OldSCIdx].InstRWs) { + if (OldRWDef->getValueAsDef("SchedModel") == RWModelDef) { + for (Record *InstDef : InstDefs) { + PrintFatalError(OldRWDef->getLoc(), "Overlapping InstRW def " + + InstDef->getName() + " also matches " + + OldRWDef->getValue("Instrs")->getValue()->getAsString()); } - assert(*RI != InstRWDef && "SchedClass has duplicate InstRW def"); - SC.InstRWs.push_back(*RI); } + assert(OldRWDef != InstRWDef && + "SchedClass has duplicate InstRW def"); + SC.InstRWs.push_back(OldRWDef); } - InstrClassMap[*II] = SCIdx; } + // Map each Instr to this new class. + for (Record *InstDef : InstDefs) + InstrClassMap[InstDef] = SCIdx; SC.InstRWs.push_back(InstRWDef); } } // True if collectProcItins found anything. bool CodeGenSchedModels::hasItineraries() const { - for (const CodeGenProcModel &PM : make_range(procModelBegin(),procModelEnd())) { + for (const CodeGenProcModel &PM : make_range(procModelBegin(),procModelEnd())) if (PM.hasItineraries()) return true; - } return false; } // Gather the processor itineraries. void CodeGenSchedModels::collectProcItins() { - DEBUG(dbgs() << "\n+++ PROBLEM ITINERARIES (collectProcItins) +++\n"); + LLVM_DEBUG(dbgs() << "\n+++ PROBLEM ITINERARIES (collectProcItins) +++\n"); for (CodeGenProcModel &ProcModel : ProcModels) { if (!ProcModel.hasItineraries()) continue; @@ -798,37 +891,39 @@ void CodeGenSchedModels::collectProcItins() { // Insert each itinerary data record in the correct position within // the processor model's ItinDefList. for (Record *ItinData : ItinRecords) { - Record *ItinDef = ItinData->getValueAsDef("TheClass"); + const Record *ItinDef = ItinData->getValueAsDef("TheClass"); bool FoundClass = false; - for (SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd(); - SCI != SCE; ++SCI) { + + for (const CodeGenSchedClass &SC : + make_range(schedClassBegin(), schedClassEnd())) { // Multiple SchedClasses may share an itinerary. Update all of them. - if (SCI->ItinClassDef == ItinDef) { - ProcModel.ItinDefList[SCI->Index] = ItinData; + if (SC.ItinClassDef == ItinDef) { + ProcModel.ItinDefList[SC.Index] = ItinData; FoundClass = true; } } if (!FoundClass) { - DEBUG(dbgs() << ProcModel.ItinsDef->getName() - << " missing class for itinerary " << ItinDef->getName() << '\n'); + LLVM_DEBUG(dbgs() << ProcModel.ItinsDef->getName() + << " missing class for itinerary " + << ItinDef->getName() << '\n'); } } // Check for missing itinerary entries. assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec"); - DEBUG( - for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) { - if (!ProcModel.ItinDefList[i]) - dbgs() << ProcModel.ItinsDef->getName() - << " missing itinerary for class " - << SchedClasses[i].Name << '\n'; - }); + LLVM_DEBUG( + for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) { + if (!ProcModel.ItinDefList[i]) + dbgs() << ProcModel.ItinsDef->getName() + << " missing itinerary for class " << SchedClasses[i].Name + << '\n'; + }); } } // Gather the read/write types for each itinerary class. void CodeGenSchedModels::collectProcItinRW() { RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW"); - std::sort(ItinRWDefs.begin(), ItinRWDefs.end(), LessRecord()); + llvm::sort(ItinRWDefs.begin(), ItinRWDefs.end(), LessRecord()); for (Record *RWDef : ItinRWDefs) { if (!RWDef->getValueInit("SchedModel")->isComplete()) PrintFatalError(RWDef->getLoc(), "SchedModel is undefined"); @@ -854,8 +949,9 @@ void CodeGenSchedModels::collectProcUnsupportedFeatures() { /// Infer new classes from existing classes. In the process, this may create new /// SchedWrites from sequences of existing SchedWrites. void CodeGenSchedModels::inferSchedClasses() { - DEBUG(dbgs() << "\n+++ INFERRING SCHED CLASSES (inferSchedClasses) +++\n"); - DEBUG(dbgs() << NumInstrSchedClasses << " instr sched classes.\n"); + LLVM_DEBUG( + dbgs() << "\n+++ INFERRING SCHED CLASSES (inferSchedClasses) +++\n"); + LLVM_DEBUG(dbgs() << NumInstrSchedClasses << " instr sched classes.\n"); // Visit all existing classes and newly created classes. for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) { @@ -881,20 +977,18 @@ void CodeGenSchedModels::inferFromItinClass(Record *ItinClassDef, const CodeGenProcModel &PM = ProcModels[PIdx]; // For all ItinRW entries. bool HasMatch = false; - for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end(); - II != IE; ++II) { - RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses"); + for (const Record *Rec : PM.ItinRWDefs) { + RecVec Matched = Rec->getValueAsListOfDefs("MatchedItinClasses"); if (!std::count(Matched.begin(), Matched.end(), ItinClassDef)) continue; if (HasMatch) - PrintFatalError((*II)->getLoc(), "Duplicate itinerary class " + PrintFatalError(Rec->getLoc(), "Duplicate itinerary class " + ItinClassDef->getName() + " in ItinResources for " + PM.ModelName); HasMatch = true; IdxVec Writes, Reads; - findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); - IdxVec ProcIndices(1, PIdx); - inferFromRW(Writes, Reads, FromClassIdx, ProcIndices); + findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); + inferFromRW(Writes, Reads, FromClassIdx, PIdx); } } } @@ -917,8 +1011,7 @@ void CodeGenSchedModels::inferFromInstRWs(unsigned SCIdx) { IdxVec Writes, Reads; findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); unsigned PIdx = getProcModel(Rec->getValueAsDef("SchedModel")).Index; - IdxVec ProcIndices(1, PIdx); - inferFromRW(Writes, Reads, SCIdx, ProcIndices); // May mutate SchedClasses. + inferFromRW(Writes, Reads, SCIdx, PIdx); // May mutate SchedClasses. } } @@ -1001,10 +1094,10 @@ bool PredTransitions::mutuallyExclusive(Record *PredDef, const CodeGenSchedRW &SchedRW = SchedModels.getSchedRW(PC.RWIdx, PC.IsRead); assert(SchedRW.HasVariants && "PredCheck must refer to a SchedVariant"); RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants"); - for (RecIter VI = Variants.begin(), VE = Variants.end(); VI != VE; ++VI) { - if ((*VI)->getValueAsDef("Predicate") == PredDef) - return true; - } + if (any_of(Variants, [PredDef](const Record *R) { + return R->getValueAsDef("Predicate") == PredDef; + })) + return true; } return false; } @@ -1022,12 +1115,10 @@ static bool hasAliasedVariants(const CodeGenSchedRW &RW, if (AliasRW.IsSequence) { IdxVec ExpandedRWs; SchedModels.expandRWSequence(AliasRW.Index, ExpandedRWs, AliasRW.IsRead); - for (IdxIter SI = ExpandedRWs.begin(), SE = ExpandedRWs.end(); - SI != SE; ++SI) { - if (hasAliasedVariants(SchedModels.getSchedRW(*SI, AliasRW.IsRead), - SchedModels)) { + for (unsigned SI : ExpandedRWs) { + if (hasAliasedVariants(SchedModels.getSchedRW(SI, AliasRW.IsRead), + SchedModels)) return true; - } } } } @@ -1036,27 +1127,16 @@ static bool hasAliasedVariants(const CodeGenSchedRW &RW, static bool hasVariant(ArrayRef<PredTransition> Transitions, CodeGenSchedModels &SchedModels) { - for (ArrayRef<PredTransition>::iterator - PTI = Transitions.begin(), PTE = Transitions.end(); - PTI != PTE; ++PTI) { - for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator - WSI = PTI->WriteSequences.begin(), WSE = PTI->WriteSequences.end(); - WSI != WSE; ++WSI) { - for (SmallVectorImpl<unsigned>::const_iterator - WI = WSI->begin(), WE = WSI->end(); WI != WE; ++WI) { - if (hasAliasedVariants(SchedModels.getSchedWrite(*WI), SchedModels)) + for (const PredTransition &PTI : Transitions) { + for (const SmallVectorImpl<unsigned> &WSI : PTI.WriteSequences) + for (unsigned WI : WSI) + if (hasAliasedVariants(SchedModels.getSchedWrite(WI), SchedModels)) return true; - } - } - for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator - RSI = PTI->ReadSequences.begin(), RSE = PTI->ReadSequences.end(); - RSI != RSE; ++RSI) { - for (SmallVectorImpl<unsigned>::const_iterator - RI = RSI->begin(), RE = RSI->end(); RI != RE; ++RI) { - if (hasAliasedVariants(SchedModels.getSchedRead(*RI), SchedModels)) + + for (const SmallVectorImpl<unsigned> &RSI : PTI.ReadSequences) + for (unsigned RI : RSI) + if (hasAliasedVariants(SchedModels.getSchedRead(RI), SchedModels)) return true; - } - } } return false; } @@ -1080,7 +1160,7 @@ void PredTransitions::getIntersectingVariants( // Push each variant. Assign TransVecIdx later. const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants"); for (Record *VarDef : VarDefs) - Variants.push_back(TransVariant(VarDef, SchedRW.Index, VarProcIdx, 0)); + Variants.emplace_back(VarDef, SchedRW.Index, VarProcIdx, 0); if (VarProcIdx == 0) GenericRW = true; } @@ -1100,12 +1180,10 @@ void PredTransitions::getIntersectingVariants( if (AliasRW.HasVariants) { const RecVec VarDefs = AliasRW.TheDef->getValueAsListOfDefs("Variants"); for (Record *VD : VarDefs) - Variants.push_back(TransVariant(VD, AliasRW.Index, AliasProcIdx, 0)); - } - if (AliasRW.IsSequence) { - Variants.push_back( - TransVariant(AliasRW.TheDef, SchedRW.Index, AliasProcIdx, 0)); + Variants.emplace_back(VD, AliasRW.Index, AliasProcIdx, 0); } + if (AliasRW.IsSequence) + Variants.emplace_back(AliasRW.TheDef, SchedRW.Index, AliasProcIdx, 0); if (AliasProcIdx == 0) GenericRW = true; } @@ -1164,7 +1242,7 @@ pushVariant(const TransVariant &VInfo, bool IsRead) { IdxVec SelectedRWs; if (VInfo.VarOrSeqDef->isSubClassOf("SchedVar")) { Record *PredDef = VInfo.VarOrSeqDef->getValueAsDef("Predicate"); - Trans.PredTerm.push_back(PredCheck(IsRead, VInfo.RWIdx,PredDef)); + Trans.PredTerm.emplace_back(IsRead, VInfo.RWIdx,PredDef); RecVec SelectedDefs = VInfo.VarOrSeqDef->getValueAsListOfDefs("Selected"); SchedModels.findRWs(SelectedDefs, SelectedRWs, IsRead); } @@ -1181,11 +1259,8 @@ pushVariant(const TransVariant &VInfo, bool IsRead) { if (SchedRW.IsVariadic) { unsigned OperIdx = RWSequences.size()-1; // Make N-1 copies of this transition's last sequence. - for (unsigned i = 1, e = SelectedRWs.size(); i != e; ++i) { - // Create a temporary copy the vector could reallocate. - RWSequences.reserve(RWSequences.size() + 1); - RWSequences.push_back(RWSequences[OperIdx]); - } + RWSequences.insert(RWSequences.end(), SelectedRWs.size() - 1, + RWSequences[OperIdx]); // Push each of the N elements of the SelectedRWs onto a copy of the last // sequence (split the current operand into N operands). // Note that write sequences should be expanded within this loop--the entire @@ -1267,7 +1342,7 @@ void PredTransitions::substituteVariants(const PredTransition &Trans) { // Build up a set of partial results starting at the back of // PredTransitions. Remember the first new transition. unsigned StartIdx = TransVec.size(); - TransVec.resize(TransVec.size() + 1); + TransVec.emplace_back(); TransVec.back().PredTerm = Trans.PredTerm; TransVec.back().ProcIndices = Trans.ProcIndices; @@ -1278,7 +1353,7 @@ void PredTransitions::substituteVariants(const PredTransition &Trans) { // Push a new (empty) write sequence onto all partial Transitions. for (std::vector<PredTransition>::iterator I = TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) { - I->WriteSequences.resize(I->WriteSequences.size() + 1); + I->WriteSequences.emplace_back(); } substituteVariantOperand(*WSI, /*IsRead=*/false, StartIdx); } @@ -1289,7 +1364,7 @@ void PredTransitions::substituteVariants(const PredTransition &Trans) { // Push a new (empty) read sequence onto all partial Transitions. for (std::vector<PredTransition>::iterator I = TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) { - I->ReadSequences.resize(I->ReadSequences.size() + 1); + I->ReadSequences.emplace_back(); } substituteVariantOperand(*RSI, /*IsRead=*/true, StartIdx); } @@ -1304,37 +1379,30 @@ static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions, for (ArrayRef<PredTransition>::iterator I = LastTransitions.begin(), E = LastTransitions.end(); I != E; ++I) { IdxVec OperWritesVariant; - for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator - WSI = I->WriteSequences.begin(), WSE = I->WriteSequences.end(); - WSI != WSE; ++WSI) { - // Create a new write representing the expanded sequence. - OperWritesVariant.push_back( - SchedModels.findOrInsertRW(*WSI, /*IsRead=*/false)); - } + transform(I->WriteSequences, std::back_inserter(OperWritesVariant), + [&SchedModels](ArrayRef<unsigned> WS) { + return SchedModels.findOrInsertRW(WS, /*IsRead=*/false); + }); IdxVec OperReadsVariant; - for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator - RSI = I->ReadSequences.begin(), RSE = I->ReadSequences.end(); - RSI != RSE; ++RSI) { - // Create a new read representing the expanded sequence. - OperReadsVariant.push_back( - SchedModels.findOrInsertRW(*RSI, /*IsRead=*/true)); - } - IdxVec ProcIndices(I->ProcIndices.begin(), I->ProcIndices.end()); + transform(I->ReadSequences, std::back_inserter(OperReadsVariant), + [&SchedModels](ArrayRef<unsigned> RS) { + return SchedModels.findOrInsertRW(RS, /*IsRead=*/true); + }); CodeGenSchedTransition SCTrans; SCTrans.ToClassIdx = SchedModels.addSchedClass(/*ItinClassDef=*/nullptr, OperWritesVariant, - OperReadsVariant, ProcIndices); - SCTrans.ProcIndices = ProcIndices; + OperReadsVariant, I->ProcIndices); + SCTrans.ProcIndices.assign(I->ProcIndices.begin(), I->ProcIndices.end()); // The final PredTerm is unique set of predicates guarding the transition. RecVec Preds; - for (SmallVectorImpl<PredCheck>::const_iterator - PI = I->PredTerm.begin(), PE = I->PredTerm.end(); PI != PE; ++PI) { - Preds.push_back(PI->Predicate); - } - RecIter PredsEnd = std::unique(Preds.begin(), Preds.end()); - Preds.resize(PredsEnd - Preds.begin()); - SCTrans.PredTerm = Preds; - SchedModels.getSchedClass(FromClassIdx).Transitions.push_back(SCTrans); + transform(I->PredTerm, std::back_inserter(Preds), + [](const PredCheck &P) { + return P.Predicate; + }); + Preds.erase(std::unique(Preds.begin(), Preds.end()), Preds.end()); + SCTrans.PredTerm = std::move(Preds); + SchedModels.getSchedClass(FromClassIdx) + .Transitions.push_back(std::move(SCTrans)); } } @@ -1345,48 +1413,42 @@ void CodeGenSchedModels::inferFromRW(ArrayRef<unsigned> OperWrites, ArrayRef<unsigned> OperReads, unsigned FromClassIdx, ArrayRef<unsigned> ProcIndices) { - DEBUG(dbgs() << "INFER RW proc("; dumpIdxVec(ProcIndices); dbgs() << ") "); + LLVM_DEBUG(dbgs() << "INFER RW proc("; dumpIdxVec(ProcIndices); + dbgs() << ") "); // Create a seed transition with an empty PredTerm and the expanded sequences // of SchedWrites for the current SchedClass. std::vector<PredTransition> LastTransitions; - LastTransitions.resize(1); + LastTransitions.emplace_back(); LastTransitions.back().ProcIndices.append(ProcIndices.begin(), ProcIndices.end()); for (unsigned WriteIdx : OperWrites) { IdxVec WriteSeq; expandRWSequence(WriteIdx, WriteSeq, /*IsRead=*/false); - unsigned Idx = LastTransitions[0].WriteSequences.size(); - LastTransitions[0].WriteSequences.resize(Idx + 1); - SmallVectorImpl<unsigned> &Seq = LastTransitions[0].WriteSequences[Idx]; - for (IdxIter WI = WriteSeq.begin(), WE = WriteSeq.end(); WI != WE; ++WI) - Seq.push_back(*WI); - DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") "); - } - DEBUG(dbgs() << " Reads: "); + LastTransitions[0].WriteSequences.emplace_back(); + SmallVectorImpl<unsigned> &Seq = LastTransitions[0].WriteSequences.back(); + Seq.append(WriteSeq.begin(), WriteSeq.end()); + LLVM_DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") "); + } + LLVM_DEBUG(dbgs() << " Reads: "); for (unsigned ReadIdx : OperReads) { IdxVec ReadSeq; expandRWSequence(ReadIdx, ReadSeq, /*IsRead=*/true); - unsigned Idx = LastTransitions[0].ReadSequences.size(); - LastTransitions[0].ReadSequences.resize(Idx + 1); - SmallVectorImpl<unsigned> &Seq = LastTransitions[0].ReadSequences[Idx]; - for (IdxIter RI = ReadSeq.begin(), RE = ReadSeq.end(); RI != RE; ++RI) - Seq.push_back(*RI); - DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") "); + LastTransitions[0].ReadSequences.emplace_back(); + SmallVectorImpl<unsigned> &Seq = LastTransitions[0].ReadSequences.back(); + Seq.append(ReadSeq.begin(), ReadSeq.end()); + LLVM_DEBUG(dbgs() << "("; dumpIdxVec(Seq); dbgs() << ") "); } - DEBUG(dbgs() << '\n'); + LLVM_DEBUG(dbgs() << '\n'); // Collect all PredTransitions for individual operands. // Iterate until no variant writes remain. while (hasVariant(LastTransitions, *this)) { PredTransitions Transitions(*this); - for (std::vector<PredTransition>::const_iterator - I = LastTransitions.begin(), E = LastTransitions.end(); - I != E; ++I) { - Transitions.substituteVariants(*I); - } - DEBUG(Transitions.dump()); + for (const PredTransition &Trans : LastTransitions) + Transitions.substituteVariants(Trans); + LLVM_DEBUG(Transitions.dump()); LastTransitions.swap(Transitions.TransVec); } // If the first transition has no variants, nothing to do. @@ -1447,6 +1509,47 @@ void CodeGenSchedModels::verifyProcResourceGroups(CodeGenProcModel &PM) { } } +// Collect all the RegisterFile definitions available in this target. +void CodeGenSchedModels::collectRegisterFiles() { + RecVec RegisterFileDefs = Records.getAllDerivedDefinitions("RegisterFile"); + + // RegisterFiles is the vector of CodeGenRegisterFile. + for (Record *RF : RegisterFileDefs) { + // For each register file definition, construct a CodeGenRegisterFile object + // and add it to the appropriate scheduling model. + CodeGenProcModel &PM = getProcModel(RF->getValueAsDef("SchedModel")); + PM.RegisterFiles.emplace_back(CodeGenRegisterFile(RF->getName(),RF)); + CodeGenRegisterFile &CGRF = PM.RegisterFiles.back(); + + // Now set the number of physical registers as well as the cost of registers + // in each register class. + CGRF.NumPhysRegs = RF->getValueAsInt("NumPhysRegs"); + RecVec RegisterClasses = RF->getValueAsListOfDefs("RegClasses"); + std::vector<int64_t> RegisterCosts = RF->getValueAsListOfInts("RegCosts"); + for (unsigned I = 0, E = RegisterClasses.size(); I < E; ++I) { + int Cost = RegisterCosts.size() > I ? RegisterCosts[I] : 1; + CGRF.Costs.emplace_back(RegisterClasses[I], Cost); + } + } +} + +// Collect all the RegisterFile definitions available in this target. +void CodeGenSchedModels::collectPfmCounters() { + for (Record *Def : Records.getAllDerivedDefinitions("PfmIssueCounter")) { + CodeGenProcModel &PM = getProcModel(Def->getValueAsDef("SchedModel")); + PM.PfmIssueCounterDefs.emplace_back(Def); + } + for (Record *Def : Records.getAllDerivedDefinitions("PfmCycleCounter")) { + CodeGenProcModel &PM = getProcModel(Def->getValueAsDef("SchedModel")); + if (PM.PfmCycleCounterDef) { + PrintFatalError(Def->getLoc(), + "multiple cycle counters for " + + Def->getValueAsDef("SchedModel")->getName()); + } + PM.PfmCycleCounterDef = Def; + } +} + // Collect and sort WriteRes, ReadAdvance, and ProcResources. void CodeGenSchedModels::collectProcResources() { ProcResourceDefs = Records.getAllDerivedDefinitions("ProcResourceUnits"); @@ -1455,26 +1558,24 @@ void CodeGenSchedModels::collectProcResources() { // Add any subtarget-specific SchedReadWrites that are directly associated // with processor resources. Refer to the parent SchedClass's ProcIndices to // determine which processors they apply to. - for (SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd(); - SCI != SCE; ++SCI) { - if (SCI->ItinClassDef) - collectItinProcResources(SCI->ItinClassDef); - else { - // This class may have a default ReadWrite list which can be overriden by - // InstRW definitions. - if (!SCI->InstRWs.empty()) { - for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end(); - RWI != RWE; ++RWI) { - Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel"); - IdxVec ProcIndices(1, getProcModel(RWModelDef).Index); - IdxVec Writes, Reads; - findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"), - Writes, Reads); - collectRWResources(Writes, Reads, ProcIndices); - } - } - collectRWResources(SCI->Writes, SCI->Reads, SCI->ProcIndices); + for (const CodeGenSchedClass &SC : + make_range(schedClassBegin(), schedClassEnd())) { + if (SC.ItinClassDef) { + collectItinProcResources(SC.ItinClassDef); + continue; + } + + // This class may have a default ReadWrite list which can be overriden by + // InstRW definitions. + for (Record *RW : SC.InstRWs) { + Record *RWModelDef = RW->getValueAsDef("SchedModel"); + unsigned PIdx = getProcModel(RWModelDef).Index; + IdxVec Writes, Reads; + findRWs(RW->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); + collectRWResources(Writes, Reads, PIdx); } + + collectRWResources(SC.Writes, SC.Reads, SC.ProcIndices); } // Add resources separately defined by each subtarget. RecVec WRDefs = Records.getAllDerivedDefinitions("WriteRes"); @@ -1509,38 +1610,45 @@ void CodeGenSchedModels::collectProcResources() { if (!is_contained(PM.ProcResourceDefs, PRG)) PM.ProcResourceDefs.push_back(PRG); } + // Add ProcResourceUnits unconditionally. + for (Record *PRU : Records.getAllDerivedDefinitions("ProcResourceUnits")) { + if (!PRU->getValueInit("SchedModel")->isComplete()) + continue; + CodeGenProcModel &PM = getProcModel(PRU->getValueAsDef("SchedModel")); + if (!is_contained(PM.ProcResourceDefs, PRU)) + PM.ProcResourceDefs.push_back(PRU); + } // Finalize each ProcModel by sorting the record arrays. for (CodeGenProcModel &PM : ProcModels) { - std::sort(PM.WriteResDefs.begin(), PM.WriteResDefs.end(), - LessRecord()); - std::sort(PM.ReadAdvanceDefs.begin(), PM.ReadAdvanceDefs.end(), - LessRecord()); - std::sort(PM.ProcResourceDefs.begin(), PM.ProcResourceDefs.end(), - LessRecord()); - DEBUG( - PM.dump(); - dbgs() << "WriteResDefs: "; - for (RecIter RI = PM.WriteResDefs.begin(), - RE = PM.WriteResDefs.end(); RI != RE; ++RI) { - if ((*RI)->isSubClassOf("WriteRes")) - dbgs() << (*RI)->getValueAsDef("WriteType")->getName() << " "; - else - dbgs() << (*RI)->getName() << " "; - } - dbgs() << "\nReadAdvanceDefs: "; - for (RecIter RI = PM.ReadAdvanceDefs.begin(), - RE = PM.ReadAdvanceDefs.end(); RI != RE; ++RI) { - if ((*RI)->isSubClassOf("ReadAdvance")) - dbgs() << (*RI)->getValueAsDef("ReadType")->getName() << " "; - else - dbgs() << (*RI)->getName() << " "; - } - dbgs() << "\nProcResourceDefs: "; - for (RecIter RI = PM.ProcResourceDefs.begin(), - RE = PM.ProcResourceDefs.end(); RI != RE; ++RI) { - dbgs() << (*RI)->getName() << " "; - } - dbgs() << '\n'); + llvm::sort(PM.WriteResDefs.begin(), PM.WriteResDefs.end(), + LessRecord()); + llvm::sort(PM.ReadAdvanceDefs.begin(), PM.ReadAdvanceDefs.end(), + LessRecord()); + llvm::sort(PM.ProcResourceDefs.begin(), PM.ProcResourceDefs.end(), + LessRecord()); + LLVM_DEBUG( + PM.dump(); + dbgs() << "WriteResDefs: "; for (RecIter RI = PM.WriteResDefs.begin(), + RE = PM.WriteResDefs.end(); + RI != RE; ++RI) { + if ((*RI)->isSubClassOf("WriteRes")) + dbgs() << (*RI)->getValueAsDef("WriteType")->getName() << " "; + else + dbgs() << (*RI)->getName() << " "; + } dbgs() << "\nReadAdvanceDefs: "; + for (RecIter RI = PM.ReadAdvanceDefs.begin(), + RE = PM.ReadAdvanceDefs.end(); + RI != RE; ++RI) { + if ((*RI)->isSubClassOf("ReadAdvance")) + dbgs() << (*RI)->getValueAsDef("ReadType")->getName() << " "; + else + dbgs() << (*RI)->getName() << " "; + } dbgs() + << "\nProcResourceDefs: "; + for (RecIter RI = PM.ProcResourceDefs.begin(), + RE = PM.ProcResourceDefs.end(); + RI != RE; ++RI) { dbgs() << (*RI)->getName() << " "; } dbgs() + << '\n'); verifyProcResourceGroups(PM); } @@ -1552,6 +1660,7 @@ void CodeGenSchedModels::checkCompleteness() { bool Complete = true; bool HadCompleteModel = false; for (const CodeGenProcModel &ProcModel : procModels()) { + const bool HasItineraries = ProcModel.hasItineraries(); if (!ProcModel.ModelDef->getValueAsBit("CompleteModel")) continue; for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { @@ -1572,7 +1681,7 @@ void CodeGenSchedModels::checkCompleteness() { const CodeGenSchedClass &SC = getSchedClass(SCIdx); if (!SC.Writes.empty()) continue; - if (SC.ItinClassDef != nullptr && + if (HasItineraries && SC.ItinClassDef != nullptr && SC.ItinClassDef->getName() != "NoItinerary") continue; @@ -1619,8 +1728,7 @@ void CodeGenSchedModels::collectItinProcResources(Record *ItinClassDef) { HasMatch = true; IdxVec Writes, Reads; findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads); - IdxVec ProcIndices(1, PIdx); - collectRWResources(Writes, Reads, ProcIndices); + collectRWResources(Writes, Reads, PIdx); } } } diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h index 46e22cd12810..07c11596adee 100644 --- a/utils/TableGen/CodeGenSchedule.h +++ b/utils/TableGen/CodeGenSchedule.h @@ -26,6 +26,7 @@ namespace llvm { class CodeGenTarget; class CodeGenSchedModels; class CodeGenInstruction; +class CodeGenRegisterClass; using RecVec = std::vector<Record*>; using RecIter = std::vector<Record*>::const_iterator; @@ -33,9 +34,6 @@ using RecIter = std::vector<Record*>::const_iterator; using IdxVec = std::vector<unsigned>; using IdxIter = std::vector<unsigned>::const_iterator; -void splitSchedReadWrites(const RecVec &RWDefs, - RecVec &WriteDefs, RecVec &ReadDefs); - /// We have two kinds of SchedReadWrites. Explicitly defined and inferred /// sequences. TheDef is nonnull for explicit SchedWrites, but Sequence may or /// may not be empty. TheDef is null for inferred sequences, and Sequence must @@ -142,9 +140,11 @@ struct CodeGenSchedClass { // off to join another inferred class. RecVec InstRWs; - CodeGenSchedClass(): Index(0), ItinClassDef(nullptr) {} + CodeGenSchedClass(unsigned Index, std::string Name, Record *ItinClassDef) + : Index(Index), Name(std::move(Name)), ItinClassDef(ItinClassDef) {} - bool isKeyEqual(Record *IC, ArrayRef<unsigned> W, ArrayRef<unsigned> R) { + bool isKeyEqual(Record *IC, ArrayRef<unsigned> W, + ArrayRef<unsigned> R) const { return ItinClassDef == IC && makeArrayRef(Writes) == W && makeArrayRef(Reads) == R; } @@ -158,6 +158,38 @@ struct CodeGenSchedClass { #endif }; +/// Represent the cost of allocating a register of register class RCDef. +/// +/// The cost of allocating a register is equivalent to the number of physical +/// registers used by the register renamer. Register costs are defined at +/// register class granularity. +struct CodeGenRegisterCost { + Record *RCDef; + unsigned Cost; + CodeGenRegisterCost(Record *RC, unsigned RegisterCost) + : RCDef(RC), Cost(RegisterCost) {} + CodeGenRegisterCost(const CodeGenRegisterCost &) = default; + CodeGenRegisterCost &operator=(const CodeGenRegisterCost &) = delete; +}; + +/// A processor register file. +/// +/// This class describes a processor register file. Register file information is +/// currently consumed by external tools like llvm-mca to predict dispatch +/// stalls due to register pressure. +struct CodeGenRegisterFile { + std::string Name; + Record *RegisterFileDef; + + unsigned NumPhysRegs; + std::vector<CodeGenRegisterCost> Costs; + + CodeGenRegisterFile(StringRef name, Record *def) + : Name(name), RegisterFileDef(def), NumPhysRegs(0) {} + + bool hasDefaultCosts() const { return Costs.empty(); } +}; + // Processor model. // // ModelName is a unique name used to name an instantiation of MCSchedModel. @@ -199,11 +231,21 @@ struct CodeGenProcModel { // Per-operand machine model resources associated with this processor. RecVec ProcResourceDefs; - RecVec ProcResGroupDefs; - CodeGenProcModel(unsigned Idx, const std::string &Name, Record *MDef, + // List of Register Files. + std::vector<CodeGenRegisterFile> RegisterFiles; + + // Optional Retire Control Unit definition. + Record *RetireControlUnit; + + // List of PfmCounters. + RecVec PfmIssueCounterDefs; + Record *PfmCycleCounterDef = nullptr; + + CodeGenProcModel(unsigned Idx, std::string Name, Record *MDef, Record *IDef) : - Index(Idx), ModelName(Name), ModelDef(MDef), ItinsDef(IDef) {} + Index(Idx), ModelName(std::move(Name)), ModelDef(MDef), ItinsDef(IDef), + RetireControlUnit(nullptr) {} bool hasItineraries() const { return !ItinsDef->getValueAsListOfDefs("IID").empty(); @@ -213,6 +255,12 @@ struct CodeGenProcModel { return !WriteResDefs.empty() || !ItinRWDefs.empty(); } + bool hasExtraProcessorInfo() const { + return RetireControlUnit || !RegisterFiles.empty() || + !PfmIssueCounterDefs.empty() || + PfmCycleCounterDef != nullptr; + } + unsigned getProcResourceIdx(Record *PRDef) const; bool isUnsupported(const CodeGenInstruction &Inst) const; @@ -336,11 +384,11 @@ public: return const_cast<CodeGenSchedRW&>( IsRead ? getSchedRead(Idx) : getSchedWrite(Idx)); } - const CodeGenSchedRW &getSchedRW(Record*Def) const { + const CodeGenSchedRW &getSchedRW(Record *Def) const { return const_cast<CodeGenSchedModels&>(*this).getSchedRW(Def); } - unsigned getSchedRWIdx(Record *Def, bool IsRead, unsigned After = 0) const; + unsigned getSchedRWIdx(const Record *Def, bool IsRead) const; // Return true if the given write record is referenced by a ReadAdvance. bool hasReadOfWrite(Record *WriteDef) const; @@ -379,9 +427,6 @@ public: unsigned findOrInsertRW(ArrayRef<unsigned> Seq, bool IsRead); - unsigned findSchedClassIdx(Record *ItinClassDef, ArrayRef<unsigned> Writes, - ArrayRef<unsigned> Reads) const; - Record *findProcResUnits(Record *ProcResKind, const CodeGenProcModel &PM, ArrayRef<SMLoc> Loc) const; @@ -398,6 +443,14 @@ private: void collectSchedClasses(); + void collectRetireControlUnits(); + + void collectRegisterFiles(); + + void collectPfmCounters(); + + void collectOptionalProcessorInfo(); + std::string createSchedClassName(Record *ItinClassDef, ArrayRef<unsigned> OperWrites, ArrayRef<unsigned> OperReads); diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index 168bd690831f..cb73ca83c9bb 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -174,6 +174,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::iPTR: return "MVT::iPTR"; case MVT::iPTRAny: return "MVT::iPTRAny"; case MVT::Untyped: return "MVT::Untyped"; + case MVT::ExceptRef: return "MVT::ExceptRef"; default: llvm_unreachable("ILLEGAL VALUE TYPE!"); } } @@ -224,6 +225,9 @@ Record *CodeGenTarget::getInstructionSet() const { return TargetRec->getValueAsDef("InstructionSet"); } +bool CodeGenTarget::getAllowRegisterRenaming() const { + return TargetRec->getValueAsInt("AllowRegisterRenaming"); +} /// getAsmParser - Return the AssemblyParser definition for this target. /// @@ -274,7 +278,7 @@ CodeGenRegBank &CodeGenTarget::getRegBank() const { void CodeGenTarget::ReadRegAltNameIndices() const { RegAltNameIndices = Records.getAllDerivedDefinitions("RegAltNameIndex"); - std::sort(RegAltNameIndices.begin(), RegAltNameIndices.end(), LessRecord()); + llvm::sort(RegAltNameIndices.begin(), RegAltNameIndices.end(), LessRecord()); } /// getRegisterByName - If there is a register with the specific AsmName, @@ -299,7 +303,7 @@ std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R) } // Remove duplicates. - std::sort(Result.begin(), Result.end()); + llvm::sort(Result.begin(), Result.end()); Result.erase(std::unique(Result.begin(), Result.end()), Result.end()); return Result; } @@ -310,7 +314,7 @@ void CodeGenTarget::ReadLegalValueTypes() const { LegalValueTypes.insert(LegalValueTypes.end(), RC.VTs.begin(), RC.VTs.end()); // Remove duplicates. - std::sort(LegalValueTypes.begin(), LegalValueTypes.end()); + llvm::sort(LegalValueTypes.begin(), LegalValueTypes.end()); LegalValueTypes.erase(std::unique(LegalValueTypes.begin(), LegalValueTypes.end()), LegalValueTypes.end()); @@ -345,13 +349,18 @@ GetInstByName(const char *Name, return I->second.get(); } -/// \brief Return all of the instructions defined by the target, ordered by +static const char *const FixedInstrs[] = { +#define HANDLE_TARGET_OPCODE(OPC) #OPC, +#include "llvm/Support/TargetOpcodes.def" + nullptr}; + +unsigned CodeGenTarget::getNumFixedInstructions() { + return array_lengthof(FixedInstrs) - 1; +} + +/// Return all of the instructions defined by the target, ordered by /// their enum value. void CodeGenTarget::ComputeInstrsByEnum() const { - static const char *const FixedInstrs[] = { -#define HANDLE_TARGET_OPCODE(OPC) #OPC, -#include "llvm/CodeGen/TargetOpcodes.def" - nullptr}; const auto &Insts = getInstructions(); for (const char *const *p = FixedInstrs; *p; ++p) { const CodeGenInstruction *Instr = GetInstByName(*p, Insts, Records); @@ -360,21 +369,29 @@ void CodeGenTarget::ComputeInstrsByEnum() const { InstrsByEnum.push_back(Instr); } unsigned EndOfPredefines = InstrsByEnum.size(); + assert(EndOfPredefines == getNumFixedInstructions() && + "Missing generic opcode"); for (const auto &I : Insts) { const CodeGenInstruction *CGI = I.second.get(); - if (CGI->Namespace != "TargetOpcode") + if (CGI->Namespace != "TargetOpcode") { InstrsByEnum.push_back(CGI); + if (CGI->TheDef->getValueAsBit("isPseudo")) + ++NumPseudoInstructions; + } } assert(InstrsByEnum.size() == Insts.size() && "Missing predefined instr"); // All of the instructions are now in random order based on the map iteration. - // Sort them by name. - std::sort(InstrsByEnum.begin() + EndOfPredefines, InstrsByEnum.end(), - [](const CodeGenInstruction *Rec1, const CodeGenInstruction *Rec2) { - return Rec1->TheDef->getName() < Rec2->TheDef->getName(); - }); + llvm::sort( + InstrsByEnum.begin() + EndOfPredefines, InstrsByEnum.end(), + [](const CodeGenInstruction *Rec1, const CodeGenInstruction *Rec2) { + const auto &D1 = *Rec1->TheDef; + const auto &D2 = *Rec2->TheDef; + return std::make_tuple(!D1.getValueAsBit("isPseudo"), D1.getName()) < + std::make_tuple(!D2.getValueAsBit("isPseudo"), D2.getName()); + }); } @@ -496,11 +513,11 @@ CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC, if (isTarget == TargetOnly) Intrinsics.push_back(CodeGenIntrinsic(Defs[I])); } - std::sort(Intrinsics.begin(), Intrinsics.end(), - [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) { - return std::tie(LHS.TargetPrefix, LHS.Name) < - std::tie(RHS.TargetPrefix, RHS.Name); - }); + llvm::sort(Intrinsics.begin(), Intrinsics.end(), + [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) { + return std::tie(LHS.TargetPrefix, LHS.Name) < + std::tie(RHS.TargetPrefix, RHS.Name); + }); Targets.push_back({"", 0, 0}); for (size_t I = 0, E = Intrinsics.size(); I < E; ++I) if (Intrinsics[I].TargetPrefix != Targets.back().Name) { @@ -604,8 +621,12 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { MVT::SimpleValueType VT; if (TyEl->isSubClassOf("LLVMMatchType")) { unsigned MatchTy = TyEl->getValueAsInt("Number"); - assert(MatchTy < OverloadedVTs.size() && - "Invalid matching number!"); + if (MatchTy >= OverloadedVTs.size()) { + PrintError(R->getLoc(), + "Parameter #" + Twine(i) + " has out of bounds matching " + "number " + Twine(MatchTy)); + PrintFatalError(Twine("ParamTypes is ") + TypeList->getAsString()); + } VT = OverloadedVTs[MatchTy]; // It only makes sense to use the extended and truncated vector element // variants with iAny types; otherwise, if the intrinsic is not @@ -688,6 +709,6 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { Properties = parseSDPatternOperatorProperties(R); // Sort the argument attributes for later benefit. - std::sort(ArgumentAttributes.begin(), ArgumentAttributes.end()); + llvm::sort(ArgumentAttributes.begin(), ArgumentAttributes.end()); } diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h index 7280d707fba6..d2833d5b6a92 100644 --- a/utils/TableGen/CodeGenTarget.h +++ b/utils/TableGen/CodeGenTarget.h @@ -62,6 +62,7 @@ class CodeGenTarget { mutable std::unique_ptr<CodeGenSchedModels> SchedModels; mutable std::vector<const CodeGenInstruction*> InstrsByEnum; + mutable unsigned NumPseudoInstructions = 0; public: CodeGenTarget(RecordKeeper &Records); ~CodeGenTarget(); @@ -77,6 +78,11 @@ public: /// Record *getInstructionSet() const; + /// getAllowRegisterRenaming - Return the AllowRegisterRenaming flag value for + /// this target. + /// + bool getAllowRegisterRenaming() const; + /// getAsmParser - Return the AssemblyParser definition for this target. /// Record *getAsmParser() const; @@ -140,11 +146,25 @@ public: return *I->second; } - /// getInstructionsByEnumValue - Return all of the instructions defined by the - /// target, ordered by their enum value. - ArrayRef<const CodeGenInstruction *> - getInstructionsByEnumValue() const { - if (InstrsByEnum.empty()) ComputeInstrsByEnum(); + /// Returns the number of predefined instructions. + static unsigned getNumFixedInstructions(); + + /// Returns the number of pseudo instructions. + unsigned getNumPseudoInstructions() const { + if (InstrsByEnum.empty()) + ComputeInstrsByEnum(); + return NumPseudoInstructions; + } + + /// Return all of the instructions defined by the target, ordered by their + /// enum value. + /// The following order of instructions is also guaranteed: + /// - fixed / generic instructions as declared in TargetOpcodes.def, in order; + /// - pseudo instructions in lexicographical order sorted by name; + /// - other instructions in lexicographical order sorted by name. + ArrayRef<const CodeGenInstruction *> getInstructionsByEnumValue() const { + if (InstrsByEnum.empty()) + ComputeInstrsByEnum(); return InstrsByEnum; } diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp index 9592ab7052f4..62a0ff700725 100644 --- a/utils/TableGen/DAGISelEmitter.cpp +++ b/utils/TableGen/DAGISelEmitter.cpp @@ -110,9 +110,11 @@ struct PatternSortingPredicate { if (LHSPatSize < RHSPatSize) return true; if (LHSPatSize > RHSPatSize) return false; - // Sort based on the UID of the pattern, giving us a deterministic ordering - // if all other sorting conditions fail. - assert(LHS == RHS || LHS->ID != RHS->ID); + // Sort based on the UID of the pattern, to reflect source order. + // Note that this is not guaranteed to be unique, since a single source + // pattern may have been resolved into multiple match patterns due to + // alternative fragments. To ensure deterministic output, always use + // std::stable_sort with this predicate. return LHS->ID < RHS->ID; } }; @@ -137,13 +139,16 @@ void DAGISelEmitter::run(raw_ostream &OS) { "// When neither of the GET_DAGISEL* macros is defined, the functions\n" "// are emitted inline.\n\n"; - DEBUG(errs() << "\n\nALL PATTERNS TO MATCH:\n\n"; - for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), - E = CGP.ptm_end(); I != E; ++I) { - errs() << "PATTERN: "; I->getSrcPattern()->dump(); - errs() << "\nRESULT: "; I->getDstPattern()->dump(); - errs() << "\n"; - }); + LLVM_DEBUG(errs() << "\n\nALL PATTERNS TO MATCH:\n\n"; + for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), + E = CGP.ptm_end(); + I != E; ++I) { + errs() << "PATTERN: "; + I->getSrcPattern()->dump(); + errs() << "\nRESULT: "; + I->getDstPattern()->dump(); + errs() << "\n"; + }); // Add all the patterns to a temporary list so we can sort them. std::vector<const PatternToMatch*> Patterns; @@ -153,7 +158,8 @@ void DAGISelEmitter::run(raw_ostream &OS) { // We want to process the matches in order of minimal cost. Sort the patterns // so the least cost one is at the start. - std::sort(Patterns.begin(), Patterns.end(), PatternSortingPredicate(CGP)); + std::stable_sort(Patterns.begin(), Patterns.end(), + PatternSortingPredicate(CGP)); // Convert each variant of each pattern into a Matcher. diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h index c672b0acac9f..ecc1f1dd094a 100644 --- a/utils/TableGen/DAGISelMatcher.h +++ b/utils/TableGen/DAGISelMatcher.h @@ -13,8 +13,8 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/CodeGen/MachineValueType.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/MachineValueType.h" namespace llvm { struct CodeGenRegister; diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp index a19b9e4b95c7..ce23651b9682 100644 --- a/utils/TableGen/DAGISelMatcherGen.cpp +++ b/utils/TableGen/DAGISelMatcherGen.cpp @@ -58,7 +58,7 @@ namespace { /// PatWithNoTypes - This is a clone of Pattern.getSrcPattern() that starts /// out with all of the types removed. This allows us to insert type checks /// as we scan the tree. - TreePatternNode *PatWithNoTypes; + TreePatternNodePtr PatWithNoTypes; /// VariableMap - A map from variable names ('$dst') to the recorded operand /// number that they were captured as. These are biased by 1 to make @@ -101,10 +101,6 @@ namespace { public: MatcherGen(const PatternToMatch &pattern, const CodeGenDAGPatterns &cgp); - ~MatcherGen() { - delete PatWithNoTypes; - } - bool EmitMatcherCode(unsigned Variant); void EmitResultCode(); @@ -134,10 +130,6 @@ namespace { return VarMapEntry-1; } - /// GetInstPatternNode - Get the pattern for an instruction. - const TreePatternNode *GetInstPatternNode(const DAGInstruction &Ins, - const TreePatternNode *N); - void EmitResultOperand(const TreePatternNode *N, SmallVectorImpl<unsigned> &ResultOps); void EmitResultOfNamedOperand(const TreePatternNode *N, @@ -521,7 +513,8 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) { } // Emit the matcher for the pattern structure and types. - EmitMatchCode(Pattern.getSrcPattern(), PatWithNoTypes, Pattern.ForceMode); + EmitMatchCode(Pattern.getSrcPattern(), PatWithNoTypes.get(), + Pattern.ForceMode); // If the pattern has a predicate on it (e.g. only enabled when a subtarget // feature is around, do the check). @@ -533,7 +526,7 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) { // because they are generally more expensive to evaluate and more difficult to // factor. for (unsigned i = 0, e = MatchedComplexPatterns.size(); i != e; ++i) { - const TreePatternNode *N = MatchedComplexPatterns[i].first; + auto N = MatchedComplexPatterns[i].first; // Remember where the results of this match get stuck. if (N->isLeaf()) { @@ -664,28 +657,6 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N, N->dump(); } -/// GetInstPatternNode - Get the pattern for an instruction. -/// -const TreePatternNode *MatcherGen:: -GetInstPatternNode(const DAGInstruction &Inst, const TreePatternNode *N) { - const TreePattern *InstPat = Inst.getPattern(); - - // FIXME2?: Assume actual pattern comes before "implicit". - TreePatternNode *InstPatNode; - if (InstPat) - InstPatNode = InstPat->getTree(0); - else if (/*isRoot*/ N == Pattern.getDstPattern()) - InstPatNode = Pattern.getSrcPattern(); - else - return nullptr; - - if (InstPatNode && !InstPatNode->isLeaf() && - InstPatNode->getOperator()->getName() == "set") - InstPatNode = InstPatNode->getChild(InstPatNode->getNumChildren()-1); - - return InstPatNode; -} - static bool mayInstNodeLoadOrStore(const TreePatternNode *N, const CodeGenDAGPatterns &CGP) { @@ -723,25 +694,6 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, CodeGenInstruction &II = CGT.getInstruction(Op); const DAGInstruction &Inst = CGP.getInstruction(Op); - // If we can, get the pattern for the instruction we're generating. We derive - // a variety of information from this pattern, such as whether it has a chain. - // - // FIXME2: This is extremely dubious for several reasons, not the least of - // which it gives special status to instructions with patterns that Pat<> - // nodes can't duplicate. - const TreePatternNode *InstPatNode = GetInstPatternNode(Inst, N); - - // NodeHasChain - Whether the instruction node we're creating takes chains. - bool NodeHasChain = InstPatNode && - InstPatNode->TreeHasProperty(SDNPHasChain, CGP); - - // Instructions which load and store from memory should have a chain, - // regardless of whether they happen to have an internal pattern saying so. - if (Pattern.getSrcPattern()->TreeHasProperty(SDNPHasChain, CGP) - && (II.hasCtrlDep || II.mayLoad || II.mayStore || II.canFoldAsLoad || - II.hasSideEffects)) - NodeHasChain = true; - bool isRoot = N == Pattern.getDstPattern(); // TreeHasOutGlue - True if this tree has glue. @@ -784,7 +736,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, const DAGDefaultOperand &DefaultOp = CGP.getDefaultOperand(OperandNode); for (unsigned i = 0, e = DefaultOp.DefaultOps.size(); i != e; ++i) - EmitResultOperand(DefaultOp.DefaultOps[i], InstOps); + EmitResultOperand(DefaultOp.DefaultOps[i].get(), InstOps); continue; } @@ -895,6 +847,26 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, NumNodesThatLoadOrStore != 1)); } + // Determine whether we need to attach a chain to this node. + bool NodeHasChain = false; + if (Pattern.getSrcPattern()->TreeHasProperty(SDNPHasChain, CGP)) { + // For some instructions, we were able to infer from the pattern whether + // they should have a chain. Otherwise, attach the chain to the root. + // + // FIXME2: This is extremely dubious for several reasons, not the least of + // which it gives special status to instructions with patterns that Pat<> + // nodes can't duplicate. + if (II.hasChain_Inferred) + NodeHasChain = II.hasChain; + else + NodeHasChain = isRoot; + // Instructions which load and store from memory should have a chain, + // regardless of whether they happen to have a pattern saying so. + if (II.hasCtrlDep || II.mayLoad || II.mayStore || II.canFoldAsLoad || + II.hasSideEffects) + NodeHasChain = true; + } + assert((!ResultVTs.empty() || TreeHasOutGlue || NodeHasChain) && "Node has no result"); diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp index 0bb656826fbd..554c7438ce3d 100644 --- a/utils/TableGen/DAGISelMatcherOpt.cpp +++ b/utils/TableGen/DAGISelMatcherOpt.cpp @@ -293,15 +293,12 @@ static void FactorNodes(std::unique_ptr<Matcher> &InputMatcherPtr) { if (Scan != e && // Don't print it's obvious nothing extra could be merged anyway. Scan+1 != e) { - DEBUG(errs() << "Couldn't merge this:\n"; - Optn->print(errs(), 4); - errs() << "into this:\n"; - OptionsToMatch[Scan]->print(errs(), 4); - if (Scan+1 != e) - OptionsToMatch[Scan+1]->printOne(errs()); - if (Scan+2 < e) - OptionsToMatch[Scan+2]->printOne(errs()); - errs() << "\n"); + LLVM_DEBUG(errs() << "Couldn't merge this:\n"; Optn->print(errs(), 4); + errs() << "into this:\n"; + OptionsToMatch[Scan]->print(errs(), 4); + if (Scan + 1 != e) OptionsToMatch[Scan + 1]->printOne(errs()); + if (Scan + 2 < e) OptionsToMatch[Scan + 2]->printOne(errs()); + errs() << "\n"); } // If we only found one option starting with this matcher, no factoring is diff --git a/utils/TableGen/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp index 1c1932a0144a..0db0f55f5ed6 100644 --- a/utils/TableGen/DFAPacketizerEmitter.cpp +++ b/utils/TableGen/DFAPacketizerEmitter.cpp @@ -278,30 +278,30 @@ public: // dbgsInsnClass - When debugging, print instruction class stages. // void dbgsInsnClass(const std::vector<unsigned> &InsnClass) { - DEBUG(dbgs() << "InsnClass: "); + LLVM_DEBUG(dbgs() << "InsnClass: "); for (unsigned i = 0; i < InsnClass.size(); ++i) { if (i > 0) { - DEBUG(dbgs() << ", "); + LLVM_DEBUG(dbgs() << ", "); } - DEBUG(dbgs() << "0x" << Twine::utohexstr(InsnClass[i])); + LLVM_DEBUG(dbgs() << "0x" << Twine::utohexstr(InsnClass[i])); } DFAInput InsnInput = getDFAInsnInput(InsnClass); - DEBUG(dbgs() << " (input: 0x" << Twine::utohexstr(InsnInput) << ")"); + LLVM_DEBUG(dbgs() << " (input: 0x" << Twine::utohexstr(InsnInput) << ")"); } // // dbgsStateInfo - When debugging, print the set of state info. // void dbgsStateInfo(const std::set<unsigned> &stateInfo) { - DEBUG(dbgs() << "StateInfo: "); + LLVM_DEBUG(dbgs() << "StateInfo: "); unsigned i = 0; for (std::set<unsigned>::iterator SI = stateInfo.begin(); SI != stateInfo.end(); ++SI, ++i) { unsigned thisState = *SI; if (i > 0) { - DEBUG(dbgs() << ", "); + LLVM_DEBUG(dbgs() << ", "); } - DEBUG(dbgs() << "0x" << Twine::utohexstr(thisState)); + LLVM_DEBUG(dbgs() << "0x" << Twine::utohexstr(thisState)); } } @@ -310,7 +310,7 @@ void dbgsStateInfo(const std::set<unsigned> &stateInfo) { // void dbgsIndent(unsigned indent) { for (unsigned i = 0; i < indent; ++i) { - DEBUG(dbgs() << " "); + LLVM_DEBUG(dbgs() << " "); } } #endif // NDEBUG @@ -361,7 +361,8 @@ void State::AddInsnClass(std::vector<unsigned> &InsnClass, DenseSet<unsigned> VisitedResourceStates; - DEBUG(dbgs() << " thisState: 0x" << Twine::utohexstr(thisState) << "\n"); + LLVM_DEBUG(dbgs() << " thisState: 0x" << Twine::utohexstr(thisState) + << "\n"); AddInsnClassStages(InsnClass, ComboBitToBitsMap, numstages - 1, numstages, thisState, thisState, @@ -378,7 +379,7 @@ void State::AddInsnClassStages(std::vector<unsigned> &InsnClass, assert((chkstage < numstages) && "AddInsnClassStages: stage out of range"); unsigned thisStage = InsnClass[chkstage]; - DEBUG({ + LLVM_DEBUG({ dbgsIndent((1 + numstages - chkstage) << 1); dbgs() << "AddInsnClassStages " << chkstage << " (0x" << Twine::utohexstr(thisStage) << ") from "; @@ -395,10 +396,10 @@ void State::AddInsnClassStages(std::vector<unsigned> &InsnClass, if (resourceMask & thisStage) { unsigned combo = ComboBitToBitsMap[resourceMask]; if (combo && ((~prevState & combo) != combo)) { - DEBUG(dbgs() << "\tSkipped Add 0x" << Twine::utohexstr(prevState) - << " - combo op 0x" << Twine::utohexstr(resourceMask) - << " (0x" << Twine::utohexstr(combo) - << ") cannot be scheduled\n"); + LLVM_DEBUG(dbgs() << "\tSkipped Add 0x" << Twine::utohexstr(prevState) + << " - combo op 0x" << Twine::utohexstr(resourceMask) + << " (0x" << Twine::utohexstr(combo) + << ") cannot be scheduled\n"); continue; } // @@ -406,7 +407,7 @@ void State::AddInsnClassStages(std::vector<unsigned> &InsnClass, // resource state if that resource was used. // unsigned ResultingResourceState = prevState | resourceMask | combo; - DEBUG({ + LLVM_DEBUG({ dbgsIndent((2 + numstages - chkstage) << 1); dbgs() << "0x" << Twine::utohexstr(prevState) << " | 0x" << Twine::utohexstr(resourceMask); @@ -433,13 +434,15 @@ void State::AddInsnClassStages(std::vector<unsigned> &InsnClass, if (VisitedResourceStates.count(ResultingResourceState) == 0) { VisitedResourceStates.insert(ResultingResourceState); PossibleStates.insert(ResultingResourceState); - DEBUG(dbgs() << "\tResultingResourceState: 0x" - << Twine::utohexstr(ResultingResourceState) << "\n"); + LLVM_DEBUG(dbgs() + << "\tResultingResourceState: 0x" + << Twine::utohexstr(ResultingResourceState) << "\n"); } else { - DEBUG(dbgs() << "\tSkipped Add - state already seen\n"); + LLVM_DEBUG(dbgs() << "\tSkipped Add - state already seen\n"); } } else { - DEBUG(dbgs() << "\tSkipped Add - no final resources available\n"); + LLVM_DEBUG(dbgs() + << "\tSkipped Add - no final resources available\n"); } } else { // @@ -447,13 +450,13 @@ void State::AddInsnClassStages(std::vector<unsigned> &InsnClass, // stage in InsnClass for available resources. // if (ResultingResourceState != prevState) { - DEBUG(dbgs() << "\n"); + LLVM_DEBUG(dbgs() << "\n"); AddInsnClassStages(InsnClass, ComboBitToBitsMap, chkstage - 1, numstages, ResultingResourceState, origState, VisitedResourceStates, PossibleStates); } else { - DEBUG(dbgs() << "\tSkipped Add - no resources available\n"); + LLVM_DEBUG(dbgs() << "\tSkipped Add - no resources available\n"); } } } @@ -494,10 +497,11 @@ bool State::canMaybeAddInsnClass(std::vector<unsigned> &InsnClass, // These cases are caught later in AddInsnClass. unsigned combo = ComboBitToBitsMap[InsnClass[i]]; if (combo && ((~resources & combo) != combo)) { - DEBUG(dbgs() << "\tSkipped canMaybeAdd 0x" - << Twine::utohexstr(resources) << " - combo op 0x" - << Twine::utohexstr(InsnClass[i]) << " (0x" - << Twine::utohexstr(combo) << ") cannot be scheduled\n"); + LLVM_DEBUG(dbgs() << "\tSkipped canMaybeAdd 0x" + << Twine::utohexstr(resources) << " - combo op 0x" + << Twine::utohexstr(InsnClass[i]) << " (0x" + << Twine::utohexstr(combo) + << ") cannot be scheduled\n"); available = false; break; } @@ -537,9 +541,10 @@ void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName, int maxResources, int numCombos, int maxStages) { unsigned numStates = states.size(); - DEBUG(dbgs() << "-----------------------------------------------------------------------------\n"); - DEBUG(dbgs() << "writeTableAndAPI\n"); - DEBUG(dbgs() << "Total states: " << numStates << "\n"); + LLVM_DEBUG(dbgs() << "-------------------------------------------------------" + "----------------------\n"); + LLVM_DEBUG(dbgs() << "writeTableAndAPI\n"); + LLVM_DEBUG(dbgs() << "Total states: " << numStates << "\n"); OS << "namespace llvm {\n"; @@ -647,9 +652,10 @@ int DFAPacketizerEmitter::collectAllFuncUnits( std::map<std::string, unsigned> &FUNameToBitsMap, int &maxFUs, raw_ostream &OS) { - DEBUG(dbgs() << "-----------------------------------------------------------------------------\n"); - DEBUG(dbgs() << "collectAllFuncUnits"); - DEBUG(dbgs() << " (" << ProcItinList.size() << " itineraries)\n"); + LLVM_DEBUG(dbgs() << "-------------------------------------------------------" + "----------------------\n"); + LLVM_DEBUG(dbgs() << "collectAllFuncUnits"); + LLVM_DEBUG(dbgs() << " (" << ProcItinList.size() << " itineraries)\n"); int totalFUs = 0; // Parse functional units for all the itineraries. @@ -657,10 +663,8 @@ int DFAPacketizerEmitter::collectAllFuncUnits( Record *Proc = ProcItinList[i]; std::vector<Record*> FUs = Proc->getValueAsListOfDefs("FU"); - DEBUG(dbgs() << " FU:" << i - << " (" << FUs.size() << " FUs) " - << Proc->getName()); - + LLVM_DEBUG(dbgs() << " FU:" << i << " (" << FUs.size() << " FUs) " + << Proc->getName()); // Convert macros to bits for each stage. unsigned numFUs = FUs.size(); @@ -669,14 +673,14 @@ int DFAPacketizerEmitter::collectAllFuncUnits( "Exceeded maximum number of representable resources"); unsigned FuncResources = (unsigned) (1U << j); FUNameToBitsMap[FUs[j]->getName()] = FuncResources; - DEBUG(dbgs() << " " << FUs[j]->getName() << ":0x" - << Twine::utohexstr(FuncResources)); + LLVM_DEBUG(dbgs() << " " << FUs[j]->getName() << ":0x" + << Twine::utohexstr(FuncResources)); } if (((int) numFUs) > maxFUs) { maxFUs = numFUs; } totalFUs += numFUs; - DEBUG(dbgs() << "\n"); + LLVM_DEBUG(dbgs() << "\n"); } return totalFUs; } @@ -690,18 +694,18 @@ int DFAPacketizerEmitter::collectAllComboFuncs( std::map<std::string, unsigned> &FUNameToBitsMap, std::map<unsigned, unsigned> &ComboBitToBitsMap, raw_ostream &OS) { - DEBUG(dbgs() << "-----------------------------------------------------------------------------\n"); - DEBUG(dbgs() << "collectAllComboFuncs"); - DEBUG(dbgs() << " (" << ComboFuncList.size() << " sets)\n"); + LLVM_DEBUG(dbgs() << "-------------------------------------------------------" + "----------------------\n"); + LLVM_DEBUG(dbgs() << "collectAllComboFuncs"); + LLVM_DEBUG(dbgs() << " (" << ComboFuncList.size() << " sets)\n"); int numCombos = 0; for (unsigned i = 0, N = ComboFuncList.size(); i < N; ++i) { Record *Func = ComboFuncList[i]; std::vector<Record*> FUs = Func->getValueAsListOfDefs("CFD"); - DEBUG(dbgs() << " CFD:" << i - << " (" << FUs.size() << " combo FUs) " - << Func->getName() << "\n"); + LLVM_DEBUG(dbgs() << " CFD:" << i << " (" << FUs.size() << " combo FUs) " + << Func->getName() << "\n"); // Convert macros to bits for each stage. for (unsigned j = 0, N = FUs.size(); j < N; ++j) { @@ -714,20 +718,20 @@ int DFAPacketizerEmitter::collectAllComboFuncs( const std::string &ComboFuncName = ComboFunc->getName(); unsigned ComboBit = FUNameToBitsMap[ComboFuncName]; unsigned ComboResources = ComboBit; - DEBUG(dbgs() << " combo: " << ComboFuncName << ":0x" - << Twine::utohexstr(ComboResources) << "\n"); + LLVM_DEBUG(dbgs() << " combo: " << ComboFuncName << ":0x" + << Twine::utohexstr(ComboResources) << "\n"); for (unsigned k = 0, M = FuncList.size(); k < M; ++k) { std::string FuncName = FuncList[k]->getName(); unsigned FuncResources = FUNameToBitsMap[FuncName]; - DEBUG(dbgs() << " " << FuncName << ":0x" - << Twine::utohexstr(FuncResources) << "\n"); + LLVM_DEBUG(dbgs() << " " << FuncName << ":0x" + << Twine::utohexstr(FuncResources) << "\n"); ComboResources |= FuncResources; } ComboBitToBitsMap[ComboBit] = ComboResources; numCombos++; - DEBUG(dbgs() << " => combo bits: " << ComboFuncName << ":0x" - << Twine::utohexstr(ComboBit) << " = 0x" - << Twine::utohexstr(ComboResources) << "\n"); + LLVM_DEBUG(dbgs() << " => combo bits: " << ComboFuncName << ":0x" + << Twine::utohexstr(ComboBit) << " = 0x" + << Twine::utohexstr(ComboResources) << "\n"); } } return numCombos; @@ -747,8 +751,8 @@ int DFAPacketizerEmitter::collectOneInsnClass(const std::string &ProcName, // The number of stages. unsigned NStages = StageList.size(); - DEBUG(dbgs() << " " << ItinData->getValueAsDef("TheClass")->getName() - << "\n"); + LLVM_DEBUG(dbgs() << " " << ItinData->getValueAsDef("TheClass")->getName() + << "\n"); std::vector<unsigned> UnitBits; @@ -760,8 +764,8 @@ int DFAPacketizerEmitter::collectOneInsnClass(const std::string &ProcName, const std::vector<Record*> &UnitList = Stage->getValueAsListOfDefs("Units"); - DEBUG(dbgs() << " stage:" << i - << " [" << UnitList.size() << " units]:"); + LLVM_DEBUG(dbgs() << " stage:" << i << " [" << UnitList.size() + << " units]:"); unsigned dbglen = 26; // cursor after stage dbgs // Compute the bitwise or of each unit used in this stage. @@ -769,7 +773,7 @@ int DFAPacketizerEmitter::collectOneInsnClass(const std::string &ProcName, for (unsigned j = 0, M = UnitList.size(); j < M; ++j) { // Conduct bitwise or. std::string UnitName = UnitList[j]->getName(); - DEBUG(dbgs() << " " << j << ":" << UnitName); + LLVM_DEBUG(dbgs() << " " << j << ":" << UnitName); dbglen += 3 + UnitName.length(); assert(FUNameToBitsMap.count(UnitName)); UnitBitValue |= FUNameToBitsMap[UnitName]; @@ -780,15 +784,16 @@ int DFAPacketizerEmitter::collectOneInsnClass(const std::string &ProcName, while (dbglen <= 64) { // line up bits dbgs dbglen += 8; - DEBUG(dbgs() << "\t"); + LLVM_DEBUG(dbgs() << "\t"); } - DEBUG(dbgs() << " (bits: 0x" << Twine::utohexstr(UnitBitValue) << ")\n"); + LLVM_DEBUG(dbgs() << " (bits: 0x" << Twine::utohexstr(UnitBitValue) + << ")\n"); } if (!UnitBits.empty()) allInsnClasses.push_back(UnitBits); - DEBUG({ + LLVM_DEBUG({ dbgs() << " "; dbgsInsnClass(UnitBits); dbgs() << "\n"; @@ -811,10 +816,10 @@ int DFAPacketizerEmitter::collectAllInsnClasses(const std::string &ProcName, unsigned M = ItinDataList.size(); int numInsnClasses = 0; - DEBUG(dbgs() << "-----------------------------------------------------------------------------\n" - << "collectAllInsnClasses " - << ProcName - << " (" << M << " classes)\n"); + LLVM_DEBUG(dbgs() << "-------------------------------------------------------" + "----------------------\n" + << "collectAllInsnClasses " << ProcName << " (" << M + << " classes)\n"); // Collect stages for each instruction class for all itinerary data for (unsigned j = 0; j < M; j++) { @@ -914,7 +919,7 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) { // while (!WorkList.empty()) { const State *current = WorkList.pop_back_val(); - DEBUG({ + LLVM_DEBUG({ dbgs() << "---------------------\n"; dbgs() << "Processing state: " << current->stateNum << " - "; dbgsStateInfo(current->stateInfo); @@ -922,7 +927,7 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) { }); for (unsigned i = 0; i < allInsnClasses.size(); i++) { std::vector<unsigned> InsnClass = allInsnClasses[i]; - DEBUG({ + LLVM_DEBUG({ dbgs() << i << " "; dbgsInsnClass(InsnClass); dbgs() << "\n"; @@ -938,11 +943,11 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) { const State *NewState = nullptr; current->AddInsnClass(InsnClass, ComboBitToBitsMap, NewStateResources); if (NewStateResources.empty()) { - DEBUG(dbgs() << " Skipped - no new states generated\n"); + LLVM_DEBUG(dbgs() << " Skipped - no new states generated\n"); continue; } - DEBUG({ + LLVM_DEBUG({ dbgs() << "\t"; dbgsStateInfo(NewStateResources); dbgs() << "\n"; @@ -954,7 +959,7 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) { auto VI = Visited.find(NewStateResources); if (VI != Visited.end()) { NewState = VI->second; - DEBUG({ + LLVM_DEBUG({ dbgs() << "\tFound existing state: " << NewState->stateNum << " - "; dbgsStateInfo(NewState->stateInfo); @@ -965,7 +970,7 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) { NewState->stateInfo = NewStateResources; Visited[NewStateResources] = NewState; WorkList.push_back(NewState); - DEBUG({ + LLVM_DEBUG({ dbgs() << "\tAccepted new state: " << NewState->stateNum << " - "; dbgsStateInfo(NewState->stateInfo); dbgs() << "\n"; diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp index 6e1d8dde981c..b99a0a973a2c 100644 --- a/utils/TableGen/DisassemblerEmitter.cpp +++ b/utils/TableGen/DisassemblerEmitter.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenTarget.h" +#include "WebAssemblyDisassemblerEmitter.h" #include "X86DisassemblerTables.h" #include "X86RecognizableInstr.h" #include "llvm/TableGen/Error.h" @@ -74,8 +75,8 @@ using namespace llvm::X86Disassembler; /// accurate. Sometimes they are not. /// (3) to fix the tables to reflect the actual context (for example, required /// prefixes), and possibly to add a new context by editing -/// lib/Target/X86/X86DisassemblerDecoderCommon.h. This is unlikely to be -/// the cause. +/// include/llvm/Support/X86DisassemblerDecoderCommon.h. This is unlikely +/// to be the cause. /// /// DisassemblerEmitter.cpp contains the implementation for the emitter, /// which simply pulls out instructions from the CodeGenTarget and pushes them @@ -125,6 +126,14 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { return; } + // WebAssembly has variable length opcodes, so can't use EmitFixedLenDecoder + // below (which depends on a Size table-gen Record), and also uses a custom + // disassembler. + if (Target.getName() == "WebAssembly") { + emitWebAssemblyDisassemblerTables(OS, Target.getInstructionsByEnumValue()); + return; + } + // ARM and Thumb have a CHECK() macro to deal with DecodeStatuses. if (Target.getName() == "ARM" || Target.getName() == "Thumb" || Target.getName() == "AArch64" || Target.getName() == "ARM64") { diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp index 610f4d21bf2d..c0902e4c6f1a 100644 --- a/utils/TableGen/FastISelEmitter.cpp +++ b/utils/TableGen/FastISelEmitter.cpp @@ -36,8 +36,18 @@ struct InstructionMemo { std::string Name; const CodeGenRegisterClass *RC; std::string SubRegNo; - std::vector<std::string>* PhysRegs; + std::vector<std::string> PhysRegs; std::string PredicateCheck; + + InstructionMemo(std::string Name, const CodeGenRegisterClass *RC, + std::string SubRegNo, std::vector<std::string> PhysRegs, + std::string PredicateCheck) + : Name(Name), RC(RC), SubRegNo(SubRegNo), PhysRegs(PhysRegs), + PredicateCheck(PredicateCheck) {} + + // Make sure we do not copy InstructionMemo. + InstructionMemo(const InstructionMemo &Other) = delete; + InstructionMemo(InstructionMemo &&Other) = default; }; } // End anonymous namespace @@ -453,6 +463,13 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) { if (II.Operands.empty()) continue; + // Allow instructions to be marked as unavailable for FastISel for + // certain cases, i.e. an ISA has two 'and' instruction which differ + // by what registers they can use but are otherwise identical for + // codegen purposes. + if (II.FastISelShouldIgnore) + continue; + // For now, ignore multi-instruction patterns. bool MultiInsts = false; for (unsigned i = 0, e = Dst->getNumChildren(); i != e; ++i) { @@ -520,10 +537,10 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) { DstRC)) continue; - std::vector<std::string>* PhysRegInputs = new std::vector<std::string>(); + std::vector<std::string> PhysRegInputs; if (InstPatNode->getOperator()->getName() == "imm" || InstPatNode->getOperator()->getName() == "fpimm") - PhysRegInputs->push_back(""); + PhysRegInputs.push_back(""); else { // Compute the PhysRegs used by the given pattern, and check that // the mapping from the src to dst patterns is simple. @@ -541,7 +558,7 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) { ++DstIndex; } - PhysRegInputs->push_back(PhysReg); + PhysRegInputs.push_back(PhysReg); } if (Op->getName() != "EXTRACT_SUBREG" && DstIndex < Dst->getNumChildren()) @@ -565,13 +582,13 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) { std::string PredicateCheck = Pattern.getPredicateCheck(); // Ok, we found a pattern that we can handle. Remember it. - InstructionMemo Memo = { + InstructionMemo Memo( Pattern.getDstPattern()->getOperator()->getName(), DstRC, SubRegNo, PhysRegInputs, PredicateCheck - }; + ); int complexity = Pattern.getPatternComplexity(CGP); @@ -585,8 +602,8 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) { // Note: Instructions with the same complexity will appear in the order // that they are encountered. - SimplePatterns[Operands][OpcodeName][VT][RetVT].insert( - std::make_pair(complexity, Memo)); + SimplePatterns[Operands][OpcodeName][VT][RetVT].emplace(complexity, + std::move(Memo)); // If any of the operands were immediates with predicates on them, strip // them down to a signature that doesn't have predicates so that we can @@ -641,22 +658,22 @@ void FastISelMap::emitInstructionCode(raw_ostream &OS, OS << " "; } - for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) { - if ((*Memo.PhysRegs)[i] != "") + for (unsigned i = 0; i < Memo.PhysRegs.size(); ++i) { + if (Memo.PhysRegs[i] != "") OS << " BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, " - << "TII.get(TargetOpcode::COPY), " - << (*Memo.PhysRegs)[i] << ").addReg(Op" << i << ");\n"; + << "TII.get(TargetOpcode::COPY), " << Memo.PhysRegs[i] + << ").addReg(Op" << i << ");\n"; } OS << " return fastEmitInst_"; if (Memo.SubRegNo.empty()) { - Operands.PrintManglingSuffix(OS, *Memo.PhysRegs, - ImmediatePredicates, true); + Operands.PrintManglingSuffix(OS, Memo.PhysRegs, ImmediatePredicates, + true); OS << "(" << InstNS << "::" << Memo.Name << ", "; OS << "&" << InstNS << "::" << Memo.RC->getName() << "RegClass"; if (!Operands.empty()) OS << ", "; - Operands.PrintArguments(OS, *Memo.PhysRegs); + Operands.PrintArguments(OS, Memo.PhysRegs); OS << ");\n"; } else { OS << "extractsubreg(" << RetVTName @@ -811,7 +828,7 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) { = SignaturesWithConstantForms.find(Operands); if (MI != SignaturesWithConstantForms.end()) { // Unique any duplicates out of the list. - std::sort(MI->second.begin(), MI->second.end()); + llvm::sort(MI->second.begin(), MI->second.end()); MI->second.erase(std::unique(MI->second.begin(), MI->second.end()), MI->second.end()); diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp index 03930d7132df..76ba1c001092 100644 --- a/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -606,12 +606,13 @@ static void resolveTableFixups(DecoderTable &Table, const FixupList &Fixups, // NumToSkip entry itself, so subtract two from the displacement here // to account for that. uint32_t FixupIdx = *I; - uint32_t Delta = DestIdx - FixupIdx - 2; - // Our NumToSkip entries are 16-bits. Make sure our table isn't too + uint32_t Delta = DestIdx - FixupIdx - 3; + // Our NumToSkip entries are 24-bits. Make sure our table isn't too // big. - assert(Delta < 65536U && "disassembler decoding table too large!"); + assert(Delta < (1u << 24)); Table[FixupIdx] = (uint8_t)Delta; Table[FixupIdx + 1] = (uint8_t)(Delta >> 8); + Table[FixupIdx + 2] = (uint8_t)(Delta >> 16); } } @@ -646,7 +647,7 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const { } else { Table.push_back(MCD::OPC_FilterValue); // Encode and emit the value to filter against. - uint8_t Buffer[8]; + uint8_t Buffer[16]; unsigned Len = encodeULEB128(Filter.first, Buffer); Table.insert(Table.end(), Buffer, Buffer + Len); // Reserve space for the NumToSkip entry. We'll backpatch the value @@ -654,6 +655,7 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const { PrevFilter = Table.size(); Table.push_back(0); Table.push_back(0); + Table.push_back(0); } // We arrive at a category of instructions with the same segment value. @@ -666,10 +668,11 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const { // of the filter itself to be able to skip forward when false. Subtract // two as to account for the width of the NumToSkip field itself. if (PrevFilter) { - uint32_t NumToSkip = Table.size() - PrevFilter - 2; - assert(NumToSkip < 65536U && "disassembler decoding table too large!"); + uint32_t NumToSkip = Table.size() - PrevFilter - 3; + assert(NumToSkip < (1u << 24) && "disassembler decoding table too large!"); Table[PrevFilter] = (uint8_t)NumToSkip; Table[PrevFilter + 1] = (uint8_t)(NumToSkip >> 8); + Table[PrevFilter + 2] = (uint8_t)(NumToSkip >> 16); } } @@ -745,13 +748,16 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, OS << (unsigned)*I++ << ", "; OS << (unsigned)*I++ << ", "; - // 16-bit numtoskip value. + // 24-bit numtoskip value. uint8_t Byte = *I++; uint32_t NumToSkip = Byte; OS << (unsigned)Byte << ", "; Byte = *I++; OS << (unsigned)Byte << ", "; NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; break; } @@ -765,13 +771,16 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, for (; *I >= 128; ++I) OS << (unsigned)*I << ", "; OS << (unsigned)*I++ << ", "; - // 16-bit numtoskip value. + // 24-bit numtoskip value. uint8_t Byte = *I++; uint32_t NumToSkip = Byte; OS << (unsigned)Byte << ", "; Byte = *I++; OS << (unsigned)Byte << ", "; NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; break; } @@ -782,13 +791,16 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, OS << (unsigned)*I << ", "; OS << (unsigned)*I++ << ", "; - // 16-bit numtoskip value. + // 24-bit numtoskip value. uint8_t Byte = *I++; uint32_t NumToSkip = Byte; OS << (unsigned)Byte << ", "; Byte = *I++; OS << (unsigned)Byte << ", "; NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n"; break; } @@ -797,7 +809,7 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, bool IsTry = *I == MCD::OPC_TryDecode; ++I; // Extract the ULEB128 encoded Opcode to a buffer. - uint8_t Buffer[8], *p = Buffer; + uint8_t Buffer[16], *p = Buffer; while ((*p++ = *I++) >= 128) assert((p - Buffer) <= (ptrdiff_t)sizeof(Buffer) && "ULEB128 value too large!"); @@ -822,13 +834,16 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS, // Fallthrough for OPC_TryDecode. - // 16-bit numtoskip value. + // 24-bit numtoskip value. uint8_t Byte = *I++; uint32_t NumToSkip = Byte; OS << (unsigned)Byte << ", "; Byte = *I++; OS << (unsigned)Byte << ", "; NumToSkip |= Byte << 8; + Byte = *I++; + OS << utostr(Byte) << ", "; + NumToSkip |= Byte << 16; OS << "// Opcode: " << NumberedInstructions[Opc]->TheDef->getName() @@ -1226,6 +1241,7 @@ void FilterChooser::emitPredicateTableEntry(DecoderTableInfo &TableInfo, TableInfo.FixupStack.back().push_back(TableInfo.Table.size()); TableInfo.Table.push_back(0); TableInfo.Table.push_back(0); + TableInfo.Table.push_back(0); } void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo, @@ -1311,18 +1327,19 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo, TableInfo.Table.push_back(MCD::OPC_CheckField); TableInfo.Table.push_back(StartBits[I-1]); TableInfo.Table.push_back(NumBits); - uint8_t Buffer[8], *p; + uint8_t Buffer[16], *p; encodeULEB128(FieldVals[I-1], Buffer); for (p = Buffer; *p >= 128 ; ++p) TableInfo.Table.push_back(*p); TableInfo.Table.push_back(*p); // Push location for NumToSkip backpatching. TableInfo.FixupStack.back().push_back(TableInfo.Table.size()); - // The fixup is always 16-bits, so go ahead and allocate the space + // The fixup is always 24-bits, so go ahead and allocate the space // in the table so all our relative position calculations work OK even // before we fully resolve the real value here. TableInfo.Table.push_back(0); TableInfo.Table.push_back(0); + TableInfo.Table.push_back(0); } // Check for soft failure of the match. @@ -1342,7 +1359,7 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo, // can decode it. TableInfo.Table.push_back(HasCompleteDecoder ? MCD::OPC_Decode : MCD::OPC_TryDecode); - uint8_t Buffer[8], *p; + uint8_t Buffer[16], *p; encodeULEB128(Opc, Buffer); for (p = Buffer; *p >= 128 ; ++p) TableInfo.Table.push_back(*p); @@ -1362,6 +1379,7 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo, // Allocate the space for the fixup. TableInfo.Table.push_back(0); TableInfo.Table.push_back(0); + TableInfo.Table.push_back(0); } } @@ -1701,10 +1719,9 @@ void FilterChooser::emitTableEntries(DecoderTableInfo &TableInfo) const { static std::string findOperandDecoderMethod(TypedInit *TI) { std::string Decoder; - RecordRecTy *Type = cast<RecordRecTy>(TI->getType()); - Record *TypeRecord = Type->getRecord(); + Record *Record = cast<DefInit>(TI)->getDef(); - RecordVal *DecoderString = TypeRecord->getValue("DecoderMethod"); + RecordVal *DecoderString = Record->getValue("DecoderMethod"); StringInit *String = DecoderString ? dyn_cast<StringInit>(DecoderString->getValue()) : nullptr; if (String) { @@ -1713,14 +1730,14 @@ static std::string findOperandDecoderMethod(TypedInit *TI) { return Decoder; } - if (TypeRecord->isSubClassOf("RegisterOperand")) - TypeRecord = TypeRecord->getValueAsDef("RegClass"); + if (Record->isSubClassOf("RegisterOperand")) + Record = Record->getValueAsDef("RegClass"); - if (TypeRecord->isSubClassOf("RegisterClass")) { - Decoder = "Decode" + TypeRecord->getName().str() + "RegisterClass"; - } else if (TypeRecord->isSubClassOf("PointerLikeRegClass")) { + if (Record->isSubClassOf("RegisterClass")) { + Decoder = "Decode" + Record->getName().str() + "RegisterClass"; + } else if (Record->isSubClassOf("PointerLikeRegClass")) { Decoder = "DecodePointerLikeRegClass" + - utostr(TypeRecord->getValueAsInt("RegClassKind")); + utostr(Record->getValueAsInt("RegClassKind")); } return Decoder; @@ -1860,9 +1877,9 @@ static bool populateInstruction(CodeGenTarget &Target, CGI.Operands.getSubOperandNumber(OpIdx); const std::string &Name = CGI.Operands[SO.first].Name; - DEBUG(dbgs() << "Numbered operand mapping for " << Def.getName() << ": " << - Name << "(" << SO.first << ", " << SO.second << ") => " << - Vals[i].getName() << "\n"); + LLVM_DEBUG(dbgs() << "Numbered operand mapping for " << Def.getName() + << ": " << Name << "(" << SO.first << ", " << SO.second + << ") => " << Vals[i].getName() << "\n"); std::string Decoder; Record *TypeRecord = CGI.Operands[SO.first].Rec; @@ -1878,10 +1895,8 @@ static bool populateInstruction(CodeGenTarget &Target, CGI.Operands[SO.first].MIOperandInfo->getNumArgs()) { Init *Arg = CGI.Operands[SO.first].MIOperandInfo-> getArg(SO.second); - if (TypedInit *TI = cast<TypedInit>(Arg)) { - RecordRecTy *Type = cast<RecordRecTy>(TI->getType()); - TypeRecord = Type->getRecord(); - } + if (DefInit *DI = cast<DefInit>(Arg)) + TypeRecord = DI->getDef(); } bool isReg = false; @@ -1959,7 +1974,7 @@ static bool populateInstruction(CodeGenTarget &Target, // to interpret it. As a first step, require the target to provide // callbacks for decoding register classes. std::string Decoder = findOperandDecoderMethod(TI); - Record *TypeRecord = cast<RecordRecTy>(TI->getType())->getRecord(); + Record *TypeRecord = cast<DefInit>(TI)->getDef(); RecordVal *HasCompleteDecoderVal = TypeRecord->getValue("hasCompleteDecoder"); @@ -2026,7 +2041,7 @@ static bool populateInstruction(CodeGenTarget &Target, Operands[Opc] = InsnOperands; #if 0 - DEBUG({ + LLVM_DEBUG({ // Dumps the instruction encoding bits. dumpBits(errs(), Bits); @@ -2048,10 +2063,16 @@ static bool populateInstruction(CodeGenTarget &Target, // emitFieldFromInstruction - Emit the templated helper function // fieldFromInstruction(). +// On Windows we make sure that this function is not inlined when +// using the VS compiler. It has a bug which causes the function +// to be optimized out in some circustances. See llvm.org/pr38292 static void emitFieldFromInstruction(formatted_raw_ostream &OS) { OS << "// Helper function for extracting fields from encoded instructions.\n" << "template<typename InsnType>\n" - << "static InsnType fieldFromInstruction(InsnType insn, unsigned startBit,\n" + << "#if defined(_MSC_VER) && !defined(__clang__)\n" + << "__declspec(noinline)\n" + << "#endif\n" + << "static InsnType fieldFromInstruction(InsnType insn, unsigned startBit,\n" << " unsigned numBits) {\n" << " assert(startBit + numBits <= (sizeof(InsnType)*8) &&\n" << " \"Instruction field out of bounds!\");\n" @@ -2068,8 +2089,10 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) { // decodeInstruction(). static void emitDecodeInstruction(formatted_raw_ostream &OS) { OS << "template<typename InsnType>\n" - << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,\n" - << " InsnType insn, uint64_t Address,\n" + << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], " + "MCInst &MI,\n" + << " InsnType insn, uint64_t " + "Address,\n" << " const void *DisAsm,\n" << " const MCSubtargetInfo &STI) {\n" << " const FeatureBitset& Bits = STI.getFeatureBits();\n" @@ -2088,7 +2111,8 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " unsigned Len = *++Ptr;\n" << " ++Ptr;\n" << " CurFieldValue = fieldFromInstruction(insn, Start, Len);\n" - << " DEBUG(dbgs() << Loc << \": OPC_ExtractField(\" << Start << \", \"\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_ExtractField(\" << Start << " + "\", \"\n" << " << Len << \"): \" << CurFieldValue << \"\\n\");\n" << " break;\n" << " }\n" @@ -2097,16 +2121,20 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " unsigned Len;\n" << " InsnType Val = decodeULEB128(++Ptr, &Len);\n" << " Ptr += Len;\n" - << " // NumToSkip is a plain 16-bit integer.\n" + << " // NumToSkip is a plain 24-bit integer.\n" << " unsigned NumToSkip = *Ptr++;\n" << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" << "\n" << " // Perform the filter operation.\n" << " if (Val != CurFieldValue)\n" << " Ptr += NumToSkip;\n" - << " DEBUG(dbgs() << Loc << \": OPC_FilterValue(\" << Val << \", \" << NumToSkip\n" - << " << \"): \" << ((Val != CurFieldValue) ? \"FAIL:\" : \"PASS:\")\n" - << " << \" continuing at \" << (Ptr - DecodeTable) << \"\\n\");\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_FilterValue(\" << Val << " + "\", \" << NumToSkip\n" + << " << \"): \" << ((Val != CurFieldValue) ? \"FAIL:\" " + ": \"PASS:\")\n" + << " << \" continuing at \" << (Ptr - DecodeTable) << " + "\"\\n\");\n" << "\n" << " break;\n" << " }\n" @@ -2117,18 +2145,23 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " // Decode the field value.\n" << " uint32_t ExpectedValue = decodeULEB128(++Ptr, &Len);\n" << " Ptr += Len;\n" - << " // NumToSkip is a plain 16-bit integer.\n" + << " // NumToSkip is a plain 24-bit integer.\n" << " unsigned NumToSkip = *Ptr++;\n" << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" << "\n" << " // If the actual and expected values don't match, skip.\n" << " if (ExpectedValue != FieldValue)\n" << " Ptr += NumToSkip;\n" - << " DEBUG(dbgs() << Loc << \": OPC_CheckField(\" << Start << \", \"\n" - << " << Len << \", \" << ExpectedValue << \", \" << NumToSkip\n" - << " << \"): FieldValue = \" << FieldValue << \", ExpectedValue = \"\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckField(\" << Start << " + "\", \"\n" + << " << Len << \", \" << ExpectedValue << \", \" << " + "NumToSkip\n" + << " << \"): FieldValue = \" << FieldValue << \", " + "ExpectedValue = \"\n" << " << ExpectedValue << \": \"\n" - << " << ((ExpectedValue == FieldValue) ? \"PASS\\n\" : \"FAIL\\n\"));\n" + << " << ((ExpectedValue == FieldValue) ? \"PASS\\n\" : " + "\"FAIL\\n\"));\n" << " break;\n" << " }\n" << " case MCD::OPC_CheckPredicate: {\n" @@ -2136,15 +2169,17 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " // Decode the Predicate Index value.\n" << " unsigned PIdx = decodeULEB128(++Ptr, &Len);\n" << " Ptr += Len;\n" - << " // NumToSkip is a plain 16-bit integer.\n" + << " // NumToSkip is a plain 24-bit integer.\n" << " unsigned NumToSkip = *Ptr++;\n" << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" << " // Check the predicate.\n" << " bool Pred;\n" << " if (!(Pred = checkDecoderPredicate(PIdx, Bits)))\n" << " Ptr += NumToSkip;\n" << " (void)Pred;\n" - << " DEBUG(dbgs() << Loc << \": OPC_CheckPredicate(\" << PIdx << \"): \"\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckPredicate(\" << PIdx " + "<< \"): \"\n" << " << (Pred ? \"PASS\\n\" : \"FAIL\\n\"));\n" << "\n" << " break;\n" @@ -2160,12 +2195,14 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " MI.clear();\n" << " MI.setOpcode(Opc);\n" << " bool DecodeComplete;\n" - << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, DecodeComplete);\n" + << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " + "DecodeComplete);\n" << " assert(DecodeComplete);\n" << "\n" - << " DEBUG(dbgs() << Loc << \": OPC_Decode: opcode \" << Opc\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Decode: opcode \" << Opc\n" << " << \", using decoder \" << DecodeIdx << \": \"\n" - << " << (S != MCDisassembler::Fail ? \"PASS\" : \"FAIL\") << \"\\n\");\n" + << " << (S != MCDisassembler::Fail ? \"PASS\" : " + "\"FAIL\") << \"\\n\");\n" << " return S;\n" << " }\n" << " case MCD::OPC_TryDecode: {\n" @@ -2175,29 +2212,35 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " Ptr += Len;\n" << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len);\n" << " Ptr += Len;\n" - << " // NumToSkip is a plain 16-bit integer.\n" + << " // NumToSkip is a plain 24-bit integer.\n" << " unsigned NumToSkip = *Ptr++;\n" << " NumToSkip |= (*Ptr++) << 8;\n" + << " NumToSkip |= (*Ptr++) << 16;\n" << "\n" << " // Perform the decode operation.\n" << " MCInst TmpMI;\n" << " TmpMI.setOpcode(Opc);\n" << " bool DecodeComplete;\n" - << " S = decodeToMCInst(S, DecodeIdx, insn, TmpMI, Address, DisAsm, DecodeComplete);\n" - << " DEBUG(dbgs() << Loc << \": OPC_TryDecode: opcode \" << Opc\n" + << " S = decodeToMCInst(S, DecodeIdx, insn, TmpMI, Address, DisAsm, " + "DecodeComplete);\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_TryDecode: opcode \" << " + "Opc\n" << " << \", using decoder \" << DecodeIdx << \": \");\n" << "\n" << " if (DecodeComplete) {\n" << " // Decoding complete.\n" - << " DEBUG(dbgs() << (S != MCDisassembler::Fail ? \"PASS\" : \"FAIL\") << \"\\n\");\n" + << " LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? \"PASS\" : " + "\"FAIL\") << \"\\n\");\n" << " MI = TmpMI;\n" << " return S;\n" << " } else {\n" << " assert(S == MCDisassembler::Fail);\n" << " // If the decoding was incomplete, skip.\n" << " Ptr += NumToSkip;\n" - << " DEBUG(dbgs() << \"FAIL: continuing at \" << (Ptr - DecodeTable) << \"\\n\");\n" - << " // Reset decode status. This also drops a SoftFail status that could be\n" + << " LLVM_DEBUG(dbgs() << \"FAIL: continuing at \" << (Ptr - " + "DecodeTable) << \"\\n\");\n" + << " // Reset decode status. This also drops a SoftFail status " + "that could be\n" << " // set before the decode attempt.\n" << " S = MCDisassembler::Success;\n" << " }\n" @@ -2213,16 +2256,18 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " bool Fail = (insn & PositiveMask) || (~insn & NegativeMask);\n" << " if (Fail)\n" << " S = MCDisassembler::SoftFail;\n" - << " DEBUG(dbgs() << Loc << \": OPC_SoftFail: \" << (Fail ? \"FAIL\\n\":\"PASS\\n\"));\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_SoftFail: \" << (Fail ? " + "\"FAIL\\n\":\"PASS\\n\"));\n" << " break;\n" << " }\n" << " case MCD::OPC_Fail: {\n" - << " DEBUG(dbgs() << Loc << \": OPC_Fail\\n\");\n" + << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Fail\\n\");\n" << " return MCDisassembler::Fail;\n" << " }\n" << " }\n" << " }\n" - << " llvm_unreachable(\"bogosity detected in disassembler state machine!\");\n" + << " llvm_unreachable(\"bogosity detected in disassembler state " + "machine!\");\n" << "}\n\n"; } diff --git a/utils/TableGen/GlobalISelEmitter.cpp b/utils/TableGen/GlobalISelEmitter.cpp index c7d662db5a2f..69726cc9f257 100644 --- a/utils/TableGen/GlobalISelEmitter.cpp +++ b/utils/TableGen/GlobalISelEmitter.cpp @@ -35,11 +35,11 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" -#include "llvm/CodeGen/MachineValueType.h" #include "llvm/Support/CodeGenCoverage.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/LowLevelTypeImpl.h" +#include "llvm/Support/MachineValueType.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" @@ -84,6 +84,8 @@ namespace { /// Get the name of the enum value used to number the predicate function. std::string getEnumNameForPredicate(const TreePredicateFn &Predicate) { + if (Predicate.hasGISelPredicateCode()) + return "GIPFP_MI_" + Predicate.getFnName(); return "GIPFP_" + Predicate.getImmTypeIdentifier().str() + "_" + Predicate.getFnName(); } @@ -100,6 +102,7 @@ private: LLT Ty; public: + LLTCodeGen() = default; LLTCodeGen(const LLT &Ty) : Ty(Ty) {} std::string getCxxEnumValue() const { @@ -148,7 +151,7 @@ public: const LLT &get() const { return Ty; } - /// This ordering is used for std::unique() and std::sort(). There's no + /// This ordering is used for std::unique() and llvm::sort(). There's no /// particular logic behind the order but either A < B or B < A must be /// true if A != B. bool operator<(const LLTCodeGen &Other) const { @@ -176,6 +179,9 @@ public: bool operator==(const LLTCodeGen &B) const { return Ty == B.Ty; } }; +// Track all types that are used so we can emit the corresponding enum. +std::set<LLTCodeGen> KnownTypes; + class InstructionMatcher; /// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for /// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...). @@ -260,6 +266,11 @@ std::string explainOperator(Record *Operator) { ")") .str(); + if (Operator->isSubClassOf("SDNodeXForm")) + return (" (Operator is an unmapped SDNodeXForm, " + Operator->getName() + + ")") + .str(); + return (" (Operator " + Operator->getName() + " not understood)").str(); } @@ -280,12 +291,16 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) { if (Predicate.isImmediatePattern()) continue; - if (Predicate.isNonExtLoad()) + if (Predicate.isNonExtLoad() || Predicate.isAnyExtLoad() || + Predicate.isSignExtLoad() || Predicate.isZeroExtLoad()) continue; if (Predicate.isNonTruncStore()) continue; + if (Predicate.isLoad() && Predicate.getMemoryVT()) + continue; + if (Predicate.isLoad() || Predicate.isStore()) { if (Predicate.isUnindexed()) continue; @@ -306,6 +321,9 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) { Predicate.isAtomicOrderingWeakerThanRelease())) continue; + if (Predicate.hasGISelPredicateCode()) + continue; + HasUnsupportedPredicate = true; Explanation = Separator + "Has a predicate (" + explainPredicates(N) + ")"; Separator = ", "; @@ -315,12 +333,7 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) { break; } - if (N->getTransformFn()) { - Explanation += Separator + "Has a transform function"; - Separator = ", "; - } - - if (!HasUnsupportedPredicate && !N->getTransformFn()) + if (!HasUnsupportedPredicate) return Error::success(); return failedImport(Explanation); @@ -394,19 +407,42 @@ public: /// A bitfield of RecordFlagsBits flags. unsigned Flags; + /// The actual run-time value, if known + int64_t RawValue; + MatchTableRecord(Optional<unsigned> LabelID_, StringRef EmitStr, - unsigned NumElements, unsigned Flags) + unsigned NumElements, unsigned Flags, + int64_t RawValue = std::numeric_limits<int64_t>::min()) : LabelID(LabelID_.hasValue() ? LabelID_.getValue() : ~0u), - EmitStr(EmitStr), NumElements(NumElements), Flags(Flags) { + EmitStr(EmitStr), NumElements(NumElements), Flags(Flags), + RawValue(RawValue) { + assert((!LabelID_.hasValue() || LabelID != ~0u) && "This value is reserved for non-labels"); } + MatchTableRecord(const MatchTableRecord &Other) = default; + MatchTableRecord(MatchTableRecord &&Other) = default; + + /// Useful if a Match Table Record gets optimized out + void turnIntoComment() { + Flags |= MTRF_Comment; + Flags &= ~MTRF_CommaFollows; + NumElements = 0; + } + + /// For Jump Table generation purposes + bool operator<(const MatchTableRecord &Other) const { + return RawValue < Other.RawValue; + } + int64_t getRawValue() const { return RawValue; } void emit(raw_ostream &OS, bool LineBreakNextAfterThis, const MatchTable &Table) const; unsigned size() const { return NumElements; } }; +class Matcher; + /// Holds the contents of a generated MatchTable to enable formatting and the /// necessary index tracking needed to support GIM_Try. class MatchTable { @@ -419,10 +455,11 @@ class MatchTable { /// The currently defined labels. DenseMap<unsigned, unsigned> LabelMap; /// Tracks the sum of MatchTableRecord::NumElements as the table is built. - unsigned CurrentSize; - + unsigned CurrentSize = 0; /// A unique identifier for a MatchTable label. - static unsigned CurrentLabelID; + unsigned CurrentLabelID = 0; + /// Determines if the table should be instrumented for rule coverage tracking. + bool IsWithCoverage; public: static MatchTableRecord LineBreak; @@ -443,11 +480,20 @@ public: return MatchTableRecord(None, NamedValue, 1, MatchTableRecord::MTRF_CommaFollows); } + static MatchTableRecord NamedValue(StringRef NamedValue, int64_t RawValue) { + return MatchTableRecord(None, NamedValue, 1, + MatchTableRecord::MTRF_CommaFollows, RawValue); + } static MatchTableRecord NamedValue(StringRef Namespace, StringRef NamedValue) { return MatchTableRecord(None, (Namespace + "::" + NamedValue).str(), 1, MatchTableRecord::MTRF_CommaFollows); } + static MatchTableRecord NamedValue(StringRef Namespace, StringRef NamedValue, + int64_t RawValue) { + return MatchTableRecord(None, (Namespace + "::" + NamedValue).str(), 1, + MatchTableRecord::MTRF_CommaFollows, RawValue); + } static MatchTableRecord IntValue(int64_t IntValue) { return MatchTableRecord(None, llvm::to_string(IntValue), 1, MatchTableRecord::MTRF_CommaFollows); @@ -465,7 +511,12 @@ public: MatchTableRecord::MTRF_CommaFollows); } - MatchTable(unsigned ID) : ID(ID), CurrentSize(0) {} + static MatchTable buildTable(ArrayRef<Matcher *> Rules, bool WithCoverage); + + MatchTable(bool WithCoverage, unsigned ID = 0) + : ID(ID), IsWithCoverage(WithCoverage) {} + + bool isWithCoverage() const { return IsWithCoverage; } void push_back(const MatchTableRecord &Value) { if (Value.Flags & MatchTableRecord::MTRF_Label) @@ -474,7 +525,7 @@ public: CurrentSize += Value.size(); } - unsigned allocateLabelID() const { return CurrentLabelID++; } + unsigned allocateLabelID() { return CurrentLabelID++; } void defineLabel(unsigned LabelID) { LabelMap.insert(std::make_pair(LabelID, CurrentSize)); @@ -519,8 +570,6 @@ public: } }; -unsigned MatchTable::CurrentLabelID = 0; - MatchTableRecord MatchTable::LineBreak = { None, "" /* Emit String */, 0 /* Elements */, MatchTableRecord::MTRF_LineBreakFollows}; @@ -573,65 +622,172 @@ class RuleMatcher; class Matcher { public: virtual ~Matcher() = default; + virtual void optimize() {} virtual void emit(MatchTable &Table) = 0; - virtual std::unique_ptr<PredicateMatcher> forgetFirstCondition() = 0; + + virtual bool hasFirstCondition() const = 0; + virtual const PredicateMatcher &getFirstCondition() const = 0; + virtual std::unique_ptr<PredicateMatcher> popFirstCondition() = 0; }; -class GroupMatcher : public Matcher { - SmallVector<std::unique_ptr<PredicateMatcher>, 8> Conditions; - SmallVector<Matcher *, 8> Rules; +MatchTable MatchTable::buildTable(ArrayRef<Matcher *> Rules, + bool WithCoverage) { + MatchTable Table(WithCoverage); + for (Matcher *Rule : Rules) + Rule->emit(Table); + + return Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak; +} + +class GroupMatcher final : public Matcher { + /// Conditions that form a common prefix of all the matchers contained. + SmallVector<std::unique_ptr<PredicateMatcher>, 1> Conditions; + + /// All the nested matchers, sharing a common prefix. + std::vector<Matcher *> Matchers; + + /// An owning collection for any auxiliary matchers created while optimizing + /// nested matchers contained. + std::vector<std::unique_ptr<Matcher>> MatcherStorage; public: - void addCondition(std::unique_ptr<PredicateMatcher> &&Predicate) { - Conditions.emplace_back(std::move(Predicate)); + /// Add a matcher to the collection of nested matchers if it meets the + /// requirements, and return true. If it doesn't, do nothing and return false. + /// + /// Expected to preserve its argument, so it could be moved out later on. + bool addMatcher(Matcher &Candidate); + + /// Mark the matcher as fully-built and ensure any invariants expected by both + /// optimize() and emit(...) methods. Generally, both sequences of calls + /// are expected to lead to a sensible result: + /// + /// addMatcher(...)*; finalize(); optimize(); emit(...); and + /// addMatcher(...)*; finalize(); emit(...); + /// + /// or generally + /// + /// addMatcher(...)*; finalize(); { optimize()*; emit(...); }* + /// + /// Multiple calls to optimize() are expected to be handled gracefully, though + /// optimize() is not expected to be idempotent. Multiple calls to finalize() + /// aren't generally supported. emit(...) is expected to be non-mutating and + /// producing the exact same results upon repeated calls. + /// + /// addMatcher() calls after the finalize() call are not supported. + /// + /// finalize() and optimize() are both allowed to mutate the contained + /// matchers, so moving them out after finalize() is not supported. + void finalize(); + void optimize() override; + void emit(MatchTable &Table) override; + + /// Could be used to move out the matchers added previously, unless finalize() + /// has been already called. If any of the matchers are moved out, the group + /// becomes safe to destroy, but not safe to re-use for anything else. + iterator_range<std::vector<Matcher *>::iterator> matchers() { + return make_range(Matchers.begin(), Matchers.end()); } - void addRule(Matcher &Rule) { Rules.push_back(&Rule); } - const std::unique_ptr<PredicateMatcher> &conditions_back() const { - return Conditions.back(); + size_t size() const { return Matchers.size(); } + bool empty() const { return Matchers.empty(); } + + std::unique_ptr<PredicateMatcher> popFirstCondition() override { + assert(!Conditions.empty() && + "Trying to pop a condition from a condition-less group"); + std::unique_ptr<PredicateMatcher> P = std::move(Conditions.front()); + Conditions.erase(Conditions.begin()); + return P; } - bool lastConditionMatches(const PredicateMatcher &Predicate) const; - bool conditions_empty() const { return Conditions.empty(); } - void clear() { - Conditions.clear(); - Rules.clear(); + const PredicateMatcher &getFirstCondition() const override { + assert(!Conditions.empty() && + "Trying to get a condition from a condition-less group"); + return *Conditions.front(); } + bool hasFirstCondition() const override { return !Conditions.empty(); } + +private: + /// See if a candidate matcher could be added to this group solely by + /// analyzing its first condition. + bool candidateConditionMatches(const PredicateMatcher &Predicate) const; +}; + +class SwitchMatcher : public Matcher { + /// All the nested matchers, representing distinct switch-cases. The first + /// conditions (as Matcher::getFirstCondition() reports) of all the nested + /// matchers must share the same type and path to a value they check, in other + /// words, be isIdenticalDownToValue, but have different values they check + /// against. + std::vector<Matcher *> Matchers; + + /// The representative condition, with a type and a path (InsnVarID and OpIdx + /// in most cases) shared by all the matchers contained. + std::unique_ptr<PredicateMatcher> Condition = nullptr; + + /// Temporary set used to check that the case values don't repeat within the + /// same switch. + std::set<MatchTableRecord> Values; + + /// An owning collection for any auxiliary matchers created while optimizing + /// nested matchers contained. + std::vector<std::unique_ptr<Matcher>> MatcherStorage; + +public: + bool addMatcher(Matcher &Candidate); + + void finalize(); void emit(MatchTable &Table) override; - std::unique_ptr<PredicateMatcher> forgetFirstCondition() override { - // We shouldn't need to mess up with groups, since we - // should have merged everything shareable upfront. - // If we start to look into reordering predicates, - // we may want to reconsider this. - assert(0 && "Groups should be formed maximal for now"); - llvm_unreachable("No need for this for now"); + iterator_range<std::vector<Matcher *>::iterator> matchers() { + return make_range(Matchers.begin(), Matchers.end()); } + size_t size() const { return Matchers.size(); } + bool empty() const { return Matchers.empty(); } + + std::unique_ptr<PredicateMatcher> popFirstCondition() override { + // SwitchMatcher doesn't have a common first condition for its cases, as all + // the cases only share a kind of a value (a type and a path to it) they + // match, but deliberately differ in the actual value they match. + llvm_unreachable("Trying to pop a condition from a condition-less group"); + } + const PredicateMatcher &getFirstCondition() const override { + llvm_unreachable("Trying to pop a condition from a condition-less group"); + } + bool hasFirstCondition() const override { return false; } + +private: + /// See if the predicate type has a Switch-implementation for it. + static bool isSupportedPredicateType(const PredicateMatcher &Predicate); + + bool candidateConditionMatches(const PredicateMatcher &Predicate) const; + + /// emit()-helper + static void emitPredicateSpecificOpcodes(const PredicateMatcher &P, + MatchTable &Table); }; /// Generates code to check that a match rule matches. class RuleMatcher : public Matcher { public: - using ActionVec = std::vector<std::unique_ptr<MatchAction>>; - using action_iterator = ActionVec::iterator; + using ActionList = std::list<std::unique_ptr<MatchAction>>; + using action_iterator = ActionList::iterator; protected: /// A list of matchers that all need to succeed for the current rule to match. /// FIXME: This currently supports a single match position but could be /// extended to support multiple positions to support div/rem fusion or /// load-multiple instructions. - std::vector<std::unique_ptr<InstructionMatcher>> Matchers; + using MatchersTy = std::vector<std::unique_ptr<InstructionMatcher>> ; + MatchersTy Matchers; /// A list of actions that need to be taken when all predicates in this rule /// have succeeded. - ActionVec Actions; + ActionList Actions; - using DefinedInsnVariablesMap = - std::map<const InstructionMatcher *, unsigned>; + using DefinedInsnVariablesMap = std::map<InstructionMatcher *, unsigned>; - /// A map of instruction matchers to the local variables created by - /// emitCaptureOpcodes(). + /// A map of instruction matchers to the local variables DefinedInsnVariablesMap InsnVariableIDs; - using MutatableInsnSet = SmallPtrSet<const InstructionMatcher *, 4>; + using MutatableInsnSet = SmallPtrSet<InstructionMatcher *, 4>; // The set of instruction matchers that have not yet been claimed for mutation // by a BuildMI. @@ -641,7 +797,7 @@ protected: /// the renderers. StringMap<OperandMatcher *> DefinedOperands; - /// ID for the next instruction variable defined with defineInsnVar() + /// ID for the next instruction variable defined with implicitlyDefineInsnVar() unsigned NextInsnVarID; /// ID for the next output instruction allocated with allocateOutputInsnID() @@ -651,6 +807,7 @@ protected: unsigned NextTempRegID; std::vector<Record *> RequiredFeatures; + std::vector<std::unique_ptr<PredicateMatcher>> EpilogueMatchers; ArrayRef<SMLoc> SrcLoc; @@ -684,16 +841,9 @@ public: action_iterator insertAction(action_iterator InsertPt, Args &&... args); /// Define an instruction without emitting any code to do so. - /// This is used for the root of the match. - unsigned implicitlyDefineInsnVar(const InstructionMatcher &Matcher); - void clearImplicitMap() { - NextInsnVarID = 0; - InsnVariableIDs.clear(); - }; - /// Define an instruction and emit corresponding state-machine opcodes. - unsigned defineInsnVar(MatchTable &Table, const InstructionMatcher &Matcher, - unsigned InsnVarID, unsigned OpIdx); - unsigned getInsnVarID(const InstructionMatcher &InsnMatcher) const; + unsigned implicitlyDefineInsnVar(InstructionMatcher &Matcher); + + unsigned getInsnVarID(InstructionMatcher &InsnMatcher) const; DefinedInsnVariablesMap::const_iterator defined_insn_vars_begin() const { return InsnVariableIDs.begin(); } @@ -715,7 +865,7 @@ public: mutatable_insns() const { return make_range(mutatable_insns_begin(), mutatable_insns_end()); } - void reserveInsnMatcherForMutation(const InstructionMatcher *InsnMatcher) { + void reserveInsnMatcherForMutation(InstructionMatcher *InsnMatcher) { bool R = MutatableInsns.erase(InsnMatcher); assert(R && "Reserving a mutatable insn that isn't available"); (void)R; @@ -743,11 +893,10 @@ public: return I->second; } - const InstructionMatcher &getInstructionMatcher(StringRef SymbolicName) const; + InstructionMatcher &getInstructionMatcher(StringRef SymbolicName) const; const OperandMatcher &getOperandMatcher(StringRef Name) const; - void emitCaptureOpcodes(MatchTable &Table); - + void optimize() override; void emit(MatchTable &Table) override; /// Compare the priority of this object and B. @@ -759,7 +908,12 @@ public: /// matcher. unsigned countRendererFns() const; - std::unique_ptr<PredicateMatcher> forgetFirstCondition() override; + std::unique_ptr<PredicateMatcher> popFirstCondition() override; + const PredicateMatcher &getFirstCondition() const override; + LLTCodeGen getFirstConditionAsRootType(); + bool hasFirstCondition() const override; + unsigned getNumOperands() const; + StringRef getOpcode() const; // FIXME: Remove this as soon as possible InstructionMatcher &insnmatchers_front() const { return *Matchers.front(); } @@ -767,6 +921,9 @@ public: unsigned allocateOutputInsnID() { return NextOutputInsnID++; } unsigned allocateTempRegID() { return NextTempRegID++; } + iterator_range<MatchersTy::iterator> insnmatchers() { + return make_range(Matchers.begin(), Matchers.end()); + } bool insnmatchers_empty() const { return Matchers.empty(); } void insnmatchers_pop_front() { Matchers.erase(Matchers.begin()); } }; @@ -777,58 +934,69 @@ using action_iterator = RuleMatcher::action_iterator; template <class PredicateTy> class PredicateListMatcher { private: - typedef std::vector<std::unique_ptr<PredicateTy>> PredicateVec; - PredicateVec Predicates; - /// Template instantiations should specialize this to return a string to use /// for the comment emitted when there are no predicates. std::string getNoPredicateComment() const; +protected: + using PredicatesTy = std::deque<std::unique_ptr<PredicateTy>>; + PredicatesTy Predicates; + + /// Track if the list of predicates was manipulated by one of the optimization + /// methods. + bool Optimized = false; + public: - /// Construct a new operand predicate and add it to the matcher. + /// Construct a new predicate and add it to the matcher. template <class Kind, class... Args> - Optional<Kind *> addPredicate(Args&&... args) { - Predicates.emplace_back( - llvm::make_unique<Kind>(std::forward<Args>(args)...)); - return static_cast<Kind *>(Predicates.back().get()); - } + Optional<Kind *> addPredicate(Args &&... args); - typename PredicateVec::const_iterator predicates_begin() const { + typename PredicatesTy::iterator predicates_begin() { return Predicates.begin(); } - typename PredicateVec::const_iterator predicates_end() const { + typename PredicatesTy::iterator predicates_end() { return Predicates.end(); } - iterator_range<typename PredicateVec::const_iterator> predicates() const { + iterator_range<typename PredicatesTy::iterator> predicates() { return make_range(predicates_begin(), predicates_end()); } - typename PredicateVec::size_type predicates_size() const { + typename PredicatesTy::size_type predicates_size() const { return Predicates.size(); } bool predicates_empty() const { return Predicates.empty(); } std::unique_ptr<PredicateTy> predicates_pop_front() { std::unique_ptr<PredicateTy> Front = std::move(Predicates.front()); - Predicates.erase(Predicates.begin()); + Predicates.pop_front(); + Optimized = true; return Front; } + void prependPredicate(std::unique_ptr<PredicateTy> &&Predicate) { + Predicates.push_front(std::move(Predicate)); + } + + void eraseNullPredicates() { + const auto NewEnd = + std::stable_partition(Predicates.begin(), Predicates.end(), + std::logical_not<std::unique_ptr<PredicateTy>>()); + if (NewEnd != Predicates.begin()) { + Predicates.erase(Predicates.begin(), NewEnd); + Optimized = true; + } + } + /// Emit MatchTable opcodes that tests whether all the predicates are met. template <class... Args> - void emitPredicateListOpcodes(MatchTable &Table, Args &&... args) const { - if (Predicates.empty()) { + void emitPredicateListOpcodes(MatchTable &Table, Args &&... args) { + if (Predicates.empty() && !Optimized) { Table << MatchTable::Comment(getNoPredicateComment()) << MatchTable::LineBreak; return; } - unsigned OpIdx = (*predicates_begin())->getOpIdx(); - (void)OpIdx; - for (const auto &Predicate : predicates()) { - assert(Predicate->getOpIdx() == OpIdx && - "Checks touch different operands?"); + for (const auto &Predicate : predicates()) Predicate->emitPredicateOpcodes(Table, std::forward<Args>(args)...); - } } }; @@ -846,8 +1014,12 @@ public: /// are currently not compared between each other. enum PredicateKind { IPM_Opcode, + IPM_NumOperands, IPM_ImmPredicate, IPM_AtomicOrderingMMO, + IPM_MemoryLLTSize, + IPM_MemoryVsLLTSize, + IPM_GenericPredicate, OPM_SameOperand, OPM_ComplexPattern, OPM_IntrinsicID, @@ -869,7 +1041,9 @@ public: PredicateMatcher(PredicateKind Kind, unsigned InsnVarID, unsigned OpIdx = ~0) : Kind(Kind), InsnVarID(InsnVarID), OpIdx(OpIdx) {} + unsigned getInsnVarID() const { return InsnVarID; } unsigned getOpIdx() const { return OpIdx; } + virtual ~PredicateMatcher() = default; /// Emit MatchTable opcodes that check the predicate for the given operand. virtual void emitPredicateOpcodes(MatchTable &Table, @@ -878,16 +1052,23 @@ public: PredicateKind getKind() const { return Kind; } virtual bool isIdentical(const PredicateMatcher &B) const { - if (InsnVarID != 0 || OpIdx != (unsigned)~0) { - // We currently don't hoist the record of instruction properly. - // Therefore we can only work on the orig instruction (InsnVarID - // == 0). - DEBUG(dbgs() << "Non-zero instr ID not supported yet\n"); - return false; - } return B.getKind() == getKind() && InsnVarID == B.InsnVarID && OpIdx == B.OpIdx; } + + virtual bool isIdenticalDownToValue(const PredicateMatcher &B) const { + return hasValue() && PredicateMatcher::isIdentical(B); + } + + virtual MatchTableRecord getValue() const { + assert(hasValue() && "Can not get a value of a value-less predicate!"); + llvm_unreachable("Not implemented yet"); + } + virtual bool hasValue() const { return false; } + + /// Report the maximum number of temporary operands needed by the predicate + /// matcher. + virtual unsigned countRendererFns() const { return 0; } }; /// Generates code to check a predicate of an operand. @@ -903,20 +1084,10 @@ public: : PredicateMatcher(Kind, InsnVarID, OpIdx) {} virtual ~OperandPredicateMatcher() {} - /// Emit MatchTable opcodes to capture instructions into the MIs table. - /// - /// Only InstructionOperandMatcher needs to do anything for this method the - /// rest just walk the tree. - virtual void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) const {} - /// Compare the priority of this object and B. /// /// Returns true if this object is more important than B. virtual bool isHigherPriorityThan(const OperandPredicateMatcher &B) const; - - /// Report the maximum number of temporary operands needed by the predicate - /// matcher. - virtual unsigned countRendererFns() const { return 0; } }; template <> @@ -935,12 +1106,17 @@ public: : OperandPredicateMatcher(OPM_SameOperand, InsnVarID, OpIdx), MatchingName(MatchingName) {} - static bool classof(const OperandPredicateMatcher *P) { + static bool classof(const PredicateMatcher *P) { return P->getKind() == OPM_SameOperand; } void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const override; + + bool isIdentical(const PredicateMatcher &B) const override { + return OperandPredicateMatcher::isIdentical(B) && + MatchingName == cast<SameOperandMatcher>(&B)->MatchingName; + } }; /// Generates code to check that an operand is a particular LLT. @@ -949,7 +1125,15 @@ protected: LLTCodeGen Ty; public: - static std::set<LLTCodeGen> KnownTypes; + static std::map<LLTCodeGen, unsigned> TypeIDValues; + + static void initTypeIDValuesMap() { + TypeIDValues.clear(); + + unsigned ID = 0; + for (const LLTCodeGen LLTy : KnownTypes) + TypeIDValues[LLTy] = ID++; + } LLTOperandMatcher(unsigned InsnVarID, unsigned OpIdx, const LLTCodeGen &Ty) : OperandPredicateMatcher(OPM_LLT, InsnVarID, OpIdx), Ty(Ty) { @@ -963,18 +1147,30 @@ public: return OperandPredicateMatcher::isIdentical(B) && Ty == cast<LLTOperandMatcher>(&B)->Ty; } + MatchTableRecord getValue() const override { + const auto VI = TypeIDValues.find(Ty); + if (VI == TypeIDValues.end()) + return MatchTable::NamedValue(getTy().getCxxEnumValue()); + return MatchTable::NamedValue(getTy().getCxxEnumValue(), VI->second); + } + bool hasValue() const override { + if (TypeIDValues.size() != KnownTypes.size()) + initTypeIDValuesMap(); + return TypeIDValues.count(Ty); + } + + LLTCodeGen getTy() const { return Ty; } void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { Table << MatchTable::Opcode("GIM_CheckType") << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx) << MatchTable::Comment("Type") - << MatchTable::NamedValue(Ty.getCxxEnumValue()) - << MatchTable::LineBreak; + << getValue() << MatchTable::LineBreak; } }; -std::set<LLTCodeGen> LLTOperandMatcher::KnownTypes; +std::map<LLTCodeGen, unsigned> LLTOperandMatcher::TypeIDValues; /// Generates code to check that an operand is a pointer to any address space. /// @@ -1207,7 +1403,18 @@ public: assert(SymbolicName.empty() && "Operand already has a symbolic name"); SymbolicName = Name; } - unsigned getOperandIndex() const { return OpIdx; } + + /// Construct a new operand predicate and add it to the matcher. + template <class Kind, class... Args> + Optional<Kind *> addPredicate(Args &&... args) { + if (isSameAsAnotherOperand()) + return None; + Predicates.emplace_back(llvm::make_unique<Kind>( + getInsnVarID(), getOpIdx(), std::forward<Args>(args)...)); + return static_cast<Kind *>(Predicates.back().get()); + } + + unsigned getOpIdx() const { return OpIdx; } unsigned getInsnVarID() const; std::string getOperandExpr(unsigned InsnVarID) const { @@ -1220,23 +1427,19 @@ public: Error addTypeCheckPredicate(const TypeSetByHwMode &VTy, bool OperandIsAPointer); - /// Emit MatchTable opcodes to capture instructions into the MIs table. - void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) const { - for (const auto &Predicate : predicates()) - Predicate->emitCaptureOpcodes(Table, Rule); - } - /// Emit MatchTable opcodes that test whether the instruction named in /// InsnVarID matches all the predicates and all the operands. - void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const { - std::string Comment; - raw_string_ostream CommentOS(Comment); - CommentOS << "MIs[" << getInsnVarID() << "] "; - if (SymbolicName.empty()) - CommentOS << "Operand " << OpIdx; - else - CommentOS << SymbolicName; - Table << MatchTable::Comment(CommentOS.str()) << MatchTable::LineBreak; + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) { + if (!Optimized) { + std::string Comment; + raw_string_ostream CommentOS(Comment); + CommentOS << "MIs[" << getInsnVarID() << "] "; + if (SymbolicName.empty()) + CommentOS << "Operand " << OpIdx; + else + CommentOS << SymbolicName; + Table << MatchTable::Comment(CommentOS.str()) << MatchTable::LineBreak; + } emitPredicateListOpcodes(Table, Rule); } @@ -1244,7 +1447,7 @@ public: /// Compare the priority of this object and B. /// /// Returns true if this object is more important than B. - bool isHigherPriorityThan(const OperandMatcher &B) const { + bool isHigherPriorityThan(OperandMatcher &B) { // Operand matchers involving more predicates have higher priority. if (predicates_size() > B.predicates_size()) return true; @@ -1252,7 +1455,7 @@ public: return false; // This assumes that predicates are added in a consistent order. - for (const auto &Predicate : zip(predicates(), B.predicates())) { + for (auto &&Predicate : zip(predicates(), B.predicates())) { if (std::get<0>(Predicate)->isHigherPriorityThan(*std::get<1>(Predicate))) return true; if (std::get<1>(Predicate)->isHigherPriorityThan(*std::get<0>(Predicate))) @@ -1264,7 +1467,7 @@ public: /// Report the maximum number of temporary operands needed by the operand /// matcher. - unsigned countRendererFns() const { + unsigned countRendererFns() { return std::accumulate( predicates().begin(), predicates().end(), 0, [](unsigned A, @@ -1277,7 +1480,7 @@ public: return AllocatedTemporariesBaseID; } - bool isSameAsAnotherOperand() const { + bool isSameAsAnotherOperand() { for (const auto &Predicate : predicates()) if (isa<SameOperandMatcher>(Predicate)) return true; @@ -1285,21 +1488,6 @@ public: } }; -// Specialize OperandMatcher::addPredicate() to refrain from adding redundant -// predicates. -template <> -template <class Kind, class... Args> -Optional<Kind *> -PredicateListMatcher<OperandPredicateMatcher>::addPredicate(Args &&... args) { - auto *OpMatcher = static_cast<OperandMatcher *>(this); - if (static_cast<OperandMatcher *>(this)->isSameAsAnotherOperand()) - return None; - Predicates.emplace_back(llvm::make_unique<Kind>(OpMatcher->getInsnVarID(), - OpMatcher->getOperandIndex(), - std::forward<Args>(args)...)); - return static_cast<Kind *>(Predicates.back().get()); -} - Error OperandMatcher::addTypeCheckPredicate(const TypeSetByHwMode &VTy, bool OperandIsAPointer) { if (!VTy.isMachineValueType()) @@ -1343,15 +1531,11 @@ public: isHigherPriorityThan(const InstructionPredicateMatcher &B) const { return Kind < B.Kind; }; - - /// Report the maximum number of temporary operands needed by the predicate - /// matcher. - virtual unsigned countRendererFns() const { return 0; } }; template <> std::string -PredicateListMatcher<InstructionPredicateMatcher>::getNoPredicateComment() const { +PredicateListMatcher<PredicateMatcher>::getNoPredicateComment() const { return "No instruction predicates"; } @@ -1360,7 +1544,17 @@ class InstructionOpcodeMatcher : public InstructionPredicateMatcher { protected: const CodeGenInstruction *I; + static DenseMap<const CodeGenInstruction *, unsigned> OpcodeValues; + public: + static void initOpcodeValuesMap(const CodeGenTarget &Target) { + OpcodeValues.clear(); + + unsigned OpcodeValue = 0; + for (const CodeGenInstruction *I : Target.getInstructionsByEnumValue()) + OpcodeValues[I] = OpcodeValue++; + } + InstructionOpcodeMatcher(unsigned InsnVarID, const CodeGenInstruction *I) : InstructionPredicateMatcher(IPM_Opcode, InsnVarID), I(I) {} @@ -1372,12 +1566,19 @@ public: return InstructionPredicateMatcher::isIdentical(B) && I == cast<InstructionOpcodeMatcher>(&B)->I; } + MatchTableRecord getValue() const override { + const auto VI = OpcodeValues.find(I); + if (VI != OpcodeValues.end()) + return MatchTable::NamedValue(I->Namespace, I->TheDef->getName(), + VI->second); + return MatchTable::NamedValue(I->Namespace, I->TheDef->getName()); + } + bool hasValue() const override { return OpcodeValues.count(I); } void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { Table << MatchTable::Opcode("GIM_CheckOpcode") << MatchTable::Comment("MI") - << MatchTable::IntValue(InsnVarID) - << MatchTable::NamedValue(I->Namespace, I->TheDef->getName()) + << MatchTable::IntValue(InsnVarID) << getValue() << MatchTable::LineBreak; } @@ -1404,6 +1605,42 @@ public: bool isConstantInstruction() const { return I->TheDef->getName() == "G_CONSTANT"; } + + StringRef getOpcode() const { return I->TheDef->getName(); } + unsigned getNumOperands() const { return I->Operands.size(); } + + StringRef getOperandType(unsigned OpIdx) const { + return I->Operands[OpIdx].OperandType; + } +}; + +DenseMap<const CodeGenInstruction *, unsigned> + InstructionOpcodeMatcher::OpcodeValues; + +class InstructionNumOperandsMatcher final : public InstructionPredicateMatcher { + unsigned NumOperands = 0; + +public: + InstructionNumOperandsMatcher(unsigned InsnVarID, unsigned NumOperands) + : InstructionPredicateMatcher(IPM_NumOperands, InsnVarID), + NumOperands(NumOperands) {} + + static bool classof(const PredicateMatcher *P) { + return P->getKind() == IPM_NumOperands; + } + + bool isIdentical(const PredicateMatcher &B) const override { + return InstructionPredicateMatcher::isIdentical(B) && + NumOperands == cast<InstructionNumOperandsMatcher>(&B)->NumOperands; + } + + void emitPredicateOpcodes(MatchTable &Table, + RuleMatcher &Rule) const override { + Table << MatchTable::Opcode("GIM_CheckNumOperands") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("Expected") + << MatchTable::IntValue(NumOperands) << MatchTable::LineBreak; + } }; /// Generates code to check that this instruction is a constant whose value @@ -1483,10 +1720,17 @@ public: : InstructionPredicateMatcher(IPM_AtomicOrderingMMO, InsnVarID), Order(Order), Comparator(Comparator) {} - static bool classof(const InstructionPredicateMatcher *P) { + static bool classof(const PredicateMatcher *P) { return P->getKind() == IPM_AtomicOrderingMMO; } + bool isIdentical(const PredicateMatcher &B) const override { + if (!InstructionPredicateMatcher::isIdentical(B)) + return false; + const auto &R = *cast<AtomicOrderingMMOPredicateMatcher>(&B); + return Order == R.Order && Comparator == R.Comparator; + } + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { StringRef Opcode = "GIM_CheckAtomicOrdering"; @@ -1503,14 +1747,113 @@ public: } }; +/// Generates code to check that the size of an MMO is exactly N bytes. +class MemorySizePredicateMatcher : public InstructionPredicateMatcher { +protected: + unsigned MMOIdx; + uint64_t Size; + +public: + MemorySizePredicateMatcher(unsigned InsnVarID, unsigned MMOIdx, unsigned Size) + : InstructionPredicateMatcher(IPM_MemoryLLTSize, InsnVarID), + MMOIdx(MMOIdx), Size(Size) {} + + static bool classof(const PredicateMatcher *P) { + return P->getKind() == IPM_MemoryLLTSize; + } + bool isIdentical(const PredicateMatcher &B) const override { + return InstructionPredicateMatcher::isIdentical(B) && + MMOIdx == cast<MemorySizePredicateMatcher>(&B)->MMOIdx && + Size == cast<MemorySizePredicateMatcher>(&B)->Size; + } + + void emitPredicateOpcodes(MatchTable &Table, + RuleMatcher &Rule) const override { + Table << MatchTable::Opcode("GIM_CheckMemorySizeEqualTo") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx) + << MatchTable::Comment("Size") << MatchTable::IntValue(Size) + << MatchTable::LineBreak; + } +}; + +/// Generates code to check that the size of an MMO is less-than, equal-to, or +/// greater than a given LLT. +class MemoryVsLLTSizePredicateMatcher : public InstructionPredicateMatcher { +public: + enum RelationKind { + GreaterThan, + EqualTo, + LessThan, + }; + +protected: + unsigned MMOIdx; + RelationKind Relation; + unsigned OpIdx; + +public: + MemoryVsLLTSizePredicateMatcher(unsigned InsnVarID, unsigned MMOIdx, + enum RelationKind Relation, + unsigned OpIdx) + : InstructionPredicateMatcher(IPM_MemoryVsLLTSize, InsnVarID), + MMOIdx(MMOIdx), Relation(Relation), OpIdx(OpIdx) {} + + static bool classof(const PredicateMatcher *P) { + return P->getKind() == IPM_MemoryVsLLTSize; + } + bool isIdentical(const PredicateMatcher &B) const override { + return InstructionPredicateMatcher::isIdentical(B) && + MMOIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->MMOIdx && + Relation == cast<MemoryVsLLTSizePredicateMatcher>(&B)->Relation && + OpIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->OpIdx; + } + + void emitPredicateOpcodes(MatchTable &Table, + RuleMatcher &Rule) const override { + Table << MatchTable::Opcode(Relation == EqualTo + ? "GIM_CheckMemorySizeEqualToLLT" + : Relation == GreaterThan + ? "GIM_CheckMemorySizeGreaterThanLLT" + : "GIM_CheckMemorySizeLessThanLLT") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx) + << MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx) + << MatchTable::LineBreak; + } +}; + +/// Generates code to check an arbitrary C++ instruction predicate. +class GenericInstructionPredicateMatcher : public InstructionPredicateMatcher { +protected: + TreePredicateFn Predicate; + +public: + GenericInstructionPredicateMatcher(unsigned InsnVarID, + TreePredicateFn Predicate) + : InstructionPredicateMatcher(IPM_GenericPredicate, InsnVarID), + Predicate(Predicate) {} + + static bool classof(const InstructionPredicateMatcher *P) { + return P->getKind() == IPM_GenericPredicate; + } + void emitPredicateOpcodes(MatchTable &Table, + RuleMatcher &Rule) const override { + Table << MatchTable::Opcode("GIM_CheckCxxInsnPredicate") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("FnId") + << MatchTable::NamedValue(getEnumNameForPredicate(Predicate)) + << MatchTable::LineBreak; + } +}; + /// Generates code to check that a set of predicates and operands match for a /// particular instruction. /// /// Typical predicates include: /// * Has a specific opcode. /// * Has an nsw/nuw flag or doesn't. -class InstructionMatcher - : public PredicateListMatcher<InstructionPredicateMatcher> { +class InstructionMatcher final : public PredicateListMatcher<PredicateMatcher> { protected: typedef std::vector<std::unique_ptr<OperandMatcher>> OperandVec; @@ -1519,6 +1862,7 @@ protected: /// The operands to match. All rendered operands must be present even if the /// condition is always true. OperandVec Operands; + bool NumOperandsCheck = true; std::string SymbolicName; unsigned InsnVarID; @@ -1531,9 +1875,17 @@ public: InsnVarID = Rule.implicitlyDefineInsnVar(*this); } + /// Construct a new instruction predicate and add it to the matcher. + template <class Kind, class... Args> + Optional<Kind *> addPredicate(Args &&... args) { + Predicates.emplace_back( + llvm::make_unique<Kind>(getInsnVarID(), std::forward<Args>(args)...)); + return static_cast<Kind *>(Predicates.back().get()); + } + RuleMatcher &getRuleMatcher() const { return Rule; } - unsigned getVarID() const { return InsnVarID; } + unsigned getInsnVarID() const { return InsnVarID; } /// Add an operand to the matcher. OperandMatcher &addOperand(unsigned OpIdx, const std::string &SymbolicName, @@ -1549,7 +1901,7 @@ public: OperandMatcher &getOperand(unsigned OpIdx) { auto I = std::find_if(Operands.begin(), Operands.end(), [&OpIdx](const std::unique_ptr<OperandMatcher> &X) { - return X->getOperandIndex() == OpIdx; + return X->getOpIdx() == OpIdx; }); if (I != Operands.end()) return **I; @@ -1572,21 +1924,17 @@ public: void pop_front() { Operands.erase(Operands.begin()); } - /// Emit MatchTable opcodes to check the shape of the match and capture - /// instructions into the MIs table. - void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) { - Table << MatchTable::Opcode("GIM_CheckNumOperands") - << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) - << MatchTable::Comment("Expected") - << MatchTable::IntValue(getNumOperands()) << MatchTable::LineBreak; - for (const auto &Operand : Operands) - Operand->emitCaptureOpcodes(Table, Rule); - } + void optimize(); /// Emit MatchTable opcodes that test whether the instruction named in /// InsnVarName matches all the predicates and all the operands. - void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const { + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) { + if (NumOperandsCheck) + InstructionNumOperandsMatcher(InsnVarID, getNumOperands()) + .emitPredicateOpcodes(Table, Rule); + emitPredicateListOpcodes(Table, Rule); + for (const auto &Operand : Operands) Operand->emitPredicateOpcodes(Table, Rule); } @@ -1594,17 +1942,19 @@ public: /// Compare the priority of this object and B. /// /// Returns true if this object is more important than B. - bool isHigherPriorityThan(const InstructionMatcher &B) const { + bool isHigherPriorityThan(InstructionMatcher &B) { // Instruction matchers involving more operands have higher priority. if (Operands.size() > B.Operands.size()) return true; if (Operands.size() < B.Operands.size()) return false; - for (const auto &Predicate : zip(predicates(), B.predicates())) { - if (std::get<0>(Predicate)->isHigherPriorityThan(*std::get<1>(Predicate))) + for (auto &&P : zip(predicates(), B.predicates())) { + auto L = static_cast<InstructionPredicateMatcher *>(std::get<0>(P).get()); + auto R = static_cast<InstructionPredicateMatcher *>(std::get<1>(P).get()); + if (L->isHigherPriorityThan(*R)) return true; - if (std::get<1>(Predicate)->isHigherPriorityThan(*std::get<0>(Predicate))) + if (R->isHigherPriorityThan(*L)) return false; } @@ -1620,13 +1970,13 @@ public: /// Report the maximum number of temporary operands needed by the instruction /// matcher. - unsigned countRendererFns() const { - return std::accumulate(predicates().begin(), predicates().end(), 0, - [](unsigned A, - const std::unique_ptr<InstructionPredicateMatcher> - &Predicate) { - return A + Predicate->countRendererFns(); - }) + + unsigned countRendererFns() { + return std::accumulate( + predicates().begin(), predicates().end(), 0, + [](unsigned A, + const std::unique_ptr<PredicateMatcher> &Predicate) { + return A + Predicate->countRendererFns(); + }) + std::accumulate( Operands.begin(), Operands.end(), 0, [](unsigned A, const std::unique_ptr<OperandMatcher> &Operand) { @@ -1634,24 +1984,36 @@ public: }); } - bool isConstantInstruction() const { - for (const auto &P : predicates()) - if (const InstructionOpcodeMatcher *Opcode = - dyn_cast<InstructionOpcodeMatcher>(P.get())) - return Opcode->isConstantInstruction(); - return false; + InstructionOpcodeMatcher &getOpcodeMatcher() { + for (auto &P : predicates()) + if (auto *OpMatcher = dyn_cast<InstructionOpcodeMatcher>(P.get())) + return *OpMatcher; + llvm_unreachable("Didn't find an opcode matcher"); + } + + bool isConstantInstruction() { + return getOpcodeMatcher().isConstantInstruction(); } + + StringRef getOpcode() { return getOpcodeMatcher().getOpcode(); } }; -template <> -template <class Kind, class... Args> -Optional<Kind *> -PredicateListMatcher<InstructionPredicateMatcher>::addPredicate( - Args &&... args) { - InstructionMatcher *InstMatcher = static_cast<InstructionMatcher *>(this); - Predicates.emplace_back(llvm::make_unique<Kind>(InstMatcher->getVarID(), - std::forward<Args>(args)...)); - return static_cast<Kind *>(Predicates.back().get()); +StringRef RuleMatcher::getOpcode() const { + return Matchers.front()->getOpcode(); +} + +unsigned RuleMatcher::getNumOperands() const { + return Matchers.front()->getNumOperands(); +} + +LLTCodeGen RuleMatcher::getFirstConditionAsRootType() { + InstructionMatcher &InsnMatcher = *Matchers.front(); + if (!InsnMatcher.predicates_empty()) + if (const auto *TM = + dyn_cast<LLTOperandMatcher>(&**InsnMatcher.predicates_begin())) + if (TM->getInsnVarID() == 0 && TM->getOpIdx() == 0) + return TM->getTy(); + return {}; } /// Generates code to check that the operand is a register defined by an @@ -1679,21 +2041,73 @@ public: InstructionMatcher &getInsnMatcher() const { return *InsnMatcher; } - void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { - unsigned InsnID = - Rule.defineInsnVar(Table, *InsnMatcher, InsnVarID, getOpIdx()); - (void)InsnID; - assert(InsnMatcher->getVarID() == InsnID && - "Mismatch between build and emit"); - InsnMatcher->emitCaptureOpcodes(Table, Rule); + void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) const { + const unsigned NewInsnVarID = InsnMatcher->getInsnVarID(); + Table << MatchTable::Opcode("GIM_RecordInsn") + << MatchTable::Comment("DefineMI") + << MatchTable::IntValue(NewInsnVarID) << MatchTable::Comment("MI") + << MatchTable::IntValue(getInsnVarID()) + << MatchTable::Comment("OpIdx") << MatchTable::IntValue(getOpIdx()) + << MatchTable::Comment("MIs[" + llvm::to_string(NewInsnVarID) + "]") + << MatchTable::LineBreak; } void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { + emitCaptureOpcodes(Table, Rule); InsnMatcher->emitPredicateOpcodes(Table, Rule); } + + bool isHigherPriorityThan(const OperandPredicateMatcher &B) const override { + if (OperandPredicateMatcher::isHigherPriorityThan(B)) + return true; + if (B.OperandPredicateMatcher::isHigherPriorityThan(*this)) + return false; + + if (const InstructionOperandMatcher *BP = + dyn_cast<InstructionOperandMatcher>(&B)) + if (InsnMatcher->isHigherPriorityThan(*BP->InsnMatcher)) + return true; + return false; + } }; +void InstructionMatcher::optimize() { + SmallVector<std::unique_ptr<PredicateMatcher>, 8> Stash; + const auto &OpcMatcher = getOpcodeMatcher(); + + Stash.push_back(predicates_pop_front()); + if (Stash.back().get() == &OpcMatcher) { + if (NumOperandsCheck && OpcMatcher.getNumOperands() < getNumOperands()) + Stash.emplace_back( + new InstructionNumOperandsMatcher(InsnVarID, getNumOperands())); + NumOperandsCheck = false; + + for (auto &OM : Operands) + for (auto &OP : OM->predicates()) + if (isa<IntrinsicIDOperandMatcher>(OP)) { + Stash.push_back(std::move(OP)); + OM->eraseNullPredicates(); + break; + } + } + + if (InsnVarID > 0) { + assert(!Operands.empty() && "Nested instruction is expected to def a vreg"); + for (auto &OP : Operands[0]->predicates()) + OP.reset(); + Operands[0]->eraseNullPredicates(); + } + for (auto &OM : Operands) { + for (auto &OP : OM->predicates()) + if (isa<LLTOperandMatcher>(OP)) + Stash.push_back(std::move(OP)); + OM->eraseNullPredicates(); + } + while (!Stash.empty()) + prependPredicate(Stash.pop_back_val()); +} + //===- Actions ------------------------------------------------------------===// class OperandRenderer { public: @@ -1706,7 +2120,8 @@ public: OR_Imm, OR_Register, OR_TempRegister, - OR_ComplexPattern + OR_ComplexPattern, + OR_Custom }; protected: @@ -1749,7 +2164,7 @@ public: Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID") << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx") - << MatchTable::IntValue(Operand.getOperandIndex()) + << MatchTable::IntValue(Operand.getOpIdx()) << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak; } }; @@ -1785,7 +2200,7 @@ public: << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID") << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx") - << MatchTable::IntValue(Operand.getOperandIndex()) + << MatchTable::IntValue(Operand.getOpIdx()) << MatchTable::NamedValue( (ZeroRegisterDef->getValue("Namespace") ? ZeroRegisterDef->getValueAsString("Namespace") @@ -1816,7 +2231,7 @@ public: const StringRef getSymbolicName() const { return SymbolicName; } void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { - const InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName); + InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName); unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher); Table << MatchTable::Opcode(Signed ? "GIR_CopyConstantAsSImm" : "GIR_CopyConstantAsUImm") @@ -1847,7 +2262,7 @@ public: const StringRef getSymbolicName() const { return SymbolicName; } void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { - const InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName); + InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName); unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher); Table << MatchTable::Opcode("GIR_CopyFConstantAsFPImm") << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID) @@ -1887,7 +2302,7 @@ public: << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID") << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx") - << MatchTable::IntValue(Operand.getOperandIndex()) + << MatchTable::IntValue(Operand.getOpIdx()) << MatchTable::Comment("SubRegIdx") << MatchTable::IntValue(SubReg->EnumValue) << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak; @@ -2018,6 +2433,37 @@ public: } }; +class CustomRenderer : public OperandRenderer { +protected: + unsigned InsnID; + const Record &Renderer; + /// The name of the operand. + const std::string SymbolicName; + +public: + CustomRenderer(unsigned InsnID, const Record &Renderer, + StringRef SymbolicName) + : OperandRenderer(OR_Custom), InsnID(InsnID), Renderer(Renderer), + SymbolicName(SymbolicName) {} + + static bool classof(const OperandRenderer *R) { + return R->getKind() == OR_Custom; + } + + void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { + InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName); + unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher); + Table << MatchTable::Opcode("GIR_CustomRenderer") + << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + << MatchTable::Comment("OldInsnID") + << MatchTable::IntValue(OldInsnVarID) + << MatchTable::Comment("Renderer") + << MatchTable::NamedValue( + "GICR_" + Renderer.getValueAsString("RendererFn").str()) + << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak; + } +}; + /// An action taken when all Matcher predicates succeeded for a parent rule. /// /// Typical actions include: @@ -2051,7 +2497,7 @@ class BuildMIAction : public MatchAction { private: unsigned InsnID; const CodeGenInstruction *I; - const InstructionMatcher *Matched; + InstructionMatcher *Matched; std::vector<std::unique_ptr<OperandRenderer>> OperandRenderers; /// True if the instruction can be built solely by mutating the opcode. @@ -2066,7 +2512,7 @@ private: if (const auto *Copy = dyn_cast<CopyRenderer>(&*Renderer.value())) { const OperandMatcher &OM = Rule.getOperandMatcher(Copy->getSymbolicName()); if (Insn != &OM.getInstructionMatcher() || - OM.getOperandIndex() != Renderer.index()) + OM.getOpIdx() != Renderer.index()) return false; } else return false; @@ -2079,10 +2525,11 @@ public: BuildMIAction(unsigned InsnID, const CodeGenInstruction *I) : InsnID(InsnID), I(I), Matched(nullptr) {} + unsigned getInsnID() const { return InsnID; } const CodeGenInstruction *getCGI() const { return I; } void chooseInsnToMutate(RuleMatcher &Rule) { - for (const auto *MutateCandidate : Rule.mutatable_insns()) { + for (auto *MutateCandidate : Rule.mutatable_insns()) { if (canMutate(Rule, MutateCandidate)) { // Take the first one we're offered that we're able to mutate. Rule.reserveInsnMatcherForMutation(MutateCandidate); @@ -2160,7 +2607,7 @@ public: std::vector<unsigned> MergeInsnIDs; for (const auto &IDMatcherPair : Rule.defined_insn_vars()) MergeInsnIDs.push_back(IDMatcherPair.second); - std::sort(MergeInsnIDs.begin(), MergeInsnIDs.end()); + llvm::sort(MergeInsnIDs.begin(), MergeInsnIDs.end()); for (const auto &MergeInsnID : MergeInsnIDs) Table << MatchTable::IntValue(MergeInsnID); Table << MatchTable::NamedValue("GIU_MergeMemOperands_EndOfList") @@ -2274,27 +2721,13 @@ action_iterator RuleMatcher::insertAction(action_iterator InsertPt, llvm::make_unique<Kind>(std::forward<Args>(args)...)); } -unsigned -RuleMatcher::implicitlyDefineInsnVar(const InstructionMatcher &Matcher) { +unsigned RuleMatcher::implicitlyDefineInsnVar(InstructionMatcher &Matcher) { unsigned NewInsnVarID = NextInsnVarID++; InsnVariableIDs[&Matcher] = NewInsnVarID; return NewInsnVarID; } -unsigned RuleMatcher::defineInsnVar(MatchTable &Table, - const InstructionMatcher &Matcher, - unsigned InsnID, unsigned OpIdx) { - unsigned NewInsnVarID = implicitlyDefineInsnVar(Matcher); - Table << MatchTable::Opcode("GIM_RecordInsn") - << MatchTable::Comment("DefineMI") << MatchTable::IntValue(NewInsnVarID) - << MatchTable::Comment("MI") << MatchTable::IntValue(InsnID) - << MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx) - << MatchTable::Comment("MIs[" + llvm::to_string(NewInsnVarID) + "]") - << MatchTable::LineBreak; - return NewInsnVarID; -} - -unsigned RuleMatcher::getInsnVarID(const InstructionMatcher &InsnMatcher) const { +unsigned RuleMatcher::getInsnVarID(InstructionMatcher &InsnMatcher) const { const auto &I = InsnVariableIDs.find(&InsnMatcher); if (I != InsnVariableIDs.end()) return I->second; @@ -2312,7 +2745,7 @@ void RuleMatcher::defineOperand(StringRef SymbolicName, OperandMatcher &OM) { OM.addPredicate<SameOperandMatcher>(OM.getSymbolicName()); } -const InstructionMatcher & +InstructionMatcher & RuleMatcher::getInstructionMatcher(StringRef SymbolicName) const { for (const auto &I : InsnVariableIDs) if (I.first->getSymbolicName() == SymbolicName) @@ -2331,25 +2764,10 @@ RuleMatcher::getOperandMatcher(StringRef Name) const { return *I->second; } -/// Emit MatchTable opcodes to check the shape of the match and capture -/// instructions into local variables. -void RuleMatcher::emitCaptureOpcodes(MatchTable &Table) { - assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet"); - unsigned InsnVarID = implicitlyDefineInsnVar(*Matchers.front()); - (void)InsnVarID; - assert(Matchers.front()->getVarID() == InsnVarID && - "IDs differ between build and emit"); - Matchers.front()->emitCaptureOpcodes(Table, *this); -} - void RuleMatcher::emit(MatchTable &Table) { if (Matchers.empty()) llvm_unreachable("Unexpected empty matcher!"); - // Reset the ID generation so that the emitted IDs match the ones - // we set while building the InstructionMatcher and such. - clearImplicitMap(); - // The representation supports rules that require multiple roots such as: // %ptr(p0) = ... // %elt0(s32) = G_LOAD %ptr @@ -2363,7 +2781,9 @@ void RuleMatcher::emit(MatchTable &Table) { unsigned LabelID = Table.allocateLabelID(); Table << MatchTable::Opcode("GIM_Try", +1) - << MatchTable::Comment("On fail goto") << MatchTable::JumpTarget(LabelID) + << MatchTable::Comment("On fail goto") + << MatchTable::JumpTarget(LabelID) + << MatchTable::Comment(("Rule ID " + Twine(RuleID) + " //").str()) << MatchTable::LineBreak; if (!RequiredFeatures.empty()) { @@ -2372,8 +2792,6 @@ void RuleMatcher::emit(MatchTable &Table) { << MatchTable::LineBreak; } - emitCaptureOpcodes(Table); - Matchers.front()->emitPredicateOpcodes(Table, *this); // We must also check if it's safe to fold the matched instructions. @@ -2388,7 +2806,7 @@ void RuleMatcher::emit(MatchTable &Table) { InsnIDs.push_back(Pair.second); } - std::sort(InsnIDs.begin(), InsnIDs.end()); + llvm::sort(InsnIDs.begin(), InsnIDs.end()); for (const auto &InsnID : InsnIDs) { // Reject the difficult cases until we have a more accurate check. @@ -2433,15 +2851,22 @@ void RuleMatcher::emit(MatchTable &Table) { } } + for (const auto &PM : EpilogueMatchers) + PM->emitPredicateOpcodes(Table, *this); + for (const auto &MA : Actions) MA->emitActionOpcodes(Table, *this); - if (GenerateCoverage) + if (Table.isWithCoverage()) Table << MatchTable::Opcode("GIR_Coverage") << MatchTable::IntValue(RuleID) << MatchTable::LineBreak; + else + Table << MatchTable::Comment(("GIR_Coverage, " + Twine(RuleID) + ",").str()) + << MatchTable::LineBreak; Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak << MatchTable::Label(LabelID); + ++NumPatternEmitted; } bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const { @@ -2505,7 +2930,7 @@ void SameOperandMatcher::emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const { const OperandMatcher &OtherOM = Rule.getOperandMatcher(MatchingName); unsigned OtherInsnVarID = Rule.getInsnVarID(OtherOM.getInstructionMatcher()); - assert(OtherInsnVarID == OtherOM.getInstructionMatcher().getVarID()); + assert(OtherInsnVarID == OtherOM.getInstructionMatcher().getInsnVarID()); Table << MatchTable::Opcode("GIM_CheckIsSameOperand") << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) @@ -2513,7 +2938,7 @@ void SameOperandMatcher::emitPredicateOpcodes(MatchTable &Table, << MatchTable::Comment("OtherMI") << MatchTable::IntValue(OtherInsnVarID) << MatchTable::Comment("OtherOpIdx") - << MatchTable::IntValue(OtherOM.getOperandIndex()) + << MatchTable::IntValue(OtherOM.getOpIdx()) << MatchTable::LineBreak; } @@ -2541,25 +2966,43 @@ private: /// GIComplexPatternEquiv. DenseMap<const Record *, const Record *> ComplexPatternEquivs; + /// Keep track of the equivalence between SDNodeXForm's and + /// GICustomOperandRenderer. Map entries are specified by subclassing + /// GISDNodeXFormEquiv. + DenseMap<const Record *, const Record *> SDNodeXFormEquivs; + + /// Keep track of Scores of PatternsToMatch similar to how the DAG does. + /// This adds compatibility for RuleMatchers to use this for ordering rules. + DenseMap<uint64_t, int> RuleMatcherScores; + // Map of predicates to their subtarget features. SubtargetFeatureInfoMap SubtargetFeatures; // Rule coverage information. Optional<CodeGenCoverage> RuleCoverage; + void gatherOpcodeValues(); + void gatherTypeIDValues(); void gatherNodeEquivs(); + // Instruction predicate code that will be emitted in generated functions. + SmallVector<std::string, 2> InstructionPredicateCodes; + unsigned getOrCreateInstructionPredicateFnId(StringRef Code); + Record *findNodeEquiv(Record *N) const; + const CodeGenInstruction *getEquivNode(Record &Equiv, + const TreePatternNode *N) const; Error importRulePredicates(RuleMatcher &M, ArrayRef<Predicate> Predicates); - Expected<InstructionMatcher &> createAndImportSelDAGMatcher( - RuleMatcher &Rule, InstructionMatcher &InsnMatcher, - const TreePatternNode *Src, unsigned &TempOpIdx) const; + Expected<InstructionMatcher &> + createAndImportSelDAGMatcher(RuleMatcher &Rule, + InstructionMatcher &InsnMatcher, + const TreePatternNode *Src, unsigned &TempOpIdx); Error importComplexPatternOperandMatcher(OperandMatcher &OM, Record *R, unsigned &TempOpIdx) const; Error importChildMatcher(RuleMatcher &Rule, InstructionMatcher &InsnMatcher, const TreePatternNode *SrcChild, bool OperandIsAPointer, unsigned OpIdx, - unsigned &TempOpIdx) const; + unsigned &TempOpIdx); Expected<BuildMIAction &> createAndImportInstructionRenderer(RuleMatcher &M, @@ -2585,9 +3028,14 @@ private: importImplicitDefRenderers(BuildMIAction &DstMIBuilder, const std::vector<Record *> &ImplicitDefs) const; - void emitImmPredicates(raw_ostream &OS, StringRef TypeIdentifier, - StringRef Type, - std::function<bool(const Record *R)> Filter); + void emitCxxPredicateFns(raw_ostream &OS, StringRef CodeFieldName, + StringRef TypeIdentifier, StringRef ArgType, + StringRef ArgName, StringRef AdditionalDeclarations, + std::function<bool(const Record *R)> Filter); + void emitImmPredicateFns(raw_ostream &OS, StringRef TypeIdentifier, + StringRef ArgType, + std::function<bool(const Record *R)> Filter); + void emitMIPredicateFns(raw_ostream &OS); /// Analyze pattern \p P, returning a matcher for it if possible. /// Otherwise, return an Error explaining why we don't support it. @@ -2595,19 +3043,15 @@ private: void declareSubtargetFeature(Record *Predicate); - TreePatternNode *fixupPatternNode(TreePatternNode *N); - void fixupPatternTrees(TreePattern *P); + MatchTable buildMatchTable(MutableArrayRef<RuleMatcher> Rules, bool Optimize, + bool WithCoverage); +public: /// Takes a sequence of \p Rules and group them based on the predicates - /// they share. \p StorageGroupMatcher is used as a memory container - /// for the the group that are created as part of this process. - /// The optimization process does not change the relative order of - /// the rules. In particular, we don't try to share predicates if - /// that means reordering the rules (e.g., we won't group R1 and R3 - /// in the following example as it would imply reordering R2 and R3 - /// => R1 p1, R2 p2, R3 p1). + /// they share. \p MatcherStorage is used as a memory container + /// for the group that are created as part of this process. /// - /// What this optimization does looks like: + /// What this optimization does looks like if GroupT = GroupMatcher: /// Output without optimization: /// \verbatim /// # R1 @@ -2628,11 +3072,34 @@ private: /// # R2 /// # predicate C /// \endverbatim - std::vector<Matcher *> optimizeRules( - const std::vector<Matcher *> &Rules, - std::vector<std::unique_ptr<GroupMatcher>> &StorageGroupMatcher); + template <class GroupT> + static std::vector<Matcher *> optimizeRules( + ArrayRef<Matcher *> Rules, + std::vector<std::unique_ptr<Matcher>> &MatcherStorage); }; +void GlobalISelEmitter::gatherOpcodeValues() { + InstructionOpcodeMatcher::initOpcodeValuesMap(Target); +} + +void GlobalISelEmitter::gatherTypeIDValues() { + LLTOperandMatcher::initTypeIDValuesMap(); +} +unsigned GlobalISelEmitter::getOrCreateInstructionPredicateFnId(StringRef Code) { + // There's not very many predicates that need to be here at the moment so we + // just maintain a simple set-like vector. If it grows then we'll need to do + // something more efficient. + const auto &I = std::find(InstructionPredicateCodes.begin(), + InstructionPredicateCodes.end(), + Code); + if (I == InstructionPredicateCodes.end()) { + unsigned ID = InstructionPredicateCodes.size(); + InstructionPredicateCodes.push_back(Code); + return ID; + } + return std::distance(InstructionPredicateCodes.begin(), I); +} + void GlobalISelEmitter::gatherNodeEquivs() { assert(NodeEquivs.empty()); for (Record *Equiv : RK.getAllDerivedDefinitions("GINodeEquiv")) @@ -2645,15 +3112,36 @@ void GlobalISelEmitter::gatherNodeEquivs() { continue; ComplexPatternEquivs[SelDAGEquiv] = Equiv; } + + assert(SDNodeXFormEquivs.empty()); + for (Record *Equiv : RK.getAllDerivedDefinitions("GISDNodeXFormEquiv")) { + Record *SelDAGEquiv = Equiv->getValueAsDef("SelDAGEquivalent"); + if (!SelDAGEquiv) + continue; + SDNodeXFormEquivs[SelDAGEquiv] = Equiv; + } } Record *GlobalISelEmitter::findNodeEquiv(Record *N) const { return NodeEquivs.lookup(N); } +const CodeGenInstruction * +GlobalISelEmitter::getEquivNode(Record &Equiv, const TreePatternNode *N) const { + for (const auto &Predicate : N->getPredicateFns()) { + if (!Equiv.isValueUnset("IfSignExtend") && Predicate.isLoad() && + Predicate.isSignExtLoad()) + return &Target.getInstruction(Equiv.getValueAsDef("IfSignExtend")); + if (!Equiv.isValueUnset("IfZeroExtend") && Predicate.isLoad() && + Predicate.isZeroExtLoad()) + return &Target.getInstruction(Equiv.getValueAsDef("IfZeroExtend")); + } + return &Target.getInstruction(Equiv.getValueAsDef("I")); +} + GlobalISelEmitter::GlobalISelEmitter(RecordKeeper &RK) - : RK(RK), CGP(RK, [&](TreePattern *P) { fixupPatternTrees(P); }), - Target(CGP.getTargetInfo()), CGRegs(RK, Target.getHwModes()) {} + : RK(RK), CGP(RK), Target(CGP.getTargetInfo()), + CGRegs(RK, Target.getHwModes()) {} //===- Emitter ------------------------------------------------------------===// @@ -2672,7 +3160,7 @@ GlobalISelEmitter::importRulePredicates(RuleMatcher &M, Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( RuleMatcher &Rule, InstructionMatcher &InsnMatcher, - const TreePatternNode *Src, unsigned &TempOpIdx) const { + const TreePatternNode *Src, unsigned &TempOpIdx) { Record *SrcGIEquivOrNull = nullptr; const CodeGenInstruction *SrcGIOrNull = nullptr; @@ -2693,7 +3181,7 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( if (!SrcGIEquivOrNull) return failedImport("Pattern operator lacks an equivalent Instruction" + explainOperator(Src->getOperator())); - SrcGIOrNull = &Target.getInstruction(SrcGIEquivOrNull->getValueAsDef("I")); + SrcGIOrNull = getEquivNode(*SrcGIEquivOrNull, Src); // The operators look good: match the opcode InsnMatcher.addPredicate<InstructionOpcodeMatcher>(SrcGIOrNull); @@ -2718,8 +3206,26 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( continue; } - // No check required. G_LOAD by itself is a non-extending load. - if (Predicate.isNonExtLoad()) + // G_LOAD is used for both non-extending and any-extending loads. + if (Predicate.isLoad() && Predicate.isNonExtLoad()) { + InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>( + 0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0); + continue; + } + if (Predicate.isLoad() && Predicate.isAnyExtLoad()) { + InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>( + 0, MemoryVsLLTSizePredicateMatcher::LessThan, 0); + continue; + } + + // No check required. We already did it by swapping the opcode. + if (!SrcGIEquivOrNull->isValueUnset("IfSignExtend") && + Predicate.isSignExtLoad()) + continue; + + // No check required. We already did it by swapping the opcode. + if (!SrcGIEquivOrNull->isValueUnset("IfZeroExtend") && + Predicate.isZeroExtLoad()) continue; // No check required. G_STORE by itself is a non-extending store. @@ -2734,8 +3240,13 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( if (!MemTyOrNone) return failedImport("MemVT could not be converted to LLT"); - OperandMatcher &OM = InsnMatcher.getOperand(0); - OM.addPredicate<LLTOperandMatcher>(MemTyOrNone.getValue()); + // MMO's work in bytes so we must take care of unusual types like i1 + // don't round down. + unsigned MemSizeInBits = + llvm::alignTo(MemTyOrNone->get().getSizeInBits(), 8); + + InsnMatcher.addPredicate<MemorySizePredicateMatcher>( + 0, MemSizeInBits / 8); continue; } } @@ -2794,6 +3305,11 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( } } + if (Predicate.hasGISelPredicateCode()) { + InsnMatcher.addPredicate<GenericInstructionPredicateMatcher>(Predicate); + continue; + } + return failedImport("Src pattern child has predicate (" + explainPredicates(Src) + ")"); } @@ -2872,7 +3388,7 @@ Error GlobalISelEmitter::importChildMatcher(RuleMatcher &Rule, const TreePatternNode *SrcChild, bool OperandIsAPointer, unsigned OpIdx, - unsigned &TempOpIdx) const { + unsigned &TempOpIdx) { OperandMatcher &OM = InsnMatcher.addOperand(OpIdx, SrcChild->getName(), TempOpIdx); if (OM.isSameAsAnotherOperand()) @@ -2986,10 +3502,6 @@ Error GlobalISelEmitter::importChildMatcher(RuleMatcher &Rule, Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer( action_iterator InsertPt, RuleMatcher &Rule, BuildMIAction &DstMIBuilder, TreePatternNode *DstChild) { - if (DstChild->getTransformFn() != nullptr) { - return failedImport("Dst pattern child has transform fn " + - DstChild->getTransformFn()->getName()); - } const auto &SubOperand = Rule.getComplexSubOperand(DstChild->getName()); if (SubOperand.hasValue()) { @@ -3000,6 +3512,18 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer( } if (!DstChild->isLeaf()) { + + if (DstChild->getOperator()->isSubClassOf("SDNodeXForm")) { + auto Child = DstChild->getChild(0); + auto I = SDNodeXFormEquivs.find(DstChild->getOperator()); + if (I != SDNodeXFormEquivs.end()) { + DstMIBuilder.addRenderer<CustomRenderer>(*I->second, Child->getName()); + return InsertPt; + } + return failedImport("SDNodeXForm " + Child->getName() + + " has no custom renderer"); + } + // We accept 'bb' here. It's an operator because BasicBlockSDNode isn't // inline, but in MI it's just another operand. if (DstChild->getOperator()->isSubClassOf("SDNode")) { @@ -3104,10 +3628,6 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer( return InsertPt; } - if (ChildRec->isSubClassOf("SDNodeXForm")) - return failedImport("Dst pattern child def is an unsupported tablegen " - "class (SDNodeXForm)"); - return failedImport( "Dst pattern child def is an unsupported tablegen class"); } @@ -3135,7 +3655,7 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer( Expected<action_iterator> GlobalISelEmitter::createAndImportSubInstructionRenderer( - action_iterator InsertPt, RuleMatcher &M, const TreePatternNode *Dst, + const action_iterator InsertPt, RuleMatcher &M, const TreePatternNode *Dst, unsigned TempRegID) { auto InsertPtOrError = createInstructionRenderer(InsertPt, M, Dst); @@ -3143,7 +3663,6 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer( if (auto Error = InsertPtOrError.takeError()) return std::move(Error); - InsertPt = InsertPtOrError.get(); BuildMIAction &DstMIBuilder = *static_cast<BuildMIAction *>(InsertPtOrError.get()->get()); @@ -3151,10 +3670,13 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer( // Assign the result to TempReg. DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, true); - InsertPtOrError = importExplicitUseRenderers(InsertPt, M, DstMIBuilder, Dst); + InsertPtOrError = + importExplicitUseRenderers(InsertPtOrError.get(), M, DstMIBuilder, Dst); if (auto Error = InsertPtOrError.takeError()) return std::move(Error); + M.insertAction<ConstrainOperandsToDefinitionAction>(InsertPt, + DstMIBuilder.getInsnID()); return InsertPtOrError.get(); } @@ -3311,7 +3833,9 @@ Error GlobalISelEmitter::importImplicitDefRenderers( Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { // Keep track of the matchers and actions to emit. + int Score = P.getPatternComplexity(CGP); RuleMatcher M(P.getSrcRecord()->getLoc()); + RuleMatcherScores[M.getRuleID()] = Score; M.addAction<DebugCommentAction>(llvm::to_string(*P.getSrcPattern()) + " => " + llvm::to_string(*P.getDstPattern())); @@ -3526,14 +4050,15 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { // Emit imm predicate table and an enum to reference them with. // The 'Predicate_' part of the name is redundant but eliminating it is more // trouble than it's worth. -void GlobalISelEmitter::emitImmPredicates( - raw_ostream &OS, StringRef TypeIdentifier, StringRef Type, +void GlobalISelEmitter::emitCxxPredicateFns( + raw_ostream &OS, StringRef CodeFieldName, StringRef TypeIdentifier, + StringRef ArgType, StringRef ArgName, StringRef AdditionalDeclarations, std::function<bool(const Record *R)> Filter) { std::vector<const Record *> MatchedRecords; const auto &Defs = RK.getAllDerivedDefinitions("PatFrag"); std::copy_if(Defs.begin(), Defs.end(), std::back_inserter(MatchedRecords), [&](Record *Record) { - return !Record->getValueAsString("ImmediateCode").empty() && + return !Record->getValueAsString(CodeFieldName).empty() && Filter(Record); }); @@ -3550,16 +4075,20 @@ void GlobalISelEmitter::emitImmPredicates( OS << "};\n"; } - OS << "bool " << Target.getName() << "InstructionSelector::testImmPredicate_" - << TypeIdentifier << "(unsigned PredicateID, " << Type - << " Imm) const {\n"; + OS << "bool " << Target.getName() << "InstructionSelector::test" << ArgName + << "Predicate_" << TypeIdentifier << "(unsigned PredicateID, " << ArgType << " " + << ArgName << ") const {\n" + << AdditionalDeclarations; + if (!AdditionalDeclarations.empty()) + OS << "\n"; if (!MatchedRecords.empty()) OS << " switch (PredicateID) {\n"; for (const auto *Record : MatchedRecords) { OS << " case GIPFP_" << TypeIdentifier << "_Predicate_" << Record->getName() << ": {\n" - << " " << Record->getValueAsString("ImmediateCode") << "\n" - << " llvm_unreachable(\"ImmediateCode should have returned\");\n" + << " " << Record->getValueAsString(CodeFieldName) << "\n" + << " llvm_unreachable(\"" << CodeFieldName + << " should have returned\");\n" << " return false;\n" << " }\n"; } @@ -3570,38 +4099,144 @@ void GlobalISelEmitter::emitImmPredicates( << "}\n"; } +void GlobalISelEmitter::emitImmPredicateFns( + raw_ostream &OS, StringRef TypeIdentifier, StringRef ArgType, + std::function<bool(const Record *R)> Filter) { + return emitCxxPredicateFns(OS, "ImmediateCode", TypeIdentifier, ArgType, + "Imm", "", Filter); +} + +void GlobalISelEmitter::emitMIPredicateFns(raw_ostream &OS) { + return emitCxxPredicateFns( + OS, "GISelPredicateCode", "MI", "const MachineInstr &", "MI", + " const MachineFunction &MF = *MI.getParent()->getParent();\n" + " const MachineRegisterInfo &MRI = MF.getRegInfo();\n" + " (void)MRI;", + [](const Record *R) { return true; }); +} + +template <class GroupT> std::vector<Matcher *> GlobalISelEmitter::optimizeRules( - const std::vector<Matcher *> &Rules, - std::vector<std::unique_ptr<GroupMatcher>> &StorageGroupMatcher) { + ArrayRef<Matcher *> Rules, + std::vector<std::unique_ptr<Matcher>> &MatcherStorage) { + std::vector<Matcher *> OptRules; - // Start with a stupid grouping for now. - std::unique_ptr<GroupMatcher> CurrentGroup = make_unique<GroupMatcher>(); - assert(CurrentGroup->conditions_empty()); - unsigned NbGroup = 0; - for (Matcher *Rule : Rules) { - std::unique_ptr<PredicateMatcher> Predicate = Rule->forgetFirstCondition(); - if (!CurrentGroup->conditions_empty() && - !CurrentGroup->lastConditionMatches(*Predicate)) { - // Start a new group. - ++NbGroup; + std::unique_ptr<GroupT> CurrentGroup = make_unique<GroupT>(); + assert(CurrentGroup->empty() && "Newly created group isn't empty!"); + unsigned NumGroups = 0; + + auto ProcessCurrentGroup = [&]() { + if (CurrentGroup->empty()) + // An empty group is good to be reused: + return; + + // If the group isn't large enough to provide any benefit, move all the + // added rules out of it and make sure to re-create the group to properly + // re-initialize it: + if (CurrentGroup->size() < 2) + for (Matcher *M : CurrentGroup->matchers()) + OptRules.push_back(M); + else { + CurrentGroup->finalize(); OptRules.push_back(CurrentGroup.get()); - StorageGroupMatcher.emplace_back(std::move(CurrentGroup)); - CurrentGroup = make_unique<GroupMatcher>(); - assert(CurrentGroup->conditions_empty()); + MatcherStorage.emplace_back(std::move(CurrentGroup)); + ++NumGroups; } - if (CurrentGroup->conditions_empty()) - CurrentGroup->addCondition(std::move(Predicate)); - CurrentGroup->addRule(*Rule); - } - if (!CurrentGroup->conditions_empty()) { - ++NbGroup; - OptRules.push_back(CurrentGroup.get()); - StorageGroupMatcher.emplace_back(std::move(CurrentGroup)); + CurrentGroup = make_unique<GroupT>(); + }; + for (Matcher *Rule : Rules) { + // Greedily add as many matchers as possible to the current group: + if (CurrentGroup->addMatcher(*Rule)) + continue; + + ProcessCurrentGroup(); + assert(CurrentGroup->empty() && "A group wasn't properly re-initialized"); + + // Try to add the pending matcher to a newly created empty group: + if (!CurrentGroup->addMatcher(*Rule)) + // If we couldn't add the matcher to an empty group, that group type + // doesn't support that kind of matchers at all, so just skip it: + OptRules.push_back(Rule); } - DEBUG(dbgs() << "NbGroup: " << NbGroup << "\n"); + ProcessCurrentGroup(); + + LLVM_DEBUG(dbgs() << "NumGroups: " << NumGroups << "\n"); + assert(CurrentGroup->empty() && "The last group wasn't properly processed"); return OptRules; } +MatchTable +GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules, + bool Optimize, bool WithCoverage) { + std::vector<Matcher *> InputRules; + for (Matcher &Rule : Rules) + InputRules.push_back(&Rule); + + if (!Optimize) + return MatchTable::buildTable(InputRules, WithCoverage); + + unsigned CurrentOrdering = 0; + StringMap<unsigned> OpcodeOrder; + for (RuleMatcher &Rule : Rules) { + const StringRef Opcode = Rule.getOpcode(); + assert(!Opcode.empty() && "Didn't expect an undefined opcode"); + if (OpcodeOrder.count(Opcode) == 0) + OpcodeOrder[Opcode] = CurrentOrdering++; + } + + std::stable_sort(InputRules.begin(), InputRules.end(), + [&OpcodeOrder](const Matcher *A, const Matcher *B) { + auto *L = static_cast<const RuleMatcher *>(A); + auto *R = static_cast<const RuleMatcher *>(B); + return std::make_tuple(OpcodeOrder[L->getOpcode()], + L->getNumOperands()) < + std::make_tuple(OpcodeOrder[R->getOpcode()], + R->getNumOperands()); + }); + + for (Matcher *Rule : InputRules) + Rule->optimize(); + + std::vector<std::unique_ptr<Matcher>> MatcherStorage; + std::vector<Matcher *> OptRules = + optimizeRules<GroupMatcher>(InputRules, MatcherStorage); + + for (Matcher *Rule : OptRules) + Rule->optimize(); + + OptRules = optimizeRules<SwitchMatcher>(OptRules, MatcherStorage); + + return MatchTable::buildTable(OptRules, WithCoverage); +} + +void GroupMatcher::optimize() { + // Make sure we only sort by a specific predicate within a range of rules that + // all have that predicate checked against a specific value (not a wildcard): + auto F = Matchers.begin(); + auto T = F; + auto E = Matchers.end(); + while (T != E) { + while (T != E) { + auto *R = static_cast<RuleMatcher *>(*T); + if (!R->getFirstConditionAsRootType().get().isValid()) + break; + ++T; + } + std::stable_sort(F, T, [](Matcher *A, Matcher *B) { + auto *L = static_cast<RuleMatcher *>(A); + auto *R = static_cast<RuleMatcher *>(B); + return L->getFirstConditionAsRootType() < + R->getFirstConditionAsRootType(); + }); + if (T != E) + F = ++T; + } + GlobalISelEmitter::optimizeRules<GroupMatcher>(Matchers, MatcherStorage) + .swap(Matchers); + GlobalISelEmitter::optimizeRules<SwitchMatcher>(Matchers, MatcherStorage) + .swap(Matchers); +} + void GlobalISelEmitter::run(raw_ostream &OS) { if (!UseCoverageFile.empty()) { RuleCoverage = CodeGenCoverage(); @@ -3617,6 +4252,11 @@ void GlobalISelEmitter::run(raw_ostream &OS) { } } + // Track the run-time opcode values + gatherOpcodeValues(); + // Track the run-time LLT ID values + gatherTypeIDValues(); + // Track the GINodeEquiv definitions. gatherNodeEquivs(); @@ -3652,14 +4292,19 @@ void GlobalISelEmitter::run(raw_ostream &OS) { Rules.push_back(std::move(MatcherOrErr.get())); } + // Comparison function to order records by name. + auto orderByName = [](const Record *A, const Record *B) { + return A->getName() < B->getName(); + }; + std::vector<Record *> ComplexPredicates = RK.getAllDerivedDefinitions("GIComplexOperandMatcher"); - std::sort(ComplexPredicates.begin(), ComplexPredicates.end(), - [](const Record *A, const Record *B) { - if (A->getName() < B->getName()) - return true; - return false; - }); + llvm::sort(ComplexPredicates.begin(), ComplexPredicates.end(), orderByName); + + std::vector<Record *> CustomRendererFns = + RK.getAllDerivedDefinitions("GICustomOperandRenderer"); + llvm::sort(CustomRendererFns.begin(), CustomRendererFns.end(), orderByName); + unsigned MaxTemporaries = 0; for (const auto &Rule : Rules) MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns()); @@ -3677,21 +4322,33 @@ void GlobalISelEmitter::run(raw_ostream &OS) { "ComplexRendererFns(" << Target.getName() << "InstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const;\n" - << " const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> " - "MatcherInfo;\n" - << " static " << Target.getName() + + << " typedef void(" << Target.getName() + << "InstructionSelector::*CustomRendererFn)(MachineInstrBuilder &, const " + "MachineInstr&) " + "const;\n" + << " const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, " + "CustomRendererFn> " + "ISelInfo;\n"; + OS << " static " << Target.getName() << "InstructionSelector::ComplexMatcherMemFn ComplexPredicateFns[];\n" - << "bool testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const " + << " static " << Target.getName() + << "InstructionSelector::CustomRendererFn CustomRenderers[];\n" + << " bool testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const " "override;\n" - << "bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) " + << " bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) " "const override;\n" - << "bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat " + << " bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat " "&Imm) const override;\n" + << " const int64_t *getMatchTable() const override;\n" + << " bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI) " + "const override;\n" << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n"; OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n" << ", State(" << MaxTemporaries << "),\n" - << "MatcherInfo({TypeObjects, FeatureBitsets, ComplexPredicateFns})\n" + << "ISelInfo(TypeObjects, NumTypeObjects, FeatureBitsets" + << ", ComplexPredicateFns, CustomRenderers)\n" << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n"; OS << "#ifdef GET_GLOBALISEL_IMPL\n"; @@ -3723,9 +4380,9 @@ void GlobalISelEmitter::run(raw_ostream &OS) { // Emit a table containing the LLT objects needed by the matcher and an enum // for the matcher to reference them with. std::vector<LLTCodeGen> TypeObjects; - for (const auto &Ty : LLTOperandMatcher::KnownTypes) + for (const auto &Ty : KnownTypes) TypeObjects.push_back(Ty); - std::sort(TypeObjects.begin(), TypeObjects.end()); + llvm::sort(TypeObjects.begin(), TypeObjects.end()); OS << "// LLT Objects.\n" << "enum {\n"; for (const auto &TypeObject : TypeObjects) { @@ -3733,7 +4390,8 @@ void GlobalISelEmitter::run(raw_ostream &OS) { TypeObject.emitCxxEnumValue(OS); OS << ",\n"; } - OS << "};\n" + OS << "};\n"; + OS << "const static size_t NumTypeObjects = " << TypeObjects.size() << ";\n" << "const static LLT TypeObjects[] = {\n"; for (const auto &TypeObject : TypeObjects) { OS << " "; @@ -3747,7 +4405,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) { std::vector<std::vector<Record *>> FeatureBitsets; for (auto &Rule : Rules) FeatureBitsets.push_back(Rule.getRequiredFeatures()); - std::sort( + llvm::sort( FeatureBitsets.begin(), FeatureBitsets.end(), [&](const std::vector<Record *> &A, const std::vector<Record *> &B) { if (A.size() < B.size()) @@ -3798,18 +4456,19 @@ void GlobalISelEmitter::run(raw_ostream &OS) { OS << "};\n" << "// See constructor for table contents\n\n"; - emitImmPredicates(OS, "I64", "int64_t", [](const Record *R) { + emitImmPredicateFns(OS, "I64", "int64_t", [](const Record *R) { bool Unset; return !R->getValueAsBitOrUnset("IsAPFloat", Unset) && !R->getValueAsBit("IsAPInt"); }); - emitImmPredicates(OS, "APFloat", "const APFloat &", [](const Record *R) { + emitImmPredicateFns(OS, "APFloat", "const APFloat &", [](const Record *R) { bool Unset; return R->getValueAsBitOrUnset("IsAPFloat", Unset); }); - emitImmPredicates(OS, "APInt", "const APInt &", [](const Record *R) { + emitImmPredicateFns(OS, "APInt", "const APInt &", [](const Record *R) { return R->getValueAsBit("IsAPInt"); }); + emitMIPredicateFns(OS); OS << "\n"; OS << Target.getName() << "InstructionSelector::ComplexMatcherMemFn\n" @@ -3821,22 +4480,30 @@ void GlobalISelEmitter::run(raw_ostream &OS) { << ", // " << Record->getName() << "\n"; OS << "};\n\n"; - OS << "bool " << Target.getName() - << "InstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage " - "&CoverageInfo) const {\n" - << " MachineFunction &MF = *I.getParent()->getParent();\n" - << " MachineRegisterInfo &MRI = MF.getRegInfo();\n" - << " // FIXME: This should be computed on a per-function basis rather " - "than per-insn.\n" - << " AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, " - "&MF);\n" - << " const PredicateBitset AvailableFeatures = getAvailableFeatures();\n" - << " NewMIVector OutMIs;\n" - << " State.MIs.clear();\n" - << " State.MIs.push_back(&I);\n\n"; + OS << "// Custom renderers.\n" + << "enum {\n" + << " GICR_Invalid,\n"; + for (const auto &Record : CustomRendererFns) + OS << " GICR_" << Record->getValueAsString("RendererFn") << ", \n"; + OS << "};\n"; + + OS << Target.getName() << "InstructionSelector::CustomRendererFn\n" + << Target.getName() << "InstructionSelector::CustomRenderers[] = {\n" + << " nullptr, // GICP_Invalid\n"; + for (const auto &Record : CustomRendererFns) + OS << " &" << Target.getName() + << "InstructionSelector::" << Record->getValueAsString("RendererFn") + << ", // " << Record->getName() << "\n"; + OS << "};\n\n"; std::stable_sort(Rules.begin(), Rules.end(), [&](const RuleMatcher &A, const RuleMatcher &B) { + int ScoreA = RuleMatcherScores[A.getRuleID()]; + int ScoreB = RuleMatcherScores[B.getRuleID()]; + if (ScoreA > ScoreB) + return true; + if (ScoreB > ScoreA) + return false; if (A.isHigherPriorityThan(B)) { assert(!B.isHigherPriorityThan(A) && "Cannot be more important " "and less important at " @@ -3845,32 +4512,37 @@ void GlobalISelEmitter::run(raw_ostream &OS) { } return false; }); - std::vector<std::unique_ptr<GroupMatcher>> StorageGroupMatcher; - std::vector<Matcher *> InputRules; - for (Matcher &Rule : Rules) - InputRules.push_back(&Rule); - - std::vector<Matcher *> OptRules = - OptimizeMatchTable ? optimizeRules(InputRules, StorageGroupMatcher) - : InputRules; + OS << "bool " << Target.getName() + << "InstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage " + "&CoverageInfo) const {\n" + << " MachineFunction &MF = *I.getParent()->getParent();\n" + << " MachineRegisterInfo &MRI = MF.getRegInfo();\n" + << " // FIXME: This should be computed on a per-function basis rather " + "than per-insn.\n" + << " AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, " + "&MF);\n" + << " const PredicateBitset AvailableFeatures = getAvailableFeatures();\n" + << " NewMIVector OutMIs;\n" + << " State.MIs.clear();\n" + << " State.MIs.push_back(&I);\n\n" + << " if (executeMatchTable(*this, OutMIs, State, ISelInfo" + << ", getMatchTable(), TII, MRI, TRI, RBI, AvailableFeatures" + << ", CoverageInfo)) {\n" + << " return true;\n" + << " }\n\n" + << " return false;\n" + << "}\n\n"; - MatchTable Table(0); - for (Matcher *Rule : OptRules) { - Rule->emit(Table); - ++NumPatternEmitted; - } - Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak; + const MatchTable Table = + buildMatchTable(Rules, OptimizeMatchTable, GenerateCoverage); + OS << "const int64_t *" << Target.getName() + << "InstructionSelector::getMatchTable() const {\n"; Table.emitDeclaration(OS); - OS << " if (executeMatchTable(*this, OutMIs, State, MatcherInfo, "; + OS << " return "; Table.emitUse(OS); - OS << ", TII, MRI, TRI, RBI, AvailableFeatures, CoverageInfo)) {\n" - << " return true;\n" - << " }\n\n"; - - OS << " return false;\n" - << "}\n" - << "#endif // ifdef GET_GLOBALISEL_IMPL\n"; + OS << ";\n}\n"; + OS << "#endif // ifdef GET_GLOBALISEL_IMPL\n"; OS << "#ifdef GET_GLOBALISEL_PREDICATES_DECL\n" << "PredicateBitset AvailableModuleFeatures;\n" @@ -3899,137 +4571,290 @@ void GlobalISelEmitter::declareSubtargetFeature(Record *Predicate) { Predicate, SubtargetFeatureInfo(Predicate, SubtargetFeatures.size())); } -TreePatternNode *GlobalISelEmitter::fixupPatternNode(TreePatternNode *N) { - if (!N->isLeaf()) { - for (unsigned I = 0, E = N->getNumChildren(); I < E; ++I) { - TreePatternNode *OrigChild = N->getChild(I); - TreePatternNode *NewChild = fixupPatternNode(OrigChild); - if (OrigChild != NewChild) - N->setChild(I, NewChild); +void RuleMatcher::optimize() { + for (auto &Item : InsnVariableIDs) { + InstructionMatcher &InsnMatcher = *Item.first; + for (auto &OM : InsnMatcher.operands()) { + // Complex Patterns are usually expensive and they relatively rarely fail + // on their own: more often we end up throwing away all the work done by a + // matching part of a complex pattern because some other part of the + // enclosing pattern didn't match. All of this makes it beneficial to + // delay complex patterns until the very end of the rule matching, + // especially for targets having lots of complex patterns. + for (auto &OP : OM->predicates()) + if (isa<ComplexPatternOperandMatcher>(OP)) + EpilogueMatchers.emplace_back(std::move(OP)); + OM->eraseNullPredicates(); } + InsnMatcher.optimize(); + } + llvm::sort( + EpilogueMatchers.begin(), EpilogueMatchers.end(), + [](const std::unique_ptr<PredicateMatcher> &L, + const std::unique_ptr<PredicateMatcher> &R) { + return std::make_tuple(L->getKind(), L->getInsnVarID(), L->getOpIdx()) < + std::make_tuple(R->getKind(), R->getInsnVarID(), R->getOpIdx()); + }); +} - if (N->getOperator()->getName() == "ld") { - // If it's a signext-load we need to adapt the pattern slightly. We need - // to split the node into (sext (ld ...)), remove the <<signext>> predicate, - // and then apply the <<signextTY>> predicate by updating the result type - // of the load. - // - // For example: - // (ld:[i32] [iPTR])<<unindexed>><<signext>><<signexti16>> - // must be transformed into: - // (sext:[i32] (ld:[i16] [iPTR])<<unindexed>>) - // - // Likewise for zeroext-load and anyext-load. - - std::vector<TreePredicateFn> Predicates; - bool IsSignExtLoad = false; - bool IsZeroExtLoad = false; - bool IsAnyExtLoad = false; - Record *MemVT = nullptr; - for (const auto &P : N->getPredicateFns()) { - if (P.isLoad() && P.isSignExtLoad()) { - IsSignExtLoad = true; - continue; - } - if (P.isLoad() && P.isZeroExtLoad()) { - IsZeroExtLoad = true; - continue; - } - if (P.isLoad() && P.isAnyExtLoad()) { - IsAnyExtLoad = true; - continue; - } - if (P.isLoad() && P.getMemoryVT()) { - MemVT = P.getMemoryVT(); - continue; - } - Predicates.push_back(P); - } - - if ((IsSignExtLoad || IsZeroExtLoad || IsAnyExtLoad) && MemVT) { - assert((IsSignExtLoad + IsZeroExtLoad + IsAnyExtLoad) == 1 && - "IsSignExtLoad, IsZeroExtLoad, IsAnyExtLoad are mutually exclusive"); - TreePatternNode *Ext = new TreePatternNode( - RK.getDef(IsSignExtLoad ? "sext" - : IsZeroExtLoad ? "zext" : "anyext"), - {N}, 1); - Ext->setType(0, N->getType(0)); - N->clearPredicateFns(); - N->setPredicateFns(Predicates); - N->setType(0, getValueType(MemVT)); - return Ext; - } - } - } - - return N; +bool RuleMatcher::hasFirstCondition() const { + if (insnmatchers_empty()) + return false; + InstructionMatcher &Matcher = insnmatchers_front(); + if (!Matcher.predicates_empty()) + return true; + for (auto &OM : Matcher.operands()) + for (auto &OP : OM->predicates()) + if (!isa<InstructionOperandMatcher>(OP)) + return true; + return false; } -void GlobalISelEmitter::fixupPatternTrees(TreePattern *P) { - for (unsigned I = 0, E = P->getNumTrees(); I < E; ++I) { - TreePatternNode *OrigTree = P->getTree(I); - TreePatternNode *NewTree = fixupPatternNode(OrigTree); - if (OrigTree != NewTree) - P->setTree(I, NewTree); - } +const PredicateMatcher &RuleMatcher::getFirstCondition() const { + assert(!insnmatchers_empty() && + "Trying to get a condition from an empty RuleMatcher"); + + InstructionMatcher &Matcher = insnmatchers_front(); + if (!Matcher.predicates_empty()) + return **Matcher.predicates_begin(); + // If there is no more predicate on the instruction itself, look at its + // operands. + for (auto &OM : Matcher.operands()) + for (auto &OP : OM->predicates()) + if (!isa<InstructionOperandMatcher>(OP)) + return *OP; + + llvm_unreachable("Trying to get a condition from an InstructionMatcher with " + "no conditions"); } -std::unique_ptr<PredicateMatcher> RuleMatcher::forgetFirstCondition() { +std::unique_ptr<PredicateMatcher> RuleMatcher::popFirstCondition() { assert(!insnmatchers_empty() && - "Trying to forget something that does not exist"); + "Trying to pop a condition from an empty RuleMatcher"); InstructionMatcher &Matcher = insnmatchers_front(); - std::unique_ptr<PredicateMatcher> Condition; if (!Matcher.predicates_empty()) - Condition = Matcher.predicates_pop_front(); - if (!Condition) { - // If there is no more predicate on the instruction itself, look at its - // operands. - assert(!Matcher.operands_empty() && - "Empty instruction should have been discarded"); - OperandMatcher &OpMatcher = **Matcher.operands_begin(); - assert(!OpMatcher.predicates_empty() && "no operand constraint"); - Condition = OpMatcher.predicates_pop_front(); - // If this operand is free of constraints, rip it off. - if (OpMatcher.predicates_empty()) - Matcher.pop_front(); - } - // Rip the instruction off when it is empty. - if (Matcher.operands_empty() && Matcher.predicates_empty()) - insnmatchers_pop_front(); - return Condition; -} - -bool GroupMatcher::lastConditionMatches( + return Matcher.predicates_pop_front(); + // If there is no more predicate on the instruction itself, look at its + // operands. + for (auto &OM : Matcher.operands()) + for (auto &OP : OM->predicates()) + if (!isa<InstructionOperandMatcher>(OP)) { + std::unique_ptr<PredicateMatcher> Result = std::move(OP); + OM->eraseNullPredicates(); + return Result; + } + + llvm_unreachable("Trying to pop a condition from an InstructionMatcher with " + "no conditions"); +} + +bool GroupMatcher::candidateConditionMatches( const PredicateMatcher &Predicate) const { - const auto &LastCondition = conditions_back(); - return Predicate.isIdentical(*LastCondition); + + if (empty()) { + // Sharing predicates for nested instructions is not supported yet as we + // currently don't hoist the GIM_RecordInsn's properly, therefore we can + // only work on the original root instruction (InsnVarID == 0): + if (Predicate.getInsnVarID() != 0) + return false; + // ... otherwise an empty group can handle any predicate with no specific + // requirements: + return true; + } + + const Matcher &Representative = **Matchers.begin(); + const auto &RepresentativeCondition = Representative.getFirstCondition(); + // ... if not empty, the group can only accomodate matchers with the exact + // same first condition: + return Predicate.isIdentical(RepresentativeCondition); +} + +bool GroupMatcher::addMatcher(Matcher &Candidate) { + if (!Candidate.hasFirstCondition()) + return false; + + const PredicateMatcher &Predicate = Candidate.getFirstCondition(); + if (!candidateConditionMatches(Predicate)) + return false; + + Matchers.push_back(&Candidate); + return true; +} + +void GroupMatcher::finalize() { + assert(Conditions.empty() && "Already finalized?"); + if (empty()) + return; + + Matcher &FirstRule = **Matchers.begin(); + for (;;) { + // All the checks are expected to succeed during the first iteration: + for (const auto &Rule : Matchers) + if (!Rule->hasFirstCondition()) + return; + const auto &FirstCondition = FirstRule.getFirstCondition(); + for (unsigned I = 1, E = Matchers.size(); I < E; ++I) + if (!Matchers[I]->getFirstCondition().isIdentical(FirstCondition)) + return; + + Conditions.push_back(FirstRule.popFirstCondition()); + for (unsigned I = 1, E = Matchers.size(); I < E; ++I) + Matchers[I]->popFirstCondition(); + } } void GroupMatcher::emit(MatchTable &Table) { - unsigned LabelID = Table.allocateLabelID(); - if (!conditions_empty()) { + unsigned LabelID = ~0U; + if (!Conditions.empty()) { + LabelID = Table.allocateLabelID(); Table << MatchTable::Opcode("GIM_Try", +1) << MatchTable::Comment("On fail goto") << MatchTable::JumpTarget(LabelID) << MatchTable::LineBreak; - for (auto &Condition : Conditions) - Condition->emitPredicateOpcodes( - Table, *static_cast<RuleMatcher *>(*Rules.begin())); } - // Emit the conditions. - // Then checks apply the rules. - for (const auto &Rule : Rules) - Rule->emit(Table); - // If we don't succeeded for that block, that means we are not going to select - // this instruction. - if (!conditions_empty()) { - Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak; - Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak + for (auto &Condition : Conditions) + Condition->emitPredicateOpcodes( + Table, *static_cast<RuleMatcher *>(*Matchers.begin())); + + for (const auto &M : Matchers) + M->emit(Table); + + // Exit the group + if (!Conditions.empty()) + Table << MatchTable::Opcode("GIM_Reject", -1) << MatchTable::LineBreak << MatchTable::Label(LabelID); +} + +bool SwitchMatcher::isSupportedPredicateType(const PredicateMatcher &P) { + return isa<InstructionOpcodeMatcher>(P) || isa<LLTOperandMatcher>(P); +} + +bool SwitchMatcher::candidateConditionMatches( + const PredicateMatcher &Predicate) const { + + if (empty()) { + // Sharing predicates for nested instructions is not supported yet as we + // currently don't hoist the GIM_RecordInsn's properly, therefore we can + // only work on the original root instruction (InsnVarID == 0): + if (Predicate.getInsnVarID() != 0) + return false; + // ... while an attempt to add even a root matcher to an empty SwitchMatcher + // could fail as not all the types of conditions are supported: + if (!isSupportedPredicateType(Predicate)) + return false; + // ... or the condition might not have a proper implementation of + // getValue() / isIdenticalDownToValue() yet: + if (!Predicate.hasValue()) + return false; + // ... otherwise an empty Switch can accomodate the condition with no + // further requirements: + return true; + } + + const Matcher &CaseRepresentative = **Matchers.begin(); + const auto &RepresentativeCondition = CaseRepresentative.getFirstCondition(); + // Switch-cases must share the same kind of condition and path to the value it + // checks: + if (!Predicate.isIdenticalDownToValue(RepresentativeCondition)) + return false; + + const auto Value = Predicate.getValue(); + // ... but be unique with respect to the actual value they check: + return Values.count(Value) == 0; +} + +bool SwitchMatcher::addMatcher(Matcher &Candidate) { + if (!Candidate.hasFirstCondition()) + return false; + + const PredicateMatcher &Predicate = Candidate.getFirstCondition(); + if (!candidateConditionMatches(Predicate)) + return false; + const auto Value = Predicate.getValue(); + Values.insert(Value); + + Matchers.push_back(&Candidate); + return true; +} + +void SwitchMatcher::finalize() { + assert(Condition == nullptr && "Already finalized"); + assert(Values.size() == Matchers.size() && "Broken SwitchMatcher"); + if (empty()) + return; + + std::stable_sort(Matchers.begin(), Matchers.end(), + [](const Matcher *L, const Matcher *R) { + return L->getFirstCondition().getValue() < + R->getFirstCondition().getValue(); + }); + Condition = Matchers[0]->popFirstCondition(); + for (unsigned I = 1, E = Values.size(); I < E; ++I) + Matchers[I]->popFirstCondition(); +} + +void SwitchMatcher::emitPredicateSpecificOpcodes(const PredicateMatcher &P, + MatchTable &Table) { + assert(isSupportedPredicateType(P) && "Predicate type is not supported"); + + if (const auto *Condition = dyn_cast<InstructionOpcodeMatcher>(&P)) { + Table << MatchTable::Opcode("GIM_SwitchOpcode") << MatchTable::Comment("MI") + << MatchTable::IntValue(Condition->getInsnVarID()); + return; + } + if (const auto *Condition = dyn_cast<LLTOperandMatcher>(&P)) { + Table << MatchTable::Opcode("GIM_SwitchType") << MatchTable::Comment("MI") + << MatchTable::IntValue(Condition->getInsnVarID()) + << MatchTable::Comment("Op") + << MatchTable::IntValue(Condition->getOpIdx()); + return; + } + + llvm_unreachable("emitPredicateSpecificOpcodes is broken: can not handle a " + "predicate type that is claimed to be supported"); +} + +void SwitchMatcher::emit(MatchTable &Table) { + assert(Values.size() == Matchers.size() && "Broken SwitchMatcher"); + if (empty()) + return; + assert(Condition != nullptr && + "Broken SwitchMatcher, hasn't been finalized?"); + + std::vector<unsigned> LabelIDs(Values.size()); + std::generate(LabelIDs.begin(), LabelIDs.end(), + [&Table]() { return Table.allocateLabelID(); }); + const unsigned Default = Table.allocateLabelID(); + + const int64_t LowerBound = Values.begin()->getRawValue(); + const int64_t UpperBound = Values.rbegin()->getRawValue() + 1; + + emitPredicateSpecificOpcodes(*Condition, Table); + + Table << MatchTable::Comment("[") << MatchTable::IntValue(LowerBound) + << MatchTable::IntValue(UpperBound) << MatchTable::Comment(")") + << MatchTable::Comment("default:") << MatchTable::JumpTarget(Default); + + int64_t J = LowerBound; + auto VI = Values.begin(); + for (unsigned I = 0, E = Values.size(); I < E; ++I) { + auto V = *VI++; + while (J++ < V.getRawValue()) + Table << MatchTable::IntValue(0); + V.turnIntoComment(); + Table << MatchTable::LineBreak << V << MatchTable::JumpTarget(LabelIDs[I]); + } + Table << MatchTable::LineBreak; + + for (unsigned I = 0, E = Values.size(); I < E; ++I) { + Table << MatchTable::Label(LabelIDs[I]); + Matchers[I]->emit(Table); + Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak; } + Table << MatchTable::Label(Default); } -unsigned OperandMatcher::getInsnVarID() const { return Insn.getVarID(); } +unsigned OperandMatcher::getInsnVarID() const { return Insn.getInsnVarID(); } } // end anonymous namespace diff --git a/utils/TableGen/InfoByHwMode.cpp b/utils/TableGen/InfoByHwMode.cpp index d5a181e130a5..7d1f71cc2647 100644 --- a/utils/TableGen/InfoByHwMode.cpp +++ b/utils/TableGen/InfoByHwMode.cpp @@ -84,7 +84,7 @@ void ValueTypeByHwMode::writeToStream(raw_ostream &OS) const { std::vector<const PairType*> Pairs; for (const auto &P : Map) Pairs.push_back(&P); - std::sort(Pairs.begin(), Pairs.end(), deref<std::less<PairType>>()); + llvm::sort(Pairs.begin(), Pairs.end(), deref<std::less<PairType>>()); OS << '{'; for (unsigned i = 0, e = Pairs.size(); i != e; ++i) { @@ -176,7 +176,7 @@ void RegSizeInfoByHwMode::writeToStream(raw_ostream &OS) const { std::vector<const PairType*> Pairs; for (const auto &P : Map) Pairs.push_back(&P); - std::sort(Pairs.begin(), Pairs.end(), deref<std::less<PairType>>()); + llvm::sort(Pairs.begin(), Pairs.end(), deref<std::less<PairType>>()); OS << '{'; for (unsigned i = 0, e = Pairs.size(); i != e; ++i) { diff --git a/utils/TableGen/InfoByHwMode.h b/utils/TableGen/InfoByHwMode.h index b2e217498888..4838198e704d 100644 --- a/utils/TableGen/InfoByHwMode.h +++ b/utils/TableGen/InfoByHwMode.h @@ -16,7 +16,7 @@ #define LLVM_UTILS_TABLEGEN_INFOBYHWMODE_H #include "CodeGenHwModes.h" -#include "llvm/CodeGen/MachineValueType.h" +#include "llvm/Support/MachineValueType.h" #include <map> #include <set> diff --git a/utils/TableGen/InstrDocsEmitter.cpp b/utils/TableGen/InstrDocsEmitter.cpp index fa9ee9569427..65cb28cd17a3 100644 --- a/utils/TableGen/InstrDocsEmitter.cpp +++ b/utils/TableGen/InstrDocsEmitter.cpp @@ -109,6 +109,7 @@ void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) { FLAG(isBarrier) FLAG(isCall) FLAG(isAdd) + FLAG(isTrap) FLAG(canFoldAsLoad) FLAG(mayLoad) //FLAG(mayLoad_Unset) // Deliberately omitted. diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index 379e3245d066..a492daac0d09 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -16,6 +16,7 @@ #include "CodeGenInstruction.h" #include "CodeGenSchedule.h" #include "CodeGenTarget.h" +#include "PredicateExpander.h" #include "SequenceToOffsetTable.h" #include "TableGenBackends.h" #include "llvm/ADT/ArrayRef.h" @@ -59,6 +60,17 @@ private: typedef std::map<std::map<unsigned, unsigned>, std::vector<std::string>> OpNameMapTy; typedef std::map<std::string, unsigned>::iterator StrUintMapIter; + + /// Generate member functions in the target-specific GenInstrInfo class. + /// + /// This method is used to custom expand TIIPredicate definitions. + /// See file llvm/Target/TargetInstPredicates.td for a description of what is + /// a TIIPredicate and how to use it. + void emitTIIHelperMethods(raw_ostream &OS); + + /// Expand TIIPredicate definitions to functions that accept a const MCInst + /// reference. + void emitMCIIHelperMethods(raw_ostream &OS); void emitRecord(const CodeGenInstruction &Inst, unsigned Num, Record *InstrInfo, std::map<std::vector<Record*>, unsigned> &EL, @@ -339,6 +351,74 @@ void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS, OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n\n"; } +void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS) { + RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate"); + if (TIIPredicates.empty()) + return; + + CodeGenTarget &Target = CDP.getTargetInfo(); + const StringRef TargetName = Target.getName(); + formatted_raw_ostream FOS(OS); + + FOS << "#ifdef GET_GENINSTRINFO_MC_DECL\n"; + FOS << "#undef GET_GENINSTRINFO_MC_DECL\n\n"; + + FOS << "namespace llvm {\n"; + FOS << "class MCInst;\n\n"; + + FOS << "namespace " << TargetName << "_MC {\n\n"; + + for (const Record *Rec : TIIPredicates) { + FOS << "bool " << Rec->getValueAsString("FunctionName") + << "(const MCInst &MI);\n"; + } + + FOS << "\n} // end " << TargetName << "_MC namespace\n"; + FOS << "} // end llvm namespace\n\n"; + + FOS << "#endif // GET_GENINSTRINFO_MC_DECL\n\n"; + + FOS << "#ifdef GET_GENINSTRINFO_MC_HELPERS\n"; + FOS << "#undef GET_GENINSTRINFO_MC_HELPERS\n\n"; + + FOS << "namespace llvm {\n"; + FOS << "namespace " << TargetName << "_MC {\n\n"; + + PredicateExpander PE; + PE.setExpandForMC(true); + for (const Record *Rec : TIIPredicates) { + FOS << "bool " << Rec->getValueAsString("FunctionName"); + FOS << "(const MCInst &MI) {\n"; + FOS << " return "; + PE.expandPredicate(FOS, Rec->getValueAsDef("Pred")); + FOS << ";\n}\n"; + } + + FOS << "\n} // end " << TargetName << "_MC namespace\n"; + FOS << "} // end llvm namespace\n\n"; + + FOS << "#endif // GET_GENISTRINFO_MC_HELPERS\n"; +} + +void InstrInfoEmitter::emitTIIHelperMethods(raw_ostream &OS) { + RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate"); + if (TIIPredicates.empty()) + return; + + formatted_raw_ostream FOS(OS); + PredicateExpander PE; + PE.setExpandForMC(false); + PE.setIndentLevel(2); + + for (const Record *Rec : TIIPredicates) { + FOS << "\n static bool " << Rec->getValueAsString("FunctionName"); + FOS << "(const MachineInstr &MI) {\n"; + FOS << " return "; + PE.expandPredicate(FOS, Rec->getValueAsDef("Pred")); + FOS << ";\n }\n"; + } +} + //===----------------------------------------------------------------------===// // Main Output. //===----------------------------------------------------------------------===// @@ -435,9 +515,11 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "struct " << ClassName << " : public TargetInstrInfo {\n" << " explicit " << ClassName << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1, int ReturnOpcode = -1);\n" - << " ~" << ClassName << "() override = default;\n" - << "};\n"; - OS << "} // end llvm namespace\n"; + << " ~" << ClassName << "() override = default;\n"; + + emitTIIHelperMethods(OS); + + OS << "\n};\n} // end llvm namespace\n"; OS << "#endif // GET_INSTRINFO_HEADER\n\n"; @@ -461,6 +543,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) { emitOperandNameMappings(OS, Target, NumberedInstructions); emitOperandTypesEnum(OS, Target); + + emitMCIIHelperMethods(OS); } void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, @@ -480,6 +564,8 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, << Inst.TheDef->getValueAsInt("Size") << ",\t" << SchedModels.getSchedClassIdx(Inst) << ",\t0"; + CodeGenTarget &Target = CDP.getTargetInfo(); + // Emit all of the target independent flags... if (Inst.isPseudo) OS << "|(1ULL<<MCID::Pseudo)"; if (Inst.isReturn) OS << "|(1ULL<<MCID::Return)"; @@ -487,8 +573,10 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, if (Inst.isIndirectBranch) OS << "|(1ULL<<MCID::IndirectBranch)"; if (Inst.isCompare) OS << "|(1ULL<<MCID::Compare)"; if (Inst.isMoveImm) OS << "|(1ULL<<MCID::MoveImm)"; + if (Inst.isMoveReg) OS << "|(1ULL<<MCID::MoveReg)"; if (Inst.isBitcast) OS << "|(1ULL<<MCID::Bitcast)"; if (Inst.isAdd) OS << "|(1ULL<<MCID::Add)"; + if (Inst.isTrap) OS << "|(1ULL<<MCID::Trap)"; if (Inst.isSelect) OS << "|(1ULL<<MCID::Select)"; if (Inst.isBarrier) OS << "|(1ULL<<MCID::Barrier)"; if (Inst.hasDelaySlot) OS << "|(1ULL<<MCID::DelaySlot)"; @@ -508,8 +596,10 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, if (Inst.Operands.isVariadic)OS << "|(1ULL<<MCID::Variadic)"; if (Inst.hasSideEffects) OS << "|(1ULL<<MCID::UnmodeledSideEffects)"; if (Inst.isAsCheapAsAMove) OS << "|(1ULL<<MCID::CheapAsAMove)"; - if (Inst.hasExtraSrcRegAllocReq) OS << "|(1ULL<<MCID::ExtraSrcRegAllocReq)"; - if (Inst.hasExtraDefRegAllocReq) OS << "|(1ULL<<MCID::ExtraDefRegAllocReq)"; + if (!Target.getAllowRegisterRenaming() || Inst.hasExtraSrcRegAllocReq) + OS << "|(1ULL<<MCID::ExtraSrcRegAllocReq)"; + if (!Target.getAllowRegisterRenaming() || Inst.hasExtraDefRegAllocReq) + OS << "|(1ULL<<MCID::ExtraDefRegAllocReq)"; if (Inst.isRegSequence) OS << "|(1ULL<<MCID::RegSequence)"; if (Inst.isExtractSubreg) OS << "|(1ULL<<MCID::ExtractSubreg)"; if (Inst.isInsertSubreg) OS << "|(1ULL<<MCID::InsertSubreg)"; @@ -550,7 +640,6 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, else OS << "OperandInfo" << OpInfo.find(OperandInfo)->second; - CodeGenTarget &Target = CDP.getTargetInfo(); if (Inst.HasComplexDeprecationPredicate) // Emit a function pointer to the complex predicate method. OS << ", -1 " diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index ba793ad9b938..06e44e3b57c1 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -34,7 +34,7 @@ public: IntrinsicEmitter(RecordKeeper &R, bool T) : Records(R), TargetOnly(T) {} - void run(raw_ostream &OS); + void run(raw_ostream &OS, bool Enums); void EmitPrefix(raw_ostream &OS); @@ -56,7 +56,7 @@ public: // IntrinsicEmitter Implementation //===----------------------------------------------------------------------===// -void IntrinsicEmitter::run(raw_ostream &OS) { +void IntrinsicEmitter::run(raw_ostream &OS, bool Enums) { emitSourceFileHeader("Intrinsic Function Source Fragment", OS); CodeGenIntrinsicTable Ints(Records, TargetOnly); @@ -66,29 +66,31 @@ void IntrinsicEmitter::run(raw_ostream &OS) { EmitPrefix(OS); - // Emit the enum information. - EmitEnumInfo(Ints, OS); - - // Emit the target metadata. - EmitTargetInfo(Ints, OS); + if (Enums) { + // Emit the enum information. + EmitEnumInfo(Ints, OS); + } else { + // Emit the target metadata. + EmitTargetInfo(Ints, OS); - // Emit the intrinsic ID -> name table. - EmitIntrinsicToNameTable(Ints, OS); + // Emit the intrinsic ID -> name table. + EmitIntrinsicToNameTable(Ints, OS); - // Emit the intrinsic ID -> overload table. - EmitIntrinsicToOverloadTable(Ints, OS); + // Emit the intrinsic ID -> overload table. + EmitIntrinsicToOverloadTable(Ints, OS); - // Emit the intrinsic declaration generator. - EmitGenerator(Ints, OS); + // Emit the intrinsic declaration generator. + EmitGenerator(Ints, OS); - // Emit the intrinsic parameter attributes. - EmitAttributes(Ints, OS); + // Emit the intrinsic parameter attributes. + EmitAttributes(Ints, OS); - // Emit code to translate GCC builtins into LLVM intrinsics. - EmitIntrinsicToBuiltinMap(Ints, true, OS); + // Emit code to translate GCC builtins into LLVM intrinsics. + EmitIntrinsicToBuiltinMap(Ints, true, OS); - // Emit code to translate MS builtins into LLVM intrinsics. - EmitIntrinsicToBuiltinMap(Ints, false, OS); + // Emit code to translate MS builtins into LLVM intrinsics. + EmitIntrinsicToBuiltinMap(Ints, false, OS); + } EmitSuffix(OS); } @@ -172,7 +174,7 @@ void IntrinsicEmitter::EmitIntrinsicToOverloadTable( } -// NOTE: This must be kept in synch with the copy in lib/VMCore/Function.cpp! +// NOTE: This must be kept in synch with the copy in lib/IR/Function.cpp! enum IIT_Info { // Common values should be encoded with 0-15. IIT_Done = 0, @@ -217,7 +219,8 @@ enum IIT_Info { IIT_V1024 = 37, IIT_STRUCT6 = 38, IIT_STRUCT7 = 39, - IIT_STRUCT8 = 40 + IIT_STRUCT8 = 40, + IIT_F128 = 41 }; static void EncodeFixedValueType(MVT::SimpleValueType VT, @@ -240,6 +243,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT, case MVT::f16: return Sig.push_back(IIT_F16); case MVT::f32: return Sig.push_back(IIT_F32); case MVT::f64: return Sig.push_back(IIT_F64); + case MVT::f128: return Sig.push_back(IIT_F128); case MVT::token: return Sig.push_back(IIT_TOKEN); case MVT::Metadata: return Sig.push_back(IIT_METADATA); case MVT::x86mmx: return Sig.push_back(IIT_MMX); @@ -839,6 +843,12 @@ void IntrinsicEmitter::EmitIntrinsicToBuiltinMap( OS << "#endif\n\n"; } -void llvm::EmitIntrinsics(RecordKeeper &RK, raw_ostream &OS, bool TargetOnly) { - IntrinsicEmitter(RK, TargetOnly).run(OS); +void llvm::EmitIntrinsicEnums(RecordKeeper &RK, raw_ostream &OS, + bool TargetOnly) { + IntrinsicEmitter(RK, TargetOnly).run(OS, /*Enums=*/true); +} + +void llvm::EmitIntrinsicImpl(RecordKeeper &RK, raw_ostream &OS, + bool TargetOnly) { + IntrinsicEmitter(RK, TargetOnly).run(OS, /*Enums=*/false); } diff --git a/utils/TableGen/LLVMBuild.txt b/utils/TableGen/LLVMBuild.txt index b0081eb588d1..66387cfa0d1a 100644 --- a/utils/TableGen/LLVMBuild.txt +++ b/utils/TableGen/LLVMBuild.txt @@ -19,4 +19,4 @@ type = BuildTool name = tblgen parent = BuildTools -required_libraries = Support TableGen +required_libraries = Support TableGen MC diff --git a/utils/TableGen/PredicateExpander.cpp b/utils/TableGen/PredicateExpander.cpp new file mode 100644 index 000000000000..68eb32794a02 --- /dev/null +++ b/utils/TableGen/PredicateExpander.cpp @@ -0,0 +1,262 @@ +//===--------------------- PredicateExpander.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// Functionalities used by the Tablegen backends to expand machine predicates. +// +//===----------------------------------------------------------------------===// + +#include "PredicateExpander.h" + +namespace llvm { + +void PredicateExpander::expandTrue(formatted_raw_ostream &OS) { OS << "true"; } +void PredicateExpander::expandFalse(formatted_raw_ostream &OS) { + OS << "false"; +} + +void PredicateExpander::expandCheckImmOperand(formatted_raw_ostream &OS, + int OpIndex, int ImmVal) { + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getImm() " << (shouldNegate() ? "!= " : "== ") << ImmVal; +} + +void PredicateExpander::expandCheckImmOperand(formatted_raw_ostream &OS, + int OpIndex, StringRef ImmVal) { + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getImm() " << (shouldNegate() ? "!= " : "== ") << ImmVal; +} + +void PredicateExpander::expandCheckRegOperand(formatted_raw_ostream &OS, + int OpIndex, const Record *Reg) { + assert(Reg->isSubClassOf("Register") && "Expected a register Record!"); + + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getReg() " << (shouldNegate() ? "!= " : "== "); + const StringRef Str = Reg->getValueAsString("Namespace"); + if (!Str.empty()) + OS << Str << "::"; + OS << Reg->getName(); +} + +void PredicateExpander::expandCheckInvalidRegOperand(formatted_raw_ostream &OS, + int OpIndex) { + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getReg() " << (shouldNegate() ? "!= " : "== ") << "0"; +} + +void PredicateExpander::expandCheckSameRegOperand(formatted_raw_ostream &OS, + int First, int Second) { + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << First + << ").getReg() " << (shouldNegate() ? "!=" : "==") << " MI" + << (isByRef() ? "." : "->") << "getOperand(" << Second << ").getReg()"; +} + +void PredicateExpander::expandCheckNumOperands(formatted_raw_ostream &OS, + int NumOps) { + OS << "MI" << (isByRef() ? "." : "->") << "getNumOperands() " + << (shouldNegate() ? "!= " : "== ") << NumOps; +} + +void PredicateExpander::expandCheckOpcode(formatted_raw_ostream &OS, + const Record *Inst) { + OS << "MI" << (isByRef() ? "." : "->") << "getOpcode() " + << (shouldNegate() ? "!= " : "== ") << Inst->getValueAsString("Namespace") + << "::" << Inst->getName(); +} + +void PredicateExpander::expandCheckOpcode(formatted_raw_ostream &OS, + const RecVec &Opcodes) { + assert(!Opcodes.empty() && "Expected at least one opcode to check!"); + bool First = true; + + if (Opcodes.size() == 1) { + OS << "( "; + expandCheckOpcode(OS, Opcodes[0]); + OS << " )"; + return; + } + + OS << '('; + increaseIndentLevel(); + for (const Record *Rec : Opcodes) { + OS << '\n'; + OS.PadToColumn(getIndentLevel() * 2); + if (!First) + OS << (shouldNegate() ? "&& " : "|| "); + + expandCheckOpcode(OS, Rec); + First = false; + } + + OS << '\n'; + decreaseIndentLevel(); + OS.PadToColumn(getIndentLevel() * 2); + OS << ')'; +} + +void PredicateExpander::expandCheckPseudo(formatted_raw_ostream &OS, + const RecVec &Opcodes) { + if (shouldExpandForMC()) + expandFalse(OS); + else + expandCheckOpcode(OS, Opcodes); +} + +void PredicateExpander::expandPredicateSequence(formatted_raw_ostream &OS, + const RecVec &Sequence, + bool IsCheckAll) { + assert(!Sequence.empty() && "Found an invalid empty predicate set!"); + if (Sequence.size() == 1) + return expandPredicate(OS, Sequence[0]); + + // Okay, there is more than one predicate in the set. + bool First = true; + OS << (shouldNegate() ? "!(" : "("); + increaseIndentLevel(); + + bool OldValue = shouldNegate(); + setNegatePredicate(false); + for (const Record *Rec : Sequence) { + OS << '\n'; + OS.PadToColumn(getIndentLevel() * 2); + if (!First) + OS << (IsCheckAll ? "&& " : "|| "); + expandPredicate(OS, Rec); + First = false; + } + OS << '\n'; + decreaseIndentLevel(); + OS.PadToColumn(getIndentLevel() * 2); + OS << ')'; + setNegatePredicate(OldValue); +} + +void PredicateExpander::expandTIIFunctionCall(formatted_raw_ostream &OS, + StringRef TargetName, + StringRef MethodName) { + OS << (shouldNegate() ? "!" : ""); + if (shouldExpandForMC()) + OS << TargetName << "_MC::"; + else + OS << TargetName << "Gen" + << "InstrInfo::"; + OS << MethodName << (isByRef() ? "(MI)" : "(*MI)"); +} + +void PredicateExpander::expandCheckIsRegOperand(formatted_raw_ostream &OS, + int OpIndex) { + OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") + << "getOperand(" << OpIndex << ").isReg() "; +} + +void PredicateExpander::expandCheckIsImmOperand(formatted_raw_ostream &OS, + int OpIndex) { + OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") + << "getOperand(" << OpIndex << ").isImm() "; +} + +void PredicateExpander::expandCheckFunctionPredicate(formatted_raw_ostream &OS, + StringRef MCInstFn, + StringRef MachineInstrFn) { + OS << (shouldExpandForMC() ? MCInstFn : MachineInstrFn) + << (isByRef() ? "(MI)" : "(*MI)"); +} + +void PredicateExpander::expandCheckNonPortable(formatted_raw_ostream &OS, + StringRef Code) { + if (shouldExpandForMC()) + return expandFalse(OS); + + OS << '(' << Code << ')'; +} + +void PredicateExpander::expandPredicate(formatted_raw_ostream &OS, + const Record *Rec) { + OS.flush(); + unsigned ColNum = getIndentLevel() * 2; + if (OS.getColumn() < ColNum) + OS.PadToColumn(ColNum); + + if (Rec->isSubClassOf("MCTrue")) { + if (shouldNegate()) + return expandFalse(OS); + return expandTrue(OS); + } + + if (Rec->isSubClassOf("MCFalse")) { + if (shouldNegate()) + return expandTrue(OS); + return expandFalse(OS); + } + + if (Rec->isSubClassOf("CheckNot")) { + flipNegatePredicate(); + expandPredicate(OS, Rec->getValueAsDef("Pred")); + flipNegatePredicate(); + return; + } + + if (Rec->isSubClassOf("CheckIsRegOperand")) + return expandCheckIsRegOperand(OS, Rec->getValueAsInt("OpIndex")); + + if (Rec->isSubClassOf("CheckIsImmOperand")) + return expandCheckIsImmOperand(OS, Rec->getValueAsInt("OpIndex")); + + if (Rec->isSubClassOf("CheckRegOperand")) + return expandCheckRegOperand(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsDef("Reg")); + + if (Rec->isSubClassOf("CheckInvalidRegOperand")) + return expandCheckInvalidRegOperand(OS, Rec->getValueAsInt("OpIndex")); + + if (Rec->isSubClassOf("CheckImmOperand")) + return expandCheckImmOperand(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsInt("ImmVal")); + + if (Rec->isSubClassOf("CheckImmOperand_s")) + return expandCheckImmOperand(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsString("ImmVal")); + + if (Rec->isSubClassOf("CheckSameRegOperand")) + return expandCheckSameRegOperand(OS, Rec->getValueAsInt("FirstIndex"), + Rec->getValueAsInt("SecondIndex")); + + if (Rec->isSubClassOf("CheckNumOperands")) + return expandCheckNumOperands(OS, Rec->getValueAsInt("NumOps")); + + if (Rec->isSubClassOf("CheckPseudo")) + return expandCheckPseudo(OS, Rec->getValueAsListOfDefs("ValidOpcodes")); + + if (Rec->isSubClassOf("CheckOpcode")) + return expandCheckOpcode(OS, Rec->getValueAsListOfDefs("ValidOpcodes")); + + if (Rec->isSubClassOf("CheckAll")) + return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"), + /* AllOf */ true); + + if (Rec->isSubClassOf("CheckAny")) + return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"), + /* AllOf */ false); + + if (Rec->isSubClassOf("CheckFunctionPredicate")) + return expandCheckFunctionPredicate( + OS, Rec->getValueAsString("MCInstFnName"), + Rec->getValueAsString("MachineInstrFnName")); + + if (Rec->isSubClassOf("CheckNonPortable")) + return expandCheckNonPortable(OS, Rec->getValueAsString("CodeBlock")); + + if (Rec->isSubClassOf("TIIPredicate")) + return expandTIIFunctionCall(OS, Rec->getValueAsString("TargetName"), + Rec->getValueAsString("FunctionName")); + + llvm_unreachable("No known rules to expand this MCInstPredicate"); +} + +} // namespace llvm diff --git a/utils/TableGen/PredicateExpander.h b/utils/TableGen/PredicateExpander.h new file mode 100644 index 000000000000..398b376f7a83 --- /dev/null +++ b/utils/TableGen/PredicateExpander.h @@ -0,0 +1,86 @@ +//===--------------------- PredicateExpander.h ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// Functionalities used by the Tablegen backends to expand machine predicates. +/// +/// See file llvm/Target/TargetInstrPredicate.td for a full list and description +/// of all the supported MCInstPredicate classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_PREDICATEEXPANDER_H +#define LLVM_UTILS_TABLEGEN_PREDICATEEXPANDER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/TableGen/Record.h" + +namespace llvm { + +class formatted_raw_ostream; + +class PredicateExpander { + bool EmitCallsByRef; + bool NegatePredicate; + bool ExpandForMC; + unsigned IndentLevel; + + PredicateExpander(const PredicateExpander &) = delete; + PredicateExpander &operator=(const PredicateExpander &) = delete; + +public: + PredicateExpander() + : EmitCallsByRef(true), NegatePredicate(false), ExpandForMC(false), + IndentLevel(1U) {} + bool isByRef() const { return EmitCallsByRef; } + bool shouldNegate() const { return NegatePredicate; } + bool shouldExpandForMC() const { return ExpandForMC; } + unsigned getIndentLevel() const { return IndentLevel; } + + void setByRef(bool Value) { EmitCallsByRef = Value; } + void flipNegatePredicate() { NegatePredicate = !NegatePredicate; } + void setNegatePredicate(bool Value) { NegatePredicate = Value; } + void setExpandForMC(bool Value) { ExpandForMC = Value; } + void increaseIndentLevel() { ++IndentLevel; } + void decreaseIndentLevel() { --IndentLevel; } + void setIndentLevel(unsigned Level) { IndentLevel = Level; } + + using RecVec = std::vector<Record *>; + void expandTrue(formatted_raw_ostream &OS); + void expandFalse(formatted_raw_ostream &OS); + void expandCheckImmOperand(formatted_raw_ostream &OS, int OpIndex, + int ImmVal); + void expandCheckImmOperand(formatted_raw_ostream &OS, int OpIndex, + StringRef ImmVal); + void expandCheckRegOperand(formatted_raw_ostream &OS, int OpIndex, + const Record *Reg); + void expandCheckSameRegOperand(formatted_raw_ostream &OS, int First, + int Second); + void expandCheckNumOperands(formatted_raw_ostream &OS, int NumOps); + void expandCheckOpcode(formatted_raw_ostream &OS, const Record *Inst); + + void expandCheckPseudo(formatted_raw_ostream &OS, const RecVec &Opcodes); + void expandCheckOpcode(formatted_raw_ostream &OS, const RecVec &Opcodes); + void expandPredicateSequence(formatted_raw_ostream &OS, + const RecVec &Sequence, bool IsCheckAll); + void expandTIIFunctionCall(formatted_raw_ostream &OS, StringRef TargetName, + StringRef MethodName); + void expandCheckIsRegOperand(formatted_raw_ostream &OS, int OpIndex); + void expandCheckIsImmOperand(formatted_raw_ostream &OS, int OpIndex); + void expandCheckInvalidRegOperand(formatted_raw_ostream &OS, int OpIndex); + void expandCheckFunctionPredicate(formatted_raw_ostream &OS, + StringRef MCInstFn, + StringRef MachineInstrFn); + void expandCheckNonPortable(formatted_raw_ostream &OS, StringRef CodeBlock); + void expandPredicate(formatted_raw_ostream &OS, const Record *Rec); +}; + +} // namespace llvm + +#endif diff --git a/utils/TableGen/PseudoLoweringEmitter.cpp b/utils/TableGen/PseudoLoweringEmitter.cpp index 63bdd36235a0..a363015730f3 100644 --- a/utils/TableGen/PseudoLoweringEmitter.cpp +++ b/utils/TableGen/PseudoLoweringEmitter.cpp @@ -120,13 +120,13 @@ addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn, } void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) { - DEBUG(dbgs() << "Pseudo definition: " << Rec->getName() << "\n"); + LLVM_DEBUG(dbgs() << "Pseudo definition: " << Rec->getName() << "\n"); // Validate that the result pattern has the corrent number and types // of arguments for the instruction it references. DagInit *Dag = Rec->getValueAsDag("ResultInst"); assert(Dag && "Missing result instruction in pseudo expansion!"); - DEBUG(dbgs() << " Result: " << *Dag << "\n"); + LLVM_DEBUG(dbgs() << " Result: " << *Dag << "\n"); DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator()); if (!OpDef) @@ -170,7 +170,7 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) { for (unsigned i = 0, e = SourceInsn.Operands.size(); i != e; ++i) SourceOperands[SourceInsn.Operands[i].Name] = i; - DEBUG(dbgs() << " Operand mapping:\n"); + LLVM_DEBUG(dbgs() << " Operand mapping:\n"); for (unsigned i = 0, e = Insn.Operands.size(); i != e; ++i) { // We've already handled constant values. Just map instruction operands // here. @@ -188,7 +188,8 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) { OperandMap[Insn.Operands[i].MIOperandNo + I].Data.Operand = SourceOp->getValue(); - DEBUG(dbgs() << " " << SourceOp->getValue() << " ==> " << i << "\n"); + LLVM_DEBUG(dbgs() << " " << SourceOp->getValue() << " ==> " << i + << "\n"); } Expansions.push_back(PseudoExpansion(SourceInsn, Insn, OperandMap)); diff --git a/utils/TableGen/RISCVCompressInstEmitter.cpp b/utils/TableGen/RISCVCompressInstEmitter.cpp new file mode 100644 index 000000000000..e03663b40f8a --- /dev/null +++ b/utils/TableGen/RISCVCompressInstEmitter.cpp @@ -0,0 +1,810 @@ +//===- RISCVCompressInstEmitter.cpp - Generator for RISCV Compression -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// RISCVCompressInstEmitter implements a tablegen-driven CompressPat based +// RISCV Instruction Compression mechanism. +// +//===--------------------------------------------------------------===// +// +// RISCVCompressInstEmitter implements a tablegen-driven CompressPat Instruction +// Compression mechanism for generating RISCV compressed instructions +// (C ISA Extension) from the expanded instruction form. + +// This tablegen backend processes CompressPat declarations in a +// td file and generates all the required checks to validate the pattern +// declarations; validate the input and output operands to generate the correct +// compressed instructions. The checks include validating different types of +// operands; register operands, immediate operands, fixed register and fixed +// immediate inputs. +// +// Example: +// class CompressPat<dag input, dag output> { +// dag Input = input; +// dag Output = output; +// list<Predicate> Predicates = []; +// } +// +// let Predicates = [HasStdExtC] in { +// def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs1, GPRNoX0:$rs2), +// (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>; +// } +// +// The result is an auto-generated header file +// 'RISCVGenCompressInstEmitter.inc' which exports two functions for +// compressing/uncompressing MCInst instructions, plus +// some helper functions: +// +// bool compressInst(MCInst& OutInst, const MCInst &MI, +// const MCSubtargetInfo &STI, +// MCContext &Context); +// +// bool uncompressInst(MCInst& OutInst, const MCInst &MI, +// const MCRegisterInfo &MRI, +// const MCSubtargetInfo &STI); +// +// The clients that include this auto-generated header file and +// invoke these functions can compress an instruction before emitting +// it in the target-specific ASM or ELF streamer or can uncompress +// an instruction before printing it when the expanded instruction +// format aliases is favored. + +//===----------------------------------------------------------------------===// + +#include "CodeGenInstruction.h" +#include "CodeGenTarget.h" +#include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <vector> +using namespace llvm; + +#define DEBUG_TYPE "compress-inst-emitter" + +namespace { +class RISCVCompressInstEmitter { + struct OpData { + enum MapKind { Operand, Imm, Reg }; + MapKind Kind; + union { + unsigned Operand; // Operand number mapped to. + uint64_t Imm; // Integer immediate value. + Record *Reg; // Physical register. + } Data; + int TiedOpIdx = -1; // Tied operand index within the instruction. + }; + struct CompressPat { + CodeGenInstruction Source; // The source instruction definition. + CodeGenInstruction Dest; // The destination instruction to transform to. + std::vector<Record *> + PatReqFeatures; // Required target features to enable pattern. + IndexedMap<OpData> + SourceOperandMap; // Maps operands in the Source Instruction to + // the corresponding Dest instruction operand. + IndexedMap<OpData> + DestOperandMap; // Maps operands in the Dest Instruction + // to the corresponding Source instruction operand. + CompressPat(CodeGenInstruction &S, CodeGenInstruction &D, + std::vector<Record *> RF, IndexedMap<OpData> &SourceMap, + IndexedMap<OpData> &DestMap) + : Source(S), Dest(D), PatReqFeatures(RF), SourceOperandMap(SourceMap), + DestOperandMap(DestMap) {} + }; + + RecordKeeper &Records; + CodeGenTarget Target; + SmallVector<CompressPat, 4> CompressPatterns; + + void addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Inst, + IndexedMap<OpData> &OperandMap, bool IsSourceInst); + void evaluateCompressPat(Record *Compress); + void emitCompressInstEmitter(raw_ostream &o, bool Compress); + bool validateTypes(Record *SubType, Record *Type, bool IsSourceInst); + bool validateRegister(Record *Reg, Record *RegClass); + void createDagOperandMapping(Record *Rec, StringMap<unsigned> &SourceOperands, + StringMap<unsigned> &DestOperands, + DagInit *SourceDag, DagInit *DestDag, + IndexedMap<OpData> &SourceOperandMap); + + void createInstOperandMapping(Record *Rec, DagInit *SourceDag, + DagInit *DestDag, + IndexedMap<OpData> &SourceOperandMap, + IndexedMap<OpData> &DestOperandMap, + StringMap<unsigned> &SourceOperands, + CodeGenInstruction &DestInst); + +public: + RISCVCompressInstEmitter(RecordKeeper &R) : Records(R), Target(R) {} + + void run(raw_ostream &o); +}; +} // End anonymous namespace. + +bool RISCVCompressInstEmitter::validateRegister(Record *Reg, Record *RegClass) { + assert(Reg->isSubClassOf("Register") && "Reg record should be a Register\n"); + assert(RegClass->isSubClassOf("RegisterClass") && "RegClass record should be" + " a RegisterClass\n"); + CodeGenRegisterClass RC = Target.getRegisterClass(RegClass); + const CodeGenRegister *R = Target.getRegisterByName(Reg->getName().lower()); + assert((R != nullptr) && + ("Register" + Reg->getName().str() + " not defined!!\n").c_str()); + return RC.contains(R); +} + +bool RISCVCompressInstEmitter::validateTypes(Record *DagOpType, + Record *InstOpType, + bool IsSourceInst) { + if (DagOpType == InstOpType) + return true; + // Only source instruction operands are allowed to not match Input Dag + // operands. + if (!IsSourceInst) + return false; + + if (DagOpType->isSubClassOf("RegisterClass") && + InstOpType->isSubClassOf("RegisterClass")) { + CodeGenRegisterClass RC = Target.getRegisterClass(InstOpType); + CodeGenRegisterClass SubRC = Target.getRegisterClass(DagOpType); + return RC.hasSubClass(&SubRC); + } + + // At this point either or both types are not registers, reject the pattern. + if (DagOpType->isSubClassOf("RegisterClass") || + InstOpType->isSubClassOf("RegisterClass")) + return false; + + // Let further validation happen when compress()/uncompress() functions are + // invoked. + LLVM_DEBUG(dbgs() << (IsSourceInst ? "Input" : "Output") + << " Dag Operand Type: '" << DagOpType->getName() + << "' and " + << "Instruction Operand Type: '" << InstOpType->getName() + << "' can't be checked at pattern validation time!\n"); + return true; +} + +/// The patterns in the Dag contain different types of operands: +/// Register operands, e.g.: GPRC:$rs1; Fixed registers, e.g: X1; Immediate +/// operands, e.g.: simm6:$imm; Fixed immediate operands, e.g.: 0. This function +/// maps Dag operands to its corresponding instruction operands. For register +/// operands and fixed registers it expects the Dag operand type to be contained +/// in the instantiated instruction operand type. For immediate operands and +/// immediates no validation checks are enforced at pattern validation time. +void RISCVCompressInstEmitter::addDagOperandMapping( + Record *Rec, DagInit *Dag, CodeGenInstruction &Inst, + IndexedMap<OpData> &OperandMap, bool IsSourceInst) { + // TiedCount keeps track of the number of operands skipped in Inst + // operands list to get to the corresponding Dag operand. This is + // necessary because the number of operands in Inst might be greater + // than number of operands in the Dag due to how tied operands + // are represented. + unsigned TiedCount = 0; + for (unsigned i = 0, e = Inst.Operands.size(); i != e; ++i) { + int TiedOpIdx = Inst.Operands[i].getTiedRegister(); + if (-1 != TiedOpIdx) { + // Set the entry in OperandMap for the tied operand we're skipping. + OperandMap[i].Kind = OperandMap[TiedOpIdx].Kind; + OperandMap[i].Data = OperandMap[TiedOpIdx].Data; + TiedCount++; + continue; + } + if (DefInit *DI = dyn_cast<DefInit>(Dag->getArg(i - TiedCount))) { + if (DI->getDef()->isSubClassOf("Register")) { + // Check if the fixed register belongs to the Register class. + if (!validateRegister(DI->getDef(), Inst.Operands[i].Rec)) + PrintFatalError(Rec->getLoc(), + "Error in Dag '" + Dag->getAsString() + + "'Register: '" + DI->getDef()->getName() + + "' is not in register class '" + + Inst.Operands[i].Rec->getName() + "'"); + OperandMap[i].Kind = OpData::Reg; + OperandMap[i].Data.Reg = DI->getDef(); + continue; + } + // Validate that Dag operand type matches the type defined in the + // corresponding instruction. Operands in the input Dag pattern are + // allowed to be a subclass of the type specified in corresponding + // instruction operand instead of being an exact match. + if (!validateTypes(DI->getDef(), Inst.Operands[i].Rec, IsSourceInst)) + PrintFatalError(Rec->getLoc(), + "Error in Dag '" + Dag->getAsString() + "'. Operand '" + + Dag->getArgNameStr(i - TiedCount) + "' has type '" + + DI->getDef()->getName() + + "' which does not match the type '" + + Inst.Operands[i].Rec->getName() + + "' in the corresponding instruction operand!"); + + OperandMap[i].Kind = OpData::Operand; + } else if (IntInit *II = dyn_cast<IntInit>(Dag->getArg(i - TiedCount))) { + // Validate that corresponding instruction operand expects an immediate. + if (Inst.Operands[i].Rec->isSubClassOf("RegisterClass")) + PrintFatalError( + Rec->getLoc(), + ("Error in Dag '" + Dag->getAsString() + "' Found immediate: '" + + II->getAsString() + + "' but corresponding instruction operand expected a register!")); + // No pattern validation check possible for values of fixed immediate. + OperandMap[i].Kind = OpData::Imm; + OperandMap[i].Data.Imm = II->getValue(); + LLVM_DEBUG( + dbgs() << " Found immediate '" << II->getValue() << "' at " + << (IsSourceInst ? "input " : "output ") + << "Dag. No validation time check possible for values of " + "fixed immediate.\n"); + } else + llvm_unreachable("Unhandled CompressPat argument type!"); + } +} + +// Verify the Dag operand count is enough to build an instruction. +static bool verifyDagOpCount(CodeGenInstruction &Inst, DagInit *Dag, + bool IsSource) { + if (Dag->getNumArgs() == Inst.Operands.size()) + return true; + // Source instructions are non compressed instructions and don't have tied + // operands. + if (IsSource) + PrintFatalError("Input operands for Inst '" + Inst.TheDef->getName() + + "' and input Dag operand count mismatch"); + // The Dag can't have more arguments than the Instruction. + if (Dag->getNumArgs() > Inst.Operands.size()) + PrintFatalError("Inst '" + Inst.TheDef->getName() + + "' and Dag operand count mismatch"); + + // The Instruction might have tied operands so the Dag might have + // a fewer operand count. + unsigned RealCount = Inst.Operands.size(); + for (unsigned i = 0; i < Inst.Operands.size(); i++) + if (Inst.Operands[i].getTiedRegister() != -1) + --RealCount; + + if (Dag->getNumArgs() != RealCount) + PrintFatalError("Inst '" + Inst.TheDef->getName() + + "' and Dag operand count mismatch"); + return true; +} + +static bool validateArgsTypes(Init *Arg1, Init *Arg2) { + DefInit *Type1 = dyn_cast<DefInit>(Arg1); + DefInit *Type2 = dyn_cast<DefInit>(Arg2); + assert(Type1 && ("Arg1 type not found\n")); + assert(Type2 && ("Arg2 type not found\n")); + return Type1->getDef() == Type2->getDef(); +} + +// Creates a mapping between the operand name in the Dag (e.g. $rs1) and +// its index in the list of Dag operands and checks that operands with the same +// name have the same types. For example in 'C_ADD $rs1, $rs2' we generate the +// mapping $rs1 --> 0, $rs2 ---> 1. If the operand appears twice in the (tied) +// same Dag we use the last occurrence for indexing. +void RISCVCompressInstEmitter::createDagOperandMapping( + Record *Rec, StringMap<unsigned> &SourceOperands, + StringMap<unsigned> &DestOperands, DagInit *SourceDag, DagInit *DestDag, + IndexedMap<OpData> &SourceOperandMap) { + for (unsigned i = 0; i < DestDag->getNumArgs(); ++i) { + // Skip fixed immediates and registers, they were handled in + // addDagOperandMapping. + if ("" == DestDag->getArgNameStr(i)) + continue; + DestOperands[DestDag->getArgNameStr(i)] = i; + } + + for (unsigned i = 0; i < SourceDag->getNumArgs(); ++i) { + // Skip fixed immediates and registers, they were handled in + // addDagOperandMapping. + if ("" == SourceDag->getArgNameStr(i)) + continue; + + StringMap<unsigned>::iterator it = + SourceOperands.find(SourceDag->getArgNameStr(i)); + if (it != SourceOperands.end()) { + // Operand sharing the same name in the Dag should be mapped as tied. + SourceOperandMap[i].TiedOpIdx = it->getValue(); + if (!validateArgsTypes(SourceDag->getArg(it->getValue()), + SourceDag->getArg(i))) + PrintFatalError(Rec->getLoc(), + "Input Operand '" + SourceDag->getArgNameStr(i) + + "' has a mismatched tied operand!\n"); + } + it = DestOperands.find(SourceDag->getArgNameStr(i)); + if (it == DestOperands.end()) + PrintFatalError(Rec->getLoc(), "Operand " + SourceDag->getArgNameStr(i) + + " defined in Input Dag but not used in" + " Output Dag!\n"); + // Input Dag operand types must match output Dag operand type. + if (!validateArgsTypes(DestDag->getArg(it->getValue()), + SourceDag->getArg(i))) + PrintFatalError(Rec->getLoc(), "Type mismatch between Input and " + "Output Dag operand '" + + SourceDag->getArgNameStr(i) + "'!"); + SourceOperands[SourceDag->getArgNameStr(i)] = i; + } +} + +/// Map operand names in the Dag to their index in both corresponding input and +/// output instructions. Validate that operands defined in the input are +/// used in the output pattern while populating the maps. +void RISCVCompressInstEmitter::createInstOperandMapping( + Record *Rec, DagInit *SourceDag, DagInit *DestDag, + IndexedMap<OpData> &SourceOperandMap, IndexedMap<OpData> &DestOperandMap, + StringMap<unsigned> &SourceOperands, CodeGenInstruction &DestInst) { + // TiedCount keeps track of the number of operands skipped in Inst + // operands list to get to the corresponding Dag operand. + unsigned TiedCount = 0; + LLVM_DEBUG(dbgs() << " Operand mapping:\n Source Dest\n"); + for (unsigned i = 0, e = DestInst.Operands.size(); i != e; ++i) { + int TiedInstOpIdx = DestInst.Operands[i].getTiedRegister(); + if (TiedInstOpIdx != -1) { + ++TiedCount; + DestOperandMap[i].Data = DestOperandMap[TiedInstOpIdx].Data; + DestOperandMap[i].Kind = DestOperandMap[TiedInstOpIdx].Kind; + if (DestOperandMap[i].Kind == OpData::Operand) + // No need to fill the SourceOperandMap here since it was mapped to + // destination operand 'TiedInstOpIdx' in a previous iteration. + LLVM_DEBUG(dbgs() << " " << DestOperandMap[i].Data.Operand + << " ====> " << i + << " Dest operand tied with operand '" + << TiedInstOpIdx << "'\n"); + continue; + } + // Skip fixed immediates and registers, they were handled in + // addDagOperandMapping. + if (DestOperandMap[i].Kind != OpData::Operand) + continue; + + unsigned DagArgIdx = i - TiedCount; + StringMap<unsigned>::iterator SourceOp = + SourceOperands.find(DestDag->getArgNameStr(DagArgIdx)); + if (SourceOp == SourceOperands.end()) + PrintFatalError(Rec->getLoc(), + "Output Dag operand '" + + DestDag->getArgNameStr(DagArgIdx) + + "' has no matching input Dag operand."); + + assert(DestDag->getArgNameStr(DagArgIdx) == + SourceDag->getArgNameStr(SourceOp->getValue()) && + "Incorrect operand mapping detected!\n"); + DestOperandMap[i].Data.Operand = SourceOp->getValue(); + SourceOperandMap[SourceOp->getValue()].Data.Operand = i; + LLVM_DEBUG(dbgs() << " " << SourceOp->getValue() << " ====> " << i + << "\n"); + } +} + +/// Validates the CompressPattern and create operand mapping. +/// These are the checks to validate a CompressPat pattern declarations. +/// Error out with message under these conditions: +/// - Dag Input opcode is an expanded instruction and Dag Output opcode is a +/// compressed instruction. +/// - Operands in Dag Input must be all used in Dag Output. +/// Register Operand type in Dag Input Type must be contained in the +/// corresponding Source Instruction type. +/// - Register Operand type in Dag Input must be the same as in Dag Ouput. +/// - Register Operand type in Dag Output must be the same as the +/// corresponding Destination Inst type. +/// - Immediate Operand type in Dag Input must be the same as in Dag Ouput. +/// - Immediate Operand type in Dag Ouput must be the same as the corresponding +/// Destination Instruction type. +/// - Fixed register must be contained in the corresponding Source Instruction +/// type. +/// - Fixed register must be contained in the corresponding Destination +/// Instruction type. Warning message printed under these conditions: +/// - Fixed immediate in Dag Input or Dag Ouput cannot be checked at this time +/// and generate warning. +/// - Immediate operand type in Dag Input differs from the corresponding Source +/// Instruction type and generate a warning. +void RISCVCompressInstEmitter::evaluateCompressPat(Record *Rec) { + // Validate input Dag operands. + DagInit *SourceDag = Rec->getValueAsDag("Input"); + assert(SourceDag && "Missing 'Input' in compress pattern!"); + LLVM_DEBUG(dbgs() << "Input: " << *SourceDag << "\n"); + + DefInit *OpDef = dyn_cast<DefInit>(SourceDag->getOperator()); + if (!OpDef) + PrintFatalError(Rec->getLoc(), + Rec->getName() + " has unexpected operator type!"); + // Checking we are transforming from compressed to uncompressed instructions. + Record *Operator = OpDef->getDef(); + if (!Operator->isSubClassOf("RVInst")) + PrintFatalError(Rec->getLoc(), "Input instruction '" + Operator->getName() + + "' is not a 32 bit wide instruction!"); + CodeGenInstruction SourceInst(Operator); + verifyDagOpCount(SourceInst, SourceDag, true); + + // Validate output Dag operands. + DagInit *DestDag = Rec->getValueAsDag("Output"); + assert(DestDag && "Missing 'Output' in compress pattern!"); + LLVM_DEBUG(dbgs() << "Output: " << *DestDag << "\n"); + + DefInit *DestOpDef = dyn_cast<DefInit>(DestDag->getOperator()); + if (!DestOpDef) + PrintFatalError(Rec->getLoc(), + Rec->getName() + " has unexpected operator type!"); + + Record *DestOperator = DestOpDef->getDef(); + if (!DestOperator->isSubClassOf("RVInst16")) + PrintFatalError(Rec->getLoc(), "Output instruction '" + + DestOperator->getName() + + "' is not a 16 bit wide instruction!"); + CodeGenInstruction DestInst(DestOperator); + verifyDagOpCount(DestInst, DestDag, false); + + // Fill the mapping from the source to destination instructions. + + IndexedMap<OpData> SourceOperandMap; + SourceOperandMap.grow(SourceInst.Operands.size()); + // Create a mapping between source Dag operands and source Inst operands. + addDagOperandMapping(Rec, SourceDag, SourceInst, SourceOperandMap, + /*IsSourceInst*/ true); + + IndexedMap<OpData> DestOperandMap; + DestOperandMap.grow(DestInst.Operands.size()); + // Create a mapping between destination Dag operands and destination Inst + // operands. + addDagOperandMapping(Rec, DestDag, DestInst, DestOperandMap, + /*IsSourceInst*/ false); + + StringMap<unsigned> SourceOperands; + StringMap<unsigned> DestOperands; + createDagOperandMapping(Rec, SourceOperands, DestOperands, SourceDag, DestDag, + SourceOperandMap); + // Create operand mapping between the source and destination instructions. + createInstOperandMapping(Rec, SourceDag, DestDag, SourceOperandMap, + DestOperandMap, SourceOperands, DestInst); + + // Get the target features for the CompressPat. + std::vector<Record *> PatReqFeatures; + std::vector<Record *> RF = Rec->getValueAsListOfDefs("Predicates"); + copy_if(RF, std::back_inserter(PatReqFeatures), [](Record *R) { + return R->getValueAsBit("AssemblerMatcherPredicate"); + }); + + CompressPatterns.push_back(CompressPat(SourceInst, DestInst, PatReqFeatures, + SourceOperandMap, DestOperandMap)); +} + +static void getReqFeatures(std::map<StringRef, int> &FeaturesMap, + const std::vector<Record *> &ReqFeatures) { + for (auto &R : ReqFeatures) { + StringRef AsmCondString = R->getValueAsString("AssemblerCondString"); + + // AsmCondString has syntax [!]F(,[!]F)* + SmallVector<StringRef, 4> Ops; + SplitString(AsmCondString, Ops, ","); + assert(!Ops.empty() && "AssemblerCondString cannot be empty"); + + for (auto &Op : Ops) { + assert(!Op.empty() && "Empty operator"); + if (FeaturesMap.find(Op) == FeaturesMap.end()) + FeaturesMap[Op] = FeaturesMap.size(); + } + } +} + +unsigned getMCOpPredicate(DenseMap<const Record *, unsigned> &MCOpPredicateMap, + std::vector<const Record *> &MCOpPredicates, + Record *Rec) { + unsigned Entry = MCOpPredicateMap[Rec]; + if (Entry) + return Entry; + + if (!Rec->isValueUnset("MCOperandPredicate")) { + MCOpPredicates.push_back(Rec); + Entry = MCOpPredicates.size(); + MCOpPredicateMap[Rec] = Entry; + return Entry; + } + + PrintFatalError(Rec->getLoc(), + "No MCOperandPredicate on this operand at all: " + + Rec->getName().str() + "'"); + return 0; +} + +static std::string mergeCondAndCode(raw_string_ostream &CondStream, + raw_string_ostream &CodeStream) { + std::string S; + raw_string_ostream CombinedStream(S); + CombinedStream.indent(4) + << "if (" + << CondStream.str().substr( + 6, CondStream.str().length() - + 10) // remove first indentation and last '&&'. + << ") {\n"; + CombinedStream << CodeStream.str(); + CombinedStream.indent(4) << " return true;\n"; + CombinedStream.indent(4) << "} // if\n"; + return CombinedStream.str(); +} + +void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, + bool Compress) { + Record *AsmWriter = Target.getAsmWriter(); + if (!AsmWriter->getValueAsInt("PassSubtarget")) + PrintFatalError("'PassSubtarget' is false. SubTargetInfo object is needed " + "for target features.\n"); + + std::string Namespace = Target.getName(); + + // Sort entries in CompressPatterns to handle instructions that can have more + // than one candidate for compression\uncompression, e.g ADD can be + // transformed to a C_ADD or a C_MV. When emitting 'uncompress()' function the + // source and destination are flipped and the sort key needs to change + // accordingly. + std::stable_sort(CompressPatterns.begin(), CompressPatterns.end(), + [Compress](const CompressPat &LHS, const CompressPat &RHS) { + if (Compress) + return (LHS.Source.TheDef->getName().str() < + RHS.Source.TheDef->getName().str()); + else + return (LHS.Dest.TheDef->getName().str() < + RHS.Dest.TheDef->getName().str()); + }); + + // A list of MCOperandPredicates for all operands in use, and the reverse map. + std::vector<const Record *> MCOpPredicates; + DenseMap<const Record *, unsigned> MCOpPredicateMap; + + std::string F; + std::string FH; + raw_string_ostream Func(F); + raw_string_ostream FuncH(FH); + bool NeedMRI = false; + + if (Compress) + o << "\n#ifdef GEN_COMPRESS_INSTR\n" + << "#undef GEN_COMPRESS_INSTR\n\n"; + else + o << "\n#ifdef GEN_UNCOMPRESS_INSTR\n" + << "#undef GEN_UNCOMPRESS_INSTR\n\n"; + + if (Compress) { + FuncH << "static bool compressInst(MCInst& OutInst,\n"; + FuncH.indent(25) << "const MCInst &MI,\n"; + FuncH.indent(25) << "const MCSubtargetInfo &STI,\n"; + FuncH.indent(25) << "MCContext &Context) {\n"; + } else { + FuncH << "static bool uncompressInst(MCInst& OutInst,\n"; + FuncH.indent(27) << "const MCInst &MI,\n"; + FuncH.indent(27) << "const MCRegisterInfo &MRI,\n"; + FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n"; + } + + if (CompressPatterns.empty()) { + o << FuncH.str(); + o.indent(2) << "return false;\n}\n"; + if (Compress) + o << "\n#endif //GEN_COMPRESS_INSTR\n"; + else + o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n"; + return; + } + + std::string CaseString(""); + raw_string_ostream CaseStream(CaseString); + std::string PrevOp(""); + std::string CurOp(""); + CaseStream << " switch (MI.getOpcode()) {\n"; + CaseStream << " default: return false;\n"; + + for (auto &CompressPat : CompressPatterns) { + std::string CondString; + std::string CodeString; + raw_string_ostream CondStream(CondString); + raw_string_ostream CodeStream(CodeString); + CodeGenInstruction &Source = + Compress ? CompressPat.Source : CompressPat.Dest; + CodeGenInstruction &Dest = Compress ? CompressPat.Dest : CompressPat.Source; + IndexedMap<OpData> SourceOperandMap = + Compress ? CompressPat.SourceOperandMap : CompressPat.DestOperandMap; + IndexedMap<OpData> &DestOperandMap = + Compress ? CompressPat.DestOperandMap : CompressPat.SourceOperandMap; + + CurOp = Source.TheDef->getName().str(); + // Check current and previous opcode to decide to continue or end a case. + if (CurOp != PrevOp) { + if (PrevOp != "") + CaseStream.indent(6) << "break;\n } // case " + PrevOp + "\n"; + CaseStream.indent(4) << "case " + Namespace + "::" + CurOp + ": {\n"; + } + + std::map<StringRef, int> FeaturesMap; + // Add CompressPat required features. + getReqFeatures(FeaturesMap, CompressPat.PatReqFeatures); + + // Add Dest instruction required features. + std::vector<Record *> ReqFeatures; + std::vector<Record *> RF = Dest.TheDef->getValueAsListOfDefs("Predicates"); + copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) { + return R->getValueAsBit("AssemblerMatcherPredicate"); + }); + getReqFeatures(FeaturesMap, ReqFeatures); + + // Emit checks for all required features. + for (auto &F : FeaturesMap) { + StringRef Op = F.first; + if (Op[0] == '!') + CondStream.indent(6) << ("!STI.getFeatureBits()[" + Namespace + + "::" + Op.substr(1) + "]") + .str() + + " &&\n"; + else + CondStream.indent(6) + << ("STI.getFeatureBits()[" + Namespace + "::" + Op + "]").str() + + " &&\n"; + } + + // Start Source Inst operands validation. + unsigned OpNo = 0; + for (OpNo = 0; OpNo < Source.Operands.size(); ++OpNo) { + if (SourceOperandMap[OpNo].TiedOpIdx != -1) { + if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass")) + CondStream.indent(6) + << "(MI.getOperand(" + << std::to_string(OpNo) + ").getReg() == MI.getOperand(" + << std::to_string(SourceOperandMap[OpNo].TiedOpIdx) + << ").getReg()) &&\n"; + else + PrintFatalError("Unexpected tied operand types!\n"); + } + // Check for fixed immediates\registers in the source instruction. + switch (SourceOperandMap[OpNo].Kind) { + case OpData::Operand: + // We don't need to do anything for source instruction operand checks. + break; + case OpData::Imm: + CondStream.indent(6) + << "(MI.getOperand(" + std::to_string(OpNo) + ").isImm()) &&\n" + + " (MI.getOperand(" + std::to_string(OpNo) + + ").getImm() == " + + std::to_string(SourceOperandMap[OpNo].Data.Imm) + ") &&\n"; + break; + case OpData::Reg: { + Record *Reg = SourceOperandMap[OpNo].Data.Reg; + CondStream.indent(6) << "(MI.getOperand(" + std::to_string(OpNo) + + ").getReg() == " + Namespace + + "::" + Reg->getName().str() + ") &&\n"; + break; + } + } + } + CodeStream.indent(6) << "// " + Dest.AsmString + "\n"; + CodeStream.indent(6) << "OutInst.setOpcode(" + Namespace + + "::" + Dest.TheDef->getName().str() + ");\n"; + OpNo = 0; + for (const auto &DestOperand : Dest.Operands) { + CodeStream.indent(6) << "// Operand: " + DestOperand.Name + "\n"; + switch (DestOperandMap[OpNo].Kind) { + case OpData::Operand: { + unsigned OpIdx = DestOperandMap[OpNo].Data.Operand; + // Check that the operand in the Source instruction fits + // the type for the Dest instruction. + if (DestOperand.Rec->isSubClassOf("RegisterClass")) { + NeedMRI = true; + // This is a register operand. Check the register class. + // Don't check register class if this is a tied operand, it was done + // for the operand its tied to. + if (DestOperand.getTiedRegister() == -1) + CondStream.indent(6) + << "(MRI.getRegClass(" + Namespace + + "::" + DestOperand.Rec->getName().str() + + "RegClassID).contains(" + "MI.getOperand(" + + std::to_string(OpIdx) + ").getReg())) &&\n"; + + CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" + + std::to_string(OpIdx) + "));\n"; + } else { + // Handling immediate operands. + unsigned Entry = getMCOpPredicate(MCOpPredicateMap, MCOpPredicates, + DestOperand.Rec); + CondStream.indent(6) << Namespace + "ValidateMCOperand(" + + "MI.getOperand(" + std::to_string(OpIdx) + + "), STI, " + std::to_string(Entry) + + ") &&\n"; + CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" + + std::to_string(OpIdx) + "));\n"; + } + break; + } + case OpData::Imm: { + unsigned Entry = + getMCOpPredicate(MCOpPredicateMap, MCOpPredicates, DestOperand.Rec); + CondStream.indent(6) + << Namespace + "ValidateMCOperand(" + "MCOperand::createImm(" + + std::to_string(DestOperandMap[OpNo].Data.Imm) + "), STI, " + + std::to_string(Entry) + ") &&\n"; + CodeStream.indent(6) + << "OutInst.addOperand(MCOperand::createImm(" + + std::to_string(DestOperandMap[OpNo].Data.Imm) + "));\n"; + } break; + case OpData::Reg: { + // Fixed register has been validated at pattern validation time. + Record *Reg = DestOperandMap[OpNo].Data.Reg; + CodeStream.indent(6) << "OutInst.addOperand(MCOperand::createReg(" + + Namespace + "::" + Reg->getName().str() + + "));\n"; + } break; + } + ++OpNo; + } + CaseStream << mergeCondAndCode(CondStream, CodeStream); + PrevOp = CurOp; + } + Func << CaseStream.str() << "\n"; + // Close brace for the last case. + Func.indent(4) << "} // case " + CurOp + "\n"; + Func.indent(2) << "} // switch\n"; + Func.indent(2) << "return false;\n}\n"; + + if (!MCOpPredicates.empty()) { + o << "static bool " << Namespace + << "ValidateMCOperand(const MCOperand &MCOp,\n" + << " const MCSubtargetInfo &STI,\n" + << " unsigned PredicateIndex) {\n" + << " switch (PredicateIndex) {\n" + << " default:\n" + << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n" + << " break;\n"; + + for (unsigned i = 0; i < MCOpPredicates.size(); ++i) { + Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate"); + if (CodeInit *SI = dyn_cast<CodeInit>(MCOpPred)) + o << " case " << i + 1 << ": {\n" + << " // " << MCOpPredicates[i]->getName().str() << SI->getValue() + << "\n" + << " }\n"; + else + llvm_unreachable("Unexpected MCOperandPredicate field!"); + } + o << " }\n" + << "}\n\n"; + } + + o << FuncH.str(); + if (NeedMRI && Compress) + o.indent(2) << "const MCRegisterInfo &MRI = *Context.getRegisterInfo();\n"; + o << Func.str(); + + if (Compress) + o << "\n#endif //GEN_COMPRESS_INSTR\n"; + else + o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n"; +} + +void RISCVCompressInstEmitter::run(raw_ostream &o) { + Record *CompressClass = Records.getClass("CompressPat"); + assert(CompressClass && "Compress class definition missing!"); + std::vector<Record *> Insts; + for (const auto &D : Records.getDefs()) { + if (D.second->isSubClassOf(CompressClass)) + Insts.push_back(D.second.get()); + } + + // Process the CompressPat definitions, validating them as we do so. + for (unsigned i = 0, e = Insts.size(); i != e; ++i) + evaluateCompressPat(Insts[i]); + + // Emit file header. + emitSourceFileHeader("Compress instruction Source Fragment", o); + // Generate compressInst() function. + emitCompressInstEmitter(o, true); + // Generate uncompressInst() function. + emitCompressInstEmitter(o, false); +} + +namespace llvm { + +void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS) { + RISCVCompressInstEmitter(RK).run(OS); +} + +} // namespace llvm diff --git a/utils/TableGen/RegisterBankEmitter.cpp b/utils/TableGen/RegisterBankEmitter.cpp index 5c6471688044..879b4162d629 100644 --- a/utils/TableGen/RegisterBankEmitter.cpp +++ b/utils/TableGen/RegisterBankEmitter.cpp @@ -291,9 +291,11 @@ void RegisterBankEmitter::run(raw_ostream &OS) { visitRegisterBankClasses( RegisterClassHierarchy, RC, "explicit", [&Bank](const CodeGenRegisterClass *RC, StringRef Kind) { - DEBUG(dbgs() << "Added " << RC->getName() << "(" << Kind << ")\n"); + LLVM_DEBUG(dbgs() + << "Added " << RC->getName() << "(" << Kind << ")\n"); Bank.addRegisterClass(RC); - }, VisitedRCs); + }, + VisitedRCs); } Banks.push_back(Bank); diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index 7eef2337c140..49016cca799e 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -15,19 +15,19 @@ #include "CodeGenRegisters.h" #include "CodeGenTarget.h" -#include "Types.h" #include "SequenceToOffsetTable.h" +#include "Types.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SparseBitVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" -#include "llvm/CodeGen/MachineValueType.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Format.h" +#include "llvm/Support/MachineValueType.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" @@ -203,11 +203,11 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, << " static const RegClassWeight RCWeightTable[] = {\n"; for (const auto &RC : RegBank.getRegClasses()) { const CodeGenRegister::Vec &Regs = RC.getMembers(); - if (Regs.empty()) + if (Regs.empty() || RC.Artificial) OS << " {0, 0"; else { std::vector<unsigned> RegUnits; - RC.buildRegUnitSet(RegUnits); + RC.buildRegUnitSet(RegBank, RegUnits); OS << " {" << (*Regs.begin())->getWeight(RegBank) << ", " << RegBank.getRegUnitSetWeight(RegUnits); } @@ -296,7 +296,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, PSetE = PSetIDs.end(); PSetI != PSetE; ++PSetI) { PSets[i].push_back(RegBank.getRegPressureSet(*PSetI).Order); } - std::sort(PSets[i].begin(), PSets[i].end()); + llvm::sort(PSets[i].begin(), PSets[i].end()); PSetsSeqs.add(PSets[i]); } diff --git a/utils/TableGen/SearchableTableEmitter.cpp b/utils/TableGen/SearchableTableEmitter.cpp index 63252e8c0391..664de2217e94 100644 --- a/utils/TableGen/SearchableTableEmitter.cpp +++ b/utils/TableGen/SearchableTableEmitter.cpp @@ -13,23 +13,85 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Format.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" +#include "CodeGenIntrinsics.h" #include <algorithm> +#include <set> #include <string> #include <vector> + using namespace llvm; #define DEBUG_TYPE "searchable-table-emitter" namespace { +struct GenericTable; + +int getAsInt(Init *B) { + return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue(); +} +int getInt(Record *R, StringRef Field) { + return getAsInt(R->getValueInit(Field)); +} + +struct GenericEnum { + using Entry = std::pair<StringRef, int64_t>; + + std::string Name; + Record *Class; + std::string PreprocessorGuard; + std::vector<std::unique_ptr<Entry>> Entries; + DenseMap<Record *, Entry *> EntryMap; +}; + +struct GenericField { + std::string Name; + RecTy *RecType = nullptr; + bool IsIntrinsic = false; + bool IsInstruction = false; + GenericEnum *Enum = nullptr; + + GenericField(StringRef Name) : Name(Name) {} +}; + +struct SearchIndex { + std::string Name; + SmallVector<GenericField, 1> Fields; + bool EarlyOut; +}; + +struct GenericTable { + std::string Name; + std::string PreprocessorGuard; + std::string CppTypeName; + SmallVector<GenericField, 2> Fields; + std::vector<Record *> Entries; + + std::unique_ptr<SearchIndex> PrimaryKey; + SmallVector<std::unique_ptr<SearchIndex>, 2> Indices; + + const GenericField *getFieldByName(StringRef Name) const { + for (const auto &Field : Fields) { + if (Name == Field.Name) + return &Field; + } + return nullptr; + } +}; + class SearchableTableEmitter { RecordKeeper &Records; + DenseMap<Init *, std::unique_ptr<CodeGenIntrinsic>> Intrinsics; + std::vector<std::unique_ptr<GenericEnum>> Enums; + DenseMap<Record *, GenericEnum *> EnumMap; + std::set<std::string> PreprocessorGuards; public: SearchableTableEmitter(RecordKeeper &R) : Records(R) {} @@ -39,38 +101,58 @@ public: private: typedef std::pair<Init *, int> SearchTableEntry; - int getAsInt(BitsInit *B) { - return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue(); - } - int getInt(Record *R, StringRef Field) { - return getAsInt(R->getValueAsBitsInit(Field)); - } + enum TypeContext { + TypeInStaticStruct, + TypeInTempStruct, + TypeInArgument, + }; - std::string primaryRepresentation(Init *I) { + std::string primaryRepresentation(const GenericField &Field, Init *I) { if (StringInit *SI = dyn_cast<StringInit>(I)) return SI->getAsString(); else if (BitsInit *BI = dyn_cast<BitsInit>(I)) return "0x" + utohexstr(getAsInt(BI)); else if (BitInit *BI = dyn_cast<BitInit>(I)) return BI->getValue() ? "true" : "false"; - else if (CodeInit *CI = dyn_cast<CodeInit>(I)) { + else if (CodeInit *CI = dyn_cast<CodeInit>(I)) return CI->getValue(); - } - PrintFatalError(SMLoc(), - "invalid field type, expected: string, bits, bit or code"); + else if (Field.IsIntrinsic) + return "Intrinsic::" + getIntrinsic(I).EnumName; + else if (Field.IsInstruction) + return I->getAsString(); + else if (Field.Enum) + return Field.Enum->EntryMap[cast<DefInit>(I)->getDef()]->first; + PrintFatalError(Twine("invalid field type for field '") + Field.Name + + "', expected: string, bits, bit or code"); + } + + bool isIntrinsic(Init *I) { + if (DefInit *DI = dyn_cast<DefInit>(I)) + return DI->getDef()->isSubClassOf("Intrinsic"); + return false; + } + + CodeGenIntrinsic &getIntrinsic(Init *I) { + std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I]; + if (!Intr) + Intr = make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef()); + return *Intr; } - std::string searchRepresentation(Init *I) { - std::string PrimaryRep = primaryRepresentation(I); - if (!isa<StringInit>(I)) - return PrimaryRep; - return StringRef(PrimaryRep).upper(); + bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index); + + bool isIntegral(Init *I) { + return isa<BitsInit>(I) || isIntrinsic(I); } - std::string searchableFieldType(Init *I) { - if (isa<StringInit>(I)) - return "const char *"; - else if (BitsInit *BI = dyn_cast<BitsInit>(I)) { + std::string searchableFieldType(const GenericField &Field, TypeContext Ctx) { + if (isa<StringRecTy>(Field.RecType)) { + if (Ctx == TypeInStaticStruct) + return "const char *"; + if (Ctx == TypeInTempStruct) + return "std::string"; + return "StringRef"; + } else if (BitsRecTy *BI = dyn_cast<BitsRecTy>(Field.RecType)) { unsigned NumBits = BI->getNumBits(); if (NumBits <= 8) NumBits = 8; @@ -81,233 +163,617 @@ private: else if (NumBits <= 64) NumBits = 64; else - PrintFatalError(SMLoc(), "bitfield too large to search"); + PrintFatalError(Twine("bitfield '") + Field.Name + + "' too large to search"); return "uint" + utostr(NumBits) + "_t"; - } - PrintFatalError(SMLoc(), "Unknown type to search by"); + } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction) + return "unsigned"; + PrintFatalError(Twine("Field '") + Field.Name + "' has unknown type '" + + Field.RecType->getAsString() + "' to search by"); } - void emitMapping(Record *MappingDesc, raw_ostream &OS); - void emitMappingEnum(std::vector<Record *> &Items, Record *InstanceClass, - raw_ostream &OS); - void - emitPrimaryTable(StringRef Name, std::vector<std::string> &FieldNames, - std::vector<std::string> &SearchFieldNames, - std::vector<std::vector<SearchTableEntry>> &SearchTables, - std::vector<Record *> &Items, raw_ostream &OS); - void emitSearchTable(StringRef Name, StringRef Field, - std::vector<SearchTableEntry> &SearchTable, - raw_ostream &OS); - void emitLookupDeclaration(StringRef Name, StringRef Field, Init *I, - raw_ostream &OS); - void emitLookupFunction(StringRef Name, StringRef Field, Init *I, - raw_ostream &OS); + void emitGenericTable(const GenericTable &Table, raw_ostream &OS); + void emitGenericEnum(const GenericEnum &Enum, raw_ostream &OS); + void emitLookupDeclaration(const GenericTable &Table, + const SearchIndex &Index, raw_ostream &OS); + void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index, + bool IsPrimary, raw_ostream &OS); + void emitIfdef(StringRef Guard, raw_ostream &OS); + + bool parseFieldType(GenericField &Field, Init *II); + std::unique_ptr<SearchIndex> + parseSearchIndex(GenericTable &Table, StringRef Name, + const std::vector<StringRef> &Key, bool EarlyOut); + void collectEnumEntries(GenericEnum &Enum, StringRef NameField, + StringRef ValueField, + const std::vector<Record *> &Items); + void collectTableEntries(GenericTable &Table, + const std::vector<Record *> &Items); }; } // End anonymous namespace. -/// Emit an enum providing symbolic access to some preferred field from -/// C++. -void SearchableTableEmitter::emitMappingEnum(std::vector<Record *> &Items, - Record *InstanceClass, - raw_ostream &OS) { - StringRef EnumNameField = InstanceClass->getValueAsString("EnumNameField"); - StringRef EnumValueField; - if (!InstanceClass->isValueUnset("EnumValueField")) - EnumValueField = InstanceClass->getValueAsString("EnumValueField"); - - OS << "enum " << InstanceClass->getName() << "Values {\n"; - for (auto Item : Items) { - OS << " " << Item->getValueAsString(EnumNameField); - if (EnumValueField != StringRef()) - OS << " = " << getInt(Item, EnumValueField); - OS << ",\n"; +// For search indices that consists of a single field whose numeric value is +// known, return that numeric value. +static int64_t getNumericKey(const SearchIndex &Index, Record *Rec) { + assert(Index.Fields.size() == 1); + + if (Index.Fields[0].Enum) { + Record *EnumEntry = Rec->getValueAsDef(Index.Fields[0].Name); + return Index.Fields[0].Enum->EntryMap[EnumEntry]->second; } - OS << "};\n\n"; -} -void SearchableTableEmitter::emitPrimaryTable( - StringRef Name, std::vector<std::string> &FieldNames, - std::vector<std::string> &SearchFieldNames, - std::vector<std::vector<SearchTableEntry>> &SearchTables, - std::vector<Record *> &Items, raw_ostream &OS) { - OS << "const " << Name << " " << Name << "sList[] = {\n"; + return getInt(Rec, Index.Fields[0].Name); +} - for (auto Item : Items) { - OS << " { "; - for (unsigned i = 0; i < FieldNames.size(); ++i) { - OS << primaryRepresentation(Item->getValueInit(FieldNames[i])); - if (i != FieldNames.size() - 1) - OS << ", "; +/// Less-than style comparison between \p LHS and \p RHS according to the +/// key of \p Index. +bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS, + const SearchIndex &Index) { + for (const auto &Field : Index.Fields) { + Init *LHSI = LHS->getValueInit(Field.Name); + Init *RHSI = RHS->getValueInit(Field.Name); + + if (isa<BitsRecTy>(Field.RecType) || isa<IntRecTy>(Field.RecType)) { + int64_t LHSi = getAsInt(LHSI); + int64_t RHSi = getAsInt(RHSI); + if (LHSi < RHSi) + return true; + if (LHSi > RHSi) + return false; + } else if (Field.IsIntrinsic) { + CodeGenIntrinsic &LHSi = getIntrinsic(LHSI); + CodeGenIntrinsic &RHSi = getIntrinsic(RHSI); + if (std::tie(LHSi.TargetPrefix, LHSi.Name) < + std::tie(RHSi.TargetPrefix, RHSi.Name)) + return true; + if (std::tie(LHSi.TargetPrefix, LHSi.Name) > + std::tie(RHSi.TargetPrefix, RHSi.Name)) + return false; + } else if (Field.IsInstruction) { + // This does not correctly compare the predefined instructions! + Record *LHSr = cast<DefInit>(LHSI)->getDef(); + Record *RHSr = cast<DefInit>(RHSI)->getDef(); + + bool LHSpseudo = LHSr->getValueAsBit("isPseudo"); + bool RHSpseudo = RHSr->getValueAsBit("isPseudo"); + if (LHSpseudo && !RHSpseudo) + return true; + if (!LHSpseudo && RHSpseudo) + return false; + + int comp = LHSr->getName().compare(RHSr->getName()); + if (comp < 0) + return true; + if (comp > 0) + return false; + } else if (Field.Enum) { + auto LHSr = cast<DefInit>(LHSI)->getDef(); + auto RHSr = cast<DefInit>(RHSI)->getDef(); + int64_t LHSv = Field.Enum->EntryMap[LHSr]->second; + int64_t RHSv = Field.Enum->EntryMap[RHSr]->second; + if (LHSv < RHSv) + return true; + if (LHSv > RHSv) + return false; + } else { + std::string LHSs = primaryRepresentation(Field, LHSI); + std::string RHSs = primaryRepresentation(Field, RHSI); + + if (isa<StringRecTy>(Field.RecType)) { + LHSs = StringRef(LHSs).upper(); + RHSs = StringRef(RHSs).upper(); + } + + int comp = LHSs.compare(RHSs); + if (comp < 0) + return true; + if (comp > 0) + return false; } - OS << "},\n"; } - OS << "};\n\n"; + return false; } -void SearchableTableEmitter::emitSearchTable( - StringRef Name, StringRef Field, std::vector<SearchTableEntry> &SearchTable, - raw_ostream &OS) { - OS << "const std::pair<" << searchableFieldType(SearchTable[0].first) - << ", int> " << Name << "sBy" << Field << "[] = {\n"; - - if (isa<BitsInit>(SearchTable[0].first)) { - std::stable_sort(SearchTable.begin(), SearchTable.end(), - [this](const SearchTableEntry &LHS, - const SearchTableEntry &RHS) { - return getAsInt(cast<BitsInit>(LHS.first)) < - getAsInt(cast<BitsInit>(RHS.first)); - }); +void SearchableTableEmitter::emitIfdef(StringRef Guard, raw_ostream &OS) { + OS << "#ifdef " << Guard << "\n"; + PreprocessorGuards.insert(Guard); +} + +/// Emit a generic enum. +void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum, + raw_ostream &OS) { + emitIfdef((Twine("GET_") + Enum.PreprocessorGuard + "_DECL").str(), OS); + + OS << "enum " << Enum.Name << " {\n"; + for (const auto &Entry : Enum.Entries) + OS << " " << Entry->first << " = " << Entry->second << ",\n"; + OS << "};\n"; + + OS << "#endif\n\n"; +} + +void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table, + const SearchIndex &Index, + bool IsPrimary, + raw_ostream &OS) { + OS << "\n"; + emitLookupDeclaration(Table, Index, OS); + OS << " {\n"; + + std::vector<Record *> IndexRowsStorage; + ArrayRef<Record *> IndexRows; + StringRef IndexTypeName; + StringRef IndexName; + + if (IsPrimary) { + IndexTypeName = Table.CppTypeName; + IndexName = Table.Name; + IndexRows = Table.Entries; } else { - std::stable_sort(SearchTable.begin(), SearchTable.end(), - [this](const SearchTableEntry &LHS, - const SearchTableEntry &RHS) { - return searchRepresentation(LHS.first) < - searchRepresentation(RHS.first); + OS << " struct IndexType {\n"; + for (const auto &Field : Index.Fields) { + OS << " " << searchableFieldType(Field, TypeInStaticStruct) << " " + << Field.Name << ";\n"; + } + OS << " unsigned _index;\n"; + OS << " };\n"; + + OS << " static const struct IndexType Index[] = {\n"; + + std::vector<std::pair<Record *, unsigned>> Entries; + Entries.reserve(Table.Entries.size()); + for (unsigned i = 0; i < Table.Entries.size(); ++i) + Entries.emplace_back(Table.Entries[i], i); + + std::stable_sort(Entries.begin(), Entries.end(), + [&](const std::pair<Record *, unsigned> &LHS, + const std::pair<Record *, unsigned> &RHS) { + return compareBy(LHS.first, RHS.first, Index); }); + + IndexRowsStorage.reserve(Entries.size()); + for (const auto &Entry : Entries) { + IndexRowsStorage.push_back(Entry.first); + + OS << " { "; + bool NeedComma = false; + for (const auto &Field : Index.Fields) { + if (NeedComma) + OS << ", "; + NeedComma = true; + + std::string Repr = + primaryRepresentation(Field, Entry.first->getValueInit(Field.Name)); + if (isa<StringRecTy>(Field.RecType)) + Repr = StringRef(Repr).upper(); + OS << Repr; + } + OS << ", " << Entry.second << " },\n"; + } + + OS << " };\n\n"; + + IndexTypeName = "IndexType"; + IndexName = "Index"; + IndexRows = IndexRowsStorage; + } + + bool IsContiguous = false; + + if (Index.Fields.size() == 1 && + (Index.Fields[0].Enum || isa<BitsRecTy>(Index.Fields[0].RecType))) { + IsContiguous = true; + for (unsigned i = 0; i < IndexRows.size(); ++i) { + if (getNumericKey(Index, IndexRows[i]) != i) { + IsContiguous = false; + break; + } + } } - for (auto Entry : SearchTable) { - OS << " { " << searchRepresentation(Entry.first) << ", " << Entry.second - << " },\n"; + if (IsContiguous) { + OS << " auto Table = makeArrayRef(" << IndexName << ");\n"; + OS << " size_t Idx = " << Index.Fields[0].Name << ";\n"; + OS << " return Idx >= Table.size() ? nullptr : "; + if (IsPrimary) + OS << "&Table[Idx]"; + else + OS << "&" << Table.Name << "[Table[Idx]._index]"; + OS << ";\n"; + OS << "}\n"; + return; } - OS << "};\n\n"; -} -void SearchableTableEmitter::emitLookupFunction(StringRef Name, StringRef Field, - Init *I, raw_ostream &OS) { - bool IsIntegral = isa<BitsInit>(I); - std::string FieldType = searchableFieldType(I); - std::string PairType = "std::pair<" + FieldType + ", int>"; - - // const SysRegs *lookupSysRegByName(const char *Name) { - OS << "const " << Name << " *" - << "lookup" << Name << "By" << Field; - OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field - << ") {\n"; - - if (IsIntegral) { - OS << " auto CanonicalVal = " << Field << ";\n"; - OS << " " << PairType << " Val = {CanonicalVal, 0};\n"; - } else { - // Make sure the result is null terminated because it's going via "char *". - OS << " std::string CanonicalVal = " << Field << ".upper();\n"; - OS << " " << PairType << " Val = {CanonicalVal.c_str(), 0};\n"; + if (Index.EarlyOut) { + const GenericField &Field = Index.Fields[0]; + std::string FirstRepr = + primaryRepresentation(Field, IndexRows[0]->getValueInit(Field.Name)); + std::string LastRepr = primaryRepresentation( + Field, IndexRows.back()->getValueInit(Field.Name)); + OS << " if ((" << Field.Name << " < " << FirstRepr << ") ||\n"; + OS << " (" << Field.Name << " > " << LastRepr << "))\n"; + OS << " return nullptr;\n\n"; } - OS << " ArrayRef<" << PairType << "> Table(" << Name << "sBy" << Field - << ");\n"; - OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Val"; - - if (IsIntegral) - OS << ");\n"; - else { - OS << ",\n "; - OS << "[](const " << PairType << " &LHS, const " << PairType - << " &RHS) {\n"; - OS << " return std::strcmp(LHS.first, RHS.first) < 0;\n"; - OS << " });\n\n"; + OS << " struct KeyType {\n"; + for (const auto &Field : Index.Fields) { + OS << " " << searchableFieldType(Field, TypeInTempStruct) << " " + << Field.Name << ";\n"; + } + OS << " };\n"; + OS << " KeyType Key = { "; + bool NeedComma = false; + for (const auto &Field : Index.Fields) { + if (NeedComma) + OS << ", "; + NeedComma = true; + + OS << Field.Name; + if (isa<StringRecTy>(Field.RecType)) { + OS << ".upper()"; + if (IsPrimary) + PrintFatalError(Twine("Use a secondary index for case-insensitive " + "comparison of field '") + + Field.Name + "' in table '" + Table.Name + "'"); + } + } + OS << " };\n"; + + OS << " auto Table = makeArrayRef(" << IndexName << ");\n"; + OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n"; + OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n"; + + for (const auto &Field : Index.Fields) { + if (isa<StringRecTy>(Field.RecType)) { + OS << " int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name + << ").compare(RHS." << Field.Name << ");\n"; + OS << " if (Cmp" << Field.Name << " < 0) return true;\n"; + OS << " if (Cmp" << Field.Name << " > 0) return false;\n"; + } else { + OS << " if (LHS." << Field.Name << " < RHS." << Field.Name << ")\n"; + OS << " return true;\n"; + OS << " if (LHS." << Field.Name << " > RHS." << Field.Name << ")\n"; + OS << " return false;\n"; + } } - OS << " if (Idx == Table.end() || CanonicalVal != Idx->first)\n"; - OS << " return nullptr;\n"; + OS << " return false;\n"; + OS << " });\n\n"; - OS << " return &" << Name << "sList[Idx->second];\n"; - OS << "}\n\n"; + OS << " if (Idx == Table.end()"; + + for (const auto &Field : Index.Fields) + OS << " ||\n Key." << Field.Name << " != Idx->" << Field.Name; + OS << ")\n return nullptr;\n"; + + if (IsPrimary) + OS << " return &*Idx;\n"; + else + OS << " return &" << Table.Name << "[Idx->_index];\n"; + + OS << "}\n"; } -void SearchableTableEmitter::emitLookupDeclaration(StringRef Name, - StringRef Field, Init *I, +void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table, + const SearchIndex &Index, raw_ostream &OS) { - bool IsIntegral = isa<BitsInit>(I); - std::string FieldType = searchableFieldType(I); - OS << "const " << Name << " *" - << "lookup" << Name << "By" << Field; - OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field - << ");\n\n"; + OS << "const " << Table.CppTypeName << " *" << Index.Name << "("; + + bool NeedComma = false; + for (const auto &Field : Index.Fields) { + if (NeedComma) + OS << ", "; + NeedComma = true; + + OS << searchableFieldType(Field, TypeInArgument) << " " << Field.Name; + } + OS << ")"; } -void SearchableTableEmitter::emitMapping(Record *InstanceClass, - raw_ostream &OS) { - StringRef TableName = InstanceClass->getName(); - std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName); +void SearchableTableEmitter::emitGenericTable(const GenericTable &Table, + raw_ostream &OS) { + emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_DECL").str(), OS); - // Gather all the records we're going to need for this particular mapping. - std::vector<std::vector<SearchTableEntry>> SearchTables; - std::vector<std::string> SearchFieldNames; + // Emit the declarations for the functions that will perform lookup. + if (Table.PrimaryKey) { + emitLookupDeclaration(Table, *Table.PrimaryKey, OS); + OS << ";\n"; + } + for (const auto &Index : Table.Indices) { + emitLookupDeclaration(Table, *Index, OS); + OS << ";\n"; + } - std::vector<std::string> FieldNames; - for (const RecordVal &Field : InstanceClass->getValues()) { - std::string FieldName = Field.getName(); + OS << "#endif\n\n"; - // Skip uninteresting fields: either built-in, special to us, or injected - // template parameters (if they contain a ':'). - if (FieldName.find(':') != std::string::npos || FieldName == "NAME" || - FieldName == "SearchableFields" || FieldName == "EnumNameField" || - FieldName == "EnumValueField") - continue; + emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS); - FieldNames.push_back(FieldName); - } + // The primary data table contains all the fields defined for this map. + OS << "const " << Table.CppTypeName << " " << Table.Name << "[] = {\n"; + for (unsigned i = 0; i < Table.Entries.size(); ++i) { + Record *Entry = Table.Entries[i]; + OS << " { "; + + bool NeedComma = false; + for (const auto &Field : Table.Fields) { + if (NeedComma) + OS << ", "; + NeedComma = true; + + OS << primaryRepresentation(Field, Entry->getValueInit(Field.Name)); + } - for (auto *Field : *InstanceClass->getValueAsListInit("SearchableFields")) { - SearchTables.emplace_back(); - SearchFieldNames.push_back(Field->getAsUnquotedString()); + OS << " }, // " << i << "\n"; } + OS << " };\n"; + + // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary + // search can be performed by "Thing". + if (Table.PrimaryKey) + emitLookupFunction(Table, *Table.PrimaryKey, true, OS); + for (const auto &Index : Table.Indices) + emitLookupFunction(Table, *Index, false, OS); - int Idx = 0; - for (Record *Item : Items) { - for (unsigned i = 0; i < SearchFieldNames.size(); ++i) { - Init *SearchVal = Item->getValueInit(SearchFieldNames[i]); - SearchTables[i].emplace_back(SearchVal, Idx); + OS << "#endif\n\n"; +} + +bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *II) { + if (auto DI = dyn_cast<DefInit>(II)) { + Record *TypeRec = DI->getDef(); + if (TypeRec->isSubClassOf("GenericEnum")) { + Field.Enum = EnumMap[TypeRec]; + Field.RecType = RecordRecTy::get(Field.Enum->Class); + return true; } - ++Idx; } - OS << "#ifdef GET_" << TableName.upper() << "_DECL\n"; - OS << "#undef GET_" << TableName.upper() << "_DECL\n"; + return false; +} + +std::unique_ptr<SearchIndex> +SearchableTableEmitter::parseSearchIndex(GenericTable &Table, StringRef Name, + const std::vector<StringRef> &Key, + bool EarlyOut) { + auto Index = llvm::make_unique<SearchIndex>(); + Index->Name = Name; + Index->EarlyOut = EarlyOut; + + for (const auto &FieldName : Key) { + const GenericField *Field = Table.getFieldByName(FieldName); + if (!Field) + PrintFatalError(Twine("Search index '") + Name + + "' refers to non-existing field '" + FieldName + + "' in table '" + Table.Name + "'"); + Index->Fields.push_back(*Field); + } - // Next emit the enum containing the top-level names for use in C++ code if - // requested - if (!InstanceClass->isValueUnset("EnumNameField")) { - emitMappingEnum(Items, InstanceClass, OS); + if (EarlyOut && isa<StringRecTy>(Index->Fields[0].RecType)) { + PrintFatalError( + "Early-out is not supported for string types (in search index '" + + Twine(Name) + "'"); } - // And the declarations for the functions that will perform lookup. - for (unsigned i = 0; i < SearchFieldNames.size(); ++i) - emitLookupDeclaration(TableName, SearchFieldNames[i], - SearchTables[i][0].first, OS); + return Index; +} - OS << "#endif\n\n"; +void SearchableTableEmitter::collectEnumEntries( + GenericEnum &Enum, StringRef NameField, StringRef ValueField, + const std::vector<Record *> &Items) { + for (auto EntryRec : Items) { + StringRef Name; + if (NameField.empty()) + Name = EntryRec->getName(); + else + Name = EntryRec->getValueAsString(NameField); + + int64_t Value = 0; + if (!ValueField.empty()) + Value = getInt(EntryRec, ValueField); + + Enum.Entries.push_back(llvm::make_unique<GenericEnum::Entry>(Name, Value)); + Enum.EntryMap.insert(std::make_pair(EntryRec, Enum.Entries.back().get())); + } - OS << "#ifdef GET_" << TableName.upper() << "_IMPL\n"; - OS << "#undef GET_" << TableName.upper() << "_IMPL\n"; + if (ValueField.empty()) { + std::stable_sort(Enum.Entries.begin(), Enum.Entries.end(), + [](const std::unique_ptr<GenericEnum::Entry> &LHS, + const std::unique_ptr<GenericEnum::Entry> &RHS) { + return LHS->first < RHS->first; + }); - // The primary data table contains all the fields defined for this map. - emitPrimaryTable(TableName, FieldNames, SearchFieldNames, SearchTables, Items, - OS); + for (size_t i = 0; i < Enum.Entries.size(); ++i) + Enum.Entries[i]->second = i; + } +} - // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary - // search can be performed by "Thing". - for (unsigned i = 0; i < SearchTables.size(); ++i) { - emitSearchTable(TableName, SearchFieldNames[i], SearchTables[i], OS); - emitLookupFunction(TableName, SearchFieldNames[i], SearchTables[i][0].first, - OS); +void SearchableTableEmitter::collectTableEntries( + GenericTable &Table, const std::vector<Record *> &Items) { + for (auto EntryRec : Items) { + for (auto &Field : Table.Fields) { + auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name)); + if (!TI) { + PrintFatalError(Twine("Record '") + EntryRec->getName() + + "' in table '" + Table.Name + "' is missing field '" + + Field.Name + "'"); + } + if (!Field.RecType) { + Field.RecType = TI->getType(); + } else { + RecTy *Ty = resolveTypes(Field.RecType, TI->getType()); + if (!Ty) + PrintFatalError(Twine("Field '") + Field.Name + "' of table '" + + Table.Name + "' has incompatible type: " + + Ty->getAsString() + " vs. " + + TI->getType()->getAsString()); + Field.RecType = Ty; + } + } + + Table.Entries.push_back(EntryRec); } - OS << "#endif\n"; + Record *IntrinsicClass = Records.getClass("Intrinsic"); + Record *InstructionClass = Records.getClass("Instruction"); + for (auto &Field : Table.Fields) { + if (auto RecordTy = dyn_cast<RecordRecTy>(Field.RecType)) { + if (IntrinsicClass && RecordTy->isSubClassOf(IntrinsicClass)) + Field.IsIntrinsic = true; + else if (InstructionClass && RecordTy->isSubClassOf(InstructionClass)) + Field.IsInstruction = true; + } + } } void SearchableTableEmitter::run(raw_ostream &OS) { - // Tables are defined to be the direct descendents of "SearchableEntry". + // Emit tables in a deterministic order to avoid needless rebuilds. + SmallVector<std::unique_ptr<GenericTable>, 4> Tables; + DenseMap<Record *, GenericTable *> TableMap; + + // Collect all definitions first. + for (auto EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) { + StringRef NameField; + if (!EnumRec->isValueUnset("NameField")) + NameField = EnumRec->getValueAsString("NameField"); + + StringRef ValueField; + if (!EnumRec->isValueUnset("ValueField")) + ValueField = EnumRec->getValueAsString("ValueField"); + + auto Enum = llvm::make_unique<GenericEnum>(); + Enum->Name = EnumRec->getName(); + Enum->PreprocessorGuard = EnumRec->getName(); + + StringRef FilterClass = EnumRec->getValueAsString("FilterClass"); + Enum->Class = Records.getClass(FilterClass); + if (!Enum->Class) + PrintFatalError(Twine("Enum FilterClass '") + FilterClass + + "' does not exist"); + + collectEnumEntries(*Enum, NameField, ValueField, + Records.getAllDerivedDefinitions(FilterClass)); + EnumMap.insert(std::make_pair(EnumRec, Enum.get())); + Enums.emplace_back(std::move(Enum)); + } + + for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) { + auto Table = llvm::make_unique<GenericTable>(); + Table->Name = TableRec->getName(); + Table->PreprocessorGuard = TableRec->getName(); + Table->CppTypeName = TableRec->getValueAsString("CppTypeName"); + + std::vector<StringRef> Fields = TableRec->getValueAsListOfStrings("Fields"); + for (const auto &FieldName : Fields) { + Table->Fields.emplace_back(FieldName); + + if (auto TypeOfVal = TableRec->getValue(("TypeOf_" + FieldName).str())) { + if (!parseFieldType(Table->Fields.back(), TypeOfVal->getValue())) { + PrintFatalError(Twine("Table '") + Table->Name + + "' has bad 'TypeOf_" + FieldName + "': " + + TypeOfVal->getValue()->getAsString()); + } + } + } + + collectTableEntries(*Table, Records.getAllDerivedDefinitions( + TableRec->getValueAsString("FilterClass"))); + + if (!TableRec->isValueUnset("PrimaryKey")) { + Table->PrimaryKey = + parseSearchIndex(*Table, TableRec->getValueAsString("PrimaryKeyName"), + TableRec->getValueAsListOfStrings("PrimaryKey"), + TableRec->getValueAsBit("PrimaryKeyEarlyOut")); + + std::stable_sort(Table->Entries.begin(), Table->Entries.end(), + [&](Record *LHS, Record *RHS) { + return compareBy(LHS, RHS, *Table->PrimaryKey); + }); + } + + TableMap.insert(std::make_pair(TableRec, Table.get())); + Tables.emplace_back(std::move(Table)); + } + + for (Record *IndexRec : Records.getAllDerivedDefinitions("SearchIndex")) { + Record *TableRec = IndexRec->getValueAsDef("Table"); + auto It = TableMap.find(TableRec); + if (It == TableMap.end()) + PrintFatalError(Twine("SearchIndex '") + IndexRec->getName() + + "' refers to non-existing table '" + TableRec->getName()); + + GenericTable &Table = *It->second; + Table.Indices.push_back(parseSearchIndex( + Table, IndexRec->getName(), IndexRec->getValueAsListOfStrings("Key"), + IndexRec->getValueAsBit("EarlyOut"))); + } + + // Translate legacy tables. Record *SearchableTable = Records.getClass("SearchableTable"); for (auto &NameRec : Records.getClasses()) { Record *Class = NameRec.second.get(); if (Class->getSuperClasses().size() != 1 || !Class->isSubClassOf(SearchableTable)) continue; - emitMapping(Class, OS); + + StringRef TableName = Class->getName(); + std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName); + if (!Class->isValueUnset("EnumNameField")) { + StringRef NameField = Class->getValueAsString("EnumNameField"); + StringRef ValueField; + if (!Class->isValueUnset("EnumValueField")) + ValueField = Class->getValueAsString("EnumValueField"); + + auto Enum = llvm::make_unique<GenericEnum>(); + Enum->Name = (Twine(Class->getName()) + "Values").str(); + Enum->PreprocessorGuard = Class->getName().upper(); + Enum->Class = Class; + + collectEnumEntries(*Enum, NameField, ValueField, Items); + + Enums.emplace_back(std::move(Enum)); + } + + auto Table = llvm::make_unique<GenericTable>(); + Table->Name = (Twine(Class->getName()) + "sList").str(); + Table->PreprocessorGuard = Class->getName().upper(); + Table->CppTypeName = Class->getName(); + + for (const RecordVal &Field : Class->getValues()) { + std::string FieldName = Field.getName(); + + // Skip uninteresting fields: either special to us, or injected + // template parameters (if they contain a ':'). + if (FieldName.find(':') != std::string::npos || + FieldName == "SearchableFields" || FieldName == "EnumNameField" || + FieldName == "EnumValueField") + continue; + + Table->Fields.emplace_back(FieldName); + } + + collectTableEntries(*Table, Items); + + for (const auto &Field : + Class->getValueAsListOfStrings("SearchableFields")) { + std::string Name = + (Twine("lookup") + Table->CppTypeName + "By" + Field).str(); + Table->Indices.push_back(parseSearchIndex(*Table, Name, {Field}, false)); + } + + Tables.emplace_back(std::move(Table)); } + + // Emit everything. + for (const auto &Enum : Enums) + emitGenericEnum(*Enum, OS); + + for (const auto &Table : Tables) + emitGenericTable(*Table, OS); + + // Put all #undefs last, to allow multiple sections guarded by the same + // define. + for (const auto &Guard : PreprocessorGuards) + OS << "#undef " << Guard << "\n"; } namespace llvm { diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 2c5658f8ce75..c5da8d8142ff 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -13,6 +13,7 @@ #include "CodeGenTarget.h" #include "CodeGenSchedule.h" +#include "PredicateExpander.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" @@ -90,8 +91,14 @@ class SubtargetEmitter { void EmitItineraries(raw_ostream &OS, std::vector<std::vector<InstrItinerary>> &ProcItinLists); + unsigned EmitRegisterFileTables(const CodeGenProcModel &ProcModel, + raw_ostream &OS); + void EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel, + raw_ostream &OS); void EmitProcessorProp(raw_ostream &OS, const Record *R, StringRef Name, char Separator); + void EmitProcessorResourceSubUnits(const CodeGenProcModel &ProcModel, + raw_ostream &OS); void EmitProcessorResources(const CodeGenProcModel &ProcModel, raw_ostream &OS); Record *FindWriteResources(const CodeGenSchedRW &SchedWrite, @@ -106,6 +113,10 @@ class SubtargetEmitter { void EmitProcessorModels(raw_ostream &OS); void EmitProcessorLookup(raw_ostream &OS); void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS); + void emitSchedModelHelpersImpl(raw_ostream &OS, + bool OnlyExpandMCInstPredicates = false); + void emitGenMCSubtargetInfo(raw_ostream &OS); + void EmitSchedModel(raw_ostream &OS); void EmitHwModeCheck(const std::string &ClassName, raw_ostream &OS); void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, @@ -128,7 +139,7 @@ void SubtargetEmitter::Enumeration(raw_ostream &OS) { // Get all records of class and sort std::vector<Record*> DefList = Records.getAllDerivedDefinitions("SubtargetFeature"); - std::sort(DefList.begin(), DefList.end(), LessRecord()); + llvm::sort(DefList.begin(), DefList.end(), LessRecord()); unsigned N = DefList.size(); if (N == 0) @@ -167,7 +178,7 @@ unsigned SubtargetEmitter::FeatureKeyValues(raw_ostream &OS) { if (FeatureList.empty()) return 0; - std::sort(FeatureList.begin(), FeatureList.end(), LessRecordFieldName()); + llvm::sort(FeatureList.begin(), FeatureList.end(), LessRecordFieldName()); // Begin feature table OS << "// Sorted (by key) array of values for CPU features.\n" @@ -192,8 +203,7 @@ unsigned SubtargetEmitter::FeatureKeyValues(raw_ostream &OS) { << "\"" << Desc << "\", " << "{ " << Target << "::" << Name << " }, "; - const std::vector<Record*> &ImpliesList = - Feature->getValueAsListOfDefs("Implies"); + RecVec ImpliesList = Feature->getValueAsListOfDefs("Implies"); OS << "{"; for (unsigned j = 0, M = ImpliesList.size(); j < M;) { @@ -218,7 +228,7 @@ unsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) { // Gather and sort processor information std::vector<Record*> ProcessorList = Records.getAllDerivedDefinitions("Processor"); - std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); + llvm::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); // Begin processor table OS << "// Sorted (by key) array of values for CPU subtype.\n" @@ -228,8 +238,7 @@ unsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) { // For each processor for (Record *Processor : ProcessorList) { StringRef Name = Processor->getValueAsString("Name"); - const std::vector<Record*> &FeatureList = - Processor->getValueAsListOfDefs("Features"); + RecVec FeatureList = Processor->getValueAsListOfDefs("Features"); // Emit as { "cpu", "description", { f1 , f2 , ... fn } }, OS << " { " @@ -261,8 +270,7 @@ void SubtargetEmitter::FormItineraryStageString(const std::string &Name, std::string &ItinString, unsigned &NStages) { // Get states list - const std::vector<Record*> &StageList = - ItinData->getValueAsListOfDefs("Stages"); + RecVec StageList = ItinData->getValueAsListOfDefs("Stages"); // For each stage unsigned N = NStages = StageList.size(); @@ -275,7 +283,7 @@ void SubtargetEmitter::FormItineraryStageString(const std::string &Name, ItinString += " { " + itostr(Cycles) + ", "; // Get unit list - const std::vector<Record*> &UnitList = Stage->getValueAsListOfDefs("Units"); + RecVec UnitList = Stage->getValueAsListOfDefs("Units"); // For each unit for (unsigned j = 0, M = UnitList.size(); j < M;) { @@ -304,7 +312,7 @@ void SubtargetEmitter::FormItineraryStageString(const std::string &Name, void SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString, unsigned &NOperandCycles) { // Get operand cycle list - const std::vector<int64_t> &OperandCycleList = + std::vector<int64_t> OperandCycleList = ItinData->getValueAsListOfInts("OperandCycles"); // For each operand cycle @@ -322,8 +330,7 @@ void SubtargetEmitter::FormItineraryBypassString(const std::string &Name, Record *ItinData, std::string &ItinString, unsigned NOperandCycles) { - const std::vector<Record*> &BypassList = - ItinData->getValueAsListOfDefs("Bypasses"); + RecVec BypassList = ItinData->getValueAsListOfDefs("Bypasses"); unsigned N = BypassList.size(); unsigned i = 0; for (; i < N;) { @@ -354,7 +361,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, if (!ItinsDefSet.insert(ProcModel.ItinsDef).second) continue; - std::vector<Record*> FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU"); + RecVec FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU"); if (FUs.empty()) continue; @@ -368,9 +375,9 @@ EmitStageAndOperandCycleData(raw_ostream &OS, OS << "} // end namespace " << Name << "FU\n"; - std::vector<Record*> BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP"); + RecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP"); if (!BPs.empty()) { - OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name + OS << "\n// Pipeline forwarding paths for itineraries \"" << Name << "\"\n" << "namespace " << Name << "Bypass {\n"; OS << " const unsigned NoBypass = 0;\n"; @@ -442,7 +449,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, } // Check to see if stage already exists and create if it doesn't - unsigned FindStage = 0; + uint16_t FindStage = 0; if (NStages > 0) { FindStage = ItinStageMap[ItinStageString]; if (FindStage == 0) { @@ -458,7 +465,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, } // Check to see if operand cycle already exists and create if it doesn't - unsigned FindOperandCycle = 0; + uint16_t FindOperandCycle = 0; if (NOperandCycles > 0) { std::string ItinOperandString = ItinOperandCycleString+ItinBypassString; FindOperandCycle = ItinOperandMap[ItinOperandString]; @@ -480,10 +487,14 @@ EmitStageAndOperandCycleData(raw_ostream &OS, } // Set up itinerary as location and location + stage count - int NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0; - InstrItinerary Intinerary = { NumUOps, FindStage, FindStage + NStages, - FindOperandCycle, - FindOperandCycle + NOperandCycles }; + int16_t NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0; + InstrItinerary Intinerary = { + NumUOps, + FindStage, + uint16_t(FindStage + NStages), + FindOperandCycle, + uint16_t(FindOperandCycle + NOperandCycles), + }; // Inject - empty slots will be 0, 0 ItinList[SchedClassIdx] = Intinerary; @@ -559,7 +570,8 @@ EmitItineraries(raw_ostream &OS, ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n"; } // End processor itinerary table - OS << " { 0, ~0U, ~0U, ~0U, ~0U } // end marker\n"; + OS << " { 0, uint16_t(~0U), uint16_t(~0U), uint16_t(~0U), uint16_t(~0U) }" + "// end marker\n"; OS << "};\n"; } } @@ -578,24 +590,216 @@ void SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R, OS << '\n'; } +void SubtargetEmitter::EmitProcessorResourceSubUnits( + const CodeGenProcModel &ProcModel, raw_ostream &OS) { + OS << "\nstatic const unsigned " << ProcModel.ModelName + << "ProcResourceSubUnits[] = {\n" + << " 0, // Invalid\n"; + + for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { + Record *PRDef = ProcModel.ProcResourceDefs[i]; + if (!PRDef->isSubClassOf("ProcResGroup")) + continue; + RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources"); + for (Record *RUDef : ResUnits) { + Record *const RU = + SchedModels.findProcResUnits(RUDef, ProcModel, PRDef->getLoc()); + for (unsigned J = 0; J < RU->getValueAsInt("NumUnits"); ++J) { + OS << " " << ProcModel.getProcResourceIdx(RU) << ", "; + } + } + OS << " // " << PRDef->getName() << "\n"; + } + OS << "};\n"; +} + +static void EmitRetireControlUnitInfo(const CodeGenProcModel &ProcModel, + raw_ostream &OS) { + int64_t ReorderBufferSize = 0, MaxRetirePerCycle = 0; + if (Record *RCU = ProcModel.RetireControlUnit) { + ReorderBufferSize = + std::max(ReorderBufferSize, RCU->getValueAsInt("ReorderBufferSize")); + MaxRetirePerCycle = + std::max(MaxRetirePerCycle, RCU->getValueAsInt("MaxRetirePerCycle")); + } + + OS << ReorderBufferSize << ", // ReorderBufferSize\n "; + OS << MaxRetirePerCycle << ", // MaxRetirePerCycle\n "; +} + +static void EmitRegisterFileInfo(const CodeGenProcModel &ProcModel, + unsigned NumRegisterFiles, + unsigned NumCostEntries, raw_ostream &OS) { + if (NumRegisterFiles) + OS << ProcModel.ModelName << "RegisterFiles,\n " << (1 + NumRegisterFiles); + else + OS << "nullptr,\n 0"; + + OS << ", // Number of register files.\n "; + if (NumCostEntries) + OS << ProcModel.ModelName << "RegisterCosts,\n "; + else + OS << "nullptr,\n "; + OS << NumCostEntries << ", // Number of register cost entries.\n"; +} + +unsigned +SubtargetEmitter::EmitRegisterFileTables(const CodeGenProcModel &ProcModel, + raw_ostream &OS) { + if (llvm::all_of(ProcModel.RegisterFiles, [](const CodeGenRegisterFile &RF) { + return RF.hasDefaultCosts(); + })) + return 0; + + // Print the RegisterCost table first. + OS << "\n// {RegisterClassID, Register Cost}\n"; + OS << "static const llvm::MCRegisterCostEntry " << ProcModel.ModelName + << "RegisterCosts" + << "[] = {\n"; + + for (const CodeGenRegisterFile &RF : ProcModel.RegisterFiles) { + // Skip register files with a default cost table. + if (RF.hasDefaultCosts()) + continue; + // Add entries to the cost table. + for (const CodeGenRegisterCost &RC : RF.Costs) { + OS << " { "; + Record *Rec = RC.RCDef; + if (Rec->getValue("Namespace")) + OS << Rec->getValueAsString("Namespace") << "::"; + OS << Rec->getName() << "RegClassID, " << RC.Cost << "},\n"; + } + } + OS << "};\n"; + + // Now generate a table with register file info. + OS << "\n // {Name, #PhysRegs, #CostEntries, IndexToCostTbl}\n"; + OS << "static const llvm::MCRegisterFileDesc " << ProcModel.ModelName + << "RegisterFiles" + << "[] = {\n" + << " { \"InvalidRegisterFile\", 0, 0, 0 },\n"; + unsigned CostTblIndex = 0; + + for (const CodeGenRegisterFile &RD : ProcModel.RegisterFiles) { + OS << " { "; + OS << '"' << RD.Name << '"' << ", " << RD.NumPhysRegs << ", "; + unsigned NumCostEntries = RD.Costs.size(); + OS << NumCostEntries << ", " << CostTblIndex << "},\n"; + CostTblIndex += NumCostEntries; + } + OS << "};\n"; + + return CostTblIndex; +} + +static bool EmitPfmIssueCountersTable(const CodeGenProcModel &ProcModel, + raw_ostream &OS) { + unsigned NumCounterDefs = 1 + ProcModel.ProcResourceDefs.size(); + std::vector<const Record *> CounterDefs(NumCounterDefs); + bool HasCounters = false; + for (const Record *CounterDef : ProcModel.PfmIssueCounterDefs) { + const Record *&CD = CounterDefs[ProcModel.getProcResourceIdx( + CounterDef->getValueAsDef("Resource"))]; + if (CD) { + PrintFatalError(CounterDef->getLoc(), + "multiple issue counters for " + + CounterDef->getValueAsDef("Resource")->getName()); + } + CD = CounterDef; + HasCounters = true; + } + if (!HasCounters) { + return false; + } + OS << "\nstatic const char* " << ProcModel.ModelName + << "PfmIssueCounters[] = {\n"; + for (unsigned i = 0; i != NumCounterDefs; ++i) { + const Record *CounterDef = CounterDefs[i]; + if (CounterDef) { + const auto PfmCounters = CounterDef->getValueAsListOfStrings("Counters"); + if (PfmCounters.empty()) + PrintFatalError(CounterDef->getLoc(), "empty counter list"); + OS << " \"" << PfmCounters[0]; + for (unsigned p = 1, e = PfmCounters.size(); p != e; ++p) + OS << ",\" \"" << PfmCounters[p]; + OS << "\", // #" << i << " = "; + OS << CounterDef->getValueAsDef("Resource")->getName() << "\n"; + } else { + OS << " nullptr, // #" << i << "\n"; + } + } + OS << "};\n"; + return true; +} + +static void EmitPfmCounters(const CodeGenProcModel &ProcModel, + const bool HasPfmIssueCounters, raw_ostream &OS) { + OS << " {\n"; + // Emit the cycle counter. + if (ProcModel.PfmCycleCounterDef) + OS << " \"" << ProcModel.PfmCycleCounterDef->getValueAsString("Counter") + << "\", // Cycle counter.\n"; + else + OS << " nullptr, // No cycle counter.\n"; + + // Emit a reference to issue counters table. + if (HasPfmIssueCounters) + OS << " " << ProcModel.ModelName << "PfmIssueCounters\n"; + else + OS << " nullptr // No issue counters.\n"; + OS << " }\n"; +} + +void SubtargetEmitter::EmitExtraProcessorInfo(const CodeGenProcModel &ProcModel, + raw_ostream &OS) { + // Generate a table of register file descriptors (one entry per each user + // defined register file), and a table of register costs. + unsigned NumCostEntries = EmitRegisterFileTables(ProcModel, OS); + + // Generate a table of ProcRes counter names. + const bool HasPfmIssueCounters = EmitPfmIssueCountersTable(ProcModel, OS); + + // Now generate a table for the extra processor info. + OS << "\nstatic const llvm::MCExtraProcessorInfo " << ProcModel.ModelName + << "ExtraInfo = {\n "; + + // Add information related to the retire control unit. + EmitRetireControlUnitInfo(ProcModel, OS); + + // Add information related to the register files (i.e. where to find register + // file descriptors and register costs). + EmitRegisterFileInfo(ProcModel, ProcModel.RegisterFiles.size(), + NumCostEntries, OS); + + EmitPfmCounters(ProcModel, HasPfmIssueCounters, OS); + + OS << "};\n"; +} + void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, raw_ostream &OS) { - OS << "\n// {Name, NumUnits, SuperIdx, IsBuffered}\n"; - OS << "static const llvm::MCProcResourceDesc " - << ProcModel.ModelName << "ProcResources" << "[] = {\n" - << " {DBGFIELD(\"InvalidUnit\") 0, 0, 0},\n"; + EmitProcessorResourceSubUnits(ProcModel, OS); + OS << "\n// {Name, NumUnits, SuperIdx, IsBuffered, SubUnitsIdxBegin}\n"; + OS << "static const llvm::MCProcResourceDesc " << ProcModel.ModelName + << "ProcResources" + << "[] = {\n" + << " {\"InvalidUnit\", 0, 0, 0, 0},\n"; + + unsigned SubUnitsOffset = 1; for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) { Record *PRDef = ProcModel.ProcResourceDefs[i]; Record *SuperDef = nullptr; unsigned SuperIdx = 0; unsigned NumUnits = 0; + const unsigned SubUnitsBeginOffset = SubUnitsOffset; int BufferSize = PRDef->getValueAsInt("BufferSize"); if (PRDef->isSubClassOf("ProcResGroup")) { RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources"); for (Record *RU : ResUnits) { NumUnits += RU->getValueAsInt("NumUnits"); + SubUnitsOffset += RU->getValueAsInt("NumUnits"); } } else { @@ -609,11 +813,17 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel, NumUnits = PRDef->getValueAsInt("NumUnits"); } // Emit the ProcResourceDesc - OS << " {DBGFIELD(\"" << PRDef->getName() << "\") "; + OS << " {\"" << PRDef->getName() << "\", "; if (PRDef->getName().size() < 15) OS.indent(15 - PRDef->getName().size()); - OS << NumUnits << ", " << SuperIdx << ", " - << BufferSize << "}, // #" << i+1; + OS << NumUnits << ", " << SuperIdx << ", " << BufferSize << ", "; + if (SubUnitsBeginOffset != SubUnitsOffset) { + OS << ProcModel.ModelName << "ProcResourceSubUnits + " + << SubUnitsBeginOffset; + } else { + OS << "nullptr"; + } + OS << "}, // #" << i+1; if (SuperDef) OS << ", Super=" << SuperDef->getName(); OS << "\n"; @@ -731,8 +941,7 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, void SubtargetEmitter::ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles, const CodeGenProcModel &PM) { - // Default to 1 resource cycle. - Cycles.resize(PRVec.size(), 1); + assert(PRVec.size() == Cycles.size() && "failed precondition"); for (unsigned i = 0, e = PRVec.size(); i != e; ++i) { Record *PRDef = PRVec[i]; RecVec SubResources; @@ -783,9 +992,9 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, return; std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back(); - DEBUG(dbgs() << "\n+++ SCHED CLASSES (GenSchedClassTables) +++\n"); + LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (GenSchedClassTables) +++\n"); for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { - DEBUG(SC.dump(&SchedModels)); + LLVM_DEBUG(SC.dump(&SchedModels)); SCTab.resize(SCTab.size() + 1); MCSchedClassDesc &SCDesc = SCTab.back(); @@ -823,7 +1032,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, IdxVec Writes = SC.Writes; IdxVec Reads = SC.Reads; if (!SC.InstRWs.empty()) { - // This class has a default ReadWrite list which can be overriden by + // This class has a default ReadWrite list which can be overridden by // InstRW definitions. Record *RWDef = nullptr; for (Record *RW : SC.InstRWs) { @@ -851,8 +1060,9 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, } } if (Writes.empty()) { - DEBUG(dbgs() << ProcModel.ModelName - << " does not have resources for class " << SC.Name << '\n'); + LLVM_DEBUG(dbgs() << ProcModel.ModelName + << " does not have resources for class " << SC.Name + << '\n'); } } // Sum resources across all operand writes. @@ -900,6 +1110,21 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, std::vector<int64_t> Cycles = WriteRes->getValueAsListOfInts("ResourceCycles"); + if (Cycles.empty()) { + // If ResourceCycles is not provided, default to one cycle per + // resource. + Cycles.resize(PRVec.size(), 1); + } else if (Cycles.size() != PRVec.size()) { + // If ResourceCycles is provided, check consistency. + PrintFatalError( + WriteRes->getLoc(), + Twine("Inconsistent resource cycles: !size(ResourceCycles) != " + "!size(ProcResources): ") + .concat(Twine(PRVec.size())) + .concat(" vs ") + .concat(Twine(Cycles.size()))); + } + ExpandProcResources(PRVec, Cycles, ProcModel); for (unsigned PRIdx = 0, PREnd = PRVec.size(); @@ -949,7 +1174,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, WriteIDs.push_back(SchedModels.getSchedRWIdx(VW, /*IsRead=*/false)); } } - std::sort(WriteIDs.begin(), WriteIDs.end()); + llvm::sort(WriteIDs.begin(), WriteIDs.end()); for(unsigned W : WriteIDs) { MCReadAdvanceEntry RAEntry; RAEntry.UseIdx = UseIdx; @@ -967,8 +1192,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel, // compression. // // WritePrecRes entries are sorted by ProcResIdx. - std::sort(WriteProcResources.begin(), WriteProcResources.end(), - LessWriteProcResources()); + llvm::sort(WriteProcResources.begin(), WriteProcResources.end(), + LessWriteProcResources()); SCDesc.NumWriteProcResEntries = WriteProcResources.size(); std::vector<MCWriteProcResEntry>::iterator WPRPos = @@ -1119,6 +1344,9 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { // For each processor model. for (const CodeGenProcModel &PM : SchedModels.procModels()) { + // Emit extra processor info if available. + if (PM.hasExtraProcessorInfo()) + EmitExtraProcessorInfo(PM, OS); // Emit processor resource table. if (PM.hasInstrSchedModel()) EmitProcessorResources(PM, OS); @@ -1159,9 +1387,13 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { OS << " nullptr, nullptr, 0, 0," << " // No instruction-level machine model.\n"; if (PM.hasItineraries()) - OS << " " << PM.ItinsDef->getName() << "\n"; + OS << " " << PM.ItinsDef->getName() << ",\n"; + else + OS << " nullptr, // No Itinerary\n"; + if (PM.hasExtraProcessorInfo()) + OS << " &" << PM.ModelName << "ExtraInfo,\n"; else - OS << " nullptr // No Itinerary\n"; + OS << " nullptr // No extra processor descriptor\n"; OS << "};\n"; } } @@ -1173,7 +1405,7 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { // Gather and sort processor information std::vector<Record*> ProcessorList = Records.getAllDerivedDefinitions("Processor"); - std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); + llvm::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName()); // Begin processor table OS << "\n"; @@ -1231,58 +1463,111 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { OS << "\n#undef DBGFIELD"; } -void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, - raw_ostream &OS) { - OS << "unsigned " << ClassName - << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," - << " const TargetSchedModel *SchedModel) const {\n"; +static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) { + std::string Buffer; + raw_string_ostream Stream(Buffer); + + // Collect all the PredicateProlog records and print them to the output + // stream. + std::vector<Record *> Prologs = + Records.getAllDerivedDefinitions("PredicateProlog"); + llvm::sort(Prologs.begin(), Prologs.end(), LessRecord()); + for (Record *P : Prologs) + Stream << P->getValueAsString("Code") << '\n'; - std::vector<Record*> Prologs = Records.getAllDerivedDefinitions("PredicateProlog"); - std::sort(Prologs.begin(), Prologs.end(), LessRecord()); - for (Record *P : Prologs) { - OS << P->getValueAsString("Code") << '\n'; + Stream.flush(); + OS << Buffer; +} + +static void emitPredicates(const CodeGenSchedTransition &T, + const CodeGenSchedClass &SC, + PredicateExpander &PE, + raw_ostream &OS) { + std::string Buffer; + raw_string_ostream StringStream(Buffer); + formatted_raw_ostream FOS(StringStream); + + FOS.PadToColumn(6); + FOS << "if ("; + for (RecIter RI = T.PredTerm.begin(), RE = T.PredTerm.end(); RI != RE; ++RI) { + if (RI != T.PredTerm.begin()) { + FOS << "\n"; + FOS.PadToColumn(8); + FOS << "&& "; + } + const Record *Rec = *RI; + if (Rec->isSubClassOf("MCSchedPredicate")) + PE.expandPredicate(FOS, Rec->getValueAsDef("Pred")); + else + FOS << "(" << Rec->getValueAsString("Predicate") << ")"; } + + FOS << ")\n"; + FOS.PadToColumn(8); + FOS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n'; + FOS.flush(); + OS << Buffer; +} + +void SubtargetEmitter::emitSchedModelHelpersImpl( + raw_ostream &OS, bool OnlyExpandMCInstPredicates) { + // Collect Variant Classes. IdxVec VariantClasses; for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { if (SC.Transitions.empty()) continue; VariantClasses.push_back(SC.Index); } + if (!VariantClasses.empty()) { - OS << " switch (SchedClass) {\n"; + bool FoundPredicates = false; for (unsigned VC : VariantClasses) { + // Emit code for each variant scheduling class. const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC); - OS << " case " << VC << ": // " << SC.Name << '\n'; IdxVec ProcIndices; for (const CodeGenSchedTransition &T : SC.Transitions) { + if (OnlyExpandMCInstPredicates && + !all_of(T.PredTerm, [](const Record *Rec) { + return Rec->isSubClassOf("MCSchedPredicate"); + })) + continue; + IdxVec PI; std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(), ProcIndices.begin(), ProcIndices.end(), std::back_inserter(PI)); ProcIndices.swap(PI); } + if (ProcIndices.empty()) + continue; + + // Emit a switch statement only if there are predicates to expand. + if (!FoundPredicates) { + OS << " switch (SchedClass) {\n"; + FoundPredicates = true; + } + + OS << " case " << VC << ": // " << SC.Name << '\n'; + PredicateExpander PE; + PE.setByRef(false); + PE.setExpandForMC(OnlyExpandMCInstPredicates); for (unsigned PI : ProcIndices) { OS << " "; - if (PI != 0) - OS << "if (SchedModel->getProcessorID() == " << PI << ") "; - OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName - << '\n'; + if (PI != 0) { + OS << (OnlyExpandMCInstPredicates + ? "if (CPUID == " + : "if (SchedModel->getProcessorID() == "); + OS << PI << ") "; + } + OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName << '\n'; + for (const CodeGenSchedTransition &T : SC.Transitions) { - if (PI != 0 && !std::count(T.ProcIndices.begin(), - T.ProcIndices.end(), PI)) { - continue; - } - OS << " if ("; - for (RecIter RI = T.PredTerm.begin(), RE = T.PredTerm.end(); - RI != RE; ++RI) { - if (RI != T.PredTerm.begin()) - OS << "\n && "; - OS << "(" << (*RI)->getValueAsString("Predicate") << ")"; - } - OS << ")\n" - << " return " << T.ToClassIdx << "; // " - << SchedModels.getSchedClass(T.ToClassIdx).Name << '\n'; + if (PI != 0 && !count(T.ProcIndices, PI)) + continue; + PE.setIndentLevel(4); + emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS); } + OS << " }\n"; if (PI == 0) break; @@ -1291,10 +1576,40 @@ void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, OS << " return " << SC.Index << ";\n"; OS << " break;\n"; } - OS << " };\n"; + + if (FoundPredicates) + OS << " };\n"; } - OS << " report_fatal_error(\"Expected a variant SchedClass\");\n" - << "} // " << ClassName << "::resolveSchedClass\n"; + + if (OnlyExpandMCInstPredicates) { + OS << " // Don't know how to resolve this scheduling class.\n" + << " return 0;\n"; + return; + } + + OS << " report_fatal_error(\"Expected a variant SchedClass\");\n"; +} + +void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, + raw_ostream &OS) { + OS << "unsigned " << ClassName + << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," + << " const TargetSchedModel *SchedModel) const {\n"; + + // Emit the predicate prolog code. + emitPredicateProlog(Records, OS); + + // Emit target predicates. + emitSchedModelHelpersImpl(OS); + + OS << "} // " << ClassName << "::resolveSchedClass\n\n"; + + OS << "unsigned " << ClassName + << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI," + << " unsigned CPUID) const {\n" + << " return " << Target << "_MC" + << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID);\n" + << "} // " << ClassName << "::resolveVariantSchedClass\n"; } void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName, @@ -1322,15 +1637,15 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, unsigned NumProcs) { std::vector<Record*> Features = Records.getAllDerivedDefinitions("SubtargetFeature"); - std::sort(Features.begin(), Features.end(), LessRecord()); + llvm::sort(Features.begin(), Features.end(), LessRecord()); OS << "// ParseSubtargetFeatures - Parses features string setting specified\n" << "// subtarget options.\n" << "void llvm::"; OS << Target; OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n" - << " DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" - << " DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n"; + << " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n" + << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n"; if (Features.empty()) { OS << "}\n"; @@ -1360,6 +1675,34 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, OS << "}\n"; } +void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) { + OS << "namespace " << Target << "_MC {\n" + << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n" + << " const MCInst *MI, unsigned CPUID) {\n"; + emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true); + OS << "}\n"; + OS << "} // end of namespace " << Target << "_MC\n\n"; + + OS << "struct " << Target + << "GenMCSubtargetInfo : public MCSubtargetInfo {\n"; + OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT, \n" + << " StringRef CPU, StringRef FS, ArrayRef<SubtargetFeatureKV> PF,\n" + << " ArrayRef<SubtargetFeatureKV> PD,\n" + << " const SubtargetInfoKV *ProcSched,\n" + << " const MCWriteProcResEntry *WPR,\n" + << " const MCWriteLatencyEntry *WL,\n" + << " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n" + << " const unsigned *OC, const unsigned *FP) :\n" + << " MCSubtargetInfo(TT, CPU, FS, PF, PD, ProcSched,\n" + << " WPR, WL, RA, IS, OC, FP) { }\n\n" + << " unsigned resolveVariantSchedClass(unsigned SchedClass,\n" + << " const MCInst *MI, unsigned CPUID) const override {\n" + << " return " << Target << "_MC" + << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID); \n"; + OS << " }\n"; + OS << "};\n"; +} + // // SubtargetEmitter::run - Main subtarget enumeration emitter. // @@ -1392,10 +1735,12 @@ void SubtargetEmitter::run(raw_ostream &OS) { #endif // MCInstrInfo initialization routine. + emitGenMCSubtargetInfo(OS); + OS << "\nstatic inline MCSubtargetInfo *create" << Target << "MCSubtargetInfoImpl(" << "const Triple &TT, StringRef CPU, StringRef FS) {\n"; - OS << " return new MCSubtargetInfo(TT, CPU, FS, "; + OS << " return new " << Target << "GenMCSubtargetInfo(TT, CPU, FS, "; if (NumFeatures) OS << Target << "FeatureKV, "; else @@ -1438,6 +1783,10 @@ void SubtargetEmitter::run(raw_ostream &OS) { std::string ClassName = Target + "GenSubtargetInfo"; OS << "namespace llvm {\n"; OS << "class DFAPacketizer;\n"; + OS << "namespace " << Target << "_MC {\n" + << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass," + << " const MCInst *MI, unsigned CPUID);\n" + << "}\n\n"; OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n" << " explicit " << ClassName << "(const Triple &TT, StringRef CPU, " << "StringRef FS);\n" @@ -1445,6 +1794,8 @@ void SubtargetEmitter::run(raw_ostream &OS) { << " unsigned resolveSchedClass(unsigned SchedClass, " << " const MachineInstr *DefMI," << " const TargetSchedModel *SchedModel) const override;\n" + << " unsigned resolveVariantSchedClass(unsigned SchedClass," + << " const MCInst *MI, unsigned CPUID) const override;\n" << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" << " const;\n"; if (TGT.getHwModes().getNumModeIds() > 1) diff --git a/utils/TableGen/SubtargetFeatureInfo.cpp b/utils/TableGen/SubtargetFeatureInfo.cpp index 5153c35b1261..f9b8853cc117 100644 --- a/utils/TableGen/SubtargetFeatureInfo.cpp +++ b/utils/TableGen/SubtargetFeatureInfo.cpp @@ -10,6 +10,7 @@ #include "SubtargetFeatureInfo.h" #include "Types.h" +#include "llvm/Config/llvm-config.h" #include "llvm/TableGen/Record.h" #include <map> diff --git a/utils/TableGen/SubtargetFeatureInfo.h b/utils/TableGen/SubtargetFeatureInfo.h index c55c16a4031e..71e6748c863f 100644 --- a/utils/TableGen/SubtargetFeatureInfo.h +++ b/utils/TableGen/SubtargetFeatureInfo.h @@ -27,20 +27,20 @@ using SubtargetFeatureInfoMap = std::map<Record *, SubtargetFeatureInfo, LessRec /// Helper class for storing information on a subtarget feature which /// participates in instruction matching. struct SubtargetFeatureInfo { - /// \brief The predicate record for this feature. + /// The predicate record for this feature. Record *TheDef; - /// \brief An unique index assigned to represent this feature. + /// An unique index assigned to represent this feature. uint64_t Index; SubtargetFeatureInfo(Record *D, uint64_t Idx) : TheDef(D), Index(Idx) {} - /// \brief The name of the enumerated constant identifying this feature. + /// The name of the enumerated constant identifying this feature. std::string getEnumName() const { return "Feature_" + TheDef->getName().str(); } - /// \brief The name of the enumerated constant identifying the bitnumber for + /// The name of the enumerated constant identifying the bitnumber for /// this feature. std::string getEnumBitName() const { return "Feature_" + TheDef->getName().str() + "Bit"; diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index b0e0385a45c7..b78260625cb2 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -24,6 +24,7 @@ using namespace llvm; enum ActionType { PrintRecords, + DumpJSON, GenEmitter, GenRegisterInfo, GenInstrInfo, @@ -32,13 +33,16 @@ enum ActionType { GenAsmMatcher, GenDisassembler, GenPseudoLowering, + GenCompressInst, GenCallingConv, GenDAGISel, GenDFAPacketizer, GenFastISel, GenSubtarget, - GenIntrinsic, - GenTgtIntrinsic, + GenIntrinsicEnums, + GenIntrinsicImpl, + GenTgtIntrinsicEnums, + GenTgtIntrinsicImpl, PrintEnums, PrintSets, GenOptParserDefs, @@ -56,6 +60,8 @@ namespace { Action(cl::desc("Action to perform:"), cl::values(clEnumValN(PrintRecords, "print-records", "Print all records to stdout (default)"), + clEnumValN(DumpJSON, "dump-json", + "Dump all records as machine-readable JSON"), clEnumValN(GenEmitter, "gen-emitter", "Generate machine code emitter"), clEnumValN(GenRegisterInfo, "gen-register-info", @@ -72,6 +78,8 @@ namespace { "Generate disassembler"), clEnumValN(GenPseudoLowering, "gen-pseudo-lowering", "Generate pseudo instruction lowering"), + clEnumValN(GenCompressInst, "gen-compress-inst-emitter", + "Generate RISCV compressed instructions."), clEnumValN(GenAsmMatcher, "gen-asm-matcher", "Generate assembly instruction matcher"), clEnumValN(GenDAGISel, "gen-dag-isel", @@ -82,9 +90,13 @@ namespace { "Generate a \"fast\" instruction selector"), clEnumValN(GenSubtarget, "gen-subtarget", "Generate subtarget enumerations"), - clEnumValN(GenIntrinsic, "gen-intrinsic", + clEnumValN(GenIntrinsicEnums, "gen-intrinsic-enums", + "Generate intrinsic enums"), + clEnumValN(GenIntrinsicImpl, "gen-intrinsic-impl", "Generate intrinsic information"), - clEnumValN(GenTgtIntrinsic, "gen-tgt-intrinsic", + clEnumValN(GenTgtIntrinsicEnums, "gen-tgt-intrinsic-enums", + "Generate target intrinsic enums"), + clEnumValN(GenTgtIntrinsicImpl, "gen-tgt-intrinsic-impl", "Generate target intrinsic information"), clEnumValN(PrintEnums, "print-enums", "Print enum values for a class"), @@ -117,6 +129,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case PrintRecords: OS << Records; // No argument, dump all contents break; + case DumpJSON: + EmitJSON(Records, OS); + break; case GenEmitter: EmitCodeEmitter(Records, OS); break; @@ -144,6 +159,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenPseudoLowering: EmitPseudoLowering(Records, OS); break; + case GenCompressInst: + EmitCompressInst(Records, OS); + break; case GenDAGISel: EmitDAGISel(Records, OS); break; @@ -156,11 +174,17 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenSubtarget: EmitSubtarget(Records, OS); break; - case GenIntrinsic: - EmitIntrinsics(Records, OS); + case GenIntrinsicEnums: + EmitIntrinsicEnums(Records, OS); + break; + case GenIntrinsicImpl: + EmitIntrinsicImpl(Records, OS); + break; + case GenTgtIntrinsicEnums: + EmitIntrinsicEnums(Records, OS, true); break; - case GenTgtIntrinsic: - EmitIntrinsics(Records, OS, true); + case GenTgtIntrinsicImpl: + EmitIntrinsicImpl(Records, OS, true); break; case GenOptParserDefs: EmitOptParser(Records, OS); diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h index 914cd5a1fc9b..1329a6d833f4 100644 --- a/utils/TableGen/TableGenBackends.h +++ b/utils/TableGen/TableGenBackends.h @@ -62,7 +62,10 @@ namespace llvm { class raw_ostream; class RecordKeeper; -void EmitIntrinsics(RecordKeeper &RK, raw_ostream &OS, bool TargetOnly = false); +void EmitIntrinsicEnums(RecordKeeper &RK, raw_ostream &OS, + bool TargetOnly = false); +void EmitIntrinsicImpl(RecordKeeper &RK, raw_ostream &OS, + bool TargetOnly = false); void EmitAsmMatcher(RecordKeeper &RK, raw_ostream &OS); void EmitAsmWriter(RecordKeeper &RK, raw_ostream &OS); void EmitCallingConv(RecordKeeper &RK, raw_ostream &OS); @@ -74,6 +77,7 @@ void EmitFastISel(RecordKeeper &RK, raw_ostream &OS); void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS); void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS); void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS); +void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS); void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS); void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS); void EmitMapTable(RecordKeeper &RK, raw_ostream &OS); diff --git a/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp b/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp new file mode 100644 index 000000000000..df63337d5637 --- /dev/null +++ b/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp @@ -0,0 +1,116 @@ +//===- WebAssemblyDisassemblerEmitter.cpp - Disassembler tables -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is part of the WebAssembly Disassembler Emitter. +// It contains the implementation of the disassembler tables. +// Documentation for the disassembler emitter in general can be found in +// WebAssemblyDisassemblerEmitter.h. +// +//===----------------------------------------------------------------------===// + +#include "WebAssemblyDisassemblerEmitter.h" +#include "llvm/TableGen/Record.h" + +namespace llvm { + +void emitWebAssemblyDisassemblerTables( + raw_ostream &OS, + const ArrayRef<const CodeGenInstruction *> &NumberedInstructions) { + // First lets organize all opcodes by (prefix) byte. Prefix 0 is the + // starting table. + std::map<unsigned, + std::map<unsigned, std::pair<unsigned, const CodeGenInstruction *>>> + OpcodeTable; + for (unsigned I = 0; I != NumberedInstructions.size(); ++I) { + auto &CGI = *NumberedInstructions[I]; + auto &Def = *CGI.TheDef; + if (!Def.getValue("Inst")) + continue; + auto &Inst = *Def.getValueAsBitsInit("Inst"); + auto Opc = static_cast<unsigned>( + reinterpret_cast<IntInit *>(Inst.convertInitializerTo(IntRecTy::get())) + ->getValue()); + if (Opc == 0xFFFFFFFF) + continue; // No opcode defined. + assert(Opc <= 0xFFFF); + auto Prefix = Opc >> 8; + Opc = Opc & 0xFF; + auto &CGIP = OpcodeTable[Prefix][Opc]; + if (!CGIP.second || + // Make sure we store the variant with the least amount of operands, + // which is the one without explicit registers. Only few instructions + // have these currently, would be good to have for all of them. + // FIXME: this picks the first of many typed variants, which is + // currently the except_ref one, though this shouldn't matter for + // disassembly purposes. + CGIP.second->Operands.OperandList.size() > + CGI.Operands.OperandList.size()) { + CGIP = std::make_pair(I, &CGI); + } + } + OS << "#include \"MCTargetDesc/WebAssemblyMCTargetDesc.h\"\n"; + OS << "\n"; + OS << "namespace llvm {\n\n"; + OS << "enum EntryType : uint8_t { "; + OS << "ET_Unused, ET_Prefix, ET_Instruction };\n\n"; + OS << "struct WebAssemblyInstruction {\n"; + OS << " uint16_t Opcode;\n"; + OS << " EntryType ET;\n"; + OS << " uint8_t NumOperands;\n"; + OS << " uint8_t Operands[4];\n"; + OS << "};\n\n"; + // Output one table per prefix. + for (auto &PrefixPair : OpcodeTable) { + if (PrefixPair.second.empty()) + continue; + OS << "WebAssemblyInstruction InstructionTable" << PrefixPair.first; + OS << "[] = {\n"; + for (unsigned I = 0; I <= 0xFF; I++) { + auto InstIt = PrefixPair.second.find(I); + if (InstIt != PrefixPair.second.end()) { + // Regular instruction. + assert(InstIt->second.second); + auto &CGI = *InstIt->second.second; + OS << " // 0x"; + OS.write_hex(static_cast<unsigned long long>(I)); + OS << ": " << CGI.AsmString << "\n"; + OS << " { " << InstIt->second.first << ", ET_Instruction, "; + OS << CGI.Operands.OperandList.size() << ", {\n"; + for (auto &Op : CGI.Operands.OperandList) { + OS << " " << Op.OperandType << ",\n"; + } + OS << " }\n"; + } else { + auto PrefixIt = OpcodeTable.find(I); + // If we have a non-empty table for it that's not 0, this is a prefix. + if (PrefixIt != OpcodeTable.end() && I && !PrefixPair.first) { + OS << " { 0, ET_Prefix, 0, {}"; + } else { + OS << " { 0, ET_Unused, 0, {}"; + } + } + OS << " },\n"; + } + OS << "};\n\n"; + } + // Create a table of all extension tables: + OS << "struct { uint8_t Prefix; const WebAssemblyInstruction *Table; }\n"; + OS << "PrefixTable[] = {\n"; + for (auto &PrefixPair : OpcodeTable) { + if (PrefixPair.second.empty() || !PrefixPair.first) + continue; + OS << " { " << PrefixPair.first << ", InstructionTable" + << PrefixPair.first; + OS << " },\n"; + } + OS << " { 0, nullptr }\n};\n\n"; + OS << "} // End llvm namespace\n"; +} + +} // namespace llvm diff --git a/utils/TableGen/WebAssemblyDisassemblerEmitter.h b/utils/TableGen/WebAssemblyDisassemblerEmitter.h new file mode 100644 index 000000000000..91f820f120a2 --- /dev/null +++ b/utils/TableGen/WebAssemblyDisassemblerEmitter.h @@ -0,0 +1,30 @@ +//===- WebAssemblyDisassemblerEmitter.h - Disassembler tables ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is part of the WebAssembly Disassembler Emitter. +// It contains the interface of the disassembler tables. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_WEBASSEMBLYDISASSEMBLEREMITTER_H +#define LLVM_UTILS_TABLEGEN_WEBASSEMBLYDISASSEMBLEREMITTER_H + +#include "CodeGenInstruction.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +void emitWebAssemblyDisassemblerTables( + raw_ostream &OS, + const ArrayRef<const CodeGenInstruction *> &NumberedInstructions); + +} // namespace llvm + +#endif diff --git a/utils/TableGen/X86DisassemblerShared.h b/utils/TableGen/X86DisassemblerShared.h index e5889e92415d..220765f72410 100644 --- a/utils/TableGen/X86DisassemblerShared.h +++ b/utils/TableGen/X86DisassemblerShared.h @@ -13,7 +13,7 @@ #include <cstring> #include <string> -#include "../../lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h" +#include "llvm/Support/X86DisassemblerDecoderCommon.h" struct InstructionSpecifier { llvm::X86Disassembler::OperandSpecifier @@ -49,6 +49,10 @@ struct OpcodeDecision { /// entries in this table, rather than 2^(ATTR_max). struct ContextDecision { OpcodeDecision opcodeDecisions[llvm::X86Disassembler::IC_max]; + + ContextDecision() { + memset(opcodeDecisions, 0, sizeof(opcodeDecisions)); + } }; #endif diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index fce41f7a2cc2..2b5cc1279605 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -112,6 +112,10 @@ static inline bool inheritsFrom(InstructionContext child, return inheritsFrom(child, IC_64BIT_XD_OPSIZE); case IC_XS_OPSIZE: return inheritsFrom(child, IC_64BIT_XS_OPSIZE); + case IC_XD_ADSIZE: + return inheritsFrom(child, IC_64BIT_XD_ADSIZE); + case IC_XS_ADSIZE: + return inheritsFrom(child, IC_64BIT_XS_ADSIZE); case IC_64BIT_REXW: return((noPrefix && inheritsFrom(child, IC_64BIT_REXW_XS, noPrefix)) || (noPrefix && inheritsFrom(child, IC_64BIT_REXW_XD, noPrefix)) || @@ -122,12 +126,17 @@ static inline bool inheritsFrom(InstructionContext child, (!AdSize64 && inheritsFrom(child, IC_64BIT_OPSIZE_ADSIZE)) || (!AdSize64 && inheritsFrom(child, IC_64BIT_REXW_ADSIZE)); case IC_64BIT_XD: - return(inheritsFrom(child, IC_64BIT_REXW_XD)); + return(inheritsFrom(child, IC_64BIT_REXW_XD) || + (!AdSize64 && inheritsFrom(child, IC_64BIT_XD_ADSIZE))); case IC_64BIT_XS: - return(inheritsFrom(child, IC_64BIT_REXW_XS)); + return(inheritsFrom(child, IC_64BIT_REXW_XS) || + (!AdSize64 && inheritsFrom(child, IC_64BIT_XS_ADSIZE))); case IC_64BIT_XD_OPSIZE: case IC_64BIT_XS_OPSIZE: return false; + case IC_64BIT_XD_ADSIZE: + case IC_64BIT_XS_ADSIZE: + return false; case IC_64BIT_REXW_XD: case IC_64BIT_REXW_XS: case IC_64BIT_REXW_OPSIZE: @@ -642,21 +651,13 @@ static const char* stringForDecisionType(ModRMDecisionType dt) { } DisassemblerTables::DisassemblerTables() { - unsigned i; - - for (i = 0; i < array_lengthof(Tables); i++) { - Tables[i] = new ContextDecision; - memset(Tables[i], 0, sizeof(ContextDecision)); - } + for (unsigned i = 0; i < array_lengthof(Tables); i++) + Tables[i] = llvm::make_unique<ContextDecision>(); HasConflicts = false; } DisassemblerTables::~DisassemblerTables() { - unsigned i; - - for (i = 0; i < array_lengthof(Tables); i++) - delete Tables[i]; } void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2, @@ -961,8 +962,12 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const { o << "IC_64BIT_REXW_ADSIZE"; else if ((index & ATTR_64BIT) && (index & ATTR_XD) && (index & ATTR_OPSIZE)) o << "IC_64BIT_XD_OPSIZE"; + else if ((index & ATTR_64BIT) && (index & ATTR_XD) && (index & ATTR_ADSIZE)) + o << "IC_64BIT_XD_ADSIZE"; else if ((index & ATTR_64BIT) && (index & ATTR_XS) && (index & ATTR_OPSIZE)) o << "IC_64BIT_XS_OPSIZE"; + else if ((index & ATTR_64BIT) && (index & ATTR_XS) && (index & ATTR_ADSIZE)) + o << "IC_64BIT_XS_ADSIZE"; else if ((index & ATTR_64BIT) && (index & ATTR_XS)) o << "IC_64BIT_XS"; else if ((index & ATTR_64BIT) && (index & ATTR_XD)) @@ -982,6 +987,10 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const { o << "IC_XS_OPSIZE"; else if ((index & ATTR_XD) && (index & ATTR_OPSIZE)) o << "IC_XD_OPSIZE"; + else if ((index & ATTR_XS) && (index & ATTR_ADSIZE)) + o << "IC_XS_ADSIZE"; + else if ((index & ATTR_XD) && (index & ATTR_ADSIZE)) + o << "IC_XD_ADSIZE"; else if (index & ATTR_XS) o << "IC_XS"; else if (index & ATTR_XD) @@ -1019,6 +1028,7 @@ void DisassemblerTables::emitContextDecisions(raw_ostream &o1, raw_ostream &o2, emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[4], XOP8_MAP_STR); emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[5], XOP9_MAP_STR); emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[6], XOPA_MAP_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[7], THREEDNOW_MAP_STR); } void DisassemblerTables::emit(raw_ostream &o) const { @@ -1075,14 +1085,9 @@ void DisassemblerTables::setTableFields(ModRMDecision &decision, if(previousInfo.name == "NOOP" && (newInfo.name == "XCHG16ar" || newInfo.name == "XCHG32ar" || - newInfo.name == "XCHG32ar64" || newInfo.name == "XCHG64ar")) continue; // special case for XCHG*ar and NOOP - if (previousInfo.name == "DATA16_PREFIX" && - newInfo.name == "DATA32_PREFIX") - continue; // special case for data16 and data32 - if (outranks(previousInfo.insnContext, newInfo.insnContext)) continue; diff --git a/utils/TableGen/X86DisassemblerTables.h b/utils/TableGen/X86DisassemblerTables.h index 552bbe95f7cd..b0ea9c2e8625 100644 --- a/utils/TableGen/X86DisassemblerTables.h +++ b/utils/TableGen/X86DisassemblerTables.h @@ -41,7 +41,8 @@ private: /// [4] XOP8 map opcode /// [5] XOP9 map opcode /// [6] XOPA map opcode - ContextDecision* Tables[7]; + /// [7] 3dnow map opcode + std::unique_ptr<ContextDecision> Tables[8]; // Table of ModRM encodings. typedef std::map<std::vector<unsigned>, unsigned> ModRMMapTy; diff --git a/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp b/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp index 05f30facd547..d5dc10ecad25 100644 --- a/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp +++ b/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp @@ -12,7 +12,6 @@ /// //===----------------------------------------------------------------------===// -#include "CodeGenDAGPatterns.h" #include "CodeGenTarget.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/TableGenBackend.h" @@ -22,6 +21,7 @@ using namespace llvm; namespace { class X86EVEX2VEXTablesEmitter { + RecordKeeper &Records; CodeGenTarget Target; // Hold all non-masked & non-broadcasted EVEX encoded instructions @@ -36,15 +36,8 @@ class X86EVEX2VEXTablesEmitter { std::vector<Entry> EVEX2VEX128; std::vector<Entry> EVEX2VEX256; - // Represents a manually added entry to the tables - struct ManualEntry { - const char *EVEXInstStr; - const char *VEXInstStr; - bool Is128Bit; - }; - public: - X86EVEX2VEXTablesEmitter(RecordKeeper &R) : Target(R) {} + X86EVEX2VEXTablesEmitter(RecordKeeper &R) : Records(R), Target(R) {} // run - Output X86 EVEX2VEX tables. void run(raw_ostream &OS); @@ -53,36 +46,11 @@ private: // Prints the given table as a C++ array of type // X86EvexToVexCompressTableEntry void printTable(const std::vector<Entry> &Table, raw_ostream &OS); - - bool inExceptionList(const CodeGenInstruction *Inst) { - // List of EVEX instructions that match VEX instructions by the encoding - // but do not perform the same operation. - static constexpr const char *ExceptionList[] = { - "VCVTQQ2PD", - "VCVTQQ2PS", - "VPMAXSQ", - "VPMAXUQ", - "VPMINSQ", - "VPMINUQ", - "VPMULLQ", - "VPSRAQ", - "VDBPSADBW", - "VRNDSCALE", - "VSCALEFPS" - }; - // Instruction's name starts with one of the entries in the exception list - for (StringRef InstStr : ExceptionList) { - if (Inst->TheDef->getName().startswith(InstStr)) - return true; - } - return false; - } - }; void X86EVEX2VEXTablesEmitter::printTable(const std::vector<Entry> &Table, raw_ostream &OS) { - std::string Size = (Table == EVEX2VEX128) ? "128" : "256"; + StringRef Size = (Table == EVEX2VEX128) ? "128" : "256"; OS << "// X86 EVEX encoded instructions that have a VEX " << Size << " encoding\n" @@ -97,83 +65,6 @@ void X86EVEX2VEXTablesEmitter::printTable(const std::vector<Entry> &Table, << ", X86::" << Pair.second->TheDef->getName() << " },\n"; } - // Some VEX instructions were duplicated to multiple EVEX versions due the - // introduction of mask variants, and thus some of the EVEX versions have - // different encoding than the VEX instruction. In order to maximize the - // compression we add these entries manually. - static constexpr ManualEntry ManuallyAddedEntries[] = { - // EVEX-Inst VEX-Inst Is128-bit - {"VMOVDQU8Z128mr", "VMOVDQUmr", true}, - {"VMOVDQU8Z128rm", "VMOVDQUrm", true}, - {"VMOVDQU8Z128rr", "VMOVDQUrr", true}, - {"VMOVDQU8Z128rr_REV", "VMOVDQUrr_REV", true}, - {"VMOVDQU16Z128mr", "VMOVDQUmr", true}, - {"VMOVDQU16Z128rm", "VMOVDQUrm", true}, - {"VMOVDQU16Z128rr", "VMOVDQUrr", true}, - {"VMOVDQU16Z128rr_REV", "VMOVDQUrr_REV", true}, - {"VMOVDQU8Z256mr", "VMOVDQUYmr", false}, - {"VMOVDQU8Z256rm", "VMOVDQUYrm", false}, - {"VMOVDQU8Z256rr", "VMOVDQUYrr", false}, - {"VMOVDQU8Z256rr_REV", "VMOVDQUYrr_REV", false}, - {"VMOVDQU16Z256mr", "VMOVDQUYmr", false}, - {"VMOVDQU16Z256rm", "VMOVDQUYrm", false}, - {"VMOVDQU16Z256rr", "VMOVDQUYrr", false}, - {"VMOVDQU16Z256rr_REV", "VMOVDQUYrr_REV", false}, - - {"VPERMILPDZ128mi", "VPERMILPDmi", true}, - {"VPERMILPDZ128ri", "VPERMILPDri", true}, - {"VPERMILPDZ128rm", "VPERMILPDrm", true}, - {"VPERMILPDZ128rr", "VPERMILPDrr", true}, - {"VPERMILPDZ256mi", "VPERMILPDYmi", false}, - {"VPERMILPDZ256ri", "VPERMILPDYri", false}, - {"VPERMILPDZ256rm", "VPERMILPDYrm", false}, - {"VPERMILPDZ256rr", "VPERMILPDYrr", false}, - - {"VPBROADCASTQZ128m", "VPBROADCASTQrm", true}, - {"VPBROADCASTQZ128r", "VPBROADCASTQrr", true}, - {"VPBROADCASTQZ256m", "VPBROADCASTQYrm", false}, - {"VPBROADCASTQZ256r", "VPBROADCASTQYrr", false}, - - {"VBROADCASTSDZ256m", "VBROADCASTSDYrm", false}, - {"VBROADCASTSDZ256r", "VBROADCASTSDYrr", false}, - - {"VBROADCASTF64X2Z128rm", "VBROADCASTF128", false}, - {"VBROADCASTI64X2Z128rm", "VBROADCASTI128", false}, - - {"VEXTRACTF64x2Z256mr", "VEXTRACTF128mr", false}, - {"VEXTRACTF64x2Z256rr", "VEXTRACTF128rr", false}, - {"VEXTRACTI64x2Z256mr", "VEXTRACTI128mr", false}, - {"VEXTRACTI64x2Z256rr", "VEXTRACTI128rr", false}, - - {"VINSERTF64x2Z256rm", "VINSERTF128rm", false}, - {"VINSERTF64x2Z256rr", "VINSERTF128rr", false}, - {"VINSERTI64x2Z256rm", "VINSERTI128rm", false}, - {"VINSERTI64x2Z256rr", "VINSERTI128rr", false}, - - // These will require some custom adjustment in the conversion pass. - {"VALIGNDZ128rri", "VPALIGNRrri", true}, - {"VALIGNQZ128rri", "VPALIGNRrri", true}, - {"VALIGNDZ128rmi", "VPALIGNRrmi", true}, - {"VALIGNQZ128rmi", "VPALIGNRrmi", true}, - {"VSHUFF32X4Z256rmi", "VPERM2F128rm", false}, - {"VSHUFF32X4Z256rri", "VPERM2F128rr", false}, - {"VSHUFF64X2Z256rmi", "VPERM2F128rm", false}, - {"VSHUFF64X2Z256rri", "VPERM2F128rr", false}, - {"VSHUFI32X4Z256rmi", "VPERM2I128rm", false}, - {"VSHUFI32X4Z256rri", "VPERM2I128rr", false}, - {"VSHUFI64X2Z256rmi", "VPERM2I128rm", false}, - {"VSHUFI64X2Z256rri", "VPERM2I128rr", false}, - }; - - // Print the manually added entries - for (const ManualEntry &Entry : ManuallyAddedEntries) { - if ((Table == EVEX2VEX128 && Entry.Is128Bit) || - (Table == EVEX2VEX256 && !Entry.Is128Bit)) { - OS << " { X86::" << Entry.EVEXInstStr << ", X86::" << Entry.VEXInstStr - << " },\n"; - } - } - OS << "};\n\n"; } @@ -210,31 +101,34 @@ static inline uint64_t getValueFromBitsInit(const BitsInit *B) { // Function object - Operator() returns true if the given VEX instruction // matches the EVEX instruction of this object. class IsMatch { - const CodeGenInstruction *Inst; + const CodeGenInstruction *EVEXInst; public: - IsMatch(const CodeGenInstruction *Inst) : Inst(Inst) {} + IsMatch(const CodeGenInstruction *EVEXInst) : EVEXInst(EVEXInst) {} - bool operator()(const CodeGenInstruction *Inst2) { - Record *Rec1 = Inst->TheDef; - Record *Rec2 = Inst2->TheDef; - uint64_t Rec1WVEX = - getValueFromBitsInit(Rec1->getValueAsBitsInit("VEX_WPrefix")); - uint64_t Rec2WVEX = - getValueFromBitsInit(Rec2->getValueAsBitsInit("VEX_WPrefix")); + bool operator()(const CodeGenInstruction *VEXInst) { + Record *RecE = EVEXInst->TheDef; + Record *RecV = VEXInst->TheDef; + uint64_t EVEX_W = + getValueFromBitsInit(RecE->getValueAsBitsInit("VEX_WPrefix")); + uint64_t VEX_W = + getValueFromBitsInit(RecV->getValueAsBitsInit("VEX_WPrefix")); - if (Rec2->getValueAsDef("OpEnc")->getName().str() != "EncVEX" || + if (RecV->getValueAsDef("OpEnc")->getName().str() != "EncVEX" || // VEX/EVEX fields - Rec2->getValueAsDef("OpPrefix") != Rec1->getValueAsDef("OpPrefix") || - Rec2->getValueAsDef("OpMap") != Rec1->getValueAsDef("OpMap") || - Rec2->getValueAsBit("hasVEX_4V") != Rec1->getValueAsBit("hasVEX_4V") || - !equalBitsInits(Rec2->getValueAsBitsInit("EVEX_LL"), - Rec1->getValueAsBitsInit("EVEX_LL")) || - (Rec1WVEX != 2 && Rec2WVEX != 2 && Rec1WVEX != Rec2WVEX) || + RecV->getValueAsDef("OpPrefix") != RecE->getValueAsDef("OpPrefix") || + RecV->getValueAsDef("OpMap") != RecE->getValueAsDef("OpMap") || + RecV->getValueAsBit("hasVEX_4V") != RecE->getValueAsBit("hasVEX_4V") || + !equalBitsInits(RecV->getValueAsBitsInit("EVEX_LL"), + RecE->getValueAsBitsInit("EVEX_LL")) || + // Match is allowed if either is VEX_WIG, or they match, or EVEX + // is VEX_W1X and VEX is VEX_W0. + (!(EVEX_W == 2 || VEX_W == 2 || EVEX_W == VEX_W || + (EVEX_W == 3 && VEX_W == 0))) || // Instruction's format - Rec2->getValueAsDef("Form") != Rec1->getValueAsDef("Form") || - Rec2->getValueAsBit("isAsmParserOnly") != - Rec1->getValueAsBit("isAsmParserOnly")) + RecV->getValueAsDef("Form") != RecE->getValueAsDef("Form") || + RecV->getValueAsBit("isAsmParserOnly") != + RecE->getValueAsBit("isAsmParserOnly")) return false; // This is needed for instructions with intrinsic version (_Int). @@ -243,9 +137,9 @@ public: // Also for instructions that their EVEX version was upgraded to work with // k-registers. For example VPCMPEQBrm (xmm output register) and // VPCMPEQBZ128rm (k register output register). - for (unsigned i = 0; i < Inst->Operands.size(); i++) { - Record *OpRec1 = Inst->Operands[i].Rec; - Record *OpRec2 = Inst2->Operands[i].Rec; + for (unsigned i = 0, e = EVEXInst->Operands.size(); i < e; i++) { + Record *OpRec1 = EVEXInst->Operands[i].Rec; + Record *OpRec2 = VEXInst->Operands[i].Rec; if (OpRec1 == OpRec2) continue; @@ -315,7 +209,7 @@ void X86EVEX2VEXTablesEmitter::run(raw_ostream &OS) { !Inst->TheDef->getValueAsBit("hasEVEX_B") && getValueFromBitsInit(Inst->TheDef-> getValueAsBitsInit("EVEX_LL")) != 2 && - !inExceptionList(Inst)) + !Inst->TheDef->getValueAsBit("notEVEX2VEXConvertible")) EVEXInsts.push_back(Inst); } @@ -324,22 +218,34 @@ void X86EVEX2VEXTablesEmitter::run(raw_ostream &OS) { getValueAsBitsInit("Opcode")); // For each EVEX instruction look for a VEX match in the appropriate vector // (instructions with the same opcode) using function object IsMatch. - auto Match = llvm::find_if(VEXInsts[Opcode], IsMatch(EVEXInst)); - if (Match != VEXInsts[Opcode].end()) { - const CodeGenInstruction *VEXInst = *Match; - - // In case a match is found add new entry to the appropriate table - switch (getValueFromBitsInit( - EVEXInst->TheDef->getValueAsBitsInit("EVEX_LL"))) { - case 0: - EVEX2VEX128.push_back(std::make_pair(EVEXInst, VEXInst)); // {0,0} - break; - case 1: - EVEX2VEX256.push_back(std::make_pair(EVEXInst, VEXInst)); // {0,1} - break; - default: - llvm_unreachable("Instruction's size not fit for the mapping!"); - } + // Allow EVEX2VEXOverride to explicitly specify a match. + const CodeGenInstruction *VEXInst = nullptr; + if (!EVEXInst->TheDef->isValueUnset("EVEX2VEXOverride")) { + StringRef AltInstStr = + EVEXInst->TheDef->getValueAsString("EVEX2VEXOverride"); + Record *AltInstRec = Records.getDef(AltInstStr); + assert(AltInstRec && "EVEX2VEXOverride instruction not found!"); + VEXInst = &Target.getInstruction(AltInstRec); + } else { + auto Match = llvm::find_if(VEXInsts[Opcode], IsMatch(EVEXInst)); + if (Match != VEXInsts[Opcode].end()) + VEXInst = *Match; + } + + if (!VEXInst) + continue; + + // In case a match is found add new entry to the appropriate table + switch (getValueFromBitsInit( + EVEXInst->TheDef->getValueAsBitsInit("EVEX_LL"))) { + case 0: + EVEX2VEX128.push_back(std::make_pair(EVEXInst, VEXInst)); // {0,0} + break; + case 1: + EVEX2VEX256.push_back(std::make_pair(EVEXInst, VEXInst)); // {0,1} + break; + default: + llvm_unreachable("Instruction's size not fit for the mapping!"); } } diff --git a/utils/TableGen/X86FoldTablesEmitter.cpp b/utils/TableGen/X86FoldTablesEmitter.cpp index ff1afa89efc8..1ea668643575 100644 --- a/utils/TableGen/X86FoldTablesEmitter.cpp +++ b/utils/TableGen/X86FoldTablesEmitter.cpp @@ -47,7 +47,9 @@ const char *ExplicitAlign[] = {"MOVDQA", "MOVAPS", "MOVAPD", "MOVNTPS", "MOVNTPD", "MOVNTDQ", "MOVNTDQA"}; // List of instructions NOT requiring explicit memory alignment. -const char *ExplicitUnalign[] = {"MOVDQU", "MOVUPS", "MOVUPD"}; +const char *ExplicitUnalign[] = {"MOVDQU", "MOVUPS", "MOVUPD", + "PCMPESTRM", "PCMPESTRI", + "PCMPISTRM", "PCMPISTRI" }; // For manually mapping instructions that do not match by their encoding. const ManualMapEntry ManualMapSet[] = { @@ -63,9 +65,9 @@ const ManualMapEntry ManualMapSet[] = { { "ADD16rr_DB", "ADD16rm", NO_UNFOLD }, { "ADD32rr_DB", "ADD32rm", NO_UNFOLD }, { "ADD64rr_DB", "ADD64rm", NO_UNFOLD }, - { "PUSH16r", "PUSH16rmm", NO_UNFOLD }, - { "PUSH32r", "PUSH32rmm", NO_UNFOLD }, - { "PUSH64r", "PUSH64rmm", NO_UNFOLD }, + { "PUSH16r", "PUSH16rmm", UNFOLD }, + { "PUSH32r", "PUSH32rmm", UNFOLD }, + { "PUSH64r", "PUSH64rmm", UNFOLD }, { "TAILJMPr", "TAILJMPm", UNFOLD }, { "TAILJMPr64", "TAILJMPm64", UNFOLD }, { "TAILJMPr64_REX", "TAILJMPm64_REX", UNFOLD }, @@ -106,8 +108,8 @@ class X86FoldTablesEmitter { friend raw_ostream &operator<<(raw_ostream &OS, const X86FoldTableEntry &E) { - OS << "{ X86::" << E.RegInst->TheDef->getName().str() - << ", X86::" << E.MemInst->TheDef->getName().str() << ", "; + OS << "{ X86::" << E.RegInst->TheDef->getName() + << ", X86::" << E.MemInst->TheDef->getName() << ", "; if (E.IsLoad) OS << "TB_FOLDED_LOAD | "; @@ -157,7 +159,7 @@ private: // Print the given table as a static const C++ array of type // X86MemoryFoldTableEntry. - void printTable(const FoldTable &Table, std::string TableName, + void printTable(const FoldTable &Table, StringRef TableName, raw_ostream &OS) { OS << "static const X86MemoryFoldTableEntry MemoryFold" << TableName << "[] = {\n"; @@ -251,16 +253,6 @@ getMemOperandSize(const Record *MemRec, const bool IntrinsicSensitive = false) { llvm_unreachable("Memory operand's size not known!"); } -// Returns true if the record's list of defs includes the given def. -static inline bool hasDefInList(const Record *Rec, const StringRef List, - const StringRef Def) { - if (!Rec->isValueUnset(List)) { - return any_of(*(Rec->getValueAsListInit(List)), - [Def](const Init *I) { return I->getAsString() == Def; }); - } - return false; -} - // Return true if the instruction defined as a register flavor. static inline bool hasRegisterFormat(const Record *Inst) { const BitsInit *FormBits = Inst->getValueAsBitsInit("FormBits"); @@ -335,20 +327,24 @@ public: MemRec->getValueAsDef("OpPrefix") || RegRec->getValueAsDef("OpMap") != MemRec->getValueAsDef("OpMap") || RegRec->getValueAsDef("OpSize") != MemRec->getValueAsDef("OpSize") || + RegRec->getValueAsDef("AdSize") != MemRec->getValueAsDef("AdSize") || RegRec->getValueAsBit("hasVEX_4V") != MemRec->getValueAsBit("hasVEX_4V") || RegRec->getValueAsBit("hasEVEX_K") != MemRec->getValueAsBit("hasEVEX_K") || RegRec->getValueAsBit("hasEVEX_Z") != MemRec->getValueAsBit("hasEVEX_Z") || - RegRec->getValueAsBit("hasEVEX_B") != - MemRec->getValueAsBit("hasEVEX_B") || + // EVEX_B means different things for memory and register forms. + RegRec->getValueAsBit("hasEVEX_B") != 0 || + MemRec->getValueAsBit("hasEVEX_B") != 0 || RegRec->getValueAsBit("hasEVEX_RC") != MemRec->getValueAsBit("hasEVEX_RC") || RegRec->getValueAsBit("hasREX_WPrefix") != MemRec->getValueAsBit("hasREX_WPrefix") || RegRec->getValueAsBit("hasLockPrefix") != MemRec->getValueAsBit("hasLockPrefix") || + RegRec->getValueAsBit("hasNoTrackPrefix") != + MemRec->getValueAsBit("hasNoTrackPrefix") || !equalBitsInits(RegRec->getValueAsBitsInit("EVEX_LL"), MemRec->getValueAsBitsInit("EVEX_LL")) || !equalBitsInits(RegRec->getValueAsBitsInit("VEX_WPrefix"), @@ -511,10 +507,8 @@ void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInstr, unsigned MemInSize = MemRec->getValueAsDag("InOperandList")->getNumArgs(); unsigned RegInSize = RegRec->getValueAsDag("InOperandList")->getNumArgs(); - // Instructions which have the WriteRMW value (Read-Modify-Write) should be - // added to Table2Addr. - if (hasDefInList(MemRec, "SchedRW", "WriteRMW") && MemOutSize != RegOutSize && - MemInSize == RegInSize) { + // Instructions which Read-Modify-Write should be added to Table2Addr. + if (MemOutSize != RegOutSize && MemInSize == RegInSize) { addEntryWithFlags(Table2Addr, RegInstr, MemInstr, S, 0); return; } @@ -548,7 +542,7 @@ void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInstr, } } else if (MemInSize == RegInSize + 1 && MemOutSize + 1 == RegOutSize) { // Store-Folding cases. - // If the memory form instruction performs performs a store, the *output* + // If the memory form instruction performs a store, the *output* // register of the register form instructions disappear and instead a // memory *input* operand appears in the memory form instruction. // For example: @@ -556,7 +550,8 @@ void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInstr, // MOVAPSmr => (outs), (ins f128mem:$dst, VR128:$src) Record *RegOpRec = RegInstr->Operands[RegOutSize - 1].Rec; Record *MemOpRec = MemInstr->Operands[RegOutSize - 1].Rec; - if (isRegisterOperand(RegOpRec) && isMemoryOperand(MemOpRec)) + if (isRegisterOperand(RegOpRec) && isMemoryOperand(MemOpRec) && + getRegOperandSize(RegOpRec) == getMemOperandSize(MemOpRec)) addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0); } diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 9afdd7e09638..efd5c195d02b 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -40,7 +40,7 @@ static uint8_t byteFromBitsInit(BitsInit &init) { uint8_t ret = 0; for (index = 0; index < width; index++) { - if (static_cast<BitInit*>(init.getBit(index))->getValue()) + if (cast<BitInit>(init.getBit(index))->getValue()) ret |= mask; mask <<= 1; @@ -80,19 +80,19 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, Form = byteFromRec(Rec, "FormBits"); Encoding = byteFromRec(Rec, "OpEncBits"); - OpSize = byteFromRec(Rec, "OpSizeBits"); - AdSize = byteFromRec(Rec, "AdSizeBits"); - HasREX_WPrefix = Rec->getValueAsBit("hasREX_WPrefix"); - HasVEX_4V = Rec->getValueAsBit("hasVEX_4V"); - VEX_WPrefix = byteFromRec(Rec,"VEX_WPrefix"); - IgnoresVEX_L = Rec->getValueAsBit("ignoresVEX_L"); - HasEVEX_L2Prefix = Rec->getValueAsBit("hasEVEX_L2"); - HasEVEX_K = Rec->getValueAsBit("hasEVEX_K"); - HasEVEX_KZ = Rec->getValueAsBit("hasEVEX_Z"); - HasEVEX_B = Rec->getValueAsBit("hasEVEX_B"); - IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly"); - ForceDisassemble = Rec->getValueAsBit("ForceDisassemble"); - CD8_Scale = byteFromRec(Rec, "CD8_Scale"); + OpSize = byteFromRec(Rec, "OpSizeBits"); + AdSize = byteFromRec(Rec, "AdSizeBits"); + HasREX_WPrefix = Rec->getValueAsBit("hasREX_WPrefix"); + HasVEX_4V = Rec->getValueAsBit("hasVEX_4V"); + VEX_WPrefix = byteFromRec(Rec,"VEX_WPrefix"); + IgnoresVEX_L = Rec->getValueAsBit("ignoresVEX_L"); + HasEVEX_L2Prefix = Rec->getValueAsBit("hasEVEX_L2"); + HasEVEX_K = Rec->getValueAsBit("hasEVEX_K"); + HasEVEX_KZ = Rec->getValueAsBit("hasEVEX_Z"); + HasEVEX_B = Rec->getValueAsBit("hasEVEX_B"); + IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly"); + ForceDisassemble = Rec->getValueAsBit("ForceDisassemble"); + CD8_Scale = byteFromRec(Rec, "CD8_Scale"); Name = Rec->getName(); @@ -164,7 +164,8 @@ InstructionContext RecognizableInstr::insnContext() const { llvm_unreachable("Don't support VEX.L if EVEX_L2 is enabled"); } // VEX_L & VEX_W - if (!EncodeRC && HasVEX_LPrefix && VEX_WPrefix == X86Local::VEX_W1) { + if (!EncodeRC && HasVEX_LPrefix && (VEX_WPrefix == X86Local::VEX_W1 || + VEX_WPrefix == X86Local::VEX_W1X)) { if (OpPrefix == X86Local::PD) insnContext = EVEX_KB(IC_EVEX_L_W_OPSIZE); else if (OpPrefix == X86Local::XS) @@ -192,7 +193,8 @@ InstructionContext RecognizableInstr::insnContext() const { llvm_unreachable("Invalid prefix"); } } else if (!EncodeRC && HasEVEX_L2Prefix && - VEX_WPrefix == X86Local::VEX_W1) { + (VEX_WPrefix == X86Local::VEX_W1 || + VEX_WPrefix == X86Local::VEX_W1X)) { // EVEX_L2 & VEX_W if (OpPrefix == X86Local::PD) insnContext = EVEX_KB(IC_EVEX_L2_W_OPSIZE); @@ -221,7 +223,8 @@ InstructionContext RecognizableInstr::insnContext() const { llvm_unreachable("Invalid prefix"); } } - else if (VEX_WPrefix == X86Local::VEX_W1) { + else if (VEX_WPrefix == X86Local::VEX_W1 || + VEX_WPrefix == X86Local::VEX_W1X) { // VEX_W if (OpPrefix == X86Local::PD) insnContext = EVEX_KB(IC_EVEX_W_OPSIZE); @@ -243,11 +246,16 @@ InstructionContext RecognizableInstr::insnContext() const { insnContext = EVEX_KB(IC_EVEX_XD); else if (OpPrefix == X86Local::XS) insnContext = EVEX_KB(IC_EVEX_XS); - else + else if (OpPrefix == X86Local::PS) insnContext = EVEX_KB(IC_EVEX); + else { + errs() << "Instruction does not use a prefix: " << Name << "\n"; + llvm_unreachable("Invalid prefix"); + } /// eof EVEX } else if (Encoding == X86Local::VEX || Encoding == X86Local::XOP) { - if (HasVEX_LPrefix && VEX_WPrefix == X86Local::VEX_W1) { + if (HasVEX_LPrefix && (VEX_WPrefix == X86Local::VEX_W1 || + VEX_WPrefix == X86Local::VEX_W1X)) { if (OpPrefix == X86Local::PD) insnContext = IC_VEX_L_W_OPSIZE; else if (OpPrefix == X86Local::XS) @@ -262,7 +270,8 @@ InstructionContext RecognizableInstr::insnContext() const { } } else if (OpPrefix == X86Local::PD && HasVEX_LPrefix) insnContext = IC_VEX_L_OPSIZE; - else if (OpPrefix == X86Local::PD && VEX_WPrefix == X86Local::VEX_W1) + else if (OpPrefix == X86Local::PD && (VEX_WPrefix == X86Local::VEX_W1 || + VEX_WPrefix == X86Local::VEX_W1X)) insnContext = IC_VEX_W_OPSIZE; else if (OpPrefix == X86Local::PD) insnContext = IC_VEX_OPSIZE; @@ -270,11 +279,14 @@ InstructionContext RecognizableInstr::insnContext() const { insnContext = IC_VEX_L_XS; else if (HasVEX_LPrefix && OpPrefix == X86Local::XD) insnContext = IC_VEX_L_XD; - else if (VEX_WPrefix == X86Local::VEX_W1 && OpPrefix == X86Local::XS) + else if ((VEX_WPrefix == X86Local::VEX_W1 || + VEX_WPrefix == X86Local::VEX_W1X) && OpPrefix == X86Local::XS) insnContext = IC_VEX_W_XS; - else if (VEX_WPrefix == X86Local::VEX_W1 && OpPrefix == X86Local::XD) + else if ((VEX_WPrefix == X86Local::VEX_W1 || + VEX_WPrefix == X86Local::VEX_W1X) && OpPrefix == X86Local::XD) insnContext = IC_VEX_W_XD; - else if (VEX_WPrefix == X86Local::VEX_W1 && OpPrefix == X86Local::PS) + else if ((VEX_WPrefix == X86Local::VEX_W1 || + VEX_WPrefix == X86Local::VEX_W1X) && OpPrefix == X86Local::PS) insnContext = IC_VEX_W; else if (HasVEX_LPrefix && OpPrefix == X86Local::PS) insnContext = IC_VEX_L; @@ -297,6 +309,8 @@ InstructionContext RecognizableInstr::insnContext() const { insnContext = IC_64BIT_XD_OPSIZE; else if (OpSize == X86Local::OpSize16 && OpPrefix == X86Local::XS) insnContext = IC_64BIT_XS_OPSIZE; + else if (AdSize == X86Local::AdSize32 && OpPrefix == X86Local::PD) + insnContext = IC_64BIT_OPSIZE_ADSIZE; else if (OpSize == X86Local::OpSize16 && AdSize == X86Local::AdSize32) insnContext = IC_64BIT_OPSIZE_ADSIZE; else if (OpSize == X86Local::OpSize16 || OpPrefix == X86Local::PD) @@ -320,6 +334,12 @@ InstructionContext RecognizableInstr::insnContext() const { insnContext = IC_XD_OPSIZE; else if (OpSize == X86Local::OpSize16 && OpPrefix == X86Local::XS) insnContext = IC_XS_OPSIZE; + else if (AdSize == X86Local::AdSize16 && OpPrefix == X86Local::XD) + insnContext = IC_XD_ADSIZE; + else if (AdSize == X86Local::AdSize16 && OpPrefix == X86Local::XS) + insnContext = IC_XS_ADSIZE; + else if (AdSize == X86Local::AdSize16 && OpPrefix == X86Local::PD) + insnContext = IC_OPSIZE_ADSIZE; else if (OpSize == X86Local::OpSize16 && AdSize == X86Local::AdSize16) insnContext = IC_OPSIZE_ADSIZE; else if (OpSize == X86Local::OpSize16 || OpPrefix == X86Local::PD) @@ -544,7 +564,6 @@ void RecognizableInstr::emitInstructionSpecifier() { HANDLE_OPERAND(rmRegister) HANDLE_OPTIONAL(immediate) HANDLE_OPTIONAL(immediate) // above might be a register in 7:4 - HANDLE_OPTIONAL(immediate) break; case X86Local::MRMSrcReg4VOp3: assert(numPhysicalOperands == 3 && @@ -663,41 +682,15 @@ void RecognizableInstr::emitInstructionSpecifier() { HANDLE_OPERAND(immediate) HANDLE_OPERAND(immediate) break; - case X86Local::MRM_F8: - if (Opcode == 0xc6) { - assert(numPhysicalOperands == 1 && - "Unexpected number of operands for X86Local::MRM_F8"); - HANDLE_OPERAND(immediate) - } else if (Opcode == 0xc7) { - assert(numPhysicalOperands == 1 && - "Unexpected number of operands for X86Local::MRM_F8"); - HANDLE_OPERAND(relocation) - } - break; - case X86Local::MRM_C0: case X86Local::MRM_C1: case X86Local::MRM_C2: - case X86Local::MRM_C3: case X86Local::MRM_C4: case X86Local::MRM_C8: - case X86Local::MRM_C9: case X86Local::MRM_CA: case X86Local::MRM_CB: - case X86Local::MRM_CF: case X86Local::MRM_D0: case X86Local::MRM_D1: - case X86Local::MRM_D4: case X86Local::MRM_D5: case X86Local::MRM_D6: - case X86Local::MRM_D7: case X86Local::MRM_D8: case X86Local::MRM_D9: - case X86Local::MRM_DA: case X86Local::MRM_DB: case X86Local::MRM_DC: - case X86Local::MRM_DD: case X86Local::MRM_DE: case X86Local::MRM_DF: - case X86Local::MRM_E0: case X86Local::MRM_E1: case X86Local::MRM_E2: - case X86Local::MRM_E3: case X86Local::MRM_E4: case X86Local::MRM_E5: - case X86Local::MRM_E8: case X86Local::MRM_E9: case X86Local::MRM_EA: - case X86Local::MRM_EB: case X86Local::MRM_EC: case X86Local::MRM_ED: - case X86Local::MRM_EE: case X86Local::MRM_EF: case X86Local::MRM_F0: - case X86Local::MRM_F1: case X86Local::MRM_F2: case X86Local::MRM_F3: - case X86Local::MRM_F4: case X86Local::MRM_F5: case X86Local::MRM_F6: - case X86Local::MRM_F7: case X86Local::MRM_F9: case X86Local::MRM_FA: - case X86Local::MRM_FB: case X86Local::MRM_FC: case X86Local::MRM_FD: - case X86Local::MRM_FE: case X86Local::MRM_FF: - // Ignored. +#define MAP(from, to) case X86Local::MRM_##from: + X86_INSTR_MRM_MAPPING +#undef MAP + HANDLE_OPTIONAL(relocation) break; } - #undef HANDLE_OPERAND - #undef HANDLE_OPTIONAL +#undef HANDLE_OPERAND +#undef HANDLE_OPTIONAL } void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { @@ -707,77 +700,64 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { case X86Local::MRM_##from: llvm::Optional<OpcodeType> opcodeType; - - ModRMFilter* filter = nullptr; - uint8_t opcodeToSet = 0; - switch (OpMap) { default: llvm_unreachable("Invalid map!"); - case X86Local::OB: - case X86Local::TB: - case X86Local::T8: - case X86Local::TA: - case X86Local::XOP8: - case X86Local::XOP9: - case X86Local::XOPA: - switch (OpMap) { - default: llvm_unreachable("Unexpected map!"); - case X86Local::OB: opcodeType = ONEBYTE; break; - case X86Local::TB: opcodeType = TWOBYTE; break; - case X86Local::T8: opcodeType = THREEBYTE_38; break; - case X86Local::TA: opcodeType = THREEBYTE_3A; break; - case X86Local::XOP8: opcodeType = XOP8_MAP; break; - case X86Local::XOP9: opcodeType = XOP9_MAP; break; - case X86Local::XOPA: opcodeType = XOPA_MAP; break; - } - - switch (Form) { - default: llvm_unreachable("Invalid form!"); - case X86Local::Pseudo: llvm_unreachable("Pseudo should not be emitted!"); - case X86Local::RawFrm: - case X86Local::AddRegFrm: - case X86Local::RawFrmMemOffs: - case X86Local::RawFrmSrc: - case X86Local::RawFrmDst: - case X86Local::RawFrmDstSrc: - case X86Local::RawFrmImm8: - case X86Local::RawFrmImm16: - filter = new DumbFilter(); - break; - case X86Local::MRMDestReg: - case X86Local::MRMSrcReg: - case X86Local::MRMSrcReg4VOp3: - case X86Local::MRMSrcRegOp4: - case X86Local::MRMXr: - filter = new ModFilter(true); - break; - case X86Local::MRMDestMem: - case X86Local::MRMSrcMem: - case X86Local::MRMSrcMem4VOp3: - case X86Local::MRMSrcMemOp4: - case X86Local::MRMXm: - filter = new ModFilter(false); - break; - case X86Local::MRM0r: case X86Local::MRM1r: - case X86Local::MRM2r: case X86Local::MRM3r: - case X86Local::MRM4r: case X86Local::MRM5r: - case X86Local::MRM6r: case X86Local::MRM7r: - filter = new ExtendedFilter(true, Form - X86Local::MRM0r); - break; - case X86Local::MRM0m: case X86Local::MRM1m: - case X86Local::MRM2m: case X86Local::MRM3m: - case X86Local::MRM4m: case X86Local::MRM5m: - case X86Local::MRM6m: case X86Local::MRM7m: - filter = new ExtendedFilter(false, Form - X86Local::MRM0m); - break; - X86_INSTR_MRM_MAPPING - filter = new ExactFilter(0xC0 + Form - X86Local::MRM_C0); \ - break; - } // switch (Form) + case X86Local::OB: opcodeType = ONEBYTE; break; + case X86Local::TB: opcodeType = TWOBYTE; break; + case X86Local::T8: opcodeType = THREEBYTE_38; break; + case X86Local::TA: opcodeType = THREEBYTE_3A; break; + case X86Local::XOP8: opcodeType = XOP8_MAP; break; + case X86Local::XOP9: opcodeType = XOP9_MAP; break; + case X86Local::XOPA: opcodeType = XOPA_MAP; break; + case X86Local::ThreeDNow: opcodeType = THREEDNOW_MAP; break; + } - opcodeToSet = Opcode; + std::unique_ptr<ModRMFilter> filter; + switch (Form) { + default: llvm_unreachable("Invalid form!"); + case X86Local::Pseudo: llvm_unreachable("Pseudo should not be emitted!"); + case X86Local::RawFrm: + case X86Local::AddRegFrm: + case X86Local::RawFrmMemOffs: + case X86Local::RawFrmSrc: + case X86Local::RawFrmDst: + case X86Local::RawFrmDstSrc: + case X86Local::RawFrmImm8: + case X86Local::RawFrmImm16: + filter = llvm::make_unique<DumbFilter>(); break; - } // switch (OpMap) + case X86Local::MRMDestReg: + case X86Local::MRMSrcReg: + case X86Local::MRMSrcReg4VOp3: + case X86Local::MRMSrcRegOp4: + case X86Local::MRMXr: + filter = llvm::make_unique<ModFilter>(true); + break; + case X86Local::MRMDestMem: + case X86Local::MRMSrcMem: + case X86Local::MRMSrcMem4VOp3: + case X86Local::MRMSrcMemOp4: + case X86Local::MRMXm: + filter = llvm::make_unique<ModFilter>(false); + break; + case X86Local::MRM0r: case X86Local::MRM1r: + case X86Local::MRM2r: case X86Local::MRM3r: + case X86Local::MRM4r: case X86Local::MRM5r: + case X86Local::MRM6r: case X86Local::MRM7r: + filter = llvm::make_unique<ExtendedFilter>(true, Form - X86Local::MRM0r); + break; + case X86Local::MRM0m: case X86Local::MRM1m: + case X86Local::MRM2m: case X86Local::MRM3m: + case X86Local::MRM4m: case X86Local::MRM5m: + case X86Local::MRM6m: case X86Local::MRM7m: + filter = llvm::make_unique<ExtendedFilter>(false, Form - X86Local::MRM0m); + break; + X86_INSTR_MRM_MAPPING + filter = llvm::make_unique<ExactFilter>(0xC0 + Form - X86Local::MRM_C0); + break; + } // switch (Form) + + uint8_t opcodeToSet = Opcode; unsigned AddressSize = 0; switch (AdSize) { @@ -808,8 +788,6 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { VEX_WPrefix == X86Local::VEX_WIG, AddressSize); } - delete filter; - #undef MAP } @@ -884,10 +862,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("VR64", TYPE_MM64) TYPE("i64imm", TYPE_IMM) TYPE("anymem", TYPE_M) - TYPE("opaque32mem", TYPE_M) - TYPE("opaque48mem", TYPE_M) - TYPE("opaque80mem", TYPE_M) - TYPE("opaque512mem", TYPE_M) + TYPE("opaquemem", TYPE_M) TYPE("SEGMENT_REG", TYPE_SEGMENTREG) TYPE("DEBUG_REG", TYPE_DEBUGREG) TYPE("CONTROL_REG", TYPE_CONTROLREG) @@ -927,7 +902,6 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("VK32WM", TYPE_VK) TYPE("VK64", TYPE_VK) TYPE("VK64WM", TYPE_VK) - TYPE("GR32_NOAX", TYPE_Rv) TYPE("vx64mem", TYPE_MVSIBX) TYPE("vx128mem", TYPE_MVSIBX) TYPE("vx256mem", TYPE_MVSIBX) @@ -938,8 +912,8 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("vx256xmem", TYPE_MVSIBX) TYPE("vy128xmem", TYPE_MVSIBY) TYPE("vy256xmem", TYPE_MVSIBY) - TYPE("vy512mem", TYPE_MVSIBY) - TYPE("vz256xmem", TYPE_MVSIBZ) + TYPE("vy512xmem", TYPE_MVSIBY) + TYPE("vz256mem", TYPE_MVSIBZ) TYPE("vz512mem", TYPE_MVSIBZ) TYPE("BNDR", TYPE_BNDR) errs() << "Unhandled type string " << s << "\n"; @@ -1120,10 +1094,7 @@ RecognizableInstr::memoryEncodingFromString(const std::string &s, ENCODING("lea64_32mem", ENCODING_RM) ENCODING("lea64mem", ENCODING_RM) ENCODING("anymem", ENCODING_RM) - ENCODING("opaque32mem", ENCODING_RM) - ENCODING("opaque48mem", ENCODING_RM) - ENCODING("opaque80mem", ENCODING_RM) - ENCODING("opaque512mem", ENCODING_RM) + ENCODING("opaquemem", ENCODING_RM) ENCODING("vx64mem", ENCODING_VSIB) ENCODING("vx128mem", ENCODING_VSIB) ENCODING("vx256mem", ENCODING_VSIB) @@ -1134,8 +1105,8 @@ RecognizableInstr::memoryEncodingFromString(const std::string &s, ENCODING("vx256xmem", ENCODING_VSIB) ENCODING("vy128xmem", ENCODING_VSIB) ENCODING("vy256xmem", ENCODING_VSIB) - ENCODING("vy512mem", ENCODING_VSIB) - ENCODING("vz256xmem", ENCODING_VSIB) + ENCODING("vy512xmem", ENCODING_VSIB) + ENCODING("vz256mem", ENCODING_VSIB) ENCODING("vz512mem", ENCODING_VSIB) errs() << "Unhandled memory encoding " << s << "\n"; llvm_unreachable("Unhandled memory encoding"); @@ -1195,7 +1166,6 @@ RecognizableInstr::opcodeModifierEncodingFromString(const std::string &s, ENCODING("GR64", ENCODING_RO) ENCODING("GR16", ENCODING_Rv) ENCODING("GR8", ENCODING_RB) - ENCODING("GR32_NOAX", ENCODING_Rv) errs() << "Unhandled opcode modifier encoding " << s << "\n"; llvm_unreachable("Unhandled opcode modifier encoding"); } diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h index 24509d16d638..c4d34ee6c80c 100644 --- a/utils/TableGen/X86RecognizableInstr.h +++ b/utils/TableGen/X86RecognizableInstr.h @@ -122,11 +122,11 @@ namespace X86Local { }; enum { - OB = 0, TB = 1, T8 = 2, TA = 3, XOP8 = 4, XOP9 = 5, XOPA = 6 + OB = 0, TB = 1, T8 = 2, TA = 3, XOP8 = 4, XOP9 = 5, XOPA = 6, ThreeDNow = 7 }; enum { - PS = 1, PD = 2, XS = 3, XD = 4 + PD = 1, XS = 2, XD = 3, PS = 4 }; enum { @@ -142,7 +142,7 @@ namespace X86Local { }; enum { - VEX_W0 = 0, VEX_W1 = 1, VEX_WIG = 2 + VEX_W0 = 0, VEX_W1 = 1, VEX_WIG = 2, VEX_W1X = 3 }; } @@ -210,12 +210,12 @@ private: /// Indicates whether the instruction should be emitted into the decode /// tables; regardless, it will be emitted into the instruction info table bool ShouldBeEmitted; - + /// The operands of the instruction, as listed in the CodeGenInstruction. /// They are not one-to-one with operands listed in the MCInst; for example, /// memory operands expand to 5 operands in the MCInst const std::vector<CGIOperandList::OperandInfo>* Operands; - + /// The description of the instruction that is emitted into the instruction /// info table InstructionSpecifier* Spec; @@ -272,7 +272,7 @@ private: static OperandEncoding writemaskRegisterEncodingFromString(const std::string &s, uint8_t OpSize); - /// \brief Adjust the encoding type for an operand based on the instruction. + /// Adjust the encoding type for an operand based on the instruction. void adjustOperandEncoding(OperandEncoding &encoding); /// handleOperand - Converts a single operand from the LLVM table format to @@ -283,7 +283,7 @@ private: /// operand exists. /// @param operandIndex - The index into the generated operand table. /// Incremented by this function one or more - /// times to reflect possible duplicate + /// times to reflect possible duplicate /// operands). /// @param physicalOperandIndex - The index of the current operand into the /// set of non-duplicate ('physical') operands. @@ -314,12 +314,12 @@ private: bool shouldBeEmitted() const { return ShouldBeEmitted; } - + /// emitInstructionSpecifier - Loads the instruction specifier for the current /// instruction into a DisassemblerTables. /// void emitInstructionSpecifier(); - + /// emitDecodePath - Populates the proper fields in the decode tables /// corresponding to the decode paths for this instruction. /// @@ -349,7 +349,7 @@ public: const CodeGenInstruction &insn, InstrUID uid); }; - + } // namespace X86Disassembler } // namespace llvm |
