diff --git a/llvm/test/TableGen/VarLenEncoder.td b/llvm/test/TableGen/VarLenEncoder.td --- a/llvm/test/TableGen/VarLenEncoder.td +++ b/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: makeUp(insn, Start + Len); + +// CHECK-DECODE-LABEL: case MCD::OPC_CheckField: { +// CHECK-DECODE: makeUp(insn, Start + Len); + +// CHECK-DECODE-LABEL: case MCD::OPC_Decode: { +// CHECK-DECODE: Len = InstrLenTable[Opc]; +// CHECK-DECODE-NEXT: makeUp(insn, Len); diff --git a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp --- a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/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,29 @@ } 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 *DI = cast(RV->getValue()); + VarLenInst VLI = VarLenInst(DI, RV); + SmallVector Bits; + + for (auto &SI : VLI) { + 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 { + for (unsigned Idx = 0U; Idx < SI.BitWidth; ++Idx) + Bits.push_back(UnsetInit::get()); + } + } + + return *BitsInit::get(Bits); } // Representation of the instruction to work on. @@ -421,7 +445,8 @@ // 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. @@ -430,11 +455,11 @@ const RecordVal *RV = AllInstructions[Opcode].EncodingDef->getValue("SoftFail"); const BitsInit *SFBits = RV ? dyn_cast(RV->getValue()) : nullptr; - for (unsigned i = 0; i < BitWidth; ++i) { + 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 +961,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 { @@ -1786,11 +1820,9 @@ } } -static std::string findOperandDecoderMethod(TypedInit *TI) { +static std::string findOperandDecoderMethod(Record *Record) { std::string Decoder; - Record *Record = cast(TI)->getDef(); - RecordVal *DecoderString = Record->getValue("DecoderMethod"); StringInit *String = DecoderString ? dyn_cast(DecoderString->getValue()) : nullptr; @@ -1813,17 +1845,90 @@ return Decoder; } -static bool +OperandInfo getOpInfo(Record *TypeRecord) { + std::string Decoder = findOperandDecoderMethod(TypeRecord); + + RecordVal *HasCompleteDecoderVal = TypeRecord->getValue("hasCompleteDecoder"); + BitInit *HasCompleteDecoderBit = + HasCompleteDecoderVal + ? dyn_cast(HasCompleteDecoderVal->getValue()) + : nullptr; + bool HasCompleteDecoder = + HasCompleteDecoderBit ? HasCompleteDecoderBit->getValue() : true; + + return OperandInfo(Decoder, HasCompleteDecoder); +} + +void parseVarLenInstOperand(const Record &Def, + std::vector &Operands, + const CodeGenInstruction &CGI) { + + const RecordVal *RV = Def.getValue("Inst"); + VarLenInst VLI(cast(RV->getValue()), RV); + SmallVector TiedTo; + + for (unsigned Idx = 0; Idx < CGI.Operands.size(); ++Idx) { + auto &Op = CGI.Operands[Idx]; + if (Op.MIOperandInfo && Op.MIOperandInfo->getNumArgs() > 0) { + for (auto *Arg : Op.MIOperandInfo->getArgs()) { + Operands.push_back(getOpInfo(cast(Arg)->getDef())); + } + } else { + Operands.push_back(getOpInfo(Op.Rec)); + } + + int TiedReg = Op.getTiedRegister(); + TiedTo.push_back(-1); + if (TiedReg != -1) { + TiedTo[Idx] = TiedReg; + TiedTo[TiedReg] = Idx; + } + } + + unsigned CurrBitPos = 0; + for (auto &EncodingSegment : VLI) { + unsigned Offset = 0; + StringRef OpName; + + if (const StringInit *SI = dyn_cast(EncodingSegment.Value)) { + OpName = SI->getValue(); + } else if (const DagInit *DI = dyn_cast(EncodingSegment.Value)) { + OpName = cast(DI->getArg(0))->getValue(); + Offset = cast(DI->getArg(2))->getValue(); + } + + if (OpName != "") { + auto OpSubOpPair = + const_cast(CGI).Operands.ParseOperandName( + OpName); + unsigned OpIdx = CGI.Operands.getFlattenedOperandNumber(OpSubOpPair); + Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset); + + int TiedReg = TiedTo[OpSubOpPair.first]; + if (TiedReg != -1) { + unsigned OpIdx = CGI.Operands.getFlattenedOperandNumber( + std::make_pair(TiedReg, OpSubOpPair.second)); + Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset); + } + } + + CurrBitPos += EncodingSegment.BitWidth; + } +} + +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; @@ -1835,7 +1940,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 @@ -1849,11 +1954,11 @@ DagInit *Out = Def.getValueAsDag("OutOperandList"); DagInit *In = Def.getValueAsDag("InOperandList"); for (unsigned i = 0; i < Out->getNumArgs(); ++i) - InOutOperands.push_back(std::make_pair(Out->getArg(i), - Out->getArgNameStr(i))); + InOutOperands.push_back( + std::make_pair(Out->getArg(i), Out->getArgNameStr(i))); for (unsigned i = 0; i < In->getNumArgs(); ++i) - InOutOperands.push_back(std::make_pair(In->getArg(i), - In->getArgNameStr(i))); + InOutOperands.push_back( + std::make_pair(In->getArg(i), In->getArgNameStr(i))); // Search for tied operands, so that we can correctly instantiate // operands that are not explicitly represented in the encoding. @@ -1870,257 +1975,254 @@ } } - std::map> NumberedInsnOperands; - std::set NumberedInsnOperandsNoTie; - if (Target.getInstructionSet()-> - getValueAsBit("decodePositionallyEncodedOperands")) { - const std::vector &Vals = Def.getValues(); - unsigned NumberedOp = 0; - - std::set NamedOpIndices; - if (Target.getInstructionSet()-> - getValueAsBit("noNamedPositionallyEncodedOperands")) - // Collect the set of operand indices that might correspond to named - // operand, and skip these when assigning operands based on position. + if (IsVarLenInst) { + parseVarLenInstOperand(EncodingDef, InsnOperands, CGI); + } else { + std::map> NumberedInsnOperands; + std::set NumberedInsnOperandsNoTie; + if (Target.getInstructionSet()->getValueAsBit( + "decodePositionallyEncodedOperands")) { + const std::vector &Vals = Def.getValues(); + unsigned NumberedOp = 0; + + std::set NamedOpIndices; + if (Target.getInstructionSet()->getValueAsBit( + "noNamedPositionallyEncodedOperands")) + // Collect the set of operand indices that might correspond to named + // operand, and skip these when assigning operands based on position. + for (unsigned i = 0, e = Vals.size(); i != e; ++i) { + unsigned OpIdx; + if (!CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx)) + continue; + + NamedOpIndices.insert(OpIdx); + } + for (unsigned i = 0, e = Vals.size(); i != e; ++i) { - unsigned OpIdx; - if (!CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx)) + // Ignore fixed fields in the record, we're looking for values like: + // bits<5> RST = { ?, ?, ?, ?, ? }; + if (Vals[i].isNonconcreteOK() || Vals[i].getValue()->isComplete()) continue; - NamedOpIndices.insert(OpIdx); - } + // Determine if Vals[i] actually contributes to the Inst encoding. + unsigned bi = 0; + for (; 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 && Var->getName() == Vals[i].getName()) + break; + } - for (unsigned i = 0, e = Vals.size(); i != e; ++i) { - // Ignore fixed fields in the record, we're looking for values like: - // bits<5> RST = { ?, ?, ?, ?, ? }; - if (Vals[i].isNonconcreteOK() || Vals[i].getValue()->isComplete()) - continue; + if (bi == Bits.getNumBits()) + continue; - // Determine if Vals[i] actually contributes to the Inst encoding. - unsigned bi = 0; - for (; 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)); + // Skip variables that correspond to explicitly-named operands. + unsigned OpIdx; + if (CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx)) + continue; - if (Var && Var->getName() == Vals[i].getName()) - break; - } + // Get the bit range for this operand: + unsigned bitStart = bi++, bitWidth = 1; + for (; 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 (bi == Bits.getNumBits()) - continue; + if (!Var) + break; - // Skip variables that correspond to explicitly-named operands. - unsigned OpIdx; - if (CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx)) - continue; + if (Var->getName() != Vals[i].getName()) + break; - // Get the bit range for this operand: - unsigned bitStart = bi++, bitWidth = 1; - for (; 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)); + ++bitWidth; + } - if (!Var) - break; + unsigned NumberOps = CGI.Operands.size(); + while (NumberedOp < NumberOps && + (CGI.Operands.isFlatOperandNotEmitted(NumberedOp) || + (!NamedOpIndices.empty() && + NamedOpIndices.count( + CGI.Operands.getSubOperandNumber(NumberedOp).first)))) + ++NumberedOp; + + OpIdx = NumberedOp++; + + // OpIdx now holds the ordered operand number of Vals[i]. + std::pair SO = + CGI.Operands.getSubOperandNumber(OpIdx); + const std::string &Name = CGI.Operands[SO.first].Name; + + LLVM_DEBUG(dbgs() << "Numbered operand mapping for " << Def.getName() + << ": " << Name << "(" << SO.first << ", " + << SO.second << ") => " << Vals[i].getName() << "\n"); + + std::string Decoder; + Record *TypeRecord = CGI.Operands[SO.first].Rec; + + RecordVal *DecoderString = TypeRecord->getValue("DecoderMethod"); + StringInit *String = + DecoderString ? dyn_cast(DecoderString->getValue()) + : nullptr; + if (String && String->getValue() != "") + Decoder = std::string(String->getValue()); + + if (Decoder == "" && CGI.Operands[SO.first].MIOperandInfo && + CGI.Operands[SO.first].MIOperandInfo->getNumArgs()) { + Init *Arg = CGI.Operands[SO.first].MIOperandInfo->getArg(SO.second); + if (DefInit *DI = cast(Arg)) + TypeRecord = DI->getDef(); + } - if (Var->getName() != Vals[i].getName()) - break; + bool isReg = false; + if (TypeRecord->isSubClassOf("RegisterOperand")) + TypeRecord = TypeRecord->getValueAsDef("RegClass"); + if (TypeRecord->isSubClassOf("RegisterClass")) { + Decoder = "Decode" + TypeRecord->getName().str() + "RegisterClass"; + isReg = true; + } else if (TypeRecord->isSubClassOf("PointerLikeRegClass")) { + Decoder = "DecodePointerLikeRegClass" + + utostr(TypeRecord->getValueAsInt("RegClassKind")); + isReg = true; + } - ++bitWidth; + DecoderString = TypeRecord->getValue("DecoderMethod"); + String = DecoderString ? dyn_cast(DecoderString->getValue()) + : nullptr; + if (!isReg && String && String->getValue() != "") + Decoder = std::string(String->getValue()); + + RecordVal *HasCompleteDecoderVal = + TypeRecord->getValue("hasCompleteDecoder"); + BitInit *HasCompleteDecoderBit = + HasCompleteDecoderVal + ? dyn_cast(HasCompleteDecoderVal->getValue()) + : nullptr; + bool HasCompleteDecoder = + HasCompleteDecoderBit ? HasCompleteDecoderBit->getValue() : true; + + OperandInfo OpInfo(Decoder, HasCompleteDecoder); + OpInfo.addField(bitStart, bitWidth, 0); + + NumberedInsnOperands[Name].push_back(OpInfo); + + // FIXME: For complex operands with custom decoders we can't handle tied + // sub-operands automatically. Skip those here and assume that this is + // fixed up elsewhere. + if (CGI.Operands[SO.first].MIOperandInfo && + CGI.Operands[SO.first].MIOperandInfo->getNumArgs() > 1 && String && + String->getValue() != "") + NumberedInsnOperandsNoTie.insert(Name); } + } - unsigned NumberOps = CGI.Operands.size(); - while (NumberedOp < NumberOps && - (CGI.Operands.isFlatOperandNotEmitted(NumberedOp) || - (!NamedOpIndices.empty() && NamedOpIndices.count( - CGI.Operands.getSubOperandNumber(NumberedOp).first)))) - ++NumberedOp; - - OpIdx = NumberedOp++; - - // OpIdx now holds the ordered operand number of Vals[i]. - std::pair SO = - CGI.Operands.getSubOperandNumber(OpIdx); - const std::string &Name = CGI.Operands[SO.first].Name; - - LLVM_DEBUG(dbgs() << "Numbered operand mapping for " << Def.getName() - << ": " << Name << "(" << SO.first << ", " << SO.second - << ") => " << Vals[i].getName() << "\n"); - - std::string Decoder; - Record *TypeRecord = CGI.Operands[SO.first].Rec; - - RecordVal *DecoderString = TypeRecord->getValue("DecoderMethod"); - StringInit *String = DecoderString ? - dyn_cast(DecoderString->getValue()) : nullptr; - if (String && String->getValue() != "") - Decoder = std::string(String->getValue()); - - if (Decoder == "" && - CGI.Operands[SO.first].MIOperandInfo && - CGI.Operands[SO.first].MIOperandInfo->getNumArgs()) { - Init *Arg = CGI.Operands[SO.first].MIOperandInfo-> - getArg(SO.second); - if (DefInit *DI = cast(Arg)) - TypeRecord = DI->getDef(); + // For each operand, see if we can figure out where it is encoded. + for (const auto &Op : InOutOperands) { + if (!NumberedInsnOperands[std::string(Op.second)].empty()) { + llvm::append_range(InsnOperands, + NumberedInsnOperands[std::string(Op.second)]); + continue; } - - bool isReg = false; - if (TypeRecord->isSubClassOf("RegisterOperand")) - TypeRecord = TypeRecord->getValueAsDef("RegClass"); - if (TypeRecord->isSubClassOf("RegisterClass")) { - Decoder = "Decode" + TypeRecord->getName().str() + "RegisterClass"; - isReg = true; - } else if (TypeRecord->isSubClassOf("PointerLikeRegClass")) { - Decoder = "DecodePointerLikeRegClass" + - utostr(TypeRecord->getValueAsInt("RegClassKind")); - isReg = true; + if (!NumberedInsnOperands[TiedNames[std::string(Op.second)]].empty()) { + if (!NumberedInsnOperandsNoTie.count( + TiedNames[std::string(Op.second)])) { + // Figure out to which (sub)operand we're tied. + unsigned i = + CGI.Operands.getOperandNamed(TiedNames[std::string(Op.second)]); + int tiedTo = CGI.Operands[i].getTiedRegister(); + if (tiedTo == -1) { + i = CGI.Operands.getOperandNamed(Op.second); + tiedTo = CGI.Operands[i].getTiedRegister(); + } + + if (tiedTo != -1) { + std::pair SO = + CGI.Operands.getSubOperandNumber(tiedTo); + + InsnOperands.push_back( + NumberedInsnOperands[TiedNames[std::string(Op.second)]] + [SO.second]); + } + } + continue; } - DecoderString = TypeRecord->getValue("DecoderMethod"); - String = DecoderString ? - dyn_cast(DecoderString->getValue()) : nullptr; - if (!isReg && String && String->getValue() != "") - Decoder = std::string(String->getValue()); - - RecordVal *HasCompleteDecoderVal = - TypeRecord->getValue("hasCompleteDecoder"); - BitInit *HasCompleteDecoderBit = HasCompleteDecoderVal ? - dyn_cast(HasCompleteDecoderVal->getValue()) : nullptr; - bool HasCompleteDecoder = HasCompleteDecoderBit ? - HasCompleteDecoderBit->getValue() : true; - - OperandInfo OpInfo(Decoder, HasCompleteDecoder); - OpInfo.addField(bitStart, bitWidth, 0); - - NumberedInsnOperands[Name].push_back(OpInfo); - - // FIXME: For complex operands with custom decoders we can't handle tied - // sub-operands automatically. Skip those here and assume that this is - // fixed up elsewhere. - if (CGI.Operands[SO.first].MIOperandInfo && - CGI.Operands[SO.first].MIOperandInfo->getNumArgs() > 1 && - String && String->getValue() != "") - NumberedInsnOperandsNoTie.insert(Name); - } - } + // At this point, we can locate the decoder field, but we need to know how + // to interpret it. As a first step, require the target to provide + // callbacks for decoding register classes. - // For each operand, see if we can figure out where it is encoded. - for (const auto &Op : InOutOperands) { - if (!NumberedInsnOperands[std::string(Op.second)].empty()) { - llvm::append_range(InsnOperands, - NumberedInsnOperands[std::string(Op.second)]); - continue; - } - if (!NumberedInsnOperands[TiedNames[std::string(Op.second)]].empty()) { - if (!NumberedInsnOperandsNoTie.count(TiedNames[std::string(Op.second)])) { - // Figure out to which (sub)operand we're tied. - unsigned i = - CGI.Operands.getOperandNamed(TiedNames[std::string(Op.second)]); - int tiedTo = CGI.Operands[i].getTiedRegister(); - if (tiedTo == -1) { - i = CGI.Operands.getOperandNamed(Op.second); - tiedTo = CGI.Operands[i].getTiedRegister(); - } + OperandInfo OpInfo = getOpInfo(cast(Op.first)->getDef()); - if (tiedTo != -1) { - std::pair SO = - CGI.Operands.getSubOperandNumber(tiedTo); + // Some bits of the operand may be required to be 1 depending on the + // instruction's encoding. Collect those bits. + if (const RecordVal *EncodedValue = EncodingDef.getValue(Op.second)) + if (const BitsInit *OpBits = + dyn_cast(EncodedValue->getValue())) + for (unsigned I = 0; I < OpBits->getNumBits(); ++I) + if (const BitInit *OpBit = dyn_cast(OpBits->getBit(I))) + if (OpBit->getValue()) + OpInfo.InitValue |= 1ULL << I; - InsnOperands.push_back( - NumberedInsnOperands[TiedNames[std::string(Op.second)]] - [SO.second]); - } - } - continue; - } + unsigned Base = ~0U; + unsigned Width = 0; + unsigned Offset = 0; - TypedInit *TI = cast(Op.first); - - // At this point, we can locate the decoder field, but we need to know how - // to interpret it. As a first step, require the target to provide - // callbacks for decoding register classes. - std::string Decoder = findOperandDecoderMethod(TI); - Record *TypeRecord = cast(TI)->getDef(); - - RecordVal *HasCompleteDecoderVal = - TypeRecord->getValue("hasCompleteDecoder"); - BitInit *HasCompleteDecoderBit = HasCompleteDecoderVal ? - dyn_cast(HasCompleteDecoderVal->getValue()) : nullptr; - bool HasCompleteDecoder = HasCompleteDecoderBit ? - HasCompleteDecoderBit->getValue() : true; - - OperandInfo OpInfo(Decoder, HasCompleteDecoder); - - // Some bits of the operand may be required to be 1 depending on the - // instruction's encoding. Collect those bits. - if (const RecordVal *EncodedValue = EncodingDef.getValue(Op.second)) - if (const BitsInit *OpBits = dyn_cast(EncodedValue->getValue())) - for (unsigned I = 0; I < OpBits->getNumBits(); ++I) - if (const BitInit *OpBit = dyn_cast(OpBits->getBit(I))) - if (OpBit->getValue()) - OpInfo.InitValue |= 1ULL << I; - - 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)); - 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; + } + continue; + } - if (!Var) { - if (Base != ~0U) { - OpInfo.addField(Base, Width, Offset); - Base = ~0U; - Width = 0; - Offset = 0; + 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; + } + continue; } - continue; - } - if (Var->getName() != Op.second && - Var->getName() != TiedNames[std::string(Op.second)]) { - if (Base != ~0U) { + 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 = ~0U; - Width = 0; - Offset = 0; + 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) { + if (Base != ~0U) OpInfo.addField(Base, Width, Offset); - Base = bi; - Width = 1; - Offset = BI->getBitNum(); - } else { - ++Width; - } - } - if (Base != ~0U) - OpInfo.addField(Base, Width, Offset); - - if (OpInfo.numFields() > 0) - InsnOperands.push_back(OpInfo); + if (OpInfo.numFields() > 0) + InsnOperands.push_back(OpInfo); + } } Operands[Opc] = InsnOperands; @@ -2143,7 +2245,7 @@ }); #endif - return true; + return Bits.getNumBits(); } // emitFieldFromInstruction - Emit the templated helper function @@ -2215,18 +2317,26 @@ // 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" + << " llvm::function_ref 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,8 +2347,10 @@ << " case MCD::OPC_ExtractField: {\n" << " unsigned Start = *++Ptr;\n" << " unsigned Len = *++Ptr;\n" - << " ++Ptr;\n" - << " CurFieldValue = fieldFromInstruction(insn, Start, Len);\n" + << " ++Ptr;\n"; + if (IsVarLenInst) + OS << " makeUp(insn, Start + Len);\n"; + OS << " CurFieldValue = fieldFromInstruction(insn, Start, Len);\n" << " LLVM_DEBUG(dbgs() << Loc << \": OPC_ExtractField(\" << Start << " "\", \"\n" << " << Len << \"): \" << CurFieldValue << \"\\n\");\n" @@ -2247,7 +2359,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,11 +2380,14 @@ << " }\n" << " case MCD::OPC_CheckField: {\n" << " unsigned Start = *++Ptr;\n" - << " unsigned Len = *++Ptr;\n" - << " InsnType FieldValue = fieldFromInstruction(insn, Start, Len);\n" + << " unsigned Len = *++Ptr;\n"; + if (IsVarLenInst) + OS << " makeUp(insn, Start + Len);\n"; + OS << " uint64_t FieldValue = 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" @@ -2322,8 +2437,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" @@ -2377,11 +2496,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 ? " @@ -2420,7 +2540,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. @@ -2472,6 +2592,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; @@ -2490,10 +2618,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()) @@ -2512,7 +2648,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 @@ -2537,6 +2673,8 @@ OS.flush(); } + if (IsVarLenInst) + emitInstrLenTable(OS, InstrLen); // Emit the predicate function. emitPredicateFunction(OS, TableInfo.Predicates, 0); @@ -2544,7 +2682,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"; } diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.h b/llvm/utils/TableGen/VarLenCodeEmitterGen.h --- a/llvm/utils/TableGen/VarLenCodeEmitterGen.h +++ b/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; diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp --- a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp +++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp @@ -58,7 +58,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; @@ -67,48 +66,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) @@ -129,15 +86,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();