summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
authorJames Molloy <jmolloy@google.com>2019-09-19 13:39:54 +0000
committerJames Molloy <jmolloy@google.com>2019-09-19 13:39:54 +0000
commit88a5fbfcea79b4711542f0587bed39aa392da12f (patch)
treef0fe771785e9a746017136a34f0d62752e6054c7 /llvm
parentb88800d8829b9a6602547e26050fffd528e21822 (diff)
downloadbcm5719-llvm-88a5fbfcea79b4711542f0587bed39aa392da12f.tar.gz
bcm5719-llvm-88a5fbfcea79b4711542f0587bed39aa392da12f.zip
[TableGen] Support encoding per-HwMode
Much like ValueTypeByHwMode/RegInfoByHwMode, this patch allows targets to modify an instruction's encoding based on HwMode. When the EncodingInfos field is non-empty the Inst and Size fields of the Instruction are ignored and taken from EncodingInfos instead. As part of this promote getHwMode() from TargetSubtargetInfo to MCSubtargetInfo. This is NFC for all existing targets - new code is generated only if targets use EncodingByHwMode. llvm-svn: 372320
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/CodeGen/TargetSubtargetInfo.h2
-rw-r--r--llvm/include/llvm/MC/MCSubtargetInfo.h2
-rw-r--r--llvm/include/llvm/Target/Target.td13
-rw-r--r--llvm/test/TableGen/HwModeEncodeDecode.td81
-rw-r--r--llvm/utils/TableGen/CodeEmitterGen.cpp130
-rw-r--r--llvm/utils/TableGen/CodeGenTarget.cpp3
-rw-r--r--llvm/utils/TableGen/FixedLenDecoderEmitter.cpp65
-rw-r--r--llvm/utils/TableGen/InfoByHwMode.cpp11
-rw-r--r--llvm/utils/TableGen/InfoByHwMode.h5
-rw-r--r--llvm/utils/TableGen/SubtargetEmitter.cpp3
10 files changed, 275 insertions, 40 deletions
diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index b24828152e5..56018eca8c2 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -110,8 +110,6 @@ public:
return nullptr;
}
- virtual unsigned getHwMode() const { return 0; }
-
/// Target can subclass this hook to select a different DAG scheduler.
virtual RegisterScheduler::FunctionPassCtor
getDAGScheduler(CodeGenOpt::Level) const {
diff --git a/llvm/include/llvm/MC/MCSubtargetInfo.h b/llvm/include/llvm/MC/MCSubtargetInfo.h
index 9490a6eceda..23a5999b359 100644
--- a/llvm/include/llvm/MC/MCSubtargetInfo.h
+++ b/llvm/include/llvm/MC/MCSubtargetInfo.h
@@ -221,6 +221,8 @@ public:
auto Found = std::lower_bound(ProcDesc.begin(), ProcDesc.end(), CPU);
return Found != ProcDesc.end() && StringRef(Found->Key) == CPU;
}
+
+ virtual unsigned getHwMode() const { return 0; }
};
} // end namespace llvm
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index fc63696142c..93a61359288 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -443,6 +443,15 @@ class InstructionEncoding {
bit hasCompleteDecoder = 1;
}
+// Allows specifying an InstructionEncoding by HwMode. If an Instruction specifies
+// an EncodingByHwMode, its Inst and Size members are ignored and Ts are used
+// to encode and decode based on HwMode.
+class EncodingByHwMode<list<HwMode> Ms = [], list<InstructionEncoding> Ts = []>
+ : HwModeSelect<Ms> {
+ // The length of this list must be the same as the length of Ms.
+ list<InstructionEncoding> Objects = Ts;
+}
+
//===----------------------------------------------------------------------===//
// Instruction set description - These classes correspond to the C++ classes in
// the Target/TargetInstrInfo.h file.
@@ -454,6 +463,10 @@ class Instruction : InstructionEncoding {
dag InOperandList; // An dag containing the MI use operand list.
string AsmString = ""; // The .s format to print the instruction with.
+ // Allows specifying a canonical InstructionEncoding by HwMode. If non-empty,
+ // the Inst member of this Instruction is ignored.
+ EncodingByHwMode EncodingInfos;
+
// Pattern - Set to the DAG pattern for this instruction, if we know of one,
// otherwise, uninitialized.
list<dag> Pattern;
diff --git a/llvm/test/TableGen/HwModeEncodeDecode.td b/llvm/test/TableGen/HwModeEncodeDecode.td
new file mode 100644
index 00000000000..b76d8564651
--- /dev/null
+++ b/llvm/test/TableGen/HwModeEncodeDecode.td
@@ -0,0 +1,81 @@
+// RUN: llvm-tblgen -gen-emitter -I %p/../../include %s | FileCheck %s --check-prefix=ENCODER
+// RUN: llvm-tblgen -gen-disassembler -I %p/../../include %s | FileCheck %s --check-prefix=DECODER
+
+include "llvm/Target/Target.td"
+
+def archInstrInfo : InstrInfo { }
+
+def arch : Target {
+ let InstructionSet = archInstrInfo;
+}
+
+def Myi32 : Operand<i32> {
+ let DecoderMethod = "DecodeMyi32";
+}
+
+def ModeA : HwMode<"+a">;
+def ModeB : HwMode<"+b">;
+
+
+def fooTypeEncA : InstructionEncoding {
+ let Size = 4;
+ field bits<32> SoftFail = 0;
+ bits<32> Inst;
+ bits<8> factor;
+ let Inst{7-0} = factor;
+ let Inst{3-2} = 0b11;
+ let Inst{1-0} = 0b00;
+}
+
+def fooTypeEncB : InstructionEncoding {
+ let Size = 4;
+ field bits<32> SoftFail = 0;
+ bits<32> Inst;
+ bits<8> factor;
+ let Inst{15-8} = factor;
+ let Inst{1-0} = 0b11;
+}
+
+let OutOperandList = (outs) in {
+def foo : Instruction {
+ let InOperandList = (ins i32imm:$factor);
+ let EncodingInfos = EncodingByHwMode<
+ [ModeA, ModeB], [fooTypeEncA,
+ fooTypeEncB]
+ >;
+ let AsmString = "foo $factor";
+}
+
+def bar: Instruction {
+ let InOperandList = (ins i32imm:$factor);
+ let Size = 4;
+ bits<32> Inst;
+ bits<32> SoftFail;
+ bits<8> factor;
+ let Inst{31-24} = factor;
+ let Inst{1-0} = 0b10;
+ let AsmString = "bar $factor";
+}
+}
+
+// DECODER-LABEL: DecoderTable_ModeA32[] =
+// DECODER-DAG: Opcode: fooTypeEncA:foo
+// DECODER-DAG: Opcode: bar
+// DECODER-LABEL: DecoderTable_ModeB32[] =
+// Note that the comment says fooTypeEncA but this is actually fooTypeEncB; plumbing
+// the correct comment text through the decoder is nontrivial.
+// DECODER-DAG: Opcode: fooTypeEncA:foo
+// DECODER-DAG: Opcode: bar
+
+// ENCODER-LABEL: static const uint64_t InstBits_ModeA[] = {
+// ENCODER: UINT64_C(2), // bar
+// ENCODER: UINT64_C(12), // foo
+
+// ENCODER-LABEL: static const uint64_t InstBits_ModeB[] = {
+// ENCODER: UINT64_C(2), // bar
+// ENCODER: UINT64_C(3), // foo
+
+// ENCODER: case ::foo: {
+// ENCODER: switch (HwMode) {
+// ENCODER: default: llvm_unreachable("Unhandled HwMode");
+// ENCODER: case 1: {
diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp
index 10c42bbc6ff..b021d08881f 100644
--- a/llvm/utils/TableGen/CodeEmitterGen.cpp
+++ b/llvm/utils/TableGen/CodeEmitterGen.cpp
@@ -46,12 +46,17 @@ 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;
};
@@ -261,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;
@@ -281,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())
@@ -317,6 +344,47 @@ static void emitInstBits(raw_ostream &OS, const APInt &Bits) {
<< ")";
}
+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);
+ 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");
@@ -327,17 +395,29 @@ void CodeEmitterGen::run(raw_ostream &o) {
ArrayRef<const CodeGenInstruction*> NumberedInstructions =
Target.getInstructionsByEnumValue();
- // Default to something sensible in case the target doesn't define Inst.
- BitWidth = 32;
+ 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"))
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 = BI->getNumBits();
- break;
+ BitWidth = std::max(BitWidth, BI->getNumBits());
}
UseAPInt = BitWidth > 64;
@@ -357,31 +437,25 @@ void CodeEmitterGen::run(raw_ostream &o) {
}
// Emit instruction base values
- o << " static const uint64_t InstBits[] = {\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;
- }
-
- BitsInit *BI = R->getValueAsBitsInit("Inst");
- BitWidth = BI->getNumBits();
+ 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.
- APInt Value(BitWidth, 0);
- for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) {
- if (BitInit *B = dyn_cast<BitInit>(BI->getBit(e - i - 1)))
- Value |= APInt(BitWidth, (uint64_t)B->getValue()) << (e - i - 1);
+ if (!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 << " ";
- emitInstBits(o, Value);
- o << "," << '\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;
diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp
index 478bbb7e480..fa8b842c97f 100644
--- a/llvm/utils/TableGen/CodeGenTarget.cpp
+++ b/llvm/utils/TableGen/CodeGenTarget.cpp
@@ -478,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"))
diff --git a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp
index 01f4115aa1d..ac69b431607 100644
--- a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp
+++ b/llvm/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"
@@ -97,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 {
@@ -2382,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(
@@ -2415,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++;
}
}
diff --git a/llvm/utils/TableGen/InfoByHwMode.cpp b/llvm/utils/TableGen/InfoByHwMode.cpp
index d9662889a5d..7cd1b0f0813 100644
--- a/llvm/utils/TableGen/InfoByHwMode.cpp
+++ b/llvm/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/llvm/utils/TableGen/InfoByHwMode.h b/llvm/utils/TableGen/InfoByHwMode.h
index 9e5cc3d5f2a..d92e5901a7f 100644
--- a/llvm/utils/TableGen/InfoByHwMode.h
+++ b/llvm/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/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index 41589b6b10d..f9705723650 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -1746,7 +1746,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) {
OpenPOWER on IntegriCloud