Skip to content

Commit 05af9c8

Browse files
authored
[TableGen] Suppress per-HwMode duplicate instructions/tables. (llvm#82567)
Currently, for per-HwMode encoding/decoding, those instructions that do not have a HwMode override are duplicated into the decoder tables for all HwModes. This includes inducing multiple tables for instructions that are otherwise unrelated (e.g., different namespace with no overrides at all). This patch adds support to suppress instruction and table duplicates. TableGen option "-gen-disassembler --suppress-per-hwmode-duplicates" enables the suppression (off by default). For one downstream backend with a complicated ISA and major cross-generation encoding differences, this eliminates ~32000 duplicate table entries at the time of this patch. There are legitimate reasons to suppress or not suppress duplicates. If there are relatively few non-overridden related instructions, it can be convenient to pull them into the per-mode tables (only need to decode the per-mode tables, slightly simpler decode function in disassembler). On the other hand, in some backends, the opposite is true or the size is too large to tolerate any duplication in the first place. We let the user decide which makes sense. This is currently off by default, though there is no reason it couldn't be enabled by default. Any existing backends downstream using the per-HwMode feature will function as before. Turning on the feature requires minor modifications to their disassembler due to more/less tables and naming.
1 parent 7e1432f commit 05af9c8

File tree

3 files changed

+137
-3
lines changed

3 files changed

+137
-3
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// RUN: llvm-tblgen -gen-disassembler -I %p/../../include %s | \
2+
// 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
5+
6+
// Test duplicate table suppression for per-HwMode decoders.
7+
8+
include "llvm/Target/Target.td"
9+
10+
def archInstrInfo : InstrInfo { }
11+
12+
def arch : Target {
13+
let InstructionSet = archInstrInfo;
14+
}
15+
16+
def Myi32 : Operand<i32> {
17+
let DecoderMethod = "DecodeMyi32";
18+
}
19+
20+
def HasA : Predicate<"Subtarget->hasA()">;
21+
def HasB : Predicate<"Subtarget->hasB()">;
22+
23+
def ModeA : HwMode<"+a", [HasA]>;
24+
def ModeB : HwMode<"+b", [HasB]>;
25+
26+
27+
def fooTypeEncA : InstructionEncoding {
28+
let Size = 4;
29+
field bits<32> SoftFail = 0;
30+
bits<32> Inst;
31+
bits<8> factor;
32+
let Inst{7...0} = factor;
33+
let Inst{3...2} = 0b11;
34+
let Inst{1...0} = 0b00;
35+
}
36+
37+
def fooTypeEncB : InstructionEncoding {
38+
let Size = 4;
39+
field bits<32> SoftFail = 0;
40+
bits<32> Inst;
41+
bits<8> factor;
42+
let Inst{15...8} = factor;
43+
let Inst{1...0} = 0b11;
44+
}
45+
46+
let OutOperandList = (outs) in {
47+
def foo : Instruction {
48+
let InOperandList = (ins i32imm:$factor);
49+
let EncodingInfos = EncodingByHwMode<
50+
[ModeA, ModeB], [fooTypeEncA, fooTypeEncB]
51+
>;
52+
let AsmString = "foo $factor";
53+
}
54+
55+
// Encoding not overridden, same namespace:
56+
// In the default case, this instruction is duplicated into both ModeA and
57+
// ModeB decoder tables.
58+
// In the suppressed case, this instruction appears in a single decoder table.
59+
def bar: Instruction {
60+
let InOperandList = (ins i32imm:$factor);
61+
let Size = 4;
62+
bits<32> Inst;
63+
bits<32> SoftFail;
64+
bits<8> factor;
65+
let Inst{31...24} = factor;
66+
let Inst{1...0} = 0b10;
67+
let AsmString = "bar $factor";
68+
}
69+
70+
def baz : Instruction {
71+
let InOperandList = (ins i32imm:$factor);
72+
bits<32> Inst;
73+
let EncodingInfos = EncodingByHwMode<
74+
[ModeB], [fooTypeEncA]
75+
>;
76+
let AsmString = "foo $factor";
77+
}
78+
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.
83+
def unrelated: Instruction {
84+
let DecoderNamespace = "Alt";
85+
let InOperandList = (ins i32imm:$factor);
86+
let Size = 4;
87+
bits<32> Inst;
88+
bits<32> SoftFail;
89+
bits<8> factor;
90+
let Inst{31...24} = factor;
91+
let Inst{1...0} = 0b10;
92+
let AsmString = "unrelated $factor";
93+
}
94+
}
95+
96+
// DECODER-LABEL: DecoderTableAlt_ModeA32[] =
97+
// DECODER-DAG: Opcode: unrelated
98+
// DECODER-LABEL: DecoderTableAlt_ModeB32[] =
99+
// DECODER-DAG: Opcode: unrelated
100+
// DECODER-LABEL: DecoderTable_ModeA32[] =
101+
// DECODER-DAG: Opcode: fooTypeEncA:foo
102+
// DECODER-DAG: Opcode: bar
103+
// DECODER-LABEL: DecoderTable_ModeB32[] =
104+
// DECODER-DAG: Opcode: fooTypeEncB:foo
105+
// DECODER-DAG: Opcode: fooTypeEncA:baz
106+
// 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/utils/TableGen/DecoderEmitter.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "llvm/ADT/StringRef.h"
2929
#include "llvm/MC/MCDecoderOps.h"
3030
#include "llvm/Support/Casting.h"
31+
#include "llvm/Support/CommandLine.h"
3132
#include "llvm/Support/Debug.h"
3233
#include "llvm/Support/ErrorHandling.h"
3334
#include "llvm/Support/FormattedStream.h"
@@ -50,6 +51,13 @@ using namespace llvm;
5051

5152
#define DEBUG_TYPE "decoder-emitter"
5253

54+
extern cl::OptionCategory DisassemblerEmitterCat;
55+
56+
cl::opt<bool> DecoderEmitterSuppressDuplicates(
57+
"suppress-per-hwmode-duplicates",
58+
cl::desc("Suppress duplication of instrs into per-HwMode decoder tables"),
59+
cl::init(false), cl::cat(DisassemblerEmitterCat));
60+
5361
namespace {
5462

5563
STATISTIC(NumEncodings, "Number of encodings considered");
@@ -2496,10 +2504,15 @@ void DecoderEmitter::run(raw_ostream &o) {
24962504
}
24972505
}
24982506
// This instruction is encoded the same on all HwModes. Emit it for all
2499-
// HwModes.
2500-
for (StringRef HwModeName : HwModeNames)
2507+
// HwModes by default, otherwise leave it in a single common table.
2508+
if (DecoderEmitterSuppressDuplicates) {
25012509
NumberedEncodings.emplace_back(NumberedInstruction->TheDef,
2502-
NumberedInstruction, HwModeName);
2510+
NumberedInstruction, "AllModes");
2511+
} else {
2512+
for (StringRef HwModeName : HwModeNames)
2513+
NumberedEncodings.emplace_back(NumberedInstruction->TheDef,
2514+
NumberedInstruction, HwModeName);
2515+
}
25032516
}
25042517
for (const auto &NumberedAlias :
25052518
RK.getAllDerivedDefinitions("AdditionalEncoding"))

llvm/utils/TableGen/DisassemblerEmitter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,7 @@ static void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
131131
EmitDecoder(Records, OS, PredicateNamespace);
132132
}
133133

134+
cl::OptionCategory DisassemblerEmitterCat("Options for -gen-disassembler");
135+
134136
static TableGen::Emitter::Opt X("gen-disassembler", EmitDisassembler,
135137
"Generate disassembler");

0 commit comments

Comments
 (0)