aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen/DecoderEmitter.cpp
diff options
context:
space:
mode:
authorSergei Barannikov <barannikov88@gmail.com>2025-08-17 23:13:48 +0300
committerGitHub <noreply@github.com>2025-08-17 20:13:48 +0000
commita10773c8646d482e8747ca37d5a51523505ffbb7 (patch)
tree8d62d82ab429f8bda597a98770abf3d110106af7 /llvm/utils/TableGen/DecoderEmitter.cpp
parent6cfedea492c11cd46f03cfad76a638bf73de40f4 (diff)
downloadllvm-a10773c8646d482e8747ca37d5a51523505ffbb7.zip
llvm-a10773c8646d482e8747ca37d5a51523505ffbb7.tar.gz
llvm-a10773c8646d482e8747ca37d5a51523505ffbb7.tar.bz2
[TableGen][DecoderEmitter] Remove EncodingIDAndOpcode struct (NFC) (#154028)
Most of the time we don't need instruction opcode. There is no need to carry it around all the time, we can easily get it by other means. Rename affected variables accordingly. Part of an effort to simplify DecoderEmitter code.
Diffstat (limited to 'llvm/utils/TableGen/DecoderEmitter.cpp')
-rw-r--r--llvm/utils/TableGen/DecoderEmitter.cpp123
1 files changed, 55 insertions, 68 deletions
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 11d06d1..b6d4363c 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -215,16 +215,6 @@ struct EncodingAndInst {
: EncodingDef(EncodingDef), Inst(Inst), HwModeName(HwModeName) {}
};
-struct EncodingIDAndOpcode {
- unsigned EncodingID;
- unsigned Opcode;
-
- EncodingIDAndOpcode() : EncodingID(0), Opcode(0) {}
- EncodingIDAndOpcode(unsigned EncodingID, unsigned Opcode)
- : EncodingID(EncodingID), Opcode(Opcode) {}
-};
-
-using EncodingIDsVec = std::vector<EncodingIDAndOpcode>;
using NamespacesHwModesMap = std::map<std::string, std::set<StringRef>>;
class DecoderEmitter {
@@ -235,11 +225,13 @@ public:
DecoderEmitter(const RecordKeeper &R, StringRef PredicateNamespace)
: RK(R), Target(R), PredicateNamespace(PredicateNamespace) {}
+ const CodeGenTarget &getTarget() const { return Target; }
+
// Emit the decoder state machine table. Returns a mask of MCD decoder ops
// that were emitted.
unsigned emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
unsigned BitWidth, StringRef Namespace,
- const EncodingIDsVec &EncodingIDs) const;
+ ArrayRef<unsigned> EncodingIDs) const;
void emitInstrLenTable(formatted_raw_ostream &OS,
ArrayRef<unsigned> InstrLen) const;
void emitPredicateFunction(formatted_raw_ostream &OS,
@@ -416,10 +408,10 @@ protected:
unsigned NumBits; // number of bits to filter
// Map of well-known segment value to the set of uid's with that value.
- std::map<uint64_t, std::vector<EncodingIDAndOpcode>> FilteredInstructions;
+ std::map<uint64_t, std::vector<unsigned>> FilteredIDs;
// Set of uid's with non-constant segment values.
- std::vector<EncodingIDAndOpcode> VariableInstructions;
+ std::vector<unsigned> VariableIDs;
// Map of well-known segment value to its delegate.
std::map<uint64_t, std::unique_ptr<const FilterChooser>> FilterChooserMap;
@@ -435,9 +427,9 @@ public:
unsigned getNumFiltered() const { return NumFiltered; }
- EncodingIDAndOpcode getSingletonOpc() const {
+ unsigned getSingletonEncodingID() const {
assert(NumFiltered == 1);
- return FilteredInstructions.begin()->second.front();
+ return FilteredIDs.begin()->second.front();
}
// Return the filter chooser for the group of instructions without constant
@@ -498,9 +490,7 @@ protected:
ArrayRef<EncodingAndInst> AllInstructions;
// Vector of uid's for this filter chooser to work on.
- // The first member of the pair is the opcode id being decoded, the second is
- // the opcode id that should be emitted.
- ArrayRef<EncodingIDAndOpcode> Opcodes;
+ ArrayRef<unsigned> EncodingIDs;
// Lookup table for the operand decoding of instructions.
const std::map<unsigned, std::vector<OperandInfo>> &Operands;
@@ -528,22 +518,20 @@ protected:
};
public:
- FilterChooser(ArrayRef<EncodingAndInst> Insts,
- ArrayRef<EncodingIDAndOpcode> IDs,
+ FilterChooser(ArrayRef<EncodingAndInst> Insts, ArrayRef<unsigned> EncodingIDs,
const std::map<unsigned, std::vector<OperandInfo>> &Ops,
unsigned BW, const DecoderEmitter *E)
- : AllInstructions(Insts), Opcodes(IDs), Operands(Ops),
+ : AllInstructions(Insts), EncodingIDs(EncodingIDs), Operands(Ops),
FilterBitValues(BW, BitValue::BIT_UNFILTERED), Parent(nullptr),
BitWidth(BW), Emitter(E) {
doFilter();
}
- FilterChooser(ArrayRef<EncodingAndInst> Insts,
- ArrayRef<EncodingIDAndOpcode> IDs,
+ FilterChooser(ArrayRef<EncodingAndInst> Insts, ArrayRef<unsigned> EncodingIDs,
const std::map<unsigned, std::vector<OperandInfo>> &Ops,
const std::vector<BitValue> &ParentFilterBitValues,
const FilterChooser &parent)
- : AllInstructions(Insts), Opcodes(IDs), Operands(Ops),
+ : AllInstructions(Insts), EncodingIDs(EncodingIDs), Operands(Ops),
FilterBitValues(ParentFilterBitValues), Parent(&parent),
BitWidth(parent.BitWidth), Emitter(parent.Emitter) {
doFilter();
@@ -608,7 +596,7 @@ protected:
// Emits table entries to decode the singleton.
void emitSingletonTableEntry(DecoderTableInfo &TableInfo,
- EncodingIDAndOpcode Opc) const;
+ unsigned EncodingID) const;
// Emits code to decode the singleton, and then to decode the rest.
void emitSingletonTableEntry(DecoderTableInfo &TableInfo,
@@ -656,8 +644,8 @@ public:
Filter::Filter(Filter &&f)
: Owner(f.Owner), StartBit(f.StartBit), NumBits(f.NumBits),
- FilteredInstructions(std::move(f.FilteredInstructions)),
- VariableInstructions(std::move(f.VariableInstructions)),
+ FilteredIDs(std::move(f.FilteredIDs)),
+ VariableIDs(std::move(f.VariableIDs)),
FilterChooserMap(std::move(f.FilterChooserMap)),
NumFiltered(f.NumFiltered) {}
@@ -667,9 +655,9 @@ Filter::Filter(const FilterChooser &owner, unsigned startBit, unsigned numBits)
NumFiltered = 0;
- for (const auto &OpcPair : Owner.Opcodes) {
+ for (unsigned EncodingID : Owner.EncodingIDs) {
// Populates the insn given the uid.
- insn_t Insn = Owner.insnWithID(OpcPair.EncodingID);
+ insn_t Insn = Owner.insnWithID(EncodingID);
// Scans the segment for possibly well-specified encoding bits.
std::optional<uint64_t> Field = fieldFromInsn(Insn, StartBit, NumBits);
@@ -677,16 +665,16 @@ Filter::Filter(const FilterChooser &owner, unsigned startBit, unsigned numBits)
if (Field) {
// The encoding bits are well-known. Lets add the uid of the
// instruction into the bucket keyed off the constant field value.
- FilteredInstructions[*Field].push_back(OpcPair);
+ FilteredIDs[*Field].push_back(EncodingID);
++NumFiltered;
} else {
// Some of the encoding bit(s) are unspecified. This contributes to
// one additional member of "Variable" instructions.
- VariableInstructions.push_back(OpcPair);
+ VariableIDs.push_back(EncodingID);
}
}
- assert((FilteredInstructions.size() + VariableInstructions.size() > 0) &&
+ assert((FilteredIDs.size() + VariableIDs.size() > 0) &&
"Filter returns no instruction categories");
}
@@ -700,7 +688,7 @@ void Filter::recurse() {
// Starts by inheriting our parent filter chooser's filter bit values.
std::vector<BitValue> BitValueArray(Owner.FilterBitValues);
- if (!VariableInstructions.empty()) {
+ if (!VariableIDs.empty()) {
for (unsigned bitIndex = 0; bitIndex < NumBits; ++bitIndex)
BitValueArray[StartBit + bitIndex] = BitValue::BIT_UNFILTERED;
@@ -708,9 +696,8 @@ void Filter::recurse() {
// group of instructions whose segment values are variable.
FilterChooserMap.try_emplace(
NO_FIXED_SEGMENTS_SENTINEL,
- std::make_unique<FilterChooser>(Owner.AllInstructions,
- VariableInstructions, Owner.Operands,
- BitValueArray, Owner));
+ std::make_unique<FilterChooser>(Owner.AllInstructions, VariableIDs,
+ Owner.Operands, BitValueArray, Owner));
}
// No need to recurse for a singleton filtered instruction.
@@ -721,7 +708,7 @@ void Filter::recurse() {
}
// Otherwise, create sub choosers.
- for (const auto &Inst : FilteredInstructions) {
+ for (const auto &Inst : FilteredIDs) {
// Marks all the segment positions with either BIT_TRUE or BIT_FALSE.
for (unsigned bitIndex = 0; bitIndex < NumBits; ++bitIndex)
BitValueArray[StartBit + bitIndex] = Inst.first & (1ULL << bitIndex)
@@ -810,7 +797,7 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
// Returns the number of fanout produced by the filter. More fanout implies
// the filter distinguishes more categories of instructions.
unsigned Filter::usefulness() const {
- return FilteredInstructions.size() + VariableInstructions.empty();
+ return FilteredIDs.size() + VariableIDs.empty();
}
//////////////////////////////////
@@ -824,14 +811,16 @@ unsigned Filter::usefulness() const {
unsigned DecoderEmitter::emitTable(formatted_raw_ostream &OS,
DecoderTable &Table, unsigned BitWidth,
StringRef Namespace,
- const EncodingIDsVec &EncodingIDs) const {
+ ArrayRef<unsigned> EncodingIDs) const {
// We'll need to be able to map from a decoded opcode into the corresponding
// EncodingID for this specific combination of BitWidth and Namespace. This
// is used below to index into NumberedEncodings.
DenseMap<unsigned, unsigned> OpcodeToEncodingID;
OpcodeToEncodingID.reserve(EncodingIDs.size());
- for (const auto &EI : EncodingIDs)
- OpcodeToEncodingID[EI.Opcode] = EI.EncodingID;
+ for (unsigned EncodingID : EncodingIDs) {
+ const Record *InstDef = NumberedEncodings[EncodingID].Inst->TheDef;
+ OpcodeToEncodingID[Target.getInstrIntValue(InstDef)] = EncodingID;
+ }
OS << "static const uint8_t DecoderTable" << Namespace << BitWidth
<< "[] = {\n";
@@ -1419,14 +1408,14 @@ void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo,
// Emits table entries to decode the singleton.
void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
- EncodingIDAndOpcode Opc) const {
- insn_t Insn = insnWithID(Opc.EncodingID);
+ unsigned EncodingID) const {
+ insn_t Insn = insnWithID(EncodingID);
// Look for islands of undecoded bits of the singleton.
std::vector<Island> Islands = getIslands(Insn);
// Emit the predicate table entry if one is needed.
- emitPredicateTableEntry(TableInfo, Opc.EncodingID);
+ emitPredicateTableEntry(TableInfo, EncodingID);
// Check any additional encoding fields needed.
for (const Island &Ilnd : reverse(Islands)) {
@@ -1451,10 +1440,10 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
}
// Check for soft failure of the match.
- emitSoftFailTableEntry(TableInfo, Opc.EncodingID);
+ emitSoftFailTableEntry(TableInfo, EncodingID);
auto [DIdx, HasCompleteDecoder] =
- getDecoderIndex(TableInfo.Decoders, Opc.EncodingID);
+ getDecoderIndex(TableInfo.Decoders, EncodingID);
// Produce OPC_Decode or OPC_TryDecode opcode based on the information
// whether the instruction decoder is complete or not. If it is complete
@@ -1471,7 +1460,8 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
: MCD::OPC_TryDecode);
TableInfo.Table.push_back(DecoderOp);
NumEncodingsSupported++;
- TableInfo.Table.insertULEB128(Opc.Opcode);
+ const Record *InstDef = AllInstructions[EncodingID].Inst->TheDef;
+ TableInfo.Table.insertULEB128(Emitter->getTarget().getInstrIntValue(InstDef));
TableInfo.Table.insertULEB128(DIdx);
if (DecoderOp == MCD::OPC_TryDecode) {
@@ -1483,12 +1473,10 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
// Emits table entries to decode the singleton, and then to decode the rest.
void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
const Filter &Best) const {
- EncodingIDAndOpcode Opc = Best.getSingletonOpc();
-
// complex singletons need predicate checks from the first singleton
// to refer forward to the variable filterchooser that follows.
TableInfo.pushScope();
- emitSingletonTableEntry(TableInfo, Opc);
+ emitSingletonTableEntry(TableInfo, Best.getSingletonEncodingID());
TableInfo.popScope();
Best.getVariableFC().emitTableEntries(TableInfo);
@@ -1516,15 +1504,15 @@ void FilterChooser::reportRegion(std::vector<std::unique_ptr<Filter>> &Filters,
// recursively descends down the decoding tree.
bool FilterChooser::filterProcessor(ArrayRef<bitAttr_t> BitAttrs,
bool AllowMixed, bool Greedy) {
- assert(Opcodes.size() >= 2 && "Nothing to filter");
+ assert(EncodingIDs.size() >= 2 && "Nothing to filter");
// Heuristics. See also doFilter()'s "Heuristics" comment when num of
// instructions is 3.
if (AllowMixed && !Greedy) {
- assert(Opcodes.size() == 3);
+ assert(EncodingIDs.size() == 3);
- for (const auto &Opcode : Opcodes) {
- insn_t Insn = insnWithID(Opcode.EncodingID);
+ for (unsigned EncodingID : EncodingIDs) {
+ insn_t Insn = insnWithID(EncodingID);
// Look for islands of undecoded bits of any instruction.
std::vector<Island> Islands = getIslands(Insn);
@@ -1681,10 +1669,10 @@ bool FilterChooser::filterProcessor(ArrayRef<bitAttr_t> BitAttrs,
// the instructions. A conflict of instructions may occur, in which case we
// dump the conflict set to the standard error.
void FilterChooser::doFilter() {
- assert(!Opcodes.empty() && "FilterChooser created with no instructions");
+ assert(!EncodingIDs.empty() && "FilterChooser created with no instructions");
// No filter needed.
- if (Opcodes.size() < 2)
+ if (EncodingIDs.size() < 2)
return;
// We maintain BIT_WIDTH copies of the bitAttrs automaton.
@@ -1712,8 +1700,8 @@ void FilterChooser::doFilter() {
if (FilterBitValues[BitIndex].isSet())
BitAttrs[BitIndex] = ATTR_FILTERED;
- for (const EncodingIDAndOpcode &OpcPair : Opcodes) {
- insn_t EncodingBits = insnWithID(OpcPair.EncodingID);
+ for (unsigned EncodingID : EncodingIDs) {
+ insn_t EncodingBits = insnWithID(EncodingID);
for (unsigned BitIndex = 0; BitIndex < BitWidth; ++BitIndex) {
switch (BitAttrs[BitIndex]) {
@@ -1750,7 +1738,7 @@ void FilterChooser::doFilter() {
// no single instruction for the maximum ATTR_MIXED region Inst{14-4} has a
// well-known encoding pattern. In such case, we backtrack and scan for the
// the very first consecutive ATTR_ALL_SET region and assign a filter to it.
- if (Opcodes.size() == 3 &&
+ if (EncodingIDs.size() == 3 &&
filterProcessor(BitAttrs, /*AllowMixed=*/true, /*Greedy=*/false))
return;
@@ -1766,8 +1754,8 @@ void FilterChooser::doFilter() {
dumpStack(errs(), Indent);
// Dump encodings.
- for (EncodingIDAndOpcode Opcode : Opcodes) {
- const EncodingAndInst &Enc = AllInstructions[Opcode.EncodingID];
+ for (unsigned EncodingID : EncodingIDs) {
+ const EncodingAndInst &Enc = AllInstructions[EncodingID];
errs() << Indent;
dumpBits(errs(), getBitsField(*Enc.EncodingDef, "Inst"), BitWidth);
errs() << " " << Enc << '\n';
@@ -1778,11 +1766,11 @@ void FilterChooser::doFilter() {
// emitTableEntries - Emit state machine entries to decode our share of
// instructions.
void FilterChooser::emitTableEntries(DecoderTableInfo &TableInfo) const {
- if (Opcodes.size() == 1) {
+ if (EncodingIDs.size() == 1) {
// There is only one instruction in the set, which is great!
// Call emitSingletonDecoder() to see whether there are any remaining
// encodings bits.
- emitSingletonTableEntry(TableInfo, Opcodes[0]);
+ emitSingletonTableEntry(TableInfo, EncodingIDs[0]);
return;
}
@@ -2528,8 +2516,8 @@ namespace {
NumberedAlias,
&Target.getInstruction(NumberedAlias->getValueAsDef("AliasOf")));
- std::map<std::pair<std::string, unsigned>, std::vector<EncodingIDAndOpcode>>
- OpcMap;
+ // Map of (namespace, size) tuple to encoding IDs.
+ std::map<std::pair<std::string, unsigned>, std::vector<unsigned>> EncMap;
std::map<unsigned, std::vector<OperandInfo>> Operands;
std::vector<unsigned> InstrLen;
bool IsVarLenInst = Target.hasVariableLengthEncodings();
@@ -2568,8 +2556,7 @@ namespace {
EncodingDef->getValueAsString("DecoderNamespace").str();
if (!NumberedEncoding.HwModeName.empty())
DecoderNamespace += "_" + NumberedEncoding.HwModeName.str();
- OpcMap[{DecoderNamespace, Size}].emplace_back(
- NEI, Target.getInstrIntValue(Def));
+ EncMap[{DecoderNamespace, Size}].push_back(NEI);
} else {
NumEncodingsOmitted++;
}
@@ -2577,7 +2564,7 @@ namespace {
DecoderTableInfo TableInfo;
unsigned OpcodeMask = 0;
- for (const auto &[NSAndByteSize, EncodingIDs] : OpcMap) {
+ for (const auto &[NSAndByteSize, EncodingIDs] : EncMap) {
const std::string &DecoderNamespace = NSAndByteSize.first;
const unsigned BitWidth = 8 * NSAndByteSize.second;
// Emit the decoder for this namespace+width combination.