Skip to content

Commit d869590

Browse files
author
z30050559
committed
[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.
1 parent 10aab63 commit d869590

File tree

6 files changed

+380
-50
lines changed

6 files changed

+380
-50
lines changed

llvm/include/llvm/MC/MCSubtargetInfo.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,23 @@ class MCSubtargetInfo {
240240
return ProcFeatures;
241241
}
242242

243-
virtual unsigned getHwMode() const { return 0; }
243+
/// HwMode ID will be stored as bits, allowing users to pull the specific
244+
/// HwMode ID (like RegInfo HwMode ID) from the bits as needed. This enables
245+
/// users to control multiple features with one hwmode (as previously) or use
246+
/// different hwmodes to control different features.
247+
enum HwModeType {
248+
HwMode_Default, // Return the smallest HwMode ID of current subtarget.
249+
HwMode_ValueType, // Return the HwMode ID that controls the ValueType.
250+
HwMode_RegInfo, // Return the HwMode ID that controls the RegSizeInfo and
251+
// SubRegRange.
252+
HwMode_EncodingInfo // Return the HwMode ID that controls the EncodingInfo.
253+
};
254+
255+
virtual unsigned getHwModeSet() const { return 0; }
256+
257+
virtual unsigned getHwMode(enum HwModeType type = HwMode_Default) const {
258+
return 0;
259+
}
244260

245261
/// Return the cache size in bytes for the given level of cache.
246262
/// Level is zero-based, so a value of zero means the first level of

llvm/test/TableGen/HwModeBitSet.td

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-REG
2+
// RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-SUBTARGET
3+
4+
include "llvm/Target/Target.td"
5+
6+
def TestTargetInstrInfo : InstrInfo;
7+
8+
def TestTarget : Target {
9+
let InstructionSet = TestTargetInstrInfo;
10+
}
11+
12+
def TestMode : HwMode<"+feat", []>;
13+
def TestMode1 : HwMode<"+feat1", []>;
14+
def TestMode2 : HwMode<"+feat2", []>;
15+
16+
class MyReg<string n>
17+
: Register<n> {
18+
let Namespace = "Test";
19+
}
20+
21+
class MyClass<int size, list<ValueType> types, dag registers>
22+
: RegisterClass<"Test", types, size, registers> {
23+
let Size = size;
24+
}
25+
26+
def X0 : MyReg<"x0">;
27+
def X1 : MyReg<"x1">;
28+
def X2 : MyReg<"x2">;
29+
def X3 : MyReg<"x3">;
30+
def X4 : MyReg<"x4">;
31+
def X5 : MyReg<"x5">;
32+
def X6 : MyReg<"x6">;
33+
def X7 : MyReg<"x7">;
34+
def X8 : MyReg<"x8">;
35+
def X9 : MyReg<"x9">;
36+
def X10 : MyReg<"x10">;
37+
def X11 : MyReg<"x11">;
38+
def X12 : MyReg<"x12">;
39+
def X13 : MyReg<"x13">;
40+
def X14 : MyReg<"x14">;
41+
def X15 : MyReg<"x15">;
42+
43+
def ValueModeVT : ValueTypeByHwMode<[DefaultMode, TestMode, TestMode1],
44+
[i32, i64, f32]>;
45+
46+
let RegInfos = RegInfoByHwMode<[DefaultMode, TestMode],
47+
[RegInfo<32,32,32>, RegInfo<64,64,64>]> in
48+
def XRegs : MyClass<32, [ValueModeVT], (sequence "X%u", 0, 15)>;
49+
50+
def sub_even : SubRegIndex<32> {
51+
let SubRegRanges = SubRegRangeByHwMode<[DefaultMode, TestMode],
52+
[SubRegRange<32>, SubRegRange<64>]>;
53+
}
54+
def sub_odd : SubRegIndex<32, 32> {
55+
let SubRegRanges = SubRegRangeByHwMode<[DefaultMode, TestMode],
56+
[SubRegRange<32, 32>, SubRegRange<64, 64>]>;
57+
}
58+
59+
def XPairs : RegisterTuples<[sub_even, sub_odd],
60+
[(decimate (rotl XRegs, 0), 2),
61+
(decimate (rotl XRegs, 1), 2)]>;
62+
63+
let RegInfos = RegInfoByHwMode<[DefaultMode, TestMode],
64+
[RegInfo<64,64,32>, RegInfo<128,128,64>]> in
65+
def XPairsClass : MyClass<64, [untyped], (add XPairs)>;
66+
67+
// Modes who are not controlling Register related features will be manipulated
68+
// the same as DefaultMode.
69+
// CHECK-REG-LABEL: RegisterClass XRegs:
70+
// CHECK-REG: SpillSize: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
71+
// CHECK-REG: SpillAlignment: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
72+
// CHECK-REG: Regs: X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
73+
74+
// CHECK-REG-LABEL: RegisterClass XPairsClass:
75+
// CHECK-REG: SpillSize: { Default:64 TestMode:128 TestMode1:64 TestMode2:64 }
76+
// CHECK-REG: SpillAlignment: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
77+
// CHECK-REG: CoveredBySubRegs: 1
78+
// CHECK-REG: Regs: X0_X1 X2_X3 X4_X5 X6_X7 X8_X9 X10_X11 X12_X13 X14_X15
79+
80+
// CHECK-REG-LABEL: SubRegIndex sub_even:
81+
// CHECK-REG: Offset: { Default:0 TestMode:0 TestMode1:0 TestMode2:0 }
82+
// CHECK-REG: Size: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
83+
// CHECK-REG-LABEL: SubRegIndex sub_odd:
84+
// CHECK-REG: Offset: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
85+
// CHECK-REG: Size: { Default:32 TestMode:64 TestMode1:32 TestMode2:32 }
86+
87+
//============================================================================//
88+
//--------------------- Encoding/Decoding parts ------------------------------//
89+
//============================================================================//
90+
def fooTypeEncDefault : InstructionEncoding {
91+
let Size = 8;
92+
field bits<64> SoftFail = 0;
93+
bits<64> Inst;
94+
bits<8> factor;
95+
let Inst{7...0} = factor;
96+
let Inst{3...2} = 0b10;
97+
let Inst{1...0} = 0b00;
98+
}
99+
100+
def fooTypeEncA : InstructionEncoding {
101+
let Size = 4;
102+
field bits<32> SoftFail = 0;
103+
bits<32> Inst;
104+
bits<8> factor;
105+
let Inst{7...0} = factor;
106+
let Inst{3...2} = 0b11;
107+
let Inst{1...0} = 0b00;
108+
}
109+
110+
111+
def foo : Instruction {
112+
let OutOperandList = (outs);
113+
let InOperandList = (ins i32imm:$factor);
114+
let EncodingInfos = EncodingByHwMode<
115+
[TestMode2, DefaultMode], [fooTypeEncA, fooTypeEncDefault]
116+
>;
117+
let AsmString = "foo $factor";
118+
}
119+
120+
// CHECK-SUBTARGET-LABEL: unsigned TestTargetGenSubtargetInfo::getHwModeSet() const {
121+
// CHECK-SUBTARGET: unsigned Modes = 0;
122+
// CHECK-SUBTARGET: if (checkFeatures("+feat")) Modes |= (1 << 0);
123+
// CHECK-SUBTARGET: if (checkFeatures("+feat1")) Modes |= (1 << 1);
124+
// CHECK-SUBTARGET: if (checkFeatures("+feat2")) Modes |= (1 << 2);
125+
// CHECK-SUBTARGET: return Modes;
126+
// CHECK-SUBTARGET: }
127+
// CHECK-SUBTARGET-LABEL: unsigned TestTargetGenSubtargetInfo::getHwMode(enum HwModeType type) const {
128+
// CHECK-SUBTARGET: unsigned Modes = getHwModeSet();
129+
// CHECK-SUBTARGET: if(!Modes)
130+
// CHECK-SUBTARGET: return Modes;
131+
// CHECK-SUBTARGET: switch (type) {
132+
// CHECK-SUBTARGET: case HwMode_Default:
133+
// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
134+
// CHECK-SUBTARGET: break;
135+
// CHECK-SUBTARGET: case HwMode_ValueType: {
136+
// CHECK-SUBTARGET: Modes &= 3;
137+
// CHECK-SUBTARGET: if (!Modes)
138+
// CHECK-SUBTARGET: return Modes;
139+
// CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes))
140+
// CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for ValueType were found!");
141+
// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
142+
// CHECK-SUBTARGET: }
143+
// CHECK-SUBTARGET: case HwMode_RegInfo: {
144+
// CHECK-SUBTARGET: Modes &= 1;
145+
// CHECK-SUBTARGET: if (!Modes)
146+
// CHECK-SUBTARGET: return Modes;
147+
// CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes))
148+
// CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for RegInfo were found!");
149+
// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
150+
// CHECK-SUBTARGET: }
151+
// CHECK-SUBTARGET: case HwMode_EncodingInfo: {
152+
// CHECK-SUBTARGET: Modes &= 4;
153+
// CHECK-SUBTARGET: if (!Modes)
154+
// CHECK-SUBTARGET: return Modes;
155+
// CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes))
156+
// CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for Encoding were found!");
157+
// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
158+
// CHECK-SUBTARGET: }
159+
// CHECK-SUBTARGET: }
160+
// CHECK-SUBTARGET: return 0; // should not get here
161+
// CHECK-SUBTARGET: }
162+

llvm/test/TableGen/HwModeEncodeDecode3.td

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,22 @@ def unrelated: Instruction {
160160
// DECODER-SUPPRESS-O2-DAG: Opcode: fooTypeEncA:baz
161161
// DECODER-SUPPRESS-O2-NOT: Opcode: bar
162162

163-
// ENCODER-LABEL: static const uint64_t InstBits_DefaultMode[] = {
163+
// For 'bar' and 'unrelated', we didn't assign any hwmodes for them,
164+
// they should keep the same in the following three tables.
165+
// For 'foo' we assigned three hwmodes(includes 'DefaultMode')
166+
// it's encodings should be different in the following three tables.
167+
// For 'baz' we only assigned ModeB for it, to avoid empty encoding
168+
// we assigned the encoding of ModeB to ModeA and DefaultMode(Even though
169+
// they will not be used).
170+
// ENCODER-LABEL: static const uint64_t InstBits[] = {
164171
// ENCODER: UINT64_C(2), // bar
165-
// ENCODER: UINT64_C(0), // baz
172+
// ENCODER: UINT64_C(12), // baz
166173
// ENCODER: UINT64_C(8), // foo
167174
// ENCODER: UINT64_C(2), // unrelated
168175

169176
// ENCODER-LABEL: static const uint64_t InstBits_ModeA[] = {
170177
// ENCODER: UINT64_C(2), // bar
171-
// ENCODER: UINT64_C(0), // baz
178+
// ENCODER: UINT64_C(12), // baz
172179
// ENCODER: UINT64_C(12), // foo
173180
// ENCODER: UINT64_C(2), // unrelated
174181

@@ -178,18 +185,53 @@ def unrelated: Instruction {
178185
// ENCODER: UINT64_C(3), // foo
179186
// ENCODER: UINT64_C(2), // unrelated
180187

181-
// ENCODER: unsigned HwMode = STI.getHwMode();
182-
// ENCODER: switch (HwMode) {
183-
// ENCODER: default: llvm_unreachable("Unknown hardware mode!"); break;
184-
// ENCODER: case 0: InstBits = InstBits_DefaultMode; break;
185-
// ENCODER: case 1: InstBits = InstBits_ModeA; break;
186-
// ENCODER: case 2: InstBits = InstBits_ModeB; break;
187-
// ENCODER: };
188-
189-
// ENCODER: case ::foo: {
190-
// ENCODER: switch (HwMode) {
191-
// ENCODER: default: llvm_unreachable("Unhandled HwMode");
192-
// ENCODER: case 0: {
193-
// ENCODER: case 1: {
194-
// ENCODER: case 2: {
195-
188+
// ENCODER-LABEL: case ::bar:
189+
// ENCODER-LABEL: case ::unrelated:
190+
// ENCODER-NOT: getHwMode
191+
// ENCODER-LABEL: case ::baz: {
192+
// ENCODER: unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_EncodingInfo);
193+
// ENCODER: HwMode &= 2;
194+
// ENCODER: switch (HwMode) {
195+
// ENCODER: default: llvm_unreachable("Unknown hardware mode!"); break;
196+
// ENCODER: case 2: InstBitsByHw = InstBits_ModeB; break;
197+
// ENCODER: };
198+
// ENCODER: Value = InstBitsByHw[opcode];
199+
// ENCODER: switch (HwMode) {
200+
// ENCODER: default: llvm_unreachable("Unhandled HwMode");
201+
// ENCODER: case 2: {
202+
// ENCODER: op = getMachineOpValue(MI, MI.getOperand(0), Fixups, STI);
203+
// ENCODER: op &= UINT64_C(240);
204+
// ENCODER: Value |= op;
205+
// ENCODER: break;
206+
// ENCODER: }
207+
// ENCODER-LABEL: case ::foo: {
208+
// ENCODER: unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_EncodingInfo);
209+
// ENCODER: HwMode &= 3;
210+
// ENCODER: switch (HwMode) {
211+
// ENCODER: default: llvm_unreachable("Unknown hardware mode!"); break;
212+
// ENCODER: case 0: InstBitsByHw = InstBits; break;
213+
// ENCODER: case 1: InstBitsByHw = InstBits_ModeA; break;
214+
// ENCODER: case 2: InstBitsByHw = InstBits_ModeB; break;
215+
// ENCODER: };
216+
// ENCODER: Value = InstBitsByHw[opcode];
217+
// ENCODER: switch (HwMode) {
218+
// ENCODER: default: llvm_unreachable("Unhandled HwMode");
219+
// ENCODER: case 0: {
220+
// ENCODER: op = getMachineOpValue(MI, MI.getOperand(0), Fixups, STI);
221+
// ENCODER: op &= UINT64_C(240);
222+
// ENCODER: Value |= op;
223+
// ENCODER: break;
224+
// ENCODER: }
225+
// ENCODER: case 1: {
226+
// ENCODER: op = getMachineOpValue(MI, MI.getOperand(0), Fixups, STI);
227+
// ENCODER: op &= UINT64_C(240);
228+
// ENCODER: Value |= op;
229+
// ENCODER: break;
230+
// ENCODER: }
231+
// ENCODER: case 2: {
232+
// ENCODER: op = getMachineOpValue(MI, MI.getOperand(0), Fixups, STI);
233+
// ENCODER: op &= UINT64_C(255);
234+
// ENCODER: op <<= 8;
235+
// ENCODER: Value |= op;
236+
// ENCODER: break;
237+
// ENCODER: }

0 commit comments

Comments
 (0)