Skip to content

Commit ee55efc

Browse files
authored
[TableGen][DecoderEmitter] Repurpose Filter class (llvm#155065)
There was a lot of confusion about the responsibilities of Filter and FilterChooser. They created instances of each other and called each other's methods. Some of the methods had similar names and did similar things. This change moves most of the Filter members to FilterChooser and turns Filter into a supplementary class with short lifetime. FilterChooser constructs an array of (candidate) Filters, chooses the best performing one, and applies it to the given set of encodings, creating inferior FilterChoosers as necessary. The Filter array is then destroyed. All responsibility for generating the decoder table now lies with FilterChooser.
1 parent f5e687d commit ee55efc

File tree

1 file changed

+69
-79
lines changed

1 file changed

+69
-79
lines changed

llvm/utils/TableGen/DecoderEmitter.cpp

Lines changed: 69 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,6 @@ class DecoderEmitter {
371371

372372
namespace {
373373

374-
class FilterChooser;
375-
376374
/// Filter - Filter works with FilterChooser to produce the decoding tree for
377375
/// the ISA.
378376
///
@@ -409,9 +407,7 @@ class FilterChooser;
409407
/// decoder could try to decode the even/odd register numbering and assign to
410408
/// VST4q8a or VST4q8b, but for the time being, the decoder chooses the "a"
411409
/// version and return the Opcode since the two have the same Asm format string.
412-
class Filter {
413-
protected:
414-
const FilterChooser &Owner; // FilterChooser who owns this filter
410+
struct Filter {
415411
unsigned StartBit; // the starting bit position
416412
unsigned NumBits; // number of bits to filter
417413

@@ -421,14 +417,8 @@ class Filter {
421417
// Set of uid's with non-constant segment values.
422418
std::vector<unsigned> VariableIDs;
423419

424-
// Map of well-known segment value to its delegate.
425-
std::map<uint64_t, std::unique_ptr<const FilterChooser>> FilterChooserMap;
426-
427-
// A filter chooser for encodings that contain some '?' in the filtered range.
428-
std::unique_ptr<const FilterChooser> VariableFC;
429-
430-
public:
431-
Filter(const FilterChooser &owner, unsigned startBit, unsigned numBits);
420+
Filter(ArrayRef<InstructionEncoding> Encodings,
421+
ArrayRef<unsigned> EncodingIDs, unsigned StartBit, unsigned NumBits);
432422

433423
bool hasSingleFilteredID() const {
434424
return FilteredIDs.size() == 1 && FilteredIDs.begin()->second.size() == 1;
@@ -439,25 +429,6 @@ class Filter {
439429
return FilteredIDs.begin()->second.front();
440430
}
441431

442-
// Return the filter chooser for the group of instructions without constant
443-
// segment values.
444-
const FilterChooser &getVariableFC() const {
445-
assert(hasSingleFilteredID() && FilterChooserMap.empty());
446-
return *VariableFC;
447-
}
448-
449-
// Divides the decoding task into sub tasks and delegates them to the
450-
// inferior FilterChooser's.
451-
//
452-
// A special case arises when there's only one entry in the filtered
453-
// instructions. In order to unambiguously decode the singleton, we need to
454-
// match the remaining undecoded encoding bits against the singleton.
455-
void recurse();
456-
457-
// Emit table entries to decode instructions given a segment or segments of
458-
// bits.
459-
void emitTableEntry(DecoderTableInfo &TableInfo) const;
460-
461432
// Returns the number of fanout produced by the filter. More fanout implies
462433
// the filter distinguishes more categories of instructions.
463434
unsigned usefulness() const;
@@ -490,19 +461,13 @@ enum bitAttr_t {
490461
/// decide what further remaining bits to look at.
491462

492463
class FilterChooser {
493-
protected:
494-
friend class Filter;
495-
496464
// Vector of encodings to choose our filter.
497465
ArrayRef<InstructionEncoding> Encodings;
498466

499467
/// Encoding IDs for this filter chooser to work on.
500468
/// Sorted by non-decreasing encoding width.
501469
SmallVector<unsigned, 0> EncodingIDs;
502470

503-
// The selected filter, if any.
504-
std::unique_ptr<Filter> BestFilter;
505-
506471
// Array of bit values passed down from our parent.
507472
// Set to all unknown for Parent == nullptr.
508473
KnownBits FilterBits;
@@ -517,6 +482,29 @@ class FilterChooser {
517482
// Parent emitter
518483
const DecoderEmitter *Emitter;
519484

485+
/// If the selected filter matches multiple encodings, then this is the
486+
/// starting position and the width of the filtered range.
487+
unsigned StartBit;
488+
unsigned NumBits;
489+
490+
/// If the selected filter matches multiple encodings, and there is
491+
/// *exactly one* encoding in which all bits are known in the filtered range,
492+
/// then this is the ID of that encoding.
493+
std::optional<unsigned> SingletonEncodingID;
494+
495+
/// If the selected filter matches multiple encodings, and there is
496+
/// *at least one* encoding in which all bits are known in the filtered range,
497+
/// then this is the FilterChooser created for the subset of encodings that
498+
/// contain some unknown bits in the filtered range.
499+
std::unique_ptr<const FilterChooser> VariableFC;
500+
501+
/// If the selected filter matches multiple encodings, and there is
502+
/// *more than one* encoding in which all bits are known in the filtered
503+
/// range, then this is a map of field values to FilterChoosers created for
504+
/// the subset of encodings sharing that field value.
505+
/// The "field value" here refers to the encoding bits in the filtered range.
506+
std::map<uint64_t, std::unique_ptr<const FilterChooser>> FilterChooserMap;
507+
520508
struct Island {
521509
unsigned StartBit;
522510
unsigned NumBits;
@@ -566,7 +554,11 @@ class FilterChooser {
566554
return Encodings[EncodingIDs.back()].getBitWidth();
567555
}
568556

569-
protected:
557+
private:
558+
/// Applies the given filter to the set of encodings this FilterChooser
559+
/// works with, creating inferior FilterChoosers as necessary.
560+
void applyFilter(const Filter &F);
561+
570562
/// dumpStack - dumpStack traverses the filter chooser chain and calls
571563
/// dumpFilterArray on each filter chooser up to the top level one.
572564
void dumpStack(raw_ostream &OS, indent Indent, unsigned PadToWidth) const;
@@ -600,8 +592,11 @@ class FilterChooser {
600592
unsigned EncodingID) const;
601593

602594
// Emits code to decode the singleton, and then to decode the rest.
603-
void emitSingletonTableEntry(DecoderTableInfo &TableInfo,
604-
const Filter &Best) const;
595+
void emitSingletonTableEntry(DecoderTableInfo &TableInfo) const;
596+
597+
// Emit table entries to decode instructions given a segment or segments of
598+
// bits.
599+
void emitTableEntry(DecoderTableInfo &TableInfo) const;
605600

606601
void emitBinaryParser(raw_ostream &OS, indent Indent,
607602
const OperandInfo &OpInfo) const;
@@ -644,12 +639,12 @@ class FilterChooser {
644639
// //
645640
///////////////////////////
646641

647-
Filter::Filter(const FilterChooser &owner, unsigned startBit, unsigned numBits)
648-
: Owner(owner), StartBit(startBit), NumBits(numBits) {
649-
assert(StartBit + NumBits - 1 < Owner.FilterBits.getBitWidth());
650-
651-
for (unsigned EncodingID : Owner.EncodingIDs) {
652-
const InstructionEncoding &Encoding = Owner.Encodings[EncodingID];
642+
Filter::Filter(ArrayRef<InstructionEncoding> Encodings,
643+
ArrayRef<unsigned> EncodingIDs, unsigned StartBit,
644+
unsigned NumBits)
645+
: StartBit(StartBit), NumBits(NumBits) {
646+
for (unsigned EncodingID : EncodingIDs) {
647+
const InstructionEncoding &Encoding = Encodings[EncodingID];
653648
KnownBits EncodingBits = Encoding.getMandatoryBits();
654649

655650
// Scans the segment for possibly well-specified encoding bits.
@@ -670,48 +665,44 @@ Filter::Filter(const FilterChooser &owner, unsigned startBit, unsigned numBits)
670665
"Filter returns no instruction categories");
671666
}
672667

673-
// Divides the decoding task into sub tasks and delegates them to the
674-
// inferior FilterChooser's.
675-
//
676-
// A special case arises when there's only one entry in the filtered
677-
// instructions. In order to unambiguously decode the singleton, we need to
678-
// match the remaining undecoded encoding bits against the singleton.
679-
void Filter::recurse() {
680-
assert(Owner.FilterBits.extractBits(NumBits, StartBit).isUnknown());
668+
void FilterChooser::applyFilter(const Filter &F) {
669+
StartBit = F.StartBit;
670+
NumBits = F.NumBits;
671+
assert(FilterBits.extractBits(NumBits, StartBit).isUnknown());
681672

682-
if (!VariableIDs.empty()) {
673+
if (!F.VariableIDs.empty()) {
683674
// Delegates to an inferior filter chooser for further processing on this
684675
// group of instructions whose segment values are variable.
685-
VariableFC = std::make_unique<FilterChooser>(Owner.Encodings, VariableIDs,
686-
Owner.FilterBits, Owner);
676+
VariableFC = std::make_unique<FilterChooser>(Encodings, F.VariableIDs,
677+
FilterBits, *this);
687678
}
688679

689680
// No need to recurse for a singleton filtered instruction.
690681
// See also Filter::emit*().
691-
if (hasSingleFilteredID()) {
682+
if (F.hasSingleFilteredID()) {
683+
SingletonEncodingID = F.getSingletonEncodingID();
692684
assert(VariableFC && "Shouldn't have created a filter for one encoding!");
693685
return;
694686
}
695687

696688
// Otherwise, create sub choosers.
697-
for (const auto &[FilterVal, InferiorEncodingIDs] : FilteredIDs) {
689+
for (const auto &[FilterVal, InferiorEncodingIDs] : F.FilteredIDs) {
698690
// Create a new filter by inserting the field bits into the parent filter.
699691
APInt FieldBits(NumBits, FilterVal);
700-
KnownBits InferiorFilterBits = Owner.FilterBits;
692+
KnownBits InferiorFilterBits = FilterBits;
701693
InferiorFilterBits.insertBits(KnownBits::makeConstant(FieldBits), StartBit);
702694

703695
// Delegates to an inferior filter chooser for further processing on this
704696
// category of instructions.
705-
FilterChooserMap.try_emplace(
706-
FilterVal,
707-
std::make_unique<FilterChooser>(Owner.Encodings, InferiorEncodingIDs,
708-
InferiorFilterBits, Owner));
697+
FilterChooserMap.try_emplace(FilterVal, std::make_unique<FilterChooser>(
698+
Encodings, InferiorEncodingIDs,
699+
InferiorFilterBits, *this));
709700
}
710701
}
711702

712703
// Emit table entries to decode instructions given a segment or segments
713704
// of bits.
714-
void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
705+
void FilterChooser::emitTableEntry(DecoderTableInfo &TableInfo) const {
715706
assert(isUInt<8>(NumBits) && "NumBits overflowed uint8 table entry!");
716707
TableInfo.Table.push_back(MCD::OPC_ExtractField);
717708

@@ -1436,15 +1427,14 @@ void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
14361427
}
14371428

14381429
// Emits table entries to decode the singleton, and then to decode the rest.
1439-
void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo,
1440-
const Filter &Best) const {
1430+
void FilterChooser::emitSingletonTableEntry(DecoderTableInfo &TableInfo) const {
14411431
// complex singletons need predicate checks from the first singleton
14421432
// to refer forward to the variable filterchooser that follows.
14431433
TableInfo.pushScope();
1444-
emitSingletonTableEntry(TableInfo, Best.getSingletonEncodingID());
1434+
emitSingletonTableEntry(TableInfo, *SingletonEncodingID);
14451435
TableInfo.popScope();
14461436

1447-
Best.getVariableFC().emitTableEntries(TableInfo);
1437+
VariableFC->emitTableEntries(TableInfo);
14481438
}
14491439

14501440
// reportRegion is a helper function for filterProcessor to mark a region as
@@ -1453,8 +1443,8 @@ void FilterChooser::reportRegion(std::vector<std::unique_ptr<Filter>> &Filters,
14531443
bitAttr_t RA, unsigned StartBit,
14541444
unsigned BitIndex, bool AllowMixed) const {
14551445
if (AllowMixed ? RA == ATTR_MIXED : RA == ATTR_ALL_SET)
1456-
Filters.push_back(
1457-
std::make_unique<Filter>(*this, StartBit, BitIndex - StartBit));
1446+
Filters.push_back(std::make_unique<Filter>(Encodings, EncodingIDs, StartBit,
1447+
BitIndex - StartBit));
14581448
}
14591449

14601450
std::unique_ptr<Filter>
@@ -1475,8 +1465,8 @@ FilterChooser::findBestFilter(ArrayRef<bitAttr_t> BitAttrs, bool AllowMixed,
14751465
std::vector<Island> Islands = getIslands(EncodingBits);
14761466
if (!Islands.empty()) {
14771467
// Found an instruction with island(s). Now just assign a filter.
1478-
return std::make_unique<Filter>(*this, Islands[0].StartBit,
1479-
Islands[0].NumBits);
1468+
return std::make_unique<Filter>(
1469+
Encodings, EncodingIDs, Islands[0].StartBit, Islands[0].NumBits);
14801470
}
14811471
}
14821472
}
@@ -1708,9 +1698,9 @@ void FilterChooser::doFilter() {
17081698
if (EncodingIDs.size() < 2)
17091699
return;
17101700

1711-
BestFilter = findBestFilter();
1701+
std::unique_ptr<Filter> BestFilter = findBestFilter();
17121702
if (BestFilter) {
1713-
BestFilter->recurse();
1703+
applyFilter(*BestFilter);
17141704
return;
17151705
}
17161706

@@ -1749,10 +1739,10 @@ void FilterChooser::emitTableEntries(DecoderTableInfo &TableInfo) const {
17491739
}
17501740

17511741
// Use the best filter to do the decoding!
1752-
if (BestFilter->hasSingleFilteredID())
1753-
emitSingletonTableEntry(TableInfo, *BestFilter);
1742+
if (SingletonEncodingID)
1743+
emitSingletonTableEntry(TableInfo);
17541744
else
1755-
BestFilter->emitTableEntry(TableInfo);
1745+
emitTableEntry(TableInfo);
17561746
}
17571747

17581748
static std::string findOperandDecoderMethod(const Record *Record) {

0 commit comments

Comments
 (0)