summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMin-Yih Hsu <minyihh@uci.edu>2022-11-20 22:35:27 -0800
committerMin-Yih Hsu <minyihh@uci.edu>2023-01-24 21:59:24 -0800
commit36c19eae27b2970c02af77c1eb6e35aa3d3bf4df (patch)
tree4db52305364c79cb73b120c5ff9cbcf0b25f9fc8
parent7454439674a4a78b9fc9dc9ffba7a60717ee310b (diff)
downloadllvm-36c19eae27b2970c02af77c1eb6e35aa3d3bf4df.tar.gz
[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
-rw-r--r--llvm/include/llvm/Target/Target.td10
-rw-r--r--llvm/test/TableGen/VarLenDecoder.td9
-rw-r--r--llvm/utils/TableGen/DecoderEmitter.cpp2
-rw-r--r--llvm/utils/TableGen/VarLenCodeEmitterGen.cpp51
-rw-r--r--llvm/utils/TableGen/VarLenCodeEmitterGen.h9
5 files changed, 54 insertions, 27 deletions
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index dccb1469ee9b..181c8eb17511 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -796,11 +796,17 @@ def operand;
/// Both DAG represent bit 6 to 8 (total of 3 bits) in the encoding of operand
/// `$src`.
def slice;
-/// You can use `encoder` to specify a custom encoder function for a specific
-/// `operand` or `encoder` directive. For example:
+/// You can use `encoder` or `decoder` to specify a custom encoder or decoder
+/// function for a specific `operand` or `slice` directive. For example:
/// (operand "$src", 4, (encoder "encodeMyImm"))
/// (slice "$src", 8, 6, (encoder "encodeMyReg"))
+/// (operand "$src", 4, (encoder "encodeMyImm"), (decoder "decodeMyImm"))
+/// The ordering of `encoder` and `decoder` in the same `operand` or `slice`
+/// doesn't matter.
+/// Note that currently we cannot assign different decoders in the same
+/// (instruction) operand.
def encoder;
+def decoder;
/// PointerLikeRegClass - Values that are designed to have pointer width are
/// derived from this. TableGen treats the register class as having a symbolic
diff --git a/llvm/test/TableGen/VarLenDecoder.td b/llvm/test/TableGen/VarLenDecoder.td
index 512cae8dbf66..0d36d14b5b8f 100644
--- a/llvm/test/TableGen/VarLenDecoder.td
+++ b/llvm/test/TableGen/VarLenDecoder.td
@@ -34,12 +34,13 @@ class MyVarInst<MyMemOperand memory_op> : Instruction {
def FOO16 : MyVarInst<MemOp16> {
let Inst = (ascend
(descend (operand "$dst", 3), 0b01000, (operand "$src.reg", 3)),
- (slice "$src.offset", 15, 0)
+ (slice "$src.offset", 15, 0, (decoder "myCustomDecoder"))
);
}
def FOO32 : MyVarInst<MemOp32> {
let Inst = (ascend
- (descend (operand "$dst", 3), 0b01001, (operand "$src.reg", 3)),
+ (descend (operand "$dst", 3), 0b01001,
+ (operand "$src.reg", 3, (decoder "myCustomDecoder"))),
(slice "$src.offset", 31, 16),
(slice "$src.offset", 15, 0)
);
@@ -63,13 +64,13 @@ def FOO32 : MyVarInst<MemOp32> {
// CHECK-NEXT: tmp = fieldFromInstruction(insn, 0, 3);
// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
// CHECK-NEXT: tmp = fieldFromInstruction(insn, 11, 16);
-// CHECK-NEXT: MI.addOperand(MCOperand::createImm(tmp));
+// CHECK-NEXT: if (!Check(S, myCustomDecoder(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
// CHECK-NEXT: return S;
// CHECK-NEXT: case 1:
// CHECK-NEXT: tmp = fieldFromInstruction(insn, 8, 3);
// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
// CHECK-NEXT: tmp = fieldFromInstruction(insn, 0, 3);
-// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
+// CHECK-NEXT: if (!Check(S, myCustomDecoder(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
// CHECK-NEXT: tmp = 0x0;
// CHECK-NEXT: insertBits(tmp, fieldFromInstruction(insn, 11, 16), 16, 16);
// CHECK-NEXT: insertBits(tmp, fieldFromInstruction(insn, 27, 16), 0, 16);
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index fef574b7b7f2..8f816744370c 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -1893,6 +1893,8 @@ void parseVarLenInstOperand(const Record &Def,
OpName);
unsigned OpIdx = CGI.Operands.getFlattenedOperandNumber(OpSubOpPair);
Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset);
+ if (!EncodingSegment.CustomDecoder.empty())
+ Operands[OpIdx].Decoder = EncodingSegment.CustomDecoder.str();
int TiedReg = TiedTo[OpSubOpPair.first];
if (TiedReg != -1) {
diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp
index 81201229079c..2c1acd8d910c 100644
--- a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp
+++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp
@@ -83,9 +83,35 @@ public:
void run(raw_ostream &OS);
};
-
} // end anonymous namespace
+// Get the name of custom encoder or decoder, if there is any.
+// Returns `{encoder name, decoder name}`.
+static std::pair<StringRef, StringRef> getCustomCoders(ArrayRef<Init *> Args) {
+ std::pair<StringRef, StringRef> Result;
+ for (const auto *Arg : Args) {
+ const auto *DI = dyn_cast<DagInit>(Arg);
+ if (!DI)
+ continue;
+ const Init *Op = DI->getOperator();
+ if (!isa<DefInit>(Op))
+ continue;
+ // syntax: `(<encoder | decoder> "function name")`
+ StringRef OpName = cast<DefInit>(Op)->getDef()->getName();
+ if (OpName != "encoder" && OpName != "decoder")
+ continue;
+ if (!DI->getNumArgs() || !isa<StringInit>(DI->getArg(0)))
+ PrintFatalError("expected '" + OpName +
+ "' directive to be followed by a custom function name.");
+ StringRef FuncName = cast<StringInit>(DI->getArg(0))->getValue();
+ if (OpName == "encoder")
+ Result.first = FuncName;
+ else
+ Result.second = FuncName;
+ }
+ return Result;
+}
+
VarLenInst::VarLenInst(const DagInit *DI, const RecordVal *TheDef)
: TheDef(TheDef), NumBits(0U) {
buildRec(DI);
@@ -123,7 +149,8 @@ void VarLenInst::buildRec(const DagInit *DI) {
}
}
} else if (Op == "operand") {
- // (operand <operand name>, <# of bits>, [(encoder <custom encoder>)])
+ // (operand <operand name>, <# of bits>,
+ // [(encoder <custom encoder>)][, (decoder <custom decoder>)])
if (DI->getNumArgs() < 2)
PrintFatalError(TheDef->getLoc(),
"Expecting at least 2 arguments for `operand`");
@@ -136,14 +163,13 @@ void VarLenInst::buildRec(const DagInit *DI) {
if (NumBitsVal <= 0)
PrintFatalError(TheDef->getLoc(), "Invalid number of bits for `operand`");
- StringRef CustomEncoder;
- if (DI->getNumArgs() >= 3)
- CustomEncoder = getCustomEncoderName(DI->getArg(2));
- Segments.push_back(
- {static_cast<unsigned>(NumBitsVal), OperandName, CustomEncoder});
+ auto [CustomEncoder, CustomDecoder] =
+ getCustomCoders(DI->getArgs().slice(2));
+ Segments.push_back({static_cast<unsigned>(NumBitsVal), OperandName,
+ CustomEncoder, CustomDecoder});
} else if (Op == "slice") {
// (slice <operand name>, <high / low bit>, <low / high bit>,
- // [(encoder <custom encoder>)])
+ // [(encoder <custom encoder>)][, (decoder <custom decoder>)])
if (DI->getNumArgs() < 3)
PrintFatalError(TheDef->getLoc(),
"Expecting at least 3 arguments for `slice`");
@@ -167,18 +193,17 @@ void VarLenInst::buildRec(const DagInit *DI) {
NumBits = static_cast<unsigned>(HiBitVal - LoBitVal + 1);
}
- StringRef CustomEncoder;
- if (DI->getNumArgs() >= 4)
- CustomEncoder = getCustomEncoderName(DI->getArg(3));
+ auto [CustomEncoder, CustomDecoder] =
+ getCustomCoders(DI->getArgs().slice(3));
if (NeedSwap) {
// Normalization: Hi bit should always be the second argument.
Init *const NewArgs[] = {OperandName, LoBit, HiBit};
Segments.push_back({NumBits,
DagInit::get(DI->getOperator(), nullptr, NewArgs, {}),
- CustomEncoder});
+ CustomEncoder, CustomDecoder});
} else {
- Segments.push_back({NumBits, DI, CustomEncoder});
+ Segments.push_back({NumBits, DI, CustomEncoder, CustomDecoder});
}
}
}
diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.h b/llvm/utils/TableGen/VarLenCodeEmitterGen.h
index 5bdedee1dd51..2b55fd1720aa 100644
--- a/llvm/utils/TableGen/VarLenCodeEmitterGen.h
+++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.h
@@ -22,6 +22,7 @@ struct EncodingSegment {
unsigned BitWidth;
const Init *Value;
StringRef CustomEncoder = "";
+ StringRef CustomDecoder = "";
};
class VarLenInst {
@@ -35,14 +36,6 @@ class VarLenInst {
void buildRec(const DagInit *DI);
- StringRef getCustomEncoderName(const Init *EI) const {
- if (const auto *DI = dyn_cast<DagInit>(EI)) {
- if (DI->getNumArgs() && isa<StringInit>(DI->getArg(0)))
- return cast<StringInit>(DI->getArg(0))->getValue();
- }
- return "";
- }
-
public:
VarLenInst() : TheDef(nullptr), NumBits(0U), HasDynamicSegment(false) {}