Skip to content

Commit 36c19ea

Browse files
committed
[TableGen] Support custom decoders for variable length instructions
Just like the encoder directive for variable-length instructions, this patch adds a new decoder directive to allow custom decoder function on an operand. Right now, due to the design of DecoderEmitter each operand can only have a single custom decoder in a given instruction. Differential Revision: https://reviews.llvm.org/D142079
1 parent 7454439 commit 36c19ea

File tree

5 files changed

+54
-27
lines changed

5 files changed

+54
-27
lines changed

llvm/include/llvm/Target/Target.td

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -796,11 +796,17 @@ def operand;
796796
/// Both DAG represent bit 6 to 8 (total of 3 bits) in the encoding of operand
797797
/// `$src`.
798798
def slice;
799-
/// You can use `encoder` to specify a custom encoder function for a specific
800-
/// `operand` or `encoder` directive. For example:
799+
/// You can use `encoder` or `decoder` to specify a custom encoder or decoder
800+
/// function for a specific `operand` or `slice` directive. For example:
801801
/// (operand "$src", 4, (encoder "encodeMyImm"))
802802
/// (slice "$src", 8, 6, (encoder "encodeMyReg"))
803+
/// (operand "$src", 4, (encoder "encodeMyImm"), (decoder "decodeMyImm"))
804+
/// The ordering of `encoder` and `decoder` in the same `operand` or `slice`
805+
/// doesn't matter.
806+
/// Note that currently we cannot assign different decoders in the same
807+
/// (instruction) operand.
803808
def encoder;
809+
def decoder;
804810

805811
/// PointerLikeRegClass - Values that are designed to have pointer width are
806812
/// derived from this. TableGen treats the register class as having a symbolic

llvm/test/TableGen/VarLenDecoder.td

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@ class MyVarInst<MyMemOperand memory_op> : Instruction {
3434
def FOO16 : MyVarInst<MemOp16> {
3535
let Inst = (ascend
3636
(descend (operand "$dst", 3), 0b01000, (operand "$src.reg", 3)),
37-
(slice "$src.offset", 15, 0)
37+
(slice "$src.offset", 15, 0, (decoder "myCustomDecoder"))
3838
);
3939
}
4040
def FOO32 : MyVarInst<MemOp32> {
4141
let Inst = (ascend
42-
(descend (operand "$dst", 3), 0b01001, (operand "$src.reg", 3)),
42+
(descend (operand "$dst", 3), 0b01001,
43+
(operand "$src.reg", 3, (decoder "myCustomDecoder"))),
4344
(slice "$src.offset", 31, 16),
4445
(slice "$src.offset", 15, 0)
4546
);
@@ -63,13 +64,13 @@ def FOO32 : MyVarInst<MemOp32> {
6364
// CHECK-NEXT: tmp = fieldFromInstruction(insn, 0, 3);
6465
// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
6566
// CHECK-NEXT: tmp = fieldFromInstruction(insn, 11, 16);
66-
// CHECK-NEXT: MI.addOperand(MCOperand::createImm(tmp));
67+
// CHECK-NEXT: if (!Check(S, myCustomDecoder(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
6768
// CHECK-NEXT: return S;
6869
// CHECK-NEXT: case 1:
6970
// CHECK-NEXT: tmp = fieldFromInstruction(insn, 8, 3);
7071
// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
7172
// CHECK-NEXT: tmp = fieldFromInstruction(insn, 0, 3);
72-
// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
73+
// CHECK-NEXT: if (!Check(S, myCustomDecoder(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
7374
// CHECK-NEXT: tmp = 0x0;
7475
// CHECK-NEXT: insertBits(tmp, fieldFromInstruction(insn, 11, 16), 16, 16);
7576
// CHECK-NEXT: insertBits(tmp, fieldFromInstruction(insn, 27, 16), 0, 16);

llvm/utils/TableGen/DecoderEmitter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,6 +1893,8 @@ void parseVarLenInstOperand(const Record &Def,
18931893
OpName);
18941894
unsigned OpIdx = CGI.Operands.getFlattenedOperandNumber(OpSubOpPair);
18951895
Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset);
1896+
if (!EncodingSegment.CustomDecoder.empty())
1897+
Operands[OpIdx].Decoder = EncodingSegment.CustomDecoder.str();
18961898

18971899
int TiedReg = TiedTo[OpSubOpPair.first];
18981900
if (TiedReg != -1) {

llvm/utils/TableGen/VarLenCodeEmitterGen.cpp

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,35 @@ class VarLenCodeEmitterGen {
8383

8484
void run(raw_ostream &OS);
8585
};
86-
8786
} // end anonymous namespace
8887

88+
// Get the name of custom encoder or decoder, if there is any.
89+
// Returns `{encoder name, decoder name}`.
90+
static std::pair<StringRef, StringRef> getCustomCoders(ArrayRef<Init *> Args) {
91+
std::pair<StringRef, StringRef> Result;
92+
for (const auto *Arg : Args) {
93+
const auto *DI = dyn_cast<DagInit>(Arg);
94+
if (!DI)
95+
continue;
96+
const Init *Op = DI->getOperator();
97+
if (!isa<DefInit>(Op))
98+
continue;
99+
// syntax: `(<encoder | decoder> "function name")`
100+
StringRef OpName = cast<DefInit>(Op)->getDef()->getName();
101+
if (OpName != "encoder" && OpName != "decoder")
102+
continue;
103+
if (!DI->getNumArgs() || !isa<StringInit>(DI->getArg(0)))
104+
PrintFatalError("expected '" + OpName +
105+
"' directive to be followed by a custom function name.");
106+
StringRef FuncName = cast<StringInit>(DI->getArg(0))->getValue();
107+
if (OpName == "encoder")
108+
Result.first = FuncName;
109+
else
110+
Result.second = FuncName;
111+
}
112+
return Result;
113+
}
114+
89115
VarLenInst::VarLenInst(const DagInit *DI, const RecordVal *TheDef)
90116
: TheDef(TheDef), NumBits(0U) {
91117
buildRec(DI);
@@ -123,7 +149,8 @@ void VarLenInst::buildRec(const DagInit *DI) {
123149
}
124150
}
125151
} else if (Op == "operand") {
126-
// (operand <operand name>, <# of bits>, [(encoder <custom encoder>)])
152+
// (operand <operand name>, <# of bits>,
153+
// [(encoder <custom encoder>)][, (decoder <custom decoder>)])
127154
if (DI->getNumArgs() < 2)
128155
PrintFatalError(TheDef->getLoc(),
129156
"Expecting at least 2 arguments for `operand`");
@@ -136,14 +163,13 @@ void VarLenInst::buildRec(const DagInit *DI) {
136163
if (NumBitsVal <= 0)
137164
PrintFatalError(TheDef->getLoc(), "Invalid number of bits for `operand`");
138165

139-
StringRef CustomEncoder;
140-
if (DI->getNumArgs() >= 3)
141-
CustomEncoder = getCustomEncoderName(DI->getArg(2));
142-
Segments.push_back(
143-
{static_cast<unsigned>(NumBitsVal), OperandName, CustomEncoder});
166+
auto [CustomEncoder, CustomDecoder] =
167+
getCustomCoders(DI->getArgs().slice(2));
168+
Segments.push_back({static_cast<unsigned>(NumBitsVal), OperandName,
169+
CustomEncoder, CustomDecoder});
144170
} else if (Op == "slice") {
145171
// (slice <operand name>, <high / low bit>, <low / high bit>,
146-
// [(encoder <custom encoder>)])
172+
// [(encoder <custom encoder>)][, (decoder <custom decoder>)])
147173
if (DI->getNumArgs() < 3)
148174
PrintFatalError(TheDef->getLoc(),
149175
"Expecting at least 3 arguments for `slice`");
@@ -167,18 +193,17 @@ void VarLenInst::buildRec(const DagInit *DI) {
167193
NumBits = static_cast<unsigned>(HiBitVal - LoBitVal + 1);
168194
}
169195

170-
StringRef CustomEncoder;
171-
if (DI->getNumArgs() >= 4)
172-
CustomEncoder = getCustomEncoderName(DI->getArg(3));
196+
auto [CustomEncoder, CustomDecoder] =
197+
getCustomCoders(DI->getArgs().slice(3));
173198

174199
if (NeedSwap) {
175200
// Normalization: Hi bit should always be the second argument.
176201
Init *const NewArgs[] = {OperandName, LoBit, HiBit};
177202
Segments.push_back({NumBits,
178203
DagInit::get(DI->getOperator(), nullptr, NewArgs, {}),
179-
CustomEncoder});
204+
CustomEncoder, CustomDecoder});
180205
} else {
181-
Segments.push_back({NumBits, DI, CustomEncoder});
206+
Segments.push_back({NumBits, DI, CustomEncoder, CustomDecoder});
182207
}
183208
}
184209
}

llvm/utils/TableGen/VarLenCodeEmitterGen.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ struct EncodingSegment {
2222
unsigned BitWidth;
2323
const Init *Value;
2424
StringRef CustomEncoder = "";
25+
StringRef CustomDecoder = "";
2526
};
2627

2728
class VarLenInst {
@@ -35,14 +36,6 @@ class VarLenInst {
3536

3637
void buildRec(const DagInit *DI);
3738

38-
StringRef getCustomEncoderName(const Init *EI) const {
39-
if (const auto *DI = dyn_cast<DagInit>(EI)) {
40-
if (DI->getNumArgs() && isa<StringInit>(DI->getArg(0)))
41-
return cast<StringInit>(DI->getArg(0))->getValue();
42-
}
43-
return "";
44-
}
45-
4639
public:
4740
VarLenInst() : TheDef(nullptr), NumBits(0U), HasDynamicSegment(false) {}
4841

0 commit comments

Comments
 (0)