aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen/DecoderEmitter.cpp
diff options
context:
space:
mode:
authorSergei Barannikov <barannikov88@gmail.com>2025-08-22 05:19:35 +0300
committerGitHub <noreply@github.com>2025-08-22 05:19:35 +0300
commit418fb5030149b5fe46d4541c4037883a04c7f3e3 (patch)
tree7f8f0be76861800165c21d68d3939cb17b1ce4bf /llvm/utils/TableGen/DecoderEmitter.cpp
parent273b6f2911d9786c2236a99ad417b4aa4fe8f93e (diff)
downloadllvm-418fb5030149b5fe46d4541c4037883a04c7f3e3.zip
llvm-418fb5030149b5fe46d4541c4037883a04c7f3e3.tar.gz
llvm-418fb5030149b5fe46d4541c4037883a04c7f3e3.tar.bz2
[TableGen][DecoderEmitter] Calculate encoding bits once (#154026)
Parse the `Inst` and `SoftField` fields once and store them in `InstructionEncoding` so that we don't parse them every time `getMandatoryEncodingBits()` is called.
Diffstat (limited to 'llvm/utils/TableGen/DecoderEmitter.cpp')
-rw-r--r--llvm/utils/TableGen/DecoderEmitter.cpp174
1 files changed, 104 insertions, 70 deletions
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 740035a..0afd918 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -157,8 +157,13 @@ 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. This is the value of the `Inst` field
+ /// with any variable references replaced with '?'.
+ KnownBits InstBits;
+
+ /// Mask of bits that should be considered unknown during decoding.
+ /// This is the value of the `SoftFail` field.
+ APInt SoftFailBits;
/// The name of the function to use for decoding. May be an empty string,
/// meaning the decoder is generated.
@@ -186,7 +191,13 @@ public:
StringRef getName() const { return Name; }
/// Returns the size of this encoding, in bits.
- unsigned getBitWidth() const { return BitWidth; }
+ unsigned getBitWidth() const { return InstBits.getBitWidth(); }
+
+ /// Returns the known bits of this encoding.
+ const KnownBits &getInstBits() const { return InstBits; }
+
+ /// Returns a mask of bits that should be considered unknown during decoding.
+ 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 +211,9 @@ public:
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 +345,6 @@ public:
} // 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 +527,14 @@ public:
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.getInstBits();
+ // 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,36 +1313,23 @@ 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.getInstBits();
+ 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))) {
- // 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
- << "} is unset!\n"
- << " - You can only mark a bit as SoftFail if it is fully defined"
- << " (1/0 - not '?') in Inst\n";
- return;
- }
-
- bool IB = cast<BitInit>(InstBits->getBit(i))->getValue();
- if (!IB) {
+ 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 {
+ } 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);
}
@@ -1797,6 +1761,75 @@ OperandInfo getOpInfo(const Record *TypeRecord) {
return OperandInfo(findOperandDecoderMethod(TypeRecord), HasCompleteDecoder);
}
+void InstructionEncoding::parseVarLenEncoding(const VarLenInst &VLI) {
+ InstBits = KnownBits(VLI.size());
+ SoftFailBits = APInt(VLI.size(), 0);
+
+ // Parse Inst field.
+ 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())
+ InstBits.One.setBit(I);
+ else
+ InstBits.Zero.setBit(I);
+ }
+ ++I;
+ }
+ } else if (const auto *B = dyn_cast<BitInit>(S.Value)) {
+ if (B->getValue())
+ InstBits.One.setBit(I);
+ else
+ InstBits.Zero.setBit(I);
+ ++I;
+ } else {
+ I += S.BitWidth;
+ }
+ }
+ assert(I == VLI.size());
+}
+
+void InstructionEncoding::parseFixedLenEncoding(const BitsInit &Bits) {
+ InstBits = KnownBits(Bits.getNumBits());
+ SoftFailBits = APInt(Bits.getNumBits(), 0);
+
+ // Parse Inst field.
+ for (auto [I, V] : enumerate(Bits.getBits())) {
+ if (const auto *B = dyn_cast<BitInit>(V)) {
+ if (B->getValue())
+ InstBits.One.setBit(I);
+ else
+ InstBits.Zero.setBit(I);
+ }
+ }
+
+ // Parse SoftFail field.
+ if (const RecordVal *SoftFailField = EncodingDef->getValue("SoftFail")) {
+ const auto *SFBits = dyn_cast<BitsInit>(SoftFailField->getValue());
+ if (!SFBits || SFBits->getNumBits() != Bits.getNumBits()) {
+ PrintNote(EncodingDef->getLoc(), "in record");
+ PrintFatalError(SoftFailField,
+ formatv("SoftFail field, if defined, must be "
+ "of the same type as Inst, which is bits<{}>",
+ Bits.getNumBits()));
+ }
+ for (auto [I, V] : enumerate(SFBits->getBits())) {
+ if (const auto *B = dyn_cast<BitInit>(V); B && B->getValue()) {
+ if (!InstBits.Zero[I] && !InstBits.One[I]) {
+ PrintNote(EncodingDef->getLoc(), "in record");
+ PrintError(SoftFailField,
+ formatv("SoftFail{{{0}} = 1 requires Inst{{{0}} "
+ "to be fully defined (0 or 1, not '?')",
+ I));
+ }
+ SoftFailBits.setBit(I);
+ }
+ }
+ }
+}
+
void InstructionEncoding::parseVarLenOperands(const VarLenInst &VLI) {
SmallVector<int> TiedTo;
@@ -2025,13 +2058,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 +2379,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();
}