[llvm] [TableGen][DecoderEmitter] Calculate encoding bits once (NFC) (PR #154026)
Sergei Barannikov via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 21 15:47:50 PDT 2025
https://github.com/s-barannikov updated https://github.com/llvm/llvm-project/pull/154026
>From a8bce78119a000c1b16a2eb7f536718e05d310f2 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Thu, 21 Aug 2025 10:57:28 +0300
Subject: [PATCH] [TableGen][DecoderEmitter] Calculate encoding bits once (NFC)
`insnWithID` is called multiple times for the same encoding ID.
Call it once and store the result in `NumberedEncodings`.
Also, give the method a more meaningful name.
---
llvm/utils/TableGen/DecoderEmitter.cpp | 160 ++++++++++++++-----------
1 file changed, 93 insertions(+), 67 deletions(-)
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 4bd9b5fa6b569..4630c95b6818a 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -157,8 +157,10 @@ class InstructionEncoding {
/// The name of this encoding (for debugging purposes).
std::string Name;
- /// The size of this encoding, in bits.
- unsigned BitWidth;
+ /// Known bits of this encoding.
+ KnownBits EncodingBits;
+
+ APInt SoftFailBits;
/// The name of the function to use for decoding. May be an empty string,
/// meaning the decoder is generated.
@@ -186,7 +188,12 @@ class InstructionEncoding {
StringRef getName() const { return Name; }
/// Returns the size of this encoding, in bits.
- unsigned getBitWidth() const { return BitWidth; }
+ unsigned getBitWidth() const { return EncodingBits.getBitWidth(); }
+
+ /// Returns the known bits of this encoding.
+ const KnownBits &getKnownBits() const { return EncodingBits; }
+
+ const APInt &getSoftFailBits() const { return SoftFailBits; }
/// Returns the name of the function to use for decoding, or an empty string
/// if the decoder is generated.
@@ -200,6 +207,9 @@ class InstructionEncoding {
ArrayRef<OperandInfo> getOperands() const { return Operands; }
private:
+ void parseVarLenEncoding(const VarLenInst &VLI);
+ void parseFixedLenEncoding(const BitsInit &Bits);
+
void parseVarLenOperands(const VarLenInst &VLI);
void parseFixedLenOperands(const BitsInit &Bits);
};
@@ -331,27 +341,6 @@ class DecoderEmitter {
} // end anonymous namespace
-static const BitsInit &getBitsField(const Record &Def, StringRef FieldName) {
- const RecordVal *RV = Def.getValue(FieldName);
- if (const BitsInit *Bits = dyn_cast<BitsInit>(RV->getValue()))
- return *Bits;
-
- // Handle variable length instructions.
- VarLenInst VLI(cast<DagInit>(RV->getValue()), RV);
- SmallVector<const Init *, 16> Bits;
-
- for (const auto &SI : VLI) {
- if (const BitsInit *BI = dyn_cast<BitsInit>(SI.Value))
- llvm::append_range(Bits, BI->getBits());
- else if (const BitInit *BI = dyn_cast<BitInit>(SI.Value))
- Bits.push_back(BI);
- else
- Bits.append(SI.BitWidth, UnsetInit::get(Def.getRecords()));
- }
-
- return *BitsInit::get(Def.getRecords(), Bits);
-}
-
namespace {
class FilterChooser;
@@ -534,30 +523,14 @@ class FilterChooser {
protected:
KnownBits getMandatoryEncodingBits(unsigned EncodingID) const {
- const Record *EncodingDef = Encodings[EncodingID].getRecord();
- const BitsInit &Bits = getBitsField(*EncodingDef, "Inst");
- 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.
- //
- // This is used for marking UNPREDICTABLE instructions in the ARM world.
- 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) {
- 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;
+ const InstructionEncoding &Encoding = Encodings[EncodingID];
+ KnownBits EncodingBits = Encoding.getKnownBits();
+ // Clear all bits that are allowed to change according to SoftFail mask.
+ EncodingBits.Zero &= ~Encoding.getSoftFailBits();
+ EncodingBits.One &= ~Encoding.getSoftFailBits();
+ // Truncate or extend with unknown bits according to the filter bit width.
+ // FIXME: We should stop doing this.
+ return EncodingBits.anyextOrTrunc(BitWidth);
}
/// dumpStack - dumpStack traverses the filter chooser chain and calls
@@ -1336,22 +1309,26 @@ void FilterChooser::emitPredicateTableEntry(DecoderTableInfo &TableInfo,
void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo,
unsigned EncodingID) const {
- const Record *EncodingDef = Encodings[EncodingID].getRecord();
- const RecordVal *RV = EncodingDef->getValue("SoftFail");
- const BitsInit *SFBits = RV ? dyn_cast<BitsInit>(RV->getValue()) : nullptr;
+ const InstructionEncoding &Encoding = Encodings[EncodingID];
+ const KnownBits &InstBits = Encoding.getKnownBits();
+ const APInt &SFBits = Encoding.getSoftFailBits();
- if (!SFBits)
+ if (SFBits.isZero())
return;
- const BitsInit *InstBits = EncodingDef->getValueAsBitsInit("Inst");
APInt PositiveMask(BitWidth, 0ULL);
APInt NegativeMask(BitWidth, 0ULL);
for (unsigned i = 0; i < BitWidth; ++i) {
- if (!isa<BitInit>(SFBits->getBit(i)) ||
- !cast<BitInit>(SFBits->getBit(i))->getValue())
+ if (!SFBits[i])
continue;
- if (!isa<BitInit>(InstBits->getBit(i))) {
+ if (InstBits.Zero[i]) {
+ // The bit is meant to be false, so emit a check to see if it is true.
+ PositiveMask.setBit(i);
+ } else if (InstBits.One[i]) {
+ // The bit is meant to be true, so emit a check to see if it is false.
+ NegativeMask.setBit(i);
+ } else {
// 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
@@ -1360,15 +1337,6 @@ 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();
@@ -1797,6 +1765,63 @@ OperandInfo getOpInfo(const Record *TypeRecord) {
return OperandInfo(findOperandDecoderMethod(TypeRecord), HasCompleteDecoder);
}
+void InstructionEncoding::parseVarLenEncoding(const VarLenInst &VLI) {
+ EncodingBits = KnownBits(VLI.size());
+ SoftFailBits = APInt(VLI.size(), 0);
+
+ unsigned I = 0;
+ for (const EncodingSegment &S : VLI) {
+ if (const auto *SegmentBits = dyn_cast<BitsInit>(S.Value)) {
+ for (const Init *V : SegmentBits->getBits()) {
+ if (const auto *B = dyn_cast<BitInit>(V)) {
+ if (B->getValue())
+ EncodingBits.One.setBit(I);
+ else
+ EncodingBits.Zero.setBit(I);
+ }
+ ++I;
+ }
+ } else if (const auto *B = dyn_cast<BitInit>(S.Value)) {
+ if (B->getValue())
+ EncodingBits.One.setBit(I);
+ else
+ EncodingBits.Zero.setBit(I);
+ ++I;
+ } else {
+ I += S.BitWidth;
+ }
+ }
+ assert(I == VLI.size());
+}
+
+void InstructionEncoding::parseFixedLenEncoding(const BitsInit &Bits) {
+ EncodingBits = KnownBits(Bits.getNumBits());
+ SoftFailBits = APInt(Bits.getNumBits(), 0);
+
+ for (auto [I, V] : enumerate(Bits.getBits())) {
+ if (const auto *B = dyn_cast<BitInit>(V)) {
+ if (B->getValue())
+ EncodingBits.One.setBit(I);
+ else
+ EncodingBits.Zero.setBit(I);
+ }
+ }
+
+ // Parse SoftFail field.
+ if (const RecordVal *SoftFailField = EncodingDef->getValue("SoftFail")) {
+ if (const auto *SFBits = dyn_cast<BitsInit>(SoftFailField->getValue())) {
+ for (auto [I, V] : enumerate(SFBits->getBits())) {
+ if (const auto *B = dyn_cast<BitInit>(V)) {
+ if (B->getValue()) {
+ assert(EncodingBits.Zero[I] || EncodingBits.One[I]);
+ SoftFailBits.setBit(I);
+ }
+ }
+ }
+ }
+ }
+}
+
void InstructionEncoding::parseVarLenOperands(const VarLenInst &VLI) {
SmallVector<int> TiedTo;
@@ -2025,13 +2050,13 @@ InstructionEncoding::InstructionEncoding(const Record *EncodingDef,
const RecordVal *InstField = EncodingDef->getValue("Inst");
if (const auto *DI = dyn_cast<DagInit>(InstField->getValue())) {
VarLenInst VLI(DI, InstField);
- BitWidth = VLI.size();
+ parseVarLenEncoding(VLI);
// If the encoding has a custom decoder, don't bother parsing the operands.
if (DecoderMethod.empty())
parseVarLenOperands(VLI);
} else {
const auto *BI = cast<BitsInit>(InstField->getValue());
- BitWidth = BI->getNumBits();
+ parseFixedLenEncoding(*BI);
// If the encoding has a custom decoder, don't bother parsing the operands.
if (DecoderMethod.empty())
parseFixedLenOperands(*BI);
@@ -2346,6 +2371,7 @@ static bool isValidEncoding(const Record *EncodingDef) {
return false;
// At least one of the encoding bits must be complete (not '?').
+ // FIXME: This should take SoftFail field into account.
return !InstInit->allInComplete();
}
More information about the llvm-commits
mailing list