[llvm] 384bc40 - [TableGen][ISel] Add OPC_CheckTypeByHwMode0 to optimize the most frequent getValueTypeForHwMode index. (#182366)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 19 14:08:23 PST 2026
Author: Craig Topper
Date: 2026-02-19T14:08:18-08:00
New Revision: 384bc40250f23a2ac6545b1017dc96d5b513050f
URL: https://github.com/llvm/llvm-project/commit/384bc40250f23a2ac6545b1017dc96d5b513050f
DIFF: https://github.com/llvm/llvm-project/commit/384bc40250f23a2ac6545b1017dc96d5b513050f.diff
LOG: [TableGen][ISel] Add OPC_CheckTypeByHwMode0 to optimize the most frequent getValueTypeForHwMode index. (#182366)
Sort the unique ValueTypeByHwMode combinations by usage and add a
compressed opcode for the most common.
Reduces the RISCVGenDAGISel.inc table by about ~12K. The most common
being XLenVT.
I plan to add EmitIntegerByHwMode0 and EmitRegisterByHwMode0 in
subsequent patches.
Assisted-by: claude
Added:
Modified:
llvm/include/llvm/CodeGen/SelectionDAGISel.h
llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
llvm/test/TableGen/RegClassByHwMode.td
llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGISel.h b/llvm/include/llvm/CodeGen/SelectionDAGISel.h
index 38a7d70ef6db0..826e0472310d5 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGISel.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGISel.h
@@ -208,6 +208,8 @@ class SelectionDAGISel {
OPC_CheckTypeI32,
OPC_CheckTypeI64,
OPC_CheckTypeByHwMode,
+ // Space-optimized form that implicitly encodes index 0.
+ OPC_CheckTypeByHwMode0,
OPC_CheckTypeRes,
OPC_CheckTypeResByHwMode,
OPC_SwitchType,
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 3e61031c18d7b..a0cdc5148d0b8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -3168,7 +3168,8 @@ static size_t IsPredicateKnownToFail(
case SelectionDAGISel::OPC_CheckType:
case SelectionDAGISel::OPC_CheckTypeI32:
case SelectionDAGISel::OPC_CheckTypeI64:
- case SelectionDAGISel::OPC_CheckTypeByHwMode: {
+ case SelectionDAGISel::OPC_CheckTypeByHwMode:
+ case SelectionDAGISel::OPC_CheckTypeByHwMode0: {
MVT VT;
switch (Opcode) {
case SelectionDAGISel::OPC_CheckTypeI32:
@@ -3180,6 +3181,9 @@ static size_t IsPredicateKnownToFail(
case SelectionDAGISel::OPC_CheckTypeByHwMode:
VT = getHwModeVT(Table, Index, SDISel);
break;
+ case SelectionDAGISel::OPC_CheckTypeByHwMode0:
+ VT = SDISel.getValueTypeForHwMode(0);
+ break;
default:
VT = getSimpleVT(Table, Index);
break;
@@ -3756,7 +3760,8 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
case OPC_CheckType:
case OPC_CheckTypeI32:
case OPC_CheckTypeI64:
- case OPC_CheckTypeByHwMode: {
+ case OPC_CheckTypeByHwMode:
+ case OPC_CheckTypeByHwMode0: {
MVT VT;
switch (Opcode) {
case OPC_CheckTypeI32:
@@ -3768,6 +3773,9 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
case OPC_CheckTypeByHwMode:
VT = getHwModeVT(MatcherTable, MatcherIndex, *this);
break;
+ case OPC_CheckTypeByHwMode0:
+ VT = getValueTypeForHwMode(0);
+ break;
default:
VT = getSimpleVT(MatcherTable, MatcherIndex);
break;
diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td
index 83531b9248f92..0a06b8991b590 100644
--- a/llvm/test/TableGen/RegClassByHwMode.td
+++ b/llvm/test/TableGen/RegClassByHwMode.td
@@ -205,9 +205,9 @@ include "Common/RegClassByHwModeCommon.td"
// ISEL-SDAG-NEXT: OPC_RecordMemRef,
// ISEL-SDAG-NEXT: OPC_RecordNode, // #0 = 'st' chained node
// ISEL-SDAG-NEXT: OPC_RecordChild1, // #1 = $val
-// ISEL-SDAG-NEXT: OPC_CheckChild1TypeByHwMode, /*{(*:i64),(m1:i64),(m2:i64)}*/0,
+// ISEL-SDAG-NEXT: OPC_CheckChild1TypeByHwMode, /*{(*:i64),(m1:i64),(m2:i64)}*/1,
// ISEL-SDAG-NEXT: OPC_RecordChild2, // #2 = $src
-// ISEL-SDAG-NEXT: OPC_CheckChild2TypeByHwMode, /*{(*:i32),(m3:i64)}*/1,
+// ISEL-SDAG-NEXT: OPC_CheckChild2TypeByHwMode, /*{(*:i32),(m3:i64)}*/0,
// ISEL-SDAG-NEXT: OPC_CheckPredicate0, // Predicate_unindexedstore
// ISEL-SDAG-NEXT: OPC_CheckPredicate1, // Predicate_store
// ISEL-SDAG-NEXT: OPC_EmitMergeInputChains1_0,
@@ -218,13 +218,13 @@ include "Common/RegClassByHwModeCommon.td"
// ISEL-SDAG-NEXT: OPC_RecordMemRef,
// ISEL-SDAG-NEXT: OPC_RecordNode, // #0 = 'ld' chained node
// ISEL-SDAG-NEXT: OPC_RecordChild1, // #1 = $src
-// ISEL-SDAG-NEXT: OPC_CheckChild1TypeByHwMode, /*{(*:i32),(m3:i64)}*/1,
+// ISEL-SDAG-NEXT: OPC_CheckChild1TypeByHwMode, /*{(*:i32),(m3:i64)}*/0,
// ISEL-SDAG-NEXT: OPC_CheckPredicate2, // Predicate_unindexedload
// ISEL-SDAG-NEXT: OPC_CheckPredicate3, // Predicate_load
// ISEL-SDAG-NEXT: OPC_CheckTypeI64,
// ISEL-SDAG-NEXT: OPC_EmitMergeInputChains1_0,
// ISEL-SDAG-NEXT: OPC_MorphNodeToByHwMode, TARGET_VAL(MyTarget::MY_LOAD), 0|OPFL_Chain|OPFL_MemRefs,
-// ISEL-SDAG-NEXT: 1/*#VTs*/, /*{(*:i64),(m1:i64),(m2:i64)}*/0, 1/*#Ops*/, /*OperandList*/0, // Ops = #1
+// ISEL-SDAG-NEXT: 1/*#VTs*/, /*{(*:i64),(m1:i64),(m2:i64)}*/1, 1/*#Ops*/, /*OperandList*/0, // Ops = #1
// ISEL-SDAG: static const uint8_t OperandLists[] = {
// ISEL-SDAG-NEXT: /* 0 */ 1,
diff --git a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
index 71b41f60fbebd..c08d0668380a7 100644
--- a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -72,7 +72,9 @@ class MatcherTableEmitter {
std::vector<std::string> VecIncludeStrings;
MapVector<std::string, unsigned, StringMap<unsigned>> VecPatterns;
- std::map<ValueTypeByHwMode, unsigned> ValueTypeMap;
+ // Map from ValueTypeByHwMode to (Index, UsageCount) pair.
+ // Index is 1-based (0 means not yet assigned).
+ std::map<ValueTypeByHwMode, std::pair<unsigned, unsigned>> ValueTypeMap;
SequenceToOffsetTable<std::vector<uint8_t>> OperandTable;
@@ -118,6 +120,21 @@ class MatcherTableEmitter {
else if (auto *PM = dyn_cast<CheckPredicateMatcher>(N))
++PredicateUsage[PM->getPredicate().getOrigPatFragRecord()];
+ // Collect ValueTypeByHwMode usage for remapping.
+ if (auto *CTM = dyn_cast<CheckTypeMatcher>(N)) {
+ if (!CTM->getType().isSimple())
+ getValueTypeID(CTM->getType());
+ } else if (auto *CCTM = dyn_cast<CheckChildTypeMatcher>(N)) {
+ if (!CCTM->getType().isSimple())
+ getValueTypeID(CCTM->getType());
+ } else if (auto *EIM = dyn_cast<EmitIntegerMatcher>(N)) {
+ if (!EIM->getVT().isSimple())
+ getValueTypeID(EIM->getVT());
+ } else if (auto *ERM = dyn_cast<EmitRegisterMatcher>(N)) {
+ if (!ERM->getVT().isSimple())
+ getValueTypeID(ERM->getVT());
+ }
+
if (const auto *EN = dyn_cast<EmitNodeMatcherCommon>(N)) {
ArrayRef<unsigned> Ops = EN->getOperandList();
std::vector<uint8_t> OpBytes;
@@ -133,6 +150,8 @@ class MatcherTableEmitter {
};
Statistic(TheMatcherList);
+ sortValueTypeByHwModeByFrequency();
+
OperandTable.layout();
// Sort ComplexPatterns by usage.
@@ -204,6 +223,26 @@ class MatcherTableEmitter {
void EmitPatternMatchTable(raw_ostream &OS);
private:
+ // Reorder ValueType indices by usage frequency (most common -> index 0).
+ // Updates the indices directly in ValueTypeMap.
+ void sortValueTypeByHwModeByFrequency() {
+ if (ValueTypeMap.empty())
+ return;
+
+ // Collect pointers to map entries with their counts for sorting.
+ using EntryPtr = std::pair<unsigned, unsigned> *;
+ std::vector<EntryPtr> Entries;
+ for (auto &[VT, IdxAndCount] : ValueTypeMap)
+ Entries.push_back(&IdxAndCount);
+
+ // Sort by count descending.
+ llvm::sort(Entries,
+ [](EntryPtr A, EntryPtr B) { return A->second > B->second; });
+
+ // Assign new indices (1-based) in frequency order.
+ for (unsigned NewIdx = 0; NewIdx < Entries.size(); ++NewIdx)
+ Entries[NewIdx]->first = NewIdx + 1;
+ }
void EmitNodePredicatesFunction(const std::vector<TreePattern *> &Preds,
StringRef Decl, raw_ostream &OS);
@@ -239,15 +278,15 @@ class MatcherTableEmitter {
}
unsigned getValueTypeID(const ValueTypeByHwMode &VT) {
- unsigned &Entry = ValueTypeMap[VT];
- if (Entry == 0) {
- Entry = ValueTypeMap.size();
- if (Entry > 256)
+ auto &[Idx, Count] = ValueTypeMap[VT];
+ if (Idx == 0) {
+ Idx = ValueTypeMap.size();
+ if (Idx > 256)
report_fatal_error(
"More ValueType by HwMode than fit in a 8-bit index");
}
-
- return Entry - 1;
+ ++Count;
+ return Idx - 1;
}
unsigned emitValueTypeByHwMode(const ValueTypeByHwMode &VTBH,
@@ -739,15 +778,23 @@ unsigned MatcherTableEmitter::EmitMatcher(const Matcher *N,
return NumBytes + 2;
}
- unsigned OpSize = 1;
+ unsigned Idx = getValueTypeID(VTBH);
+ unsigned OpSize;
if (cast<CheckTypeMatcher>(N)->getResNo() == 0) {
- OS << "OPC_CheckTypeByHwMode, ";
+ if (Idx == 0) {
+ OS << "OPC_CheckTypeByHwMode0,";
+ OpSize = 1;
+ } else {
+ OS << "OPC_CheckTypeByHwMode, " << Idx << ",";
+ OpSize = 2;
+ }
} else {
OS << "OPC_CheckTypeResByHwMode, "
- << cast<CheckTypeMatcher>(N)->getResNo() << ", ";
- OpSize += 1;
+ << cast<CheckTypeMatcher>(N)->getResNo() << ", " << Idx << ",";
+ OpSize = 3;
}
- OpSize += emitValueTypeByHwMode(VTBH, OS);
+ if (!OmitComments)
+ OS << "/*" << VTBH << "*/";
OS << '\n';
return OpSize;
}
@@ -1405,7 +1452,8 @@ void MatcherTableEmitter::EmitValueTypeFunction(raw_ostream &OS) {
OS << " switch (Index) {\n";
OS << " default: llvm_unreachable(\"Unexpected index\");\n";
- for (const auto &[VTs, Idx] : ValueTypeMap) {
+ for (const auto &[VTs, IdxAndCount] : ValueTypeMap) {
+ const auto &[Idx, Count] = IdxAndCount;
OS << " case " << (Idx - 1) << ":\n";
if (VTs.isSimple()) {
OS << " return " << getEnumName(VTs.getSimple()) << ";\n";
More information about the llvm-commits
mailing list