aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/utils/TableGen')
-rw-r--r--llvm/utils/TableGen/AsmMatcherEmitter.cpp139
-rw-r--r--llvm/utils/TableGen/AsmWriterEmitter.cpp113
-rw-r--r--llvm/utils/TableGen/AsmWriterInst.cpp7
-rw-r--r--llvm/utils/TableGen/CallingConvEmitter.cpp18
-rw-r--r--llvm/utils/TableGen/CodeEmitterGen.cpp8
-rw-r--r--llvm/utils/TableGen/CodeGenDAGPatterns.cpp34
-rw-r--r--llvm/utils/TableGen/CodeGenDAGPatterns.h8
-rw-r--r--llvm/utils/TableGen/CodeGenInstruction.cpp2
-rw-r--r--llvm/utils/TableGen/CodeGenIntrinsics.h10
-rw-r--r--llvm/utils/TableGen/CodeGenMapTable.cpp26
-rw-r--r--llvm/utils/TableGen/CodeGenRegisters.cpp19
-rw-r--r--llvm/utils/TableGen/CodeGenRegisters.h4
-rw-r--r--llvm/utils/TableGen/CodeGenSchedule.cpp351
-rw-r--r--llvm/utils/TableGen/CodeGenSchedule.h13
-rw-r--r--llvm/utils/TableGen/CodeGenTarget.cpp255
-rw-r--r--llvm/utils/TableGen/CodeGenTarget.h9
-rw-r--r--llvm/utils/TableGen/DAGISelEmitter.cpp14
-rw-r--r--llvm/utils/TableGen/DAGISelMatcher.h20
-rw-r--r--llvm/utils/TableGen/DAGISelMatcherEmitter.cpp226
-rw-r--r--llvm/utils/TableGen/DAGISelMatcherGen.cpp10
-rw-r--r--llvm/utils/TableGen/DFAEmitter.cpp5
-rw-r--r--llvm/utils/TableGen/DFAPacketizerEmitter.cpp2
-rw-r--r--llvm/utils/TableGen/DirectiveEmitter.cpp760
-rw-r--r--llvm/utils/TableGen/ExegesisEmitter.cpp2
-rw-r--r--llvm/utils/TableGen/FixedLenDecoderEmitter.cpp44
-rw-r--r--llvm/utils/TableGen/GICombinerEmitter.cpp55
-rw-r--r--llvm/utils/TableGen/GlobalISel/CodeExpander.cpp23
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp2
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.cpp2
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp15
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchTree.h5
-rw-r--r--llvm/utils/TableGen/GlobalISelEmitter.cpp802
-rw-r--r--llvm/utils/TableGen/InstrInfoEmitter.cpp39
-rw-r--r--llvm/utils/TableGen/IntrinsicEmitter.cpp16
-rw-r--r--llvm/utils/TableGen/OptParserEmitter.cpp309
-rw-r--r--llvm/utils/TableGen/PredicateExpander.cpp22
-rw-r--r--llvm/utils/TableGen/PredicateExpander.h3
-rw-r--r--llvm/utils/TableGen/PseudoLoweringEmitter.cpp114
-rw-r--r--llvm/utils/TableGen/RISCVCompressInstEmitter.cpp234
-rw-r--r--llvm/utils/TableGen/RegisterBankEmitter.cpp19
-rw-r--r--llvm/utils/TableGen/RegisterInfoEmitter.cpp47
-rw-r--r--llvm/utils/TableGen/SearchableTableEmitter.cpp229
-rw-r--r--llvm/utils/TableGen/SubtargetEmitter.cpp122
-rw-r--r--llvm/utils/TableGen/SubtargetFeatureInfo.cpp5
-rw-r--r--llvm/utils/TableGen/SubtargetFeatureInfo.h5
-rw-r--r--llvm/utils/TableGen/TableGen.cpp30
-rw-r--r--llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp15
-rw-r--r--llvm/utils/TableGen/X86DisassemblerTables.cpp2
-rw-r--r--llvm/utils/TableGen/X86FoldTablesEmitter.cpp27
-rw-r--r--llvm/utils/TableGen/X86RecognizableInstr.cpp5
50 files changed, 2571 insertions, 1675 deletions
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index 3d63059dcb8b..9d304910ba4e 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -612,7 +612,7 @@ struct MatchableInfo {
/// operator< - Compare two matchables.
bool operator<(const MatchableInfo &RHS) const {
// The primary comparator is the instruction mnemonic.
- if (int Cmp = Mnemonic.compare(RHS.Mnemonic))
+ if (int Cmp = Mnemonic.compare_lower(RHS.Mnemonic))
return Cmp == -1;
if (AsmOperands.size() != RHS.AsmOperands.size())
@@ -789,9 +789,8 @@ public:
}
bool hasOptionalOperands() const {
- return find_if(Classes, [](const ClassInfo &Class) {
- return Class.IsOptional;
- }) != Classes.end();
+ return any_of(Classes,
+ [](const ClassInfo &Class) { return Class.IsOptional; });
}
};
@@ -1018,7 +1017,7 @@ void MatchableInfo::tokenizeAsmString(const AsmMatcherInfo &Info,
case '$': {
if (InTok) {
- addAsmOperand(String.slice(Prev, i), false);
+ addAsmOperand(String.slice(Prev, i), IsIsolatedToken);
InTok = false;
IsIsolatedToken = false;
}
@@ -1113,9 +1112,7 @@ static std::string getEnumNameForToken(StringRef Str) {
case '-': Res += "_MINUS_"; break;
case '#': Res += "_HASH_"; break;
default:
- if ((*it >= 'A' && *it <= 'Z') ||
- (*it >= 'a' && *it <= 'z') ||
- (*it >= '0' && *it <= '9'))
+ if (isAlnum(*it))
Res += *it;
else
Res += "_" + utostr((unsigned) *it) + "_";
@@ -1980,7 +1977,7 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
}
CvtOS << " unsigned OpIdx;\n";
CvtOS << " Inst.setOpcode(Opcode);\n";
- CvtOS << " for (const uint8_t *p = Converter; *p; p+= 2) {\n";
+ CvtOS << " for (const uint8_t *p = Converter; *p; p += 2) {\n";
if (HasOptionalOperands) {
CvtOS << " OpIdx = *(p + 1) - DefaultsOffset[*(p + 1)];\n";
} else {
@@ -1990,14 +1987,14 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
CvtOS << " default: llvm_unreachable(\"invalid conversion entry!\");\n";
CvtOS << " case CVT_Reg:\n";
CvtOS << " static_cast<" << TargetOperandClass
- << "&>(*Operands[OpIdx]).addRegOperands(Inst, 1);\n";
+ << " &>(*Operands[OpIdx]).addRegOperands(Inst, 1);\n";
CvtOS << " break;\n";
CvtOS << " case CVT_Tied: {\n";
CvtOS << " assert(OpIdx < (size_t)(std::end(TiedAsmOperandTable) -\n";
- CvtOS << " std::begin(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 << " if (TiedResOpnd != (uint8_t)-1)\n";
CvtOS << " Inst.addOperand(Inst.getOperand(TiedResOpnd));\n";
CvtOS << " break;\n";
CvtOS << " }\n";
@@ -2012,7 +2009,7 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
<< " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n"
<< " unsigned NumMCOperands = 0;\n"
<< " const uint8_t *Converter = ConversionTable[Kind];\n"
- << " for (const uint8_t *p = Converter; *p; p+= 2) {\n"
+ << " for (const uint8_t *p = Converter; *p; p += 2) {\n"
<< " switch (*p) {\n"
<< " default: llvm_unreachable(\"invalid conversion entry!\");\n"
<< " case CVT_Reg:\n"
@@ -2129,12 +2126,12 @@ emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
<< OpInfo.MINumOperands << ");\n"
<< " } else {\n"
<< " static_cast<" << TargetOperandClass
- << "&>(*Operands[OpIdx])." << Op.Class->RenderMethod
+ << " &>(*Operands[OpIdx])." << Op.Class->RenderMethod
<< "(Inst, " << OpInfo.MINumOperands << ");\n"
<< " }\n";
} else {
CvtOS << " static_cast<" << TargetOperandClass
- << "&>(*Operands[OpIdx])." << Op.Class->RenderMethod
+ << " &>(*Operands[OpIdx])." << Op.Class->RenderMethod
<< "(Inst, " << OpInfo.MINumOperands << ");\n";
}
CvtOS << " break;\n";
@@ -2390,9 +2387,9 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target,
static void emitOperandMatchErrorDiagStrings(AsmMatcherInfo &Info, raw_ostream &OS) {
// If the target does not use DiagnosticString for any operands, don't emit
// an unused function.
- if (std::all_of(
- Info.Classes.begin(), Info.Classes.end(),
- [](const ClassInfo &CI) { return CI.DiagnosticString.empty(); }))
+ if (llvm::all_of(Info.Classes, [](const ClassInfo &CI) {
+ return CI.DiagnosticString.empty();
+ }))
return;
OS << "static const char *getMatchKindDiag(" << Info.Target.getName()
@@ -2448,7 +2445,7 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info,
OS << "static unsigned validateOperandClass(MCParsedAsmOperand &GOp, "
<< "MatchClassKind Kind) {\n";
OS << " " << Info.Target.getName() << "Operand &Operand = ("
- << Info.Target.getName() << "Operand&)GOp;\n";
+ << Info.Target.getName() << "Operand &)GOp;\n";
// The InvalidMatchClass is not to match any operand.
OS << " if (Kind == InvalidMatchClass)\n";
@@ -2811,7 +2808,7 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info,
Record *AsmVariant = Target.getAsmParserVariant(VC);
int AsmParserVariantNo = AsmVariant->getValueAsInt("Variant");
StringRef AsmParserVariantName = AsmVariant->getValueAsString("Name");
- OS << " case " << AsmParserVariantNo << ":\n";
+ OS << " case " << AsmParserVariantNo << ":\n";
emitMnemonicAliasVariant(OS, Info, Aliases, /*Indent=*/2,
AsmParserVariantName);
OS << " break;\n";
@@ -2880,7 +2877,7 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
OS << " { ";
// Store a pascal-style length byte in the mnemonic.
- std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str();
+ std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.lower();
OS << StringTable.GetOrAddStringOffset(LenMnemonic, false)
<< " /* " << II.Mnemonic << " */, ";
@@ -2978,7 +2975,7 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
"FeatureBitsets[it->RequiredFeaturesIdx];\n";
OS << " if (!ParseForAllFeatures && (AvailableFeatures & "
"RequiredFeatures) != RequiredFeatures)\n";
- OS << " continue;\n\n";
+ OS << " continue;\n\n";
// Emit check to ensure the operand number matches.
OS << " // check if the operand in question has a custom parser.\n";
@@ -3011,10 +3008,10 @@ static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
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 << " 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 << " 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";
@@ -3086,7 +3083,7 @@ static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target,
OS << "\n";
OS << " std::string Res = \", did you mean: \";\n";
OS << " unsigned i = 0;\n";
- OS << " for( ; i < Candidates.size() - 1; i++)\n";
+ OS << " for (; i < Candidates.size() - 1; i++)\n";
OS << " Res += Candidates[i].str() + \", \";\n";
OS << " return Res + Candidates[i].str() + \"?\";\n";
}
@@ -3094,6 +3091,67 @@ static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target,
OS << "\n";
}
+static void emitMnemonicChecker(raw_ostream &OS,
+ CodeGenTarget &Target,
+ unsigned VariantCount,
+ bool HasMnemonicFirst,
+ bool HasMnemonicAliases) {
+ OS << "static bool " << Target.getName()
+ << "CheckMnemonic(StringRef Mnemonic,\n";
+ OS << " "
+ << "const FeatureBitset &AvailableFeatures,\n";
+ OS << " "
+ << "unsigned VariantID) {\n";
+
+ if (!VariantCount) {
+ OS << " return false;\n";
+ } else {
+ if (HasMnemonicAliases) {
+ OS << " // Process all MnemonicAliases to remap the mnemonic.\n";
+ OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures, VariantID);";
+ OS << "\n\n";
+ }
+ OS << " // Find the appropriate table for this asm variant.\n";
+ OS << " const MatchEntry *Start, *End;\n";
+ OS << " switch (VariantID) {\n";
+ OS << " default: llvm_unreachable(\"invalid variant!\");\n";
+ for (unsigned VC = 0; VC != VariantCount; ++VC) {
+ Record *AsmVariant = Target.getAsmParserVariant(VC);
+ int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
+ OS << " case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC
+ << "); End = std::end(MatchTable" << VC << "); break;\n";
+ }
+ OS << " }\n\n";
+
+ OS << " // Search the table.\n";
+ if (HasMnemonicFirst) {
+ OS << " auto MnemonicRange = "
+ "std::equal_range(Start, End, Mnemonic, LessOpcode());\n\n";
+ } else {
+ OS << " auto MnemonicRange = std::make_pair(Start, End);\n";
+ OS << " unsigned SIndex = Mnemonic.empty() ? 0 : 1;\n";
+ OS << " if (!Mnemonic.empty())\n";
+ OS << " MnemonicRange = "
+ << "std::equal_range(Start, End, Mnemonic.lower(), LessOpcode());\n\n";
+ }
+
+ OS << " if (MnemonicRange.first == MnemonicRange.second)\n";
+ OS << " return false;\n\n";
+
+ OS << " for (const MatchEntry *it = MnemonicRange.first, "
+ << "*ie = MnemonicRange.second;\n";
+ OS << " it != ie; ++it) {\n";
+ OS << " const FeatureBitset &RequiredFeatures =\n";
+ OS << " FeatureBitsets[it->RequiredFeaturesIdx];\n";
+ OS << " if ((AvailableFeatures & RequiredFeatures) == ";
+ OS << "RequiredFeatures)\n";
+ OS << " return true;\n";
+ OS << " }\n";
+ OS << " return false;\n";
+ }
+ OS << "}\n";
+ OS << "\n";
+}
// Emit a function mapping match classes to strings, for debugging.
static void emitMatchClassKindNames(std::forward_list<ClassInfo> &Infos,
@@ -3194,7 +3252,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << "#undef GET_ASSEMBLER_HEADER\n";
OS << " // This should be included into the middle of the declaration of\n";
OS << " // your subclasses implementation of MCTargetAsmParser.\n";
- OS << " FeatureBitset ComputeAvailableFeatures(const FeatureBitset& FB) const;\n";
+ OS << " FeatureBitset ComputeAvailableFeatures(const FeatureBitset &FB) const;\n";
if (HasOptionalOperands) {
OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, "
<< "unsigned Opcode,\n"
@@ -3324,7 +3382,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
HasDeprecation |= MI->HasDeprecation;
// Store a pascal-style length byte in the mnemonic.
- std::string LenMnemonic = char(MI->Mnemonic.size()) + MI->Mnemonic.str();
+ std::string LenMnemonic = char(MI->Mnemonic.size()) + MI->Mnemonic.lower();
MaxMnemonicIndex = std::max(MaxMnemonicIndex,
StringTable.GetOrAddStringOffset(LenMnemonic, false));
}
@@ -3438,7 +3496,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
continue;
// Store a pascal-style length byte in the mnemonic.
- std::string LenMnemonic = char(MI->Mnemonic.size()) + MI->Mnemonic.str();
+ std::string LenMnemonic =
+ char(MI->Mnemonic.size()) + MI->Mnemonic.lower();
OS << " { " << StringTable.GetOrAddStringOffset(LenMnemonic, false)
<< " /* " << MI->Mnemonic << " */, "
<< Target.getInstNamespace() << "::"
@@ -3497,12 +3556,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " // Get the instruction mnemonic, which is the first token.\n";
if (HasMnemonicFirst) {
OS << " StringRef Mnemonic = ((" << Target.getName()
- << "Operand&)*Operands[0]).getToken();\n\n";
+ << "Operand &)*Operands[0]).getToken();\n\n";
} else {
OS << " StringRef Mnemonic;\n";
OS << " if (Operands[0]->isToken())\n";
OS << " Mnemonic = ((" << Target.getName()
- << "Operand&)*Operands[0]).getToken();\n\n";
+ << "Operand &)*Operands[0]).getToken();\n\n";
}
if (HasMnemonicAliases) {
@@ -3552,7 +3611,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
}
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"AsmMatcher: found \" <<\n"
- << " std::distance(MnemonicRange.first, MnemonicRange.second) << \n"
+ << " std::distance(MnemonicRange.first, MnemonicRange.second) <<\n"
<< " \" encodings with mnemonic '\" << Mnemonic << \"'\\n\");\n\n";
OS << " // Return a more specific error code if no mnemonics match.\n";
@@ -3727,10 +3786,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " FeatureBitset NewMissingFeatures = RequiredFeatures & "
"~AvailableFeatures;\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Missing target features:\";\n";
- OS << " for (unsigned I = 0, E = NewMissingFeatures.size(); I != E; ++I)\n";
- OS << " if (NewMissingFeatures[I])\n";
- OS << " dbgs() << ' ' << I;\n";
- OS << " dbgs() << \"\\n\");\n";
+ OS << " for (unsigned I = 0, E = NewMissingFeatures.size(); I != E; ++I)\n";
+ OS << " if (NewMissingFeatures[I])\n";
+ OS << " dbgs() << ' ' << I;\n";
+ OS << " dbgs() << \"\\n\");\n";
if (ReportMultipleNearMisses) {
OS << " FeaturesNearMiss = NearMissInfo::getMissedFeature(NewMissingFeatures);\n";
} else {
@@ -3865,7 +3924,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " getTargetOptions().MCNoDeprecatedWarn &&\n";
OS << " MII.getDeprecatedInfo(Inst, getSTI(), Info)) {\n";
OS << " SMLoc Loc = ((" << Target.getName()
- << "Operand&)*Operands[0]).getStartLoc();\n";
+ << "Operand &)*Operands[0]).getStartLoc();\n";
OS << " getParser().Warning(Loc, Info, None);\n";
OS << " }\n";
}
@@ -3908,6 +3967,14 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
emitMnemonicSpellChecker(OS, Target, VariantCount);
OS << "#endif // GET_MNEMONIC_SPELL_CHECKER\n\n";
+
+ OS << "\n#ifdef GET_MNEMONIC_CHECKER\n";
+ OS << "#undef GET_MNEMONIC_CHECKER\n\n";
+
+ emitMnemonicChecker(OS, Target, VariantCount,
+ HasMnemonicFirst, HasMnemonicAliases);
+
+ OS << "#endif // GET_MNEMONIC_CHECKER\n\n";
}
namespace llvm {
diff --git a/llvm/utils/TableGen/AsmWriterEmitter.cpp b/llvm/utils/TableGen/AsmWriterEmitter.cpp
index d10ea71e97e3..92df204475b9 100644
--- a/llvm/utils/TableGen/AsmWriterEmitter.cpp
+++ b/llvm/utils/TableGen/AsmWriterEmitter.cpp
@@ -64,9 +64,15 @@ public:
AsmWriterEmitter(RecordKeeper &R);
void run(raw_ostream &o);
-
private:
- void EmitPrintInstruction(raw_ostream &o);
+ void EmitGetMnemonic(
+ raw_ostream &o,
+ std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
+ unsigned &BitsLeft, unsigned &AsmStrBits);
+ void EmitPrintInstruction(
+ raw_ostream &o,
+ std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
+ unsigned &BitsLeft, unsigned &AsmStrBits);
void EmitGetRegisterName(raw_ostream &o);
void EmitPrintAliasInstruction(raw_ostream &O);
@@ -212,12 +218,11 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
// Otherwise, scan to see if all of the other instructions in this command
// set share the operand.
- if (std::any_of(Idxs.begin()+1, Idxs.end(),
- [&](unsigned Idx) {
- const AsmWriterInst &OtherInst = Instructions[Idx];
- return OtherInst.Operands.size() == Op ||
- OtherInst.Operands[Op] != FirstInst.Operands[Op];
- }))
+ if (any_of(drop_begin(Idxs), [&](unsigned Idx) {
+ const AsmWriterInst &OtherInst = Instructions[Idx];
+ return OtherInst.Operands.size() == Op ||
+ OtherInst.Operands[Op] != FirstInst.Operands[Op];
+ }))
break;
// Okay, everything in this command set has the same next operand. Add it
@@ -288,22 +293,19 @@ static void UnescapeAliasString(std::string &Str) {
}
}
-/// EmitPrintInstruction - Generate the code for the "printInstruction" method
-/// implementation. Destroys all instances of AsmWriterInst information, by
-/// clearing the Instructions vector.
-void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
+void AsmWriterEmitter::EmitGetMnemonic(
+ raw_ostream &O,
+ std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
+ unsigned &BitsLeft, unsigned &AsmStrBits) {
Record *AsmWriter = Target.getAsmWriter();
StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
- O << "/// printInstruction - This method is automatically generated by "
+ O << "/// getMnemonic - This method is automatically generated by "
"tablegen\n"
"/// from the instruction set description.\n"
- "void "
- << Target.getName() << ClassName
- << "::printInstruction(const MCInst *MI, uint64_t Address, "
- << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")
- << "raw_ostream &O) {\n";
+ "std::pair<const char *, uint64_t> "
+ << Target.getName() << ClassName << "::getMnemonic(const MCInst *MI) {\n";
// Build an aggregate string, and build a table of offsets into it.
SequenceToOffsetTable<std::string> StringTable;
@@ -349,13 +351,11 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
}
// Figure out how many bits we used for the string index.
- unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+2);
+ AsmStrBits = Log2_32_Ceil(MaxStringIdx + 2);
// To reduce code size, we compactify common instructions into a few bits
// in the opcode-indexed table.
- unsigned BitsLeft = OpcodeInfoBits-AsmStrBits;
-
- std::vector<std::vector<std::string>> TableDrivenOperandPrinters;
+ BitsLeft = OpcodeInfoBits - AsmStrBits;
while (true) {
std::vector<std::string> UniqueOperandCommands;
@@ -435,15 +435,47 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
++Table;
}
- // Emit the initial tab character.
- O << " O << \"\\t\";\n\n";
-
O << " // Emit the opcode for the instruction.\n";
O << BitsString;
+ // Return mnemonic string and bits.
+ O << " return {AsmStrs+(Bits & " << (1 << AsmStrBits) - 1
+ << ")-1, Bits};\n\n";
+
+ O << "}\n";
+}
+
+/// EmitPrintInstruction - Generate the code for the "printInstruction" method
+/// implementation. Destroys all instances of AsmWriterInst information, by
+/// clearing the Instructions vector.
+void AsmWriterEmitter::EmitPrintInstruction(
+ raw_ostream &O,
+ std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
+ unsigned &BitsLeft, unsigned &AsmStrBits) {
+ const unsigned OpcodeInfoBits = 64;
+ Record *AsmWriter = Target.getAsmWriter();
+ StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
+ bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
+
+ O << "/// printInstruction - This method is automatically generated by "
+ "tablegen\n"
+ "/// from the instruction set description.\n"
+ "void "
+ << Target.getName() << ClassName
+ << "::printInstruction(const MCInst *MI, uint64_t Address, "
+ << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")
+ << "raw_ostream &O) {\n";
+
+ // Emit the initial tab character.
+ O << " O << \"\\t\";\n\n";
+
// Emit the starting string.
- O << " assert(Bits != 0 && \"Cannot print this instruction.\");\n"
- << " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ")-1;\n\n";
+ O << " auto MnemonicInfo = getMnemonic(MI);\n\n";
+ O << " O << MnemonicInfo.first;\n\n";
+
+ O << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32)
+ << "_t Bits = MnemonicInfo.second;\n"
+ << " assert(Bits != 0 && \"Cannot print this instruction.\");\n";
// Output the table driven operand information.
BitsLeft = OpcodeInfoBits-AsmStrBits;
@@ -489,10 +521,8 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
}
// Okay, delete instructions with no operand info left.
- auto I = llvm::remove_if(Instructions,
- [](AsmWriterInst &Inst) { return Inst.Operands.empty(); });
- Instructions.erase(I, Instructions.end());
-
+ llvm::erase_if(Instructions,
+ [](AsmWriterInst &Inst) { return Inst.Operands.empty(); });
// Because this is a vector, we want to emit from the end. Reverse all of the
// elements in the vector.
@@ -683,9 +713,7 @@ public:
++Next;
} else {
// $name, just eat the usual suspects.
- while (I != End &&
- ((*I >= 'a' && *I <= 'z') || (*I >= 'A' && *I <= 'Z') ||
- (*I >= '0' && *I <= '9') || *I == '_'))
+ while (I != End && (isAlnum(*I) || *I == '_'))
++I;
Next = I;
}
@@ -1232,13 +1260,10 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
<< " 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"
- << SI->getValue() << "\n"
- << " }\n";
- } else
- llvm_unreachable("Unexpected MCOperandPredicate field!");
+ StringRef MCOpPred = MCOpPredicates[i]->getValueAsString("MCOperandPredicate");
+ O << " case " << i + 1 << ": {\n"
+ << MCOpPred.data() << "\n"
+ << " }\n";
}
O << " }\n"
<< "}\n\n";
@@ -1262,7 +1287,11 @@ AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) {
}
void AsmWriterEmitter::run(raw_ostream &O) {
- EmitPrintInstruction(O);
+ std::vector<std::vector<std::string>> TableDrivenOperandPrinters;
+ unsigned BitsLeft = 0;
+ unsigned AsmStrBits = 0;
+ EmitGetMnemonic(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);
+ EmitPrintInstruction(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);
EmitGetRegisterName(O);
EmitPrintAliasInstruction(O);
}
diff --git a/llvm/utils/TableGen/AsmWriterInst.cpp b/llvm/utils/TableGen/AsmWriterInst.cpp
index 24d29ffc28e5..cf24f79334ca 100644
--- a/llvm/utils/TableGen/AsmWriterInst.cpp
+++ b/llvm/utils/TableGen/AsmWriterInst.cpp
@@ -18,12 +18,7 @@
using namespace llvm;
-static bool isIdentChar(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z') ||
- (C >= '0' && C <= '9') ||
- C == '_';
-}
+static bool isIdentChar(char C) { return isAlnum(C) || C == '_'; }
std::string AsmWriterOperand::getCode(bool PassSubtarget) const {
if (OperandType == isLiteralTextOperand) {
diff --git a/llvm/utils/TableGen/CallingConvEmitter.cpp b/llvm/utils/TableGen/CallingConvEmitter.cpp
index a4e993f80ec9..9e997483d21d 100644
--- a/llvm/utils/TableGen/CallingConvEmitter.cpp
+++ b/llvm/utils/TableGen/CallingConvEmitter.cpp
@@ -38,6 +38,7 @@ void CallingConvEmitter::run(raw_ostream &O) {
// Emit prototypes for all of the non-custom CC's so that they can forward ref
// each other.
+ Records.startTimer("Emit prototypes");
for (Record *CC : CCs) {
if (!CC->getValueAsBit("Custom")) {
unsigned Pad = CC->getName().size();
@@ -56,6 +57,7 @@ void CallingConvEmitter::run(raw_ostream &O) {
}
// Emit each non-custom calling convention description in full.
+ Records.startTimer("Emit full descriptions");
for (Record *CC : CCs) {
if (!CC->getValueAsBit("Custom"))
EmitCallingConv(CC, O);
@@ -85,7 +87,7 @@ void CallingConvEmitter::EmitCallingConv(Record *CC, raw_ostream &O) {
EmitAction(CCActions->getElementAsRecord(i), 2, O);
}
- O << "\n return true; // CC didn't match.\n";
+ O << "\n return true; // CC didn't match.\n";
O << "}\n";
}
@@ -238,11 +240,11 @@ void CallingConvEmitter::EmitAction(Record *Action,
O << IndentStr << "LocInfo = CCValAssign::FPExt;\n";
} else {
O << IndentStr << "if (ArgFlags.isSExt())\n"
- << IndentStr << IndentStr << "LocInfo = CCValAssign::SExt;\n"
+ << IndentStr << " LocInfo = CCValAssign::SExt;\n"
<< IndentStr << "else if (ArgFlags.isZExt())\n"
- << IndentStr << IndentStr << "LocInfo = CCValAssign::ZExt;\n"
+ << IndentStr << " LocInfo = CCValAssign::ZExt;\n"
<< IndentStr << "else\n"
- << IndentStr << IndentStr << "LocInfo = CCValAssign::AExt;\n";
+ << IndentStr << " LocInfo = CCValAssign::AExt;\n";
}
} else if (Action->isSubClassOf("CCPromoteToUpperBitsInType")) {
Record *DestTy = Action->getValueAsDef("DestTy");
@@ -254,11 +256,11 @@ void CallingConvEmitter::EmitAction(Record *Action,
"point");
} else {
O << IndentStr << "if (ArgFlags.isSExt())\n"
- << IndentStr << IndentStr << "LocInfo = CCValAssign::SExtUpper;\n"
+ << IndentStr << " LocInfo = CCValAssign::SExtUpper;\n"
<< IndentStr << "else if (ArgFlags.isZExt())\n"
- << IndentStr << IndentStr << "LocInfo = CCValAssign::ZExtUpper;\n"
+ << IndentStr << " LocInfo = CCValAssign::ZExtUpper;\n"
<< IndentStr << "else\n"
- << IndentStr << IndentStr << "LocInfo = CCValAssign::AExtUpper;\n";
+ << IndentStr << " LocInfo = CCValAssign::AExtUpper;\n";
}
} else if (Action->isSubClassOf("CCBitConvertToType")) {
Record *DestTy = Action->getValueAsDef("DestTy");
@@ -282,7 +284,7 @@ void CallingConvEmitter::EmitAction(Record *Action,
O << IndentStr
<< "if (" << Action->getValueAsString("FuncName") << "(ValNo, ValVT, "
<< "LocVT, LocInfo, ArgFlags, State))\n";
- O << IndentStr << IndentStr << "return false;\n";
+ O << IndentStr << " return false;\n";
} else {
errs() << *Action;
PrintFatalError(Action->getLoc(), "Unknown CCAction!");
diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp
index 6338d44fb2a7..53bf953b13cf 100644
--- a/llvm/utils/TableGen/CodeEmitterGen.cpp
+++ b/llvm/utils/TableGen/CodeEmitterGen.cpp
@@ -311,7 +311,7 @@ std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *Enc
for (const RecordVal &RV : EncodingDef->getValues()) {
// Ignore fixed fields in the record, we're looking for values like:
// bits<5> RST = { ?, ?, ?, ?, ? };
- if (RV.getPrefix() || RV.getValue()->isComplete())
+ if (RV.isNonconcreteOK() || RV.getValue()->isComplete())
continue;
AddCodeToMergeInOperand(R, BI, std::string(RV.getName()), NumberedOp,
@@ -483,7 +483,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
<< " Inst = Inst.zext(" << BitWidth << ");\n"
<< " if (Scratch.getBitWidth() != " << BitWidth << ")\n"
<< " Scratch = Scratch.zext(" << BitWidth << ");\n"
- << " LoadIntFromMemory(Inst, (uint8_t*)&InstBits[opcode * " << NumWords
+ << " LoadIntFromMemory(Inst, (uint8_t *)&InstBits[opcode * " << NumWords
<< "], " << NumBytes << ");\n"
<< " APInt &Value = Inst;\n"
<< " APInt &op = Scratch;\n"
@@ -643,9 +643,9 @@ void CodeEmitterGen::run(raw_ostream &o) {
<< " report_fatal_error(Msg.str());\n"
<< " }\n"
<< "#else\n"
- << "// Silence unused variable warning on targets that don't use MCII for "
+ << " // Silence unused variable warning on targets that don't use MCII for "
"other purposes (e.g. BPF).\n"
- << "(void)MCII;\n"
+ << " (void)MCII;\n"
<< "#endif // NDEBUG\n";
o << "}\n";
o << "#endif\n";
diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
index 6fdc116721f3..1ca4a68eb155 100644
--- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -507,9 +507,9 @@ bool TypeInfer::EnforceSmallerThan(TypeSetByHwMode &Small,
// Always treat non-scalable MVTs as smaller than scalable MVTs for the
// purposes of ordering.
auto ASize = std::make_tuple(A.isScalableVector(), A.getScalarSizeInBits(),
- A.getSizeInBits());
+ A.getSizeInBits().getKnownMinSize());
auto BSize = std::make_tuple(B.isScalableVector(), B.getScalarSizeInBits(),
- B.getSizeInBits());
+ B.getSizeInBits().getKnownMinSize());
return ASize < BSize;
};
auto SameKindLE = [](MVT A, MVT B) -> bool {
@@ -520,8 +520,10 @@ bool TypeInfer::EnforceSmallerThan(TypeSetByHwMode &Small,
std::make_tuple(B.isVector(), B.isScalableVector()))
return false;
- return std::make_tuple(A.getScalarSizeInBits(), A.getSizeInBits()) <=
- std::make_tuple(B.getScalarSizeInBits(), B.getSizeInBits());
+ return std::make_tuple(A.getScalarSizeInBits(),
+ A.getSizeInBits().getKnownMinSize()) <=
+ std::make_tuple(B.getScalarSizeInBits(),
+ B.getSizeInBits().getKnownMinSize());
};
for (unsigned M : Modes) {
@@ -728,14 +730,14 @@ bool TypeInfer::EnforceSameSize(TypeSetByHwMode &A, TypeSetByHwMode &B) {
if (B.empty())
Changed |= EnforceAny(B);
- auto NoSize = [](const SmallSet<unsigned,2> &Sizes, MVT T) -> bool {
+ auto NoSize = [](const SmallSet<TypeSize, 2> &Sizes, MVT T) -> bool {
return !Sizes.count(T.getSizeInBits());
};
for (unsigned M : union_modes(A, B)) {
TypeSetByHwMode::SetType &AS = A.get(M);
TypeSetByHwMode::SetType &BS = B.get(M);
- SmallSet<unsigned,2> AN, BN;
+ SmallSet<TypeSize, 2> AN, BN;
for (MVT T : AS)
AN.insert(T.getSizeInBits());
@@ -871,7 +873,7 @@ bool TreePredicateFn::hasPredCode() const {
}
std::string TreePredicateFn::getPredCode() const {
- std::string Code = "";
+ std::string Code;
if (!isLoad() && !isStore() && !isAtomic()) {
Record *MemoryVT = getMemoryVT();
@@ -2388,7 +2390,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
MVT::SimpleValueType VT = P.second.SimpleTy;
if (VT == MVT::iPTR || VT == MVT::iPTRAny)
continue;
- unsigned Size = MVT(VT).getSizeInBits();
+ unsigned Size = MVT(VT).getFixedSizeInBits();
// Make sure that the value is representable for this type.
if (Size >= 32)
continue;
@@ -3086,7 +3088,7 @@ CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R,
VerifyInstructionFlags();
}
-Record *CodeGenDAGPatterns::getSDNodeNamed(const std::string &Name) const {
+Record *CodeGenDAGPatterns::getSDNodeNamed(StringRef Name) const {
Record *N = Records.getDef(Name);
if (!N || !N->isSubClassOf("SDNode"))
PrintFatalError("Error getting SDNode '" + Name + "'!");
@@ -3589,6 +3591,9 @@ static bool hasNullFragReference(DagInit *DI) {
if (Operator->getName() == "null_frag") return true;
// If any of the arguments reference the null fragment, return true.
for (unsigned i = 0, e = DI->getNumArgs(); i != e; ++i) {
+ if (auto Arg = dyn_cast<DefInit>(DI->getArg(i)))
+ if (Arg->getDef()->getName() == "null_frag")
+ return true;
DagInit *Arg = dyn_cast<DagInit>(DI->getArg(i));
if (Arg && hasNullFragReference(Arg))
return true;
@@ -3696,10 +3701,11 @@ void CodeGenDAGPatterns::parseInstructionPattern(
for (unsigned i = 0; i != NumResults; ++i) {
if (i == CGI.Operands.size()) {
const std::string &OpName =
- std::find_if(InstResults.begin(), InstResults.end(),
- [](const std::pair<std::string, TreePatternNodePtr> &P) {
- return P.second;
- })
+ llvm::find_if(
+ InstResults,
+ [](const std::pair<std::string, TreePatternNodePtr> &P) {
+ return P.second;
+ })
->first;
I.error("'" + OpName + "' set but does not appear in operand list!");
@@ -4288,7 +4294,7 @@ void CodeGenDAGPatterns::ExpandHwModeBasedTypes() {
std::vector<Predicate> Preds = P.Predicates;
const std::vector<Predicate> &MC = ModeChecks[Mode];
- Preds.insert(Preds.end(), MC.begin(), MC.end());
+ llvm::append_range(Preds, MC);
PatternsToMatch.emplace_back(P.getSrcRecord(), Preds, std::move(NewSrc),
std::move(NewDst), P.getDstRegs(),
P.getAddedComplexity(), Record::getNewUID(),
diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.h b/llvm/utils/TableGen/CodeGenDAGPatterns.h
index a3b84d76fde9..bc939fe9acc1 100644
--- a/llvm/utils/TableGen/CodeGenDAGPatterns.h
+++ b/llvm/utils/TableGen/CodeGenDAGPatterns.h
@@ -14,7 +14,6 @@
#ifndef LLVM_UTILS_TABLEGEN_CODEGENDAGPATTERNS_H
#define LLVM_UTILS_TABLEGEN_CODEGENDAGPATTERNS_H
-#include "CodeGenHwModes.h"
#include "CodeGenIntrinsics.h"
#include "CodeGenTarget.h"
#include "SDNodeProperties.h"
@@ -42,7 +41,6 @@ class SDNodeInfo;
class TreePattern;
class TreePatternNode;
class CodeGenDAGPatterns;
-class ComplexPattern;
/// Shared pointer for TreePatternNode.
using TreePatternNodePtr = std::shared_ptr<TreePatternNode>;
@@ -190,7 +188,7 @@ private:
struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> {
using SetType = MachineValueTypeSet;
- std::vector<unsigned> AddrSpaces;
+ SmallVector<unsigned, 16> AddrSpaces;
TypeSetByHwMode() = default;
TypeSetByHwMode(const TypeSetByHwMode &VTS) = default;
@@ -438,8 +436,6 @@ public:
unsigned getScope() const { return Scope; }
const std::string &getIdentifier() const { return Identifier; }
- std::string getFullName() const;
-
bool operator==(const ScopedName &o) const;
bool operator!=(const ScopedName &o) const;
};
@@ -1180,7 +1176,7 @@ public:
const CodeGenTarget &getTargetInfo() const { return Target; }
const TypeSetByHwMode &getLegalTypes() const { return LegalVTS; }
- Record *getSDNodeNamed(const std::string &Name) const;
+ Record *getSDNodeNamed(StringRef Name) const;
const SDNodeInfo &getSDNodeInfo(Record *R) const {
auto F = SDNodes.find(R);
diff --git a/llvm/utils/TableGen/CodeGenInstruction.cpp b/llvm/utils/TableGen/CodeGenInstruction.cpp
index 1df5902b081e..960fe08677f7 100644
--- a/llvm/utils/TableGen/CodeGenInstruction.cpp
+++ b/llvm/utils/TableGen/CodeGenInstruction.cpp
@@ -472,7 +472,7 @@ HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const {
/// include text from the specified variant, returning the new string.
std::string CodeGenInstruction::
FlattenAsmStringVariants(StringRef Cur, unsigned Variant) {
- std::string Res = "";
+ std::string Res;
for (;;) {
// Find the start of the next variant string.
diff --git a/llvm/utils/TableGen/CodeGenIntrinsics.h b/llvm/utils/TableGen/CodeGenIntrinsics.h
index af59c1f3d833..c469f662a42d 100644
--- a/llvm/utils/TableGen/CodeGenIntrinsics.h
+++ b/llvm/utils/TableGen/CodeGenIntrinsics.h
@@ -148,6 +148,7 @@ struct CodeGenIntrinsic {
enum ArgAttrKind {
NoCapture,
NoAlias,
+ NoUndef,
Returned,
ReadOnly,
WriteOnly,
@@ -176,6 +177,13 @@ struct CodeGenIntrinsic {
return Properties & (1 << Prop);
}
+ /// Goes through all IntrProperties that have IsDefault
+ /// value set and sets the property.
+ void setDefaultProperties(Record *R, std::vector<Record *> DefaultProperties);
+
+ /// Helper function to set property \p Name to true;
+ void setProperty(Record *R);
+
/// Returns true if the parameter at \p ParamIdx is a pointer type. Returns
/// false if the parameter is not a pointer, or \p ParamIdx is greater than
/// the size of \p IS.ParamVTs.
@@ -185,7 +193,7 @@ struct CodeGenIntrinsic {
bool isParamImmArg(unsigned ParamIdx) const;
- CodeGenIntrinsic(Record *R);
+ CodeGenIntrinsic(Record *R, std::vector<Record *> DefaultProperties);
};
class CodeGenIntrinsicTable {
diff --git a/llvm/utils/TableGen/CodeGenMapTable.cpp b/llvm/utils/TableGen/CodeGenMapTable.cpp
index baca0768b26b..289a20a96f02 100644
--- a/llvm/utils/TableGen/CodeGenMapTable.cpp
+++ b/llvm/utils/TableGen/CodeGenMapTable.cpp
@@ -144,25 +144,15 @@ public:
}
}
- std::string getName() const {
- return Name;
- }
+ const std::string &getName() const { return Name; }
- std::string getFilterClass() {
- return FilterClass;
- }
+ const std::string &getFilterClass() const { return FilterClass; }
- ListInit *getRowFields() const {
- return RowFields;
- }
+ ListInit *getRowFields() const { return RowFields; }
- ListInit *getColFields() const {
- return ColFields;
- }
+ ListInit *getColFields() const { return ColFields; }
- ListInit *getKeyCol() const {
- return KeyCol;
- }
+ ListInit *getKeyCol() const { return KeyCol; }
const std::vector<ListInit*> &getValueCols() const {
return ValueCols;
@@ -200,7 +190,7 @@ private:
public:
MapTableEmitter(CodeGenTarget &Target, RecordKeeper &Records, Record *IMRec):
Target(Target), InstrMapDesc(IMRec) {
- const std::string FilterClass = InstrMapDesc.getFilterClass();
+ const std::string &FilterClass = InstrMapDesc.getFilterClass();
InstrDefs = Records.getAllDerivedDefinitions(FilterClass);
}
@@ -384,7 +374,7 @@ unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) {
for (unsigned i = 0; i < TotalNumInstr; i++) {
Record *CurInstr = NumberedInstructions[i]->TheDef;
std::vector<Record*> ColInstrs = MapTable[CurInstr];
- std::string OutStr("");
+ std::string OutStr;
unsigned RelExists = 0;
if (!ColInstrs.empty()) {
for (unsigned j = 0; j < NumCol; j++) {
@@ -422,7 +412,7 @@ void MapTableEmitter::emitBinSearch(raw_ostream &OS, unsigned TableSize) {
OS << " unsigned start = 0;\n";
OS << " unsigned end = " << TableSize << ";\n";
OS << " while (start < end) {\n";
- OS << " mid = start + (end - start)/2;\n";
+ OS << " mid = start + (end - start) / 2;\n";
OS << " if (Opcode == " << InstrMapDesc.getName() << "Table[mid][0]) {\n";
OS << " break;\n";
OS << " }\n";
diff --git a/llvm/utils/TableGen/CodeGenRegisters.cpp b/llvm/utils/TableGen/CodeGenRegisters.cpp
index 4584bc7cfae3..f9a7ba6bba80 100644
--- a/llvm/utils/TableGen/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/CodeGenRegisters.cpp
@@ -196,7 +196,7 @@ void CodeGenRegister::buildObjectGraph(CodeGenRegBank &RegBank) {
}
}
-const StringRef CodeGenRegister::getName() const {
+StringRef CodeGenRegister::getName() const {
assert(TheDef && "no def");
return TheDef->getName();
}
@@ -496,11 +496,10 @@ void CodeGenRegister::computeSecondarySubRegs(CodeGenRegBank &RegBank) {
assert(getSubRegIndex(SubReg) == SubRegIdx && "LeadingSuperRegs correct");
for (CodeGenRegister *SubReg : Cand->ExplicitSubRegs) {
if (CodeGenSubRegIndex *SubRegIdx = getSubRegIndex(SubReg)) {
- if (SubRegIdx->ConcatenationOf.empty()) {
+ if (SubRegIdx->ConcatenationOf.empty())
Parts.push_back(SubRegIdx);
- } else
- for (CodeGenSubRegIndex *SubIdx : SubRegIdx->ConcatenationOf)
- Parts.push_back(SubIdx);
+ else
+ append_range(Parts, SubRegIdx->ConcatenationOf);
} else {
// Sub-register doesn't exist.
Parts.clear();
@@ -743,6 +742,8 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
TopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1) {
GeneratePressureSet = R->getValueAsBit("GeneratePressureSet");
std::vector<Record*> TypeList = R->getValueAsListOfDefs("RegTypes");
+ if (TypeList.empty())
+ PrintFatalError(R->getLoc(), "RegTypes list must not be empty!");
for (unsigned i = 0, e = TypeList.size(); i != e; ++i) {
Record *Type = TypeList[i];
if (!Type->isSubClassOf("ValueType"))
@@ -751,7 +752,6 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
"' does not derive from the ValueType class!");
VTs.push_back(getValueTypeByHwMode(Type, RegBank.getHwModes()));
}
- assert(!VTs.empty() && "RegisterClass must contain at least one ValueType!");
// Allocation order 0 is the full set. AltOrders provides others.
const SetTheory::RecVec *Elements = RegBank.getSets().expand(R);
@@ -998,6 +998,8 @@ CodeGenRegisterClass::getMatchingSubClassWithSubRegs(
const CodeGenRegisterClass *B) {
// If there are multiple, identical register classes, prefer the original
// register class.
+ if (A == B)
+ return false;
if (A->getMembers().size() == B->getMembers().size())
return A == this;
return A->getMembers().size() > B->getMembers().size();
@@ -1235,8 +1237,7 @@ CodeGenSubRegIndex *CodeGenRegBank::getSubRegIdx(Record *Def) {
const CodeGenSubRegIndex *
CodeGenRegBank::findSubRegIdx(const Record* Def) const {
- auto I = Def2SubRegIdx.find(Def);
- return (I == Def2SubRegIdx.end()) ? nullptr : I->second;
+ return Def2SubRegIdx.lookup(Def);
}
CodeGenRegister *CodeGenRegBank::getReg(Record *Def) {
@@ -2008,7 +2009,7 @@ void CodeGenRegBank::computeRegUnitSets() {
if (RCRegUnits.empty())
continue;
- LLVM_DEBUG(dbgs() << "RC " << RC.getName() << " Units: \n";
+ LLVM_DEBUG(dbgs() << "RC " << RC.getName() << " Units:\n";
for (auto U
: RCRegUnits) printRegUnitName(U);
dbgs() << "\n UnitSetIDs:");
diff --git a/llvm/utils/TableGen/CodeGenRegisters.h b/llvm/utils/TableGen/CodeGenRegisters.h
index 2b200adef312..5228e6518fe5 100644
--- a/llvm/utils/TableGen/CodeGenRegisters.h
+++ b/llvm/utils/TableGen/CodeGenRegisters.h
@@ -163,7 +163,7 @@ namespace llvm {
CodeGenRegister(Record *R, unsigned Enum);
- const StringRef getName() const;
+ StringRef getName() const;
// Extract more information from TheDef. This is used to build an object
// graph after all CodeGenRegister objects have been created.
@@ -353,7 +353,7 @@ namespace llvm {
unsigned getNumValueTypes() const { return VTs.size(); }
bool hasType(const ValueTypeByHwMode &VT) const {
- return std::find(VTs.begin(), VTs.end(), VT) != VTs.end();
+ return llvm::is_contained(VTs, VT);
}
const ValueTypeByHwMode &getValueTypeNum(unsigned VTNum) const {
diff --git a/llvm/utils/TableGen/CodeGenSchedule.cpp b/llvm/utils/TableGen/CodeGenSchedule.cpp
index 67583c736cd2..b20eb6eff422 100644
--- a/llvm/utils/TableGen/CodeGenSchedule.cpp
+++ b/llvm/utils/TableGen/CodeGenSchedule.cpp
@@ -86,7 +86,7 @@ struct InstRegexOp : public SetTheory::Operator {
auto Pseudos = Instructions.slice(NumGeneric, NumPseudos);
auto NonPseudos = Instructions.slice(NumGeneric + NumPseudos);
- for (Init *Arg : make_range(Expr->arg_begin(), Expr->arg_end())) {
+ for (Init *Arg : Expr->getArgs()) {
StringInit *SI = dyn_cast<StringInit>(Arg);
if (!SI)
PrintFatalError(Loc, "instregex requires pattern string: " +
@@ -248,8 +248,7 @@ void CodeGenSchedModels::checkSTIPredicates() const {
}
PrintError(R->getLoc(), "STIPredicate " + Name + " multiply declared.");
- PrintNote(It->second->getLoc(), "Previous declaration was here.");
- PrintFatalError(R->getLoc(), "Invalid STIPredicateDecl found.");
+ PrintFatalNote(It->second->getLoc(), "Previous declaration was here.");
}
// Disallow InstructionEquivalenceClasses with an empty instruction list.
@@ -284,7 +283,7 @@ static APInt constructOperandMask(ArrayRef<int64_t> Indices) {
static void
processSTIPredicate(STIPredicateFunction &Fn,
- const DenseMap<Record *, unsigned> &ProcModelMap) {
+ const ProcModelMapTy &ProcModelMap) {
DenseMap<const Record *, unsigned> Opcode2Index;
using OpcodeMapPair = std::pair<const Record *, OpcodeInfo>;
std::vector<OpcodeMapPair> OpcodeMappings;
@@ -454,10 +453,8 @@ void CodeGenSchedModels::checkMCInstPredicates() const {
PrintError(TIIPred->getLoc(),
"TIIPredicate " + Name + " is multiply defined.");
- PrintNote(It->second->getLoc(),
- " Previous definition of " + Name + " was here.");
- PrintFatalError(TIIPred->getLoc(),
- "Found conflicting definitions of TIIPredicate.");
+ PrintFatalNote(It->second->getLoc(),
+ " Previous definition of " + Name + " was here.");
}
}
@@ -953,9 +950,9 @@ void CodeGenSchedModels::collectSchedClasses() {
}
// If ProcIndices contains zero, the class applies to all processors.
LLVM_DEBUG({
- if (!std::count(ProcIndices.begin(), ProcIndices.end(), 0)) {
+ if (!llvm::is_contained(ProcIndices, 0)) {
for (const CodeGenProcModel &PM : ProcModels) {
- if (!std::count(ProcIndices.begin(), ProcIndices.end(), PM.Index))
+ if (!llvm::is_contained(ProcIndices, PM.Index))
dbgs() << "No machine model for " << Inst->TheDef->getName()
<< " on processor " << PM.ModelName << '\n';
}
@@ -1083,13 +1080,14 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
if (RWD->getValueAsDef("SchedModel") == RWModelDef &&
RWModelDef->getValueAsBit("FullInstRWOverlapCheck")) {
assert(!InstDefs.empty()); // Checked at function start.
- PrintFatalError
- (InstRWDef->getLoc(),
- "Overlapping InstRW definition for \"" +
- InstDefs.front()->getName() +
- "\" also matches previous \"" +
- RWD->getValue("Instrs")->getValue()->getAsString() +
- "\".");
+ PrintError(
+ InstRWDef->getLoc(),
+ "Overlapping InstRW definition for \"" +
+ InstDefs.front()->getName() +
+ "\" also matches previous \"" +
+ RWD->getValue("Instrs")->getValue()->getAsString() +
+ "\".");
+ PrintFatalNote(RWD->getLoc(), "Previous match was here.");
}
}
LLVM_DEBUG(dbgs() << "InstRW: Reuse SC " << OldSCIdx << ":"
@@ -1118,13 +1116,13 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
for (Record *OldRWDef : SchedClasses[OldSCIdx].InstRWs) {
if (OldRWDef->getValueAsDef("SchedModel") == RWModelDef) {
assert(!InstDefs.empty()); // Checked at function start.
- PrintFatalError
- (InstRWDef->getLoc(),
- "Overlapping InstRW definition for \"" +
- InstDefs.front()->getName() +
- "\" also matches previous \"" +
- OldRWDef->getValue("Instrs")->getValue()->getAsString() +
- "\".");
+ PrintError(
+ InstRWDef->getLoc(),
+ "Overlapping InstRW definition for \"" +
+ InstDefs.front()->getName() + "\" also matches previous \"" +
+ OldRWDef->getValue("Instrs")->getValue()->getAsString() +
+ "\".");
+ PrintFatalNote(OldRWDef->getLoc(), "Previous match was here.");
}
assert(OldRWDef != InstRWDef &&
"SchedClass has duplicate InstRW def");
@@ -1210,11 +1208,10 @@ void CodeGenSchedModels::collectProcItinRW() {
// Gather the unsupported features for processor models.
void CodeGenSchedModels::collectProcUnsupportedFeatures() {
- for (CodeGenProcModel &ProcModel : ProcModels) {
- for (Record *Pred : ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures")) {
- ProcModel.UnsupportedFeaturesDefs.push_back(Pred);
- }
- }
+ for (CodeGenProcModel &ProcModel : ProcModels)
+ append_range(
+ ProcModel.UnsupportedFeaturesDefs,
+ ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures"));
}
/// Infer new classes from existing classes. In the process, this may create new
@@ -1250,7 +1247,7 @@ void CodeGenSchedModels::inferFromItinClass(Record *ItinClassDef,
bool HasMatch = false;
for (const Record *Rec : PM.ItinRWDefs) {
RecVec Matched = Rec->getValueAsListOfDefs("MatchedItinClasses");
- if (!std::count(Matched.begin(), Matched.end(), ItinClassDef))
+ if (!llvm::is_contained(Matched, ItinClassDef))
continue;
if (HasMatch)
PrintFatalError(Rec->getLoc(), "Duplicate itinerary class "
@@ -1283,6 +1280,7 @@ void CodeGenSchedModels::inferFromInstRWs(unsigned SCIdx) {
findRWs(Rec->getValueAsListOfDefs("OperandReadWrites"), Writes, Reads);
unsigned PIdx = getProcModel(Rec->getValueAsDef("SchedModel")).Index;
inferFromRW(Writes, Reads, SCIdx, PIdx); // May mutate SchedClasses.
+ SchedClasses[SCIdx].InstRWProcIndices.insert(PIdx);
}
}
@@ -1315,7 +1313,13 @@ struct PredTransition {
SmallVector<PredCheck, 4> PredTerm;
SmallVector<SmallVector<unsigned,4>, 16> WriteSequences;
SmallVector<SmallVector<unsigned,4>, 16> ReadSequences;
- SmallVector<unsigned, 4> ProcIndices;
+ unsigned ProcIndex = 0;
+
+ PredTransition() = default;
+ PredTransition(ArrayRef<PredCheck> PT, unsigned ProcId) {
+ PredTerm.assign(PT.begin(), PT.end());
+ ProcIndex = ProcId;
+ }
};
// Encapsulate a set of partially constructed transitions.
@@ -1328,17 +1332,18 @@ public:
PredTransitions(CodeGenSchedModels &sm): SchedModels(sm) {}
- void substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq,
+ bool substituteVariantOperand(const SmallVectorImpl<unsigned> &RWSeq,
bool IsRead, unsigned StartIdx);
- void substituteVariants(const PredTransition &Trans);
+ bool substituteVariants(const PredTransition &Trans);
#ifndef NDEBUG
void dump() const;
#endif
private:
- bool mutuallyExclusive(Record *PredDef, ArrayRef<PredCheck> Term);
+ bool mutuallyExclusive(Record *PredDef, ArrayRef<Record *> Preds,
+ ArrayRef<PredCheck> Term);
void getIntersectingVariants(
const CodeGenSchedRW &SchedRW, unsigned TransIdx,
std::vector<TransVariant> &IntersectingVariants);
@@ -1357,6 +1362,7 @@ private:
// are always checked in the order they are defined in the .td file. Later
// conditions implicitly negate any prior condition.
bool PredTransitions::mutuallyExclusive(Record *PredDef,
+ ArrayRef<Record *> Preds,
ArrayRef<PredCheck> Term) {
for (const PredCheck &PC: Term) {
if (PC.Predicate == PredDef)
@@ -1367,49 +1373,49 @@ bool PredTransitions::mutuallyExclusive(Record *PredDef,
RecVec Variants = SchedRW.TheDef->getValueAsListOfDefs("Variants");
if (any_of(Variants, [PredDef](const Record *R) {
return R->getValueAsDef("Predicate") == PredDef;
- }))
- return true;
- }
- return false;
-}
-
-static bool hasAliasedVariants(const CodeGenSchedRW &RW,
- CodeGenSchedModels &SchedModels) {
- if (RW.HasVariants)
- return true;
-
- for (Record *Alias : RW.Aliases) {
- const CodeGenSchedRW &AliasRW =
- SchedModels.getSchedRW(Alias->getValueAsDef("AliasRW"));
- if (AliasRW.HasVariants)
+ })) {
+ // To check if PredDef is mutually exclusive with PC we also need to
+ // check that PC.Predicate is exclusive with all predicates from variant
+ // we're expanding. Consider following RW sequence with two variants
+ // (1 & 2), where A, B and C are predicates from corresponding SchedVars:
+ //
+ // 1:A/B - 2:C/B
+ //
+ // Here C is not mutually exclusive with variant (1), because A doesn't
+ // exist in variant (2). This means we have possible transitions from A
+ // to C and from A to B, and fully expanded sequence would look like:
+ //
+ // if (A & C) return ...;
+ // if (A & B) return ...;
+ // if (B) return ...;
+ //
+ // Now let's consider another sequence:
+ //
+ // 1:A/B - 2:A/B
+ //
+ // Here A in variant (2) is mutually exclusive with variant (1), because
+ // A also exists in (2). This means A->B transition is impossible and
+ // expanded sequence would look like:
+ //
+ // if (A) return ...;
+ // if (B) return ...;
+ if (!count(Preds, PC.Predicate))
+ continue;
return true;
- if (AliasRW.IsSequence) {
- IdxVec ExpandedRWs;
- SchedModels.expandRWSequence(AliasRW.Index, ExpandedRWs, AliasRW.IsRead);
- for (unsigned SI : ExpandedRWs) {
- if (hasAliasedVariants(SchedModels.getSchedRW(SI, AliasRW.IsRead),
- SchedModels))
- return true;
- }
}
}
return false;
}
-static bool hasVariant(ArrayRef<PredTransition> Transitions,
- CodeGenSchedModels &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 (const SmallVectorImpl<unsigned> &RSI : PTI.ReadSequences)
- for (unsigned RI : RSI)
- if (hasAliasedVariants(SchedModels.getSchedRead(RI), SchedModels))
- return true;
+static std::vector<Record *> getAllPredicates(ArrayRef<TransVariant> Variants,
+ unsigned ProcId) {
+ std::vector<Record *> Preds;
+ for (auto &Variant : Variants) {
+ if (!Variant.VarOrSeqDef->isSubClassOf("SchedVar"))
+ continue;
+ Preds.push_back(Variant.VarOrSeqDef->getValueAsDef("Predicate"));
}
- return false;
+ return Preds;
}
// Populate IntersectingVariants with any variants or aliased sequences of the
@@ -1428,12 +1434,14 @@ void PredTransitions::getIntersectingVariants(
Record *ModelDef = SchedRW.TheDef->getValueAsDef("SchedModel");
VarProcIdx = SchedModels.getProcModel(ModelDef).Index;
}
- // Push each variant. Assign TransVecIdx later.
- const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants");
- for (Record *VarDef : VarDefs)
- Variants.emplace_back(VarDef, SchedRW.Index, VarProcIdx, 0);
- if (VarProcIdx == 0)
- GenericRW = true;
+ if (VarProcIdx == 0 || VarProcIdx == TransVec[TransIdx].ProcIndex) {
+ // Push each variant. Assign TransVecIdx later.
+ const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants");
+ for (Record *VarDef : VarDefs)
+ Variants.emplace_back(VarDef, SchedRW.Index, VarProcIdx, 0);
+ if (VarProcIdx == 0)
+ GenericRW = true;
+ }
}
for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end();
AI != AE; ++AI) {
@@ -1445,6 +1453,17 @@ void PredTransitions::getIntersectingVariants(
Record *ModelDef = (*AI)->getValueAsDef("SchedModel");
AliasProcIdx = SchedModels.getProcModel(ModelDef).Index;
}
+ if (AliasProcIdx && AliasProcIdx != TransVec[TransIdx].ProcIndex)
+ continue;
+ if (!Variants.empty()) {
+ const CodeGenProcModel &PM =
+ *(SchedModels.procModelBegin() + AliasProcIdx);
+ PrintFatalError((*AI)->getLoc(),
+ "Multiple variants defined for processor " +
+ PM.ModelName +
+ " Ensure only one SchedAlias exists per RW.");
+ }
+
const CodeGenSchedRW &AliasRW =
SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));
@@ -1458,29 +1477,17 @@ void PredTransitions::getIntersectingVariants(
if (AliasProcIdx == 0)
GenericRW = true;
}
+ std::vector<Record *> AllPreds =
+ getAllPredicates(Variants, TransVec[TransIdx].ProcIndex);
for (TransVariant &Variant : Variants) {
// Don't expand variants if the processor models don't intersect.
// A zero processor index means any processor.
- SmallVectorImpl<unsigned> &ProcIndices = TransVec[TransIdx].ProcIndices;
- if (ProcIndices[0] && Variant.ProcIdx) {
- unsigned Cnt = std::count(ProcIndices.begin(), ProcIndices.end(),
- Variant.ProcIdx);
- if (!Cnt)
- continue;
- if (Cnt > 1) {
- const CodeGenProcModel &PM =
- *(SchedModels.procModelBegin() + Variant.ProcIdx);
- PrintFatalError(Variant.VarOrSeqDef->getLoc(),
- "Multiple variants defined for processor " +
- PM.ModelName +
- " Ensure only one SchedAlias exists per RW.");
- }
- }
if (Variant.VarOrSeqDef->isSubClassOf("SchedVar")) {
Record *PredDef = Variant.VarOrSeqDef->getValueAsDef("Predicate");
- if (mutuallyExclusive(PredDef, TransVec[TransIdx].PredTerm))
+ if (mutuallyExclusive(PredDef, AllPreds, TransVec[TransIdx].PredTerm))
continue;
}
+
if (IntersectingVariants.empty()) {
// The first variant builds on the existing transition.
Variant.TransVecIdx = TransIdx;
@@ -1507,9 +1514,6 @@ pushVariant(const TransVariant &VInfo, bool IsRead) {
// If this operand transition is reached through a processor-specific alias,
// then the whole transition is specific to this processor.
- if (VInfo.ProcIdx != 0)
- Trans.ProcIndices.assign(1, VInfo.ProcIdx);
-
IdxVec SelectedRWs;
if (VInfo.VarOrSeqDef->isSubClassOf("SchedVar")) {
Record *PredDef = VInfo.VarOrSeqDef->getValueAsDef("Predicate");
@@ -1530,6 +1534,7 @@ pushVariant(const TransVariant &VInfo, bool IsRead) {
if (SchedRW.IsVariadic) {
unsigned OperIdx = RWSequences.size()-1;
// Make N-1 copies of this transition's last sequence.
+ RWSequences.reserve(RWSequences.size() + SelectedRWs.size() - 1);
RWSequences.insert(RWSequences.end(), SelectedRWs.size() - 1,
RWSequences[OperIdx]);
// Push each of the N elements of the SelectedRWs onto a copy of the last
@@ -1543,8 +1548,7 @@ pushVariant(const TransVariant &VInfo, bool IsRead) {
ExpandedRWs.push_back(*RWI);
else
SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead);
- RWSequences[OperIdx].insert(RWSequences[OperIdx].end(),
- ExpandedRWs.begin(), ExpandedRWs.end());
+ llvm::append_range(RWSequences[OperIdx], ExpandedRWs);
}
assert(OperIdx == RWSequences.size() && "missed a sequence");
}
@@ -1560,7 +1564,7 @@ pushVariant(const TransVariant &VInfo, bool IsRead) {
else
SchedModels.expandRWSequence(*RWI, ExpandedRWs, IsRead);
}
- Seq.insert(Seq.end(), ExpandedRWs.begin(), ExpandedRWs.end());
+ llvm::append_range(Seq, ExpandedRWs);
}
}
@@ -1568,9 +1572,9 @@ pushVariant(const TransVariant &VInfo, bool IsRead) {
// operand. StartIdx is an index into TransVec where partial results
// starts. RWSeq must be applied to all transitions between StartIdx and the end
// of TransVec.
-void PredTransitions::substituteVariantOperand(
- const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) {
-
+bool PredTransitions::substituteVariantOperand(
+ const SmallVectorImpl<unsigned> &RWSeq, bool IsRead, unsigned StartIdx) {
+ bool Subst = false;
// Visit each original RW within the current sequence.
for (SmallVectorImpl<unsigned>::const_iterator
RWI = RWSeq.begin(), RWE = RWSeq.end(); RWI != RWE; ++RWI) {
@@ -1580,27 +1584,25 @@ void PredTransitions::substituteVariantOperand(
// revisited (TransEnd must be loop invariant).
for (unsigned TransIdx = StartIdx, TransEnd = TransVec.size();
TransIdx != TransEnd; ++TransIdx) {
- // In the common case, push RW onto the current operand's sequence.
- if (!hasAliasedVariants(SchedRW, SchedModels)) {
- if (IsRead)
- TransVec[TransIdx].ReadSequences.back().push_back(*RWI);
- else
- TransVec[TransIdx].WriteSequences.back().push_back(*RWI);
- continue;
- }
// Distribute this partial PredTransition across intersecting variants.
// This will push a copies of TransVec[TransIdx] on the back of TransVec.
std::vector<TransVariant> IntersectingVariants;
getIntersectingVariants(SchedRW, TransIdx, IntersectingVariants);
// Now expand each variant on top of its copy of the transition.
- for (std::vector<TransVariant>::const_iterator
- IVI = IntersectingVariants.begin(),
- IVE = IntersectingVariants.end();
- IVI != IVE; ++IVI) {
- pushVariant(*IVI, IsRead);
+ for (const TransVariant &IV : IntersectingVariants)
+ pushVariant(IV, IsRead);
+ if (IntersectingVariants.empty()) {
+ if (IsRead)
+ TransVec[TransIdx].ReadSequences.back().push_back(*RWI);
+ else
+ TransVec[TransIdx].WriteSequences.back().push_back(*RWI);
+ continue;
+ } else {
+ Subst = true;
}
}
}
+ return Subst;
}
// For each variant of a Read/Write in Trans, substitute the sequence of
@@ -1609,13 +1611,13 @@ void PredTransitions::substituteVariantOperand(
// predicates should result in linear growth in the total number variants.
//
// This is one step in a breadth-first search of nested variants.
-void PredTransitions::substituteVariants(const PredTransition &Trans) {
+bool 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.emplace_back();
- TransVec.back().PredTerm = Trans.PredTerm;
- TransVec.back().ProcIndices = Trans.ProcIndices;
+ bool Subst = false;
+ assert(Trans.ProcIndex != 0);
+ TransVec.emplace_back(Trans.PredTerm, Trans.ProcIndex);
// Visit each original write sequence.
for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator
@@ -1626,7 +1628,7 @@ void PredTransitions::substituteVariants(const PredTransition &Trans) {
TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {
I->WriteSequences.emplace_back();
}
- substituteVariantOperand(*WSI, /*IsRead=*/false, StartIdx);
+ Subst |= substituteVariantOperand(*WSI, /*IsRead=*/false, StartIdx);
}
// Visit each original read sequence.
for (SmallVectorImpl<SmallVector<unsigned,4>>::const_iterator
@@ -1637,10 +1639,37 @@ void PredTransitions::substituteVariants(const PredTransition &Trans) {
TransVec.begin() + StartIdx, E = TransVec.end(); I != E; ++I) {
I->ReadSequences.emplace_back();
}
- substituteVariantOperand(*RSI, /*IsRead=*/true, StartIdx);
+ Subst |= substituteVariantOperand(*RSI, /*IsRead=*/true, StartIdx);
}
+ return Subst;
+}
+
+static void addSequences(CodeGenSchedModels &SchedModels,
+ const SmallVectorImpl<SmallVector<unsigned, 4>> &Seqs,
+ IdxVec &Result, bool IsRead) {
+ for (const auto &S : Seqs)
+ if (!S.empty())
+ Result.push_back(SchedModels.findOrInsertRW(S, IsRead));
}
+#ifndef NDEBUG
+static void dumpRecVec(const RecVec &RV) {
+ for (const Record *R : RV)
+ dbgs() << R->getName() << ", ";
+}
+#endif
+
+static void dumpTransition(const CodeGenSchedModels &SchedModels,
+ const CodeGenSchedClass &FromSC,
+ const CodeGenSchedTransition &SCTrans,
+ const RecVec &Preds) {
+ LLVM_DEBUG(dbgs() << "Adding transition from " << FromSC.Name << "("
+ << FromSC.Index << ") to "
+ << SchedModels.getSchedClass(SCTrans.ToClassIdx).Name << "("
+ << SCTrans.ToClassIdx << ") on pred term: (";
+ dumpRecVec(Preds);
+ dbgs() << ") on processor (" << SCTrans.ProcIndex << ")\n");
+}
// Create a new SchedClass for each variant found by inferFromRW. Pass
static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions,
unsigned FromClassIdx,
@@ -1649,21 +1678,25 @@ static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions,
// requires creating a new SchedClass.
for (ArrayRef<PredTransition>::iterator
I = LastTransitions.begin(), E = LastTransitions.end(); I != E; ++I) {
- IdxVec OperWritesVariant;
- transform(I->WriteSequences, std::back_inserter(OperWritesVariant),
- [&SchedModels](ArrayRef<unsigned> WS) {
- return SchedModels.findOrInsertRW(WS, /*IsRead=*/false);
- });
- IdxVec OperReadsVariant;
- transform(I->ReadSequences, std::back_inserter(OperReadsVariant),
- [&SchedModels](ArrayRef<unsigned> RS) {
- return SchedModels.findOrInsertRW(RS, /*IsRead=*/true);
- });
+ // Variant expansion (substituteVariants) may create unconditional
+ // transitions. We don't need to build sched classes for them.
+ if (I->PredTerm.empty())
+ continue;
+ IdxVec OperWritesVariant, OperReadsVariant;
+ addSequences(SchedModels, I->WriteSequences, OperWritesVariant, false);
+ addSequences(SchedModels, I->ReadSequences, OperReadsVariant, true);
CodeGenSchedTransition SCTrans;
+
+ // Transition should not contain processor indices already assigned to
+ // InstRWs in this scheduling class.
+ const CodeGenSchedClass &FromSC = SchedModels.getSchedClass(FromClassIdx);
+ if (FromSC.InstRWProcIndices.count(I->ProcIndex))
+ continue;
+ SCTrans.ProcIndex = I->ProcIndex;
SCTrans.ToClassIdx =
- SchedModels.addSchedClass(/*ItinClassDef=*/nullptr, OperWritesVariant,
- OperReadsVariant, I->ProcIndices);
- SCTrans.ProcIndices.assign(I->ProcIndices.begin(), I->ProcIndices.end());
+ SchedModels.addSchedClass(/*ItinClassDef=*/nullptr, OperWritesVariant,
+ OperReadsVariant, I->ProcIndex);
+
// The final PredTerm is unique set of predicates guarding the transition.
RecVec Preds;
transform(I->PredTerm, std::back_inserter(Preds),
@@ -1671,12 +1704,36 @@ static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions,
return P.Predicate;
});
Preds.erase(std::unique(Preds.begin(), Preds.end()), Preds.end());
+ dumpTransition(SchedModels, FromSC, SCTrans, Preds);
SCTrans.PredTerm = std::move(Preds);
SchedModels.getSchedClass(FromClassIdx)
.Transitions.push_back(std::move(SCTrans));
}
}
+std::vector<unsigned> CodeGenSchedModels::getAllProcIndices() const {
+ std::vector<unsigned> ProcIdVec;
+ for (const auto &PM : ProcModelMap)
+ if (PM.second != 0)
+ ProcIdVec.push_back(PM.second);
+ // The order of the keys (Record pointers) of ProcModelMap are not stable.
+ // Sort to stabalize the values.
+ llvm::sort(ProcIdVec);
+ return ProcIdVec;
+}
+
+static std::vector<PredTransition>
+makePerProcessorTransitions(const PredTransition &Trans,
+ ArrayRef<unsigned> ProcIndices) {
+ std::vector<PredTransition> PerCpuTransVec;
+ for (unsigned ProcId : ProcIndices) {
+ assert(ProcId != 0);
+ PerCpuTransVec.push_back(Trans);
+ PerCpuTransVec.back().ProcIndex = ProcId;
+ }
+ return PerCpuTransVec;
+}
+
// Create new SchedClasses for the given ReadWrite list. If any of the
// ReadWrites refers to a SchedVariant, create a new SchedClass for each variant
// of the ReadWrite list, following Aliases if necessary.
@@ -1686,13 +1743,10 @@ void CodeGenSchedModels::inferFromRW(ArrayRef<unsigned> OperWrites,
ArrayRef<unsigned> ProcIndices) {
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.emplace_back();
- LastTransitions.back().ProcIndices.append(ProcIndices.begin(),
- ProcIndices.end());
for (unsigned WriteIdx : OperWrites) {
IdxVec WriteSeq;
@@ -1713,18 +1767,21 @@ void CodeGenSchedModels::inferFromRW(ArrayRef<unsigned> OperWrites,
}
LLVM_DEBUG(dbgs() << '\n');
+ LastTransitions = makePerProcessorTransitions(
+ LastTransitions[0], llvm::is_contained(ProcIndices, 0)
+ ? ArrayRef<unsigned>(getAllProcIndices())
+ : ProcIndices);
// Collect all PredTransitions for individual operands.
// Iterate until no variant writes remain.
- while (hasVariant(LastTransitions, *this)) {
+ bool SubstitutedAny;
+ do {
+ SubstitutedAny = false;
PredTransitions Transitions(*this);
for (const PredTransition &Trans : LastTransitions)
- Transitions.substituteVariants(Trans);
+ SubstitutedAny |= Transitions.substituteVariants(Trans);
LLVM_DEBUG(Transitions.dump());
LastTransitions.swap(Transitions.TransVec);
- }
- // If the first transition has no variants, nothing to do.
- if (LastTransitions[0].PredTerm.empty())
- return;
+ } while (SubstitutedAny);
// WARNING: We are about to mutate the SchedClasses vector. Do not refer to
// OperWrites, OperReads, or ProcIndices after calling inferFromTransitions.
@@ -1767,8 +1824,7 @@ void CodeGenSchedModels::verifyProcResourceGroups(CodeGenProcModel &PM) {
OtherUnits.begin(), OtherUnits.end())
!= CheckUnits.end()) {
// CheckUnits and OtherUnits overlap
- OtherUnits.insert(OtherUnits.end(), CheckUnits.begin(),
- CheckUnits.end());
+ llvm::append_range(OtherUnits, CheckUnits);
if (!hasSuperGroup(OtherUnits, PM)) {
PrintFatalError((PM.ProcResourceDefs[i])->getLoc(),
"proc resource group overlaps with "
@@ -1990,7 +2046,7 @@ void CodeGenSchedModels::collectItinProcResources(Record *ItinClassDef) {
for (RecIter II = PM.ItinRWDefs.begin(), IE = PM.ItinRWDefs.end();
II != IE; ++II) {
RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");
- if (!std::count(Matched.begin(), Matched.end(), ItinClassDef))
+ if (!llvm::is_contained(Matched, ItinClassDef))
continue;
if (HasMatch)
PrintFatalError((*II)->getLoc(), "Duplicate itinerary class "
@@ -2191,13 +2247,14 @@ void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const {
dbgs().indent(10);
}
}
- dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices); dbgs() << '\n';
+ dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices);
if (!Transitions.empty()) {
dbgs() << "\n Transitions for Proc ";
for (const CodeGenSchedTransition &Transition : Transitions) {
- dumpIdxVec(Transition.ProcIndices);
+ dbgs() << Transition.ProcIndex << ", ";
}
}
+ dbgs() << '\n';
}
void PredTransitions::dump() const {
diff --git a/llvm/utils/TableGen/CodeGenSchedule.h b/llvm/utils/TableGen/CodeGenSchedule.h
index c487d142d46c..9020447c940b 100644
--- a/llvm/utils/TableGen/CodeGenSchedule.h
+++ b/llvm/utils/TableGen/CodeGenSchedule.h
@@ -16,10 +16,12 @@
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/SetTheory.h"
+#include <map>
namespace llvm {
@@ -94,7 +96,7 @@ struct CodeGenSchedRW {
/// Represent a transition between SchedClasses induced by SchedVariant.
struct CodeGenSchedTransition {
unsigned ToClassIdx;
- IdxVec ProcIndices;
+ unsigned ProcIndex;
RecVec PredTerm;
};
@@ -139,6 +141,8 @@ struct CodeGenSchedClass {
// Instructions should be ignored by this class because they have been split
// off to join another inferred class.
RecVec InstRWs;
+ // InstRWs processor indices. Filled in inferFromInstRWs
+ DenseSet<unsigned> InstRWProcIndices;
CodeGenSchedClass(unsigned Index, std::string Name, Record *ItinClassDef)
: Index(Index), Name(std::move(Name)), ItinClassDef(ItinClassDef) {}
@@ -358,8 +362,7 @@ public:
OpcodeGroup(OpcodeGroup &&Other) = default;
void addOpcode(const Record *Opcode) {
- assert(std::find(Opcodes.begin(), Opcodes.end(), Opcode) == Opcodes.end() &&
- "Opcode already in set!");
+ assert(!llvm::is_contained(Opcodes, Opcode) && "Opcode already in set!");
Opcodes.push_back(Opcode);
}
@@ -407,6 +410,8 @@ public:
ArrayRef<OpcodeGroup> getGroups() const { return Groups; }
};
+using ProcModelMapTy = DenseMap<const Record *, unsigned>;
+
/// Top level container for machine model data.
class CodeGenSchedModels {
RecordKeeper &Records;
@@ -419,7 +424,6 @@ class CodeGenSchedModels {
std::vector<CodeGenProcModel> ProcModels;
// Map Processor's MachineModel or ProcItin to a CodeGenProcModel index.
- using ProcModelMapTy = DenseMap<Record*, unsigned>;
ProcModelMapTy ProcModelMap;
// Per-operand SchedReadWrite types.
@@ -441,6 +445,7 @@ class CodeGenSchedModels {
InstClassMapTy InstrClassMap;
std::vector<STIPredicateFunction> STIPredicates;
+ std::vector<unsigned> getAllProcIndices() const;
public:
CodeGenSchedModels(RecordKeeper& RK, const CodeGenTarget &TGT);
diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp
index 891a08ea590e..8f6d212df5ec 100644
--- a/llvm/utils/TableGen/CodeGenTarget.cpp
+++ b/llvm/utils/TableGen/CodeGenTarget.cpp
@@ -76,6 +76,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::f128: return "MVT::f128";
case MVT::ppcf128: return "MVT::ppcf128";
case MVT::x86mmx: return "MVT::x86mmx";
+ case MVT::x86amx: return "MVT::x86amx";
case MVT::Glue: return "MVT::Glue";
case MVT::isVoid: return "MVT::isVoid";
case MVT::v1i1: return "MVT::v1i1";
@@ -86,6 +87,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v32i1: return "MVT::v32i1";
case MVT::v64i1: return "MVT::v64i1";
case MVT::v128i1: return "MVT::v128i1";
+ case MVT::v256i1: return "MVT::v256i1";
case MVT::v512i1: return "MVT::v512i1";
case MVT::v1024i1: return "MVT::v1024i1";
case MVT::v1i8: return "MVT::v1i8";
@@ -126,6 +128,9 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v8i64: return "MVT::v8i64";
case MVT::v16i64: return "MVT::v16i64";
case MVT::v32i64: return "MVT::v32i64";
+ case MVT::v64i64: return "MVT::v64i64";
+ case MVT::v128i64: return "MVT::v128i64";
+ case MVT::v256i64: return "MVT::v256i64";
case MVT::v1i128: return "MVT::v1i128";
case MVT::v2f16: return "MVT::v2f16";
case MVT::v3f16: return "MVT::v3f16";
@@ -163,6 +168,9 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v8f64: return "MVT::v8f64";
case MVT::v16f64: return "MVT::v16f64";
case MVT::v32f64: return "MVT::v32f64";
+ case MVT::v64f64: return "MVT::v64f64";
+ case MVT::v128f64: return "MVT::v128f64";
+ case MVT::v256f64: return "MVT::v256f64";
case MVT::nxv1i1: return "MVT::nxv1i1";
case MVT::nxv2i1: return "MVT::nxv2i1";
case MVT::nxv4i1: return "MVT::nxv4i1";
@@ -204,21 +212,22 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::nxv2bf16: return "MVT::nxv2bf16";
case MVT::nxv4bf16: return "MVT::nxv4bf16";
case MVT::nxv8bf16: return "MVT::nxv8bf16";
- case MVT::nxv1f32: return "MVT::nxv1f32";
- case MVT::nxv2f32: return "MVT::nxv2f32";
- case MVT::nxv4f32: return "MVT::nxv4f32";
- case MVT::nxv8f32: return "MVT::nxv8f32";
- case MVT::nxv16f32: return "MVT::nxv16f32";
- case MVT::nxv1f64: return "MVT::nxv1f64";
- case MVT::nxv2f64: return "MVT::nxv2f64";
- case MVT::nxv4f64: return "MVT::nxv4f64";
- case MVT::nxv8f64: return "MVT::nxv8f64";
- case MVT::token: return "MVT::token";
- case MVT::Metadata: return "MVT::Metadata";
- case MVT::iPTR: return "MVT::iPTR";
- case MVT::iPTRAny: return "MVT::iPTRAny";
- case MVT::Untyped: return "MVT::Untyped";
- case MVT::exnref: return "MVT::exnref";
+ case MVT::nxv1f32: return "MVT::nxv1f32";
+ case MVT::nxv2f32: return "MVT::nxv2f32";
+ case MVT::nxv4f32: return "MVT::nxv4f32";
+ case MVT::nxv8f32: return "MVT::nxv8f32";
+ case MVT::nxv16f32: return "MVT::nxv16f32";
+ case MVT::nxv1f64: return "MVT::nxv1f64";
+ case MVT::nxv2f64: return "MVT::nxv2f64";
+ case MVT::nxv4f64: return "MVT::nxv4f64";
+ case MVT::nxv8f64: return "MVT::nxv8f64";
+ case MVT::token: return "MVT::token";
+ case MVT::Metadata: return "MVT::Metadata";
+ case MVT::iPTR: return "MVT::iPTR";
+ case MVT::iPTRAny: return "MVT::iPTRAny";
+ case MVT::Untyped: return "MVT::Untyped";
+ case MVT::funcref: return "MVT::funcref";
+ case MVT::externref: return "MVT::externref";
default: llvm_unreachable("ILLEGAL VALUE TYPE!");
}
}
@@ -251,19 +260,27 @@ CodeGenTarget::CodeGenTarget(RecordKeeper &records)
CodeGenTarget::~CodeGenTarget() {
}
-const StringRef CodeGenTarget::getName() const {
- return TargetRec->getName();
-}
+StringRef CodeGenTarget::getName() const { return TargetRec->getName(); }
+/// getInstNamespace - Find and return the target machine's instruction
+/// namespace. The namespace is cached because it is requested multiple times.
StringRef CodeGenTarget::getInstNamespace() const {
- for (const CodeGenInstruction *Inst : getInstructionsByEnumValue()) {
- // Make sure not to pick up "TargetOpcode" by accidentally getting
- // the namespace off the PHI instruction or something.
- if (Inst->Namespace != "TargetOpcode")
- return Inst->Namespace;
+ if (InstNamespace.empty()) {
+ for (const CodeGenInstruction *Inst : getInstructionsByEnumValue()) {
+ // We are not interested in the "TargetOpcode" namespace.
+ if (Inst->Namespace != "TargetOpcode") {
+ InstNamespace = Inst->Namespace;
+ break;
+ }
+ }
}
- return "";
+ return InstNamespace;
+}
+
+StringRef CodeGenTarget::getRegNamespace() const {
+ auto &RegClasses = RegBank->getRegClasses();
+ return RegClasses.size() > 0 ? RegClasses.front().Namespace : "";
}
Record *CodeGenTarget::getInstructionSet() const {
@@ -324,7 +341,8 @@ CodeGenRegBank &CodeGenTarget::getRegBank() const {
Optional<CodeGenRegisterClass *>
CodeGenTarget::getSuperRegForSubReg(const ValueTypeByHwMode &ValueTy,
CodeGenRegBank &RegBank,
- const CodeGenSubRegIndex *SubIdx) const {
+ const CodeGenSubRegIndex *SubIdx,
+ bool MustBeAllocatable) const {
std::vector<CodeGenRegisterClass *> Candidates;
auto &RegClasses = RegBank.getRegClasses();
@@ -337,10 +355,11 @@ CodeGenTarget::getSuperRegForSubReg(const ValueTypeByHwMode &ValueTy,
continue;
// We have a class. Check if it supports this value type.
- if (llvm::none_of(SubClassWithSubReg->VTs,
- [&ValueTy](const ValueTypeByHwMode &ClassVT) {
- return ClassVT == ValueTy;
- }))
+ if (!llvm::is_contained(SubClassWithSubReg->VTs, ValueTy))
+ continue;
+
+ // If necessary, check that it is allocatable.
+ if (MustBeAllocatable && !SubClassWithSubReg->Allocatable)
continue;
// We have a register class which supports both the value type and
@@ -376,11 +395,7 @@ void CodeGenTarget::ReadRegAltNameIndices() const {
/// getRegisterByName - If there is a register with the specific AsmName,
/// return it.
const CodeGenRegister *CodeGenTarget::getRegisterByName(StringRef Name) const {
- const StringMap<CodeGenRegister*> &Regs = getRegBank().getRegistersByName();
- StringMap<CodeGenRegister*>::const_iterator I = Regs.find(Name);
- if (I == Regs.end())
- return nullptr;
- return I->second;
+ return getRegBank().getRegistersByName().lookup(Name);
}
std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R)
@@ -390,7 +405,7 @@ std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R)
for (const auto &RC : getRegBank().getRegClasses()) {
if (RC.contains(Reg)) {
ArrayRef<ValueTypeByHwMode> InVTs = RC.getValueTypes();
- Result.insert(Result.end(), InVTs.begin(), InVTs.end());
+ llvm::append_range(Result, InVTs);
}
}
@@ -403,7 +418,7 @@ std::vector<ValueTypeByHwMode> CodeGenTarget::getRegisterVTs(Record *R)
void CodeGenTarget::ReadLegalValueTypes() const {
for (const auto &RC : getRegBank().getRegClasses())
- LegalValueTypes.insert(LegalValueTypes.end(), RC.VTs.begin(), RC.VTs.end());
+ llvm::append_range(LegalValueTypes, RC.VTs);
// Remove duplicates.
llvm::sort(LegalValueTypes);
@@ -419,8 +434,6 @@ CodeGenSchedModels &CodeGenTarget::getSchedModels() const {
}
void CodeGenTarget::ReadInstructions() const {
- NamedRegionTimer T("Read Instructions", "Time spent reading instructions",
- "CodeGenTarget", "CodeGenTarget", TimeRegions);
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
if (Insts.size() <= 2)
PrintFatalError("No 'Instruction' subclasses defined!");
@@ -599,12 +612,19 @@ ComplexPattern::ComplexPattern(Record *R) {
//===----------------------------------------------------------------------===//
CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) {
- std::vector<Record*> Defs = RC.getAllDerivedDefinitions("Intrinsic");
+ std::vector<Record *> IntrProperties =
+ RC.getAllDerivedDefinitions("IntrinsicProperty");
+ std::vector<Record *> DefaultProperties;
+ for (Record *Rec : IntrProperties)
+ if (Rec->getValueAsBit("IsDefault"))
+ DefaultProperties.push_back(Rec);
+
+ std::vector<Record *> Defs = RC.getAllDerivedDefinitions("Intrinsic");
Intrinsics.reserve(Defs.size());
for (unsigned I = 0, e = Defs.size(); I != e; ++I)
- Intrinsics.push_back(CodeGenIntrinsic(Defs[I]));
+ Intrinsics.push_back(CodeGenIntrinsic(Defs[I], DefaultProperties));
llvm::sort(Intrinsics,
[](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) {
@@ -620,7 +640,8 @@ CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) {
Targets.back().Count = Intrinsics.size() - Targets.back().Offset;
}
-CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
+CodeGenIntrinsic::CodeGenIntrinsic(Record *R,
+ std::vector<Record *> DefaultProperties) {
TheDef = R;
std::string DefName = std::string(R->getName());
ArrayRef<SMLoc> DefLoc = R->getLoc();
@@ -773,70 +794,12 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
assert(Property->isSubClassOf("IntrinsicProperty") &&
"Expected a property!");
- if (Property->getName() == "IntrNoMem")
- ModRef = NoMem;
- else if (Property->getName() == "IntrReadMem")
- ModRef = ModRefBehavior(ModRef & ~MR_Mod);
- else if (Property->getName() == "IntrWriteMem")
- ModRef = ModRefBehavior(ModRef & ~MR_Ref);
- else if (Property->getName() == "IntrArgMemOnly")
- ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_ArgMem);
- else if (Property->getName() == "IntrInaccessibleMemOnly")
- ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_InaccessibleMem);
- else if (Property->getName() == "IntrInaccessibleMemOrArgMemOnly")
- ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_ArgMem |
- MR_InaccessibleMem);
- else if (Property->getName() == "Commutative")
- isCommutative = true;
- else if (Property->getName() == "Throws")
- canThrow = true;
- else if (Property->getName() == "IntrNoDuplicate")
- isNoDuplicate = true;
- else if (Property->getName() == "IntrConvergent")
- isConvergent = true;
- else if (Property->getName() == "IntrNoReturn")
- isNoReturn = true;
- else if (Property->getName() == "IntrNoSync")
- isNoSync = true;
- else if (Property->getName() == "IntrNoFree")
- isNoFree = true;
- else if (Property->getName() == "IntrWillReturn")
- isWillReturn = true;
- else if (Property->getName() == "IntrCold")
- isCold = true;
- else if (Property->getName() == "IntrSpeculatable")
- isSpeculatable = true;
- else if (Property->getName() == "IntrHasSideEffects")
- hasSideEffects = true;
- else if (Property->isSubClassOf("NoCapture")) {
- unsigned ArgNo = Property->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, NoCapture, 0);
- } else if (Property->isSubClassOf("NoAlias")) {
- unsigned ArgNo = Property->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, NoAlias, 0);
- } else if (Property->isSubClassOf("Returned")) {
- unsigned ArgNo = Property->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, Returned, 0);
- } else if (Property->isSubClassOf("ReadOnly")) {
- unsigned ArgNo = Property->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, ReadOnly, 0);
- } else if (Property->isSubClassOf("WriteOnly")) {
- unsigned ArgNo = Property->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, WriteOnly, 0);
- } else if (Property->isSubClassOf("ReadNone")) {
- unsigned ArgNo = Property->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, ReadNone, 0);
- } else if (Property->isSubClassOf("ImmArg")) {
- unsigned ArgNo = Property->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, ImmArg, 0);
- } else if (Property->isSubClassOf("Align")) {
- unsigned ArgNo = Property->getValueAsInt("ArgNo");
- uint64_t Align = Property->getValueAsInt("Align");
- ArgumentAttributes.emplace_back(ArgNo, Alignment, Align);
- } else
- llvm_unreachable("Unknown property!");
+ setProperty(Property);
}
+ // Set default properties to true.
+ setDefaultProperties(R, DefaultProperties);
+
// Also record the SDPatternOperator Properties.
Properties = parseSDPatternOperatorProperties(R);
@@ -844,6 +807,92 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
llvm::sort(ArgumentAttributes);
}
+void CodeGenIntrinsic::setDefaultProperties(
+ Record *R, std::vector<Record *> DefaultProperties) {
+ // opt-out of using default attributes.
+ if (R->getValueAsBit("DisableDefaultAttributes"))
+ return;
+
+ for (Record *Rec : DefaultProperties)
+ setProperty(Rec);
+}
+
+void CodeGenIntrinsic::setProperty(Record *R) {
+ if (R->getName() == "IntrNoMem")
+ ModRef = NoMem;
+ else if (R->getName() == "IntrReadMem") {
+ if (!(ModRef & MR_Ref))
+ PrintFatalError(TheDef->getLoc(),
+ Twine("IntrReadMem cannot be used after IntrNoMem or "
+ "IntrWriteMem. Default is ReadWrite"));
+ ModRef = ModRefBehavior(ModRef & ~MR_Mod);
+ } else if (R->getName() == "IntrWriteMem") {
+ if (!(ModRef & MR_Mod))
+ PrintFatalError(TheDef->getLoc(),
+ Twine("IntrWriteMem cannot be used after IntrNoMem or "
+ "IntrReadMem. Default is ReadWrite"));
+ ModRef = ModRefBehavior(ModRef & ~MR_Ref);
+ } else if (R->getName() == "IntrArgMemOnly")
+ ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_ArgMem);
+ else if (R->getName() == "IntrInaccessibleMemOnly")
+ ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_InaccessibleMem);
+ else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly")
+ ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_ArgMem |
+ MR_InaccessibleMem);
+ else if (R->getName() == "Commutative")
+ isCommutative = true;
+ else if (R->getName() == "Throws")
+ canThrow = true;
+ else if (R->getName() == "IntrNoDuplicate")
+ isNoDuplicate = true;
+ else if (R->getName() == "IntrConvergent")
+ isConvergent = true;
+ else if (R->getName() == "IntrNoReturn")
+ isNoReturn = true;
+ else if (R->getName() == "IntrNoSync")
+ isNoSync = true;
+ else if (R->getName() == "IntrNoFree")
+ isNoFree = true;
+ else if (R->getName() == "IntrWillReturn")
+ isWillReturn = !isNoReturn;
+ else if (R->getName() == "IntrCold")
+ isCold = true;
+ else if (R->getName() == "IntrSpeculatable")
+ isSpeculatable = true;
+ else if (R->getName() == "IntrHasSideEffects")
+ hasSideEffects = true;
+ else if (R->isSubClassOf("NoCapture")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ ArgumentAttributes.emplace_back(ArgNo, NoCapture, 0);
+ } else if (R->isSubClassOf("NoAlias")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ ArgumentAttributes.emplace_back(ArgNo, NoAlias, 0);
+ } else if (R->isSubClassOf("NoUndef")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ ArgumentAttributes.emplace_back(ArgNo, NoUndef, 0);
+ } else if (R->isSubClassOf("Returned")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ ArgumentAttributes.emplace_back(ArgNo, Returned, 0);
+ } else if (R->isSubClassOf("ReadOnly")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ ArgumentAttributes.emplace_back(ArgNo, ReadOnly, 0);
+ } else if (R->isSubClassOf("WriteOnly")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ ArgumentAttributes.emplace_back(ArgNo, WriteOnly, 0);
+ } else if (R->isSubClassOf("ReadNone")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ ArgumentAttributes.emplace_back(ArgNo, ReadNone, 0);
+ } else if (R->isSubClassOf("ImmArg")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ ArgumentAttributes.emplace_back(ArgNo, ImmArg, 0);
+ } else if (R->isSubClassOf("Align")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ uint64_t Align = R->getValueAsInt("Align");
+ ArgumentAttributes.emplace_back(ArgNo, Alignment, Align);
+ } else
+ llvm_unreachable("Unknown property!");
+}
+
bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const {
if (ParamIdx >= IS.ParamVTs.size())
return false;
diff --git a/llvm/utils/TableGen/CodeGenTarget.h b/llvm/utils/TableGen/CodeGenTarget.h
index 6c89f34c50ec..9de9b512f74f 100644
--- a/llvm/utils/TableGen/CodeGenTarget.h
+++ b/llvm/utils/TableGen/CodeGenTarget.h
@@ -60,6 +60,7 @@ class CodeGenTarget {
mutable std::unique_ptr<CodeGenSchedModels> SchedModels;
+ mutable StringRef InstNamespace;
mutable std::vector<const CodeGenInstruction*> InstrsByEnum;
mutable unsigned NumPseudoInstructions = 0;
public:
@@ -67,12 +68,15 @@ public:
~CodeGenTarget();
Record *getTargetRecord() const { return TargetRec; }
- const StringRef getName() const;
+ StringRef getName() const;
/// getInstNamespace - Return the target-specific instruction namespace.
///
StringRef getInstNamespace() const;
+ /// getRegNamespace - Return the target-specific register namespace.
+ StringRef getRegNamespace() const;
+
/// getInstructionSet - Return the InstructionSet object.
///
Record *getInstructionSet() const;
@@ -107,7 +111,8 @@ public:
/// covers \p SubIdx if it exists.
Optional<CodeGenRegisterClass *>
getSuperRegForSubReg(const ValueTypeByHwMode &Ty, CodeGenRegBank &RegBank,
- const CodeGenSubRegIndex *SubIdx) const;
+ const CodeGenSubRegIndex *SubIdx,
+ bool MustBeAllocatable = false) const;
/// getRegisterByName - If there is a register with the specific AsmName,
/// return it.
diff --git a/llvm/utils/TableGen/DAGISelEmitter.cpp b/llvm/utils/TableGen/DAGISelEmitter.cpp
index d8e78ce55c7b..32ed0bf98743 100644
--- a/llvm/utils/TableGen/DAGISelEmitter.cpp
+++ b/llvm/utils/TableGen/DAGISelEmitter.cpp
@@ -23,9 +23,10 @@ namespace {
/// DAGISelEmitter - The top-level class which coordinates construction
/// and emission of the instruction selector.
class DAGISelEmitter {
+ RecordKeeper &Records; // Just so we can get at the timing functions.
CodeGenDAGPatterns CGP;
public:
- explicit DAGISelEmitter(RecordKeeper &R) : CGP(R) {}
+ explicit DAGISelEmitter(RecordKeeper &R) : Records(R), CGP(R) {}
void run(raw_ostream &OS);
};
} // End anonymous namespace
@@ -150,6 +151,7 @@ void DAGISelEmitter::run(raw_ostream &OS) {
});
// Add all the patterns to a temporary list so we can sort them.
+ Records.startTimer("Sort patterns");
std::vector<const PatternToMatch*> Patterns;
for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), E = CGP.ptm_end();
I != E; ++I)
@@ -157,11 +159,10 @@ 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::stable_sort(Patterns.begin(), Patterns.end(),
- PatternSortingPredicate(CGP));
-
+ llvm::stable_sort(Patterns, PatternSortingPredicate(CGP));
// Convert each variant of each pattern into a Matcher.
+ Records.startTimer("Convert to matchers");
std::vector<Matcher*> PatternMatchers;
for (unsigned i = 0, e = Patterns.size(); i != e; ++i) {
for (unsigned Variant = 0; ; ++Variant) {
@@ -175,14 +176,19 @@ void DAGISelEmitter::run(raw_ostream &OS) {
std::unique_ptr<Matcher> TheMatcher =
std::make_unique<ScopeMatcher>(PatternMatchers);
+ Records.startTimer("Optimize matchers");
OptimizeMatcher(TheMatcher, CGP);
+
//Matcher->dump();
+
+ Records.startTimer("Emit matcher table");
EmitMatcherTable(TheMatcher.get(), CGP, OS);
}
namespace llvm {
void EmitDAGISel(RecordKeeper &RK, raw_ostream &OS) {
+ RK.startTimer("Parse patterns");
DAGISelEmitter(RK).run(OS);
}
diff --git a/llvm/utils/TableGen/DAGISelMatcher.h b/llvm/utils/TableGen/DAGISelMatcher.h
index 223513fc8d38..ff9a0cb335d1 100644
--- a/llvm/utils/TableGen/DAGISelMatcher.h
+++ b/llvm/utils/TableGen/DAGISelMatcher.h
@@ -31,7 +31,7 @@ Matcher *ConvertPatternToMatcher(const PatternToMatch &Pattern,unsigned Variant,
const CodeGenDAGPatterns &CGP);
void OptimizeMatcher(std::unique_ptr<Matcher> &Matcher,
const CodeGenDAGPatterns &CGP);
-void EmitMatcherTable(const Matcher *Matcher, const CodeGenDAGPatterns &CGP,
+void EmitMatcherTable(Matcher *Matcher, const CodeGenDAGPatterns &CGP,
raw_ostream &OS);
@@ -41,6 +41,7 @@ class Matcher {
// The next matcher node that is executed after this one. Null if this is the
// last stage of a match.
std::unique_ptr<Matcher> Next;
+ size_t Size; // Size in bytes of matcher and all its children (if any).
virtual void anchor();
public:
enum KindTy {
@@ -85,7 +86,10 @@ public:
EmitNode, // Create a DAG node
EmitNodeXForm, // Run a SDNodeXForm
CompleteMatch, // Finish a match and update the results.
- MorphNodeTo // Build a node, finish a match and update results.
+ MorphNodeTo, // Build a node, finish a match and update results.
+
+ // Highest enum value; watch out when adding more.
+ HighestKind = MorphNodeTo
};
const KindTy Kind;
@@ -94,6 +98,8 @@ protected:
public:
virtual ~Matcher() {}
+ unsigned getSize() const { return Size; }
+ void setSize(unsigned sz) { Size = sz; }
KindTy getKind() const { return Kind; }
Matcher *getNext() { return Next.get(); }
@@ -700,7 +706,7 @@ public:
const ComplexPattern &getPattern() const { return Pattern; }
unsigned getMatchNumber() const { return MatchNumber; }
- const std::string getName() const { return Name; }
+ std::string getName() const { return Name; }
unsigned getFirstResult() const { return FirstResult; }
static bool classof(const Matcher *N) {
@@ -757,8 +763,8 @@ private:
}
};
-/// CheckImmAllOnesVMatcher - This check if the current node is an build vector
-/// of all ones.
+/// CheckImmAllOnesVMatcher - This checks if the current node is a build_vector
+/// or splat_vector of all ones.
class CheckImmAllOnesVMatcher : public Matcher {
public:
CheckImmAllOnesVMatcher() : Matcher(CheckImmAllOnesV) {}
@@ -773,8 +779,8 @@ private:
bool isContradictoryImpl(const Matcher *M) const override;
};
-/// CheckImmAllZerosVMatcher - This check if the current node is an build vector
-/// of all zeros.
+/// CheckImmAllZerosVMatcher - This checks if the current node is a
+/// build_vector or splat_vector of all zeros.
class CheckImmAllZerosVMatcher : public Matcher {
public:
CheckImmAllZerosVMatcher() : Matcher(CheckImmAllZerosV) {}
diff --git a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
index d9ec14aab8a8..03528a46aea7 100644
--- a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -23,6 +23,7 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
+
using namespace llvm;
enum {
@@ -47,6 +48,8 @@ namespace {
class MatcherTableEmitter {
const CodeGenDAGPatterns &CGP;
+ SmallVector<unsigned, Matcher::HighestKind+1> OpcodeCounts;
+
DenseMap<TreePattern *, unsigned> NodePredicateMap;
std::vector<TreePredicateFn> NodePredicates;
std::vector<TreePredicateFn> NodePredicatesWithOperands;
@@ -79,12 +82,15 @@ class MatcherTableEmitter {
}
public:
- MatcherTableEmitter(const CodeGenDAGPatterns &cgp)
- : CGP(cgp) {}
+ MatcherTableEmitter(const CodeGenDAGPatterns &cgp) : CGP(cgp) {
+ OpcodeCounts.assign(Matcher::HighestKind+1, 0);
+ }
- unsigned EmitMatcherList(const Matcher *N, unsigned Indent,
+ unsigned EmitMatcherList(const Matcher *N, const unsigned Indent,
unsigned StartIdx, raw_ostream &OS);
+ unsigned SizeMatcherList(Matcher *N, raw_ostream &OS);
+
void EmitPredicateFunctions(raw_ostream &OS);
void EmitHistogram(const Matcher *N, raw_ostream &OS);
@@ -95,7 +101,9 @@ private:
void EmitNodePredicatesFunction(const std::vector<TreePredicateFn> &Preds,
StringRef Decl, raw_ostream &OS);
- unsigned EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
+ unsigned SizeMatcher(Matcher *N, raw_ostream &OS);
+
+ unsigned EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
raw_ostream &OS);
unsigned getNodePredicate(TreePredicateFn Pred) {
@@ -165,7 +173,7 @@ static std::string GetPatFromTreePatternNode(const TreePatternNode *N) {
return str;
}
-static unsigned GetVBRSize(unsigned Val) {
+static size_t GetVBRSize(unsigned Val) {
if (Val <= 127) return 1;
unsigned NumBytes = 0;
@@ -219,6 +227,78 @@ static std::string getIncludePath(const Record *R) {
return str;
}
+/// This function traverses the matcher tree and sizes all the nodes
+/// that are children of the three kinds of nodes that have them.
+unsigned MatcherTableEmitter::
+SizeMatcherList(Matcher *N, raw_ostream &OS) {
+ unsigned Size = 0;
+ while (N) {
+ Size += SizeMatcher(N, OS);
+ N = N->getNext();
+ }
+ return Size;
+}
+
+/// This function sizes the children of the three kinds of nodes that
+/// have them. It does so by using special cases for those three
+/// nodes, but sharing the code in EmitMatcher() for the other kinds.
+unsigned MatcherTableEmitter::
+SizeMatcher(Matcher *N, raw_ostream &OS) {
+ unsigned Idx = 0;
+
+ ++OpcodeCounts[N->getKind()];
+ switch (N->getKind()) {
+ // The Scope matcher has its kind, a series of child size + child,
+ // and a trailing zero.
+ case Matcher::Scope: {
+ ScopeMatcher *SM = cast<ScopeMatcher>(N);
+ assert(SM->getNext() == nullptr && "Scope matcher should not have next");
+ unsigned Size = 1; // Count the kind.
+ for (unsigned i = 0, e = SM->getNumChildren(); i != e; ++i) {
+ const size_t ChildSize = SizeMatcherList(SM->getChild(i), OS);
+ assert(ChildSize != 0 && "Matcher cannot have child of size 0");
+ SM->getChild(i)->setSize(ChildSize);
+ Size += GetVBRSize(ChildSize) + ChildSize; // Count VBR and child size.
+ }
+ ++Size; // Count the zero sentinel.
+ return Size;
+ }
+
+ // SwitchOpcode and SwitchType have their kind, a series of child size +
+ // opcode/type + child, and a trailing zero.
+ case Matcher::SwitchOpcode:
+ case Matcher::SwitchType: {
+ unsigned Size = 1; // Count the kind.
+ unsigned NumCases;
+ if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N))
+ NumCases = SOM->getNumCases();
+ else
+ NumCases = cast<SwitchTypeMatcher>(N)->getNumCases();
+ for (unsigned i = 0, e = NumCases; i != e; ++i) {
+ Matcher *Child;
+ if (SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N)) {
+ Child = SOM->getCaseMatcher(i);
+ Size += 2; // Count the child's opcode.
+ } else {
+ Child = cast<SwitchTypeMatcher>(N)->getCaseMatcher(i);
+ ++Size; // Count the child's type.
+ }
+ const size_t ChildSize = SizeMatcherList(Child, OS);
+ assert(ChildSize != 0 && "Matcher cannot have child of size 0");
+ Child->setSize(ChildSize);
+ Size += GetVBRSize(ChildSize) + ChildSize; // Count VBR and child size.
+ }
+ ++Size; // Count the zero sentinel.
+ return Size;
+ }
+
+ default:
+ // Employ the matcher emitter to size other matchers.
+ return EmitMatcher(N, 0, Idx, OS);
+ }
+ llvm_unreachable("Unreachable");
+}
+
static void BeginEmitFunction(raw_ostream &OS, StringRef RetType,
StringRef Decl, bool AddOverride) {
OS << "#ifdef GET_DAGISEL_DECL\n";
@@ -250,7 +330,7 @@ void MatcherTableEmitter::EmitPatternMatchTable(raw_ostream &OS) {
BeginEmitFunction(OS, "StringRef", "getPatternForIndex(unsigned Index)",
true/*AddOverride*/);
OS << "{\n";
- OS << "static const char * PATTERN_MATCH_TABLE[] = {\n";
+ OS << "static const char *PATTERN_MATCH_TABLE[] = {\n";
for (const auto &It : VecPatterns) {
OS << "\"" << It.first << "\",\n";
@@ -264,7 +344,7 @@ void MatcherTableEmitter::EmitPatternMatchTable(raw_ostream &OS) {
BeginEmitFunction(OS, "StringRef", "getIncludePathForIndex(unsigned Index)",
true/*AddOverride*/);
OS << "{\n";
- OS << "static const char * INCLUDE_PATH_TABLE[] = {\n";
+ OS << "static const char *INCLUDE_PATH_TABLE[] = {\n";
for (const auto &It : VecIncludeStrings) {
OS << "\"" << It << "\",\n";
@@ -279,19 +359,16 @@ void MatcherTableEmitter::EmitPatternMatchTable(raw_ostream &OS) {
/// EmitMatcher - Emit bytes for the specified matcher and return
/// the number of bytes emitted.
unsigned MatcherTableEmitter::
-EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
+EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
raw_ostream &OS) {
OS.indent(Indent);
switch (N->getKind()) {
case Matcher::Scope: {
const ScopeMatcher *SM = cast<ScopeMatcher>(N);
- assert(SM->getNext() == nullptr && "Shouldn't have next after scope");
-
unsigned StartIdx = CurrentIdx;
// Emit all of the children.
- SmallString<128> TmpBuf;
for (unsigned i = 0, e = SM->getNumChildren(); i != e; ++i) {
if (i == 0) {
OS << "OPC_Scope, ";
@@ -304,34 +381,21 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS.indent(Indent);
}
- // We need to encode the child and the offset of the failure code before
- // emitting either of them. Handle this by buffering the output into a
- // string while we get the size. Unfortunately, the offset of the
- // children depends on the VBR size of the child, so for large children we
- // have to iterate a bit.
- unsigned ChildSize = 0;
- unsigned VBRSize = 0;
- do {
- VBRSize = GetVBRSize(ChildSize);
-
- TmpBuf.clear();
- raw_svector_ostream OS(TmpBuf);
- ChildSize = EmitMatcherList(SM->getChild(i), Indent+1,
- CurrentIdx+VBRSize, OS);
- } while (GetVBRSize(ChildSize) != VBRSize);
-
- assert(ChildSize != 0 && "Should not have a zero-sized child!");
-
- CurrentIdx += EmitVBRValue(ChildSize, OS);
+ size_t ChildSize = SM->getChild(i)->getSize();
+ size_t VBRSize = GetVBRSize(ChildSize);
+ EmitVBRValue(ChildSize, OS);
if (!OmitComments) {
- OS << "/*->" << CurrentIdx+ChildSize << "*/";
-
+ OS << "/*->" << CurrentIdx + VBRSize + ChildSize << "*/";
if (i == 0)
OS << " // " << SM->getNumChildren() << " children in Scope";
}
+ OS << '\n';
- OS << '\n' << TmpBuf;
- CurrentIdx += ChildSize;
+ ChildSize = EmitMatcherList(SM->getChild(i), Indent+1,
+ CurrentIdx + VBRSize, OS);
+ assert(ChildSize == SM->getChild(i)->getSize() &&
+ "Emitted child size does not match calculated size");
+ CurrentIdx += VBRSize + ChildSize;
}
// Emit a zero as a sentinel indicating end of 'Scope'.
@@ -450,7 +514,6 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
++CurrentIdx;
// For each case we emit the size, then the opcode, then the matcher.
- SmallString<128> TmpBuf;
for (unsigned i = 0, e = NumCases; i != e; ++i) {
const Matcher *Child;
unsigned IdxSize;
@@ -462,24 +525,6 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
IdxSize = 1; // size of type in table is 1 byte.
}
- // We need to encode the opcode and the offset of the case code before
- // emitting the case code. Handle this by buffering the output into a
- // string while we get the size. Unfortunately, the offset of the
- // children depends on the VBR size of the child, so for large children we
- // have to iterate a bit.
- unsigned ChildSize = 0;
- unsigned VBRSize = 0;
- do {
- VBRSize = GetVBRSize(ChildSize);
-
- TmpBuf.clear();
- raw_svector_ostream OS(TmpBuf);
- ChildSize = EmitMatcherList(Child, Indent+1, CurrentIdx+VBRSize+IdxSize,
- OS);
- } while (GetVBRSize(ChildSize) != VBRSize);
-
- assert(ChildSize != 0 && "Should not have a zero-sized child!");
-
if (i != 0) {
if (!OmitComments)
OS << "/*" << format_decimal(CurrentIdx, IndexWidth) << "*/";
@@ -489,20 +534,19 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
"/*SwitchOpcode*/ " : "/*SwitchType*/ ");
}
- // Emit the VBR.
- CurrentIdx += EmitVBRValue(ChildSize, OS);
-
+ size_t ChildSize = Child->getSize();
+ CurrentIdx += EmitVBRValue(ChildSize, OS) + IdxSize;
if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N))
OS << "TARGET_VAL(" << SOM->getCaseOpcode(i).getEnumName() << "),";
else
OS << getEnumName(cast<SwitchTypeMatcher>(N)->getCaseType(i)) << ',';
-
- CurrentIdx += IdxSize;
-
if (!OmitComments)
- OS << "// ->" << CurrentIdx+ChildSize;
+ OS << "// ->" << CurrentIdx + ChildSize;
OS << '\n';
- OS << TmpBuf;
+
+ ChildSize = EmitMatcherList(Child, Indent+1, CurrentIdx, OS);
+ assert(ChildSize == Child->getSize() &&
+ "Emitted child size does not match calculated size");
CurrentIdx += ChildSize;
}
@@ -515,8 +559,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
" // EndSwitchOpcode" : " // EndSwitchType");
OS << '\n';
- ++CurrentIdx;
- return CurrentIdx-StartIdx;
+ return CurrentIdx - StartIdx + 1;
}
case Matcher::CheckType:
@@ -810,9 +853,10 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
llvm_unreachable("Unreachable");
}
-/// EmitMatcherList - Emit the bytes for the specified matcher subtree.
+/// This function traverses the matcher tree and emits all the nodes.
+/// The nodes have already been sized.
unsigned MatcherTableEmitter::
-EmitMatcherList(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
+EmitMatcherList(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
raw_ostream &OS) {
unsigned Size = 0;
while (N) {
@@ -841,12 +885,12 @@ void MatcherTableEmitter::EmitNodePredicatesFunction(
OS << " default: llvm_unreachable(\"Invalid predicate in table?\");\n";
for (unsigned i = 0, e = Preds.size(); i != e; ++i) {
// Emit the predicate code corresponding to this pattern.
- TreePredicateFn PredFn = Preds[i];
+ const TreePredicateFn PredFn = Preds[i];
assert(!PredFn.isAlwaysTrue() && "No code in this predicate");
- OS << " case " << i << ": { \n";
+ OS << " case " << i << ": {\n";
for (auto *SimilarPred :
- NodePredicatesByCodeToRun[PredFn.getCodeToRunOnSDNode()])
+ NodePredicatesByCodeToRun[PredFn.getCodeToRunOnSDNode()])
OS << " // " << TreePredicateFn(SimilarPred).getFnName() <<'\n';
OS << PredFn.getCodeToRunOnSDNode() << "\n }\n";
@@ -887,7 +931,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) {
BeginEmitFunction(OS, "bool",
"CheckComplexPattern(SDNode *Root, SDNode *Parent,\n"
" SDValue N, unsigned PatternNo,\n"
- " SmallVectorImpl<std::pair<SDValue, SDNode*>> &Result)",
+ " SmallVectorImpl<std::pair<SDValue, SDNode *>> &Result)",
true/*AddOverride*/);
OS << "{\n";
OS << " unsigned NextRes = Result.size();\n";
@@ -975,28 +1019,6 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) {
}
}
-static void BuildHistogram(const Matcher *M, std::vector<unsigned> &OpcodeFreq){
- for (; M != nullptr; M = M->getNext()) {
- // Count this node.
- if (unsigned(M->getKind()) >= OpcodeFreq.size())
- OpcodeFreq.resize(M->getKind()+1);
- OpcodeFreq[M->getKind()]++;
-
- // Handle recursive nodes.
- if (const ScopeMatcher *SM = dyn_cast<ScopeMatcher>(M)) {
- for (unsigned i = 0, e = SM->getNumChildren(); i != e; ++i)
- BuildHistogram(SM->getChild(i), OpcodeFreq);
- } else if (const SwitchOpcodeMatcher *SOM =
- dyn_cast<SwitchOpcodeMatcher>(M)) {
- for (unsigned i = 0, e = SOM->getNumCases(); i != e; ++i)
- BuildHistogram(SOM->getCaseMatcher(i), OpcodeFreq);
- } else if (const SwitchTypeMatcher *STM = dyn_cast<SwitchTypeMatcher>(M)) {
- for (unsigned i = 0, e = STM->getNumCases(); i != e; ++i)
- BuildHistogram(STM->getCaseMatcher(i), OpcodeFreq);
- }
- }
-}
-
static StringRef getOpcodeString(Matcher::KindTy Kind) {
switch (Kind) {
case Matcher::Scope: return "OPC_Scope"; break;
@@ -1048,20 +1070,17 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M,
if (OmitComments)
return;
- std::vector<unsigned> OpcodeFreq;
- BuildHistogram(M, OpcodeFreq);
-
OS << " // Opcode Histogram:\n";
- for (unsigned i = 0, e = OpcodeFreq.size(); i != e; ++i) {
+ for (unsigned i = 0, e = OpcodeCounts.size(); i != e; ++i) {
OS << " // #"
<< left_justify(getOpcodeString((Matcher::KindTy)i), HistOpcWidth)
- << " = " << OpcodeFreq[i] << '\n';
+ << " = " << OpcodeCounts[i] << '\n';
}
OS << '\n';
}
-void llvm::EmitMatcherTable(const Matcher *TheMatcher,
+void llvm::EmitMatcherTable(Matcher *TheMatcher,
const CodeGenDAGPatterns &CGP,
raw_ostream &OS) {
OS << "#if defined(GET_DAGISEL_DECL) && defined(GET_DAGISEL_BODY)\n";
@@ -1096,12 +1115,23 @@ void llvm::EmitMatcherTable(const Matcher *TheMatcher,
BeginEmitFunction(OS, "void", "SelectCode(SDNode *N)", false/*AddOverride*/);
MatcherTableEmitter MatcherEmitter(CGP);
+ // First we size all the children of the three kinds of matchers that have
+ // them. This is done by sharing the code in EmitMatcher(). but we don't
+ // want to emit anything, so we turn off comments and use a null stream.
+ bool SaveOmitComments = OmitComments;
+ OmitComments = true;
+ raw_null_ostream NullOS;
+ unsigned TotalSize = MatcherEmitter.SizeMatcherList(TheMatcher, NullOS);
+ OmitComments = SaveOmitComments;
+
+ // Now that the matchers are sized, we can emit the code for them to the
+ // final stream.
OS << "{\n";
OS << " // Some target values are emitted as 2 bytes, TARGET_VAL handles\n";
OS << " // this.\n";
OS << " #define TARGET_VAL(X) X & 255, unsigned(X) >> 8\n";
OS << " static const unsigned char MatcherTable[] = {\n";
- unsigned TotalSize = MatcherEmitter.EmitMatcherList(TheMatcher, 1, 0, OS);
+ TotalSize = MatcherEmitter.EmitMatcherList(TheMatcher, 1, 0, OS);
OS << " 0\n }; // Total Array size is " << (TotalSize+1) << " bytes\n\n";
MatcherEmitter.EmitHistogram(TheMatcher, OS);
diff --git a/llvm/utils/TableGen/DAGISelMatcherGen.cpp b/llvm/utils/TableGen/DAGISelMatcherGen.cpp
index 123ea3374c74..f7415b87e1c0 100644
--- a/llvm/utils/TableGen/DAGISelMatcherGen.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcherGen.cpp
@@ -282,7 +282,9 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
// check to ensure that this gets folded into the normal top-level
// OpcodeSwitch.
if (N == Pattern.getSrcPattern()) {
- const SDNodeInfo &NI = CGP.getSDNodeInfo(CGP.getSDNodeNamed("build_vector"));
+ MVT VT = N->getSimpleType(0);
+ StringRef Name = VT.isScalableVector() ? "splat_vector" : "build_vector";
+ const SDNodeInfo &NI = CGP.getSDNodeInfo(CGP.getSDNodeNamed(Name));
AddMatcher(new CheckOpcodeMatcher(NI));
}
return AddMatcher(new CheckImmAllOnesVMatcher());
@@ -292,7 +294,9 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
// check to ensure that this gets folded into the normal top-level
// OpcodeSwitch.
if (N == Pattern.getSrcPattern()) {
- const SDNodeInfo &NI = CGP.getSDNodeInfo(CGP.getSDNodeNamed("build_vector"));
+ MVT VT = N->getSimpleType(0);
+ StringRef Name = VT.isScalableVector() ? "splat_vector" : "build_vector";
+ const SDNodeInfo &NI = CGP.getSDNodeInfo(CGP.getSDNodeNamed(Name));
AddMatcher(new CheckOpcodeMatcher(NI));
}
return AddMatcher(new CheckImmAllZerosVMatcher());
@@ -744,7 +748,7 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
}
}
- errs() << "unhandled leaf node: \n";
+ errs() << "unhandled leaf node:\n";
N->dump();
}
diff --git a/llvm/utils/TableGen/DFAEmitter.cpp b/llvm/utils/TableGen/DFAEmitter.cpp
index 7391f6845a4b..781cb0636fa1 100644
--- a/llvm/utils/TableGen/DFAEmitter.cpp
+++ b/llvm/utils/TableGen/DFAEmitter.cpp
@@ -174,7 +174,7 @@ namespace {
struct Action {
Record *R = nullptr;
unsigned I = 0;
- std::string S = nullptr;
+ std::string S;
Action() = default;
Action(Record *R, unsigned I, std::string S) : R(R), I(I), S(S) {}
@@ -346,8 +346,7 @@ Transition::Transition(Record *R, Automaton *Parent) {
} else if (isa<IntRecTy>(SymbolV->getType())) {
Actions.emplace_back(nullptr, R->getValueAsInt(A), "");
Types.emplace_back("unsigned");
- } else if (isa<StringRecTy>(SymbolV->getType()) ||
- isa<CodeRecTy>(SymbolV->getType())) {
+ } else if (isa<StringRecTy>(SymbolV->getType())) {
Actions.emplace_back(nullptr, 0, std::string(R->getValueAsString(A)));
Types.emplace_back("std::string");
} else {
diff --git a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
index bc4a084b3224..40d9385e5e9e 100644
--- a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
+++ b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
@@ -263,7 +263,7 @@ void DFAPacketizerEmitter::emitForItineraries(
OS << " " << ProcModelStartIdx[Model] << ", // " << Model->ModelName
<< "\n";
}
- OS << ScheduleClasses.size() << "\n};\n\n";
+ OS << " " << ScheduleClasses.size() << "\n};\n\n";
// The type of a state in the nondeterministic automaton we're defining.
using NfaStateTy = uint64_t;
diff --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp
index 2061ff1fdd1a..c9daa9b24155 100644
--- a/llvm/utils/TableGen/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/DirectiveEmitter.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/TableGen/DirectiveEmitter.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
@@ -40,23 +40,15 @@ private:
namespace llvm {
-// Get Directive or Clause name formatted by replacing whitespaces with
-// underscores.
-std::string getFormattedName(StringRef Name) {
- std::string N = Name.str();
- std::replace(N.begin(), N.end(), ' ', '_');
- return N;
-}
-
// Generate enum class
void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS,
- StringRef Enum, StringRef Prefix, StringRef CppNamespace,
- bool MakeEnumAvailableInNamespace) {
+ StringRef Enum, StringRef Prefix,
+ const DirectiveLanguage &DirLang) {
OS << "\n";
OS << "enum class " << Enum << " {\n";
for (const auto &R : Records) {
- const auto Name = R->getValueAsString("name");
- OS << " " << Prefix << getFormattedName(Name) << ",\n";
+ BaseRecord Rec{R};
+ OS << " " << Prefix << Rec.getFormattedName() << ",\n";
}
OS << "};\n";
OS << "\n";
@@ -68,44 +60,130 @@ void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS,
// At the same time we do not loose the strong type guarantees of the enum
// class, that is we cannot pass an unsigned as Directive without an explicit
// cast.
- if (MakeEnumAvailableInNamespace) {
+ if (DirLang.hasMakeEnumAvailableInNamespace()) {
OS << "\n";
for (const auto &R : Records) {
- const auto FormattedName = getFormattedName(R->getValueAsString("name"));
- OS << "constexpr auto " << Prefix << FormattedName << " = "
- << "llvm::" << CppNamespace << "::" << Enum << "::" << Prefix
- << FormattedName << ";\n";
+ BaseRecord Rec{R};
+ OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = "
+ << "llvm::" << DirLang.getCppNamespace() << "::" << Enum
+ << "::" << Prefix << Rec.getFormattedName() << ";\n";
}
}
}
+// Generate enums for values that clauses can take.
+// Also generate function declarations for get<Enum>Name(StringRef Str).
+void GenerateEnumClauseVal(const std::vector<Record *> &Records,
+ raw_ostream &OS, const DirectiveLanguage &DirLang,
+ std::string &EnumHelperFuncs) {
+ for (const auto &R : Records) {
+ Clause C{R};
+ const auto &ClauseVals = C.getClauseVals();
+ if (ClauseVals.size() <= 0)
+ continue;
+
+ const auto &EnumName = C.getEnumName();
+ if (EnumName.size() == 0) {
+ PrintError("enumClauseValue field not set in Clause" +
+ C.getFormattedName() + ".");
+ return;
+ }
+
+ OS << "\n";
+ OS << "enum class " << EnumName << " {\n";
+ for (const auto &CV : ClauseVals) {
+ ClauseVal CVal{CV};
+ OS << " " << CV->getName() << "=" << CVal.getValue() << ",\n";
+ }
+ OS << "};\n";
+
+ if (DirLang.hasMakeEnumAvailableInNamespace()) {
+ OS << "\n";
+ for (const auto &CV : ClauseVals) {
+ OS << "constexpr auto " << CV->getName() << " = "
+ << "llvm::" << DirLang.getCppNamespace() << "::" << EnumName
+ << "::" << CV->getName() << ";\n";
+ }
+ EnumHelperFuncs += (llvm::Twine(EnumName) + llvm::Twine(" get") +
+ llvm::Twine(EnumName) + llvm::Twine("(StringRef);\n"))
+ .str();
+
+ EnumHelperFuncs +=
+ (llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang.getName()) +
+ llvm::Twine(EnumName) + llvm::Twine("Name(") +
+ llvm::Twine(EnumName) + llvm::Twine(");\n"))
+ .str();
+ }
+ }
+}
+
+bool HasDuplicateClauses(const std::vector<Record *> &Clauses,
+ const Directive &Directive,
+ llvm::StringSet<> &CrtClauses) {
+ bool HasError = false;
+ for (const auto &C : Clauses) {
+ VersionedClause VerClause{C};
+ const auto insRes = CrtClauses.insert(VerClause.getClause().getName());
+ if (!insRes.second) {
+ PrintError("Clause " + VerClause.getClause().getRecordName() +
+ " already defined on directive " + Directive.getRecordName());
+ HasError = true;
+ }
+ }
+ return HasError;
+}
+
+// Check for duplicate clauses in lists. Clauses cannot appear twice in the
+// three allowed list. Also, since required implies allowed, clauses cannot
+// appear in both the allowedClauses and requiredClauses lists.
+bool HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) {
+ bool HasDuplicate = false;
+ for (const auto &D : Directives) {
+ Directive Dir{D};
+ llvm::StringSet<> Clauses;
+ // Check for duplicates in the three allowed lists.
+ if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
+ HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) ||
+ HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) {
+ HasDuplicate = true;
+ }
+ // Check for duplicate between allowedClauses and required
+ Clauses.clear();
+ if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
+ HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) {
+ HasDuplicate = true;
+ }
+ if (HasDuplicate)
+ PrintFatalError("One or more clauses are defined multiple times on"
+ " directive " +
+ Dir.getRecordName());
+ }
+
+ return HasDuplicate;
+}
+
+// Check consitency of records. Return true if an error has been detected.
+// Return false if the records are valid.
+bool DirectiveLanguage::HasValidityErrors() const {
+ if (getDirectiveLanguages().size() != 1) {
+ PrintFatalError("A single definition of DirectiveLanguage is needed.");
+ return true;
+ }
+
+ return HasDuplicateClausesInDirectives(getDirectives());
+}
+
// Generate the declaration section for the enumeration in the directive
// language
void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
-
- const auto &DirectiveLanguages =
- Records.getAllDerivedDefinitions("DirectiveLanguage");
-
- if (DirectiveLanguages.size() != 1) {
- PrintError("A single definition of DirectiveLanguage is needed.");
+ const auto DirLang = DirectiveLanguage{Records};
+ if (DirLang.HasValidityErrors())
return;
- }
- const auto &DirectiveLanguage = DirectiveLanguages[0];
- StringRef LanguageName = DirectiveLanguage->getValueAsString("name");
- StringRef DirectivePrefix =
- DirectiveLanguage->getValueAsString("directivePrefix");
- StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix");
- StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace");
- bool MakeEnumAvailableInNamespace =
- DirectiveLanguage->getValueAsBit("makeEnumAvailableInNamespace");
- bool EnableBitmaskEnumInNamespace =
- DirectiveLanguage->getValueAsBit("enableBitmaskEnumInNamespace");
-
- OS << "#ifndef LLVM_" << LanguageName << "_INC\n";
- OS << "#define LLVM_" << LanguageName << "_INC\n";
-
- if (EnableBitmaskEnumInNamespace)
+ OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n";
+ OS << "#define LLVM_" << DirLang.getName() << "_INC\n";
+
+ if (DirLang.hasEnableBitmaskEnumInNamespace())
OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n";
OS << "\n";
@@ -114,41 +192,48 @@ void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
// Open namespaces defined in the directive language
llvm::SmallVector<StringRef, 2> Namespaces;
- llvm::SplitString(CppNamespace, Namespaces, "::");
+ llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
for (auto Ns : Namespaces)
OS << "namespace " << Ns << " {\n";
- if (EnableBitmaskEnumInNamespace)
+ if (DirLang.hasEnableBitmaskEnumInNamespace())
OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
// Emit Directive enumeration
- const auto &Directives = Records.getAllDerivedDefinitions("Directive");
- GenerateEnumClass(Directives, OS, "Directive", DirectivePrefix, CppNamespace,
- MakeEnumAvailableInNamespace);
+ GenerateEnumClass(DirLang.getDirectives(), OS, "Directive",
+ DirLang.getDirectivePrefix(), DirLang);
// Emit Clause enumeration
- const auto &Clauses = Records.getAllDerivedDefinitions("Clause");
- GenerateEnumClass(Clauses, OS, "Clause", ClausePrefix, CppNamespace,
- MakeEnumAvailableInNamespace);
+ GenerateEnumClass(DirLang.getClauses(), OS, "Clause",
+ DirLang.getClausePrefix(), DirLang);
+
+ // Emit ClauseVal enumeration
+ std::string EnumHelperFuncs;
+ GenerateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs);
// Generic function signatures
OS << "\n";
OS << "// Enumeration helper functions\n";
- OS << "Directive get" << LanguageName
+ OS << "Directive get" << DirLang.getName()
<< "DirectiveKind(llvm::StringRef Str);\n";
OS << "\n";
- OS << "llvm::StringRef get" << LanguageName
+ OS << "llvm::StringRef get" << DirLang.getName()
<< "DirectiveName(Directive D);\n";
OS << "\n";
- OS << "Clause get" << LanguageName << "ClauseKind(llvm::StringRef Str);\n";
+ OS << "Clause get" << DirLang.getName()
+ << "ClauseKind(llvm::StringRef Str);\n";
OS << "\n";
- OS << "llvm::StringRef get" << LanguageName << "ClauseName(Clause C);\n";
+ OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n";
OS << "\n";
OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "
<< "Version.\n";
OS << "bool isAllowedClauseForDirective(Directive D, "
<< "Clause C, unsigned Version);\n";
OS << "\n";
+ if (EnumHelperFuncs.length() > 0) {
+ OS << EnumHelperFuncs;
+ OS << "\n";
+ }
// Closing namespaces
for (auto Ns : llvm::reverse(Namespaces))
@@ -156,138 +241,183 @@ void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
OS << "} // namespace llvm\n";
- OS << "#endif // LLVM_" << LanguageName << "_INC\n";
+ OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n";
}
// Generate function implementation for get<Enum>Name(StringRef Str)
void GenerateGetName(const std::vector<Record *> &Records, raw_ostream &OS,
- StringRef Enum, StringRef Prefix, StringRef LanguageName,
- StringRef Namespace) {
+ StringRef Enum, const DirectiveLanguage &DirLang,
+ StringRef Prefix) {
OS << "\n";
- OS << "llvm::StringRef llvm::" << Namespace << "::get" << LanguageName << Enum
- << "Name(" << Enum << " Kind) {\n";
+ OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
+ << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n";
OS << " switch (Kind) {\n";
for (const auto &R : Records) {
- const auto Name = R->getValueAsString("name");
- const auto AlternativeName = R->getValueAsString("alternativeName");
- OS << " case " << Prefix << getFormattedName(Name) << ":\n";
+ BaseRecord Rec{R};
+ OS << " case " << Prefix << Rec.getFormattedName() << ":\n";
OS << " return \"";
- if (AlternativeName.empty())
- OS << Name;
+ if (Rec.getAlternativeName().empty())
+ OS << Rec.getName();
else
- OS << AlternativeName;
+ OS << Rec.getAlternativeName();
OS << "\";\n";
}
OS << " }\n"; // switch
- OS << " llvm_unreachable(\"Invalid " << LanguageName << " " << Enum
+ OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum
<< " kind\");\n";
OS << "}\n";
}
// Generate function implementation for get<Enum>Kind(StringRef Str)
void GenerateGetKind(const std::vector<Record *> &Records, raw_ostream &OS,
- StringRef Enum, StringRef Prefix, StringRef LanguageName,
- StringRef Namespace, bool ImplicitAsUnknown) {
+ StringRef Enum, const DirectiveLanguage &DirLang,
+ StringRef Prefix, bool ImplicitAsUnknown) {
- auto DefaultIt = std::find_if(Records.begin(), Records.end(), [](Record *R) {
- return R->getValueAsBit("isDefault") == true;
- });
+ auto DefaultIt = llvm::find_if(
+ Records, [](Record *R) { return R->getValueAsBit("isDefault") == true; });
if (DefaultIt == Records.end()) {
- PrintError("A least one " + Enum + " must be defined as default.");
+ PrintError("At least one " + Enum + " must be defined as default.");
return;
}
- const auto FormattedDefaultName =
- getFormattedName((*DefaultIt)->getValueAsString("name"));
+ BaseRecord DefaultRec{(*DefaultIt)};
OS << "\n";
- OS << Enum << " llvm::" << Namespace << "::get" << LanguageName << Enum
- << "Kind(llvm::StringRef Str) {\n";
+ OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get"
+ << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n";
OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n";
for (const auto &R : Records) {
- const auto Name = R->getValueAsString("name");
+ BaseRecord Rec{R};
if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) {
- OS << " .Case(\"" << Name << "\"," << Prefix << FormattedDefaultName
- << ")\n";
+ OS << " .Case(\"" << Rec.getName() << "\"," << Prefix
+ << DefaultRec.getFormattedName() << ")\n";
} else {
- OS << " .Case(\"" << Name << "\"," << Prefix << getFormattedName(Name)
- << ")\n";
+ OS << " .Case(\"" << Rec.getName() << "\"," << Prefix
+ << Rec.getFormattedName() << ")\n";
}
}
- OS << " .Default(" << Prefix << FormattedDefaultName << ");\n";
+ OS << " .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n";
OS << "}\n";
}
+// Generate function implementation for get<ClauseVal>Kind(StringRef Str)
+void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
+ for (const auto &R : DirLang.getClauses()) {
+ Clause C{R};
+ const auto &ClauseVals = C.getClauseVals();
+ if (ClauseVals.size() <= 0)
+ continue;
+
+ auto DefaultIt = llvm::find_if(ClauseVals, [](Record *CV) {
+ return CV->getValueAsBit("isDefault") == true;
+ });
+
+ if (DefaultIt == ClauseVals.end()) {
+ PrintError("At least one val in Clause " + C.getFormattedName() +
+ " must be defined as default.");
+ return;
+ }
+ const auto DefaultName = (*DefaultIt)->getName();
+
+ const auto &EnumName = C.getEnumName();
+ if (EnumName.size() == 0) {
+ PrintError("enumClauseValue field not set in Clause" +
+ C.getFormattedName() + ".");
+ return;
+ }
+
+ OS << "\n";
+ OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get"
+ << EnumName << "(llvm::StringRef Str) {\n";
+ OS << " return llvm::StringSwitch<" << EnumName << ">(Str)\n";
+ for (const auto &CV : ClauseVals) {
+ ClauseVal CVal{CV};
+ OS << " .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName()
+ << ")\n";
+ }
+ OS << " .Default(" << DefaultName << ");\n";
+ OS << "}\n";
+
+ OS << "\n";
+ OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
+ << DirLang.getName() << EnumName
+ << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName
+ << " x) {\n";
+ OS << " switch (x) {\n";
+ for (const auto &CV : ClauseVals) {
+ ClauseVal CVal{CV};
+ OS << " case " << CV->getName() << ":\n";
+ OS << " return \"" << CVal.getFormattedName() << "\";\n";
+ }
+ OS << " }\n"; // switch
+ OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " "
+ << EnumName << " kind\");\n";
+ OS << "}\n";
+ }
+}
+
void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
raw_ostream &OS, StringRef DirectiveName,
- StringRef DirectivePrefix,
- StringRef ClausePrefix,
+ const DirectiveLanguage &DirLang,
llvm::StringSet<> &Cases) {
for (const auto &C : Clauses) {
- const auto MinVersion = C->getValueAsInt("minVersion");
- const auto MaxVersion = C->getValueAsInt("maxVersion");
- const auto SpecificClause = C->getValueAsDef("clause");
- const auto ClauseName =
- getFormattedName(SpecificClause->getValueAsString("name"));
-
- if (Cases.find(ClauseName) == Cases.end()) {
- Cases.insert(ClauseName);
- OS << " case " << ClausePrefix << ClauseName << ":\n";
- OS << " return " << MinVersion << " <= Version && " << MaxVersion
- << " >= Version;\n";
+ VersionedClause VerClause{C};
+
+ const auto ClauseFormattedName = VerClause.getClause().getFormattedName();
+
+ if (Cases.find(ClauseFormattedName) == Cases.end()) {
+ Cases.insert(ClauseFormattedName);
+ OS << " case " << DirLang.getClausePrefix() << ClauseFormattedName
+ << ":\n";
+ OS << " return " << VerClause.getMinVersion()
+ << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n";
}
}
}
// Generate the isAllowedClauseForDirective function implementation.
-void GenerateIsAllowedClause(const std::vector<Record *> &Directives,
- raw_ostream &OS, StringRef LanguageName,
- StringRef DirectivePrefix, StringRef ClausePrefix,
- StringRef CppNamespace) {
+void GenerateIsAllowedClause(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
OS << "\n";
- OS << "bool llvm::" << CppNamespace << "::isAllowedClauseForDirective("
+ OS << "bool llvm::" << DirLang.getCppNamespace()
+ << "::isAllowedClauseForDirective("
<< "Directive D, Clause C, unsigned Version) {\n";
- OS << " assert(unsigned(D) <= llvm::" << CppNamespace
+ OS << " assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace()
<< "::Directive_enumSize);\n";
- OS << " assert(unsigned(C) <= llvm::" << CppNamespace
+ OS << " assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace()
<< "::Clause_enumSize);\n";
OS << " switch (D) {\n";
- for (const auto &D : Directives) {
-
- const auto DirectiveName = D->getValueAsString("name");
- const auto &AllowedClauses = D->getValueAsListOfDefs("allowedClauses");
- const auto &AllowedOnceClauses =
- D->getValueAsListOfDefs("allowedOnceClauses");
- const auto &AllowedExclusiveClauses =
- D->getValueAsListOfDefs("allowedExclusiveClauses");
- const auto &RequiredClauses = D->getValueAsListOfDefs("requiredClauses");
+ for (const auto &D : DirLang.getDirectives()) {
+ Directive Dir{D};
- OS << " case " << DirectivePrefix << getFormattedName(DirectiveName)
+ OS << " case " << DirLang.getDirectivePrefix() << Dir.getFormattedName()
<< ":\n";
- if (AllowedClauses.size() == 0 && AllowedOnceClauses.size() == 0 &&
- AllowedExclusiveClauses.size() == 0 && RequiredClauses.size() == 0) {
+ if (Dir.getAllowedClauses().size() == 0 &&
+ Dir.getAllowedOnceClauses().size() == 0 &&
+ Dir.getAllowedExclusiveClauses().size() == 0 &&
+ Dir.getRequiredClauses().size() == 0) {
OS << " return false;\n";
} else {
OS << " switch (C) {\n";
llvm::StringSet<> Cases;
- GenerateCaseForVersionedClauses(AllowedClauses, OS, DirectiveName,
- DirectivePrefix, ClausePrefix, Cases);
+ GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS,
+ Dir.getName(), DirLang, Cases);
- GenerateCaseForVersionedClauses(AllowedOnceClauses, OS, DirectiveName,
- DirectivePrefix, ClausePrefix, Cases);
+ GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS,
+ Dir.getName(), DirLang, Cases);
- GenerateCaseForVersionedClauses(AllowedExclusiveClauses, OS,
- DirectiveName, DirectivePrefix,
- ClausePrefix, Cases);
+ GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS,
+ Dir.getName(), DirLang, Cases);
- GenerateCaseForVersionedClauses(RequiredClauses, OS, DirectiveName,
- DirectivePrefix, ClausePrefix, Cases);
+ GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS,
+ Dir.getName(), DirLang, Cases);
OS << " default:\n";
OS << " return false;\n";
@@ -297,37 +427,32 @@ void GenerateIsAllowedClause(const std::vector<Record *> &Directives,
}
OS << " }\n"; // End of directives switch
- OS << " llvm_unreachable(\"Invalid " << LanguageName
+ OS << " llvm_unreachable(\"Invalid " << DirLang.getName()
<< " Directive kind\");\n";
OS << "}\n"; // End of function isAllowedClauseForDirective
}
// Generate a simple enum set with the give clauses.
void GenerateClauseSet(const std::vector<Record *> &Clauses, raw_ostream &OS,
- StringRef ClauseEnumSetClass, StringRef ClauseSetPrefix,
- StringRef DirectiveName, StringRef DirectivePrefix,
- StringRef ClausePrefix, StringRef CppNamespace) {
+ StringRef ClauseSetPrefix, Directive &Dir,
+ const DirectiveLanguage &DirLang) {
OS << "\n";
- OS << " static " << ClauseEnumSetClass << " " << ClauseSetPrefix
- << DirectivePrefix << getFormattedName(DirectiveName) << " {\n";
+ OS << " static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix
+ << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n";
for (const auto &C : Clauses) {
- const auto SpecificClause = C->getValueAsDef("clause");
- const auto ClauseName = SpecificClause->getValueAsString("name");
- OS << " llvm::" << CppNamespace << "::Clause::" << ClausePrefix
- << getFormattedName(ClauseName) << ",\n";
+ VersionedClause VerClause{C};
+ OS << " llvm::" << DirLang.getCppNamespace()
+ << "::Clause::" << DirLang.getClausePrefix()
+ << VerClause.getClause().getFormattedName() << ",\n";
}
OS << " };\n";
}
// Generate an enum set for the 4 kinds of clauses linked to a directive.
-void GenerateDirectiveClauseSets(const std::vector<Record *> &Directives,
- raw_ostream &OS, StringRef LanguageName,
- StringRef ClauseEnumSetClass,
- StringRef DirectivePrefix,
- StringRef ClausePrefix,
- StringRef CppNamespace) {
+void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS);
@@ -336,35 +461,24 @@ void GenerateDirectiveClauseSets(const std::vector<Record *> &Directives,
// Open namespaces defined in the directive language.
llvm::SmallVector<StringRef, 2> Namespaces;
- llvm::SplitString(CppNamespace, Namespaces, "::");
+ llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
for (auto Ns : Namespaces)
OS << "namespace " << Ns << " {\n";
- for (const auto &D : Directives) {
- const auto DirectiveName = D->getValueAsString("name");
-
- const auto &AllowedClauses = D->getValueAsListOfDefs("allowedClauses");
- const auto &AllowedOnceClauses =
- D->getValueAsListOfDefs("allowedOnceClauses");
- const auto &AllowedExclusiveClauses =
- D->getValueAsListOfDefs("allowedExclusiveClauses");
- const auto &RequiredClauses = D->getValueAsListOfDefs("requiredClauses");
+ for (const auto &D : DirLang.getDirectives()) {
+ Directive Dir{D};
OS << "\n";
- OS << " // Sets for " << DirectiveName << "\n";
-
- GenerateClauseSet(AllowedClauses, OS, ClauseEnumSetClass, "allowedClauses_",
- DirectiveName, DirectivePrefix, ClausePrefix,
- CppNamespace);
- GenerateClauseSet(AllowedOnceClauses, OS, ClauseEnumSetClass,
- "allowedOnceClauses_", DirectiveName, DirectivePrefix,
- ClausePrefix, CppNamespace);
- GenerateClauseSet(AllowedExclusiveClauses, OS, ClauseEnumSetClass,
- "allowedExclusiveClauses_", DirectiveName,
- DirectivePrefix, ClausePrefix, CppNamespace);
- GenerateClauseSet(RequiredClauses, OS, ClauseEnumSetClass,
- "requiredClauses_", DirectiveName, DirectivePrefix,
- ClausePrefix, CppNamespace);
+ OS << " // Sets for " << Dir.getName() << "\n";
+
+ GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir,
+ DirLang);
+ GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_",
+ Dir, DirLang);
+ GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS,
+ "allowedExclusiveClauses_", Dir, DirLang);
+ GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir,
+ DirLang);
}
// Closing namespaces
@@ -377,118 +491,253 @@ void GenerateDirectiveClauseSets(const std::vector<Record *> &Directives,
// Generate a map of directive (key) with DirectiveClauses struct as values.
// The struct holds the 4 sets of enumeration for the 4 kinds of clauses
// allowances (allowed, allowed once, allowed exclusive and required).
-void GenerateDirectiveClauseMap(const std::vector<Record *> &Directives,
- raw_ostream &OS, StringRef LanguageName,
- StringRef ClauseEnumSetClass,
- StringRef DirectivePrefix,
- StringRef ClausePrefix,
- StringRef CppNamespace) {
+void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS);
OS << "\n";
- OS << "struct " << LanguageName << "DirectiveClauses {\n";
- OS << " const " << ClauseEnumSetClass << " allowed;\n";
- OS << " const " << ClauseEnumSetClass << " allowedOnce;\n";
- OS << " const " << ClauseEnumSetClass << " allowedExclusive;\n";
- OS << " const " << ClauseEnumSetClass << " requiredOneOf;\n";
- OS << "};\n";
+ OS << "{\n";
- OS << "\n";
-
- OS << "std::unordered_map<llvm::" << CppNamespace << "::Directive, "
- << LanguageName << "DirectiveClauses>\n";
- OS << " directiveClausesTable = {\n";
-
- for (const auto &D : Directives) {
- const auto FormattedDirectiveName =
- getFormattedName(D->getValueAsString("name"));
- OS << " {llvm::" << CppNamespace << "::Directive::" << DirectivePrefix
- << FormattedDirectiveName << ",\n";
+ for (const auto &D : DirLang.getDirectives()) {
+ Directive Dir{D};
+ OS << " {llvm::" << DirLang.getCppNamespace()
+ << "::Directive::" << DirLang.getDirectivePrefix()
+ << Dir.getFormattedName() << ",\n";
OS << " {\n";
- OS << " llvm::" << CppNamespace << "::allowedClauses_"
- << DirectivePrefix << FormattedDirectiveName << ",\n";
- OS << " llvm::" << CppNamespace << "::allowedOnceClauses_"
- << DirectivePrefix << FormattedDirectiveName << ",\n";
- OS << " llvm::" << CppNamespace << "::allowedExclusiveClauses_"
- << DirectivePrefix << FormattedDirectiveName << ",\n";
- OS << " llvm::" << CppNamespace << "::requiredClauses_"
- << DirectivePrefix << FormattedDirectiveName << ",\n";
+ OS << " llvm::" << DirLang.getCppNamespace() << "::allowedClauses_"
+ << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
+ OS << " llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_"
+ << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
+ OS << " llvm::" << DirLang.getCppNamespace()
+ << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix()
+ << Dir.getFormattedName() << ",\n";
+ OS << " llvm::" << DirLang.getCppNamespace() << "::requiredClauses_"
+ << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
OS << " }\n";
OS << " },\n";
}
- OS << "};\n";
+ OS << "}\n";
}
-// Generate the implemenation section for the enumeration in the directive
-// language
-void EmitDirectivesFlangImpl(const std::vector<Record *> &Directives,
- raw_ostream &OS, StringRef LanguageName,
- StringRef ClauseEnumSetClass,
- StringRef DirectivePrefix, StringRef ClausePrefix,
- StringRef CppNamespace) {
+// Generate classes entry for Flang clauses in the Flang parse-tree
+// If the clause as a non-generic class, no entry is generated.
+// If the clause does not hold a value, an EMPTY_CLASS is used.
+// If the clause class is generic then a WRAPPER_CLASS is used. When the value
+// is optional, the value class is wrapped into a std::optional.
+void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
- GenerateDirectiveClauseSets(Directives, OS, LanguageName, ClauseEnumSetClass,
- DirectivePrefix, ClausePrefix, CppNamespace);
+ IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS);
+
+ OS << "\n";
- GenerateDirectiveClauseMap(Directives, OS, LanguageName, ClauseEnumSetClass,
- DirectivePrefix, ClausePrefix, CppNamespace);
+ for (const auto &C : DirLang.getClauses()) {
+ Clause Clause{C};
+ if (!Clause.getFlangClass().empty()) {
+ OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", ";
+ if (Clause.isValueOptional() && Clause.isValueList()) {
+ OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>";
+ } else if (Clause.isValueOptional()) {
+ OS << "std::optional<" << Clause.getFlangClass() << ">";
+ } else if (Clause.isValueList()) {
+ OS << "std::list<" << Clause.getFlangClass() << ">";
+ } else {
+ OS << Clause.getFlangClass();
+ }
+ } else {
+ OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName();
+ }
+ OS << ");\n";
+ }
}
-// Generate the implemenation section for the enumeration in the directive
-// language.
-void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) {
+// Generate a list of the different clause classes for Flang.
+void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
- const auto &DirectiveLanguages =
- Records.getAllDerivedDefinitions("DirectiveLanguage");
+ IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS);
- if (DirectiveLanguages.size() != 1) {
- PrintError("A single definition of DirectiveLanguage is needed.");
- return;
+ OS << "\n";
+ llvm::interleaveComma(DirLang.getClauses(), OS, [&](Record *C) {
+ Clause Clause{C};
+ OS << Clause.getFormattedParserClassName() << "\n";
+ });
+}
+
+// Generate dump node list for the clauses holding a generic class name.
+void GenerateFlangClauseDump(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
+
+ IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS);
+
+ OS << "\n";
+ for (const auto &C : DirLang.getClauses()) {
+ Clause Clause{C};
+ OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", "
+ << Clause.getFormattedParserClassName() << ")\n";
}
+}
- const auto &DirectiveLanguage = DirectiveLanguages[0];
- StringRef DirectivePrefix =
- DirectiveLanguage->getValueAsString("directivePrefix");
- StringRef LanguageName = DirectiveLanguage->getValueAsString("name");
- StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix");
- StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace");
- StringRef ClauseEnumSetClass =
- DirectiveLanguage->getValueAsString("clauseEnumSetClass");
+// Generate Unparse functions for clauses classes in the Flang parse-tree
+// If the clause is a non-generic class, no entry is generated.
+void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
- const auto &Directives = Records.getAllDerivedDefinitions("Directive");
+ IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS);
- EmitDirectivesFlangImpl(Directives, OS, LanguageName, ClauseEnumSetClass,
- DirectivePrefix, ClausePrefix, CppNamespace);
+ OS << "\n";
+
+ for (const auto &C : DirLang.getClauses()) {
+ Clause Clause{C};
+ if (!Clause.getFlangClass().empty()) {
+ if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) {
+ OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
+ << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
+ OS << " Word(\"" << Clause.getName().upper() << "\");\n";
+
+ OS << " Walk(\"(\", x.v, \")\");\n";
+ OS << "}\n";
+ } else if (Clause.isValueOptional()) {
+ OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
+ << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
+ OS << " Word(\"" << Clause.getName().upper() << "\");\n";
+ OS << " Put(\"(\");\n";
+ OS << " if (x.v.has_value())\n";
+ if (Clause.isValueList())
+ OS << " Walk(x.v, \",\");\n";
+ else
+ OS << " Walk(x.v);\n";
+ OS << " else\n";
+ OS << " Put(\"" << Clause.getDefaultValue() << "\");\n";
+ OS << " Put(\")\");\n";
+ OS << "}\n";
+ } else {
+ OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
+ << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
+ OS << " Word(\"" << Clause.getName().upper() << "\");\n";
+ OS << " Put(\"(\");\n";
+ if (Clause.isValueList())
+ OS << " Walk(x.v, \",\");\n";
+ else
+ OS << " Walk(x.v);\n";
+ OS << " Put(\")\");\n";
+ OS << "}\n";
+ }
+ } else {
+ OS << "void Before(const " << DirLang.getFlangClauseBaseClass()
+ << "::" << Clause.getFormattedParserClassName() << " &) { Word(\""
+ << Clause.getName().upper() << "\"); }\n";
+ }
+ }
}
-// Generate the implemenation for the enumeration in the directive
-// language. This code can be included in library.
-void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
+// Generate the implementation section for the enumeration in the directive
+// language
+void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
- const auto &DirectiveLanguages =
- Records.getAllDerivedDefinitions("DirectiveLanguage");
+ GenerateDirectiveClauseSets(DirLang, OS);
- if (DirectiveLanguages.size() != 1) {
- PrintError("A single definition of DirectiveLanguage is needed.");
- return;
+ GenerateDirectiveClauseMap(DirLang, OS);
+
+ GenerateFlangClauseParserClass(DirLang, OS);
+
+ GenerateFlangClauseParserClassList(DirLang, OS);
+
+ GenerateFlangClauseDump(DirLang, OS);
+
+ GenerateFlangClauseUnparse(DirLang, OS);
+}
+
+void GenerateClauseClassMacro(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
+ // Generate macros style information for legacy code in clang
+ IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS);
+
+ OS << "\n";
+
+ OS << "#ifndef CLAUSE\n";
+ OS << "#define CLAUSE(Enum, Str, Implicit)\n";
+ OS << "#endif\n";
+ OS << "#ifndef CLAUSE_CLASS\n";
+ OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n";
+ OS << "#endif\n";
+ OS << "#ifndef CLAUSE_NO_CLASS\n";
+ OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n";
+ OS << "#endif\n";
+ OS << "\n";
+ OS << "#define __CLAUSE(Name, Class) \\\n";
+ OS << " CLAUSE(" << DirLang.getClausePrefix()
+ << "##Name, #Name, /* Implicit */ false) \\\n";
+ OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix()
+ << "##Name, #Name, Class)\n";
+ OS << "#define __CLAUSE_NO_CLASS(Name) \\\n";
+ OS << " CLAUSE(" << DirLang.getClausePrefix()
+ << "##Name, #Name, /* Implicit */ false) \\\n";
+ OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n";
+ OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n";
+ OS << " CLAUSE(" << DirLang.getClausePrefix()
+ << "##Name, Str, /* Implicit */ true) \\\n";
+ OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix()
+ << "##Name, Str, Class)\n";
+ OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n";
+ OS << " CLAUSE(" << DirLang.getClausePrefix()
+ << "##Name, Str, /* Implicit */ true) \\\n";
+ OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n";
+ OS << "\n";
+
+ for (const auto &R : DirLang.getClauses()) {
+ Clause C{R};
+ if (C.getClangClass().empty()) { // NO_CLASS
+ if (C.isImplicit()) {
+ OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \""
+ << C.getFormattedName() << "\")\n";
+ } else {
+ OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n";
+ }
+ } else { // CLASS
+ if (C.isImplicit()) {
+ OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \""
+ << C.getFormattedName() << "\", " << C.getClangClass() << ")\n";
+ } else {
+ OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass()
+ << ")\n";
+ }
+ }
}
- const auto &DirectiveLanguage = DirectiveLanguages[0];
- StringRef DirectivePrefix =
- DirectiveLanguage->getValueAsString("directivePrefix");
- StringRef LanguageName = DirectiveLanguage->getValueAsString("name");
- StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix");
- StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace");
- const auto &Directives = Records.getAllDerivedDefinitions("Directive");
- const auto &Clauses = Records.getAllDerivedDefinitions("Clause");
+ OS << "\n";
+ OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n";
+ OS << "#undef __IMPLICIT_CLAUSE_CLASS\n";
+ OS << "#undef __CLAUSE\n";
+ OS << "#undef CLAUSE_NO_CLASS\n";
+ OS << "#undef CLAUSE_CLASS\n";
+ OS << "#undef CLAUSE\n";
+}
+
+// Generate the implementation section for the enumeration in the directive
+// language.
+void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) {
+ const auto DirLang = DirectiveLanguage{Records};
+ if (DirLang.HasValidityErrors())
+ return;
+
+ EmitDirectivesFlangImpl(DirLang, OS);
- StringRef IncludeHeader =
- DirectiveLanguage->getValueAsString("includeHeader");
+ GenerateClauseClassMacro(DirLang, OS);
+}
- if (!IncludeHeader.empty())
- OS << "#include \"" << IncludeHeader << "\"\n\n";
+// Generate the implementation for the enumeration in the directive
+// language. This code can be included in library.
+void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
+ const auto DirLang = DirectiveLanguage{Records};
+ if (DirLang.HasValidityErrors())
+ return;
+
+ if (!DirLang.getIncludeHeader().empty())
+ OS << "#include \"" << DirLang.getIncludeHeader() << "\"\n\n";
OS << "#include \"llvm/ADT/StringRef.h\"\n";
OS << "#include \"llvm/ADT/StringSwitch.h\"\n";
@@ -496,29 +745,32 @@ void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
OS << "\n";
OS << "using namespace llvm;\n";
llvm::SmallVector<StringRef, 2> Namespaces;
- llvm::SplitString(CppNamespace, Namespaces, "::");
+ llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
for (auto Ns : Namespaces)
OS << "using namespace " << Ns << ";\n";
// getDirectiveKind(StringRef Str)
- GenerateGetKind(Directives, OS, "Directive", DirectivePrefix, LanguageName,
- CppNamespace, /*ImplicitAsUnknown=*/false);
+ GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang,
+ DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false);
// getDirectiveName(Directive Kind)
- GenerateGetName(Directives, OS, "Directive", DirectivePrefix, LanguageName,
- CppNamespace);
+ GenerateGetName(DirLang.getDirectives(), OS, "Directive", DirLang,
+ DirLang.getDirectivePrefix());
// getClauseKind(StringRef Str)
- GenerateGetKind(Clauses, OS, "Clause", ClausePrefix, LanguageName,
- CppNamespace, /*ImplicitAsUnknown=*/true);
+ GenerateGetKind(DirLang.getClauses(), OS, "Clause", DirLang,
+ DirLang.getClausePrefix(),
+ /*ImplicitAsUnknown=*/true);
// getClauseName(Clause Kind)
- GenerateGetName(Clauses, OS, "Clause", ClausePrefix, LanguageName,
- CppNamespace);
+ GenerateGetName(DirLang.getClauses(), OS, "Clause", DirLang,
+ DirLang.getClausePrefix());
+
+ // get<ClauseVal>Kind(StringRef Str)
+ GenerateGetKindClauseVal(DirLang, OS);
// isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
- GenerateIsAllowedClause(Directives, OS, LanguageName, DirectivePrefix,
- ClausePrefix, CppNamespace);
+ GenerateIsAllowedClause(DirLang, OS);
}
} // namespace llvm
diff --git a/llvm/utils/TableGen/ExegesisEmitter.cpp b/llvm/utils/TableGen/ExegesisEmitter.cpp
index 8f784e4a4121..4e532c371691 100644
--- a/llvm/utils/TableGen/ExegesisEmitter.cpp
+++ b/llvm/utils/TableGen/ExegesisEmitter.cpp
@@ -144,7 +144,7 @@ void ExegesisEmitter::emitPfmCountersInfo(const Record &Def,
void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const {
// Emit the counter name table.
- OS << "\nstatic const char* " << Target << "PfmCounterNames[] = {\n";
+ OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n";
for (const auto &NameAndIndex : PfmCounterNameTable)
OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second
<< "\n";
diff --git a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp
index 88d210f7fd39..01b39df055ad 100644
--- a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp
+++ b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp
@@ -226,6 +226,8 @@ typedef std::vector<bit_value_t> insn_t;
namespace {
+static const uint64_t NO_FIXED_SEGMENTS_SENTINEL = -1ULL;
+
class FilterChooser;
/// Filter - Filter works with FilterChooser to produce the decoding tree for
@@ -279,7 +281,7 @@ protected:
std::vector<EncodingIDAndOpcode> VariableInstructions;
// Map of well-known segment value to its delegate.
- std::map<unsigned, std::unique_ptr<const FilterChooser>> FilterChooserMap;
+ std::map<uint64_t, std::unique_ptr<const FilterChooser>> FilterChooserMap;
// Number of instructions which fall under FilteredInstructions category.
unsigned NumFiltered;
@@ -305,7 +307,7 @@ public:
const FilterChooser &getVariableFC() const {
assert(NumFiltered == 1);
assert(FilterChooserMap.size() == 1);
- return *(FilterChooserMap.find((unsigned)-1)->second);
+ return *(FilterChooserMap.find(NO_FIXED_SEGMENTS_SENTINEL)->second);
}
// Divides the decoding task into sub tasks and delegates them to the
@@ -602,10 +604,9 @@ void Filter::recurse() {
// Delegates to an inferior filter chooser for further processing on this
// group of instructions whose segment values are variable.
- FilterChooserMap.insert(
- std::make_pair(-1U, std::make_unique<FilterChooser>(
- Owner->AllInstructions, VariableInstructions,
- Owner->Operands, BitValueArray, *Owner)));
+ FilterChooserMap.insert(std::make_pair(NO_FIXED_SEGMENTS_SENTINEL,
+ std::make_unique<FilterChooser>(Owner->AllInstructions,
+ VariableInstructions, Owner->Operands, BitValueArray, *Owner)));
}
// No need to recurse for a singleton filtered instruction.
@@ -674,7 +675,7 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
for (auto &Filter : FilterChooserMap) {
// Field value -1 implies a non-empty set of variable instructions.
// See also recurse().
- if (Filter.first == (unsigned)-1) {
+ if (Filter.first == NO_FIXED_SEGMENTS_SENTINEL) {
HasFallthrough = true;
// Each scope should always have at least one filter value to check
@@ -721,7 +722,7 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
assert(TableInfo.FixupStack.size() > 1 && "fixup stack underflow!");
FixupScopeList::iterator Source = TableInfo.FixupStack.end() - 1;
FixupScopeList::iterator Dest = Source - 1;
- Dest->insert(Dest->end(), Source->begin(), Source->end());
+ llvm::append_range(*Dest, *Source);
TableInfo.FixupStack.pop_back();
// If there is no fallthrough, then the final filter should get fixed
@@ -941,7 +942,7 @@ emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates,
// The predicate function is just a big switch statement based on the
// input predicate index.
OS.indent(Indentation) << "static bool checkDecoderPredicate(unsigned Idx, "
- << "const FeatureBitset& Bits) {\n";
+ << "const FeatureBitset &Bits) {\n";
Indentation += 2;
if (!Predicates.empty()) {
OS.indent(Indentation) << "switch (Idx) {\n";
@@ -965,7 +966,7 @@ emitDecoderFunction(formatted_raw_ostream &OS, DecoderSet &Decoders,
unsigned Indentation) const {
// The decoder function is just a big switch statement based on the
// input decoder index.
- OS.indent(Indentation) << "template<typename InsnType>\n";
+ OS.indent(Indentation) << "template <typename InsnType>\n";
OS.indent(Indentation) << "static DecodeStatus decodeToMCInst(DecodeStatus S,"
<< " unsigned Idx, InsnType insn, MCInst &MI,\n";
OS.indent(Indentation) << " uint64_t "
@@ -1192,7 +1193,7 @@ bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation,
if (!Pred->getValue("AssemblerMatcherPredicate"))
continue;
- if (!dyn_cast<DagInit>(Pred->getValue("AssemblerCondDag")->getValue()))
+ if (!isa<DagInit>(Pred->getValue("AssemblerCondDag")->getValue()))
continue;
const DagInit *D = Pred->getValueAsDag("AssemblerCondDag");
@@ -1886,7 +1887,7 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
for (unsigned i = 0, e = Vals.size(); i != e; ++i) {
// Ignore fixed fields in the record, we're looking for values like:
// bits<5> RST = { ?, ?, ?, ?, ? };
- if (Vals[i].getPrefix() || Vals[i].getValue()->isComplete())
+ if (Vals[i].isNonconcreteOK() || Vals[i].getValue()->isComplete())
continue;
// Determine if Vals[i] actually contributes to the Inst encoding.
@@ -2009,9 +2010,8 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
// For each operand, see if we can figure out where it is encoded.
for (const auto &Op : InOutOperands) {
if (!NumberedInsnOperands[std::string(Op.second)].empty()) {
- InsnOperands.insert(InsnOperands.end(),
- NumberedInsnOperands[std::string(Op.second)].begin(),
- NumberedInsnOperands[std::string(Op.second)].end());
+ llvm::append_range(InsnOperands,
+ NumberedInsnOperands[std::string(Op.second)]);
continue;
}
if (!NumberedInsnOperands[TiedNames[std::string(Op.second)]].empty()) {
@@ -2162,7 +2162,7 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) {
<< "// * Support shift (<<, >>) with signed and unsigned integers on the "
"RHS\n"
<< "// * Support put (<<) to raw_ostream&\n"
- << "template<typename InsnType>\n"
+ << "template <typename InsnType>\n"
<< "#if defined(_MSC_VER) && !defined(__clang__)\n"
<< "__declspec(noinline)\n"
<< "#endif\n"
@@ -2182,7 +2182,7 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) {
<< " return (insn & fieldMask) >> startBit;\n"
<< "}\n"
<< "\n"
- << "template<typename InsnType>\n"
+ << "template <typename InsnType>\n"
<< "static InsnType fieldFromInstruction(InsnType insn, unsigned "
"startBit,\n"
<< " unsigned numBits, "
@@ -2193,7 +2193,7 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) {
<< " return (insn >> startBit) & fieldMask;\n"
<< "}\n"
<< "\n"
- << "template<typename InsnType>\n"
+ << "template <typename InsnType>\n"
<< "static InsnType fieldFromInstruction(InsnType insn, unsigned "
"startBit,\n"
<< " unsigned numBits) {\n"
@@ -2205,14 +2205,14 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) {
// emitDecodeInstruction - Emit the templated helper function
// decodeInstruction().
static void emitDecodeInstruction(formatted_raw_ostream &OS) {
- OS << "template<typename InsnType>\n"
+ OS << "template <typename InsnType>\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"
+ << " const FeatureBitset &Bits = STI.getFeatureBits();\n"
<< "\n"
<< " const uint8_t *Ptr = DecodeTable;\n"
<< " InsnType CurFieldValue = 0;\n"
@@ -2374,7 +2374,7 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) {
<< " if (Fail)\n"
<< " S = MCDisassembler::SoftFail;\n"
<< " LLVM_DEBUG(dbgs() << Loc << \": OPC_SoftFail: \" << (Fail ? "
- "\"FAIL\\n\":\"PASS\\n\"));\n"
+ "\"FAIL\\n\" : \"PASS\\n\"));\n"
<< " break;\n"
<< " }\n"
<< " case MCD::OPC_Fail: {\n"
@@ -2392,8 +2392,8 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) {
void FixedLenDecoderEmitter::run(raw_ostream &o) {
formatted_raw_ostream OS(o);
OS << "#include \"llvm/MC/MCInst.h\"\n";
- OS << "#include \"llvm/Support/Debug.h\"\n";
OS << "#include \"llvm/Support/DataTypes.h\"\n";
+ OS << "#include \"llvm/Support/Debug.h\"\n";
OS << "#include \"llvm/Support/LEB128.h\"\n";
OS << "#include \"llvm/Support/raw_ostream.h\"\n";
OS << "#include <assert.h>\n";
diff --git a/llvm/utils/TableGen/GICombinerEmitter.cpp b/llvm/utils/TableGen/GICombinerEmitter.cpp
index e2a670070ae7..ab00cff63998 100644
--- a/llvm/utils/TableGen/GICombinerEmitter.cpp
+++ b/llvm/utils/TableGen/GICombinerEmitter.cpp
@@ -150,7 +150,7 @@ protected:
/// A block of arbitrary C++ to finish testing the match.
/// FIXME: This is a temporary measure until we have actual pattern matching
- const CodeInit *MatchingFixupCode = nullptr;
+ const StringInit *MatchingFixupCode = nullptr;
/// The MatchData defined by the match stage and required by the apply stage.
/// This allows the plumbing of arbitrary data from C++ predicates between the
@@ -199,7 +199,7 @@ public:
unsigned allocUID() { return UID++; }
StringRef getName() const { return TheDef.getName(); }
const Record &getDef() const { return TheDef; }
- const CodeInit *getMatchingFixupCode() const { return MatchingFixupCode; }
+ const StringInit *getMatchingFixupCode() const { return MatchingFixupCode; }
size_t getNumRoots() const { return Roots.size(); }
GIMatchDag &getMatchDag() { return MatchDag; }
@@ -346,8 +346,6 @@ void CombineRule::declareMatchData(StringRef PatternSymbol, StringRef Type,
}
bool CombineRule::parseDefs() {
- NamedRegionTimer T("parseDefs", "Time spent parsing the defs", "Rule Parsing",
- "Time spent on rule parsing", TimeRegions);
DagInit *Defs = TheDef.getValueAsDag("Defs");
if (Defs->getOperatorAsDef(TheDef.getLoc())->getName() != "defs") {
@@ -434,9 +432,9 @@ bool CombineRule::parseInstructionMatcher(
}
if (InstrOperand.isDef()) {
- if (find_if(Roots, [&](const RootInfo &X) {
+ if (any_of(Roots, [&](const RootInfo &X) {
return X.getPatternSymbol() == Name;
- }) != Roots.end()) {
+ })) {
N->setMatchRoot();
}
}
@@ -462,9 +460,9 @@ bool CombineRule::parseWipMatchOpcodeMatcher(const CodeGenTarget &Target,
MatchDag.addInstrNode(makeDebugName(*this, Name), insertStrTab(Name),
MatchDag.getContext().makeEmptyOperandList());
- if (find_if(Roots, [&](const RootInfo &X) {
+ if (any_of(Roots, [&](const RootInfo &X) {
return ArgName && X.getPatternSymbol() == ArgName->getValue();
- }) != Roots.end()) {
+ })) {
N->setMatchRoot();
}
@@ -488,8 +486,6 @@ bool CombineRule::parseWipMatchOpcodeMatcher(const CodeGenTarget &Target,
return false;
}
bool CombineRule::parseMatcher(const CodeGenTarget &Target) {
- NamedRegionTimer T("parseMatcher", "Time spent parsing the matcher",
- "Rule Parsing", "Time spent on rule parsing", TimeRegions);
StringMap<std::vector<VarInfo>> NamedEdgeDefs;
StringMap<std::vector<VarInfo>> NamedEdgeUses;
DagInit *Matchers = TheDef.getValueAsDag("Match");
@@ -518,10 +514,10 @@ bool CombineRule::parseMatcher(const CodeGenTarget &Target) {
// Parse arbitrary C++ code we have in lieu of supporting MIR matching
- if (const CodeInit *CodeI = dyn_cast<CodeInit>(Matchers->getArg(I))) {
+ if (const StringInit *StringI = dyn_cast<StringInit>(Matchers->getArg(I))) {
assert(!MatchingFixupCode &&
"Only one block of arbitrary code is currently permitted");
- MatchingFixupCode = CodeI;
+ MatchingFixupCode = StringI;
MatchDag.setHasPostMatchPredicate(true);
continue;
}
@@ -593,6 +589,7 @@ bool CombineRule::parseMatcher(const CodeGenTarget &Target) {
}
class GICombinerEmitter {
+ RecordKeeper &Records;
StringRef Name;
const CodeGenTarget &Target;
Record *Combiner;
@@ -618,7 +615,6 @@ public:
/// response to the generated cl::opt.
void emitNameMatcher(raw_ostream &OS) const;
- void generateDeclarationsCodeForTree(raw_ostream &OS, const GIMatchTree &Tree) const;
void generateCodeForTree(raw_ostream &OS, const GIMatchTree &Tree,
StringRef Indent) const;
};
@@ -626,7 +622,7 @@ public:
GICombinerEmitter::GICombinerEmitter(RecordKeeper &RK,
const CodeGenTarget &Target,
StringRef Name, Record *Combiner)
- : Name(Name), Target(Target), Combiner(Combiner) {}
+ : Records(RK), Name(Name), Target(Target), Combiner(Combiner) {}
void GICombinerEmitter::emitNameMatcher(raw_ostream &OS) const {
std::vector<std::pair<std::string, std::string>> Cases;
@@ -762,7 +758,7 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS,
DagInit *Applyer = RuleDef.getValueAsDag("Apply");
if (Applyer->getOperatorAsDef(RuleDef.getLoc())->getName() !=
"apply") {
- PrintError(RuleDef.getLoc(), "Expected apply operator");
+ PrintError(RuleDef.getLoc(), "Expected 'apply' operator in Apply DAG");
return;
}
@@ -803,16 +799,16 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS,
OS << Indent << " && [&]() {\n"
<< Indent << " "
<< CodeExpander(Rule->getMatchingFixupCode()->getValue(), Expansions,
- Rule->getMatchingFixupCode()->getLoc(), ShowExpansions)
+ RuleDef.getLoc(), ShowExpansions)
<< "\n"
<< Indent << " return true;\n"
<< Indent << " }()";
}
OS << ") {\n" << Indent << " ";
- if (const CodeInit *Code = dyn_cast<CodeInit>(Applyer->getArg(0))) {
+ if (const StringInit *Code = dyn_cast<StringInit>(Applyer->getArg(0))) {
OS << CodeExpander(Code->getAsUnquotedString(), Expansions,
- Code->getLoc(), ShowExpansions)
+ RuleDef.getLoc(), ShowExpansions)
<< "\n"
<< Indent << " return true;\n"
<< Indent << " }\n";
@@ -850,6 +846,7 @@ static void emitAdditionalHelperMethodArguments(raw_ostream &OS,
}
void GICombinerEmitter::run(raw_ostream &OS) {
+ Records.startTimer("Gather rules");
gatherRules(Rules, Combiner->getValueAsListOfDefs("Rules"));
if (StopAfterParse) {
MatchDagCtx.print(errs());
@@ -861,11 +858,8 @@ void GICombinerEmitter::run(raw_ostream &OS) {
PrintFatalError(Combiner->getLoc(), "Failed to parse one or more rules");
LLVM_DEBUG(dbgs() << "Optimizing tree for " << Rules.size() << " rules\n");
std::unique_ptr<GIMatchTree> Tree;
+ Records.startTimer("Optimize combiner");
{
- NamedRegionTimer T("Optimize", "Time spent optimizing the combiner",
- "Code Generation", "Time spent generating code",
- TimeRegions);
-
GIMatchTreeBuilder TreeBuilder(0);
for (const auto &Rule : Rules) {
bool HadARoot = false;
@@ -887,9 +881,7 @@ void GICombinerEmitter::run(raw_ostream &OS) {
return;
}
- NamedRegionTimer T("Emit", "Time spent emitting the combiner",
- "Code Generation", "Time spent generating code",
- TimeRegions);
+ Records.startTimer("Emit combiner");
OS << "#ifdef " << Name.upper() << "_GENCOMBINERHELPER_DEPS\n"
<< "#include \"llvm/ADT/SparseBitVector.h\"\n"
<< "namespace llvm {\n"
@@ -906,7 +898,6 @@ void GICombinerEmitter::run(raw_ostream &OS) {
<< " bool isRuleDisabled(unsigned ID) const;\n"
<< " bool setRuleEnabled(StringRef RuleIdentifier);\n"
<< " bool setRuleDisabled(StringRef RuleIdentifier);\n"
- << "\n"
<< "};\n"
<< "\n"
<< "class " << getClassName();
@@ -914,10 +905,10 @@ void GICombinerEmitter::run(raw_ostream &OS) {
if (!StateClass.empty())
OS << " : public " << StateClass;
OS << " {\n"
- << " const " << getClassName() << "RuleConfig *RuleConfig;\n"
+ << " const " << getClassName() << "RuleConfig *RuleConfig;\n"
<< "\n"
<< "public:\n"
- << " template<typename ... Args>" << getClassName() << "(const "
+ << " template <typename... Args>" << getClassName() << "(const "
<< getClassName() << "RuleConfig &RuleConfig, Args &&... args) : ";
if (!StateClass.empty())
OS << StateClass << "(std::forward<Args>(args)...), ";
@@ -947,9 +938,9 @@ void GICombinerEmitter::run(raw_ostream &OS) {
<< " if (First >= Last)\n"
<< " report_fatal_error(\"Beginning of range should be before "
"end of range\");\n"
- << " return {{ *First, *Last + 1 }};\n"
+ << " return {{*First, *Last + 1}};\n"
<< " } else if (RangePair.first == \"*\") {\n"
- << " return {{ 0, " << Rules.size() << " }};\n"
+ << " return {{0, " << Rules.size() << "}};\n"
<< " } else {\n"
<< " const auto I = getRuleIdxForIdentifier(RangePair.first);\n"
<< " if (!I.hasValue())\n"
@@ -963,7 +954,7 @@ void GICombinerEmitter::run(raw_ostream &OS) {
OS << "bool " << getClassName() << "RuleConfig::setRule"
<< (Enabled ? "Enabled" : "Disabled") << "(StringRef RuleIdentifier) {\n"
<< " auto MaybeRange = getRuleRangeForIdentifier(RuleIdentifier);\n"
- << " if(!MaybeRange.hasValue())\n"
+ << " if (!MaybeRange.hasValue())\n"
<< " return false;\n"
<< " for (auto I = MaybeRange->first; I < MaybeRange->second; ++I)\n"
<< " DisabledRules." << (Enabled ? "reset" : "set") << "(I);\n"
@@ -1026,7 +1017,7 @@ void GICombinerEmitter::run(raw_ostream &OS) {
<< " MachineBasicBlock *MBB = MI.getParent();\n"
<< " MachineFunction *MF = MBB->getParent();\n"
<< " MachineRegisterInfo &MRI = MF->getRegInfo();\n"
- << " SmallVector<MachineInstr *, 8> MIs = { &MI };\n\n"
+ << " SmallVector<MachineInstr *, 8> MIs = {&MI};\n\n"
<< " (void)MBB; (void)MF; (void)MRI; (void)RuleConfig;\n\n";
OS << " // Match data\n";
diff --git a/llvm/utils/TableGen/GlobalISel/CodeExpander.cpp b/llvm/utils/TableGen/GlobalISel/CodeExpander.cpp
index d59a9b8e3b65..3ebb293f466e 100644
--- a/llvm/utils/TableGen/GlobalISel/CodeExpander.cpp
+++ b/llvm/utils/TableGen/GlobalISel/CodeExpander.cpp
@@ -58,21 +58,15 @@ void CodeExpander::emit(raw_ostream &OS) const {
// Warn if we split because no terminator was found.
StringRef EndVar = StartVar.drop_front(2 /* ${ */ + Var.size());
if (EndVar.empty()) {
- size_t LocOffset = StartVar.data() - Code.data();
- PrintWarning(
- Loc.size() > 0 && Loc[0].isValid()
- ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
- : SMLoc(),
- "Unterminated expansion");
+ PrintWarning(Loc, "Unterminated expansion '${" + Var + "'");
+ PrintNote("Code: [{" + Code + "}]");
}
auto ValueI = Expansions.find(Var);
if (ValueI == Expansions.end()) {
- size_t LocOffset = StartVar.data() - Code.data();
- PrintError(Loc.size() > 0 && Loc[0].isValid()
- ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
- : SMLoc(),
- "Attempting to expand an undeclared variable " + Var);
+ PrintError(Loc,
+ "Attempt to expand an undeclared variable '" + Var + "'");
+ PrintNote("Code: [{" + Code + "}]");
}
if (ShowExpansions)
OS << "/*$" << Var << "{*/";
@@ -82,11 +76,8 @@ void CodeExpander::emit(raw_ostream &OS) const {
continue;
}
- size_t LocOffset = Current.data() - Code.data();
- PrintWarning(Loc.size() > 0 && Loc[0].isValid()
- ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
- : SMLoc(),
- "Assuming missing escape character");
+ PrintWarning(Loc, "Assuming missing escape character: \\$");
+ PrintNote("Code: [{" + Code + "}]");
OS << "$";
Current = Current.drop_front(1);
}
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp b/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp
index a3a9b7d8b037..7e037dd03b60 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchDag.cpp
@@ -41,7 +41,7 @@ void GIMatchDag::writeDOTGraph(raw_ostream &OS, StringRef ID) const {
SmallVector<std::pair<unsigned, StringRef>, 8> ToPrint;
for (const auto &Assignment : N->user_assigned_operand_names())
ToPrint.emplace_back(Assignment.first, Assignment.second);
- llvm::sort(ToPrint.begin(), ToPrint.end());
+ llvm::sort(ToPrint);
StringRef Separator = "";
for (const auto &Assignment : ToPrint) {
OS << Separator << "$" << Assignment.second << "=getOperand("
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.cpp b/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.cpp
index 218b741be20c..ad9fbea8f881 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.cpp
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchDagInstr.cpp
@@ -27,7 +27,7 @@ void GIMatchDagInstr::print(raw_ostream &OS) const {
SmallVector<std::pair<unsigned, StringRef>, 8> ToPrint;
for (const auto &Assignment : UserAssignedNamesForOperands)
ToPrint.emplace_back(Assignment.first, Assignment.second);
- llvm::sort(ToPrint.begin(), ToPrint.end());
+ llvm::sort(ToPrint);
StringRef Separator = "";
for (const auto &Assignment : ToPrint) {
OS << Separator << "$" << Assignment.second << "=getOperand("
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp
index 96dc4fc94893..d08a83333c30 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp
@@ -121,8 +121,7 @@ void GIMatchTreeBuilderLeafInfo::declareInstr(const GIMatchDagInstr *Instr, unsi
Info.bindOperandVariable(VarBinding.second, ID, VarBinding.first);
// Clear the bit indicating we haven't visited this instr.
- const auto &NodeI = std::find(MatchDag.instr_nodes_begin(),
- MatchDag.instr_nodes_end(), Instr);
+ const auto &NodeI = find(MatchDag.instr_nodes(), Instr);
assert(NodeI != MatchDag.instr_nodes_end() && "Instr isn't in this DAG");
unsigned InstrIdx = MatchDag.getInstrNodeIdx(NodeI);
RemainingInstrNodes.reset(InstrIdx);
@@ -266,11 +265,10 @@ void GIMatchTreeBuilder::runStep() {
LLVM_DEBUG(dbgs() << "Leaf contains multiple rules, drop after the first "
"fully tested rule\n");
auto FirstFullyTested =
- std::find_if(Leaves.begin(), Leaves.end(),
- [](const GIMatchTreeBuilderLeafInfo &X) {
- return X.isFullyTraversed() && X.isFullyTested() &&
- !X.getMatchDag().hasPostMatchPredicate();
- });
+ llvm::find_if(Leaves, [](const GIMatchTreeBuilderLeafInfo &X) {
+ return X.isFullyTraversed() && X.isFullyTested() &&
+ !X.getMatchDag().hasPostMatchPredicate();
+ });
if (FirstFullyTested != Leaves.end())
FirstFullyTested++;
@@ -456,8 +454,7 @@ void GIMatchTreeOpcodePartitioner::repartition(
// predicates for one instruction in the same DAG. That should be
// impossible.
assert(AllOpcodes && "Conflicting opcode predicates");
- for (const CodeGenInstruction *Expected : OpcodeP->getInstrs())
- OpcodesForThisPredicate.push_back(Expected);
+ append_range(OpcodesForThisPredicate, OpcodeP->getInstrs());
}
for (const CodeGenInstruction *Expected : OpcodesForThisPredicate) {
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h
index b86f6454589c..bf41a2e0e234 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h
@@ -353,10 +353,7 @@ public:
void declareOperand(unsigned InstrID, unsigned OpIdx);
GIMatchTreeInstrInfo *getInstrInfo(unsigned ID) const {
- auto I = InstrIDToInfo.find(ID);
- if (I != InstrIDToInfo.end())
- return I->second;
- return nullptr;
+ return InstrIDToInfo.lookup(ID);
}
void dump(raw_ostream &OS) const {
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 4e8dcc52fc20..0a6985a3eac2 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -187,17 +187,21 @@ class InstructionMatcher;
static Optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) {
MVT VT(SVT);
- if (VT.isVector() && VT.getVectorNumElements() != 1)
+ if (VT.isScalableVector())
+ return None;
+
+ if (VT.isFixedLengthVector() && VT.getVectorNumElements() != 1)
return LLTCodeGen(
LLT::vector(VT.getVectorNumElements(), VT.getScalarSizeInBits()));
if (VT.isInteger() || VT.isFloatingPoint())
return LLTCodeGen(LLT::scalar(VT.getSizeInBits()));
+
return None;
}
static std::string explainPredicates(const TreePatternNode *N) {
- std::string Explanation = "";
+ std::string Explanation;
StringRef Separator = "";
for (const TreePredicateCall &Call : N->getPredicateCalls()) {
const TreePredicateFn &P = Call.Fn;
@@ -301,8 +305,8 @@ static Error failedImport(const Twine &Reason) {
}
static Error isTrivialOperatorNode(const TreePatternNode *N) {
- std::string Explanation = "";
- std::string Separator = "";
+ std::string Explanation;
+ std::string Separator;
bool HasUnsupportedPredicate = false;
for (const TreePredicateCall &Call : N->getPredicateCalls()) {
@@ -389,6 +393,10 @@ getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) {
return Name;
}
+static std::string getScopedName(unsigned Scope, const std::string &Name) {
+ return ("pred:" + Twine(Scope) + ":" + Name).str();
+}
+
//===- MatchTable Helpers -------------------------------------------------===//
class MatchTable;
@@ -445,9 +453,8 @@ public:
MatchTableRecord(Optional<unsigned> LabelID_, StringRef EmitStr,
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),
- RawValue(RawValue) {
+ : LabelID(LabelID_.getValueOr(~0u)), EmitStr(EmitStr),
+ NumElements(NumElements), Flags(Flags), RawValue(RawValue) {
assert((!LabelID_.hasValue() || LabelID != ~0u) &&
"This value is reserved for non-labels");
}
@@ -852,6 +859,11 @@ protected:
DefinedComplexPatternSubOperandMap;
/// A map of Symbolic Names to ComplexPattern sub-operands.
DefinedComplexPatternSubOperandMap ComplexSubOperands;
+ /// A map used to for multiple referenced error check of ComplexSubOperand.
+ /// ComplexSubOperand can't be referenced multiple from different operands,
+ /// however multiple references from same operand are allowed since that is
+ /// how 'same operand checks' are generated.
+ StringMap<std::string> ComplexSubOperandsParentName;
uint64_t RuleID;
static uint64_t NextRuleID;
@@ -917,14 +929,25 @@ public:
void definePhysRegOperand(Record *Reg, OperandMatcher &OM);
Error defineComplexSubOperand(StringRef SymbolicName, Record *ComplexPattern,
- unsigned RendererID, unsigned SubOperandID) {
- if (ComplexSubOperands.count(SymbolicName))
- return failedImport(
- "Complex suboperand referenced more than once (Operand: " +
- SymbolicName + ")");
+ unsigned RendererID, unsigned SubOperandID,
+ StringRef ParentSymbolicName) {
+ std::string ParentName(ParentSymbolicName);
+ if (ComplexSubOperands.count(SymbolicName)) {
+ const std::string &RecordedParentName =
+ ComplexSubOperandsParentName[SymbolicName];
+ if (RecordedParentName != ParentName)
+ return failedImport("Error: Complex suboperand " + SymbolicName +
+ " referenced by different operands: " +
+ RecordedParentName + " and " + ParentName + ".");
+ // Complex suboperand referenced more than once from same the operand is
+ // used to generate 'same operand check'. Emitting of
+ // GIR_ComplexSubOperandRenderer for them is already handled.
+ return Error::success();
+ }
ComplexSubOperands[SymbolicName] =
std::make_tuple(ComplexPattern, RendererID, SubOperandID);
+ ComplexSubOperandsParentName[SymbolicName] = ParentName;
return Error::success();
}
@@ -992,10 +1015,6 @@ protected:
bool Optimized = false;
public:
- /// Construct a new predicate and add it to the matcher.
- template <class Kind, class... Args>
- Optional<Kind *> addPredicate(Args &&... args);
-
typename PredicatesTy::iterator predicates_begin() {
return Predicates.begin();
}
@@ -1089,6 +1108,7 @@ public:
IPM_MemoryVsLLTSize,
IPM_MemoryAddressSpace,
IPM_MemoryAlignment,
+ IPM_VectorSplatImm,
IPM_GenericPredicate,
OPM_SameOperand,
OPM_ComplexPattern,
@@ -1101,6 +1121,7 @@ public:
OPM_PointerToAny,
OPM_RegBank,
OPM_MBB,
+ OPM_RecordNamedOperand,
};
protected:
@@ -1270,10 +1291,15 @@ public:
: OperandPredicateMatcher(OPM_PointerToAny, InsnVarID, OpIdx),
SizeInBits(SizeInBits) {}
- static bool classof(const OperandPredicateMatcher *P) {
+ static bool classof(const PredicateMatcher *P) {
return P->getKind() == OPM_PointerToAny;
}
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ SizeInBits == cast<PointerToAnyOperandMatcher>(&B)->SizeInBits;
+ }
+
void emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const override {
Table << MatchTable::Opcode("GIM_CheckPointerToAny")
@@ -1284,6 +1310,40 @@ public:
}
};
+/// Generates code to record named operand in RecordedOperands list at StoreIdx.
+/// Predicates with 'let PredicateCodeUsesOperands = 1' get RecordedOperands as
+/// an argument to predicate's c++ code once all operands have been matched.
+class RecordNamedOperandMatcher : public OperandPredicateMatcher {
+protected:
+ unsigned StoreIdx;
+ std::string Name;
+
+public:
+ RecordNamedOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
+ unsigned StoreIdx, StringRef Name)
+ : OperandPredicateMatcher(OPM_RecordNamedOperand, InsnVarID, OpIdx),
+ StoreIdx(StoreIdx), Name(Name) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_RecordNamedOperand;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ StoreIdx == cast<RecordNamedOperandMatcher>(&B)->StoreIdx &&
+ Name == cast<RecordNamedOperandMatcher>(&B)->Name;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIM_RecordNamedOperand")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("StoreIdx") << MatchTable::IntValue(StoreIdx)
+ << MatchTable::Comment("Name : " + Name) << MatchTable::LineBreak;
+ }
+};
+
/// Generates code to check that an operand is a particular target constant.
class ComplexPatternOperandMatcher : public OperandPredicateMatcher {
protected:
@@ -1523,7 +1583,7 @@ public:
AllocatedTemporariesBaseID(AllocatedTemporariesBaseID) {}
bool hasSymbolicName() const { return !SymbolicName.empty(); }
- const StringRef getSymbolicName() const { return SymbolicName; }
+ StringRef getSymbolicName() const { return SymbolicName; }
void setSymbolicName(StringRef Name) {
assert(SymbolicName.empty() && "Operand already has a symbolic name");
SymbolicName = std::string(Name);
@@ -1670,10 +1730,23 @@ PredicateListMatcher<PredicateMatcher>::getNoPredicateComment() const {
/// Generates code to check the opcode of an instruction.
class InstructionOpcodeMatcher : public InstructionPredicateMatcher {
protected:
- const CodeGenInstruction *I;
+ // Allow matching one to several, similar opcodes that share properties. This
+ // is to handle patterns where one SelectionDAG operation maps to multiple
+ // GlobalISel ones (e.g. G_BUILD_VECTOR and G_BUILD_VECTOR_TRUNC). The first
+ // is treated as the canonical opcode.
+ SmallVector<const CodeGenInstruction *, 2> Insts;
static DenseMap<const CodeGenInstruction *, unsigned> OpcodeValues;
+
+ MatchTableRecord getInstValue(const CodeGenInstruction *I) const {
+ 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());
+ }
+
public:
static void initOpcodeValuesMap(const CodeGenTarget &Target) {
OpcodeValues.clear();
@@ -1683,8 +1756,13 @@ public:
OpcodeValues[I] = OpcodeValue++;
}
- InstructionOpcodeMatcher(unsigned InsnVarID, const CodeGenInstruction *I)
- : InstructionPredicateMatcher(IPM_Opcode, InsnVarID), I(I) {}
+ InstructionOpcodeMatcher(unsigned InsnVarID,
+ ArrayRef<const CodeGenInstruction *> I)
+ : InstructionPredicateMatcher(IPM_Opcode, InsnVarID),
+ Insts(I.begin(), I.end()) {
+ assert((Insts.size() == 1 || Insts.size() == 2) &&
+ "unexpected number of opcode alternatives");
+ }
static bool classof(const PredicateMatcher *P) {
return P->getKind() == IPM_Opcode;
@@ -1692,22 +1770,36 @@ public:
bool isIdentical(const PredicateMatcher &B) const override {
return InstructionPredicateMatcher::isIdentical(B) &&
- I == cast<InstructionOpcodeMatcher>(&B)->I;
+ Insts == cast<InstructionOpcodeMatcher>(&B)->Insts;
}
+
+ bool hasValue() const override {
+ return Insts.size() == 1 && OpcodeValues.count(Insts[0]);
+ }
+
+ // TODO: This is used for the SwitchMatcher optimization. We should be able to
+ // return a list of the opcodes to match.
MatchTableRecord getValue() const override {
+ assert(Insts.size() == 1);
+
+ const CodeGenInstruction *I = Insts[0];
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) << getValue()
- << MatchTable::LineBreak;
+ StringRef CheckType = Insts.size() == 1 ?
+ "GIM_CheckOpcode" : "GIM_CheckOpcodeIsEither";
+ Table << MatchTable::Opcode(CheckType) << MatchTable::Comment("MI")
+ << MatchTable::IntValue(InsnVarID);
+
+ for (const CodeGenInstruction *I : Insts)
+ Table << getInstValue(I);
+ Table << MatchTable::LineBreak;
}
/// Compare the priority of this object and B.
@@ -1725,20 +1817,32 @@ public:
// using instruction frequency information to improve compile time.
if (const InstructionOpcodeMatcher *BO =
dyn_cast<InstructionOpcodeMatcher>(&B))
- return I->TheDef->getName() < BO->I->TheDef->getName();
+ return Insts[0]->TheDef->getName() < BO->Insts[0]->TheDef->getName();
return false;
};
bool isConstantInstruction() const {
- return I->TheDef->getName() == "G_CONSTANT";
+ return Insts.size() == 1 && Insts[0]->TheDef->getName() == "G_CONSTANT";
}
- StringRef getOpcode() const { return I->TheDef->getName(); }
- bool isVariadicNumOperands() const { return I->Operands.isVariadic; }
+ // The first opcode is the canonical opcode, and later are alternatives.
+ StringRef getOpcode() const {
+ return Insts[0]->TheDef->getName();
+ }
+
+ ArrayRef<const CodeGenInstruction *> getAlternativeOpcodes() {
+ return Insts;
+ }
+
+ bool isVariadicNumOperands() const {
+ // If one is variadic, they all should be.
+ return Insts[0]->Operands.isVariadic;
+ }
StringRef getOperandType(unsigned OpIdx) const {
- return I->Operands[OpIdx].OperandType;
+ // Types expected to be uniform for all alternatives.
+ return Insts[0]->Operands[OpIdx].OperandType;
}
};
@@ -2021,6 +2125,42 @@ public:
}
};
+// Matcher for immAllOnesV/immAllZerosV
+class VectorSplatImmPredicateMatcher : public InstructionPredicateMatcher {
+public:
+ enum SplatKind {
+ AllZeros,
+ AllOnes
+ };
+
+private:
+ SplatKind Kind;
+
+public:
+ VectorSplatImmPredicateMatcher(unsigned InsnVarID, SplatKind K)
+ : InstructionPredicateMatcher(IPM_VectorSplatImm, InsnVarID), Kind(K) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_VectorSplatImm;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return InstructionPredicateMatcher::isIdentical(B) &&
+ Kind == static_cast<const VectorSplatImmPredicateMatcher &>(B).Kind;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override {
+ if (Kind == AllOnes)
+ Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllOnes");
+ else
+ Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllZeros");
+
+ Table << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID);
+ Table << MatchTable::LineBreak;
+ }
+};
+
/// Generates code to check an arbitrary C++ instruction predicate.
class GenericInstructionPredicateMatcher : public InstructionPredicateMatcher {
protected:
@@ -2077,8 +2217,9 @@ protected:
SmallVector<std::pair<Record *, unsigned>, 2> PhysRegInputs;
public:
- InstructionMatcher(RuleMatcher &Rule, StringRef SymbolicName)
- : Rule(Rule), SymbolicName(SymbolicName) {
+ InstructionMatcher(RuleMatcher &Rule, StringRef SymbolicName,
+ bool NumOpsCheck = true)
+ : Rule(Rule), NumOperandsCheck(NumOpsCheck), SymbolicName(SymbolicName) {
// We create a new instruction matcher.
// Get a new ID for that instruction.
InsnVarID = Rule.implicitlyDefineInsnVar(*this);
@@ -2108,10 +2249,10 @@ public:
}
OperandMatcher &getOperand(unsigned OpIdx) {
- auto I = std::find_if(Operands.begin(), Operands.end(),
- [&OpIdx](const std::unique_ptr<OperandMatcher> &X) {
- return X->getOpIdx() == OpIdx;
- });
+ auto I = llvm::find_if(Operands,
+ [&OpIdx](const std::unique_ptr<OperandMatcher> &X) {
+ return X->getOpIdx() == OpIdx;
+ });
if (I != Operands.end())
return **I;
llvm_unreachable("Failed to lookup operand");
@@ -2267,9 +2408,10 @@ protected:
public:
InstructionOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
- RuleMatcher &Rule, StringRef SymbolicName)
+ RuleMatcher &Rule, StringRef SymbolicName,
+ bool NumOpsCheck = true)
: OperandPredicateMatcher(OPM_Instruction, InsnVarID, OpIdx),
- InsnMatcher(new InstructionMatcher(Rule, SymbolicName)) {}
+ InsnMatcher(new InstructionMatcher(Rule, SymbolicName, NumOpsCheck)) {}
static bool classof(const PredicateMatcher *P) {
return P->getKind() == OPM_Instruction;
@@ -2395,7 +2537,7 @@ public:
return R->getKind() == OR_Copy;
}
- const StringRef getSymbolicName() const { return SymbolicName; }
+ StringRef getSymbolicName() const { return SymbolicName; }
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
@@ -2462,7 +2604,7 @@ public:
return R->getKind() == OR_CopyOrAddZeroReg;
}
- const StringRef getSymbolicName() const { return SymbolicName; }
+ StringRef getSymbolicName() const { return SymbolicName; }
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
@@ -2499,7 +2641,7 @@ public:
return R->getKind() == OR_CopyConstantAsImm;
}
- const StringRef getSymbolicName() const { return SymbolicName; }
+ StringRef getSymbolicName() const { return SymbolicName; }
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
@@ -2530,7 +2672,7 @@ public:
return R->getKind() == OR_CopyFConstantAsFPImm;
}
- const StringRef getSymbolicName() const { return SymbolicName; }
+ StringRef getSymbolicName() const { return SymbolicName; }
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
@@ -2564,7 +2706,7 @@ public:
return R->getKind() == OR_CopySubReg;
}
- const StringRef getSymbolicName() const { return SymbolicName; }
+ StringRef getSymbolicName() const { return SymbolicName; }
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
@@ -2587,12 +2729,13 @@ protected:
unsigned InsnID;
const Record *RegisterDef;
bool IsDef;
+ const CodeGenTarget &Target;
public:
- AddRegisterRenderer(unsigned InsnID, const Record *RegisterDef,
- bool IsDef = false)
+ AddRegisterRenderer(unsigned InsnID, const CodeGenTarget &Target,
+ const Record *RegisterDef, bool IsDef = false)
: OperandRenderer(OR_Register), InsnID(InsnID), RegisterDef(RegisterDef),
- IsDef(IsDef) {}
+ IsDef(IsDef), Target(Target) {}
static bool classof(const OperandRenderer *R) {
return R->getKind() == OR_Register;
@@ -2600,13 +2743,17 @@ public:
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
Table << MatchTable::Opcode("GIR_AddRegister")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::NamedValue(
- (RegisterDef->getValue("Namespace")
- ? RegisterDef->getValueAsString("Namespace")
- : ""),
- RegisterDef->getName())
- << MatchTable::Comment("AddRegisterRegFlags");
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID);
+ if (RegisterDef->getName() != "zero_reg") {
+ Table << MatchTable::NamedValue(
+ (RegisterDef->getValue("Namespace")
+ ? RegisterDef->getValueAsString("Namespace")
+ : ""),
+ RegisterDef->getName());
+ } else {
+ Table << MatchTable::NamedValue(Target.getRegNamespace(), "NoRegister");
+ }
+ Table << MatchTable::Comment("AddRegisterRegFlags");
// TODO: This is encoded as a 64-bit element, but only 16 or 32-bits are
// really needed for a physical register reference. We can pack the
@@ -2628,12 +2775,14 @@ protected:
unsigned TempRegID;
const CodeGenSubRegIndex *SubRegIdx;
bool IsDef;
+ bool IsDead;
public:
TempRegRenderer(unsigned InsnID, unsigned TempRegID, bool IsDef = false,
- const CodeGenSubRegIndex *SubReg = nullptr)
+ const CodeGenSubRegIndex *SubReg = nullptr,
+ bool IsDead = false)
: OperandRenderer(OR_Register), InsnID(InsnID), TempRegID(TempRegID),
- SubRegIdx(SubReg), IsDef(IsDef) {}
+ SubRegIdx(SubReg), IsDef(IsDef), IsDead(IsDead) {}
static bool classof(const OperandRenderer *R) {
return R->getKind() == OR_TempRegister;
@@ -2650,9 +2799,13 @@ public:
<< MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
<< MatchTable::Comment("TempRegFlags");
- if (IsDef)
- Table << MatchTable::NamedValue("RegState::Define");
- else
+ if (IsDef) {
+ SmallString<32> RegFlags;
+ RegFlags += "RegState::Define";
+ if (IsDead)
+ RegFlags += "|RegState::Dead";
+ Table << MatchTable::NamedValue(RegFlags);
+ } else
Table << MatchTable::IntValue(0);
if (SubRegIdx)
@@ -3365,6 +3518,16 @@ private:
// Rule coverage information.
Optional<CodeGenCoverage> RuleCoverage;
+ /// Variables used to help with collecting of named operands for predicates
+ /// with 'let PredicateCodeUsesOperands = 1'. WaitingForNamedOperands is set
+ /// to the number of named operands that predicate expects. Store locations in
+ /// StoreIdxForName correspond to the order in which operand names appear in
+ /// predicate's argument list.
+ /// When we visit named leaf operand and WaitingForNamedOperands is not zero,
+ /// add matcher that will record operand and decrease counter.
+ unsigned WaitingForNamedOperands = 0;
+ StringMap<unsigned> StoreIdxForName;
+
void gatherOpcodeValues();
void gatherTypeIDValues();
void gatherNodeEquivs();
@@ -3394,7 +3557,11 @@ private:
Expected<action_iterator>
createInstructionRenderer(action_iterator InsertPt, RuleMatcher &M,
const TreePatternNode *Dst);
- void importExplicitDefRenderers(BuildMIAction &DstMIBuilder);
+
+ Expected<action_iterator>
+ importExplicitDefRenderers(action_iterator InsertPt, RuleMatcher &M,
+ BuildMIAction &DstMIBuilder,
+ const TreePatternNode *Dst);
Expected<action_iterator>
importExplicitUseRenderers(action_iterator InsertPt, RuleMatcher &M,
@@ -3413,7 +3580,8 @@ private:
void emitCxxPredicateFns(raw_ostream &OS, StringRef CodeFieldName,
StringRef TypeIdentifier, StringRef ArgType,
- StringRef ArgName, StringRef AdditionalDeclarations,
+ StringRef ArgName, StringRef AdditionalArgs,
+ StringRef AdditionalDeclarations,
std::function<bool(const Record *R)> Filter);
void emitImmPredicateFns(raw_ostream &OS, StringRef TypeIdentifier,
StringRef ArgType,
@@ -3455,6 +3623,12 @@ private:
Optional<const CodeGenRegisterClass *>
inferRegClassFromPattern(TreePatternNode *N);
+ // Add builtin predicates.
+ Expected<InstructionMatcher &>
+ addBuiltinPredicates(const Record *SrcGIEquivOrNull,
+ const TreePredicateFn &Predicate,
+ InstructionMatcher &InsnMatcher, bool &HasAddedMatcher);
+
public:
/// Takes a sequence of \p Rules and group them based on the predicates
/// they share. \p MatcherStorage is used as a memory container
@@ -3562,6 +3736,147 @@ GlobalISelEmitter::importRulePredicates(RuleMatcher &M,
return Error::success();
}
+Expected<InstructionMatcher &> GlobalISelEmitter::addBuiltinPredicates(
+ const Record *SrcGIEquivOrNull, const TreePredicateFn &Predicate,
+ InstructionMatcher &InsnMatcher, bool &HasAddedMatcher) {
+ if (Predicate.isLoad() || Predicate.isStore() || Predicate.isAtomic()) {
+ if (const ListInit *AddrSpaces = Predicate.getAddressSpaces()) {
+ SmallVector<unsigned, 4> ParsedAddrSpaces;
+
+ for (Init *Val : AddrSpaces->getValues()) {
+ IntInit *IntVal = dyn_cast<IntInit>(Val);
+ if (!IntVal)
+ return failedImport("Address space is not an integer");
+ ParsedAddrSpaces.push_back(IntVal->getValue());
+ }
+
+ if (!ParsedAddrSpaces.empty()) {
+ InsnMatcher.addPredicate<MemoryAddressSpacePredicateMatcher>(
+ 0, ParsedAddrSpaces);
+ }
+ }
+
+ int64_t MinAlign = Predicate.getMinAlignment();
+ if (MinAlign > 0)
+ InsnMatcher.addPredicate<MemoryAlignmentPredicateMatcher>(0, MinAlign);
+ }
+
+ // G_LOAD is used for both non-extending and any-extending loads.
+ if (Predicate.isLoad() && Predicate.isNonExtLoad()) {
+ InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
+ 0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0);
+ return InsnMatcher;
+ }
+ if (Predicate.isLoad() && Predicate.isAnyExtLoad()) {
+ InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
+ 0, MemoryVsLLTSizePredicateMatcher::LessThan, 0);
+ return InsnMatcher;
+ }
+
+ if (Predicate.isStore()) {
+ if (Predicate.isTruncStore()) {
+ // FIXME: If MemoryVT is set, we end up with 2 checks for the MMO size.
+ InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
+ 0, MemoryVsLLTSizePredicateMatcher::LessThan, 0);
+ return InsnMatcher;
+ }
+ if (Predicate.isNonTruncStore()) {
+ // We need to check the sizes match here otherwise we could incorrectly
+ // match truncating stores with non-truncating ones.
+ InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
+ 0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0);
+ }
+ }
+
+ // No check required. We already did it by swapping the opcode.
+ if (!SrcGIEquivOrNull->isValueUnset("IfSignExtend") &&
+ Predicate.isSignExtLoad())
+ return InsnMatcher;
+
+ // No check required. We already did it by swapping the opcode.
+ if (!SrcGIEquivOrNull->isValueUnset("IfZeroExtend") &&
+ Predicate.isZeroExtLoad())
+ return InsnMatcher;
+
+ // No check required. G_STORE by itself is a non-extending store.
+ if (Predicate.isNonTruncStore())
+ return InsnMatcher;
+
+ if (Predicate.isLoad() || Predicate.isStore() || Predicate.isAtomic()) {
+ if (Predicate.getMemoryVT() != nullptr) {
+ Optional<LLTCodeGen> MemTyOrNone =
+ MVTToLLT(getValueType(Predicate.getMemoryVT()));
+
+ if (!MemTyOrNone)
+ return failedImport("MemVT could not be converted to LLT");
+
+ // 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);
+ return InsnMatcher;
+ }
+ }
+
+ if (Predicate.isLoad() || Predicate.isStore()) {
+ // No check required. A G_LOAD/G_STORE is an unindexed load.
+ if (Predicate.isUnindexed())
+ return InsnMatcher;
+ }
+
+ if (Predicate.isAtomic()) {
+ if (Predicate.isAtomicOrderingMonotonic()) {
+ InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Monotonic");
+ return InsnMatcher;
+ }
+ if (Predicate.isAtomicOrderingAcquire()) {
+ InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Acquire");
+ return InsnMatcher;
+ }
+ if (Predicate.isAtomicOrderingRelease()) {
+ InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Release");
+ return InsnMatcher;
+ }
+ if (Predicate.isAtomicOrderingAcquireRelease()) {
+ InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
+ "AcquireRelease");
+ return InsnMatcher;
+ }
+ if (Predicate.isAtomicOrderingSequentiallyConsistent()) {
+ InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
+ "SequentiallyConsistent");
+ return InsnMatcher;
+ }
+ }
+
+ if (Predicate.isAtomicOrderingAcquireOrStronger()) {
+ InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
+ "Acquire", AtomicOrderingMMOPredicateMatcher::AO_OrStronger);
+ return InsnMatcher;
+ }
+ if (Predicate.isAtomicOrderingWeakerThanAcquire()) {
+ InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
+ "Acquire", AtomicOrderingMMOPredicateMatcher::AO_WeakerThan);
+ return InsnMatcher;
+ }
+
+ if (Predicate.isAtomicOrderingReleaseOrStronger()) {
+ InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
+ "Release", AtomicOrderingMMOPredicateMatcher::AO_OrStronger);
+ return InsnMatcher;
+ }
+ if (Predicate.isAtomicOrderingWeakerThanRelease()) {
+ InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
+ "Release", AtomicOrderingMMOPredicateMatcher::AO_WeakerThan);
+ return InsnMatcher;
+ }
+ HasAddedMatcher = false;
+ return InsnMatcher;
+}
+
Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
const TreePatternNode *Src, unsigned &TempOpIdx) {
@@ -3603,6 +3918,7 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
for (const TreePredicateCall &Call : Src->getPredicateCalls()) {
const TreePredicateFn &Predicate = Call.Fn;
+ bool HasAddedBuiltinMatcher = true;
if (Predicate.isAlwaysTrue())
continue;
@@ -3611,154 +3927,35 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
continue;
}
- // An address space check is needed in all contexts if there is one.
- if (Predicate.isLoad() || Predicate.isStore() || Predicate.isAtomic()) {
- if (const ListInit *AddrSpaces = Predicate.getAddressSpaces()) {
- SmallVector<unsigned, 4> ParsedAddrSpaces;
-
- for (Init *Val : AddrSpaces->getValues()) {
- IntInit *IntVal = dyn_cast<IntInit>(Val);
- if (!IntVal)
- return failedImport("Address space is not an integer");
- ParsedAddrSpaces.push_back(IntVal->getValue());
- }
-
- if (!ParsedAddrSpaces.empty()) {
- InsnMatcher.addPredicate<MemoryAddressSpacePredicateMatcher>(
- 0, ParsedAddrSpaces);
- }
- }
-
- int64_t MinAlign = Predicate.getMinAlignment();
- if (MinAlign > 0)
- InsnMatcher.addPredicate<MemoryAlignmentPredicateMatcher>(0, MinAlign);
- }
-
- // 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;
- }
-
- if (Predicate.isStore()) {
- if (Predicate.isTruncStore()) {
- // FIXME: If MemoryVT is set, we end up with 2 checks for the MMO size.
- InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
- 0, MemoryVsLLTSizePredicateMatcher::LessThan, 0);
- continue;
- }
- if (Predicate.isNonTruncStore()) {
- // We need to check the sizes match here otherwise we could incorrectly
- // match truncating stores with non-truncating ones.
- InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
- 0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0);
- }
- }
-
- // 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.
- if (Predicate.isNonTruncStore())
- continue;
-
- if (Predicate.isLoad() || Predicate.isStore() || Predicate.isAtomic()) {
- if (Predicate.getMemoryVT() != nullptr) {
- Optional<LLTCodeGen> MemTyOrNone =
- MVTToLLT(getValueType(Predicate.getMemoryVT()));
-
- if (!MemTyOrNone)
- return failedImport("MemVT could not be converted to LLT");
-
- // 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;
- }
- }
-
- if (Predicate.isLoad() || Predicate.isStore()) {
- // No check required. A G_LOAD/G_STORE is an unindexed load.
- if (Predicate.isUnindexed())
- continue;
- }
-
- if (Predicate.isAtomic()) {
- if (Predicate.isAtomicOrderingMonotonic()) {
- InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
- "Monotonic");
- continue;
- }
- if (Predicate.isAtomicOrderingAcquire()) {
- InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Acquire");
- continue;
- }
- if (Predicate.isAtomicOrderingRelease()) {
- InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("Release");
- continue;
- }
- if (Predicate.isAtomicOrderingAcquireRelease()) {
- InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
- "AcquireRelease");
- continue;
- }
- if (Predicate.isAtomicOrderingSequentiallyConsistent()) {
- InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
- "SequentiallyConsistent");
- continue;
- }
-
- if (Predicate.isAtomicOrderingAcquireOrStronger()) {
- InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
- "Acquire", AtomicOrderingMMOPredicateMatcher::AO_OrStronger);
- continue;
- }
- if (Predicate.isAtomicOrderingWeakerThanAcquire()) {
- InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
- "Acquire", AtomicOrderingMMOPredicateMatcher::AO_WeakerThan);
- continue;
- }
-
- if (Predicate.isAtomicOrderingReleaseOrStronger()) {
- InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
- "Release", AtomicOrderingMMOPredicateMatcher::AO_OrStronger);
- continue;
- }
- if (Predicate.isAtomicOrderingWeakerThanRelease()) {
- InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
- "Release", AtomicOrderingMMOPredicateMatcher::AO_WeakerThan);
- continue;
- }
- }
+ auto InsnMatcherOrError = addBuiltinPredicates(
+ SrcGIEquivOrNull, Predicate, InsnMatcher, HasAddedBuiltinMatcher);
+ if (auto Error = InsnMatcherOrError.takeError())
+ return std::move(Error);
if (Predicate.hasGISelPredicateCode()) {
+ if (Predicate.usesOperands()) {
+ assert(WaitingForNamedOperands == 0 &&
+ "previous predicate didn't find all operands or "
+ "nested predicate that uses operands");
+ TreePattern *TP = Predicate.getOrigPatFragRecord();
+ WaitingForNamedOperands = TP->getNumArgs();
+ for (unsigned i = 0; i < WaitingForNamedOperands; ++i)
+ StoreIdxForName[getScopedName(Call.Scope, TP->getArgName(i))] = i;
+ }
InsnMatcher.addPredicate<GenericInstructionPredicateMatcher>(Predicate);
continue;
}
-
- return failedImport("Src pattern child has predicate (" +
- explainPredicates(Src) + ")");
+ if (!HasAddedBuiltinMatcher) {
+ return failedImport("Src pattern child has predicate (" +
+ explainPredicates(Src) + ")");
+ }
}
+
+ bool IsAtomic = false;
if (SrcGIEquivOrNull && SrcGIEquivOrNull->getValueAsBit("CheckMMOIsNonAtomic"))
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("NotAtomic");
else if (SrcGIEquivOrNull && SrcGIEquivOrNull->getValueAsBit("CheckMMOIsAtomic")) {
+ IsAtomic = true;
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
"Unordered", AtomicOrderingMMOPredicateMatcher::AO_OrStronger);
}
@@ -3812,6 +4009,27 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
}
}
+ // Hack around an unfortunate mistake in how atomic store (and really
+ // atomicrmw in general) operands were ordered. A ISD::STORE used the order
+ // <stored value>, <pointer> order. ISD::ATOMIC_STORE used the opposite,
+ // <pointer>, <stored value>. In GlobalISel there's just the one store
+ // opcode, so we need to swap the operands here to get the right type check.
+ if (IsAtomic && SrcGIOrNull->TheDef->getName() == "G_STORE") {
+ assert(NumChildren == 2 && "wrong operands for atomic store");
+
+ TreePatternNode *PtrChild = Src->getChild(0);
+ TreePatternNode *ValueChild = Src->getChild(1);
+
+ if (auto Error = importChildMatcher(Rule, InsnMatcher, PtrChild, true,
+ false, 1, TempOpIdx))
+ return std::move(Error);
+
+ if (auto Error = importChildMatcher(Rule, InsnMatcher, ValueChild, false,
+ false, 0, TempOpIdx))
+ return std::move(Error);
+ return InsnMatcher;
+ }
+
// Match the used operands (i.e. the children of the operator).
bool IsIntrinsic =
SrcGIOrNull->TheDef->getName() == "G_INTRINSIC" ||
@@ -3902,12 +4120,22 @@ Error GlobalISelEmitter::importChildMatcher(
bool OperandIsImmArg, unsigned OpIdx, unsigned &TempOpIdx) {
Record *PhysReg = nullptr;
- StringRef SrcChildName = getSrcChildName(SrcChild, PhysReg);
+ std::string SrcChildName = std::string(getSrcChildName(SrcChild, PhysReg));
+ if (!SrcChild->isLeaf() &&
+ SrcChild->getOperator()->isSubClassOf("ComplexPattern")) {
+ // The "name" of a non-leaf complex pattern (MY_PAT $op1, $op2) is
+ // "MY_PAT:op1:op2" and the ones with same "name" represent same operand.
+ std::string PatternName = std::string(SrcChild->getOperator()->getName());
+ for (unsigned i = 0; i < SrcChild->getNumChildren(); ++i) {
+ PatternName += ":";
+ PatternName += SrcChild->getChild(i)->getName();
+ }
+ SrcChildName = PatternName;
+ }
OperandMatcher &OM =
- PhysReg
- ? InsnMatcher.addPhysRegInput(PhysReg, OpIdx, TempOpIdx)
- : InsnMatcher.addOperand(OpIdx, std::string(SrcChildName), TempOpIdx);
+ PhysReg ? InsnMatcher.addPhysRegInput(PhysReg, OpIdx, TempOpIdx)
+ : InsnMatcher.addOperand(OpIdx, SrcChildName, TempOpIdx);
if (OM.isSameAsAnotherOperand())
return Error::success();
@@ -3954,9 +4182,9 @@ Error GlobalISelEmitter::importChildMatcher(
for (unsigned i = 0, e = SrcChild->getNumChildren(); i != e; ++i) {
auto *SubOperand = SrcChild->getChild(i);
if (!SubOperand->getName().empty()) {
- if (auto Error = Rule.defineComplexSubOperand(SubOperand->getName(),
- SrcChild->getOperator(),
- RendererID, i))
+ if (auto Error = Rule.defineComplexSubOperand(
+ SubOperand->getName(), SrcChild->getOperator(), RendererID, i,
+ SrcChildName))
return Error;
}
}
@@ -4002,6 +4230,13 @@ Error GlobalISelEmitter::importChildMatcher(
if (auto *ChildDefInit = dyn_cast<DefInit>(SrcChild->getLeafValue())) {
auto *ChildRec = ChildDefInit->getDef();
+ if (WaitingForNamedOperands) {
+ auto PA = SrcChild->getNamesAsPredicateArg().begin();
+ std::string Name = getScopedName(PA->getScope(), PA->getIdentifier());
+ OM.addPredicate<RecordNamedOperandMatcher>(StoreIdxForName[Name], Name);
+ --WaitingForNamedOperands;
+ }
+
// Check for register classes.
if (ChildRec->isSubClassOf("RegisterClass") ||
ChildRec->isSubClassOf("RegisterOperand")) {
@@ -4044,6 +4279,40 @@ Error GlobalISelEmitter::importChildMatcher(
if (ChildRec->getName() == "srcvalue")
return Error::success();
+ const bool ImmAllOnesV = ChildRec->getName() == "immAllOnesV";
+ if (ImmAllOnesV || ChildRec->getName() == "immAllZerosV") {
+ auto MaybeInsnOperand = OM.addPredicate<InstructionOperandMatcher>(
+ InsnMatcher.getRuleMatcher(), SrcChild->getName(), false);
+ InstructionOperandMatcher &InsnOperand = **MaybeInsnOperand;
+
+ ValueTypeByHwMode VTy = ChildTypes.front().getValueTypeByHwMode();
+
+ const CodeGenInstruction &BuildVector
+ = Target.getInstruction(RK.getDef("G_BUILD_VECTOR"));
+ const CodeGenInstruction &BuildVectorTrunc
+ = Target.getInstruction(RK.getDef("G_BUILD_VECTOR_TRUNC"));
+
+ // Treat G_BUILD_VECTOR as the canonical opcode, and G_BUILD_VECTOR_TRUNC
+ // as an alternative.
+ InsnOperand.getInsnMatcher().addPredicate<InstructionOpcodeMatcher>(
+ makeArrayRef({&BuildVector, &BuildVectorTrunc}));
+
+ // TODO: Handle both G_BUILD_VECTOR and G_BUILD_VECTOR_TRUNC We could
+ // theoretically not emit any opcode check, but getOpcodeMatcher currently
+ // has to succeed.
+ OperandMatcher &OM =
+ InsnOperand.getInsnMatcher().addOperand(0, "", TempOpIdx);
+ if (auto Error =
+ OM.addTypeCheckPredicate(VTy, false /* OperandIsAPointer */))
+ return failedImport(toString(std::move(Error)) +
+ " for result of Src pattern operator");
+
+ InsnOperand.getInsnMatcher().addPredicate<VectorSplatImmPredicateMatcher>(
+ ImmAllOnesV ? VectorSplatImmPredicateMatcher::AllOnes
+ : VectorSplatImmPredicateMatcher::AllZeros);
+ return Error::success();
+ }
+
return failedImport(
"Src pattern child def is an unsupported tablegen class");
}
@@ -4155,7 +4424,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
return failedImport("Dst operand has an unsupported type");
if (ChildRec->isSubClassOf("Register")) {
- DstMIBuilder.addRenderer<AddRegisterRenderer>(ChildRec);
+ DstMIBuilder.addRenderer<AddRegisterRenderer>(Target, ChildRec);
return InsertPt;
}
@@ -4215,12 +4484,15 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
&Target.getInstruction(RK.getDef("COPY")));
BuildMIAction &CopyToPhysRegMIBuilder =
*static_cast<BuildMIAction *>(InsertPt->get());
- CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(PhysInput.first,
+ CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(Target,
+ PhysInput.first,
true);
CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysInput.first);
}
- importExplicitDefRenderers(DstMIBuilder);
+ if (auto Error = importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Dst)
+ .takeError())
+ return std::move(Error);
if (auto Error = importExplicitUseRenderers(InsertPt, M, DstMIBuilder, Dst)
.takeError())
@@ -4372,13 +4644,39 @@ Expected<action_iterator> GlobalISelEmitter::createInstructionRenderer(
DstI);
}
-void GlobalISelEmitter::importExplicitDefRenderers(
- BuildMIAction &DstMIBuilder) {
+Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
+ action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
+ const TreePatternNode *Dst) {
const CodeGenInstruction *DstI = DstMIBuilder.getCGI();
- for (unsigned I = 0; I < DstI->Operands.NumDefs; ++I) {
- const CGIOperandList::OperandInfo &DstIOperand = DstI->Operands[I];
- DstMIBuilder.addRenderer<CopyRenderer>(DstIOperand.Name);
+ const unsigned NumDefs = DstI->Operands.NumDefs;
+ if (NumDefs == 0)
+ return InsertPt;
+
+ DstMIBuilder.addRenderer<CopyRenderer>(DstI->Operands[0].Name);
+
+ // Some instructions have multiple defs, but are missing a type entry
+ // (e.g. s_cc_out operands).
+ if (Dst->getExtTypes().size() < NumDefs)
+ return failedImport("unhandled discarded def");
+
+ // Patterns only handle a single result, so any result after the first is an
+ // implicitly dead def.
+ for (unsigned I = 1; I < NumDefs; ++I) {
+ const TypeSetByHwMode &ExtTy = Dst->getExtType(I);
+ if (!ExtTy.isMachineValueType())
+ return failedImport("unsupported typeset");
+
+ auto OpTy = MVTToLLT(ExtTy.getMachineValueType().SimpleTy);
+ if (!OpTy)
+ return failedImport("unsupported type");
+
+ unsigned TempRegID = M.allocateTempRegID();
+ InsertPt =
+ M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
+ DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, true, nullptr, true);
}
+
+ return InsertPt;
}
Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
@@ -4392,6 +4690,8 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
// EXTRACT_SUBREG needs to use a subregister COPY.
if (Name == "EXTRACT_SUBREG") {
+ if (!Dst->getChild(1)->isLeaf())
+ return failedImport("EXTRACT_SUBREG child #1 is not a leaf");
DefInit *SubRegInit = dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue());
if (!SubRegInit)
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
@@ -4578,7 +4878,7 @@ Error GlobalISelEmitter::importDefaultOperandRenderers(
IDMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
} else {
- DstMIBuilder.addRenderer<AddRegisterRenderer>(Def);
+ DstMIBuilder.addRenderer<AddRegisterRenderer>(Target, Def);
}
continue;
}
@@ -4653,6 +4953,17 @@ GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) {
return None;
return getRegClassFromLeaf(RCChild);
}
+ if (InstName == "INSERT_SUBREG") {
+ TreePatternNode *Child0 = N->getChild(0);
+ assert(Child0->getNumTypes() == 1 && "Unexpected number of types!");
+ const TypeSetByHwMode &VTy = Child0->getExtType(0);
+ return inferSuperRegisterClassForNode(VTy, Child0, N->getChild(2));
+ }
+ if (InstName == "EXTRACT_SUBREG") {
+ assert(N->getNumTypes() == 1 && "Unexpected number of types!");
+ const TypeSetByHwMode &VTy = N->getExtType(0);
+ return inferSuperRegisterClass(VTy, N->getChild(1));
+ }
// Handle destination record types that we can safely infer a register class
// from.
@@ -4689,7 +5000,8 @@ GlobalISelEmitter::inferSuperRegisterClass(const TypeSetByHwMode &Ty,
// Use the information we found above to find a minimal register class which
// supports the subregister and type we want.
auto RC =
- Target.getSuperRegForSubReg(Ty.getValueTypeByHwMode(), CGRegs, SubIdx);
+ Target.getSuperRegForSubReg(Ty.getValueTypeByHwMode(), CGRegs, SubIdx,
+ /* MustBeAllocatable */ true);
if (!RC)
return None;
return *RC;
@@ -4777,9 +5089,9 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
if (Dst->isLeaf()) {
Record *RCDef = getInitValueAsRegClass(Dst->getLeafValue());
-
- const CodeGenRegisterClass &RC = Target.getRegisterClass(RCDef);
if (RCDef) {
+ const CodeGenRegisterClass &RC = Target.getRegisterClass(RCDef);
+
// We need to replace the def and all its uses with the specified
// operand. However, we must also insert COPY's wherever needed.
// For now, emit a copy and let the register allocator clean up.
@@ -4814,8 +5126,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
auto &DstI = Target.getInstruction(DstOp);
StringRef DstIName = DstI.TheDef->getName();
- if (DstI.Operands.NumDefs != Src->getExtTypes().size())
- return failedImport("Src pattern results and dst MI defs are different (" +
+ if (DstI.Operands.NumDefs < Src->getExtTypes().size())
+ return failedImport("Src pattern result has more defs than dst MI (" +
to_string(Src->getExtTypes().size()) + " def(s) vs " +
to_string(DstI.Operands.NumDefs) + " def(s))");
@@ -5035,7 +5347,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// trouble than it's worth.
void GlobalISelEmitter::emitCxxPredicateFns(
raw_ostream &OS, StringRef CodeFieldName, StringRef TypeIdentifier,
- StringRef ArgType, StringRef ArgName, StringRef AdditionalDeclarations,
+ StringRef ArgType, StringRef ArgName, StringRef AdditionalArgs,
+ StringRef AdditionalDeclarations,
std::function<bool(const Record *R)> Filter) {
std::vector<const Record *> MatchedRecords;
const auto &Defs = RK.getAllDerivedDefinitions("PatFrag");
@@ -5060,7 +5373,7 @@ void GlobalISelEmitter::emitCxxPredicateFns(
OS << "bool " << Target.getName() << "InstructionSelector::test" << ArgName
<< "Predicate_" << TypeIdentifier << "(unsigned PredicateID, " << ArgType << " "
- << ArgName << ") const {\n"
+ << ArgName << AdditionalArgs <<") const {\n"
<< AdditionalDeclarations;
if (!AdditionalDeclarations.empty())
OS << "\n";
@@ -5086,12 +5399,13 @@ 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);
+ "Imm", "", "", Filter);
}
void GlobalISelEmitter::emitMIPredicateFns(raw_ostream &OS) {
return emitCxxPredicateFns(
OS, "GISelPredicateCode", "MI", "const MachineInstr &", "MI",
+ ", const std::array<const MachineOperand *, 3> &Operands",
" const MachineFunction &MF = *MI.getParent()->getParent();\n"
" const MachineRegisterInfo &MRI = MF.getRegInfo();\n"
" (void)MRI;",
@@ -5117,8 +5431,7 @@ std::vector<Matcher *> GlobalISelEmitter::optimizeRules(
// 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);
+ append_range(OptRules, CurrentGroup->matchers());
else {
CurrentGroup->finalize();
OptRules.push_back(CurrentGroup.get());
@@ -5167,15 +5480,13 @@ GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules,
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());
- });
+ llvm::stable_sort(InputRules, [&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();
@@ -5308,7 +5619,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
<< " typedef void(" << Target.getName()
<< "InstructionSelector::*CustomRendererFn)(MachineInstrBuilder &, const "
- "MachineInstr&, int) "
+ "MachineInstr &, int) "
"const;\n"
<< " const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, "
"CustomRendererFn> "
@@ -5324,7 +5635,8 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
<< " 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) "
+ << " bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI"
+ ", const std::array<const MachineOperand *, 3> &Operands) "
"const override;\n"
<< "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n";
@@ -5360,7 +5672,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
OS << "void " << Target.getName() << "InstructionSelector"
"::setupGeneratedPerFunctionState(MachineFunction &MF) {\n"
" AvailableFunctionFeatures = computeAvailableFunctionFeatures("
- "(const " << Target.getName() << "Subtarget*)&MF.getSubtarget(), &MF);\n"
+ "(const " << Target.getName() << "Subtarget *)&MF.getSubtarget(), &MF);\n"
"}\n";
if (Target.getName() == "X86" || Target.getName() == "AArch64") {
@@ -5378,8 +5690,7 @@ 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 : KnownTypes)
- TypeObjects.push_back(Ty);
+ append_range(TypeObjects, KnownTypes);
llvm::sort(TypeObjects);
OS << "// LLT Objects.\n"
<< "enum {\n";
@@ -5481,7 +5792,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
<< "enum {\n"
<< " GICR_Invalid,\n";
for (const auto &Record : CustomRendererFns)
- OS << " GICR_" << Record->getValueAsString("RendererFn") << ", \n";
+ OS << " GICR_" << Record->getValueAsString("RendererFn") << ",\n";
OS << "};\n";
OS << Target.getName() << "InstructionSelector::CustomRendererFn\n"
@@ -5774,11 +6085,10 @@ void SwitchMatcher::finalize() {
if (empty())
return;
- std::stable_sort(Matchers.begin(), Matchers.end(),
- [](const Matcher *L, const Matcher *R) {
- return L->getFirstCondition().getValue() <
- R->getFirstCondition().getValue();
- });
+ llvm::stable_sort(Matchers, [](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();
diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp
index f3141735a995..9ff385faec56 100644
--- a/llvm/utils/TableGen/InstrInfoEmitter.cpp
+++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp
@@ -182,11 +182,10 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
if (Constraint.isNone())
Res += "0";
else if (Constraint.isEarlyClobber())
- Res += "(1 << MCOI::EARLY_CLOBBER)";
+ Res += "MCOI_EARLY_CLOBBER";
else {
assert(Constraint.isTied());
- Res += "((" + utostr(Constraint.getTiedOperand()) +
- " << 16) | (1 << MCOI::TIED_TO))";
+ Res += "MCOI_TIED_TO(" + utostr(Constraint.getTiedOperand()) + ")";
}
Result.push_back(Res);
@@ -280,7 +279,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,
for (const auto &Op : Operands)
OS << " " << Op.first << " = " << Op.second << ",\n";
- OS << "OPERAND_LAST";
+ OS << " OPERAND_LAST";
OS << "\n};\n";
OS << "} // end namespace OpName\n";
OS << "} // end namespace " << Namespace << "\n";
@@ -316,7 +315,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,
OS << " return OperandMap[" << TableIndex++ << "][NamedIdx];\n";
}
- OS << " default: return -1;\n";
+ OS << " default: return -1;\n";
OS << " }\n";
} else {
// There are no operands, so no need to emit anything
@@ -371,7 +370,7 @@ void InstrInfoEmitter::emitOperandTypeMappings(
OS << "namespace " << Namespace << " {\n";
OS << "LLVM_READONLY\n";
OS << "static int getOperandType(uint16_t Opcode, uint16_t OpIdx) {\n";
- // TODO: Factor out instructions with same operands to compress the tables.
+ // TODO: Factor out duplicate operand lists to compress the tables.
if (!NumberedInstructions.empty()) {
std::vector<int> OperandOffsets;
std::vector<Record *> OperandRecords;
@@ -385,7 +384,7 @@ void InstrInfoEmitter::emitOperandTypeMappings(
OperandRecords.push_back(Op.Rec);
++CurrentOffset;
} else {
- for (Init *Arg : make_range(MIOI->arg_begin(), MIOI->arg_end())) {
+ for (Init *Arg : MIOI->getArgs()) {
OperandRecords.push_back(cast<DefInit>(Arg)->getDef());
++CurrentOffset;
}
@@ -393,16 +392,26 @@ void InstrInfoEmitter::emitOperandTypeMappings(
}
}
- // Emit the table of offsets for the opcode lookup.
- OS << " const int Offsets[] = {\n";
+ // Emit the table of offsets (indexes) into the operand type table.
+ // Size the unsigned integer offset to save space.
+ assert(OperandRecords.size() <= UINT32_MAX &&
+ "Too many operands for offset table");
+ OS << ((OperandRecords.size() <= UINT16_MAX) ? " const uint16_t"
+ : " const uint32_t");
+ OS << " Offsets[] = {\n";
for (int I = 0, E = OperandOffsets.size(); I != E; ++I)
OS << " " << OperandOffsets[I] << ",\n";
OS << " };\n";
// Add an entry for the end so that we don't need to special case it below.
OperandOffsets.push_back(OperandRecords.size());
+
// Emit the actual operand types in a flat table.
- OS << " const int OpcodeOperandTypes[] = {\n ";
+ // Size the signed integer operand type to save space.
+ assert(EnumVal <= INT16_MAX &&
+ "Too many operand types for operand types table");
+ OS << ((EnumVal <= INT8_MAX) ? " const int8_t" : " const int16_t");
+ OS << " OpcodeOperandTypes[] = {\n ";
for (int I = 0, E = OperandRecords.size(), CurOffset = 1; I != E; ++I) {
// We print each Opcode's operands in its own row.
if (I == OperandOffsets[CurOffset]) {
@@ -532,6 +541,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
unsigned ListNumber = 0;
// Emit all of the instruction's implicit uses and defs.
+ Records.startTimer("Emit uses/defs");
for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
Record *Inst = II->TheDef;
std::vector<Record*> Uses = Inst->getValueAsListOfDefs("Uses");
@@ -549,10 +559,12 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OperandInfoMapTy OperandInfoIDs;
// Emit all of the operand info records.
+ Records.startTimer("Emit operand info");
EmitOperandInfo(OS, OperandInfoIDs);
// Emit all of the MCInstrDesc records in their ENUM ordering.
//
+ Records.startTimer("Emit InstrDesc records");
OS << "\nextern const MCInstrDesc " << TargetName << "Insts[] = {\n";
ArrayRef<const CodeGenInstruction*> NumberedInstructions =
Target.getInstructionsByEnumValue();
@@ -568,6 +580,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OS << "};\n\n";
// Emit the array of instruction names.
+ Records.startTimer("Emit instruction names");
InstrNames.layout();
InstrNames.emitStringLiteralDef(OS, Twine("extern const char ") + TargetName +
"InstrNameData[]");
@@ -628,6 +641,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
}
// MCInstrInfo initialization routine.
+ Records.startTimer("Emit initialization routine");
OS << "static inline void Init" << TargetName
<< "MCInstrInfo(MCInstrInfo *II) {\n";
OS << " II->InitMCInstrInfo(" << TargetName << "Insts, " << TargetName
@@ -706,10 +720,13 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n";
+ Records.startTimer("Emit operand name mappings");
emitOperandNameMappings(OS, Target, NumberedInstructions);
+ Records.startTimer("Emit operand type mappings");
emitOperandTypeMappings(OS, Target, NumberedInstructions);
+ Records.startTimer("Emit helper methods");
emitMCIIHelperMethods(OS, TargetName);
}
@@ -862,7 +879,9 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) {
namespace llvm {
void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS) {
+ RK.startTimer("Analyze DAG patterns");
InstrInfoEmitter(RK).run(OS);
+ RK.startTimer("Emit map table");
EmitMapTable(RK, OS);
}
diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp
index 7e4191494149..4be0d90a45d2 100644
--- a/llvm/utils/TableGen/IntrinsicEmitter.cpp
+++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp
@@ -246,13 +246,16 @@ enum IIT_Info {
IIT_SUBDIVIDE4_ARG = 45,
IIT_VEC_OF_BITCASTS_TO_INT = 46,
IIT_V128 = 47,
- IIT_BF16 = 48
+ IIT_BF16 = 48,
+ IIT_STRUCT9 = 49,
+ IIT_V256 = 50,
+ IIT_AMX = 51
};
static void EncodeFixedValueType(MVT::SimpleValueType VT,
std::vector<unsigned char> &Sig) {
if (MVT(VT).isInteger()) {
- unsigned BitWidth = MVT(VT).getSizeInBits();
+ unsigned BitWidth = MVT(VT).getFixedSizeInBits();
switch (BitWidth) {
default: PrintFatalError("unhandled integer type width in intrinsic!");
case 1: return Sig.push_back(IIT_I1);
@@ -274,6 +277,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT,
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);
+ case MVT::x86amx: return Sig.push_back(IIT_AMX);
// MVT::OtherVT is used to mean the empty struct type here.
case MVT::Other: return Sig.push_back(IIT_EMPTYSTRUCT);
// MVT::isVoid is used to represent varargs here.
@@ -384,6 +388,7 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
case 32: Sig.push_back(IIT_V32); break;
case 64: Sig.push_back(IIT_V64); break;
case 128: Sig.push_back(IIT_V128); break;
+ case 256: Sig.push_back(IIT_V256); break;
case 512: Sig.push_back(IIT_V512); break;
case 1024: Sig.push_back(IIT_V1024); break;
}
@@ -469,6 +474,7 @@ static void ComputeFixedEncoding(const CodeGenIntrinsic &Int,
case 6: TypeSig.push_back(IIT_STRUCT6); break;
case 7: TypeSig.push_back(IIT_STRUCT7); break;
case 8: TypeSig.push_back(IIT_STRUCT8); break;
+ case 9: TypeSig.push_back(IIT_STRUCT9); break;
default: llvm_unreachable("Unhandled case in struct");
}
@@ -687,6 +693,12 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
OS << "Attribute::NoAlias";
addComma = true;
break;
+ case CodeGenIntrinsic::NoUndef:
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::NoUndef";
+ addComma = true;
+ break;
case CodeGenIntrinsic::Returned:
if (addComma)
OS << ",";
diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp
index 251533a8d154..8e6c05885e5b 100644
--- a/llvm/utils/TableGen/OptParserEmitter.cpp
+++ b/llvm/utils/TableGen/OptParserEmitter.cpp
@@ -20,7 +20,7 @@
using namespace llvm;
-static const std::string getOptionName(const Record &R) {
+static std::string getOptionName(const Record &R) {
// Use the record name unless EnumName is defined.
if (isa<UnsetInit>(R.getValueInit("EnumName")))
return std::string(R.getName());
@@ -35,19 +35,20 @@ static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
return OS;
}
-static const std::string getOptionSpelling(const Record &R,
- size_t &PrefixLength) {
+static std::string getOptionSpelling(const Record &R, size_t &PrefixLength) {
std::vector<StringRef> Prefixes = R.getValueAsListOfStrings("Prefixes");
StringRef Name = R.getValueAsString("Name");
+
if (Prefixes.empty()) {
PrefixLength = 0;
return Name.str();
}
+
PrefixLength = Prefixes[0].size();
return (Twine(Prefixes[0]) + Twine(Name)).str();
}
-static const std::string getOptionSpelling(const Record &R) {
+static std::string getOptionSpelling(const Record &R) {
size_t PrefixLength;
return getOptionSpelling(R, PrefixLength);
}
@@ -59,75 +60,29 @@ static void emitNameUsingSpelling(raw_ostream &OS, const Record &R) {
OS << "[" << PrefixLength << "]";
}
-class MarshallingKindInfo {
+class MarshallingInfo {
public:
+ static constexpr const char *MacroName = "OPTION_WITH_MARSHALLING";
const Record &R;
- const char *MacroName;
bool ShouldAlwaysEmit;
+ StringRef MacroPrefix;
StringRef KeyPath;
StringRef DefaultValue;
StringRef NormalizedValuesScope;
-
- void emit(raw_ostream &OS) const {
- write_cstring(OS, StringRef(getOptionSpelling(R)));
- OS << ", ";
- OS << ShouldAlwaysEmit;
- OS << ", ";
- OS << KeyPath;
- OS << ", ";
- emitScopedNormalizedValue(OS, DefaultValue);
- OS << ", ";
- emitSpecific(OS);
- }
-
- virtual Optional<StringRef> emitValueTable(raw_ostream &OS) const {
- return None;
- }
-
- virtual ~MarshallingKindInfo() = default;
-
- static std::unique_ptr<MarshallingKindInfo> create(const Record &R);
-
-protected:
- void emitScopedNormalizedValue(raw_ostream &OS,
- StringRef NormalizedValue) const {
- if (!NormalizedValuesScope.empty())
- OS << NormalizedValuesScope << "::";
- OS << NormalizedValue;
- }
-
- virtual void emitSpecific(raw_ostream &OS) const = 0;
- MarshallingKindInfo(const Record &R, const char *MacroName)
- : R(R), MacroName(MacroName) {}
-};
-
-class MarshallingFlagInfo final : public MarshallingKindInfo {
-public:
- bool IsPositive;
-
- void emitSpecific(raw_ostream &OS) const override { OS << IsPositive; }
-
- static std::unique_ptr<MarshallingKindInfo> create(const Record &R) {
- std::unique_ptr<MarshallingFlagInfo> Ret(new MarshallingFlagInfo(R));
- Ret->IsPositive = R.getValueAsBit("IsPositive");
- return Ret;
- }
-
-private:
- MarshallingFlagInfo(const Record &R)
- : MarshallingKindInfo(R, "OPTION_WITH_MARSHALLING_FLAG") {}
-};
-
-class MarshallingStringInfo final : public MarshallingKindInfo {
-public:
- StringRef NormalizerRetTy;
+ StringRef ImpliedCheck;
+ StringRef ImpliedValue;
+ StringRef ShouldParse;
StringRef Normalizer;
StringRef Denormalizer;
+ StringRef ValueMerger;
+ StringRef ValueExtractor;
int TableIndex = -1;
std::vector<StringRef> Values;
std::vector<StringRef> NormalizedValues;
std::string ValueTableName;
+ static size_t NextTableIndex;
+
static constexpr const char *ValueTablePreamble = R"(
struct SimpleEnumValue {
const char *Name;
@@ -143,17 +98,39 @@ struct SimpleEnumValueTable {
static constexpr const char *ValueTablesDecl =
"static const SimpleEnumValueTable SimpleEnumValueTables[] = ";
- void emitSpecific(raw_ostream &OS) const override {
- emitScopedNormalizedValue(OS, NormalizerRetTy);
+ MarshallingInfo(const Record &R) : R(R) {}
+
+ std::string getMacroName() const {
+ return (MacroPrefix + MarshallingInfo::MacroName).str();
+ }
+
+ void emit(raw_ostream &OS) const {
+ write_cstring(OS, StringRef(getOptionSpelling(R)));
+ OS << ", ";
+ OS << ShouldParse;
+ OS << ", ";
+ OS << ShouldAlwaysEmit;
+ OS << ", ";
+ OS << KeyPath;
+ OS << ", ";
+ emitScopedNormalizedValue(OS, DefaultValue);
+ OS << ", ";
+ OS << ImpliedCheck;
+ OS << ", ";
+ emitScopedNormalizedValue(OS, ImpliedValue);
OS << ", ";
OS << Normalizer;
OS << ", ";
OS << Denormalizer;
OS << ", ";
+ OS << ValueMerger;
+ OS << ", ";
+ OS << ValueExtractor;
+ OS << ", ";
OS << TableIndex;
}
- Optional<StringRef> emitValueTable(raw_ostream &OS) const override {
+ Optional<StringRef> emitValueTable(raw_ostream &OS) const {
if (TableIndex == -1)
return {};
OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n";
@@ -169,73 +146,66 @@ struct SimpleEnumValueTable {
return StringRef(ValueTableName);
}
- static std::unique_ptr<MarshallingKindInfo> create(const Record &R) {
- assert(!isa<UnsetInit>(R.getValueInit("NormalizerRetTy")) &&
- "String options must have a type");
-
- std::unique_ptr<MarshallingStringInfo> Ret(new MarshallingStringInfo(R));
- Ret->NormalizerRetTy = R.getValueAsString("NormalizerRetTy");
-
- Ret->Normalizer = R.getValueAsString("Normalizer");
- Ret->Denormalizer = R.getValueAsString("Denormalizer");
-
- if (!isa<UnsetInit>(R.getValueInit("NormalizedValues"))) {
- assert(!isa<UnsetInit>(R.getValueInit("Values")) &&
- "Cannot provide normalized values for value-less options");
- Ret->TableIndex = NextTableIndex++;
- Ret->NormalizedValues = R.getValueAsListOfStrings("NormalizedValues");
- Ret->Values.reserve(Ret->NormalizedValues.size());
- Ret->ValueTableName = getOptionName(R) + "ValueTable";
-
- StringRef ValuesStr = R.getValueAsString("Values");
- for (;;) {
- size_t Idx = ValuesStr.find(',');
- if (Idx == StringRef::npos)
- break;
- if (Idx > 0)
- Ret->Values.push_back(ValuesStr.slice(0, Idx));
- ValuesStr = ValuesStr.slice(Idx + 1, StringRef::npos);
- }
- if (!ValuesStr.empty())
- Ret->Values.push_back(ValuesStr);
-
- assert(Ret->Values.size() == Ret->NormalizedValues.size() &&
- "The number of normalized values doesn't match the number of "
- "values");
- }
-
- return Ret;
- }
-
private:
- MarshallingStringInfo(const Record &R)
- : MarshallingKindInfo(R, "OPTION_WITH_MARSHALLING_STRING") {}
-
- static size_t NextTableIndex;
+ void emitScopedNormalizedValue(raw_ostream &OS,
+ StringRef NormalizedValue) const {
+ if (!NormalizedValuesScope.empty())
+ OS << NormalizedValuesScope << "::";
+ OS << NormalizedValue;
+ }
};
-size_t MarshallingStringInfo::NextTableIndex = 0;
+size_t MarshallingInfo::NextTableIndex = 0;
-std::unique_ptr<MarshallingKindInfo>
-MarshallingKindInfo::create(const Record &R) {
+static MarshallingInfo createMarshallingInfo(const Record &R) {
assert(!isa<UnsetInit>(R.getValueInit("KeyPath")) &&
!isa<UnsetInit>(R.getValueInit("DefaultValue")) &&
- "Must provide at least a key-path and a default value for emitting "
- "marshalling information");
-
- std::unique_ptr<MarshallingKindInfo> Ret = nullptr;
- StringRef MarshallingKindStr = R.getValueAsString("MarshallingKind");
-
- if (MarshallingKindStr == "flag")
- Ret = MarshallingFlagInfo::create(R);
- else if (MarshallingKindStr == "string")
- Ret = MarshallingStringInfo::create(R);
-
- Ret->ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit");
- Ret->KeyPath = R.getValueAsString("KeyPath");
- Ret->DefaultValue = R.getValueAsString("DefaultValue");
- if (!isa<UnsetInit>(R.getValueInit("NormalizedValuesScope")))
- Ret->NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope");
+ !isa<UnsetInit>(R.getValueInit("ValueMerger")) &&
+ "MarshallingInfo must have a provide a keypath, default value and a "
+ "value merger");
+
+ MarshallingInfo Ret(R);
+
+ Ret.ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit");
+ Ret.MacroPrefix = R.getValueAsString("MacroPrefix");
+ Ret.KeyPath = R.getValueAsString("KeyPath");
+ Ret.DefaultValue = R.getValueAsString("DefaultValue");
+ Ret.NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope");
+ Ret.ImpliedCheck = R.getValueAsString("ImpliedCheck");
+ Ret.ImpliedValue =
+ R.getValueAsOptionalString("ImpliedValue").getValueOr(Ret.DefaultValue);
+
+ Ret.ShouldParse = R.getValueAsString("ShouldParse");
+ Ret.Normalizer = R.getValueAsString("Normalizer");
+ Ret.Denormalizer = R.getValueAsString("Denormalizer");
+ Ret.ValueMerger = R.getValueAsString("ValueMerger");
+ Ret.ValueExtractor = R.getValueAsString("ValueExtractor");
+
+ if (!isa<UnsetInit>(R.getValueInit("NormalizedValues"))) {
+ assert(!isa<UnsetInit>(R.getValueInit("Values")) &&
+ "Cannot provide normalized values for value-less options");
+ Ret.TableIndex = MarshallingInfo::NextTableIndex++;
+ Ret.NormalizedValues = R.getValueAsListOfStrings("NormalizedValues");
+ Ret.Values.reserve(Ret.NormalizedValues.size());
+ Ret.ValueTableName = getOptionName(R) + "ValueTable";
+
+ StringRef ValuesStr = R.getValueAsString("Values");
+ for (;;) {
+ size_t Idx = ValuesStr.find(',');
+ if (Idx == StringRef::npos)
+ break;
+ if (Idx > 0)
+ Ret.Values.push_back(ValuesStr.slice(0, Idx));
+ ValuesStr = ValuesStr.slice(Idx + 1, StringRef::npos);
+ }
+ if (!ValuesStr.empty())
+ Ret.Values.push_back(ValuesStr);
+
+ assert(Ret.Values.size() == Ret.NormalizedValues.size() &&
+ "The number of normalized values doesn't match the number of "
+ "values");
+ }
+
return Ret;
}
@@ -258,13 +228,12 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
PrefixesT Prefixes;
Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0"));
unsigned CurPrefix = 0;
- for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
- const Record &R = *Opts[i];
- std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes");
- PrefixKeyT prfkey(prf.begin(), prf.end());
+ for (const Record &R : llvm::make_pointee_range(Opts)) {
+ std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");
+ PrefixKeyT PrefixKey(RPrefixes.begin(), RPrefixes.end());
unsigned NewPrefix = CurPrefix + 1;
- if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") +
- Twine(NewPrefix)).str())).second)
+ std::string Prefix = (Twine("prefix_") + Twine(NewPrefix)).str();
+ if (Prefixes.insert(std::make_pair(PrefixKey, Prefix)).second)
CurPrefix = NewPrefix;
}
@@ -274,19 +243,16 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << "// Prefixes\n\n";
OS << "#ifdef PREFIX\n";
OS << "#define COMMA ,\n";
- for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end();
- I != E; ++I) {
+ for (const auto &Prefix : Prefixes) {
OS << "PREFIX(";
// Prefix name.
- OS << I->second;
+ OS << Prefix.second;
// Prefix values.
OS << ", {";
- for (PrefixKeyT::const_iterator PI = I->first.begin(),
- PE = I->first.end(); PI != PE; ++PI) {
- OS << "\"" << *PI << "\" COMMA ";
- }
+ for (StringRef PrefixKey : Prefix.first)
+ OS << "\"" << PrefixKey << "\" COMMA ";
OS << "nullptr})\n";
}
OS << "#undef COMMA\n";
@@ -295,9 +261,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << "/////////\n";
OS << "// Groups\n\n";
OS << "#ifdef OPTION\n";
- for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
- const Record &R = *Groups[i];
-
+ for (const Record &R : llvm::make_pointee_range(Groups)) {
// Start a single option entry.
OS << "OPTION(";
@@ -344,8 +308,8 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
auto WriteOptRecordFields = [&](raw_ostream &OS, const Record &R) {
// The option prefix;
- std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes");
- OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", ";
+ std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");
+ OS << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())] << ", ";
// The option string.
emitNameUsingSpelling(OS, R);
@@ -382,8 +346,8 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << "nullptr";
} else {
OS << "\"";
- for (size_t i = 0, e = AliasArgs.size(); i != e; ++i)
- OS << AliasArgs[i] << "\\0";
+ for (StringRef AliasArg : AliasArgs)
+ OS << AliasArg << "\\0";
OS << "\"";
}
@@ -427,39 +391,63 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << "nullptr";
};
- std::vector<std::unique_ptr<MarshallingKindInfo>> OptsWithMarshalling;
- for (unsigned I = 0, E = Opts.size(); I != E; ++I) {
- const Record &R = *Opts[I];
+ auto IsMarshallingOption = [](const Record &R) {
+ return !isa<UnsetInit>(R.getValueInit("KeyPath")) &&
+ !R.getValueAsString("KeyPath").empty();
+ };
+ std::vector<const Record *> OptsWithMarshalling;
+ for (const Record &R : llvm::make_pointee_range(Opts)) {
// Start a single option entry.
OS << "OPTION(";
WriteOptRecordFields(OS, R);
OS << ")\n";
- if (!isa<UnsetInit>(R.getValueInit("MarshallingKind")))
- OptsWithMarshalling.push_back(MarshallingKindInfo::create(R));
+ if (IsMarshallingOption(R))
+ OptsWithMarshalling.push_back(&R);
}
OS << "#endif // OPTION\n";
- for (const auto &KindInfo : OptsWithMarshalling) {
- OS << "#ifdef " << KindInfo->MacroName << "\n";
- OS << KindInfo->MacroName << "(";
- WriteOptRecordFields(OS, KindInfo->R);
+ auto CmpMarshallingOpts = [](const Record *const *A, const Record *const *B) {
+ unsigned AID = (*A)->getID();
+ unsigned BID = (*B)->getID();
+
+ if (AID < BID)
+ return -1;
+ if (AID > BID)
+ return 1;
+ return 0;
+ };
+ // The RecordKeeper stores records (options) in lexicographical order, and we
+ // have reordered the options again when generating prefix groups. We need to
+ // restore the original definition order of options with marshalling to honor
+ // the topology of the dependency graph implied by `DefaultAnyOf`.
+ array_pod_sort(OptsWithMarshalling.begin(), OptsWithMarshalling.end(),
+ CmpMarshallingOpts);
+
+ std::vector<MarshallingInfo> MarshallingInfos;
+ for (const auto *R : OptsWithMarshalling)
+ MarshallingInfos.push_back(createMarshallingInfo(*R));
+
+ for (const auto &MI : MarshallingInfos) {
+ OS << "#ifdef " << MI.getMacroName() << "\n";
+ OS << MI.getMacroName() << "(";
+ WriteOptRecordFields(OS, MI.R);
OS << ", ";
- KindInfo->emit(OS);
+ MI.emit(OS);
OS << ")\n";
- OS << "#endif // " << KindInfo->MacroName << "\n";
+ OS << "#endif // " << MI.getMacroName() << "\n";
}
OS << "\n";
OS << "#ifdef SIMPLE_ENUM_VALUE_TABLE";
OS << "\n";
- OS << MarshallingStringInfo::ValueTablePreamble;
+ OS << MarshallingInfo::ValueTablePreamble;
std::vector<StringRef> ValueTableNames;
- for (const auto &KindInfo : OptsWithMarshalling)
- if (auto MaybeValueTableName = KindInfo->emitValueTable(OS))
+ for (const auto &MI : MarshallingInfos)
+ if (auto MaybeValueTableName = MI.emitValueTable(OS))
ValueTableNames.push_back(*MaybeValueTableName);
- OS << MarshallingStringInfo::ValueTablesDecl << "{";
+ OS << MarshallingInfo::ValueTablesDecl << "{";
for (auto ValueTableName : ValueTableNames)
OS << "{" << ValueTableName << ", sizeof(" << ValueTableName
<< ") / sizeof(SimpleEnumValue)"
@@ -475,8 +463,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << "#ifdef OPTTABLE_ARG_INIT\n";
OS << "//////////\n";
OS << "// Option Values\n\n";
- for (unsigned I = 0, E = Opts.size(); I != E; ++I) {
- const Record &R = *Opts[I];
+ for (const Record &R : llvm::make_pointee_range(Opts)) {
if (isa<UnsetInit>(R.getValueInit("ValuesCode")))
continue;
OS << "{\n";
diff --git a/llvm/utils/TableGen/PredicateExpander.cpp b/llvm/utils/TableGen/PredicateExpander.cpp
index 9f7f40db2626..a76640f6d11f 100644
--- a/llvm/utils/TableGen/PredicateExpander.cpp
+++ b/llvm/utils/TableGen/PredicateExpander.cpp
@@ -198,6 +198,18 @@ void PredicateExpander::expandCheckIsImmOperand(raw_ostream &OS, int OpIndex) {
<< "getOperand(" << OpIndex << ").isImm() ";
}
+void PredicateExpander::expandCheckFunctionPredicateWithTII(
+ raw_ostream &OS, StringRef MCInstFn, StringRef MachineInstrFn,
+ StringRef TIIPtr) {
+ if (!shouldExpandForMC()) {
+ OS << (TIIPtr.empty() ? "TII" : TIIPtr) << "->" << MachineInstrFn;
+ OS << (isByRef() ? "(MI)" : "(*MI)");
+ return;
+ }
+
+ OS << MCInstFn << (isByRef() ? "(MI" : "(*MI") << ", MCII)";
+}
+
void PredicateExpander::expandCheckFunctionPredicate(raw_ostream &OS,
StringRef MCInstFn,
StringRef MachineInstrFn) {
@@ -358,10 +370,18 @@ void PredicateExpander::expandPredicate(raw_ostream &OS, const Record *Rec) {
return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"),
/* AllOf */ false);
- if (Rec->isSubClassOf("CheckFunctionPredicate"))
+ if (Rec->isSubClassOf("CheckFunctionPredicate")) {
return expandCheckFunctionPredicate(
OS, Rec->getValueAsString("MCInstFnName"),
Rec->getValueAsString("MachineInstrFnName"));
+ }
+
+ if (Rec->isSubClassOf("CheckFunctionPredicateWithTII")) {
+ return expandCheckFunctionPredicateWithTII(
+ OS, Rec->getValueAsString("MCInstFnName"),
+ Rec->getValueAsString("MachineInstrFnName"),
+ Rec->getValueAsString("TIIPtrName"));
+ }
if (Rec->isSubClassOf("CheckNonPortable"))
return expandCheckNonPortable(OS, Rec->getValueAsString("CodeBlock"));
diff --git a/llvm/utils/TableGen/PredicateExpander.h b/llvm/utils/TableGen/PredicateExpander.h
index 115a81cf123b..29cca92d902c 100644
--- a/llvm/utils/TableGen/PredicateExpander.h
+++ b/llvm/utils/TableGen/PredicateExpander.h
@@ -79,6 +79,9 @@ public:
void expandCheckInvalidRegOperand(raw_ostream &OS, int OpIndex);
void expandCheckFunctionPredicate(raw_ostream &OS, StringRef MCInstFn,
StringRef MachineInstrFn);
+ void expandCheckFunctionPredicateWithTII(raw_ostream &OS, StringRef MCInstFn,
+ StringRef MachineInstrFn,
+ StringRef TIIPtr);
void expandCheckNonPortable(raw_ostream &OS, StringRef CodeBlock);
void expandPredicate(raw_ostream &OS, const Record *Rec);
void expandReturnStatement(raw_ostream &OS, const Record *Rec);
diff --git a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp
index 3a80d8e5d1c4..e05409db67d0 100644
--- a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp
+++ b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp
@@ -89,11 +89,15 @@ addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn,
// problem.
// FIXME: We probably shouldn't ever get a non-zero BaseIdx here.
assert(BaseIdx == 0 && "Named subargument in pseudo expansion?!");
- if (DI->getDef() != Insn.Operands[BaseIdx + i].Rec)
- PrintFatalError(Rec->getLoc(),
- "Pseudo operand type '" + DI->getDef()->getName() +
- "' does not match expansion operand type '" +
- Insn.Operands[BaseIdx + i].Rec->getName() + "'");
+ // FIXME: Are the message operand types backward?
+ if (DI->getDef() != Insn.Operands[BaseIdx + i].Rec) {
+ PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
+ "', operand type '" + DI->getDef()->getName() +
+ "' does not match expansion operand type '" +
+ Insn.Operands[BaseIdx + i].Rec->getName() + "'");
+ PrintFatalNote(DI->getDef(),
+ "Value was assigned at the following location:");
+ }
// Source operand maps to destination operand. The Data element
// will be filled in later, just set the Kind for now. Do it
// for each corresponding MachineInstr operand, not just the first.
@@ -128,23 +132,38 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) {
LLVM_DEBUG(dbgs() << " Result: " << *Dag << "\n");
DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator());
- if (!OpDef)
- PrintFatalError(Rec->getLoc(), Rec->getName() +
- " has unexpected operator type!");
+ if (!OpDef) {
+ PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
+ "', result operator is not a record");
+ PrintFatalNote(Rec->getValue("ResultInst"),
+ "Result was assigned at the following location:");
+ }
Record *Operator = OpDef->getDef();
- if (!Operator->isSubClassOf("Instruction"))
- PrintFatalError(Rec->getLoc(), "Pseudo result '" + Operator->getName() +
- "' is not an instruction!");
+ if (!Operator->isSubClassOf("Instruction")) {
+ PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
+ "', result operator '" + Operator->getName() +
+ "' is not an instruction");
+ PrintFatalNote(Rec->getValue("ResultInst"),
+ "Result was assigned at the following location:");
+ }
CodeGenInstruction Insn(Operator);
- if (Insn.isCodeGenOnly || Insn.isPseudo)
- PrintFatalError(Rec->getLoc(), "Pseudo result '" + Operator->getName() +
- "' cannot be another pseudo instruction!");
+ if (Insn.isCodeGenOnly || Insn.isPseudo) {
+ PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
+ "', result operator '" + Operator->getName() +
+ "' cannot be a pseudo instruction");
+ PrintFatalNote(Rec->getValue("ResultInst"),
+ "Result was assigned at the following location:");
+ }
- if (Insn.Operands.size() != Dag->getNumArgs())
- PrintFatalError(Rec->getLoc(), "Pseudo result '" + Operator->getName() +
- "' operand count mismatch");
+ if (Insn.Operands.size() != Dag->getNumArgs()) {
+ PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
+ "', result operator '" + Operator->getName() +
+ "' has the wrong number of operands");
+ PrintFatalNote(Rec->getValue("ResultInst"),
+ "Result was assigned at the following location:");
+ }
unsigned NumMIOperands = 0;
for (unsigned i = 0, e = Insn.Operands.size(); i != e; ++i)
@@ -177,10 +196,13 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) {
continue;
StringMap<unsigned>::iterator SourceOp =
SourceOperands.find(Dag->getArgNameStr(i));
- if (SourceOp == SourceOperands.end())
- PrintFatalError(Rec->getLoc(),
- "Pseudo output operand '" + Dag->getArgNameStr(i) +
- "' has no matching source operand.");
+ if (SourceOp == SourceOperands.end()) {
+ PrintError(Rec, "In pseudo instruction '" + Rec->getName() +
+ "', output operand '" + Dag->getArgNameStr(i) +
+ "' has no matching source operand");
+ PrintFatalNote(Rec->getValue("ResultInst"),
+ "Value was assigned at the following location:");
+ }
// Map the source operand to the destination operand index for each
// MachineInstr operand.
for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I)
@@ -204,15 +226,15 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
if (!Expansions.empty()) {
o << " switch (MI->getOpcode()) {\n"
- << " default: return false;\n";
+ << " default: return false;\n";
for (auto &Expansion : Expansions) {
CodeGenInstruction &Source = Expansion.Source;
CodeGenInstruction &Dest = Expansion.Dest;
- o << " case " << Source.Namespace << "::"
+ o << " case " << Source.Namespace << "::"
<< Source.TheDef->getName() << ": {\n"
- << " MCInst TmpInst;\n"
- << " MCOperand MCOp;\n"
- << " TmpInst.setOpcode(" << Dest.Namespace << "::"
+ << " MCInst TmpInst;\n"
+ << " MCOperand MCOp;\n"
+ << " TmpInst.setOpcode(" << Dest.Namespace << "::"
<< Dest.TheDef->getName() << ");\n";
// Copy the operands from the source instruction.
@@ -221,23 +243,23 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
// expansion DAG.
unsigned MIOpNo = 0;
for (const auto &DestOperand : Dest.Operands) {
- o << " // Operand: " << DestOperand.Name << "\n";
+ o << " // Operand: " << DestOperand.Name << "\n";
for (unsigned i = 0, e = DestOperand.MINumOperands; i != e; ++i) {
switch (Expansion.OperandMap[MIOpNo + i].Kind) {
case OpData::Operand:
- o << " lowerOperand(MI->getOperand("
+ o << " lowerOperand(MI->getOperand("
<< Source.Operands[Expansion.OperandMap[MIOpNo].Data
.Operand].MIOperandNo + i
<< "), MCOp);\n"
- << " TmpInst.addOperand(MCOp);\n";
+ << " TmpInst.addOperand(MCOp);\n";
break;
case OpData::Imm:
- o << " TmpInst.addOperand(MCOperand::createImm("
+ o << " TmpInst.addOperand(MCOperand::createImm("
<< Expansion.OperandMap[MIOpNo + i].Data.Imm << "));\n";
break;
case OpData::Reg: {
Record *Reg = Expansion.OperandMap[MIOpNo + i].Data.Reg;
- o << " TmpInst.addOperand(MCOperand::createReg(";
+ o << " TmpInst.addOperand(MCOperand::createReg(";
// "zero_reg" is special.
if (Reg->getName() == "zero_reg")
o << "0";
@@ -253,15 +275,15 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
}
if (Dest.Operands.isVariadic) {
MIOpNo = Source.Operands.size() + 1;
- o << " // variable_ops\n";
- o << " for (unsigned i = " << MIOpNo
+ o << " // variable_ops\n";
+ o << " for (unsigned i = " << MIOpNo
<< ", e = MI->getNumOperands(); i != e; ++i)\n"
- << " if (lowerOperand(MI->getOperand(i), MCOp))\n"
- << " TmpInst.addOperand(MCOp);\n";
+ << " if (lowerOperand(MI->getOperand(i), MCOp))\n"
+ << " TmpInst.addOperand(MCOp);\n";
}
- o << " EmitToStreamer(OutStreamer, TmpInst);\n"
- << " break;\n"
- << " }\n";
+ o << " EmitToStreamer(OutStreamer, TmpInst);\n"
+ << " break;\n"
+ << " }\n";
}
o << " }\n return true;";
} else
@@ -271,24 +293,18 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
}
void PseudoLoweringEmitter::run(raw_ostream &o) {
- Record *ExpansionClass = Records.getClass("PseudoInstExpansion");
- Record *InstructionClass = Records.getClass("Instruction");
- assert(ExpansionClass && "PseudoInstExpansion class definition missing!");
- assert(InstructionClass && "Instruction class definition missing!");
-
- std::vector<Record*> Insts;
- for (const auto &D : Records.getDefs()) {
- if (D.second->isSubClassOf(ExpansionClass) &&
- D.second->isSubClassOf(InstructionClass))
- Insts.push_back(D.second.get());
- }
+ StringRef Classes[] = {"PseudoInstExpansion", "Instruction"};
+ std::vector<Record *> Insts =
+ Records.getAllDerivedDefinitions(makeArrayRef(Classes));
// Process the pseudo expansion definitions, validating them as we do so.
+ Records.startTimer("Process definitions");
for (unsigned i = 0, e = Insts.size(); i != e; ++i)
evaluateExpansion(Insts[i]);
// Generate expansion code to lower the pseudo to an MCInst of the real
// instruction.
+ Records.startTimer("Emit expansion code");
emitLoweringEmitter(o);
}
diff --git a/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp b/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp
index f298e639bf7f..183c8f9494db 100644
--- a/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp
+++ b/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp
@@ -37,11 +37,11 @@
// compressing/uncompressing MCInst instructions, plus
// some helper functions:
//
-// bool compressInst(MCInst& OutInst, const MCInst &MI,
+// bool compressInst(MCInst &OutInst, const MCInst &MI,
// const MCSubtargetInfo &STI,
// MCContext &Context);
//
-// bool uncompressInst(MCInst& OutInst, const MCInst &MI,
+// bool uncompressInst(MCInst &OutInst, const MCInst &MI,
// const MCRegisterInfo &MRI,
// const MCSubtargetInfo &STI);
//
@@ -101,11 +101,12 @@ class RISCVCompressInstEmitter {
IndexedMap<OpData>
DestOperandMap; // Maps operands in the Dest Instruction
// to the corresponding Source instruction operand.
+ bool IsCompressOnly;
CompressPat(CodeGenInstruction &S, CodeGenInstruction &D,
std::vector<Record *> RF, IndexedMap<OpData> &SourceMap,
- IndexedMap<OpData> &DestMap)
+ IndexedMap<OpData> &DestMap, bool IsCompressOnly)
: Source(S), Dest(D), PatReqFeatures(RF), SourceOperandMap(SourceMap),
- DestOperandMap(DestMap) {}
+ DestOperandMap(DestMap), IsCompressOnly(IsCompressOnly) {}
};
enum EmitterType { Compress, Uncompress, CheckCompress };
RecordKeeper &Records;
@@ -138,13 +139,12 @@ public:
} // 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");
+ assert(Reg->isSubClassOf("Register") && "Reg record should be a Register");
+ assert(RegClass->isSubClassOf("RegisterClass") &&
+ "RegClass record should be a RegisterClass");
const 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());
+ assert((R != nullptr) && "Register not defined!!");
return RC.contains(R);
}
@@ -237,9 +237,9 @@ void RISCVCompressInstEmitter::addDagOperandMapping(
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!"));
+ "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();
@@ -285,11 +285,7 @@ static bool verifyDagOpCount(CodeGenInstruction &Inst, DagInit *Dag,
}
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();
+ return cast<DefInit>(Arg1)->getDef() == cast<DefInit>(Arg2)->getDef();
}
// Creates a mapping between the operand name in the Dag (e.g. $rs1) and
@@ -471,7 +467,8 @@ void RISCVCompressInstEmitter::evaluateCompressPat(Record *Rec) {
});
CompressPatterns.push_back(CompressPat(SourceInst, DestInst, PatReqFeatures,
- SourceOperandMap, DestOperandMap));
+ SourceOperandMap, DestOperandMap,
+ Rec->getValueAsBit("isCompressOnly")));
}
static void
@@ -514,50 +511,41 @@ getReqFeatures(std::set<std::pair<bool, StringRef>> &FeaturesSet,
static unsigned getPredicates(DenseMap<const Record *, unsigned> &PredicateMap,
std::vector<const Record *> &Predicates,
Record *Rec, StringRef Name) {
- unsigned Entry = PredicateMap[Rec];
+ unsigned &Entry = PredicateMap[Rec];
if (Entry)
return Entry;
if (!Rec->isValueUnset(Name)) {
Predicates.push_back(Rec);
Entry = Predicates.size();
- PredicateMap[Rec] = Entry;
return Entry;
}
PrintFatalError(Rec->getLoc(), "No " + Name +
- " predicate on this operand at all: '" + Rec->getName().str() + "'");
+ " predicate on this operand at all: '" +
+ Rec->getName() + "'");
return 0;
}
-static void printPredicates(std::vector<const Record *> &Predicates,
+static void printPredicates(const std::vector<const Record *> &Predicates,
StringRef Name, raw_ostream &o) {
for (unsigned i = 0; i < Predicates.size(); ++i) {
- Init *Pred = Predicates[i]->getValueInit(Name);
- if (CodeInit *SI = dyn_cast<CodeInit>(Pred))
- o << " case " << i + 1 << ": {\n"
- << " // " << Predicates[i]->getName().str() << "\n"
- << " " << SI->getValue() << "\n"
- << " }\n";
- else
- llvm_unreachable("Unexpected predicate field!");
+ StringRef Pred = Predicates[i]->getValueAsString(Name);
+ o << " case " << i + 1 << ": {\n"
+ << " // " << Predicates[i]->getName() << "\n"
+ << " " << Pred << "\n"
+ << " }\n";
}
}
-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();
+static void mergeCondAndCode(raw_ostream &CombinedStream, StringRef CondStr,
+ StringRef CodeStr) {
+ // Remove first indentation and last '&&'.
+ CondStr = CondStr.drop_front(6).drop_back(4);
+ CombinedStream.indent(4) << "if (" << CondStr << ") {\n";
+ CombinedStream << CodeStr;
CombinedStream.indent(4) << " return true;\n";
CombinedStream.indent(4) << "} // if\n";
- return CombinedStream.str();
}
void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
@@ -568,23 +556,20 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
"'PassSubtarget' is false. SubTargetInfo object is needed "
"for target features.\n");
- std::string Namespace = std::string(Target.getName());
+ StringRef 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.
- llvm::stable_sort(CompressPatterns,
- [EType](const CompressPat &LHS, const CompressPat &RHS) {
- if (EType == EmitterType::Compress ||
- EType == EmitterType::CheckCompress)
- return (LHS.Source.TheDef->getName().str() <
- RHS.Source.TheDef->getName().str());
- else
- return (LHS.Dest.TheDef->getName().str() <
- RHS.Dest.TheDef->getName().str());
- });
+ llvm::stable_sort(CompressPatterns, [EType](const CompressPat &LHS,
+ const CompressPat &RHS) {
+ if (EType == EmitterType::Compress || EType == EmitterType::CheckCompress)
+ return (LHS.Source.TheDef->getName() < RHS.Source.TheDef->getName());
+ else
+ return (LHS.Dest.TheDef->getName() < RHS.Dest.TheDef->getName());
+ });
// A list of MCOperandPredicates for all operands in use, and the reverse map.
std::vector<const Record *> MCOpPredicates;
@@ -610,17 +595,17 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
<< "#undef GEN_CHECK_COMPRESS_INSTR\n\n";
if (EType == EmitterType::Compress) {
- FuncH << "static bool compressInst(MCInst& OutInst,\n";
+ 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 if (EType == EmitterType::Uncompress){
- FuncH << "static bool uncompressInst(MCInst& OutInst,\n";
+ 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";
} else if (EType == EmitterType::CheckCompress) {
- FuncH << "static bool isCompressibleInst(const MachineInstr& MI,\n";
+ FuncH << "static bool isCompressibleInst(const MachineInstr &MI,\n";
FuncH.indent(27) << "const RISCVSubtarget *Subtarget,\n";
FuncH.indent(27) << "const MCRegisterInfo &MRI,\n";
FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n";
@@ -638,10 +623,10 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
return;
}
- std::string CaseString("");
+ std::string CaseString;
raw_string_ostream CaseStream(CaseString);
- std::string PrevOp("");
- std::string CurOp("");
+ StringRef PrevOp;
+ StringRef CurOp;
CaseStream << " switch (MI.getOpcode()) {\n";
CaseStream << " default: return false;\n";
@@ -651,6 +636,9 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
EType == EmitterType::Compress || EType == EmitterType::Uncompress;
for (auto &CompressPat : CompressPatterns) {
+ if (EType == EmitterType::Uncompress && CompressPat.IsCompressOnly)
+ continue;
+
std::string CondString;
std::string CodeString;
raw_string_ostream CondStream(CondString);
@@ -664,10 +652,10 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
IndexedMap<OpData> &DestOperandMap = CompressOrCheck ?
CompressPat.DestOperandMap : CompressPat.SourceOperandMap;
- CurOp = Source.TheDef->getName().str();
+ CurOp = Source.TheDef->getName();
// Check current and previous opcode to decide to continue or end a case.
if (CurOp != PrevOp) {
- if (PrevOp != "")
+ if (!PrevOp.empty())
CaseStream.indent(6) << "break;\n } // case " + PrevOp + "\n";
CaseStream.indent(4) << "case " + Namespace + "::" + CurOp + ": {\n";
}
@@ -688,9 +676,9 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
// Emit checks for all required features.
for (auto &Op : FeaturesSet) {
StringRef Not = Op.first ? "!" : "";
- CondStream.indent(6)
- << Not << ("STI.getFeatureBits()[" + Namespace + "::" + Op.second + "]").str() +
- " &&\n";
+ CondStream.indent(6) << Not << "STI.getFeatureBits()[" << Namespace
+ << "::" << Op.second << "]"
+ << " &&\n";
}
// Emit checks for all required feature groups.
@@ -699,8 +687,8 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
for (auto &Op : Set) {
bool isLast = &Op == &*Set.rbegin();
StringRef Not = Op.first ? "!" : "";
- CondStream << Not << ("STI.getFeatureBits()[" + Namespace + "::" + Op.second +
- "]").str();
+ CondStream << Not << "STI.getFeatureBits()[" << Namespace
+ << "::" << Op.second << "]";
if (!isLast)
CondStream << " || ";
}
@@ -713,10 +701,8 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
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";
+ << "(MI.getOperand(" << OpNo << ").getReg() == MI.getOperand("
+ << SourceOperandMap[OpNo].TiedOpIdx << ").getReg()) &&\n";
else
PrintFatalError("Unexpected tied operand types!\n");
}
@@ -727,27 +713,26 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
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";
+ << "(MI.getOperand(" << OpNo << ").isImm()) &&\n"
+ << " (MI.getOperand(" << OpNo
+ << ").getImm() == " << 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";
+ CondStream.indent(6)
+ << "(MI.getOperand(" << OpNo << ").getReg() == " << Namespace
+ << "::" << Reg->getName() << ") &&\n";
break;
}
}
}
- CodeStream.indent(6) << "// " + Dest.AsmString + "\n";
+ CodeStream.indent(6) << "// " << Dest.AsmString << "\n";
if (CompressOrUncompress)
- CodeStream.indent(6) << "OutInst.setOpcode(" + Namespace +
- "::" + Dest.TheDef->getName().str() + ");\n";
+ CodeStream.indent(6) << "OutInst.setOpcode(" << Namespace
+ << "::" << Dest.TheDef->getName() << ");\n";
OpNo = 0;
for (const auto &DestOperand : Dest.Operands) {
- CodeStream.indent(6) << "// Operand: " + DestOperand.Name + "\n";
+ CodeStream.indent(6) << "// Operand: " << DestOperand.Name << "\n";
switch (DestOperandMap[OpNo].Kind) {
case OpData::Operand: {
unsigned OpIdx = DestOperandMap[OpNo].Data.Operand;
@@ -759,68 +744,67 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
// 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";
+ CondStream.indent(6) << "(MRI.getRegClass(" << Namespace
+ << "::" << DestOperand.Rec->getName()
+ << "RegClassID).contains(MI.getOperand("
+ << OpIdx << ").getReg())) &&\n";
if (CompressOrUncompress)
- CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" +
- std::to_string(OpIdx) + "));\n";
+ CodeStream.indent(6)
+ << "OutInst.addOperand(MI.getOperand(" << OpIdx << "));\n";
} else {
// Handling immediate operands.
if (CompressOrUncompress) {
- unsigned Entry = getPredicates(MCOpPredicateMap, MCOpPredicates,
- DestOperand.Rec, StringRef("MCOperandPredicate"));
- CondStream.indent(6) << Namespace + "ValidateMCOperand(" +
- "MI.getOperand(" + std::to_string(OpIdx) +
- "), STI, " + std::to_string(Entry) +
- ") &&\n";
+ unsigned Entry =
+ getPredicates(MCOpPredicateMap, MCOpPredicates, DestOperand.Rec,
+ "MCOperandPredicate");
+ CondStream.indent(6)
+ << Namespace << "ValidateMCOperand("
+ << "MI.getOperand(" << OpIdx << "), STI, " << Entry << ") &&\n";
} else {
- unsigned Entry = getPredicates(ImmLeafPredicateMap, ImmLeafPredicates,
- DestOperand.Rec, StringRef("ImmediateCode"));
- CondStream.indent(6) << "MI.getOperand(" + std::to_string(OpIdx) +
- ").isImm() && \n";
- CondStream.indent(6) << Namespace + "ValidateMachineOperand(" +
- "MI.getOperand(" + std::to_string(OpIdx) +
- "), Subtarget, " + std::to_string(Entry) +
- ") &&\n";
+ unsigned Entry =
+ getPredicates(ImmLeafPredicateMap, ImmLeafPredicates,
+ DestOperand.Rec, "ImmediateCode");
+ CondStream.indent(6)
+ << "MI.getOperand(" << OpIdx << ").isImm() &&\n";
+ CondStream.indent(6) << Namespace << "ValidateMachineOperand("
+ << "MI.getOperand(" << OpIdx
+ << "), Subtarget, " << Entry << ") &&\n";
}
if (CompressOrUncompress)
- CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" +
- std::to_string(OpIdx) + "));\n";
+ CodeStream.indent(6)
+ << "OutInst.addOperand(MI.getOperand(" << OpIdx << "));\n";
}
break;
}
case OpData::Imm: {
if (CompressOrUncompress) {
unsigned Entry = getPredicates(MCOpPredicateMap, MCOpPredicates,
- DestOperand.Rec, StringRef("MCOperandPredicate"));
+ DestOperand.Rec, "MCOperandPredicate");
CondStream.indent(6)
- << Namespace + "ValidateMCOperand(" + "MCOperand::createImm(" +
- std::to_string(DestOperandMap[OpNo].Data.Imm) + "), STI, " +
- std::to_string(Entry) + ") &&\n";
+ << Namespace << "ValidateMCOperand("
+ << "MCOperand::createImm(" << DestOperandMap[OpNo].Data.Imm
+ << "), STI, " << Entry << ") &&\n";
} else {
unsigned Entry = getPredicates(ImmLeafPredicateMap, ImmLeafPredicates,
- DestOperand.Rec, StringRef("ImmediateCode"));
+ DestOperand.Rec, "ImmediateCode");
CondStream.indent(6)
- << Namespace + "ValidateMachineOperand(" + "MachineOperand::CreateImm(" +
- std::to_string(DestOperandMap[OpNo].Data.Imm) + "), SubTarget, " +
- std::to_string(Entry) + ") &&\n";
+ << Namespace
+ << "ValidateMachineOperand(MachineOperand::CreateImm("
+ << DestOperandMap[OpNo].Data.Imm << "), SubTarget, " << Entry
+ << ") &&\n";
}
if (CompressOrUncompress)
- CodeStream.indent(6)
- << "OutInst.addOperand(MCOperand::createImm(" +
- std::to_string(DestOperandMap[OpNo].Data.Imm) + "));\n";
+ CodeStream.indent(6) << "OutInst.addOperand(MCOperand::createImm("
+ << DestOperandMap[OpNo].Data.Imm << "));\n";
} break;
case OpData::Reg: {
if (CompressOrUncompress) {
// 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";
+ CodeStream.indent(6)
+ << "OutInst.addOperand(MCOperand::createReg(" << Namespace
+ << "::" << Reg->getName() << "));\n";
}
} break;
}
@@ -828,12 +812,12 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
}
if (CompressOrUncompress)
CodeStream.indent(6) << "OutInst.setLoc(MI.getLoc());\n";
- CaseStream << mergeCondAndCode(CondStream, CodeStream);
+ mergeCondAndCode(CaseStream, CondStream.str(), CodeStream.str());
PrevOp = CurOp;
}
Func << CaseStream.str() << "\n";
// Close brace for the last case.
- Func.indent(4) << "} // case " + CurOp + "\n";
+ Func.indent(4) << "} // case " << CurOp << "\n";
Func.indent(2) << "} // switch\n";
Func.indent(2) << "return false;\n}\n";
@@ -858,7 +842,7 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
<< "ValidateMachineOperand(const MachineOperand &MO,\n"
<< " const RISCVSubtarget *Subtarget,\n"
<< " unsigned PredicateIndex) {\n"
- << " int64_t Imm = MO.getImm(); \n"
+ << " int64_t Imm = MO.getImm();\n"
<< " switch (PredicateIndex) {\n"
<< " default:\n"
<< " llvm_unreachable(\"Unknown ImmLeaf Predicate kind\");\n"
@@ -884,13 +868,7 @@ void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
}
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());
- }
+ std::vector<Record *> Insts = Records.getAllDerivedDefinitions("CompressPat");
// Process the CompressPat definitions, validating them as we do so.
for (unsigned i = 0, e = Insts.size(); i != e; ++i)
diff --git a/llvm/utils/TableGen/RegisterBankEmitter.cpp b/llvm/utils/TableGen/RegisterBankEmitter.cpp
index 586f857b1fb0..0725657150f8 100644
--- a/llvm/utils/TableGen/RegisterBankEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterBankEmitter.cpp
@@ -71,10 +71,7 @@ public:
/// Add a register class to the bank without duplicates.
void addRegisterClass(const CodeGenRegisterClass *RC) {
- if (std::find_if(RCs.begin(), RCs.end(),
- [&RC](const CodeGenRegisterClass *X) {
- return X == RC;
- }) != RCs.end())
+ if (llvm::is_contained(RCs, RC))
return;
// FIXME? We really want the register size rather than the spill size
@@ -131,9 +128,12 @@ void RegisterBankEmitter::emitHeader(raw_ostream &OS,
// <Target>RegisterBankInfo.h
OS << "namespace llvm {\n"
<< "namespace " << TargetName << " {\n"
- << "enum {\n";
+ << "enum : unsigned {\n";
+
+ OS << " InvalidRegBankID = ~0u,\n";
+ unsigned ID = 0;
for (const auto &Bank : Banks)
- OS << " " << Bank.getEnumeratorName() << ",\n";
+ OS << " " << Bank.getEnumeratorName() << " = " << ID++ << ",\n";
OS << " NumRegisterBanks,\n"
<< "};\n"
<< "} // end namespace " << TargetName << "\n"
@@ -168,7 +168,7 @@ void RegisterBankEmitter::emitBaseClassDefinition(
/// to the class.
static void visitRegisterBankClasses(
const CodeGenRegBank &RegisterClassHierarchy,
- const CodeGenRegisterClass *RC, const Twine Kind,
+ const CodeGenRegisterClass *RC, const Twine &Kind,
std::function<void(const CodeGenRegisterClass *, StringRef)> VisitFn,
SmallPtrSetImpl<const CodeGenRegisterClass *> &VisitedRCs) {
@@ -182,7 +182,7 @@ static void visitRegisterBankClasses(
for (const auto &PossibleSubclass : RegisterClassHierarchy.getRegClasses()) {
std::string TmpKind =
- (Twine(Kind) + " (" + PossibleSubclass.getName() + ")").str();
+ (Kind + " (" + PossibleSubclass.getName() + ")").str();
// Visit each subclass of an explicitly named class.
if (RC != &PossibleSubclass && RC->hasSubClass(&PossibleSubclass))
@@ -279,6 +279,7 @@ void RegisterBankEmitter::run(raw_ostream &OS) {
StringRef TargetName = Target.getName();
const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank();
+ Records.startTimer("Analyze records");
std::vector<RegisterBank> Banks;
for (const auto &V : Records.getAllDerivedDefinitions("RegisterBank")) {
SmallPtrSet<const CodeGenRegisterClass *, 8> VisitedRCs;
@@ -300,6 +301,7 @@ void RegisterBankEmitter::run(raw_ostream &OS) {
}
// Warn about ambiguous MIR caused by register bank/class name clashes.
+ Records.startTimer("Warn ambiguous");
for (const auto &Class : RegisterClassHierarchy.getRegClasses()) {
for (const auto &Bank : Banks) {
if (Bank.getName().lower() == StringRef(Class.getName()).lower()) {
@@ -312,6 +314,7 @@ void RegisterBankEmitter::run(raw_ostream &OS) {
}
}
+ Records.startTimer("Emit output");
emitSourceFileHeader("Register Bank Source Fragments", OS);
OS << "#ifdef GET_REGBANK_DECLARATIONS\n"
<< "#undef GET_REGBANK_DECLARATIONS\n";
diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
index a615587efdee..dce7594dec2f 100644
--- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
@@ -127,7 +127,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
OS << " " << Reg.getName() << " = " << Reg.EnumValue << ",\n";
assert(Registers.size() == Registers.back().EnumValue &&
"Register enum value mismatch!");
- OS << " NUM_TARGET_REGS \t// " << Registers.size()+1 << "\n";
+ OS << " NUM_TARGET_REGS // " << Registers.size()+1 << "\n";
OS << "};\n";
if (!Namespace.empty())
OS << "} // end namespace " << Namespace << "\n";
@@ -146,7 +146,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
for (const auto &RC : RegisterClasses)
OS << " " << RC.getName() << "RegClassID"
<< " = " << RC.EnumValue << ",\n";
- OS << "\n };\n";
+ OS << "\n};\n";
if (!Namespace.empty())
OS << "} // end namespace " << Namespace << "\n\n";
}
@@ -323,7 +323,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
OS << "/// Get the dimensions of register pressure impacted by this "
<< "register class.\n"
<< "/// Returns a -1 terminated array of pressure set IDs\n"
- << "const int* " << ClassName << "::\n"
+ << "const int *" << ClassName << "::\n"
<< "getRegClassPressureSets(const TargetRegisterClass *RC) const {\n";
OS << " static const " << getMinimalTypeForRange(PSetsSeqs.size() - 1, 32)
<< " RCSetStartTable[] = {\n ";
@@ -337,7 +337,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
OS << "/// Get the dimensions of register pressure impacted by this "
<< "register unit.\n"
<< "/// Returns a -1 terminated array of pressure set IDs\n"
- << "const int* " << ClassName << "::\n"
+ << "const int *" << ClassName << "::\n"
<< "getRegUnitPressureSets(unsigned RegUnit) const {\n"
<< " assert(RegUnit < " << RegBank.getNumNativeRegUnits()
<< " && \"invalid register unit\");\n";
@@ -356,11 +356,10 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
using DwarfRegNumsMapPair = std::pair<Record*, std::vector<int64_t>>;
using DwarfRegNumsVecTy = std::vector<DwarfRegNumsMapPair>;
-void finalizeDwarfRegNumsKeys(DwarfRegNumsVecTy &DwarfRegNums) {
+static void finalizeDwarfRegNumsKeys(DwarfRegNumsVecTy &DwarfRegNums) {
// Sort and unique to get a map-like vector. We want the last assignment to
// match previous behaviour.
- std::stable_sort(DwarfRegNums.begin(), DwarfRegNums.end(),
- on_first<LessRecordRegister>());
+ llvm::stable_sort(DwarfRegNums, on_first<LessRecordRegister>());
// Warn about duplicate assignments.
const Record *LastSeenReg = nullptr;
for (const auto &X : DwarfRegNums) {
@@ -462,18 +461,16 @@ void RegisterInfoEmitter::EmitRegMappingTables(
DefInit *DI = cast<DefInit>(V->getValue());
Record *Alias = DI->getDef();
- const auto &AliasIter =
- std::lower_bound(DwarfRegNums.begin(), DwarfRegNums.end(), Alias,
- [](const DwarfRegNumsMapPair &A, const Record *B) {
- return LessRecordRegister()(A.first, B);
- });
+ const auto &AliasIter = llvm::lower_bound(
+ DwarfRegNums, Alias, [](const DwarfRegNumsMapPair &A, const Record *B) {
+ return LessRecordRegister()(A.first, B);
+ });
assert(AliasIter != DwarfRegNums.end() && AliasIter->first == Alias &&
"Expected Alias to be present in map");
- const auto &RegIter =
- std::lower_bound(DwarfRegNums.begin(), DwarfRegNums.end(), Reg,
- [](const DwarfRegNumsMapPair &A, const Record *B) {
- return LessRecordRegister()(A.first, B);
- });
+ const auto &RegIter = llvm::lower_bound(
+ DwarfRegNums, Reg, [](const DwarfRegNumsMapPair &A, const Record *B) {
+ return LessRecordRegister()(A.first, B);
+ });
assert(RegIter != DwarfRegNums.end() && RegIter->first == Reg &&
"Expected Reg to be present in map");
RegIter->second = AliasIter->second;
@@ -960,7 +957,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
const auto &RUMasks = Reg.getRegUnitLaneMasks();
MaskVec &LaneMaskVec = RegUnitLaneMasks[i];
assert(LaneMaskVec.empty());
- LaneMaskVec.insert(LaneMaskVec.begin(), RUMasks.begin(), RUMasks.end());
+ llvm::append_range(LaneMaskVec, RUMasks);
// Terminator mask should not be used inside of the list.
#ifndef NDEBUG
for (LaneBitmask M : LaneMaskVec) {
@@ -1167,7 +1164,7 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
<< " LaneBitmask reverseComposeSubRegIndexLaneMaskImpl"
<< "(unsigned, LaneBitmask) const override;\n"
<< " const TargetRegisterClass *getSubClassWithSubReg"
- << "(const TargetRegisterClass*, unsigned) const override;\n";
+ << "(const TargetRegisterClass *, unsigned) const override;\n";
}
OS << " const RegClassWeight &getRegClassWeight("
<< "const TargetRegisterClass *RC) const override;\n"
@@ -1288,7 +1285,8 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << CGH.getMode(M).Name;
OS << ")\n";
for (const auto &RC : RegisterClasses) {
- assert(RC.EnumValue == EV++ && "Unexpected order of register classes");
+ assert(RC.EnumValue == EV && "Unexpected order of register classes");
+ ++EV;
(void)EV;
const RegSizeInfo &RI = RC.RSI.get(M);
OS << " { " << RI.RegSize << ", " << RI.SpillSize << ", "
@@ -1435,7 +1433,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
}
OS << "\nnamespace {\n";
- OS << " const TargetRegisterClass* const RegisterClasses[] = {\n";
+ OS << " const TargetRegisterClass *const RegisterClasses[] = {\n";
for (const auto &RC : RegisterClasses)
OS << " &" << RC.getQualifiedName() << "RegClass,\n";
OS << " };\n";
@@ -1615,9 +1613,16 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
void RegisterInfoEmitter::run(raw_ostream &OS) {
CodeGenRegBank &RegBank = Target.getRegBank();
+ Records.startTimer("Print enums");
runEnums(OS, Target, RegBank);
+
+ Records.startTimer("Print MC registers");
runMCDesc(OS, Target, RegBank);
+
+ Records.startTimer("Print header fragment");
runTargetHeader(OS, Target, RegBank);
+
+ Records.startTimer("Print target registers");
runTargetDesc(OS, Target, RegBank);
if (RegisterInfoDebug)
diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index 326cb4e54edc..912d43b2caa1 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//
+#include "CodeGenIntrinsics.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Format.h"
@@ -19,7 +21,6 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
-#include "CodeGenIntrinsics.h"
#include <algorithm>
#include <set>
#include <string>
@@ -53,6 +54,7 @@ struct GenericEnum {
struct GenericField {
std::string Name;
RecTy *RecType = nullptr;
+ bool IsCode = false;
bool IsIntrinsic = false;
bool IsInstruction = false;
GenericEnum *Enum = nullptr;
@@ -62,12 +64,14 @@ struct GenericField {
struct SearchIndex {
std::string Name;
+ SMLoc Loc; // Source location of PrimaryKey or Key field definition.
SmallVector<GenericField, 1> Fields;
bool EarlyOut = false;
};
struct GenericTable {
std::string Name;
+ ArrayRef<SMLoc> Locs; // Source locations from the Record instance.
std::string PreprocessorGuard;
std::string CppTypeName;
SmallVector<GenericField, 2> Fields;
@@ -106,15 +110,17 @@ private:
TypeInArgument,
};
- 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))
+ std::string primaryRepresentation(SMLoc Loc, const GenericField &Field,
+ Init *I) {
+ if (StringInit *SI = dyn_cast<StringInit>(I)) {
+ if (Field.IsCode || SI->hasCodeFormat())
+ return std::string(SI->getValue());
+ else
+ 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))
- return std::string(CI->getValue());
else if (Field.IsIntrinsic)
return "Intrinsic::" + getIntrinsic(I).EnumName;
else if (Field.IsInstruction)
@@ -122,11 +128,12 @@ private:
else if (Field.Enum) {
auto *Entry = Field.Enum->EntryMap[cast<DefInit>(I)->getDef()];
if (!Entry)
- PrintFatalError(Twine("Entry for field '") + Field.Name + "' is null");
+ PrintFatalError(Loc,
+ Twine("Entry for field '") + Field.Name + "' is null");
return std::string(Entry->first);
}
- PrintFatalError(Twine("invalid field type for field '") + Field.Name +
- "', expected: string, bits, bit or code");
+ PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name +
+ "'; expected: bit, bits, string, or code");
}
bool isIntrinsic(Init *I) {
@@ -138,17 +145,16 @@ private:
CodeGenIntrinsic &getIntrinsic(Init *I) {
std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I];
if (!Intr)
- Intr = std::make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef());
+ Intr = std::make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef(),
+ std::vector<Record *>());
return *Intr;
}
bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index);
- bool isIntegral(Init *I) {
- return isa<BitsInit>(I) || isa<CodeInit>(I) || isIntrinsic(I);
- }
-
- std::string searchableFieldType(const GenericField &Field, TypeContext Ctx) {
+ std::string searchableFieldType(const GenericTable &Table,
+ const SearchIndex &Index,
+ const GenericField &Field, TypeContext Ctx) {
if (isa<StringRecTy>(Field.RecType)) {
if (Ctx == TypeInStaticStruct)
return "const char *";
@@ -165,12 +171,16 @@ private:
return "uint32_t";
if (NumBits <= 64)
return "uint64_t";
- PrintFatalError(Twine("bitfield '") + Field.Name +
- "' too large to search");
+ PrintFatalError(Index.Loc, Twine("In table '") + Table.Name +
+ "' lookup method '" + Index.Name +
+ "', key field '" + Field.Name +
+ "' of type bits is too large");
} else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction)
return "unsigned";
- PrintFatalError(Twine("Field '") + Field.Name + "' has unknown type '" +
- Field.RecType->getAsString() + "' to search by");
+ PrintFatalError(Index.Loc,
+ Twine("In table '") + Table.Name + "' lookup method '" +
+ Index.Name + "', key field '" + Field.Name +
+ "' has invalid type: " + Field.RecType->getAsString());
}
void emitGenericTable(const GenericTable &Table, raw_ostream &OS);
@@ -183,7 +193,7 @@ private:
bool parseFieldType(GenericField &Field, Init *II);
std::unique_ptr<SearchIndex>
- parseSearchIndex(GenericTable &Table, StringRef Name,
+ parseSearchIndex(GenericTable &Table, const RecordVal *RecVal, StringRef Name,
const std::vector<StringRef> &Key, bool EarlyOut);
void collectEnumEntries(GenericEnum &Enum, StringRef NameField,
StringRef ValueField,
@@ -258,8 +268,8 @@ bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS,
if (LHSv > RHSv)
return false;
} else {
- std::string LHSs = primaryRepresentation(Field, LHSI);
- std::string RHSs = primaryRepresentation(Field, RHSI);
+ std::string LHSs = primaryRepresentation(Index.Loc, Field, LHSI);
+ std::string RHSs = primaryRepresentation(Index.Loc, Field, RHSI);
if (isa<StringRecTy>(Field.RecType)) {
LHSs = StringRef(LHSs).upper();
@@ -314,7 +324,8 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
} else {
OS << " struct IndexType {\n";
for (const auto &Field : Index.Fields) {
- OS << " " << searchableFieldType(Field, TypeInStaticStruct) << " "
+ OS << " "
+ << searchableFieldType(Table, Index, Field, TypeInStaticStruct) << " "
<< Field.Name << ";\n";
}
OS << " unsigned _index;\n";
@@ -327,11 +338,10 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
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);
- });
+ llvm::stable_sort(Entries, [&](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) {
@@ -344,8 +354,8 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
OS << ", ";
NeedComma = true;
- std::string Repr =
- primaryRepresentation(Field, Entry.first->getValueInit(Field.Name));
+ std::string Repr = primaryRepresentation(
+ Index.Loc, Field, Entry.first->getValueInit(Field.Name));
if (isa<StringRecTy>(Field.RecType))
Repr = StringRef(Repr).upper();
OS << Repr;
@@ -388,10 +398,10 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
if (Index.EarlyOut) {
const GenericField &Field = Index.Fields[0];
- std::string FirstRepr =
- primaryRepresentation(Field, IndexRows[0]->getValueInit(Field.Name));
+ std::string FirstRepr = primaryRepresentation(
+ Index.Loc, Field, IndexRows[0]->getValueInit(Field.Name));
std::string LastRepr = primaryRepresentation(
- Field, IndexRows.back()->getValueInit(Field.Name));
+ Index.Loc, Field, IndexRows.back()->getValueInit(Field.Name));
OS << " if ((" << Field.Name << " < " << FirstRepr << ") ||\n";
OS << " (" << Field.Name << " > " << LastRepr << "))\n";
OS << " return nullptr;\n\n";
@@ -399,11 +409,11 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
OS << " struct KeyType {\n";
for (const auto &Field : Index.Fields) {
- OS << " " << searchableFieldType(Field, TypeInTempStruct) << " "
- << Field.Name << ";\n";
+ OS << " " << searchableFieldType(Table, Index, Field, TypeInTempStruct)
+ << " " << Field.Name << ";\n";
}
OS << " };\n";
- OS << " KeyType Key = { ";
+ OS << " KeyType Key = {";
bool NeedComma = false;
for (const auto &Field : Index.Fields) {
if (NeedComma)
@@ -414,12 +424,14 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
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 + "'");
+ PrintFatalError(Index.Loc,
+ Twine("In table '") + Table.Name +
+ "', use a secondary lookup method for "
+ "case-insensitive comparison of field '" +
+ Field.Name + "'");
}
}
- OS << " };\n";
+ OS << "};\n";
OS << " auto Table = makeArrayRef(" << IndexName << ");\n";
OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
@@ -476,7 +488,8 @@ void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
OS << ", ";
NeedComma = true;
- OS << searchableFieldType(Field, TypeInArgument) << " " << Field.Name;
+ OS << searchableFieldType(Table, Index, Field, TypeInArgument) << " "
+ << Field.Name;
}
OS << ")";
}
@@ -511,7 +524,8 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
OS << ", ";
NeedComma = true;
- OS << primaryRepresentation(Field, Entry->getValueInit(Field.Name));
+ OS << primaryRepresentation(Table.Locs[0], Field,
+ Entry->getValueInit(Field.Name));
}
OS << " }, // " << i << "\n";
@@ -528,40 +542,49 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
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);
+bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) {
+ if (auto Type = dyn_cast<StringInit>(TypeOf)) {
+ if (Type->getValue() == "code") {
+ Field.IsCode = true;
return true;
+ } else {
+ if (Record *TypeRec = Records.getDef(Type->getValue())) {
+ if (TypeRec->isSubClassOf("GenericEnum")) {
+ Field.Enum = EnumMap[TypeRec];
+ Field.RecType = RecordRecTy::get(Field.Enum->Class);
+ return true;
+ }
+ }
}
}
return false;
}
-std::unique_ptr<SearchIndex>
-SearchableTableEmitter::parseSearchIndex(GenericTable &Table, StringRef Name,
- const std::vector<StringRef> &Key,
- bool EarlyOut) {
+std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
+ GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name,
+ const std::vector<StringRef> &Key, bool EarlyOut) {
auto Index = std::make_unique<SearchIndex>();
Index->Name = std::string(Name);
+ Index->Loc = KeyRecVal->getLoc();
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 + "'");
+ PrintFatalError(
+ KeyRecVal,
+ Twine("In table '") + Table.Name +
+ "', 'PrimaryKey' or 'Key' refers to nonexistent field '" +
+ FieldName + "'");
+
Index->Fields.push_back(*Field);
}
if (EarlyOut && isa<StringRecTy>(Index->Fields[0].RecType)) {
PrintFatalError(
- "Early-out is not supported for string types (in search index '" +
- Twine(Name) + "'");
+ KeyRecVal, Twine("In lookup method '") + Name + "', early-out is not " +
+ "supported for a first key field of type string");
}
return Index;
@@ -586,11 +609,11 @@ void SearchableTableEmitter::collectEnumEntries(
}
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;
- });
+ llvm::stable_sort(Enum.Entries,
+ [](const std::unique_ptr<GenericEnum::Entry> &LHS,
+ const std::unique_ptr<GenericEnum::Entry> &RHS) {
+ return LHS->first < RHS->first;
+ });
for (size_t i = 0; i < Enum.Entries.size(); ++i)
Enum.Entries[i]->second = i;
@@ -600,31 +623,33 @@ void SearchableTableEmitter::collectEnumEntries(
void SearchableTableEmitter::collectTableEntries(
GenericTable &Table, const std::vector<Record *> &Items) {
if (Items.empty())
- PrintWarning(Twine("Table '") + Table.Name + "' has no items");
+ PrintFatalError(Table.Locs,
+ Twine("Table '") + Table.Name + "' has no entries");
for (auto EntryRec : Items) {
for (auto &Field : Table.Fields) {
auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name));
if (!TI || !TI->isComplete()) {
- PrintFatalError(EntryRec->getLoc(),
- Twine("Record '") + EntryRec->getName() +
- "' in table '" + Table.Name +
- "' is missing field '" + Field.Name + "'");
+ PrintFatalError(EntryRec, Twine("Record '") + EntryRec->getName() +
+ "' for 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: " +
- Field.RecType->getAsString() + " vs. " +
- TI->getType()->getAsString());
+ PrintFatalError(EntryRec->getValue(Field.Name),
+ Twine("Field '") + Field.Name + "' of table '" +
+ Table.Name + "' entry has incompatible type: " +
+ TI->getType()->getAsString() + " vs. " +
+ Field.RecType->getAsString());
Field.RecType = Ty;
}
}
- Table.Entries.push_back(EntryRec);
+ Table.Entries.push_back(EntryRec); // Add record to table's record list.
}
Record *IntrinsicClass = Records.getClass("Intrinsic");
@@ -665,8 +690,9 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
StringRef FilterClass = EnumRec->getValueAsString("FilterClass");
Enum->Class = Records.getClass(FilterClass);
if (!Enum->Class)
- PrintFatalError(EnumRec->getLoc(), Twine("Enum FilterClass '") +
- FilterClass + "' does not exist");
+ PrintFatalError(EnumRec->getValue("FilterClass"),
+ Twine("Enum FilterClass '") + FilterClass +
+ "' does not exist");
collectEnumEntries(*Enum, NameField, ValueField,
Records.getAllDerivedDefinitions(FilterClass));
@@ -677,36 +703,44 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) {
auto Table = std::make_unique<GenericTable>();
Table->Name = std::string(TableRec->getName());
+ Table->Locs = TableRec->getLoc();
Table->PreprocessorGuard = std::string(TableRec->getName());
Table->CppTypeName = std::string(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(TableRec->getLoc(),
- Twine("Table '") + Table->Name +
- "' has bad 'TypeOf_" + FieldName +
- "': " + TypeOfVal->getValue()->getAsString());
+ Table->Fields.emplace_back(FieldName); // Construct a GenericField.
+
+ if (auto TypeOfRecordVal = TableRec->getValue(("TypeOf_" + FieldName).str())) {
+ if (!parseFieldType(Table->Fields.back(), TypeOfRecordVal->getValue())) {
+ PrintError(TypeOfRecordVal,
+ Twine("Table '") + Table->Name +
+ "' has invalid 'TypeOf_" + FieldName +
+ "': " + TypeOfRecordVal->getValue()->getAsString());
+ PrintFatalNote("The 'TypeOf_xxx' field must be a string naming a "
+ "GenericEnum record, or \"code\"");
}
}
}
- collectTableEntries(*Table, Records.getAllDerivedDefinitions(
- TableRec->getValueAsString("FilterClass")));
+ StringRef FilterClass = TableRec->getValueAsString("FilterClass");
+ if (!Records.getClass(FilterClass))
+ PrintFatalError(TableRec->getValue("FilterClass"),
+ Twine("Table FilterClass '") +
+ FilterClass + "' does not exist");
+
+ collectTableEntries(*Table, Records.getAllDerivedDefinitions(FilterClass));
if (!TableRec->isValueUnset("PrimaryKey")) {
Table->PrimaryKey =
- parseSearchIndex(*Table, TableRec->getValueAsString("PrimaryKeyName"),
+ parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"),
+ 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);
- });
+ llvm::stable_sort(Table->Entries, [&](Record *LHS, Record *RHS) {
+ return compareBy(LHS, RHS, *Table->PrimaryKey);
+ });
}
TableMap.insert(std::make_pair(TableRec, Table.get()));
@@ -717,15 +751,16 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
Record *TableRec = IndexRec->getValueAsDef("Table");
auto It = TableMap.find(TableRec);
if (It == TableMap.end())
- PrintFatalError(IndexRec->getLoc(),
+ PrintFatalError(IndexRec->getValue("Table"),
Twine("SearchIndex '") + IndexRec->getName() +
- "' refers to non-existing table '" +
+ "' refers to nonexistent table '" +
TableRec->getName());
GenericTable &Table = *It->second;
- Table.Indices.push_back(parseSearchIndex(
- Table, IndexRec->getName(), IndexRec->getValueAsListOfStrings("Key"),
- IndexRec->getValueAsBit("EarlyOut")));
+ Table.Indices.push_back(
+ parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(),
+ IndexRec->getValueAsListOfStrings("Key"),
+ IndexRec->getValueAsBit("EarlyOut")));
}
// Translate legacy tables.
@@ -756,6 +791,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
auto Table = std::make_unique<GenericTable>();
Table->Name = (Twine(Class->getName()) + "sList").str();
+ Table->Locs = Class->getLoc();
Table->PreprocessorGuard = Class->getName().upper();
Table->CppTypeName = std::string(Class->getName());
@@ -778,7 +814,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
Class->getValueAsListOfStrings("SearchableFields")) {
std::string Name =
(Twine("lookup") + Table->CppTypeName + "By" + Field).str();
- Table->Indices.push_back(parseSearchIndex(*Table, Name, {Field}, false));
+ Table->Indices.push_back(parseSearchIndex(*Table, Class->getValue(Field),
+ Name, {Field}, false));
}
Tables.emplace_back(std::move(Table));
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index 68ee839c43ba..7d2b4b929df3 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -114,7 +114,6 @@ class SubtargetEmitter {
SchedClassTables &SchedTables);
void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS);
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);
@@ -267,12 +266,15 @@ SubtargetEmitter::CPUKeyValues(raw_ostream &OS,
for (Record *Processor : ProcessorList) {
StringRef Name = Processor->getValueAsString("Name");
RecVec FeatureList = Processor->getValueAsListOfDefs("Features");
+ RecVec TuneFeatureList = Processor->getValueAsListOfDefs("TuneFeatures");
// Emit as { "cpu", "description", 0, { f1 , f2 , ... fn } },
OS << " { "
<< "\"" << Name << "\", ";
printFeatureMask(OS, FeatureList, FeatureMap);
+ OS << ", ";
+ printFeatureMask(OS, TuneFeatureList, FeatureMap);
// Emit the scheduler model pointer.
const std::string &ProcModelName =
@@ -728,10 +730,8 @@ void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel,
unsigned QueueID = 0;
if (ProcModel.LoadQueue) {
const Record *Queue = ProcModel.LoadQueue->getValueAsDef("QueueDescriptor");
- QueueID =
- 1 + std::distance(ProcModel.ProcResourceDefs.begin(),
- std::find(ProcModel.ProcResourceDefs.begin(),
- ProcModel.ProcResourceDefs.end(), Queue));
+ QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(),
+ find(ProcModel.ProcResourceDefs, Queue));
}
OS << " " << QueueID << ", // Resource Descriptor for the Load Queue\n";
@@ -739,10 +739,8 @@ void SubtargetEmitter::EmitLoadStoreQueueInfo(const CodeGenProcModel &ProcModel,
if (ProcModel.StoreQueue) {
const Record *Queue =
ProcModel.StoreQueue->getValueAsDef("QueueDescriptor");
- QueueID =
- 1 + std::distance(ProcModel.ProcResourceDefs.begin(),
- std::find(ProcModel.ProcResourceDefs.begin(),
- ProcModel.ProcResourceDefs.end(), Queue));
+ QueueID = 1 + std::distance(ProcModel.ProcResourceDefs.begin(),
+ find(ProcModel.ProcResourceDefs, Queue));
}
OS << " " << QueueID << ", // Resource Descriptor for the Store Queue\n";
}
@@ -1005,8 +1003,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
bool HasVariants = false;
for (const CodeGenSchedTransition &CGT :
make_range(SC.Transitions.begin(), SC.Transitions.end())) {
- if (CGT.ProcIndices[0] == 0 ||
- is_contained(CGT.ProcIndices, ProcModel.Index)) {
+ if (CGT.ProcIndex == ProcModel.Index) {
HasVariants = true;
break;
}
@@ -1219,11 +1216,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
}
else {
SCDesc.WriteLatencyIdx = SchedTables.WriteLatencies.size();
- SchedTables.WriteLatencies.insert(SchedTables.WriteLatencies.end(),
- WriteLatencies.begin(),
- WriteLatencies.end());
- SchedTables.WriterNames.insert(SchedTables.WriterNames.end(),
- WriterNames.begin(), WriterNames.end());
+ llvm::append_range(SchedTables.WriteLatencies, WriteLatencies);
+ llvm::append_range(SchedTables.WriterNames, WriterNames);
}
// ReadAdvanceEntries must remain in operand order.
SCDesc.NumReadAdvanceEntries = ReadAdvanceEntries.size();
@@ -1235,8 +1229,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
SCDesc.ReadAdvanceIdx = RAPos - SchedTables.ReadAdvanceEntries.begin();
else {
SCDesc.ReadAdvanceIdx = SchedTables.ReadAdvanceEntries.size();
- SchedTables.ReadAdvanceEntries.insert(RAPos, ReadAdvanceEntries.begin(),
- ReadAdvanceEntries.end());
+ llvm::append_range(SchedTables.ReadAdvanceEntries, ReadAdvanceEntries);
}
}
}
@@ -1443,20 +1436,20 @@ static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) {
OS << Buffer;
}
+static bool isTruePredicate(const Record *Rec) {
+ return Rec->isSubClassOf("MCSchedPredicate") &&
+ Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue");
+}
+
static void emitPredicates(const CodeGenSchedTransition &T,
const CodeGenSchedClass &SC, PredicateExpander &PE,
raw_ostream &OS) {
std::string Buffer;
raw_string_ostream SS(Buffer);
- auto IsTruePredicate = [](const Record *Rec) {
- return Rec->isSubClassOf("MCSchedPredicate") &&
- Rec->getValueAsDef("Pred")->isSubClassOf("MCTrue");
- };
-
// If not all predicates are MCTrue, then we need an if-stmt.
unsigned NumNonTruePreds =
- T.PredTerm.size() - count_if(T.PredTerm, IsTruePredicate);
+ T.PredTerm.size() - count_if(T.PredTerm, isTruePredicate);
SS.indent(PE.getIndentLevel() * 2);
@@ -1468,7 +1461,7 @@ static void emitPredicates(const CodeGenSchedTransition &T,
for (const Record *Rec : T.PredTerm) {
// Skip predicates that evaluate to "true".
- if (IsTruePredicate(Rec))
+ if (isTruePredicate(Rec))
continue;
if (FirstNonTruePredicate) {
@@ -1504,7 +1497,8 @@ static void emitPredicates(const CodeGenSchedTransition &T,
// Used by method `SubtargetEmitter::emitSchedModelHelpersImpl()` to generate
// epilogue code for the auto-generated helper.
-void emitSchedModelHelperEpilogue(raw_ostream &OS, bool ShouldReturnZero) {
+static void emitSchedModelHelperEpilogue(raw_ostream &OS,
+ bool ShouldReturnZero) {
if (ShouldReturnZero) {
OS << " // Don't know how to resolve this scheduling class.\n"
<< " return 0;\n";
@@ -1514,15 +1508,15 @@ void emitSchedModelHelperEpilogue(raw_ostream &OS, bool ShouldReturnZero) {
OS << " report_fatal_error(\"Expected a variant SchedClass\");\n";
}
-bool hasMCSchedPredicates(const CodeGenSchedTransition &T) {
+static bool hasMCSchedPredicates(const CodeGenSchedTransition &T) {
return all_of(T.PredTerm, [](const Record *Rec) {
return Rec->isSubClassOf("MCSchedPredicate");
});
}
-void collectVariantClasses(const CodeGenSchedModels &SchedModels,
- IdxVec &VariantClasses,
- bool OnlyExpandMCInstPredicates) {
+static void collectVariantClasses(const CodeGenSchedModels &SchedModels,
+ IdxVec &VariantClasses,
+ bool OnlyExpandMCInstPredicates) {
for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {
// Ignore non-variant scheduling classes.
if (SC.Transitions.empty())
@@ -1541,19 +1535,24 @@ void collectVariantClasses(const CodeGenSchedModels &SchedModels,
}
}
-void collectProcessorIndices(const CodeGenSchedClass &SC, IdxVec &ProcIndices) {
+static void collectProcessorIndices(const CodeGenSchedClass &SC,
+ IdxVec &ProcIndices) {
// A variant scheduling class may define transitions for multiple
// processors. This function identifies wich processors are associated with
// transition rules specified by variant class `SC`.
for (const CodeGenSchedTransition &T : SC.Transitions) {
IdxVec PI;
- std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(),
- ProcIndices.begin(), ProcIndices.end(),
- std::back_inserter(PI));
+ std::set_union(&T.ProcIndex, &T.ProcIndex + 1, ProcIndices.begin(),
+ ProcIndices.end(), std::back_inserter(PI));
ProcIndices.swap(PI);
}
}
+static bool isAlwaysTrue(const CodeGenSchedTransition &T) {
+ return llvm::all_of(T.PredTerm,
+ [](const Record *R) { return isTruePredicate(R); });
+}
+
void SubtargetEmitter::emitSchedModelHelpersImpl(
raw_ostream &OS, bool OnlyExpandMCInstPredicates) {
IdxVec VariantClasses;
@@ -1596,8 +1595,9 @@ void SubtargetEmitter::emitSchedModelHelpersImpl(
}
// Now emit transitions associated with processor PI.
+ const CodeGenSchedTransition *FinalT = nullptr;
for (const CodeGenSchedTransition &T : SC.Transitions) {
- if (PI != 0 && !count(T.ProcIndices, PI))
+ if (PI != 0 && T.ProcIndex != PI)
continue;
// Emit only transitions based on MCSchedPredicate, if it's the case.
@@ -1610,9 +1610,17 @@ void SubtargetEmitter::emitSchedModelHelpersImpl(
if (OnlyExpandMCInstPredicates && !hasMCSchedPredicates(T))
continue;
+ // If transition is folded to 'return X' it should be the last one.
+ if (isAlwaysTrue(T)) {
+ FinalT = &T;
+ continue;
+ }
PE.setIndentLevel(3);
emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS);
}
+ if (FinalT)
+ emitPredicates(*FinalT, SchedModels.getSchedClass(FinalT->ToClassIdx),
+ PE, OS);
OS << " }\n";
@@ -1646,9 +1654,9 @@ void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName,
OS << "unsigned " << ClassName
<< "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI,"
- << " unsigned CPUID) const {\n"
+ << " const MCInstrInfo *MCII, unsigned CPUID) const {\n"
<< " return " << Target << "_MC"
- << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID);\n"
+ << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n"
<< "} // " << ClassName << "::resolveVariantSchedClass\n\n";
STIPredicateExpander PE(Target);
@@ -1692,17 +1700,19 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS,
<< "// subtarget options.\n"
<< "void llvm::";
OS << Target;
- OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n"
+ OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, "
+ << "StringRef FS) {\n"
<< " LLVM_DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n"
- << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n";
+ << " LLVM_DEBUG(dbgs() << \"\\nCPU:\" << CPU);\n"
+ << " LLVM_DEBUG(dbgs() << \"\\nTuneCPU:\" << TuneCPU << \"\\n\\n\");\n";
if (Features.empty()) {
OS << "}\n";
return;
}
- OS << " InitMCProcessorInfo(CPU, FS);\n"
- << " const FeatureBitset& Bits = getFeatureBits();\n";
+ OS << " InitMCProcessorInfo(CPU, TuneCPU, FS);\n"
+ << " const FeatureBitset &Bits = getFeatureBits();\n";
for (Record *R : Features) {
// Next record
@@ -1727,26 +1737,28 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS,
void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
OS << "namespace " << Target << "_MC {\n"
<< "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n"
- << " const MCInst *MI, unsigned CPUID) {\n";
+ << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID) {\n";
emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true);
OS << "}\n";
OS << "} // end 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"
+ OS << " " << Target << "GenMCSubtargetInfo(const Triple &TT,\n"
+ << " StringRef CPU, StringRef TuneCPU, StringRef FS,\n"
+ << " ArrayRef<SubtargetFeatureKV> PF,\n"
<< " ArrayRef<SubtargetSubTypeKV> PD,\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,\n"
+ << " MCSubtargetInfo(TT, CPU, TuneCPU, FS, PF, PD,\n"
<< " WPR, WL, RA, IS, OC, FP) { }\n\n"
<< " unsigned resolveVariantSchedClass(unsigned SchedClass,\n"
- << " const MCInst *MI, unsigned CPUID) const override {\n"
+ << " const MCInst *MI, const MCInstrInfo *MCII,\n"
+ << " unsigned CPUID) const override {\n"
<< " return " << Target << "_MC"
- << "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID); \n";
+ << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n";
OS << " }\n";
if (TGT.getHwModes().getNumModeIds() > 1)
OS << " unsigned getHwMode() const override;\n";
@@ -1817,8 +1829,9 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "\nstatic inline MCSubtargetInfo *create" << Target
<< "MCSubtargetInfoImpl("
- << "const Triple &TT, StringRef CPU, StringRef FS) {\n";
- OS << " return new " << Target << "GenMCSubtargetInfo(TT, CPU, FS, ";
+ << "const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS) {\n";
+ OS << " return new " << Target
+ << "GenMCSubtargetInfo(TT, CPU, TuneCPU, FS, ";
if (NumFeatures)
OS << Target << "FeatureKV, ";
else
@@ -1862,17 +1875,18 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "class DFAPacketizer;\n";
OS << "namespace " << Target << "_MC {\n"
<< "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,"
- << " const MCInst *MI, unsigned CPUID);\n"
+ << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID);\n"
<< "} // end namespace " << Target << "_MC\n\n";
OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
<< " explicit " << ClassName << "(const Triple &TT, StringRef CPU, "
- << "StringRef FS);\n"
+ << "StringRef TuneCPU, StringRef FS);\n"
<< "public:\n"
<< " 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"
+ << " const MCInst *MI, const MCInstrInfo *MCII,"
+ << " unsigned CPUID) const override;\n"
<< " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"
<< " const;\n";
if (TGT.getHwModes().getNumModeIds() > 1)
@@ -1909,8 +1923,8 @@ void SubtargetEmitter::run(raw_ostream &OS) {
}
OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, "
- << "StringRef FS)\n"
- << " : TargetSubtargetInfo(TT, CPU, FS, ";
+ << "StringRef TuneCPU, StringRef FS)\n"
+ << " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, ";
if (NumFeatures)
OS << "makeArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), ";
else
diff --git a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
index 3821f4757464..105ed82c9d02 100644
--- a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
+++ b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp
@@ -7,11 +7,10 @@
//===----------------------------------------------------------------------===//
#include "SubtargetFeatureInfo.h"
-
#include "Types.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
-
#include <map>
using namespace llvm;
@@ -113,7 +112,7 @@ void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
StringRef TargetName, StringRef ClassName, StringRef FuncName,
SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
OS << "FeatureBitset " << TargetName << ClassName << "::\n"
- << FuncName << "(const FeatureBitset& FB) const {\n";
+ << FuncName << "(const FeatureBitset &FB) const {\n";
OS << " FeatureBitset Features;\n";
for (const auto &SF : SubtargetFeatures) {
const SubtargetFeatureInfo &SFI = SF.second;
diff --git a/llvm/utils/TableGen/SubtargetFeatureInfo.h b/llvm/utils/TableGen/SubtargetFeatureInfo.h
index d72f8b93461f..8c8a4487934c 100644
--- a/llvm/utils/TableGen/SubtargetFeatureInfo.h
+++ b/llvm/utils/TableGen/SubtargetFeatureInfo.h
@@ -9,17 +9,12 @@
#ifndef LLVM_UTIL_TABLEGEN_SUBTARGETFEATUREINFO_H
#define LLVM_UTIL_TABLEGEN_SUBTARGETFEATUREINFO_H
-#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
-
#include <map>
#include <string>
#include <vector>
namespace llvm {
-class Record;
-class RecordKeeper;
-
struct SubtargetFeatureInfo;
using SubtargetFeatureInfoMap = std::map<Record *, SubtargetFeatureInfo, LessRecordByID>;
diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp
index 8015a58471ca..6d851da34731 100644
--- a/llvm/utils/TableGen/TableGen.cpp
+++ b/llvm/utils/TableGen/TableGen.cpp
@@ -12,9 +12,7 @@
#include "TableGenBackends.h" // Declares all backends.
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Signals.h"
+#include "llvm/Support/InitLLVM.h"
#include "llvm/TableGen/Main.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/SetTheory.h"
@@ -23,6 +21,8 @@ using namespace llvm;
enum ActionType {
PrintRecords,
+ PrintDetailedRecords,
+ NullBackend,
DumpJSON,
GenEmitter,
GenRegisterInfo,
@@ -60,9 +60,6 @@ enum ActionType {
};
namespace llvm {
-/// Storage for TimeRegionsOpt as a global so that backends aren't required to
-/// include CommandLine.h
-bool TimeRegions = false;
cl::opt<bool> EmitLongStrLiterals(
"long-string-literals",
cl::desc("when emitting large string tables, prefer string literals over "
@@ -77,6 +74,10 @@ cl::opt<ActionType> Action(
cl::values(
clEnumValN(PrintRecords, "print-records",
"Print all records to stdout (default)"),
+ clEnumValN(PrintDetailedRecords, "print-detailed-records",
+ "Print full details of all records to stdout"),
+ clEnumValN(NullBackend, "null-backend",
+ "Do nothing after parsing (useful for timing)"),
clEnumValN(DumpJSON, "dump-json",
"Dump all records as machine-readable JSON"),
clEnumValN(GenEmitter, "gen-emitter", "Generate machine code emitter"),
@@ -144,15 +145,15 @@ cl::opt<std::string> Class("class", cl::desc("Print Enum list for this class"),
cl::value_desc("class name"),
cl::cat(PrintEnumsCat));
-cl::opt<bool, true>
- TimeRegionsOpt("time-regions",
- cl::desc("Time regions of tablegens execution"),
- cl::location(TimeRegions));
-
bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
switch (Action) {
case PrintRecords:
- OS << Records; // No argument, dump all contents
+ OS << Records; // No argument, dump all contents
+ break;
+ case PrintDetailedRecords:
+ EmitDetailedRecords(Records, OS);
+ break;
+ case NullBackend: // No backend at all.
break;
case DumpJSON:
EmitJSON(Records, OS);
@@ -278,12 +279,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
}
int main(int argc, char **argv) {
- sys::PrintStackTraceOnErrorSignal(argv[0]);
- PrettyStackTraceProgram X(argc, argv);
+ InitLLVM X(argc, argv);
cl::ParseCommandLineOptions(argc, argv);
- llvm_shutdown_obj Y;
-
return TableGenMain(argv[0], &LLVMTableGenMain);
}
diff --git a/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp b/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp
index 54aa5a8164f2..7518b262e6e9 100644
--- a/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp
+++ b/llvm/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp
@@ -39,9 +39,15 @@ void emitWebAssemblyDisassemblerTables(
->getValue());
if (Opc == 0xFFFFFFFF)
continue; // No opcode defined.
- assert(Opc <= 0xFFFF);
- auto Prefix = Opc >> 8;
- Opc = Opc & 0xFF;
+ assert(Opc <= 0xFFFFFF);
+ unsigned Prefix;
+ if (Opc <= 0xFFFF) {
+ Prefix = Opc >> 8;
+ Opc = Opc & 0xFF;
+ } else {
+ Prefix = Opc >> 16;
+ Opc = Opc & 0xFFFF;
+ }
auto &CGIP = OpcodeTable[Prefix][Opc];
// All wasm instructions have a StackBased field of type string, we only
// want the instructions for which this is "true".
@@ -133,8 +139,7 @@ void emitWebAssemblyDisassemblerTables(
}
// Store operands if no prior occurrence.
if (OperandStart == OperandTable.size()) {
- OperandTable.insert(OperandTable.end(), CurOperandList.begin(),
- CurOperandList.end());
+ llvm::append_range(OperandTable, CurOperandList);
}
OS << OperandStart;
} else {
diff --git a/llvm/utils/TableGen/X86DisassemblerTables.cpp b/llvm/utils/TableGen/X86DisassemblerTables.cpp
index 76e4fd9a13ee..331664f875b7 100644
--- a/llvm/utils/TableGen/X86DisassemblerTables.cpp
+++ b/llvm/utils/TableGen/X86DisassemblerTables.cpp
@@ -763,7 +763,7 @@ void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2,
}
if (index == 256) {
// If all 256 entries are MODRM_ONEENTRY, omit output.
- assert(MODRM_ONEENTRY == 0);
+ static_assert(MODRM_ONEENTRY == 0, "");
--i2;
o2 << "},\n";
} else {
diff --git a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
index 8026c324cd40..85d926215113 100644
--- a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
+++ b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
@@ -127,6 +127,15 @@ class X86FoldTablesEmitter {
OS << "0 },\n";
}
+
+ bool operator<(const X86FoldTableEntry &RHS) const {
+ bool LHSpseudo = RegInst->TheDef->getValueAsBit("isPseudo");
+ bool RHSpseudo = RHS.RegInst->TheDef->getValueAsBit("isPseudo");
+ if (LHSpseudo != RHSpseudo)
+ return LHSpseudo;
+
+ return RegInst->TheDef->getName() < RHS.RegInst->TheDef->getName();
+ }
};
typedef std::vector<X86FoldTableEntry> FoldTable;
@@ -225,14 +234,8 @@ static inline unsigned int getRegOperandSize(const Record *RegRec) {
}
// Return the size of the memory operand
-static inline unsigned int
-getMemOperandSize(const Record *MemRec, const bool IntrinsicSensitive = false) {
+static inline unsigned getMemOperandSize(const Record *MemRec) {
if (MemRec->isSubClassOf("Operand")) {
- // Intrinsic memory instructions use ssmem/sdmem.
- if (IntrinsicSensitive &&
- (MemRec->getName() == "sdmem" || MemRec->getName() == "ssmem"))
- return 128;
-
StringRef Name =
MemRec->getValueAsDef("ParserMatchClass")->getValueAsString("Name");
if (Name == "Mem8")
@@ -568,8 +571,6 @@ void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInstr,
getRegOperandSize(RegOpRec) == getMemOperandSize(MemOpRec))
addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0);
}
-
- return;
}
void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) {
@@ -653,6 +654,14 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) {
&(Target.getInstruction(MemInstIter)), Entry.Strategy);
}
+ // Sort the tables before printing.
+ llvm::sort(Table2Addr);
+ llvm::sort(Table0);
+ llvm::sort(Table1);
+ llvm::sort(Table2);
+ llvm::sort(Table3);
+ llvm::sort(Table4);
+
// Print all tables.
printTable(Table2Addr, "Table2Addr", OS);
printTable(Table0, "Table0", OS);
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index 84f6d5210d74..e4b7c05cfb88 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -54,7 +54,7 @@ static uint8_t byteFromBitsInit(BitsInit &init) {
/// @param rec - The record from which to extract the value.
/// @param name - The name of the field in the record.
/// @return - The field, as translated by byteFromBitsInit().
-static uint8_t byteFromRec(const Record* rec, const std::string &name) {
+static uint8_t byteFromRec(const Record* rec, StringRef name) {
BitsInit* bits = rec->getValueAsBitsInit(name);
return byteFromBitsInit(*bits);
}
@@ -874,6 +874,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("i16imm", TYPE_IMM)
TYPE("i16i8imm", TYPE_IMM)
TYPE("GR16", TYPE_R16)
+ TYPE("GR16orGR32orGR64", TYPE_R16)
TYPE("i32mem", TYPE_M)
TYPE("i32imm", TYPE_IMM)
TYPE("i32i8imm", TYPE_IMM)
@@ -1035,6 +1036,7 @@ RecognizableInstr::rmRegisterEncodingFromString(const std::string &s,
ENCODING("RST", ENCODING_FP)
ENCODING("RSTi", ENCODING_FP)
ENCODING("GR16", ENCODING_RM)
+ ENCODING("GR16orGR32orGR64",ENCODING_RM)
ENCODING("GR32", ENCODING_RM)
ENCODING("GR32orGR64", ENCODING_RM)
ENCODING("GR64", ENCODING_RM)
@@ -1072,6 +1074,7 @@ OperandEncoding
RecognizableInstr::roRegisterEncodingFromString(const std::string &s,
uint8_t OpSize) {
ENCODING("GR16", ENCODING_REG)
+ ENCODING("GR16orGR32orGR64",ENCODING_REG)
ENCODING("GR32", ENCODING_REG)
ENCODING("GR32orGR64", ENCODING_REG)
ENCODING("GR64", ENCODING_REG)