diff options
Diffstat (limited to 'llvm/utils/TableGen/DecoderEmitter.cpp')
-rw-r--r-- | llvm/utils/TableGen/DecoderEmitter.cpp | 653 |
1 files changed, 317 insertions, 336 deletions
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index 88f245238138..dd78dc02159b 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -226,7 +226,7 @@ static BitsInit &getBitsField(const Record &def, StringRef str) { VarLenInst VLI = VarLenInst(cast<DagInit>(RV->getValue()), RV); SmallVector<Init *, 16> Bits; - for (auto &SI : VLI) { + for (const auto &SI : VLI) { if (const BitsInit *BI = dyn_cast<BitsInit>(SI.Value)) { for (unsigned Idx = 0U; Idx < BI->getNumBits(); ++Idx) { Bits.push_back(BI->getBit(Idx)); @@ -441,16 +441,15 @@ public: protected: // 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); + const Record *EncodingDef = AllInstructions[Opcode].EncodingDef; + BitsInit &Bits = getBitsField(*EncodingDef, "Inst"); + Insn.resize(std::max(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. - const RecordVal *RV = - AllInstructions[Opcode].EncodingDef->getValue("SoftFail"); + const RecordVal *RV = EncodingDef->getValue("SoftFail"); const BitsInit *SFBits = RV ? dyn_cast<BitsInit>(RV->getValue()) : nullptr; for (unsigned i = 0; i < Bits.getNumBits(); ++i) { if (SFBits && bitFromBits(*SFBits, i) == BIT_TRUE) @@ -472,10 +471,11 @@ protected: // Populates the field of the insn given the start position and the number of // consecutive bits to scan for. // - // Returns false if there exists any uninitialized bit value in the range. - // Returns true, otherwise. - bool fieldFromInsn(uint64_t &Field, insn_t &Insn, unsigned StartBit, - unsigned NumBits) const; + // Returns a pair of values (indicator, field), where the indicator is false + // if there exists any uninitialized bit value in the range and true if all + // bits are well-known. The second value is the potentially populated field. + std::pair<bool, uint64_t> fieldFromInsn(const insn_t &Insn, unsigned StartBit, + unsigned NumBits) const; /// dumpFilterArray - dumpFilterArray prints out debugging info for the given /// filter array as a series of chars. @@ -581,26 +581,25 @@ Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, NumFiltered = 0; LastOpcFiltered = {0, 0}; - for (unsigned i = 0, e = Owner->Opcodes.size(); i != e; ++i) { + for (const auto &OpcPair : Owner->Opcodes) { insn_t Insn; // Populates the insn given the uid. - Owner->insnWithID(Insn, Owner->Opcodes[i].EncodingID); + Owner->insnWithID(Insn, OpcPair.EncodingID); - uint64_t Field; // Scans the segment for possibly well-specified encoding bits. - bool ok = Owner->fieldFromInsn(Field, Insn, StartBit, NumBits); + auto [Ok, Field] = Owner->fieldFromInsn(Insn, StartBit, NumBits); - if (ok) { + if (Ok) { // The encoding bits are well-known. Lets add the uid of the // instruction into the bucket keyed off the constant field value. - LastOpcFiltered = Owner->Opcodes[i]; + LastOpcFiltered = OpcPair; FilteredInstructions[Field].push_back(LastOpcFiltered); ++NumFiltered; } else { // Some of the encoding bit(s) are unspecified. This contributes to // one additional member of "Variable" instructions. - VariableInstructions.push_back(Owner->Opcodes[i]); + VariableInstructions.push_back(OpcPair); } } @@ -699,7 +698,7 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const { size_t PrevFilter = 0; bool HasFallthrough = false; - for (auto &Filter : FilterChooserMap) { + for (const auto &Filter : FilterChooserMap) { // Field value -1 implies a non-empty set of variable instructions. // See also recurse(). if (Filter.first == NO_FIXED_SEGMENTS_SENTINEL) { @@ -784,7 +783,7 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table, // is used below to index into NumberedEncodings. DenseMap<unsigned, unsigned> OpcodeToEncodingID; OpcodeToEncodingID.reserve(EncodingIDs.size()); - for (auto &EI : EncodingIDs) + for (const auto &EI : EncodingIDs) OpcodeToEncodingID[EI.Opcode] = EI.EncodingID; OS.indent(Indentation) << "static const uint8_t DecoderTable" << Namespace @@ -1038,27 +1037,29 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS, } OS.indent(Indentation) << "}\n"; Indentation -= 2; - OS.indent(Indentation) << "}\n\n"; + OS.indent(Indentation) << "}\n"; } // Populates the field of the insn given the start position and the number of // consecutive bits to scan for. // -// Returns false if and on the first uninitialized bit value encountered. -// Returns true, otherwise. -bool FilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn, - unsigned StartBit, unsigned NumBits) const { - Field = 0; +// Returns a pair of values (indicator, field), where the indicator is false +// if there exists any uninitialized bit value in the range and true if all +// bits are well-known. The second value is the potentially populated field. +std::pair<bool, uint64_t> FilterChooser::fieldFromInsn(const insn_t &Insn, + unsigned StartBit, + unsigned NumBits) const { + uint64_t Field = 0; for (unsigned i = 0; i < NumBits; ++i) { if (Insn[StartBit + i] == BIT_UNSET) - return false; + return {false, Field}; if (Insn[StartBit + i] == BIT_TRUE) Field = Field | (1ULL << i); } - return true; + return {true, Field}; } /// dumpFilterArray - dumpFilterArray prints out debugging info for the given @@ -1246,14 +1247,14 @@ unsigned FilterChooser::getDecoderIndex(DecoderSet &Decoders, unsigned Opc, // If ParenIfBinOp is true, print a surrounding () if Val uses && or ||. bool FilterChooser::emitPredicateMatchAux(const Init &Val, bool ParenIfBinOp, raw_ostream &OS) const { - if (auto *D = dyn_cast<DefInit>(&Val)) { + if (const auto *D = dyn_cast<DefInit>(&Val)) { if (!D->getDef()->isSubClassOf("SubtargetFeature")) return true; OS << "Bits[" << Emitter->PredicateNamespace << "::" << D->getAsString() << "]"; return false; } - if (auto *D = dyn_cast<DagInit>(&Val)) { + if (const auto *D = dyn_cast<DagInit>(&Val)) { std::string Op = D->getOperator()->getAsString(); if (Op == "not" && D->getNumArgs() == 1) { OS << '!'; @@ -1350,9 +1351,9 @@ void FilterChooser::emitPredicateTableEntry(DecoderTableInfo &TableInfo, encodeULEB128(PIdx, S); TableInfo.Table.push_back(MCD::OPC_CheckPredicate); - // Predicate index - for (unsigned i = 0, e = PBytes.size(); i != e; ++i) - TableInfo.Table.push_back(PBytes[i]); + // Predicate index. + for (const auto PB : PBytes) + TableInfo.Table.push_back(PB); // Push location for NumToSkip backpatching. TableInfo.FixupStack.back().push_back(TableInfo.Table.size()); TableInfo.Table.push_back(0); @@ -1362,13 +1363,13 @@ void FilterChooser::emitPredicateTableEntry(DecoderTableInfo &TableInfo, void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo, unsigned Opc) const { - const RecordVal *RV = AllInstructions[Opc].EncodingDef->getValue("SoftFail"); + const Record *EncodingDef = AllInstructions[Opc].EncodingDef; + const RecordVal *RV = EncodingDef->getValue("SoftFail"); BitsInit *SFBits = RV ? dyn_cast<BitsInit>(RV->getValue()) : nullptr; if (!SFBits) return; - BitsInit *InstBits = - AllInstructions[Opc].EncodingDef->getValueAsBitsInit("Inst"); + BitsInit *InstBits = EncodingDef->getValueAsBitsInit("Inst"); APInt PositiveMask(BitWidth, 0ULL); APInt NegativeMask(BitWidth, 0ULL); @@ -1495,9 +1496,9 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo, raw_svector_ostream S(Bytes); encodeULEB128(DIdx, S); - // Decoder index - for (unsigned i = 0, e = Bytes.size(); i != e; ++i) - TableInfo.Table.push_back(Bytes[i]); + // Decoder index. + for (const auto B : Bytes) + TableInfo.Table.push_back(B); if (!HasCompleteDecoder) { // Push location for NumToSkip backpatching. @@ -1566,7 +1567,7 @@ bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) { if (AllowMixed && !Greedy) { assert(numInstructions == 3); - for (auto Opcode : Opcodes) { + for (const auto &Opcode : Opcodes) { std::vector<unsigned> StartBits; std::vector<unsigned> EndBits; std::vector<uint64_t> FieldVals; @@ -1613,10 +1614,10 @@ bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) { else bitAttrs.push_back(ATTR_NONE); - for (unsigned InsnIndex = 0; InsnIndex < numInstructions; ++InsnIndex) { + for (const auto &OpcPair : Opcodes) { insn_t insn; - insnWithID(insn, Opcodes[InsnIndex].EncodingID); + insnWithID(insn, OpcPair.EncodingID); for (BitIndex = 0; BitIndex < BitWidth; ++BitIndex) { switch (bitAttrs[BitIndex]) { @@ -1760,14 +1761,14 @@ bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) { bool AllUseless = true; unsigned BestScore = 0; - for (unsigned i = 0, e = Filters.size(); i != e; ++i) { - unsigned Usefulness = Filters[i].usefulness(); + for (const auto &[Idx, Filter] : enumerate(Filters)) { + unsigned Usefulness = Filter.usefulness(); if (Usefulness) AllUseless = false; if (Usefulness > BestScore) { - BestIndex = i; + BestIndex = Idx; BestScore = Usefulness; } } @@ -1892,8 +1893,7 @@ void parseVarLenInstOperand(const Record &Def, VarLenInst VLI(cast<DagInit>(RV->getValue()), RV); SmallVector<int> TiedTo; - for (unsigned Idx = 0; Idx < CGI.Operands.size(); ++Idx) { - auto &Op = CGI.Operands[Idx]; + for (const auto &[Idx, Op] : enumerate(CGI.Operands)) { if (Op.MIOperandInfo && Op.MIOperandInfo->getNumArgs() > 0) for (auto *Arg : Op.MIOperandInfo->getArgs()) Operands.push_back(getOpInfo(cast<DefInit>(Arg)->getDef())); @@ -1909,7 +1909,7 @@ void parseVarLenInstOperand(const Record &Def, } unsigned CurrBitPos = 0; - for (auto &EncodingSegment : VLI) { + for (const auto &EncodingSegment : VLI) { unsigned Offset = 0; StringRef OpName; @@ -2028,26 +2028,23 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, std::vector<std::pair<Init *, StringRef>> InOutOperands; DagInit *Out = Def.getValueAsDag("OutOperandList"); DagInit *In = Def.getValueAsDag("InOperandList"); - for (unsigned i = 0; i < Out->getNumArgs(); ++i) - InOutOperands.push_back(std::pair(Out->getArg(i), Out->getArgNameStr(i))); - for (unsigned i = 0; i < In->getNumArgs(); ++i) - InOutOperands.push_back(std::pair(In->getArg(i), In->getArgNameStr(i))); + for (const auto &[Idx, Arg] : enumerate(Out->getArgs())) + InOutOperands.push_back(std::pair(Arg, Out->getArgNameStr(Idx))); + for (const auto &[Idx, Arg] : enumerate(In->getArgs())) + InOutOperands.push_back(std::pair(Arg, In->getArgNameStr(Idx))); // Search for tied operands, so that we can correctly instantiate // operands that are not explicitly represented in the encoding. std::map<std::string, std::string> TiedNames; - for (unsigned i = 0; i < CGI.Operands.size(); ++i) { - auto &Op = CGI.Operands[i]; - for (unsigned j = 0; j < Op.Constraints.size(); ++j) { - const CGIOperandList::ConstraintInfo &CI = Op.Constraints[j]; + for (const auto &[I, Op] : enumerate(CGI.Operands)) { + for (const auto &[J, CI] : enumerate(Op.Constraints)) { if (CI.isTied()) { - int tiedTo = CI.getTiedOperand(); std::pair<unsigned, unsigned> SO = - CGI.Operands.getSubOperandNumber(tiedTo); + CGI.Operands.getSubOperandNumber(CI.getTiedOperand()); std::string TiedName = CGI.Operands[SO.first].SubOpNames[SO.second]; if (TiedName.empty()) TiedName = CGI.Operands[SO.first].Name; - std::string MyName = Op.SubOpNames[j]; + std::string MyName = Op.SubOpNames[J]; if (MyName.empty()) MyName = Op.Name; @@ -2099,10 +2096,9 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, // Decode each of the sub-ops separately. assert(SubOps && SubArgDag->getNumArgs() == SubOps->getNumArgs()); - for (unsigned i = 0; i < SubOps->getNumArgs(); ++i) { - StringRef SubOpName = SubArgDag->getArgNameStr(i); - OperandInfo SubOpInfo = - getOpInfo(cast<DefInit>(SubOps->getArg(i))->getDef()); + for (const auto &[I, Arg] : enumerate(SubOps->getArgs())) { + StringRef SubOpName = SubArgDag->getArgNameStr(I); + OperandInfo SubOpInfo = getOpInfo(cast<DefInit>(Arg)->getDef()); addOneOperandFields(EncodingDef, Bits, TiedNames, SubOpName, SubOpInfo); @@ -2169,273 +2165,253 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, // using the VS compiler. It has a bug which causes the function // to be optimized out in some circumstances. See llvm.org/pr38292 static void emitFieldFromInstruction(formatted_raw_ostream &OS) { - OS << "// Helper functions for extracting fields from encoded instructions.\n" - << "// InsnType must either be integral or an APInt-like object that " - "must:\n" - << "// * be default-constructible and copy-constructible\n" - << "// * be constructible from an APInt (this can be private)\n" - << "// * Support insertBits(bits, startBit, numBits)\n" - << "// * Support extractBitsAsZExtValue(numBits, startBit)\n" - << "// * Support the ~, &, ==, and != operators with other objects of " - "the same type\n" - << "// * Support the != and bitwise & with uint64_t\n" - << "// * Support put (<<) to raw_ostream&\n" - << "template <typename InsnType>\n" - << "#if defined(_MSC_VER) && !defined(__clang__)\n" - << "__declspec(noinline)\n" - << "#endif\n" - << "static std::enable_if_t<std::is_integral<InsnType>::value, InsnType>\n" - << "fieldFromInstruction(const InsnType &insn, unsigned startBit,\n" - << " unsigned numBits) {\n" - << " assert(startBit + numBits <= 64 && \"Cannot support >64-bit " - "extractions!\");\n" - << " assert(startBit + numBits <= (sizeof(InsnType) * 8) &&\n" - << " \"Instruction field out of bounds!\");\n" - << " InsnType fieldMask;\n" - << " if (numBits == sizeof(InsnType) * 8)\n" - << " fieldMask = (InsnType)(-1LL);\n" - << " else\n" - << " fieldMask = (((InsnType)1 << numBits) - 1) << startBit;\n" - << " return (insn & fieldMask) >> startBit;\n" - << "}\n" - << "\n" - << "template <typename InsnType>\n" - << "static std::enable_if_t<!std::is_integral<InsnType>::value, " - "uint64_t>\n" - << "fieldFromInstruction(const InsnType &insn, unsigned startBit,\n" - << " unsigned numBits) {\n" - << " return insn.extractBitsAsZExtValue(numBits, startBit);\n" - << "}\n\n"; + OS << R"( +// Helper functions for extracting fields from encoded instructions. +// InsnType must either be integral or an APInt-like object that must: +// * be default-constructible and copy-constructible +// * be constructible from an APInt (this can be private) +// * Support insertBits(bits, startBit, numBits) +// * Support extractBitsAsZExtValue(numBits, startBit) +// * Support the ~, &, ==, and != operators with other objects of the same type +// * Support the != and bitwise & with uint64_t +// * Support put (<<) to raw_ostream& +template <typename InsnType> +#if defined(_MSC_VER) && !defined(__clang__) +__declspec(noinline) +#endif +static std::enable_if_t<std::is_integral<InsnType>::value, InsnType> +fieldFromInstruction(const InsnType &insn, unsigned startBit, + unsigned numBits) { + assert(startBit + numBits <= 64 && "Cannot support >64-bit extractions!"); + assert(startBit + numBits <= (sizeof(InsnType) * 8) && + "Instruction field out of bounds!"); + InsnType fieldMask; + if (numBits == sizeof(InsnType) * 8) + fieldMask = (InsnType)(-1LL); + else + fieldMask = (((InsnType)1 << numBits) - 1) << startBit; + return (insn & fieldMask) >> startBit; +} + +template <typename InsnType> +static std::enable_if_t<!std::is_integral<InsnType>::value, uint64_t> +fieldFromInstruction(const InsnType &insn, unsigned startBit, + unsigned numBits) { + return insn.extractBitsAsZExtValue(numBits, startBit); +} +)"; } // emitInsertBits - Emit the templated helper function insertBits(). static void emitInsertBits(formatted_raw_ostream &OS) { - OS << "// Helper function for inserting bits extracted from an encoded " - "instruction into\n" - << "// a field.\n" - << "template <typename InsnType>\n" - << "static std::enable_if_t<std::is_integral<InsnType>::value>\n" - << "insertBits(InsnType &field, InsnType bits, unsigned startBit, " - "unsigned numBits) {\n" - << " assert(startBit + numBits <= sizeof field * 8);\n" - << " field |= (InsnType)bits << startBit;\n" - << "}\n" - << "\n" - << "template <typename InsnType>\n" - << "static std::enable_if_t<!std::is_integral<InsnType>::value>\n" - << "insertBits(InsnType &field, uint64_t bits, unsigned startBit, " - "unsigned numBits) {\n" - << " field.insertBits(bits, startBit, numBits);\n" - << "}\n\n"; + OS << R"( +// Helper function for inserting bits extracted from an encoded instruction into +// a field. +template <typename InsnType> +static std::enable_if_t<std::is_integral<InsnType>::value> +insertBits(InsnType &field, InsnType bits, unsigned startBit, unsigned numBits) { + assert(startBit + numBits <= sizeof field * 8); + field |= (InsnType)bits << startBit; +} + +template <typename InsnType> +static std::enable_if_t<!std::is_integral<InsnType>::value> +insertBits(InsnType &field, uint64_t bits, unsigned startBit, unsigned numBits) { + field.insertBits(bits, startBit, numBits); +} +)"; } // emitDecodeInstruction - Emit the templated helper function // decodeInstruction(). static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst) { - OS << "template <typename InsnType>\n" - << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], " - "MCInst &MI,\n" - << " InsnType insn, uint64_t " - "Address,\n" - << " const MCDisassembler *DisAsm,\n" - << " const MCSubtargetInfo &STI"; + OS << R"( +template <typename InsnType> +static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, + InsnType insn, uint64_t Address, + const MCDisassembler *DisAsm, + const MCSubtargetInfo &STI)"; if (IsVarLenInst) { - OS << ",\n" - << " llvm::function_ref<void(APInt " - "&," - << " uint64_t)> makeUp"; + OS << ",\n " + "llvm::function_ref<void(APInt &, uint64_t)> makeUp"; } - OS << ") {\n" - << " const FeatureBitset &Bits = STI.getFeatureBits();\n" - << "\n" - << " const uint8_t *Ptr = DecodeTable;\n" - << " uint64_t CurFieldValue = 0;\n" - << " DecodeStatus S = MCDisassembler::Success;\n" - << " while (true) {\n" - << " ptrdiff_t Loc = Ptr - DecodeTable;\n" - << " switch (*Ptr) {\n" - << " default:\n" - << " errs() << Loc << \": Unexpected decode table opcode!\\n\";\n" - << " return MCDisassembler::Fail;\n" - << " case MCD::OPC_ExtractField: {\n" - << " // Decode the start value.\n" - << " unsigned DecodedLen;\n" - << " unsigned Start = decodeULEB128(++Ptr, &DecodedLen);\n" - << " Ptr += DecodedLen;\n" - << " unsigned Len = *Ptr++;\n"; + OS << R"() { + const FeatureBitset &Bits = STI.getFeatureBits(); + + const uint8_t *Ptr = DecodeTable; + uint64_t CurFieldValue = 0; + DecodeStatus S = MCDisassembler::Success; + while (true) { + ptrdiff_t Loc = Ptr - DecodeTable; + switch (*Ptr) { + default: + errs() << Loc << ": Unexpected decode table opcode!\n"; + return MCDisassembler::Fail; + case MCD::OPC_ExtractField: { + // Decode the start value. + unsigned DecodedLen; + unsigned Start = decodeULEB128(++Ptr, &DecodedLen); + Ptr += DecodedLen; + unsigned Len = *Ptr++;)"; 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" - << " break;\n" - << " }\n" - << " case MCD::OPC_FilterValue: {\n" - << " // Decode the field value.\n" - << " unsigned Len;\n" - << " uint64_t Val = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " // NumToSkip is a plain 24-bit integer.\n" - << " unsigned NumToSkip = *Ptr++;\n" - << " NumToSkip |= (*Ptr++) << 8;\n" - << " NumToSkip |= (*Ptr++) << 16;\n" - << "\n" - << " // Perform the filter operation.\n" - << " if (Val != CurFieldValue)\n" - << " Ptr += NumToSkip;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_FilterValue(\" << Val << " - "\", \" << NumToSkip\n" - << " << \"): \" << ((Val != CurFieldValue) ? \"FAIL:\" " - ": \"PASS:\")\n" - << " << \" continuing at \" << (Ptr - DecodeTable) << " - "\"\\n\");\n" - << "\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_CheckField: {\n" - << " // Decode the start value.\n" - << " unsigned Len;\n" - << " unsigned Start = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " Len = *Ptr;\n"; + OS << "\n makeUp(insn, Start + Len);"; + OS << R"( + CurFieldValue = fieldFromInstruction(insn, Start, Len); + LLVM_DEBUG(dbgs() << Loc << ": OPC_ExtractField(" << Start << ", " + << Len << "): " << CurFieldValue << "\n"); + break; + } + case MCD::OPC_FilterValue: { + // Decode the field value. + unsigned Len; + uint64_t Val = decodeULEB128(++Ptr, &Len); + Ptr += Len; + // NumToSkip is a plain 24-bit integer. + unsigned NumToSkip = *Ptr++; + NumToSkip |= (*Ptr++) << 8; + NumToSkip |= (*Ptr++) << 16; + + // Perform the filter operation. + if (Val != CurFieldValue) + Ptr += NumToSkip; + LLVM_DEBUG(dbgs() << Loc << ": OPC_FilterValue(" << Val << ", " << NumToSkip + << "): " << ((Val != CurFieldValue) ? "FAIL:" : "PASS:") + << " continuing at " << (Ptr - DecodeTable) << "\n"); + + break; + } + case MCD::OPC_CheckField: { + // Decode the start value. + unsigned Len; + unsigned Start = decodeULEB128(++Ptr, &Len); + Ptr += Len; + Len = *Ptr;)"; if (IsVarLenInst) - OS << " makeUp(insn, Start + Len);\n"; - OS << " uint64_t FieldValue = fieldFromInstruction(insn, Start, Len);\n" - << " // Decode the field value.\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" - << " NumToSkip |= (*Ptr++) << 16;\n" - << "\n" - << " // If the actual and expected values don't match, skip.\n" - << " if (ExpectedValue != FieldValue)\n" - << " Ptr += NumToSkip;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckField(\" << Start << " - "\", \"\n" - << " << Len << \", \" << ExpectedValue << \", \" << " - "NumToSkip\n" - << " << \"): FieldValue = \" << FieldValue << \", " - "ExpectedValue = \"\n" - << " << ExpectedValue << \": \"\n" - << " << ((ExpectedValue == FieldValue) ? \"PASS\\n\" : " - "\"FAIL\\n\"));\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_CheckPredicate: {\n" - << " unsigned Len;\n" - << " // Decode the Predicate Index value.\n" - << " unsigned PIdx = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " // NumToSkip is a plain 24-bit integer.\n" - << " unsigned NumToSkip = *Ptr++;\n" - << " NumToSkip |= (*Ptr++) << 8;\n" - << " NumToSkip |= (*Ptr++) << 16;\n" - << " // Check the predicate.\n" - << " bool Pred;\n" - << " if (!(Pred = checkDecoderPredicate(PIdx, Bits)))\n" - << " Ptr += NumToSkip;\n" - << " (void)Pred;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_CheckPredicate(\" << PIdx " - "<< \"): \"\n" - << " << (Pred ? \"PASS\\n\" : \"FAIL\\n\"));\n" - << "\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_Decode: {\n" - << " unsigned Len;\n" - << " // Decode the Opcode value.\n" - << " unsigned Opc = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len);\n" - << " Ptr += Len;\n" - << "\n" - << " MI.clear();\n" - << " MI.setOpcode(Opc);\n" - << " bool DecodeComplete;\n"; + OS << "\n makeUp(insn, Start + Len);"; + OS << R"( + uint64_t FieldValue = fieldFromInstruction(insn, Start, Len); + // Decode the field value. + unsigned PtrLen = 0; + uint64_t ExpectedValue = decodeULEB128(++Ptr, &PtrLen); + Ptr += PtrLen; + // NumToSkip is a plain 24-bit integer. + unsigned NumToSkip = *Ptr++; + NumToSkip |= (*Ptr++) << 8; + NumToSkip |= (*Ptr++) << 16; + + // If the actual and expected values don't match, skip. + if (ExpectedValue != FieldValue) + Ptr += NumToSkip; + LLVM_DEBUG(dbgs() << Loc << ": OPC_CheckField(" << Start << ", " + << Len << ", " << ExpectedValue << ", " << NumToSkip + << "): FieldValue = " << FieldValue << ", ExpectedValue = " + << ExpectedValue << ": " + << ((ExpectedValue == FieldValue) ? "PASS\n" : "FAIL\n")); + break; + } + case MCD::OPC_CheckPredicate: { + unsigned Len; + // Decode the Predicate Index value. + unsigned PIdx = decodeULEB128(++Ptr, &Len); + Ptr += Len; + // NumToSkip is a plain 24-bit integer. + unsigned NumToSkip = *Ptr++; + NumToSkip |= (*Ptr++) << 8; + NumToSkip |= (*Ptr++) << 16; + // Check the predicate. + bool Pred; + if (!(Pred = checkDecoderPredicate(PIdx, Bits))) + Ptr += NumToSkip; + (void)Pred; + LLVM_DEBUG(dbgs() << Loc << ": OPC_CheckPredicate(" << PIdx << "): " + << (Pred ? "PASS\n" : "FAIL\n")); + + break; + } + case MCD::OPC_Decode: { + unsigned Len; + // Decode the Opcode value. + unsigned Opc = decodeULEB128(++Ptr, &Len); + Ptr += Len; + unsigned DecodeIdx = decodeULEB128(Ptr, &Len); + Ptr += Len; + + MI.clear(); + MI.setOpcode(Opc); + bool DecodeComplete;)"; if (IsVarLenInst) { - OS << " Len = InstrLenTable[Opc];\n" - << " makeUp(insn, Len);\n"; + OS << "\n Len = InstrLenTable[Opc];\n" + << " makeUp(insn, Len);"; + } + OS << R"( + S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, DecodeComplete); + assert(DecodeComplete); + + LLVM_DEBUG(dbgs() << Loc << ": OPC_Decode: opcode " << Opc + << ", using decoder " << DecodeIdx << ": " + << (S != MCDisassembler::Fail ? "PASS" : "FAIL") << "\n"); + return S; + } + case MCD::OPC_TryDecode: { + unsigned Len; + // Decode the Opcode value. + unsigned Opc = decodeULEB128(++Ptr, &Len); + Ptr += Len; + unsigned DecodeIdx = decodeULEB128(Ptr, &Len); + Ptr += Len; + // NumToSkip is a plain 24-bit integer. + unsigned NumToSkip = *Ptr++; + NumToSkip |= (*Ptr++) << 8; + NumToSkip |= (*Ptr++) << 16; + + // Perform the decode operation. + MCInst TmpMI; + TmpMI.setOpcode(Opc); + bool DecodeComplete; + S = decodeToMCInst(S, DecodeIdx, insn, TmpMI, Address, DisAsm, DecodeComplete); + LLVM_DEBUG(dbgs() << Loc << ": OPC_TryDecode: opcode " << Opc + << ", using decoder " << DecodeIdx << ": "); + + if (DecodeComplete) { + // Decoding complete. + LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? "PASS" : "FAIL") << "\n"); + MI = TmpMI; + return S; + } else { + assert(S == MCDisassembler::Fail); + // If the decoding was incomplete, skip. + Ptr += NumToSkip; + LLVM_DEBUG(dbgs() << "FAIL: continuing at " << (Ptr - DecodeTable) << "\n"); + // Reset decode status. This also drops a SoftFail status that could be + // set before the decode attempt. + S = MCDisassembler::Success; + } + break; + } + case MCD::OPC_SoftFail: { + // Decode the mask values. + unsigned Len; + uint64_t PositiveMask = decodeULEB128(++Ptr, &Len); + Ptr += Len; + uint64_t NegativeMask = decodeULEB128(Ptr, &Len); + Ptr += Len; + bool Fail = (insn & PositiveMask) != 0 || (~insn & NegativeMask) != 0; + if (Fail) + S = MCDisassembler::SoftFail; + LLVM_DEBUG(dbgs() << Loc << ": OPC_SoftFail: " << (Fail ? "FAIL\n" : "PASS\n")); + break; + } + case MCD::OPC_Fail: { + LLVM_DEBUG(dbgs() << Loc << ": OPC_Fail\n"); + return MCDisassembler::Fail; + } + } } - OS << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " - "DecodeComplete);\n" - << " assert(DecodeComplete);\n" - << "\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Decode: opcode \" << Opc\n" - << " << \", using decoder \" << DecodeIdx << \": \"\n" - << " << (S != MCDisassembler::Fail ? \"PASS\" : " - "\"FAIL\") << \"\\n\");\n" - << " return S;\n" - << " }\n" - << " case MCD::OPC_TryDecode: {\n" - << " unsigned Len;\n" - << " // Decode the Opcode value.\n" - << " unsigned Opc = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " unsigned DecodeIdx = decodeULEB128(Ptr, &Len);\n" - << " Ptr += Len;\n" - << " // NumToSkip is a plain 24-bit integer.\n" - << " unsigned NumToSkip = *Ptr++;\n" - << " NumToSkip |= (*Ptr++) << 8;\n" - << " NumToSkip |= (*Ptr++) << 16;\n" - << "\n" - << " // Perform the decode operation.\n" - << " MCInst TmpMI;\n" - << " TmpMI.setOpcode(Opc);\n" - << " bool DecodeComplete;\n" - << " S = decodeToMCInst(S, DecodeIdx, insn, TmpMI, Address, DisAsm, " - "DecodeComplete);\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_TryDecode: opcode \" << " - "Opc\n" - << " << \", using decoder \" << DecodeIdx << \": \");\n" - << "\n" - << " if (DecodeComplete) {\n" - << " // Decoding complete.\n" - << " LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? \"PASS\" : " - "\"FAIL\") << \"\\n\");\n" - << " MI = TmpMI;\n" - << " return S;\n" - << " } else {\n" - << " assert(S == MCDisassembler::Fail);\n" - << " // If the decoding was incomplete, skip.\n" - << " Ptr += NumToSkip;\n" - << " LLVM_DEBUG(dbgs() << \"FAIL: continuing at \" << (Ptr - " - "DecodeTable) << \"\\n\");\n" - << " // Reset decode status. This also drops a SoftFail status " - "that could be\n" - << " // set before the decode attempt.\n" - << " S = MCDisassembler::Success;\n" - << " }\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_SoftFail: {\n" - << " // Decode the mask values.\n" - << " unsigned Len;\n" - << " uint64_t PositiveMask = decodeULEB128(++Ptr, &Len);\n" - << " Ptr += Len;\n" - << " uint64_t NegativeMask = decodeULEB128(Ptr, &Len);\n" - << " Ptr += Len;\n" - << " bool Fail = (insn & PositiveMask) != 0 || (~insn & " - "NegativeMask) != 0;\n" - << " if (Fail)\n" - << " S = MCDisassembler::SoftFail;\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_SoftFail: \" << (Fail ? " - "\"FAIL\\n\" : \"PASS\\n\"));\n" - << " break;\n" - << " }\n" - << " case MCD::OPC_Fail: {\n" - << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Fail\\n\");\n" - << " return MCDisassembler::Fail;\n" - << " }\n" - << " }\n" - << " }\n" - << " llvm_unreachable(\"bogosity detected in disassembler state " - "machine!\");\n" - << "}\n\n"; + llvm_unreachable("bogosity detected in disassembler state machine!"); +} + +)"; } // Helper to propagate SoftFail status. Returns false if the status is Fail; @@ -2443,10 +2419,13 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS, // is correct to propagate the values of this enum; see comment on 'enum // DecodeStatus'.) static void emitCheck(formatted_raw_ostream &OS) { - OS << "static bool Check(DecodeStatus &Out, DecodeStatus In) {\n" - << " Out = static_cast<DecodeStatus>(Out & In);\n" - << " return Out != MCDisassembler::Fail;\n" - << "}\n\n"; + OS << R"( +static bool Check(DecodeStatus &Out, DecodeStatus In) { + Out = static_cast<DecodeStatus>(Out & In); + return Out != MCDisassembler::Fail; +} + +)"; } // Collect all HwModes referenced by the target for encoding purposes, @@ -2469,16 +2448,18 @@ collectHwModesReferencedForEncodings(const CodeGenHwModes &HWM, // Emits disassembler code for instruction decoding. void DecoderEmitter::run(raw_ostream &o) { formatted_raw_ostream OS(o); - OS << "#include \"llvm/MC/MCInst.h\"\n"; - OS << "#include \"llvm/MC/MCSubtargetInfo.h\"\n"; - OS << "#include \"llvm/Support/DataTypes.h\"\n"; - OS << "#include \"llvm/Support/Debug.h\"\n"; - OS << "#include \"llvm/Support/LEB128.h\"\n"; - OS << "#include \"llvm/Support/raw_ostream.h\"\n"; - OS << "#include \"llvm/TargetParser/SubtargetFeature.h\"\n"; - OS << "#include <assert.h>\n"; - OS << '\n'; - OS << "namespace llvm {\n\n"; + OS << R"( +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/SubtargetFeature.h" +#include <assert.h> + +namespace llvm { +)"; emitFieldFromInstruction(OS); emitInsertBits(OS); @@ -2533,9 +2514,9 @@ void DecoderEmitter::run(raw_ostream &o) { bool IsVarLenInst = Target.hasVariableLengthEncodings(); unsigned MaxInstLen = 0; - for (unsigned i = 0; i < NumberedEncodings.size(); ++i) { - const Record *EncodingDef = NumberedEncodings[i].EncodingDef; - const CodeGenInstruction *Inst = NumberedEncodings[i].Inst; + for (const auto &[NEI, NumberedEncoding] : enumerate(NumberedEncodings)) { + const Record *EncodingDef = NumberedEncoding.EncodingDef; + const CodeGenInstruction *Inst = NumberedEncoding.Inst; const Record *Def = Inst->TheDef; unsigned Size = EncodingDef->getValueAsInt("Size"); if (Def->getValueAsString("Namespace") == "TargetOpcode" || @@ -2546,7 +2527,7 @@ void DecoderEmitter::run(raw_ostream &o) { continue; } - if (i < NumberedInstructions.size()) + if (NEI < NumberedInstructions.size()) NumInstructions++; NumEncodings++; @@ -2556,19 +2537,19 @@ void DecoderEmitter::run(raw_ostream &o) { if (IsVarLenInst) InstrLen.resize(NumberedInstructions.size(), 0); - if (unsigned Len = populateInstruction(Target, *EncodingDef, *Inst, i, + if (unsigned Len = populateInstruction(Target, *EncodingDef, *Inst, NEI, Operands, IsVarLenInst)) { if (IsVarLenInst) { MaxInstLen = std::max(MaxInstLen, Len); - InstrLen[i] = Len; + InstrLen[NEI] = Len; } std::string DecoderNamespace = std::string(EncodingDef->getValueAsString("DecoderNamespace")); - if (!NumberedEncodings[i].HwModeName.empty()) + if (!NumberedEncoding.HwModeName.empty()) DecoderNamespace += - std::string("_") + NumberedEncodings[i].HwModeName.str(); + std::string("_") + NumberedEncoding.HwModeName.str(); OpcMap[std::pair(DecoderNamespace, Size)].emplace_back( - i, Target.getInstrIntValue(Def)); + NEI, Target.getInstrIntValue(Def)); } else { NumEncodingsOmitted++; } |