aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen/DecoderEmitter.cpp
diff options
context:
space:
mode:
authorSergei Barannikov <barannikov88@gmail.com>2025-08-22 01:37:47 +0300
committerGitHub <noreply@github.com>2025-08-22 01:37:47 +0300
commitc74afaac6c9bbf61ef1d9c3ef264affc37cb2009 (patch)
tree164d9011105705c8117e28893bc4e24e90307f94 /llvm/utils/TableGen/DecoderEmitter.cpp
parenta3ed96b899baddd4865f1ef09f01a83da011db5c (diff)
downloadllvm-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.cpp242
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");