Skip to content

Commit 8853d1c

Browse files
author
z30050559
committed
[TableGen] fix HwMode logic in CodeEmitterGen
1. Since we have obtained HwMode Id from getHwMode() interface, we no longer need to perform bit related operations when checking the case. 2. When generating the InstBits table, if the instruction does not have the HwMode ID corresponding to the current hwmode table, the base encoding will be generated based on the encoding defined in the top-level Instruction class. 3. Add testcase to test the correctness of hwmode encoding in APInt mode 4. Fixed a bug in the 'getOperandBitOffset' interface: it would check the HwMode ID for a instruction but did not preemptively fetch the HwMode ID. 5. Fix up some comments and clean up some codes.
1 parent d869590 commit 8853d1c

File tree

8 files changed

+373
-115
lines changed

8 files changed

+373
-115
lines changed

llvm/include/llvm/MC/MCSubtargetInfo.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,14 @@ class MCSubtargetInfo {
240240
return ProcFeatures;
241241
}
242242

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.
243+
/// HwMode IDs are stored and accessed in a bit set format, enabling
244+
/// users to efficiently retrieve specific IDs, such as the RegInfo
245+
/// HwMode ID, from the set as required. Using this approach, various
246+
/// types of HwMode IDs can be added to a subtarget to manage different
247+
/// attributes within that subtarget, significantly enhancing the
248+
/// scalability and usability of HwMode. Moreover, to ensure compatibility,
249+
/// this method also supports controlling multiple attributes with a single
250+
/// HwMode ID, just as was done previously.
247251
enum HwModeType {
248252
HwMode_Default, // Return the smallest HwMode ID of current subtarget.
249253
HwMode_ValueType, // Return the HwMode ID that controls the ValueType.
@@ -252,8 +256,13 @@ class MCSubtargetInfo {
252256
HwMode_EncodingInfo // Return the HwMode ID that controls the EncodingInfo.
253257
};
254258

259+
/// Return a bit set containing all HwMode IDs of the current subtarget.
255260
virtual unsigned getHwModeSet() const { return 0; }
256261

262+
/// HwMode ID corresponding to the 'type' parameter is retrieved from the
263+
/// HwMode bit set of the current subtarget. It’s important to note that if
264+
/// the current subtarget possesses two HwMode IDs and both control a single
265+
/// attribute (such as RegInfo), this interface will result in an error.
257266
virtual unsigned getHwMode(enum HwModeType type = HwMode_Default) const {
258267
return 0;
259268
}

llvm/test/TableGen/HwModeBitSet.td

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
// This is to test the scenario where different HwMode attributes coexist.
12
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-REG
23
// RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-SUBTARGET
34

5+
46
include "llvm/Target/Target.td"
57

68
def TestTargetInstrInfo : InstrInfo;
@@ -109,6 +111,7 @@ def fooTypeEncA : InstructionEncoding {
109111

110112

111113
def foo : Instruction {
114+
bits<32> Inst;
112115
let OutOperandList = (outs);
113116
let InOperandList = (ins i32imm:$factor);
114117
let EncodingInfos = EncodingByHwMode<
@@ -126,37 +129,34 @@ def foo : Instruction {
126129
// CHECK-SUBTARGET: }
127130
// CHECK-SUBTARGET-LABEL: unsigned TestTargetGenSubtargetInfo::getHwMode(enum HwModeType type) const {
128131
// CHECK-SUBTARGET: unsigned Modes = getHwModeSet();
129-
// CHECK-SUBTARGET: if(!Modes)
132+
// CHECK-SUBTARGET: if (!Modes)
130133
// CHECK-SUBTARGET: return Modes;
131134
// CHECK-SUBTARGET: switch (type) {
132135
// CHECK-SUBTARGET: case HwMode_Default:
133136
// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
134-
// CHECK-SUBTARGET: break;
135-
// CHECK-SUBTARGET: case HwMode_ValueType: {
137+
// CHECK-SUBTARGET: case HwMode_ValueType:
136138
// CHECK-SUBTARGET: Modes &= 3;
137139
// CHECK-SUBTARGET: if (!Modes)
138140
// CHECK-SUBTARGET: return Modes;
139141
// CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes))
140142
// CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for ValueType were found!");
141143
// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
142-
// CHECK-SUBTARGET: }
143-
// CHECK-SUBTARGET: case HwMode_RegInfo: {
144+
// CHECK-SUBTARGET: case HwMode_RegInfo:
144145
// CHECK-SUBTARGET: Modes &= 1;
145146
// CHECK-SUBTARGET: if (!Modes)
146147
// CHECK-SUBTARGET: return Modes;
147148
// CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes))
148149
// CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for RegInfo were found!");
149150
// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
150-
// CHECK-SUBTARGET: }
151-
// CHECK-SUBTARGET: case HwMode_EncodingInfo: {
151+
// CHECK-SUBTARGET: case HwMode_EncodingInfo:
152152
// CHECK-SUBTARGET: Modes &= 4;
153153
// CHECK-SUBTARGET: if (!Modes)
154154
// CHECK-SUBTARGET: return Modes;
155155
// CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes))
156-
// CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for Encoding were found!");
156+
// CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for EncodingInfo were found!");
157157
// CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1;
158158
// CHECK-SUBTARGET: }
159-
// CHECK-SUBTARGET: }
159+
// CHECK-SUBTARGET: llvm_unreachable("unexpected HwModeType");
160160
// CHECK-SUBTARGET: return 0; // should not get here
161161
// CHECK-SUBTARGET: }
162162

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
// This testcase is to test the correctness of HwMode encoding under the 'APInt' Mode.
2+
// RUN: llvm-tblgen -gen-emitter -I %p/../../include %s | \
3+
// RUN: FileCheck %s --check-prefix=ENCODER
4+
5+
include "llvm/Target/Target.td"
6+
7+
def archInstrInfo : InstrInfo { }
8+
9+
def arch : Target {
10+
let InstructionSet = archInstrInfo;
11+
}
12+
13+
def Myi32 : Operand<i32> {
14+
let DecoderMethod = "DecodeMyi32";
15+
}
16+
17+
def HasA : Predicate<"Subtarget->hasA()">;
18+
def HasB : Predicate<"Subtarget->hasB()">;
19+
20+
def ModeA : HwMode<"+a", [HasA]>; // Mode 1
21+
def ModeB : HwMode<"+b", [HasB]>; // Mode 2
22+
def ModeC : HwMode<"+c", []>; // Mode 3
23+
24+
25+
def fooTypeEncDefault : InstructionEncoding {
26+
let Size = 16;
27+
field bits<128> SoftFail = 0;
28+
bits<128> Inst;
29+
bits<8> factor;
30+
let Inst{127...120} = factor;
31+
let Inst{3...2} = 0b10;
32+
let Inst{1...0} = 0b00;
33+
}
34+
35+
def fooTypeEncA : InstructionEncoding {
36+
let Size = 16;
37+
field bits<128> SoftFail = 0;
38+
bits<128> Inst;
39+
bits<8> factor;
40+
let Inst{119...112} = factor;
41+
let Inst{3...2} = 0b11;
42+
let Inst{1...0} = 0b00;
43+
}
44+
45+
def fooTypeEncB : InstructionEncoding {
46+
let Size = 16;
47+
field bits<128> SoftFail = 0;
48+
bits<128> Inst;
49+
bits<8> factor;
50+
let Inst{119...112} = factor;
51+
let Inst{111...110} = 0b11;
52+
}
53+
54+
def fooTypeEncC : InstructionEncoding {
55+
let Size = 16;
56+
field bits<128> SoftFail = 0;
57+
bits<128> Inst;
58+
bits<8> factor;
59+
let Inst{31...24} = factor;
60+
let Inst{23...21} = 0b110;
61+
let Inst{1...0} = 0b11;
62+
}
63+
64+
// Test for DefaultMode as a selector.
65+
def foo : Instruction {
66+
bits<128> Inst;
67+
let OutOperandList = (outs);
68+
let InOperandList = (ins i32imm:$factor);
69+
let EncodingInfos = EncodingByHwMode<
70+
[ModeC, ModeA, ModeB, DefaultMode],
71+
[fooTypeEncC, fooTypeEncA, fooTypeEncB, fooTypeEncDefault]>;
72+
let AsmString = "foo $factor";
73+
}
74+
75+
def bar: Instruction {
76+
let OutOperandList = (outs);
77+
let InOperandList = (ins i32imm:$factor);
78+
let Size = 4;
79+
bits<32> Inst;
80+
bits<32> SoftFail;
81+
bits<8> factor;
82+
let Inst{31...24} = factor;
83+
let Inst{1...0} = 0b10;
84+
let AsmString = "bar $factor";
85+
}
86+
87+
def baz : Instruction {
88+
let OutOperandList = (outs);
89+
let InOperandList = (ins i32imm:$factor);
90+
bits<32> Inst;
91+
let EncodingInfos = EncodingByHwMode<
92+
[ModeB], [fooTypeEncA]
93+
>;
94+
let AsmString = "foo $factor";
95+
}
96+
97+
def unrelated: Instruction {
98+
let OutOperandList = (outs);
99+
let DecoderNamespace = "Alt";
100+
let InOperandList = (ins i32imm:$factor);
101+
let Size = 4;
102+
bits<32> Inst;
103+
bits<32> SoftFail;
104+
bits<8> factor;
105+
let Inst{31...24} = factor;
106+
let Inst{1...0} = 0b10;
107+
let AsmString = "unrelated $factor";
108+
}
109+
110+
// For 'bar' and 'unrelated', we didn't assign any HwModes for them,
111+
// they should keep the same in the following four tables.
112+
// For 'foo' we assigned four HwModes( includes 'DefaultMode' ),
113+
// it's encodings should be different in the following four tables.
114+
// For 'baz' we only assigned ModeB for it, so it will be presented
115+
// as '0' in the tables of ModeA, ModeC and Default Mode.
116+
// ENCODER-LABEL: static const uint64_t InstBits[] = {
117+
// ENCODER: UINT64_C(2), UINT64_C(0), // bar
118+
// ENCODER: UINT64_C(0), UINT64_C(0), // baz
119+
// ENCODER: UINT64_C(8), UINT64_C(0), // foo
120+
// ENCODER: UINT64_C(2), UINT64_C(0), // unrelated
121+
// ENCODER-LABEL: static const uint64_t InstBits_ModeA[] = {
122+
// ENCODER: UINT64_C(2), UINT64_C(0), // bar
123+
// ENCODER: UINT64_C(0), UINT64_C(0), // baz
124+
// ENCODER: UINT64_C(12), UINT64_C(0), // foo
125+
// ENCODER: UINT64_C(2), UINT64_C(0), // unrelated
126+
// ENCODER-LABEL: static const uint64_t InstBits_ModeB[] = {
127+
// ENCODER: UINT64_C(2), UINT64_C(0), // bar
128+
// ENCODER: UINT64_C(12), UINT64_C(0), // baz
129+
// ENCODER: UINT64_C(0), UINT64_C(211106232532992), // foo
130+
// ENCODER: UINT64_C(2), UINT64_C(0), // unrelated
131+
// ENCODER-LABEL: static const uint64_t InstBits_ModeC[] = {
132+
// ENCODER: UINT64_C(2), UINT64_C(0), // bar
133+
// ENCODER: UINT64_C(0), UINT64_C(0), // baz
134+
// ENCODER: UINT64_C(12582915), UINT64_C(0), // foo
135+
// ENCODER: UINT64_C(2), UINT64_C(0), // unrelated
136+
137+
138+
// ENCODER: const uint64_t *InstBitsByHw;
139+
// ENCODER: const unsigned opcode = MI.getOpcode();
140+
// ENCODER: if (Scratch.getBitWidth() != 128)
141+
// ENCODER: Scratch = Scratch.zext(128);
142+
// ENCODER: Inst = APInt(128, ArrayRef(InstBits + opcode * 2, 2));
143+
// ENCODER: APInt &Value = Inst;
144+
// ENCODER: APInt &op = Scratch;
145+
// ENCODER: switch (opcode) {
146+
// ENCODER-LABEL: case ::bar:
147+
// ENCODER-LABEL: case ::unrelated:
148+
// ENCODER-NOT: getHwMode
149+
// ENCODER-LABEL: case ::foo: {
150+
// ENCODER: unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_EncodingInfo);
151+
// ENCODER: switch (HwMode) {
152+
// ENCODER: default: llvm_unreachable("Unknown hardware mode!"); break;
153+
// ENCODER: case 0: InstBitsByHw = InstBits; break;
154+
// ENCODER: case 1: InstBitsByHw = InstBits_ModeA; break;
155+
// ENCODER: case 2: InstBitsByHw = InstBits_ModeB; break;
156+
// ENCODER: case 3: InstBitsByHw = InstBits_ModeC; break;
157+
// ENCODER: };
158+
// ENCODER: Inst = APInt(128, ArrayRef(InstBitsByHw + opcode * 2, 2));
159+
// ENCODER: Value = Inst;
160+
// ENCODER: switch (HwMode) {
161+
// ENCODER: default: llvm_unreachable("Unhandled HwMode");
162+
// ENCODER: case 0: {
163+
// ENCODER: op.clearAllBits();
164+
// ENCODER: getMachineOpValue(MI, MI.getOperand(0), op, Fixups, STI);
165+
// ENCODER: Value.insertBits(op.extractBitsAsZExtValue(8, 0), 120, 8);
166+
// ENCODER: break;
167+
// ENCODER: }
168+
// ENCODER: case 1: {
169+
// ENCODER: op.clearAllBits();
170+
// ENCODER: getMachineOpValue(MI, MI.getOperand(0), op, Fixups, STI);
171+
// ENCODER: Value.insertBits(op.extractBitsAsZExtValue(8, 0), 112, 8);
172+
// ENCODER: break;
173+
// ENCODER: }
174+
// ENCODER: case 2: {
175+
// ENCODER: op.clearAllBits();
176+
// ENCODER: getMachineOpValue(MI, MI.getOperand(0), op, Fixups, STI);
177+
// ENCODER: Value.insertBits(op.extractBitsAsZExtValue(8, 0), 112, 8);
178+
// ENCODER: break;
179+
// ENCODER: }
180+
// ENCODER: case 3: {
181+
// ENCODER: op.clearAllBits();
182+
// ENCODER: getMachineOpValue(MI, MI.getOperand(0), op, Fixups, STI);
183+
// ENCODER: Value.insertBits(op.extractBitsAsZExtValue(8, 0), 24, 8);
184+
// ENCODER: break;
185+
// ENCODER: }
186+
// ENCODER-LABEL: case ::baz: {
187+
// ENCODER: unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_EncodingInfo);
188+
// ENCODER: switch (HwMode) {
189+
// ENCODER: default: llvm_unreachable("Unknown hardware mode!"); break;
190+
// ENCODER: case 2: InstBitsByHw = InstBits_ModeB; break;
191+
// ENCODER: };
192+
// ENCODER: Inst = APInt(128, ArrayRef(InstBitsByHw + opcode * 2, 2));
193+
// ENCODER: Value = Inst;
194+
// ENCODER: switch (HwMode) {
195+
// ENCODER: default: llvm_unreachable("Unhandled HwMode");
196+
// ENCODER: case 2: {
197+
// ENCODER: getMachineOpValue(MI, MI.getOperand(0), op, Fixups, STI);
198+
// ENCODER: Value.insertBits(op.extractBitsAsZExtValue(8, 0), 112, 8);
199+
// ENCODER: break;
200+
// ENCODER: }
201+
202+
// ENCODER-LABEL: uint32_t archMCCodeEmitter::getOperandBitOffset
203+
// ENCODER: switch (MI.getOpcode()) {
204+
// ENCODER-LABEL: case ::bar:
205+
// ENCODER-LABEL: case ::unrelated: {
206+
// ENCODER-NOT: getHwMode
207+
// ENCODER-LABEL: case ::foo: {
208+
// ENCODER: unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_EncodingInfo);
209+
// ENCODER: switch (HwMode) {
210+
// ENCODER: default: llvm_unreachable("Unhandled HwMode");
211+
// ENCODER: case 0: {
212+
// ENCODER: switch (OpNum) {
213+
// ENCODER: case 0:
214+
// ENCODER: return 120;
215+
// ENCODER: }
216+
// ENCODER: break;
217+
// ENCODER: }
218+
// ENCODER: case 1: {
219+
// ENCODER: switch (OpNum) {
220+
// ENCODER: case 0:
221+
// ENCODER: return 112;
222+
// ENCODER: }
223+
// ENCODER: break;
224+
// ENCODER: }
225+
// ENCODER: case 2: {
226+
// ENCODER: switch (OpNum) {
227+
// ENCODER: case 0:
228+
// ENCODER: return 112;
229+
// ENCODER: }
230+
// ENCODER: break;
231+
// ENCODER: }
232+
// ENCODER: case 3: {
233+
// ENCODER: switch (OpNum) {
234+
// ENCODER: case 0:
235+
// ENCODER: return 24;
236+
// ENCODER: }
237+
// ENCODER: break;
238+
// ENCODER: }
239+
// ENCODER: }
240+
// ENCODER: break;
241+
// ENCODER: }

llvm/test/TableGen/HwModeEncodeDecode.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def fooTypeEncB : InstructionEncoding {
4141

4242
let OutOperandList = (outs) in {
4343
def foo : Instruction {
44+
bits<32> Inst;
4445
let InOperandList = (ins i32imm:$factor);
4546
let EncodingInfos = EncodingByHwMode<
4647
[ModeA, ModeB], [fooTypeEncA,

llvm/test/TableGen/HwModeEncodeDecode2.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def fooTypeEncB : InstructionEncoding {
4545

4646
let OutOperandList = (outs) in {
4747
def foo : Instruction {
48+
bits<32> Inst;
4849
let InOperandList = (ins i32imm:$factor);
4950
let EncodingInfos = EncodingByHwMode<
5051
[ModeA, ModeB], [fooTypeEncA, fooTypeEncB]

0 commit comments

Comments
 (0)