diff options
author | Min-Yih Hsu <minyihh@uci.edu> | 2022-11-20 22:35:27 -0800 |
---|---|---|
committer | Min-Yih Hsu <minyihh@uci.edu> | 2023-01-24 21:59:24 -0800 |
commit | 36c19eae27b2970c02af77c1eb6e35aa3d3bf4df (patch) | |
tree | 4db52305364c79cb73b120c5ff9cbcf0b25f9fc8 | |
parent | 7454439674a4a78b9fc9dc9ffba7a60717ee310b (diff) | |
download | llvm-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.td | 10 | ||||
-rw-r--r-- | llvm/test/TableGen/VarLenDecoder.td | 9 | ||||
-rw-r--r-- | llvm/utils/TableGen/DecoderEmitter.cpp | 2 | ||||
-rw-r--r-- | llvm/utils/TableGen/VarLenCodeEmitterGen.cpp | 51 | ||||
-rw-r--r-- | llvm/utils/TableGen/VarLenCodeEmitterGen.h | 9 |
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) {} |