[llvm] [TableGen] Extract InstructionEncoding class into a separate file (NFC) (PR #158505)
Sergei Barannikov via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 14 12:42:48 PDT 2025
https://github.com/s-barannikov updated https://github.com/llvm/llvm-project/pull/158505
>From eedef0f978fde3e1237fdfcc9dd68fd6a606da65 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sun, 14 Sep 2025 22:10:49 +0300
Subject: [PATCH 1/3] Move IgnoreNonDecodableOperands check out of
addOneOperandFields
---
llvm/utils/TableGen/DecoderEmitter.cpp | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index a8a9036a1a7f4..bfcddd134c887 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -159,6 +159,8 @@ struct EncodingField {
};
struct OperandInfo {
+ StringRef Name;
+ bool HasNoEncoding = false;
std::vector<EncodingField> Fields;
std::string Decoder;
bool HasCompleteDecoder;
@@ -621,6 +623,7 @@ class DecoderTableBuilder {
private:
void emitBinaryParser(raw_ostream &OS, indent Indent,
+ const InstructionEncoding &Encoding,
const OperandInfo &OpInfo) const;
void emitDecoder(raw_ostream &OS, indent Indent, unsigned EncodingID) const;
@@ -1089,7 +1092,18 @@ FilterChooser::getIslands(const KnownBits &EncodingBits) const {
}
void DecoderTableBuilder::emitBinaryParser(raw_ostream &OS, indent Indent,
+ const InstructionEncoding &Encoding,
const OperandInfo &OpInfo) const {
+ if (OpInfo.HasNoEncoding) {
+ // If an operand has no encoding, the old behavior is to not decode it
+ // automatically and let the target do it. This is error-prone, so the
+ // new behavior is to report an error.
+ if (!IgnoreNonDecodableOperands)
+ PrintError(Encoding.getRecord()->getLoc(),
+ "could not find field for operand '" + OpInfo.Name + "'");
+ return;
+ }
+
// Special case for 'bits<0>'.
if (OpInfo.Fields.empty() && !OpInfo.InitValue) {
if (IgnoreNonDecodableOperands)
@@ -1154,7 +1168,7 @@ void DecoderTableBuilder::emitDecoder(raw_ostream &OS, indent Indent,
}
for (const OperandInfo &Op : Encoding.getOperands())
- emitBinaryParser(OS, Indent, Op);
+ emitBinaryParser(OS, Indent, Encoding, Op);
}
unsigned DecoderTableBuilder::getDecoderIndex(unsigned EncodingID) const {
@@ -1903,6 +1917,8 @@ static void addOneOperandFields(const Record *EncodingDef,
std::map<StringRef, StringRef> &TiedNames,
const Record *OpRec, StringRef OpName,
OperandInfo &OpInfo) {
+ OpInfo.Name = OpName;
+
// Find a field with the operand's name.
const RecordVal *OpEncodingField = EncodingDef->getValue(OpName);
@@ -1911,13 +1927,9 @@ static void addOneOperandFields(const Record *EncodingDef,
if (auto I = TiedNames.find(OpName); I != TiedNames.end())
OpEncodingField = EncodingDef->getValue(I->second);
- // If still no luck, the old behavior is to not decode this operand
- // automatically and let the target do it. This is error-prone, so
- // the new behavior is to report an error.
+ // If still no luck, we're done with this operand.
if (!OpEncodingField) {
- if (!IgnoreNonDecodableOperands)
- PrintError(EncodingDef->getLoc(),
- "could not find field for operand '" + OpName + "'");
+ OpInfo.HasNoEncoding = true;
return;
}
}
>From 9917199d1ab74ec9c276f98217b7a5280fd306cb Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sun, 14 Sep 2025 22:02:59 +0300
Subject: [PATCH 2/3] [TableGen] Extract InstructionEncoding class into a
separate file (NFC)
---
llvm/utils/TableGen/Common/CMakeLists.txt | 1 +
.../TableGen/Common/InstructionEncoding.cpp | 429 ++++++++++++++
.../TableGen/Common/InstructionEncoding.h | 150 +++++
llvm/utils/TableGen/DecoderEmitter.cpp | 535 +-----------------
4 files changed, 581 insertions(+), 534 deletions(-)
create mode 100644 llvm/utils/TableGen/Common/InstructionEncoding.cpp
create mode 100644 llvm/utils/TableGen/Common/InstructionEncoding.h
diff --git a/llvm/utils/TableGen/Common/CMakeLists.txt b/llvm/utils/TableGen/Common/CMakeLists.txt
index 7342156980f35..66279a3ed3755 100644
--- a/llvm/utils/TableGen/Common/CMakeLists.txt
+++ b/llvm/utils/TableGen/Common/CMakeLists.txt
@@ -29,6 +29,7 @@ add_llvm_library(LLVMTableGenCommon STATIC OBJECT EXCLUDE_FROM_ALL DISABLE_LLVM_
CodeGenTarget.cpp
DAGISelMatcher.cpp
InfoByHwMode.cpp
+ InstructionEncoding.cpp
OptEmitter.cpp
PredicateExpander.cpp
SubtargetFeatureInfo.cpp
diff --git a/llvm/utils/TableGen/Common/InstructionEncoding.cpp b/llvm/utils/TableGen/Common/InstructionEncoding.cpp
new file mode 100644
index 0000000000000..22163e1898333
--- /dev/null
+++ b/llvm/utils/TableGen/Common/InstructionEncoding.cpp
@@ -0,0 +1,429 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "InstructionEncoding.h"
+#include "CodeGenInstruction.h"
+#include "VarLenCodeEmitterGen.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/TableGen/Error.h"
+
+using namespace llvm;
+
+static std::string findOperandDecoderMethod(const Record *Record) {
+ std::string Decoder;
+
+ const RecordVal *DecoderString = Record->getValue("DecoderMethod");
+ const StringInit *String =
+ DecoderString ? dyn_cast<StringInit>(DecoderString->getValue()) : nullptr;
+ if (String) {
+ Decoder = String->getValue().str();
+ if (!Decoder.empty())
+ return Decoder;
+ }
+
+ if (Record->isSubClassOf("RegisterOperand"))
+ // Allows use of a DecoderMethod in referenced RegisterClass if set.
+ return findOperandDecoderMethod(Record->getValueAsDef("RegClass"));
+
+ if (Record->isSubClassOf("RegisterClass")) {
+ Decoder = "Decode" + Record->getName().str() + "RegisterClass";
+ } else if (Record->isSubClassOf("PointerLikeRegClass")) {
+ Decoder = "DecodePointerLikeRegClass" +
+ utostr(Record->getValueAsInt("RegClassKind"));
+ }
+
+ return Decoder;
+}
+
+static OperandInfo getOpInfo(const Record *TypeRecord) {
+ const RecordVal *HasCompleteDecoderVal =
+ TypeRecord->getValue("hasCompleteDecoder");
+ const BitInit *HasCompleteDecoderBit =
+ HasCompleteDecoderVal
+ ? dyn_cast<BitInit>(HasCompleteDecoderVal->getValue())
+ : nullptr;
+ bool HasCompleteDecoder =
+ HasCompleteDecoderBit ? HasCompleteDecoderBit->getValue() : true;
+
+ return OperandInfo(findOperandDecoderMethod(TypeRecord), HasCompleteDecoder);
+}
+
+void InstructionEncoding::parseVarLenEncoding(const VarLenInst &VLI) {
+ InstBits = KnownBits(VLI.size());
+ SoftFailMask = 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 &RecordInstBits) {
+ // For fixed length instructions, sometimes the `Inst` field specifies more
+ // bits than the actual size of the instruction, which is specified in `Size`.
+ // In such cases, we do some basic validation and drop the upper bits.
+ unsigned BitWidth = EncodingDef->getValueAsInt("Size") * 8;
+ unsigned InstNumBits = RecordInstBits.getNumBits();
+
+ // Returns true if all bits in `Bits` are zero or unset.
+ auto CheckAllZeroOrUnset = [&](ArrayRef<const Init *> Bits,
+ const RecordVal *Field) {
+ bool AllZeroOrUnset = llvm::all_of(Bits, [](const Init *Bit) {
+ if (const auto *BI = dyn_cast<BitInit>(Bit))
+ return !BI->getValue();
+ return isa<UnsetInit>(Bit);
+ });
+ if (AllZeroOrUnset)
+ return;
+ PrintNote([Field](raw_ostream &OS) { Field->print(OS); });
+ PrintFatalError(EncodingDef, Twine(Name) + ": Size is " + Twine(BitWidth) +
+ " bits, but " + Field->getName() +
+ " bits beyond that are not zero/unset");
+ };
+
+ if (InstNumBits < BitWidth)
+ PrintFatalError(EncodingDef, Twine(Name) + ": Size is " + Twine(BitWidth) +
+ " bits, but Inst specifies only " +
+ Twine(InstNumBits) + " bits");
+
+ if (InstNumBits > BitWidth) {
+ // Ensure that all the bits beyond 'Size' are 0 or unset (i.e., carry no
+ // actual encoding).
+ ArrayRef<const Init *> UpperBits =
+ RecordInstBits.getBits().drop_front(BitWidth);
+ const RecordVal *InstField = EncodingDef->getValue("Inst");
+ CheckAllZeroOrUnset(UpperBits, InstField);
+ }
+
+ ArrayRef<const Init *> ActiveInstBits =
+ RecordInstBits.getBits().take_front(BitWidth);
+ InstBits = KnownBits(BitWidth);
+ SoftFailMask = APInt(BitWidth, 0);
+
+ // Parse Inst field.
+ for (auto [I, V] : enumerate(ActiveInstBits)) {
+ if (const auto *B = dyn_cast<BitInit>(V)) {
+ if (B->getValue())
+ InstBits.One.setBit(I);
+ else
+ InstBits.Zero.setBit(I);
+ }
+ }
+
+ // Parse SoftFail field.
+ const RecordVal *SoftFailField = EncodingDef->getValue("SoftFail");
+ if (!SoftFailField)
+ return;
+
+ const auto *SFBits = dyn_cast<BitsInit>(SoftFailField->getValue());
+ if (!SFBits || SFBits->getNumBits() != InstNumBits) {
+ PrintNote(EncodingDef->getLoc(), "in record");
+ PrintFatalError(SoftFailField,
+ formatv("SoftFail field, if defined, must be "
+ "of the same type as Inst, which is bits<{}>",
+ InstNumBits));
+ }
+
+ if (InstNumBits > BitWidth) {
+ // Ensure that all upper bits of `SoftFail` are 0 or unset.
+ ArrayRef<const Init *> UpperBits = SFBits->getBits().drop_front(BitWidth);
+ CheckAllZeroOrUnset(UpperBits, SoftFailField);
+ }
+
+ ArrayRef<const Init *> ActiveSFBits = SFBits->getBits().take_front(BitWidth);
+ for (auto [I, V] : enumerate(ActiveSFBits)) {
+ 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));
+ }
+ SoftFailMask.setBit(I);
+ }
+ }
+}
+
+void InstructionEncoding::parseVarLenOperands(const VarLenInst &VLI) {
+ SmallVector<int> TiedTo;
+
+ for (const auto &[Idx, Op] : enumerate(Inst->Operands)) {
+ if (Op.MIOperandInfo && Op.MIOperandInfo->getNumArgs() > 0)
+ for (auto *Arg : Op.MIOperandInfo->getArgs())
+ Operands.push_back(getOpInfo(cast<DefInit>(Arg)->getDef()));
+ else
+ Operands.push_back(getOpInfo(Op.Rec));
+
+ int TiedReg = Op.getTiedRegister();
+ TiedTo.push_back(-1);
+ if (TiedReg != -1) {
+ TiedTo[Idx] = TiedReg;
+ TiedTo[TiedReg] = Idx;
+ }
+ }
+
+ unsigned CurrBitPos = 0;
+ for (const auto &EncodingSegment : VLI) {
+ unsigned Offset = 0;
+ StringRef OpName;
+
+ if (const StringInit *SI = dyn_cast<StringInit>(EncodingSegment.Value)) {
+ OpName = SI->getValue();
+ } else if (const DagInit *DI = dyn_cast<DagInit>(EncodingSegment.Value)) {
+ OpName = cast<StringInit>(DI->getArg(0))->getValue();
+ Offset = cast<IntInit>(DI->getArg(2))->getValue();
+ }
+
+ if (!OpName.empty()) {
+ auto OpSubOpPair = Inst->Operands.parseOperandName(OpName);
+ unsigned OpIdx = Inst->Operands.getFlattenedOperandNumber(OpSubOpPair);
+ Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset);
+ if (!EncodingSegment.CustomDecoder.empty())
+ Operands[OpIdx].Decoder = EncodingSegment.CustomDecoder.str();
+
+ int TiedReg = TiedTo[OpSubOpPair.first];
+ if (TiedReg != -1) {
+ unsigned OpIdx = Inst->Operands.getFlattenedOperandNumber(
+ {TiedReg, OpSubOpPair.second});
+ Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset);
+ }
+ }
+
+ CurrBitPos += EncodingSegment.BitWidth;
+ }
+}
+
+static void debugDumpRecord(const Record &Rec) {
+ // Dump the record, so we can see what's going on.
+ PrintNote([&Rec](raw_ostream &OS) {
+ OS << "Dumping record for previous error:\n";
+ OS << Rec;
+ });
+}
+
+/// For an operand field named OpName: populate OpInfo.InitValue with the
+/// constant-valued bit values, and OpInfo.Fields with the ranges of bits to
+/// insert from the decoded instruction.
+static void addOneOperandFields(const Record *EncodingDef,
+ const BitsInit &InstBits,
+ std::map<StringRef, StringRef> &TiedNames,
+ const Record *OpRec, StringRef OpName,
+ OperandInfo &OpInfo) {
+ OpInfo.Name = OpName;
+
+ // Find a field with the operand's name.
+ const RecordVal *OpEncodingField = EncodingDef->getValue(OpName);
+
+ // If there is no such field, try tied operand's name.
+ if (!OpEncodingField) {
+ if (auto I = TiedNames.find(OpName); I != TiedNames.end())
+ OpEncodingField = EncodingDef->getValue(I->second);
+
+ // If still no luck, we're done with this operand.
+ if (!OpEncodingField) {
+ OpInfo.HasNoEncoding = true;
+ return;
+ }
+ }
+
+ // Some or all bits of the operand may be required to be 0 or 1 depending
+ // on the instruction's encoding. Collect those bits.
+ if (const auto *OpBit = dyn_cast<BitInit>(OpEncodingField->getValue())) {
+ OpInfo.InitValue = OpBit->getValue();
+ return;
+ }
+ if (const auto *OpBits = dyn_cast<BitsInit>(OpEncodingField->getValue())) {
+ if (OpBits->getNumBits() == 0) {
+ if (OpInfo.Decoder.empty()) {
+ PrintError(EncodingDef->getLoc(), "operand '" + OpName + "' of type '" +
+ OpRec->getName() +
+ "' must have a decoder method");
+ }
+ return;
+ }
+ for (unsigned I = 0; I < OpBits->getNumBits(); ++I) {
+ if (const auto *OpBit = dyn_cast<BitInit>(OpBits->getBit(I)))
+ OpInfo.InitValue = OpInfo.InitValue.value_or(0) |
+ static_cast<uint64_t>(OpBit->getValue()) << I;
+ }
+ }
+
+ // Find out where the variable bits of the operand are encoded. The bits don't
+ // have to be consecutive or in ascending order. For example, an operand could
+ // be encoded as follows:
+ //
+ // 7 6 5 4 3 2 1 0
+ // {1, op{5}, op{2}, op{1}, 0, op{4}, op{3}, ?}
+ //
+ // In this example the operand is encoded in three segments:
+ //
+ // Base Width Offset
+ // op{2...1} 4 2 1
+ // op{4...3} 1 2 3
+ // op{5} 6 1 5
+ //
+ for (unsigned I = 0, J = 0; I != InstBits.getNumBits(); I = J) {
+ const VarInit *Var;
+ unsigned Offset = 0;
+ for (; J != InstBits.getNumBits(); ++J) {
+ const Init *BitJ = InstBits.getBit(J);
+ if (const auto *VBI = dyn_cast<VarBitInit>(BitJ)) {
+ Var = dyn_cast<VarInit>(VBI->getBitVar());
+ if (I == J)
+ Offset = VBI->getBitNum();
+ else if (VBI->getBitNum() != Offset + J - I)
+ break;
+ } else {
+ Var = dyn_cast<VarInit>(BitJ);
+ }
+ if (!Var ||
+ (Var->getName() != OpName && Var->getName() != TiedNames[OpName]))
+ break;
+ }
+ if (I == J)
+ ++J;
+ else
+ OpInfo.addField(I, J - I, Offset);
+ }
+}
+
+void InstructionEncoding::parseFixedLenOperands(const BitsInit &Bits) {
+ // Search for tied operands, so that we can correctly instantiate
+ // operands that are not explicitly represented in the encoding.
+ std::map<StringRef, StringRef> TiedNames;
+ for (const auto &Op : Inst->Operands) {
+ for (const auto &[J, CI] : enumerate(Op.Constraints)) {
+ if (!CI.isTied())
+ continue;
+ std::pair<unsigned, unsigned> SO =
+ Inst->Operands.getSubOperandNumber(CI.getTiedOperand());
+ StringRef TiedName = Inst->Operands[SO.first].SubOpNames[SO.second];
+ if (TiedName.empty())
+ TiedName = Inst->Operands[SO.first].Name;
+ StringRef MyName = Op.SubOpNames[J];
+ if (MyName.empty())
+ MyName = Op.Name;
+
+ TiedNames[MyName] = TiedName;
+ TiedNames[TiedName] = MyName;
+ }
+ }
+
+ // For each operand, see if we can figure out where it is encoded.
+ for (const CGIOperandList::OperandInfo &Op : Inst->Operands) {
+ // Lookup the decoder method and construct a new OperandInfo to hold our
+ // result.
+ OperandInfo OpInfo = getOpInfo(Op.Rec);
+
+ // If we have named sub-operands...
+ if (Op.MIOperandInfo && !Op.SubOpNames[0].empty()) {
+ // Then there should not be a custom decoder specified on the top-level
+ // type.
+ if (!OpInfo.Decoder.empty()) {
+ PrintError(EncodingDef,
+ "DecoderEmitter: operand \"" + Op.Name + "\" has type \"" +
+ Op.Rec->getName() +
+ "\" with a custom DecoderMethod, but also named "
+ "sub-operands.");
+ continue;
+ }
+
+ // Decode each of the sub-ops separately.
+ for (auto [SubOpName, SubOp] :
+ zip_equal(Op.SubOpNames, Op.MIOperandInfo->getArgs())) {
+ const Record *SubOpRec = cast<DefInit>(SubOp)->getDef();
+ OperandInfo SubOpInfo = getOpInfo(SubOpRec);
+ addOneOperandFields(EncodingDef, Bits, TiedNames, SubOpRec, SubOpName,
+ SubOpInfo);
+ Operands.push_back(std::move(SubOpInfo));
+ }
+ continue;
+ }
+
+ // Otherwise, if we have an operand with sub-operands, but they aren't
+ // named...
+ if (Op.MIOperandInfo && OpInfo.Decoder.empty()) {
+ // If we have sub-ops, we'd better have a custom decoder.
+ // (Otherwise we don't know how to populate them properly...)
+ if (Op.MIOperandInfo->getNumArgs()) {
+ PrintError(EncodingDef,
+ "DecoderEmitter: operand \"" + Op.Name +
+ "\" has non-empty MIOperandInfo, but doesn't "
+ "have a custom decoder!");
+ debugDumpRecord(*EncodingDef);
+ continue;
+ }
+ }
+
+ addOneOperandFields(EncodingDef, Bits, TiedNames, Op.Rec, Op.Name, OpInfo);
+ Operands.push_back(std::move(OpInfo));
+ }
+}
+
+InstructionEncoding::InstructionEncoding(const Record *EncodingDef,
+ const CodeGenInstruction *Inst)
+ : EncodingDef(EncodingDef), Inst(Inst) {
+ const Record *InstDef = Inst->TheDef;
+
+ // Give this encoding a name.
+ if (EncodingDef != InstDef)
+ Name = (EncodingDef->getName() + Twine(':')).str();
+ Name.append(InstDef->getName());
+
+ DecoderNamespace = EncodingDef->getValueAsString("DecoderNamespace");
+ DecoderMethod = EncodingDef->getValueAsString("DecoderMethod");
+ if (!DecoderMethod.empty())
+ HasCompleteDecoder = EncodingDef->getValueAsBit("hasCompleteDecoder");
+
+ const RecordVal *InstField = EncodingDef->getValue("Inst");
+ if (const auto *DI = dyn_cast<DagInit>(InstField->getValue())) {
+ VarLenInst VLI(DI, InstField);
+ 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());
+ parseFixedLenEncoding(*BI);
+ // If the encoding has a custom decoder, don't bother parsing the operands.
+ if (DecoderMethod.empty())
+ parseFixedLenOperands(*BI);
+ }
+
+ if (DecoderMethod.empty()) {
+ // A generated decoder is always successful if none of the operand
+ // decoders can fail (all are always successful).
+ HasCompleteDecoder = all_of(Operands, [](const OperandInfo &Op) {
+ // By default, a generated operand decoder is assumed to always succeed.
+ // This can be overridden by the user.
+ return Op.Decoder.empty() || Op.HasCompleteDecoder;
+ });
+ }
+}
diff --git a/llvm/utils/TableGen/Common/InstructionEncoding.h b/llvm/utils/TableGen/Common/InstructionEncoding.h
new file mode 100644
index 0000000000000..2fd195e17321a
--- /dev/null
+++ b/llvm/utils/TableGen/Common/InstructionEncoding.h
@@ -0,0 +1,150 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UTILS_TABLEGEN_INSTRUCTIONENCODING_H
+#define LLVM_UTILS_TABLEGEN_INSTRUCTIONENCODING_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/KnownBits.h"
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+class BitsInit;
+class CodeGenInstruction;
+class Record;
+class RecordVal;
+class VarLenInst;
+
+// Represents a span of bits in the instruction encoding that's based on a span
+// of bits in an operand's encoding.
+//
+// Width is the width of the span.
+// Base is the starting position of that span in the instruction encoding.
+// Offset if the starting position of that span in the operand's encoding.
+// That is, bits {Base + Width - 1, Base} in the instruction encoding form
+// bits {Offset + Width - 1, Offset} in the operands encoding.
+struct EncodingField {
+ unsigned Base, Width, Offset;
+ EncodingField(unsigned B, unsigned W, unsigned O)
+ : Base(B), Width(W), Offset(O) {}
+};
+
+struct OperandInfo {
+ StringRef Name;
+ bool HasNoEncoding = false;
+ std::vector<EncodingField> Fields;
+ std::string Decoder;
+ bool HasCompleteDecoder;
+ std::optional<uint64_t> InitValue;
+
+ OperandInfo(std::string D, bool HCD) : Decoder(D), HasCompleteDecoder(HCD) {}
+
+ void addField(unsigned Base, unsigned Width, unsigned Offset) {
+ Fields.emplace_back(Base, Width, Offset);
+ }
+
+ ArrayRef<EncodingField> fields() const { return Fields; }
+};
+
+/// Represents a parsed InstructionEncoding record or a record derived from it.
+class InstructionEncoding {
+ /// The Record this encoding originates from.
+ const Record *EncodingDef;
+
+ /// The instruction this encoding is for.
+ const CodeGenInstruction *Inst;
+
+ /// The name of this encoding (for debugging purposes).
+ std::string Name;
+
+ /// The namespace in which this encoding exists.
+ StringRef DecoderNamespace;
+
+ /// 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 SoftFailMask;
+
+ /// The name of the function to use for decoding. May be an empty string,
+ /// meaning the decoder is generated.
+ StringRef DecoderMethod;
+
+ /// Whether the custom decoding function always succeeds. If a custom decoder
+ /// function is specified, the value is taken from the target description,
+ /// otherwise it is inferred.
+ bool HasCompleteDecoder;
+
+ /// Information about the operands' contribution to this encoding.
+ SmallVector<OperandInfo, 16> Operands;
+
+public:
+ InstructionEncoding(const Record *EncodingDef,
+ const CodeGenInstruction *Inst);
+
+ /// Returns the Record this encoding originates from.
+ const Record *getRecord() const { return EncodingDef; }
+
+ /// Returns the instruction this encoding is for.
+ const CodeGenInstruction *getInstruction() const { return Inst; }
+
+ /// Returns the name of this encoding, for debugging purposes.
+ StringRef getName() const { return Name; }
+
+ /// Returns the namespace in which this encoding exists.
+ StringRef getDecoderNamespace() const { return DecoderNamespace; }
+
+ /// Returns the size of this encoding, in bits.
+ 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 &getSoftFailMask() const { return SoftFailMask; }
+
+ /// Returns the known bits of this encoding that must match for
+ /// successful decoding.
+ KnownBits getMandatoryBits() const {
+ KnownBits EncodingBits = InstBits;
+ // Mark all bits that are allowed to change according to SoftFail mask
+ // as unknown.
+ EncodingBits.Zero &= ~SoftFailMask;
+ EncodingBits.One &= ~SoftFailMask;
+ return EncodingBits;
+ }
+
+ /// Returns the name of the function to use for decoding, or an empty string
+ /// if the decoder is generated.
+ StringRef getDecoderMethod() const { return DecoderMethod; }
+
+ /// Returns whether the decoder (either generated or specified by the user)
+ /// always succeeds.
+ bool hasCompleteDecoder() const { return HasCompleteDecoder; }
+
+ /// Returns information about the operands' contribution to this encoding.
+ ArrayRef<OperandInfo> getOperands() const { return Operands; }
+
+private:
+ void parseVarLenEncoding(const VarLenInst &VLI);
+ void parseFixedLenEncoding(const BitsInit &RecordInstBits);
+
+ void parseVarLenOperands(const VarLenInst &VLI);
+ void parseFixedLenOperands(const BitsInit &Bits);
+};
+
+} // namespace llvm
+
+#endif // LLVM_UTILS_TABLEGEN_INSTRUCTIONENCODING_H
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index bfcddd134c887..8ff1c89f3699c 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -15,6 +15,7 @@
#include "Common/CodeGenInstruction.h"
#include "Common/CodeGenTarget.h"
#include "Common/InfoByHwMode.h"
+#include "Common/InstructionEncoding.h"
#include "Common/VarLenCodeEmitterGen.h"
#include "TableGenBackends.h"
#include "llvm/ADT/APInt.h"
@@ -144,126 +145,6 @@ static void printKnownBits(raw_ostream &OS, const KnownBits &Bits,
namespace {
-// Represents a span of bits in the instruction encoding that's based on a span
-// of bits in an operand's encoding.
-//
-// Width is the width of the span.
-// Base is the starting position of that span in the instruction encoding.
-// Offset if the starting position of that span in the operand's encoding.
-// That is, bits {Base + Width - 1, Base} in the instruction encoding form
-// bits {Offset + Width - 1, Offset} in the operands encoding.
-struct EncodingField {
- unsigned Base, Width, Offset;
- EncodingField(unsigned B, unsigned W, unsigned O)
- : Base(B), Width(W), Offset(O) {}
-};
-
-struct OperandInfo {
- StringRef Name;
- bool HasNoEncoding = false;
- std::vector<EncodingField> Fields;
- std::string Decoder;
- bool HasCompleteDecoder;
- std::optional<uint64_t> InitValue;
-
- OperandInfo(std::string D, bool HCD) : Decoder(D), HasCompleteDecoder(HCD) {}
-
- void addField(unsigned Base, unsigned Width, unsigned Offset) {
- Fields.emplace_back(Base, Width, Offset);
- }
-
- ArrayRef<EncodingField> fields() const { return Fields; }
-};
-
-/// Represents a parsed InstructionEncoding record or a record derived from it.
-class InstructionEncoding {
- /// The Record this encoding originates from.
- const Record *EncodingDef;
-
- /// The instruction this encoding is for.
- const CodeGenInstruction *Inst;
-
- /// The name of this encoding (for debugging purposes).
- std::string Name;
-
- /// The namespace in which this encoding exists.
- StringRef DecoderNamespace;
-
- /// 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 SoftFailMask;
-
- /// The name of the function to use for decoding. May be an empty string,
- /// meaning the decoder is generated.
- StringRef DecoderMethod;
-
- /// Whether the custom decoding function always succeeds. If a custom decoder
- /// function is specified, the value is taken from the target description,
- /// otherwise it is inferred.
- bool HasCompleteDecoder;
-
- /// Information about the operands' contribution to this encoding.
- SmallVector<OperandInfo, 16> Operands;
-
-public:
- InstructionEncoding(const Record *EncodingDef,
- const CodeGenInstruction *Inst);
-
- /// Returns the Record this encoding originates from.
- const Record *getRecord() const { return EncodingDef; }
-
- /// Returns the instruction this encoding is for.
- const CodeGenInstruction *getInstruction() const { return Inst; }
-
- /// Returns the name of this encoding, for debugging purposes.
- StringRef getName() const { return Name; }
-
- /// Returns the namespace in which this encoding exists.
- StringRef getDecoderNamespace() const { return DecoderNamespace; }
-
- /// Returns the size of this encoding, in bits.
- 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 &getSoftFailMask() const { return SoftFailMask; }
-
- /// Returns the known bits of this encoding that must match for
- /// successful decoding.
- KnownBits getMandatoryBits() const {
- KnownBits EncodingBits = InstBits;
- // Mark all bits that are allowed to change according to SoftFail mask
- // as unknown.
- EncodingBits.Zero &= ~SoftFailMask;
- EncodingBits.One &= ~SoftFailMask;
- return EncodingBits;
- }
-
- /// Returns the name of the function to use for decoding, or an empty string
- /// if the decoder is generated.
- StringRef getDecoderMethod() const { return DecoderMethod; }
-
- /// Returns whether the decoder (either generated or specified by the user)
- /// always succeeds.
- bool hasCompleteDecoder() const { return HasCompleteDecoder; }
-
- /// Returns information about the operands' contribution to this encoding.
- ArrayRef<OperandInfo> getOperands() const { return Operands; }
-
-private:
- void parseVarLenEncoding(const VarLenInst &VLI);
- void parseFixedLenEncoding(const BitsInit &RecordInstBits);
-
- void parseVarLenOperands(const VarLenInst &VLI);
- void parseFixedLenOperands(const BitsInit &Bits);
-};
-
/// Sorting predicate to sort encoding IDs by encoding width.
class LessEncodingIDByWidth {
ArrayRef<InstructionEncoding> Encodings;
@@ -1695,420 +1576,6 @@ void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) const {
}
}
-static std::string findOperandDecoderMethod(const Record *Record) {
- std::string Decoder;
-
- const RecordVal *DecoderString = Record->getValue("DecoderMethod");
- const StringInit *String =
- DecoderString ? dyn_cast<StringInit>(DecoderString->getValue()) : nullptr;
- if (String) {
- Decoder = String->getValue().str();
- if (!Decoder.empty())
- return Decoder;
- }
-
- if (Record->isSubClassOf("RegisterOperand"))
- // Allows use of a DecoderMethod in referenced RegisterClass if set.
- return findOperandDecoderMethod(Record->getValueAsDef("RegClass"));
-
- if (Record->isSubClassOf("RegisterClass")) {
- Decoder = "Decode" + Record->getName().str() + "RegisterClass";
- } else if (Record->isSubClassOf("PointerLikeRegClass")) {
- Decoder = "DecodePointerLikeRegClass" +
- utostr(Record->getValueAsInt("RegClassKind"));
- }
-
- return Decoder;
-}
-
-OperandInfo getOpInfo(const Record *TypeRecord) {
- const RecordVal *HasCompleteDecoderVal =
- TypeRecord->getValue("hasCompleteDecoder");
- const BitInit *HasCompleteDecoderBit =
- HasCompleteDecoderVal
- ? dyn_cast<BitInit>(HasCompleteDecoderVal->getValue())
- : nullptr;
- bool HasCompleteDecoder =
- HasCompleteDecoderBit ? HasCompleteDecoderBit->getValue() : true;
-
- return OperandInfo(findOperandDecoderMethod(TypeRecord), HasCompleteDecoder);
-}
-
-void InstructionEncoding::parseVarLenEncoding(const VarLenInst &VLI) {
- InstBits = KnownBits(VLI.size());
- SoftFailMask = 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 &RecordInstBits) {
- // For fixed length instructions, sometimes the `Inst` field specifies more
- // bits than the actual size of the instruction, which is specified in `Size`.
- // In such cases, we do some basic validation and drop the upper bits.
- unsigned BitWidth = EncodingDef->getValueAsInt("Size") * 8;
- unsigned InstNumBits = RecordInstBits.getNumBits();
-
- // Returns true if all bits in `Bits` are zero or unset.
- auto CheckAllZeroOrUnset = [&](ArrayRef<const Init *> Bits,
- const RecordVal *Field) {
- bool AllZeroOrUnset = llvm::all_of(Bits, [](const Init *Bit) {
- if (const auto *BI = dyn_cast<BitInit>(Bit))
- return !BI->getValue();
- return isa<UnsetInit>(Bit);
- });
- if (AllZeroOrUnset)
- return;
- PrintNote([Field](raw_ostream &OS) { Field->print(OS); });
- PrintFatalError(EncodingDef, Twine(Name) + ": Size is " + Twine(BitWidth) +
- " bits, but " + Field->getName() +
- " bits beyond that are not zero/unset");
- };
-
- if (InstNumBits < BitWidth)
- PrintFatalError(EncodingDef, Twine(Name) + ": Size is " + Twine(BitWidth) +
- " bits, but Inst specifies only " +
- Twine(InstNumBits) + " bits");
-
- if (InstNumBits > BitWidth) {
- // Ensure that all the bits beyond 'Size' are 0 or unset (i.e., carry no
- // actual encoding).
- ArrayRef<const Init *> UpperBits =
- RecordInstBits.getBits().drop_front(BitWidth);
- const RecordVal *InstField = EncodingDef->getValue("Inst");
- CheckAllZeroOrUnset(UpperBits, InstField);
- }
-
- ArrayRef<const Init *> ActiveInstBits =
- RecordInstBits.getBits().take_front(BitWidth);
- InstBits = KnownBits(BitWidth);
- SoftFailMask = APInt(BitWidth, 0);
-
- // Parse Inst field.
- for (auto [I, V] : enumerate(ActiveInstBits)) {
- if (const auto *B = dyn_cast<BitInit>(V)) {
- if (B->getValue())
- InstBits.One.setBit(I);
- else
- InstBits.Zero.setBit(I);
- }
- }
-
- // Parse SoftFail field.
- const RecordVal *SoftFailField = EncodingDef->getValue("SoftFail");
- if (!SoftFailField)
- return;
-
- const auto *SFBits = dyn_cast<BitsInit>(SoftFailField->getValue());
- if (!SFBits || SFBits->getNumBits() != InstNumBits) {
- PrintNote(EncodingDef->getLoc(), "in record");
- PrintFatalError(SoftFailField,
- formatv("SoftFail field, if defined, must be "
- "of the same type as Inst, which is bits<{}>",
- InstNumBits));
- }
-
- if (InstNumBits > BitWidth) {
- // Ensure that all upper bits of `SoftFail` are 0 or unset.
- ArrayRef<const Init *> UpperBits = SFBits->getBits().drop_front(BitWidth);
- CheckAllZeroOrUnset(UpperBits, SoftFailField);
- }
-
- ArrayRef<const Init *> ActiveSFBits = SFBits->getBits().take_front(BitWidth);
- for (auto [I, V] : enumerate(ActiveSFBits)) {
- 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));
- }
- SoftFailMask.setBit(I);
- }
- }
-}
-
-void InstructionEncoding::parseVarLenOperands(const VarLenInst &VLI) {
- SmallVector<int> TiedTo;
-
- for (const auto &[Idx, Op] : enumerate(Inst->Operands)) {
- if (Op.MIOperandInfo && Op.MIOperandInfo->getNumArgs() > 0)
- for (auto *Arg : Op.MIOperandInfo->getArgs())
- Operands.push_back(getOpInfo(cast<DefInit>(Arg)->getDef()));
- else
- Operands.push_back(getOpInfo(Op.Rec));
-
- int TiedReg = Op.getTiedRegister();
- TiedTo.push_back(-1);
- if (TiedReg != -1) {
- TiedTo[Idx] = TiedReg;
- TiedTo[TiedReg] = Idx;
- }
- }
-
- unsigned CurrBitPos = 0;
- for (const auto &EncodingSegment : VLI) {
- unsigned Offset = 0;
- StringRef OpName;
-
- if (const StringInit *SI = dyn_cast<StringInit>(EncodingSegment.Value)) {
- OpName = SI->getValue();
- } else if (const DagInit *DI = dyn_cast<DagInit>(EncodingSegment.Value)) {
- OpName = cast<StringInit>(DI->getArg(0))->getValue();
- Offset = cast<IntInit>(DI->getArg(2))->getValue();
- }
-
- if (!OpName.empty()) {
- auto OpSubOpPair = Inst->Operands.parseOperandName(OpName);
- unsigned OpIdx = Inst->Operands.getFlattenedOperandNumber(OpSubOpPair);
- Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset);
- if (!EncodingSegment.CustomDecoder.empty())
- Operands[OpIdx].Decoder = EncodingSegment.CustomDecoder.str();
-
- int TiedReg = TiedTo[OpSubOpPair.first];
- if (TiedReg != -1) {
- unsigned OpIdx = Inst->Operands.getFlattenedOperandNumber(
- {TiedReg, OpSubOpPair.second});
- Operands[OpIdx].addField(CurrBitPos, EncodingSegment.BitWidth, Offset);
- }
- }
-
- CurrBitPos += EncodingSegment.BitWidth;
- }
-}
-
-static void debugDumpRecord(const Record &Rec) {
- // Dump the record, so we can see what's going on.
- PrintNote([&Rec](raw_ostream &OS) {
- OS << "Dumping record for previous error:\n";
- OS << Rec;
- });
-}
-
-/// For an operand field named OpName: populate OpInfo.InitValue with the
-/// constant-valued bit values, and OpInfo.Fields with the ranges of bits to
-/// insert from the decoded instruction.
-static void addOneOperandFields(const Record *EncodingDef,
- const BitsInit &InstBits,
- std::map<StringRef, StringRef> &TiedNames,
- const Record *OpRec, StringRef OpName,
- OperandInfo &OpInfo) {
- OpInfo.Name = OpName;
-
- // Find a field with the operand's name.
- const RecordVal *OpEncodingField = EncodingDef->getValue(OpName);
-
- // If there is no such field, try tied operand's name.
- if (!OpEncodingField) {
- if (auto I = TiedNames.find(OpName); I != TiedNames.end())
- OpEncodingField = EncodingDef->getValue(I->second);
-
- // If still no luck, we're done with this operand.
- if (!OpEncodingField) {
- OpInfo.HasNoEncoding = true;
- return;
- }
- }
-
- // Some or all bits of the operand may be required to be 0 or 1 depending
- // on the instruction's encoding. Collect those bits.
- if (const auto *OpBit = dyn_cast<BitInit>(OpEncodingField->getValue())) {
- OpInfo.InitValue = OpBit->getValue();
- return;
- }
- if (const auto *OpBits = dyn_cast<BitsInit>(OpEncodingField->getValue())) {
- if (OpBits->getNumBits() == 0) {
- if (OpInfo.Decoder.empty()) {
- PrintError(EncodingDef->getLoc(), "operand '" + OpName + "' of type '" +
- OpRec->getName() +
- "' must have a decoder method");
- }
- return;
- }
- for (unsigned I = 0; I < OpBits->getNumBits(); ++I) {
- if (const auto *OpBit = dyn_cast<BitInit>(OpBits->getBit(I)))
- OpInfo.InitValue = OpInfo.InitValue.value_or(0) |
- static_cast<uint64_t>(OpBit->getValue()) << I;
- }
- }
-
- // Find out where the variable bits of the operand are encoded. The bits don't
- // have to be consecutive or in ascending order. For example, an operand could
- // be encoded as follows:
- //
- // 7 6 5 4 3 2 1 0
- // {1, op{5}, op{2}, op{1}, 0, op{4}, op{3}, ?}
- //
- // In this example the operand is encoded in three segments:
- //
- // Base Width Offset
- // op{2...1} 4 2 1
- // op{4...3} 1 2 3
- // op{5} 6 1 5
- //
- for (unsigned I = 0, J = 0; I != InstBits.getNumBits(); I = J) {
- const VarInit *Var;
- unsigned Offset = 0;
- for (; J != InstBits.getNumBits(); ++J) {
- const Init *BitJ = InstBits.getBit(J);
- if (const auto *VBI = dyn_cast<VarBitInit>(BitJ)) {
- Var = dyn_cast<VarInit>(VBI->getBitVar());
- if (I == J)
- Offset = VBI->getBitNum();
- else if (VBI->getBitNum() != Offset + J - I)
- break;
- } else {
- Var = dyn_cast<VarInit>(BitJ);
- }
- if (!Var ||
- (Var->getName() != OpName && Var->getName() != TiedNames[OpName]))
- break;
- }
- if (I == J)
- ++J;
- else
- OpInfo.addField(I, J - I, Offset);
- }
-}
-
-void InstructionEncoding::parseFixedLenOperands(const BitsInit &Bits) {
- // Search for tied operands, so that we can correctly instantiate
- // operands that are not explicitly represented in the encoding.
- std::map<StringRef, StringRef> TiedNames;
- for (const auto &Op : Inst->Operands) {
- for (const auto &[J, CI] : enumerate(Op.Constraints)) {
- if (!CI.isTied())
- continue;
- std::pair<unsigned, unsigned> SO =
- Inst->Operands.getSubOperandNumber(CI.getTiedOperand());
- StringRef TiedName = Inst->Operands[SO.first].SubOpNames[SO.second];
- if (TiedName.empty())
- TiedName = Inst->Operands[SO.first].Name;
- StringRef MyName = Op.SubOpNames[J];
- if (MyName.empty())
- MyName = Op.Name;
-
- TiedNames[MyName] = TiedName;
- TiedNames[TiedName] = MyName;
- }
- }
-
- // For each operand, see if we can figure out where it is encoded.
- for (const CGIOperandList::OperandInfo &Op : Inst->Operands) {
- // Lookup the decoder method and construct a new OperandInfo to hold our
- // result.
- OperandInfo OpInfo = getOpInfo(Op.Rec);
-
- // If we have named sub-operands...
- if (Op.MIOperandInfo && !Op.SubOpNames[0].empty()) {
- // Then there should not be a custom decoder specified on the top-level
- // type.
- if (!OpInfo.Decoder.empty()) {
- PrintError(EncodingDef,
- "DecoderEmitter: operand \"" + Op.Name + "\" has type \"" +
- Op.Rec->getName() +
- "\" with a custom DecoderMethod, but also named "
- "sub-operands.");
- continue;
- }
-
- // Decode each of the sub-ops separately.
- for (auto [SubOpName, SubOp] :
- zip_equal(Op.SubOpNames, Op.MIOperandInfo->getArgs())) {
- const Record *SubOpRec = cast<DefInit>(SubOp)->getDef();
- OperandInfo SubOpInfo = getOpInfo(SubOpRec);
- addOneOperandFields(EncodingDef, Bits, TiedNames, SubOpRec, SubOpName,
- SubOpInfo);
- Operands.push_back(std::move(SubOpInfo));
- }
- continue;
- }
-
- // Otherwise, if we have an operand with sub-operands, but they aren't
- // named...
- if (Op.MIOperandInfo && OpInfo.Decoder.empty()) {
- // If we have sub-ops, we'd better have a custom decoder.
- // (Otherwise we don't know how to populate them properly...)
- if (Op.MIOperandInfo->getNumArgs()) {
- PrintError(EncodingDef,
- "DecoderEmitter: operand \"" + Op.Name +
- "\" has non-empty MIOperandInfo, but doesn't "
- "have a custom decoder!");
- debugDumpRecord(*EncodingDef);
- continue;
- }
- }
-
- addOneOperandFields(EncodingDef, Bits, TiedNames, Op.Rec, Op.Name, OpInfo);
- Operands.push_back(std::move(OpInfo));
- }
-}
-
-InstructionEncoding::InstructionEncoding(const Record *EncodingDef,
- const CodeGenInstruction *Inst)
- : EncodingDef(EncodingDef), Inst(Inst) {
- const Record *InstDef = Inst->TheDef;
-
- // Give this encoding a name.
- if (EncodingDef != InstDef)
- Name = (EncodingDef->getName() + Twine(':')).str();
- Name.append(InstDef->getName());
-
- DecoderNamespace = EncodingDef->getValueAsString("DecoderNamespace");
- DecoderMethod = EncodingDef->getValueAsString("DecoderMethod");
- if (!DecoderMethod.empty())
- HasCompleteDecoder = EncodingDef->getValueAsBit("hasCompleteDecoder");
-
- const RecordVal *InstField = EncodingDef->getValue("Inst");
- if (const auto *DI = dyn_cast<DagInit>(InstField->getValue())) {
- VarLenInst VLI(DI, InstField);
- 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());
- parseFixedLenEncoding(*BI);
- // If the encoding has a custom decoder, don't bother parsing the operands.
- if (DecoderMethod.empty())
- parseFixedLenOperands(*BI);
- }
-
- if (DecoderMethod.empty()) {
- // A generated decoder is always successful if none of the operand
- // decoders can fail (all are always successful).
- HasCompleteDecoder = all_of(Operands, [](const OperandInfo &Op) {
- // By default, a generated operand decoder is assumed to always succeed.
- // This can be overridden by the user.
- return Op.Decoder.empty() || Op.HasCompleteDecoder;
- });
- }
-}
-
// emitDecodeInstruction - Emit the templated helper function
// decodeInstruction().
static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst,
>From 3af64b8fcc23efa0e4fc5e1c560365d70bfb2245 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sun, 14 Sep 2025 22:42:29 +0300
Subject: [PATCH 3/3] Fix header guard
---
llvm/utils/TableGen/Common/InstructionEncoding.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/utils/TableGen/Common/InstructionEncoding.h b/llvm/utils/TableGen/Common/InstructionEncoding.h
index 2fd195e17321a..40c89dd4c6f2d 100644
--- a/llvm/utils/TableGen/Common/InstructionEncoding.h
+++ b/llvm/utils/TableGen/Common/InstructionEncoding.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_UTILS_TABLEGEN_INSTRUCTIONENCODING_H
-#define LLVM_UTILS_TABLEGEN_INSTRUCTIONENCODING_H
+#ifndef LLVM_UTILS_TABLEGEN_COMMON_INSTRUCTIONENCODING_H
+#define LLVM_UTILS_TABLEGEN_COMMON_INSTRUCTIONENCODING_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
@@ -147,4 +147,4 @@ class InstructionEncoding {
} // namespace llvm
-#endif // LLVM_UTILS_TABLEGEN_INSTRUCTIONENCODING_H
+#endif // LLVM_UTILS_TABLEGEN_COMMON_INSTRUCTIONENCODING_H
More information about the llvm-commits
mailing list