[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