Index: llvm/include/llvm/Target/Target.td =================================================================== --- llvm/include/llvm/Target/Target.td +++ llvm/include/llvm/Target/Target.td @@ -796,11 +796,17 @@ /// 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 Index: llvm/test/TableGen/VarLenDecoder.td =================================================================== --- llvm/test/TableGen/VarLenDecoder.td +++ llvm/test/TableGen/VarLenDecoder.td @@ -34,12 +34,13 @@ def FOO16 : MyVarInst { 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 { 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 @@ // 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); Index: llvm/utils/TableGen/DecoderEmitter.cpp =================================================================== --- llvm/utils/TableGen/DecoderEmitter.cpp +++ llvm/utils/TableGen/DecoderEmitter.cpp @@ -1893,6 +1893,8 @@ 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) { Index: llvm/utils/TableGen/VarLenCodeEmitterGen.h =================================================================== --- llvm/utils/TableGen/VarLenCodeEmitterGen.h +++ llvm/utils/TableGen/VarLenCodeEmitterGen.h @@ -22,6 +22,7 @@ unsigned BitWidth; const Init *Value; StringRef CustomEncoder = ""; + StringRef CustomDecoder = ""; }; class VarLenInst { @@ -35,14 +36,6 @@ void buildRec(const DagInit *DI); - StringRef getCustomEncoderName(const Init *EI) const { - if (const auto *DI = dyn_cast(EI)) { - if (DI->getNumArgs() && isa(DI->getArg(0))) - return cast(DI->getArg(0))->getValue(); - } - return ""; - } - public: VarLenInst() : TheDef(nullptr), NumBits(0U), HasDynamicSegment(false) {} Index: llvm/utils/TableGen/VarLenCodeEmitterGen.cpp =================================================================== --- llvm/utils/TableGen/VarLenCodeEmitterGen.cpp +++ llvm/utils/TableGen/VarLenCodeEmitterGen.cpp @@ -83,9 +83,35 @@ 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 getCustomCoders(ArrayRef Args) { + std::pair Result; + for (const auto *Arg : Args) { + const auto *DI = dyn_cast(Arg); + if (!DI) + continue; + const Init *Op = DI->getOperator(); + if (!isa(Op)) + continue; + // syntax: `( "function name")` + StringRef OpName = cast(Op)->getDef()->getName(); + if (OpName != "encoder" && OpName != "decoder") + continue; + if (!DI->getNumArgs() || !isa(DI->getArg(0))) + PrintFatalError("expected '" + OpName + + "' directive to be followed by a custom function name."); + StringRef FuncName = cast(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 @@ } } } else if (Op == "operand") { - // (operand , <# of bits>, [(encoder )]) + // (operand , <# of bits>, + // [(encoder )][, (decoder )]) if (DI->getNumArgs() < 2) PrintFatalError(TheDef->getLoc(), "Expecting at least 2 arguments for `operand`"); @@ -136,14 +163,13 @@ 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(NumBitsVal), OperandName, CustomEncoder}); + auto [CustomEncoder, CustomDecoder] = + getCustomCoders(DI->getArgs().slice(2)); + Segments.push_back({static_cast(NumBitsVal), OperandName, + CustomEncoder, CustomDecoder}); } else if (Op == "slice") { // (slice , , , - // [(encoder )]) + // [(encoder )][, (decoder )]) if (DI->getNumArgs() < 3) PrintFatalError(TheDef->getLoc(), "Expecting at least 3 arguments for `slice`"); @@ -167,18 +193,17 @@ NumBits = static_cast(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}); } } }