aboutsummaryrefslogtreecommitdiff
path: root/utils/TableGen
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-10-23 17:51:42 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-10-23 17:51:42 +0000
commit1d5ae1026e831016fc29fd927877c86af904481f (patch)
tree2cdfd12620fcfa5d9e4a0389f85368e8e36f63f9 /utils/TableGen
parente6d1592492a3a379186bfb02bd0f4eda0669c0d5 (diff)
Notes
Diffstat (limited to 'utils/TableGen')
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp19
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp3
-rw-r--r--utils/TableGen/CallingConvEmitter.cpp4
-rw-r--r--utils/TableGen/CodeEmitterGen.cpp305
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp42
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.h4
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp1
-rw-r--r--utils/TableGen/CodeGenInstruction.h1
-rw-r--r--utils/TableGen/CodeGenIntrinsics.h8
-rw-r--r--utils/TableGen/CodeGenMapTable.cpp12
-rw-r--r--utils/TableGen/CodeGenRegisters.cpp52
-rw-r--r--utils/TableGen/CodeGenRegisters.h26
-rw-r--r--utils/TableGen/CodeGenSchedule.cpp24
-rw-r--r--utils/TableGen/CodeGenTarget.cpp70
-rw-r--r--utils/TableGen/CodeGenTarget.h6
-rw-r--r--utils/TableGen/DAGISelEmitter.cpp2
-rw-r--r--utils/TableGen/DAGISelMatcher.h8
-rw-r--r--utils/TableGen/DAGISelMatcherEmitter.cpp22
-rw-r--r--utils/TableGen/DAGISelMatcherGen.cpp10
-rw-r--r--utils/TableGen/DAGISelMatcherOpt.cpp9
-rw-r--r--utils/TableGen/DFAEmitter.cpp394
-rw-r--r--utils/TableGen/DFAEmitter.h107
-rw-r--r--utils/TableGen/DFAPacketizerEmitter.cpp657
-rw-r--r--utils/TableGen/DisassemblerEmitter.cpp2
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.cpp93
-rw-r--r--utils/TableGen/GICombinerEmitter.cpp452
-rw-r--r--utils/TableGen/GlobalISel/CMakeLists.txt7
-rw-r--r--utils/TableGen/GlobalISel/CodeExpander.cpp93
-rw-r--r--utils/TableGen/GlobalISel/CodeExpander.h55
-rw-r--r--utils/TableGen/GlobalISel/CodeExpansions.h43
-rw-r--r--utils/TableGen/GlobalISelEmitter.cpp775
-rw-r--r--utils/TableGen/InfoByHwMode.cpp11
-rw-r--r--utils/TableGen/InfoByHwMode.h5
-rw-r--r--utils/TableGen/InstrDocsEmitter.cpp2
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp52
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp20
-rw-r--r--utils/TableGen/RISCVCompressInstEmitter.cpp13
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp4
-rw-r--r--utils/TableGen/SearchableTableEmitter.cpp16
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp8
-rw-r--r--utils/TableGen/SubtargetFeatureInfo.cpp12
-rw-r--r--utils/TableGen/TableGen.cpp157
-rw-r--r--utils/TableGen/TableGenBackends.h2
-rw-r--r--utils/TableGen/WebAssemblyDisassemblerEmitter.cpp2
-rw-r--r--utils/TableGen/X86DisassemblerTables.cpp2
-rw-r--r--utils/TableGen/X86EVEX2VEXTablesEmitter.cpp1
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp14
47 files changed, 2740 insertions, 887 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index 146d10835b8d..1d39b300091f 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -1111,6 +1111,7 @@ static std::string getEnumNameForToken(StringRef Str) {
case '<': Res += "_LT_"; break;
case '>': Res += "_GT_"; break;
case '-': Res += "_MINUS_"; break;
+ case '#': Res += "_HASH_"; break;
default:
if ((*it >= 'A' && *it <= 'Z') ||
(*it >= 'a' && *it <= 'z') ||
@@ -1439,7 +1440,7 @@ void AsmMatcherInfo::buildOperandMatchInfo() {
/// Map containing a mask with all operands indices that can be found for
/// that class inside a instruction.
- typedef std::map<ClassInfo *, unsigned, less_ptr<ClassInfo>> OpClassMaskTy;
+ typedef std::map<ClassInfo *, unsigned, deref<std::less<>>> OpClassMaskTy;
OpClassMaskTy OpClassMask;
for (const auto &MI : Matchables) {
@@ -1515,7 +1516,7 @@ void AsmMatcherInfo::buildInfo() {
if (!V.empty() && V != Variant.Name)
continue;
- auto II = llvm::make_unique<MatchableInfo>(*CGI);
+ auto II = std::make_unique<MatchableInfo>(*CGI);
II->initialize(*this, SingletonRegisters, Variant, HasMnemonicFirst);
@@ -1532,7 +1533,7 @@ void AsmMatcherInfo::buildInfo() {
std::vector<Record*> AllInstAliases =
Records.getAllDerivedDefinitions("InstAlias");
for (unsigned i = 0, e = AllInstAliases.size(); i != e; ++i) {
- auto Alias = llvm::make_unique<CodeGenInstAlias>(AllInstAliases[i],
+ auto Alias = std::make_unique<CodeGenInstAlias>(AllInstAliases[i],
Target);
// If the tblgen -match-prefix option is specified (for tblgen hackers),
@@ -1546,7 +1547,7 @@ void AsmMatcherInfo::buildInfo() {
if (!V.empty() && V != Variant.Name)
continue;
- auto II = llvm::make_unique<MatchableInfo>(std::move(Alias));
+ auto II = std::make_unique<MatchableInfo>(std::move(Alias));
II->initialize(*this, SingletonRegisters, Variant, HasMnemonicFirst);
@@ -1615,7 +1616,7 @@ void AsmMatcherInfo::buildInfo() {
II->TheDef->getValueAsString("TwoOperandAliasConstraint");
if (Constraint != "") {
// Start by making a copy of the original matchable.
- auto AliasII = llvm::make_unique<MatchableInfo>(*II);
+ auto AliasII = std::make_unique<MatchableInfo>(*II);
// Adjust it to be a two-operand alias.
AliasII->formTwoOperandAlias(Constraint);
@@ -2381,7 +2382,7 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target,
OS << " NumMatchClassKinds\n";
OS << "};\n\n";
- OS << "}\n\n";
+ OS << "} // end anonymous namespace\n\n";
}
/// emitMatchClassDiagStrings - Emit a function to get the diagnostic text to be
@@ -2866,7 +2867,7 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
OS << " }\n";
OS << " };\n";
- OS << "} // end anonymous namespace.\n\n";
+ OS << "} // end anonymous namespace\n\n";
OS << "static const OperandMatchEntry OperandMatchTable["
<< Info.OperandMatchInfo.size() << "] = {\n";
@@ -3366,7 +3367,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
}
OS << "};\n\n"
- << "const static FeatureBitset FeatureBitsets[] {\n"
+ << "static constexpr FeatureBitset FeatureBitsets[] = {\n"
<< " {}, // AMFBS_None\n";
for (const auto &FeatureBitset : FeatureBitsets) {
if (FeatureBitset.empty())
@@ -3422,7 +3423,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " }\n";
OS << " };\n";
- OS << "} // end anonymous namespace.\n\n";
+ OS << "} // end anonymous namespace\n\n";
unsigned VariantCount = Target.getAsmParserVariantCount();
for (unsigned VC = 0; VC != VariantCount; ++VC) {
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp
index 05d81f133505..b5c7f35be0e5 100644
--- a/utils/TableGen/AsmWriterEmitter.cpp
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -784,8 +784,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
continue; // Aliases with priority 0 are never emitted.
const DagInit *DI = R->getValueAsDag("ResultInst");
- const DefInit *Op = cast<DefInit>(DI->getOperator());
- AliasMap[getQualifiedName(Op->getDef())].insert(
+ AliasMap[getQualifiedName(DI->getOperatorAsDef(R->getLoc()))].insert(
std::make_pair(CodeGenInstAlias(R, Target), Priority));
}
diff --git a/utils/TableGen/CallingConvEmitter.cpp b/utils/TableGen/CallingConvEmitter.cpp
index de5044e24d49..9eabb44d9004 100644
--- a/utils/TableGen/CallingConvEmitter.cpp
+++ b/utils/TableGen/CallingConvEmitter.cpp
@@ -264,6 +264,10 @@ void CallingConvEmitter::EmitAction(Record *Action,
Record *DestTy = Action->getValueAsDef("DestTy");
O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n";
O << IndentStr << "LocInfo = CCValAssign::BCvt;\n";
+ } else if (Action->isSubClassOf("CCTruncToType")) {
+ Record *DestTy = Action->getValueAsDef("DestTy");
+ O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n";
+ O << IndentStr << "LocInfo = CCValAssign::Trunc;\n";
} else if (Action->isSubClassOf("CCPassIndirect")) {
Record *DestTy = Action->getValueAsDef("DestTy");
O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n";
diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp
index da65763905a8..42f69cb253d2 100644
--- a/utils/TableGen/CodeEmitterGen.cpp
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -16,6 +16,7 @@
#include "CodeGenTarget.h"
#include "SubtargetFeatureInfo.h"
#include "Types.h"
+#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
@@ -45,12 +46,19 @@ public:
private:
int getVariableBit(const std::string &VarName, BitsInit *BI, int bit);
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,
std::set<unsigned> &NamedOpIndices,
std::string &Case, CodeGenTarget &Target);
+ void emitInstructionBaseValues(
+ raw_ostream &o, ArrayRef<const CodeGenInstruction *> NumberedInstructions,
+ CodeGenTarget &Target, int HwMode = -1);
+ unsigned BitWidth;
+ bool UseAPInt;
};
// If the VarBitInit at position 'bit' matches the specified variable then
@@ -126,7 +134,10 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(OpIdx);
std::string &EncoderMethodName = CGI.Operands[SO.first].EncoderMethodName;
-
+
+ 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.
if (!EncoderMethodName.empty()) {
@@ -134,18 +145,54 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
// 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" +
- " op = " + EncoderMethodName + "(MI, " + utostr(OpIdx);
- Case += ", Fixups, STI";
- Case += ");\n";
+ Case += " // op: " + VarName + "\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" +
- " op = getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
- Case += ", Fixups, STI";
+ Case += " // op: " + VarName + "\n";
+ if (UseAPInt) {
+ Case += " getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
+ Case += ", op, Fixups, STI";
+ } else {
+ Case += " op = getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
+ Case += ", Fixups, STI";
+ }
Case += ");\n";
}
-
+
+ // Precalculate the number of lits this variable contributes to in the
+ // operand. If there is a single lit (consecutive range of bits) we can use a
+ // destructive sequence on APInt that reduces memory allocations.
+ int numOperandLits = 0;
+ for (int tmpBit = bit; tmpBit >= 0;) {
+ int varBit = getVariableBit(VarName, BI, tmpBit);
+
+ // If this bit isn't from a variable, skip it.
+ if (varBit == -1) {
+ --tmpBit;
+ continue;
+ }
+
+ // Figure out the consecutive range of bits covered by this operand, in
+ // order to generate better encoding code.
+ int beginVarBit = varBit;
+ int N = 1;
+ for (--tmpBit; tmpBit >= 0;) {
+ varBit = getVariableBit(VarName, BI, tmpBit);
+ if (varBit == -1 || varBit != (beginVarBit - N))
+ break;
+ ++N;
+ --tmpBit;
+ }
+ ++numOperandLits;
+ }
+
for (; bit >= 0; ) {
int varBit = getVariableBit(VarName, BI, bit);
@@ -166,20 +213,52 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
++N;
--bit;
}
-
- uint64_t opMask = ~(uint64_t)0 >> (64-N);
- int opShift = beginVarBit - N + 1;
- opMask <<= opShift;
- opShift = beginInstBit - beginVarBit;
-
- if (opShift > 0) {
- Case += " Value |= (op & UINT64_C(" + utostr(opMask) + ")) << " +
- itostr(opShift) + ";\n";
- } else if (opShift < 0) {
- Case += " Value |= (op & UINT64_C(" + utostr(opMask) + ")) >> " +
- itostr(-opShift) + ";\n";
+
+ std::string maskStr;
+ int opShift;
+
+ unsigned loBit = beginVarBit - N + 1;
+ unsigned hiBit = loBit + N;
+ unsigned loInstBit = beginInstBit - N + 1;
+ if (UseAPInt) {
+ std::string extractStr;
+ if (N >= 64) {
+ extractStr = "op.extractBits(" + itostr(hiBit - loBit) + ", " +
+ itostr(loBit) + ")";
+ Case += " Value.insertBits(" + extractStr + ", " +
+ itostr(loInstBit) + ");\n";
+ } else {
+ extractStr = "op.extractBitsAsZExtValue(" + itostr(hiBit - loBit) +
+ ", " + itostr(loBit) + ")";
+ Case += " Value.insertBits(" + extractStr + ", " +
+ itostr(loInstBit) + ", " + itostr(hiBit - loBit) + ");\n";
+ }
} else {
- Case += " Value |= op & UINT64_C(" + utostr(opMask) + ");\n";
+ uint64_t opMask = ~(uint64_t)0 >> (64 - N);
+ opShift = beginVarBit - N + 1;
+ opMask <<= opShift;
+ maskStr = "UINT64_C(" + utostr(opMask) + ")";
+ opShift = beginInstBit - beginVarBit;
+
+ if (numOperandLits == 1) {
+ Case += " op &= " + maskStr + ";\n";
+ if (opShift > 0) {
+ Case += " op <<= " + itostr(opShift) + ";\n";
+ } else if (opShift < 0) {
+ Case += " op >>= " + itostr(-opShift) + ";\n";
+ }
+ Case += " Value |= op;\n";
+ } else {
+ if (opShift > 0) {
+ Case += " Value |= (op & " + maskStr + ") << " +
+ itostr(opShift) + ";\n";
+ } else if (opShift < 0) {
+ Case += " Value |= (op & " + maskStr + ") >> " +
+ itostr(-opShift) + ";\n";
+ } else {
+ Case += " Value |= (op & " + maskStr + ");\n";
+ }
+ }
}
}
}
@@ -187,7 +266,29 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
std::string CodeEmitterGen::getInstructionCase(Record *R,
CodeGenTarget &Target) {
std::string Case;
- BitsInit *BI = R->getValueAsBitsInit("Inst");
+ if (const RecordVal *RV = R->getValue("EncodingInfos")) {
+ if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
+ const CodeGenHwModes &HWM = Target.getHwModes();
+ EncodingInfoByHwMode EBM(DI->getDef(), HWM);
+ Case += " switch (HwMode) {\n";
+ Case += " default: llvm_unreachable(\"Unhandled HwMode\");\n";
+ for (auto &KV : EBM.Map) {
+ Case += " case " + itostr(KV.first) + ": {\n";
+ Case += getInstructionCaseForEncoding(R, KV.second, Target);
+ Case += " break;\n";
+ Case += " }\n";
+ }
+ Case += " }\n";
+ return Case;
+ }
+ }
+ return getInstructionCaseForEncoding(R, R, Target);
+}
+
+std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *EncodingDef,
+ CodeGenTarget &Target) {
+ std::string Case;
+ BitsInit *BI = EncodingDef->getValueAsBitsInit("Inst");
unsigned NumberedOp = 0;
std::set<unsigned> NamedOpIndices;
@@ -207,7 +308,7 @@ std::string CodeEmitterGen::getInstructionCase(Record *R,
// Loop over all of the fields in the instruction, determining which are the
// operands to the instruction.
- for (const RecordVal &RV : R->getValues()) {
+ for (const RecordVal &RV : EncodingDef->getValues()) {
// Ignore fixed fields in the record, we're looking for values like:
// bits<5> RST = { ?, ?, ?, ?, ? };
if (RV.getPrefix() || RV.getValue()->isComplete())
@@ -237,6 +338,54 @@ getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) {
return Name;
}
+static void emitInstBits(raw_ostream &OS, const APInt &Bits) {
+ for (unsigned I = 0; I < Bits.getNumWords(); ++I)
+ OS << ((I > 0) ? ", " : "") << "UINT64_C(" << utostr(Bits.getRawData()[I])
+ << ")";
+}
+
+void CodeEmitterGen::emitInstructionBaseValues(
+ raw_ostream &o, ArrayRef<const CodeGenInstruction *> NumberedInstructions,
+ CodeGenTarget &Target, int HwMode) {
+ const CodeGenHwModes &HWM = Target.getHwModes();
+ if (HwMode == -1)
+ o << " static const uint64_t InstBits[] = {\n";
+ else
+ o << " static const uint64_t InstBits_" << HWM.getMode(HwMode).Name
+ << "[] = {\n";
+
+ for (const CodeGenInstruction *CGI : NumberedInstructions) {
+ Record *R = CGI->TheDef;
+
+ if (R->getValueAsString("Namespace") == "TargetOpcode" ||
+ R->getValueAsBit("isPseudo")) {
+ o << " "; emitInstBits(o, APInt(BitWidth, 0)); o << ",\n";
+ continue;
+ }
+
+ Record *EncodingDef = R;
+ if (const RecordVal *RV = R->getValue("EncodingInfos")) {
+ if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
+ EncodingInfoByHwMode EBM(DI->getDef(), HWM);
+ if (EBM.hasMode(HwMode))
+ EncodingDef = EBM.get(HwMode);
+ }
+ }
+ BitsInit *BI = EncodingDef->getValueAsBitsInit("Inst");
+
+ // 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);
+ }
+ o << " ";
+ emitInstBits(o, Value);
+ o << "," << '\t' << "// " << R->getName() << "\n";
+ }
+ o << " UINT64_C(0)\n };\n";
+}
+
void CodeEmitterGen::run(raw_ostream &o) {
CodeGenTarget Target(Records);
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
@@ -247,34 +396,66 @@ void CodeEmitterGen::run(raw_ostream &o) {
ArrayRef<const CodeGenInstruction*> NumberedInstructions =
Target.getInstructionsByEnumValue();
- // Emit function declaration
- o << "uint64_t " << Target.getName();
- o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
- << " SmallVectorImpl<MCFixup> &Fixups,\n"
- << " const MCSubtargetInfo &STI) const {\n";
-
- // Emit instruction base values
- o << " static const uint64_t InstBits[] = {\n";
+ const CodeGenHwModes &HWM = Target.getHwModes();
+ // The set of HwModes used by instruction encodings.
+ std::set<unsigned> HwModes;
+ BitWidth = 0;
for (const CodeGenInstruction *CGI : NumberedInstructions) {
Record *R = CGI->TheDef;
-
if (R->getValueAsString("Namespace") == "TargetOpcode" ||
- R->getValueAsBit("isPseudo")) {
- o << " UINT64_C(0),\n";
+ R->getValueAsBit("isPseudo"))
continue;
- }
+ if (const RecordVal *RV = R->getValue("EncodingInfos")) {
+ if (DefInit *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
+ EncodingInfoByHwMode EBM(DI->getDef(), HWM);
+ for (auto &KV : EBM.Map) {
+ BitsInit *BI = KV.second->getValueAsBitsInit("Inst");
+ BitWidth = std::max(BitWidth, BI->getNumBits());
+ HwModes.insert(KV.first);
+ }
+ continue;
+ }
+ }
BitsInit *BI = R->getValueAsBitsInit("Inst");
+ BitWidth = std::max(BitWidth, BI->getNumBits());
+ }
+ UseAPInt = BitWidth > 64;
+
+ // Emit function declaration
+ if (UseAPInt) {
+ o << "void " << Target.getName()
+ << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
+ << " SmallVectorImpl<MCFixup> &Fixups,\n"
+ << " APInt &Inst,\n"
+ << " APInt &Scratch,\n"
+ << " const MCSubtargetInfo &STI) const {\n";
+ } else {
+ o << "uint64_t " << Target.getName();
+ o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
+ << " SmallVectorImpl<MCFixup> &Fixups,\n"
+ << " const MCSubtargetInfo &STI) const {\n";
+ }
+
+ // Emit instruction base values
+ if (HwModes.empty()) {
+ emitInstructionBaseValues(o, NumberedInstructions, Target, -1);
+ } else {
+ for (unsigned HwMode : HwModes)
+ emitInstructionBaseValues(o, NumberedInstructions, Target, (int)HwMode);
+ }
- // Start by filling in fixed values.
- uint64_t Value = 0;
- for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) {
- if (BitInit *B = dyn_cast<BitInit>(BI->getBit(e-i-1)))
- Value |= (uint64_t)B->getValue() << (e-i-1);
+ if (!HwModes.empty()) {
+ o << " const uint64_t *InstBits;\n";
+ o << " unsigned HwMode = STI.getHwMode();\n";
+ o << " switch (HwMode) {\n";
+ o << " default: llvm_unreachable(\"Unknown hardware mode!\"); break;\n";
+ for (unsigned I : HwModes) {
+ o << " case " << I << ": InstBits = InstBits_" << HWM.getMode(I).Name
+ << "; break;\n";
}
- o << " UINT64_C(" << Value << ")," << '\t' << "// " << R->getName() << "\n";
+ o << " };\n";
}
- o << " UINT64_C(0)\n };\n";
// Map to accumulate all the cases.
std::map<std::string, std::vector<std::string>> CaseMap;
@@ -294,11 +475,26 @@ void CodeEmitterGen::run(raw_ostream &o) {
}
// Emit initial function code
- o << " const unsigned opcode = MI.getOpcode();\n"
- << " uint64_t Value = InstBits[opcode];\n"
- << " uint64_t op = 0;\n"
- << " (void)op; // suppress warning\n"
- << " switch (opcode) {\n";
+ if (UseAPInt) {
+ int NumWords = APInt::getNumWords(BitWidth);
+ int NumBytes = (BitWidth + 7) / 8;
+ o << " const unsigned opcode = MI.getOpcode();\n"
+ << " if (Inst.getBitWidth() != " << BitWidth << ")\n"
+ << " Inst = Inst.zext(" << BitWidth << ");\n"
+ << " if (Scratch.getBitWidth() != " << BitWidth << ")\n"
+ << " Scratch = Scratch.zext(" << BitWidth << ");\n"
+ << " LoadIntFromMemory(Inst, (uint8_t*)&InstBits[opcode * " << NumWords
+ << "], " << NumBytes << ");\n"
+ << " APInt &Value = Inst;\n"
+ << " APInt &op = Scratch;\n"
+ << " switch (opcode) {\n";
+ } else {
+ o << " const unsigned opcode = MI.getOpcode();\n"
+ << " uint64_t Value = InstBits[opcode];\n"
+ << " uint64_t op = 0;\n"
+ << " (void)op; // suppress warning\n"
+ << " switch (opcode) {\n";
+ }
// Emit each case statement
std::map<std::string, std::vector<std::string>>::iterator IE, EE;
@@ -322,9 +518,12 @@ void CodeEmitterGen::run(raw_ostream &o) {
<< " raw_string_ostream Msg(msg);\n"
<< " Msg << \"Not supported instr: \" << MI;\n"
<< " report_fatal_error(Msg.str());\n"
- << " }\n"
- << " return Value;\n"
- << "}\n\n";
+ << " }\n";
+ if (UseAPInt)
+ o << " Inst = Value;\n";
+ else
+ o << " return Value;\n";
+ o << "}\n\n";
const auto &All = SubtargetFeatureInfo::getAll(Records);
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatures;
@@ -385,8 +584,8 @@ void CodeEmitterGen::run(raw_ostream &o) {
o << " " << getNameForFeatureBitset(FeatureBitset) << ",\n";
}
o << "};\n\n"
- << "const static FeatureBitset FeatureBitsets[] {\n"
- << " {}, // CEFBS_None\n";
+ << "static constexpr FeatureBitset FeatureBitsets[] = {\n"
+ << " {}, // CEFBS_None\n";
for (const auto &FeatureBitset : FeatureBitsets) {
if (FeatureBitset.empty())
continue;
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index c8f710d66a03..46f986ca0176 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -769,7 +769,10 @@ void TypeInfer::expandOverloads(TypeSetByHwMode::SetType &Out,
for (MVT T : MVT::integer_valuetypes())
if (Legal.count(T))
Out.insert(T);
- for (MVT T : MVT::integer_vector_valuetypes())
+ for (MVT T : MVT::integer_fixedlen_vector_valuetypes())
+ if (Legal.count(T))
+ Out.insert(T);
+ for (MVT T : MVT::integer_scalable_vector_valuetypes())
if (Legal.count(T))
Out.insert(T);
return;
@@ -777,7 +780,10 @@ void TypeInfer::expandOverloads(TypeSetByHwMode::SetType &Out,
for (MVT T : MVT::fp_valuetypes())
if (Legal.count(T))
Out.insert(T);
- for (MVT T : MVT::fp_vector_valuetypes())
+ for (MVT T : MVT::fp_fixedlen_vector_valuetypes())
+ if (Legal.count(T))
+ Out.insert(T);
+ for (MVT T : MVT::fp_scalable_vector_valuetypes())
if (Legal.count(T))
Out.insert(T);
return;
@@ -883,7 +889,8 @@ std::string TreePredicateFn::getPredCode() const {
if (isLoad()) {
if (!isUnindexed() && !isNonExtLoad() && !isAnyExtLoad() &&
!isSignExtLoad() && !isZeroExtLoad() && getMemoryVT() == nullptr &&
- getScalarMemoryVT() == nullptr)
+ getScalarMemoryVT() == nullptr && getAddressSpaces() == nullptr &&
+ getMinAlignment() < 1)
PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(),
"IsLoad cannot be used by itself");
} else {
@@ -903,7 +910,8 @@ std::string TreePredicateFn::getPredCode() const {
if (isStore()) {
if (!isUnindexed() && !isTruncStore() && !isNonTruncStore() &&
- getMemoryVT() == nullptr && getScalarMemoryVT() == nullptr)
+ getMemoryVT() == nullptr && getScalarMemoryVT() == nullptr &&
+ getAddressSpaces() == nullptr && getMinAlignment() < 1)
PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(),
"IsStore cannot be used by itself");
} else {
@@ -917,6 +925,7 @@ std::string TreePredicateFn::getPredCode() const {
if (isAtomic()) {
if (getMemoryVT() == nullptr && !isAtomicOrderingMonotonic() &&
+ getAddressSpaces() == nullptr &&
!isAtomicOrderingAcquire() && !isAtomicOrderingRelease() &&
!isAtomicOrderingAcquireRelease() &&
!isAtomicOrderingSequentiallyConsistent() &&
@@ -977,6 +986,13 @@ std::string TreePredicateFn::getPredCode() const {
Code += ")\nreturn false;\n";
}
+ int64_t MinAlign = getMinAlignment();
+ if (MinAlign > 0) {
+ Code += "if (cast<MemSDNode>(N)->getAlignment() < ";
+ Code += utostr(MinAlign);
+ Code += ")\nreturn false;\n";
+ }
+
Record *MemoryVT = getMemoryVT();
if (MemoryVT)
@@ -1177,6 +1193,13 @@ ListInit *TreePredicateFn::getAddressSpaces() const {
return R->getValueAsListInit("AddressSpaces");
}
+int64_t TreePredicateFn::getMinAlignment() const {
+ Record *R = getOrigPatFragRecord()->getRecord();
+ if (R->isValueUnset("MinAlignment"))
+ return 0;
+ return R->getValueAsInt("MinAlignment");
+}
+
Record *TreePredicateFn::getScalarMemoryVT() const {
Record *R = getOrigPatFragRecord()->getRecord();
if (R->isValueUnset("ScalarMemoryVT"))
@@ -1373,9 +1396,11 @@ getPatternComplexity(const CodeGenDAGPatterns &CGP) const {
///
std::string PatternToMatch::getPredicateCheck() const {
SmallVector<const Predicate*,4> PredList;
- for (const Predicate &P : Predicates)
- PredList.push_back(&P);
- llvm::sort(PredList, deref<llvm::less>());
+ for (const Predicate &P : Predicates) {
+ if (!P.getCondString().empty())
+ PredList.push_back(&P);
+ }
+ llvm::sort(PredList, deref<std::less<>>());
std::string Check;
for (unsigned i = 0, e = PredList.size(); i != e; ++i) {
@@ -2772,6 +2797,7 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
if (Operator->isSubClassOf("SDNode") &&
Operator->getName() != "imm" &&
+ Operator->getName() != "timm" &&
Operator->getName() != "fpimm" &&
Operator->getName() != "tglobaltlsaddr" &&
Operator->getName() != "tconstpool" &&
@@ -3083,7 +3109,7 @@ void CodeGenDAGPatterns::ParsePatternFragments(bool OutFrags) {
ListInit *LI = Frag->getValueAsListInit("Fragments");
TreePattern *P =
- (PatternFragments[Frag] = llvm::make_unique<TreePattern>(
+ (PatternFragments[Frag] = std::make_unique<TreePattern>(
Frag, LI, !Frag->isSubClassOf("OutPatFrag"),
*this)).get();
diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h
index 2b49a64c3f1d..80fc932a7a50 100644
--- a/utils/TableGen/CodeGenDAGPatterns.h
+++ b/utils/TableGen/CodeGenDAGPatterns.h
@@ -594,6 +594,7 @@ public:
Record *getScalarMemoryVT() const;
ListInit *getAddressSpaces() const;
+ int64_t getMinAlignment() const;
// If true, indicates that GlobalISel-based C++ code was supplied.
bool hasGISelPredicateCode() const;
@@ -1075,8 +1076,11 @@ public:
std::string C = IsHwMode
? std::string("MF->getSubtarget().checkFeatures(\"" + Features + "\")")
: std::string(Def->getValueAsString("CondString"));
+ if (C.empty())
+ return "";
return IfCond ? C : "!("+C+')';
}
+
bool operator==(const Predicate &P) const {
return IfCond == P.IfCond && IsHwMode == P.IsHwMode && Def == P.Def;
}
diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp
index 2463824469ab..fde946d06589 100644
--- a/utils/TableGen/CodeGenInstruction.cpp
+++ b/utils/TableGen/CodeGenInstruction.cpp
@@ -363,6 +363,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R)
Namespace = R->getValueAsString("Namespace");
AsmString = R->getValueAsString("AsmString");
+ isPreISelOpcode = R->getValueAsBit("isPreISelOpcode");
isReturn = R->getValueAsBit("isReturn");
isEHScopeReturn = R->getValueAsBit("isEHScopeReturn");
isBranch = R->getValueAsBit("isBranch");
diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h
index bb5b1369649f..2cb28425df7a 100644
--- a/utils/TableGen/CodeGenInstruction.h
+++ b/utils/TableGen/CodeGenInstruction.h
@@ -231,6 +231,7 @@ template <typename T> class ArrayRef;
std::vector<Record*> ImplicitDefs, ImplicitUses;
// Various boolean values we track for the instruction.
+ bool isPreISelOpcode : 1;
bool isReturn : 1;
bool isEHScopeReturn : 1;
bool isBranch : 1;
diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h
index 7b74bb07d6e0..83e780671b43 100644
--- a/utils/TableGen/CodeGenIntrinsics.h
+++ b/utils/TableGen/CodeGenIntrinsics.h
@@ -141,6 +141,7 @@ struct CodeGenIntrinsic {
enum ArgAttribute {
NoCapture,
+ NoAlias,
Returned,
ReadOnly,
WriteOnly,
@@ -154,6 +155,13 @@ struct CodeGenIntrinsic {
return Properties & (1 << Prop);
}
+ /// Returns true if the parameter at \p ParamIdx is a pointer type. Returns
+ /// false if the parameter is not a pointer, or \p ParamIdx is greater than
+ /// the size of \p IS.ParamVTs.
+ ///
+ /// Note that this requires that \p IS.ParamVTs is available.
+ bool isParamAPointer(unsigned ParamIdx) const;
+
CodeGenIntrinsic(Record *R);
};
diff --git a/utils/TableGen/CodeGenMapTable.cpp b/utils/TableGen/CodeGenMapTable.cpp
index b1774b01ba8c..793bb61481e7 100644
--- a/utils/TableGen/CodeGenMapTable.cpp
+++ b/utils/TableGen/CodeGenMapTable.cpp
@@ -132,7 +132,7 @@ public:
MapRec->getName() + "' has empty " + "`ValueCols' field!");
for (Init *I : ColValList->getValues()) {
- ListInit *ColI = dyn_cast<ListInit>(I);
+ auto *ColI = cast<ListInit>(I);
// Make sure that all the sub-lists in 'ValueCols' have same number of
// elements as the fields in 'ColFields'.
@@ -168,7 +168,7 @@ public:
return ValueCols;
}
};
-} // End anonymous namespace.
+} // end anonymous namespace
//===----------------------------------------------------------------------===//
@@ -226,7 +226,7 @@ public:
void emitMapFuncBody(raw_ostream &OS, unsigned TableSize);
};
-} // End anonymous namespace.
+} // end anonymous namespace
//===----------------------------------------------------------------------===//
@@ -521,7 +521,7 @@ static void emitEnums(raw_ostream &OS, RecordKeeper &Records) {
unsigned ListSize = List->size();
for (unsigned j = 0; j < ListSize; j++) {
- ListInit *ListJ = dyn_cast<ListInit>(List->getElement(j));
+ auto *ListJ = cast<ListInit>(List->getElement(j));
if (ListJ->size() != ColFields->size())
PrintFatalError("Record `" + CurMap->getName() + "', field "
@@ -604,8 +604,8 @@ void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) {
// Emit map tables and the functions to query them.
IMap.emitTablesWithFunc(OS);
}
- OS << "} // End " << NameSpace << " namespace\n";
- OS << "} // End llvm namespace\n";
+ OS << "} // end namespace " << NameSpace << "\n";
+ OS << "} // end namespace llvm\n";
OS << "#endif // GET_INSTRMAP_INFO\n\n";
}
diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp
index f87c6d6c945a..6153c759b123 100644
--- a/utils/TableGen/CodeGenRegisters.cpp
+++ b/utils/TableGen/CodeGenRegisters.cpp
@@ -639,7 +639,8 @@ struct TupleExpander : SetTheory::Expander {
// Precompute some types.
Record *RegisterCl = Def->getRecords().getClass("Register");
RecTy *RegisterRecTy = RecordRecTy::get(RegisterCl);
- StringInit *BlankName = StringInit::get("");
+ std::vector<StringRef> RegNames =
+ Def->getValueAsListOfStrings("RegAsmNames");
// Zip them up.
for (unsigned n = 0; n != Length; ++n) {
@@ -656,11 +657,20 @@ struct TupleExpander : SetTheory::Expander {
unsigned(Reg->getValueAsInt("CostPerUse")));
}
+ StringInit *AsmName = StringInit::get("");
+ if (!RegNames.empty()) {
+ if (RegNames.size() <= n)
+ PrintFatalError(Def->getLoc(),
+ "Register tuple definition missing name for '" +
+ Name + "'.");
+ AsmName = StringInit::get(RegNames[n]);
+ }
+
// Create a new Record representing the synthesized register. This record
// is only for consumption by CodeGenRegister, it is not added to the
// RecordKeeper.
SynthDefs.emplace_back(
- llvm::make_unique<Record>(Name, Def->getLoc(), Def->getRecords()));
+ std::make_unique<Record>(Name, Def->getLoc(), Def->getRecords()));
Record *NewReg = SynthDefs.back().get();
Elts.insert(NewReg);
@@ -683,9 +693,8 @@ struct TupleExpander : SetTheory::Expander {
if (Field == "SubRegs")
RV.setValue(ListInit::get(Tuple, RegisterRecTy));
- // Provide a blank AsmName. MC hacks are required anyway.
if (Field == "AsmName")
- RV.setValue(BlankName);
+ RV.setValue(AsmName);
// CostPerUse is aggregated from all Tuple members.
if (Field == "CostPerUse")
@@ -725,8 +734,8 @@ struct TupleExpander : SetTheory::Expander {
//===----------------------------------------------------------------------===//
static void sortAndUniqueRegisters(CodeGenRegister::Vec &M) {
- llvm::sort(M, deref<llvm::less>());
- M.erase(std::unique(M.begin(), M.end(), deref<llvm::equal>()), M.end());
+ llvm::sort(M, deref<std::less<>>());
+ M.erase(std::unique(M.begin(), M.end(), deref<std::equal_to<>>()), M.end());
}
CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
@@ -851,7 +860,7 @@ void CodeGenRegisterClass::inheritProperties(CodeGenRegBank &RegBank) {
bool CodeGenRegisterClass::contains(const CodeGenRegister *Reg) const {
return std::binary_search(Members.begin(), Members.end(), Reg,
- deref<llvm::less>());
+ deref<std::less<>>());
}
namespace llvm {
@@ -887,7 +896,7 @@ static bool testSubClass(const CodeGenRegisterClass *A,
return A->RSI.isSubClassOf(B->RSI) &&
std::includes(A->getMembers().begin(), A->getMembers().end(),
B->getMembers().begin(), B->getMembers().end(),
- deref<llvm::less>());
+ deref<std::less<>>());
}
/// Sorting predicate for register classes. This provides a topological
@@ -1089,7 +1098,7 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records,
Sets.addFieldExpander("RegisterClass", "MemberList");
Sets.addFieldExpander("CalleeSavedRegs", "SaveList");
Sets.addExpander("RegisterTuples",
- llvm::make_unique<TupleExpander>(SynthDefs));
+ std::make_unique<TupleExpander>(SynthDefs));
// Read in the user-defined (named) sub-register indices.
// More indices will be synthesized later.
@@ -2131,9 +2140,10 @@ void CodeGenRegBank::inferCommonSubClass(CodeGenRegisterClass *RC) {
const CodeGenRegister::Vec &Memb1 = RC1->getMembers();
const CodeGenRegister::Vec &Memb2 = RC2->getMembers();
CodeGenRegister::Vec Intersection;
- std::set_intersection(
- Memb1.begin(), Memb1.end(), Memb2.begin(), Memb2.end(),
- std::inserter(Intersection, Intersection.begin()), deref<llvm::less>());
+ std::set_intersection(Memb1.begin(), Memb1.end(), Memb2.begin(),
+ Memb2.end(),
+ std::inserter(Intersection, Intersection.begin()),
+ deref<std::less<>>());
// Skip disjoint class pairs.
if (Intersection.empty())
@@ -2158,7 +2168,8 @@ void CodeGenRegBank::inferCommonSubClass(CodeGenRegisterClass *RC) {
void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) {
// Map SubRegIndex to set of registers in RC supporting that SubRegIndex.
typedef std::map<const CodeGenSubRegIndex *, CodeGenRegister::Vec,
- deref<llvm::less>> SubReg2SetMap;
+ deref<std::less<>>>
+ SubReg2SetMap;
// Compute the set of registers supporting each SubRegIndex.
SubReg2SetMap SRSets;
@@ -2357,6 +2368,21 @@ CodeGenRegBank::getRegClassForRegister(Record *R) {
return FoundRC;
}
+const CodeGenRegisterClass *
+CodeGenRegBank::getMinimalPhysRegClass(Record *RegRecord,
+ ValueTypeByHwMode *VT) {
+ const CodeGenRegister *Reg = getReg(RegRecord);
+ const CodeGenRegisterClass *BestRC = nullptr;
+ for (const auto &RC : getRegClasses()) {
+ if ((!VT || RC.hasType(*VT)) &&
+ RC.contains(Reg) && (!BestRC || BestRC->hasSubClass(&RC)))
+ BestRC = &RC;
+ }
+
+ assert(BestRC && "Couldn't find the register class");
+ return BestRC;
+}
+
BitVector CodeGenRegBank::computeCoveredRegisters(ArrayRef<Record*> Regs) {
SetVector<const CodeGenRegister*> Set;
diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h
index f04a90f8fde5..6d933baec2ae 100644
--- a/utils/TableGen/CodeGenRegisters.h
+++ b/utils/TableGen/CodeGenRegisters.h
@@ -93,7 +93,8 @@ namespace llvm {
// Map of composite subreg indices.
typedef std::map<CodeGenSubRegIndex *, CodeGenSubRegIndex *,
- deref<llvm::less>> CompMap;
+ deref<std::less<>>>
+ CompMap;
// Returns the subreg index that results from composing this with Idx.
// Returns NULL if this and Idx don't compose.
@@ -137,15 +138,14 @@ namespace llvm {
/// list of subregisters they are composed of (if any). Do this recursively.
void computeConcatTransitiveClosure();
+ bool operator<(const CodeGenSubRegIndex &RHS) const {
+ return this->EnumValue < RHS.EnumValue;
+ }
+
private:
CompMap Composed;
};
- inline bool operator<(const CodeGenSubRegIndex &A,
- const CodeGenSubRegIndex &B) {
- return A.EnumValue < B.EnumValue;
- }
-
/// CodeGenRegister - Represents a register definition.
struct CodeGenRegister {
Record *TheDef;
@@ -156,7 +156,8 @@ namespace llvm {
bool Artificial;
// Map SubRegIndex -> Register.
- typedef std::map<CodeGenSubRegIndex *, CodeGenRegister *, deref<llvm::less>>
+ typedef std::map<CodeGenSubRegIndex *, CodeGenRegister *,
+ deref<std::less<>>>
SubRegMap;
CodeGenRegister(Record *R, unsigned Enum);
@@ -347,6 +348,10 @@ namespace llvm {
ArrayRef<ValueTypeByHwMode> getValueTypes() const { return VTs; }
unsigned getNumValueTypes() const { return VTs.size(); }
+ bool hasType(const ValueTypeByHwMode &VT) const {
+ return std::find(VTs.begin(), VTs.end(), VT) != VTs.end();
+ }
+
const ValueTypeByHwMode &getValueTypeNum(unsigned VTNum) const {
if (VTNum < VTs.size())
return VTs[VTNum];
@@ -708,6 +713,13 @@ namespace llvm {
/// return the superclass. Otherwise return null.
const CodeGenRegisterClass* getRegClassForRegister(Record *R);
+ // Analog of TargetRegisterInfo::getMinimalPhysRegClass. Unlike
+ // getRegClassForRegister, this tries to find the smallest class containing
+ // the physical register. If \p VT is specified, it will only find classes
+ // with a matching type
+ const CodeGenRegisterClass *
+ getMinimalPhysRegClass(Record *RegRecord, ValueTypeByHwMode *VT = nullptr);
+
// Get the sum of unit weights.
unsigned getRegUnitSetWeight(const std::vector<unsigned> &Units) const {
unsigned Weight = 0;
diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp
index fd007044a16e..f12d7d484a8e 100644
--- a/utils/TableGen/CodeGenSchedule.cpp
+++ b/utils/TableGen/CodeGenSchedule.cpp
@@ -172,8 +172,8 @@ CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
// Allow Set evaluation to recognize the dags used in InstRW records:
// (instrs Op1, Op1...)
- Sets.addOperator("instrs", llvm::make_unique<InstrsOp>());
- Sets.addOperator("instregex", llvm::make_unique<InstRegexOp>(Target));
+ Sets.addOperator("instrs", std::make_unique<InstrsOp>());
+ Sets.addOperator("instregex", std::make_unique<InstRegexOp>(Target));
// Instantiate a CodeGenProcModel for each SchedMachineModel with the values
// that are explicitly referenced in tablegen records. Resources associated
@@ -1083,9 +1083,13 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
if (RWD->getValueAsDef("SchedModel") == RWModelDef &&
RWModelDef->getValueAsBit("FullInstRWOverlapCheck")) {
for (Record *Inst : InstDefs) {
- PrintFatalError(InstRWDef->getLoc(), "Overlapping InstRW def " +
- Inst->getName() + " also matches " +
- RWD->getValue("Instrs")->getValue()->getAsString());
+ PrintFatalError
+ (InstRWDef->getLoc(),
+ "Overlapping InstRW definition for \"" +
+ Inst->getName() +
+ "\" also matches previous \"" +
+ RWD->getValue("Instrs")->getValue()->getAsString() +
+ "\".");
}
}
}
@@ -1115,9 +1119,13 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
for (Record *OldRWDef : SchedClasses[OldSCIdx].InstRWs) {
if (OldRWDef->getValueAsDef("SchedModel") == RWModelDef) {
for (Record *InstDef : InstDefs) {
- PrintFatalError(OldRWDef->getLoc(), "Overlapping InstRW def " +
- InstDef->getName() + " also matches " +
- OldRWDef->getValue("Instrs")->getValue()->getAsString());
+ PrintFatalError
+ (InstRWDef->getLoc(),
+ "Overlapping InstRW definition for \"" +
+ InstDef->getName() +
+ "\" also matches previous \"" +
+ OldRWDef->getValue("Instrs")->getValue()->getAsString() +
+ "\".");
}
}
assert(OldRWDef != InstRWDef &&
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index b65e1b6af791..fa8b842c97f9 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -98,6 +98,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v256i8: return "MVT::v256i8";
case MVT::v1i16: return "MVT::v1i16";
case MVT::v2i16: return "MVT::v2i16";
+ case MVT::v3i16: return "MVT::v3i16";
case MVT::v4i16: return "MVT::v4i16";
case MVT::v8i16: return "MVT::v8i16";
case MVT::v16i16: return "MVT::v16i16";
@@ -126,8 +127,11 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v32i64: return "MVT::v32i64";
case MVT::v1i128: return "MVT::v1i128";
case MVT::v2f16: return "MVT::v2f16";
+ case MVT::v3f16: return "MVT::v3f16";
case MVT::v4f16: return "MVT::v4f16";
case MVT::v8f16: return "MVT::v8f16";
+ case MVT::v16f16: return "MVT::v16f16";
+ case MVT::v32f16: return "MVT::v32f16";
case MVT::v1f32: return "MVT::v1f32";
case MVT::v2f32: return "MVT::v2f32";
case MVT::v3f32: return "MVT::v3f32";
@@ -289,10 +293,57 @@ Record *CodeGenTarget::getAsmWriter() const {
CodeGenRegBank &CodeGenTarget::getRegBank() const {
if (!RegBank)
- RegBank = llvm::make_unique<CodeGenRegBank>(Records, getHwModes());
+ RegBank = std::make_unique<CodeGenRegBank>(Records, getHwModes());
return *RegBank;
}
+Optional<CodeGenRegisterClass *>
+CodeGenTarget::getSuperRegForSubReg(const ValueTypeByHwMode &ValueTy,
+ CodeGenRegBank &RegBank,
+ const CodeGenSubRegIndex *SubIdx) const {
+ std::vector<CodeGenRegisterClass *> Candidates;
+ auto &RegClasses = RegBank.getRegClasses();
+
+ // Try to find a register class which supports ValueTy, and also contains
+ // SubIdx.
+ for (CodeGenRegisterClass &RC : RegClasses) {
+ // Is there a subclass of this class which contains this subregister index?
+ CodeGenRegisterClass *SubClassWithSubReg = RC.getSubClassWithSubReg(SubIdx);
+ if (!SubClassWithSubReg)
+ continue;
+
+ // We have a class. Check if it supports this value type.
+ if (llvm::none_of(SubClassWithSubReg->VTs,
+ [&ValueTy](const ValueTypeByHwMode &ClassVT) {
+ return ClassVT == ValueTy;
+ }))
+ continue;
+
+ // We have a register class which supports both the value type and
+ // subregister index. Remember it.
+ Candidates.push_back(SubClassWithSubReg);
+ }
+
+ // If we didn't find anything, we're done.
+ if (Candidates.empty())
+ return None;
+
+ // Find and return the largest of our candidate classes.
+ llvm::stable_sort(Candidates, [&](const CodeGenRegisterClass *A,
+ const CodeGenRegisterClass *B) {
+ if (A->getMembers().size() > B->getMembers().size())
+ return true;
+
+ if (A->getMembers().size() < B->getMembers().size())
+ return false;
+
+ // Order by name as a tie-breaker.
+ return StringRef(A->getName()) < B->getName();
+ });
+
+ return Candidates[0];
+}
+
void CodeGenTarget::ReadRegAltNameIndices() const {
RegAltNameIndices = Records.getAllDerivedDefinitions("RegAltNameIndex");
llvm::sort(RegAltNameIndices, LessRecord());
@@ -339,7 +390,7 @@ void CodeGenTarget::ReadLegalValueTypes() const {
CodeGenSchedModels &CodeGenTarget::getSchedModels() const {
if (!SchedModels)
- SchedModels = llvm::make_unique<CodeGenSchedModels>(Records, *this);
+ SchedModels = std::make_unique<CodeGenSchedModels>(Records, *this);
return *SchedModels;
}
@@ -352,7 +403,7 @@ void CodeGenTarget::ReadInstructions() const {
// Parse the instructions defined in the .td file.
for (unsigned i = 0, e = Insts.size(); i != e; ++i)
- Instructions[Insts[i]] = llvm::make_unique<CodeGenInstruction>(Insts[i]);
+ Instructions[Insts[i]] = std::make_unique<CodeGenInstruction>(Insts[i]);
}
static const CodeGenInstruction *
@@ -427,7 +478,8 @@ void CodeGenTarget::reverseBitsForLittleEndianEncoding() {
if (!isLittleEndianEncoding())
return;
- std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
+ std::vector<Record *> Insts =
+ Records.getAllDerivedDefinitions("InstructionEncoding");
for (Record *R : Insts) {
if (R->getValueAsString("Namespace") == "TargetOpcode" ||
R->getValueAsBit("isPseudo"))
@@ -733,6 +785,9 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
else if (Property->isSubClassOf("NoCapture")) {
unsigned ArgNo = Property->getValueAsInt("ArgNo");
ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture));
+ } else if (Property->isSubClassOf("NoAlias")) {
+ unsigned ArgNo = Property->getValueAsInt("ArgNo");
+ ArgumentAttributes.push_back(std::make_pair(ArgNo, NoAlias));
} else if (Property->isSubClassOf("Returned")) {
unsigned ArgNo = Property->getValueAsInt("ArgNo");
ArgumentAttributes.push_back(std::make_pair(ArgNo, Returned));
@@ -758,3 +813,10 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
// Sort the argument attributes for later benefit.
llvm::sort(ArgumentAttributes);
}
+
+bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const {
+ if (ParamIdx >= IS.ParamVTs.size())
+ return false;
+ MVT ParamType = MVT(IS.ParamVTs[ParamIdx]);
+ return ParamType == MVT::iPTR || ParamType == MVT::iPTRAny;
+}
diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h
index 1ab2de269c76..d52ffac4ce6c 100644
--- a/utils/TableGen/CodeGenTarget.h
+++ b/utils/TableGen/CodeGenTarget.h
@@ -103,6 +103,12 @@ public:
/// getRegBank - Return the register bank description.
CodeGenRegBank &getRegBank() const;
+ /// Return the largest register class on \p RegBank which supports \p Ty and
+ /// covers \p SubIdx if it exists.
+ Optional<CodeGenRegisterClass *>
+ getSuperRegForSubReg(const ValueTypeByHwMode &Ty, CodeGenRegBank &RegBank,
+ const CodeGenSubRegIndex *SubIdx) const;
+
/// getRegisterByName - If there is a register with the specific AsmName,
/// return it.
const CodeGenRegister *getRegisterByName(StringRef Name) const;
diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp
index fb0c6faa5295..d8e78ce55c7b 100644
--- a/utils/TableGen/DAGISelEmitter.cpp
+++ b/utils/TableGen/DAGISelEmitter.cpp
@@ -173,7 +173,7 @@ void DAGISelEmitter::run(raw_ostream &OS) {
}
std::unique_ptr<Matcher> TheMatcher =
- llvm::make_unique<ScopeMatcher>(PatternMatchers);
+ std::make_unique<ScopeMatcher>(PatternMatchers);
OptimizeMatcher(TheMatcher, CGP);
//Matcher->dump();
diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h
index 0a782e84a372..223513fc8d38 100644
--- a/utils/TableGen/DAGISelMatcher.h
+++ b/utils/TableGen/DAGISelMatcher.h
@@ -932,13 +932,15 @@ private:
///
class EmitCopyToRegMatcher : public Matcher {
unsigned SrcSlot; // Value to copy into the physreg.
- Record *DestPhysReg;
+ const CodeGenRegister *DestPhysReg;
+
public:
- EmitCopyToRegMatcher(unsigned srcSlot, Record *destPhysReg)
+ EmitCopyToRegMatcher(unsigned srcSlot,
+ const CodeGenRegister *destPhysReg)
: Matcher(EmitCopyToReg), SrcSlot(srcSlot), DestPhysReg(destPhysReg) {}
unsigned getSrcSlot() const { return SrcSlot; }
- Record *getDestPhysReg() const { return DestPhysReg; }
+ const CodeGenRegister *getDestPhysReg() const { return DestPhysReg; }
static bool classof(const Matcher *N) {
return N->getKind() == EmitCopyToReg;
diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp
index cecbc6cccdff..e9f1fb93d516 100644
--- a/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -670,12 +670,22 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << '\n';
return 2+MN->getNumNodes();
}
- case Matcher::EmitCopyToReg:
- OS << "OPC_EmitCopyToReg, "
- << cast<EmitCopyToRegMatcher>(N)->getSrcSlot() << ", "
- << getQualifiedName(cast<EmitCopyToRegMatcher>(N)->getDestPhysReg())
- << ",\n";
- return 3;
+ case Matcher::EmitCopyToReg: {
+ const auto *C2RMatcher = cast<EmitCopyToRegMatcher>(N);
+ int Bytes = 3;
+ const CodeGenRegister *Reg = C2RMatcher->getDestPhysReg();
+ if (Reg->EnumValue > 255) {
+ assert(isUInt<16>(Reg->EnumValue) && "not handled");
+ OS << "OPC_EmitCopyToReg2, " << C2RMatcher->getSrcSlot() << ", "
+ << "TARGET_VAL(" << getQualifiedName(Reg->TheDef) << "),\n";
+ ++Bytes;
+ } else {
+ OS << "OPC_EmitCopyToReg, " << C2RMatcher->getSrcSlot() << ", "
+ << getQualifiedName(Reg->TheDef) << ",\n";
+ }
+
+ return Bytes;
+ }
case Matcher::EmitNodeXForm: {
const EmitNodeXFormMatcher *XF = cast<EmitNodeXFormMatcher>(N);
OS << "OPC_EmitNodeXForm, " << getNodeXFormID(XF->getNodeXForm()) << ", "
diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp
index 8f54beeba65b..49c09c7d195e 100644
--- a/utils/TableGen/DAGISelMatcherGen.cpp
+++ b/utils/TableGen/DAGISelMatcherGen.cpp
@@ -141,7 +141,7 @@ namespace {
SmallVectorImpl<unsigned> &ResultOps);
};
-} // end anon namespace.
+} // end anonymous namespace
MatcherGen::MatcherGen(const PatternToMatch &pattern,
const CodeGenDAGPatterns &cgp)
@@ -867,9 +867,13 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
if (isRoot && !PhysRegInputs.empty()) {
// Emit all of the CopyToReg nodes for the input physical registers. These
// occur in patterns like (mul:i8 AL:i8, GR8:i8:$src).
- for (unsigned i = 0, e = PhysRegInputs.size(); i != e; ++i)
+ for (unsigned i = 0, e = PhysRegInputs.size(); i != e; ++i) {
+ const CodeGenRegister *Reg =
+ CGP.getTargetInfo().getRegBank().getReg(PhysRegInputs[i].first);
AddMatcher(new EmitCopyToRegMatcher(PhysRegInputs[i].second,
- PhysRegInputs[i].first));
+ Reg));
+ }
+
// Even if the node has no other glue inputs, the resultant node must be
// glued to the CopyFromReg nodes we just generated.
TreeHasInGlue = true;
diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp
index 7d51b0769372..6746fdd676a7 100644
--- a/utils/TableGen/DAGISelMatcherOpt.cpp
+++ b/utils/TableGen/DAGISelMatcherOpt.cpp
@@ -409,13 +409,14 @@ static void FactorNodes(std::unique_ptr<Matcher> &InputMatcherPtr) {
DenseMap<unsigned, unsigned> TypeEntry;
SmallVector<std::pair<MVT::SimpleValueType, Matcher*>, 8> Cases;
for (unsigned i = 0, e = NewOptionsToMatch.size(); i != e; ++i) {
- CheckTypeMatcher *CTM =
- cast_or_null<CheckTypeMatcher>(FindNodeWithKind(NewOptionsToMatch[i],
- Matcher::CheckType));
+ Matcher* M = FindNodeWithKind(NewOptionsToMatch[i], Matcher::CheckType);
+ assert(M && isa<CheckTypeMatcher>(M) && "Unknown Matcher type");
+
+ auto *CTM = cast<CheckTypeMatcher>(M);
Matcher *MatcherWithoutCTM = NewOptionsToMatch[i]->unlinkNode(CTM);
MVT::SimpleValueType CTMTy = CTM->getType();
delete CTM;
-
+
unsigned &Entry = TypeEntry[CTMTy];
if (Entry != 0) {
// If we have unfactored duplicate types, then we should factor them.
diff --git a/utils/TableGen/DFAEmitter.cpp b/utils/TableGen/DFAEmitter.cpp
new file mode 100644
index 000000000000..dd3db7c150ba
--- /dev/null
+++ b/utils/TableGen/DFAEmitter.cpp
@@ -0,0 +1,394 @@
+//===- DFAEmitter.cpp - Finite state automaton emitter --------------------===//
+//
+// 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 class can produce a generic deterministic finite state automaton (DFA),
+// given a set of possible states and transitions.
+//
+// The input transitions can be nondeterministic - this class will produce the
+// deterministic equivalent state machine.
+//
+// The generated code can run the DFA and produce an accepted / not accepted
+// state and also produce, given a sequence of transitions that results in an
+// accepted state, the sequence of intermediate states. This is useful if the
+// initial automaton was nondeterministic - it allows mapping back from the DFA
+// to the NFA.
+//
+//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "dfa-emitter"
+
+#include "DFAEmitter.h"
+#include "CodeGenTarget.h"
+#include "SequenceToOffsetTable.h"
+#include "TableGenBackends.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/UniqueVector.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <cassert>
+#include <cstdint>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// DfaEmitter implementation. This is independent of the GenAutomaton backend.
+//===----------------------------------------------------------------------===//
+
+void DfaEmitter::addTransition(state_type From, state_type To, action_type A) {
+ Actions.insert(A);
+ NfaStates.insert(From);
+ NfaStates.insert(To);
+ NfaTransitions[{From, A}].push_back(To);
+ ++NumNfaTransitions;
+}
+
+void DfaEmitter::visitDfaState(DfaState DS) {
+ // For every possible action...
+ auto FromId = DfaStates.idFor(DS);
+ for (action_type A : Actions) {
+ DfaState NewStates;
+ DfaTransitionInfo TI;
+ // For every represented state, word pair in the original NFA...
+ for (state_type &FromState : DS) {
+ // If this action is possible from this state add the transitioned-to
+ // states to NewStates.
+ auto I = NfaTransitions.find({FromState, A});
+ if (I == NfaTransitions.end())
+ continue;
+ for (state_type &ToState : I->second) {
+ NewStates.push_back(ToState);
+ TI.emplace_back(FromState, ToState);
+ }
+ }
+ if (NewStates.empty())
+ continue;
+ // Sort and unique.
+ sort(NewStates);
+ NewStates.erase(std::unique(NewStates.begin(), NewStates.end()),
+ NewStates.end());
+ sort(TI);
+ TI.erase(std::unique(TI.begin(), TI.end()), TI.end());
+ unsigned ToId = DfaStates.insert(NewStates);
+ DfaTransitions.emplace(std::make_pair(FromId, A), std::make_pair(ToId, TI));
+ }
+}
+
+void DfaEmitter::constructDfa() {
+ DfaState Initial(1, /*NFA initial state=*/0);
+ DfaStates.insert(Initial);
+
+ // Note that UniqueVector starts indices at 1, not zero.
+ unsigned DfaStateId = 1;
+ while (DfaStateId <= DfaStates.size())
+ visitDfaState(DfaStates[DfaStateId++]);
+}
+
+void DfaEmitter::emit(StringRef Name, raw_ostream &OS) {
+ constructDfa();
+
+ OS << "// Input NFA has " << NfaStates.size() << " states with "
+ << NumNfaTransitions << " transitions.\n";
+ OS << "// Generated DFA has " << DfaStates.size() << " states with "
+ << DfaTransitions.size() << " transitions.\n\n";
+
+ // Implementation note: We don't bake a simple std::pair<> here as it requires
+ // significantly more effort to parse. A simple test with a large array of
+ // struct-pairs (N=100000) took clang-10 6s to parse. The same array of
+ // std::pair<uint64_t, uint64_t> took 242s. Instead we allow the user to
+ // define the pair type.
+ //
+ // FIXME: It may make sense to emit these as ULEB sequences instead of
+ // pairs of uint64_t.
+ OS << "// A zero-terminated sequence of NFA state transitions. Every DFA\n";
+ OS << "// transition implies a set of NFA transitions. These are referred\n";
+ OS << "// to by index in " << Name << "Transitions[].\n";
+
+ SequenceToOffsetTable<DfaTransitionInfo> Table;
+ std::map<DfaTransitionInfo, unsigned> EmittedIndices;
+ for (auto &T : DfaTransitions)
+ Table.add(T.second.second);
+ Table.layout();
+ OS << "std::array<NfaStatePair, " << Table.size() << "> " << Name
+ << "TransitionInfo = {{\n";
+ Table.emit(
+ OS,
+ [](raw_ostream &OS, std::pair<uint64_t, uint64_t> P) {
+ OS << "{" << P.first << ", " << P.second << "}";
+ },
+ "{0ULL, 0ULL}");
+
+ OS << "}};\n\n";
+
+ OS << "// A transition in the generated " << Name << " DFA.\n";
+ OS << "struct " << Name << "Transition {\n";
+ OS << " unsigned FromDfaState; // The transitioned-from DFA state.\n";
+ OS << " ";
+ printActionType(OS);
+ OS << " Action; // The input symbol that causes this transition.\n";
+ OS << " unsigned ToDfaState; // The transitioned-to DFA state.\n";
+ OS << " unsigned InfoIdx; // Start index into " << Name
+ << "TransitionInfo.\n";
+ OS << "};\n\n";
+
+ OS << "// A table of DFA transitions, ordered by {FromDfaState, Action}.\n";
+ OS << "// The initial state is 1, not zero.\n";
+ OS << "std::array<" << Name << "Transition, " << DfaTransitions.size() << "> "
+ << Name << "Transitions = {{\n";
+ for (auto &KV : DfaTransitions) {
+ dfa_state_type From = KV.first.first;
+ dfa_state_type To = KV.second.first;
+ action_type A = KV.first.second;
+ unsigned InfoIdx = Table.get(KV.second.second);
+ OS << " {" << From << ", ";
+ printActionValue(A, OS);
+ OS << ", " << To << ", " << InfoIdx << "},\n";
+ }
+ OS << "\n}};\n\n";
+}
+
+void DfaEmitter::printActionType(raw_ostream &OS) { OS << "uint64_t"; }
+
+void DfaEmitter::printActionValue(action_type A, raw_ostream &OS) { OS << A; }
+
+//===----------------------------------------------------------------------===//
+// AutomatonEmitter implementation
+//===----------------------------------------------------------------------===//
+
+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 = nullptr;
+
+ 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 ActionTuple = std::vector<Action>;
+class Automaton;
+
+class Transition {
+ uint64_t NewState;
+ // The tuple of actions that causes this transition.
+ ActionTuple Actions;
+ // The types of the actions; this is the same across all transitions.
+ SmallVector<std::string, 4> Types;
+
+public:
+ Transition(Record *R, Automaton *Parent);
+ const ActionTuple &getActions() { return Actions; }
+ SmallVector<std::string, 4> getTypes() { return Types; }
+
+ bool canTransitionFrom(uint64_t State);
+ uint64_t transitionFrom(uint64_t State);
+};
+
+class Automaton {
+ RecordKeeper &Records;
+ Record *R;
+ std::vector<Transition> Transitions;
+ /// All possible action tuples, uniqued.
+ UniqueVector<ActionTuple> Actions;
+ /// The fields within each Transition object to find the action symbols.
+ std::vector<StringRef> ActionSymbolFields;
+
+public:
+ Automaton(RecordKeeper &Records, Record *R);
+ void emit(raw_ostream &OS);
+
+ ArrayRef<StringRef> getActionSymbolFields() { return ActionSymbolFields; }
+ /// If the type of action A has been overridden (there exists a field
+ /// "TypeOf_A") return that, otherwise return the empty string.
+ StringRef getActionSymbolType(StringRef A);
+};
+
+class AutomatonEmitter {
+ RecordKeeper &Records;
+
+public:
+ AutomatonEmitter(RecordKeeper &R) : Records(R) {}
+ void run(raw_ostream &OS);
+};
+
+/// A DfaEmitter implementation that can print our variant action type.
+class CustomDfaEmitter : public DfaEmitter {
+ const UniqueVector<ActionTuple> &Actions;
+ std::string TypeName;
+
+public:
+ CustomDfaEmitter(const UniqueVector<ActionTuple> &Actions, StringRef TypeName)
+ : Actions(Actions), TypeName(TypeName) {}
+
+ void printActionType(raw_ostream &OS) override;
+ void printActionValue(action_type A, raw_ostream &OS) override;
+};
+} // namespace
+
+void AutomatonEmitter::run(raw_ostream &OS) {
+ for (Record *R : Records.getAllDerivedDefinitions("GenericAutomaton")) {
+ Automaton A(Records, R);
+ OS << "#ifdef GET_" << R->getName() << "_DECL\n";
+ A.emit(OS);
+ OS << "#endif // GET_" << R->getName() << "_DECL\n";
+ }
+}
+
+Automaton::Automaton(RecordKeeper &Records, Record *R)
+ : Records(Records), R(R) {
+ LLVM_DEBUG(dbgs() << "Emitting automaton for " << R->getName() << "\n");
+ ActionSymbolFields = R->getValueAsListOfStrings("SymbolFields");
+}
+
+void Automaton::emit(raw_ostream &OS) {
+ StringRef TransitionClass = R->getValueAsString("TransitionClass");
+ for (Record *T : Records.getAllDerivedDefinitions(TransitionClass)) {
+ assert(T->isSubClassOf("Transition"));
+ Transitions.emplace_back(T, this);
+ Actions.insert(Transitions.back().getActions());
+ }
+
+ LLVM_DEBUG(dbgs() << " Action alphabet cardinality: " << Actions.size()
+ << "\n");
+ LLVM_DEBUG(dbgs() << " Each state has " << Transitions.size()
+ << " potential transitions.\n");
+
+ StringRef Name = R->getName();
+
+ CustomDfaEmitter Emitter(Actions, std::string(Name) + "Action");
+ // Starting from the initial state, build up a list of possible states and
+ // transitions.
+ std::deque<uint64_t> Worklist(1, 0);
+ std::set<uint64_t> SeenStates;
+ unsigned NumTransitions = 0;
+ SeenStates.insert(Worklist.front());
+ while (!Worklist.empty()) {
+ uint64_t State = Worklist.front();
+ Worklist.pop_front();
+ for (Transition &T : Transitions) {
+ if (!T.canTransitionFrom(State))
+ continue;
+ uint64_t NewState = T.transitionFrom(State);
+ if (SeenStates.emplace(NewState).second)
+ Worklist.emplace_back(NewState);
+ ++NumTransitions;
+ Emitter.addTransition(State, NewState, Actions.idFor(T.getActions()));
+ }
+ }
+ LLVM_DEBUG(dbgs() << " NFA automaton has " << SeenStates.size()
+ << " states with " << NumTransitions << " transitions.\n");
+
+ const auto &ActionTypes = Transitions.back().getTypes();
+ OS << "// The type of an action in the " << Name << " automaton.\n";
+ if (ActionTypes.size() == 1) {
+ OS << "using " << Name << "Action = " << ActionTypes[0] << ";\n";
+ } else {
+ OS << "using " << Name << "Action = std::tuple<" << join(ActionTypes, ", ")
+ << ">;\n";
+ }
+ OS << "\n";
+
+ Emitter.emit(Name, OS);
+}
+
+StringRef Automaton::getActionSymbolType(StringRef A) {
+ Twine Ty = "TypeOf_" + A;
+ if (!R->getValue(Ty.str()))
+ return "";
+ return R->getValueAsString(Ty.str());
+}
+
+Transition::Transition(Record *R, Automaton *Parent) {
+ BitsInit *NewStateInit = R->getValueAsBitsInit("NewState");
+ NewState = 0;
+ assert(NewStateInit->getNumBits() <= sizeof(uint64_t) * 8 &&
+ "State cannot be represented in 64 bits!");
+ for (unsigned I = 0; I < NewStateInit->getNumBits(); ++I) {
+ if (auto *Bit = dyn_cast<BitInit>(NewStateInit->getBit(I))) {
+ if (Bit->getValue())
+ NewState |= 1ULL << I;
+ }
+ }
+
+ 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, "");
+ Types.emplace_back(Ty->getAsString());
+ } else if (isa<IntRecTy>(SymbolV->getType())) {
+ Actions.emplace_back(nullptr, R->getValueAsInt(A), "");
+ Types.emplace_back("unsigned");
+ } else if (isa<StringRecTy>(SymbolV->getType()) ||
+ isa<CodeRecTy>(SymbolV->getType())) {
+ Actions.emplace_back(nullptr, 0, R->getValueAsString(A));
+ Types.emplace_back("std::string");
+ } else {
+ report_fatal_error("Unhandled symbol type!");
+ }
+
+ StringRef TypeOverride = Parent->getActionSymbolType(A);
+ if (!TypeOverride.empty())
+ Types.back() = TypeOverride;
+ }
+}
+
+bool Transition::canTransitionFrom(uint64_t State) {
+ if ((State & NewState) == 0)
+ // The bits we want to set are not set;
+ return true;
+ return false;
+}
+
+uint64_t Transition::transitionFrom(uint64_t State) {
+ return State | NewState;
+}
+
+void CustomDfaEmitter::printActionType(raw_ostream &OS) { OS << TypeName; }
+
+void CustomDfaEmitter::printActionValue(action_type A, raw_ostream &OS) {
+ const ActionTuple &AT = Actions[A];
+ if (AT.size() > 1)
+ OS << "std::make_tuple(";
+ bool First = true;
+ for (const auto &SingleAction : AT) {
+ if (!First)
+ OS << ", ";
+ First = false;
+ SingleAction.print(OS);
+ }
+ if (AT.size() > 1)
+ OS << ")";
+}
+
+namespace llvm {
+
+void EmitAutomata(RecordKeeper &RK, raw_ostream &OS) {
+ AutomatonEmitter(RK).run(OS);
+}
+
+} // namespace llvm
diff --git a/utils/TableGen/DFAEmitter.h b/utils/TableGen/DFAEmitter.h
new file mode 100644
index 000000000000..76de8f72cd88
--- /dev/null
+++ b/utils/TableGen/DFAEmitter.h
@@ -0,0 +1,107 @@
+//===--------------------- DfaEmitter.h -----------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+// Defines a generic automaton builder. This takes a set of transitions and
+// states that represent a nondeterministic finite state automaton (NFA) and
+// emits a determinized DFA in a form that include/llvm/Support/Automaton.h can
+// drive.
+//
+// See file llvm/TableGen/Automaton.td for the TableGen API definition.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UTILS_TABLEGEN_DFAEMITTER_H
+#define LLVM_UTILS_TABLEGEN_DFAEMITTER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/UniqueVector.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Record.h"
+#include <set>
+#include <unordered_map>
+
+namespace llvm {
+
+class raw_ostream;
+/// Construct a deterministic finite state automaton from possible
+/// nondeterministic state and transition data.
+///
+/// The state type is a 64-bit unsigned integer. The generated automaton is
+/// invariant to the sparsity of the state representation - its size is only
+/// a function of the cardinality of the set of states.
+///
+/// The inputs to this emitter are considered to define a nondeterministic
+/// finite state automaton (NFA). This is then converted to a DFA during
+/// emission. The emitted tables can be used to by
+/// include/llvm/Support/Automaton.h.
+class DfaEmitter {
+public:
+ // The type of an NFA state. The initial state is always zero.
+ using state_type = uint64_t;
+ // The type of an action.
+ using action_type = uint64_t;
+
+ DfaEmitter() = default;
+ virtual ~DfaEmitter() = default;
+
+ void addTransition(state_type From, state_type To, action_type A);
+ void emit(StringRef Name, raw_ostream &OS);
+
+protected:
+ /// Emit the C++ type of an action to OS.
+ virtual void printActionType(raw_ostream &OS);
+ /// Emit the C++ value of an action A to OS.
+ virtual void printActionValue(action_type A, raw_ostream &OS);
+
+private:
+ /// The state type of deterministic states. These are only used internally to
+ /// this class. This is an ID into the DfaStates UniqueVector.
+ using dfa_state_type = unsigned;
+
+ /// The actual representation of a DFA state, which is a union of one or more
+ /// NFA states.
+ using DfaState = SmallVector<state_type, 4>;
+
+ /// A DFA transition consists of a set of NFA states transitioning to a
+ /// new set of NFA states. The DfaTransitionInfo tracks, for every
+ /// transitioned-from NFA state, a set of valid transitioned-to states.
+ ///
+ /// Emission of this transition relation allows algorithmic determination of
+ /// the possible candidate NFA paths taken under a given input sequence to
+ /// reach a given DFA state.
+ using DfaTransitionInfo = SmallVector<std::pair<state_type, state_type>, 4>;
+
+ /// The set of all possible actions.
+ std::set<action_type> Actions;
+
+ /// The set of nondeterministic transitions. A state-action pair can
+ /// transition to multiple target states.
+ std::map<std::pair<state_type, action_type>, std::vector<state_type>>
+ NfaTransitions;
+ std::set<state_type> NfaStates;
+ unsigned NumNfaTransitions = 0;
+
+ /// The set of deterministic states. DfaStates.getId(DfaState) returns an ID,
+ /// which is dfa_state_type. Note that because UniqueVector reserves state
+ /// zero, the initial DFA state is always 1.
+ UniqueVector<DfaState> DfaStates;
+ /// The set of deterministic transitions. A state-action pair has only a
+ /// single target state.
+ std::map<std::pair<dfa_state_type, action_type>,
+ std::pair<dfa_state_type, DfaTransitionInfo>>
+ DfaTransitions;
+
+ /// Visit all NFA states and construct the DFA.
+ void constructDfa();
+ /// Visit a single DFA state and construct all possible transitions to new DFA
+ /// states.
+ void visitDfaState(DfaState DS);
+};
+
+} // namespace llvm
+
+#endif
diff --git a/utils/TableGen/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp
index dabcc8f8ed55..ccb4ef1b9678 100644
--- a/utils/TableGen/DFAPacketizerEmitter.cpp
+++ b/utils/TableGen/DFAPacketizerEmitter.cpp
@@ -17,6 +17,7 @@
#define DEBUG_TYPE "dfa-emitter"
#include "CodeGenTarget.h"
+#include "DFAEmitter.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -29,6 +30,7 @@
#include <map>
#include <set>
#include <string>
+#include <unordered_map>
#include <vector>
using namespace llvm;
@@ -154,121 +156,13 @@ public:
int &maxStages,
raw_ostream &OS);
- void run(raw_ostream &OS);
-};
-
-//
-// State represents the usage of machine resources if the packet contains
-// a set of instruction classes.
-//
-// Specifically, currentState is a set of bit-masks.
-// The nth bit in a bit-mask indicates whether the nth resource is being used
-// by this state. The set of bit-masks in a state represent the different
-// possible outcomes of transitioning to this state.
-// For example: consider a two resource architecture: resource L and resource M
-// with three instruction classes: L, M, and L_or_M.
-// From the initial state (currentState = 0x00), if we add instruction class
-// L_or_M we will transition to a state with currentState = [0x01, 0x10]. This
-// represents the possible resource states that can result from adding a L_or_M
-// instruction
-//
-// Another way of thinking about this transition is we are mapping a NDFA with
-// two states [0x01] and [0x10] into a DFA with a single state [0x01, 0x10].
-//
-// A State instance also contains a collection of transitions from that state:
-// a map from inputs to new states.
-//
-class State {
- public:
- static int currentStateNum;
- // stateNum is the only member used for equality/ordering, all other members
- // can be mutated even in const State objects.
- const int stateNum;
- mutable bool isInitial;
- mutable std::set<unsigned> stateInfo;
- typedef std::map<std::vector<unsigned>, const State *> TransitionMap;
- mutable TransitionMap Transitions;
-
- State();
-
- bool operator<(const State &s) const {
- return stateNum < s.stateNum;
- }
-
- //
- // canMaybeAddInsnClass - Quickly verifies if an instruction of type InsnClass
- // may be a valid transition from this state i.e., can an instruction of type
- // InsnClass be added to the packet represented by this state.
- //
- // Note that for multiple stages, this quick check does not take into account
- // any possible resource competition between the stages themselves. That is
- // enforced in AddInsnClassStages which checks the cross product of all
- // stages for resource availability (which is a more involved check).
- //
- bool canMaybeAddInsnClass(std::vector<unsigned> &InsnClass,
- std::map<unsigned, unsigned> &ComboBitToBitsMap) const;
-
- //
- // AddInsnClass - Return all combinations of resource reservation
- // which are possible from this state (PossibleStates).
- //
- // PossibleStates is the set of valid resource states that ensue from valid
- // transitions.
- //
- void AddInsnClass(std::vector<unsigned> &InsnClass,
- std::map<unsigned, unsigned> &ComboBitToBitsMap,
- std::set<unsigned> &PossibleStates) const;
-
- //
- // AddInsnClassStages - Return all combinations of resource reservation
- // resulting from the cross product of all stages for this InsnClass
- // which are possible from this state (PossibleStates).
- //
- void AddInsnClassStages(std::vector<unsigned> &InsnClass,
- std::map<unsigned, unsigned> &ComboBitToBitsMap,
- unsigned chkstage, unsigned numstages,
- unsigned prevState, unsigned origState,
- DenseSet<unsigned> &VisitedResourceStates,
- std::set<unsigned> &PossibleStates) const;
-
- //
- // addTransition - Add a transition from this state given the input InsnClass
- //
- void addTransition(std::vector<unsigned> InsnClass, const State *To) const;
-
- //
- // hasTransition - Returns true if there is a transition from this state
- // given the input InsnClass
- //
- bool hasTransition(std::vector<unsigned> InsnClass) const;
-};
-
-//
-// class DFA: deterministic finite automaton for processor resource tracking.
-//
-class DFA {
-public:
- DFA() = default;
-
- // Set of states. Need to keep this sorted to emit the transition table.
- typedef std::set<State> StateSet;
- StateSet states;
+ // Emit code for a subset of itineraries.
+ void emitForItineraries(raw_ostream &OS,
+ std::vector<Record *> &ProcItinList,
+ std::string DFAName);
- State *currentState = nullptr;
-
- //
- // Modify the DFA.
- //
- const State &newState();
-
- //
- // writeTable: Print out a table representing the DFA.
- //
- void writeTableAndAPI(raw_ostream &OS, const std::string &ClassName,
- int numInsnClasses = 0,
- int maxResources = 0, int numCombos = 0, int maxStages = 0);
+ void run(raw_ostream &OS);
};
-
} // end anonymous namespace
#ifndef NDEBUG
@@ -289,22 +183,6 @@ void dbgsInsnClass(const std::vector<unsigned> &InsnClass) {
}
//
-// dbgsStateInfo - When debugging, print the set of state info.
-//
-void dbgsStateInfo(const std::set<unsigned> &stateInfo) {
- LLVM_DEBUG(dbgs() << "StateInfo: ");
- unsigned i = 0;
- for (std::set<unsigned>::iterator SI = stateInfo.begin();
- SI != stateInfo.end(); ++SI, ++i) {
- unsigned thisState = *SI;
- if (i > 0) {
- LLVM_DEBUG(dbgs() << ", ");
- }
- LLVM_DEBUG(dbgs() << "0x" << Twine::utohexstr(thisState));
- }
-}
-
-//
// dbgsIndent - When debugging, indent by the specified amount.
//
void dbgsIndent(unsigned indent) {
@@ -314,336 +192,10 @@ void dbgsIndent(unsigned indent) {
}
#endif // NDEBUG
-//
-// Constructors and destructors for State and DFA
-//
-State::State() :
- stateNum(currentStateNum++), isInitial(false) {}
-
-//
-// addTransition - Add a transition from this state given the input InsnClass
-//
-void State::addTransition(std::vector<unsigned> InsnClass, const State *To)
- const {
- assert(!Transitions.count(InsnClass) &&
- "Cannot have multiple transitions for the same input");
- Transitions[InsnClass] = To;
-}
-
-//
-// hasTransition - Returns true if there is a transition from this state
-// given the input InsnClass
-//
-bool State::hasTransition(std::vector<unsigned> InsnClass) const {
- return Transitions.count(InsnClass) > 0;
-}
-
-//
-// AddInsnClass - Return all combinations of resource reservation
-// which are possible from this state (PossibleStates).
-//
-// PossibleStates is the set of valid resource states that ensue from valid
-// transitions.
-//
-void State::AddInsnClass(std::vector<unsigned> &InsnClass,
- std::map<unsigned, unsigned> &ComboBitToBitsMap,
- std::set<unsigned> &PossibleStates) const {
- //
- // Iterate over all resource states in currentState.
- //
- unsigned numstages = InsnClass.size();
- assert((numstages > 0) && "InsnClass has no stages");
-
- for (std::set<unsigned>::iterator SI = stateInfo.begin();
- SI != stateInfo.end(); ++SI) {
- unsigned thisState = *SI;
-
- DenseSet<unsigned> VisitedResourceStates;
-
- LLVM_DEBUG(dbgs() << " thisState: 0x" << Twine::utohexstr(thisState)
- << "\n");
- AddInsnClassStages(InsnClass, ComboBitToBitsMap,
- numstages - 1, numstages,
- thisState, thisState,
- VisitedResourceStates, PossibleStates);
- }
-}
-
-void State::AddInsnClassStages(std::vector<unsigned> &InsnClass,
- std::map<unsigned, unsigned> &ComboBitToBitsMap,
- unsigned chkstage, unsigned numstages,
- unsigned prevState, unsigned origState,
- DenseSet<unsigned> &VisitedResourceStates,
- std::set<unsigned> &PossibleStates) const {
- assert((chkstage < numstages) && "AddInsnClassStages: stage out of range");
- unsigned thisStage = InsnClass[chkstage];
-
- LLVM_DEBUG({
- dbgsIndent((1 + numstages - chkstage) << 1);
- dbgs() << "AddInsnClassStages " << chkstage << " (0x"
- << Twine::utohexstr(thisStage) << ") from ";
- dbgsInsnClass(InsnClass);
- dbgs() << "\n";
- });
-
- //
- // Iterate over all possible resources used in thisStage.
- // For ex: for thisStage = 0x11, all resources = {0x01, 0x10}.
- //
- for (unsigned int j = 0; j < DFA_MAX_RESOURCES; ++j) {
- unsigned resourceMask = (0x1 << j);
- if (resourceMask & thisStage) {
- unsigned combo = ComboBitToBitsMap[resourceMask];
- if (combo && ((~prevState & combo) != combo)) {
- LLVM_DEBUG(dbgs() << "\tSkipped Add 0x" << Twine::utohexstr(prevState)
- << " - combo op 0x" << Twine::utohexstr(resourceMask)
- << " (0x" << Twine::utohexstr(combo)
- << ") cannot be scheduled\n");
- continue;
- }
- //
- // For each possible resource used in thisStage, generate the
- // resource state if that resource was used.
- //
- unsigned ResultingResourceState = prevState | resourceMask | combo;
- LLVM_DEBUG({
- dbgsIndent((2 + numstages - chkstage) << 1);
- dbgs() << "0x" << Twine::utohexstr(prevState) << " | 0x"
- << Twine::utohexstr(resourceMask);
- if (combo)
- dbgs() << " | 0x" << Twine::utohexstr(combo);
- dbgs() << " = 0x" << Twine::utohexstr(ResultingResourceState) << " ";
- });
-
- //
- // If this is the final stage for this class
- //
- if (chkstage == 0) {
- //
- // Check if the resulting resource state can be accommodated in this
- // packet.
- // We compute resource OR prevState (originally started as origState).
- // If the result of the OR is different than origState, it implies
- // that there is at least one resource that can be used to schedule
- // thisStage in the current packet.
- // Insert ResultingResourceState into PossibleStates only if we haven't
- // processed ResultingResourceState before.
- //
- if (ResultingResourceState != prevState) {
- if (VisitedResourceStates.count(ResultingResourceState) == 0) {
- VisitedResourceStates.insert(ResultingResourceState);
- PossibleStates.insert(ResultingResourceState);
- LLVM_DEBUG(dbgs()
- << "\tResultingResourceState: 0x"
- << Twine::utohexstr(ResultingResourceState) << "\n");
- } else {
- LLVM_DEBUG(dbgs() << "\tSkipped Add - state already seen\n");
- }
- } else {
- LLVM_DEBUG(dbgs()
- << "\tSkipped Add - no final resources available\n");
- }
- } else {
- //
- // If the current resource can be accommodated, check the next
- // stage in InsnClass for available resources.
- //
- if (ResultingResourceState != prevState) {
- LLVM_DEBUG(dbgs() << "\n");
- AddInsnClassStages(InsnClass, ComboBitToBitsMap,
- chkstage - 1, numstages,
- ResultingResourceState, origState,
- VisitedResourceStates, PossibleStates);
- } else {
- LLVM_DEBUG(dbgs() << "\tSkipped Add - no resources available\n");
- }
- }
- }
- }
-}
-
-//
-// canMaybeAddInsnClass - Quickly verifies if an instruction of type InsnClass
-// may be a valid transition from this state i.e., can an instruction of type
-// InsnClass be added to the packet represented by this state.
-//
-// Note that this routine is performing conservative checks that can be
-// quickly executed acting as a filter before calling AddInsnClassStages.
-// Any cases allowed through here will be caught later in AddInsnClassStages
-// which performs the more expensive exact check.
-//
-bool State::canMaybeAddInsnClass(std::vector<unsigned> &InsnClass,
- std::map<unsigned, unsigned> &ComboBitToBitsMap) const {
- for (std::set<unsigned>::const_iterator SI = stateInfo.begin();
- SI != stateInfo.end(); ++SI) {
- // Check to see if all required resources are available.
- bool available = true;
-
- // Inspect each stage independently.
- // note: This is a conservative check as we aren't checking for
- // possible resource competition between the stages themselves
- // The full cross product is examined later in AddInsnClass.
- for (unsigned i = 0; i < InsnClass.size(); ++i) {
- unsigned resources = *SI;
- if ((~resources & InsnClass[i]) == 0) {
- available = false;
- break;
- }
- // Make sure _all_ resources for a combo function are available.
- // note: This is a quick conservative check as it won't catch an
- // unscheduleable combo if this stage is an OR expression
- // containing a combo.
- // These cases are caught later in AddInsnClass.
- unsigned combo = ComboBitToBitsMap[InsnClass[i]];
- if (combo && ((~resources & combo) != combo)) {
- LLVM_DEBUG(dbgs() << "\tSkipped canMaybeAdd 0x"
- << Twine::utohexstr(resources) << " - combo op 0x"
- << Twine::utohexstr(InsnClass[i]) << " (0x"
- << Twine::utohexstr(combo)
- << ") cannot be scheduled\n");
- available = false;
- break;
- }
- }
-
- if (available) {
- return true;
- }
- }
- return false;
-}
-
-const State &DFA::newState() {
- auto IterPair = states.insert(State());
- assert(IterPair.second && "State already exists");
- return *IterPair.first;
-}
-
-int State::currentStateNum = 0;
-
DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R):
TargetName(CodeGenTarget(R).getName()), Records(R) {}
//
-// writeTableAndAPI - Print out a table representing the DFA and the
-// associated API to create a DFA packetizer.
-//
-// Format:
-// DFAStateInputTable[][2] = pairs of <Input, Transition> for all valid
-// transitions.
-// DFAStateEntryTable[i] = Index of the first entry in DFAStateInputTable for
-// the ith state.
-//
-//
-void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName,
- int numInsnClasses,
- int maxResources, int numCombos, int maxStages) {
- unsigned numStates = states.size();
-
- LLVM_DEBUG(dbgs() << "-------------------------------------------------------"
- "----------------------\n");
- LLVM_DEBUG(dbgs() << "writeTableAndAPI\n");
- LLVM_DEBUG(dbgs() << "Total states: " << numStates << "\n");
-
- OS << "namespace llvm {\n";
-
- OS << "\n// Input format:\n";
- OS << "#define DFA_MAX_RESTERMS " << DFA_MAX_RESTERMS
- << "\t// maximum AND'ed resource terms\n";
- OS << "#define DFA_MAX_RESOURCES " << DFA_MAX_RESOURCES
- << "\t// maximum resource bits in one term\n";
-
- OS << "\n// " << TargetName << "DFAStateInputTable[][2] = "
- << "pairs of <Input, NextState> for all valid\n";
- OS << "// transitions.\n";
- OS << "// " << numStates << "\tstates\n";
- OS << "// " << numInsnClasses << "\tinstruction classes\n";
- OS << "// " << maxResources << "\tresources max\n";
- OS << "// " << numCombos << "\tcombo resources\n";
- OS << "// " << maxStages << "\tstages max\n";
- OS << "const " << DFA_TBLTYPE << " "
- << TargetName << "DFAStateInputTable[][2] = {\n";
-
- // This table provides a map to the beginning of the transitions for State s
- // in DFAStateInputTable.
- std::vector<int> StateEntry(numStates+1);
- static const std::string SentinelEntry = "{-1, -1}";
-
- // Tracks the total valid transitions encountered so far. It is used
- // to construct the StateEntry table.
- int ValidTransitions = 0;
- DFA::StateSet::iterator SI = states.begin();
- for (unsigned i = 0; i < numStates; ++i, ++SI) {
- assert ((SI->stateNum == (int) i) && "Mismatch in state numbers");
- StateEntry[i] = ValidTransitions;
- for (State::TransitionMap::iterator
- II = SI->Transitions.begin(), IE = SI->Transitions.end();
- II != IE; ++II) {
- OS << "{0x" << Twine::utohexstr(getDFAInsnInput(II->first)) << ", "
- << II->second->stateNum << "},\t";
- }
- ValidTransitions += SI->Transitions.size();
-
- // If there are no valid transitions from this stage, we need a sentinel
- // transition.
- if (ValidTransitions == StateEntry[i]) {
- OS << SentinelEntry << ",\t";
- ++ValidTransitions;
- }
-
- OS << " // state " << i << ": " << StateEntry[i];
- if (StateEntry[i] != (ValidTransitions-1)) { // More than one transition.
- OS << "-" << (ValidTransitions-1);
- }
- OS << "\n";
- }
-
- // Print out a sentinel entry at the end of the StateInputTable. This is
- // needed to iterate over StateInputTable in DFAPacketizer::ReadTable()
- OS << SentinelEntry << "\t";
- OS << " // state " << numStates << ": " << ValidTransitions;
- OS << "\n";
-
- OS << "};\n\n";
- OS << "// " << TargetName << "DFAStateEntryTable[i] = "
- << "Index of the first entry in DFAStateInputTable for\n";
- OS << "// "
- << "the ith state.\n";
- OS << "// " << numStates << " states\n";
- OS << "const unsigned int " << TargetName << "DFAStateEntryTable[] = {\n";
-
- // Multiply i by 2 since each entry in DFAStateInputTable is a set of
- // two numbers.
- unsigned lastState = 0;
- for (unsigned i = 0; i < numStates; ++i) {
- if (i && ((i % 10) == 0)) {
- lastState = i-1;
- OS << " // states " << (i-10) << ":" << lastState << "\n";
- }
- OS << StateEntry[i] << ", ";
- }
-
- // Print out the index to the sentinel entry in StateInputTable
- OS << ValidTransitions << ", ";
- OS << " // states " << (lastState+1) << ":" << numStates << "\n";
-
- OS << "};\n";
- OS << "} // namespace\n";
-
- //
- // Emit DFA Packetizer tables if the target is a VLIW machine.
- //
- std::string SubTargetClassName = TargetName + "GenSubtargetInfo";
- OS << "\n" << "#include \"llvm/CodeGen/DFAPacketizer.h\"\n";
- OS << "namespace llvm {\n";
- OS << "DFAPacketizer *" << SubTargetClassName << "::"
- << "createDFAPacketizer(const InstrItineraryData *IID) const {\n"
- << " return new DFAPacketizer(IID, " << TargetName
- << "DFAStateInputTable, " << TargetName << "DFAStateEntryTable);\n}\n\n";
- OS << "} // End llvm namespace \n";
-}
-
-//
// collectAllFuncUnits - Construct a map of function unit names to bits.
//
int DFAPacketizerEmitter::collectAllFuncUnits(
@@ -837,10 +389,32 @@ int DFAPacketizerEmitter::collectAllInsnClasses(const std::string &ProcName,
// Run the worklist algorithm to generate the DFA.
//
void DFAPacketizerEmitter::run(raw_ostream &OS) {
+ OS << "\n"
+ << "#include \"llvm/CodeGen/DFAPacketizer.h\"\n";
+ OS << "namespace llvm {\n";
+
+ OS << "\n// Input format:\n";
+ OS << "#define DFA_MAX_RESTERMS " << DFA_MAX_RESTERMS
+ << "\t// maximum AND'ed resource terms\n";
+ OS << "#define DFA_MAX_RESOURCES " << DFA_MAX_RESOURCES
+ << "\t// maximum resource bits in one term\n";
+
// Collect processor iteraries.
std::vector<Record*> ProcItinList =
Records.getAllDerivedDefinitions("ProcessorItineraries");
+ std::unordered_map<std::string, std::vector<Record*>> ItinsByNamespace;
+ for (Record *R : ProcItinList)
+ ItinsByNamespace[R->getValueAsString("PacketizerNamespace")].push_back(R);
+
+ for (auto &KV : ItinsByNamespace)
+ emitForItineraries(OS, KV.second, KV.first);
+ OS << "} // end namespace llvm\n";
+}
+
+void DFAPacketizerEmitter::emitForItineraries(
+ raw_ostream &OS, std::vector<Record *> &ProcItinList,
+ std::string DFAName) {
//
// Collect the Functional units.
//
@@ -855,8 +429,7 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) {
std::map<unsigned, unsigned> ComboBitToBitsMap;
std::vector<Record*> ComboFuncList =
Records.getAllDerivedDefinitions("ComboFuncUnits");
- int numCombos = collectAllComboFuncs(ComboFuncList,
- FUNameToBitsMap, ComboBitToBitsMap, OS);
+ collectAllComboFuncs(ComboFuncList, FUNameToBitsMap, ComboBitToBitsMap, OS);
//
// Collect the itineraries.
@@ -887,103 +460,89 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) {
FUNameToBitsMap, ItinDataList, maxStages, OS);
}
- //
- // Run a worklist algorithm to generate the DFA.
- //
- DFA D;
- const State *Initial = &D.newState();
- Initial->isInitial = true;
- Initial->stateInfo.insert(0x0);
- SmallVector<const State*, 32> WorkList;
- std::map<std::set<unsigned>, const State*> Visited;
-
- WorkList.push_back(Initial);
-
- //
- // Worklist algorithm to create a DFA for processor resource tracking.
- // C = {set of InsnClasses}
- // Begin with initial node in worklist. Initial node does not have
- // any consumed resources,
- // ResourceState = 0x0
- // Visited = {}
- // While worklist != empty
- // S = first element of worklist
- // For every instruction class C
- // if we can accommodate C in S:
- // S' = state with resource states = {S Union C}
- // Add a new transition: S x C -> S'
- // If S' is not in Visited:
- // Add S' to worklist
- // Add S' to Visited
- //
- while (!WorkList.empty()) {
- const State *current = WorkList.pop_back_val();
- LLVM_DEBUG({
- dbgs() << "---------------------\n";
- dbgs() << "Processing state: " << current->stateNum << " - ";
- dbgsStateInfo(current->stateInfo);
- dbgs() << "\n";
- });
- for (unsigned i = 0; i < allInsnClasses.size(); i++) {
- std::vector<unsigned> InsnClass = allInsnClasses[i];
- LLVM_DEBUG({
- dbgs() << i << " ";
- dbgsInsnClass(InsnClass);
- dbgs() << "\n";
- });
-
- std::set<unsigned> NewStateResources;
- //
- // If we haven't already created a transition for this input
- // and the state can accommodate this InsnClass, create a transition.
- //
- if (!current->hasTransition(InsnClass) &&
- current->canMaybeAddInsnClass(InsnClass, ComboBitToBitsMap)) {
- const State *NewState = nullptr;
- current->AddInsnClass(InsnClass, ComboBitToBitsMap, NewStateResources);
- if (NewStateResources.empty()) {
- LLVM_DEBUG(dbgs() << " Skipped - no new states generated\n");
- continue;
- }
-
- LLVM_DEBUG({
- dbgs() << "\t";
- dbgsStateInfo(NewStateResources);
- dbgs() << "\n";
- });
-
- //
- // If we have seen this state before, then do not create a new state.
- //
- auto VI = Visited.find(NewStateResources);
- if (VI != Visited.end()) {
- NewState = VI->second;
- LLVM_DEBUG({
- dbgs() << "\tFound existing state: " << NewState->stateNum
- << " - ";
- dbgsStateInfo(NewState->stateInfo);
- dbgs() << "\n";
- });
- } else {
- NewState = &D.newState();
- NewState->stateInfo = NewStateResources;
- Visited[NewStateResources] = NewState;
- WorkList.push_back(NewState);
- LLVM_DEBUG({
- dbgs() << "\tAccepted new state: " << NewState->stateNum << " - ";
- dbgsStateInfo(NewState->stateInfo);
- dbgs() << "\n";
- });
+ // The type of a state in the nondeterministic automaton we're defining.
+ using NfaStateTy = unsigned;
+
+ // Given a resource state, return all resource states by applying
+ // InsnClass.
+ auto applyInsnClass = [&](ArrayRef<unsigned> InsnClass,
+ NfaStateTy State) -> std::deque<unsigned> {
+ std::deque<unsigned> V(1, State);
+ // Apply every stage in the class individually.
+ for (unsigned Stage : InsnClass) {
+ // Apply this stage to every existing member of V in turn.
+ size_t Sz = V.size();
+ for (unsigned I = 0; I < Sz; ++I) {
+ unsigned S = V.front();
+ V.pop_front();
+
+ // For this stage, state combination, try all possible resources.
+ for (unsigned J = 0; J < DFA_MAX_RESOURCES; ++J) {
+ unsigned ResourceMask = 1U << J;
+ if ((ResourceMask & Stage) == 0)
+ // This resource isn't required by this stage.
+ continue;
+ unsigned Combo = ComboBitToBitsMap[ResourceMask];
+ if (Combo && ((~S & Combo) != Combo))
+ // This combo units bits are not available.
+ continue;
+ unsigned ResultingResourceState = S | ResourceMask | Combo;
+ if (ResultingResourceState == S)
+ continue;
+ V.push_back(ResultingResourceState);
}
-
- current->addTransition(InsnClass, NewState);
+ }
+ }
+ return V;
+ };
+
+ // Given a resource state, return a quick (conservative) guess as to whether
+ // InsnClass can be applied. This is a filter for the more heavyweight
+ // applyInsnClass.
+ auto canApplyInsnClass = [](ArrayRef<unsigned> InsnClass,
+ NfaStateTy State) -> bool {
+ for (unsigned Resources : InsnClass) {
+ if ((State | Resources) == State)
+ return false;
+ }
+ return true;
+ };
+
+ DfaEmitter Emitter;
+ std::deque<NfaStateTy> Worklist(1, 0);
+ std::set<NfaStateTy> SeenStates;
+ SeenStates.insert(Worklist.front());
+ while (!Worklist.empty()) {
+ NfaStateTy State = Worklist.front();
+ Worklist.pop_front();
+ for (unsigned i = 0; i < allInsnClasses.size(); i++) {
+ const std::vector<unsigned> &InsnClass = allInsnClasses[i];
+ if (!canApplyInsnClass(InsnClass, State))
+ continue;
+ for (unsigned NewState : applyInsnClass(InsnClass, State)) {
+ if (SeenStates.emplace(NewState).second)
+ Worklist.emplace_back(NewState);
+ Emitter.addTransition(State, NewState, getDFAInsnInput(InsnClass));
}
}
}
- // Print out the table.
- D.writeTableAndAPI(OS, TargetName,
- numInsnClasses, maxResources, numCombos, maxStages);
+ OS << "} // end namespace llvm\n\n";
+ OS << "namespace {\n";
+ std::string TargetAndDFAName = TargetName + DFAName;
+ Emitter.emit(TargetAndDFAName, OS);
+ OS << "} // end anonymous namespace\n\n";
+
+ std::string SubTargetClassName = TargetName + "GenSubtargetInfo";
+ OS << "namespace llvm {\n";
+ OS << "DFAPacketizer *" << SubTargetClassName << "::"
+ << "create" << DFAName
+ << "DFAPacketizer(const InstrItineraryData *IID) const {\n"
+ << " static Automaton<uint64_t> A(ArrayRef<" << TargetAndDFAName
+ << "Transition>(" << TargetAndDFAName << "Transitions), "
+ << TargetAndDFAName << "TransitionInfo);\n"
+ << " return new DFAPacketizer(IID, A);\n"
+ << "\n}\n\n";
}
namespace llvm {
diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp
index 9e75c7fba77b..0002b0e14db6 100644
--- a/utils/TableGen/DisassemblerEmitter.cpp
+++ b/utils/TableGen/DisassemblerEmitter.cpp
@@ -153,4 +153,4 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
"MCDisassembler::Success", "MCDisassembler::Fail", "");
}
-} // End llvm namespace
+} // end namespace llvm
diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp
index f5e975d2e5ae..ac69b431607d 100644
--- a/utils/TableGen/FixedLenDecoderEmitter.cpp
+++ b/utils/TableGen/FixedLenDecoderEmitter.cpp
@@ -13,6 +13,7 @@
#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
+#include "InfoByHwMode.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/CachedHashString.h"
@@ -64,9 +65,10 @@ struct OperandInfo {
std::vector<EncodingField> Fields;
std::string Decoder;
bool HasCompleteDecoder;
+ uint64_t InitValue;
OperandInfo(std::string D, bool HCD)
- : Decoder(std::move(D)), HasCompleteDecoder(HCD) {}
+ : Decoder(std::move(D)), HasCompleteDecoder(HCD), InitValue(0) {}
void addField(unsigned Base, unsigned Width, unsigned Offset) {
Fields.push_back(EncodingField(Base, Width, Offset));
@@ -96,9 +98,11 @@ struct DecoderTableInfo {
struct EncodingAndInst {
const Record *EncodingDef;
const CodeGenInstruction *Inst;
+ StringRef HwModeName;
- EncodingAndInst(const Record *EncodingDef, const CodeGenInstruction *Inst)
- : EncodingDef(EncodingDef), Inst(Inst) {}
+ EncodingAndInst(const Record *EncodingDef, const CodeGenInstruction *Inst,
+ StringRef HwModeName = "")
+ : EncodingDef(EncodingDef), Inst(Inst), HwModeName(HwModeName) {}
};
struct EncodingIDAndOpcode {
@@ -599,7 +603,7 @@ void Filter::recurse() {
// Delegates to an inferior filter chooser for further processing on this
// group of instructions whose segment values are variable.
FilterChooserMap.insert(
- std::make_pair(-1U, llvm::make_unique<FilterChooser>(
+ std::make_pair(-1U, std::make_unique<FilterChooser>(
Owner->AllInstructions, VariableInstructions,
Owner->Operands, BitValueArray, *Owner)));
}
@@ -625,7 +629,7 @@ void Filter::recurse() {
// Delegates to an inferior filter chooser for further processing on this
// category of instructions.
FilterChooserMap.insert(std::make_pair(
- Inst.first, llvm::make_unique<FilterChooser>(
+ Inst.first, std::make_unique<FilterChooser>(
Owner->AllInstructions, Inst.second,
Owner->Operands, BitValueArray, *Owner)));
}
@@ -1103,12 +1107,15 @@ void FilterChooser::emitBinaryParser(raw_ostream &o, unsigned &Indentation,
bool &OpHasCompleteDecoder) const {
const std::string &Decoder = OpInfo.Decoder;
- if (OpInfo.numFields() != 1)
- o.indent(Indentation) << "tmp = 0;\n";
+ if (OpInfo.numFields() != 1 || OpInfo.InitValue != 0) {
+ o.indent(Indentation) << "tmp = 0x";
+ o.write_hex(OpInfo.InitValue);
+ o << ";\n";
+ }
for (const EncodingField &EF : OpInfo) {
o.indent(Indentation) << "tmp ";
- if (OpInfo.numFields() != 1) o << '|';
+ if (OpInfo.numFields() != 1 || OpInfo.InitValue != 0) o << '|';
o << "= fieldFromInstruction"
<< "(insn, " << EF.Base << ", " << EF.Width << ')';
if (OpInfo.numFields() != 1 || EF.Offset != 0)
@@ -2026,6 +2033,16 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
HasCompleteDecoderBit->getValue() : true;
OperandInfo OpInfo(Decoder, HasCompleteDecoder);
+
+ // 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;
@@ -2368,12 +2385,50 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) {
Target.reverseBitsForLittleEndianEncoding();
// Parameterize the decoders based on namespace and instruction width.
+ std::set<StringRef> HwModeNames;
const auto &NumberedInstructions = Target.getInstructionsByEnumValue();
NumberedEncodings.reserve(NumberedInstructions.size());
DenseMap<Record *, unsigned> IndexOfInstruction;
+ // First, collect all HwModes referenced by the target.
for (const auto &NumberedInstruction : NumberedInstructions) {
IndexOfInstruction[NumberedInstruction->TheDef] = NumberedEncodings.size();
- NumberedEncodings.emplace_back(NumberedInstruction->TheDef, NumberedInstruction);
+
+ if (const RecordVal *RV =
+ NumberedInstruction->TheDef->getValue("EncodingInfos")) {
+ if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
+ const CodeGenHwModes &HWM = Target.getHwModes();
+ EncodingInfoByHwMode EBM(DI->getDef(), HWM);
+ for (auto &KV : EBM.Map)
+ HwModeNames.insert(HWM.getMode(KV.first).Name);
+ }
+ }
+ }
+
+ // If HwModeNames is empty, add the empty string so we always have one HwMode.
+ if (HwModeNames.empty())
+ HwModeNames.insert("");
+
+ for (const auto &NumberedInstruction : NumberedInstructions) {
+ IndexOfInstruction[NumberedInstruction->TheDef] = NumberedEncodings.size();
+
+ if (const RecordVal *RV =
+ NumberedInstruction->TheDef->getValue("EncodingInfos")) {
+ if (DefInit *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
+ const CodeGenHwModes &HWM = Target.getHwModes();
+ EncodingInfoByHwMode EBM(DI->getDef(), HWM);
+ for (auto &KV : EBM.Map) {
+ NumberedEncodings.emplace_back(KV.second, NumberedInstruction,
+ HWM.getMode(KV.first).Name);
+ HwModeNames.insert(HWM.getMode(KV.first).Name);
+ }
+ continue;
+ }
+ }
+ // This instruction is encoded the same on all HwModes. Emit it for all
+ // HwModes.
+ for (StringRef HwModeName : HwModeNames)
+ NumberedEncodings.emplace_back(NumberedInstruction->TheDef,
+ NumberedInstruction, HwModeName);
}
for (const auto &NumberedAlias : RK.getAllDerivedDefinitions("AdditionalEncoding"))
NumberedEncodings.emplace_back(
@@ -2401,13 +2456,19 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) {
NumInstructions++;
NumEncodings++;
- StringRef DecoderNamespace = EncodingDef->getValueAsString("DecoderNamespace");
+ if (!Size)
+ continue;
- if (Size) {
- if (populateInstruction(Target, *EncodingDef, *Inst, i, Operands)) {
- OpcMap[std::make_pair(DecoderNamespace, Size)].emplace_back(i, IndexOfInstruction.find(Def)->second);
- } else
- NumEncodingsOmitted++;
+ if (populateInstruction(Target, *EncodingDef, *Inst, i, Operands)) {
+ std::string DecoderNamespace =
+ EncodingDef->getValueAsString("DecoderNamespace");
+ if (!NumberedEncodings[i].HwModeName.empty())
+ DecoderNamespace +=
+ std::string("_") + NumberedEncodings[i].HwModeName.str();
+ OpcMap[std::make_pair(DecoderNamespace, Size)].emplace_back(
+ i, IndexOfInstruction.find(Def)->second);
+ } else {
+ NumEncodingsOmitted++;
}
}
@@ -2451,7 +2512,7 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) {
// Emit the main entry point for the decoder, decodeInstruction().
emitDecodeInstruction(OS);
- OS << "\n} // End llvm namespace\n";
+ OS << "\n} // end namespace llvm\n";
}
namespace llvm {
diff --git a/utils/TableGen/GICombinerEmitter.cpp b/utils/TableGen/GICombinerEmitter.cpp
new file mode 100644
index 000000000000..5dc4d6b07740
--- /dev/null
+++ b/utils/TableGen/GICombinerEmitter.cpp
@@ -0,0 +1,452 @@
+//===- GlobalCombinerEmitter.cpp - Generate a combiner --------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file Generate a combiner implementation for GlobalISel from a declarative
+/// syntax
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include "CodeGenTarget.h"
+#include "GlobalISel/CodeExpander.h"
+#include "GlobalISel/CodeExpansions.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "gicombiner-emitter"
+
+// FIXME: Use ALWAYS_ENABLED_STATISTIC once it's available.
+unsigned NumPatternTotal = 0;
+STATISTIC(NumPatternTotalStatistic, "Total number of patterns");
+
+cl::OptionCategory
+ GICombinerEmitterCat("Options for -gen-global-isel-combiner");
+static cl::list<std::string>
+ SelectedCombiners("combiners", cl::desc("Emit the specified combiners"),
+ cl::cat(GICombinerEmitterCat), cl::CommaSeparated);
+static cl::opt<bool> ShowExpansions(
+ "gicombiner-show-expansions",
+ cl::desc("Use C++ comments to indicate occurence of code expansion"),
+ cl::cat(GICombinerEmitterCat));
+
+namespace {
+typedef uint64_t RuleID;
+
+class RootInfo {
+ StringRef PatternSymbol;
+
+public:
+ RootInfo(StringRef PatternSymbol) : PatternSymbol(PatternSymbol) {}
+
+ StringRef getPatternSymbol() const { return PatternSymbol; }
+};
+
+class CombineRule {
+protected:
+ /// A unique ID for this rule
+ /// ID's are used for debugging and run-time disabling of rules among other
+ /// things.
+ RuleID ID;
+
+ /// The record defining this rule.
+ const Record &TheDef;
+
+ /// The roots of a match. These are the leaves of the DAG that are closest to
+ /// the end of the function. I.e. the nodes that are encountered without
+ /// following any edges of the DAG described by the pattern as we work our way
+ /// from the bottom of the function to the top.
+ std::vector<RootInfo> Roots;
+
+ /// A block of arbitrary C++ to finish testing the match.
+ /// FIXME: This is a temporary measure until we have actual pattern matching
+ const CodeInit *MatchingFixupCode = nullptr;
+public:
+ CombineRule(const CodeGenTarget &Target, RuleID ID, const Record &R)
+ : ID(ID), TheDef(R) {}
+ bool parseDefs();
+ bool parseMatcher(const CodeGenTarget &Target);
+
+ RuleID getID() const { return ID; }
+ StringRef getName() const { return TheDef.getName(); }
+ const Record &getDef() const { return TheDef; }
+ const CodeInit *getMatchingFixupCode() const { return MatchingFixupCode; }
+ size_t getNumRoots() const { return Roots.size(); }
+
+ using const_root_iterator = std::vector<RootInfo>::const_iterator;
+ const_root_iterator roots_begin() const { return Roots.begin(); }
+ const_root_iterator roots_end() const { return Roots.end(); }
+ iterator_range<const_root_iterator> roots() const {
+ return llvm::make_range(Roots.begin(), Roots.end());
+ }
+};
+
+/// A convenience function to check that an Init refers to a specific def. This
+/// is primarily useful for testing for defs and similar in DagInit's since
+/// DagInit's support any type inside them.
+static bool isSpecificDef(const Init &N, StringRef Def) {
+ if (const DefInit *OpI = dyn_cast<DefInit>(&N))
+ if (OpI->getDef()->getName() == Def)
+ return true;
+ return false;
+}
+
+/// A convenience function to check that an Init refers to a def that is a
+/// subclass of the given class and coerce it to a def if it is. This is
+/// primarily useful for testing for subclasses of GIMatchKind and similar in
+/// DagInit's since DagInit's support any type inside them.
+static Record *getDefOfSubClass(const Init &N, StringRef Cls) {
+ if (const DefInit *OpI = dyn_cast<DefInit>(&N))
+ if (OpI->getDef()->isSubClassOf(Cls))
+ return OpI->getDef();
+ return nullptr;
+}
+
+bool CombineRule::parseDefs() {
+ NamedRegionTimer T("parseDefs", "Time spent parsing the defs", "Rule Parsing",
+ "Time spent on rule parsing", TimeRegions);
+ DagInit *Defs = TheDef.getValueAsDag("Defs");
+
+ if (Defs->getOperatorAsDef(TheDef.getLoc())->getName() != "defs") {
+ PrintError(TheDef.getLoc(), "Expected defs operator");
+ return false;
+ }
+
+ for (unsigned I = 0, E = Defs->getNumArgs(); I < E; ++I) {
+ // Roots should be collected into Roots
+ if (isSpecificDef(*Defs->getArg(I), "root")) {
+ Roots.emplace_back(Defs->getArgNameStr(I));
+ continue;
+ }
+
+ // Otherwise emit an appropriate error message.
+ if (getDefOfSubClass(*Defs->getArg(I), "GIDefKind"))
+ PrintError(TheDef.getLoc(),
+ "This GIDefKind not implemented in tablegen");
+ else if (getDefOfSubClass(*Defs->getArg(I), "GIDefKindWithArgs"))
+ PrintError(TheDef.getLoc(),
+ "This GIDefKindWithArgs not implemented in tablegen");
+ else
+ PrintError(TheDef.getLoc(),
+ "Expected a subclass of GIDefKind or a sub-dag whose "
+ "operator is of type GIDefKindWithArgs");
+ return false;
+ }
+
+ if (Roots.empty()) {
+ PrintError(TheDef.getLoc(), "Combine rules must have at least one root");
+ return false;
+ }
+ return true;
+}
+
+bool CombineRule::parseMatcher(const CodeGenTarget &Target) {
+ NamedRegionTimer T("parseMatcher", "Time spent parsing the matcher",
+ "Rule Parsing", "Time spent on rule parsing", TimeRegions);
+ DagInit *Matchers = TheDef.getValueAsDag("Match");
+
+ if (Matchers->getOperatorAsDef(TheDef.getLoc())->getName() != "match") {
+ PrintError(TheDef.getLoc(), "Expected match operator");
+ return false;
+ }
+
+ if (Matchers->getNumArgs() == 0) {
+ PrintError(TheDef.getLoc(), "Matcher is empty");
+ return false;
+ }
+
+ // The match section consists of a list of matchers and predicates. Parse each
+ // one and add the equivalent GIMatchDag nodes, predicates, and edges.
+ for (unsigned I = 0; I < Matchers->getNumArgs(); ++I) {
+
+ // Parse arbitrary C++ code we have in lieu of supporting MIR matching
+ if (const CodeInit *CodeI = dyn_cast<CodeInit>(Matchers->getArg(I))) {
+ assert(!MatchingFixupCode &&
+ "Only one block of arbitrary code is currently permitted");
+ MatchingFixupCode = CodeI;
+ continue;
+ }
+
+ PrintError(TheDef.getLoc(),
+ "Expected a subclass of GIMatchKind or a sub-dag whose "
+ "operator is either of a GIMatchKindWithArgs or Instruction");
+ PrintNote("Pattern was `" + Matchers->getArg(I)->getAsString() + "'");
+ return false;
+ }
+ return true;
+}
+
+class GICombinerEmitter {
+ StringRef Name;
+ const CodeGenTarget &Target;
+ Record *Combiner;
+ std::vector<std::unique_ptr<CombineRule>> Rules;
+ std::unique_ptr<CombineRule> makeCombineRule(const Record &R);
+
+ void gatherRules(std::vector<std::unique_ptr<CombineRule>> &ActiveRules,
+ const std::vector<Record *> &&RulesAndGroups);
+
+public:
+ explicit GICombinerEmitter(RecordKeeper &RK, const CodeGenTarget &Target,
+ StringRef Name, Record *Combiner);
+ ~GICombinerEmitter() {}
+
+ StringRef getClassName() const {
+ return Combiner->getValueAsString("Classname");
+ }
+ void run(raw_ostream &OS);
+
+ /// Emit the name matcher (guarded by #ifndef NDEBUG) used to disable rules in
+ /// response to the generated cl::opt.
+ void emitNameMatcher(raw_ostream &OS) const;
+ void generateCodeForRule(raw_ostream &OS, const CombineRule *Rule,
+ StringRef Indent) const;
+};
+
+GICombinerEmitter::GICombinerEmitter(RecordKeeper &RK,
+ const CodeGenTarget &Target,
+ StringRef Name, Record *Combiner)
+ : Name(Name), Target(Target), Combiner(Combiner) {}
+
+void GICombinerEmitter::emitNameMatcher(raw_ostream &OS) const {
+ std::vector<std::pair<std::string, std::string>> Cases;
+ Cases.reserve(Rules.size());
+
+ for (const CombineRule &EnumeratedRule : make_pointee_range(Rules)) {
+ std::string Code;
+ raw_string_ostream SS(Code);
+ SS << "return " << EnumeratedRule.getID() << ";\n";
+ Cases.push_back(std::make_pair(EnumeratedRule.getName(), SS.str()));
+ }
+
+ OS << "static Optional<uint64_t> getRuleIdxForIdentifier(StringRef "
+ "RuleIdentifier) {\n"
+ << " uint64_t I;\n"
+ << " // getAtInteger(...) returns false on success\n"
+ << " bool Parsed = !RuleIdentifier.getAsInteger(0, I);\n"
+ << " if (Parsed)\n"
+ << " return I;\n\n"
+ << "#ifndef NDEBUG\n";
+ StringMatcher Matcher("RuleIdentifier", Cases, OS);
+ Matcher.Emit();
+ OS << "#endif // ifndef NDEBUG\n\n"
+ << " return None;\n"
+ << "}\n";
+}
+
+std::unique_ptr<CombineRule>
+GICombinerEmitter::makeCombineRule(const Record &TheDef) {
+ std::unique_ptr<CombineRule> Rule =
+ std::make_unique<CombineRule>(Target, NumPatternTotal, TheDef);
+
+ if (!Rule->parseDefs())
+ return nullptr;
+ if (!Rule->parseMatcher(Target))
+ return nullptr;
+ // For now, don't support multi-root rules. We'll come back to this later
+ // once we have the algorithm changes to support it.
+ if (Rule->getNumRoots() > 1) {
+ PrintError(TheDef.getLoc(), "Multi-root matches are not supported (yet)");
+ return nullptr;
+ }
+ return Rule;
+}
+
+/// Recurse into GICombineGroup's and flatten the ruleset into a simple list.
+void GICombinerEmitter::gatherRules(
+ std::vector<std::unique_ptr<CombineRule>> &ActiveRules,
+ const std::vector<Record *> &&RulesAndGroups) {
+ for (Record *R : RulesAndGroups) {
+ if (R->isValueUnset("Rules")) {
+ std::unique_ptr<CombineRule> Rule = makeCombineRule(*R);
+ if (Rule == nullptr) {
+ PrintError(R->getLoc(), "Failed to parse rule");
+ continue;
+ }
+ ActiveRules.emplace_back(std::move(Rule));
+ ++NumPatternTotal;
+ } else
+ gatherRules(ActiveRules, R->getValueAsListOfDefs("Rules"));
+ }
+}
+
+void GICombinerEmitter::generateCodeForRule(raw_ostream &OS,
+ const CombineRule *Rule,
+ StringRef Indent) const {
+ {
+ const Record &RuleDef = Rule->getDef();
+
+ OS << Indent << "// Rule: " << RuleDef.getName() << "\n"
+ << Indent << "if (!isRuleDisabled(" << Rule->getID() << ")) {\n";
+
+ CodeExpansions Expansions;
+ for (const RootInfo &Root : Rule->roots()) {
+ Expansions.declare(Root.getPatternSymbol(), "MI");
+ }
+ DagInit *Applyer = RuleDef.getValueAsDag("Apply");
+ if (Applyer->getOperatorAsDef(RuleDef.getLoc())->getName() !=
+ "apply") {
+ PrintError(RuleDef.getLoc(), "Expected apply operator");
+ return;
+ }
+
+ OS << Indent << " if (1\n";
+
+ if (Rule->getMatchingFixupCode() &&
+ !Rule->getMatchingFixupCode()->getValue().empty()) {
+ // FIXME: Single-use lambda's like this are a serious compile-time
+ // performance and memory issue. It's convenient for this early stage to
+ // defer some work to successive patches but we need to eliminate this
+ // before the ruleset grows to small-moderate size. Last time, it became
+ // a big problem for low-mem systems around the 500 rule mark but by the
+ // time we grow that large we should have merged the ISel match table
+ // mechanism with the Combiner.
+ OS << Indent << " && [&]() {\n"
+ << Indent << " "
+ << CodeExpander(Rule->getMatchingFixupCode()->getValue(), Expansions,
+ Rule->getMatchingFixupCode()->getLoc(), ShowExpansions)
+ << "\n"
+ << Indent << " return true;\n"
+ << Indent << " }()";
+ }
+ OS << ") {\n" << Indent << " ";
+
+ if (const CodeInit *Code = dyn_cast<CodeInit>(Applyer->getArg(0))) {
+ OS << CodeExpander(Code->getAsUnquotedString(), Expansions,
+ Code->getLoc(), ShowExpansions)
+ << "\n"
+ << Indent << " return true;\n"
+ << Indent << " }\n";
+ } else {
+ PrintError(RuleDef.getLoc(), "Expected apply code block");
+ return;
+ }
+
+ OS << Indent << "}\n";
+ }
+}
+
+void GICombinerEmitter::run(raw_ostream &OS) {
+ gatherRules(Rules, Combiner->getValueAsListOfDefs("Rules"));
+ NamedRegionTimer T("Emit", "Time spent emitting the combiner",
+ "Code Generation", "Time spent generating code",
+ TimeRegions);
+ OS << "#ifdef " << Name.upper() << "_GENCOMBINERHELPER_DEPS\n"
+ << "#include \"llvm/ADT/SparseBitVector.h\"\n"
+ << "namespace llvm {\n"
+ << "extern cl::OptionCategory GICombinerOptionCategory;\n"
+ << "} // end namespace llvm\n"
+ << "#endif // ifdef " << Name.upper() << "_GENCOMBINERHELPER_DEPS\n\n";
+
+ OS << "#ifdef " << Name.upper() << "_GENCOMBINERHELPER_H\n"
+ << "class " << getClassName() << " {\n"
+ << " SparseBitVector<> DisabledRules;\n"
+ << "\n"
+ << "public:\n"
+ << " bool parseCommandLineOption();\n"
+ << " bool isRuleDisabled(unsigned ID) const;\n"
+ << " bool setRuleDisabled(StringRef RuleIdentifier);\n"
+ << "\n"
+ << " bool tryCombineAll(\n"
+ << " GISelChangeObserver &Observer,\n"
+ << " MachineInstr &MI,\n"
+ << " MachineIRBuilder &B) const;\n"
+ << "};\n\n";
+
+ emitNameMatcher(OS);
+
+ OS << "bool " << getClassName()
+ << "::setRuleDisabled(StringRef RuleIdentifier) {\n"
+ << " std::pair<StringRef, StringRef> RangePair = "
+ "RuleIdentifier.split('-');\n"
+ << " if (!RangePair.second.empty()) {\n"
+ << " const auto First = getRuleIdxForIdentifier(RangePair.first);\n"
+ << " const auto Last = getRuleIdxForIdentifier(RangePair.second);\n"
+ << " if (!First.hasValue() || !Last.hasValue())\n"
+ << " return false;\n"
+ << " if (First >= Last)\n"
+ << " report_fatal_error(\"Beginning of range should be before end of "
+ "range\");\n"
+ << " for (auto I = First.getValue(); I < Last.getValue(); ++I)\n"
+ << " DisabledRules.set(I);\n"
+ << " return true;\n"
+ << " } else {\n"
+ << " const auto I = getRuleIdxForIdentifier(RangePair.first);\n"
+ << " if (!I.hasValue())\n"
+ << " return false;\n"
+ << " DisabledRules.set(I.getValue());\n"
+ << " return true;\n"
+ << " }\n"
+ << " return false;\n"
+ << "}\n";
+
+ OS << "bool " << getClassName()
+ << "::isRuleDisabled(unsigned RuleID) const {\n"
+ << " return DisabledRules.test(RuleID);\n"
+ << "}\n";
+ OS << "#endif // ifdef " << Name.upper() << "_GENCOMBINERHELPER_H\n\n";
+
+ OS << "#ifdef " << Name.upper() << "_GENCOMBINERHELPER_CPP\n"
+ << "\n"
+ << "cl::list<std::string> " << Name << "Option(\n"
+ << " \"" << Name.lower() << "-disable-rule\",\n"
+ << " cl::desc(\"Disable one or more combiner rules temporarily in "
+ << "the " << Name << " pass\"),\n"
+ << " cl::CommaSeparated,\n"
+ << " cl::Hidden,\n"
+ << " cl::cat(GICombinerOptionCategory));\n"
+ << "\n"
+ << "bool " << getClassName() << "::parseCommandLineOption() {\n"
+ << " for (const auto &Identifier : " << Name << "Option)\n"
+ << " if (!setRuleDisabled(Identifier))\n"
+ << " return false;\n"
+ << " return true;\n"
+ << "}\n\n";
+
+ OS << "bool " << getClassName() << "::tryCombineAll(\n"
+ << " GISelChangeObserver &Observer,\n"
+ << " MachineInstr &MI,\n"
+ << " MachineIRBuilder &B) const {\n"
+ << " CombinerHelper Helper(Observer, B);\n"
+ << " MachineBasicBlock *MBB = MI.getParent();\n"
+ << " MachineFunction *MF = MBB->getParent();\n"
+ << " MachineRegisterInfo &MRI = MF->getRegInfo();\n"
+ << " (void)MBB; (void)MF; (void)MRI;\n\n";
+
+ for (const auto &Rule : Rules)
+ generateCodeForRule(OS, Rule.get(), " ");
+ OS << "\n return false;\n"
+ << "}\n"
+ << "#endif // ifdef " << Name.upper() << "_GENCOMBINERHELPER_CPP\n";
+}
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+void EmitGICombiner(RecordKeeper &RK, raw_ostream &OS) {
+ CodeGenTarget Target(RK);
+ emitSourceFileHeader("Global Combiner", OS);
+
+ if (SelectedCombiners.empty())
+ PrintFatalError("No combiners selected with -combiners");
+ for (const auto &Combiner : SelectedCombiners) {
+ Record *CombinerDef = RK.getDef(Combiner);
+ if (!CombinerDef)
+ PrintFatalError("Could not find " + Combiner);
+ GICombinerEmitter(RK, Target, Combiner, CombinerDef).run(OS);
+ }
+ NumPatternTotalStatistic = NumPatternTotal;
+}
+
+} // namespace llvm
diff --git a/utils/TableGen/GlobalISel/CMakeLists.txt b/utils/TableGen/GlobalISel/CMakeLists.txt
new file mode 100644
index 000000000000..2f74d1087bcd
--- /dev/null
+++ b/utils/TableGen/GlobalISel/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+llvm_add_library(LLVMTableGenGlobalISel STATIC DISABLE_LLVM_LINK_LLVM_DYLIB
+ CodeExpander.cpp
+ )
diff --git a/utils/TableGen/GlobalISel/CodeExpander.cpp b/utils/TableGen/GlobalISel/CodeExpander.cpp
new file mode 100644
index 000000000000..d59a9b8e3b65
--- /dev/null
+++ b/utils/TableGen/GlobalISel/CodeExpander.cpp
@@ -0,0 +1,93 @@
+//===- CodeExpander.cpp - Expand variables in a string --------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file Expand the variables in a string.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeExpander.h"
+#include "CodeExpansions.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Error.h"
+
+using namespace llvm;
+
+void CodeExpander::emit(raw_ostream &OS) const {
+ StringRef Current = Code;
+
+ while (!Current.empty()) {
+ size_t Pos = Current.find_first_of("$\n\\");
+ if (Pos == StringRef::npos) {
+ OS << Current;
+ Current = "";
+ continue;
+ }
+
+ OS << Current.substr(0, Pos);
+ Current = Current.substr(Pos);
+
+ if (Current.startswith("\n")) {
+ OS << "\n" << Indent;
+ Current = Current.drop_front(1);
+ continue;
+ }
+
+ if (Current.startswith("\\$") || Current.startswith("\\\\")) {
+ OS << Current[1];
+ Current = Current.drop_front(2);
+ continue;
+ }
+
+ if (Current.startswith("\\")) {
+ Current = Current.drop_front(1);
+ continue;
+ }
+
+ if (Current.startswith("${")) {
+ StringRef StartVar = Current;
+ Current = Current.drop_front(2);
+ StringRef Var;
+ std::tie(Var, Current) = Current.split("}");
+
+ // Warn if we split because no terminator was found.
+ StringRef EndVar = StartVar.drop_front(2 /* ${ */ + Var.size());
+ if (EndVar.empty()) {
+ size_t LocOffset = StartVar.data() - Code.data();
+ PrintWarning(
+ Loc.size() > 0 && Loc[0].isValid()
+ ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
+ : SMLoc(),
+ "Unterminated expansion");
+ }
+
+ auto ValueI = Expansions.find(Var);
+ if (ValueI == Expansions.end()) {
+ size_t LocOffset = StartVar.data() - Code.data();
+ PrintError(Loc.size() > 0 && Loc[0].isValid()
+ ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
+ : SMLoc(),
+ "Attempting to expand an undeclared variable " + Var);
+ }
+ if (ShowExpansions)
+ OS << "/*$" << Var << "{*/";
+ OS << Expansions.lookup(Var);
+ if (ShowExpansions)
+ OS << "/*}*/";
+ continue;
+ }
+
+ size_t LocOffset = Current.data() - Code.data();
+ PrintWarning(Loc.size() > 0 && Loc[0].isValid()
+ ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
+ : SMLoc(),
+ "Assuming missing escape character");
+ OS << "$";
+ Current = Current.drop_front(1);
+ }
+}
diff --git a/utils/TableGen/GlobalISel/CodeExpander.h b/utils/TableGen/GlobalISel/CodeExpander.h
new file mode 100644
index 000000000000..bd6946de5925
--- /dev/null
+++ b/utils/TableGen/GlobalISel/CodeExpander.h
@@ -0,0 +1,55 @@
+//===- CodeExpander.h - Expand variables in a string ----------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file Expand the variables in a string.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UTILS_TABLEGEN_CODEEXPANDER_H
+#define LLVM_UTILS_TABLEGEN_CODEEXPANDER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SMLoc.h"
+
+namespace llvm {
+class CodeExpansions;
+class raw_ostream;
+
+/// Emit the given code with all '${foo}' placeholders expanded to their
+/// replacements.
+///
+/// It's an error to use an undefined expansion and expansion-like output that
+/// needs to be emitted verbatim can be escaped as '\${foo}'
+///
+/// The emitted code can be given a custom indent to enable both indentation by
+/// an arbitrary amount of whitespace and emission of the code as a comment.
+class CodeExpander {
+ StringRef Code;
+ const CodeExpansions &Expansions;
+ const ArrayRef<SMLoc> &Loc;
+ bool ShowExpansions;
+ StringRef Indent;
+
+public:
+ CodeExpander(StringRef Code, const CodeExpansions &Expansions,
+ const ArrayRef<SMLoc> &Loc, bool ShowExpansions,
+ StringRef Indent = " ")
+ : Code(Code), Expansions(Expansions), Loc(Loc),
+ ShowExpansions(ShowExpansions), Indent(Indent) {}
+
+ void emit(raw_ostream &OS) const;
+};
+
+inline raw_ostream &operator<<(raw_ostream &OS, const CodeExpander &Expander) {
+ Expander.emit(OS);
+ return OS;
+}
+} // end namespace llvm
+
+#endif // ifndef LLVM_UTILS_TABLEGEN_CODEEXPANDER_H
diff --git a/utils/TableGen/GlobalISel/CodeExpansions.h b/utils/TableGen/GlobalISel/CodeExpansions.h
new file mode 100644
index 000000000000..bb890ec8f57e
--- /dev/null
+++ b/utils/TableGen/GlobalISel/CodeExpansions.h
@@ -0,0 +1,43 @@
+//===- CodeExpansions.h - Record expansions for CodeExpander --------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file Record the expansions to use in a CodeExpander.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringMap.h"
+
+#ifndef LLVM_UTILS_TABLEGEN_CODEEXPANSIONS_H
+#define LLVM_UTILS_TABLEGEN_CODEEXPANSIONS_H
+namespace llvm {
+class CodeExpansions {
+public:
+ using const_iterator = StringMap<std::string>::const_iterator;
+
+protected:
+ StringMap<std::string> Expansions;
+
+public:
+ void declare(StringRef Name, StringRef Expansion) {
+ bool Inserted = Expansions.try_emplace(Name, Expansion).second;
+ assert(Inserted && "Declared variable twice");
+ (void)Inserted;
+ }
+
+ std::string lookup(StringRef Variable) const {
+ return Expansions.lookup(Variable);
+ }
+
+ const_iterator begin() const { return Expansions.begin(); }
+ const_iterator end() const { return Expansions.end(); }
+ const_iterator find(StringRef Variable) const {
+ return Expansions.find(Variable);
+ }
+};
+} // end namespace llvm
+#endif // ifndef LLVM_UTILS_TABLEGEN_CODEEXPANSIONS_H
diff --git a/utils/TableGen/GlobalISelEmitter.cpp b/utils/TableGen/GlobalISelEmitter.cpp
index f1c02134198b..d8d4c9f4f55c 100644
--- a/utils/TableGen/GlobalISelEmitter.cpp
+++ b/utils/TableGen/GlobalISelEmitter.cpp
@@ -249,6 +249,10 @@ static std::string explainPredicates(const TreePatternNode *N) {
OS << ']';
}
+ int64_t MinAlign = P.getMinAlignment();
+ if (MinAlign > 0)
+ Explanation += " MinAlign=" + utostr(MinAlign);
+
if (P.isAtomicOrderingMonotonic())
Explanation += " monotonic";
if (P.isAtomicOrderingAcquire())
@@ -329,6 +333,9 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) {
const ListInit *AddrSpaces = Predicate.getAddressSpaces();
if (AddrSpaces && !AddrSpaces->empty())
continue;
+
+ if (Predicate.getMinAlignment() > 0)
+ continue;
}
if (Predicate.isAtomic() && Predicate.getMemoryVT())
@@ -822,6 +829,10 @@ protected:
/// the renderers.
StringMap<OperandMatcher *> DefinedOperands;
+ /// A map of anonymous physical register operands defined by the matchers that
+ /// may be referenced by the renderers.
+ DenseMap<Record *, OperandMatcher *> PhysRegOperands;
+
/// ID for the next instruction variable defined with implicitlyDefineInsnVar()
unsigned NextInsnVarID;
@@ -904,6 +915,8 @@ public:
void defineOperand(StringRef SymbolicName, OperandMatcher &OM);
+ void definePhysRegOperand(Record *Reg, OperandMatcher &OM);
+
Error defineComplexSubOperand(StringRef SymbolicName, Record *ComplexPattern,
unsigned RendererID, unsigned SubOperandID) {
if (ComplexSubOperands.count(SymbolicName))
@@ -927,6 +940,7 @@ public:
InstructionMatcher &getInstructionMatcher(StringRef SymbolicName) const;
const OperandMatcher &getOperandMatcher(StringRef Name) const;
+ const OperandMatcher &getPhysRegOperandMatcher(Record *) const;
void optimize() override;
void emit(MatchTable &Table) override;
@@ -1048,14 +1062,17 @@ public:
IPM_Opcode,
IPM_NumOperands,
IPM_ImmPredicate,
+ IPM_Imm,
IPM_AtomicOrderingMMO,
IPM_MemoryLLTSize,
IPM_MemoryVsLLTSize,
IPM_MemoryAddressSpace,
+ IPM_MemoryAlignment,
IPM_GenericPredicate,
OPM_SameOperand,
OPM_ComplexPattern,
OPM_IntrinsicID,
+ OPM_CmpPredicate,
OPM_Instruction,
OPM_Int,
OPM_LiteralInt,
@@ -1324,6 +1341,23 @@ public:
}
};
+class ImmOperandMatcher : public OperandPredicateMatcher {
+public:
+ ImmOperandMatcher(unsigned InsnVarID, unsigned OpIdx)
+ : OperandPredicateMatcher(IPM_Imm, InsnVarID, OpIdx) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_Imm;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIM_CheckIsImm") << MatchTable::Comment("MI")
+ << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
+ << MatchTable::IntValue(OpIdx) << MatchTable::LineBreak;
+ }
+};
+
/// Generates code to check that an operand is a G_CONSTANT with a particular
/// int.
class ConstantIntOperandMatcher : public OperandPredicateMatcher {
@@ -1381,6 +1415,36 @@ public:
}
};
+/// Generates code to check that an operand is an CmpInst predicate
+class CmpPredicateOperandMatcher : public OperandPredicateMatcher {
+protected:
+ std::string PredName;
+
+public:
+ CmpPredicateOperandMatcher(unsigned InsnVarID, unsigned OpIdx,
+ std::string P)
+ : OperandPredicateMatcher(OPM_CmpPredicate, InsnVarID, OpIdx), PredName(P) {}
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ PredName == cast<CmpPredicateOperandMatcher>(&B)->PredName;
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_CmpPredicate;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIM_CheckCmpPredicate")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("Predicate")
+ << MatchTable::NamedValue("CmpInst", PredName)
+ << MatchTable::LineBreak;
+ }
+};
+
/// Generates code to check that an operand is an intrinsic ID.
class IntrinsicIDOperandMatcher : public OperandPredicateMatcher {
protected:
@@ -1442,7 +1506,7 @@ public:
Optional<Kind *> addPredicate(Args &&... args) {
if (isSameAsAnotherOperand())
return None;
- Predicates.emplace_back(llvm::make_unique<Kind>(
+ Predicates.emplace_back(std::make_unique<Kind>(
getInsnVarID(), getOpIdx(), std::forward<Args>(args)...));
return static_cast<Kind *>(Predicates.back().get());
}
@@ -1849,6 +1913,40 @@ public:
}
};
+class MemoryAlignmentPredicateMatcher : public InstructionPredicateMatcher {
+protected:
+ unsigned MMOIdx;
+ int MinAlign;
+
+public:
+ MemoryAlignmentPredicateMatcher(unsigned InsnVarID, unsigned MMOIdx,
+ int MinAlign)
+ : InstructionPredicateMatcher(IPM_MemoryAlignment, InsnVarID),
+ MMOIdx(MMOIdx), MinAlign(MinAlign) {
+ assert(MinAlign > 0);
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_MemoryAlignment;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ if (!InstructionPredicateMatcher::isIdentical(B))
+ return false;
+ auto *Other = cast<MemoryAlignmentPredicateMatcher>(&B);
+ return MMOIdx == Other->MMOIdx && MinAlign == Other->MinAlign;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIM_CheckMemoryAlignment")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
+ << MatchTable::Comment("MinAlign") << MatchTable::IntValue(MinAlign)
+ << MatchTable::LineBreak;
+ }
+};
+
/// Generates code to check that the size of an MMO is less-than, equal-to, or
/// greater than a given LLT.
class MemoryVsLLTSizePredicateMatcher : public InstructionPredicateMatcher {
@@ -1945,6 +2043,11 @@ protected:
std::string SymbolicName;
unsigned InsnVarID;
+ /// PhysRegInputs - List list has an entry for each explicitly specified
+ /// physreg input to the pattern. The first elt is the Register node, the
+ /// second is the recorded slot number the input pattern match saved it in.
+ SmallVector<std::pair<Record *, unsigned>, 2> PhysRegInputs;
+
public:
InstructionMatcher(RuleMatcher &Rule, StringRef SymbolicName)
: Rule(Rule), SymbolicName(SymbolicName) {
@@ -1957,7 +2060,7 @@ public:
template <class Kind, class... Args>
Optional<Kind *> addPredicate(Args &&... args) {
Predicates.emplace_back(
- llvm::make_unique<Kind>(getInsnVarID(), std::forward<Args>(args)...));
+ std::make_unique<Kind>(getInsnVarID(), std::forward<Args>(args)...));
return static_cast<Kind *>(Predicates.back().get());
}
@@ -1986,6 +2089,20 @@ public:
llvm_unreachable("Failed to lookup operand");
}
+ OperandMatcher &addPhysRegInput(Record *Reg, unsigned OpIdx,
+ unsigned TempOpIdx) {
+ assert(SymbolicName.empty());
+ OperandMatcher *OM = new OperandMatcher(*this, OpIdx, "", TempOpIdx);
+ Operands.emplace_back(OM);
+ Rule.definePhysRegOperand(Reg, *OM);
+ PhysRegInputs.emplace_back(Reg, OpIdx);
+ return *OM;
+ }
+
+ ArrayRef<std::pair<Record *, unsigned>> getPhysRegInputs() const {
+ return PhysRegInputs;
+ }
+
StringRef getSymbolicName() const { return SymbolicName; }
unsigned getNumOperands() const { return Operands.size(); }
OperandVec::iterator operands_begin() { return Operands.begin(); }
@@ -2193,9 +2310,11 @@ public:
OR_Copy,
OR_CopyOrAddZeroReg,
OR_CopySubReg,
+ OR_CopyPhysReg,
OR_CopyConstantAsImm,
OR_CopyFConstantAsFPImm,
OR_Imm,
+ OR_SubRegIndex,
OR_Register,
OR_TempRegister,
OR_ComplexPattern,
@@ -2247,6 +2366,38 @@ public:
}
};
+/// A CopyRenderer emits code to copy a virtual register to a specific physical
+/// register.
+class CopyPhysRegRenderer : public OperandRenderer {
+protected:
+ unsigned NewInsnID;
+ Record *PhysReg;
+
+public:
+ CopyPhysRegRenderer(unsigned NewInsnID, Record *Reg)
+ : OperandRenderer(OR_CopyPhysReg), NewInsnID(NewInsnID),
+ PhysReg(Reg) {
+ assert(PhysReg);
+ }
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_CopyPhysReg;
+ }
+
+ Record *getPhysReg() const { return PhysReg; }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
+ const OperandMatcher &Operand = Rule.getPhysRegOperandMatcher(PhysReg);
+ unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
+ Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID")
+ << MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID")
+ << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
+ << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::Comment(PhysReg->getName())
+ << MatchTable::LineBreak;
+ }
+};
+
/// A CopyOrAddZeroRegRenderer emits code to copy a single operand from an
/// existing instruction to the one being built. If the operand turns out to be
/// a 'G_CONSTANT 0' then it replaces the operand with a zero register.
@@ -2393,11 +2544,13 @@ class AddRegisterRenderer : public OperandRenderer {
protected:
unsigned InsnID;
const Record *RegisterDef;
+ bool IsDef;
public:
- AddRegisterRenderer(unsigned InsnID, const Record *RegisterDef)
- : OperandRenderer(OR_Register), InsnID(InsnID), RegisterDef(RegisterDef) {
- }
+ AddRegisterRenderer(unsigned InsnID, const Record *RegisterDef,
+ bool IsDef = false)
+ : OperandRenderer(OR_Register), InsnID(InsnID), RegisterDef(RegisterDef),
+ IsDef(IsDef) {}
static bool classof(const OperandRenderer *R) {
return R->getKind() == OR_Register;
@@ -2411,7 +2564,16 @@ public:
? RegisterDef->getValueAsString("Namespace")
: ""),
RegisterDef->getName())
- << MatchTable::LineBreak;
+ << MatchTable::Comment("AddRegisterRegFlags");
+
+ // TODO: This is encoded as a 64-bit element, but only 16 or 32-bits are
+ // really needed for a physical register reference. We can pack the
+ // register and flags in a single field.
+ if (IsDef)
+ Table << MatchTable::NamedValue("RegState::Define");
+ else
+ Table << MatchTable::IntValue(0);
+ Table << MatchTable::LineBreak;
}
};
@@ -2467,6 +2629,28 @@ public:
}
};
+/// Adds an enum value for a subreg index to the instruction being built.
+class SubRegIndexRenderer : public OperandRenderer {
+protected:
+ unsigned InsnID;
+ const CodeGenSubRegIndex *SubRegIdx;
+
+public:
+ SubRegIndexRenderer(unsigned InsnID, const CodeGenSubRegIndex *SRI)
+ : OperandRenderer(OR_SubRegIndex), InsnID(InsnID), SubRegIdx(SRI) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_SubRegIndex;
+ }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIR_AddImm") << MatchTable::Comment("InsnID")
+ << MatchTable::IntValue(InsnID) << MatchTable::Comment("SubRegIndex")
+ << MatchTable::IntValue(SubRegIdx->EnumValue)
+ << MatchTable::LineBreak;
+ }
+};
+
/// Adds operands by calling a renderer function supplied by the ComplexPattern
/// matcher function.
class RenderComplexPatternOperand : public OperandRenderer {
@@ -2620,7 +2804,7 @@ public:
template <class Kind, class... Args>
Kind &addRenderer(Args&&... args) {
OperandRenderers.emplace_back(
- llvm::make_unique<Kind>(InsnID, std::forward<Args>(args)...));
+ std::make_unique<Kind>(InsnID, std::forward<Args>(args)...));
return *static_cast<Kind *>(OperandRenderers.back().get());
}
@@ -2747,7 +2931,9 @@ private:
public:
MakeTempRegisterAction(const LLTCodeGen &Ty, unsigned TempRegID)
- : Ty(Ty), TempRegID(TempRegID) {}
+ : Ty(Ty), TempRegID(TempRegID) {
+ KnownTypes.insert(Ty);
+ }
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
Table << MatchTable::Opcode("GIR_MakeTempReg")
@@ -2781,7 +2967,7 @@ const std::vector<Record *> &RuleMatcher::getRequiredFeatures() const {
// iterator.
template <class Kind, class... Args>
Kind &RuleMatcher::addAction(Args &&... args) {
- Actions.emplace_back(llvm::make_unique<Kind>(std::forward<Args>(args)...));
+ Actions.emplace_back(std::make_unique<Kind>(std::forward<Args>(args)...));
return *static_cast<Kind *>(Actions.back().get());
}
@@ -2796,7 +2982,7 @@ template <class Kind, class... Args>
action_iterator RuleMatcher::insertAction(action_iterator InsertPt,
Args &&... args) {
return Actions.emplace(InsertPt,
- llvm::make_unique<Kind>(std::forward<Args>(args)...));
+ std::make_unique<Kind>(std::forward<Args>(args)...));
}
unsigned RuleMatcher::implicitlyDefineInsnVar(InstructionMatcher &Matcher) {
@@ -2823,6 +3009,13 @@ void RuleMatcher::defineOperand(StringRef SymbolicName, OperandMatcher &OM) {
OM.addPredicate<SameOperandMatcher>(OM.getSymbolicName());
}
+void RuleMatcher::definePhysRegOperand(Record *Reg, OperandMatcher &OM) {
+ if (PhysRegOperands.find(Reg) == PhysRegOperands.end()) {
+ PhysRegOperands[Reg] = &OM;
+ return;
+ }
+}
+
InstructionMatcher &
RuleMatcher::getInstructionMatcher(StringRef SymbolicName) const {
for (const auto &I : InsnVariableIDs)
@@ -2833,6 +3026,18 @@ RuleMatcher::getInstructionMatcher(StringRef SymbolicName) const {
}
const OperandMatcher &
+RuleMatcher::getPhysRegOperandMatcher(Record *Reg) const {
+ const auto &I = PhysRegOperands.find(Reg);
+
+ if (I == PhysRegOperands.end()) {
+ PrintFatalError(SrcLoc, "Register " + Reg->getName() +
+ " was not declared in matcher");
+ }
+
+ return *I->second;
+}
+
+const OperandMatcher &
RuleMatcher::getOperandMatcher(StringRef Name) const {
const auto &I = DefinedOperands.find(Name);
@@ -3079,9 +3284,9 @@ private:
bool OperandIsAPointer, unsigned OpIdx,
unsigned &TempOpIdx);
- Expected<BuildMIAction &>
- createAndImportInstructionRenderer(RuleMatcher &M,
- const TreePatternNode *Dst);
+ Expected<BuildMIAction &> createAndImportInstructionRenderer(
+ RuleMatcher &M, InstructionMatcher &InsnMatcher,
+ const TreePatternNode *Src, const TreePatternNode *Dst);
Expected<action_iterator> createAndImportSubInstructionRenderer(
action_iterator InsertPt, RuleMatcher &M, const TreePatternNode *Dst,
unsigned TempReg);
@@ -3089,6 +3294,7 @@ private:
createInstructionRenderer(action_iterator InsertPt, RuleMatcher &M,
const TreePatternNode *Dst);
void importExplicitDefRenderers(BuildMIAction &DstMIBuilder);
+
Expected<action_iterator>
importExplicitUseRenderers(action_iterator InsertPt, RuleMatcher &M,
BuildMIAction &DstMIBuilder,
@@ -3122,6 +3328,32 @@ private:
MatchTable buildMatchTable(MutableArrayRef<RuleMatcher> Rules, bool Optimize,
bool WithCoverage);
+ /// 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 *>
+ inferSuperRegisterClassForNode(const TypeSetByHwMode &Ty,
+ TreePatternNode *SuperRegNode,
+ TreePatternNode *SubRegIdxNode);
+ 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 *>
+ inferSuperRegisterClass(const TypeSetByHwMode &Ty,
+ TreePatternNode *SubRegIdxNode);
+
+ /// Return the CodeGenRegisterClass associated with \p Leaf if it has one.
+ Optional<const CodeGenRegisterClass *>
+ getRegClassFromLeaf(TreePatternNode *Leaf);
+
+ /// Return a CodeGenRegisterClass for \p N if one can be found. Return None
+ /// otherwise.
+ Optional<const CodeGenRegisterClass *>
+ inferRegClassFromPattern(TreePatternNode *N);
+
public:
/// Takes a sequence of \p Rules and group them based on the predicates
/// they share. \p MatcherStorage is used as a memory container
@@ -3190,6 +3422,13 @@ Record *GlobalISelEmitter::findNodeEquiv(Record *N) const {
const CodeGenInstruction *
GlobalISelEmitter::getEquivNode(Record &Equiv, const TreePatternNode *N) const {
+ if (N->getNumChildren() >= 1) {
+ // setcc operation maps to two different G_* instructions based on the type.
+ if (!Equiv.isValueUnset("IfFloatingPoint") &&
+ MVT(N->getChild(0)->getSimpleType(0)).isFloatingPoint())
+ return &Target.getInstruction(Equiv.getValueAsDef("IfFloatingPoint"));
+ }
+
for (const TreePredicateCall &Call : N->getPredicateCalls()) {
const TreePredicateFn &Predicate = Call.Fn;
if (!Equiv.isValueUnset("IfSignExtend") && Predicate.isLoad() &&
@@ -3199,6 +3438,7 @@ GlobalISelEmitter::getEquivNode(Record &Equiv, const TreePatternNode *N) const {
Predicate.isZeroExtLoad())
return &Target.getInstruction(Equiv.getValueAsDef("IfZeroExtend"));
}
+
return &Target.getInstruction(Equiv.getValueAsDef("I"));
}
@@ -3212,7 +3452,7 @@ Error
GlobalISelEmitter::importRulePredicates(RuleMatcher &M,
ArrayRef<Predicate> Predicates) {
for (const Predicate &P : Predicates) {
- if (!P.Def)
+ if (!P.Def || P.getCondString().empty())
continue;
declareSubtargetFeature(P.Def);
M.addRequiredFeature(P.Def);
@@ -3287,6 +3527,10 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
0, ParsedAddrSpaces);
}
}
+
+ int64_t MinAlign = Predicate.getMinAlignment();
+ if (MinAlign > 0)
+ InsnMatcher.addPredicate<MemoryAlignmentPredicateMatcher>(0, MinAlign);
}
// G_LOAD is used for both non-extending and any-extending loads.
@@ -3301,11 +3545,19 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
continue;
}
- if (Predicate.isStore() && Predicate.isTruncStore()) {
- // FIXME: If MemoryVT is set, we end up with 2 checks for the MMO size.
- InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
- 0, MemoryVsLLTSizePredicateMatcher::LessThan, 0);
- continue;
+ if (Predicate.isStore()) {
+ if (Predicate.isTruncStore()) {
+ // FIXME: If MemoryVT is set, we end up with 2 checks for the MMO size.
+ InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
+ 0, MemoryVsLLTSizePredicateMatcher::LessThan, 0);
+ continue;
+ }
+ if (Predicate.isNonTruncStore()) {
+ // We need to check the sizes match here otherwise we could incorrectly
+ // match truncating stores with non-truncating ones.
+ InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
+ 0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0);
+ }
}
// No check required. We already did it by swapping the opcode.
@@ -3405,6 +3657,10 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
}
if (SrcGIEquivOrNull && SrcGIEquivOrNull->getValueAsBit("CheckMMOIsNonAtomic"))
InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("NotAtomic");
+ else if (SrcGIEquivOrNull && SrcGIEquivOrNull->getValueAsBit("CheckMMOIsAtomic")) {
+ InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>(
+ "Unordered", AtomicOrderingMMOPredicateMatcher::AO_OrStronger);
+ }
if (Src->isLeaf()) {
Init *SrcInit = Src->getLeafValue();
@@ -3427,8 +3683,43 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
return InsnMatcher;
}
+ // Special case because the operand order is changed from setcc. The
+ // predicate operand needs to be swapped from the last operand to the first
+ // source.
+
+ unsigned NumChildren = Src->getNumChildren();
+ bool IsFCmp = SrcGIOrNull->TheDef->getName() == "G_FCMP";
+
+ if (IsFCmp || SrcGIOrNull->TheDef->getName() == "G_ICMP") {
+ TreePatternNode *SrcChild = Src->getChild(NumChildren - 1);
+ if (SrcChild->isLeaf()) {
+ DefInit *DI = dyn_cast<DefInit>(SrcChild->getLeafValue());
+ Record *CCDef = DI ? DI->getDef() : nullptr;
+ if (!CCDef || !CCDef->isSubClassOf("CondCode"))
+ return failedImport("Unable to handle CondCode");
+
+ OperandMatcher &OM =
+ InsnMatcher.addOperand(OpIdx++, SrcChild->getName(), TempOpIdx);
+ StringRef PredType = IsFCmp ? CCDef->getValueAsString("FCmpPredicate") :
+ CCDef->getValueAsString("ICmpPredicate");
+
+ if (!PredType.empty()) {
+ OM.addPredicate<CmpPredicateOperandMatcher>(PredType);
+ // Process the other 2 operands normally.
+ --NumChildren;
+ }
+ }
+ }
+
// Match the used operands (i.e. the children of the operator).
- for (unsigned i = 0, e = Src->getNumChildren(); i != e; ++i) {
+ bool IsIntrinsic =
+ SrcGIOrNull->TheDef->getName() == "G_INTRINSIC" ||
+ SrcGIOrNull->TheDef->getName() == "G_INTRINSIC_W_SIDE_EFFECTS";
+ const CodeGenIntrinsic *II = Src->getIntrinsicInfo(CGP);
+ if (IsIntrinsic && !II)
+ return failedImport("Expected IntInit containing intrinsic ID)");
+
+ for (unsigned i = 0; i != NumChildren; ++i) {
TreePatternNode *SrcChild = Src->getChild(i);
// SelectionDAG allows pointers to be represented with iN since it doesn't
@@ -3436,19 +3727,21 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
// Coerce integers to pointers to address space 0 if the context indicates a pointer.
bool OperandIsAPointer = SrcGIOrNull->isOperandAPointer(i);
- // For G_INTRINSIC/G_INTRINSIC_W_SIDE_EFFECTS, the operand immediately
- // following the defs is an intrinsic ID.
- if ((SrcGIOrNull->TheDef->getName() == "G_INTRINSIC" ||
- SrcGIOrNull->TheDef->getName() == "G_INTRINSIC_W_SIDE_EFFECTS") &&
- i == 0) {
- if (const CodeGenIntrinsic *II = Src->getIntrinsicInfo(CGP)) {
+ if (IsIntrinsic) {
+ // For G_INTRINSIC/G_INTRINSIC_W_SIDE_EFFECTS, the operand immediately
+ // following the defs is an intrinsic ID.
+ if (i == 0) {
OperandMatcher &OM =
InsnMatcher.addOperand(OpIdx++, SrcChild->getName(), TempOpIdx);
OM.addPredicate<IntrinsicIDOperandMatcher>(II);
continue;
}
- return failedImport("Expected IntInit containing instrinsic ID)");
+ // We have to check intrinsics for llvm_anyptr_ty parameters.
+ //
+ // Note that we have to look at the i-1th parameter, because we don't
+ // have the intrinsic ID in the intrinsic's parameter list.
+ OperandIsAPointer |= II->isParamAPointer(i - 1);
}
if (auto Error =
@@ -3473,14 +3766,37 @@ Error GlobalISelEmitter::importComplexPatternOperandMatcher(
return Error::success();
}
+// Get the name to use for a pattern operand. For an anonymous physical register
+// input, this should use the register name.
+static StringRef getSrcChildName(const TreePatternNode *SrcChild,
+ Record *&PhysReg) {
+ StringRef SrcChildName = SrcChild->getName();
+ if (SrcChildName.empty() && SrcChild->isLeaf()) {
+ if (auto *ChildDefInit = dyn_cast<DefInit>(SrcChild->getLeafValue())) {
+ auto *ChildRec = ChildDefInit->getDef();
+ if (ChildRec->isSubClassOf("Register")) {
+ SrcChildName = ChildRec->getName();
+ PhysReg = ChildRec;
+ }
+ }
+ }
+
+ return SrcChildName;
+}
+
Error GlobalISelEmitter::importChildMatcher(RuleMatcher &Rule,
InstructionMatcher &InsnMatcher,
const TreePatternNode *SrcChild,
bool OperandIsAPointer,
unsigned OpIdx,
unsigned &TempOpIdx) {
- OperandMatcher &OM =
- InsnMatcher.addOperand(OpIdx, SrcChild->getName(), TempOpIdx);
+
+ Record *PhysReg = nullptr;
+ StringRef SrcChildName = getSrcChildName(SrcChild, PhysReg);
+
+ OperandMatcher &OM = PhysReg ?
+ InsnMatcher.addPhysRegInput(PhysReg, OpIdx, TempOpIdx) :
+ InsnMatcher.addOperand(OpIdx, SrcChildName, TempOpIdx);
if (OM.isSameAsAnotherOperand())
return Error::success();
@@ -3496,6 +3812,10 @@ Error GlobalISelEmitter::importChildMatcher(RuleMatcher &Rule,
OM.addPredicate<MBBOperandMatcher>();
return Error::success();
}
+ if (SrcChild->getOperator()->getName() == "timm") {
+ OM.addPredicate<ImmOperandMatcher>();
+ return Error::success();
+ }
}
}
@@ -3569,6 +3889,20 @@ Error GlobalISelEmitter::importChildMatcher(RuleMatcher &Rule,
return Error::success();
}
+ if (ChildRec->isSubClassOf("Register")) {
+ // This just be emitted as a copy to the specific register.
+ ValueTypeByHwMode VT = ChildTypes.front().getValueTypeByHwMode();
+ const CodeGenRegisterClass *RC
+ = CGRegs.getMinimalPhysRegClass(ChildRec, &VT);
+ if (!RC) {
+ return failedImport(
+ "Could not determine physical register class of pattern source");
+ }
+
+ OM.addPredicate<RegisterBankOperandMatcher>(*RC);
+ return Error::success();
+ }
+
// Check for ValueType.
if (ChildRec->isSubClassOf("ValueType")) {
// We already added a type check as standard practice so this doesn't need
@@ -3631,7 +3965,10 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
// rendered as operands.
// FIXME: The target should be able to choose sign-extended when appropriate
// (e.g. on Mips).
- if (DstChild->getOperator()->getName() == "imm") {
+ if (DstChild->getOperator()->getName() == "timm") {
+ DstMIBuilder.addRenderer<CopyRenderer>(DstChild->getName());
+ return InsertPt;
+ } else if (DstChild->getOperator()->getName() == "imm") {
DstMIBuilder.addRenderer<CopyConstantAsImmRenderer>(DstChild->getName());
return InsertPt;
} else if (DstChild->getOperator()->getName() == "fpimm") {
@@ -3708,6 +4045,12 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
return InsertPt;
}
+ if (ChildRec->isSubClassOf("SubRegIndex")) {
+ CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(ChildRec);
+ DstMIBuilder.addRenderer<ImmRenderer>(SubIdx->EnumValue);
+ return InsertPt;
+ }
+
if (ChildRec->isSubClassOf("ComplexPattern")) {
const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec);
if (ComplexPattern == ComplexPatternEquivs.end())
@@ -3729,7 +4072,8 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
}
Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
- RuleMatcher &M, const TreePatternNode *Dst) {
+ RuleMatcher &M, InstructionMatcher &InsnMatcher, const TreePatternNode *Src,
+ const TreePatternNode *Dst) {
auto InsertPtOrError = createInstructionRenderer(M.actions_end(), M, Dst);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
@@ -3737,6 +4081,17 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
action_iterator InsertPt = InsertPtOrError.get();
BuildMIAction &DstMIBuilder = *static_cast<BuildMIAction *>(InsertPt->get());
+ for (auto PhysInput : InsnMatcher.getPhysRegInputs()) {
+ InsertPt = M.insertAction<BuildMIAction>(
+ InsertPt, M.allocateOutputInsnID(),
+ &Target.getInstruction(RK.getDef("COPY")));
+ BuildMIAction &CopyToPhysRegMIBuilder =
+ *static_cast<BuildMIAction *>(InsertPt->get());
+ CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(PhysInput.first,
+ true);
+ CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysInput.first);
+ }
+
importExplicitDefRenderers(DstMIBuilder);
if (auto Error = importExplicitUseRenderers(InsertPt, M, DstMIBuilder, Dst)
@@ -3768,6 +4123,78 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer(
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
+ // We need to make sure that when we import an INSERT_SUBREG as a
+ // subinstruction that it ends up being constrained to the correct super
+ // register and subregister classes.
+ auto OpName = Target.getInstruction(Dst->getOperator()).TheDef->getName();
+ if (OpName == "INSERT_SUBREG") {
+ auto SubClass = inferRegClassFromPattern(Dst->getChild(1));
+ if (!SubClass)
+ return failedImport(
+ "Cannot infer register class from INSERT_SUBREG operand #1");
+ Optional<const CodeGenRegisterClass *> SuperClass =
+ inferSuperRegisterClassForNode(Dst->getExtType(0), Dst->getChild(0),
+ Dst->getChild(2));
+ if (!SuperClass)
+ return failedImport(
+ "Cannot infer register class for INSERT_SUBREG operand #0");
+ // The destination and the super register source of an INSERT_SUBREG must
+ // be the same register class.
+ M.insertAction<ConstrainOperandToRegClassAction>(
+ InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
+ M.insertAction<ConstrainOperandToRegClassAction>(
+ InsertPt, DstMIBuilder.getInsnID(), 1, **SuperClass);
+ M.insertAction<ConstrainOperandToRegClassAction>(
+ InsertPt, DstMIBuilder.getInsnID(), 2, **SubClass);
+ return InsertPtOrError.get();
+ }
+
+ if (OpName == "EXTRACT_SUBREG") {
+ // EXTRACT_SUBREG selects into a subregister COPY but unlike most
+ // instructions, the result register class is controlled by the
+ // subregisters of the operand. As a result, we must constrain the result
+ // class rather than check that it's already the right one.
+ auto SuperClass = inferRegClassFromPattern(Dst->getChild(0));
+ if (!SuperClass)
+ return failedImport(
+ "Cannot infer register class from EXTRACT_SUBREG operand #0");
+
+ auto SubIdx = inferSubRegIndexForNode(Dst->getChild(1));
+ if (!SubIdx)
+ return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
+
+ const auto &SrcRCDstRCPair =
+ (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
+ assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
+ M.insertAction<ConstrainOperandToRegClassAction>(
+ InsertPt, DstMIBuilder.getInsnID(), 0, *SrcRCDstRCPair->second);
+ M.insertAction<ConstrainOperandToRegClassAction>(
+ InsertPt, DstMIBuilder.getInsnID(), 1, *SrcRCDstRCPair->first);
+
+ // We're done with this pattern! It's eligible for GISel emission; return
+ // it.
+ return InsertPtOrError.get();
+ }
+
+ // Similar to INSERT_SUBREG, we also have to handle SUBREG_TO_REG as a
+ // subinstruction.
+ if (OpName == "SUBREG_TO_REG") {
+ auto SubClass = inferRegClassFromPattern(Dst->getChild(1));
+ if (!SubClass)
+ return failedImport(
+ "Cannot infer register class from SUBREG_TO_REG child #1");
+ auto SuperClass = inferSuperRegisterClass(Dst->getExtType(0),
+ Dst->getChild(2));
+ if (!SuperClass)
+ return failedImport(
+ "Cannot infer register class for SUBREG_TO_REG operand #0");
+ M.insertAction<ConstrainOperandToRegClassAction>(
+ InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
+ M.insertAction<ConstrainOperandToRegClassAction>(
+ InsertPt, DstMIBuilder.getInsnID(), 2, **SubClass);
+ return InsertPtOrError.get();
+ }
+
M.insertAction<ConstrainOperandsToDefinitionAction>(InsertPt,
DstMIBuilder.getInsnID());
return InsertPtOrError.get();
@@ -3786,12 +4213,9 @@ Expected<action_iterator> GlobalISelEmitter::createInstructionRenderer(
// COPY_TO_REGCLASS is just a copy with a ConstrainOperandToRegClassAction
// attached. Similarly for EXTRACT_SUBREG except that's a subregister copy.
- if (DstI->TheDef->getName() == "COPY_TO_REGCLASS")
- DstI = &Target.getInstruction(RK.getDef("COPY"));
- else if (DstI->TheDef->getName() == "EXTRACT_SUBREG")
+ StringRef Name = DstI->TheDef->getName();
+ if (Name == "COPY_TO_REGCLASS" || Name == "EXTRACT_SUBREG")
DstI = &Target.getInstruction(RK.getDef("COPY"));
- else if (DstI->TheDef->getName() == "REG_SEQUENCE")
- return failedImport("Unable to emit REG_SEQUENCE");
return M.insertAction<BuildMIAction>(InsertPt, M.allocateOutputInsnID(),
DstI);
@@ -3812,8 +4236,11 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
const CodeGenInstruction *DstI = DstMIBuilder.getCGI();
CodeGenInstruction *OrigDstI = &Target.getInstruction(Dst->getOperator());
+ StringRef Name = OrigDstI->TheDef->getName();
+ unsigned ExpectedDstINumUses = Dst->getNumChildren();
+
// EXTRACT_SUBREG needs to use a subregister COPY.
- if (OrigDstI->TheDef->getName() == "EXTRACT_SUBREG") {
+ if (Name == "EXTRACT_SUBREG") {
if (!Dst->getChild(0)->isLeaf())
return failedImport("EXTRACT_SUBREG child #1 is not a leaf");
@@ -3843,10 +4270,41 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
}
+ if (Name == "REG_SEQUENCE") {
+ if (!Dst->getChild(0)->isLeaf())
+ return failedImport("REG_SEQUENCE child #0 is not a leaf");
+
+ Record *RCDef = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue());
+ if (!RCDef)
+ return failedImport("REG_SEQUENCE child #0 could not "
+ "be coerced to a register class");
+
+ if ((ExpectedDstINumUses - 1) % 2 != 0)
+ return failedImport("Malformed REG_SEQUENCE");
+
+ for (unsigned I = 1; I != ExpectedDstINumUses; I += 2) {
+ TreePatternNode *ValChild = Dst->getChild(I);
+ TreePatternNode *SubRegChild = Dst->getChild(I + 1);
+
+ if (DefInit *SubRegInit =
+ dyn_cast<DefInit>(SubRegChild->getLeafValue())) {
+ CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
+
+ auto InsertPtOrError =
+ importExplicitUseRenderer(InsertPt, M, DstMIBuilder, ValChild);
+ if (auto Error = InsertPtOrError.takeError())
+ return std::move(Error);
+ InsertPt = InsertPtOrError.get();
+ DstMIBuilder.addRenderer<SubRegIndexRenderer>(SubIdx);
+ }
+ }
+
+ return InsertPt;
+ }
+
// Render the explicit uses.
unsigned DstINumUses = OrigDstI->Operands.size() - OrigDstI->Operands.NumDefs;
- unsigned ExpectedDstINumUses = Dst->getNumChildren();
- if (OrigDstI->TheDef->getName() == "COPY_TO_REGCLASS") {
+ if (Name == "COPY_TO_REGCLASS") {
DstINumUses--; // Ignore the class constraint.
ExpectedDstINumUses--;
}
@@ -3945,6 +4403,126 @@ Error GlobalISelEmitter::importImplicitDefRenderers(
return Error::success();
}
+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;
+ CodeGenRegisterClass *RC = CGRegs.getRegClass(RCRec);
+ if (!RC)
+ return None;
+ return RC;
+}
+
+Optional<const CodeGenRegisterClass *>
+GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) {
+ if (!N)
+ return None;
+
+ if (N->isLeaf())
+ return getRegClassFromLeaf(N);
+
+ // We don't have a leaf node, so we have to try and infer something. Check
+ // that we have an instruction that we an infer something from.
+
+ // Only handle things that produce a single type.
+ if (N->getNumTypes() != 1)
+ return None;
+ Record *OpRec = N->getOperator();
+
+ // We only want instructions.
+ if (!OpRec->isSubClassOf("Instruction"))
+ return None;
+
+ // 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;
+
+ // Handle any special-case instructions which we can safely infer register
+ // classes from.
+ StringRef InstName = Inst.TheDef->getName();
+ bool IsRegSequence = InstName == "REG_SEQUENCE";
+ if (IsRegSequence || InstName == "COPY_TO_REGCLASS") {
+ // If we have a COPY_TO_REGCLASS, then we need to handle it specially. It
+ // has the desired register class as the first child.
+ TreePatternNode *RCChild = N->getChild(IsRegSequence ? 0 : 1);
+ if (!RCChild->isLeaf())
+ return None;
+ return getRegClassFromLeaf(RCChild);
+ }
+
+ // Handle destination record types that we can safely infer a register class
+ // from.
+ const auto &DstIOperand = Inst.Operands[0];
+ Record *DstIOpRec = DstIOperand.Rec;
+ if (DstIOpRec->isSubClassOf("RegisterOperand")) {
+ DstIOpRec = DstIOpRec->getValueAsDef("RegClass");
+ const CodeGenRegisterClass &RC = Target.getRegisterClass(DstIOpRec);
+ return &RC;
+ }
+
+ if (DstIOpRec->isSubClassOf("RegisterClass")) {
+ const CodeGenRegisterClass &RC = Target.getRegisterClass(DstIOpRec);
+ return &RC;
+ }
+
+ return None;
+}
+
+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;
+ if (!SubRegIdxNode->isLeaf())
+ return None;
+ DefInit *SubRegInit = dyn_cast<DefInit>(SubRegIdxNode->getLeafValue());
+ if (!SubRegInit)
+ return None;
+ CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
+
+ // Use the information we found above to find a minimal register class which
+ // supports the subregister and type we want.
+ auto RC =
+ Target.getSuperRegForSubReg(Ty.getValueTypeByHwMode(), CGRegs, SubIdx);
+ if (!RC)
+ return None;
+ return *RC;
+}
+
+Optional<const CodeGenRegisterClass *>
+GlobalISelEmitter::inferSuperRegisterClassForNode(
+ const TypeSetByHwMode &Ty, TreePatternNode *SuperRegNode,
+ TreePatternNode *SubRegIdxNode) {
+ assert(SuperRegNode && "Expected super register node!");
+ // Check if we already have a defined register class for the super register
+ // node. If we do, then we should preserve that rather than inferring anything
+ // 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 =
+ inferRegClassFromPattern(SuperRegNode))
+ return *SuperRegisterClass;
+ return inferSuperRegisterClass(Ty, SubRegIdxNode);
+}
+
+Optional<CodeGenSubRegIndex *>
+GlobalISelEmitter::inferSubRegIndexForNode(TreePatternNode *SubRegIdxNode) {
+ if (!SubRegIdxNode->isLeaf())
+ return None;
+
+ DefInit *SubRegInit = dyn_cast<DefInit>(SubRegIdxNode->getLeafValue());
+ if (!SubRegInit)
+ return None;
+ return CGRegs.getSubRegIdx(SubRegInit->getDef());
+}
+
Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// Keep track of the matchers and actions to emit.
int Score = P.getPatternComplexity(CGP);
@@ -4035,6 +4613,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
return failedImport("Pattern operator isn't an instruction");
auto &DstI = Target.getInstruction(DstOp);
+ StringRef DstIName = DstI.TheDef->getName();
+
if (DstI.Operands.NumDefs != Src->getExtTypes().size())
return failedImport("Src pattern results and dst MI defs are different (" +
to_string(Src->getExtTypes().size()) + " def(s) vs " +
@@ -4048,13 +4628,17 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
const auto &DstIOperand = DstI.Operands[OpIdx];
Record *DstIOpRec = DstIOperand.Rec;
- if (DstI.TheDef->getName() == "COPY_TO_REGCLASS") {
+ if (DstIName == "COPY_TO_REGCLASS") {
DstIOpRec = getInitValueAsRegClass(Dst->getChild(1)->getLeafValue());
if (DstIOpRec == nullptr)
return failedImport(
"COPY_TO_REGCLASS operand #1 isn't a register class");
- } else if (DstI.TheDef->getName() == "EXTRACT_SUBREG") {
+ } else if (DstIName == "REG_SEQUENCE") {
+ DstIOpRec = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue());
+ if (DstIOpRec == nullptr)
+ return failedImport("REG_SEQUENCE operand #0 isn't a register class");
+ } else if (DstIName == "EXTRACT_SUBREG") {
if (!Dst->getChild(0)->isLeaf())
return failedImport("EXTRACT_SUBREG operand #0 isn't a leaf");
@@ -4063,8 +4647,33 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
DstIOpRec = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue());
if (DstIOpRec == nullptr)
+ return failedImport("EXTRACT_SUBREG operand #0 isn't a register class");
+ } else if (DstIName == "INSERT_SUBREG") {
+ auto MaybeSuperClass = inferSuperRegisterClassForNode(
+ VTy, Dst->getChild(0), Dst->getChild(2));
+ if (!MaybeSuperClass)
return failedImport(
- "EXTRACT_SUBREG operand #0 isn't a register class");
+ "Cannot infer register class for INSERT_SUBREG operand #0");
+ // Move to the next pattern here, because the register class we found
+ // doesn't necessarily have a record associated with it. So, we can't
+ // set DstIOpRec using this.
+ OperandMatcher &OM = InsnMatcher.getOperand(OpIdx);
+ OM.setSymbolicName(DstIOperand.Name);
+ M.defineOperand(OM.getSymbolicName(), OM);
+ OM.addPredicate<RegisterBankOperandMatcher>(**MaybeSuperClass);
+ ++OpIdx;
+ continue;
+ } else if (DstIName == "SUBREG_TO_REG") {
+ auto MaybeRegClass = inferSuperRegisterClass(VTy, Dst->getChild(2));
+ if (!MaybeRegClass)
+ return failedImport(
+ "Cannot infer register class for SUBREG_TO_REG operand #0");
+ OperandMatcher &OM = InsnMatcher.getOperand(OpIdx);
+ OM.setSymbolicName(DstIOperand.Name);
+ M.defineOperand(OM.getSymbolicName(), OM);
+ OM.addPredicate<RegisterBankOperandMatcher>(**MaybeRegClass);
+ ++OpIdx;
+ continue;
} else if (DstIOpRec->isSubClassOf("RegisterOperand"))
DstIOpRec = DstIOpRec->getValueAsDef("RegClass");
else if (!DstIOpRec->isSubClassOf("RegisterClass"))
@@ -4079,7 +4688,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
++OpIdx;
}
- auto DstMIBuilderOrError = createAndImportInstructionRenderer(M, Dst);
+ auto DstMIBuilderOrError =
+ createAndImportInstructionRenderer(M, InsnMatcher, Src, Dst);
if (auto Error = DstMIBuilderOrError.takeError())
return std::move(Error);
BuildMIAction &DstMIBuilder = DstMIBuilderOrError.get();
@@ -4093,7 +4703,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// Constrain the registers to classes. This is normally derived from the
// emitted instruction but a few instructions require special handling.
- if (DstI.TheDef->getName() == "COPY_TO_REGCLASS") {
+ if (DstIName == "COPY_TO_REGCLASS") {
// COPY_TO_REGCLASS does not provide operand constraints itself but the
// result is constrained to the class given by the second child.
Record *DstIOpRec =
@@ -4111,28 +4721,16 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
return std::move(M);
}
- if (DstI.TheDef->getName() == "EXTRACT_SUBREG") {
- // EXTRACT_SUBREG selects into a subregister COPY but unlike most
- // instructions, the result register class is controlled by the
- // subregisters of the operand. As a result, we must constrain the result
- // class rather than check that it's already the right one.
- if (!Dst->getChild(0)->isLeaf())
- return failedImport("EXTRACT_SUBREG child #1 is not a leaf");
+ if (DstIName == "EXTRACT_SUBREG") {
+ auto SuperClass = inferRegClassFromPattern(Dst->getChild(0));
+ if (!SuperClass)
+ return failedImport(
+ "Cannot infer register class from EXTRACT_SUBREG operand #0");
- DefInit *SubRegInit = dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue());
- if (!SubRegInit)
+ auto SubIdx = inferSubRegIndexForNode(Dst->getChild(1));
+ if (!SubIdx)
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
- // Constrain the result to the same register bank as the operand.
- Record *DstIOpRec =
- getInitValueAsRegClass(Dst->getChild(0)->getLeafValue());
-
- if (DstIOpRec == nullptr)
- return failedImport("EXTRACT_SUBREG operand #1 isn't a register class");
-
- CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
- CodeGenRegisterClass *SrcRC = CGRegs.getRegClass(DstIOpRec);
-
// It would be nice to leave this constraint implicit but we're required
// to pick a register class so constrain the result to a register class
// that can hold the correct MVT.
@@ -4143,7 +4741,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
"Expected Src of EXTRACT_SUBREG to have one result type");
const auto &SrcRCDstRCPair =
- SrcRC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx);
+ (*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
M.addAction<ConstrainOperandToRegClassAction>(0, 0, *SrcRCDstRCPair->second);
M.addAction<ConstrainOperandToRegClassAction>(0, 1, *SrcRCDstRCPair->first);
@@ -4154,6 +4752,51 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
return std::move(M);
}
+ if (DstIName == "INSERT_SUBREG") {
+ assert(Src->getExtTypes().size() == 1 &&
+ "Expected Src of INSERT_SUBREG to have one result type");
+ // We need to constrain the destination, a super regsister source, and a
+ // subregister source.
+ auto SubClass = inferRegClassFromPattern(Dst->getChild(1));
+ if (!SubClass)
+ return failedImport(
+ "Cannot infer register class from INSERT_SUBREG operand #1");
+ auto SuperClass = inferSuperRegisterClassForNode(
+ Src->getExtType(0), Dst->getChild(0), Dst->getChild(2));
+ if (!SuperClass)
+ return failedImport(
+ "Cannot infer register class for INSERT_SUBREG operand #0");
+ M.addAction<ConstrainOperandToRegClassAction>(0, 0, **SuperClass);
+ M.addAction<ConstrainOperandToRegClassAction>(0, 1, **SuperClass);
+ M.addAction<ConstrainOperandToRegClassAction>(0, 2, **SubClass);
+ ++NumPatternImported;
+ return std::move(M);
+ }
+
+ if (DstIName == "SUBREG_TO_REG") {
+ // We need to constrain the destination and subregister source.
+ assert(Src->getExtTypes().size() == 1 &&
+ "Expected Src of SUBREG_TO_REG to have one result type");
+
+ // Attempt to infer the subregister source from the first child. If it has
+ // an explicitly given register class, we'll use that. Otherwise, we will
+ // fail.
+ auto SubClass = inferRegClassFromPattern(Dst->getChild(1));
+ if (!SubClass)
+ return failedImport(
+ "Cannot infer register class from SUBREG_TO_REG child #1");
+ // We don't have a child to look at that might have a super register node.
+ auto SuperClass =
+ inferSuperRegisterClass(Src->getExtType(0), Dst->getChild(2));
+ if (!SuperClass)
+ return failedImport(
+ "Cannot infer register class for SUBREG_TO_REG operand #0");
+ M.addAction<ConstrainOperandToRegClassAction>(0, 0, **SuperClass);
+ M.addAction<ConstrainOperandToRegClassAction>(0, 2, **SubClass);
+ ++NumPatternImported;
+ return std::move(M);
+ }
+
M.addAction<ConstrainOperandsToDefinitionAction>(0);
// We're done with this pattern! It's eligible for GISel emission; return it.
@@ -4235,7 +4878,7 @@ std::vector<Matcher *> GlobalISelEmitter::optimizeRules(
std::vector<std::unique_ptr<Matcher>> &MatcherStorage) {
std::vector<Matcher *> OptRules;
- std::unique_ptr<GroupT> CurrentGroup = make_unique<GroupT>();
+ std::unique_ptr<GroupT> CurrentGroup = std::make_unique<GroupT>();
assert(CurrentGroup->empty() && "Newly created group isn't empty!");
unsigned NumGroups = 0;
@@ -4256,7 +4899,7 @@ std::vector<Matcher *> GlobalISelEmitter::optimizeRules(
MatcherStorage.emplace_back(std::move(CurrentGroup));
++NumGroups;
}
- CurrentGroup = make_unique<GroupT>();
+ CurrentGroup = std::make_unique<GroupT>();
};
for (Matcher *Rule : Rules) {
// Greedily add as many matchers as possible to the current group:
diff --git a/utils/TableGen/InfoByHwMode.cpp b/utils/TableGen/InfoByHwMode.cpp
index d9662889a5db..7cd1b0f08132 100644
--- a/utils/TableGen/InfoByHwMode.cpp
+++ b/utils/TableGen/InfoByHwMode.cpp
@@ -192,6 +192,17 @@ void RegSizeInfoByHwMode::writeToStream(raw_ostream &OS) const {
OS << '}';
}
+EncodingInfoByHwMode::EncodingInfoByHwMode(Record *R, const CodeGenHwModes &CGH) {
+ const HwModeSelect &MS = CGH.getHwModeSelect(R);
+ for (const HwModeSelect::PairType &P : MS.Items) {
+ assert(P.second && P.second->isSubClassOf("InstructionEncoding") &&
+ "Encoding must subclass InstructionEncoding");
+ auto I = Map.insert({P.first, P.second});
+ assert(I.second && "Duplicate entry?");
+ (void)I;
+ }
+}
+
namespace llvm {
raw_ostream &operator<<(raw_ostream &OS, const ValueTypeByHwMode &T) {
T.writeToStream(OS);
diff --git a/utils/TableGen/InfoByHwMode.h b/utils/TableGen/InfoByHwMode.h
index 9e5cc3d5f2a4..d92e5901a7f3 100644
--- a/utils/TableGen/InfoByHwMode.h
+++ b/utils/TableGen/InfoByHwMode.h
@@ -184,6 +184,11 @@ raw_ostream &operator<<(raw_ostream &OS, const ValueTypeByHwMode &T);
raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfo &T);
raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfoByHwMode &T);
+struct EncodingInfoByHwMode : public InfoByHwMode<Record*> {
+ EncodingInfoByHwMode(Record *R, const CodeGenHwModes &CGH);
+ EncodingInfoByHwMode() = default;
+};
+
} // namespace llvm
#endif // LLVM_UTILS_TABLEGEN_INFOBYHWMODE_H
diff --git a/utils/TableGen/InstrDocsEmitter.cpp b/utils/TableGen/InstrDocsEmitter.cpp
index 91c457ba08fd..45fa936b9574 100644
--- a/utils/TableGen/InstrDocsEmitter.cpp
+++ b/utils/TableGen/InstrDocsEmitter.cpp
@@ -231,4 +231,4 @@ void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
}
}
-} // end llvm namespace
+} // end namespace llvm
diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
index 2d367f538b71..300ba36a7007 100644
--- a/utils/TableGen/InstrInfoEmitter.cpp
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -332,6 +332,10 @@ void InstrInfoEmitter::emitOperandTypeMappings(
StringRef Namespace = Target.getInstNamespace();
std::vector<Record *> Operands = Records.getAllDerivedDefinitions("Operand");
+ std::vector<Record *> RegisterOperands =
+ Records.getAllDerivedDefinitions("RegisterOperand");
+ std::vector<Record *> RegisterClasses =
+ Records.getAllDerivedDefinitions("RegisterClass");
OS << "#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n";
OS << "#undef GET_INSTRINFO_OPERAND_TYPES_ENUM\n";
@@ -341,10 +345,13 @@ void InstrInfoEmitter::emitOperandTypeMappings(
OS << "enum OperandType {\n";
unsigned EnumVal = 0;
- for (const Record *Op : Operands) {
- if (!Op->isAnonymous())
- OS << " " << Op->getName() << " = " << EnumVal << ",\n";
- ++EnumVal;
+ for (const std::vector<Record *> *RecordsToAdd :
+ {&Operands, &RegisterOperands, &RegisterClasses}) {
+ for (const Record *Op : *RecordsToAdd) {
+ if (!Op->isAnonymous())
+ OS << " " << Op->getName() << " = " << EnumVal << ",\n";
+ ++EnumVal;
+ }
}
OS << " OPERAND_TYPE_LIST_END" << "\n};\n";
@@ -358,7 +365,8 @@ void InstrInfoEmitter::emitOperandTypeMappings(
OS << "namespace llvm {\n";
OS << "namespace " << Namespace << " {\n";
OS << "LLVM_READONLY\n";
- OS << "int getOperandType(uint16_t Opcode, uint16_t OpIdx) {\n";
+ OS << "static int getOperandType(uint16_t Opcode, uint16_t OpIdx) {\n";
+ // TODO: Factor out instructions with same operands to compress the tables.
if (!NumberedInstructions.empty()) {
std::vector<int> OperandOffsets;
std::vector<Record *> OperandRecords;
@@ -399,7 +407,10 @@ void InstrInfoEmitter::emitOperandTypeMappings(
OS << "/**/\n ";
}
Record *OpR = OperandRecords[I];
- if (OpR->isSubClassOf("Operand") && !OpR->isAnonymous())
+ if ((OpR->isSubClassOf("Operand") ||
+ OpR->isSubClassOf("RegisterOperand") ||
+ OpR->isSubClassOf("RegisterClass")) &&
+ !OpR->isAnonymous())
OS << "OpTypes::" << OpR->getName();
else
OS << -1;
@@ -414,7 +425,7 @@ void InstrInfoEmitter::emitOperandTypeMappings(
OS << "}\n";
OS << "} // end namespace " << Namespace << "\n";
OS << "} // end namespace llvm\n";
- OS << "#endif //GET_INSTRINFO_OPERAND_TYPE\n\n";
+ OS << "#endif // GET_INSTRINFO_OPERAND_TYPE\n\n";
}
void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS,
@@ -436,8 +447,8 @@ void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS,
<< "(const MCInst &MI);\n";
}
- OS << "\n} // end " << TargetName << "_MC namespace\n";
- OS << "} // end llvm namespace\n\n";
+ OS << "\n} // end namespace " << TargetName << "_MC\n";
+ OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_INSTRINFO_MC_HELPER_DECLS\n\n";
@@ -459,8 +470,8 @@ void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS,
OS << "\n}\n\n";
}
- OS << "} // end " << TargetName << "_MC namespace\n";
- OS << "} // end llvm namespace\n\n";
+ OS << "} // end namespace " << TargetName << "_MC\n";
+ OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_GENISTRINFO_MC_HELPERS\n";
}
@@ -576,7 +587,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
<< TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, "
<< NumberedInstructions.size() << ");\n}\n\n";
- OS << "} // end llvm namespace\n";
+ OS << "} // end namespace llvm\n";
OS << "#endif // GET_INSTRINFO_MC_DESC\n\n";
@@ -592,7 +603,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
<< " ~" << ClassName << "() override = default;\n";
- OS << "\n};\n} // end llvm namespace\n";
+ OS << "\n};\n} // end namespace llvm\n";
OS << "#endif // GET_INSTRINFO_HEADER\n\n";
@@ -620,7 +631,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
<< " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName
<< "InstrNameIndices, " << TargetName << "InstrNameData, "
<< NumberedInstructions.size() << ");\n}\n";
- OS << "} // end llvm namespace\n";
+ OS << "} // end namespace llvm\n";
OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n";
@@ -651,6 +662,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
CodeGenTarget &Target = CDP.getTargetInfo();
// Emit all of the target independent flags...
+ if (Inst.isPreISelOpcode) OS << "|(1ULL<<MCID::PreISelOpcode)";
if (Inst.isPseudo) OS << "|(1ULL<<MCID::Pseudo)";
if (Inst.isReturn) OS << "|(1ULL<<MCID::Return)";
if (Inst.isEHScopeReturn) OS << "|(1ULL<<MCID::EHScopeReturn)";
@@ -765,8 +777,8 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) {
OS << " " << Inst->TheDef->getName() << "\t= " << Num++ << ",\n";
OS << " INSTRUCTION_LIST_END = " << Num << "\n";
OS << " };\n\n";
- OS << "} // end " << Namespace << " namespace\n";
- OS << "} // end llvm namespace\n";
+ OS << "} // end namespace " << Namespace << "\n";
+ OS << "} // end namespace llvm\n";
OS << "#endif // GET_INSTRINFO_ENUM\n\n";
OS << "#ifdef GET_INSTRINFO_SCHED_ENUM\n";
@@ -780,9 +792,9 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) {
OS << " " << Class.Name << "\t= " << Num++ << ",\n";
OS << " SCHED_LIST_END = " << Num << "\n";
OS << " };\n";
- OS << "} // end Sched namespace\n";
- OS << "} // end " << Namespace << " namespace\n";
- OS << "} // end llvm namespace\n";
+ OS << "} // end namespace Sched\n";
+ OS << "} // end namespace " << Namespace << "\n";
+ OS << "} // end namespace llvm\n";
OS << "#endif // GET_INSTRINFO_SCHED_ENUM\n\n";
}
@@ -794,4 +806,4 @@ void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS) {
EmitMapTable(RK, OS);
}
-} // end llvm namespace
+} // end namespace llvm
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
index 979af98f6768..e01f91c20456 100644
--- a/utils/TableGen/IntrinsicEmitter.cpp
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -220,7 +220,11 @@ enum IIT_Info {
IIT_STRUCT7 = 39,
IIT_STRUCT8 = 40,
IIT_F128 = 41,
- IIT_VEC_ELEMENT = 42
+ IIT_VEC_ELEMENT = 42,
+ IIT_SCALABLE_VEC = 43,
+ IIT_SUBDIVIDE2_ARG = 44,
+ IIT_SUBDIVIDE4_ARG = 45,
+ IIT_VEC_OF_BITCASTS_TO_INT = 46
};
static void EncodeFixedValueType(MVT::SimpleValueType VT,
@@ -292,6 +296,12 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
Sig.push_back(IIT_PTR_TO_ELT);
else if (R->isSubClassOf("LLVMVectorElementType"))
Sig.push_back(IIT_VEC_ELEMENT);
+ else if (R->isSubClassOf("LLVMSubdivide2VectorType"))
+ Sig.push_back(IIT_SUBDIVIDE2_ARG);
+ else if (R->isSubClassOf("LLVMSubdivide4VectorType"))
+ Sig.push_back(IIT_SUBDIVIDE4_ARG);
+ else if (R->isSubClassOf("LLVMVectorOfBitcastsToInt"))
+ Sig.push_back(IIT_VEC_OF_BITCASTS_TO_INT);
else
Sig.push_back(IIT_ARG);
return Sig.push_back((Number << 3) | 7 /*IITDescriptor::AK_MatchType*/);
@@ -339,6 +349,8 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
if (MVT(VT).isVector()) {
MVT VVT = VT;
+ if (VVT.isScalableVector())
+ Sig.push_back(IIT_SCALABLE_VEC);
switch (VVT.getVectorNumElements()) {
default: PrintFatalError("unhandled vector type width in intrinsic!");
case 1: Sig.push_back(IIT_V1); break;
@@ -647,6 +659,12 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
OS << "Attribute::NoCapture";
addComma = true;
break;
+ case CodeGenIntrinsic::NoAlias:
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::NoAlias";
+ addComma = true;
+ break;
case CodeGenIntrinsic::Returned:
if (addComma)
OS << ",";
diff --git a/utils/TableGen/RISCVCompressInstEmitter.cpp b/utils/TableGen/RISCVCompressInstEmitter.cpp
index e62f528ebc2e..2f1d3898f182 100644
--- a/utils/TableGen/RISCVCompressInstEmitter.cpp
+++ b/utils/TableGen/RISCVCompressInstEmitter.cpp
@@ -411,12 +411,8 @@ void RISCVCompressInstEmitter::evaluateCompressPat(Record *Rec) {
assert(SourceDag && "Missing 'Input' in compress pattern!");
LLVM_DEBUG(dbgs() << "Input: " << *SourceDag << "\n");
- DefInit *OpDef = dyn_cast<DefInit>(SourceDag->getOperator());
- if (!OpDef)
- PrintFatalError(Rec->getLoc(),
- Rec->getName() + " has unexpected operator type!");
// Checking we are transforming from compressed to uncompressed instructions.
- Record *Operator = OpDef->getDef();
+ Record *Operator = SourceDag->getOperatorAsDef(Rec->getLoc());
if (!Operator->isSubClassOf("RVInst"))
PrintFatalError(Rec->getLoc(), "Input instruction '" + Operator->getName() +
"' is not a 32 bit wide instruction!");
@@ -428,12 +424,7 @@ void RISCVCompressInstEmitter::evaluateCompressPat(Record *Rec) {
assert(DestDag && "Missing 'Output' in compress pattern!");
LLVM_DEBUG(dbgs() << "Output: " << *DestDag << "\n");
- DefInit *DestOpDef = dyn_cast<DefInit>(DestDag->getOperator());
- if (!DestOpDef)
- PrintFatalError(Rec->getLoc(),
- Rec->getName() + " has unexpected operator type!");
-
- Record *DestOperator = DestOpDef->getDef();
+ Record *DestOperator = DestDag->getOperatorAsDef(Rec->getLoc());
if (!DestOperator->isSubClassOf("RVInst16"))
PrintFatalError(Rec->getLoc(), "Output instruction '" +
DestOperator->getName() +
diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp
index 1b619072c814..513cd14e0fab 100644
--- a/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/utils/TableGen/RegisterInfoEmitter.cpp
@@ -888,7 +888,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
// Keep track of sub-register names as well. These are not differentially
// encoded.
typedef SmallVector<const CodeGenSubRegIndex*, 4> SubRegIdxVec;
- SequenceToOffsetTable<SubRegIdxVec, deref<llvm::less>> SubRegIdxSeqs;
+ SequenceToOffsetTable<SubRegIdxVec, deref<std::less<>>> SubRegIdxSeqs;
SmallVector<SubRegIdxVec, 4> SubRegIdxLists(Regs.size());
SequenceToOffsetTable<std::string> RegStrings;
@@ -1315,7 +1315,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
// Compress the sub-reg index lists.
typedef std::vector<const CodeGenSubRegIndex*> IdxList;
SmallVector<IdxList, 8> SuperRegIdxLists(RegisterClasses.size());
- SequenceToOffsetTable<IdxList, deref<llvm::less>> SuperRegIdxSeqs;
+ SequenceToOffsetTable<IdxList, deref<std::less<>>> SuperRegIdxSeqs;
BitVector MaskBV(RegisterClasses.size());
for (const auto &RC : RegisterClasses) {
diff --git a/utils/TableGen/SearchableTableEmitter.cpp b/utils/TableGen/SearchableTableEmitter.cpp
index 954b63e7253c..f08f8aa01956 100644
--- a/utils/TableGen/SearchableTableEmitter.cpp
+++ b/utils/TableGen/SearchableTableEmitter.cpp
@@ -134,7 +134,7 @@ private:
CodeGenIntrinsic &getIntrinsic(Init *I) {
std::unique_ptr<CodeGenIntrinsic> &Intr = Intrinsics[I];
if (!Intr)
- Intr = make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef());
+ Intr = std::make_unique<CodeGenIntrinsic>(cast<DefInit>(I)->getDef());
return *Intr;
}
@@ -496,7 +496,7 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS);
// The primary data table contains all the fields defined for this map.
- OS << "const " << Table.CppTypeName << " " << Table.Name << "[] = {\n";
+ OS << "constexpr " << Table.CppTypeName << " " << Table.Name << "[] = {\n";
for (unsigned i = 0; i < Table.Entries.size(); ++i) {
Record *Entry = Table.Entries[i];
OS << " { ";
@@ -541,7 +541,7 @@ std::unique_ptr<SearchIndex>
SearchableTableEmitter::parseSearchIndex(GenericTable &Table, StringRef Name,
const std::vector<StringRef> &Key,
bool EarlyOut) {
- auto Index = llvm::make_unique<SearchIndex>();
+ auto Index = std::make_unique<SearchIndex>();
Index->Name = Name;
Index->EarlyOut = EarlyOut;
@@ -577,7 +577,7 @@ void SearchableTableEmitter::collectEnumEntries(
if (!ValueField.empty())
Value = getInt(EntryRec, ValueField);
- Enum.Entries.push_back(llvm::make_unique<GenericEnum::Entry>(Name, Value));
+ Enum.Entries.push_back(std::make_unique<GenericEnum::Entry>(Name, Value));
Enum.EntryMap.insert(std::make_pair(EntryRec, Enum.Entries.back().get()));
}
@@ -647,7 +647,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
if (!EnumRec->isValueUnset("ValueField"))
ValueField = EnumRec->getValueAsString("ValueField");
- auto Enum = llvm::make_unique<GenericEnum>();
+ auto Enum = std::make_unique<GenericEnum>();
Enum->Name = EnumRec->getName();
Enum->PreprocessorGuard = EnumRec->getName();
@@ -664,7 +664,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
}
for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) {
- auto Table = llvm::make_unique<GenericTable>();
+ auto Table = std::make_unique<GenericTable>();
Table->Name = TableRec->getName();
Table->PreprocessorGuard = TableRec->getName();
Table->CppTypeName = TableRec->getValueAsString("CppTypeName");
@@ -733,7 +733,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
if (!Class->isValueUnset("EnumValueField"))
ValueField = Class->getValueAsString("EnumValueField");
- auto Enum = llvm::make_unique<GenericEnum>();
+ auto Enum = std::make_unique<GenericEnum>();
Enum->Name = (Twine(Class->getName()) + "Values").str();
Enum->PreprocessorGuard = Class->getName().upper();
Enum->Class = Class;
@@ -743,7 +743,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
Enums.emplace_back(std::move(Enum));
}
- auto Table = llvm::make_unique<GenericTable>();
+ auto Table = std::make_unique<GenericTable>();
Table->Name = (Twine(Class->getName()) + "sList").str();
Table->PreprocessorGuard = Class->getName().upper();
Table->CppTypeName = Class->getName();
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
index 9ce2b3b275c8..9b094adb7d5c 100644
--- a/utils/TableGen/SubtargetEmitter.cpp
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -1057,6 +1057,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
LLVM_DEBUG(dbgs() << ProcModel.ModelName
<< " does not have resources for class " << SC.Name
<< '\n');
+ SCDesc.NumMicroOps = MCSchedClassDesc::InvalidNumMicroOps;
}
}
// Sum resources across all operand writes.
@@ -1728,7 +1729,7 @@ void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
<< " const MCInst *MI, unsigned CPUID) {\n";
emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true);
OS << "}\n";
- OS << "} // end of namespace " << Target << "_MC\n\n";
+ OS << "} // end namespace " << Target << "_MC\n\n";
OS << "struct " << Target
<< "GenMCSubtargetInfo : public MCSubtargetInfo {\n";
@@ -1746,7 +1747,10 @@ void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
<< " return " << Target << "_MC"
<< "::resolveVariantSchedClassImpl(SchedClass, MI, CPUID); \n";
OS << " }\n";
+ if (TGT.getHwModes().getNumModeIds() > 1)
+ OS << " unsigned getHwMode() const override;\n";
OS << "};\n";
+ EmitHwModeCheck(Target + "GenMCSubtargetInfo", OS);
}
void SubtargetEmitter::EmitMCInstrAnalysisPredicateFunctions(raw_ostream &OS) {
@@ -1858,7 +1862,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "namespace " << Target << "_MC {\n"
<< "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,"
<< " const MCInst *MI, unsigned CPUID);\n"
- << "}\n\n";
+ << "} // end namespace " << Target << "_MC\n\n";
OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
<< " explicit " << ClassName << "(const Triple &TT, StringRef CPU, "
<< "StringRef FS);\n"
diff --git a/utils/TableGen/SubtargetFeatureInfo.cpp b/utils/TableGen/SubtargetFeatureInfo.cpp
index edf0b4a01c6d..5430f73d5e09 100644
--- a/utils/TableGen/SubtargetFeatureInfo.cpp
+++ b/utils/TableGen/SubtargetFeatureInfo.cpp
@@ -38,6 +38,10 @@ SubtargetFeatureInfo::getAll(const RecordKeeper &Records) {
if (Pred->getName().empty())
PrintFatalError(Pred->getLoc(), "Predicate has no name!");
+ // Ignore always true predicates.
+ if (Pred->getValueAsString("CondString").empty())
+ continue;
+
SubtargetFeatures.emplace_back(
Pred, SubtargetFeatureInfo(Pred, SubtargetFeatures.size()));
}
@@ -95,9 +99,11 @@ void SubtargetFeatureInfo::emitComputeAvailableFeatures(
OS << " PredicateBitset Features;\n";
for (const auto &SF : SubtargetFeatures) {
const SubtargetFeatureInfo &SFI = SF.second;
+ StringRef CondStr = SFI.TheDef->getValueAsString("CondString");
+ assert(!CondStr.empty() && "true predicate should have been filtered");
- OS << " if (" << SFI.TheDef->getValueAsString("CondString") << ")\n";
- OS << " Features[" << SFI.getEnumBitName() << "] = 1;\n";
+ OS << " if (" << CondStr << ")\n";
+ OS << " Features.set(" << SFI.getEnumBitName() << ");\n";
}
OS << " return Features;\n";
OS << "}\n\n";
@@ -142,7 +148,7 @@ void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
} while (true);
OS << ")\n";
- OS << " Features[" << SFI.getEnumBitName() << "] = 1;\n";
+ OS << " Features.set(" << SFI.getEnumBitName() << ");\n";
}
OS << " return Features;\n";
OS << "}\n\n";
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index c485ed2feb7a..f730d91160ad 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -49,10 +49,12 @@ enum ActionType {
GenAttributes,
GenSearchableTables,
GenGlobalISel,
+ GenGICombiner,
GenX86EVEX2VEXTables,
GenX86FoldTables,
GenRegisterBank,
GenExegesis,
+ GenAutomata,
};
namespace llvm {
@@ -62,75 +64,75 @@ bool TimeRegions = false;
} // end namespace llvm
namespace {
- cl::opt<ActionType>
- Action(cl::desc("Action to perform:"),
- cl::values(clEnumValN(PrintRecords, "print-records",
- "Print all records to stdout (default)"),
- clEnumValN(DumpJSON, "dump-json",
- "Dump all records as machine-readable JSON"),
- clEnumValN(GenEmitter, "gen-emitter",
- "Generate machine code emitter"),
- clEnumValN(GenRegisterInfo, "gen-register-info",
- "Generate registers and register classes info"),
- clEnumValN(GenInstrInfo, "gen-instr-info",
- "Generate instruction descriptions"),
- clEnumValN(GenInstrDocs, "gen-instr-docs",
- "Generate instruction documentation"),
- clEnumValN(GenCallingConv, "gen-callingconv",
- "Generate calling convention descriptions"),
- clEnumValN(GenAsmWriter, "gen-asm-writer",
- "Generate assembly writer"),
- clEnumValN(GenDisassembler, "gen-disassembler",
- "Generate disassembler"),
- clEnumValN(GenPseudoLowering, "gen-pseudo-lowering",
- "Generate pseudo instruction lowering"),
- clEnumValN(GenCompressInst, "gen-compress-inst-emitter",
- "Generate RISCV compressed instructions."),
- clEnumValN(GenAsmMatcher, "gen-asm-matcher",
- "Generate assembly instruction matcher"),
- clEnumValN(GenDAGISel, "gen-dag-isel",
- "Generate a DAG instruction selector"),
- clEnumValN(GenDFAPacketizer, "gen-dfa-packetizer",
- "Generate DFA Packetizer for VLIW targets"),
- clEnumValN(GenFastISel, "gen-fast-isel",
- "Generate a \"fast\" instruction selector"),
- clEnumValN(GenSubtarget, "gen-subtarget",
- "Generate subtarget enumerations"),
- clEnumValN(GenIntrinsicEnums, "gen-intrinsic-enums",
- "Generate intrinsic enums"),
- clEnumValN(GenIntrinsicImpl, "gen-intrinsic-impl",
- "Generate intrinsic information"),
- clEnumValN(GenTgtIntrinsicEnums, "gen-tgt-intrinsic-enums",
- "Generate target intrinsic enums"),
- clEnumValN(GenTgtIntrinsicImpl, "gen-tgt-intrinsic-impl",
- "Generate target intrinsic information"),
- clEnumValN(PrintEnums, "print-enums",
- "Print enum values for a class"),
- clEnumValN(PrintSets, "print-sets",
- "Print expanded sets for testing DAG exprs"),
- clEnumValN(GenOptParserDefs, "gen-opt-parser-defs",
- "Generate option definitions"),
- clEnumValN(GenCTags, "gen-ctags",
- "Generate ctags-compatible index"),
- clEnumValN(GenAttributes, "gen-attrs",
- "Generate attributes"),
- clEnumValN(GenSearchableTables, "gen-searchable-tables",
- "Generate generic binary-searchable table"),
- clEnumValN(GenGlobalISel, "gen-global-isel",
- "Generate GlobalISel selector"),
- clEnumValN(GenX86EVEX2VEXTables, "gen-x86-EVEX2VEX-tables",
- "Generate X86 EVEX to VEX compress tables"),
- clEnumValN(GenX86FoldTables, "gen-x86-fold-tables",
- "Generate X86 fold tables"),
- clEnumValN(GenRegisterBank, "gen-register-bank",
- "Generate registers bank descriptions"),
- clEnumValN(GenExegesis, "gen-exegesis",
- "Generate llvm-exegesis tables")));
+cl::opt<ActionType> Action(
+ cl::desc("Action to perform:"),
+ cl::values(
+ clEnumValN(PrintRecords, "print-records",
+ "Print all records to stdout (default)"),
+ clEnumValN(DumpJSON, "dump-json",
+ "Dump all records as machine-readable JSON"),
+ clEnumValN(GenEmitter, "gen-emitter", "Generate machine code emitter"),
+ clEnumValN(GenRegisterInfo, "gen-register-info",
+ "Generate registers and register classes info"),
+ clEnumValN(GenInstrInfo, "gen-instr-info",
+ "Generate instruction descriptions"),
+ clEnumValN(GenInstrDocs, "gen-instr-docs",
+ "Generate instruction documentation"),
+ clEnumValN(GenCallingConv, "gen-callingconv",
+ "Generate calling convention descriptions"),
+ clEnumValN(GenAsmWriter, "gen-asm-writer", "Generate assembly writer"),
+ clEnumValN(GenDisassembler, "gen-disassembler",
+ "Generate disassembler"),
+ clEnumValN(GenPseudoLowering, "gen-pseudo-lowering",
+ "Generate pseudo instruction lowering"),
+ clEnumValN(GenCompressInst, "gen-compress-inst-emitter",
+ "Generate RISCV compressed instructions."),
+ clEnumValN(GenAsmMatcher, "gen-asm-matcher",
+ "Generate assembly instruction matcher"),
+ clEnumValN(GenDAGISel, "gen-dag-isel",
+ "Generate a DAG instruction selector"),
+ clEnumValN(GenDFAPacketizer, "gen-dfa-packetizer",
+ "Generate DFA Packetizer for VLIW targets"),
+ clEnumValN(GenFastISel, "gen-fast-isel",
+ "Generate a \"fast\" instruction selector"),
+ clEnumValN(GenSubtarget, "gen-subtarget",
+ "Generate subtarget enumerations"),
+ clEnumValN(GenIntrinsicEnums, "gen-intrinsic-enums",
+ "Generate intrinsic enums"),
+ clEnumValN(GenIntrinsicImpl, "gen-intrinsic-impl",
+ "Generate intrinsic information"),
+ clEnumValN(GenTgtIntrinsicEnums, "gen-tgt-intrinsic-enums",
+ "Generate target intrinsic enums"),
+ clEnumValN(GenTgtIntrinsicImpl, "gen-tgt-intrinsic-impl",
+ "Generate target intrinsic information"),
+ clEnumValN(PrintEnums, "print-enums", "Print enum values for a class"),
+ clEnumValN(PrintSets, "print-sets",
+ "Print expanded sets for testing DAG exprs"),
+ clEnumValN(GenOptParserDefs, "gen-opt-parser-defs",
+ "Generate option definitions"),
+ clEnumValN(GenCTags, "gen-ctags", "Generate ctags-compatible index"),
+ clEnumValN(GenAttributes, "gen-attrs", "Generate attributes"),
+ clEnumValN(GenSearchableTables, "gen-searchable-tables",
+ "Generate generic binary-searchable table"),
+ clEnumValN(GenGlobalISel, "gen-global-isel",
+ "Generate GlobalISel selector"),
+ clEnumValN(GenGICombiner, "gen-global-isel-combiner",
+ "Generate GlobalISel combiner"),
+ clEnumValN(GenX86EVEX2VEXTables, "gen-x86-EVEX2VEX-tables",
+ "Generate X86 EVEX to VEX compress tables"),
+ clEnumValN(GenX86FoldTables, "gen-x86-fold-tables",
+ "Generate X86 fold tables"),
+ clEnumValN(GenRegisterBank, "gen-register-bank",
+ "Generate registers bank descriptions"),
+ clEnumValN(GenExegesis, "gen-exegesis",
+ "Generate llvm-exegesis tables"),
+ clEnumValN(GenAutomata, "gen-automata",
+ "Generate generic automata")));
- 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"), cl::cat(PrintEnumsCat));
+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"),
+ cl::cat(PrintEnumsCat));
cl::opt<bool, true>
TimeRegionsOpt("time-regions",
@@ -235,6 +237,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenGlobalISel:
EmitGlobalISel(Records, OS);
break;
+ case GenGICombiner:
+ EmitGICombiner(Records, OS);
+ break;
case GenRegisterBank:
EmitRegisterBank(Records, OS);
break;
@@ -247,6 +252,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenExegesis:
EmitExegesis(Records, OS);
break;
+ case GenAutomata:
+ EmitAutomata(Records, OS);
+ break;
}
return false;
@@ -263,11 +271,16 @@ int main(int argc, char **argv) {
return TableGenMain(argv[0], &LLVMTableGenMain);
}
-#ifdef __has_feature
-#if __has_feature(address_sanitizer)
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) || \
+ __has_feature(leak_sanitizer)
+
#include <sanitizer/lsan_interface.h>
// Disable LeakSanitizer for this binary as it has too many leaks that are not
// very interesting to fix. See compiler-rt/include/sanitizer/lsan_interface.h .
LLVM_ATTRIBUTE_USED int __lsan_is_turned_off() { return 1; }
-#endif // __has_feature(address_sanitizer)
-#endif // defined(__has_feature)
+
+#endif
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index 135ec65c0f95..8c067dd51b3b 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -85,10 +85,12 @@ void EmitCTags(RecordKeeper &RK, raw_ostream &OS);
void EmitAttributes(RecordKeeper &RK, raw_ostream &OS);
void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS);
void EmitGlobalISel(RecordKeeper &RK, raw_ostream &OS);
+void EmitGICombiner(RecordKeeper &RK, raw_ostream &OS);
void EmitX86EVEX2VEXTables(RecordKeeper &RK, raw_ostream &OS);
void EmitX86FoldTables(RecordKeeper &RK, raw_ostream &OS);
void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS);
void EmitExegesis(RecordKeeper &RK, raw_ostream &OS);
+void EmitAutomata(RecordKeeper &RK, raw_ostream &OS);
} // End llvm namespace
diff --git a/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp b/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp
index 365cba5a60ca..54aa5a8164f2 100644
--- a/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp
+++ b/utils/TableGen/WebAssemblyDisassemblerEmitter.cpp
@@ -167,7 +167,7 @@ void emitWebAssemblyDisassemblerTables(
OS << " },\n";
}
OS << " { 0, nullptr }\n};\n\n";
- OS << "} // End llvm namespace\n";
+ OS << "} // end namespace llvm\n";
}
} // namespace llvm
diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp
index 8036aecc4f4b..14bce4c29446 100644
--- a/utils/TableGen/X86DisassemblerTables.cpp
+++ b/utils/TableGen/X86DisassemblerTables.cpp
@@ -651,7 +651,7 @@ static const char* stringForDecisionType(ModRMDecisionType dt) {
DisassemblerTables::DisassemblerTables() {
for (unsigned i = 0; i < array_lengthof(Tables); i++)
- Tables[i] = llvm::make_unique<ContextDecision>();
+ Tables[i] = std::make_unique<ContextDecision>();
HasConflicts = false;
}
diff --git a/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp b/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp
index 3df14f40e4a9..6dc7e31e0dab 100644
--- a/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp
+++ b/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp
@@ -98,6 +98,7 @@ public:
bool EVEX_W1_VEX_W0 = RecE->getValueAsBit("EVEX_W1_VEX_W0");
if (RecV->getValueAsDef("OpEnc")->getName().str() != "EncVEX" ||
+ RecV->getValueAsBit("isCodeGenOnly") != RecE->getValueAsBit("isCodeGenOnly") ||
// VEX/EVEX fields
RecV->getValueAsDef("OpPrefix") != RecE->getValueAsDef("OpPrefix") ||
RecV->getValueAsDef("OpMap") != RecE->getValueAsDef("OpMap") ||
diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp
index ab8a8855c478..33dc6f3f9e23 100644
--- a/utils/TableGen/X86RecognizableInstr.cpp
+++ b/utils/TableGen/X86RecognizableInstr.cpp
@@ -749,7 +749,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
case X86Local::RawFrmImm8:
case X86Local::RawFrmImm16:
case X86Local::AddCCFrm:
- filter = llvm::make_unique<DumbFilter>();
+ filter = std::make_unique<DumbFilter>();
break;
case X86Local::MRMDestReg:
case X86Local::MRMSrcReg:
@@ -758,7 +758,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
case X86Local::MRMSrcRegCC:
case X86Local::MRMXrCC:
case X86Local::MRMXr:
- filter = llvm::make_unique<ModFilter>(true);
+ filter = std::make_unique<ModFilter>(true);
break;
case X86Local::MRMDestMem:
case X86Local::MRMSrcMem:
@@ -767,22 +767,22 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
case X86Local::MRMSrcMemCC:
case X86Local::MRMXmCC:
case X86Local::MRMXm:
- filter = llvm::make_unique<ModFilter>(false);
+ filter = std::make_unique<ModFilter>(false);
break;
case X86Local::MRM0r: case X86Local::MRM1r:
case X86Local::MRM2r: case X86Local::MRM3r:
case X86Local::MRM4r: case X86Local::MRM5r:
case X86Local::MRM6r: case X86Local::MRM7r:
- filter = llvm::make_unique<ExtendedFilter>(true, Form - X86Local::MRM0r);
+ filter = std::make_unique<ExtendedFilter>(true, Form - X86Local::MRM0r);
break;
case X86Local::MRM0m: case X86Local::MRM1m:
case X86Local::MRM2m: case X86Local::MRM3m:
case X86Local::MRM4m: case X86Local::MRM5m:
case X86Local::MRM6m: case X86Local::MRM7m:
- filter = llvm::make_unique<ExtendedFilter>(false, Form - X86Local::MRM0m);
+ filter = std::make_unique<ExtendedFilter>(false, Form - X86Local::MRM0m);
break;
X86_INSTR_MRM_MAPPING
- filter = llvm::make_unique<ExactFilter>(0xC0 + Form - X86Local::MRM_C0);
+ filter = std::make_unique<ExactFilter>(0xC0 + Form - X86Local::MRM_C0);
break;
} // switch (Form)
@@ -854,6 +854,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("GR64", TYPE_R64)
TYPE("i8mem", TYPE_M)
TYPE("i8imm", TYPE_IMM)
+ TYPE("u4imm", TYPE_UIMM8)
TYPE("u8imm", TYPE_UIMM8)
TYPE("i16u8imm", TYPE_UIMM8)
TYPE("i32u8imm", TYPE_UIMM8)
@@ -973,6 +974,7 @@ RecognizableInstr::immediateEncodingFromString(const std::string &s,
ENCODING("i64i32imm", ENCODING_ID)
ENCODING("i64i8imm", ENCODING_IB)
ENCODING("i8imm", ENCODING_IB)
+ ENCODING("u4imm", ENCODING_IB)
ENCODING("u8imm", ENCODING_IB)
ENCODING("i16u8imm", ENCODING_IB)
ENCODING("i32u8imm", ENCODING_IB)