Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 55 additions & 68 deletions llvm/utils/TableGen/DecoderEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -235,11 +225,13 @@ class DecoderEmitter {
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,
Expand Down Expand Up @@ -416,10 +408,10 @@ class Filter {
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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple lines down from here (github won't let me add the comment there) there's a reference to FilteredInstructions in a comment that got missed in the rename

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's no longer there, 6a7ade0 removed the reference along with the field.
Thanks anyway!

Expand All @@ -435,9 +427,9 @@ class Filter {

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
Expand Down Expand Up @@ -498,9 +490,7 @@ class FilterChooser {
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;
Expand Down Expand Up @@ -528,22 +518,20 @@ class FilterChooser {
};

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();
Expand Down Expand Up @@ -608,7 +596,7 @@ class FilterChooser {

// 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,
Expand Down Expand Up @@ -656,8 +644,8 @@ class FilterChooser {

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) {}

Expand All @@ -667,26 +655,26 @@ 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);

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");
}

Expand All @@ -700,17 +688,16 @@ 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;

// Delegates to an inferior filter chooser for further processing on this
// 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.
Expand All @@ -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)
Expand Down Expand Up @@ -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();
}

//////////////////////////////////
Expand All @@ -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";
Expand Down Expand Up @@ -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)) {
Expand All @@ -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
Expand All @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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]) {
Expand Down Expand Up @@ -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;

Expand All @@ -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';
Expand All @@ -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;
}

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -2568,16 +2556,15 @@ 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++;
}
}

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.
Expand Down