Index: llvm/test/TableGen/VarLenEncoder.td =================================================================== --- llvm/test/TableGen/VarLenEncoder.td +++ llvm/test/TableGen/VarLenEncoder.td @@ -1,4 +1,6 @@ // RUN: llvm-tblgen -gen-emitter -I %p/../../include %s | FileCheck %s +// RUN: llvm-tblgen -gen-disassembler -I %p/../../include %s | \ +// RUN: FileCheck --check-prefix=CHECK-DECODE %s // Check if VarLenCodeEmitterGen works correctly. @@ -22,6 +24,18 @@ dag Extension; } +class MemOp16 : MyMemOperand<(ops GR64:$reg, i16imm:$offset)> { + // Testing sub-operand referencing. + let Base = (operand "$"#op_name#".reg", 8); + let Extension = (operand "$"#op_name#".offset", 16); +} + +class MemOp32 : MyMemOperand<(ops GR64:$reg, i32imm:$offset)> { + let Base = (operand "$"#op_name#".reg", 8); + // Testing variable-length instruction encoding. + let Extension = (operand "$"#op_name#".offset", 32); +} + class MyVarInst : Instruction { dag Inst; @@ -30,7 +44,12 @@ // Testing `ascend` and `descend` let Inst = (ascend - (descend 0b10110111, memory_op.Base), + (descend 0b10110111, memory_op.Base, + !cond( + !isa(memory_op) : 0b0, + !isa(memory_op) : 0b1, + ) + ), memory_op.Extension, // Testing operand referencing. (operand "$dst", 4), @@ -41,61 +60,96 @@ ); } -class MemOp16 : MyMemOperand<(ops GR64:$reg, i16imm:$offset)> { - // Testing sub-operand referencing. - let Base = (operand "$"#op_name#".reg", 8); - let Extension = (operand "$"#op_name#".offset", 16); -} - -class MemOp32 : MyMemOperand<(ops GR64:$reg, i32imm:$offset)> { - let Base = (operand "$"#op_name#".reg", 8); - // Testing variable-length instruction encoding. - let Extension = (operand "$"#op_name#".offset", 32); -} - def FOO16 : MyVarInst>; def FOO32 : MyVarInst>; // The fixed bits part -// CHECK: {/*NumBits*/41, +// CHECK: {/*NumBits*/42, // CHECK-SAME: // FOO16 -// CHECK: {/*NumBits*/57, +// CHECK: {/*NumBits*/58, // CHECK-SAME: // FOO32 -// CHECK: UINT64_C(46848), // FOO16 -// CHECK: UINT64_C(46848), // FOO32 +// CHECK: UINT64_C(93696), // FOO16 +// CHECK: UINT64_C(93697), // FOO32 // CHECK-LABEL: case ::FOO16: { -// CHECK: Scratch = Scratch.zextOrSelf(41); +// CHECK: Scratch = Scratch.zextOrSelf(42); // src.reg -// CHECK: getMachineOpValue(MI, MI.getOperand(1), /*Pos=*/0, Scratch, Fixups, STI); -// CHECK: Inst.insertBits(Scratch.extractBits(8, 0), 0); +// CHECK: getMachineOpValue(MI, MI.getOperand(1), /*Pos=*/1, Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(8, 0), 1); // src.offset -// CHECK: getMachineOpValue(MI, MI.getOperand(2), /*Pos=*/16, Scratch, Fixups, STI); -// CHECK: Inst.insertBits(Scratch.extractBits(16, 0), 16); +// CHECK: getMachineOpValue(MI, MI.getOperand(2), /*Pos=*/17, Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(16, 0), 17); // 1st dst -// CHECK: getMachineOpValue(MI, MI.getOperand(0), /*Pos=*/32, Scratch, Fixups, STI); -// CHECK: Inst.insertBits(Scratch.extractBits(4, 0), 32); +// CHECK: getMachineOpValue(MI, MI.getOperand(0), /*Pos=*/33, Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(4, 0), 33); // 2nd dst -// CHECK: getMachineOpValue(MI, MI.getOperand(0), /*Pos=*/36, Scratch, Fixups, STI); -// CHECK: Inst.insertBits(Scratch.extractBits(3, 1), 36); +// CHECK: getMachineOpValue(MI, MI.getOperand(0), /*Pos=*/37, Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(3, 1), 37); // dst w/ custom encoder -// CHECK: myCustomEncoder(MI, /*OpIdx=*/0, /*Pos=*/39, Scratch, Fixups, STI); -// CHECK: Inst.insertBits(Scratch.extractBits(2, 0), 39); +// CHECK: myCustomEncoder(MI, /*OpIdx=*/0, /*Pos=*/40, Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(2, 0), 40); // CHECK-LABEL: case ::FOO32: { -// CHECK: Scratch = Scratch.zextOrSelf(57); +// CHECK: Scratch = Scratch.zextOrSelf(58); // src.reg -// CHECK: getMachineOpValue(MI, MI.getOperand(1), /*Pos=*/0, Scratch, Fixups, STI); -// CHECK: Inst.insertBits(Scratch.extractBits(8, 0), 0); +// CHECK: getMachineOpValue(MI, MI.getOperand(1), /*Pos=*/1, Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(8, 0), 1); // src.offset -// CHECK: getMachineOpValue(MI, MI.getOperand(2), /*Pos=*/16, Scratch, Fixups, STI); -// CHECK: Inst.insertBits(Scratch.extractBits(32, 0), 16); +// CHECK: getMachineOpValue(MI, MI.getOperand(2), /*Pos=*/17, Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(32, 0), 17); // 1st dst -// CHECK: getMachineOpValue(MI, MI.getOperand(0), /*Pos=*/48, Scratch, Fixups, STI); -// CHECK: Inst.insertBits(Scratch.extractBits(4, 0), 48); +// CHECK: getMachineOpValue(MI, MI.getOperand(0), /*Pos=*/49, Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(4, 0), 49); // 2nd dst -// CHECK: getMachineOpValue(MI, MI.getOperand(0), /*Pos=*/52, Scratch, Fixups, STI); -// CHECK: Inst.insertBits(Scratch.extractBits(3, 1), 52); +// CHECK: getMachineOpValue(MI, MI.getOperand(0), /*Pos=*/53, Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(3, 1), 53); // dst w/ custom encoder -// CHECK: myCustomEncoder(MI, /*OpIdx=*/0, /*Pos=*/55, Scratch, Fixups, STI); -// CHECK: Inst.insertBits(Scratch.extractBits(2, 0), 55); +// CHECK: myCustomEncoder(MI, /*OpIdx=*/0, /*Pos=*/56, Scratch, Fixups, STI); +// CHECK: Inst.insertBits(Scratch.extractBits(2, 0), 56); + +// CHECK-DECODE: MCD::OPC_ExtractField, 0, 1, // Inst{0} ... +// CHECK-DECODE-NEXT: MCD::OPC_FilterValue, 0, 12, 0, 0, // Skip to: 20 +// CHECK-DECODE-NEXT: MCD::OPC_CheckField, 9, 8, 183, 1, 21, 0, 0, // Skip to: 37 +// CHECK-DECODE-NEXT: MCD::OPC_Decode, 244, 1, 0, // Opcode: FOO16 +// CHECK-DECODE-NEXT: MCD::OPC_FilterValue, 1, 12, 0, 0, // Skip to: 37 +// CHECK-DECODE-NEXT: MCD::OPC_CheckField, 9, 8, 183, 1, 4, 0, 0, // Skip to: 37 +// CHECK-DECODE-NEXT: MCD::OPC_Decode, 245, 1, 1, // Opcode: FOO32 +// CHECK-DECODE-NEXT: MCD::OPC_Fail, + +// Instruction length table +// CHECK-DECODE: 42, +// CHECK-DECODE-NEXT: 58, +// CHECK-DECODE-NEXT: }; + +// CHECK-DECODE-LABEL: case 0: +// CHECK-DECODE: tmp = 0x0; +// CHECK-DECODE-NEXT: insertBits(tmp, fieldFromInstruction(insn, 33, 4), 0, 4); +// CHECK-DECODE-NEXT: insertBits(tmp, fieldFromInstruction(insn, 37, 3), 1, 3); +// CHECK-DECODE-NEXT: insertBits(tmp, fieldFromInstruction(insn, 40, 2), 0, 2); +// CHECK-DECODE-NEXT: if (DecodeRegClassRegisterClass(MI, tmp, Address, Decoder) == MCDisassembler::Fail) { return MCDisassembler::Fail; } +// CHECK-DECODE-NEXT: tmp = fieldFromInstruction(insn, 1, 8); +// CHECK-DECODE-NEXT: if (DecodeRegClassRegisterClass(MI, tmp, Address, Decoder) == MCDisassembler::Fail) { return MCDisassembler::Fail; } +// CHECK-DECODE-NEXT: tmp = fieldFromInstruction(insn, 17, 16); +// CHECK-DECODE-NEXT: MI.addOperand(MCOperand::createImm(tmp)); +// CHECK-DECODE-NEXT: return S; +// CHECK-DECODE-NEXT: case 1: +// CHECK-DECODE-NEXT: tmp = 0x0; +// CHECK-DECODE-NEXT: insertBits(tmp, fieldFromInstruction(insn, 49, 4), 0, 4); +// CHECK-DECODE-NEXT: insertBits(tmp, fieldFromInstruction(insn, 53, 3), 1, 3); +// CHECK-DECODE-NEXT: insertBits(tmp, fieldFromInstruction(insn, 56, 2), 0, 2); +// CHECK-DECODE-NEXT: if (DecodeRegClassRegisterClass(MI, tmp, Address, Decoder) == MCDisassembler::Fail) { return MCDisassembler::Fail; } +// CHECK-DECODE-NEXT: tmp = fieldFromInstruction(insn, 1, 8); +// CHECK-DECODE-NEXT: if (DecodeRegClassRegisterClass(MI, tmp, Address, Decoder) == MCDisassembler::Fail) { return MCDisassembler::Fail; } +// CHECK-DECODE-NEXT: tmp = fieldFromInstruction(insn, 17, 32); +// CHECK-DECODE-NEXT: MI.addOperand(MCOperand::createImm(tmp)); +// CHECK-DECODE-NEXT: return S; + +// CHECK-DECODE-LABEL: case MCD::OPC_ExtractField: { +// CHECK-DECODE: CurFieldValue = fieldFromInstruction(insn, Start, Len, makeUp); + +// CHECK-DECODE-LABEL: case MCD::OPC_CheckField: { +// CHECK-DECODE: uint64_t FieldValue = fieldFromInstruction(insn, Start, Len, makeUp); + +// CHECK-DECODE-LABEL: case MCD::OPC_Decode: { +// CHECK-DECODE: Len = InstrLenTable[Opc]; +// CHECK-DECODE-NEXT: makeUp(insn, Len); Index: llvm/utils/TableGen/FixedLenDecoderEmitter.cpp =================================================================== --- llvm/utils/TableGen/FixedLenDecoderEmitter.cpp +++ llvm/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -14,6 +14,7 @@ #include "CodeGenInstruction.h" #include "CodeGenTarget.h" #include "InfoByHwMode.h" +#include "VarLenCodeEmitterGen.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/CachedHashString.h" @@ -143,6 +144,8 @@ void emitTable(formatted_raw_ostream &o, DecoderTable &Table, unsigned Indentation, unsigned BitWidth, StringRef Namespace) const; + void emitInstrLenTable(formatted_raw_ostream &OS, + std::vector &InstrLen) const; void emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates, unsigned Indentation) const; @@ -217,8 +220,70 @@ } static BitsInit &getBitsField(const Record &def, StringRef str) { - BitsInit *bits = def.getValueAsBitsInit(str); - return *bits; + const RecordVal *RV = def.getValue(str); + if (BitsInit *bits = dyn_cast(RV->getValue())) + return *bits; + + // variable length instruction + DagInit *dag = cast(RV->getValue()); + VarLenInst VLI = VarLenInst(dag, RV); + SmallVector Bits; + auto SI = VLI.begin(), SE = VLI.end(); + + std::map, int>>> + SlicesMap; + + while (SI != SE) { + if (const BitsInit *BI = dyn_cast(SI->Value)) { + for (unsigned Idx = 0U; Idx < BI->getNumBits(); ++Idx) { + Bits.push_back(BI->getBit(Idx)); + } + } else if (const BitInit *BI = dyn_cast(SI->Value)) { + Bits.push_back(const_cast(BI)); + } else if (const StringInit *OpName = dyn_cast(SI->Value)) { + // (operand "$", ) + StringRef Str = OpName->getValue(); + VarInit *VI = VarInit::get(Str.substr(1), BitsRecTy::get(SI->BitWidth)); + for (unsigned Idx = 0U; Idx < SI->BitWidth; ++Idx) { + VarBitInit *VBI = VarBitInit::get(VI, Idx); + Bits.push_back(VBI); + } + } else if (const DagInit *DI = dyn_cast(SI->Value)) { + // (slice "$", LoBit, HiBit) + // We don't know how long this operand will be until + // we gather all of the slices. + StringRef Str = cast(DI->getArg(0))->getValue(); + int64_t Hi = cast(DI->getArg(1))->getValue(); + int64_t Lo = cast(DI->getArg(2))->getValue(); + SlicesMap[Str.str()].push_back({{Lo, Hi + 1}, Bits.size()}); + + for (int64_t Idx = Lo; Idx <= Hi; ++Idx) { + // reserve a space; + Bits.push_back(UnsetInit::get()); + } + } else { + llvm_unreachable("What kind of init it is ?"); + } + ++SI; + } + + for (auto &Slices : SlicesMap) { + int Len = 0; + + for (auto &S : Slices.second) + Len = std::max(Len, S.first.second); + + VarInit *VI = VarInit::get(StringInit::get(Slices.first.substr(1)), + BitsRecTy::get(Len)); + for (auto &S : Slices.second) { + int BitsIdx = S.second; + int VarIdx = S.first.first; + int VarIdxEnd = S.first.second; + for (; VarIdx < VarIdxEnd; ++BitsIdx, ++VarIdx) + Bits[BitsIdx] = VarBitInit::get(VI, VarIdx); + } + } + return *BitsInit::get(Bits); } // Representation of the instruction to work on. @@ -421,20 +486,21 @@ // Populates the insn given the uid. void insnWithID(insn_t &Insn, unsigned Opcode) const { BitsInit &Bits = getBitsField(*AllInstructions[Opcode].EncodingDef, "Inst"); - + Insn.resize(BitWidth > Bits.getNumBits() ? BitWidth : Bits.getNumBits(), + BIT_UNSET); // We may have a SoftFail bitmask, which specifies a mask where an encoding // may differ from the value in "Inst" and yet still be valid, but the // disassembler should return SoftFail instead of Success. // // This is used for marking UNPREDICTABLE instructions in the ARM world. - BitsInit *SFBits = - AllInstructions[Opcode].EncodingDef->getValueAsBitsInit("SoftFail"); - - for (unsigned i = 0; i < BitWidth; ++i) { + const RecordVal *RV = + AllInstructions[Opcode].EncodingDef->getValue("SoftFail"); + const BitsInit *SFBits = RV ? dyn_cast(RV->getValue()) : nullptr; + for (unsigned i = 0; i < Bits.getNumBits(); ++i) { if (SFBits && bitFromBits(*SFBits, i) == BIT_TRUE) - Insn.push_back(BIT_UNSET); + Insn[i] = BIT_UNSET; else - Insn.push_back(bitFromBits(Bits, i)); + Insn[i] = bitFromBits(Bits, i); } } @@ -936,6 +1002,15 @@ OS.indent(Indentation) << "};\n\n"; } +void FixedLenDecoderEmitter::emitInstrLenTable( + formatted_raw_ostream &OS, std::vector &InstrLen) const { + OS << "static const uint8_t InstrLenTable[] = {\n"; + for (unsigned &Len : InstrLen) { + OS << Len << ",\n"; + } + OS << "};\n\n"; +} + void FixedLenDecoderEmitter:: emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates, unsigned Indentation) const { @@ -1309,8 +1384,9 @@ void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo, unsigned Opc) const { - BitsInit *SFBits = - AllInstructions[Opc].EncodingDef->getValueAsBitsInit("SoftFail"); + const RecordVal *RV = AllInstructions[Opc].EncodingDef->getValue("SoftFail"); + BitsInit *SFBits = RV ? dyn_cast(RV->getValue()) : nullptr; + if (!SFBits) return; BitsInit *InstBits = AllInstructions[Opc].EncodingDef->getValueAsBitsInit("Inst"); @@ -1812,17 +1888,19 @@ return Decoder; } -static bool +static unsigned populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, const CodeGenInstruction &CGI, unsigned Opc, - std::map> &Operands) { + std::map> &Operands, + bool isVarLenInst) { const Record &Def = *CGI.TheDef; // If all the bit positions are not specified; do not decode this instruction. // We are bound to fail! For proper disassembly, the well-known encoding bits // of the instruction must be fully specified. BitsInit &Bits = getBitsField(EncodingDef, "Inst"); - if (Bits.allInComplete()) return false; + if (Bits.allInComplete()) + return 0; std::vector InsnOperands; @@ -1834,7 +1912,7 @@ InsnOperands.push_back( OperandInfo(std::string(InstDecoder), HasCompleteInstDecoder)); Operands[Opc] = InsnOperands; - return true; + return Bits.getNumBits(); } // Generate a description of the operand of the instruction that we know @@ -2068,58 +2146,90 @@ if (OpBit->getValue()) OpInfo.InitValue |= 1ULL << I; - unsigned Base = ~0U; - unsigned Width = 0; - unsigned Offset = 0; + auto getOpInfo = [&](OperandInfo OI, StringRef SubOpName) { + unsigned Base = ~0U; + unsigned Width = 0; + unsigned Offset = 0; - for (unsigned bi = 0; bi < Bits.getNumBits(); ++bi) { - VarInit *Var = nullptr; - VarBitInit *BI = dyn_cast(Bits.getBit(bi)); - if (BI) - Var = dyn_cast(BI->getBitVar()); - else - Var = dyn_cast(Bits.getBit(bi)); - - if (!Var) { - if (Base != ~0U) { - OpInfo.addField(Base, Width, Offset); - Base = ~0U; - Width = 0; - Offset = 0; + for (unsigned bi = 0; bi < Bits.getNumBits(); ++bi) { + VarInit *Var = nullptr; + VarBitInit *BI = dyn_cast(Bits.getBit(bi)); + if (BI) + Var = dyn_cast(BI->getBitVar()); + else + Var = dyn_cast(Bits.getBit(bi)); + + if (!Var) { + if (Base != ~0U) { + OI.addField(Base, Width, Offset); + Base = ~0U; + Width = 0; + Offset = 0; + } + continue; + } + + StringRef OpName = Var->getName(), SubOpName2; + StringRef::size_type DotIdx = OpName.find_first_of('.'); + if (DotIdx != StringRef::npos) + SubOpName2 = OpName.substr(DotIdx + 1); + OpName = OpName.substr(0, DotIdx); + + if ((OpName != Op.second && + OpName != TiedNames[std::string(Op.second)]) || + SubOpName2 != SubOpName) { + if (Base != ~0U) { + OI.addField(Base, Width, Offset); + Base = ~0U; + Width = 0; + Offset = 0; + } + continue; } - continue; - } - if (Var->getName() != Op.second && - Var->getName() != TiedNames[std::string(Op.second)]) { - if (Base != ~0U) { - OpInfo.addField(Base, Width, Offset); - Base = ~0U; - Width = 0; - Offset = 0; + if (Base == ~0U) { + Base = bi; + Width = 1; + Offset = BI ? BI->getBitNum() : 0; + } else if (BI && BI->getBitNum() != Offset + Width) { + OI.addField(Base, Width, Offset); + Base = bi; + Width = 1; + Offset = BI->getBitNum(); + } else { + ++Width; } - continue; } - if (Base == ~0U) { - Base = bi; - Width = 1; - Offset = BI ? BI->getBitNum() : 0; - } else if (BI && BI->getBitNum() != Offset + Width) { - OpInfo.addField(Base, Width, Offset); - Base = bi; - Width = 1; - Offset = BI->getBitNum(); - } else { - ++Width; + if (Base != ~0U) + OI.addField(Base, Width, Offset); + + if (OI.numFields() > 0) + InsnOperands.push_back(OI); + }; + + if (isVarLenInst) { + // For complex operand, most of the fixed length ISA use custom decoder. + // That does not work for variable length ISA since the position of the + // operand is not at fixed position. We have to traverse down to every + // single operand of the complex operand for decoding. + // FIXME: Can decodePositionallyEncodedOperands be migrated to this ? + auto OpIdx = + const_cast(CGI).Operands.ParseOperandName( + '$' + Op.second.str()); + DagInit *DI = CGI.Operands[OpIdx.first].MIOperandInfo; + if (DI && DI->getNumArgs() && OpInfo.Decoder == "") { + for (unsigned i = 0U; i < DI->getNumArgs(); ++i) { + TypedInit *TI = cast(DI->getArg(i)); + StringRef SubOpName = DI->getArgNameStr(i); + getOpInfo( + OperandInfo(findOperandDecoderMethod(TI), HasCompleteDecoder), + SubOpName); + } + continue; } } - - if (Base != ~0U) - OpInfo.addField(Base, Width, Offset); - - if (OpInfo.numFields() > 0) - InsnOperands.push_back(OpInfo); + getOpInfo(OpInfo, ""); } Operands[Opc] = InsnOperands; @@ -2142,7 +2252,7 @@ }); #endif - return true; + return Bits.getNumBits(); } // emitFieldFromInstruction - Emit the templated helper function @@ -2185,8 +2295,12 @@ << "template \n" << "static std::enable_if_t::value, " "uint64_t>\n" - << "fieldFromInstruction(const InsnType &insn, unsigned startBit,\n" - << " unsigned numBits) {\n" + << "fieldFromInstruction(InsnType &insn, unsigned startBit,\n" + << " unsigned numBits,\n" + << " std::function " + "makeUp\n" + << " = [](InsnType &insn, uint64_t){}) {\n" + << " makeUp(insn, startBit + numBits);\n" << " return insn.extractBitsAsZExtValue(numBits, startBit);\n" << "}\n\n"; } @@ -2214,18 +2328,25 @@ // emitDecodeInstruction - Emit the templated helper function // decodeInstruction(). -static void emitDecodeInstruction(formatted_raw_ostream &OS) { +static void emitDecodeInstruction(formatted_raw_ostream &OS, + bool isVarLenInst) { OS << "template \n" << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], " "MCInst &MI,\n" << " InsnType insn, uint64_t " "Address,\n" << " const void *DisAsm,\n" - << " const MCSubtargetInfo &STI) {\n" + << " const MCSubtargetInfo &STI"; + if (isVarLenInst) { + OS << ",\n" + << " std::function makeUp"; + } + OS << ") {\n" << " const FeatureBitset &Bits = STI.getFeatureBits();\n" << "\n" << " const uint8_t *Ptr = DecodeTable;\n" - << " InsnType CurFieldValue = 0;\n" + << " uint64_t CurFieldValue = 0;\n" << " DecodeStatus S = MCDisassembler::Success;\n" << " while (true) {\n" << " ptrdiff_t Loc = Ptr - DecodeTable;\n" @@ -2237,7 +2358,9 @@ << " unsigned Start = *++Ptr;\n" << " unsigned Len = *++Ptr;\n" << " ++Ptr;\n" - << " CurFieldValue = fieldFromInstruction(insn, Start, Len);\n" + << " CurFieldValue = " + << (isVarLenInst ? "fieldFromInstruction(insn, Start, Len, makeUp);\n" + : "fieldFromInstruction(insn, Start, Len);\n") << " LLVM_DEBUG(dbgs() << Loc << \": OPC_ExtractField(\" << Start << " "\", \"\n" << " << Len << \"): \" << CurFieldValue << \"\\n\");\n" @@ -2246,7 +2369,7 @@ << " case MCD::OPC_FilterValue: {\n" << " // Decode the field value.\n" << " unsigned Len;\n" - << " InsnType Val = decodeULEB128(++Ptr, &Len);\n" + << " uint64_t Val = decodeULEB128(++Ptr, &Len);\n" << " Ptr += Len;\n" << " // NumToSkip is a plain 24-bit integer.\n" << " unsigned NumToSkip = *Ptr++;\n" @@ -2268,10 +2391,13 @@ << " case MCD::OPC_CheckField: {\n" << " unsigned Start = *++Ptr;\n" << " unsigned Len = *++Ptr;\n" - << " InsnType FieldValue = fieldFromInstruction(insn, Start, Len);\n" + << " uint64_t FieldValue = " + << (isVarLenInst ? "fieldFromInstruction(insn, Start, Len, makeUp);\n" + : "fieldFromInstruction(insn, Start, Len);\n") << " // Decode the field value.\n" - << " InsnType ExpectedValue = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" + << " unsigned PtrLen = 0;\n" + << " uint64_t ExpectedValue = decodeULEB128(++Ptr, &PtrLen);\n" + << " Ptr += PtrLen;\n" << " // NumToSkip is a plain 24-bit integer.\n" << " unsigned NumToSkip = *Ptr++;\n" << " NumToSkip |= (*Ptr++) << 8;\n" @@ -2321,8 +2447,12 @@ << "\n" << " MI.clear();\n" << " MI.setOpcode(Opc);\n" - << " bool DecodeComplete;\n" - << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " + << " bool DecodeComplete;\n"; + if (isVarLenInst) { + OS << " Len = InstrLenTable[Opc];\n" + << " makeUp(insn, Len);\n"; + } + OS << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " "DecodeComplete);\n" << " assert(DecodeComplete);\n" << "\n" @@ -2376,11 +2506,12 @@ << " case MCD::OPC_SoftFail: {\n" << " // Decode the mask values.\n" << " unsigned Len;\n" - << " InsnType PositiveMask = decodeULEB128(++Ptr, &Len);\n" + << " uint64_t PositiveMask = decodeULEB128(++Ptr, &Len);\n" << " Ptr += Len;\n" - << " InsnType NegativeMask = decodeULEB128(Ptr, &Len);\n" + << " uint64_t NegativeMask = decodeULEB128(Ptr, &Len);\n" << " Ptr += Len;\n" - << " bool Fail = (insn & PositiveMask) || (~insn & NegativeMask);\n" + << " bool Fail = (insn & PositiveMask) != 0 || (~insn & " + "NegativeMask) != 0;\n" << " if (Fail)\n" << " S = MCDisassembler::SoftFail;\n" << " LLVM_DEBUG(dbgs() << Loc << \": OPC_SoftFail: \" << (Fail ? " @@ -2419,7 +2550,7 @@ // Parameterize the decoders based on namespace and instruction width. std::set HwModeNames; - const auto &NumberedInstructions = Target.getInstructionsByEnumValue(); + const auto NumberedInstructions = Target.getInstructionsByEnumValue(); NumberedEncodings.reserve(NumberedInstructions.size()); DenseMap IndexOfInstruction; // First, collect all HwModes referenced by the target. @@ -2471,6 +2602,14 @@ std::map, std::vector> OpcMap; std::map> Operands; + std::vector InstrLen; + + bool isVarLenInst = + any_of(NumberedInstructions, [](const CodeGenInstruction *CGI) { + RecordVal *RV = CGI->TheDef->getValue("Inst"); + return RV && isa(RV->getValue()); + }); + unsigned maxInstLen = 0; for (unsigned i = 0; i < NumberedEncodings.size(); ++i) { const Record *EncodingDef = NumberedEncodings[i].EncodingDef; @@ -2489,10 +2628,18 @@ NumInstructions++; NumEncodings++; - if (!Size) + if (!Size && !isVarLenInst) continue; - if (populateInstruction(Target, *EncodingDef, *Inst, i, Operands)) { + if (isVarLenInst) + InstrLen.resize(NumberedInstructions.size(), 0); + + if (unsigned Len = populateInstruction(Target, *EncodingDef, *Inst, i, + Operands, isVarLenInst)) { + if (isVarLenInst) { + maxInstLen = std::max(maxInstLen, Len); + InstrLen[i] = Len; + } std::string DecoderNamespace = std::string(EncodingDef->getValueAsString("DecoderNamespace")); if (!NumberedEncodings[i].HwModeName.empty()) @@ -2511,7 +2658,7 @@ ArrayRef NumberedEncodingsRef( NumberedEncodings.data(), NumberedEncodings.size()); FilterChooser FC(NumberedEncodingsRef, Opc.second, Operands, - 8 * Opc.first.second, this); + isVarLenInst ? maxInstLen : 8 * Opc.first.second, this); // The decode table is cleared for each top level decoder function. The // predicates and decoders themselves, however, are shared across all @@ -2536,6 +2683,8 @@ OS.flush(); } + if (isVarLenInst) + emitInstrLenTable(OS, InstrLen); // Emit the predicate function. emitPredicateFunction(OS, TableInfo.Predicates, 0); @@ -2543,7 +2692,7 @@ emitDecoderFunction(OS, TableInfo.Decoders, 0); // Emit the main entry point for the decoder, decodeInstruction(). - emitDecodeInstruction(OS); + emitDecodeInstruction(OS, isVarLenInst); OS << "\n} // end namespace llvm\n"; } Index: llvm/utils/TableGen/VarLenCodeEmitterGen.h =================================================================== --- llvm/utils/TableGen/VarLenCodeEmitterGen.h +++ llvm/utils/TableGen/VarLenCodeEmitterGen.h @@ -14,8 +14,52 @@ #ifndef LLVM_UTILS_TABLEGEN_VARLENCODEEMITTERGEN_H #define LLVM_UTILS_TABLEGEN_VARLENCODEEMITTERGEN_H +#include "llvm/TableGen/Record.h" + namespace llvm { +struct EncodingSegment { + unsigned BitWidth; + const Init *Value; + StringRef CustomEncoder = ""; +}; + +class VarLenInst { + const RecordVal *TheDef; + size_t NumBits; + + // Set if any of the segment is not fixed value. + bool HasDynamicSegment; + + SmallVector Segments; + + 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) {} + + explicit VarLenInst(const DagInit *DI, const RecordVal *TheDef); + + /// Number of bits + size_t size() const { return NumBits; } + + using const_iterator = decltype(Segments)::const_iterator; + + const_iterator begin() const { return Segments.begin(); } + const_iterator end() const { return Segments.end(); } + size_t getNumSegments() const { return Segments.size(); } + + bool isFixedValueOnly() const { return !HasDynamicSegment; } +}; + class RecordKeeper; class raw_ostream; Index: llvm/utils/TableGen/VarLenCodeEmitterGen.cpp =================================================================== --- llvm/utils/TableGen/VarLenCodeEmitterGen.cpp +++ llvm/utils/TableGen/VarLenCodeEmitterGen.cpp @@ -57,7 +57,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Record.h" using namespace llvm; @@ -66,48 +65,6 @@ class VarLenCodeEmitterGen { RecordKeeper &Records; - struct EncodingSegment { - unsigned BitWidth; - const Init *Value; - StringRef CustomEncoder = ""; - }; - - class VarLenInst { - RecordVal *TheDef; - size_t NumBits; - - // Set if any of the segment is not fixed value. - bool HasDynamicSegment; - - SmallVector Segments; - - 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) {} - - explicit VarLenInst(const DagInit *DI, RecordVal *TheDef); - - /// Number of bits - size_t size() const { return NumBits; } - - using const_iterator = decltype(Segments)::const_iterator; - - const_iterator begin() const { return Segments.begin(); } - const_iterator end() const { return Segments.end(); } - size_t getNumSegments() const { return Segments.size(); } - - bool isFixedValueOnly() const { return !HasDynamicSegment; } - }; - DenseMap VarLenInsts; // Emit based values (i.e. fixed bits in the encoded instructions) @@ -128,15 +85,14 @@ } // end anonymous namespace -VarLenCodeEmitterGen::VarLenInst::VarLenInst(const DagInit *DI, - RecordVal *TheDef) +VarLenInst::VarLenInst(const DagInit *DI, const RecordVal *TheDef) : TheDef(TheDef), NumBits(0U) { buildRec(DI); for (const auto &S : Segments) NumBits += S.BitWidth; } -void VarLenCodeEmitterGen::VarLenInst::buildRec(const DagInit *DI) { +void VarLenInst::buildRec(const DagInit *DI) { assert(TheDef && "The def record is nullptr ?"); std::string Op = DI->getOperator()->getAsString();