summaryrefslogtreecommitdiff
path: root/utils/TableGen
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
commiteb11fae6d08f479c0799db45860a98af528fa6e7 (patch)
tree44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /utils/TableGen
parentb8a2042aa938069e862750553db0e4d82d25822c (diff)
Notes
Diffstat (limited to 'utils/TableGen')
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp317
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp24
-rw-r--r--utils/TableGen/CMakeLists.txt3
-rw-r--r--utils/TableGen/CTagsEmitter.cpp2
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp1048
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.h158
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp21
-rw-r--r--utils/TableGen/CodeGenInstruction.h9
-rw-r--r--utils/TableGen/CodeGenIntrinsics.h2
-rw-r--r--utils/TableGen/CodeGenMapTable.cpp7
-rw-r--r--utils/TableGen/CodeGenRegisters.cpp225
-rw-r--r--utils/TableGen/CodeGenRegisters.h30
-rw-r--r--utils/TableGen/CodeGenSchedule.cpp834
-rw-r--r--utils/TableGen/CodeGenSchedule.h79
-rw-r--r--utils/TableGen/CodeGenTarget.cpp65
-rw-r--r--utils/TableGen/CodeGenTarget.h30
-rw-r--r--utils/TableGen/DAGISelEmitter.cpp28
-rw-r--r--utils/TableGen/DAGISelMatcher.h2
-rw-r--r--utils/TableGen/DAGISelMatcherGen.cpp78
-rw-r--r--utils/TableGen/DAGISelMatcherOpt.cpp15
-rw-r--r--utils/TableGen/DFAPacketizerEmitter.cpp143
-rw-r--r--utils/TableGen/DisassemblerEmitter.cpp13
-rw-r--r--utils/TableGen/FastISelEmitter.cpp49
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.cpp163
-rw-r--r--utils/TableGen/GlobalISelEmitter.cpp1793
-rw-r--r--utils/TableGen/InfoByHwMode.cpp4
-rw-r--r--utils/TableGen/InfoByHwMode.h2
-rw-r--r--utils/TableGen/InstrDocsEmitter.cpp1
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp101
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp56
-rw-r--r--utils/TableGen/LLVMBuild.txt2
-rw-r--r--utils/TableGen/PredicateExpander.cpp262
-rw-r--r--utils/TableGen/PredicateExpander.h86
-rw-r--r--utils/TableGen/PseudoLoweringEmitter.cpp9
-rw-r--r--utils/TableGen/RISCVCompressInstEmitter.cpp810
-rw-r--r--utils/TableGen/RegisterBankEmitter.cpp6
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp12
-rw-r--r--utils/TableGen/SearchableTableEmitter.cpp842
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp509
-rw-r--r--utils/TableGen/SubtargetFeatureInfo.cpp1
-rw-r--r--utils/TableGen/SubtargetFeatureInfo.h8
-rw-r--r--utils/TableGen/TableGen.cpp40
-rw-r--r--utils/TableGen/TableGenBackends.h6
-rw-r--r--utils/TableGen/WebAssemblyDisassemblerEmitter.cpp116
-rw-r--r--utils/TableGen/WebAssemblyDisassemblerEmitter.h30
-rw-r--r--utils/TableGen/X86DisassemblerShared.h6
-rw-r--r--utils/TableGen/X86DisassemblerTables.cpp39
-rw-r--r--utils/TableGen/X86DisassemblerTables.h3
-rw-r--r--utils/TableGen/X86EVEX2VEXTablesEmitter.cpp208
-rw-r--r--utils/TableGen/X86FoldTablesEmitter.cpp45
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp248
-rw-r--r--utils/TableGen/X86RecognizableInstr.h20
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