Skip to content

Commit ffcba0a

Browse files
z30050559zhengwentao (C)
authored andcommitted
[TableGen] fix tlbgen for EncodingByHwMode
By using 'HwMode', we can let one instruction have different encodings. But there are some defects in the original TableGen logic in llvm framework. 1. If we use HwModes to control one instruction's encodings, there will generate multiple copies of the original DecoderTables to where the instruction belongs. But for instructions who are not controlled by HwModes, tablegen still generate multiple copies of DecoderTables for them, which is an absolutely redundant behavior. 2. If we use HwModes to control one instruction's encodings, when get binary code for instruction, framework will check all subtargets' HwModes, but we only set HwModes for subtargets whose instructions' encodings conflict, those subtargets without HwModes will cause 'llvm_unreachable'. 3. RegInfoByHwMode and EncodingByHwModes cannot coexist, and resolve it by store HwModes Id in bits. 4. Fix DefaultMode logic for EncodingByHwMode in Decoder and CodeEmitter.
1 parent ffe4181 commit ffcba0a

File tree

8 files changed

+224
-115
lines changed

8 files changed

+224
-115
lines changed

llvm/test/TableGen/HwModeEncodeDecode2.td

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// RUN: llvm-tblgen -gen-disassembler -I %p/../../include %s | \
22
// RUN: FileCheck %s --check-prefix=DECODER
3-
// RUN: llvm-tblgen -gen-disassembler --suppress-per-hwmode-duplicates -I \
4-
// RUN: %p/../../include %s | FileCheck %s --check-prefix=DECODER-SUPPRESS
53

64
// Test duplicate table suppression for per-HwMode decoders.
75

@@ -76,10 +74,8 @@ let OutOperandList = (outs) in {
7674
let AsmString = "foo $factor";
7775
}
7876

79-
// Encoding not overridden, different namespace:
80-
// In the default case, this instruction is duplicated into two Alt decoder
81-
// tables (ModeA and ModeB).
82-
// In the suppressed case, this instruction appears in a single decoder table.
77+
// Instructions whose DecoderNamespace doesn't contain valid
78+
// EncodingInfos attribute, should remain the same as before.
8379
def unrelated: Instruction {
8480
let DecoderNamespace = "Alt";
8581
let InOperandList = (ins i32imm:$factor);
@@ -93,9 +89,7 @@ let OutOperandList = (outs) in {
9389
}
9490
}
9591

96-
// DECODER-LABEL: DecoderTableAlt_ModeA32[] =
97-
// DECODER-DAG: Opcode: unrelated
98-
// DECODER-LABEL: DecoderTableAlt_ModeB32[] =
92+
// DECODER-LABEL: DecoderTableAlt32[] =
9993
// DECODER-DAG: Opcode: unrelated
10094
// DECODER-LABEL: DecoderTable_ModeA32[] =
10195
// DECODER-DAG: Opcode: fooTypeEncA:foo
@@ -104,16 +98,3 @@ let OutOperandList = (outs) in {
10498
// DECODER-DAG: Opcode: fooTypeEncB:foo
10599
// DECODER-DAG: Opcode: fooTypeEncA:baz
106100
// DECODER-DAG: Opcode: bar
107-
108-
109-
// DECODER-SUPPRESS-LABEL: DecoderTableAlt_AllModes32[] =
110-
// DECODER-SUPPRESS-DAG: Opcode: unrelated
111-
// DECODER-SUPPRESS-LABEL: DecoderTable_AllModes32[] =
112-
// DECODER-SUPPRESS-DAG: Opcode: bar
113-
// DECODER-SUPPRESS-LABEL: DecoderTable_ModeA32[] =
114-
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncA:foo
115-
// DECODER-SUPPRESS-NOT: Opcode: bar
116-
// DECODER-SUPPRESS-LABEL: DecoderTable_ModeB32[] =
117-
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncB:foo
118-
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncA:baz
119-
// DECODER-SUPPRESS-NOT: Opcode: bar

llvm/test/TableGen/HwModeEncodeDecode3.td

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// RUN: FileCheck %s --check-prefix=ENCODER
33
// RUN: llvm-tblgen -gen-disassembler -I %p/../../include %s | \
44
// RUN: FileCheck %s --check-prefix=DECODER
5-
// RUN: llvm-tblgen -gen-disassembler --suppress-per-hwmode-duplicates -I \
6-
// RUN: %p/../../include %s | FileCheck %s --check-prefix=DECODER-SUPPRESS
75

86
include "llvm/Target/Target.td"
97

@@ -20,8 +18,8 @@ def Myi32 : Operand<i32> {
2018
def HasA : Predicate<"Subtarget->hasA()">;
2119
def HasB : Predicate<"Subtarget->hasB()">;
2220

23-
def ModeA : HwMode<"+a", [HasA]>;
24-
def ModeB : HwMode<"+b", [HasB]>;
21+
def ModeA : HwMode<"+a", [HasA]>; // hwmode ID 1
22+
def ModeB : HwMode<"+b", [HasB]>; // hwmode ID 2
2523

2624

2725
def fooTypeEncDefault : InstructionEncoding {
@@ -98,17 +96,24 @@ def unrelated: Instruction {
9896
let AsmString = "unrelated $factor";
9997
}
10098

99+
// DecoderTable64 is assigned with 'DefaultMode',
100+
// the table name should remain the same as before.
101+
// DECODER-LABEL: DecoderTable64[] =
102+
// DECODER-DAG: Opcode: fooTypeEncDefault:foo
101103

102-
// DECODER-LABEL: DecoderTableAlt_DefaultMode32[] =
103-
// DECODER-DAG: Opcode: unrelated
104-
// DECODER-LABEL: DecoderTableAlt_ModeA32[] =
105-
// DECODER-DAG: Opcode: unrelated
106-
// DECODER-LABEL: DecoderTableAlt_ModeB32[] =
104+
// DecoderTable without any valid HwModes
105+
// should not have any suffix in table name.
106+
// The table should remain the same as before.
107+
// DECODER-LABEL: DecoderTableAlt32[] =
107108
// DECODER-DAG: Opcode: unrelated
108-
// DECODER-LABEL: DecoderTable_DefaultMode32[] =
109-
// DECODER-DAG: Opcode: bar
110-
// DECODER-LABEL: DecoderTable_DefaultMode64[] =
111-
// DECODER-DAG: Opcode: fooTypeEncDefault:foo
109+
// DECODER-NOT: DecoderTableAlt_ModeA32[]
110+
// DECODER-NOT: DecoderTableAlt_ModeB32[]
111+
112+
// The DecoderTable32 contains two valid hwmodes, we will
113+
// generate two tables corresponding to these hwmodes.
114+
// Still want to say we didn't assign 'DefaultMode' to DecoderTable32,
115+
// instead we assign 'DefaultMode' to DecoderTable64, so
116+
// DecoderTable32 won't appear here.
112117
// DECODER-LABEL: DecoderTable_ModeA32[] =
113118
// DECODER-DAG: Opcode: fooTypeEncA:foo
114119
// DECODER-DAG: Opcode: bar
@@ -118,30 +123,24 @@ def unrelated: Instruction {
118123
// DECODER-DAG: Opcode: bar
119124

120125

121-
// DECODER-SUPPRESS-LABEL: DecoderTableAlt_AllModes32[] =
122-
// DECODER-SUPPRESS-DAG: Opcode: unrelated
123-
// DECODER-SUPPRESS-LABEL: DecoderTable_AllModes32[] =
124-
// DECODER-SUPPRESS-DAG: Opcode: bar
125-
// DECODER-SUPPRESS-LABEL: DecoderTable_DefaultMode64[] =
126-
// DECODER-SUPPRESS-NOT: Opcode: bar
127-
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncDefault:foo
128-
// DECODER-SUPPRESS-LABEL: DecoderTable_ModeA32[] =
129-
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncA:foo
130-
// DECODER-SUPPRESS-NOT: Opcode: bar
131-
// DECODER-SUPPRESS-LABEL: DecoderTable_ModeB32[] =
132-
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncB:foo
133-
// DECODER-SUPPRESS-DAG: Opcode: fooTypeEncA:baz
134-
// DECODER-SUPPRESS-NOT: Opcode: bar
135-
136-
// ENCODER-LABEL: static const uint64_t InstBits_DefaultMode[] = {
126+
// For 'bar' and 'unrelated', we didn't assign any hwmodes for them,
127+
// they should keep the same in the following three tables.
128+
// For 'foo' we assigned three hwmodes(includes 'DefaultMode')
129+
// it's encodings should be different in the following three tables.
130+
// For 'baz' we only assigned ModeB for it, to avoid empty encoding
131+
// we assigned the encoding of ModeB to ModeA and DefaultMode(Even though
132+
// they will not be used).
133+
// ENCODER-LABEL: static const uint64_t InstBits[] = {
137134
// ENCODER: UINT64_C(2), // bar
138-
// ENCODER: UINT64_C(0), // baz
135+
// To avoid empty encoding, we choose the encoding of ModeB for baz here
136+
// ENCODER: UINT64_C(12), // baz
139137
// ENCODER: UINT64_C(8), // foo
140138
// ENCODER: UINT64_C(2), // unrelated
141139

142140
// ENCODER-LABEL: static const uint64_t InstBits_ModeA[] = {
143141
// ENCODER: UINT64_C(2), // bar
144-
// ENCODER: UINT64_C(0), // baz
142+
// To avoid empty encoding, we choose the encoding of ModeB for baz here
143+
// ENCODER: UINT64_C(12), // baz
145144
// ENCODER: UINT64_C(12), // foo
146145
// ENCODER: UINT64_C(2), // unrelated
147146

@@ -151,18 +150,39 @@ def unrelated: Instruction {
151150
// ENCODER: UINT64_C(3), // foo
152151
// ENCODER: UINT64_C(2), // unrelated
153152

153+
// Sink the logic of hwmodes selection to per instruction level.
154+
// ENCODER-LABEL: case ::bar:
155+
// ENCODER: op = getMachineOpValue
156+
// ENCODER-LABEL: case ::baz: {
157+
// ENCODER: unsigned HwMode = STI.getHwMode();
158+
// ENCODER: HwMode &= 2;
159+
// ENCODER: switch (HwMode) {
160+
// ENCODER: default: llvm_unreachable("Unknown hardware mode!"); break;
161+
// ENCODER: case 2: InstBitsByHw = InstBits_ModeB; break;
162+
// ENCODER: };
163+
// ENCODER: Value = InstBitsByHw[opcode];
164+
// ENCODER: switch (HwMode) {
165+
// ENCODER: default: llvm_unreachable("Unhandled HwMode");
166+
// ENCODER: case 2: {
167+
// ENCODER: op = getMachineOpValue
168+
// ENCODER-LABEL: case ::foo: {
154169
// ENCODER: unsigned HwMode = STI.getHwMode();
170+
// ENCODER: HwMode &= 3;
155171
// ENCODER: switch (HwMode) {
156172
// ENCODER: default: llvm_unreachable("Unknown hardware mode!"); break;
157-
// ENCODER: case 0: InstBits = InstBits_DefaultMode; break;
158-
// ENCODER: case 1: InstBits = InstBits_ModeA; break;
159-
// ENCODER: case 2: InstBits = InstBits_ModeB; break;
173+
// ENCODER: case 0: InstBitsByHw = InstBits; break;
174+
// ENCODER: case 1: InstBitsByHw = InstBits_ModeA; break;
175+
// ENCODER: case 2: InstBitsByHw = InstBits_ModeB; break;
160176
// ENCODER: };
177+
// ENCODER: Value = InstBitsByHw[opcode];
178+
// ENCODER: switch (HwMode) {
179+
// ENCODER: default: llvm_unreachable("Unhandled HwMode");
180+
// ENCODER: case 0: {
181+
// ENCODER: op = getMachineOpValue
182+
// ENCODER: case 1: {
183+
// ENCODER: op = getMachineOpValue
184+
// ENCODER: case 2: {
185+
// ENCODER: op = getMachineOpValue
186+
161187

162-
// ENCODER: case ::foo: {
163-
// ENCODER: switch (HwMode) {
164-
// ENCODER: default: llvm_unreachable("Unhandled HwMode");
165-
// ENCODER: case 0: {
166-
// ENCODER: case 1: {
167-
// ENCODER: case 2: {
168188

llvm/utils/TableGen/CodeEmitterGen.cpp

Lines changed: 69 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class CodeEmitterGen {
6868

6969
void emitInstructionBaseValues(
7070
raw_ostream &o, ArrayRef<const CodeGenInstruction *> NumberedInstructions,
71-
CodeGenTarget &Target, int HwMode = -1);
71+
CodeGenTarget &Target, unsigned HwMode = DefaultMode);
7272
void
7373
emitCaseMap(raw_ostream &o,
7474
const std::map<std::string, std::vector<std::string>> &CaseMap);
@@ -281,7 +281,7 @@ std::pair<std::string, std::string>
281281
CodeEmitterGen::getInstructionCases(Record *R, CodeGenTarget &Target) {
282282
std::string Case, BitOffsetCase;
283283

284-
auto append = [&](const char *S) {
284+
auto append = [&](const std::string &S) {
285285
Case += S;
286286
BitOffsetCase += S;
287287
};
@@ -290,11 +290,54 @@ CodeEmitterGen::getInstructionCases(Record *R, CodeGenTarget &Target) {
290290
if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
291291
const CodeGenHwModes &HWM = Target.getHwModes();
292292
EncodingInfoByHwMode EBM(DI->getDef(), HWM);
293+
unsigned EncodingHwModesInBits = DefaultMode;
294+
for (auto &[ModeId, Encoding] : EBM) {
295+
// DefaultMode is 0, skip it.
296+
if (ModeId != DefaultMode)
297+
EncodingHwModesInBits |= (1 << (ModeId - 1));
298+
}
299+
300+
// Get HwModes for this Instr by bitwise AND operations,
301+
// and find the table to which this instr and hwmode belong.
302+
append(" unsigned HwMode = STI.getHwMode();\n");
303+
append(" HwMode &= " + itostr(EncodingHwModesInBits) + ";\n");
304+
append(" switch (HwMode) {\n");
305+
append(" default: llvm_unreachable(\"Unknown hardware mode!\"); "
306+
"break;\n");
307+
for (auto &[ModeId, Encoding] : EBM) {
308+
if (ModeId == DefaultMode) {
309+
append(" case " + itostr(DefaultMode) +
310+
": InstBitsByHw = InstBits");
311+
} else {
312+
append(" case " + itostr(1 << (ModeId - 1)) +
313+
": InstBitsByHw = InstBits_" +
314+
std::string(HWM.getMode(ModeId).Name));
315+
}
316+
append("; break;\n");
317+
}
318+
append(" };\n");
319+
320+
// We need to remodify the 'Inst' value from the table we found above.
321+
if (UseAPInt) {
322+
int NumWords = APInt::getNumWords(BitWidth);
323+
append(" Inst = APInt(" + itostr(BitWidth));
324+
append(", ArrayRef(InstBitsByHw + opcode * " + itostr(NumWords) +
325+
", " + itostr(NumWords));
326+
append("));\n");
327+
append(" Value = Inst;\n");
328+
} else {
329+
append(" Value = InstBitsByHw[opcode];\n");
330+
}
331+
293332
append(" switch (HwMode) {\n");
294333
append(" default: llvm_unreachable(\"Unhandled HwMode\");\n");
295-
for (auto &KV : EBM) {
296-
append((" case " + itostr(KV.first) + ": {\n").c_str());
297-
addInstructionCasesForEncoding(R, KV.second, Target, Case,
334+
for (auto &[ModeId, Encoding] : EBM) {
335+
if (ModeId == DefaultMode) {
336+
append(" case " + itostr(DefaultMode) + ": {\n");
337+
} else {
338+
append(" case " + itostr(1 << (ModeId - 1)) + ": {\n");
339+
}
340+
addInstructionCasesForEncoding(R, Encoding, Target, Case,
298341
BitOffsetCase);
299342
append(" break;\n");
300343
append(" }\n");
@@ -360,9 +403,9 @@ static void emitInstBits(raw_ostream &OS, const APInt &Bits) {
360403

361404
void CodeEmitterGen::emitInstructionBaseValues(
362405
raw_ostream &o, ArrayRef<const CodeGenInstruction *> NumberedInstructions,
363-
CodeGenTarget &Target, int HwMode) {
406+
CodeGenTarget &Target, unsigned HwMode) {
364407
const CodeGenHwModes &HWM = Target.getHwModes();
365-
if (HwMode == -1)
408+
if (HwMode == DefaultMode)
366409
o << " static const uint64_t InstBits[] = {\n";
367410
else
368411
o << " static const uint64_t InstBits_"
@@ -383,8 +426,17 @@ void CodeEmitterGen::emitInstructionBaseValues(
383426
if (const RecordVal *RV = R->getValue("EncodingInfos")) {
384427
if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
385428
EncodingInfoByHwMode EBM(DI->getDef(), HWM);
386-
if (EBM.hasMode(HwMode))
429+
if (EBM.hasMode(HwMode)) {
387430
EncodingDef = EBM.get(HwMode);
431+
} else {
432+
// If this Instr dosen't have this HwMode, just choose
433+
// the encoding from the first HwMode. Otherwise, the encoding
434+
// info would be empty.
435+
for (auto &[ModeId, Encoding] : EBM) {
436+
EncodingDef = Encoding;
437+
break;
438+
}
439+
}
388440
}
389441
}
390442
BitsInit *BI = EncodingDef->getValueAsBitsInit("Inst");
@@ -479,23 +531,17 @@ void CodeEmitterGen::run(raw_ostream &o) {
479531
}
480532

481533
// Emit instruction base values
482-
if (HwModes.empty()) {
483-
emitInstructionBaseValues(o, NumberedInstructions, Target, -1);
484-
} else {
485-
for (unsigned HwMode : HwModes)
486-
emitInstructionBaseValues(o, NumberedInstructions, Target, (int)HwMode);
487-
}
488-
534+
emitInstructionBaseValues(o, NumberedInstructions, Target, DefaultMode);
489535
if (!HwModes.empty()) {
490-
o << " const uint64_t *InstBits;\n";
491-
o << " unsigned HwMode = STI.getHwMode();\n";
492-
o << " switch (HwMode) {\n";
493-
o << " default: llvm_unreachable(\"Unknown hardware mode!\"); break;\n";
494-
for (unsigned I : HwModes) {
495-
o << " case " << I << ": InstBits = InstBits_"
496-
<< HWM.getModeName(I, /*IncludeDefault=*/true) << "; break;\n";
536+
// Emit table for instrs whose encodings are controlled by HwModes.
537+
for (unsigned HwMode : HwModes) {
538+
if (HwMode == DefaultMode)
539+
continue;
540+
emitInstructionBaseValues(o, NumberedInstructions, Target, HwMode);
497541
}
498-
o << " };\n";
542+
543+
// This pointer will be assigned to the HwMode table later.
544+
o << " const uint64_t *InstBitsByHw;\n";
499545
}
500546

501547
// Map to accumulate all the cases.

llvm/utils/TableGen/CodeGenHwModes.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ CodeGenHwModes::CodeGenHwModes(RecordKeeper &RK) : Records(RK) {
7474
ModeIds.insert(std::pair(R, Modes.size()));
7575
}
7676

77+
assert(Modes.size() <= 32 && "number of HwModes exceeds maximum of 32");
78+
7779
for (Record *R : Records.getAllDerivedDefinitions("HwModeSelect")) {
7880
auto P = ModeSelects.emplace(std::pair(R, HwModeSelect(R, *this)));
7981
assert(P.second);

0 commit comments

Comments
 (0)