Skip to content

Commit 384bc40

Browse files
authored
[TableGen][ISel] Add OPC_CheckTypeByHwMode0 to optimize the most frequent getValueTypeForHwMode index. (llvm#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
1 parent 7513fbd commit 384bc40

File tree

4 files changed

+77
-19
lines changed

4 files changed

+77
-19
lines changed

llvm/include/llvm/CodeGen/SelectionDAGISel.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ class SelectionDAGISel {
208208
OPC_CheckTypeI32,
209209
OPC_CheckTypeI64,
210210
OPC_CheckTypeByHwMode,
211+
// Space-optimized form that implicitly encodes index 0.
212+
OPC_CheckTypeByHwMode0,
211213
OPC_CheckTypeRes,
212214
OPC_CheckTypeResByHwMode,
213215
OPC_SwitchType,

llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3168,7 +3168,8 @@ static size_t IsPredicateKnownToFail(
31683168
case SelectionDAGISel::OPC_CheckType:
31693169
case SelectionDAGISel::OPC_CheckTypeI32:
31703170
case SelectionDAGISel::OPC_CheckTypeI64:
3171-
case SelectionDAGISel::OPC_CheckTypeByHwMode: {
3171+
case SelectionDAGISel::OPC_CheckTypeByHwMode:
3172+
case SelectionDAGISel::OPC_CheckTypeByHwMode0: {
31723173
MVT VT;
31733174
switch (Opcode) {
31743175
case SelectionDAGISel::OPC_CheckTypeI32:
@@ -3180,6 +3181,9 @@ static size_t IsPredicateKnownToFail(
31803181
case SelectionDAGISel::OPC_CheckTypeByHwMode:
31813182
VT = getHwModeVT(Table, Index, SDISel);
31823183
break;
3184+
case SelectionDAGISel::OPC_CheckTypeByHwMode0:
3185+
VT = SDISel.getValueTypeForHwMode(0);
3186+
break;
31833187
default:
31843188
VT = getSimpleVT(Table, Index);
31853189
break;
@@ -3756,7 +3760,8 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
37563760
case OPC_CheckType:
37573761
case OPC_CheckTypeI32:
37583762
case OPC_CheckTypeI64:
3759-
case OPC_CheckTypeByHwMode: {
3763+
case OPC_CheckTypeByHwMode:
3764+
case OPC_CheckTypeByHwMode0: {
37603765
MVT VT;
37613766
switch (Opcode) {
37623767
case OPC_CheckTypeI32:
@@ -3768,6 +3773,9 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
37683773
case OPC_CheckTypeByHwMode:
37693774
VT = getHwModeVT(MatcherTable, MatcherIndex, *this);
37703775
break;
3776+
case OPC_CheckTypeByHwMode0:
3777+
VT = getValueTypeForHwMode(0);
3778+
break;
37713779
default:
37723780
VT = getSimpleVT(MatcherTable, MatcherIndex);
37733781
break;

llvm/test/TableGen/RegClassByHwMode.td

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,9 @@ include "Common/RegClassByHwModeCommon.td"
205205
// ISEL-SDAG-NEXT: OPC_RecordMemRef,
206206
// ISEL-SDAG-NEXT: OPC_RecordNode, // #0 = 'st' chained node
207207
// ISEL-SDAG-NEXT: OPC_RecordChild1, // #1 = $val
208-
// ISEL-SDAG-NEXT: OPC_CheckChild1TypeByHwMode, /*{(*:i64),(m1:i64),(m2:i64)}*/0,
208+
// ISEL-SDAG-NEXT: OPC_CheckChild1TypeByHwMode, /*{(*:i64),(m1:i64),(m2:i64)}*/1,
209209
// ISEL-SDAG-NEXT: OPC_RecordChild2, // #2 = $src
210-
// ISEL-SDAG-NEXT: OPC_CheckChild2TypeByHwMode, /*{(*:i32),(m3:i64)}*/1,
210+
// ISEL-SDAG-NEXT: OPC_CheckChild2TypeByHwMode, /*{(*:i32),(m3:i64)}*/0,
211211
// ISEL-SDAG-NEXT: OPC_CheckPredicate0, // Predicate_unindexedstore
212212
// ISEL-SDAG-NEXT: OPC_CheckPredicate1, // Predicate_store
213213
// ISEL-SDAG-NEXT: OPC_EmitMergeInputChains1_0,
@@ -218,13 +218,13 @@ include "Common/RegClassByHwModeCommon.td"
218218
// ISEL-SDAG-NEXT: OPC_RecordMemRef,
219219
// ISEL-SDAG-NEXT: OPC_RecordNode, // #0 = 'ld' chained node
220220
// ISEL-SDAG-NEXT: OPC_RecordChild1, // #1 = $src
221-
// ISEL-SDAG-NEXT: OPC_CheckChild1TypeByHwMode, /*{(*:i32),(m3:i64)}*/1,
221+
// ISEL-SDAG-NEXT: OPC_CheckChild1TypeByHwMode, /*{(*:i32),(m3:i64)}*/0,
222222
// ISEL-SDAG-NEXT: OPC_CheckPredicate2, // Predicate_unindexedload
223223
// ISEL-SDAG-NEXT: OPC_CheckPredicate3, // Predicate_load
224224
// ISEL-SDAG-NEXT: OPC_CheckTypeI64,
225225
// ISEL-SDAG-NEXT: OPC_EmitMergeInputChains1_0,
226226
// ISEL-SDAG-NEXT: OPC_MorphNodeToByHwMode, TARGET_VAL(MyTarget::MY_LOAD), 0|OPFL_Chain|OPFL_MemRefs,
227-
// ISEL-SDAG-NEXT: 1/*#VTs*/, /*{(*:i64),(m1:i64),(m2:i64)}*/0, 1/*#Ops*/, /*OperandList*/0, // Ops = #1
227+
// ISEL-SDAG-NEXT: 1/*#VTs*/, /*{(*:i64),(m1:i64),(m2:i64)}*/1, 1/*#Ops*/, /*OperandList*/0, // Ops = #1
228228

229229
// ISEL-SDAG: static const uint8_t OperandLists[] = {
230230
// ISEL-SDAG-NEXT: /* 0 */ 1,

llvm/utils/TableGen/DAGISelMatcherEmitter.cpp

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ class MatcherTableEmitter {
7272
std::vector<std::string> VecIncludeStrings;
7373
MapVector<std::string, unsigned, StringMap<unsigned>> VecPatterns;
7474

75-
std::map<ValueTypeByHwMode, unsigned> ValueTypeMap;
75+
// Map from ValueTypeByHwMode to (Index, UsageCount) pair.
76+
// Index is 1-based (0 means not yet assigned).
77+
std::map<ValueTypeByHwMode, std::pair<unsigned, unsigned>> ValueTypeMap;
7678

7779
SequenceToOffsetTable<std::vector<uint8_t>> OperandTable;
7880

@@ -118,6 +120,21 @@ class MatcherTableEmitter {
118120
else if (auto *PM = dyn_cast<CheckPredicateMatcher>(N))
119121
++PredicateUsage[PM->getPredicate().getOrigPatFragRecord()];
120122

123+
// Collect ValueTypeByHwMode usage for remapping.
124+
if (auto *CTM = dyn_cast<CheckTypeMatcher>(N)) {
125+
if (!CTM->getType().isSimple())
126+
getValueTypeID(CTM->getType());
127+
} else if (auto *CCTM = dyn_cast<CheckChildTypeMatcher>(N)) {
128+
if (!CCTM->getType().isSimple())
129+
getValueTypeID(CCTM->getType());
130+
} else if (auto *EIM = dyn_cast<EmitIntegerMatcher>(N)) {
131+
if (!EIM->getVT().isSimple())
132+
getValueTypeID(EIM->getVT());
133+
} else if (auto *ERM = dyn_cast<EmitRegisterMatcher>(N)) {
134+
if (!ERM->getVT().isSimple())
135+
getValueTypeID(ERM->getVT());
136+
}
137+
121138
if (const auto *EN = dyn_cast<EmitNodeMatcherCommon>(N)) {
122139
ArrayRef<unsigned> Ops = EN->getOperandList();
123140
std::vector<uint8_t> OpBytes;
@@ -133,6 +150,8 @@ class MatcherTableEmitter {
133150
};
134151
Statistic(TheMatcherList);
135152

153+
sortValueTypeByHwModeByFrequency();
154+
136155
OperandTable.layout();
137156

138157
// Sort ComplexPatterns by usage.
@@ -204,6 +223,26 @@ class MatcherTableEmitter {
204223
void EmitPatternMatchTable(raw_ostream &OS);
205224

206225
private:
226+
// Reorder ValueType indices by usage frequency (most common -> index 0).
227+
// Updates the indices directly in ValueTypeMap.
228+
void sortValueTypeByHwModeByFrequency() {
229+
if (ValueTypeMap.empty())
230+
return;
231+
232+
// Collect pointers to map entries with their counts for sorting.
233+
using EntryPtr = std::pair<unsigned, unsigned> *;
234+
std::vector<EntryPtr> Entries;
235+
for (auto &[VT, IdxAndCount] : ValueTypeMap)
236+
Entries.push_back(&IdxAndCount);
237+
238+
// Sort by count descending.
239+
llvm::sort(Entries,
240+
[](EntryPtr A, EntryPtr B) { return A->second > B->second; });
241+
242+
// Assign new indices (1-based) in frequency order.
243+
for (unsigned NewIdx = 0; NewIdx < Entries.size(); ++NewIdx)
244+
Entries[NewIdx]->first = NewIdx + 1;
245+
}
207246
void EmitNodePredicatesFunction(const std::vector<TreePattern *> &Preds,
208247
StringRef Decl, raw_ostream &OS);
209248

@@ -239,15 +278,15 @@ class MatcherTableEmitter {
239278
}
240279

241280
unsigned getValueTypeID(const ValueTypeByHwMode &VT) {
242-
unsigned &Entry = ValueTypeMap[VT];
243-
if (Entry == 0) {
244-
Entry = ValueTypeMap.size();
245-
if (Entry > 256)
281+
auto &[Idx, Count] = ValueTypeMap[VT];
282+
if (Idx == 0) {
283+
Idx = ValueTypeMap.size();
284+
if (Idx > 256)
246285
report_fatal_error(
247286
"More ValueType by HwMode than fit in a 8-bit index");
248287
}
249-
250-
return Entry - 1;
288+
++Count;
289+
return Idx - 1;
251290
}
252291

253292
unsigned emitValueTypeByHwMode(const ValueTypeByHwMode &VTBH,
@@ -739,15 +778,23 @@ unsigned MatcherTableEmitter::EmitMatcher(const Matcher *N,
739778
return NumBytes + 2;
740779
}
741780

742-
unsigned OpSize = 1;
781+
unsigned Idx = getValueTypeID(VTBH);
782+
unsigned OpSize;
743783
if (cast<CheckTypeMatcher>(N)->getResNo() == 0) {
744-
OS << "OPC_CheckTypeByHwMode, ";
784+
if (Idx == 0) {
785+
OS << "OPC_CheckTypeByHwMode0,";
786+
OpSize = 1;
787+
} else {
788+
OS << "OPC_CheckTypeByHwMode, " << Idx << ",";
789+
OpSize = 2;
790+
}
745791
} else {
746792
OS << "OPC_CheckTypeResByHwMode, "
747-
<< cast<CheckTypeMatcher>(N)->getResNo() << ", ";
748-
OpSize += 1;
793+
<< cast<CheckTypeMatcher>(N)->getResNo() << ", " << Idx << ",";
794+
OpSize = 3;
749795
}
750-
OpSize += emitValueTypeByHwMode(VTBH, OS);
796+
if (!OmitComments)
797+
OS << "/*" << VTBH << "*/";
751798
OS << '\n';
752799
return OpSize;
753800
}
@@ -1405,7 +1452,8 @@ void MatcherTableEmitter::EmitValueTypeFunction(raw_ostream &OS) {
14051452
OS << " switch (Index) {\n";
14061453
OS << " default: llvm_unreachable(\"Unexpected index\");\n";
14071454

1408-
for (const auto &[VTs, Idx] : ValueTypeMap) {
1455+
for (const auto &[VTs, IdxAndCount] : ValueTypeMap) {
1456+
const auto &[Idx, Count] = IdxAndCount;
14091457
OS << " case " << (Idx - 1) << ":\n";
14101458
if (VTs.isSimple()) {
14111459
OS << " return " << getEnumName(VTs.getSimple()) << ";\n";

0 commit comments

Comments
 (0)