diff options
author | Sergei Barannikov <barannikov88@gmail.com> | 2025-08-22 01:37:47 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-08-22 01:37:47 +0300 |
commit | c74afaac6c9bbf61ef1d9c3ef264affc37cb2009 (patch) | |
tree | 164d9011105705c8117e28893bc4e24e90307f94 /llvm/utils/TableGen/DecoderEmitter.cpp | |
parent | a3ed96b899baddd4865f1ef09f01a83da011db5c (diff) | |
download | llvm-c74afaac6c9bbf61ef1d9c3ef264affc37cb2009.zip llvm-c74afaac6c9bbf61ef1d9c3ef264affc37cb2009.tar.gz llvm-c74afaac6c9bbf61ef1d9c3ef264affc37cb2009.tar.bz2 |
[TableGen][DecoderEmitter] Use KnownBits for filters/encodings (NFCI) (#154691)
`KnownBits` is faster and smaller than `std::vector<BitValue>`.
It is also more convenient to use.
Diffstat (limited to 'llvm/utils/TableGen/DecoderEmitter.cpp')
-rw-r--r-- | llvm/utils/TableGen/DecoderEmitter.cpp | 242 |
1 files changed, 86 insertions, 156 deletions
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index dfd42bd..4bd9b5f 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -34,6 +34,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/KnownBits.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" @@ -101,6 +102,22 @@ STATISTIC(NumEncodingsOmitted, "Number of encodings omitted"); static unsigned getNumToSkipInBytes() { return LargeTable ? 3 : 2; } +/// Similar to KnownBits::print(), but allows you to specify a character to use +/// to print unknown bits. +static void printKnownBits(raw_ostream &OS, const KnownBits &Bits, + char Unknown) { + for (unsigned I = Bits.getBitWidth(); I--;) { + if (Bits.Zero[I] && Bits.One[I]) + OS << '!'; + else if (Bits.Zero[I]) + OS << '0'; + else if (Bits.One[I]) + OS << '1'; + else + OS << Unknown; + } +} + namespace { struct EncodingField { @@ -312,66 +329,8 @@ public: StringRef PredicateNamespace; }; -// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system -// for a bit value. -// -// BIT_UNFILTERED is used as the init value for a filter position. It is used -// only for filter processings. -struct BitValue { - enum bit_value_t : uint8_t { - BIT_FALSE, // '0' - BIT_TRUE, // '1' - BIT_UNSET, // '?', printed as '_' - BIT_UNFILTERED // unfiltered, printed as '.' - }; - - BitValue(bit_value_t V) : V(V) {} - explicit BitValue(const Init *Init) { - if (const auto *Bit = dyn_cast<BitInit>(Init)) - V = Bit->getValue() ? BIT_TRUE : BIT_FALSE; - else - V = BIT_UNSET; - } - BitValue(const BitsInit &Bits, unsigned Idx) : BitValue(Bits.getBit(Idx)) {} - - bool isSet() const { return V == BIT_TRUE || V == BIT_FALSE; } - bool isUnset() const { return V == BIT_UNSET; } - std::optional<uint64_t> getValue() const { - if (isSet()) - return static_cast<uint64_t>(V); - return std::nullopt; - } - - // For printing a bit value. - operator StringRef() const { - switch (V) { - case BIT_FALSE: - return "0"; - case BIT_TRUE: - return "1"; - case BIT_UNSET: - return "_"; - case BIT_UNFILTERED: - return "."; - } - llvm_unreachable("Unknow bit value"); - } - - bool operator==(bit_value_t Other) const { return Other == V; } - bool operator!=(bit_value_t Other) const { return Other != V; } - -private: - bit_value_t V; -}; - } // end anonymous namespace -// Prints the bit value for each position. -static void dumpBits(raw_ostream &OS, const BitsInit &Bits, unsigned BitWidth) { - for (const Init *Bit : reverse(Bits.getBits().take_front(BitWidth))) - OS << BitValue(Bit); -} - static const BitsInit &getBitsField(const Record &Def, StringRef FieldName) { const RecordVal *RV = Def.getValue(FieldName); if (const BitsInit *Bits = dyn_cast<BitsInit>(RV->getValue())) @@ -393,27 +352,6 @@ static const BitsInit &getBitsField(const Record &Def, StringRef FieldName) { return *BitsInit::get(Def.getRecords(), Bits); } -// Representation of the instruction to work on. -typedef std::vector<BitValue> insn_t; - -/// Extracts a NumBits long field from Insn, starting from StartBit. -/// Returns the value of the field if all bits are well-known, -/// otherwise std::nullopt. -static std::optional<uint64_t> -fieldFromInsn(const insn_t &Insn, unsigned StartBit, unsigned NumBits) { - uint64_t Field = 0; - - for (unsigned BitIndex = 0; BitIndex < NumBits; ++BitIndex) { - if (Insn[StartBit + BitIndex] == BitValue::BIT_UNSET) - return std::nullopt; - - if (Insn[StartBit + BitIndex] == BitValue::BIT_TRUE) - Field = Field | (1ULL << BitIndex); - } - - return Field; -} - namespace { class FilterChooser; @@ -552,8 +490,8 @@ protected: std::unique_ptr<Filter> BestFilter; // Array of bit values passed down from our parent. - // Set to all BIT_UNFILTERED's for Parent == NULL. - std::vector<BitValue> FilterBitValues; + // Set to all unknown for Parent == nullptr. + KnownBits FilterBits; // Links to the FilterChooser above us in the decoding tree. const FilterChooser *Parent; @@ -574,19 +512,18 @@ public: FilterChooser(ArrayRef<InstructionEncoding> Encodings, ArrayRef<unsigned> EncodingIDs, unsigned BW, const DecoderEmitter *E) - : Encodings(Encodings), EncodingIDs(EncodingIDs), - FilterBitValues(BW, BitValue::BIT_UNFILTERED), Parent(nullptr), - BitWidth(BW), Emitter(E) { + : Encodings(Encodings), EncodingIDs(EncodingIDs), FilterBits(BW), + Parent(nullptr), BitWidth(BW), Emitter(E) { doFilter(); } FilterChooser(ArrayRef<InstructionEncoding> Encodings, ArrayRef<unsigned> EncodingIDs, - const std::vector<BitValue> &ParentFilterBitValues, - const FilterChooser &parent) + const KnownBits &ParentFilterBits, const FilterChooser &parent) : Encodings(Encodings), EncodingIDs(EncodingIDs), - FilterBitValues(ParentFilterBitValues), Parent(&parent), + FilterBits(ParentFilterBits), Parent(&parent), BitWidth(parent.BitWidth), Emitter(parent.Emitter) { + assert(!FilterBits.hasConflict() && "Broken filter"); doFilter(); } @@ -596,11 +533,10 @@ public: unsigned getBitWidth() const { return BitWidth; } protected: - // Populates the insn given the uid. - insn_t insnWithID(unsigned EncodingID) const { + KnownBits getMandatoryEncodingBits(unsigned EncodingID) const { const Record *EncodingDef = Encodings[EncodingID].getRecord(); const BitsInit &Bits = getBitsField(*EncodingDef, "Inst"); - insn_t Insn(std::max(BitWidth, Bits.getNumBits()), BitValue::BIT_UNSET); + KnownBits Insn(std::max(BitWidth, Bits.getNumBits())); // 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. @@ -609,31 +545,34 @@ protected: 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 && BitValue(*SFBits, i) == BitValue::BIT_TRUE) - Insn[i] = BitValue::BIT_UNSET; - else - Insn[i] = BitValue(Bits, i); + if (SFBits) { + const auto *B = dyn_cast<BitInit>(SFBits->getBit(i)); + if (B && B->getValue()) + continue; + } + if (const auto *B = dyn_cast<BitInit>(Bits.getBit(i))) { + if (B->getValue()) + Insn.One.setBit(i); + else + Insn.Zero.setBit(i); + } } return Insn; } - /// dumpFilterArray - dumpFilterArray prints out debugging info for the given - /// filter array as a series of chars. - void dumpFilterArray(raw_ostream &OS, ArrayRef<BitValue> Filter) const; - /// dumpStack - dumpStack traverses the filter chooser chain and calls /// dumpFilterArray on each filter chooser up to the top level one. void dumpStack(raw_ostream &OS, indent Indent) const; - bool PositionFiltered(unsigned Idx) const { - return FilterBitValues[Idx].isSet(); + bool isPositionFiltered(unsigned Idx) const { + return FilterBits.Zero[Idx] || FilterBits.One[Idx]; } // Calculates the island(s) needed to decode the instruction. // This returns a list of undecoded bits of an instructions, for example, // Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be // decoded bits in order to verify that the instruction matches the Opcode. - std::vector<Island> getIslands(const insn_t &Insn) const; + std::vector<Island> getIslands(const KnownBits &EncodingBits) const; // Emits code to check the Predicates member of an instruction are true. // Returns true if predicate matches were emitted, false otherwise. @@ -711,15 +650,15 @@ Filter::Filter(const FilterChooser &owner, unsigned startBit, unsigned numBits) for (unsigned EncodingID : Owner.EncodingIDs) { // Populates the insn given the uid. - insn_t Insn = Owner.insnWithID(EncodingID); + KnownBits EncodingBits = Owner.getMandatoryEncodingBits(EncodingID); // Scans the segment for possibly well-specified encoding bits. - std::optional<uint64_t> Field = fieldFromInsn(Insn, StartBit, NumBits); + KnownBits FieldBits = EncodingBits.extractBits(NumBits, StartBit); - if (Field) { + if (FieldBits.isConstant()) { // The encoding bits are well-known. Lets add the uid of the // instruction into the bucket keyed off the constant field value. - FilteredIDs[*Field].push_back(EncodingID); + FilteredIDs[FieldBits.getConstant().getZExtValue()].push_back(EncodingID); ++NumFiltered; } else { // Some of the encoding bit(s) are unspecified. This contributes to @@ -740,16 +679,14 @@ Filter::Filter(const FilterChooser &owner, unsigned startBit, unsigned numBits) // match the remaining undecoded encoding bits against the singleton. void Filter::recurse() { // Starts by inheriting our parent filter chooser's filter bit values. - std::vector<BitValue> BitValueArray(Owner.FilterBitValues); + KnownBits FilterBits = Owner.FilterBits; + assert(FilterBits.extractBits(NumBits, StartBit).isUnknown()); if (!VariableIDs.empty()) { - for (unsigned bitIndex = 0; bitIndex < NumBits; ++bitIndex) - BitValueArray[StartBit + bitIndex] = BitValue::BIT_UNFILTERED; - // Delegates to an inferior filter chooser for further processing on this // group of instructions whose segment values are variable. VariableFC = std::make_unique<FilterChooser>(Owner.Encodings, VariableIDs, - BitValueArray, Owner); + FilterBits, Owner); } // No need to recurse for a singleton filtered instruction. @@ -761,17 +698,15 @@ void Filter::recurse() { // Otherwise, create sub choosers. for (const auto &[FilterVal, EncodingIDs] : FilteredIDs) { - // Marks all the segment positions with either BIT_TRUE or BIT_FALSE. - for (unsigned bitIndex = 0; bitIndex < NumBits; ++bitIndex) - BitValueArray[StartBit + bitIndex] = FilterVal & (1ULL << bitIndex) - ? BitValue::BIT_TRUE - : BitValue::BIT_FALSE; + // Create a new filter by inserting the field bits into the parent filter. + APInt FieldBits(NumBits, FilterVal); + FilterBits.insertBits(KnownBits::makeConstant(FieldBits), StartBit); // Delegates to an inferior filter chooser for further processing on this // category of instructions. FilterChooserMap.try_emplace( FilterVal, std::make_unique<FilterChooser>(Owner.Encodings, EncodingIDs, - BitValueArray, Owner)); + FilterBits, Owner)); } } @@ -1147,21 +1082,13 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS, OS << "}\n"; } -/// dumpFilterArray - dumpFilterArray prints out debugging info for the given -/// filter array as a series of chars. -void FilterChooser::dumpFilterArray(raw_ostream &OS, - ArrayRef<BitValue> Filter) const { - for (unsigned bitIndex = BitWidth; bitIndex > 0; bitIndex--) - OS << Filter[bitIndex - 1]; -} - /// dumpStack - dumpStack traverses the filter chooser chain and calls /// dumpFilterArray on each filter chooser up to the top level one. void FilterChooser::dumpStack(raw_ostream &OS, indent Indent) const { if (Parent) Parent->dumpStack(OS, Indent); OS << Indent; - dumpFilterArray(OS, FilterBitValues); + printKnownBits(OS, FilterBits, '.'); OS << '\n'; } @@ -1170,7 +1097,7 @@ void FilterChooser::dumpStack(raw_ostream &OS, indent Indent) const { // Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be // decoded bits in order to verify that the instruction matches the Opcode. std::vector<FilterChooser::Island> -FilterChooser::getIslands(const insn_t &Insn) const { +FilterChooser::getIslands(const KnownBits &EncodingBits) const { std::vector<Island> Islands; uint64_t FieldVal; unsigned StartBit; @@ -1181,28 +1108,29 @@ FilterChooser::getIslands(const insn_t &Insn) const { unsigned State = 0; for (unsigned i = 0; i < BitWidth; ++i) { - std::optional<uint64_t> Val = Insn[i].getValue(); - bool Filtered = PositionFiltered(i); + bool IsKnown = EncodingBits.Zero[i] || EncodingBits.One[i]; + bool Filtered = isPositionFiltered(i); switch (State) { default: llvm_unreachable("Unreachable code!"); case 0: case 1: - if (Filtered || !Val) { + if (Filtered || !IsKnown) { State = 1; // Still in Water } else { State = 2; // Into the Island StartBit = i; - FieldVal = *Val; + FieldVal = static_cast<uint64_t>(EncodingBits.One[i]); } break; case 2: - if (Filtered || !Val) { + if (Filtered || !IsKnown) { State = 1; // Into the Water Islands.push_back({StartBit, i - StartBit, FieldVal}); } else { State = 2; // Still in Island - FieldVal |= *Val << (i - StartBit); + FieldVal |= static_cast<uint64_t>(EncodingBits.One[i]) + << (i - StartBit); } break; } @@ -1419,19 +1347,11 @@ void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo, APInt PositiveMask(BitWidth, 0ULL); APInt NegativeMask(BitWidth, 0ULL); for (unsigned i = 0; i < BitWidth; ++i) { - BitValue B(*SFBits, i); - BitValue IB(*InstBits, i); - - if (B != BitValue::BIT_TRUE) + if (!isa<BitInit>(SFBits->getBit(i)) || + !cast<BitInit>(SFBits->getBit(i))->getValue()) continue; - if (IB == BitValue::BIT_FALSE) { - // The bit is meant to be false, so emit a check to see if it is true. - PositiveMask.setBit(i); - } else if (IB == BitValue::BIT_TRUE) { - // The bit is meant to be true, so emit a check to see if it is false. - NegativeMask.setBit(i); - } else { + if (!isa<BitInit>(InstBits->getBit(i))) { // The bit is not set; this must be an error! errs() << "SoftFail Conflict: bit SoftFail{" << i << "} in " << Encodings[EncodingID].getName() << " is set but Inst{" << i @@ -1440,6 +1360,15 @@ void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo, << " (1/0 - not '?') in Inst\n"; return; } + + bool IB = cast<BitInit>(InstBits->getBit(i))->getValue(); + if (!IB) { + // The bit is meant to be false, so emit a check to see if it is true. + PositiveMask.setBit(i); + } else { + // The bit is meant to be true, so emit a check to see if it is false. + NegativeMask.setBit(i); + } } bool NeedPositiveMask = PositiveMask.getBoolValue(); @@ -1456,10 +1385,10 @@ void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo, // Emits table entries to decode the singleton. void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo, unsigned EncodingID) const { - insn_t Insn = insnWithID(EncodingID); + KnownBits EncodingBits = getMandatoryEncodingBits(EncodingID); // Look for islands of undecoded bits of the singleton. - std::vector<Island> Islands = getIslands(Insn); + std::vector<Island> Islands = getIslands(EncodingBits); // Emit the predicate table entry if one is needed. emitPredicateTableEntry(TableInfo, EncodingID); @@ -1559,10 +1488,10 @@ bool FilterChooser::filterProcessor(ArrayRef<bitAttr_t> BitAttrs, assert(EncodingIDs.size() == 3); for (unsigned EncodingID : EncodingIDs) { - insn_t Insn = insnWithID(EncodingID); + KnownBits EncodingBits = getMandatoryEncodingBits(EncodingID); // Look for islands of undecoded bits of any instruction. - std::vector<Island> Islands = getIslands(Insn); + std::vector<Island> Islands = getIslands(EncodingBits); if (!Islands.empty()) { // Found an instruction with island(s). Now just assign a filter. runSingleFilter(Islands[0].StartBit, Islands[0].NumBits); @@ -1742,28 +1671,29 @@ void FilterChooser::doFilter() { SmallVector<bitAttr_t, 128> BitAttrs(BitWidth, ATTR_NONE); // FILTERED bit positions provide no entropy and are not worthy of pursuing. - // Filter::recurse() set either BIT_TRUE or BIT_FALSE for each position. + // Filter::recurse() set either 1 or 0 for each position. for (unsigned BitIndex = 0; BitIndex < BitWidth; ++BitIndex) - if (FilterBitValues[BitIndex].isSet()) + if (isPositionFiltered(BitIndex)) BitAttrs[BitIndex] = ATTR_FILTERED; for (unsigned EncodingID : EncodingIDs) { - insn_t EncodingBits = insnWithID(EncodingID); + KnownBits EncodingBits = getMandatoryEncodingBits(EncodingID); for (unsigned BitIndex = 0; BitIndex < BitWidth; ++BitIndex) { + bool IsKnown = EncodingBits.Zero[BitIndex] || EncodingBits.One[BitIndex]; switch (BitAttrs[BitIndex]) { case ATTR_NONE: - if (EncodingBits[BitIndex] == BitValue::BIT_UNSET) - BitAttrs[BitIndex] = ATTR_ALL_UNSET; - else + if (IsKnown) BitAttrs[BitIndex] = ATTR_ALL_SET; + else + BitAttrs[BitIndex] = ATTR_ALL_UNSET; break; case ATTR_ALL_SET: - if (EncodingBits[BitIndex] == BitValue::BIT_UNSET) + if (!IsKnown) BitAttrs[BitIndex] = ATTR_MIXED; break; case ATTR_ALL_UNSET: - if (EncodingBits[BitIndex] != BitValue::BIT_UNSET) + if (IsKnown) BitAttrs[BitIndex] = ATTR_MIXED; break; case ATTR_MIXED: @@ -1804,7 +1734,7 @@ void FilterChooser::doFilter() { for (unsigned EncodingID : EncodingIDs) { const InstructionEncoding &Enc = Encodings[EncodingID]; errs() << Indent; - dumpBits(errs(), getBitsField(*Enc.getRecord(), "Inst"), BitWidth); + printKnownBits(errs(), getMandatoryEncodingBits(EncodingID), '_'); errs() << " " << Enc.getName() << '\n'; } PrintFatalError("Decoding conflict encountered"); |