aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/utils')
-rw-r--r--llvm/utils/TableGen/AsmMatcherEmitter.cpp72
-rw-r--r--llvm/utils/TableGen/AsmWriterEmitter.cpp17
-rw-r--r--llvm/utils/TableGen/Attributes.cpp6
-rw-r--r--llvm/utils/TableGen/CodeEmitterGen.cpp126
-rw-r--r--llvm/utils/TableGen/CodeGenDAGPatterns.cpp33
-rw-r--r--llvm/utils/TableGen/CodeGenDAGPatterns.h8
-rw-r--r--llvm/utils/TableGen/CodeGenInstruction.cpp96
-rw-r--r--llvm/utils/TableGen/CodeGenInstruction.h43
-rw-r--r--llvm/utils/TableGen/CodeGenIntrinsics.h64
-rw-r--r--llvm/utils/TableGen/CodeGenRegisters.cpp28
-rw-r--r--llvm/utils/TableGen/CodeGenRegisters.h15
-rw-r--r--llvm/utils/TableGen/CodeGenSchedule.cpp20
-rw-r--r--llvm/utils/TableGen/CodeGenSchedule.h3
-rw-r--r--llvm/utils/TableGen/CodeGenTarget.cpp81
-rw-r--r--llvm/utils/TableGen/CodeGenTarget.h2
-rw-r--r--llvm/utils/TableGen/CompressInstEmitter.cpp61
-rw-r--r--llvm/utils/TableGen/DFAEmitter.cpp38
-rw-r--r--llvm/utils/TableGen/DXILEmitter.cpp18
-rw-r--r--llvm/utils/TableGen/DecoderEmitter.cpp320
-rw-r--r--llvm/utils/TableGen/DisassemblerEmitter.cpp26
-rw-r--r--llvm/utils/TableGen/FastISelEmitter.cpp24
-rw-r--r--llvm/utils/TableGen/GICombinerEmitter.cpp46
-rw-r--r--llvm/utils/TableGen/GlobalISel/CodeExpansions.h6
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp21
-rw-r--r--llvm/utils/TableGen/GlobalISel/GIMatchTree.h6
-rw-r--r--llvm/utils/TableGen/GlobalISelEmitter.cpp159
-rw-r--r--llvm/utils/TableGen/InstrInfoEmitter.cpp59
-rw-r--r--llvm/utils/TableGen/IntrinsicEmitter.cpp376
-rw-r--r--llvm/utils/TableGen/OptParserEmitter.cpp87
-rw-r--r--llvm/utils/TableGen/PseudoLoweringEmitter.cpp3
-rw-r--r--llvm/utils/TableGen/RISCVTargetDefEmitter.cpp82
-rw-r--r--llvm/utils/TableGen/RegisterInfoEmitter.cpp152
-rw-r--r--llvm/utils/TableGen/SearchableTableEmitter.cpp12
-rw-r--r--llvm/utils/TableGen/SequenceToOffsetTable.h46
-rw-r--r--llvm/utils/TableGen/SubtargetEmitter.cpp10
-rw-r--r--llvm/utils/TableGen/TableGen.cpp9
-rw-r--r--llvm/utils/TableGen/TableGenBackends.h1
-rw-r--r--llvm/utils/TableGen/VarLenCodeEmitterGen.cpp54
-rw-r--r--llvm/utils/TableGen/VarLenCodeEmitterGen.h9
-rw-r--r--llvm/utils/TableGen/X86DisassemblerTables.cpp5
-rw-r--r--llvm/utils/TableGen/X86RecognizableInstr.cpp18
-rw-r--r--llvm/utils/TableGen/X86RecognizableInstr.h1
-rw-r--r--llvm/utils/split-file/split-file.cpp178
43 files changed, 1513 insertions, 928 deletions
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index 1acc2a86d176..c13e5b5deff6 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -595,8 +595,9 @@ struct MatchableInfo {
/// findAsmOperandNamed - Find the first AsmOperand with the specified name.
/// This does not check the suboperand index.
int findAsmOperandNamed(StringRef N, int LastIdx = -1) const {
- auto I = std::find_if(AsmOperands.begin() + LastIdx + 1, AsmOperands.end(),
- [&](const AsmOperand &Op) { return Op.SrcOpName == N; });
+ auto I =
+ llvm::find_if(llvm::drop_begin(AsmOperands, LastIdx + 1),
+ [&](const AsmOperand &Op) { return Op.SrcOpName == N; });
return (I != AsmOperands.end()) ? I - AsmOperands.begin() : -1;
}
@@ -1449,17 +1450,23 @@ void AsmMatcherInfo::buildOperandMatchInfo() {
typedef std::map<ClassInfo *, unsigned, deref<std::less<>>> OpClassMaskTy;
OpClassMaskTy OpClassMask;
+ bool CallCustomParserForAllOperands =
+ AsmParser->getValueAsBit("CallCustomParserForAllOperands");
for (const auto &MI : Matchables) {
OpClassMask.clear();
// Keep track of all operands of this instructions which belong to the
// same class.
+ unsigned NumOptionalOps = 0;
for (unsigned i = 0, e = MI->AsmOperands.size(); i != e; ++i) {
const MatchableInfo::AsmOperand &Op = MI->AsmOperands[i];
- if (Op.Class->ParserMethod.empty())
- continue;
- unsigned &OperandMask = OpClassMask[Op.Class];
- OperandMask |= (1 << i);
+ if (CallCustomParserForAllOperands || !Op.Class->ParserMethod.empty()) {
+ unsigned &OperandMask = OpClassMask[Op.Class];
+ OperandMask |= maskTrailingOnes<unsigned>(NumOptionalOps + 1)
+ << (i - NumOptionalOps);
+ }
+ if (Op.Class->IsOptional)
+ ++NumOptionalOps;
}
// Generate operand match info for each mnemonic/operand class pair.
@@ -2835,12 +2842,12 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info,
return true;
}
-static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
- const AsmMatcherInfo &Info, StringRef ClassName,
- StringToOffsetTable &StringTable,
- unsigned MaxMnemonicIndex,
- unsigned MaxFeaturesIndex,
- bool HasMnemonicFirst) {
+static void
+emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
+ const AsmMatcherInfo &Info, StringRef ClassName,
+ StringToOffsetTable &StringTable,
+ unsigned MaxMnemonicIndex, unsigned MaxFeaturesIndex,
+ bool HasMnemonicFirst, const Record &AsmParser) {
unsigned MaxMask = 0;
for (const OperandMatchEntry &OMI : Info.OperandMatchInfo) {
MaxMask |= OMI.OperandMask;
@@ -2991,9 +2998,12 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
OS << " continue;\n\n";
// Emit call to the custom parser method
+ StringRef ParserName = AsmParser.getValueAsString("OperandParserMethod");
+ if (ParserName.empty())
+ ParserName = "tryCustomParseOperand";
OS << " // call custom parse method to handle the operand\n";
- OS << " OperandMatchResultTy Result = ";
- OS << "tryCustomParseOperand(Operands, it->Class);\n";
+ OS << " OperandMatchResultTy Result = " << ParserName
+ << "(Operands, it->Class);\n";
OS << " if (Result != MatchOperand_NoMatch)\n";
OS << " return Result;\n";
OS << " }\n\n";
@@ -3028,11 +3038,9 @@ static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
OS << " if (OpndNum1 != OpndNum2) {\n";
OS << " auto &SrcOp1 = Operands[OpndNum1];\n";
OS << " auto &SrcOp2 = Operands[OpndNum2];\n";
- OS << " if (SrcOp1->isReg() && SrcOp2->isReg()) {\n";
- OS << " if (!AsmParser.regsEqual(*SrcOp1, *SrcOp2)) {\n";
- OS << " ErrorInfo = OpndNum2;\n";
- OS << " return false;\n";
- OS << " }\n";
+ OS << " if (!AsmParser.areEqualRegs(*SrcOp1, *SrcOp2)) {\n";
+ OS << " ErrorInfo = OpndNum2;\n";
+ OS << " return false;\n";
OS << " }\n";
OS << " }\n";
OS << " break;\n";
@@ -3667,7 +3675,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " else\n";
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \": \");\n";
OS << " if (ActualIdx >= Operands.size()) {\n";
- OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"actual operand index out of range \");\n";
+ OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"actual operand "
+ "index out of range\\n\");\n";
if (ReportMultipleNearMisses) {
OS << " bool ThisOperandValid = (Formal == " <<"InvalidMatchClass) || "
"isSubclass(Formal, OptionalMatchClass);\n";
@@ -3686,17 +3695,26 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " break;\n";
OS << " }\n";
OS << " } else {\n";
- OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"but formal operand not required\\n\");\n";
- OS << " break;\n";
+ OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"but formal "
+ "operand not required\\n\");\n";
OS << " }\n";
OS << " continue;\n";
} else {
- OS << " OperandsValid = (Formal == InvalidMatchClass) || isSubclass(Formal, OptionalMatchClass);\n";
- OS << " if (!OperandsValid) ErrorInfo = ActualIdx;\n";
+ OS << " if (Formal == InvalidMatchClass) {\n";
if (HasOptionalOperands) {
- OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands
+ OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands
<< ");\n";
}
+ OS << " break;\n";
+ OS << " }\n";
+ OS << " if (isSubclass(Formal, OptionalMatchClass)) {\n";
+ if (HasOptionalOperands) {
+ OS << " OptionalOperandsMask.set(FormalIdx);\n";
+ }
+ OS << " continue;\n";
+ OS << " }\n";
+ OS << " OperandsValid = false;\n";
+ OS << " ErrorInfo = ActualIdx;\n";
OS << " break;\n";
}
OS << " }\n";
@@ -3929,7 +3947,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " MII.getDeprecatedInfo(Inst, getSTI(), Info)) {\n";
OS << " SMLoc Loc = ((" << Target.getName()
<< "Operand &)*Operands[0]).getStartLoc();\n";
- OS << " getParser().Warning(Loc, Info, None);\n";
+ OS << " getParser().Warning(Loc, Info, std::nullopt);\n";
OS << " }\n";
}
@@ -3961,7 +3979,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
if (!Info.OperandMatchInfo.empty())
emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable,
MaxMnemonicIndex, FeatureBitsets.size(),
- HasMnemonicFirst);
+ HasMnemonicFirst, *AsmParser);
OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n";
diff --git a/llvm/utils/TableGen/AsmWriterEmitter.cpp b/llvm/utils/TableGen/AsmWriterEmitter.cpp
index 1d738274c75a..f2e4d15a2c75 100644
--- a/llvm/utils/TableGen/AsmWriterEmitter.cpp
+++ b/llvm/utils/TableGen/AsmWriterEmitter.cpp
@@ -412,7 +412,7 @@ void AsmWriterEmitter::EmitGetMnemonic(
<< "_t Bits = 0;\n";
while (BytesNeeded != 0) {
// Figure out how big this table section needs to be, but no bigger than 4.
- unsigned TableSize = std::min(1 << Log2_32(BytesNeeded), 4);
+ unsigned TableSize = std::min(llvm::bit_floor(BytesNeeded), 4u);
BytesNeeded -= TableSize;
TableSize *= 8; // Convert to bits;
uint64_t Mask = (1ULL << TableSize) - 1;
@@ -618,10 +618,11 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
"/// for the specified register.\n"
"const char *" << Target.getName() << ClassName << "::";
if (hasAltNames)
- O << "\ngetRegisterName(unsigned RegNo, unsigned AltIdx) {\n";
+ O << "\ngetRegisterName(MCRegister Reg, unsigned AltIdx) {\n";
else
- O << "getRegisterName(unsigned RegNo) {\n";
- O << " assert(RegNo && RegNo < " << (Registers.size()+1)
+ O << "getRegisterName(MCRegister Reg) {\n";
+ O << " unsigned RegNo = Reg.id();\n"
+ << " assert(RegNo && RegNo < " << (Registers.size() + 1)
<< " && \"Invalid register number!\");\n"
<< "\n";
@@ -1177,10 +1178,10 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
O << "#endif\n\n";
O.indent(2) << "AliasMatchingData M {\n";
- O.indent(2) << " makeArrayRef(OpToPatterns),\n";
- O.indent(2) << " makeArrayRef(Patterns),\n";
- O.indent(2) << " makeArrayRef(Conds),\n";
- O.indent(2) << " StringRef(AsmStrings, array_lengthof(AsmStrings)),\n";
+ O.indent(2) << " ArrayRef(OpToPatterns),\n";
+ O.indent(2) << " ArrayRef(Patterns),\n";
+ O.indent(2) << " ArrayRef(Conds),\n";
+ O.indent(2) << " StringRef(AsmStrings, std::size(AsmStrings)),\n";
if (MCOpPredicates.empty())
O.indent(2) << " nullptr,\n";
else
diff --git a/llvm/utils/TableGen/Attributes.cpp b/llvm/utils/TableGen/Attributes.cpp
index 1f975f52d6e7..735c53dd6fcf 100644
--- a/llvm/utils/TableGen/Attributes.cpp
+++ b/llvm/utils/TableGen/Attributes.cpp
@@ -43,7 +43,7 @@ void Attributes::emitTargetIndependentNames(raw_ostream &OS) {
<< "(FIRST, SECOND) ATTRIBUTE_ALL(FIRST, SECOND)\n";
OS << "#endif\n\n";
for (StringRef KindName : KindNames) {
- for (auto A : Records.getAllDerivedDefinitions(KindName)) {
+ for (auto *A : Records.getAllDerivedDefinitions(KindName)) {
OS << MacroName << "(" << A->getName() << ","
<< A->getValueAsString("AttrString") << ")\n";
}
@@ -63,7 +63,7 @@ void Attributes::emitTargetIndependentNames(raw_ostream &OS) {
unsigned Value = 1; // Leave zero for AttrKind::None.
for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr"}) {
OS << "First" << KindName << " = " << Value << ",\n";
- for (auto A : Records.getAllDerivedDefinitions(KindName)) {
+ for (auto *A : Records.getAllDerivedDefinitions(KindName)) {
OS << A->getName() << " = " << Value << ",\n";
Value++;
}
@@ -112,7 +112,7 @@ void Attributes::emitAttributeProperties(raw_ostream &OS) {
OS << "#undef GET_ATTR_PROP_TABLE\n";
OS << "static const uint8_t AttrPropTable[] = {\n";
for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr"}) {
- for (auto A : Records.getAllDerivedDefinitions(KindName)) {
+ for (auto *A : Records.getAllDerivedDefinitions(KindName)) {
OS << "0";
for (Init *P : *A->getValueAsListInit("Properties"))
OS << " | AttributeProperty::" << cast<DefInit>(P)->getDef()->getName();
diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp
index 1d00c3cfd069..dc4fd589eaa8 100644
--- a/llvm/utils/TableGen/CodeEmitterGen.cpp
+++ b/llvm/utils/TableGen/CodeEmitterGen.cpp
@@ -25,7 +25,6 @@
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
-#include <cassert>
#include <cstdint>
#include <map>
#include <set>
@@ -50,9 +49,8 @@ private:
std::string getInstructionCase(Record *R, CodeGenTarget &Target);
std::string getInstructionCaseForEncoding(Record *R, Record *EncodingDef,
CodeGenTarget &Target);
- void AddCodeToMergeInOperand(Record *R, BitsInit *BI,
- const std::string &VarName,
- unsigned &NumberedOp,
+ bool addCodeToMergeInOperand(Record *R, BitsInit *BI,
+ const std::string &VarName, unsigned &NumberedOp,
std::set<unsigned> &NamedOpIndices,
std::string &Case, CodeGenTarget &Target);
@@ -79,11 +77,13 @@ int CodeEmitterGen::getVariableBit(const std::string &VarName,
return -1;
}
-void CodeEmitterGen::
-AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
- unsigned &NumberedOp,
- std::set<unsigned> &NamedOpIndices,
- std::string &Case, CodeGenTarget &Target) {
+// Returns true if it succeeds, false if an error.
+bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
+ const std::string &VarName,
+ unsigned &NumberedOp,
+ std::set<unsigned> &NamedOpIndices,
+ std::string &Case,
+ CodeGenTarget &Target) {
CodeGenInstruction &CGI = Target.getInstruction(R);
// Determine if VarName actually contributes to the Inst encoding.
@@ -99,18 +99,27 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
// If we found no bits, ignore this value, otherwise emit the call to get the
// operand encoding.
- if (bit < 0) return;
-
+ if (bit < 0)
+ return true;
+
// If the operand matches by name, reference according to that
// operand number. Non-matching operands are assumed to be in
// order.
unsigned OpIdx;
- if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) {
+ std::pair<unsigned, unsigned> SubOp;
+ if (CGI.Operands.hasSubOperandAlias(VarName, SubOp)) {
+ OpIdx = CGI.Operands[SubOp.first].MIOperandNo + SubOp.second;
+ } else if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) {
// Get the machine operand number for the indicated operand.
OpIdx = CGI.Operands[OpIdx].MIOperandNo;
- assert(!CGI.Operands.isFlatOperandNotEmitted(OpIdx) &&
- "Explicitly used operand also marked as not emitted!");
} else {
+ // Fall back to positional lookup. By default, we now disable positional
+ // lookup (and print an error, below), but even so, we'll do the lookup to
+ // help print a helpful diagnostic message.
+ //
+ // TODO: When we remove useDeprecatedPositionallyEncodedOperands, delete all
+ // this code, just leaving a "no operand named X in record Y" error.
+
unsigned NumberOps = CGI.Operands.size();
/// If this operand is not supposed to be emitted by the
/// generated emitter, skip it.
@@ -123,41 +132,59 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
if (NumberedOp >=
CGI.Operands.back().MIOperandNo + CGI.Operands.back().MINumOperands) {
- std::string E;
- raw_string_ostream S(E);
- S << "Too few operands in record " << R->getName()
- << " (no match for variable " << VarName << "):\n";
- S << *R;
- PrintFatalError(R, E);
+ if (!Target.getInstructionSet()->getValueAsBit(
+ "useDeprecatedPositionallyEncodedOperands")) {
+ PrintError(R, Twine("No operand named ") + VarName + " in record " +
+ R->getName() +
+ " (would've given 'too few operands' error with "
+ "useDeprecatedPositionallyEncodedOperands=true)");
+ } else {
+ PrintError(R, "Too few operands in record " + R->getName() +
+ " (no match for variable " + VarName + ")");
+ }
+ return false;
}
OpIdx = NumberedOp++;
+
+ if (!Target.getInstructionSet()->getValueAsBit(
+ "useDeprecatedPositionallyEncodedOperands")) {
+ std::pair<unsigned, unsigned> SO =
+ CGI.Operands.getSubOperandNumber(OpIdx);
+ std::string OpName = CGI.Operands[SO.first].Name;
+ PrintError(R, Twine("No operand named ") + VarName + " in record " +
+ R->getName() + " (would've used positional operand #" +
+ Twine(SO.first) + " ('" + OpName + "') sub-op #" +
+ Twine(SO.second) +
+ " with useDeprecatedPositionallyEncodedOperands=true)");
+ return false;
+ }
}
-
+
+ if (CGI.Operands.isFlatOperandNotEmitted(OpIdx)) {
+ PrintError(R, "Operand " + VarName + " used but also marked as not emitted!");
+ return false;
+ }
+
std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(OpIdx);
- std::string &EncoderMethodName = CGI.Operands[SO.first].EncoderMethodName;
+ std::string &EncoderMethodName =
+ CGI.Operands[SO.first].EncoderMethodNames[SO.second];
if (UseAPInt)
Case += " op.clearAllBits();\n";
- // If the source operand has a custom encoder, use it. This will
- // get the encoding for all of the suboperands.
+ Case += " // op: " + VarName + "\n";
+
+ // If the source operand has a custom encoder, use it.
if (!EncoderMethodName.empty()) {
- // A custom encoder has all of the information for the
- // sub-operands, if there are more than one, so only
- // query the encoder once per source operand.
- if (SO.second == 0) {
- Case += " // op: " + VarName + "\n";
- if (UseAPInt) {
- Case += " " + EncoderMethodName + "(MI, " + utostr(OpIdx);
- Case += ", op";
- } else {
- Case += " op = " + EncoderMethodName + "(MI, " + utostr(OpIdx);
- }
- Case += ", Fixups, STI);\n";
+ if (UseAPInt) {
+ Case += " " + EncoderMethodName + "(MI, " + utostr(OpIdx);
+ Case += ", op";
+ } else {
+ Case += " op = " + EncoderMethodName + "(MI, " + utostr(OpIdx);
}
+ Case += ", Fixups, STI);\n";
} else {
- Case += " // op: " + VarName + "\n";
if (UseAPInt) {
Case += " getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
Case += ", op, Fixups, STI";
@@ -263,6 +290,7 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
}
}
}
+ return true;
}
std::string CodeEmitterGen::getInstructionCase(Record *R,
@@ -310,14 +338,25 @@ std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *Enc
// Loop over all of the fields in the instruction, determining which are the
// operands to the instruction.
+ bool Success = true;
for (const RecordVal &RV : EncodingDef->getValues()) {
// Ignore fixed fields in the record, we're looking for values like:
// bits<5> RST = { ?, ?, ?, ?, ? };
if (RV.isNonconcreteOK() || RV.getValue()->isComplete())
continue;
- AddCodeToMergeInOperand(R, BI, std::string(RV.getName()), NumberedOp,
- NamedOpIndices, Case, Target);
+ Success &=
+ addCodeToMergeInOperand(R, BI, std::string(RV.getName()), NumberedOp,
+ NamedOpIndices, Case, Target);
+ }
+
+ if (!Success) {
+ // Dump the record, so we can see what's going on...
+ std::string E;
+ raw_string_ostream S(E);
+ S << "Dumping record for previous error:\n";
+ S << *R;
+ PrintNote(E);
}
StringRef PostEmitter = R->getValueAsString("PostEncoderMethod");
@@ -370,8 +409,8 @@ void CodeEmitterGen::emitInstructionBaseValues(
// Start by filling in fixed values.
APInt Value(BitWidth, 0);
for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) {
- if (BitInit *B = dyn_cast<BitInit>(BI->getBit(e - i - 1)))
- Value |= APInt(BitWidth, (uint64_t)B->getValue()) << (e - i - 1);
+ if (auto *B = dyn_cast<BitInit>(BI->getBit(i)); B && B->getValue())
+ Value.setBit(i);
}
o << " ";
emitInstBits(o, Value);
@@ -478,9 +517,8 @@ void CodeEmitterGen::run(raw_ostream &o) {
o << " const unsigned opcode = MI.getOpcode();\n"
<< " if (Scratch.getBitWidth() != " << BitWidth << ")\n"
<< " Scratch = Scratch.zext(" << BitWidth << ");\n"
- << " Inst = APInt(" << BitWidth
- << ", makeArrayRef(InstBits + opcode * " << NumWords << ", " << NumWords
- << "));\n"
+ << " Inst = APInt(" << BitWidth << ", ArrayRef(InstBits + opcode * "
+ << NumWords << ", " << NumWords << "));\n"
<< " APInt &Value = Inst;\n"
<< " APInt &op = Scratch;\n"
<< " switch (opcode) {\n";
diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
index c15728ac7d23..dd04778e2dbe 100644
--- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -544,9 +544,9 @@ bool TypeInfer::EnforceSmallerThan(TypeSetByHwMode &Small, TypeSetByHwMode &Big,
// 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().getKnownMinSize());
+ A.getSizeInBits().getKnownMinValue());
auto BSize = std::make_tuple(B.isScalableVector(), B.getScalarSizeInBits(),
- B.getSizeInBits().getKnownMinSize());
+ B.getSizeInBits().getKnownMinValue());
return ASize < BSize;
};
auto SameKindLE = [](MVT A, MVT B) -> bool {
@@ -558,9 +558,9 @@ bool TypeInfer::EnforceSmallerThan(TypeSetByHwMode &Small, TypeSetByHwMode &Big,
return false;
return std::make_tuple(A.getScalarSizeInBits(),
- A.getSizeInBits().getKnownMinSize()) <=
+ A.getSizeInBits().getKnownMinValue()) <=
std::make_tuple(B.getScalarSizeInBits(),
- B.getSizeInBits().getKnownMinSize());
+ B.getSizeInBits().getKnownMinValue());
};
for (unsigned M : Modes) {
@@ -740,7 +740,7 @@ bool TypeInfer::EnforceSameNumElts(TypeSetByHwMode &V, TypeSetByHwMode &W) {
auto NoLength = [](const SmallDenseSet<ElementCount> &Lengths,
MVT T) -> bool {
return !Lengths.count(T.isVector() ? T.getVectorElementCount()
- : ElementCount::getNull());
+ : ElementCount());
};
SmallVector<unsigned, 4> Modes;
@@ -751,11 +751,9 @@ bool TypeInfer::EnforceSameNumElts(TypeSetByHwMode &V, TypeSetByHwMode &W) {
SmallDenseSet<ElementCount> VN, WN;
for (MVT T : VS)
- VN.insert(T.isVector() ? T.getVectorElementCount()
- : ElementCount::getNull());
+ VN.insert(T.isVector() ? T.getVectorElementCount() : ElementCount());
for (MVT T : WS)
- WN.insert(T.isVector() ? T.getVectorElementCount()
- : ElementCount::getNull());
+ WN.insert(T.isVector() ? T.getVectorElementCount() : ElementCount());
Changed |= berase_if(VS, std::bind(NoLength, WN, std::placeholders::_1));
Changed |= berase_if(WS, std::bind(NoLength, VN, std::placeholders::_1));
@@ -2998,7 +2996,7 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
// chain.
if (Int.IS.RetVTs.empty())
Operator = getDAGPatterns().get_intrinsic_void_sdnode();
- else if (Int.ModRef != CodeGenIntrinsic::NoMem || Int.hasSideEffects)
+ else if (!Int.ME.doesNotAccessMemory() || Int.hasSideEffects)
// Has side-effects, requires chain.
Operator = getDAGPatterns().get_intrinsic_w_chain_sdnode();
else // Otherwise, no chain.
@@ -3637,16 +3635,17 @@ public:
if (N->NodeHasProperty(SDNPHasChain, CDP)) hasChain = true;
if (const CodeGenIntrinsic *IntInfo = N->getIntrinsicInfo(CDP)) {
+ ModRefInfo MR = IntInfo->ME.getModRef();
// If this is an intrinsic, analyze it.
- if (IntInfo->ModRef & CodeGenIntrinsic::MR_Ref)
- mayLoad = true;// These may load memory.
+ if (isRefSet(MR))
+ mayLoad = true; // These may load memory.
- if (IntInfo->ModRef & CodeGenIntrinsic::MR_Mod)
- mayStore = true;// Intrinsics that can write to memory are 'mayStore'.
+ if (isModSet(MR))
+ mayStore = true; // Intrinsics that can write to memory are 'mayStore'.
- if (IntInfo->ModRef >= CodeGenIntrinsic::ReadWriteMem ||
- IntInfo->hasSideEffects)
- // ReadWriteMem intrinsics can have other strange effects.
+ // Consider intrinsics that don't specify any restrictions on memory
+ // effects as having a side-effect.
+ if (IntInfo->ME == MemoryEffects::unknown() || IntInfo->hasSideEffects)
hasSideEffects = true;
}
}
diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.h b/llvm/utils/TableGen/CodeGenDAGPatterns.h
index dbdc72f0873a..ec35e6680088 100644
--- a/llvm/utils/TableGen/CodeGenDAGPatterns.h
+++ b/llvm/utils/TableGen/CodeGenDAGPatterns.h
@@ -50,7 +50,7 @@ using TreePatternNodePtr = std::shared_ptr<TreePatternNode>;
/// To reduce the allocations even further, make MachineValueTypeSet own
/// the storage and use std::array as the bit container.
struct MachineValueTypeSet {
- static_assert(std::is_same<std::underlying_type<MVT::SimpleValueType>::type,
+ static_assert(std::is_same<std::underlying_type_t<MVT::SimpleValueType>,
uint8_t>::value,
"Change uint8_t here to the SimpleValueType's type");
static unsigned constexpr Capacity = std::numeric_limits<uint8_t>::max()+1;
@@ -69,7 +69,7 @@ struct MachineValueTypeSet {
unsigned size() const {
unsigned Count = 0;
for (WordType W : Words)
- Count += countPopulation(W);
+ Count += llvm::popcount(W);
return Count;
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
@@ -150,7 +150,7 @@ struct MachineValueTypeSet {
WordType W = Set->Words[SkipWords];
W &= maskLeadingOnes<WordType>(WordWidth-SkipBits);
if (W != 0)
- return Count + findFirstSet(W);
+ return Count + llvm::countr_zero(W);
Count += WordWidth;
SkipWords++;
}
@@ -158,7 +158,7 @@ struct MachineValueTypeSet {
for (unsigned i = SkipWords; i != NumWords; ++i) {
WordType W = Set->Words[i];
if (W != 0)
- return Count + findFirstSet(W);
+ return Count + llvm::countr_zero(W);
Count += WordWidth;
}
return Capacity;
diff --git a/llvm/utils/TableGen/CodeGenInstruction.cpp b/llvm/utils/TableGen/CodeGenInstruction.cpp
index ba12633ace8c..238c6a1b6ba8 100644
--- a/llvm/utils/TableGen/CodeGenInstruction.cpp
+++ b/llvm/utils/TableGen/CodeGenInstruction.cpp
@@ -67,6 +67,10 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
ArgName = InDI->getArgNameStr(i-NumDefs);
}
+ DagInit *SubArgDag = dyn_cast<DagInit>(ArgInit);
+ if (SubArgDag)
+ ArgInit = SubArgDag->getOperator();
+
DefInit *Arg = dyn_cast<DefInit>(ArgInit);
if (!Arg)
PrintFatalError(R->getLoc(), "Illegal operand for the '" + R->getName() +
@@ -116,10 +120,11 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
} else if (Rec->isSubClassOf("RegisterClass")) {
OperandType = "OPERAND_REGISTER";
} else if (!Rec->isSubClassOf("PointerLikeRegClass") &&
- !Rec->isSubClassOf("unknown_class"))
+ !Rec->isSubClassOf("unknown_class")) {
PrintFatalError(R->getLoc(), "Unknown operand class '" + Rec->getName() +
"' in '" + R->getName() +
"' instruction!");
+ }
// Check that the operand has a name and that it's unique.
if (ArgName.empty())
@@ -132,20 +137,60 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
Twine(i) +
" has the same name as a previous operand!");
- OperandList.emplace_back(
+ OperandInfo &OpInfo = OperandList.emplace_back(
Rec, std::string(ArgName), std::string(PrintMethod),
- std::string(EncoderMethod), OperandNamespace + "::" + OperandType,
- MIOperandNo, NumOps, MIOpInfo);
+ OperandNamespace + "::" + OperandType, MIOperandNo, NumOps, MIOpInfo);
+
+ if (SubArgDag) {
+ if (SubArgDag->getNumArgs() != NumOps) {
+ PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +
+ "', operand #" + Twine(i) + " has " +
+ Twine(SubArgDag->getNumArgs()) +
+ " sub-arg names, expected " +
+ Twine(NumOps) + ".");
+ }
+
+ for (unsigned j = 0; j < NumOps; ++j) {
+ if (!isa<UnsetInit>(SubArgDag->getArg(j)))
+ PrintFatalError(R->getLoc(),
+ "In instruction '" + R->getName() + "', operand #" +
+ Twine(i) + " sub-arg #" + Twine(j) +
+ " has unexpected operand (expected only $name).");
+
+ StringRef SubArgName = SubArgDag->getArgNameStr(j);
+ if (SubArgName.empty())
+ PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +
+ "', operand #" + Twine(i) +
+ " has no name!");
+ if (!OperandNames.insert(std::string(SubArgName)).second)
+ PrintFatalError(R->getLoc(),
+ "In instruction '" + R->getName() + "', operand #" +
+ Twine(i) + " sub-arg #" + Twine(j) +
+ " has the same name as a previous operand!");
+
+ if (auto MaybeEncoderMethod =
+ cast<DefInit>(MIOpInfo->getArg(j))
+ ->getDef()
+ ->getValueAsOptionalString("EncoderMethod")) {
+ OpInfo.EncoderMethodNames[j] = *MaybeEncoderMethod;
+ }
+
+ OpInfo.SubOpNames[j] = SubArgName;
+ SubOpAliases[SubArgName] = std::make_pair(MIOperandNo, j);
+ }
+ } else if (!EncoderMethod.empty()) {
+ // If we have no explicit sub-op dag, but have an top-level encoder
+ // method, the single encoder will multiple sub-ops, itself.
+ OpInfo.EncoderMethodNames[0] = EncoderMethod;
+ for (unsigned j = 1; j < NumOps; ++j)
+ OpInfo.DoNotEncode[j] = true;
+ }
+
MIOperandNo += NumOps;
}
if (VariadicOuts)
--NumDefs;
-
- // Make sure the constraints list for each operand is large enough to hold
- // constraint info, even if none is present.
- for (OperandInfo &OpInfo : OperandList)
- OpInfo.Constraints.resize(OpInfo.MINumOperands);
}
@@ -175,6 +220,17 @@ bool CGIOperandList::hasOperandNamed(StringRef Name, unsigned &OpIdx) const {
return false;
}
+bool CGIOperandList::hasSubOperandAlias(
+ StringRef Name, std::pair<unsigned, unsigned> &SubOp) const {
+ assert(!Name.empty() && "Cannot search for operand with no name!");
+ auto SubOpIter = SubOpAliases.find(Name);
+ if (SubOpIter != SubOpAliases.end()) {
+ SubOp = SubOpIter->second;
+ return true;
+ }
+ return false;
+}
+
std::pair<unsigned,unsigned>
CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
if (Op.empty() || Op[0] != '$')
@@ -195,7 +251,21 @@ CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
OpName = OpName.substr(0, DotIdx);
}
- unsigned OpIdx = getOperandNamed(OpName);
+ unsigned OpIdx;
+
+ if (std::pair<unsigned, unsigned> SubOp; hasSubOperandAlias(OpName, SubOp)) {
+ // Found a name for a piece of an operand, just return it directly.
+ if (!SubOpName.empty()) {
+ PrintFatalError(
+ TheDef->getLoc(),
+ TheDef->getName() +
+ ": Cannot use dotted suboperand name within suboperand '" +
+ OpName + "'");
+ }
+ return SubOp;
+ }
+
+ OpIdx = getOperandNamed(OpName);
if (SubOpName.empty()) { // If no suboperand name was specified:
// If one was needed, throw.
@@ -350,8 +420,6 @@ void CGIOperandList::ProcessDisableEncoding(StringRef DisableEncoding) {
std::pair<unsigned,unsigned> Op = ParseOperandName(OpName, false);
// Mark the operand as not-to-be encoded.
- if (Op.second >= OperandList[Op.first].DoNotEncode.size())
- OperandList[Op.first].DoNotEncode.resize(Op.second+1);
OperandList[Op.first].DoNotEncode[Op.second] = true;
}
@@ -511,9 +579,9 @@ FlattenAsmStringVariants(StringRef Cur, unsigned Variant) {
return Res;
}
-bool CodeGenInstruction::isOperandImpl(unsigned i,
+bool CodeGenInstruction::isOperandImpl(StringRef OpListName, unsigned i,
StringRef PropertyName) const {
- DagInit *ConstraintList = TheDef->getValueAsDag("InOperandList");
+ DagInit *ConstraintList = TheDef->getValueAsDag(OpListName);
if (!ConstraintList || i >= ConstraintList->getNumArgs())
return false;
diff --git a/llvm/utils/TableGen/CodeGenInstruction.h b/llvm/utils/TableGen/CodeGenInstruction.h
index d3de6d95780c..72626caada56 100644
--- a/llvm/utils/TableGen/CodeGenInstruction.h
+++ b/llvm/utils/TableGen/CodeGenInstruction.h
@@ -14,6 +14,7 @@
#define LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H
#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MachineValueType.h"
#include <cassert>
@@ -83,13 +84,16 @@ template <typename T> class ArrayRef;
/// otherwise, it's empty.
std::string Name;
+ /// The names of sub-operands, if given, otherwise empty.
+ std::vector<std::string> SubOpNames;
+
/// PrinterMethodName - The method used to print operands of this type in
/// the asmprinter.
std::string PrinterMethodName;
- /// EncoderMethodName - The method used to get the machine operand value
- /// for binary encoding. "getMachineOpValue" by default.
- std::string EncoderMethodName;
+ /// The method used to get the machine operand value for binary
+ /// encoding, per sub-operand. If empty, uses "getMachineOpValue".
+ std::vector<std::string> EncoderMethodNames;
/// OperandType - A value from MCOI::OperandType representing the type of
/// the operand.
@@ -118,12 +122,12 @@ template <typename T> class ArrayRef;
std::vector<ConstraintInfo> Constraints;
OperandInfo(Record *R, const std::string &N, const std::string &PMN,
- const std::string &EMN, const std::string &OT, unsigned MION,
- unsigned MINO, DagInit *MIOI)
- : Rec(R), Name(N), PrinterMethodName(PMN), EncoderMethodName(EMN),
- OperandType(OT), MIOperandNo(MION), MINumOperands(MINO),
- MIOperandInfo(MIOI) {}
-
+ const std::string &OT, unsigned MION, unsigned MINO,
+ DagInit *MIOI)
+ : Rec(R), Name(N), SubOpNames(MINO), PrinterMethodName(PMN),
+ EncoderMethodNames(MINO), OperandType(OT), MIOperandNo(MION),
+ MINumOperands(MINO), DoNotEncode(MINO), MIOperandInfo(MIOI),
+ Constraints(MINO) {}
/// getTiedOperand - If this operand is tied to another one, return the
/// other operand number. Otherwise, return -1.
@@ -149,6 +153,9 @@ template <typename T> class ArrayRef;
/// type (which is a record).
std::vector<OperandInfo> OperandList;
+ /// SubOpAliases - List of alias names for suboperands.
+ StringMap<std::pair<unsigned, unsigned>> SubOpAliases;
+
// Information gleaned from the operand list.
bool isPredicable;
bool hasOptionalDef;
@@ -179,6 +186,9 @@ template <typename T> class ArrayRef;
/// operand. Otherwise, return false.
bool hasOperandNamed(StringRef Name, unsigned &OpIdx) const;
+ bool hasSubOperandAlias(StringRef Name,
+ std::pair<unsigned, unsigned> &SubOp) const;
+
/// ParseOperandName - Parse an operand name like "$foo" or "$foo.bar",
/// where $foo is a whole operand and $foo.bar refers to a suboperand.
/// This aborts if the name is invalid. If AllowWholeOp is true, references
@@ -313,17 +323,22 @@ template <typename T> class ArrayRef;
// This can be used on intructions that use typeN or ptypeN to identify
// operands that should be considered as pointers even though SelectionDAG
// didn't make a distinction between integer and pointers.
- bool isOperandAPointer(unsigned i) const {
- return isOperandImpl(i, "IsPointer");
+ bool isInOperandAPointer(unsigned i) const {
+ return isOperandImpl("InOperandList", i, "IsPointer");
+ }
+
+ bool isOutOperandAPointer(unsigned i) const {
+ return isOperandImpl("OutOperandList", i, "IsPointer");
}
/// Check if the operand is required to be an immediate.
- bool isOperandImmArg(unsigned i) const {
- return isOperandImpl(i, "IsImmediate");
+ bool isInOperandImmArg(unsigned i) const {
+ return isOperandImpl("InOperandList", i, "IsImmediate");
}
private:
- bool isOperandImpl(unsigned i, StringRef PropertyName) const;
+ bool isOperandImpl(StringRef OpListName, unsigned i,
+ StringRef PropertyName) const;
};
diff --git a/llvm/utils/TableGen/CodeGenIntrinsics.h b/llvm/utils/TableGen/CodeGenIntrinsics.h
index 599795e3c065..0558918b3028 100644
--- a/llvm/utils/TableGen/CodeGenIntrinsics.h
+++ b/llvm/utils/TableGen/CodeGenIntrinsics.h
@@ -14,7 +14,9 @@
#define LLVM_UTILS_TABLEGEN_CODEGENINTRINSICS_H
#include "SDNodeProperties.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/MachineValueType.h"
+#include "llvm/Support/ModRef.h"
#include <string>
#include <vector>
@@ -57,51 +59,8 @@ struct CodeGenIntrinsic {
IntrinsicSignature IS;
- /// Bit flags describing the type (ref/mod) and location of memory
- /// accesses that may be performed by the intrinsics. Analogous to
- /// \c FunctionModRefBehaviour.
- enum ModRefBits {
- /// The intrinsic may access memory that is otherwise inaccessible via
- /// LLVM IR.
- MR_InaccessibleMem = 1,
-
- /// The intrinsic may access memory through pointer arguments.
- /// LLVM IR.
- MR_ArgMem = 2,
-
- /// The intrinsic may access memory anywhere, i.e. it is not restricted
- /// to access through pointer arguments.
- MR_Anywhere = 4 | MR_ArgMem | MR_InaccessibleMem,
-
- /// The intrinsic may read memory.
- MR_Ref = 8,
-
- /// The intrinsic may write memory.
- MR_Mod = 16,
-
- /// The intrinsic may both read and write memory.
- MR_ModRef = MR_Ref | MR_Mod,
- };
-
- /// Memory mod/ref behavior of this intrinsic, corresponding to intrinsic
- /// properties (IntrReadMem, IntrArgMemOnly, etc.).
- enum ModRefBehavior {
- NoMem = 0,
- ReadArgMem = MR_Ref | MR_ArgMem,
- ReadInaccessibleMem = MR_Ref | MR_InaccessibleMem,
- ReadInaccessibleMemOrArgMem = MR_Ref | MR_ArgMem | MR_InaccessibleMem,
- ReadMem = MR_Ref | MR_Anywhere,
- WriteArgMem = MR_Mod | MR_ArgMem,
- WriteInaccessibleMem = MR_Mod | MR_InaccessibleMem,
- WriteInaccessibleMemOrArgMem = MR_Mod | MR_ArgMem | MR_InaccessibleMem,
- WriteMem = MR_Mod | MR_Anywhere,
- ReadWriteArgMem = MR_ModRef | MR_ArgMem,
- ReadWriteInaccessibleMem = MR_ModRef | MR_InaccessibleMem,
- ReadWriteInaccessibleMemOrArgMem = MR_ModRef | MR_ArgMem |
- MR_InaccessibleMem,
- ReadWriteMem = MR_ModRef | MR_Anywhere,
- };
- ModRefBehavior ModRef;
+ /// Memory effects of the intrinsic.
+ MemoryEffects ME = MemoryEffects::unknown();
/// SDPatternOperator Properties applied to the intrinsic.
unsigned Properties;
@@ -154,6 +113,7 @@ struct CodeGenIntrinsic {
NoCapture,
NoAlias,
NoUndef,
+ NonNull,
Returned,
ReadOnly,
WriteOnly,
@@ -163,20 +123,20 @@ struct CodeGenIntrinsic {
};
struct ArgAttribute {
- unsigned Index;
ArgAttrKind Kind;
uint64_t Value;
- ArgAttribute(unsigned Idx, ArgAttrKind K, uint64_t V)
- : Index(Idx), Kind(K), Value(V) {}
+ ArgAttribute(ArgAttrKind K, uint64_t V) : Kind(K), Value(V) {}
bool operator<(const ArgAttribute &Other) const {
- return std::tie(Index, Kind, Value) <
- std::tie(Other.Index, Other.Kind, Other.Value);
+ return std::tie(Kind, Value) < std::tie(Other.Kind, Other.Value);
}
};
- std::vector<ArgAttribute> ArgumentAttributes;
+ /// Vector of attributes for each argument.
+ SmallVector<SmallVector<ArgAttribute, 0>> ArgumentAttributes;
+
+ void addArgAttribute(unsigned Idx, ArgAttrKind AK, uint64_t V = 0);
bool hasProperty(enum SDNP Prop) const {
return Properties & (1 << Prop);
@@ -217,6 +177,8 @@ public:
bool empty() const { return Intrinsics.empty(); }
size_t size() const { return Intrinsics.size(); }
+ auto begin() const { return Intrinsics.begin(); }
+ auto end() const { return Intrinsics.end(); }
CodeGenIntrinsic &operator[](size_t Pos) { return Intrinsics[Pos]; }
const CodeGenIntrinsic &operator[](size_t Pos) const {
return Intrinsics[Pos];
diff --git a/llvm/utils/TableGen/CodeGenRegisters.cpp b/llvm/utils/TableGen/CodeGenRegisters.cpp
index 93ed86cfb7e5..8ad8a7a5bc9b 100644
--- a/llvm/utils/TableGen/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/CodeGenRegisters.cpp
@@ -154,8 +154,8 @@ CodeGenRegister::CodeGenRegister(Record *R, unsigned Enum)
: TheDef(R), EnumValue(Enum),
CostPerUse(R->getValueAsListOfInts("CostPerUse")),
CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")),
- HasDisjunctSubRegs(false), SubRegsComplete(false),
- SuperRegsComplete(false), TopoSig(~0u) {
+ HasDisjunctSubRegs(false), Constant(R->getValueAsBit("isConstant")),
+ SubRegsComplete(false), SuperRegsComplete(false), TopoSig(~0u) {
Artificial = R->getValueAsBit("isArtificial");
}
@@ -803,10 +803,12 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
Allocatable = R->getValueAsBit("isAllocatable");
AltOrderSelect = R->getValueAsString("AltOrderSelect");
int AllocationPriority = R->getValueAsInt("AllocationPriority");
- if (AllocationPriority < 0 || AllocationPriority > 63)
- PrintFatalError(R->getLoc(), "AllocationPriority out of range [0,63]");
+ if (!isUInt<5>(AllocationPriority))
+ PrintFatalError(R->getLoc(), "AllocationPriority out of range [0,31]");
this->AllocationPriority = AllocationPriority;
+ GlobalPriority = R->getValueAsBit("GlobalPriority");
+
BitsInit *TSF = R->getValueAsBitsInit("TSFlags");
for (unsigned I = 0, E = TSF->getNumBits(); I != E; ++I) {
BitInit *Bit = cast<BitInit>(TSF->getBit(I));
@@ -821,7 +823,8 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank,
StringRef Name, Key Props)
: Members(*Props.Members), TheDef(nullptr), Name(std::string(Name)),
TopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1), RSI(Props.RSI),
- CopyCost(0), Allocatable(true), AllocationPriority(0), TSFlags(0) {
+ CopyCost(0), Allocatable(true), AllocationPriority(0),
+ GlobalPriority(false), TSFlags(0) {
Artificial = true;
GeneratePressureSet = false;
for (const auto R : Members) {
@@ -849,6 +852,7 @@ void CodeGenRegisterClass::inheritProperties(CodeGenRegBank &RegBank) {
});
AltOrderSelect = Super.AltOrderSelect;
AllocationPriority = Super.AllocationPriority;
+ GlobalPriority = Super.GlobalPriority;
TSFlags = Super.TSFlags;
GeneratePressureSet |= Super.GeneratePressureSet;
@@ -1020,7 +1024,7 @@ void CodeGenRegisterClass::computeSubClasses(CodeGenRegBank &RegBank) {
RC.inheritProperties(RegBank);
}
-Optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>>
+std::optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>>
CodeGenRegisterClass::getMatchingSubClassWithSubRegs(
CodeGenRegBank &RegBank, const CodeGenSubRegIndex *SubIdx) const {
auto SizeOrder = [this](const CodeGenRegisterClass *A,
@@ -1040,7 +1044,7 @@ CodeGenRegisterClass::getMatchingSubClassWithSubRegs(
// index and order them by size. BiggestSuperRC should always be first.
CodeGenRegisterClass *BiggestSuperRegRC = getSubClassWithSubReg(SubIdx);
if (!BiggestSuperRegRC)
- return None;
+ return std::nullopt;
BitVector SuperRegRCsBV = BiggestSuperRegRC->getSubClasses();
std::vector<CodeGenRegisterClass *> SuperRegRCs;
for (auto &RC : RegClasses)
@@ -1103,7 +1107,7 @@ CodeGenRegisterClass::getMatchingSubClassWithSubRegs(
return std::make_pair(ChosenSuperRegClass, SubRegRC);
}
- return None;
+ return std::nullopt;
}
void CodeGenRegisterClass::getSuperRegClasses(const CodeGenSubRegIndex *SubIdx,
@@ -1365,11 +1369,15 @@ getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex *, 8> &Parts) {
unsigned Size = Parts.front()->Size;
unsigned LastOffset = Parts.front()->Offset;
unsigned LastSize = Parts.front()->Size;
+ unsigned UnknownSize = (uint16_t)-1;
for (unsigned i = 1, e = Parts.size(); i != e; ++i) {
Name += '_';
Name += Parts[i]->getName();
- Size += Parts[i]->Size;
- if (Parts[i]->Offset != (LastOffset + LastSize))
+ if (Size == UnknownSize || Parts[i]->Size == UnknownSize)
+ Size = UnknownSize;
+ else
+ Size += Parts[i]->Size;
+ if (LastSize == UnknownSize || Parts[i]->Offset != (LastOffset + LastSize))
isContinuous = false;
LastOffset = Parts[i]->Offset;
LastSize = Parts[i]->Size;
diff --git a/llvm/utils/TableGen/CodeGenRegisters.h b/llvm/utils/TableGen/CodeGenRegisters.h
index e5e92fc81f50..765425ed68cb 100644
--- a/llvm/utils/TableGen/CodeGenRegisters.h
+++ b/llvm/utils/TableGen/CodeGenRegisters.h
@@ -154,6 +154,7 @@ namespace llvm {
bool CoveredBySubRegs;
bool HasDisjunctSubRegs;
bool Artificial;
+ bool Constant;
// Map SubRegIndex -> Register.
typedef std::map<CodeGenSubRegIndex *, CodeGenRegister *,
@@ -233,7 +234,7 @@ namespace llvm {
const RegUnitList &getRegUnits() const { return RegUnits; }
ArrayRef<LaneBitmask> getRegUnitLaneMasks() const {
- return makeArrayRef(RegUnitLaneMasks).slice(0, NativeRegUnits.count());
+ return ArrayRef(RegUnitLaneMasks).slice(0, NativeRegUnits.count());
}
// Get the native register units. This is a prefix of getRegUnits().
@@ -331,6 +332,7 @@ namespace llvm {
bool Allocatable;
StringRef AltOrderSelect;
uint8_t AllocationPriority;
+ bool GlobalPriority;
uint8_t TSFlags;
/// Contains the combination of the lane masks of all subregisters.
LaneBitmask LaneMask;
@@ -390,7 +392,7 @@ namespace llvm {
/// \return std::pair<SubClass, SubRegClass> where SubClass is a SubClass is
/// a class where every register has SubIdx and SubRegClass is a class where
/// every register is covered by the SubIdx subregister of SubClass.
- Optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>>
+ std::optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>>
getMatchingSubClassWithSubRegs(CodeGenRegBank &RegBank,
const CodeGenSubRegIndex *SubIdx) const;
@@ -470,6 +472,13 @@ namespace llvm {
// Called by CodeGenRegBank::CodeGenRegBank().
static void computeSubClasses(CodeGenRegBank&);
+
+ // Get ordering value among register base classes.
+ std::optional<int> getBaseClassOrder() const {
+ if (TheDef && !TheDef->isValueUnset("BaseClassOrder"))
+ return TheDef->getValueAsInt("BaseClassOrder");
+ return {};
+ }
};
// Register categories are used when we need to deterine the category a
@@ -522,7 +531,7 @@ namespace llvm {
ArrayRef<const CodeGenRegister*> getRoots() const {
assert(!(Roots[1] && !Roots[0]) && "Invalid roots array");
- return makeArrayRef(Roots, !!Roots[0] + !!Roots[1]);
+ return ArrayRef(Roots, !!Roots[0] + !!Roots[1]);
}
};
diff --git a/llvm/utils/TableGen/CodeGenSchedule.cpp b/llvm/utils/TableGen/CodeGenSchedule.cpp
index 4933bfc476f4..441a088c1731 100644
--- a/llvm/utils/TableGen/CodeGenSchedule.cpp
+++ b/llvm/utils/TableGen/CodeGenSchedule.cpp
@@ -100,7 +100,7 @@ struct InstRegexOp : public SetTheory::Operator {
if (removeParens(Original).find_first_of("|?") != std::string::npos)
FirstMeta = 0;
- Optional<Regex> Regexpr = None;
+ std::optional<Regex> Regexpr;
StringRef Prefix = Original.substr(0, FirstMeta);
StringRef PatStr = Original.substr(FirstMeta);
if (!PatStr.empty()) {
@@ -492,7 +492,7 @@ void CodeGenSchedModels::collectLoadStoreQueueInfo() {
if (PM.StoreQueue) {
PrintError(Queue->getLoc(),
"Expected a single StoreQueue definition");
- PrintNote(PM.LoadQueue->getLoc(),
+ PrintNote(PM.StoreQueue->getLoc(),
"Previous definition of StoreQueue was here");
}
@@ -734,14 +734,12 @@ unsigned CodeGenSchedModels::getSchedRWIdx(const Record *Def,
}
bool CodeGenSchedModels::hasReadOfWrite(Record *WriteDef) const {
- for (const CodeGenSchedRW &Read : SchedReads) {
- Record *ReadDef = Read.TheDef;
- if (!ReadDef || !ReadDef->isSubClassOf("ProcReadAdvance"))
- continue;
-
- RecVec ValidWrites = ReadDef->getValueAsListOfDefs("ValidWrites");
- if (is_contained(ValidWrites, WriteDef)) {
- return true;
+ for (auto& ProcModel : ProcModels) {
+ const RecVec &RADefs = ProcModel.ReadAdvanceDefs;
+ for (auto& RADef : RADefs) {
+ RecVec ValidWrites = RADef->getValueAsListOfDefs("ValidWrites");
+ if (is_contained(ValidWrites, WriteDef))
+ return true;
}
}
return false;
@@ -840,7 +838,7 @@ unsigned CodeGenSchedModels::findRWForSequence(ArrayRef<unsigned> Seq,
std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites;
auto I = find_if(RWVec, [Seq](CodeGenSchedRW &RW) {
- return makeArrayRef(RW.Sequence) == Seq;
+ return ArrayRef(RW.Sequence) == Seq;
});
// Index zero reserved for invalid RW.
return I == RWVec.end() ? 0 : std::distance(RWVec.begin(), I);
diff --git a/llvm/utils/TableGen/CodeGenSchedule.h b/llvm/utils/TableGen/CodeGenSchedule.h
index f7e35b0c808f..bbf5381ad086 100644
--- a/llvm/utils/TableGen/CodeGenSchedule.h
+++ b/llvm/utils/TableGen/CodeGenSchedule.h
@@ -145,8 +145,7 @@ struct CodeGenSchedClass {
bool isKeyEqual(Record *IC, ArrayRef<unsigned> W,
ArrayRef<unsigned> R) const {
- return ItinClassDef == IC && makeArrayRef(Writes) == W &&
- makeArrayRef(Reads) == R;
+ return ItinClassDef == IC && ArrayRef(Writes) == W && ArrayRef(Reads) == R;
}
// Is this class generated from a variants if existing classes? Instructions
diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp
index af2e8576af2e..b7240f01300c 100644
--- a/llvm/utils/TableGen/CodeGenTarget.cpp
+++ b/llvm/utils/TableGen/CodeGenTarget.cpp
@@ -91,8 +91,11 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v256i1: return "MVT::v256i1";
case MVT::v512i1: return "MVT::v512i1";
case MVT::v1024i1: return "MVT::v1024i1";
+ case MVT::v2048i1: return "MVT::v2048i1";
case MVT::v128i2: return "MVT::v128i2";
+ case MVT::v256i2: return "MVT::v256i2";
case MVT::v64i4: return "MVT::v64i4";
+ case MVT::v128i4: return "MVT::v128i4";
case MVT::v1i8: return "MVT::v1i8";
case MVT::v2i8: return "MVT::v2i8";
case MVT::v4i8: return "MVT::v4i8";
@@ -123,6 +126,10 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v6i32: return "MVT::v6i32";
case MVT::v7i32: return "MVT::v7i32";
case MVT::v8i32: return "MVT::v8i32";
+ case MVT::v9i32: return "MVT::v9i32";
+ case MVT::v10i32: return "MVT::v10i32";
+ case MVT::v11i32: return "MVT::v11i32";
+ case MVT::v12i32: return "MVT::v12i32";
case MVT::v16i32: return "MVT::v16i32";
case MVT::v32i32: return "MVT::v32i32";
case MVT::v64i32: return "MVT::v64i32";
@@ -169,6 +176,10 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v6f32: return "MVT::v6f32";
case MVT::v7f32: return "MVT::v7f32";
case MVT::v8f32: return "MVT::v8f32";
+ case MVT::v9f32: return "MVT::v9f32";
+ case MVT::v10f32: return "MVT::v10f32";
+ case MVT::v11f32: return "MVT::v11f32";
+ case MVT::v12f32: return "MVT::v12f32";
case MVT::v16f32: return "MVT::v16f32";
case MVT::v32f32: return "MVT::v32f32";
case MVT::v64f32: return "MVT::v64f32";
@@ -358,11 +369,9 @@ CodeGenRegBank &CodeGenTarget::getRegBank() const {
return *RegBank;
}
-Optional<CodeGenRegisterClass *>
-CodeGenTarget::getSuperRegForSubReg(const ValueTypeByHwMode &ValueTy,
- CodeGenRegBank &RegBank,
- const CodeGenSubRegIndex *SubIdx,
- bool MustBeAllocatable) const {
+std::optional<CodeGenRegisterClass *> CodeGenTarget::getSuperRegForSubReg(
+ const ValueTypeByHwMode &ValueTy, CodeGenRegBank &RegBank,
+ const CodeGenSubRegIndex *SubIdx, bool MustBeAllocatable) const {
std::vector<CodeGenRegisterClass *> Candidates;
auto &RegClasses = RegBank.getRegClasses();
@@ -389,7 +398,7 @@ CodeGenTarget::getSuperRegForSubReg(const ValueTypeByHwMode &ValueTy,
// If we didn't find anything, we're done.
if (Candidates.empty())
- return None;
+ return std::nullopt;
// Find and return the largest of our candidate classes.
llvm::stable_sort(Candidates, [&](const CodeGenRegisterClass *A,
@@ -482,7 +491,7 @@ static const char *FixedInstrs[] = {
nullptr};
unsigned CodeGenTarget::getNumFixedInstructions() {
- return array_lengthof(FixedInstrs) - 1;
+ return std::size(FixedInstrs) - 1;
}
/// Return all of the instructions defined by the target, ordered by
@@ -665,7 +674,6 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R,
TheDef = R;
std::string DefName = std::string(R->getName());
ArrayRef<SMLoc> DefLoc = R->getLoc();
- ModRef = ReadWriteMem;
Properties = 0;
isOverloaded = false;
isCommutative = false;
@@ -823,7 +831,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R,
Properties = parseSDPatternOperatorProperties(R);
// Sort the argument attributes for later benefit.
- llvm::sort(ArgumentAttributes);
+ for (auto &Attrs : ArgumentAttributes)
+ llvm::sort(Attrs);
}
void CodeGenIntrinsic::setDefaultProperties(
@@ -838,26 +847,25 @@ void CodeGenIntrinsic::setDefaultProperties(
void CodeGenIntrinsic::setProperty(Record *R) {
if (R->getName() == "IntrNoMem")
- ModRef = NoMem;
+ ME = MemoryEffects::none();
else if (R->getName() == "IntrReadMem") {
- if (!(ModRef & MR_Ref))
+ if (ME.onlyWritesMemory())
PrintFatalError(TheDef->getLoc(),
Twine("IntrReadMem cannot be used after IntrNoMem or "
"IntrWriteMem. Default is ReadWrite"));
- ModRef = ModRefBehavior(ModRef & ~MR_Mod);
+ ME &= MemoryEffects::readOnly();
} else if (R->getName() == "IntrWriteMem") {
- if (!(ModRef & MR_Mod))
+ if (ME.onlyReadsMemory())
PrintFatalError(TheDef->getLoc(),
Twine("IntrWriteMem cannot be used after IntrNoMem or "
"IntrReadMem. Default is ReadWrite"));
- ModRef = ModRefBehavior(ModRef & ~MR_Ref);
+ ME &= MemoryEffects::writeOnly();
} else if (R->getName() == "IntrArgMemOnly")
- ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_ArgMem);
+ ME &= MemoryEffects::argMemOnly();
else if (R->getName() == "IntrInaccessibleMemOnly")
- ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_InaccessibleMem);
+ ME &= MemoryEffects::inaccessibleMemOnly();
else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly")
- ModRef = ModRefBehavior((ModRef & ~MR_Anywhere) | MR_ArgMem |
- MR_InaccessibleMem);
+ ME &= MemoryEffects::inaccessibleOrArgMemOnly();
else if (R->getName() == "Commutative")
isCommutative = true;
else if (R->getName() == "Throws")
@@ -886,32 +894,35 @@ void CodeGenIntrinsic::setProperty(Record *R) {
hasSideEffects = true;
else if (R->isSubClassOf("NoCapture")) {
unsigned ArgNo = R->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, NoCapture, 0);
+ addArgAttribute(ArgNo, NoCapture);
} else if (R->isSubClassOf("NoAlias")) {
unsigned ArgNo = R->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, NoAlias, 0);
+ addArgAttribute(ArgNo, NoAlias);
} else if (R->isSubClassOf("NoUndef")) {
unsigned ArgNo = R->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, NoUndef, 0);
+ addArgAttribute(ArgNo, NoUndef);
+ } else if (R->isSubClassOf("NonNull")) {
+ unsigned ArgNo = R->getValueAsInt("ArgNo");
+ addArgAttribute(ArgNo, NonNull);
} else if (R->isSubClassOf("Returned")) {
unsigned ArgNo = R->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, Returned, 0);
+ addArgAttribute(ArgNo, Returned);
} else if (R->isSubClassOf("ReadOnly")) {
unsigned ArgNo = R->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, ReadOnly, 0);
+ addArgAttribute(ArgNo, ReadOnly);
} else if (R->isSubClassOf("WriteOnly")) {
unsigned ArgNo = R->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, WriteOnly, 0);
+ addArgAttribute(ArgNo, WriteOnly);
} else if (R->isSubClassOf("ReadNone")) {
unsigned ArgNo = R->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, ReadNone, 0);
+ addArgAttribute(ArgNo, ReadNone);
} else if (R->isSubClassOf("ImmArg")) {
unsigned ArgNo = R->getValueAsInt("ArgNo");
- ArgumentAttributes.emplace_back(ArgNo, ImmArg, 0);
+ addArgAttribute(ArgNo, ImmArg);
} else if (R->isSubClassOf("Align")) {
unsigned ArgNo = R->getValueAsInt("ArgNo");
uint64_t Align = R->getValueAsInt("Align");
- ArgumentAttributes.emplace_back(ArgNo, Alignment, Align);
+ addArgAttribute(ArgNo, Alignment, Align);
} else
llvm_unreachable("Unknown property!");
}
@@ -925,7 +936,17 @@ bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const {
bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const {
// Convert argument index to attribute index starting from `FirstArgIndex`.
- ArgAttribute Val{ParamIdx + 1, ImmArg, 0};
- return std::binary_search(ArgumentAttributes.begin(),
- ArgumentAttributes.end(), Val);
+ ++ParamIdx;
+ if (ParamIdx >= ArgumentAttributes.size())
+ return false;
+ ArgAttribute Val{ImmArg, 0};
+ return std::binary_search(ArgumentAttributes[ParamIdx].begin(),
+ ArgumentAttributes[ParamIdx].end(), Val);
+}
+
+void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK,
+ uint64_t V) {
+ if (Idx >= ArgumentAttributes.size())
+ ArgumentAttributes.resize(Idx + 1);
+ ArgumentAttributes[Idx].emplace_back(AK, V);
}
diff --git a/llvm/utils/TableGen/CodeGenTarget.h b/llvm/utils/TableGen/CodeGenTarget.h
index f14828f2c347..6846e6b5c77a 100644
--- a/llvm/utils/TableGen/CodeGenTarget.h
+++ b/llvm/utils/TableGen/CodeGenTarget.h
@@ -108,7 +108,7 @@ public:
/// Return the largest register class on \p RegBank which supports \p Ty and
/// covers \p SubIdx if it exists.
- Optional<CodeGenRegisterClass *>
+ std::optional<CodeGenRegisterClass *>
getSuperRegForSubReg(const ValueTypeByHwMode &Ty, CodeGenRegBank &RegBank,
const CodeGenSubRegIndex *SubIdx,
bool MustBeAllocatable = false) const;
diff --git a/llvm/utils/TableGen/CompressInstEmitter.cpp b/llvm/utils/TableGen/CompressInstEmitter.cpp
index 1fd85939e74e..a18d6a6b8854 100644
--- a/llvm/utils/TableGen/CompressInstEmitter.cpp
+++ b/llvm/utils/TableGen/CompressInstEmitter.cpp
@@ -45,20 +45,16 @@
// instructions, plus some helper functions:
//
// bool compressInst(MCInst &OutInst, const MCInst &MI,
-// const MCSubtargetInfo &STI,
-// MCContext &Context);
+// const MCSubtargetInfo &STI);
//
// bool uncompressInst(MCInst &OutInst, const MCInst &MI,
-// const MCRegisterInfo &MRI,
// const MCSubtargetInfo &STI);
//
// In addition, it exports a function for checking whether
// an instruction is compressable:
//
// bool isCompressibleInst(const MachineInstr& MI,
-// const <TargetName>Subtarget *Subtarget,
-// const MCRegisterInfo &MRI,
-// const MCSubtargetInfo &STI);
+// const <TargetName>Subtarget &STI);
//
// The clients that include this auto-generated header file and
// invoke these functions can compress an instruction before emitting
@@ -595,7 +591,6 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
std::string FH;
raw_string_ostream Func(F);
raw_string_ostream FuncH(FH);
- bool NeedMRI = false;
if (EType == EmitterType::Compress)
o << "\n#ifdef GEN_COMPRESS_INSTR\n"
@@ -610,18 +605,14 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
if (EType == EmitterType::Compress) {
FuncH << "static bool compressInst(MCInst &OutInst,\n";
FuncH.indent(25) << "const MCInst &MI,\n";
- FuncH.indent(25) << "const MCSubtargetInfo &STI,\n";
- FuncH.indent(25) << "MCContext &Context) {\n";
+ FuncH.indent(25) << "const MCSubtargetInfo &STI) {\n";
} else if (EType == EmitterType::Uncompress) {
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.indent(27) << "const " << TargetName << "Subtarget *Subtarget,\n";
- FuncH.indent(27) << "const MCRegisterInfo &MRI,\n";
- FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n";
+ FuncH.indent(31) << "const " << TargetName << "Subtarget &STI) {\n";
}
if (CompressPatterns.empty()) {
@@ -647,6 +638,12 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
EType == EmitterType::Compress || EType == EmitterType::CheckCompress;
bool CompressOrUncompress =
EType == EmitterType::Compress || EType == EmitterType::Uncompress;
+ std::string ValidatorName =
+ CompressOrUncompress
+ ? (TargetName + "ValidateMCOperandFor" +
+ (EType == EmitterType::Compress ? "Compress" : "Uncompress"))
+ .str()
+ : "";
for (auto &CompressPat : CompressPatterns) {
if (EType == EmitterType::Uncompress && CompressPat.IsCompressOnly)
@@ -716,7 +713,10 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
if (SourceOperandMap[OpNo].TiedOpIdx != -1) {
if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass"))
CondStream.indent(6)
- << "(MI.getOperand(" << OpNo << ").getReg() == MI.getOperand("
+ << "(MI.getOperand(" << OpNo << ").isReg()) && (MI.getOperand("
+ << SourceOperandMap[OpNo].TiedOpIdx << ").isReg()) &&\n"
+ << " (MI.getOperand(" << OpNo
+ << ").getReg() == MI.getOperand("
<< SourceOperandMap[OpNo].TiedOpIdx << ").getReg()) &&\n";
else
PrintFatalError("Unexpected tied operand types!\n");
@@ -735,7 +735,8 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
case OpData::Reg: {
Record *Reg = SourceOperandMap[OpNo].Data.Reg;
CondStream.indent(6)
- << "(MI.getOperand(" << OpNo << ").getReg() == " << TargetName
+ << "(MI.getOperand(" << OpNo << ").isReg()) &&\n"
+ << " (MI.getOperand(" << OpNo << ").getReg() == " << TargetName
<< "::" << Reg->getName() << ") &&\n";
break;
}
@@ -753,16 +754,21 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
unsigned OpIdx = DestOperandMap[OpNo].Data.Operand;
// Check that the operand in the Source instruction fits
// the type for the Dest instruction.
- if (DestOperand.Rec->isSubClassOf("RegisterClass")) {
- NeedMRI = true;
+ if (DestOperand.Rec->isSubClassOf("RegisterClass") ||
+ DestOperand.Rec->isSubClassOf("RegisterOperand")) {
+ auto *ClassRec = DestOperand.Rec->isSubClassOf("RegisterClass")
+ ? DestOperand.Rec
+ : DestOperand.Rec->getValueAsDef("RegClass");
// This is a register operand. Check the register class.
// Don't check register class if this is a tied operand, it was done
// for the operand its tied to.
if (DestOperand.getTiedRegister() == -1)
- CondStream.indent(6) << "(MRI.getRegClass(" << TargetName
- << "::" << DestOperand.Rec->getName()
- << "RegClassID).contains(MI.getOperand("
- << OpIdx << ").getReg())) &&\n";
+ CondStream.indent(6)
+ << "(MI.getOperand(" << OpIdx << ").isReg()) &&\n"
+ << " (" << TargetName << "MCRegisterClasses["
+ << TargetName << "::" << ClassRec->getName()
+ << "RegClassID].contains(MI.getOperand(" << OpIdx
+ << ").getReg())) &&\n";
if (CompressOrUncompress)
CodeStream.indent(6)
@@ -774,7 +780,7 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
getPredicates(MCOpPredicateMap, MCOpPredicates, DestOperand.Rec,
"MCOperandPredicate");
CondStream.indent(6)
- << TargetName << "ValidateMCOperand("
+ << ValidatorName << "("
<< "MI.getOperand(" << OpIdx << "), STI, " << Entry << ") &&\n";
} else {
unsigned Entry =
@@ -784,7 +790,7 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
<< "MI.getOperand(" << OpIdx << ").isImm() &&\n";
CondStream.indent(6) << TargetName << "ValidateMachineOperand("
<< "MI.getOperand(" << OpIdx
- << "), Subtarget, " << Entry << ") &&\n";
+ << "), &STI, " << Entry << ") &&\n";
}
if (CompressOrUncompress)
CodeStream.indent(6)
@@ -797,7 +803,7 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
unsigned Entry = getPredicates(MCOpPredicateMap, MCOpPredicates,
DestOperand.Rec, "MCOperandPredicate");
CondStream.indent(6)
- << TargetName << "ValidateMCOperand("
+ << ValidatorName << "("
<< "MCOperand::createImm(" << DestOperandMap[OpNo].Data.Imm
<< "), STI, " << Entry << ") &&\n";
} else {
@@ -806,7 +812,7 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
CondStream.indent(6)
<< TargetName
<< "ValidateMachineOperand(MachineOperand::CreateImm("
- << DestOperandMap[OpNo].Data.Imm << "), SubTarget, " << Entry
+ << DestOperandMap[OpNo].Data.Imm << "), &STI, " << Entry
<< ") &&\n";
}
if (CompressOrUncompress)
@@ -837,8 +843,7 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
Func.indent(2) << "return false;\n}\n";
if (!MCOpPredicates.empty()) {
- o << "static bool " << TargetName
- << "ValidateMCOperand(const MCOperand &MCOp,\n"
+ o << "static bool " << ValidatorName << "(const MCOperand &MCOp,\n"
<< " const MCSubtargetInfo &STI,\n"
<< " unsigned PredicateIndex) {\n"
<< " switch (PredicateIndex) {\n"
@@ -870,8 +875,6 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
}
o << FuncH.str();
- if (NeedMRI && EType == EmitterType::Compress)
- o.indent(2) << "const MCRegisterInfo &MRI = *Context.getRegisterInfo();\n";
o << Func.str();
if (EType == EmitterType::Compress)
diff --git a/llvm/utils/TableGen/DFAEmitter.cpp b/llvm/utils/TableGen/DFAEmitter.cpp
index f2d9165c5c8c..705908226fa1 100644
--- a/llvm/utils/TableGen/DFAEmitter.cpp
+++ b/llvm/utils/TableGen/DFAEmitter.cpp
@@ -35,6 +35,7 @@
#include <map>
#include <set>
#include <string>
+#include <variant>
#include <vector>
#define DEBUG_TYPE "dfa-emitter"
@@ -169,30 +170,8 @@ void DfaEmitter::printActionValue(action_type A, raw_ostream &OS) { OS << A; }
//===----------------------------------------------------------------------===//
namespace {
-// FIXME: This entire discriminated union could be removed with c++17:
-// using Action = std::variant<Record *, unsigned, std::string>;
-struct Action {
- Record *R = nullptr;
- unsigned I = 0;
- std::string S;
-
- Action() = default;
- Action(Record *R, unsigned I, std::string S) : R(R), I(I), S(S) {}
-
- void print(raw_ostream &OS) const {
- if (R)
- OS << R->getName();
- else if (!S.empty())
- OS << '"' << S << '"';
- else
- OS << I;
- }
- bool operator<(const Action &Other) const {
- return std::make_tuple(R, I, S) <
- std::make_tuple(Other.R, Other.I, Other.S);
- }
-};
+using Action = std::variant<Record *, unsigned, std::string>;
using ActionTuple = std::vector<Action>;
class Automaton;
@@ -342,13 +321,13 @@ Transition::Transition(Record *R, Automaton *Parent) {
for (StringRef A : Parent->getActionSymbolFields()) {
RecordVal *SymbolV = R->getValue(A);
if (auto *Ty = dyn_cast<RecordRecTy>(SymbolV->getType())) {
- Actions.emplace_back(R->getValueAsDef(A), 0, "");
+ Actions.emplace_back(R->getValueAsDef(A));
Types.emplace_back(Ty->getAsString());
} else if (isa<IntRecTy>(SymbolV->getType())) {
- Actions.emplace_back(nullptr, R->getValueAsInt(A), "");
+ Actions.emplace_back(static_cast<unsigned>(R->getValueAsInt(A)));
Types.emplace_back("unsigned");
} else if (isa<StringRecTy>(SymbolV->getType())) {
- Actions.emplace_back(nullptr, 0, std::string(R->getValueAsString(A)));
+ Actions.emplace_back(std::string(R->getValueAsString(A)));
Types.emplace_back("std::string");
} else {
report_fatal_error("Unhandled symbol type!");
@@ -380,7 +359,12 @@ void CustomDfaEmitter::printActionValue(action_type A, raw_ostream &OS) {
ListSeparator LS;
for (const auto &SingleAction : AT) {
OS << LS;
- SingleAction.print(OS);
+ if (const auto *R = std::get_if<Record *>(&SingleAction))
+ OS << (*R)->getName();
+ else if (const auto *S = std::get_if<std::string>(&SingleAction))
+ OS << '"' << *S << '"';
+ else
+ OS << std::get<unsigned>(SingleAction);
}
if (AT.size() > 1)
OS << ")";
diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp
index cd41fbaa6ca1..44c1df3e9ac4 100644
--- a/llvm/utils/TableGen/DXILEmitter.cpp
+++ b/llvm/utils/TableGen/DXILEmitter.cpp
@@ -21,7 +21,7 @@
#include "llvm/TableGen/Record.h"
using namespace llvm;
-using namespace llvm::DXIL;
+using namespace llvm::dxil;
namespace {
@@ -144,7 +144,7 @@ static std::string parameterKindToString(ParameterKind Kind) {
case ParameterKind::DXIL_HANDLE:
return "DXIL_HANDLE";
}
- llvm_unreachable("Unknown llvm::DXIL::ParameterKind enum");
+ llvm_unreachable("Unknown llvm::dxil::ParameterKind enum");
}
static void emitDXILOpEnum(DXILOperationData &DXILOp, raw_ostream &OS) {
@@ -238,14 +238,14 @@ static void emitDXILIntrinsicMap(std::vector<DXILOperationData> &DXILOps,
raw_ostream &OS) {
OS << "\n";
// FIXME: use array instead of SmallDenseMap.
- OS << "static const SmallDenseMap<Intrinsic::ID, DXIL::OpCode> LowerMap = "
+ OS << "static const SmallDenseMap<Intrinsic::ID, dxil::OpCode> LowerMap = "
"{\n";
for (auto &DXILOp : DXILOps) {
if (DXILOp.Intrinsic.empty())
continue;
- // {Intrinsic::sin, DXIL::OpCode::Sin},
+ // {Intrinsic::sin, dxil::OpCode::Sin},
OS << " { Intrinsic::" << DXILOp.Intrinsic
- << ", DXIL::OpCode::" << DXILOp.DXILOp << "},\n";
+ << ", dxil::OpCode::" << DXILOp.DXILOp << "},\n";
}
OS << "};\n";
OS << "\n";
@@ -340,16 +340,16 @@ static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
Parameters.layout();
// Emit the DXIL operation table.
- //{DXIL::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary,
+ //{dxil::OpCode::Sin, OpCodeNameIndex, OpCodeClass::Unary,
// OpCodeClassNameIndex,
// OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone, 0,
// 3, ParameterTableOffset},
- OS << "static const OpCodeProperty *getOpCodeProperty(DXIL::OpCode DXILOp) "
+ OS << "static const OpCodeProperty *getOpCodeProperty(dxil::OpCode DXILOp) "
"{\n";
OS << " static const OpCodeProperty OpCodeProps[] = {\n";
for (auto &DXILOp : DXILOps) {
- OS << " { DXIL::OpCode::" << DXILOp.DXILOp << ", "
+ OS << " { dxil::OpCode::" << DXILOp.DXILOp << ", "
<< OpStrings.get(DXILOp.DXILOp.str())
<< ", OpCodeClass::" << DXILOp.DXILClass << ", "
<< OpClassStrings.get(getDXILOpClassName(DXILOp.DXILClass)) << ", "
@@ -375,7 +375,7 @@ static void emitDXILOperationTable(std::vector<DXILOperationData> &DXILOps,
OS << "}\n\n";
// Emit the string tables.
- OS << "static const char *getOpCodeName(DXIL::OpCode DXILOp) {\n\n";
+ OS << "static const char *getOpCodeName(dxil::OpCode DXILOp) {\n\n";
OpStrings.emitStringLiteralDef(OS,
" static const char DXILOpCodeNameTable[]");
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 8477e0639f90..8f816744370c 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -127,17 +127,8 @@ class DecoderEmitter {
std::vector<EncodingAndInst> NumberedEncodings;
public:
- // Defaults preserved here for documentation, even though they aren't
- // strictly necessary given the way that this is currently being called.
- DecoderEmitter(RecordKeeper &R, std::string PredicateNamespace,
- std::string GPrefix = "if (",
- std::string GPostfix = " == MCDisassembler::Fail)",
- std::string ROK = "MCDisassembler::Success",
- std::string RFail = "MCDisassembler::Fail", std::string L = "")
- : RK(R), Target(R), PredicateNamespace(std::move(PredicateNamespace)),
- GuardPrefix(std::move(GPrefix)), GuardPostfix(std::move(GPostfix)),
- ReturnOK(std::move(ROK)), ReturnFail(std::move(RFail)),
- Locals(std::move(L)) {}
+ DecoderEmitter(RecordKeeper &R, std::string PredicateNamespace)
+ : RK(R), Target(R), PredicateNamespace(std::move(PredicateNamespace)) {}
// Emit the decoder state machine table.
void emitTable(formatted_raw_ostream &o, DecoderTable &Table,
@@ -160,9 +151,6 @@ private:
public:
std::string PredicateNamespace;
- std::string GuardPrefix, GuardPostfix;
- std::string ReturnOK, ReturnFail;
- std::string Locals;
};
} // end anonymous namespace
@@ -1170,11 +1158,11 @@ void FilterChooser::emitBinaryParser(raw_ostream &o, unsigned &Indentation,
if (Decoder != "") {
OpHasCompleteDecoder = OpInfo.HasCompleteDecoder;
- o.indent(Indentation) << Emitter->GuardPrefix << Decoder
- << "(MI, tmp, Address, Decoder)"
- << Emitter->GuardPostfix
- << " { " << (OpHasCompleteDecoder ? "" : "DecodeComplete = false; ")
- << "return MCDisassembler::Fail; }\n";
+ o.indent(Indentation) << "if (!Check(S, " << Decoder
+ << "(MI, tmp, Address, Decoder))) { "
+ << (OpHasCompleteDecoder ? ""
+ : "DecodeComplete = false; ")
+ << "return MCDisassembler::Fail; }\n";
} else {
OpHasCompleteDecoder = true;
o.indent(Indentation) << "MI.addOperand(MCOperand::createImm(tmp));\n";
@@ -1189,11 +1177,11 @@ void FilterChooser::emitDecoder(raw_ostream &OS, unsigned Indentation,
// If a custom instruction decoder was specified, use that.
if (Op.numFields() == 0 && !Op.Decoder.empty()) {
HasCompleteDecoder = Op.HasCompleteDecoder;
- OS.indent(Indentation) << Emitter->GuardPrefix << Op.Decoder
- << "(MI, insn, Address, Decoder)"
- << Emitter->GuardPostfix
- << " { " << (HasCompleteDecoder ? "" : "DecodeComplete = false; ")
- << "return MCDisassembler::Fail; }\n";
+ OS.indent(Indentation)
+ << "if (!Check(S, " << Op.Decoder
+ << "(MI, insn, Address, Decoder))) { "
+ << (HasCompleteDecoder ? "" : "DecodeComplete = false; ")
+ << "return MCDisassembler::Fail; }\n";
break;
}
@@ -1905,6 +1893,8 @@ void parseVarLenInstOperand(const Record &Def,
OpName);
unsigned OpIdx = CGI.Operands.getFlattenedOperandNumber(OpSubOpPair);
Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset);
+ if (!EncodingSegment.CustomDecoder.empty())
+ Operands[OpIdx].Decoder = EncodingSegment.CustomDecoder.str();
int TiedReg = TiedTo[OpSubOpPair.first];
if (TiedReg != -1) {
@@ -1918,6 +1908,55 @@ void parseVarLenInstOperand(const Record &Def,
}
}
+static void debugDumpRecord(const Record &Rec) {
+ // Dump the record, so we can see what's going on...
+ std::string E;
+ raw_string_ostream S(E);
+ S << "Dumping record for previous error:\n";
+ S << Rec;
+ PrintNote(E);
+}
+
+/// For an operand field named OpName: populate OpInfo.InitValue with the
+/// constant-valued bit values, and OpInfo.Fields with the ranges of bits to
+/// insert from the decoded instruction.
+static void addOneOperandFields(const Record &EncodingDef, const BitsInit &Bits,
+ std::map<std::string, std::string> &TiedNames,
+ StringRef OpName, OperandInfo &OpInfo) {
+ // Some bits of the operand may be required to be 1 depending on the
+ // instruction's encoding. Collect those bits.
+ if (const RecordVal *EncodedValue = EncodingDef.getValue(OpName))
+ if (const BitsInit *OpBits = dyn_cast<BitsInit>(EncodedValue->getValue()))
+ for (unsigned I = 0; I < OpBits->getNumBits(); ++I)
+ if (const BitInit *OpBit = dyn_cast<BitInit>(OpBits->getBit(I)))
+ if (OpBit->getValue())
+ OpInfo.InitValue |= 1ULL << I;
+
+ for (unsigned I = 0, J = 0; I != Bits.getNumBits(); I = J) {
+ VarInit *Var;
+ unsigned Offset = 0;
+ for (; J != Bits.getNumBits(); ++J) {
+ VarBitInit *BJ = dyn_cast<VarBitInit>(Bits.getBit(J));
+ if (BJ) {
+ Var = dyn_cast<VarInit>(BJ->getBitVar());
+ if (I == J)
+ Offset = BJ->getBitNum();
+ else if (BJ->getBitNum() != Offset + J - I)
+ break;
+ } else {
+ Var = dyn_cast<VarInit>(Bits.getBit(J));
+ }
+ if (!Var || (Var->getName() != OpName &&
+ Var->getName() != TiedNames[std::string(OpName)]))
+ break;
+ }
+ if (I == J)
+ ++J;
+ else
+ OpInfo.addField(I, J - I, Offset);
+ }
+}
+
static unsigned
populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
const CodeGenInstruction &CGI, unsigned Opc,
@@ -1966,14 +2005,23 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
// operands that are not explicitly represented in the encoding.
std::map<std::string, std::string> TiedNames;
for (unsigned i = 0; i < CGI.Operands.size(); ++i) {
- int tiedTo = CGI.Operands[i].getTiedRegister();
- if (tiedTo != -1) {
- std::pair<unsigned, unsigned> SO =
- CGI.Operands.getSubOperandNumber(tiedTo);
- TiedNames[std::string(InOutOperands[i].second)] =
- std::string(InOutOperands[SO.first].second);
- TiedNames[std::string(InOutOperands[SO.first].second)] =
- std::string(InOutOperands[i].second);
+ auto &Op = CGI.Operands[i];
+ for (unsigned j = 0; j < Op.Constraints.size(); ++j) {
+ const CGIOperandList::ConstraintInfo &CI = Op.Constraints[j];
+ if (CI.isTied()) {
+ int tiedTo = CI.getTiedOperand();
+ std::pair<unsigned, unsigned> SO =
+ CGI.Operands.getSubOperandNumber(tiedTo);
+ std::string TiedName = CGI.Operands[SO.first].SubOpNames[SO.second];
+ if (TiedName.empty())
+ TiedName = CGI.Operands[SO.first].Name;
+ std::string MyName = Op.SubOpNames[j];
+ if (MyName.empty())
+ MyName = Op.Name;
+
+ TiedNames[MyName] = TiedName;
+ TiedNames[TiedName] = MyName;
+ }
}
}
@@ -1982,8 +2030,12 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
} else {
std::map<std::string, std::vector<OperandInfo>> NumberedInsnOperands;
std::set<std::string> NumberedInsnOperandsNoTie;
- if (Target.getInstructionSet()->getValueAsBit(
- "decodePositionallyEncodedOperands")) {
+ bool SupportPositionalDecoding =
+ Target.getInstructionSet()->getValueAsBit(
+ "useDeprecatedPositionallyEncodedOperands") &&
+ Target.getInstructionSet()->getValueAsBit(
+ "decodePositionallyEncodedOperands");
+ if (SupportPositionalDecoding) {
const std::vector<RecordVal> &Vals = Def.getValues();
unsigned NumberedOp = 0;
@@ -2025,7 +2077,9 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
// Skip variables that correspond to explicitly-named operands.
unsigned OpIdx;
- if (CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx))
+ std::pair<unsigned, unsigned> SubOp;
+ if (CGI.Operands.hasSubOperandAlias(Vals[i].getName(), SubOp) ||
+ CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx))
continue;
// Get the bit range for this operand:
@@ -2127,106 +2181,113 @@ 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()) {
- llvm::append_range(InsnOperands,
- NumberedInsnOperands[std::string(Op.second)]);
- continue;
- }
- if (!NumberedInsnOperands[TiedNames[std::string(Op.second)]].empty()) {
- if (!NumberedInsnOperandsNoTie.count(
- TiedNames[std::string(Op.second)])) {
- // Figure out to which (sub)operand we're tied.
- unsigned i =
- CGI.Operands.getOperandNamed(TiedNames[std::string(Op.second)]);
- int tiedTo = CGI.Operands[i].getTiedRegister();
- if (tiedTo == -1) {
- i = CGI.Operands.getOperandNamed(Op.second);
- tiedTo = CGI.Operands[i].getTiedRegister();
- }
-
- if (tiedTo != -1) {
- std::pair<unsigned, unsigned> SO =
- CGI.Operands.getSubOperandNumber(tiedTo);
+ Init *OpInit = Op.first;
+ StringRef OpName = Op.second;
- InsnOperands.push_back(
- NumberedInsnOperands[TiedNames[std::string(Op.second)]]
- [SO.second]);
- }
+ if (SupportPositionalDecoding) {
+ if (!NumberedInsnOperands[std::string(OpName)].empty()) {
+ llvm::append_range(InsnOperands,
+ NumberedInsnOperands[std::string(OpName)]);
+ continue;
}
- continue;
- }
-
- // At this point, we can locate the decoder field, but we need to know how
- // to interpret it. As a first step, require the target to provide
- // callbacks for decoding register classes.
-
- OperandInfo OpInfo = getOpInfo(cast<DefInit>(Op.first)->getDef());
-
- // Some bits of the operand may be required to be 1 depending on the
- // instruction's encoding. Collect those bits.
- if (const RecordVal *EncodedValue = EncodingDef.getValue(Op.second))
- if (const BitsInit *OpBits =
- dyn_cast<BitsInit>(EncodedValue->getValue()))
- for (unsigned I = 0; I < OpBits->getNumBits(); ++I)
- if (const BitInit *OpBit = dyn_cast<BitInit>(OpBits->getBit(I)))
- if (OpBit->getValue())
- OpInfo.InitValue |= 1ULL << I;
-
- unsigned Base = ~0U;
- unsigned Width = 0;
- unsigned Offset = 0;
-
- for (unsigned bi = 0; bi < Bits.getNumBits(); ++bi) {
- VarInit *Var = nullptr;
- VarBitInit *BI = dyn_cast<VarBitInit>(Bits.getBit(bi));
- if (BI)
- Var = dyn_cast<VarInit>(BI->getBitVar());
- else
- Var = dyn_cast<VarInit>(Bits.getBit(bi));
-
- if (!Var) {
- if (Base != ~0U) {
- OpInfo.addField(Base, Width, Offset);
- Base = ~0U;
- Width = 0;
- Offset = 0;
+ if (!NumberedInsnOperands[TiedNames[std::string(OpName)]].empty()) {
+ if (!NumberedInsnOperandsNoTie.count(
+ TiedNames[std::string(OpName)])) {
+ // Figure out to which (sub)operand we're tied.
+ unsigned i =
+ CGI.Operands.getOperandNamed(TiedNames[std::string(OpName)]);
+ int tiedTo = CGI.Operands[i].getTiedRegister();
+ if (tiedTo == -1) {
+ i = CGI.Operands.getOperandNamed(OpName);
+ tiedTo = CGI.Operands[i].getTiedRegister();
+ }
+
+ if (tiedTo != -1) {
+ std::pair<unsigned, unsigned> SO =
+ CGI.Operands.getSubOperandNumber(tiedTo);
+
+ InsnOperands.push_back(
+ NumberedInsnOperands[TiedNames[std::string(OpName)]]
+ [SO.second]);
+ }
}
continue;
}
+ }
- if ((Var->getName() != Op.second &&
- Var->getName() != TiedNames[std::string(Op.second)])) {
- if (Base != ~0U) {
- OpInfo.addField(Base, Width, Offset);
- Base = ~0U;
- Width = 0;
- Offset = 0;
- }
+ // We're ready to find the instruction encoding locations for this operand.
+
+ // First, find the operand type ("OpInit"), and sub-op names
+ // ("SubArgDag") if present.
+ DagInit *SubArgDag = dyn_cast<DagInit>(OpInit);
+ if (SubArgDag)
+ OpInit = SubArgDag->getOperator();
+ Record *OpTypeRec = cast<DefInit>(OpInit)->getDef();
+ // Lookup the sub-operands from the operand type record (note that only
+ // Operand subclasses have MIOperandInfo, see CodeGenInstruction.cpp).
+ DagInit *SubOps = OpTypeRec->isSubClassOf("Operand")
+ ? OpTypeRec->getValueAsDag("MIOperandInfo")
+ : nullptr;
+
+ // Lookup the decoder method and construct a new OperandInfo to hold our result.
+ OperandInfo OpInfo = getOpInfo(OpTypeRec);
+
+ // If we have named sub-operands...
+ if (SubArgDag) {
+ // Then there should not be a custom decoder specified on the top-level
+ // type.
+ if (!OpInfo.Decoder.empty()) {
+ PrintError(EncodingDef.getLoc(),
+ "DecoderEmitter: operand \"" + OpName + "\" has type \"" +
+ OpInit->getAsString() +
+ "\" with a custom DecoderMethod, but also named "
+ "sub-operands.");
continue;
}
- if (Base == ~0U) {
- Base = bi;
- Width = 1;
- Offset = BI ? BI->getBitNum() : 0;
- } else if (BI && BI->getBitNum() != Offset + Width) {
- OpInfo.addField(Base, Width, Offset);
- Base = bi;
- Width = 1;
- Offset = BI->getBitNum();
- } else {
- ++Width;
+ // Decode each of the sub-ops separately.
+ assert(SubOps && SubArgDag->getNumArgs() == SubOps->getNumArgs());
+ for (unsigned i = 0; i < SubOps->getNumArgs(); ++i) {
+ StringRef SubOpName = SubArgDag->getArgNameStr(i);
+ OperandInfo SubOpInfo =
+ getOpInfo(cast<DefInit>(SubOps->getArg(i))->getDef());
+
+ addOneOperandFields(EncodingDef, Bits, TiedNames, SubOpName,
+ SubOpInfo);
+ InsnOperands.push_back(SubOpInfo);
}
+ continue;
}
- if (Base != ~0U)
- OpInfo.addField(Base, Width, Offset);
+ // Otherwise, if we have an operand with sub-operands, but they aren't
+ // named...
+ if (SubOps && OpInfo.Decoder.empty()) {
+ // If it's a single sub-operand, and no custom decoder, use the decoder
+ // from the one sub-operand.
+ if (SubOps->getNumArgs() == 1)
+ OpInfo = getOpInfo(cast<DefInit>(SubOps->getArg(0))->getDef());
+
+ // If we have multiple sub-ops, there'd better have a custom
+ // decoder. (Otherwise we don't know how to populate them properly...)
+ if (SubOps->getNumArgs() > 1) {
+ PrintError(EncodingDef.getLoc(),
+ "DecoderEmitter: operand \"" + OpName +
+ "\" uses MIOperandInfo with multiple ops, but doesn't "
+ "have a custom decoder!");
+ debugDumpRecord(EncodingDef);
+ continue;
+ }
+ }
+ addOneOperandFields(EncodingDef, Bits, TiedNames, OpName, OpInfo);
+ // FIXME: it should be an error not to find a definition for a given
+ // operand, rather than just failing to add it to the resulting
+ // instruction! (This is a longstanding bug, which will be addressed in an
+ // upcoming change.)
if (OpInfo.numFields() > 0)
InsnOperands.push_back(OpInfo);
}
}
-
Operands[Opc] = InsnOperands;
#if 0
@@ -2254,7 +2315,7 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
// fieldFromInstruction().
// On Windows we make sure that this function is not inlined when
// using the VS compiler. It has a bug which causes the function
-// to be optimized out in some circustances. See llvm.org/pr38292
+// to be optimized out in some circumstances. See llvm.org/pr38292
static void emitFieldFromInstruction(formatted_raw_ostream &OS) {
OS << "// Helper functions for extracting fields from encoded instructions.\n"
<< "// InsnType must either be integral or an APInt-like object that "
@@ -2520,6 +2581,17 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS,
<< "}\n\n";
}
+// Helper to propagate SoftFail status. Returns false if the status is Fail;
+// callers are expected to early-exit in that condition. (Note, the '&' operator
+// is correct to propagate the values of this enum; see comment on 'enum
+// DecodeStatus'.)
+static void emitCheck(formatted_raw_ostream &OS) {
+ OS << "static bool Check(DecodeStatus &Out, DecodeStatus In) {\n"
+ << " Out = static_cast<DecodeStatus>(Out & In);\n"
+ << " return Out != MCDisassembler::Fail;\n"
+ << "}\n\n";
+}
+
// Emits disassembler code for instruction decoding.
void DecoderEmitter::run(raw_ostream &o) {
formatted_raw_ostream OS(o);
@@ -2536,6 +2608,7 @@ void DecoderEmitter::run(raw_ostream &o) {
emitFieldFromInstruction(OS);
emitInsertBits(OS);
+ emitCheck(OS);
Target.reverseBitsForLittleEndianEncoding();
@@ -2671,7 +2744,6 @@ void DecoderEmitter::run(raw_ostream &o) {
// Print the table to the output stream.
emitTable(OS, TableInfo.Table, 0, FC.getBitWidth(), Opc.first.first);
- OS.flush();
}
// For variable instruction, we emit a instruction length table
@@ -2694,12 +2766,8 @@ void DecoderEmitter::run(raw_ostream &o) {
namespace llvm {
void EmitDecoder(RecordKeeper &RK, raw_ostream &OS,
- const std::string &PredicateNamespace,
- const std::string &GPrefix, const std::string &GPostfix,
- const std::string &ROK, const std::string &RFail,
- const std::string &L) {
- DecoderEmitter(RK, PredicateNamespace, GPrefix, GPostfix, ROK, RFail, L)
- .run(OS);
+ const std::string &PredicateNamespace) {
+ DecoderEmitter(RK, PredicateNamespace).run(OS);
}
} // end namespace llvm
diff --git a/llvm/utils/TableGen/DisassemblerEmitter.cpp b/llvm/utils/TableGen/DisassemblerEmitter.cpp
index 297d12c5d0e9..dfa4b30ee569 100644
--- a/llvm/utils/TableGen/DisassemblerEmitter.cpp
+++ b/llvm/utils/TableGen/DisassemblerEmitter.cpp
@@ -96,10 +96,7 @@ using namespace llvm::X86Disassembler;
namespace llvm {
extern void EmitDecoder(RecordKeeper &RK, raw_ostream &OS,
- const std::string &PredicateNamespace,
- const std::string &GPrefix, const std::string &GPostfix,
- const std::string &ROK, const std::string &RFail,
- const std::string &L);
+ const std::string &PredicateNamespace);
void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
CodeGenTarget Target(Records);
@@ -132,23 +129,10 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
return;
}
- // ARM and Thumb have a CHECK() macro to deal with DecodeStatuses.
- if (Target.getName() == "ARM" || Target.getName() == "Thumb" ||
- Target.getName() == "AArch64" || Target.getName() == "ARM64") {
- std::string PredicateNamespace = std::string(Target.getName());
- if (PredicateNamespace == "Thumb")
- PredicateNamespace = "ARM";
-
- EmitDecoder(Records, OS, PredicateNamespace, "if (!Check(S, ", "))", "S",
- "MCDisassembler::Fail",
- " MCDisassembler::DecodeStatus S = "
- "MCDisassembler::Success;\n(void)S;");
- return;
- }
-
- EmitDecoder(Records, OS, std::string(Target.getName()), "if (",
- " == MCDisassembler::Fail)", "MCDisassembler::Success",
- "MCDisassembler::Fail", "");
+ std::string PredicateNamespace = std::string(Target.getName());
+ if (PredicateNamespace == "Thumb")
+ PredicateNamespace = "ARM";
+ EmitDecoder(Records, OS, PredicateNamespace);
}
} // end namespace llvm
diff --git a/llvm/utils/TableGen/FastISelEmitter.cpp b/llvm/utils/TableGen/FastISelEmitter.cpp
index 49c2ead468e3..0a88f67be168 100644
--- a/llvm/utils/TableGen/FastISelEmitter.cpp
+++ b/llvm/utils/TableGen/FastISelEmitter.cpp
@@ -381,14 +381,9 @@ class FastISelMap {
OperandsOpcodeTypeRetPredMap SimplePatterns;
// This is used to check that there are no duplicate predicates
- typedef std::multimap<std::string, bool> PredCheckMap;
- typedef std::map<MVT::SimpleValueType, PredCheckMap> RetPredCheckMap;
- typedef std::map<MVT::SimpleValueType, RetPredCheckMap> TypeRetPredCheckMap;
- typedef std::map<std::string, TypeRetPredCheckMap> OpcodeTypeRetPredCheckMap;
- typedef std::map<OperandsSignature, OpcodeTypeRetPredCheckMap>
- OperandsOpcodeTypeRetPredCheckMap;
-
- OperandsOpcodeTypeRetPredCheckMap SimplePatternsCheck;
+ std::set<std::tuple<OperandsSignature, std::string, MVT::SimpleValueType,
+ MVT::SimpleValueType, std::string>>
+ SimplePatternsCheck;
std::map<OperandsSignature, std::vector<OperandsSignature> >
SignaturesWithConstantForms;
@@ -587,16 +582,15 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
int complexity = Pattern.getPatternComplexity(CGP);
- if (SimplePatternsCheck[Operands][OpcodeName][VT]
- [RetVT].count(PredicateCheck)) {
+ auto inserted_simple_pattern = SimplePatternsCheck.insert(
+ std::make_tuple(Operands, OpcodeName, VT, RetVT, PredicateCheck));
+ if (!inserted_simple_pattern.second) {
PrintFatalError(Pattern.getSrcRecord()->getLoc(),
"Duplicate predicate in FastISel table!");
}
- SimplePatternsCheck[Operands][OpcodeName][VT][RetVT].insert(
- std::make_pair(PredicateCheck, true));
- // Note: Instructions with the same complexity will appear in the order
- // that they are encountered.
+ // Note: Instructions with the same complexity will appear in the order
+ // that they are encountered.
SimplePatterns[Operands][OpcodeName][VT][RetVT].emplace(complexity,
std::move(Memo));
@@ -655,7 +649,7 @@ void FastISelMap::emitInstructionCode(raw_ostream &OS,
for (unsigned i = 0; i < Memo.PhysRegs.size(); ++i) {
if (Memo.PhysRegs[i] != "")
- OS << " BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, "
+ OS << " BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, "
<< "TII.get(TargetOpcode::COPY), " << Memo.PhysRegs[i]
<< ").addReg(Op" << i << ");\n";
}
diff --git a/llvm/utils/TableGen/GICombinerEmitter.cpp b/llvm/utils/TableGen/GICombinerEmitter.cpp
index 77e05aebf53a..2ae313081a6f 100644
--- a/llvm/utils/TableGen/GICombinerEmitter.cpp
+++ b/llvm/utils/TableGen/GICombinerEmitter.cpp
@@ -636,7 +636,7 @@ void GICombinerEmitter::emitNameMatcher(raw_ostream &OS) const {
std::make_pair(std::string(EnumeratedRule.getName()), Code));
}
- OS << "static Optional<uint64_t> getRuleIdxForIdentifier(StringRef "
+ OS << "static std::optional<uint64_t> getRuleIdxForIdentifier(StringRef "
"RuleIdentifier) {\n"
<< " uint64_t I;\n"
<< " // getAtInteger(...) returns false on success\n"
@@ -647,7 +647,7 @@ void GICombinerEmitter::emitNameMatcher(raw_ostream &OS) const {
StringMatcher Matcher("RuleIdentifier", Cases, OS);
Matcher.Emit();
OS << "#endif // ifndef NDEBUG\n\n"
- << " return None;\n"
+ << " return std::nullopt;\n"
<< "}\n";
}
@@ -764,6 +764,29 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS,
OS << Indent << " if (1\n";
+ // Emit code for C++ Predicates.
+ if (RuleDef.getValue("Predicates")) {
+ ListInit *Preds = RuleDef.getValueAsListInit("Predicates");
+ for (Init *I : Preds->getValues()) {
+ if (DefInit *Pred = dyn_cast<DefInit>(I)) {
+ Record *Def = Pred->getDef();
+ if (!Def->isSubClassOf("Predicate")) {
+ PrintError(Def->getLoc(), "Unknown 'Predicate' Type");
+ return;
+ }
+
+ StringRef CondString = Def->getValueAsString("CondString");
+ if (CondString.empty())
+ continue;
+
+ OS << Indent << " && (\n"
+ << Indent << " // Predicate: " << Def->getName() << "\n"
+ << Indent << " " << CondString << "\n"
+ << Indent << " )\n";
+ }
+ }
+ }
+
// Attempt to emit code for any untested predicates left over. Note that
// isFullyTested() will remain false even if we succeed here and therefore
// combine rule elision will not be performed. This is because we do not
@@ -800,16 +823,19 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS,
<< Indent << " "
<< CodeExpander(Rule->getMatchingFixupCode()->getValue(), Expansions,
RuleDef.getLoc(), ShowExpansions)
- << "\n"
+ << '\n'
<< Indent << " return true;\n"
<< Indent << " }()";
}
- OS << ") {\n" << Indent << " ";
+ OS << Indent << " ) {\n" << Indent << " ";
if (const StringInit *Code = dyn_cast<StringInit>(Applyer->getArg(0))) {
- OS << CodeExpander(Code->getAsUnquotedString(), Expansions,
+ OS << " LLVM_DEBUG(dbgs() << \"Applying rule '"
+ << RuleDef.getName()
+ << "'\\n\");\n"
+ << CodeExpander(Code->getAsUnquotedString(), Expansions,
RuleDef.getLoc(), ShowExpansions)
- << "\n"
+ << '\n'
<< Indent << " return true;\n"
<< Indent << " }\n";
} else {
@@ -842,7 +868,7 @@ static void emitAdditionalHelperMethodArguments(raw_ostream &OS,
Record *Combiner) {
for (Record *Arg : Combiner->getValueAsListOfDefs("AdditionalArguments"))
OS << ",\n " << Arg->getValueAsString("Type")
- << Arg->getValueAsString("Name");
+ << " " << Arg->getValueAsString("Name");
}
void GICombinerEmitter::run(raw_ostream &OS) {
@@ -924,7 +950,7 @@ void GICombinerEmitter::run(raw_ostream &OS) {
emitNameMatcher(OS);
- OS << "static Optional<std::pair<uint64_t, uint64_t>> "
+ OS << "static std::optional<std::pair<uint64_t, uint64_t>> "
"getRuleRangeForIdentifier(StringRef RuleIdentifier) {\n"
<< " std::pair<StringRef, StringRef> RangePair = "
"RuleIdentifier.split('-');\n"
@@ -934,7 +960,7 @@ void GICombinerEmitter::run(raw_ostream &OS) {
<< " const auto Last = "
"getRuleIdxForIdentifier(RangePair.second);\n"
<< " if (!First || !Last)\n"
- << " return None;\n"
+ << " return std::nullopt;\n"
<< " if (First >= Last)\n"
<< " report_fatal_error(\"Beginning of range should be before "
"end of range\");\n"
@@ -945,7 +971,7 @@ void GICombinerEmitter::run(raw_ostream &OS) {
<< " }\n"
<< " const auto I = getRuleIdxForIdentifier(RangePair.first);\n"
<< " if (!I)\n"
- << " return None;\n"
+ << " return std::nullopt;\n"
<< " return {{*I, *I + 1}};\n"
<< "}\n\n";
diff --git a/llvm/utils/TableGen/GlobalISel/CodeExpansions.h b/llvm/utils/TableGen/GlobalISel/CodeExpansions.h
index bb890ec8f57e..f536e801b27f 100644
--- a/llvm/utils/TableGen/GlobalISel/CodeExpansions.h
+++ b/llvm/utils/TableGen/GlobalISel/CodeExpansions.h
@@ -24,9 +24,9 @@ protected:
public:
void declare(StringRef Name, StringRef Expansion) {
- bool Inserted = Expansions.try_emplace(Name, Expansion).second;
- assert(Inserted && "Declared variable twice");
- (void)Inserted;
+ // Duplicates are not inserted. The expansion refers to different
+ // MachineOperands using the same virtual register.
+ Expansions.try_emplace(Name, Expansion);
}
std::string lookup(StringRef Variable) const {
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp
index 42055ad4f608..d98884493e84 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.cpp
@@ -580,6 +580,10 @@ void GIMatchTreeOpcodePartitioner::applyForPartition(
}
}
for (auto &Leaf : NewLeaves) {
+ // Skip any leaves that don't care about this instruction.
+ if (!Leaf.getInstrInfo(InstrID))
+ continue;
+
for (unsigned OpIdx : ReferencedOperands.set_bits()) {
Leaf.declareOperand(InstrID, OpIdx);
}
@@ -697,8 +701,10 @@ void GIMatchTreeVRegDefPartitioner::repartition(
for (const auto &Leaf : enumerate(Leaves)) {
GIMatchTreeInstrInfo *InstrInfo = Leaf.value().getInstrInfo(InstrID);
if (!InstrInfo)
- for (auto &Partition : Partitions)
+ for (auto &Partition : Partitions) {
+ Partition.second.resize(Leaf.index() + 1);
Partition.second.set(Leaf.index());
+ }
}
}
@@ -762,17 +768,18 @@ void GIMatchTreeVRegDefPartitioner::emitPartitionResults(
void GIMatchTreeVRegDefPartitioner::generatePartitionSelectorCode(
raw_ostream &OS, StringRef Indent) const {
- OS << Indent << "Partition = -1\n"
- << Indent << "if (MIs.size() <= NewInstrID) MIs.resize(NewInstrID + 1);\n"
+ OS << Indent << "Partition = -1;\n"
+ << Indent << "if (MIs.size() <= " << NewInstrID << ") MIs.resize("
+ << (NewInstrID + 1) << ");\n"
<< Indent << "MIs[" << NewInstrID << "] = nullptr;\n"
- << Indent << "if (MIs[" << InstrID << "].getOperand(" << OpIdx
- << ").isReg()))\n"
+ << Indent << "if (MIs[" << InstrID << "]->getOperand(" << OpIdx
+ << ").isReg())\n"
<< Indent << " MIs[" << NewInstrID << "] = MRI.getVRegDef(MIs[" << InstrID
- << "].getOperand(" << OpIdx << ").getReg()));\n";
+ << "]->getOperand(" << OpIdx << ").getReg());\n";
for (const auto &Pair : ResultToPartition)
OS << Indent << "if (MIs[" << NewInstrID << "] "
- << (Pair.first ? "==" : "!=")
+ << (Pair.first ? "!=" : "==")
<< " nullptr) Partition = " << Pair.second << ";\n";
OS << Indent << "if (Partition == -1) return false;\n";
diff --git a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h
index 55a86259661d..0ce4060fe7b4 100644
--- a/llvm/utils/TableGen/GlobalISel/GIMatchTree.h
+++ b/llvm/utils/TableGen/GlobalISel/GIMatchTree.h
@@ -24,12 +24,12 @@ class GIMatchTreeVariableBinding {
StringRef Name;
// The matched instruction it is bound to.
unsigned InstrID;
- // The matched operand (if appropriate) it is bound to.
- Optional<unsigned> OpIdx;
+ // The matched operand (if appropriate) it is bound to.
+ std::optional<unsigned> OpIdx;
public:
GIMatchTreeVariableBinding(StringRef Name, unsigned InstrID,
- Optional<unsigned> OpIdx = None)
+ std::optional<unsigned> OpIdx = std::nullopt)
: Name(Name), InstrID(InstrID), OpIdx(OpIdx) {}
bool isInstr() const { return !OpIdx; }
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 4b47cda41567..c79c79948a80 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -32,7 +32,6 @@
#include "CodeGenDAGPatterns.h"
#include "CodeGenInstruction.h"
#include "SubtargetFeatureInfo.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CodeGenCoverage.h"
#include "llvm/Support/CommandLine.h"
@@ -184,11 +183,12 @@ public:
"Unexpected mismatch of scalable property");
return Ty.isVector()
? std::make_tuple(Ty.isScalable(),
- Ty.getSizeInBits().getKnownMinSize()) <
- std::make_tuple(Other.Ty.isScalable(),
- Other.Ty.getSizeInBits().getKnownMinSize())
- : Ty.getSizeInBits().getFixedSize() <
- Other.Ty.getSizeInBits().getFixedSize();
+ Ty.getSizeInBits().getKnownMinValue()) <
+ std::make_tuple(
+ Other.Ty.isScalable(),
+ Other.Ty.getSizeInBits().getKnownMinValue())
+ : Ty.getSizeInBits().getFixedValue() <
+ Other.Ty.getSizeInBits().getFixedValue();
}
bool operator==(const LLTCodeGen &B) const { return Ty == B.Ty; }
@@ -200,7 +200,7 @@ std::set<LLTCodeGen> KnownTypes;
class InstructionMatcher;
/// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for
/// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...).
-static Optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) {
+static std::optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) {
MVT VT(SVT);
if (VT.isVector() && !VT.getVectorElementCount().isScalar())
@@ -210,7 +210,7 @@ static Optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) {
if (VT.isInteger() || VT.isFloatingPoint())
return LLTCodeGen(LLT::scalar(VT.getSizeInBits()));
- return None;
+ return std::nullopt;
}
static std::string explainPredicates(const TreePatternNode *N) {
@@ -466,7 +466,7 @@ public:
/// The actual run-time value, if known
int64_t RawValue;
- MatchTableRecord(Optional<unsigned> LabelID_, StringRef EmitStr,
+ MatchTableRecord(std::optional<unsigned> LabelID_, StringRef EmitStr,
unsigned NumElements, unsigned Flags,
int64_t RawValue = std::numeric_limits<int64_t>::min())
: LabelID(LabelID_.value_or(~0u)), EmitStr(EmitStr),
@@ -518,7 +518,8 @@ class MatchTable {
public:
static MatchTableRecord LineBreak;
static MatchTableRecord Comment(StringRef Comment) {
- return MatchTableRecord(None, Comment, 0, MatchTableRecord::MTRF_Comment);
+ return MatchTableRecord(std::nullopt, Comment, 0,
+ MatchTableRecord::MTRF_Comment);
}
static MatchTableRecord Opcode(StringRef Opcode, int IndentAdjust = 0) {
unsigned ExtraFlags = 0;
@@ -527,29 +528,29 @@ public:
if (IndentAdjust < 0)
ExtraFlags |= MatchTableRecord::MTRF_Outdent;
- return MatchTableRecord(None, Opcode, 1,
+ return MatchTableRecord(std::nullopt, Opcode, 1,
MatchTableRecord::MTRF_CommaFollows | ExtraFlags);
}
static MatchTableRecord NamedValue(StringRef NamedValue) {
- return MatchTableRecord(None, NamedValue, 1,
+ return MatchTableRecord(std::nullopt, NamedValue, 1,
MatchTableRecord::MTRF_CommaFollows);
}
static MatchTableRecord NamedValue(StringRef NamedValue, int64_t RawValue) {
- return MatchTableRecord(None, NamedValue, 1,
+ return MatchTableRecord(std::nullopt, NamedValue, 1,
MatchTableRecord::MTRF_CommaFollows, RawValue);
}
static MatchTableRecord NamedValue(StringRef Namespace,
StringRef NamedValue) {
- return MatchTableRecord(None, (Namespace + "::" + NamedValue).str(), 1,
- MatchTableRecord::MTRF_CommaFollows);
+ return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
+ 1, MatchTableRecord::MTRF_CommaFollows);
}
static MatchTableRecord NamedValue(StringRef Namespace, StringRef NamedValue,
int64_t RawValue) {
- return MatchTableRecord(None, (Namespace + "::" + NamedValue).str(), 1,
- MatchTableRecord::MTRF_CommaFollows, RawValue);
+ return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
+ 1, MatchTableRecord::MTRF_CommaFollows, RawValue);
}
static MatchTableRecord IntValue(int64_t IntValue) {
- return MatchTableRecord(None, llvm::to_string(IntValue), 1,
+ return MatchTableRecord(std::nullopt, llvm::to_string(IntValue), 1,
MatchTableRecord::MTRF_CommaFollows);
}
static MatchTableRecord Label(unsigned LabelID) {
@@ -625,7 +626,7 @@ public:
};
MatchTableRecord MatchTable::LineBreak = {
- None, "" /* Emit String */, 0 /* Elements */,
+ std::nullopt, "" /* Emit String */, 0 /* Elements */,
MatchTableRecord::MTRF_LineBreakFollows};
void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis,
@@ -965,11 +966,11 @@ public:
return Error::success();
}
- Optional<DefinedComplexPatternSubOperand>
+ std::optional<DefinedComplexPatternSubOperand>
getComplexSubOperand(StringRef SymbolicName) const {
const auto &I = ComplexSubOperands.find(SymbolicName);
if (I == ComplexSubOperands.end())
- return None;
+ return std::nullopt;
return I->second;
}
@@ -1642,9 +1643,9 @@ public:
/// Construct a new operand predicate and add it to the matcher.
template <class Kind, class... Args>
- Optional<Kind *> addPredicate(Args &&... args) {
+ std::optional<Kind *> addPredicate(Args &&...args) {
if (isSameAsAnotherOperand())
- return None;
+ return std::nullopt;
Predicates.emplace_back(std::make_unique<Kind>(
getInsnVarID(), getOpIdx(), std::forward<Args>(args)...));
return static_cast<Kind *>(Predicates.back().get());
@@ -2301,7 +2302,7 @@ public:
/// Construct a new instruction predicate and add it to the matcher.
template <class Kind, class... Args>
- Optional<Kind *> addPredicate(Args &&... args) {
+ std::optional<Kind *> addPredicate(Args &&...args) {
Predicates.emplace_back(
std::make_unique<Kind>(getInsnVarID(), std::forward<Args>(args)...));
return static_cast<Kind *>(Predicates.back().get());
@@ -2522,6 +2523,12 @@ public:
return true;
return false;
}
+
+ /// Report the maximum number of temporary operands needed by the predicate
+ /// matcher.
+ unsigned countRendererFns() const override {
+ return InsnMatcher->countRendererFns();
+ }
};
void InstructionMatcher::optimize() {
@@ -2944,7 +2951,7 @@ private:
unsigned RendererID;
/// When provided, this is the suboperand of the ComplexPattern operand to
/// render. Otherwise all the suboperands will be rendered.
- Optional<unsigned> SubOperand;
+ std::optional<unsigned> SubOperand;
unsigned getNumOperands() const {
return TheDef.getValueAsDag("Operands")->getNumArgs();
@@ -2953,7 +2960,7 @@ private:
public:
RenderComplexPatternOperand(unsigned InsnID, const Record &TheDef,
StringRef SymbolicName, unsigned RendererID,
- Optional<unsigned> SubOperand = None)
+ std::optional<unsigned> SubOperand = std::nullopt)
: OperandRenderer(OR_ComplexPattern), InsnID(InsnID), TheDef(TheDef),
SymbolicName(SymbolicName), RendererID(RendererID),
SubOperand(SubOperand) {}
@@ -2970,7 +2977,7 @@ public:
<< MatchTable::IntValue(RendererID);
if (SubOperand)
Table << MatchTable::Comment("SubOperand")
- << MatchTable::IntValue(SubOperand.value());
+ << MatchTable::IntValue(*SubOperand);
Table << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
}
};
@@ -3135,7 +3142,7 @@ public:
<< MatchTable::LineBreak;
if (!I->ImplicitDefs.empty() || !I->ImplicitUses.empty()) {
- for (auto Def : I->ImplicitDefs) {
+ for (auto *Def : I->ImplicitDefs) {
auto Namespace = Def->getValue("Namespace")
? Def->getValueAsString("Namespace")
: "";
@@ -3144,7 +3151,7 @@ public:
<< MatchTable::NamedValue(Namespace, Def->getName())
<< MatchTable::LineBreak;
}
- for (auto Use : I->ImplicitUses) {
+ for (auto *Use : I->ImplicitUses) {
auto Namespace = Use->getValue("Namespace")
? Use->getValueAsString("Namespace")
: "";
@@ -3545,7 +3552,7 @@ static Expected<LLTCodeGen> getInstResultType(const TreePatternNode *Dst) {
if (ChildTypes.size() != 1)
return failedImport("Dst pattern child has multiple results");
- Optional<LLTCodeGen> MaybeOpTy;
+ std::optional<LLTCodeGen> MaybeOpTy;
if (ChildTypes.front().isMachineValueType()) {
MaybeOpTy =
MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
@@ -3591,7 +3598,7 @@ private:
SubtargetFeatureInfoMap SubtargetFeatures;
// Rule coverage information.
- Optional<CodeGenCoverage> RuleCoverage;
+ std::optional<CodeGenCoverage> RuleCoverage;
/// Variables used to help with collecting of named operands for predicates
/// with 'let PredicateCodeUsesOperands = 1'. WaitingForNamedOperands is set
@@ -3675,31 +3682,31 @@ private:
/// Infer a CodeGenRegisterClass for the type of \p SuperRegNode. The returned
/// CodeGenRegisterClass will support the CodeGenRegisterClass of
/// \p SubRegNode, and the subregister index defined by \p SubRegIdxNode.
- /// If no register class is found, return None.
- Optional<const CodeGenRegisterClass *>
+ /// If no register class is found, return std::nullopt.
+ std::optional<const CodeGenRegisterClass *>
inferSuperRegisterClassForNode(const TypeSetByHwMode &Ty,
TreePatternNode *SuperRegNode,
TreePatternNode *SubRegIdxNode);
- Optional<CodeGenSubRegIndex *>
+ std::optional<CodeGenSubRegIndex *>
inferSubRegIndexForNode(TreePatternNode *SubRegIdxNode);
/// Infer a CodeGenRegisterClass which suppoorts \p Ty and \p SubRegIdxNode.
- /// Return None if no such class exists.
- Optional<const CodeGenRegisterClass *>
+ /// Return std::nullopt if no such class exists.
+ std::optional<const CodeGenRegisterClass *>
inferSuperRegisterClass(const TypeSetByHwMode &Ty,
TreePatternNode *SubRegIdxNode);
/// Return the CodeGenRegisterClass associated with \p Leaf if it has one.
- Optional<const CodeGenRegisterClass *>
+ std::optional<const CodeGenRegisterClass *>
getRegClassFromLeaf(TreePatternNode *Leaf);
- /// Return a CodeGenRegisterClass for \p N if one can be found. Return None
- /// otherwise.
- Optional<const CodeGenRegisterClass *>
+ /// Return a CodeGenRegisterClass for \p N if one can be found. Return
+ /// std::nullopt otherwise.
+ std::optional<const CodeGenRegisterClass *>
inferRegClassFromPattern(TreePatternNode *N);
/// Return the size of the MemoryVT in this predicate, if possible.
- Optional<unsigned>
+ std::optional<unsigned>
getMemSizeBitsFromPredicate(const TreePredicateFn &Predicate);
// Add builtin predicates.
@@ -3816,12 +3823,13 @@ Error GlobalISelEmitter::importRulePredicates(RuleMatcher &M,
return Error::success();
}
-Optional<unsigned> GlobalISelEmitter::getMemSizeBitsFromPredicate(const TreePredicateFn &Predicate) {
- Optional<LLTCodeGen> MemTyOrNone =
+std::optional<unsigned> GlobalISelEmitter::getMemSizeBitsFromPredicate(
+ const TreePredicateFn &Predicate) {
+ std::optional<LLTCodeGen> MemTyOrNone =
MVTToLLT(getValueType(Predicate.getMemoryVT()));
if (!MemTyOrNone)
- return None;
+ return std::nullopt;
// Align so unusual types like i1 don't get rounded down.
return llvm::alignTo(
@@ -4007,8 +4015,10 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
for (const TypeSetByHwMode &VTy : Src->getExtTypes()) {
// Results don't have a name unless they are the root node. The caller will
// set the name if appropriate.
+ const bool OperandIsAPointer =
+ SrcGIOrNull && SrcGIOrNull->isOutOperandAPointer(OpIdx);
OperandMatcher &OM = InsnMatcher.addOperand(OpIdx++, "", TempOpIdx);
- if (auto Error = OM.addTypeCheckPredicate(VTy, false /* OperandIsAPointer */))
+ if (auto Error = OM.addTypeCheckPredicate(VTy, OperandIsAPointer))
return failedImport(toString(std::move(Error)) +
" for result of Src pattern operator");
}
@@ -4156,13 +4166,13 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
// argument that is required to be an immediate, we should not emit an LLT
// type check, and should not be looking for a G_CONSTANT defined
// register.
- bool OperandIsImmArg = SrcGIOrNull->isOperandImmArg(i);
+ bool OperandIsImmArg = SrcGIOrNull->isInOperandImmArg(i);
// SelectionDAG allows pointers to be represented with iN since it doesn't
// distinguish between pointers and integers but they are different types in GlobalISel.
// Coerce integers to pointers to address space 0 if the context indicates a pointer.
//
- bool OperandIsAPointer = SrcGIOrNull->isOperandAPointer(i);
+ bool OperandIsAPointer = SrcGIOrNull->isInOperandAPointer(i);
if (IsIntrinsic) {
// For G_INTRINSIC/G_INTRINSIC_W_SIDE_EFFECTS, the operand immediately
@@ -4414,7 +4424,7 @@ Error GlobalISelEmitter::importChildMatcher(
// Treat G_BUILD_VECTOR as the canonical opcode, and G_BUILD_VECTOR_TRUNC
// as an alternative.
InsnOperand.getInsnMatcher().addPredicate<InstructionOpcodeMatcher>(
- makeArrayRef({&BuildVector, &BuildVectorTrunc}));
+ ArrayRef({&BuildVector, &BuildVectorTrunc}));
// TODO: Handle both G_BUILD_VECTOR and G_BUILD_VECTOR_TRUNC We could
// theoretically not emit any opcode check, but getOpcodeMatcher currently
@@ -4536,7 +4546,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
if (ChildTypes.size() != 1)
return failedImport("Dst pattern child has multiple results");
- Optional<LLTCodeGen> OpTyOrNone = None;
+ std::optional<LLTCodeGen> OpTyOrNone;
if (ChildTypes.front().isMachineValueType())
OpTyOrNone = MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
if (!OpTyOrNone)
@@ -4650,7 +4660,7 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer(
if (!SubClass)
return failedImport(
"Cannot infer register class from INSERT_SUBREG operand #1");
- Optional<const CodeGenRegisterClass *> SuperClass =
+ std::optional<const CodeGenRegisterClass *> SuperClass =
inferSuperRegisterClassForNode(Dst->getExtType(0), Dst->getChild(0),
Dst->getChild(2));
if (!SuperClass)
@@ -4968,7 +4978,7 @@ Error GlobalISelEmitter::importDefaultOperandRenderers(
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
DagInit *DefaultOps) const {
for (const auto *DefaultOp : DefaultOps->getArgs()) {
- Optional<LLTCodeGen> OpTyOrNone = None;
+ std::optional<LLTCodeGen> OpTyOrNone;
// Look through ValueType operators.
if (const DagInit *DefaultDagOp = dyn_cast<DagInit>(DefaultOp)) {
@@ -4986,7 +4996,7 @@ Error GlobalISelEmitter::importDefaultOperandRenderers(
auto Def = DefaultDefOp->getDef();
if (Def->getName() == "undef_tied_input") {
unsigned TempRegID = M.allocateTempRegID();
- M.insertAction<MakeTempRegisterAction>(InsertPt, OpTyOrNone.value(),
+ M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTyOrNone,
TempRegID);
InsertPt = M.insertAction<BuildMIAction>(
InsertPt, M.allocateOutputInsnID(),
@@ -5020,23 +5030,23 @@ Error GlobalISelEmitter::importImplicitDefRenderers(
return Error::success();
}
-Optional<const CodeGenRegisterClass *>
+std::optional<const CodeGenRegisterClass *>
GlobalISelEmitter::getRegClassFromLeaf(TreePatternNode *Leaf) {
assert(Leaf && "Expected node?");
assert(Leaf->isLeaf() && "Expected leaf?");
Record *RCRec = getInitValueAsRegClass(Leaf->getLeafValue());
if (!RCRec)
- return None;
+ return std::nullopt;
CodeGenRegisterClass *RC = CGRegs.getRegClass(RCRec);
if (!RC)
- return None;
+ return std::nullopt;
return RC;
}
-Optional<const CodeGenRegisterClass *>
+std::optional<const CodeGenRegisterClass *>
GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) {
if (!N)
- return None;
+ return std::nullopt;
if (N->isLeaf())
return getRegClassFromLeaf(N);
@@ -5046,18 +5056,18 @@ GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) {
// Only handle things that produce a single type.
if (N->getNumTypes() != 1)
- return None;
+ return std::nullopt;
Record *OpRec = N->getOperator();
// We only want instructions.
if (!OpRec->isSubClassOf("Instruction"))
- return None;
+ return std::nullopt;
// Don't want to try and infer things when there could potentially be more
// than one candidate register class.
auto &Inst = Target.getInstruction(OpRec);
if (Inst.Operands.NumDefs > 1)
- return None;
+ return std::nullopt;
// Handle any special-case instructions which we can safely infer register
// classes from.
@@ -5068,7 +5078,7 @@ GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) {
// has the desired register class as the first child.
TreePatternNode *RCChild = N->getChild(IsRegSequence ? 0 : 1);
if (!RCChild->isLeaf())
- return None;
+ return std::nullopt;
return getRegClassFromLeaf(RCChild);
}
if (InstName == "INSERT_SUBREG") {
@@ -5098,21 +5108,21 @@ GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) {
return &RC;
}
- return None;
+ return std::nullopt;
}
-Optional<const CodeGenRegisterClass *>
+std::optional<const CodeGenRegisterClass *>
GlobalISelEmitter::inferSuperRegisterClass(const TypeSetByHwMode &Ty,
TreePatternNode *SubRegIdxNode) {
assert(SubRegIdxNode && "Expected subregister index node!");
// We need a ValueTypeByHwMode for getSuperRegForSubReg.
if (!Ty.isValueTypeByHwMode(false))
- return None;
+ return std::nullopt;
if (!SubRegIdxNode->isLeaf())
- return None;
+ return std::nullopt;
DefInit *SubRegInit = dyn_cast<DefInit>(SubRegIdxNode->getLeafValue());
if (!SubRegInit)
- return None;
+ return std::nullopt;
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
// Use the information we found above to find a minimal register class which
@@ -5121,11 +5131,11 @@ GlobalISelEmitter::inferSuperRegisterClass(const TypeSetByHwMode &Ty,
Target.getSuperRegForSubReg(Ty.getValueTypeByHwMode(), CGRegs, SubIdx,
/* MustBeAllocatable */ true);
if (!RC)
- return None;
+ return std::nullopt;
return *RC;
}
-Optional<const CodeGenRegisterClass *>
+std::optional<const CodeGenRegisterClass *>
GlobalISelEmitter::inferSuperRegisterClassForNode(
const TypeSetByHwMode &Ty, TreePatternNode *SuperRegNode,
TreePatternNode *SubRegIdxNode) {
@@ -5135,20 +5145,20 @@ GlobalISelEmitter::inferSuperRegisterClassForNode(
// from the subregister index node. We can assume that whoever wrote the
// pattern in the first place made sure that the super register and
// subregister are compatible.
- if (Optional<const CodeGenRegisterClass *> SuperRegisterClass =
+ if (std::optional<const CodeGenRegisterClass *> SuperRegisterClass =
inferRegClassFromPattern(SuperRegNode))
return *SuperRegisterClass;
return inferSuperRegisterClass(Ty, SubRegIdxNode);
}
-Optional<CodeGenSubRegIndex *>
+std::optional<CodeGenSubRegIndex *>
GlobalISelEmitter::inferSubRegIndexForNode(TreePatternNode *SubRegIdxNode) {
if (!SubRegIdxNode->isLeaf())
- return None;
+ return std::nullopt;
DefInit *SubRegInit = dyn_cast<DefInit>(SubRegIdxNode->getLeafValue());
if (!SubRegInit)
- return None;
+ return std::nullopt;
return CGRegs.getSubRegIdx(SubRegInit->getDef());
}
@@ -5673,11 +5683,11 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
auto RuleCoverageBufOrErr = MemoryBuffer::getFile(UseCoverageFile);
if (!RuleCoverageBufOrErr) {
PrintWarning(SMLoc(), "Missing rule coverage data");
- RuleCoverage = None;
+ RuleCoverage = std::nullopt;
} else {
if (!RuleCoverage->parse(*RuleCoverageBufOrErr.get(), Target.getName())) {
PrintWarning(SMLoc(), "Ignoring invalid or missing rule coverage data");
- RuleCoverage = None;
+ RuleCoverage = std::nullopt;
}
}
}
@@ -5849,6 +5859,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
// Emit a table containing the PredicateBitsets objects needed by the matcher
// and an enum for the matcher to reference them with.
std::vector<std::vector<Record *>> FeatureBitsets;
+ FeatureBitsets.reserve(Rules.size());
for (auto &Rule : Rules)
FeatureBitsets.push_back(Rule.getRequiredFeatures());
llvm::sort(FeatureBitsets, [&](const std::vector<Record *> &A,
diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp
index da8d0a0096fd..564c3ed64e26 100644
--- a/llvm/utils/TableGen/InstrInfoEmitter.cpp
+++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp
@@ -117,9 +117,9 @@ private:
static void PrintDefList(const std::vector<Record*> &Uses,
unsigned Num, raw_ostream &OS) {
OS << "static const MCPhysReg ImplicitList" << Num << "[] = { ";
- for (Record *U : Uses)
- OS << getQualifiedName(U) << ", ";
- OS << "0 };\n";
+ for (auto [Idx, U] : enumerate(Uses))
+ OS << (Idx ? ", " : "") << getQualifiedName(U);
+ OS << " };\n";
}
//===----------------------------------------------------------------------===//
@@ -907,16 +907,14 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
// 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");
- if (!Uses.empty()) {
- unsigned &IL = EmittedLists[Uses];
- if (!IL) PrintDefList(Uses, IL = ++ListNumber, OS);
- }
- std::vector<Record*> Defs = Inst->getValueAsListOfDefs("Defs");
- if (!Defs.empty()) {
- unsigned &IL = EmittedLists[Defs];
- if (!IL) PrintDefList(Defs, IL = ++ListNumber, OS);
+ std::vector<Record *> ImplicitOps = II->ImplicitUses;
+ llvm::append_range(ImplicitOps, II->ImplicitDefs);
+ if (!ImplicitOps.empty()) {
+ unsigned &IL = EmittedLists[ImplicitOps];
+ if (!IL) {
+ IL = ++ListNumber;
+ PrintDefList(ImplicitOps, IL, OS);
+ }
}
}
@@ -926,20 +924,19 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
Records.startTimer("Emit operand info");
EmitOperandInfo(OS, OperandInfoIDs);
- // Emit all of the MCInstrDesc records in their ENUM ordering.
- //
+ // Emit all of the MCInstrDesc records in reverse ENUM ordering.
Records.startTimer("Emit InstrDesc records");
OS << "\nextern const MCInstrDesc " << TargetName << "Insts[] = {\n";
ArrayRef<const CodeGenInstruction*> NumberedInstructions =
Target.getInstructionsByEnumValue();
SequenceToOffsetTable<std::string> InstrNames;
- unsigned Num = 0;
- for (const CodeGenInstruction *Inst : NumberedInstructions) {
+ unsigned Num = NumberedInstructions.size();
+ for (const CodeGenInstruction *Inst : reverse(NumberedInstructions)) {
// Keep a list of the instruction names.
InstrNames.add(std::string(Inst->TheDef->getName()));
// Emit the record into the table.
- emitRecord(*Inst, Num++, InstrInfo, EmittedLists, OperandInfoIDs, OS);
+ emitRecord(*Inst, --Num, InstrInfo, EmittedLists, OperandInfoIDs, OS);
}
OS << "};\n\n";
@@ -1032,7 +1029,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OS << "namespace llvm {\n";
OS << "struct " << ClassName << " : public TargetInstrInfo {\n"
<< " explicit " << ClassName
- << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1, int ReturnOpcode = -1);\n"
+ << "(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u, "
+ "unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u);\n"
<< " ~" << ClassName << "() override = default;\n";
@@ -1065,8 +1063,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OS << "extern const MCInstrInfo::ComplexDeprecationPredicate " << TargetName
<< "InstrComplexDeprecationInfos[];\n";
OS << ClassName << "::" << ClassName
- << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode, int "
- "ReturnOpcode)\n"
+ << "(unsigned CFSetupOpcode, unsigned CFDestroyOpcode, unsigned "
+ "CatchRetOpcode, unsigned ReturnOpcode)\n"
<< " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, "
"ReturnOpcode) {\n"
<< " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName
@@ -1118,7 +1116,9 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
OS << Num << ",\t" << MinOperands << ",\t"
<< Inst.Operands.NumDefs << ",\t"
<< Inst.TheDef->getValueAsInt("Size") << ",\t"
- << SchedModels.getSchedClassIdx(Inst) << ",\t0";
+ << SchedModels.getSchedClassIdx(Inst) << ",\t"
+ << Inst.ImplicitUses.size() << ",\t"
+ << Inst.ImplicitDefs.size() << ",\t0";
CodeGenTarget &Target = CDP.getTargetInfo();
@@ -1183,18 +1183,13 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
OS.write_hex(Value);
OS << "ULL, ";
- // Emit the implicit uses and defs lists...
- std::vector<Record*> UseList = Inst.TheDef->getValueAsListOfDefs("Uses");
- if (UseList.empty())
- OS << "nullptr, ";
- else
- OS << "ImplicitList" << EmittedLists[UseList] << ", ";
-
- std::vector<Record*> DefList = Inst.TheDef->getValueAsListOfDefs("Defs");
- if (DefList.empty())
+ // Emit the implicit use/def list...
+ std::vector<Record *> ImplicitOps = Inst.ImplicitUses;
+ llvm::append_range(ImplicitOps, Inst.ImplicitDefs);
+ if (ImplicitOps.empty())
OS << "nullptr, ";
else
- OS << "ImplicitList" << EmittedLists[DefList] << ", ";
+ OS << "ImplicitList" << EmittedLists[ImplicitOps] << ", ";
// Emit the operand info.
std::vector<std::string> OperandInfo = GetOperandInfo(Inst);
diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp
index fca2bc34e09a..946a58417594 100644
--- a/llvm/utils/TableGen/IntrinsicEmitter.cpp
+++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp
@@ -361,10 +361,10 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
unsigned Tmp = 0;
switch (VT) {
default: break;
- case MVT::iPTRAny: ++Tmp; LLVM_FALLTHROUGH;
- case MVT::vAny: ++Tmp; LLVM_FALLTHROUGH;
- case MVT::fAny: ++Tmp; LLVM_FALLTHROUGH;
- case MVT::iAny: ++Tmp; LLVM_FALLTHROUGH;
+ case MVT::iPTRAny: ++Tmp; [[fallthrough]];
+ case MVT::vAny: ++Tmp; [[fallthrough]];
+ case MVT::fAny: ++Tmp; [[fallthrough]];
+ case MVT::iAny: ++Tmp; [[fallthrough]];
case MVT::Any: {
// If this is an "any" valuetype, then the type is the type of the next
// type in the list specified to getIntrinsic().
@@ -444,16 +444,16 @@ static void UpdateArgCodes(Record *R, std::vector<unsigned char> &ArgCodes,
break;
case MVT::iPTRAny:
++Tmp;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case MVT::vAny:
++Tmp;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case MVT::fAny:
++Tmp;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case MVT::iAny:
++Tmp;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case MVT::Any:
unsigned OriginalIdx = ArgCodes.size() - NumInserted;
assert(OriginalIdx >= Mapping.size());
@@ -601,49 +601,64 @@ void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints,
}
namespace {
-struct AttributeComparator {
- bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
- // Sort throwing intrinsics after non-throwing intrinsics.
- if (L->canThrow != R->canThrow)
- return R->canThrow;
+std::optional<bool> compareFnAttributes(const CodeGenIntrinsic *L,
+ const CodeGenIntrinsic *R) {
+ // Sort throwing intrinsics after non-throwing intrinsics.
+ if (L->canThrow != R->canThrow)
+ return R->canThrow;
+
+ if (L->isNoDuplicate != R->isNoDuplicate)
+ return R->isNoDuplicate;
- if (L->isNoDuplicate != R->isNoDuplicate)
- return R->isNoDuplicate;
+ if (L->isNoMerge != R->isNoMerge)
+ return R->isNoMerge;
- if (L->isNoMerge != R->isNoMerge)
- return R->isNoMerge;
+ if (L->isNoReturn != R->isNoReturn)
+ return R->isNoReturn;
- if (L->isNoReturn != R->isNoReturn)
- return R->isNoReturn;
+ if (L->isNoCallback != R->isNoCallback)
+ return R->isNoCallback;
- if (L->isNoCallback != R->isNoCallback)
- return R->isNoCallback;
+ if (L->isNoSync != R->isNoSync)
+ return R->isNoSync;
- if (L->isNoSync != R->isNoSync)
- return R->isNoSync;
+ if (L->isNoFree != R->isNoFree)
+ return R->isNoFree;
- if (L->isNoFree != R->isNoFree)
- return R->isNoFree;
+ if (L->isWillReturn != R->isWillReturn)
+ return R->isWillReturn;
- if (L->isWillReturn != R->isWillReturn)
- return R->isWillReturn;
+ if (L->isCold != R->isCold)
+ return R->isCold;
- if (L->isCold != R->isCold)
- return R->isCold;
+ if (L->isConvergent != R->isConvergent)
+ return R->isConvergent;
- if (L->isConvergent != R->isConvergent)
- return R->isConvergent;
+ if (L->isSpeculatable != R->isSpeculatable)
+ return R->isSpeculatable;
- if (L->isSpeculatable != R->isSpeculatable)
- return R->isSpeculatable;
+ if (L->hasSideEffects != R->hasSideEffects)
+ return R->hasSideEffects;
+
+ // Try to order by readonly/readnone attribute.
+ uint32_t LK = L->ME.toIntValue();
+ uint32_t RK = R->ME.toIntValue();
+ if (LK != RK) return (LK > RK);
+
+ return std::nullopt;
+}
- if (L->hasSideEffects != R->hasSideEffects)
- return R->hasSideEffects;
+struct FnAttributeComparator {
+ bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
+ return compareFnAttributes(L, R).value_or(false);
+ }
+};
+
+struct AttributeComparator {
+ bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
+ if (std::optional<bool> Res = compareFnAttributes(L, R))
+ return *Res;
- // Try to order by readonly/readnone attribute.
- CodeGenIntrinsic::ModRefBehavior LK = L->ModRef;
- CodeGenIntrinsic::ModRefBehavior RK = R->ModRef;
- if (LK != RK) return (LK > RK);
// Order by argument attributes.
// This is reliable because each side is already sorted internally.
return (L->ArgumentAttributes < R->ArgumentAttributes);
@@ -656,6 +671,118 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
raw_ostream &OS) {
OS << "// Add parameter attributes that are not common to all intrinsics.\n";
OS << "#ifdef GET_INTRINSIC_ATTRIBUTES\n";
+
+ // Compute unique argument attribute sets.
+ std::map<SmallVector<CodeGenIntrinsic::ArgAttribute, 0>, unsigned>
+ UniqArgAttributes;
+ OS << "static AttributeSet getIntrinsicArgAttributeSet("
+ << "LLVMContext &C, unsigned ID) {\n"
+ << " switch (ID) {\n"
+ << " default: llvm_unreachable(\"Invalid attribute set number\");\n";
+ for (const CodeGenIntrinsic &Int : Ints) {
+ for (auto &Attrs : Int.ArgumentAttributes) {
+ if (Attrs.empty())
+ continue;
+
+ unsigned ID = UniqArgAttributes.size();
+ if (!UniqArgAttributes.try_emplace(Attrs, ID).second)
+ continue;
+
+ assert(is_sorted(Attrs) &&
+ "Argument attributes are not sorted");
+
+ OS << " case " << ID << ":\n";
+ OS << " return AttributeSet::get(C, {\n";
+ for (const CodeGenIntrinsic::ArgAttribute &Attr : Attrs) {
+ switch (Attr.Kind) {
+ case CodeGenIntrinsic::NoCapture:
+ OS << " Attribute::get(C, Attribute::NoCapture),\n";
+ break;
+ case CodeGenIntrinsic::NoAlias:
+ OS << " Attribute::get(C, Attribute::NoAlias),\n";
+ break;
+ case CodeGenIntrinsic::NoUndef:
+ OS << " Attribute::get(C, Attribute::NoUndef),\n";
+ break;
+ case CodeGenIntrinsic::NonNull:
+ OS << " Attribute::get(C, Attribute::NonNull),\n";
+ break;
+ case CodeGenIntrinsic::Returned:
+ OS << " Attribute::get(C, Attribute::Returned),\n";
+ break;
+ case CodeGenIntrinsic::ReadOnly:
+ OS << " Attribute::get(C, Attribute::ReadOnly),\n";
+ break;
+ case CodeGenIntrinsic::WriteOnly:
+ OS << " Attribute::get(C, Attribute::WriteOnly),\n";
+ break;
+ case CodeGenIntrinsic::ReadNone:
+ OS << " Attribute::get(C, Attribute::ReadNone),\n";
+ break;
+ case CodeGenIntrinsic::ImmArg:
+ OS << " Attribute::get(C, Attribute::ImmArg),\n";
+ break;
+ case CodeGenIntrinsic::Alignment:
+ OS << " Attribute::get(C, Attribute::Alignment, "
+ << Attr.Value << "),\n";
+ break;
+ }
+ }
+ OS << " });\n";
+ }
+ }
+ OS << " }\n";
+ OS << "}\n\n";
+
+ // Compute unique function attribute sets.
+ std::map<const CodeGenIntrinsic*, unsigned, FnAttributeComparator>
+ UniqFnAttributes;
+ OS << "static AttributeSet getIntrinsicFnAttributeSet("
+ << "LLVMContext &C, unsigned ID) {\n"
+ << " switch (ID) {\n"
+ << " default: llvm_unreachable(\"Invalid attribute set number\");\n";
+ for (const CodeGenIntrinsic &Intrinsic : Ints) {
+ unsigned ID = UniqFnAttributes.size();
+ if (!UniqFnAttributes.try_emplace(&Intrinsic, ID).second)
+ continue;
+
+ OS << " case " << ID << ":\n"
+ << " return AttributeSet::get(C, {\n";
+ if (!Intrinsic.canThrow)
+ OS << " Attribute::get(C, Attribute::NoUnwind),\n";
+ if (Intrinsic.isNoReturn)
+ OS << " Attribute::get(C, Attribute::NoReturn),\n";
+ if (Intrinsic.isNoCallback)
+ OS << " Attribute::get(C, Attribute::NoCallback),\n";
+ if (Intrinsic.isNoSync)
+ OS << " Attribute::get(C, Attribute::NoSync),\n";
+ if (Intrinsic.isNoFree)
+ OS << " Attribute::get(C, Attribute::NoFree),\n";
+ if (Intrinsic.isWillReturn)
+ OS << " Attribute::get(C, Attribute::WillReturn),\n";
+ if (Intrinsic.isCold)
+ OS << " Attribute::get(C, Attribute::Cold),\n";
+ if (Intrinsic.isNoDuplicate)
+ OS << " Attribute::get(C, Attribute::NoDuplicate),\n";
+ if (Intrinsic.isNoMerge)
+ OS << " Attribute::get(C, Attribute::NoMerge),\n";
+ if (Intrinsic.isConvergent)
+ OS << " Attribute::get(C, Attribute::Convergent),\n";
+ if (Intrinsic.isSpeculatable)
+ OS << " Attribute::get(C, Attribute::Speculatable),\n";
+
+ MemoryEffects ME = Intrinsic.ME;
+ // TODO: IntrHasSideEffects should affect not only readnone intrinsics.
+ if (ME.doesNotAccessMemory() && Intrinsic.hasSideEffects)
+ ME = MemoryEffects::unknown();
+ if (ME != MemoryEffects::unknown()) {
+ OS << " Attribute::getWithMemoryEffects(C, "
+ << "MemoryEffects::createFromIntValue(" << ME.toIntValue() << ")),\n";
+ }
+ OS << " });\n";
+ }
+ OS << " }\n";
+ OS << "}\n\n";
OS << "AttributeList Intrinsic::getAttributes(LLVMContext &C, ID id) {\n";
// Compute the maximum number of attribute arguments and the map
@@ -686,7 +813,7 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
}
OS << " };\n\n";
- OS << " AttributeList AS[" << maxArgAttrs + 1 << "];\n";
+ OS << " std::pair<unsigned, AttributeSet> AS[" << maxArgAttrs + 1 << "];\n";
OS << " unsigned NumAttrs = 0;\n";
OS << " if (id != 0) {\n";
OS << " switch(IntrinsicsToAttributesMap[id - 1]) {\n";
@@ -699,182 +826,41 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
// Keep track of the number of attributes we're writing out.
unsigned numAttrs = 0;
- // The argument attributes are alreadys sorted by argument index.
- unsigned Ai = 0, Ae = Intrinsic.ArgumentAttributes.size();
- if (Ae) {
- while (Ai != Ae) {
- unsigned AttrIdx = Intrinsic.ArgumentAttributes[Ai].Index;
-
- OS << " const Attribute::AttrKind AttrParam" << AttrIdx << "[]= {";
- ListSeparator LS(",");
-
- bool AllValuesAreZero = true;
- SmallVector<uint64_t, 8> Values;
- do {
- switch (Intrinsic.ArgumentAttributes[Ai].Kind) {
- case CodeGenIntrinsic::NoCapture:
- OS << LS << "Attribute::NoCapture";
- break;
- case CodeGenIntrinsic::NoAlias:
- OS << LS << "Attribute::NoAlias";
- break;
- case CodeGenIntrinsic::NoUndef:
- OS << LS << "Attribute::NoUndef";
- break;
- case CodeGenIntrinsic::Returned:
- OS << LS << "Attribute::Returned";
- break;
- case CodeGenIntrinsic::ReadOnly:
- OS << LS << "Attribute::ReadOnly";
- break;
- case CodeGenIntrinsic::WriteOnly:
- OS << LS << "Attribute::WriteOnly";
- break;
- case CodeGenIntrinsic::ReadNone:
- OS << LS << "Attribute::ReadNone";
- break;
- case CodeGenIntrinsic::ImmArg:
- OS << LS << "Attribute::ImmArg";
- break;
- case CodeGenIntrinsic::Alignment:
- OS << LS << "Attribute::Alignment";
- break;
- }
- uint64_t V = Intrinsic.ArgumentAttributes[Ai].Value;
- Values.push_back(V);
- AllValuesAreZero &= (V == 0);
-
- ++Ai;
- } while (Ai != Ae && Intrinsic.ArgumentAttributes[Ai].Index == AttrIdx);
- OS << "};\n";
-
- // Generate attribute value array if not all attribute values are zero.
- if (!AllValuesAreZero) {
- OS << " const uint64_t AttrValParam" << AttrIdx << "[]= {";
- ListSeparator LSV(",");
- for (const auto V : Values)
- OS << LSV << V;
- OS << "};\n";
- }
+ for (const auto &[AttrIdx, Attrs] :
+ enumerate(Intrinsic.ArgumentAttributes)) {
+ if (Attrs.empty())
+ continue;
- OS << " AS[" << numAttrs++ << "] = AttributeList::get(C, "
- << AttrIdx << ", AttrParam" << AttrIdx;
- if (!AllValuesAreZero)
- OS << ", AttrValParam" << AttrIdx;
- OS << ");\n";
- }
+ unsigned ID = UniqArgAttributes.find(Attrs)->second;
+ OS << " AS[" << numAttrs++ << "] = {" << AttrIdx
+ << ", getIntrinsicArgAttributeSet(C, " << ID << ")};\n";
}
if (!Intrinsic.canThrow ||
- (Intrinsic.ModRef != CodeGenIntrinsic::ReadWriteMem &&
+ (Intrinsic.ME != MemoryEffects::unknown() &&
!Intrinsic.hasSideEffects) ||
Intrinsic.isNoReturn || Intrinsic.isNoCallback || Intrinsic.isNoSync ||
Intrinsic.isNoFree || Intrinsic.isWillReturn || Intrinsic.isCold ||
Intrinsic.isNoDuplicate || Intrinsic.isNoMerge ||
Intrinsic.isConvergent || Intrinsic.isSpeculatable) {
- OS << " const Attribute::AttrKind Atts[] = {";
- ListSeparator LS(",");
- if (!Intrinsic.canThrow)
- OS << LS << "Attribute::NoUnwind";
- if (Intrinsic.isNoReturn)
- OS << LS << "Attribute::NoReturn";
- if (Intrinsic.isNoCallback)
- OS << LS << "Attribute::NoCallback";
- if (Intrinsic.isNoSync)
- OS << LS << "Attribute::NoSync";
- if (Intrinsic.isNoFree)
- OS << LS << "Attribute::NoFree";
- if (Intrinsic.isWillReturn)
- OS << LS << "Attribute::WillReturn";
- if (Intrinsic.isCold)
- OS << LS << "Attribute::Cold";
- if (Intrinsic.isNoDuplicate)
- OS << LS << "Attribute::NoDuplicate";
- if (Intrinsic.isNoMerge)
- OS << LS << "Attribute::NoMerge";
- if (Intrinsic.isConvergent)
- OS << LS << "Attribute::Convergent";
- if (Intrinsic.isSpeculatable)
- OS << LS << "Attribute::Speculatable";
-
- switch (Intrinsic.ModRef) {
- case CodeGenIntrinsic::NoMem:
- if (Intrinsic.hasSideEffects)
- break;
- OS << LS;
- OS << "Attribute::ReadNone";
- break;
- case CodeGenIntrinsic::ReadArgMem:
- OS << LS;
- OS << "Attribute::ReadOnly,";
- OS << "Attribute::ArgMemOnly";
- break;
- case CodeGenIntrinsic::ReadMem:
- OS << LS;
- OS << "Attribute::ReadOnly";
- break;
- case CodeGenIntrinsic::ReadInaccessibleMem:
- OS << LS;
- OS << "Attribute::ReadOnly,";
- OS << "Attribute::InaccessibleMemOnly";
- break;
- case CodeGenIntrinsic::ReadInaccessibleMemOrArgMem:
- OS << LS;
- OS << "Attribute::ReadOnly,";
- OS << "Attribute::InaccessibleMemOrArgMemOnly";
- break;
- case CodeGenIntrinsic::WriteArgMem:
- OS << LS;
- OS << "Attribute::WriteOnly,";
- OS << "Attribute::ArgMemOnly";
- break;
- case CodeGenIntrinsic::WriteMem:
- OS << LS;
- OS << "Attribute::WriteOnly";
- break;
- case CodeGenIntrinsic::WriteInaccessibleMem:
- OS << LS;
- OS << "Attribute::WriteOnly,";
- OS << "Attribute::InaccessibleMemOnly";
- break;
- case CodeGenIntrinsic::WriteInaccessibleMemOrArgMem:
- OS << LS;
- OS << "Attribute::WriteOnly,";
- OS << "Attribute::InaccessibleMemOrArgMemOnly";
- break;
- case CodeGenIntrinsic::ReadWriteArgMem:
- OS << LS;
- OS << "Attribute::ArgMemOnly";
- break;
- case CodeGenIntrinsic::ReadWriteInaccessibleMem:
- OS << LS;
- OS << "Attribute::InaccessibleMemOnly";
- break;
- case CodeGenIntrinsic::ReadWriteInaccessibleMemOrArgMem:
- OS << LS;
- OS << "Attribute::InaccessibleMemOrArgMemOnly";
- break;
- case CodeGenIntrinsic::ReadWriteMem:
- break;
- }
- OS << "};\n";
- OS << " AS[" << numAttrs++ << "] = AttributeList::get(C, "
- << "AttributeList::FunctionIndex, Atts);\n";
+ unsigned ID = UniqFnAttributes.find(&Intrinsic)->second;
+ OS << " AS[" << numAttrs++ << "] = {AttributeList::FunctionIndex, "
+ << "getIntrinsicFnAttributeSet(C, " << ID << ")};\n";
}
if (numAttrs) {
OS << " NumAttrs = " << numAttrs << ";\n";
OS << " break;\n";
- OS << " }\n";
+ OS << " }\n";
} else {
OS << " return AttributeList();\n";
- OS << " }\n";
+ OS << " }\n";
}
}
OS << " }\n";
OS << " }\n";
- OS << " return AttributeList::get(C, makeArrayRef(AS, NumAttrs));\n";
+ OS << " return AttributeList::get(C, ArrayRef(AS, NumAttrs));\n";
OS << "}\n";
OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n";
}
diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp
index 182cd0076090..d363191bd9b8 100644
--- a/llvm/utils/TableGen/OptParserEmitter.cpp
+++ b/llvm/utils/TableGen/OptParserEmitter.cpp
@@ -54,9 +54,10 @@ static std::string getOptionSpelling(const Record &R) {
static void emitNameUsingSpelling(raw_ostream &OS, const Record &R) {
size_t PrefixLength;
- OS << "&";
- write_cstring(OS, StringRef(getOptionSpelling(R, PrefixLength)));
- OS << "[" << PrefixLength << "]";
+ OS << "llvm::StringLiteral(";
+ write_cstring(
+ OS, StringRef(getOptionSpelling(R, PrefixLength)).substr(PrefixLength));
+ OS << ")";
}
class MarshallingInfo {
@@ -129,7 +130,7 @@ struct SimpleEnumValueTable {
OS << TableIndex;
}
- Optional<StringRef> emitValueTable(raw_ostream &OS) const {
+ std::optional<StringRef> emitValueTable(raw_ostream &OS) const {
if (TableIndex == -1)
return {};
OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n";
@@ -236,8 +237,14 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
CurPrefix = NewPrefix;
}
- // Dump prefixes.
+ DenseSet<StringRef> PrefixesUnionSet;
+ for (const auto &Prefix : Prefixes)
+ PrefixesUnionSet.insert(Prefix.first.begin(), Prefix.first.end());
+ SmallVector<StringRef> PrefixesUnion(PrefixesUnionSet.begin(),
+ PrefixesUnionSet.end());
+ array_pod_sort(PrefixesUnion.begin(), PrefixesUnion.end());
+ // Dump prefixes.
OS << "/////////\n";
OS << "// Prefixes\n\n";
OS << "#ifdef PREFIX\n";
@@ -251,12 +258,42 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
// Prefix values.
OS << ", {";
for (const auto &PrefixKey : Prefix.first)
- OS << "\"" << PrefixKey << "\" COMMA ";
- OS << "nullptr})\n";
+ OS << "llvm::StringLiteral(\"" << PrefixKey << "\") COMMA ";
+ // Append an empty element to avoid ending up with an empty array.
+ OS << "llvm::StringLiteral(\"\")})\n";
}
OS << "#undef COMMA\n";
OS << "#endif // PREFIX\n\n";
+ // Dump prefix unions.
+ OS << "/////////\n";
+ OS << "// Prefix Union\n\n";
+ OS << "#ifdef PREFIX_UNION\n";
+ OS << "#define COMMA ,\n";
+ OS << "PREFIX_UNION({\n";
+ for (const auto &Prefix : PrefixesUnion) {
+ OS << "llvm::StringLiteral(\"" << Prefix << "\") COMMA ";
+ }
+ OS << "llvm::StringLiteral(\"\")})\n";
+ OS << "#undef COMMA\n";
+ OS << "#endif // PREFIX_UNION\n\n";
+
+ // Dump groups.
+ OS << "/////////\n";
+ OS << "// ValuesCode\n\n";
+ OS << "#ifdef OPTTABLE_VALUES_CODE\n";
+ for (const Record &R : llvm::make_pointee_range(Opts)) {
+ // The option values, if any;
+ if (!isa<UnsetInit>(R.getValueInit("ValuesCode"))) {
+ assert(isa<UnsetInit>(R.getValueInit("Values")) &&
+ "Cannot choose between Values and ValuesCode");
+ OS << "#define VALUES_CODE " << getOptionName(R) << "_Values\n";
+ OS << R.getValueAsString("ValuesCode") << "\n";
+ OS << "#undef VALUES_CODE\n";
+ }
+ }
+ OS << "#endif\n";
+
OS << "/////////\n";
OS << "// Groups\n\n";
OS << "#ifdef OPTION\n";
@@ -265,7 +302,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << "OPTION(";
// The option prefix;
- OS << "nullptr";
+ OS << "llvm::ArrayRef<llvm::StringLiteral>()";
// The option string.
OS << ", \"" << R.getValueAsString("Name") << '"';
@@ -386,6 +423,9 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << ", ";
if (!isa<UnsetInit>(R.getValueInit("Values")))
write_cstring(OS, R.getValueAsString("Values"));
+ else if (!isa<UnsetInit>(R.getValueInit("ValuesCode"))) {
+ OS << getOptionName(R) << "_Values";
+ }
else
OS << "nullptr";
};
@@ -424,6 +464,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
CmpMarshallingOpts);
std::vector<MarshallingInfo> MarshallingInfos;
+ MarshallingInfos.reserve(OptsWithMarshalling.size());
for (const auto *R : OptsWithMarshalling)
MarshallingInfos.push_back(createMarshallingInfo(*R));
@@ -448,40 +489,14 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << MarshallingInfo::ValueTablesDecl << "{";
for (auto ValueTableName : ValueTableNames)
- OS << "{" << ValueTableName << ", sizeof(" << ValueTableName
- << ") / sizeof(SimpleEnumValue)"
- << "},\n";
+ OS << "{" << ValueTableName << ", std::size(" << ValueTableName << ")},\n";
OS << "};\n";
OS << "static const unsigned SimpleEnumValueTablesSize = "
- "sizeof(SimpleEnumValueTables) / sizeof(SimpleEnumValueTable);\n";
+ "std::size(SimpleEnumValueTables);\n";
OS << "#endif // SIMPLE_ENUM_VALUE_TABLE\n";
OS << "\n";
OS << "\n";
- OS << "#ifdef OPTTABLE_ARG_INIT\n";
- OS << "//////////\n";
- OS << "// Option Values\n\n";
- for (const Record &R : llvm::make_pointee_range(Opts)) {
- if (isa<UnsetInit>(R.getValueInit("ValuesCode")))
- continue;
- OS << "{\n";
- OS << "bool ValuesWereAdded;\n";
- OS << R.getValueAsString("ValuesCode");
- OS << "\n";
- for (StringRef Prefix : R.getValueAsListOfStrings("Prefixes")) {
- OS << "ValuesWereAdded = Opt.addValues(";
- std::string S(Prefix);
- S += R.getValueAsString("Name");
- write_cstring(OS, S);
- OS << ", Values);\n";
- OS << "(void)ValuesWereAdded;\n";
- OS << "assert(ValuesWereAdded && \"Couldn't add values to "
- "OptTable!\");\n";
- }
- OS << "}\n";
- }
- OS << "\n";
- OS << "#endif // OPTTABLE_ARG_INIT\n";
}
} // end namespace llvm
diff --git a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp
index dc04174217fb..6a1e1332d767 100644
--- a/llvm/utils/TableGen/PseudoLoweringEmitter.cpp
+++ b/llvm/utils/TableGen/PseudoLoweringEmitter.cpp
@@ -300,8 +300,7 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
void PseudoLoweringEmitter::run(raw_ostream &o) {
StringRef Classes[] = {"PseudoInstExpansion", "Instruction"};
- std::vector<Record *> Insts =
- Records.getAllDerivedDefinitions(makeArrayRef(Classes));
+ std::vector<Record *> Insts = Records.getAllDerivedDefinitions(Classes);
// Process the pseudo expansion definitions, validating them as we do so.
Records.startTimer("Process definitions");
diff --git a/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp b/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp
new file mode 100644
index 000000000000..fa6508cbfc69
--- /dev/null
+++ b/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp
@@ -0,0 +1,82 @@
+//===- RISCVTargetDefEmitter.cpp - Generate lists of RISCV CPUs -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits the include file needed by the target
+// parser to parse the RISC-V CPUs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TableGenBackends.h"
+#include "llvm/Support/RISCVISAInfo.h"
+#include "llvm/TableGen/Record.h"
+
+using namespace llvm;
+
+using ISAInfoTy = llvm::Expected<std::unique_ptr<RISCVISAInfo>>;
+
+// We can generate march string from target features as what has been described
+// in RISCV ISA specification (version 20191213) 'Chapter 27. ISA Extension
+// Naming Conventions'.
+//
+// This is almost the same as RISCVFeatures::parseFeatureBits, except that we
+// get feature name from feature records instead of feature bits.
+static std::string getMArch(const Record &Rec) {
+ std::vector<std::string> FeatureVector;
+ int XLen = 32;
+
+ // Convert features to FeatureVector.
+ for (auto *Feature : Rec.getValueAsListOfDefs("Features")) {
+ StringRef FeatureName = Feature->getValueAsString("Name");
+ if (llvm::RISCVISAInfo::isSupportedExtensionFeature(FeatureName))
+ FeatureVector.push_back((Twine("+") + FeatureName).str());
+ else if (FeatureName == "64bit")
+ XLen = 64;
+ }
+
+ ISAInfoTy ISAInfo = llvm::RISCVISAInfo::parseFeatures(XLen, FeatureVector);
+ if (!ISAInfo)
+ report_fatal_error("Invalid features");
+
+ // RISCVISAInfo::toString will generate a march string with all the extensions
+ // we have added to it.
+ return (*ISAInfo)->toString();
+}
+
+void llvm::EmitRISCVTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
+ OS << "#ifndef PROC\n"
+ << "#define PROC(ENUM, NAME, DEFAULT_MARCH)\n"
+ << "#endif\n\n";
+
+ OS << "PROC(INVALID, {\"invalid\"}, {\"\"})\n";
+ // Iterate on all definition records.
+ for (const Record *Rec : RK.getAllDerivedDefinitions("RISCVProcessorModel")) {
+ std::string MArch = Rec->getValueAsString("DefaultMarch").str();
+
+ // Compute MArch from features if we don't specify it.
+ if (MArch.empty())
+ MArch = getMArch(*Rec);
+
+ OS << "PROC(" << Rec->getName() << ", "
+ << "{\"" << Rec->getValueAsString("Name") << "\"}, "
+ << "{\"" << MArch << "\"})\n";
+ }
+ OS << "\n#undef PROC\n";
+ OS << "\n";
+ OS << "#ifndef TUNE_PROC\n"
+ << "#define TUNE_PROC(ENUM, NAME)\n"
+ << "#endif\n\n";
+ OS << "TUNE_PROC(GENERIC, \"generic\")\n";
+
+ for (const Record *Rec :
+ RK.getAllDerivedDefinitions("RISCVTuneProcessorModel")) {
+ OS << "TUNE_PROC(" << Rec->getName() << ", "
+ << "\"" << Rec->getValueAsString("Name") << "\")\n";
+ }
+
+ OS << "\n#undef TUNE_PROC\n";
+}
diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
index 3a0fa564074e..113cebf8a08e 100644
--- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
@@ -440,7 +440,7 @@ void RegisterInfoEmitter::EmitRegMappingTables(
OS << "extern const unsigned " << Namespace
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << I << "Dwarf2LSize";
if (!isCtor)
- OS << " = array_lengthof(" << Namespace
+ OS << " = std::size(" << Namespace
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << I << "Dwarf2L);\n\n";
else
OS << ";\n\n";
@@ -498,7 +498,7 @@ void RegisterInfoEmitter::EmitRegMappingTables(
OS << "extern const unsigned " << Namespace
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << i << "L2DwarfSize";
if (!isCtor)
- OS << " = array_lengthof(" << Namespace
+ OS << " = std::size(" << Namespace
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << i << "L2Dwarf);\n\n";
else
OS << ";\n\n";
@@ -1169,6 +1169,8 @@ 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 *getSubRegisterClass"
<< "(const TargetRegisterClass *, unsigned) const override;\n";
}
OS << " const RegClassWeight &getRegClassWeight("
@@ -1190,12 +1192,17 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
<< "MCRegister) const override;\n"
<< " bool isArgumentRegister(const MachineFunction &, "
<< "MCRegister) const override;\n"
+ << " bool isConstantPhysReg(MCRegister PhysReg) const override final;\n"
<< " /// Devirtualized TargetFrameLowering.\n"
<< " static const " << TargetName << "FrameLowering *getFrameLowering(\n"
- << " const MachineFunction &MF);\n"
- << "};\n\n";
+ << " const MachineFunction &MF);\n";
const auto &RegisterClasses = RegBank.getRegClasses();
+ if (llvm::any_of(RegisterClasses, [](const auto &RC) { return RC.getBaseClassOrder(); })) {
+ OS << " const TargetRegisterClass *getPhysRegBaseClass(MCRegister Reg) const override;\n";
+ }
+
+ OS << "};\n\n";
if (!RegisterClasses.empty()) {
OS << "namespace " << RegisterClasses.front().Namespace
@@ -1401,12 +1408,12 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << " const MCRegisterClass &MCR = " << Target.getName()
<< "MCRegisterClasses[" << RC.getQualifiedName() + "RegClassID];\n"
<< " const ArrayRef<MCPhysReg> Order[] = {\n"
- << " makeArrayRef(MCR.begin(), MCR.getNumRegs()";
+ << " ArrayRef(MCR.begin(), MCR.getNumRegs()";
for (unsigned oi = 1, oe = RC.getNumOrders(); oi != oe; ++oi)
if (RC.getOrder(oi).empty())
OS << "),\n ArrayRef<MCPhysReg>(";
else
- OS << "),\n makeArrayRef(AltOrder" << oi;
+ OS << "),\n ArrayRef(AltOrder" << oi;
OS << ")\n };\n const unsigned Select = " << RC.getName()
<< "AltOrderSelect(MF);\n assert(Select < " << RC.getNumOrders()
<< ");\n return Order[Select];\n}\n";
@@ -1425,10 +1432,11 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
<< SuperRegIdxSeqs.get(SuperRegIdxLists[RC.EnumValue]) << ",\n ";
printMask(OS, RC.LaneMask);
OS << ",\n " << (unsigned)RC.AllocationPriority << ",\n "
+ << (RC.GlobalPriority ? "true" : "false") << ",\n "
<< format("0x%02x", RC.TSFlags) << ", /* TSFlags */\n "
- << (RC.HasDisjunctSubRegs?"true":"false")
+ << (RC.HasDisjunctSubRegs ? "true" : "false")
<< ", /* HasDisjunctSubRegs */\n "
- << (RC.CoveredBySubRegs?"true":"false")
+ << (RC.CoveredBySubRegs ? "true" : "false")
<< ", /* CoveredBySubRegs */\n ";
if (RC.getSuperClasses().empty())
OS << "NullRegClasses,\n ";
@@ -1510,16 +1518,16 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
emitComposeSubRegIndexLaneMask(OS, RegBank, ClassName);
}
- // Emit getSubClassWithSubReg.
if (!SubRegIndices.empty()) {
+ // Emit getSubClassWithSubReg.
OS << "const TargetRegisterClass *" << ClassName
<< "::getSubClassWithSubReg(const TargetRegisterClass *RC, unsigned Idx)"
<< " const {\n";
// Use the smallest type that can hold a regclass ID with room for a
// sentinel.
- if (RegisterClasses.size() < UINT8_MAX)
+ if (RegisterClasses.size() <= UINT8_MAX)
OS << " static const uint8_t Table[";
- else if (RegisterClasses.size() < UINT16_MAX)
+ else if (RegisterClasses.size() <= UINT16_MAX)
OS << " static const uint16_t Table[";
else
PrintFatalError("Too many register classes.");
@@ -1540,10 +1548,105 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
<< " assert(Idx < " << SubRegIndicesSize << " && \"Bad subreg\");\n"
<< " unsigned TV = Table[RC->getID()][Idx];\n"
<< " return TV ? getRegClass(TV - 1) : nullptr;\n}\n\n";
+
+ // Emit getSubRegisterClass
+ OS << "const TargetRegisterClass *" << ClassName
+ << "::getSubRegisterClass(const TargetRegisterClass *RC, unsigned Idx)"
+ << " const {\n";
+
+ // Use the smallest type that can hold a regclass ID with room for a
+ // sentinel.
+ if (RegisterClasses.size() <= UINT8_MAX)
+ OS << " static const uint8_t Table[";
+ else if (RegisterClasses.size() <= UINT16_MAX)
+ OS << " static const uint16_t Table[";
+ else
+ PrintFatalError("Too many register classes.");
+
+ OS << RegisterClasses.size() << "][" << SubRegIndicesSize << "] = {\n";
+
+ for (const auto &RC : RegisterClasses) {
+ OS << " {\t// " << RC.getName() << '\n';
+ for (auto &Idx : SubRegIndices) {
+ std::optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>>
+ MatchingSubClass = RC.getMatchingSubClassWithSubRegs(RegBank, &Idx);
+
+ unsigned EnumValue = 0;
+ if (MatchingSubClass) {
+ CodeGenRegisterClass *SubRegClass = MatchingSubClass->second;
+ EnumValue = SubRegClass->EnumValue + 1;
+ }
+
+ OS << " " << EnumValue << ",\t// "
+ << RC.getName() << ':' << Idx.getName();
+
+ if (MatchingSubClass) {
+ CodeGenRegisterClass *SubRegClass = MatchingSubClass->second;
+ OS << " -> " << SubRegClass->getName();
+ }
+
+ OS << '\n';
+ }
+
+ OS << " },\n";
+ }
+ OS << " };\n assert(RC && \"Missing regclass\");\n"
+ << " if (!Idx) return RC;\n --Idx;\n"
+ << " assert(Idx < " << SubRegIndicesSize << " && \"Bad subreg\");\n"
+ << " unsigned TV = Table[RC->getID()][Idx];\n"
+ << " return TV ? getRegClass(TV - 1) : nullptr;\n}\n\n";
}
EmitRegUnitPressure(OS, RegBank, ClassName);
+ // Emit register base class mapper
+ if (!RegisterClasses.empty()) {
+ // Collect base classes
+ SmallVector<const CodeGenRegisterClass*> BaseClasses;
+ for (const auto &RC : RegisterClasses) {
+ if (RC.getBaseClassOrder())
+ BaseClasses.push_back(&RC);
+ }
+ if (!BaseClasses.empty()) {
+ // Represent class indexes with uint8_t and allocate one index for nullptr
+ assert(BaseClasses.size() <= UINT8_MAX && "Too many base register classes");
+
+ // Apply order
+ struct BaseClassOrdering {
+ bool operator()(const CodeGenRegisterClass *LHS, const CodeGenRegisterClass *RHS) const {
+ return std::pair(*LHS->getBaseClassOrder(), LHS->EnumValue)
+ < std::pair(*RHS->getBaseClassOrder(), RHS->EnumValue);
+ }
+ };
+ llvm::stable_sort(BaseClasses, BaseClassOrdering());
+
+ // Build mapping for Regs (+1 for NoRegister)
+ std::vector<uint8_t> Mapping(Regs.size() + 1, 0);
+ for (int RCIdx = BaseClasses.size() - 1; RCIdx >= 0; --RCIdx) {
+ for (const auto Reg : BaseClasses[RCIdx]->getMembers())
+ Mapping[Reg->EnumValue] = RCIdx + 1;
+ }
+
+ OS << "\n// Register to base register class mapping\n\n";
+ OS << "\n";
+ OS << "const TargetRegisterClass *" << ClassName
+ << "::getPhysRegBaseClass(MCRegister Reg)"
+ << " const {\n";
+ OS << " static const TargetRegisterClass *BaseClasses[" << (BaseClasses.size() + 1) << "] = {\n";
+ OS << " nullptr,\n";
+ for (const auto RC : BaseClasses)
+ OS << " &" << RC->getQualifiedName() << "RegClass,\n";
+ OS << " };\n";
+ OS << " static const uint8_t Mapping[" << Mapping.size() << "] = {\n ";
+ for (const uint8_t Value : Mapping)
+ OS << (unsigned)Value << ",";
+ OS << " };\n\n";
+ OS << " assert(Reg < sizeof(Mapping));\n";
+ OS << " return BaseClasses[Mapping[Reg]];\n";
+ OS << "}\n";
+ }
+ }
+
// Emit the constructor of the class...
OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n";
OS << "extern const MCPhysReg " << TargetName << "RegDiffLists[];\n";
@@ -1614,6 +1717,15 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
ArrayRef<Record*>(OPSet.begin(), OPSet.end()));
}
+ // Add all constant physical registers to the preserved mask:
+ SetTheory::RecSet ConstantSet;
+ for (auto &Reg : RegBank.getRegisters()) {
+ if (Reg.Constant)
+ ConstantSet.insert(Reg.TheDef);
+ }
+ Covered |= RegBank.computeCoveredRegisters(
+ ArrayRef<Record *>(ConstantSet.begin(), ConstantSet.end()));
+
OS << "static const uint32_t " << CSRSet->getName()
<< "_RegMask[] = { ";
printBitVectorAsHex(OS, Covered, 32);
@@ -1628,9 +1740,9 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
for (Record *CSRSet : CSRSets)
OS << " " << CSRSet->getName() << "_RegMask,\n";
OS << " };\n";
- OS << " return makeArrayRef(Masks);\n";
+ OS << " return ArrayRef(Masks);\n";
} else {
- OS << " return None;\n";
+ OS << " return std::nullopt;\n";
}
OS << "}\n\n";
@@ -1678,6 +1790,15 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << " false;\n";
OS << "}\n\n";
+ OS << "bool " << ClassName << "::\n"
+ << "isConstantPhysReg(MCRegister PhysReg) const {\n"
+ << " return\n";
+ for (const auto &Reg : Regs)
+ if (Reg.Constant)
+ OS << " PhysReg == " << getQualifiedName(Reg.TheDef) << " ||\n";
+ OS << " false;\n";
+ OS << "}\n\n";
+
OS << "ArrayRef<const char *> " << ClassName
<< "::getRegMaskNames() const {\n";
if (!CSRSets.empty()) {
@@ -1685,9 +1806,9 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
for (Record *CSRSet : CSRSets)
OS << " " << '"' << CSRSet->getName() << '"' << ",\n";
OS << " };\n";
- OS << " return makeArrayRef(Names);\n";
+ OS << " return ArrayRef(Names);\n";
} else {
- OS << " return None;\n";
+ OS << " return std::nullopt;\n";
}
OS << "}\n\n";
@@ -1767,6 +1888,7 @@ void RegisterInfoEmitter::debugDump(raw_ostream &OS) {
OS << "SubRegIndex " << SRI.getName() << ":\n";
OS << "\tLaneMask: " << PrintLaneMask(SRI.LaneMask) << '\n';
OS << "\tAllSuperRegsCovered: " << SRI.AllSuperRegsCovered << '\n';
+ OS << "\tOffset, Size: " << SRI.Offset << ", " << SRI.Size << '\n';
}
for (const CodeGenRegister &R : RegBank.getRegisters()) {
diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index 327c53e93a41..c88a2db55502 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -378,7 +378,7 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
}
if (IsContiguous) {
- OS << " auto Table = makeArrayRef(" << IndexName << ");\n";
+ OS << " auto Table = ArrayRef(" << IndexName << ");\n";
OS << " size_t Idx = " << Index.Fields[0].Name << ";\n";
OS << " return Idx >= Table.size() ? nullptr : ";
if (IsPrimary)
@@ -423,7 +423,7 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
}
OS << "};\n";
- OS << " auto Table = makeArrayRef(" << IndexName << ");\n";
+ OS << " auto Table = ArrayRef(" << IndexName << ");\n";
OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,\n";
OS << " [](const " << IndexTypeName << " &LHS, const KeyType &RHS) {\n";
@@ -574,7 +574,7 @@ std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
void SearchableTableEmitter::collectEnumEntries(
GenericEnum &Enum, StringRef NameField, StringRef ValueField,
const std::vector<Record *> &Items) {
- for (auto EntryRec : Items) {
+ for (auto *EntryRec : Items) {
StringRef Name;
if (NameField.empty())
Name = EntryRec->getName();
@@ -607,7 +607,7 @@ void SearchableTableEmitter::collectTableEntries(
PrintFatalError(Table.Locs,
Twine("Table '") + Table.Name + "' has no entries");
- for (auto EntryRec : Items) {
+ for (auto *EntryRec : Items) {
for (auto &Field : Table.Fields) {
auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name));
if (!TI || !TI->isComplete()) {
@@ -662,7 +662,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
DenseMap<Record *, GenericTable *> TableMap;
// Collect all definitions first.
- for (auto EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) {
+ for (auto *EnumRec : Records.getAllDerivedDefinitions("GenericEnum")) {
StringRef NameField;
if (!EnumRec->isValueUnset("NameField"))
NameField = EnumRec->getValueAsString("NameField");
@@ -688,7 +688,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
Enums.emplace_back(std::move(Enum));
}
- for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) {
+ for (auto *TableRec : Records.getAllDerivedDefinitions("GenericTable")) {
auto Table = std::make_unique<GenericTable>();
Table->Name = std::string(TableRec->getName());
Table->Locs = TableRec->getLoc();
diff --git a/llvm/utils/TableGen/SequenceToOffsetTable.h b/llvm/utils/TableGen/SequenceToOffsetTable.h
index 1b3451c24cb0..77a404d07b7d 100644
--- a/llvm/utils/TableGen/SequenceToOffsetTable.h
+++ b/llvm/utils/TableGen/SequenceToOffsetTable.h
@@ -26,48 +26,6 @@
namespace llvm {
extern llvm::cl::opt<bool> EmitLongStrLiterals;
-// Helper function for SequenceToOffsetTable<string>.
-static inline void printStrLitEscChar(raw_ostream &OS, char C) {
- const char *Escapes[] = {
- "\\000", "\\001", "\\002", "\\003", "\\004", "\\005", "\\006", "\\007",
- "\\010", "\\t", "\\n", "\\013", "\\014", "\\r", "\\016", "\\017",
- "\\020", "\\021", "\\022", "\\023", "\\024", "\\025", "\\026", "\\027",
- "\\030", "\\031", "\\032", "\\033", "\\034", "\\035", "\\036", "\\037",
- " ", "!", "\\\"", "#", "$", "%", "&", "'",
- "(", ")", "*", "+", ",", "-", ".", "/",
- "0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", ":", ";", "<", "=", ">", "?",
- "@", "A", "B", "C", "D", "E", "F", "G",
- "H", "I", "J", "K", "L", "M", "N", "O",
- "P", "Q", "R", "S", "T", "U", "V", "W",
- "X", "Y", "Z", "[", "\\\\", "]", "^", "_",
- "`", "a", "b", "c", "d", "e", "f", "g",
- "h", "i", "j", "k", "l", "m", "n", "o",
- "p", "q", "r", "s", "t", "u", "v", "w",
- "x", "y", "z", "{", "|", "}", "~", "\\177",
- "\\200", "\\201", "\\202", "\\203", "\\204", "\\205", "\\206", "\\207",
- "\\210", "\\211", "\\212", "\\213", "\\214", "\\215", "\\216", "\\217",
- "\\220", "\\221", "\\222", "\\223", "\\224", "\\225", "\\226", "\\227",
- "\\230", "\\231", "\\232", "\\233", "\\234", "\\235", "\\236", "\\237",
- "\\240", "\\241", "\\242", "\\243", "\\244", "\\245", "\\246", "\\247",
- "\\250", "\\251", "\\252", "\\253", "\\254", "\\255", "\\256", "\\257",
- "\\260", "\\261", "\\262", "\\263", "\\264", "\\265", "\\266", "\\267",
- "\\270", "\\271", "\\272", "\\273", "\\274", "\\275", "\\276", "\\277",
- "\\300", "\\301", "\\302", "\\303", "\\304", "\\305", "\\306", "\\307",
- "\\310", "\\311", "\\312", "\\313", "\\314", "\\315", "\\316", "\\317",
- "\\320", "\\321", "\\322", "\\323", "\\324", "\\325", "\\326", "\\327",
- "\\330", "\\331", "\\332", "\\333", "\\334", "\\335", "\\336", "\\337",
- "\\340", "\\341", "\\342", "\\343", "\\344", "\\345", "\\346", "\\347",
- "\\350", "\\351", "\\352", "\\353", "\\354", "\\355", "\\356", "\\357",
- "\\360", "\\361", "\\362", "\\363", "\\364", "\\365", "\\366", "\\367",
- "\\370", "\\371", "\\372", "\\373", "\\374", "\\375", "\\376", "\\377"};
-
- static_assert(sizeof Escapes / sizeof Escapes[0] ==
- std::numeric_limits<unsigned char>::max() + 1,
- "unsupported character type");
- OS << Escapes[static_cast<unsigned char>(C)];
-}
-
static inline void printChar(raw_ostream &OS, char C) {
unsigned char UC(C);
if (isalnum(UC) || ispunct(UC)) {
@@ -184,9 +142,7 @@ public:
<< Decl << " = {\n";
for (auto I : Seqs) {
OS << " /* " << I.second << " */ \"";
- for (auto C : I.first) {
- printStrLitEscChar(OS, C);
- }
+ OS.write_escaped(I.first);
OS << "\\0\"\n";
}
OS << "};\n"
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index 88827607b517..8afe6d37d0e0 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -10,8 +10,8 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenTarget.h"
#include "CodeGenSchedule.h"
+#include "CodeGenTarget.h"
#include "PredicateExpander.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/STLExtras.h"
@@ -1862,7 +1862,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
if (NumFeatures)
OS << Target << "FeatureKV, ";
else
- OS << "None, ";
+ OS << "std::nullopt, ";
if (NumProcs)
OS << Target << "SubTypeKV, ";
else
@@ -1953,11 +1953,11 @@ void SubtargetEmitter::run(raw_ostream &OS) {
<< "StringRef TuneCPU, StringRef FS)\n"
<< " : TargetSubtargetInfo(TT, CPU, TuneCPU, FS, ";
if (NumFeatures)
- OS << "makeArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), ";
+ OS << "ArrayRef(" << Target << "FeatureKV, " << NumFeatures << "), ";
else
- OS << "None, ";
+ OS << "std::nullopt, ";
if (NumProcs)
- OS << "makeArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), ";
+ OS << "ArrayRef(" << Target << "SubTypeKV, " << NumProcs << "), ";
else
OS << "None, ";
OS << '\n'; OS.indent(24);
diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp
index efd641887232..746e2dd1db16 100644
--- a/llvm/utils/TableGen/TableGen.cpp
+++ b/llvm/utils/TableGen/TableGen.cpp
@@ -58,6 +58,7 @@ enum ActionType {
GenDirectivesEnumDecl,
GenDirectivesEnumImpl,
GenDXILOperation,
+ GenRISCVTargetDef,
};
namespace llvm {
@@ -141,8 +142,9 @@ cl::opt<ActionType> Action(
clEnumValN(GenDirectivesEnumImpl, "gen-directive-impl",
"Generate directive related implementation code"),
clEnumValN(GenDXILOperation, "gen-dxil-operation",
- "Generate DXIL operation information")));
-
+ "Generate DXIL operation information"),
+ clEnumValN(GenRISCVTargetDef, "gen-riscv-target-def",
+ "Generate the list of CPU for RISCV")));
cl::OptionCategory PrintEnumsCat("Options for -print-enums");
cl::opt<std::string> Class("class", cl::desc("Print Enum list for this class"),
cl::value_desc("class name"),
@@ -278,6 +280,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenDXILOperation:
EmitDXILOperation(Records, OS);
break;
+ case GenRISCVTargetDef:
+ EmitRISCVTargetDef(Records, OS);
+ break;
}
return false;
diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h
index 4dff13095696..ac44babb1261 100644
--- a/llvm/utils/TableGen/TableGenBackends.h
+++ b/llvm/utils/TableGen/TableGenBackends.h
@@ -94,6 +94,7 @@ void EmitAutomata(RecordKeeper &RK, raw_ostream &OS);
void EmitDirectivesDecl(RecordKeeper &RK, raw_ostream &OS);
void EmitDirectivesImpl(RecordKeeper &RK, raw_ostream &OS);
void EmitDXILOperation(RecordKeeper &RK, raw_ostream &OS);
+void EmitRISCVTargetDef(const RecordKeeper &RK, raw_ostream &OS);
} // End llvm namespace
diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp
index a6bbe2f7ff37..2c1acd8d910c 100644
--- a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp
+++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp
@@ -83,9 +83,35 @@ public:
void run(raw_ostream &OS);
};
-
} // end anonymous namespace
+// Get the name of custom encoder or decoder, if there is any.
+// Returns `{encoder name, decoder name}`.
+static std::pair<StringRef, StringRef> getCustomCoders(ArrayRef<Init *> Args) {
+ std::pair<StringRef, StringRef> Result;
+ for (const auto *Arg : Args) {
+ const auto *DI = dyn_cast<DagInit>(Arg);
+ if (!DI)
+ continue;
+ const Init *Op = DI->getOperator();
+ if (!isa<DefInit>(Op))
+ continue;
+ // syntax: `(<encoder | decoder> "function name")`
+ StringRef OpName = cast<DefInit>(Op)->getDef()->getName();
+ if (OpName != "encoder" && OpName != "decoder")
+ continue;
+ if (!DI->getNumArgs() || !isa<StringInit>(DI->getArg(0)))
+ PrintFatalError("expected '" + OpName +
+ "' directive to be followed by a custom function name.");
+ StringRef FuncName = cast<StringInit>(DI->getArg(0))->getValue();
+ if (OpName == "encoder")
+ Result.first = FuncName;
+ else
+ Result.second = FuncName;
+ }
+ return Result;
+}
+
VarLenInst::VarLenInst(const DagInit *DI, const RecordVal *TheDef)
: TheDef(TheDef), NumBits(0U) {
buildRec(DI);
@@ -123,7 +149,8 @@ void VarLenInst::buildRec(const DagInit *DI) {
}
}
} else if (Op == "operand") {
- // (operand <operand name>, <# of bits>, [(encoder <custom encoder>)])
+ // (operand <operand name>, <# of bits>,
+ // [(encoder <custom encoder>)][, (decoder <custom decoder>)])
if (DI->getNumArgs() < 2)
PrintFatalError(TheDef->getLoc(),
"Expecting at least 2 arguments for `operand`");
@@ -136,14 +163,13 @@ void VarLenInst::buildRec(const DagInit *DI) {
if (NumBitsVal <= 0)
PrintFatalError(TheDef->getLoc(), "Invalid number of bits for `operand`");
- StringRef CustomEncoder;
- if (DI->getNumArgs() >= 3)
- CustomEncoder = getCustomEncoderName(DI->getArg(2));
- Segments.push_back(
- {static_cast<unsigned>(NumBitsVal), OperandName, CustomEncoder});
+ auto [CustomEncoder, CustomDecoder] =
+ getCustomCoders(DI->getArgs().slice(2));
+ Segments.push_back({static_cast<unsigned>(NumBitsVal), OperandName,
+ CustomEncoder, CustomDecoder});
} else if (Op == "slice") {
// (slice <operand name>, <high / low bit>, <low / high bit>,
- // [(encoder <custom encoder>)])
+ // [(encoder <custom encoder>)][, (decoder <custom decoder>)])
if (DI->getNumArgs() < 3)
PrintFatalError(TheDef->getLoc(),
"Expecting at least 3 arguments for `slice`");
@@ -167,18 +193,17 @@ void VarLenInst::buildRec(const DagInit *DI) {
NumBits = static_cast<unsigned>(HiBitVal - LoBitVal + 1);
}
- StringRef CustomEncoder;
- if (DI->getNumArgs() >= 4)
- CustomEncoder = getCustomEncoderName(DI->getArg(3));
+ auto [CustomEncoder, CustomDecoder] =
+ getCustomCoders(DI->getArgs().slice(3));
if (NeedSwap) {
// Normalization: Hi bit should always be the second argument.
Init *const NewArgs[] = {OperandName, LoBit, HiBit};
Segments.push_back({NumBits,
DagInit::get(DI->getOperator(), nullptr, NewArgs, {}),
- CustomEncoder});
+ CustomEncoder, CustomDecoder});
} else {
- Segments.push_back({NumBits, DI, CustomEncoder});
+ Segments.push_back({NumBits, DI, CustomEncoder, CustomDecoder});
}
}
}
@@ -449,7 +474,8 @@ std::string VarLenCodeEmitterGen::getInstructionCaseForEncoding(
auto OpIdx = CGI.Operands.ParseOperandName(OperandName);
unsigned FlatOpIdx = CGI.Operands.getFlattenedOperandNumber(OpIdx);
- StringRef CustomEncoder = CGI.Operands[OpIdx.first].EncoderMethodName;
+ StringRef CustomEncoder =
+ CGI.Operands[OpIdx.first].EncoderMethodNames[OpIdx.second];
if (ES.CustomEncoder.size())
CustomEncoder = ES.CustomEncoder;
diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.h b/llvm/utils/TableGen/VarLenCodeEmitterGen.h
index 5bdedee1dd51..2b55fd1720aa 100644
--- a/llvm/utils/TableGen/VarLenCodeEmitterGen.h
+++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.h
@@ -22,6 +22,7 @@ struct EncodingSegment {
unsigned BitWidth;
const Init *Value;
StringRef CustomEncoder = "";
+ StringRef CustomDecoder = "";
};
class VarLenInst {
@@ -35,14 +36,6 @@ class VarLenInst {
void buildRec(const DagInit *DI);
- StringRef getCustomEncoderName(const Init *EI) const {
- if (const auto *DI = dyn_cast<DagInit>(EI)) {
- if (DI->getNumArgs() && isa<StringInit>(DI->getArg(0)))
- return cast<StringInit>(DI->getArg(0))->getValue();
- }
- return "";
- }
-
public:
VarLenInst() : TheDef(nullptr), NumBits(0U), HasDynamicSegment(false) {}
diff --git a/llvm/utils/TableGen/X86DisassemblerTables.cpp b/llvm/utils/TableGen/X86DisassemblerTables.cpp
index 2fa8fce81422..601591d9f53d 100644
--- a/llvm/utils/TableGen/X86DisassemblerTables.cpp
+++ b/llvm/utils/TableGen/X86DisassemblerTables.cpp
@@ -16,7 +16,6 @@
#include "X86DisassemblerTables.h"
#include "X86DisassemblerShared.h"
#include "X86ModRMFilters.h"
-#include "llvm/ADT/STLArrayExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
@@ -653,7 +652,7 @@ static const char* stringForDecisionType(ModRMDecisionType dt) {
}
DisassemblerTables::DisassemblerTables() {
- for (unsigned i = 0; i < llvm::array_lengthof(Tables); i++)
+ for (unsigned i = 0; i < std::size(Tables); i++)
Tables[i] = std::make_unique<ContextDecision>();
HasConflicts = false;
@@ -763,7 +762,7 @@ void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2,
}
if (index == 256) {
// If all 256 entries are MODRM_ONEENTRY, omit output.
- static_assert(MODRM_ONEENTRY == 0, "");
+ static_assert(MODRM_ONEENTRY == 0);
--i2;
o2 << "},\n";
} else {
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index 9afde66fe6f3..e5c1e53936f6 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -546,6 +546,18 @@ void RecognizableInstr::emitInstructionSpecifier() {
HANDLE_OPERAND(roRegister)
HANDLE_OPTIONAL(immediate)
break;
+ case X86Local::MRMDestMem4VOp3CC:
+ // Operand 1 is a register operand in the Reg/Opcode field.
+ // Operand 2 is a register operand in the R/M field.
+ // Operand 3 is VEX.vvvv
+ // Operand 4 is condition code.
+ assert(numPhysicalOperands == 4 &&
+ "Unexpected number of operands for MRMDestMem4VOp3CC");
+ HANDLE_OPERAND(roRegister)
+ HANDLE_OPERAND(memory)
+ HANDLE_OPERAND(vvvvRegister)
+ HANDLE_OPERAND(opcodeModifier)
+ break;
case X86Local::MRMDestMem:
case X86Local::MRMDestMemFSIB:
// Operand 1 is a memory operand (possibly SIB-extended)
@@ -767,7 +779,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
#define MAP(from, to) \
case X86Local::MRM_##from:
- llvm::Optional<OpcodeType> opcodeType;
+ std::optional<OpcodeType> opcodeType;
switch (OpMap) {
default: llvm_unreachable("Invalid map!");
case X86Local::OB: opcodeType = ONEBYTE; break;
@@ -808,6 +820,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
filter = std::make_unique<ModFilter>(true);
break;
case X86Local::MRMDestMem:
+ case X86Local::MRMDestMem4VOp3CC:
case X86Local::MRMDestMemFSIB:
case X86Local::MRMSrcMem:
case X86Local::MRMSrcMemFSIB:
@@ -858,7 +871,8 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
if (Form == X86Local::AddRegFrm || Form == X86Local::MRMSrcRegCC ||
Form == X86Local::MRMSrcMemCC || Form == X86Local::MRMXrCC ||
- Form == X86Local::MRMXmCC || Form == X86Local::AddCCFrm) {
+ Form == X86Local::MRMXmCC || Form == X86Local::AddCCFrm ||
+ Form == X86Local::MRMDestMem4VOp3CC) {
uint8_t Count = Form == X86Local::AddRegFrm ? 8 : 16;
assert(((opcodeToSet % Count) == 0) && "ADDREG_FRM opcode not aligned");
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.h b/llvm/utils/TableGen/X86RecognizableInstr.h
index 67aba26a142b..ea56a9d7d994 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.h
+++ b/llvm/utils/TableGen/X86RecognizableInstr.h
@@ -106,6 +106,7 @@ namespace X86Local {
RawFrmImm16 = 8,
AddCCFrm = 9,
PrefixByte = 10,
+ MRMDestMem4VOp3CC = 20,
MRMr0 = 21,
MRMSrcMemFSIB = 22,
MRMDestMemFSIB = 23,
diff --git a/llvm/utils/split-file/split-file.cpp b/llvm/utils/split-file/split-file.cpp
new file mode 100644
index 000000000000..4a92c1be78a2
--- /dev/null
+++ b/llvm/utils/split-file/split-file.cpp
@@ -0,0 +1,178 @@
+//===- split-file.cpp - Input splitting utility ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Split input into multipe parts separated by regex '^(.|//)--- ' and extract
+// the specified part.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/WithColor.h"
+#include <string>
+#include <system_error>
+
+using namespace llvm;
+
+static cl::OptionCategory cat("split-file Options");
+
+static cl::opt<std::string> input(cl::Positional, cl::desc("filename"),
+ cl::cat(cat));
+
+static cl::opt<std::string> output(cl::Positional, cl::desc("directory"),
+ cl::value_desc("directory"), cl::cat(cat));
+
+static cl::opt<bool> leadingLines("leading-lines",
+ cl::desc("Preserve line numbers"),
+ cl::cat(cat));
+
+static cl::opt<bool> noLeadingLines("no-leading-lines",
+ cl::desc("Don't preserve line numbers (default)"),
+ cl::cat(cat));
+
+static StringRef toolName;
+static int errorCount;
+
+[[noreturn]] static void fatal(StringRef filename, const Twine &message) {
+ if (filename.empty())
+ WithColor::error(errs(), toolName) << message << '\n';
+ else
+ WithColor::error(errs(), toolName) << filename << ": " << message << '\n';
+ exit(1);
+}
+
+static void error(StringRef filename, int64_t line, const Twine &message) {
+ ++errorCount;
+ errs() << filename << ':' << line << ": ";
+ WithColor::error(errs()) << message << '\n';
+}
+
+namespace {
+struct Part {
+ const char *begin = nullptr;
+ const char *end = nullptr;
+ int64_t leadingLines = 0;
+};
+} // namespace
+
+static int handle(MemoryBuffer &inputBuf, StringRef input) {
+ DenseMap<StringRef, Part> partToBegin;
+ StringRef lastPart, separator;
+ StringRef EOL = inputBuf.getBuffer().detectEOL();
+ for (line_iterator i(inputBuf, /*SkipBlanks=*/false, '\0'); !i.is_at_eof();) {
+ const int64_t lineNo = i.line_number();
+ const StringRef line = *i++;
+ const size_t markerLen = line.startswith("//") ? 6 : 5;
+ if (!(line.size() >= markerLen &&
+ line.substr(markerLen - 4).startswith("--- ")))
+ continue;
+ separator = line.substr(0, markerLen);
+ const StringRef partName = line.substr(markerLen);
+ if (partName.empty()) {
+ error(input, lineNo, "empty part name");
+ continue;
+ }
+ if (isSpace(partName.front()) || isSpace(partName.back())) {
+ error(input, lineNo, "part name cannot have leading or trailing space");
+ continue;
+ }
+
+ auto res = partToBegin.try_emplace(partName);
+ if (!res.second) {
+ error(input, lineNo,
+ "'" + separator + partName + "' occurs more than once");
+ continue;
+ }
+ if (!lastPart.empty())
+ partToBegin[lastPart].end = line.data();
+ Part &cur = res.first->second;
+ if (!i.is_at_eof())
+ cur.begin = i->data();
+ // If --leading-lines is specified, numEmptyLines is 0. Append newlines so
+ // that the extracted part preserves line numbers.
+ cur.leadingLines = leadingLines ? i.line_number() - 1 : 0;
+
+ lastPart = partName;
+ }
+ if (lastPart.empty())
+ fatal(input, "no part separator was found");
+ if (errorCount)
+ return 1;
+ partToBegin[lastPart].end = inputBuf.getBufferEnd();
+
+ std::vector<std::unique_ptr<ToolOutputFile>> outputFiles;
+ SmallString<256> partPath;
+ for (auto &keyValue : partToBegin) {
+ partPath.clear();
+ sys::path::append(partPath, output, keyValue.first);
+ std::error_code ec =
+ sys::fs::create_directories(sys::path::parent_path(partPath));
+ if (ec)
+ fatal(input, ec.message());
+ auto f = std::make_unique<ToolOutputFile>(partPath.str(), ec,
+ llvm::sys::fs::OF_None);
+ if (!f)
+ fatal(input, ec.message());
+
+ Part &part = keyValue.second;
+ for (int64_t i = 0; i != part.leadingLines; ++i)
+ (*f).os() << EOL;
+ if (part.begin)
+ (*f).os().write(part.begin, part.end - part.begin);
+ outputFiles.push_back(std::move(f));
+ }
+
+ for (std::unique_ptr<ToolOutputFile> &outputFile : outputFiles)
+ outputFile->keep();
+ return 0;
+}
+
+int main(int argc, const char **argv) {
+ toolName = sys::path::stem(argv[0]);
+ cl::HideUnrelatedOptions({&cat});
+ cl::ParseCommandLineOptions(
+ argc, argv,
+ "Split input into multiple parts separated by regex '^(.|//)--- ' and "
+ "extract the part specified by '^(.|//)--- <part>'\n",
+ nullptr,
+ /*EnvVar=*/nullptr,
+ /*LongOptionsUseDoubleDash=*/true);
+
+ if (input.empty())
+ fatal("", "input filename is not specified");
+ if (output.empty())
+ fatal("", "output directory is not specified");
+ ErrorOr<std::unique_ptr<MemoryBuffer>> bufferOrErr =
+ MemoryBuffer::getFileOrSTDIN(input);
+ if (std::error_code ec = bufferOrErr.getError())
+ fatal(input, ec.message());
+
+ // Delete output if it is a file or an empty directory, so that we can create
+ // a directory.
+ sys::fs::file_status status;
+ if (std::error_code ec = sys::fs::status(output, status))
+ if (ec.value() != static_cast<int>(std::errc::no_such_file_or_directory))
+ fatal(output, ec.message());
+ if (status.type() != sys::fs::file_type::file_not_found &&
+ status.type() != sys::fs::file_type::directory_file &&
+ status.type() != sys::fs::file_type::regular_file)
+ fatal(output, "output cannot be a special file");
+ if (std::error_code ec = sys::fs::remove(output, /*IgnoreNonExisting=*/true))
+ if (ec.value() != static_cast<int>(std::errc::directory_not_empty) &&
+ ec.value() != static_cast<int>(std::errc::file_exists))
+ fatal(output, ec.message());
+ return handle(**bufferOrErr, input);
+}