1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
// RUN: llvm-tblgen -gen-disassembler -I %p/../../../include %s | FileCheck %s --check-prefix=CHECK-DEFAULT
// RUN: llvm-tblgen -gen-disassembler -specialize-decoders-per-bitwidth -I %p/../../../include %s | FileCheck %s --check-prefix=CHECK-SPECIALIZE-NO-TABLE
// RUN: llvm-tblgen -gen-disassembler -specialize-decoders-per-bitwidth -use-fn-table-in-decode-to-mcinst -I %p/../../../include %s | FileCheck %s --check-prefix=CHECK-SPECIALIZE-TABLE
include "llvm/Target/Target.td"
def archInstrInfo : InstrInfo { }
def arch : Target {
let InstructionSet = archInstrInfo;
}
let Namespace = "arch" in {
def R0 : Register<"r0">;
def R1 : Register<"r1">;
def R2 : Register<"r2">;
def R3 : Register<"r3">;
}
def Regs : RegisterClass<"Regs", [i32], 32, (add R0, R1, R2, R3)>;
// Bit 0 of the encoding determines the size (8 or 16 bits).
// Bits {3..1} define the number of operands encoded.
class Instruction8Bit<int NumOps> : Instruction {
let Size = 1;
let OutOperandList = (outs);
field bits<8> Inst;
let Inst{0} = 0;
let Inst{3-1} = NumOps;
}
class Instruction16Bit<int NumOps> : Instruction {
let Size = 2;
let OutOperandList = (outs);
field bits<16> Inst;
let Inst{0} = 1;
let Inst{3-1} = NumOps;
}
// Define instructions to generate 4 cases in decodeToMCInst.
// Each register operand needs 2 bits to encode.
// An instruction with no inputs.
def Inst0 : Instruction8Bit<0> {
let Inst{7-4} = 0;
let InOperandList = (ins);
let AsmString = "Inst0";
}
// An instruction with a single input.
def Inst1 : Instruction8Bit<1> {
bits<2> r0;
let Inst{5-4} = r0;
let Inst{7-6} = 0;
let InOperandList = (ins Regs:$r0);
let AsmString = "Inst1";
}
// An instruction with two inputs.
def Inst2 : Instruction16Bit<2> {
bits<2> r0;
bits<2> r1;
let Inst{5-4} = r0;
let Inst{7-6} = r1;
let Inst{15-8} = 0;
let InOperandList = (ins Regs:$r0, Regs:$r1);
let AsmString = "Inst2";
}
// An instruction with three inputs. .
def Inst3 : Instruction16Bit<3> {
bits<2> r0;
bits<2> r1;
bits<2> r2;
let Inst{5-4} = r0;
let Inst{7-6} = r1;
let Inst{9-8} = r2;
let Inst{15-10} = 0;
let InOperandList = (ins Regs:$r0, Regs:$r1, Regs:$r2);
let AsmString = "Inst3";
}
// -----------------------------------------------------------------------------
// In the default case, we emit a single decodeToMCinst function and DecodeIdx
// is shared across all bitwidths.
// CHECK-DEFAULT-LABEL: DecoderTable8
// CHECK-DEFAULT: using decoder 0
// CHECK-DEFAULT: using decoder 1
// CHECK-DEFAULT: };
// CHECK-DEFAULT-LABEL: DecoderTable16
// CHECK-DEFAULT: using decoder 2
// CHECK-DEFAULT: using decoder 3
// CHECK-DEFAULT: };
// CHECK-DEFAULT-LABEL: template <typename InsnType>
// CHECK-DEFAULT-NEXT: static DecodeStatus decodeToMCInst
// CHECK-DEFAULT: case 0
// CHECK-DEFAULT: case 1
// CHECK-DEFAULT: case 2
// CHECK-DEFAULT: case 3
// -----------------------------------------------------------------------------
// When we specialize per bitwidth, we emit 2 decodeToMCInst functions and
// DecodeIdx is assigned per bit width.
// CHECK-SPECIALIZE-NO-TABLE-LABEL: DecoderTable8
// CHECK-SPECIALIZE-NO-TABLE: 8, // 0: BitWidth 8
// CHECK-SPECIALIZE-NO-TABLE: using decoder 0
// CHECK-SPECIALIZE-NO-TABLE: using decoder 1
// CHECK-SPECIALIZE-NO-TABLE: };
// CHECK-SPECIALIZE-NO-TABLE-LABEL: template <typename InsnType>
// CHECK-SPECIALIZE-NO-TABLE-NEXT: static std::enable_if_t<InsnBitWidth<InsnType> == 8, DecodeStatus>
// CHECK-SPECIALIZE-NO-TABLE-NEXT: decodeToMCInst
// CHECK-SPECIALIZE-NO-TABLE: case 0
// CHECK-SPECIALIZE-NO-TABLE: case 1
// CHECK-SPECIALIZE-NO-TABLE-LABEL: DecoderTable16
// CHECK-SPECIALIZE-NO-TABLE: 16, // 0: BitWidth 16
// CHECK-SPECIALIZE-NO-TABLE: using decoder 0
// CHECK-SPECIALIZE-NO-TABLE: using decoder 1
// CHECK-SPECIALIZE-NO-TABLE: };
// CHECK-SPECIALIZE-NO-TABLE-LABEL: template <typename InsnType>
// CHECK-SPECIALIZE-NO-TABLE-NEXT: static std::enable_if_t<InsnBitWidth<InsnType> == 16, DecodeStatus>
// CHECK-SPECIALIZE-NO-TABLE-NEXT: decodeToMCInst
// CHECK-SPECIALIZE-NO-TABLE: case 0
// CHECK-SPECIALIZE-NO-TABLE: case 1
// CHECK-SPECIALIZE-NO-TABLE-LABEL: template <typename InsnType>
// CHECK-SPECIALIZE-NO-TABLE-NEXT: decodeInstruction
// CHECK-SPECIALIZE-NO-TABLE: uint32_t BitWidth = decodeULEB128AndIncUnsafe(Ptr);
// CHECK-SPECIALIZE-NO-TABLE-NEXT: assert(InsnBitWidth<InsnType> == BitWidth &&
// -----------------------------------------------------------------------------
// Per bitwidth specialization with function table.
// 8 bit deccoder table, functions, and function table.
// CHECK-SPECIALIZE-TABLE-LABEL: DecoderTable8
// CHECK-SPECIALIZE-TABLE: 8, // 0: BitWidth 8
// CHECK-SPECIALIZE-TABLE: using decoder 0
// CHECK-SPECIALIZE-TABLE: using decoder 1
// CHECK-SPECIALIZE-TABLE: };
// CHECK-SPECIALIZE-TABLE-LABEL: template <typename InsnType>
// CHECK-SPECIALIZE-TABLE-NEXT: static std::enable_if_t<InsnBitWidth<InsnType> == 8, DecodeStatus>
// CHECK-SPECIALIZE-TABLE-NEXT: decodeFn_8bit_0
// CHECK-SPECIALIZE-TABLE-LABEL: template <typename InsnType>
// CHECK-SPECIALIZE-TABLE-NEXT: static std::enable_if_t<InsnBitWidth<InsnType> == 8, DecodeStatus>
// CHECK-SPECIALIZE-TABLE-NEXT: decodeFn_8bit_1
// CHECK-SPECIALIZE-TABLE-LABEL: template <typename InsnType>
// CHECK-SPECIALIZE-TABLE-NEXT: static std::enable_if_t<InsnBitWidth<InsnType> == 8, DecodeStatus>
// CHECK-SPECIALIZE-TABLE-NEXT: decodeToMCInst
// CHECK-SPECIALIZE-TABLE-LABEL: static constexpr DecodeFnTy decodeFnTable[] = {
// CHECK-SPECIALIZE-TABLE-NEXT: decodeFn_8bit_0,
// CHECK-SPECIALIZE-TABLE-NEXT: decodeFn_8bit_1,
// CHECK-SPECIALIZE-TABLE-NEXT: };
// 16 bit deccoder table, functions, and function table.
// CHECK-SPECIALIZE-TABLE-LABEL: DecoderTable16
// CHECK-SPECIALIZE-TABLE: 16, // 0: BitWidth 16
// CHECK-SPECIALIZE-TABLE: using decoder 0
// CHECK-SPECIALIZE-TABLE: using decoder 1
// CHECK-SPECIALIZE-TABLE: };
// CHECK-SPECIALIZE-TABLE-LABEL: template <typename InsnType>
// CHECK-SPECIALIZE-TABLE-NEXT: static std::enable_if_t<InsnBitWidth<InsnType> == 16, DecodeStatus>
// CHECK-SPECIALIZE-TABLE-NEXT: decodeFn_16bit_0
// CHECK-SPECIALIZE-TABLE-LABEL: template <typename InsnType>
// CHECK-SPECIALIZE-TABLE-NEXT: static std::enable_if_t<InsnBitWidth<InsnType> == 16, DecodeStatus>
// CHECK-SPECIALIZE-TABLE-NEXT: decodeFn_16bit_1
// CHECK-SPECIALIZE-TABLE-LABEL: template <typename InsnType>
// CHECK-SPECIALIZE-TABLE-NEXT: static std::enable_if_t<InsnBitWidth<InsnType> == 16, DecodeStatus>
// CHECK-SPECIALIZE-TABLE-NEXT: decodeToMCInst
// CHECK-SPECIALIZE-TABLE-LABEL: static constexpr DecodeFnTy decodeFnTable[] = {
// CHECK-SPECIALIZE-TABLE-NEXT: decodeFn_16bit_0,
// CHECK-SPECIALIZE-TABLE-NEXT: decodeFn_16bit_1,
// CHECK-SPECIALIZE-TABLE-NEXT: };
// CHECK-SPECIALIZE-TABLE-LABEL: template <typename InsnType>
// CHECK-SPECIALIZE-TABLE-NEXT: decodeInstruction
// CHECK-SPECIALIZE-TABLE: uint32_t BitWidth = decodeULEB128AndIncUnsafe(Ptr);
// CHECK-SPECIALIZE-TABLE-NEXT: assert(InsnBitWidth<InsnType> == BitWidth &&
|