[llvm-branch-commits] [llvm] [GlobalISel] Recursively Optimise MatchTable Matchers (PR #197143)

Pierre van Houtryve via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue May 12 05:12:40 PDT 2026


https://github.com/Pierre-vh updated https://github.com/llvm/llvm-project/pull/197143

>From 13960994418b0079bb70bc6a5b1e7fec3c84c86f Mon Sep 17 00:00:00 2001
From: pvanhout <pierre.vanhoutryve at amd.com>
Date: Tue, 12 May 2026 11:08:12 +0200
Subject: [PATCH 1/3] [GlobalISel] Recursively Optimise MatchTable Matchers

The core of this change is the additional call to `Matcher::optimize()` in the `optimizeRules` function,
which enables the match table optimization logic to recurse on the children of every GroupMatcher, forming
additional groups (which hoist more common predicates into a shared group).

To enable that, I had to update the `getFirstConditionAsRootType` implementation to support `GroupMatcher`.
I also included a small refactoring of the match table optimization pipeline that was identical between the
GlobalISel and GlobalISelCombiner emitters.

The results of this change are up to a 25% size reduction for GlobalISel match tables.
There is a tiny increase (a few bytes) in a combiner table because we now create new groups
(which need up to 3 additional opcodes because of the new `Try` and `Reject` required) to hoist one predicate for only 2 rules, which
result in a small net negative change (one or two more ops).

I used a small bash script to compare all relevant files, this is the before/after:
```
FILE                                          OLD      NEW    DIFF%    SAME?
----                                      -------  -------    -----    -----
AArch64GenGlobalISel.inc                   202434   192045    -5,1%       no
AArch64GenPostLegalizeGICombiner.inc         4428     4432     0,1%       no
AArch64GenPreLegalizeGICombiner.inc          8974     8977     0,0%       no
AMDGPUGenGlobalISel.inc                    789379   590082   -25,2%       no
AMDGPUGenPostLegalizeGICombiner.inc          9203     9207     0,0%       no
AMDGPUGenPreLegalizeGICombiner.inc           8950     8954     0,0%       no
AMDGPUGenRegBankGICombiner.inc               1981     1981     0,0%      yes
```
---
 .../GlobalISel/preselect-process-phis.mir     |   3 +
 .../select-intrinsic-aarch64-sdiv.mir         |  18 ++
 .../MatchTableOptimizerRecursion.td           | 204 ++++++++++++++++++
 .../GlobalISel/GlobalISelMatchTable.cpp       |  86 ++++++--
 .../Common/GlobalISel/GlobalISelMatchTable.h  |  19 +-
 .../TableGen/GlobalISelCombinerEmitter.cpp    |  35 +--
 llvm/utils/TableGen/GlobalISelEmitter.cpp     |  39 +---
 7 files changed, 310 insertions(+), 94 deletions(-)
 create mode 100644 llvm/test/TableGen/GlobalISelEmitter/MatchTableOptimizerRecursion.td

diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir b/llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir
index d59ffff8e5629..9c9ae861fd8e3 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir
@@ -1,5 +1,8 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 # RUN: llc -verify-machineinstrs -mtriple aarch64--- --run-pass=instruction-select -global-isel-abort=1 %s -o - | FileCheck %s
+
+# XFAIL: *
+
 ---
 name:            test_loop_phi_fpr_to_gpr
 alignment:       4
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-intrinsic-aarch64-sdiv.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-intrinsic-aarch64-sdiv.mir
index 2dc8c9d4772df..82b5eff9b66a0 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/select-intrinsic-aarch64-sdiv.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-intrinsic-aarch64-sdiv.mir
@@ -1,6 +1,24 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 # RUN: llc -mtriple=aarch64-- -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
 
+# XFAIL: *
+
+# MatchTable Before:
+#   /* 268430 */ GIM_Try, /*On fail goto*//*Label 4045*/ GIMT_Encode4(268475), // Rule ID 4220 //
+#   /* 268435 */   GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
+#   /* 268438 */   GIM_CheckIntrinsicID, /*MI*/0, /*Op*/1, GIMT_Encode2(Intrinsic::aarch64_sdiv),
+#   /* 268443 */   GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_i32,
+#   /* 268446 */   GIM_RootCheckType, /*Op*/2, /*Type*/GILLT_i32,
+#   /* 268449 */   GIM_RootCheckType, /*Op*/3, /*Type*/GILLT_i32,
+#
+# MatchTable After:
+#   /* 241275 */     GIM_SwitchType, /*MI*/0, /*Op*/0, /*[*/GIMT_Encode2(7), GIMT_Encode2(9), /*)*//*default:*//*Label 6365*/ GIMT_Encode4(241364),
+#   /* 241286 */     /*GILLT_i32*//*Label 6363*/ GIMT_Encode4(241294),
+#   /* 241290 */     /*GILLT_i64*//*Label 6364*/ GIMT_Encode4(241329),
+#
+# Matching fails because type is S32 (index 2), but switch wants i32 (index 7).
+
+
 --- |
   target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
 
diff --git a/llvm/test/TableGen/GlobalISelEmitter/MatchTableOptimizerRecursion.td b/llvm/test/TableGen/GlobalISelEmitter/MatchTableOptimizerRecursion.td
new file mode 100644
index 0000000000000..0beda69a843c4
--- /dev/null
+++ b/llvm/test/TableGen/GlobalISelEmitter/MatchTableOptimizerRecursion.td
@@ -0,0 +1,204 @@
+// RUN: llvm-tblgen %s -gen-global-isel -optimize-match-table=true -I %p/../../../include -I %p/../Common | FileCheck %s
+
+include "llvm/Target/Target.td"
+include "GlobalISelEmitterCommon.td"
+
+// Check the MatchTable recursively optimizes to maximize group formation.
+
+def InstFourOperands : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, GPR32:$src4), []>;
+
+def S0 : Register<"s0"> { let Namespace = "MyTarget"; }
+def S1 : Register<"s1"> { let Namespace = "MyTarget"; }
+def Z0 : Register<"s1"> { let Namespace = "MyTarget"; }
+def Z1 : Register<"s1"> { let Namespace = "MyTarget"; }
+
+def GPR8_A     : RegisterClass<"MyTarget", [i8], 8, (add Z0)>;
+def LOAD8_A    : I<(outs GPR8_A:$dst), (ins GPR8_A:$src), []>;
+def LOAD8Imm_A : I<(outs GPR8_A:$dst), (ins GPR8_A:$src), []>;
+
+def GPR8_B     : RegisterClass<"MyTarget", [i8], 8, (add Z1)>;
+def LOAD8_B    : I<(outs GPR8_B:$dst), (ins GPR8_B:$src), []>;
+def LOAD8Imm_B : I<(outs GPR8_B:$dst), (ins GPR8_B:$src), []>;
+
+def GPR16_A     : RegisterClass<"MyTarget", [i16], 16, (add S0)>;
+def LOAD16_A    : I<(outs GPR16_A:$dst), (ins GPR16_A:$src), []>;
+def LOAD16Imm_A : I<(outs GPR16_A:$dst), (ins GPR16_A:$src), []>;
+
+def GPR16_B     : RegisterClass<"MyTarget", [i16], 16, (add S0)>;
+def LOAD16_B    : I<(outs GPR16_B:$dst), (ins GPR16_B:$src), []>;
+def LOAD16Imm_B : I<(outs GPR16_B:$dst), (ins GPR16_B:$src), []>;
+
+
+def : Pat<(i8 (load GPR8_A:$src)),
+          (LOAD8_A GPR8_A:$src)>;
+def : Pat<(i8 (load GPR8_B:$src)),
+          (LOAD8_B GPR8_B:$src)>;
+
+def : Pat<(i8 (load (add GPR8_A:$src, 10))),
+          (LOAD8Imm_A GPR8_A:$src)>;
+def : Pat<(i8 (load (add GPR8_B:$src, 10))),
+          (LOAD8Imm_B GPR8_B:$src)>;
+
+def : Pat<(i16 (load GPR16_A:$src)),
+          (LOAD16_A GPR16_A:$src)>;
+def : Pat<(i16 (load GPR16_B:$src)),
+          (LOAD16_B GPR16_B:$src)>;
+
+def : Pat<(i16 (load (add GPR16_A:$src, 10))),
+          (LOAD16Imm_A GPR16_A:$src)>;
+def : Pat<(i16 (load (add GPR16_B:$src, 10))),
+          (LOAD16Imm_B GPR16_B:$src)>;
+
+
+// CHECK:      const uint8_t *MyTargetInstructionSelector::getMatchTable() const {
+// CHECK-NEXT:   constexpr static uint8_t MatchTable0[] = {
+// CHECK-NEXT:      /*   0 */ GIM_Try, /*On fail goto*//*Label 0*/ GIMT_Encode4(377),
+// CHECK-NEXT:      /*   5 */   GIM_CheckOpcode, /*MI*/0, GIMT_Encode2(TargetOpcode::G_LOAD),
+// CHECK-NEXT:      /*   9 */   GIM_SwitchType, /*MI*/0, /*Op*/0, /*[*/GIMT_Encode2(0), GIMT_Encode2(2), /*)*//*default:*//*Label 3*/ GIMT_Encode4(376),
+// CHECK-NEXT:      /*  20 */   /*GILLT_s8*//*Label 1*/ GIMT_Encode4(28),
+// CHECK-NEXT:      /*  24 */   /*GILLT_s16*//*Label 2*/ GIMT_Encode4(202),
+// CHECK-NEXT:      /*  28 */   // Label 1: @28
+// CHECK-NEXT:      /*  28 */   GIM_Try, /*On fail goto*//*Label 4*/ GIMT_Encode4(201),
+// CHECK-NEXT:      /*  33 */     GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
+// CHECK-NEXT:      /*  36 */     GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
+// CHECK-NEXT:      /*  40 */     GIM_Try, /*On fail goto*//*Label 5*/ GIMT_Encode4(96), // Rule ID 2 //
+// CHECK-NEXT:      /*  45 */       GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR8_ARegClassID),
+// CHECK-NEXT:      /*  49 */       // MIs[0] Operand 1
+// CHECK-NEXT:      /*  49 */       GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/8,
+// CHECK-NEXT:      /*  53 */       GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
+// CHECK-NEXT:      /*  57 */       GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_ADD),
+// CHECK-NEXT:      /*  61 */       GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s8,
+// CHECK-NEXT:      /*  65 */       GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s8,
+// CHECK-NEXT:      /*  69 */       GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR8_ARegClassID),
+// CHECK-NEXT:      /*  74 */       GIM_CheckConstantInt8, /*MI*/1, /*Op*/2, 10,
+// CHECK-NEXT:      /*  78 */       GIM_CheckIsSafeToFold, /*NumInsns*/1,
+// CHECK-NEXT:      /*  80 */       // (ld:{ *:[i8] } (add:{ *:[i8] } GPR8_A:{ *:[i8] }:$src, 10:{ *:[i8] }))<<P:Predicate_unindexedload>><<P:Predicate_load>>  =>  (LOAD8Imm_A:{ *:[i8] } GPR8_A:{ *:[i8] }:$src)
+// CHECK-NEXT:      /*  80 */       GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::LOAD8Imm_A),
+// CHECK-NEXT:      /*  83 */       GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]
+// CHECK-NEXT:      /*  85 */       GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src
+// CHECK-NEXT:      /*  89 */       GIR_MergeMemOperands, /*InsnID*/0, /*NumInsns*/2, /*MergeInsnID's*/0, 1,
+// CHECK-NEXT:      /*  94 */       GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT:      /*  95 */       // GIR_Coverage, 2,
+// CHECK-NEXT:      /*  95 */       GIR_EraseRootFromParent_Done,
+// CHECK-NEXT:      /*  96 */     // Label 5: @96
+// CHECK-NEXT:      /*  96 */     GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4(152), // Rule ID 3 //
+// CHECK-NEXT:      /* 101 */       GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR8_BRegClassID),
+// CHECK-NEXT:      /* 105 */       // MIs[0] Operand 1
+// CHECK-NEXT:      /* 105 */       GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/8,
+// CHECK-NEXT:      /* 109 */       GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
+// CHECK-NEXT:      /* 113 */       GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_ADD),
+// CHECK-NEXT:      /* 117 */       GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s8,
+// CHECK-NEXT:      /* 121 */       GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s8,
+// CHECK-NEXT:      /* 125 */       GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR8_BRegClassID),
+// CHECK-NEXT:      /* 130 */       GIM_CheckConstantInt8, /*MI*/1, /*Op*/2, 10,
+// CHECK-NEXT:      /* 134 */       GIM_CheckIsSafeToFold, /*NumInsns*/1,
+// CHECK-NEXT:      /* 136 */       // (ld:{ *:[i8] } (add:{ *:[i8] } GPR8_B:{ *:[i8] }:$src, 10:{ *:[i8] }))<<P:Predicate_unindexedload>><<P:Predicate_load>>  =>  (LOAD8Imm_B:{ *:[i8] } GPR8_B:{ *:[i8] }:$src)
+// CHECK-NEXT:      /* 136 */       GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::LOAD8Imm_B),
+// CHECK-NEXT:      /* 139 */       GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]
+// CHECK-NEXT:      /* 141 */       GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src
+// CHECK-NEXT:      /* 145 */       GIR_MergeMemOperands, /*InsnID*/0, /*NumInsns*/2, /*MergeInsnID's*/0, 1,
+// CHECK-NEXT:      /* 150 */       GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT:      /* 151 */       // GIR_Coverage, 3,
+// CHECK-NEXT:      /* 151 */       GIR_EraseRootFromParent_Done,
+// CHECK-NEXT:      /* 152 */     // Label 6: @152
+// CHECK-NEXT:      /* 152 */     GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(176), // Rule ID 0 //
+// CHECK-NEXT:      /* 157 */       GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR8_ARegClassID),
+// CHECK-NEXT:      /* 161 */       // MIs[0] src
+// CHECK-NEXT:      /* 161 */       GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/8,
+// CHECK-NEXT:      /* 165 */       GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR8_ARegClassID),
+// CHECK-NEXT:      /* 169 */       // (ld:{ *:[i8] } GPR8_A:{ *:[i8] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>>  =>  (LOAD8_A:{ *:[i8] } GPR8_A:{ *:[i8] }:$src)
+// CHECK-NEXT:      /* 169 */       GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::LOAD8_A),
+// CHECK-NEXT:      /* 174 */       GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT:      /* 175 */       // GIR_Coverage, 0,
+// CHECK-NEXT:      /* 175 */       GIR_Done,
+// CHECK-NEXT:      /* 176 */     // Label 7: @176
+// CHECK-NEXT:      /* 176 */     GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(200), // Rule ID 1 //
+// CHECK-NEXT:      /* 181 */       GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR8_BRegClassID),
+// CHECK-NEXT:      /* 185 */       // MIs[0] src
+// CHECK-NEXT:      /* 185 */       GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/8,
+// CHECK-NEXT:      /* 189 */       GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR8_BRegClassID),
+// CHECK-NEXT:      /* 193 */       // (ld:{ *:[i8] } GPR8_B:{ *:[i8] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>>  =>  (LOAD8_B:{ *:[i8] } GPR8_B:{ *:[i8] }:$src)
+// CHECK-NEXT:      /* 193 */       GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::LOAD8_B),
+// CHECK-NEXT:      /* 198 */       GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT:      /* 199 */       // GIR_Coverage, 1,
+// CHECK-NEXT:      /* 199 */       GIR_Done,
+// CHECK-NEXT:      /* 200 */     // Label 8: @200
+// CHECK-NEXT:      /* 200 */     GIM_Reject,
+// CHECK-NEXT:      /* 201 */   // Label 4: @201
+// CHECK-NEXT:      /* 201 */   GIM_Reject,
+// CHECK-NEXT:      /* 202 */   // Label 2: @202
+// CHECK-NEXT:      /* 202 */   GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4(375),
+// CHECK-NEXT:      /* 207 */     GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
+// CHECK-NEXT:      /* 210 */     GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
+// CHECK-NEXT:      /* 214 */     GIM_Try, /*On fail goto*//*Label 10*/ GIMT_Encode4(270), // Rule ID 6 //
+// CHECK-NEXT:      /* 219 */       GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR16_ARegClassID),
+// CHECK-NEXT:      /* 223 */       // MIs[0] Operand 1
+// CHECK-NEXT:      /* 223 */       GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/16,
+// CHECK-NEXT:      /* 227 */       GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
+// CHECK-NEXT:      /* 231 */       GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_ADD),
+// CHECK-NEXT:      /* 235 */       GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s16,
+// CHECK-NEXT:      /* 239 */       GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s16,
+// CHECK-NEXT:      /* 243 */       GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR16_ARegClassID),
+// CHECK-NEXT:      /* 248 */       GIM_CheckConstantInt8, /*MI*/1, /*Op*/2, 10,
+// CHECK-NEXT:      /* 252 */       GIM_CheckIsSafeToFold, /*NumInsns*/1,
+// CHECK-NEXT:      /* 254 */       // (ld:{ *:[i16] } (add:{ *:[i16] } GPR16_A:{ *:[i16] }:$src, 10:{ *:[i16] }))<<P:Predicate_unindexedload>><<P:Predicate_load>>  =>  (LOAD16Imm_A:{ *:[i16] } GPR16_A:{ *:[i16] }:$src)
+// CHECK-NEXT:      /* 254 */       GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::LOAD16Imm_A),
+// CHECK-NEXT:      /* 257 */       GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]
+// CHECK-NEXT:      /* 259 */       GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src
+// CHECK-NEXT:      /* 263 */       GIR_MergeMemOperands, /*InsnID*/0, /*NumInsns*/2, /*MergeInsnID's*/0, 1,
+// CHECK-NEXT:      /* 268 */       GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT:      /* 269 */       // GIR_Coverage, 6,
+// CHECK-NEXT:      /* 269 */       GIR_EraseRootFromParent_Done,
+// CHECK-NEXT:      /* 270 */     // Label 10: @270
+// CHECK-NEXT:      /* 270 */     GIM_Try, /*On fail goto*//*Label 11*/ GIMT_Encode4(326), // Rule ID 7 //
+// CHECK-NEXT:      /* 275 */       GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR16_BRegClassID),
+// CHECK-NEXT:      /* 279 */       // MIs[0] Operand 1
+// CHECK-NEXT:      /* 279 */       GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/16,
+// CHECK-NEXT:      /* 283 */       GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
+// CHECK-NEXT:      /* 287 */       GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_ADD),
+// CHECK-NEXT:      /* 291 */       GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s16,
+// CHECK-NEXT:      /* 295 */       GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s16,
+// CHECK-NEXT:      /* 299 */       GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR16_BRegClassID),
+// CHECK-NEXT:      /* 304 */       GIM_CheckConstantInt8, /*MI*/1, /*Op*/2, 10,
+// CHECK-NEXT:      /* 308 */       GIM_CheckIsSafeToFold, /*NumInsns*/1,
+// CHECK-NEXT:      /* 310 */       // (ld:{ *:[i16] } (add:{ *:[i16] } GPR16_B:{ *:[i16] }:$src, 10:{ *:[i16] }))<<P:Predicate_unindexedload>><<P:Predicate_load>>  =>  (LOAD16Imm_B:{ *:[i16] } GPR16_B:{ *:[i16] }:$src)
+// CHECK-NEXT:      /* 310 */       GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::LOAD16Imm_B),
+// CHECK-NEXT:      /* 313 */       GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]
+// CHECK-NEXT:      /* 315 */       GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src
+// CHECK-NEXT:      /* 319 */       GIR_MergeMemOperands, /*InsnID*/0, /*NumInsns*/2, /*MergeInsnID's*/0, 1,
+// CHECK-NEXT:      /* 324 */       GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT:      /* 325 */       // GIR_Coverage, 7,
+// CHECK-NEXT:      /* 325 */       GIR_EraseRootFromParent_Done,
+// CHECK-NEXT:      /* 326 */     // Label 11: @326
+// CHECK-NEXT:      /* 326 */     GIM_Try, /*On fail goto*//*Label 12*/ GIMT_Encode4(350), // Rule ID 4 //
+// CHECK-NEXT:      /* 331 */       GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR16_ARegClassID),
+// CHECK-NEXT:      /* 335 */       // MIs[0] src
+// CHECK-NEXT:      /* 335 */       GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/16,
+// CHECK-NEXT:      /* 339 */       GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR16_ARegClassID),
+// CHECK-NEXT:      /* 343 */       // (ld:{ *:[i16] } GPR16_A:{ *:[i16] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>>  =>  (LOAD16_A:{ *:[i16] } GPR16_A:{ *:[i16] }:$src)
+// CHECK-NEXT:      /* 343 */       GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::LOAD16_A),
+// CHECK-NEXT:      /* 348 */       GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT:      /* 349 */       // GIR_Coverage, 4,
+// CHECK-NEXT:      /* 349 */       GIR_Done,
+// CHECK-NEXT:      /* 350 */     // Label 12: @350
+// CHECK-NEXT:      /* 350 */     GIM_Try, /*On fail goto*//*Label 13*/ GIMT_Encode4(374), // Rule ID 5 //
+// CHECK-NEXT:      /* 355 */       GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR16_BRegClassID),
+// CHECK-NEXT:      /* 359 */       // MIs[0] src
+// CHECK-NEXT:      /* 359 */       GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/16,
+// CHECK-NEXT:      /* 363 */       GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR16_BRegClassID),
+// CHECK-NEXT:      /* 367 */       // (ld:{ *:[i16] } GPR16_B:{ *:[i16] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>>  =>  (LOAD16_B:{ *:[i16] } GPR16_B:{ *:[i16] }:$src)
+// CHECK-NEXT:      /* 367 */       GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::LOAD16_B),
+// CHECK-NEXT:      /* 372 */       GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT:      /* 373 */       // GIR_Coverage, 5,
+// CHECK-NEXT:      /* 373 */       GIR_Done,
+// CHECK-NEXT:      /* 374 */     // Label 13: @374
+// CHECK-NEXT:      /* 374 */     GIM_Reject,
+// CHECK-NEXT:      /* 375 */   // Label 9: @375
+// CHECK-NEXT:      /* 375 */   GIM_Reject,
+// CHECK-NEXT:      /* 376 */   // Label 3: @376
+// CHECK-NEXT:      /* 376 */   GIM_Reject,
+// CHECK-NEXT:      /* 377 */ // Label 0: @377
+// CHECK-NEXT:      /* 377 */ GIM_Reject,
+// CHECK-NEXT:      /* 378 */ }; // Size: 378 bytes
+// CHECK-NEXT:   return MatchTable0;
+// CHECK-NEXT: }
diff --git a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
index ab20eb6e2f790..d34388839e4a3 100644
--- a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
+++ b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
@@ -93,10 +93,11 @@ llvm::gi::getNameForFeatureBitset(ArrayRef<const Record *> FeatureBitset,
 }
 
 template <class GroupT>
-std::vector<Matcher *>
-llvm::gi::optimizeRules(ArrayRef<Matcher *> Rules,
-                        std::vector<std::unique_ptr<Matcher>> &MatcherStorage) {
+static std::vector<Matcher *>
+optimizeRules(ArrayRef<Matcher *> Rules,
+              std::vector<std::unique_ptr<Matcher>> &MatcherStorage) {
 
+  std::vector<Matcher *> Worklist(Rules.begin(), Rules.end());
   std::vector<Matcher *> OptRules;
   std::unique_ptr<GroupT> CurrentGroup = std::make_unique<GroupT>();
   assert(CurrentGroup->empty() && "Newly created group isn't empty!");
@@ -114,13 +115,15 @@ llvm::gi::optimizeRules(ArrayRef<Matcher *> Rules,
       append_range(OptRules, CurrentGroup->matchers());
     else {
       CurrentGroup->finalize();
+      CurrentGroup->optimize();
       OptRules.push_back(CurrentGroup.get());
       MatcherStorage.emplace_back(std::move(CurrentGroup));
       ++NumGroups;
     }
     CurrentGroup = std::make_unique<GroupT>();
   };
-  for (Matcher *Rule : Rules) {
+
+  for (Matcher *Rule : Worklist) {
     // Greedily add as many matchers as possible to the current group:
     if (CurrentGroup->addMatcher(*Rule))
       continue;
@@ -136,19 +139,50 @@ llvm::gi::optimizeRules(ArrayRef<Matcher *> Rules,
   }
   ProcessCurrentGroup();
 
+  assert(OptRules.size() <= Worklist.size() && "Optimization added rules?");
   LLVM_DEBUG(dbgs() << "NumGroups: " << NumGroups << "\n");
   (void)NumGroups;
   assert(CurrentGroup->empty() && "The last group wasn't properly processed");
   return OptRules;
 }
 
-template std::vector<Matcher *> llvm::gi::optimizeRules<GroupMatcher>(
-    ArrayRef<Matcher *> Rules,
-    std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
+std::vector<Matcher *> llvm::gi::optimizeRuleset(
+    MutableArrayRef<RuleMatcher> Rules,
+    std::vector<std::unique_ptr<Matcher>> &MatcherStorage) {
+  std::vector<Matcher *> InputRules;
+  InputRules.reserve(Rules.size());
+  for (RuleMatcher &Rule : Rules)
+    InputRules.push_back(&Rule);
+
+  // Now sort the Rules.
+  unsigned CurrentOrdering = 0;
+  StringMap<unsigned> OpcodeOrder;
+  for (RuleMatcher &Rule : Rules) {
+    const StringRef Opcode = Rule.getOpcode();
+    assert(!Opcode.empty() && "Didn't expect an undefined opcode");
+    if (OpcodeOrder.try_emplace(Opcode, CurrentOrdering).second)
+      ++CurrentOrdering;
+  }
+
+  llvm::stable_sort(
+      InputRules, [&OpcodeOrder](const Matcher *A, const Matcher *B) {
+        const auto *L = cast<RuleMatcher>(A);
+        const auto *R = cast<RuleMatcher>(B);
+        return std::tuple(OpcodeOrder[L->getOpcode()],
+                          L->insnmatchers_front().getNumOperandMatchers()) <
+               std::tuple(OpcodeOrder[R->getOpcode()],
+                          R->insnmatchers_front().getNumOperandMatchers());
+      });
+
+  for (Matcher *R : InputRules)
+    R->optimize();
 
-template std::vector<Matcher *> llvm::gi::optimizeRules<SwitchMatcher>(
-    ArrayRef<Matcher *> Rules,
-    std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
+  // Then form groups, and switches in that order.
+  std::vector<Matcher *> OptRules =
+      optimizeRules<GroupMatcher>(InputRules, MatcherStorage);
+  OptRules = optimizeRules<SwitchMatcher>(OptRules, MatcherStorage);
+  return OptRules;
+}
 
 static std::string getEncodedEmitStr(StringRef NamedValue, unsigned NumBytes) {
   if (NumBytes == 2 || NumBytes == 4 || NumBytes == 8)
@@ -603,21 +637,20 @@ void GroupMatcher::emit(MatchTable &Table) {
 void GroupMatcher::optimize() {
   // Make sure we only sort by a specific predicate within a range of rules that
   // all have that predicate checked against a specific value (not a wildcard):
+  // TODO: Is this even relevant ? Check diffs w/ just using a simple sort
+  // instead of this.
   auto F = Matchers.begin();
   auto T = F;
   auto E = Matchers.end();
   while (T != E) {
     while (T != E) {
-      auto *R = static_cast<RuleMatcher *>(*T);
-      if (!R->getFirstConditionAsRootType().get().isValid())
+      if (!(*T)->getFirstConditionAsRootType().get().isValid())
         break;
       ++T;
     }
     std::stable_sort(F, T, [](Matcher *A, Matcher *B) {
-      auto *L = static_cast<RuleMatcher *>(A);
-      auto *R = static_cast<RuleMatcher *>(B);
-      return L->getFirstConditionAsRootType() <
-             R->getFirstConditionAsRootType();
+      return A->getFirstConditionAsRootType() <
+             B->getFirstConditionAsRootType();
     });
     if (T != E)
       F = ++T;
@@ -626,6 +659,19 @@ void GroupMatcher::optimize() {
   Matchers = optimizeRules<SwitchMatcher>(Matchers, MatcherStorage);
 }
 
+LLTCodeGen GroupMatcher::getFirstConditionAsRootType() const {
+  if (!hasFirstCondition())
+    return {};
+
+  const PredicateMatcher &PM = *Conditions.front();
+  if (const auto *TM = dyn_cast<LLTOperandMatcher>(&PM)) {
+    if (TM->getInsnVarID() == 0 && TM->getOpIdx() == 0)
+      return TM->getTy();
+  }
+
+  return {};
+}
+
 //===- SwitchMatcher ------------------------------------------------------===//
 
 SwitchMatcher::SwitchMatcher() : Matcher(MK_Switch) {}
@@ -817,13 +863,15 @@ bool RuleMatcher::recordsOperand() const {
   return matchersRecordOperand(Matchers);
 }
 
-LLTCodeGen RuleMatcher::getFirstConditionAsRootType() {
+LLTCodeGen RuleMatcher::getFirstConditionAsRootType() const {
   InstructionMatcher &InsnMatcher = *Matchers.front();
-  if (!InsnMatcher.predicates_empty())
+  if (!InsnMatcher.predicates_empty()) {
     if (const auto *TM =
-            dyn_cast<LLTOperandMatcher>(&**InsnMatcher.predicates_begin()))
+            dyn_cast<LLTOperandMatcher>(&**InsnMatcher.predicates_begin())) {
       if (TM->getInsnVarID() == 0 && TM->getOpIdx() == 0)
         return TM->getTy();
+    }
+  }
   return {};
 }
 
diff --git a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
index 543fd0a457939..5d1dc889f8523 100644
--- a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
+++ b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
@@ -47,6 +47,7 @@ class CodeGenRegisterClass;
 namespace gi {
 class MatchTable;
 class Matcher;
+class RuleMatcher;
 class OperandMatcher;
 class MatchAction;
 class PredicateMatcher;
@@ -70,8 +71,7 @@ std::string getNameForFeatureBitset(ArrayRef<const Record *> FeatureBitset,
 /// they share. \p MatcherStorage is used as a memory container
 /// for the group that are created as part of this process.
 ///
-/// What this optimization does looks like if GroupT = GroupMatcher:
-/// Output without optimization:
+/// Example of GroupMatcher formation via this function:
 /// \verbatim
 /// # R1
 ///  # predicate A
@@ -91,10 +91,9 @@ std::string getNameForFeatureBitset(ArrayRef<const Record *> FeatureBitset,
 ///  # R2
 ///   # predicate C
 /// \endverbatim
-template <class GroupT>
 std::vector<Matcher *>
-optimizeRules(ArrayRef<Matcher *> Rules,
-              std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
+optimizeRuleset(MutableArrayRef<RuleMatcher> Rules,
+                std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
 
 /// A record to be stored in a MatchTable.
 ///
@@ -323,6 +322,7 @@ class Matcher {
 
   virtual bool hasFirstCondition() const = 0;
   virtual const PredicateMatcher &getFirstCondition() const = 0;
+  virtual LLTCodeGen getFirstConditionAsRootType() const = 0;
   virtual std::unique_ptr<PredicateMatcher> popFirstCondition() = 0;
 
   /// Check recursively if the matcher records named operands for use in C++
@@ -394,6 +394,7 @@ class GroupMatcher final : public Matcher {
            "Trying to get a condition from a condition-less group");
     return *Conditions.front();
   }
+  LLTCodeGen getFirstConditionAsRootType() const override;
   bool hasFirstCondition() const override { return !Conditions.empty(); }
 
   bool recordsOperand() const override;
@@ -469,7 +470,11 @@ class SwitchMatcher : public Matcher {
   }
 
   const PredicateMatcher &getFirstCondition() const override {
-    llvm_unreachable("Trying to pop a condition from a condition-less group");
+    llvm_unreachable("Trying to get a condition from a condition-less group");
+  }
+
+  LLTCodeGen getFirstConditionAsRootType() const override {
+    llvm_unreachable("Trying to get a condition from a condition-less group");
   }
 
   bool hasFirstCondition() const override { return false; }
@@ -720,7 +725,7 @@ class RuleMatcher : public Matcher {
 
   std::unique_ptr<PredicateMatcher> popFirstCondition() override;
   const PredicateMatcher &getFirstCondition() const override;
-  LLTCodeGen getFirstConditionAsRootType();
+  LLTCodeGen getFirstConditionAsRootType() const override;
   bool hasFirstCondition() const override;
   StringRef getOpcode() const;
 
diff --git a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
index e01f2a2685049..deb126cbd716a 100644
--- a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
@@ -2712,41 +2712,8 @@ GICombinerEmitter::GICombinerEmitter(const RecordKeeper &RK,
 
 MatchTable
 GICombinerEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules) {
-  std::vector<Matcher *> InputRules;
-  for (Matcher &Rule : Rules)
-    InputRules.push_back(&Rule);
-
-  unsigned CurrentOrdering = 0;
-  StringMap<unsigned> OpcodeOrder;
-  for (RuleMatcher &Rule : Rules) {
-    const StringRef Opcode = Rule.getOpcode();
-    assert(!Opcode.empty() && "Didn't expect an undefined opcode");
-    if (OpcodeOrder.try_emplace(Opcode, CurrentOrdering).second)
-      ++CurrentOrdering;
-  }
-
-  llvm::stable_sort(InputRules, [&OpcodeOrder](const Matcher *A,
-                                               const Matcher *B) {
-    auto *L = static_cast<const RuleMatcher *>(A);
-    auto *R = static_cast<const RuleMatcher *>(B);
-    return std::tuple(OpcodeOrder[L->getOpcode()],
-                      L->insnmatchers_front().getNumOperandMatchers()) <
-           std::tuple(OpcodeOrder[R->getOpcode()],
-                      R->insnmatchers_front().getNumOperandMatchers());
-  });
-
-  for (Matcher *Rule : InputRules)
-    Rule->optimize();
-
   std::vector<std::unique_ptr<Matcher>> MatcherStorage;
-  std::vector<Matcher *> OptRules =
-      optimizeRules<GroupMatcher>(InputRules, MatcherStorage);
-
-  for (Matcher *Rule : OptRules)
-    Rule->optimize();
-
-  OptRules = optimizeRules<SwitchMatcher>(OptRules, MatcherStorage);
-
+  std::vector<Matcher *> OptRules = optimizeRuleset(Rules, MatcherStorage);
   return MatchTable::buildTable(OptRules, /*WithCoverage*/ false,
                                 /*IsCombiner*/ true);
 }
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index aa30525db83ca..e659906a6a112 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -2309,44 +2309,15 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
 MatchTable
 GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules,
                                    bool Optimize, bool WithCoverage) {
-  std::vector<Matcher *> InputRules;
-  for (Matcher &Rule : Rules)
-    InputRules.push_back(&Rule);
-
-  if (!Optimize)
+  if (!Optimize) {
+    std::vector<Matcher *> InputRules;
+    for (Matcher &Rule : Rules)
+      InputRules.push_back(&Rule);
     return MatchTable::buildTable(InputRules, WithCoverage);
-
-  unsigned CurrentOrdering = 0;
-  StringMap<unsigned> OpcodeOrder;
-  for (RuleMatcher &Rule : Rules) {
-    const StringRef Opcode = Rule.getOpcode();
-    assert(!Opcode.empty() && "Didn't expect an undefined opcode");
-    if (OpcodeOrder.try_emplace(Opcode, CurrentOrdering).second)
-      ++CurrentOrdering;
   }
 
-  llvm::stable_sort(
-      InputRules, [&OpcodeOrder](const Matcher *A, const Matcher *B) {
-        auto *L = static_cast<const RuleMatcher *>(A);
-        auto *R = static_cast<const RuleMatcher *>(B);
-        return std::tuple(OpcodeOrder[L->getOpcode()],
-                          L->insnmatchers_front().getNumOperandMatchers()) <
-               std::tuple(OpcodeOrder[R->getOpcode()],
-                          R->insnmatchers_front().getNumOperandMatchers());
-      });
-
-  for (Matcher *Rule : InputRules)
-    Rule->optimize();
-
   std::vector<std::unique_ptr<Matcher>> MatcherStorage;
-  std::vector<Matcher *> OptRules =
-      optimizeRules<GroupMatcher>(InputRules, MatcherStorage);
-
-  for (Matcher *Rule : OptRules)
-    Rule->optimize();
-
-  OptRules = optimizeRules<SwitchMatcher>(OptRules, MatcherStorage);
-
+  std::vector<Matcher *> OptRules = optimizeRuleset(Rules, MatcherStorage);
   return MatchTable::buildTable(OptRules, WithCoverage);
 }
 

>From 21024a1e559e018421b4cb461db2ad2c531564d1 Mon Sep 17 00:00:00 2001
From: pvanhout <pierre.vanhoutryve at amd.com>
Date: Tue, 12 May 2026 12:59:25 +0200
Subject: [PATCH 2/3] Fix tests

---
 .../GlobalISel/preselect-process-phis.mir     |  6 ++---
 .../select-intrinsic-aarch64-sdiv.mir         | 26 +++----------------
 2 files changed, 6 insertions(+), 26 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir b/llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir
index 9c9ae861fd8e3..b36c25baabb63 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir
@@ -1,8 +1,6 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 # RUN: llc -verify-machineinstrs -mtriple aarch64--- --run-pass=instruction-select -global-isel-abort=1 %s -o - | FileCheck %s
 
-# XFAIL: *
-
 ---
 name:            test_loop_phi_fpr_to_gpr
 alignment:       4
@@ -57,7 +55,7 @@ body:             |
     successors: %bb.2(0x80000000)
 
     %3:gpr(s16) = G_PHI %1(s16), %bb.1, %5(s16), %bb.2
-    %5:fpr(f16) = G_FPTRUNC %8(s32)
+    %5:fpr(f16) = G_FPTRUNC %8(f32)
     G_STORE %3(s16), %4(p0) :: (store (s16) into `ptr undef`)
     G_BR %bb.2
 
@@ -116,7 +114,7 @@ body:             |
     successors: %bb.2(0x80000000)
 
     %3:fpr(s16) = G_PHI %5(s16), %bb.2, %1(s16), %bb.1
-    %5:fpr(f16) = G_FPTRUNC %8(s32)
+    %5:fpr(f16) = G_FPTRUNC %8(f32)
     G_STORE %3(s16), %4(p0) :: (store (s16) into `ptr undef`)
     G_BR %bb.2
 
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-intrinsic-aarch64-sdiv.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-intrinsic-aarch64-sdiv.mir
index 82b5eff9b66a0..eeeddae96cefb 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/select-intrinsic-aarch64-sdiv.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-intrinsic-aarch64-sdiv.mir
@@ -1,24 +1,6 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
 # RUN: llc -mtriple=aarch64-- -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
 
-# XFAIL: *
-
-# MatchTable Before:
-#   /* 268430 */ GIM_Try, /*On fail goto*//*Label 4045*/ GIMT_Encode4(268475), // Rule ID 4220 //
-#   /* 268435 */   GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
-#   /* 268438 */   GIM_CheckIntrinsicID, /*MI*/0, /*Op*/1, GIMT_Encode2(Intrinsic::aarch64_sdiv),
-#   /* 268443 */   GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_i32,
-#   /* 268446 */   GIM_RootCheckType, /*Op*/2, /*Type*/GILLT_i32,
-#   /* 268449 */   GIM_RootCheckType, /*Op*/3, /*Type*/GILLT_i32,
-#
-# MatchTable After:
-#   /* 241275 */     GIM_SwitchType, /*MI*/0, /*Op*/0, /*[*/GIMT_Encode2(7), GIMT_Encode2(9), /*)*//*default:*//*Label 6365*/ GIMT_Encode4(241364),
-#   /* 241286 */     /*GILLT_i32*//*Label 6363*/ GIMT_Encode4(241294),
-#   /* 241290 */     /*GILLT_i64*//*Label 6364*/ GIMT_Encode4(241329),
-#
-# Matching fails because type is S32 (index 2), but switch wants i32 (index 7).
-
-
 --- |
   target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
 
@@ -48,8 +30,8 @@ body:             |
     ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1
     ; CHECK-NEXT: [[SDIVWr:%[0-9]+]]:gpr32 = SDIVWr [[COPY]], [[COPY1]]
     ; CHECK-NEXT: $w0 = COPY [[SDIVWr]]
-    %0(s32) = COPY $w0
-    %1(s32) = COPY $w1
-    %2(s32) = G_INTRINSIC intrinsic(@llvm.aarch64.sdiv.i32), %0, %1
-    $w0 = COPY %2(s32)
+    %0(i32) = COPY $w0
+    %1(i32) = COPY $w1
+    %2(i32) = G_INTRINSIC intrinsic(@llvm.aarch64.sdiv.i32), %0, %1
+    $w0 = COPY %2(i32)
 ...

>From 2e548736350118696f776b37e5938d0f9a5fbf61 Mon Sep 17 00:00:00 2001
From: pvanhout <pierre.vanhoutryve at amd.com>
Date: Tue, 12 May 2026 14:12:20 +0200
Subject: [PATCH 3/3] Comments

---
 .../TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp      | 5 +----
 llvm/utils/TableGen/GlobalISelEmitter.cpp                    | 4 +---
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
index d34388839e4a3..517ef0e92d716 100644
--- a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
+++ b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
@@ -149,10 +149,7 @@ optimizeRules(ArrayRef<Matcher *> Rules,
 std::vector<Matcher *> llvm::gi::optimizeRuleset(
     MutableArrayRef<RuleMatcher> Rules,
     std::vector<std::unique_ptr<Matcher>> &MatcherStorage) {
-  std::vector<Matcher *> InputRules;
-  InputRules.reserve(Rules.size());
-  for (RuleMatcher &Rule : Rules)
-    InputRules.push_back(&Rule);
+  SmallVector<Matcher *> InputRules(make_pointer_range(Rules));
 
   // Now sort the Rules.
   unsigned CurrentOrdering = 0;
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index e659906a6a112..813cf0f6c087b 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -2310,9 +2310,7 @@ MatchTable
 GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules,
                                    bool Optimize, bool WithCoverage) {
   if (!Optimize) {
-    std::vector<Matcher *> InputRules;
-    for (Matcher &Rule : Rules)
-      InputRules.push_back(&Rule);
+    SmallVector<Matcher *> InputRules(make_pointer_range(Rules));
     return MatchTable::buildTable(InputRules, WithCoverage);
   }
 



More information about the llvm-branch-commits mailing list