[llvm] [TableGen] Use bitwise operations to access HwMode ID. (PR #88377)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 15 23:29:23 PDT 2024
https://github.com/superZWT123 updated https://github.com/llvm/llvm-project/pull/88377
>From c5f65eed586321c370f553b2691b14d30b90eb46 Mon Sep 17 00:00:00 2001
From: z30050559 <zhengwentao3 at huawei.com>
Date: Tue, 26 Mar 2024 15:20:58 +0800
Subject: [PATCH] [TableGen] Use bitwise operations to access HwMode ID.
1. Bitwise operations are used to access HwMode, allowing for the
coexistence of HwMode IDs for different features (such as RegInfo
and EncodingInfo). This will provide better scalability for HwMode.
Currently, most users utilize HwMode primarily for configuring
Register-related information, and few use it for configuring Encoding.
The limited scalability of HwMode has been a significant factor in this
usage pattern.
2. Sink the HwMode Encodings selection logic down to per instruction level,
this makes the logic for choosing encodings clearer and provides better
error messages.
3. Add some HwMode ID conflict detection to the getHwMode() interface.
---
llvm/include/llvm/MC/MCSubtargetInfo.h | 18 +-
llvm/test/TableGen/HwModeBitSet.td | 162 ++++++++++++++++++
llvm/test/TableGen/HwModeEncodeDecode3.td | 78 +++++++--
llvm/utils/TableGen/CodeEmitterGen.cpp | 93 +++++++---
llvm/utils/TableGen/Common/CodeGenHwModes.cpp | 2 +
llvm/utils/TableGen/SubtargetEmitter.cpp | 77 ++++++++-
6 files changed, 380 insertions(+), 50 deletions(-)
create mode 100644 llvm/test/TableGen/HwModeBitSet.td
diff --git a/llvm/include/llvm/MC/MCSubtargetInfo.h b/llvm/include/llvm/MC/MCSubtargetInfo.h
index f172a799aa3331..70b14665ea9ebd 100644
--- a/llvm/include/llvm/MC/MCSubtargetInfo.h
+++ b/llvm/include/llvm/MC/MCSubtargetInfo.h
@@ -240,7 +240,23 @@ class MCSubtargetInfo {
return ProcFeatures;
}
- virtual unsigned getHwMode() const { return 0; }
+ /// HwMode ID will be stored as bits, allowing users to pull the specific
+ /// HwMode ID (like RegInfo HwMode ID) from the bits as needed. This enables
+ /// users to control multiple features with one hwmode (as previously) or use
+ /// different hwmodes to control different features.
+ enum HwModeType {
+ HwMode_Default, // Return the smallest HwMode ID of current subtarget.
+ HwMode_ValueType, // Return the HwMode ID that controls the ValueType.
+ HwMode_RegInfo, // Return the HwMode ID that controls the RegSizeInfo and
+ // SubRegRange.
+ HwMode_EncodingInfo // Return the HwMode ID that controls the EncodingInfo.
+ };
+
+ virtual unsigned getHwModeSet() const { return 0; }
+
+ virtual unsigned getHwMode(enum HwModeType type = HwMode_Default) const {
+ return 0;
+ }
/// Return the cache size in bytes for the given level of cache.
/// Level is zero-based, so a value of zero means the first level of
diff --git a/llvm/test/TableGen/HwModeBitSet.td b/llvm/test/TableGen/HwModeBitSet.td
new file mode 100644
index 00000000000000..c642906f6f4a88
--- /dev/null
+++ b/llvm/test/TableGen/HwModeBitSet.td
@@ -0,0 +1,162 @@
+// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-REG
+// RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-SUBTARGET
+
+include "llvm/Target/Target.td"
+
+def TestTargetInstrInfo : InstrInfo;
+
+def TestTarget : Target {
+ let InstructionSet = TestTargetInstrInfo;
+}
+
+def TestMode : HwMode<"+feat", []>;
+def TestMode1 : HwMode<"+feat1", []>;
+def TestMode2 : HwMode<"+feat2", []>;
+
+class MyReg<string n>
+ : Register<n> {
+ let Namespace = "Test";
+}
+
+class MyClass<int size, list<ValueType> types, dag registers>
+ : RegisterClass<"Test", types, size, registers> {
+ let Size = size;
+}
+
+def X0 : MyReg<"x0">;
+def X1 : MyReg<"x1">;
+def X2 : MyReg<"x2">;
+def X3 : MyReg<"x3">;
+def X4 : MyReg<"x4">;
+def X5 : MyReg<"x5">;
+def X6 : MyReg<"x6">;
+def X7 : MyReg<"x7">;
+def X8 : MyReg<"x8">;
+def X9 : MyReg<"x9">;
+def X10 : MyReg<"x10">;
+def X11 : MyReg<"x11">;
+def X12 : MyReg<"x12">;
+def X13 : MyReg<"x13">;
+def X14 : MyReg<"x14">;
+def X15 : MyReg<"x15">;
+
+def ValueModeVT : ValueTypeByHwMode<[DefaultMode, TestMode, TestMode1],
+ [i32, i64, f32]>;
+
+let RegInfos = RegInfoByHwMode<[DefaultMode, TestMode],
+ [RegInfo<32,32,32>, RegInfo<64,64,64>]> in
+def XRegs : MyClass<32, [ValueModeVT], (sequence "X%u", 0, 15)>;
+
+def sub_even : SubRegIndex<32> {
+ let SubRegRanges = SubRegRangeByHwMode<[DefaultMode, TestMode],
+ [SubRegRange<32>, SubRegRange<64>]>;
+}
+def sub_odd : SubRegIndex<32, 32> {
+ let SubRegRanges = SubRegRangeByHwMode<[DefaultMode, TestMode],
+ [SubRegRange<32, 32>, SubRegRange<64, 64>]>;
+}
+
+def XPairs : RegisterTuples<[sub_even, sub_odd],
+ [(decimate (rotl XRegs, 0), 2),
+ (decimate (rotl XRegs, 1), 2)]>;
+
+let RegInfos = RegInfoByHwMode<[DefaultMode, TestMode],
+ [RegInfo<64,64,32>, RegInfo<128,128,64>]> in
+def XPairsClass : MyClass<64, [untyped], (add XPairs)>;
+
+// Modes who are not controlling Register related features will be manipulated
+// the same as DefaultMode.
+// CHECK-REG-LABEL: RegisterClass XRegs:
+// CHECK-REG: SpillSize: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
+// CHECK-REG: SpillAlignment: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
+// CHECK-REG: Regs: X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+
+// CHECK-REG-LABEL: RegisterClass XPairsClass:
+// CHECK-REG: SpillSize: { Default:64 TestMode:128 TestMode1:64 TestMode2:64 }
+// CHECK-REG: SpillAlignment: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
+// CHECK-REG: CoveredBySubRegs: 1
+// CHECK-REG: Regs: X0_X1 X2_X3 X4_X5 X6_X7 X8_X9 X10_X11 X12_X13 X14_X15
+
+// CHECK-REG-LABEL: SubRegIndex sub_even:
+// CHECK-REG: Offset: { Default:0 TestMode:0 TestMode1:0 TestMode2:0 }
+// CHECK-REG: Size: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
+// CHECK-REG-LABEL: SubRegIndex sub_odd:
+// CHECK-REG: Offset: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
+// CHECK-REG: Size: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
+
+//============================================================================//
+//--------------------- Encoding/Decoding parts ------------------------------//
+//============================================================================//
+def fooTypeEncDefault : InstructionEncoding {
+ let Size = 8;
+ field bits<64> SoftFail = 0;
+ bits<64> Inst;
+ bits<8> factor;
+ let Inst{7...0} = factor;
+ let Inst{3...2} = 0b10;
+ let Inst{1...0} = 0b00;
+}
+
+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 foo : Instruction {
+ let OutOperandList = (outs);
+ let InOperandList = (ins i32imm:$factor);
+ let EncodingInfos = EncodingByHwMode<
+ [TestMode2, DefaultMode], [fooTypeEncA, fooTypeEncDefault]
+ >;
+ let AsmString = "foo $factor";
+}
+
+// CHECK-SUBTARGET-LABEL: unsigned TestTargetGenSubtargetInfo::getHwModeSet() const {
+// CHECK-SUBTARGET: unsigned Modes = 0;
+// CHECK-SUBTARGET: if (checkFeatures("+feat")) Modes |= (1 << 0);
+// CHECK-SUBTARGET: if (checkFeatures("+feat1")) Modes |= (1 << 1);
+// CHECK-SUBTARGET: if (checkFeatures("+feat2")) Modes |= (1 << 2);
+// CHECK-SUBTARGET: return Modes;
+// CHECK-SUBTARGET: }
+// CHECK-SUBTARGET-LABEL: unsigned TestTargetGenSubtargetInfo::getHwMode(enum HwModeType type) const {
+// CHECK-SUBTARGET: unsigned Modes = getHwModeSet();
+// CHECK-SUBTARGET: if(!Modes)
+// CHECK-SUBTARGET: return Modes;
+// CHECK-SUBTARGET: switch (type) {
+// CHECK-SUBTARGET: case HwMode_Default:
+// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
+// CHECK-SUBTARGET: break;
+// CHECK-SUBTARGET: case HwMode_ValueType: {
+// CHECK-SUBTARGET: Modes &= 3;
+// CHECK-SUBTARGET: if (!Modes)
+// CHECK-SUBTARGET: return Modes;
+// CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes))
+// CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for ValueType were found!");
+// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
+// CHECK-SUBTARGET: }
+// CHECK-SUBTARGET: case HwMode_RegInfo: {
+// CHECK-SUBTARGET: Modes &= 1;
+// CHECK-SUBTARGET: if (!Modes)
+// CHECK-SUBTARGET: return Modes;
+// CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes))
+// CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for RegInfo were found!");
+// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
+// CHECK-SUBTARGET: }
+// CHECK-SUBTARGET: case HwMode_EncodingInfo: {
+// CHECK-SUBTARGET: Modes &= 4;
+// CHECK-SUBTARGET: if (!Modes)
+// CHECK-SUBTARGET: return Modes;
+// CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes))
+// CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for Encoding were found!");
+// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
+// CHECK-SUBTARGET: }
+// CHECK-SUBTARGET: }
+// CHECK-SUBTARGET: return 0; // should not get here
+// CHECK-SUBTARGET: }
+
diff --git a/llvm/test/TableGen/HwModeEncodeDecode3.td b/llvm/test/TableGen/HwModeEncodeDecode3.td
index 8e0266b2c55af9..bc65d4a1d40d3b 100644
--- a/llvm/test/TableGen/HwModeEncodeDecode3.td
+++ b/llvm/test/TableGen/HwModeEncodeDecode3.td
@@ -160,15 +160,22 @@ def unrelated: Instruction {
// DECODER-SUPPRESS-O2-DAG: Opcode: fooTypeEncA:baz
// DECODER-SUPPRESS-O2-NOT: Opcode: bar
-// ENCODER-LABEL: static const uint64_t InstBits_DefaultMode[] = {
+// For 'bar' and 'unrelated', we didn't assign any hwmodes for them,
+// they should keep the same in the following three tables.
+// For 'foo' we assigned three hwmodes(includes 'DefaultMode')
+// it's encodings should be different in the following three tables.
+// For 'baz' we only assigned ModeB for it, to avoid empty encoding
+// we assigned the encoding of ModeB to ModeA and DefaultMode(Even though
+// they will not be used).
+// ENCODER-LABEL: static const uint64_t InstBits[] = {
// ENCODER: UINT64_C(2), // bar
-// ENCODER: UINT64_C(0), // baz
+// ENCODER: UINT64_C(12), // baz
// ENCODER: UINT64_C(8), // foo
// ENCODER: UINT64_C(2), // unrelated
// ENCODER-LABEL: static const uint64_t InstBits_ModeA[] = {
// ENCODER: UINT64_C(2), // bar
-// ENCODER: UINT64_C(0), // baz
+// ENCODER: UINT64_C(12), // baz
// ENCODER: UINT64_C(12), // foo
// ENCODER: UINT64_C(2), // unrelated
@@ -178,18 +185,53 @@ def unrelated: Instruction {
// ENCODER: UINT64_C(3), // foo
// ENCODER: UINT64_C(2), // unrelated
-// ENCODER: unsigned HwMode = STI.getHwMode();
-// ENCODER: switch (HwMode) {
-// ENCODER: default: llvm_unreachable("Unknown hardware mode!"); break;
-// ENCODER: case 0: InstBits = InstBits_DefaultMode; break;
-// ENCODER: case 1: InstBits = InstBits_ModeA; break;
-// ENCODER: case 2: InstBits = InstBits_ModeB; break;
-// ENCODER: };
-
-// ENCODER: case ::foo: {
-// ENCODER: switch (HwMode) {
-// ENCODER: default: llvm_unreachable("Unhandled HwMode");
-// ENCODER: case 0: {
-// ENCODER: case 1: {
-// ENCODER: case 2: {
-
+// ENCODER-LABEL: case ::bar:
+// ENCODER-LABEL: case ::unrelated:
+// ENCODER-NOT: getHwMode
+// ENCODER-LABEL: case ::baz: {
+// ENCODER: unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_EncodingInfo);
+// ENCODER: HwMode &= 2;
+// ENCODER: switch (HwMode) {
+// ENCODER: default: llvm_unreachable("Unknown hardware mode!"); break;
+// ENCODER: case 2: InstBitsByHw = InstBits_ModeB; break;
+// ENCODER: };
+// ENCODER: Value = InstBitsByHw[opcode];
+// ENCODER: switch (HwMode) {
+// ENCODER: default: llvm_unreachable("Unhandled HwMode");
+// ENCODER: case 2: {
+// ENCODER: op = getMachineOpValue(MI, MI.getOperand(0), Fixups, STI);
+// ENCODER: op &= UINT64_C(240);
+// ENCODER: Value |= op;
+// ENCODER: break;
+// ENCODER: }
+// ENCODER-LABEL: case ::foo: {
+// ENCODER: unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_EncodingInfo);
+// ENCODER: HwMode &= 3;
+// ENCODER: switch (HwMode) {
+// ENCODER: default: llvm_unreachable("Unknown hardware mode!"); break;
+// ENCODER: case 0: InstBitsByHw = InstBits; break;
+// ENCODER: case 1: InstBitsByHw = InstBits_ModeA; break;
+// ENCODER: case 2: InstBitsByHw = InstBits_ModeB; break;
+// ENCODER: };
+// ENCODER: Value = InstBitsByHw[opcode];
+// ENCODER: switch (HwMode) {
+// ENCODER: default: llvm_unreachable("Unhandled HwMode");
+// ENCODER: case 0: {
+// ENCODER: op = getMachineOpValue(MI, MI.getOperand(0), Fixups, STI);
+// ENCODER: op &= UINT64_C(240);
+// ENCODER: Value |= op;
+// ENCODER: break;
+// ENCODER: }
+// ENCODER: case 1: {
+// ENCODER: op = getMachineOpValue(MI, MI.getOperand(0), Fixups, STI);
+// ENCODER: op &= UINT64_C(240);
+// ENCODER: Value |= op;
+// ENCODER: break;
+// ENCODER: }
+// ENCODER: case 2: {
+// ENCODER: op = getMachineOpValue(MI, MI.getOperand(0), Fixups, STI);
+// ENCODER: op &= UINT64_C(255);
+// ENCODER: op <<= 8;
+// ENCODER: Value |= op;
+// ENCODER: break;
+// ENCODER: }
diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp
index a57885f22d7e3e..31a51c19e67c11 100644
--- a/llvm/utils/TableGen/CodeEmitterGen.cpp
+++ b/llvm/utils/TableGen/CodeEmitterGen.cpp
@@ -68,7 +68,7 @@ class CodeEmitterGen {
void emitInstructionBaseValues(
raw_ostream &o, ArrayRef<const CodeGenInstruction *> NumberedInstructions,
- CodeGenTarget &Target, int HwMode = -1);
+ CodeGenTarget &Target, unsigned HwMode = DefaultMode);
void
emitCaseMap(raw_ostream &o,
const std::map<std::string, std::vector<std::string>> &CaseMap);
@@ -281,7 +281,7 @@ std::pair<std::string, std::string>
CodeEmitterGen::getInstructionCases(Record *R, CodeGenTarget &Target) {
std::string Case, BitOffsetCase;
- auto append = [&](const char *S) {
+ auto append = [&](const std::string &S) {
Case += S;
BitOffsetCase += S;
};
@@ -290,11 +290,55 @@ CodeEmitterGen::getInstructionCases(Record *R, CodeGenTarget &Target) {
if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
const CodeGenHwModes &HWM = Target.getHwModes();
EncodingInfoByHwMode EBM(DI->getDef(), HWM);
+ unsigned EncodingHwModesInBits = DefaultMode;
+ for (auto &[ModeId, Encoding] : EBM) {
+ // DefaultMode is 0, skip it.
+ if (ModeId != DefaultMode)
+ EncodingHwModesInBits |= (1 << (ModeId - 1));
+ }
+
+ // Get HwModes for this Instr by bitwise AND operations,
+ // and find the table to which this instr and hwmode belong.
+ append(" unsigned HwMode = "
+ "STI.getHwMode(MCSubtargetInfo::HwMode_EncodingInfo);\n");
+ append(" HwMode &= " + itostr(EncodingHwModesInBits) + ";\n");
+ append(" switch (HwMode) {\n");
+ append(" default: llvm_unreachable(\"Unknown hardware mode!\"); "
+ "break;\n");
+ for (auto &[ModeId, Encoding] : EBM) {
+ if (ModeId == DefaultMode) {
+ append(" case " + itostr(DefaultMode) +
+ ": InstBitsByHw = InstBits");
+ } else {
+ append(" case " + itostr(1 << (ModeId - 1)) +
+ ": InstBitsByHw = InstBits_" +
+ std::string(HWM.getMode(ModeId).Name));
+ }
+ append("; break;\n");
+ }
+ append(" };\n");
+
+ // We need to remodify the 'Inst' value from the table we found above.
+ if (UseAPInt) {
+ int NumWords = APInt::getNumWords(BitWidth);
+ append(" Inst = APInt(" + itostr(BitWidth));
+ append(", ArrayRef(InstBitsByHw + opcode * " + itostr(NumWords) + ", " +
+ itostr(NumWords));
+ append("));\n");
+ append(" Value = Inst;\n");
+ } else {
+ append(" Value = InstBitsByHw[opcode];\n");
+ }
+
append(" switch (HwMode) {\n");
append(" default: llvm_unreachable(\"Unhandled HwMode\");\n");
- for (auto &KV : EBM) {
- append((" case " + itostr(KV.first) + ": {\n").c_str());
- addInstructionCasesForEncoding(R, KV.second, Target, Case,
+ for (auto &[ModeId, Encoding] : EBM) {
+ if (ModeId == DefaultMode) {
+ append(" case " + itostr(DefaultMode) + ": {\n");
+ } else {
+ append(" case " + itostr(1 << (ModeId - 1)) + ": {\n");
+ }
+ addInstructionCasesForEncoding(R, Encoding, Target, Case,
BitOffsetCase);
append(" break;\n");
append(" }\n");
@@ -360,9 +404,9 @@ static void emitInstBits(raw_ostream &OS, const APInt &Bits) {
void CodeEmitterGen::emitInstructionBaseValues(
raw_ostream &o, ArrayRef<const CodeGenInstruction *> NumberedInstructions,
- CodeGenTarget &Target, int HwMode) {
+ CodeGenTarget &Target, unsigned HwMode) {
const CodeGenHwModes &HWM = Target.getHwModes();
- if (HwMode == -1)
+ if (HwMode == DefaultMode)
o << " static const uint64_t InstBits[] = {\n";
else
o << " static const uint64_t InstBits_"
@@ -383,8 +427,17 @@ void CodeEmitterGen::emitInstructionBaseValues(
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))
+ if (EBM.hasMode(HwMode)) {
EncodingDef = EBM.get(HwMode);
+ } else {
+ // If this Instr dosen't have this HwMode, just choose
+ // the encoding from the first HwMode. Otherwise, the encoding
+ // info would be empty.
+ for (auto &[ModeId, Encoding] : EBM) {
+ EncodingDef = Encoding;
+ break;
+ }
+ }
}
}
BitsInit *BI = EncodingDef->getValueAsBitsInit("Inst");
@@ -479,23 +532,17 @@ void CodeEmitterGen::run(raw_ostream &o) {
}
// Emit instruction base values
- if (HwModes.empty()) {
- emitInstructionBaseValues(o, NumberedInstructions, Target, -1);
- } else {
- for (unsigned HwMode : HwModes)
- emitInstructionBaseValues(o, NumberedInstructions, Target, (int)HwMode);
- }
-
+ emitInstructionBaseValues(o, NumberedInstructions, Target, DefaultMode);
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.getModeName(I, /*IncludeDefault=*/true) << "; break;\n";
+ // Emit table for instrs whose encodings are controlled by HwModes.
+ for (unsigned HwMode : HwModes) {
+ if (HwMode == DefaultMode)
+ continue;
+ emitInstructionBaseValues(o, NumberedInstructions, Target, HwMode);
}
- o << " };\n";
+
+ // This pointer will be assigned to the HwMode table later.
+ o << " const uint64_t *InstBitsByHw;\n";
}
// Map to accumulate all the cases.
diff --git a/llvm/utils/TableGen/Common/CodeGenHwModes.cpp b/llvm/utils/TableGen/Common/CodeGenHwModes.cpp
index fec74d29c8bbbd..124cfbaf4fb747 100644
--- a/llvm/utils/TableGen/Common/CodeGenHwModes.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenHwModes.cpp
@@ -74,6 +74,8 @@ CodeGenHwModes::CodeGenHwModes(RecordKeeper &RK) : Records(RK) {
ModeIds.insert(std::pair(R, Modes.size()));
}
+ assert(Modes.size() <= 32 && "number of HwModes exceeds maximum of 32");
+
for (Record *R : Records.getAllDerivedDefinitions("HwModeSelect")) {
auto P = ModeSelects.emplace(std::pair(R, HwModeSelect(R, *this)));
assert(P.second);
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index 2e2c57b802ee54..e445c07270c258 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -1781,13 +1781,68 @@ void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName,
if (CGH.getNumModeIds() == 1)
return;
- OS << "unsigned " << ClassName << "::getHwMode() const {\n";
+ // Collect all HwModes and related features defined in the TD files,
+ // and store them in bit format.
+ unsigned ValueTypeModes = 0;
+ unsigned RegInfoModes = 0;
+ unsigned EncodingInfoModes = 0;
+ for (const auto &MS : CGH.getHwModeSelects()) {
+ for (const HwModeSelect::PairType &P : MS.second.Items) {
+ if (P.first == DefaultMode)
+ continue;
+ if (P.second->isSubClassOf("ValueType")) {
+ ValueTypeModes |= (1 << (P.first - 1));
+ } else if (P.second->isSubClassOf("RegInfo") ||
+ P.second->isSubClassOf("SubRegRange")) {
+ RegInfoModes |= (1 << (P.first - 1));
+ } else if (P.second->isSubClassOf("InstructionEncoding")) {
+ EncodingInfoModes |= (1 << (P.first - 1));
+ }
+ }
+ }
+
+ // Start emitting for getHwModeSet().
+ OS << "unsigned " << ClassName << "::getHwModeSet() const {\n";
+ OS << " // Collect HwModes and store them in bits\n";
+ OS << " unsigned Modes = 0;\n";
for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) {
const HwMode &HM = CGH.getMode(M);
- OS << " if (checkFeatures(\"" << HM.Features << "\")) return " << M
- << ";\n";
+ OS << " if (checkFeatures(\"" << HM.Features << "\")) Modes |= (1 << "
+ << (M - 1) << ");\n";
}
- OS << " return 0;\n}\n";
+ OS << " return Modes;\n}\n";
+ // End emitting for getHwModeSet().
+
+ // Start emitting for getHwMode().
+ OS << "unsigned " << ClassName
+ << "::getHwMode(enum HwModeType type) const {\n";
+ OS << " unsigned Modes = getHwModeSet();\n";
+ OS << "\n if(!Modes)\n return Modes;\n\n";
+ OS << " switch (type) {\n";
+ OS << " case HwMode_Default:\n return llvm::countr_zero(Modes) + 1;\n"
+ << " break;\n";
+ OS << " case HwMode_ValueType: {\n Modes &= " << ValueTypeModes << ";\n"
+ << " if (!Modes)\n return Modes;\n"
+ << " if (!llvm::has_single_bit<unsigned>(Modes))\n"
+ << " llvm_unreachable(\"Two or more HwModes for ValueType were "
+ "found!\");\n"
+ << " return llvm::countr_zero(Modes) + 1;\n }\n";
+ OS << " case HwMode_RegInfo: {\n Modes &= " << RegInfoModes << ";\n"
+ << " if (!Modes)\n return Modes;\n"
+ << " if (!llvm::has_single_bit<unsigned>(Modes))\n"
+ << " llvm_unreachable(\"Two or more HwModes for RegInfo were "
+ "found!\");\n"
+ << " return llvm::countr_zero(Modes) + 1;\n }\n";
+ OS << " case HwMode_EncodingInfo: {\n Modes &= " << EncodingInfoModes
+ << ";\n"
+ << " if (!Modes)\n return Modes;\n"
+ << " if (!llvm::has_single_bit<unsigned>(Modes))\n"
+ << " llvm_unreachable(\"Two or more HwModes for Encoding were "
+ "found!\");\n"
+ << " return llvm::countr_zero(Modes) + 1;\n }\n";
+ OS << " }\n";
+ OS << " return 0; // should not get here\n}\n";
+ // End emitting for getHwMode().
}
void SubtargetEmitter::emitGetMacroFusions(const std::string &ClassName,
@@ -1876,8 +1931,11 @@ void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
<< " return " << Target << "_MC"
<< "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n";
OS << " }\n";
- if (TGT.getHwModes().getNumModeIds() > 1)
- OS << " unsigned getHwMode() const override;\n";
+ if (TGT.getHwModes().getNumModeIds() > 1) {
+ OS << " unsigned getHwModeSet() const override;\n";
+ OS << " unsigned getHwMode(enum HwModeType type = HwMode_Default) const "
+ "override;\n";
+ }
OS << "};\n";
EmitHwModeCheck(Target + "GenMCSubtargetInfo", OS);
}
@@ -2004,8 +2062,11 @@ void SubtargetEmitter::run(raw_ostream &OS) {
<< " unsigned CPUID) const override;\n"
<< " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"
<< " const;\n";
- if (TGT.getHwModes().getNumModeIds() > 1)
- OS << " unsigned getHwMode() const override;\n";
+ if (TGT.getHwModes().getNumModeIds() > 1) {
+ OS << " unsigned getHwModeSet() const override;\n";
+ OS << " unsigned getHwMode(enum HwModeType type = HwMode_Default) const "
+ "override;\n";
+ }
if (TGT.hasMacroFusion())
OS << " std::vector<MacroFusionPredTy> getMacroFusions() const "
"override;\n";
More information about the llvm-commits
mailing list