Skip to content

Commit bad02e3

Browse files
authored
[TableGen][DecoderEmitter] Avoid using a sentinel value (#153986)
`NO_FIXED_SEGMENTS_SENTINEL` has a value that is actually a valid field encoding and so it cannot be used as a sentinel. Replace the sentinel with a new member variable, `VariableFC`, that contains the value previously stored in `FilterChooserMap` with `NO_FIXED_SEGMENTS_SENTINEL` key.
1 parent 9c02d66 commit bad02e3

File tree

2 files changed

+76
-43
lines changed

2 files changed

+76
-43
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: llvm-tblgen -gen-disassembler -I %p/../../../include %s | FileCheck %s
2+
3+
include "llvm/Target/Target.td"
4+
5+
class I : Instruction {
6+
let InOperandList = (ins);
7+
let OutOperandList = (outs);
8+
let Size = 16;
9+
bits<128> Inst;
10+
}
11+
12+
// Check that a 64-bit filter with all bits set does not confuse DecoderEmitter.
13+
//
14+
// CHECK-LABEL: static const uint8_t DecoderTable128[] = {
15+
// CHECK-NEXT: MCD::OPC_ExtractField, 0, 64,
16+
// CHECK-NEXT: MCD::OPC_FilterValue, 1, 8, 0,
17+
// CHECK-NEXT: MCD::OPC_CheckFieldOrFail, 127, 1, 1,
18+
// CHECK-NEXT: MCD::OPC_Decode, 187, 2, 0,
19+
// CHECK-NEXT: MCD::OPC_FilterValueOrFail, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1,
20+
// CHECK-NEXT: MCD::OPC_CheckFieldOrFail, 127, 1, 0,
21+
// CHECK-NEXT: MCD::OPC_Decode, 186, 2, 0,
22+
// CHECK-NEXT: MCD::OPC_Fail,
23+
// CHECK-NEXT: 0
24+
// CHECK-NEXT: };
25+
26+
def I1 : I {
27+
let Inst{63...0} = -1;
28+
let Inst{127} = 0;
29+
}
30+
31+
def I2 : I {
32+
let Inst{63...0} = 1;
33+
let Inst{127} = 1;
34+
}
35+
36+
def II : InstrInfo;
37+
38+
def MyTarget : Target {
39+
let InstructionSet = II;
40+
}

llvm/utils/TableGen/DecoderEmitter.cpp

Lines changed: 36 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -360,9 +360,6 @@ fieldFromInsn(const insn_t &Insn, unsigned StartBit, unsigned NumBits) {
360360

361361
namespace {
362362

363-
static constexpr uint64_t NO_FIXED_SEGMENTS_SENTINEL =
364-
std::numeric_limits<uint64_t>::max();
365-
366363
class FilterChooser;
367364

368365
/// Filter - Filter works with FilterChooser to produce the decoding tree for
@@ -416,6 +413,9 @@ class Filter {
416413
// Map of well-known segment value to its delegate.
417414
std::map<uint64_t, std::unique_ptr<const FilterChooser>> FilterChooserMap;
418415

416+
// A filter chooser for encodings that contain some '?' in the filtered range.
417+
std::unique_ptr<const FilterChooser> VariableFC;
418+
419419
// Number of instructions which fall under FilteredInstructions category.
420420
unsigned NumFiltered;
421421

@@ -435,8 +435,8 @@ class Filter {
435435
// Return the filter chooser for the group of instructions without constant
436436
// segment values.
437437
const FilterChooser &getVariableFC() const {
438-
assert(NumFiltered == 1 && FilterChooserMap.size() == 1);
439-
return *(FilterChooserMap.find(NO_FIXED_SEGMENTS_SENTINEL)->second);
438+
assert(NumFiltered == 1 && FilterChooserMap.empty());
439+
return *VariableFC;
440440
}
441441

442442
// Divides the decoding task into sub tasks and delegates them to the
@@ -647,7 +647,7 @@ Filter::Filter(Filter &&f)
647647
FilteredIDs(std::move(f.FilteredIDs)),
648648
VariableIDs(std::move(f.VariableIDs)),
649649
FilterChooserMap(std::move(f.FilterChooserMap)),
650-
NumFiltered(f.NumFiltered) {}
650+
VariableFC(std::move(f.VariableFC)), NumFiltered(f.NumFiltered) {}
651651

652652
Filter::Filter(const FilterChooser &owner, unsigned startBit, unsigned numBits)
653653
: Owner(owner), StartBit(startBit), NumBits(numBits) {
@@ -694,16 +694,15 @@ void Filter::recurse() {
694694

695695
// Delegates to an inferior filter chooser for further processing on this
696696
// group of instructions whose segment values are variable.
697-
FilterChooserMap.try_emplace(
698-
NO_FIXED_SEGMENTS_SENTINEL,
697+
VariableFC =
699698
std::make_unique<FilterChooser>(Owner.AllInstructions, VariableIDs,
700-
Owner.Operands, BitValueArray, Owner));
699+
Owner.Operands, BitValueArray, Owner);
701700
}
702701

703702
// No need to recurse for a singleton filtered instruction.
704703
// See also Filter::emit*().
705704
if (getNumFiltered() == 1) {
706-
assert(FilterChooserMap.size() == 1);
705+
assert(VariableFC && "Shouldn't have created a filter for one encoding!");
707706
return;
708707
}
709708

@@ -733,46 +732,30 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
733732
TableInfo.Table.insertULEB128(StartBit);
734733
TableInfo.Table.push_back(NumBits);
735734

736-
// If the NO_FIXED_SEGMENTS_SENTINEL is present, we need to add a new scope
737-
// for this filter. Otherwise, we can skip adding a new scope and any
738-
// patching added will automatically be added to the enclosing scope.
739-
740-
// If NO_FIXED_SEGMENTS_SENTINEL is present, it will be last entry in
741-
// FilterChooserMap.
742-
735+
// If VariableFC is present, we need to add a new scope for this filter.
736+
// Otherwise, we can skip adding a new scope and any patching added will
737+
// automatically be added to the enclosing scope.
743738
const uint64_t LastFilter = FilterChooserMap.rbegin()->first;
744-
bool HasFallthrough = LastFilter == NO_FIXED_SEGMENTS_SENTINEL;
745-
if (HasFallthrough)
746-
TableInfo.pushScope();
739+
if (VariableFC)
740+
TableInfo.FixupStack.emplace_back();
747741

748742
DecoderTable &Table = TableInfo.Table;
749743

750744
size_t PrevFilter = 0;
751745
for (const auto &[FilterVal, Delegate] : FilterChooserMap) {
752-
// Field value NO_FIXED_SEGMENTS_SENTINEL implies a non-empty set of
753-
// variable instructions. See also recurse().
754-
if (FilterVal == NO_FIXED_SEGMENTS_SENTINEL) {
755-
// Each scope should always have at least one filter value to check
756-
// for.
757-
assert(PrevFilter != 0 && "empty filter set!");
758-
TableInfo.popScope();
759-
PrevFilter = 0; // Don't re-process the filter's fallthrough.
746+
// The last filtervalue emitted can be OPC_FilterValue if we are at
747+
// outermost scope.
748+
const uint8_t DecoderOp =
749+
FilterVal == LastFilter && TableInfo.isOutermostScope()
750+
? MCD::OPC_FilterValueOrFail
751+
: MCD::OPC_FilterValue;
752+
Table.push_back(DecoderOp);
753+
Table.insertULEB128(FilterVal);
754+
if (DecoderOp == MCD::OPC_FilterValue) {
755+
// Reserve space for the NumToSkip entry. We'll backpatch the value later.
756+
PrevFilter = Table.insertNumToSkip();
760757
} else {
761-
// The last filtervalue emitted can be OPC_FilterValue if we are at
762-
// outermost scope.
763-
const uint8_t DecoderOp =
764-
FilterVal == LastFilter && TableInfo.isOutermostScope()
765-
? MCD::OPC_FilterValueOrFail
766-
: MCD::OPC_FilterValue;
767-
Table.push_back(DecoderOp);
768-
Table.insertULEB128(FilterVal);
769-
if (DecoderOp == MCD::OPC_FilterValue) {
770-
// Reserve space for the NumToSkip entry. We'll backpatch the value
771-
// later.
772-
PrevFilter = Table.insertNumToSkip();
773-
} else {
774-
PrevFilter = 0;
775-
}
758+
PrevFilter = 0;
776759
}
777760

778761
// We arrive at a category of instructions with the same segment value.
@@ -787,6 +770,16 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
787770
Table.patchNumToSkip(PrevFilter, Table.size());
788771
}
789772

773+
if (VariableFC) {
774+
// Each scope should always have at least one filter value to check for.
775+
assert(PrevFilter != 0 && "empty filter set!");
776+
TableInfo.popScope();
777+
PrevFilter = 0; // Don't re-process the filter's fallthrough.
778+
779+
// Delegate to the sub filter chooser for further decoding.
780+
VariableFC->emitTableEntries(TableInfo);
781+
}
782+
790783
// If there is no fallthrough and the final filter was not in the outermost
791784
// scope, then it must be fixed up according to the enclosing scope rather
792785
// than the current position.

0 commit comments

Comments
 (0)