-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[TableGen][DecoderEmitter] Optimize single-case OPC_ExtractField #155414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
s-barannikov
merged 1 commit into
llvm:main
from
s-barannikov:tablegen/decoder/optimize-single-field-case
Aug 26, 2025
Merged
[TableGen][DecoderEmitter] Optimize single-case OPC_ExtractField #155414
s-barannikov
merged 1 commit into
llvm:main
from
s-barannikov:tablegen/decoder/optimize-single-field-case
Aug 26, 2025
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
OPC_ExtractField followed by a single OPC_FilterValue is equivalent to OPC_CheckField. Optimize this relatively common case.
@llvm/pr-subscribers-tablegen Author: Sergei Barannikov (s-barannikov) ChangesOPC_ExtractField followed by a single OPC_FilterValue is equivalent to Full diff: https://github.com/llvm/llvm-project/pull/155414.diff 5 Files Affected:
diff --git a/llvm/test/TableGen/trydecode-emission.td b/llvm/test/TableGen/trydecode-emission.td
index 6e47909b8f09a..5d1c18fe65d0e 100644
--- a/llvm/test/TableGen/trydecode-emission.td
+++ b/llvm/test/TableGen/trydecode-emission.td
@@ -34,11 +34,10 @@ def InstB : TestInstruction {
let hasCompleteDecoder = 0;
}
-// CHECK: /* 0 */ MCD::OPC_ExtractField, 4, 4, // Inst{7-4} ...
-// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
-// CHECK-NEXT: /* 5 */ MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 17
-// CHECK-NEXT: /* 11 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 17
-// CHECK-NEXT: /* 17 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA, DecodeIdx: {{[0-9]+}}
+// CHECK: /* 0 */ MCD::OPC_CheckFieldOrFail, 4, 4, 0,
+// CHECK-NEXT: /* 4 */ MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 16
+// CHECK-NEXT: /* 10 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 16
+// CHECK-NEXT: /* 16 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA, DecodeIdx: {{[0-9]+}}
// CHECK-NEXT: };
// CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
@@ -47,11 +46,10 @@ def InstB : TestInstruction {
// CHECK-NEXT: NumToSkip |= (*Ptr++) << 8;
// CHECK-NEXT: return NumToSkip;
-// CHECK-LARGE: /* 0 */ MCD::OPC_ExtractField, 4, 4, // Inst{7-4} ...
-// CHECK-LARGE-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
-// CHECK-LARGE-NEXT: /* 5 */ MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 19
-// CHECK-LARGE-NEXT: /* 12 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 19
-// CHECK-LARGE-NEXT: /* 19 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA, DecodeIdx: {{[0-9]+}}
+// CHECK-LARGE: /* 0 */ MCD::OPC_CheckFieldOrFail, 4, 4, 0,
+// CHECK-LARGE-NEXT: /* 4 */ MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 18
+// CHECK-LARGE-NEXT: /* 11 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 18
+// CHECK-LARGE-NEXT: /* 18 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA, DecodeIdx: {{[0-9]+}}
// CHECK-LARGE-NEXT: };
// CHECK-LARGE: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
diff --git a/llvm/test/TableGen/trydecode-emission2.td b/llvm/test/TableGen/trydecode-emission2.td
index 826b1715514f9..375be9ad13d19 100644
--- a/llvm/test/TableGen/trydecode-emission2.td
+++ b/llvm/test/TableGen/trydecode-emission2.td
@@ -31,27 +31,23 @@ def InstB : TestInstruction {
let hasCompleteDecoder = 0;
}
-// CHECK: /* 0 */ MCD::OPC_ExtractField, 2, 1, // Inst{2} ...
-// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
-// CHECK-NEXT: /* 5 */ MCD::OPC_ExtractField, 5, 3, // Inst{7-5} ...
-// CHECK-NEXT: /* 8 */ MCD::OPC_FilterValueOrFail, 0
-// CHECK-NEXT: /* 10 */ MCD::OPC_CheckField, 0, 2, 3, 6, 0, // Skip to: 22
-// CHECK-NEXT: /* 16 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 22
-// CHECK-NEXT: /* 22 */ MCD::OPC_CheckFieldOrFail, 3, 2, 0,
-// CHECK-NEXT: /* 26 */ MCD::OPC_TryDecodeOrFail, {{[0-9]+}}, {{[0-9]+}}, 1,
+// CHECK: /* 0 */ MCD::OPC_CheckFieldOrFail, 2, 1, 0,
+// CHECK-NEXT: /* 4 */ MCD::OPC_CheckFieldOrFail, 5, 3, 0,
+// CHECK-NEXT: /* 8 */ MCD::OPC_CheckField, 0, 2, 3, 6, 0, // Skip to: 20
+// CHECK-NEXT: /* 14 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 20
+// CHECK-NEXT: /* 20 */ MCD::OPC_CheckFieldOrFail, 3, 2, 0,
+// CHECK-NEXT: /* 24 */ MCD::OPC_TryDecodeOrFail, {{[0-9]+}}, {{[0-9]+}}, 1,
// CHECK-NEXT: };
// CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
// CHECK: if (!Check(S, DecodeInstA(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
-// CHECK-LARGE: /* 0 */ MCD::OPC_ExtractField, 2, 1, // Inst{2} ...
-// CHECK-LARGE-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
-// CHECK-LARGE-NEXT: /* 5 */ MCD::OPC_ExtractField, 5, 3, // Inst{7-5} ...
-// CHECK-LARGE-NEXT: /* 8 */ MCD::OPC_FilterValueOrFail, 0,
-// CHECK-LARGE-NEXT: /* 10 */ MCD::OPC_CheckField, 0, 2, 3, 7, 0, 0, // Skip to: 24
-// CHECK-LARGE-NEXT: /* 17 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 24
-// CHECK-LARGE-NEXT: /* 24 */ MCD::OPC_CheckFieldOrFail, 3, 2, 0,
-// CHECK-LARGE-NEXT: /* 28 */ MCD::OPC_TryDecodeOrFail, {{[0-9]+}}, {{[0-9]+}}, 1,
+// CHECK-LARGE: /* 0 */ MCD::OPC_CheckFieldOrFail, 2, 1, 0,
+// CHECK-LARGE-NEXT: /* 4 */ MCD::OPC_CheckFieldOrFail, 5, 3, 0,
+// CHECK-LARGE-NEXT: /* 8 */ MCD::OPC_CheckField, 0, 2, 3, 7, 0, 0, // Skip to: 22
+// CHECK-LARGE-NEXT: /* 15 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 22
+// CHECK-LARGE-NEXT: /* 22 */ MCD::OPC_CheckFieldOrFail, 3, 2, 0,
+// CHECK-LARGE-NEXT: /* 26 */ MCD::OPC_TryDecodeOrFail, {{[0-9]+}}, {{[0-9]+}}, 1,
// CHECK-LARGE-NEXT: };
// CHECK-LARGE: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
diff --git a/llvm/test/TableGen/trydecode-emission3.td b/llvm/test/TableGen/trydecode-emission3.td
index 039a37ba416f6..9696724ce2836 100644
--- a/llvm/test/TableGen/trydecode-emission3.td
+++ b/llvm/test/TableGen/trydecode-emission3.td
@@ -35,20 +35,18 @@ def InstB : TestInstruction {
let AsmString = "InstB";
}
-// CHECK: /* 0 */ MCD::OPC_ExtractField, 4, 4, // Inst{7-4} ...
-// CHECK-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
-// CHECK-NEXT: /* 5 */ MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 17
-// CHECK-NEXT: /* 11 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 17
-// CHECK-NEXT: /* 17 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
+// CHECK: /* 0 */ MCD::OPC_CheckFieldOrFail, 4, 4, 0,
+// CHECK-NEXT: /* 4 */ MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 16
+// CHECK-NEXT: /* 10 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 16
+// CHECK-NEXT: /* 16 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
// CHECK-NEXT: };
// CHECK: if (!Check(S, DecodeInstBOp(MI, tmp, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
-// CHECK-LARGE: /* 0 */ MCD::OPC_ExtractField, 4, 4, // Inst{7-4} ...
-// CHECK-LARGE-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0,
-// CHECK-LARGE-NEXT: /* 5 */ MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 19
-// CHECK-LARGE-NEXT: /* 12 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 19
-// CHECK-LARGE-NEXT: /* 19 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA, DecodeIdx: {{[0-9]+}}
+// CHECK-LARGE: /* 0 */ MCD::OPC_CheckFieldOrFail, 4, 4, 0,
+// CHECK-LARGE-NEXT: /* 4 */ MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 18
+// CHECK-LARGE-NEXT: /* 11 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 18
+// CHECK-LARGE-NEXT: /* 18 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA, DecodeIdx: {{[0-9]+}}
// CHECK-LARGE-NEXT: };
// CHECK-LARGE: if (!Check(S, DecodeInstBOp(MI, tmp, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
diff --git a/llvm/test/TableGen/trydecode-emission4.td b/llvm/test/TableGen/trydecode-emission4.td
index d00d17501f16f..03cb635dbcaad 100644
--- a/llvm/test/TableGen/trydecode-emission4.td
+++ b/llvm/test/TableGen/trydecode-emission4.td
@@ -33,22 +33,19 @@ def InstB : TestInstruction {
let hasCompleteDecoder = 0;
}
-// CHECK: /* 0 */ MCD::OPC_ExtractField, 250, 3, 4, // Inst{509-506} ...
-// CHECK-NEXT: /* 4 */ MCD::OPC_FilterValueOrFail, 0,
-// CHECK-NEXT: /* 6 */ MCD::OPC_CheckField, 248, 3, 2, 0, 6, 0, // Skip to: 19
-// CHECK-NEXT: /* 13 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 19
-// CHECK-NEXT: /* 19 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA, DecodeIdx: {{[0-9]+}}
+// CHECK: /* 0 */ MCD::OPC_CheckFieldOrFail, 250, 3, 4, 0,
+// CHECK-NEXT: /* 5 */ MCD::OPC_CheckField, 248, 3, 2, 0, 6, 0, // Skip to: 18
+// CHECK-NEXT: /* 12 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 18
+// CHECK-NEXT: /* 18 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA, DecodeIdx: {{[0-9]+}}
// CHECK-NEXT: };
// CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
-// CHECK-LARGE: /* 0 */ MCD::OPC_ExtractField, 250, 3, 4, // Inst{509-506} ...
-// CHECK-LARGE-NEXT: /* 4 */ MCD::OPC_FilterValueOrFail, 0,
-// CHECK-LARGE-NEXT: /* 6 */ MCD::OPC_CheckField, 248, 3, 2, 0, 7, 0, 0, // Skip to: 21
-// CHECK-LARGE-NEXT: /* 14 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 21
-// CHECK-LARGE-NEXT: /* 21 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA, DecodeIdx: {{[0-9]+}}
+// CHECK-LARGE: /* 0 */ MCD::OPC_CheckFieldOrFail, 250, 3, 4, 0,
+// CHECK-LARGE-NEXT: /* 5 */ MCD::OPC_CheckField, 248, 3, 2, 0, 7, 0, 0, // Skip to: 20
+// CHECK-LARGE-NEXT: /* 13 */ MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, DecodeIdx: {{[0-9]+}}, Skip to: 20
+// CHECK-LARGE-NEXT: /* 20 */ MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA, DecodeIdx: {{[0-9]+}}
// CHECK-LARGE-NEXT: };
// CHECK-LARGE: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
-
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 9105d24f66d6d..ecdc48775c9c1 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -425,15 +425,6 @@ struct Filter {
Filter(ArrayRef<InstructionEncoding> Encodings,
ArrayRef<unsigned> EncodingIDs, unsigned StartBit, unsigned NumBits);
- bool hasSingleFilteredID() const {
- return FilteredIDs.size() == 1 && FilteredIDs.begin()->second.size() == 1;
- }
-
- unsigned getSingletonEncodingID() const {
- assert(hasSingleFilteredID());
- return FilteredIDs.begin()->second.front();
- }
-
// Returns the number of fanout produced by the filter. More fanout implies
// the filter distinguishes more categories of instructions.
unsigned usefulness() const;
@@ -679,14 +670,6 @@ void FilterChooser::applyFilter(const Filter &F) {
FilterBits, *this);
}
- // No need to recurse for a singleton filtered instruction.
- // See also Filter::emit*().
- if (F.hasSingleFilteredID()) {
- SingletonEncodingID = F.getSingletonEncodingID();
- assert(VariableFC && "Shouldn't have created a filter for one encoding!");
- return;
- }
-
// Otherwise, create sub choosers.
for (const auto &[FilterVal, InferiorEncodingIDs] : F.FilteredIDs) {
// Create a new filter by inserting the field bits into the parent filter.
@@ -1646,6 +1629,8 @@ void FilterChooser::dump() const {
}
void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) const {
+ DecoderTable &Table = TableInfo.Table;
+
// If there are other encodings that could match if those with all bits
// known don't, enter a scope so that they have a chance.
if (FC.VariableFC)
@@ -1657,9 +1642,23 @@ void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) const {
// fully defined, but we still need to check if the remaining (unfiltered)
// bits are valid for this encoding. We also need to check predicates etc.
emitSingletonTableEntry(FC);
+ } else if (FC.FilterChooserMap.size() == 1) {
+ // If there is only one possible field value, emit a combined OPC_CheckField
+ // instead of OPC_ExtractField + OPC_FilterValue.
+ const auto &[FilterVal, Delegate] = *FC.FilterChooserMap.begin();
+ Table.insertOpcode(!TableInfo.isOutermostScope()
+ ? MCD::OPC_CheckField
+ : MCD::OPC_CheckFieldOrFail);
+ Table.insertULEB128(FC.StartBit);
+ Table.insertUInt8(FC.NumBits);
+ Table.insertULEB128(FilterVal);
+ if (!TableInfo.isOutermostScope())
+ TableInfo.FixupStack.back().push_back(TableInfo.Table.insertNumToSkip());
+
+ // Emit table entries for the only case.
+ emitTableEntries(*Delegate);
} else {
// The general case: emit a switch over the field value.
- DecoderTable &Table = TableInfo.Table;
Table.insertOpcode(MCD::OPC_ExtractField);
Table.insertULEB128(FC.StartBit);
Table.insertUInt8(FC.NumBits);
|
This reduces the size of some tables by 4-7%, average is 0.8%. |
jurahul
approved these changes
Aug 26, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
OPC_ExtractField followed by a single OPC_FilterValue is equivalent to
OPC_CheckField. Optimize this relatively common case.