[llvm] [AArch64][GlobalISel] Constrain G_CONSTANT_FOLD_BARRIER operand register classes (PR #177997)

Cullen Rhodes via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 30 06:03:41 PST 2026


https://github.com/c-rhodes updated https://github.com/llvm/llvm-project/pull/177997

>From d3e9fc89f6adbcbf0f74c97d67f4d7dbd83de092 Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Fri, 23 Jan 2026 15:42:10 +0000
Subject: [PATCH 1/6] [AArch64][GlobalISel] Constrain G_AND operands to GPR64
 register class

Instruction selection is lowering:

  bb.1:
    %6:gpr(s64) = G_CONSTANT i64 457873110
    ...
  bb.2:
    %12:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
    %24:gpr(s64) = G_CONSTANT i64 0
    %13:gpr(s64) = G_AND %24, %12
    ...

to:

  %13:gpr64 = ANDXrr %24:gpr64, %6:gpr64sp'

which is causing the verifier to fail with:

  Expected a GPR64 register, but got a GPR64sp register

this patch fixes this by constraining the G_AND operand(s) register
class to GPR64.

Fixes #166563.
---
 .../GISel/AArch64InstructionSelector.cpp      |  40 +++
 .../CodeGen/AArch64/GlobalISel/166563.mir     | 245 ++++++++++++++++++
 2 files changed, 285 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/166563.mir

diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 7605bbea51f56..55b4ad9626116 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -2359,6 +2359,46 @@ bool AArch64InstructionSelector::earlySelect(MachineInstr &I) {
     I.eraseFromParent();
     return true;
   }
+  case TargetOpcode::G_AND: {
+    Register Dst = I.getOperand(0).getReg();
+    Register LHS = I.getOperand(1).getReg();
+    Register RHS = I.getOperand(2).getReg();
+    LLT Ty = MRI.getType(Dst);
+
+    if (Ty.isVector() || Ty.getSizeInBits() != 64)
+      return false;
+
+    auto match = [&](Register Op1, Register Op2) {
+      auto Op1Cst = getIConstantVRegValWithLookThrough(Op1, MRI);
+      if (!(Op1Cst && Op1Cst->Value == 0))
+        return false;
+      // Expecting a G_CONSTANT_FOLD_BARRIER that can't be looked thru.
+      auto Op2Cst = getIConstantVRegValWithLookThrough(Op2, MRI);
+      if (Op2Cst)
+        return false;
+      return true;
+    };
+
+    if (!match(LHS, RHS) && !match(RHS, LHS))
+      return false;
+
+    // Copy either operand into plain GPR class if necessary so the opcode is
+    // legal.
+    auto moveToGPR64 = [&](Register &Reg) {
+      const TargetRegisterClass *RC = MRI.getRegClassOrNull(Reg);
+      if (!Reg.isVirtual() || (RC && RC == &AArch64::GPR64RegClass))
+        return;
+      auto Copy = MIB.buildCopy({&AArch64::GPR64RegClass}, {Reg});
+      selectCopy(*Copy, TII, MRI, TRI, RBI);
+      Reg = Copy.getReg(0);
+    };
+
+    moveToGPR64(LHS);
+    moveToGPR64(RHS);
+    auto NewAnd = MIB.buildInstr(AArch64::ANDXrr, {Dst}, {LHS, RHS});
+    I.eraseFromParent();
+    return constrainSelectedInstRegOperands(*NewAnd, TII, TRI, RBI);
+  }
   case TargetOpcode::G_SEXT:
     // Check for i64 sext(i32 vector_extract) prior to tablegen to select SMOV
     // over a normal extend.
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/166563.mir b/llvm/test/CodeGen/AArch64/GlobalISel/166563.mir
new file mode 100644
index 0000000000000..a6b2001376b37
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/166563.mir
@@ -0,0 +1,245 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -run-pass=instruction-select -verify-machineinstrs -mtriple aarch64 %s -o - | FileCheck %s
+
+# Crash reproducer from: https://github.com/llvm/llvm-project/issues/166563
+
+---
+name:            pr166563
+alignment:       4
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+liveins:
+  - { reg: '$w0', virtual-reg: '' }
+body:             |
+  ; CHECK-LABEL: name: pr166563
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.2(0x30000000), %bb.1(0x50000000)
+  ; CHECK-NEXT:   liveins: $w0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr32 = COPY $w0
+  ; CHECK-NEXT:   [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 457873110
+  ; CHECK-NEXT:   [[SUBREG_TO_REG:%[0-9]+]]:gpr64sp = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
+  ; CHECK-NEXT:   [[MOVi32imm1:%[0-9]+]]:gpr32 = MOVi32imm 1
+  ; CHECK-NEXT:   TBNZW [[MOVi32imm1]], 0, %bb.2
+  ; CHECK-NEXT:   B %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.6(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   B %bb.6
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.3(0x40000000), %bb.4(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   TBZW [[COPY]], 0, %bb.4
+  ; CHECK-NEXT:   B %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SUBSXri:%[0-9]+]]:gpr64 = SUBSXri [[SUBREG_TO_REG]], 2, 0, implicit-def dead $nzcv
+  ; CHECK-NEXT:   B %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4:
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $xzr
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr64 = COPY [[SUBREG_TO_REG]]
+  ; CHECK-NEXT:   [[ANDXrr:%[0-9]+]]:gpr64 = ANDXrr [[COPY1]], [[COPY2]]
+  ; CHECK-NEXT:   $x0 = COPY [[ANDXrr]]
+  ; CHECK-NEXT:   RET_ReallyLR implicit $x0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr64sp = PHI [[SUBSXri]], %bb.3, %14, %bb.5
+  ; CHECK-NEXT:   [[SUBSXri1:%[0-9]+]]:gpr64 = SUBSXri [[PHI]], 1, 0, implicit-def dead $nzcv
+  ; CHECK-NEXT:   B %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.6:
+  ; CHECK-NEXT:   successors: %bb.7(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.7:
+  ; CHECK-NEXT:   successors: %bb.7(0x7c000000), %bb.6(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SUBSXri2:%[0-9]+]]:gpr64 = SUBSXri [[SUBREG_TO_REG]], 0, 0, implicit-def $nzcv
+  ; CHECK-NEXT:   Bcc 8, %bb.7, implicit $nzcv
+  ; CHECK-NEXT:   B %bb.6
+  bb.1:
+    successors: %bb.3(0x30000000), %bb.2(0x50000000)
+    liveins: $w0
+
+    %2:gpr(s32) = COPY $w0
+    %6:gpr(s64) = G_CONSTANT i64 457873110
+    %36:gpr(s32) = G_CONSTANT i32 1
+    G_BRCOND %36(s32), %bb.3
+    G_BR %bb.2
+
+  bb.2:
+    successors: %bb.7(0x80000000)
+
+    %7:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
+    G_BR %bb.7
+
+  bb.3:
+    successors: %bb.4(0x40000000), %bb.5(0x40000000)
+
+    %28:gpr(s32) = G_CONSTANT i32 1
+    %29:gpr(s32) = G_XOR %2, %28
+    %26:gpr(s32) = G_AND %29, %28
+    G_BRCOND %26(s32), %bb.5
+    G_BR %bb.4
+
+  bb.4:
+    successors: %bb.6(0x80000000)
+
+    %14:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
+    %23:gpr(s64) = G_CONSTANT i64 -2
+    %16:gpr(s64) = G_ADD %14, %23
+    G_BR %bb.6
+
+  bb.5:
+    %12:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
+    %24:gpr(s64) = G_CONSTANT i64 0
+    %13:gpr(s64) = G_AND %24, %12
+    $x0 = COPY %13(s64)
+    RET_ReallyLR implicit $x0
+
+  bb.6:
+    successors: %bb.6(0x80000000)
+
+    %17:gpr(s64) = G_PHI %16(s64), %bb.4, %19(s64), %bb.6
+    %22:gpr(s64) = G_CONSTANT i64 -1
+    %19:gpr(s64) = G_ADD %17, %22
+    G_BR %bb.6
+
+  bb.7:
+    successors: %bb.8(0x80000000)
+
+  bb.8:
+    successors: %bb.8(0x7c000000), %bb.7(0x04000000)
+
+    %25:gpr(s64) = G_CONSTANT i64 0
+    %32:gpr(s32) = G_ICMP intpred(ugt), %7(s64), %25
+    G_BRCOND %32(s32), %bb.8
+    G_BR %bb.7
+...
+---
+name:            pr166563_commuted_and
+alignment:       4
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+liveins:
+  - { reg: '$w0', virtual-reg: '' }
+body:             |
+  ; CHECK-LABEL: name: pr166563_commuted_and
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.2(0x30000000), %bb.1(0x50000000)
+  ; CHECK-NEXT:   liveins: $w0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr32 = COPY $w0
+  ; CHECK-NEXT:   [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 457873110
+  ; CHECK-NEXT:   [[SUBREG_TO_REG:%[0-9]+]]:gpr64sp = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
+  ; CHECK-NEXT:   [[MOVi32imm1:%[0-9]+]]:gpr32 = MOVi32imm 1
+  ; CHECK-NEXT:   TBNZW [[MOVi32imm1]], 0, %bb.2
+  ; CHECK-NEXT:   B %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.6(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   B %bb.6
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.3(0x40000000), %bb.4(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   TBZW [[COPY]], 0, %bb.4
+  ; CHECK-NEXT:   B %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SUBSXri:%[0-9]+]]:gpr64 = SUBSXri [[SUBREG_TO_REG]], 2, 0, implicit-def dead $nzcv
+  ; CHECK-NEXT:   B %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4:
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $xzr
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr64 = COPY [[SUBREG_TO_REG]]
+  ; CHECK-NEXT:   [[ANDXrr:%[0-9]+]]:gpr64 = ANDXrr [[COPY2]], [[COPY1]]
+  ; CHECK-NEXT:   $x0 = COPY [[ANDXrr]]
+  ; CHECK-NEXT:   RET_ReallyLR implicit $x0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr64sp = PHI [[SUBSXri]], %bb.3, %14, %bb.5
+  ; CHECK-NEXT:   [[SUBSXri1:%[0-9]+]]:gpr64 = SUBSXri [[PHI]], 1, 0, implicit-def dead $nzcv
+  ; CHECK-NEXT:   B %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.6:
+  ; CHECK-NEXT:   successors: %bb.7(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.7:
+  ; CHECK-NEXT:   successors: %bb.7(0x7c000000), %bb.6(0x04000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SUBSXri2:%[0-9]+]]:gpr64 = SUBSXri [[SUBREG_TO_REG]], 0, 0, implicit-def $nzcv
+  ; CHECK-NEXT:   Bcc 8, %bb.7, implicit $nzcv
+  ; CHECK-NEXT:   B %bb.6
+  bb.1:
+    successors: %bb.3(0x30000000), %bb.2(0x50000000)
+    liveins: $w0
+
+    %2:gpr(s32) = COPY $w0
+    %6:gpr(s64) = G_CONSTANT i64 457873110
+    %36:gpr(s32) = G_CONSTANT i32 1
+    G_BRCOND %36(s32), %bb.3
+    G_BR %bb.2
+
+  bb.2:
+    successors: %bb.7(0x80000000)
+
+    %7:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
+    G_BR %bb.7
+
+  bb.3:
+    successors: %bb.4(0x40000000), %bb.5(0x40000000)
+
+    %28:gpr(s32) = G_CONSTANT i32 1
+    %29:gpr(s32) = G_XOR %2, %28
+    %26:gpr(s32) = G_AND %29, %28
+    G_BRCOND %26(s32), %bb.5
+    G_BR %bb.4
+
+  bb.4:
+    successors: %bb.6(0x80000000)
+
+    %14:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
+    %23:gpr(s64) = G_CONSTANT i64 -2
+    %16:gpr(s64) = G_ADD %14, %23
+    G_BR %bb.6
+
+  bb.5:
+    %12:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
+    %24:gpr(s64) = G_CONSTANT i64 0
+    %13:gpr(s64) = G_AND %12, %24
+    $x0 = COPY %13(s64)
+    RET_ReallyLR implicit $x0
+
+  bb.6:
+    successors: %bb.6(0x80000000)
+
+    %17:gpr(s64) = G_PHI %16(s64), %bb.4, %19(s64), %bb.6
+    %22:gpr(s64) = G_CONSTANT i64 -1
+    %19:gpr(s64) = G_ADD %17, %22
+    G_BR %bb.6
+
+  bb.7:
+    successors: %bb.8(0x80000000)
+
+  bb.8:
+    successors: %bb.8(0x7c000000), %bb.7(0x04000000)
+
+    %25:gpr(s64) = G_CONSTANT i64 0
+    %32:gpr(s32) = G_ICMP intpred(ugt), %7(s64), %25
+    G_BRCOND %32(s32), %bb.8
+    G_BR %bb.7
+...

>From 09c0c9c3e34d6e499dde800116e23d864a0d3aa8 Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Tue, 27 Jan 2026 11:16:56 +0000
Subject: [PATCH 2/6] constrain G_CONSTANT_FOLD_BARRIER

---
 .../CodeGen/GlobalISel/InstructionSelect.cpp  |  9 ++-
 .../GISel/AArch64InstructionSelector.cpp      | 61 +++++++------------
 .../CodeGen/AArch64/GlobalISel/166563.mir     | 10 ++-
 3 files changed, 33 insertions(+), 47 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
index fc379b5f19d5a..4b1a8a34ab3fc 100644
--- a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
@@ -356,7 +356,14 @@ bool InstructionSelect::selectInstr(MachineInstr &MI) {
     return true;
   }
 
-  // Eliminate hints or G_CONSTANT_FOLD_BARRIER.
+  if (MI.getOpcode() == TargetOpcode::G_CONSTANT_FOLD_BARRIER) {
+    // Allow targets to provide custom handling before falling back to the
+    // generic elimination below.
+    if (ISel->select(MI))
+      return true;
+  }
+
+  // Eliminate hints or a remaining G_CONSTANT_FOLD_BARRIER.
   if (isPreISelGenericOptimizationHint(MI.getOpcode()) ||
       MI.getOpcode() == TargetOpcode::G_CONSTANT_FOLD_BARRIER) {
     auto [DstReg, SrcReg] = MI.getFirst2Regs();
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 55b4ad9626116..36e2c689aba13 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -2359,46 +2359,6 @@ bool AArch64InstructionSelector::earlySelect(MachineInstr &I) {
     I.eraseFromParent();
     return true;
   }
-  case TargetOpcode::G_AND: {
-    Register Dst = I.getOperand(0).getReg();
-    Register LHS = I.getOperand(1).getReg();
-    Register RHS = I.getOperand(2).getReg();
-    LLT Ty = MRI.getType(Dst);
-
-    if (Ty.isVector() || Ty.getSizeInBits() != 64)
-      return false;
-
-    auto match = [&](Register Op1, Register Op2) {
-      auto Op1Cst = getIConstantVRegValWithLookThrough(Op1, MRI);
-      if (!(Op1Cst && Op1Cst->Value == 0))
-        return false;
-      // Expecting a G_CONSTANT_FOLD_BARRIER that can't be looked thru.
-      auto Op2Cst = getIConstantVRegValWithLookThrough(Op2, MRI);
-      if (Op2Cst)
-        return false;
-      return true;
-    };
-
-    if (!match(LHS, RHS) && !match(RHS, LHS))
-      return false;
-
-    // Copy either operand into plain GPR class if necessary so the opcode is
-    // legal.
-    auto moveToGPR64 = [&](Register &Reg) {
-      const TargetRegisterClass *RC = MRI.getRegClassOrNull(Reg);
-      if (!Reg.isVirtual() || (RC && RC == &AArch64::GPR64RegClass))
-        return;
-      auto Copy = MIB.buildCopy({&AArch64::GPR64RegClass}, {Reg});
-      selectCopy(*Copy, TII, MRI, TRI, RBI);
-      Reg = Copy.getReg(0);
-    };
-
-    moveToGPR64(LHS);
-    moveToGPR64(RHS);
-    auto NewAnd = MIB.buildInstr(AArch64::ANDXrr, {Dst}, {LHS, RHS});
-    I.eraseFromParent();
-    return constrainSelectedInstRegOperands(*NewAnd, TII, TRI, RBI);
-  }
   case TargetOpcode::G_SEXT:
     // Check for i64 sext(i32 vector_extract) prior to tablegen to select SMOV
     // over a normal extend.
@@ -2819,6 +2779,27 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     constrainSelectedInstRegOperands(I, TII, TRI, RBI);
     return true;
   }
+  case TargetOpcode::G_CONSTANT_FOLD_BARRIER: {
+    auto ConstrainToRC = [&](Register Reg) {
+      const RegisterBank &RB = *RBI.getRegBank(Reg, MRI, TRI);
+      const TargetRegisterClass *RC =
+          getRegClassForTypeOnBank(MRI.getType(Reg), RB);
+      return RC && RBI.constrainGenericRegister(Reg, *RC, MRI);
+    };
+
+    auto [DstReg, SrcReg] = I.getFirst2Regs();
+    if (!ConstrainToRC(DstReg) || !ConstrainToRC(SrcReg))
+      return false;
+
+    if (const auto *DstRC = MRI.getRegClassOrNull(DstReg))
+      MRI.setRegClass(SrcReg, DstRC);
+
+    assert(canReplaceReg(DstReg, SrcReg, MRI) &&
+           "Must be able to replace dst with src!");
+    I.eraseFromParent();
+    MRI.replaceRegWith(DstReg, SrcReg);
+    return true;
+  }
   case TargetOpcode::G_EXTRACT: {
     Register DstReg = I.getOperand(0).getReg();
     Register SrcReg = I.getOperand(1).getReg();
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/166563.mir b/llvm/test/CodeGen/AArch64/GlobalISel/166563.mir
index a6b2001376b37..7e376f4f3c394 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/166563.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/166563.mir
@@ -19,7 +19,7 @@ body:             |
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr32 = COPY $w0
   ; CHECK-NEXT:   [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 457873110
-  ; CHECK-NEXT:   [[SUBREG_TO_REG:%[0-9]+]]:gpr64sp = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
+  ; CHECK-NEXT:   [[SUBREG_TO_REG:%[0-9]+]]:gpr64common = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
   ; CHECK-NEXT:   [[MOVi32imm1:%[0-9]+]]:gpr32 = MOVi32imm 1
   ; CHECK-NEXT:   TBNZW [[MOVi32imm1]], 0, %bb.2
   ; CHECK-NEXT:   B %bb.1
@@ -43,8 +43,7 @@ body:             |
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT: bb.4:
   ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $xzr
-  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr64 = COPY [[SUBREG_TO_REG]]
-  ; CHECK-NEXT:   [[ANDXrr:%[0-9]+]]:gpr64 = ANDXrr [[COPY1]], [[COPY2]]
+  ; CHECK-NEXT:   [[ANDXrr:%[0-9]+]]:gpr64 = ANDXrr [[COPY1]], [[SUBREG_TO_REG]]
   ; CHECK-NEXT:   $x0 = COPY [[ANDXrr]]
   ; CHECK-NEXT:   RET_ReallyLR implicit $x0
   ; CHECK-NEXT: {{  $}}
@@ -139,7 +138,7 @@ body:             |
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr32 = COPY $w0
   ; CHECK-NEXT:   [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 457873110
-  ; CHECK-NEXT:   [[SUBREG_TO_REG:%[0-9]+]]:gpr64sp = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
+  ; CHECK-NEXT:   [[SUBREG_TO_REG:%[0-9]+]]:gpr64common = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
   ; CHECK-NEXT:   [[MOVi32imm1:%[0-9]+]]:gpr32 = MOVi32imm 1
   ; CHECK-NEXT:   TBNZW [[MOVi32imm1]], 0, %bb.2
   ; CHECK-NEXT:   B %bb.1
@@ -163,8 +162,7 @@ body:             |
   ; CHECK-NEXT: {{  $}}
   ; CHECK-NEXT: bb.4:
   ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $xzr
-  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr64 = COPY [[SUBREG_TO_REG]]
-  ; CHECK-NEXT:   [[ANDXrr:%[0-9]+]]:gpr64 = ANDXrr [[COPY2]], [[COPY1]]
+  ; CHECK-NEXT:   [[ANDXrr:%[0-9]+]]:gpr64 = ANDXrr [[SUBREG_TO_REG]], [[COPY1]]
   ; CHECK-NEXT:   $x0 = COPY [[ANDXrr]]
   ; CHECK-NEXT:   RET_ReallyLR implicit $x0
   ; CHECK-NEXT: {{  $}}

>From 12e2fa2827e1ed1ce1d72134f807b659da28a402 Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Wed, 28 Jan 2026 13:44:22 +0000
Subject: [PATCH 3/6] move fix to generic selection

---
 .../include/llvm/CodeGen/TargetRegisterInfo.h |   9 ++
 .../CodeGen/GlobalISel/InstructionSelect.cpp  |  21 ++--
 .../Target/AArch64/AArch64RegisterInfo.cpp    |  34 ++++++
 llvm/lib/Target/AArch64/AArch64RegisterInfo.h |   4 +
 .../GISel/AArch64InstructionSelector.cpp      | 111 +++++-------------
 llvm/lib/Target/AMDGPU/SIRegisterInfo.h       |   5 +-
 .../Target/Mips/MipsInstructionSelector.cpp   |  42 ++-----
 llvm/lib/Target/Mips/MipsRegisterInfo.cpp     |  31 +++++
 llvm/lib/Target/Mips/MipsRegisterInfo.h       |   4 +
 .../RISCV/GISel/RISCVInstructionSelector.cpp  |  48 ++------
 llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp   |  37 ++++++
 llvm/lib/Target/RISCV/RISCVRegisterInfo.h     |   4 +
 12 files changed, 183 insertions(+), 167 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 35b14e8b8fd30..2fbbe0ee0932e 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -21,6 +21,7 @@
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/RegisterBank.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/IR/CallingConv.h"
 #include "llvm/MC/LaneBitmask.h"
 #include "llvm/MC/MCRegisterInfo.h"
@@ -382,6 +383,14 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
   const TargetRegisterClass *
     getAllocatableClass(const TargetRegisterClass *RC) const;
 
+  /// Given a register bank, and a type, return the smallest register class
+  /// that can represent that combination.
+  virtual const TargetRegisterClass *
+  getRegClassForTypeOnBank(LLT Ty, const RegisterBank &Bank,
+                           const TargetSubtargetInfo *STI = nullptr) const {
+    return nullptr;
+  }
+
   /// Returns a bitset indexed by register number indicating if a register is
   /// allocatable or not. If a register class is specified, returns the subset
   /// for the class.
diff --git a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
index 4b1a8a34ab3fc..c689413cc1293 100644
--- a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
@@ -23,6 +23,7 @@
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/RegisterBankInfo.h"
 #include "llvm/CodeGen/TargetLowering.h"
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
@@ -356,17 +357,21 @@ bool InstructionSelect::selectInstr(MachineInstr &MI) {
     return true;
   }
 
-  if (MI.getOpcode() == TargetOpcode::G_CONSTANT_FOLD_BARRIER) {
-    // Allow targets to provide custom handling before falling back to the
-    // generic elimination below.
-    if (ISel->select(MI))
-      return true;
-  }
-
-  // Eliminate hints or a remaining G_CONSTANT_FOLD_BARRIER.
+  // Eliminate hints or G_CONSTANT_FOLD_BARRIER.
   if (isPreISelGenericOptimizationHint(MI.getOpcode()) ||
       MI.getOpcode() == TargetOpcode::G_CONSTANT_FOLD_BARRIER) {
+    const RegisterBankInfo *RBI = ISel->MF->getSubtarget().getRegBankInfo();
+    const TargetRegisterInfo *TRI = ISel->MF->getSubtarget().getRegisterInfo();
+    auto ConstrainToRC = [&](Register Reg) {
+      const RegisterBank *RB = RBI->getRegBank(Reg, MRI, *TRI);
+      const TargetRegisterClass *RC = TRI->getRegClassForTypeOnBank(
+          MRI.getType(Reg), *RB, &ISel->MF->getSubtarget());
+      return !RC || (RC && RBI->constrainGenericRegister(Reg, *RC, MRI));
+    };
+
     auto [DstReg, SrcReg] = MI.getFirst2Regs();
+    if (!ConstrainToRC(DstReg) || !ConstrainToRC(SrcReg))
+      return false;
 
     // At this point, the destination register class of the op may have
     // been decided.
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
index 8c0dd4381fae8..86003693973a8 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
@@ -17,6 +17,7 @@
 #include "AArch64MachineFunctionInfo.h"
 #include "AArch64SMEAttributes.h"
 #include "AArch64Subtarget.h"
+#include "GISel/AArch64RegisterBankInfo.h"
 #include "MCTargetDesc/AArch64AddressingModes.h"
 #include "MCTargetDesc/AArch64InstPrinter.h"
 #include "llvm/ADT/BitVector.h"
@@ -1442,3 +1443,36 @@ bool AArch64RegisterInfo::isIgnoredCVReg(MCRegister LLVMReg) const {
   return (LLVMReg >= AArch64::Z0 && LLVMReg <= AArch64::Z31) ||
          (LLVMReg >= AArch64::P0 && LLVMReg <= AArch64::P15);
 }
+
+// FIXME: This should be target-independent, inferred from the types declared
+// for each class in the bank.
+const TargetRegisterClass *AArch64RegisterInfo::getRegClassForTypeOnBank(
+    LLT Ty, const RegisterBank &RB, const TargetSubtargetInfo *STI) const {
+  if (RB.getID() == AArch64::GPRRegBankID) {
+    if (Ty.getSizeInBits() <= 32)
+      return &AArch64::GPR32RegClass;
+    if (Ty.getSizeInBits() == 64)
+      return &AArch64::GPR64RegClass;
+    if (Ty.getSizeInBits() == 128)
+      return &AArch64::XSeqPairsClassRegClass;
+    return nullptr;
+  }
+
+  if (RB.getID() == AArch64::FPRRegBankID) {
+    switch (Ty.getSizeInBits()) {
+    case 8:
+      return &AArch64::FPR8RegClass;
+    case 16:
+      return &AArch64::FPR16RegClass;
+    case 32:
+      return &AArch64::FPR32RegClass;
+    case 64:
+      return &AArch64::FPR64RegClass;
+    case 128:
+      return &AArch64::FPR128RegClass;
+    }
+    return nullptr;
+  }
+
+  return nullptr;
+}
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
index 89d1802ab98d5..7ce922aee3f97 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
@@ -154,6 +154,10 @@ class AArch64RegisterInfo final : public AArch64GenRegisterInfo {
   bool shouldAnalyzePhysregInMachineLoopInfo(MCRegister R) const override;
 
   bool isIgnoredCVReg(MCRegister LLVMReg) const override;
+
+  const TargetRegisterClass *getRegClassForTypeOnBank(
+      LLT Ty, const RegisterBank &Bank,
+      const TargetSubtargetInfo *STI = nullptr) const override;
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 36e2c689aba13..46d1d2c1029bd 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -564,45 +564,6 @@ AArch64InstructionSelector::AArch64InstructionSelector(
 {
 }
 
-// FIXME: This should be target-independent, inferred from the types declared
-// for each class in the bank.
-//
-/// Given a register bank, and a type, return the smallest register class that
-/// can represent that combination.
-static const TargetRegisterClass *
-getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB,
-                         bool GetAllRegSet = false) {
-  if (RB.getID() == AArch64::GPRRegBankID) {
-    if (Ty.getSizeInBits() <= 32)
-      return GetAllRegSet ? &AArch64::GPR32allRegClass
-                          : &AArch64::GPR32RegClass;
-    if (Ty.getSizeInBits() == 64)
-      return GetAllRegSet ? &AArch64::GPR64allRegClass
-                          : &AArch64::GPR64RegClass;
-    if (Ty.getSizeInBits() == 128)
-      return &AArch64::XSeqPairsClassRegClass;
-    return nullptr;
-  }
-
-  if (RB.getID() == AArch64::FPRRegBankID) {
-    switch (Ty.getSizeInBits()) {
-    case 8:
-      return &AArch64::FPR8RegClass;
-    case 16:
-      return &AArch64::FPR16RegClass;
-    case 32:
-      return &AArch64::FPR32RegClass;
-    case 64:
-      return &AArch64::FPR64RegClass;
-    case 128:
-      return &AArch64::FPR128RegClass;
-    }
-    return nullptr;
-  }
-
-  return nullptr;
-}
-
 /// Given a register bank, and size in bits, return the smallest register class
 /// that can represent that combination.
 static const TargetRegisterClass *
@@ -1000,7 +961,9 @@ static bool selectDebugInstr(MachineInstr &I, MachineRegisterInfo &MRI,
         dyn_cast<const TargetRegisterClass *>(RegClassOrBank);
     if (!RC) {
       const RegisterBank &RB = *cast<const RegisterBank *>(RegClassOrBank);
-      RC = getRegClassForTypeOnBank(Ty, RB);
+      const TargetRegisterInfo *TRI =
+          I.getMF()->getSubtarget().getRegisterInfo();
+      RC = TRI->getRegClassForTypeOnBank(Ty, RB);
       if (!RC) {
         LLVM_DEBUG(
             dbgs() << "Warning: DBG_VALUE operand has unexpected size/bank\n");
@@ -1904,7 +1867,7 @@ bool AArch64InstructionSelector::selectVectorAshrLshr(
   unsigned Opc = 0;
   unsigned NegOpc = 0;
   const TargetRegisterClass *RC =
-      getRegClassForTypeOnBank(Ty, RBI.getRegBank(AArch64::FPRRegBankID));
+      TRI.getRegClassForTypeOnBank(Ty, RBI.getRegBank(AArch64::FPRRegBankID));
   if (Ty == LLT::fixed_vector(2, 64)) {
     Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
     NegOpc = AArch64::NEGv2i64;
@@ -2543,7 +2506,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
           return false;
         }
         const RegisterBank &RB = *cast<const RegisterBank *>(RegClassOrBank);
-        DefRC = getRegClassForTypeOnBank(DefTy, RB);
+        DefRC = TRI.getRegClassForTypeOnBank(DefTy, RB);
         if (!DefRC) {
           LLVM_DEBUG(dbgs() << "PHI operand has unexpected size/bank\n");
           return false;
@@ -2717,7 +2680,8 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     }
 
     if (isFP) {
-      const TargetRegisterClass &FPRRC = *getRegClassForTypeOnBank(DefTy, RB);
+      const TargetRegisterClass &FPRRC =
+          *TRI.getRegClassForTypeOnBank(DefTy, RB);
       // For 16, 64, and 128b values, emit a constant pool load.
       switch (DefSize) {
       default:
@@ -2779,27 +2743,6 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     constrainSelectedInstRegOperands(I, TII, TRI, RBI);
     return true;
   }
-  case TargetOpcode::G_CONSTANT_FOLD_BARRIER: {
-    auto ConstrainToRC = [&](Register Reg) {
-      const RegisterBank &RB = *RBI.getRegBank(Reg, MRI, TRI);
-      const TargetRegisterClass *RC =
-          getRegClassForTypeOnBank(MRI.getType(Reg), RB);
-      return RC && RBI.constrainGenericRegister(Reg, *RC, MRI);
-    };
-
-    auto [DstReg, SrcReg] = I.getFirst2Regs();
-    if (!ConstrainToRC(DstReg) || !ConstrainToRC(SrcReg))
-      return false;
-
-    if (const auto *DstRC = MRI.getRegClassOrNull(DstReg))
-      MRI.setRegClass(SrcReg, DstRC);
-
-    assert(canReplaceReg(DstReg, SrcReg, MRI) &&
-           "Must be able to replace dst with src!");
-    I.eraseFromParent();
-    MRI.replaceRegWith(DstReg, SrcReg);
-    return true;
-  }
   case TargetOpcode::G_EXTRACT: {
     Register DstReg = I.getOperand(0).getReg();
     Register SrcReg = I.getOperand(1).getReg();
@@ -3031,7 +2974,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     if (isa<GStore>(LdSt) && ValTy.getSizeInBits() > MemSizeInBits) {
       unsigned SubReg;
       LLT MemTy = LdSt.getMMO().getMemoryType();
-      auto *RC = getRegClassForTypeOnBank(MemTy, RB);
+      auto *RC = TRI.getRegClassForTypeOnBank(MemTy, RB);
       if (!getSubRegForClass(RC, TRI, SubReg))
         return false;
 
@@ -3047,7 +2990,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
       if (RB.getID() == AArch64::FPRRegBankID) {
         unsigned SubReg;
         LLT MemTy = LdSt.getMMO().getMemoryType();
-        auto *RC = getRegClassForTypeOnBank(MemTy, RB);
+        auto *RC = TRI.getRegClassForTypeOnBank(MemTy, RB);
         if (!getSubRegForClass(RC, TRI, SubReg))
           return false;
         Register OldDst = LdSt.getReg(0);
@@ -3061,7 +3004,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
             .addImm(0)
             .addUse(NewDst)
             .addImm(SubReg);
-        auto SubRegRC = getRegClassForTypeOnBank(MRI.getType(OldDst), RB);
+        auto SubRegRC = TRI.getRegClassForTypeOnBank(MRI.getType(OldDst), RB);
         RBI.constrainGenericRegister(OldDst, *SubRegRC, MRI);
         MIB.setInstr(LdSt);
         ValTy = MemTy; // This is no longer an extending load.
@@ -3251,11 +3194,13 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     }
 
     if (DstRB.getID() == AArch64::GPRRegBankID) {
-      const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
+      const TargetRegisterClass *DstRC =
+          TRI.getRegClassForTypeOnBank(DstTy, DstRB);
       if (!DstRC)
         return false;
 
-      const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB);
+      const TargetRegisterClass *SrcRC =
+          TRI.getRegClassForTypeOnBank(SrcTy, SrcRB);
       if (!SrcRC)
         return false;
 
@@ -3548,7 +3493,8 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
     const Register DstReg = I.getOperand(0).getReg();
     const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI);
-    const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
+    const TargetRegisterClass *DstRC =
+        TRI.getRegClassForTypeOnBank(DstTy, DstRB);
     RBI.constrainGenericRegister(DstReg, *DstRC, MRI);
     return true;
   }
@@ -3840,7 +3786,7 @@ AArch64InstructionSelector::emitNarrowVector(Register DstReg, Register SrcReg,
                                              MachineRegisterInfo &MRI) const {
   LLT DstTy = MRI.getType(DstReg);
   const TargetRegisterClass *RC =
-      getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(SrcReg, MRI, TRI));
+      TRI.getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(SrcReg, MRI, TRI));
   if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
     LLVM_DEBUG(dbgs() << "Unsupported register class!\n");
     return nullptr;
@@ -3970,7 +3916,7 @@ MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
   }
 
   const TargetRegisterClass *DstRC =
-      getRegClassForTypeOnBank(ScalarTy, DstRB, true);
+      TRI.getRegClassForTypeOnBank(ScalarTy, DstRB);
   if (!DstRC) {
     LLVM_DEBUG(dbgs() << "Could not determine destination register class.\n");
     return nullptr;
@@ -3978,8 +3924,7 @@ MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
 
   const RegisterBank &VecRB = *RBI.getRegBank(VecReg, MRI, TRI);
   const LLT &VecTy = MRI.getType(VecReg);
-  const TargetRegisterClass *VecRC =
-      getRegClassForTypeOnBank(VecTy, VecRB, true);
+  const TargetRegisterClass *VecRC = TRI.getRegClassForTypeOnBank(VecTy, VecRB);
   if (!VecRC) {
     LLVM_DEBUG(dbgs() << "Could not determine source register class.\n");
     return nullptr;
@@ -4139,7 +4084,7 @@ bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &I,
     // For scalar sources, treat as a pseudo-vector of NarrowTy elements.
     unsigned EltSize = WideTy.isVector() ? WideTy.getScalarSizeInBits()
                                          : NarrowTy.getSizeInBits();
-    const TargetRegisterClass *RC = getRegClassForTypeOnBank(
+    const TargetRegisterClass *RC = TRI.getRegClassForTypeOnBank(
         LLT::fixed_vector(NumElts, EltSize), *RBI.getRegBank(SrcReg, MRI, TRI));
     unsigned SubReg = 0;
     bool Found = getSubRegForClass(RC, TRI, SubReg);
@@ -4600,7 +4545,7 @@ MachineInstr *AArch64InstructionSelector::emitVectorConcat(
   const LLT ScalarTy = LLT::scalar(Op1Ty.getSizeInBits());
   const RegisterBank &FPRBank = *RBI.getRegBank(Op1, MRI, TRI);
   const TargetRegisterClass *DstRC =
-      getRegClassForTypeOnBank(Op1Ty.multiplyElements(2), FPRBank);
+      TRI.getRegClassForTypeOnBank(Op1Ty.multiplyElements(2), FPRBank);
 
   MachineInstr *WidenedOp1 =
       emitScalarToVector(ScalarTy.getSizeInBits(), DstRC, Op1, MIRBuilder);
@@ -5582,8 +5527,8 @@ bool AArch64InstructionSelector::selectIndexedExtLoad(
                         .addImm(InsertIntoSubReg);
     RBI.constrainGenericRegister(
         SubToReg.getReg(0),
-        *getRegClassForTypeOnBank(MRI.getType(Dst),
-                                  *RBI.getRegBank(Dst, MRI, TRI)),
+        *TRI.getRegClassForTypeOnBank(MRI.getType(Dst),
+                                      *RBI.getRegBank(Dst, MRI, TRI)),
         MRI);
   } else {
     auto Copy = MIB.buildCopy(Dst, LdMI.getReg(1));
@@ -5859,11 +5804,11 @@ bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
       }))
     return false;
   unsigned SubReg;
-  const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
+  const TargetRegisterClass *EltRC = TRI.getRegClassForTypeOnBank(EltTy, EltRB);
   if (!EltRC)
     return false;
   const TargetRegisterClass *DstRC =
-      getRegClassForTypeOnBank(MRI.getType(Dst), DstRB);
+      TRI.getRegClassForTypeOnBank(MRI.getType(Dst), DstRB);
   if (!DstRC)
     return false;
   if (!getSubRegForClass(EltRC, TRI, SubReg))
@@ -5924,7 +5869,7 @@ bool AArch64InstructionSelector::selectBuildVector(MachineInstr &I,
   if (DstSize < 128) {
     // Force this to be FPR using the destination vector.
     const TargetRegisterClass *RC =
-        getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(DstVec, MRI, TRI));
+        TRI.getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(DstVec, MRI, TRI));
     if (!RC)
       return false;
     if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
@@ -5966,8 +5911,8 @@ bool AArch64InstructionSelector::selectBuildVector(MachineInstr &I,
 
     Register DstReg = PrevMI->getOperand(0).getReg();
     if (PrevMI == ScalarToVec && DstReg.isVirtual()) {
-      const TargetRegisterClass *RC =
-          getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(DstVec, MRI, TRI));
+      const TargetRegisterClass *RC = TRI.getRegClassForTypeOnBank(
+          DstTy, *RBI.getRegBank(DstVec, MRI, TRI));
       RBI.constrainGenericRegister(DstReg, *RC, MRI);
     }
   }
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.h b/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
index 2e2916f68f584..62ed20c3fff8c 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
@@ -364,8 +364,9 @@ class SIRegisterInfo final : public AMDGPUGenRegisterInfo {
   const TargetRegisterClass *
   getRegClassForSizeOnBank(unsigned Size, const RegisterBank &Bank) const;
 
-  const TargetRegisterClass *
-  getRegClassForTypeOnBank(LLT Ty, const RegisterBank &Bank) const {
+  const TargetRegisterClass *getRegClassForTypeOnBank(
+      LLT Ty, const RegisterBank &Bank,
+      const TargetSubtargetInfo *STI = nullptr) const override {
     return getRegClassForSizeOnBank(Ty.getSizeInBits(), Bank);
   }
 
diff --git a/llvm/lib/Target/Mips/MipsInstructionSelector.cpp b/llvm/lib/Target/Mips/MipsInstructionSelector.cpp
index bd02b57bfc860..029f1c4a5cef9 100644
--- a/llvm/lib/Target/Mips/MipsInstructionSelector.cpp
+++ b/llvm/lib/Target/Mips/MipsInstructionSelector.cpp
@@ -45,8 +45,6 @@ class MipsInstructionSelector : public InstructionSelector {
   bool materialize32BitImm(Register DestReg, APInt Imm,
                            MachineIRBuilder &B) const;
   bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
-  const TargetRegisterClass *
-  getRegClassForTypeOnBank(Register Reg, MachineRegisterInfo &MRI) const;
   unsigned selectLoadStoreOpCode(MachineInstr &I,
                                  MachineRegisterInfo &MRI) const;
   bool buildUnalignedStore(MachineInstr &I, unsigned Opc,
@@ -108,7 +106,9 @@ bool MipsInstructionSelector::selectCopy(MachineInstr &I,
   if (DstReg.isPhysical())
     return true;
 
-  const TargetRegisterClass *RC = getRegClassForTypeOnBank(DstReg, MRI);
+  const TargetRegisterClass *RC = TRI.getRegClassForTypeOnBank(
+      MRI.getType(DstReg), *RBI.getRegBank(DstReg, MRI, TRI),
+      &MF->getSubtarget());
   if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
     LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
                       << " operand\n");
@@ -117,34 +117,6 @@ bool MipsInstructionSelector::selectCopy(MachineInstr &I,
   return true;
 }
 
-const TargetRegisterClass *MipsInstructionSelector::getRegClassForTypeOnBank(
-    Register Reg, MachineRegisterInfo &MRI) const {
-  const LLT Ty = MRI.getType(Reg);
-  const unsigned TySize = Ty.getSizeInBits();
-
-  if (isRegInGprb(Reg, MRI)) {
-    assert((Ty.isScalar() || Ty.isPointer()) &&
-           (TySize == 32 || TySize == 64) &&
-           "Register class not available for LLT, register bank combination");
-    if (TySize == 32)
-      return &Mips::GPR32RegClass;
-    if (TySize == 64)
-      return &Mips::GPR64RegClass;
-  }
-
-  if (isRegInFprb(Reg, MRI)) {
-    if (Ty.isScalar()) {
-      assert((TySize == 32 || TySize == 64) &&
-             "Register class not available for LLT, register bank combination");
-      if (TySize == 32)
-        return &Mips::FGR32RegClass;
-      return STI.isFP64bit() ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass;
-    }
-  }
-
-  llvm_unreachable("Unsupported register bank.");
-}
-
 bool MipsInstructionSelector::materialize32BitImm(Register DestReg, APInt Imm,
                                                   MachineIRBuilder &B) const {
   assert(Imm.getBitWidth() == 32 && "Unsupported immediate size.");
@@ -428,7 +400,9 @@ bool MipsInstructionSelector::select(MachineInstr &I) {
     if (DestReg.isPhysical())
       DefRC = TRI.getRegClass(DestReg);
     else
-      DefRC = getRegClassForTypeOnBank(DestReg, MRI);
+      DefRC = TRI.getRegClassForTypeOnBank(MRI.getType(DestReg),
+                                           *RBI.getRegBank(DestReg, MRI, TRI),
+                                           &MF.getSubtarget());
 
     I.setDesc(TII.get(TargetOpcode::PHI));
     return RBI.constrainGenericRegister(DestReg, *DefRC, MRI);
@@ -576,7 +550,9 @@ bool MipsInstructionSelector::select(MachineInstr &I) {
              .addDef(Dst);
 
     // Set class based on register bank, there can be fpr and gpr implicit def.
-    MRI.setRegClass(Dst, getRegClassForTypeOnBank(Dst, MRI));
+    MRI.setRegClass(Dst, TRI.getRegClassForTypeOnBank(
+                             MRI.getType(Dst), *RBI.getRegBank(Dst, MRI, TRI),
+                             &MF.getSubtarget()));
     break;
   }
   case G_CONSTANT: {
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index 948d4db8585db..288224a6f2284 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -14,6 +14,7 @@
 #include "MCTargetDesc/MipsABIInfo.h"
 #include "Mips.h"
 #include "MipsMachineFunction.h"
+#include "MipsRegisterBankInfo.h"
 #include "MipsSubtarget.h"
 #include "MipsTargetMachine.h"
 #include "llvm/ADT/BitVector.h"
@@ -319,3 +320,33 @@ bool MipsRegisterInfo::canRealignStack(const MachineFunction &MF) const {
   // sized objects.
   return MF.getRegInfo().canReserveReg(BP);
 }
+
+const TargetRegisterClass *MipsRegisterInfo::getRegClassForTypeOnBank(
+    LLT Ty, const RegisterBank &RB, const TargetSubtargetInfo *STI) const {
+  const unsigned TySize = Ty.getSizeInBits();
+
+  if (RB.getID() == Mips::GPRBRegBankID) {
+    assert((Ty.isScalar() || Ty.isPointer()) &&
+           (TySize == 32 || TySize == 64) &&
+           "Register class not available for LLT, register bank combination");
+    if (TySize == 32)
+      return &Mips::GPR32RegClass;
+    if (TySize == 64)
+      return &Mips::GPR64RegClass;
+  }
+
+  if (RB.getID() == Mips::FPRBRegBankID) {
+    if (Ty.isScalar()) {
+      assert((TySize == 32 || TySize == 64) &&
+             "Register class not available for LLT, register bank combination");
+      if (TySize == 32)
+        return &Mips::FGR32RegClass;
+      assert(STI != nullptr);
+      return static_cast<const MipsSubtarget *>(STI)->isFP64bit()
+                 ? &Mips::FGR64RegClass
+                 : &Mips::AFGR64RegClass;
+    }
+  }
+
+  llvm_unreachable("Unsupported register bank.");
+}
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.h b/llvm/lib/Target/Mips/MipsRegisterInfo.h
index e2e81af4a8af1..39c86b5ec16f9 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.h
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.h
@@ -60,6 +60,10 @@ class MipsRegisterInfo : public MipsGenRegisterInfo {
   /// Return GPR register class.
   virtual const TargetRegisterClass *intRegClass(unsigned Size) const = 0;
 
+  const TargetRegisterClass *
+  getRegClassForTypeOnBank(LLT Ty, const RegisterBank &Bank,
+                           const TargetSubtargetInfo *STI) const override;
+
 private:
   virtual void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo,
                            int FrameIndex, uint64_t StackSize,
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 8769bb2238980..51a3c7b3a7a97 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -54,9 +54,6 @@ class RISCVInstructionSelector : public InstructionSelector {
   static const char *getName() { return DEBUG_TYPE; }
 
 private:
-  const TargetRegisterClass *
-  getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) const;
-
   static constexpr unsigned MaxRecursionDepth = 6;
 
   bool hasAllNBitUsers(const MachineInstr &MI, unsigned Bits,
@@ -1105,7 +1102,7 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
         }
 
         const RegisterBank &RB = *cast<const RegisterBank *>(RegClassOrBank);
-        DefRC = getRegClassForTypeOnBank(DefTy, RB);
+        DefRC = TRI.getRegClassForTypeOnBank(DefTy, RB, &MF->getSubtarget());
         if (!DefRC) {
           LLVM_DEBUG(dbgs() << "PHI operand has unexpected size/bank\n");
           return false;
@@ -1506,39 +1503,6 @@ void RISCVInstructionSelector::renderAddiPairImmLarge(MachineInstrBuilder &MIB,
   MIB.addImm(Imm);
 }
 
-const TargetRegisterClass *RISCVInstructionSelector::getRegClassForTypeOnBank(
-    LLT Ty, const RegisterBank &RB) const {
-  if (RB.getID() == RISCV::GPRBRegBankID) {
-    if (Ty.getSizeInBits() <= 32 || (STI.is64Bit() && Ty.getSizeInBits() == 64))
-      return &RISCV::GPRRegClass;
-  }
-
-  if (RB.getID() == RISCV::FPRBRegBankID) {
-    if (Ty.getSizeInBits() == 16)
-      return &RISCV::FPR16RegClass;
-    if (Ty.getSizeInBits() == 32)
-      return &RISCV::FPR32RegClass;
-    if (Ty.getSizeInBits() == 64)
-      return &RISCV::FPR64RegClass;
-  }
-
-  if (RB.getID() == RISCV::VRBRegBankID) {
-    if (Ty.getSizeInBits().getKnownMinValue() <= 64)
-      return &RISCV::VRRegClass;
-
-    if (Ty.getSizeInBits().getKnownMinValue() == 128)
-      return &RISCV::VRM2RegClass;
-
-    if (Ty.getSizeInBits().getKnownMinValue() == 256)
-      return &RISCV::VRM4RegClass;
-
-    if (Ty.getSizeInBits().getKnownMinValue() == 512)
-      return &RISCV::VRM8RegClass;
-  }
-
-  return nullptr;
-}
-
 bool RISCVInstructionSelector::isRegInGprb(Register Reg) const {
   return RBI.getRegBank(Reg, *MRI, TRI)->getID() == RISCV::GPRBRegBankID;
 }
@@ -1553,8 +1517,9 @@ bool RISCVInstructionSelector::selectCopy(MachineInstr &MI) const {
   if (DstReg.isPhysical())
     return true;
 
-  const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(
-      MRI->getType(DstReg), *RBI.getRegBank(DstReg, *MRI, TRI));
+  const TargetRegisterClass *DstRC = TRI.getRegClassForTypeOnBank(
+      MRI->getType(DstReg), *RBI.getRegBank(DstReg, *MRI, TRI),
+      &MF->getSubtarget());
   assert(DstRC &&
          "Register class not available for LLT, register bank combination");
 
@@ -1576,8 +1541,9 @@ bool RISCVInstructionSelector::selectImplicitDef(MachineInstr &MI,
   assert(MI.getOpcode() == TargetOpcode::G_IMPLICIT_DEF);
 
   const Register DstReg = MI.getOperand(0).getReg();
-  const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(
-      MRI->getType(DstReg), *RBI.getRegBank(DstReg, *MRI, TRI));
+  const TargetRegisterClass *DstRC = TRI.getRegClassForTypeOnBank(
+      MRI->getType(DstReg), *RBI.getRegBank(DstReg, *MRI, TRI),
+      &MF->getSubtarget());
 
   assert(DstRC &&
          "Register class not available for LLT, register bank combination");
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 0770935b749d9..d764eace00800 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "RISCVRegisterInfo.h"
+#include "GISel/RISCVRegisterBankInfo.h"
 #include "RISCV.h"
 #include "RISCVSubtarget.h"
 #include "llvm/ADT/SmallSet.h"
@@ -1091,3 +1092,39 @@ RISCVRegisterInfo::findVRegWithEncoding(const TargetRegisterClass &RegClass,
     return Reg;
   return getMatchingSuperReg(Reg, RISCV::sub_vrm1_0, &RegClass);
 }
+
+const TargetRegisterClass *RISCVRegisterInfo::getRegClassForTypeOnBank(
+    LLT Ty, const RegisterBank &RB, const TargetSubtargetInfo *STI) const {
+  assert(STI != nullptr);
+  if (RB.getID() == RISCV::GPRBRegBankID) {
+    if (Ty.getSizeInBits() <= 32 ||
+        (static_cast<const RISCVSubtarget *>(STI)->is64Bit() &&
+         Ty.getSizeInBits() == 64))
+      return &RISCV::GPRRegClass;
+  }
+
+  if (RB.getID() == RISCV::FPRBRegBankID) {
+    if (Ty.getSizeInBits() == 16)
+      return &RISCV::FPR16RegClass;
+    if (Ty.getSizeInBits() == 32)
+      return &RISCV::FPR32RegClass;
+    if (Ty.getSizeInBits() == 64)
+      return &RISCV::FPR64RegClass;
+  }
+
+  if (RB.getID() == RISCV::VRBRegBankID) {
+    if (Ty.getSizeInBits().getKnownMinValue() <= 64)
+      return &RISCV::VRRegClass;
+
+    if (Ty.getSizeInBits().getKnownMinValue() == 128)
+      return &RISCV::VRM2RegClass;
+
+    if (Ty.getSizeInBits().getKnownMinValue() == 256)
+      return &RISCV::VRM4RegClass;
+
+    if (Ty.getSizeInBits().getKnownMinValue() == 512)
+      return &RISCV::VRM8RegClass;
+  }
+
+  return nullptr;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h
index f29f85e4987f6..d98240447454c 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h
@@ -168,6 +168,10 @@ struct RISCVRegisterInfo : public RISCVGenRegisterInfo {
   static bool isRVVRegClass(const TargetRegisterClass *RC) {
     return RISCVRI::isVRegClass(RC->TSFlags);
   }
+
+  const TargetRegisterClass *
+  getRegClassForTypeOnBank(LLT Ty, const RegisterBank &Bank,
+                           const TargetSubtargetInfo *STI) const override;
 };
 } // namespace llvm
 

>From 626eeb89624e56f0009cd0ab1500eb2d73260c11 Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Thu, 29 Jan 2026 10:48:12 +0000
Subject: [PATCH 4/6] Revert "move fix to generic selection"

This reverts commit 12e2fa2827e1ed1ce1d72134f807b659da28a402.
---
 .../include/llvm/CodeGen/TargetRegisterInfo.h |   9 --
 .../CodeGen/GlobalISel/InstructionSelect.cpp  |  21 ++--
 .../Target/AArch64/AArch64RegisterInfo.cpp    |  34 ------
 llvm/lib/Target/AArch64/AArch64RegisterInfo.h |   4 -
 .../GISel/AArch64InstructionSelector.cpp      | 111 +++++++++++++-----
 llvm/lib/Target/AMDGPU/SIRegisterInfo.h       |   5 +-
 .../Target/Mips/MipsInstructionSelector.cpp   |  42 +++++--
 llvm/lib/Target/Mips/MipsRegisterInfo.cpp     |  31 -----
 llvm/lib/Target/Mips/MipsRegisterInfo.h       |   4 -
 .../RISCV/GISel/RISCVInstructionSelector.cpp  |  48 ++++++--
 llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp   |  37 ------
 llvm/lib/Target/RISCV/RISCVRegisterInfo.h     |   4 -
 12 files changed, 167 insertions(+), 183 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 2fbbe0ee0932e..35b14e8b8fd30 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -21,7 +21,6 @@
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/RegisterBank.h"
-#include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/IR/CallingConv.h"
 #include "llvm/MC/LaneBitmask.h"
 #include "llvm/MC/MCRegisterInfo.h"
@@ -383,14 +382,6 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
   const TargetRegisterClass *
     getAllocatableClass(const TargetRegisterClass *RC) const;
 
-  /// Given a register bank, and a type, return the smallest register class
-  /// that can represent that combination.
-  virtual const TargetRegisterClass *
-  getRegClassForTypeOnBank(LLT Ty, const RegisterBank &Bank,
-                           const TargetSubtargetInfo *STI = nullptr) const {
-    return nullptr;
-  }
-
   /// Returns a bitset indexed by register number indicating if a register is
   /// allocatable or not. If a register class is specified, returns the subset
   /// for the class.
diff --git a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
index c689413cc1293..4b1a8a34ab3fc 100644
--- a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
@@ -23,7 +23,6 @@
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/RegisterBankInfo.h"
 #include "llvm/CodeGen/TargetLowering.h"
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
@@ -357,21 +356,17 @@ bool InstructionSelect::selectInstr(MachineInstr &MI) {
     return true;
   }
 
-  // Eliminate hints or G_CONSTANT_FOLD_BARRIER.
+  if (MI.getOpcode() == TargetOpcode::G_CONSTANT_FOLD_BARRIER) {
+    // Allow targets to provide custom handling before falling back to the
+    // generic elimination below.
+    if (ISel->select(MI))
+      return true;
+  }
+
+  // Eliminate hints or a remaining G_CONSTANT_FOLD_BARRIER.
   if (isPreISelGenericOptimizationHint(MI.getOpcode()) ||
       MI.getOpcode() == TargetOpcode::G_CONSTANT_FOLD_BARRIER) {
-    const RegisterBankInfo *RBI = ISel->MF->getSubtarget().getRegBankInfo();
-    const TargetRegisterInfo *TRI = ISel->MF->getSubtarget().getRegisterInfo();
-    auto ConstrainToRC = [&](Register Reg) {
-      const RegisterBank *RB = RBI->getRegBank(Reg, MRI, *TRI);
-      const TargetRegisterClass *RC = TRI->getRegClassForTypeOnBank(
-          MRI.getType(Reg), *RB, &ISel->MF->getSubtarget());
-      return !RC || (RC && RBI->constrainGenericRegister(Reg, *RC, MRI));
-    };
-
     auto [DstReg, SrcReg] = MI.getFirst2Regs();
-    if (!ConstrainToRC(DstReg) || !ConstrainToRC(SrcReg))
-      return false;
 
     // At this point, the destination register class of the op may have
     // been decided.
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
index 86003693973a8..8c0dd4381fae8 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
@@ -17,7 +17,6 @@
 #include "AArch64MachineFunctionInfo.h"
 #include "AArch64SMEAttributes.h"
 #include "AArch64Subtarget.h"
-#include "GISel/AArch64RegisterBankInfo.h"
 #include "MCTargetDesc/AArch64AddressingModes.h"
 #include "MCTargetDesc/AArch64InstPrinter.h"
 #include "llvm/ADT/BitVector.h"
@@ -1443,36 +1442,3 @@ bool AArch64RegisterInfo::isIgnoredCVReg(MCRegister LLVMReg) const {
   return (LLVMReg >= AArch64::Z0 && LLVMReg <= AArch64::Z31) ||
          (LLVMReg >= AArch64::P0 && LLVMReg <= AArch64::P15);
 }
-
-// FIXME: This should be target-independent, inferred from the types declared
-// for each class in the bank.
-const TargetRegisterClass *AArch64RegisterInfo::getRegClassForTypeOnBank(
-    LLT Ty, const RegisterBank &RB, const TargetSubtargetInfo *STI) const {
-  if (RB.getID() == AArch64::GPRRegBankID) {
-    if (Ty.getSizeInBits() <= 32)
-      return &AArch64::GPR32RegClass;
-    if (Ty.getSizeInBits() == 64)
-      return &AArch64::GPR64RegClass;
-    if (Ty.getSizeInBits() == 128)
-      return &AArch64::XSeqPairsClassRegClass;
-    return nullptr;
-  }
-
-  if (RB.getID() == AArch64::FPRRegBankID) {
-    switch (Ty.getSizeInBits()) {
-    case 8:
-      return &AArch64::FPR8RegClass;
-    case 16:
-      return &AArch64::FPR16RegClass;
-    case 32:
-      return &AArch64::FPR32RegClass;
-    case 64:
-      return &AArch64::FPR64RegClass;
-    case 128:
-      return &AArch64::FPR128RegClass;
-    }
-    return nullptr;
-  }
-
-  return nullptr;
-}
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
index 7ce922aee3f97..89d1802ab98d5 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
@@ -154,10 +154,6 @@ class AArch64RegisterInfo final : public AArch64GenRegisterInfo {
   bool shouldAnalyzePhysregInMachineLoopInfo(MCRegister R) const override;
 
   bool isIgnoredCVReg(MCRegister LLVMReg) const override;
-
-  const TargetRegisterClass *getRegClassForTypeOnBank(
-      LLT Ty, const RegisterBank &Bank,
-      const TargetSubtargetInfo *STI = nullptr) const override;
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 46d1d2c1029bd..36e2c689aba13 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -564,6 +564,45 @@ AArch64InstructionSelector::AArch64InstructionSelector(
 {
 }
 
+// FIXME: This should be target-independent, inferred from the types declared
+// for each class in the bank.
+//
+/// Given a register bank, and a type, return the smallest register class that
+/// can represent that combination.
+static const TargetRegisterClass *
+getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB,
+                         bool GetAllRegSet = false) {
+  if (RB.getID() == AArch64::GPRRegBankID) {
+    if (Ty.getSizeInBits() <= 32)
+      return GetAllRegSet ? &AArch64::GPR32allRegClass
+                          : &AArch64::GPR32RegClass;
+    if (Ty.getSizeInBits() == 64)
+      return GetAllRegSet ? &AArch64::GPR64allRegClass
+                          : &AArch64::GPR64RegClass;
+    if (Ty.getSizeInBits() == 128)
+      return &AArch64::XSeqPairsClassRegClass;
+    return nullptr;
+  }
+
+  if (RB.getID() == AArch64::FPRRegBankID) {
+    switch (Ty.getSizeInBits()) {
+    case 8:
+      return &AArch64::FPR8RegClass;
+    case 16:
+      return &AArch64::FPR16RegClass;
+    case 32:
+      return &AArch64::FPR32RegClass;
+    case 64:
+      return &AArch64::FPR64RegClass;
+    case 128:
+      return &AArch64::FPR128RegClass;
+    }
+    return nullptr;
+  }
+
+  return nullptr;
+}
+
 /// Given a register bank, and size in bits, return the smallest register class
 /// that can represent that combination.
 static const TargetRegisterClass *
@@ -961,9 +1000,7 @@ static bool selectDebugInstr(MachineInstr &I, MachineRegisterInfo &MRI,
         dyn_cast<const TargetRegisterClass *>(RegClassOrBank);
     if (!RC) {
       const RegisterBank &RB = *cast<const RegisterBank *>(RegClassOrBank);
-      const TargetRegisterInfo *TRI =
-          I.getMF()->getSubtarget().getRegisterInfo();
-      RC = TRI->getRegClassForTypeOnBank(Ty, RB);
+      RC = getRegClassForTypeOnBank(Ty, RB);
       if (!RC) {
         LLVM_DEBUG(
             dbgs() << "Warning: DBG_VALUE operand has unexpected size/bank\n");
@@ -1867,7 +1904,7 @@ bool AArch64InstructionSelector::selectVectorAshrLshr(
   unsigned Opc = 0;
   unsigned NegOpc = 0;
   const TargetRegisterClass *RC =
-      TRI.getRegClassForTypeOnBank(Ty, RBI.getRegBank(AArch64::FPRRegBankID));
+      getRegClassForTypeOnBank(Ty, RBI.getRegBank(AArch64::FPRRegBankID));
   if (Ty == LLT::fixed_vector(2, 64)) {
     Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
     NegOpc = AArch64::NEGv2i64;
@@ -2506,7 +2543,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
           return false;
         }
         const RegisterBank &RB = *cast<const RegisterBank *>(RegClassOrBank);
-        DefRC = TRI.getRegClassForTypeOnBank(DefTy, RB);
+        DefRC = getRegClassForTypeOnBank(DefTy, RB);
         if (!DefRC) {
           LLVM_DEBUG(dbgs() << "PHI operand has unexpected size/bank\n");
           return false;
@@ -2680,8 +2717,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     }
 
     if (isFP) {
-      const TargetRegisterClass &FPRRC =
-          *TRI.getRegClassForTypeOnBank(DefTy, RB);
+      const TargetRegisterClass &FPRRC = *getRegClassForTypeOnBank(DefTy, RB);
       // For 16, 64, and 128b values, emit a constant pool load.
       switch (DefSize) {
       default:
@@ -2743,6 +2779,27 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     constrainSelectedInstRegOperands(I, TII, TRI, RBI);
     return true;
   }
+  case TargetOpcode::G_CONSTANT_FOLD_BARRIER: {
+    auto ConstrainToRC = [&](Register Reg) {
+      const RegisterBank &RB = *RBI.getRegBank(Reg, MRI, TRI);
+      const TargetRegisterClass *RC =
+          getRegClassForTypeOnBank(MRI.getType(Reg), RB);
+      return RC && RBI.constrainGenericRegister(Reg, *RC, MRI);
+    };
+
+    auto [DstReg, SrcReg] = I.getFirst2Regs();
+    if (!ConstrainToRC(DstReg) || !ConstrainToRC(SrcReg))
+      return false;
+
+    if (const auto *DstRC = MRI.getRegClassOrNull(DstReg))
+      MRI.setRegClass(SrcReg, DstRC);
+
+    assert(canReplaceReg(DstReg, SrcReg, MRI) &&
+           "Must be able to replace dst with src!");
+    I.eraseFromParent();
+    MRI.replaceRegWith(DstReg, SrcReg);
+    return true;
+  }
   case TargetOpcode::G_EXTRACT: {
     Register DstReg = I.getOperand(0).getReg();
     Register SrcReg = I.getOperand(1).getReg();
@@ -2974,7 +3031,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     if (isa<GStore>(LdSt) && ValTy.getSizeInBits() > MemSizeInBits) {
       unsigned SubReg;
       LLT MemTy = LdSt.getMMO().getMemoryType();
-      auto *RC = TRI.getRegClassForTypeOnBank(MemTy, RB);
+      auto *RC = getRegClassForTypeOnBank(MemTy, RB);
       if (!getSubRegForClass(RC, TRI, SubReg))
         return false;
 
@@ -2990,7 +3047,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
       if (RB.getID() == AArch64::FPRRegBankID) {
         unsigned SubReg;
         LLT MemTy = LdSt.getMMO().getMemoryType();
-        auto *RC = TRI.getRegClassForTypeOnBank(MemTy, RB);
+        auto *RC = getRegClassForTypeOnBank(MemTy, RB);
         if (!getSubRegForClass(RC, TRI, SubReg))
           return false;
         Register OldDst = LdSt.getReg(0);
@@ -3004,7 +3061,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
             .addImm(0)
             .addUse(NewDst)
             .addImm(SubReg);
-        auto SubRegRC = TRI.getRegClassForTypeOnBank(MRI.getType(OldDst), RB);
+        auto SubRegRC = getRegClassForTypeOnBank(MRI.getType(OldDst), RB);
         RBI.constrainGenericRegister(OldDst, *SubRegRC, MRI);
         MIB.setInstr(LdSt);
         ValTy = MemTy; // This is no longer an extending load.
@@ -3194,13 +3251,11 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     }
 
     if (DstRB.getID() == AArch64::GPRRegBankID) {
-      const TargetRegisterClass *DstRC =
-          TRI.getRegClassForTypeOnBank(DstTy, DstRB);
+      const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
       if (!DstRC)
         return false;
 
-      const TargetRegisterClass *SrcRC =
-          TRI.getRegClassForTypeOnBank(SrcTy, SrcRB);
+      const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB);
       if (!SrcRC)
         return false;
 
@@ -3493,8 +3548,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
     const Register DstReg = I.getOperand(0).getReg();
     const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI);
-    const TargetRegisterClass *DstRC =
-        TRI.getRegClassForTypeOnBank(DstTy, DstRB);
+    const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
     RBI.constrainGenericRegister(DstReg, *DstRC, MRI);
     return true;
   }
@@ -3786,7 +3840,7 @@ AArch64InstructionSelector::emitNarrowVector(Register DstReg, Register SrcReg,
                                              MachineRegisterInfo &MRI) const {
   LLT DstTy = MRI.getType(DstReg);
   const TargetRegisterClass *RC =
-      TRI.getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(SrcReg, MRI, TRI));
+      getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(SrcReg, MRI, TRI));
   if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
     LLVM_DEBUG(dbgs() << "Unsupported register class!\n");
     return nullptr;
@@ -3916,7 +3970,7 @@ MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
   }
 
   const TargetRegisterClass *DstRC =
-      TRI.getRegClassForTypeOnBank(ScalarTy, DstRB);
+      getRegClassForTypeOnBank(ScalarTy, DstRB, true);
   if (!DstRC) {
     LLVM_DEBUG(dbgs() << "Could not determine destination register class.\n");
     return nullptr;
@@ -3924,7 +3978,8 @@ MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
 
   const RegisterBank &VecRB = *RBI.getRegBank(VecReg, MRI, TRI);
   const LLT &VecTy = MRI.getType(VecReg);
-  const TargetRegisterClass *VecRC = TRI.getRegClassForTypeOnBank(VecTy, VecRB);
+  const TargetRegisterClass *VecRC =
+      getRegClassForTypeOnBank(VecTy, VecRB, true);
   if (!VecRC) {
     LLVM_DEBUG(dbgs() << "Could not determine source register class.\n");
     return nullptr;
@@ -4084,7 +4139,7 @@ bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &I,
     // For scalar sources, treat as a pseudo-vector of NarrowTy elements.
     unsigned EltSize = WideTy.isVector() ? WideTy.getScalarSizeInBits()
                                          : NarrowTy.getSizeInBits();
-    const TargetRegisterClass *RC = TRI.getRegClassForTypeOnBank(
+    const TargetRegisterClass *RC = getRegClassForTypeOnBank(
         LLT::fixed_vector(NumElts, EltSize), *RBI.getRegBank(SrcReg, MRI, TRI));
     unsigned SubReg = 0;
     bool Found = getSubRegForClass(RC, TRI, SubReg);
@@ -4545,7 +4600,7 @@ MachineInstr *AArch64InstructionSelector::emitVectorConcat(
   const LLT ScalarTy = LLT::scalar(Op1Ty.getSizeInBits());
   const RegisterBank &FPRBank = *RBI.getRegBank(Op1, MRI, TRI);
   const TargetRegisterClass *DstRC =
-      TRI.getRegClassForTypeOnBank(Op1Ty.multiplyElements(2), FPRBank);
+      getRegClassForTypeOnBank(Op1Ty.multiplyElements(2), FPRBank);
 
   MachineInstr *WidenedOp1 =
       emitScalarToVector(ScalarTy.getSizeInBits(), DstRC, Op1, MIRBuilder);
@@ -5527,8 +5582,8 @@ bool AArch64InstructionSelector::selectIndexedExtLoad(
                         .addImm(InsertIntoSubReg);
     RBI.constrainGenericRegister(
         SubToReg.getReg(0),
-        *TRI.getRegClassForTypeOnBank(MRI.getType(Dst),
-                                      *RBI.getRegBank(Dst, MRI, TRI)),
+        *getRegClassForTypeOnBank(MRI.getType(Dst),
+                                  *RBI.getRegBank(Dst, MRI, TRI)),
         MRI);
   } else {
     auto Copy = MIB.buildCopy(Dst, LdMI.getReg(1));
@@ -5804,11 +5859,11 @@ bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
       }))
     return false;
   unsigned SubReg;
-  const TargetRegisterClass *EltRC = TRI.getRegClassForTypeOnBank(EltTy, EltRB);
+  const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
   if (!EltRC)
     return false;
   const TargetRegisterClass *DstRC =
-      TRI.getRegClassForTypeOnBank(MRI.getType(Dst), DstRB);
+      getRegClassForTypeOnBank(MRI.getType(Dst), DstRB);
   if (!DstRC)
     return false;
   if (!getSubRegForClass(EltRC, TRI, SubReg))
@@ -5869,7 +5924,7 @@ bool AArch64InstructionSelector::selectBuildVector(MachineInstr &I,
   if (DstSize < 128) {
     // Force this to be FPR using the destination vector.
     const TargetRegisterClass *RC =
-        TRI.getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(DstVec, MRI, TRI));
+        getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(DstVec, MRI, TRI));
     if (!RC)
       return false;
     if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
@@ -5911,8 +5966,8 @@ bool AArch64InstructionSelector::selectBuildVector(MachineInstr &I,
 
     Register DstReg = PrevMI->getOperand(0).getReg();
     if (PrevMI == ScalarToVec && DstReg.isVirtual()) {
-      const TargetRegisterClass *RC = TRI.getRegClassForTypeOnBank(
-          DstTy, *RBI.getRegBank(DstVec, MRI, TRI));
+      const TargetRegisterClass *RC =
+          getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(DstVec, MRI, TRI));
       RBI.constrainGenericRegister(DstReg, *RC, MRI);
     }
   }
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.h b/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
index 62ed20c3fff8c..2e2916f68f584 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
@@ -364,9 +364,8 @@ class SIRegisterInfo final : public AMDGPUGenRegisterInfo {
   const TargetRegisterClass *
   getRegClassForSizeOnBank(unsigned Size, const RegisterBank &Bank) const;
 
-  const TargetRegisterClass *getRegClassForTypeOnBank(
-      LLT Ty, const RegisterBank &Bank,
-      const TargetSubtargetInfo *STI = nullptr) const override {
+  const TargetRegisterClass *
+  getRegClassForTypeOnBank(LLT Ty, const RegisterBank &Bank) const {
     return getRegClassForSizeOnBank(Ty.getSizeInBits(), Bank);
   }
 
diff --git a/llvm/lib/Target/Mips/MipsInstructionSelector.cpp b/llvm/lib/Target/Mips/MipsInstructionSelector.cpp
index 029f1c4a5cef9..bd02b57bfc860 100644
--- a/llvm/lib/Target/Mips/MipsInstructionSelector.cpp
+++ b/llvm/lib/Target/Mips/MipsInstructionSelector.cpp
@@ -45,6 +45,8 @@ class MipsInstructionSelector : public InstructionSelector {
   bool materialize32BitImm(Register DestReg, APInt Imm,
                            MachineIRBuilder &B) const;
   bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
+  const TargetRegisterClass *
+  getRegClassForTypeOnBank(Register Reg, MachineRegisterInfo &MRI) const;
   unsigned selectLoadStoreOpCode(MachineInstr &I,
                                  MachineRegisterInfo &MRI) const;
   bool buildUnalignedStore(MachineInstr &I, unsigned Opc,
@@ -106,9 +108,7 @@ bool MipsInstructionSelector::selectCopy(MachineInstr &I,
   if (DstReg.isPhysical())
     return true;
 
-  const TargetRegisterClass *RC = TRI.getRegClassForTypeOnBank(
-      MRI.getType(DstReg), *RBI.getRegBank(DstReg, MRI, TRI),
-      &MF->getSubtarget());
+  const TargetRegisterClass *RC = getRegClassForTypeOnBank(DstReg, MRI);
   if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
     LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
                       << " operand\n");
@@ -117,6 +117,34 @@ bool MipsInstructionSelector::selectCopy(MachineInstr &I,
   return true;
 }
 
+const TargetRegisterClass *MipsInstructionSelector::getRegClassForTypeOnBank(
+    Register Reg, MachineRegisterInfo &MRI) const {
+  const LLT Ty = MRI.getType(Reg);
+  const unsigned TySize = Ty.getSizeInBits();
+
+  if (isRegInGprb(Reg, MRI)) {
+    assert((Ty.isScalar() || Ty.isPointer()) &&
+           (TySize == 32 || TySize == 64) &&
+           "Register class not available for LLT, register bank combination");
+    if (TySize == 32)
+      return &Mips::GPR32RegClass;
+    if (TySize == 64)
+      return &Mips::GPR64RegClass;
+  }
+
+  if (isRegInFprb(Reg, MRI)) {
+    if (Ty.isScalar()) {
+      assert((TySize == 32 || TySize == 64) &&
+             "Register class not available for LLT, register bank combination");
+      if (TySize == 32)
+        return &Mips::FGR32RegClass;
+      return STI.isFP64bit() ? &Mips::FGR64RegClass : &Mips::AFGR64RegClass;
+    }
+  }
+
+  llvm_unreachable("Unsupported register bank.");
+}
+
 bool MipsInstructionSelector::materialize32BitImm(Register DestReg, APInt Imm,
                                                   MachineIRBuilder &B) const {
   assert(Imm.getBitWidth() == 32 && "Unsupported immediate size.");
@@ -400,9 +428,7 @@ bool MipsInstructionSelector::select(MachineInstr &I) {
     if (DestReg.isPhysical())
       DefRC = TRI.getRegClass(DestReg);
     else
-      DefRC = TRI.getRegClassForTypeOnBank(MRI.getType(DestReg),
-                                           *RBI.getRegBank(DestReg, MRI, TRI),
-                                           &MF.getSubtarget());
+      DefRC = getRegClassForTypeOnBank(DestReg, MRI);
 
     I.setDesc(TII.get(TargetOpcode::PHI));
     return RBI.constrainGenericRegister(DestReg, *DefRC, MRI);
@@ -550,9 +576,7 @@ bool MipsInstructionSelector::select(MachineInstr &I) {
              .addDef(Dst);
 
     // Set class based on register bank, there can be fpr and gpr implicit def.
-    MRI.setRegClass(Dst, TRI.getRegClassForTypeOnBank(
-                             MRI.getType(Dst), *RBI.getRegBank(Dst, MRI, TRI),
-                             &MF.getSubtarget()));
+    MRI.setRegClass(Dst, getRegClassForTypeOnBank(Dst, MRI));
     break;
   }
   case G_CONSTANT: {
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index 288224a6f2284..948d4db8585db 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -14,7 +14,6 @@
 #include "MCTargetDesc/MipsABIInfo.h"
 #include "Mips.h"
 #include "MipsMachineFunction.h"
-#include "MipsRegisterBankInfo.h"
 #include "MipsSubtarget.h"
 #include "MipsTargetMachine.h"
 #include "llvm/ADT/BitVector.h"
@@ -320,33 +319,3 @@ bool MipsRegisterInfo::canRealignStack(const MachineFunction &MF) const {
   // sized objects.
   return MF.getRegInfo().canReserveReg(BP);
 }
-
-const TargetRegisterClass *MipsRegisterInfo::getRegClassForTypeOnBank(
-    LLT Ty, const RegisterBank &RB, const TargetSubtargetInfo *STI) const {
-  const unsigned TySize = Ty.getSizeInBits();
-
-  if (RB.getID() == Mips::GPRBRegBankID) {
-    assert((Ty.isScalar() || Ty.isPointer()) &&
-           (TySize == 32 || TySize == 64) &&
-           "Register class not available for LLT, register bank combination");
-    if (TySize == 32)
-      return &Mips::GPR32RegClass;
-    if (TySize == 64)
-      return &Mips::GPR64RegClass;
-  }
-
-  if (RB.getID() == Mips::FPRBRegBankID) {
-    if (Ty.isScalar()) {
-      assert((TySize == 32 || TySize == 64) &&
-             "Register class not available for LLT, register bank combination");
-      if (TySize == 32)
-        return &Mips::FGR32RegClass;
-      assert(STI != nullptr);
-      return static_cast<const MipsSubtarget *>(STI)->isFP64bit()
-                 ? &Mips::FGR64RegClass
-                 : &Mips::AFGR64RegClass;
-    }
-  }
-
-  llvm_unreachable("Unsupported register bank.");
-}
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.h b/llvm/lib/Target/Mips/MipsRegisterInfo.h
index 39c86b5ec16f9..e2e81af4a8af1 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.h
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.h
@@ -60,10 +60,6 @@ class MipsRegisterInfo : public MipsGenRegisterInfo {
   /// Return GPR register class.
   virtual const TargetRegisterClass *intRegClass(unsigned Size) const = 0;
 
-  const TargetRegisterClass *
-  getRegClassForTypeOnBank(LLT Ty, const RegisterBank &Bank,
-                           const TargetSubtargetInfo *STI) const override;
-
 private:
   virtual void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo,
                            int FrameIndex, uint64_t StackSize,
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 51a3c7b3a7a97..8769bb2238980 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -54,6 +54,9 @@ class RISCVInstructionSelector : public InstructionSelector {
   static const char *getName() { return DEBUG_TYPE; }
 
 private:
+  const TargetRegisterClass *
+  getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) const;
+
   static constexpr unsigned MaxRecursionDepth = 6;
 
   bool hasAllNBitUsers(const MachineInstr &MI, unsigned Bits,
@@ -1102,7 +1105,7 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
         }
 
         const RegisterBank &RB = *cast<const RegisterBank *>(RegClassOrBank);
-        DefRC = TRI.getRegClassForTypeOnBank(DefTy, RB, &MF->getSubtarget());
+        DefRC = getRegClassForTypeOnBank(DefTy, RB);
         if (!DefRC) {
           LLVM_DEBUG(dbgs() << "PHI operand has unexpected size/bank\n");
           return false;
@@ -1503,6 +1506,39 @@ void RISCVInstructionSelector::renderAddiPairImmLarge(MachineInstrBuilder &MIB,
   MIB.addImm(Imm);
 }
 
+const TargetRegisterClass *RISCVInstructionSelector::getRegClassForTypeOnBank(
+    LLT Ty, const RegisterBank &RB) const {
+  if (RB.getID() == RISCV::GPRBRegBankID) {
+    if (Ty.getSizeInBits() <= 32 || (STI.is64Bit() && Ty.getSizeInBits() == 64))
+      return &RISCV::GPRRegClass;
+  }
+
+  if (RB.getID() == RISCV::FPRBRegBankID) {
+    if (Ty.getSizeInBits() == 16)
+      return &RISCV::FPR16RegClass;
+    if (Ty.getSizeInBits() == 32)
+      return &RISCV::FPR32RegClass;
+    if (Ty.getSizeInBits() == 64)
+      return &RISCV::FPR64RegClass;
+  }
+
+  if (RB.getID() == RISCV::VRBRegBankID) {
+    if (Ty.getSizeInBits().getKnownMinValue() <= 64)
+      return &RISCV::VRRegClass;
+
+    if (Ty.getSizeInBits().getKnownMinValue() == 128)
+      return &RISCV::VRM2RegClass;
+
+    if (Ty.getSizeInBits().getKnownMinValue() == 256)
+      return &RISCV::VRM4RegClass;
+
+    if (Ty.getSizeInBits().getKnownMinValue() == 512)
+      return &RISCV::VRM8RegClass;
+  }
+
+  return nullptr;
+}
+
 bool RISCVInstructionSelector::isRegInGprb(Register Reg) const {
   return RBI.getRegBank(Reg, *MRI, TRI)->getID() == RISCV::GPRBRegBankID;
 }
@@ -1517,9 +1553,8 @@ bool RISCVInstructionSelector::selectCopy(MachineInstr &MI) const {
   if (DstReg.isPhysical())
     return true;
 
-  const TargetRegisterClass *DstRC = TRI.getRegClassForTypeOnBank(
-      MRI->getType(DstReg), *RBI.getRegBank(DstReg, *MRI, TRI),
-      &MF->getSubtarget());
+  const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(
+      MRI->getType(DstReg), *RBI.getRegBank(DstReg, *MRI, TRI));
   assert(DstRC &&
          "Register class not available for LLT, register bank combination");
 
@@ -1541,9 +1576,8 @@ bool RISCVInstructionSelector::selectImplicitDef(MachineInstr &MI,
   assert(MI.getOpcode() == TargetOpcode::G_IMPLICIT_DEF);
 
   const Register DstReg = MI.getOperand(0).getReg();
-  const TargetRegisterClass *DstRC = TRI.getRegClassForTypeOnBank(
-      MRI->getType(DstReg), *RBI.getRegBank(DstReg, *MRI, TRI),
-      &MF->getSubtarget());
+  const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(
+      MRI->getType(DstReg), *RBI.getRegBank(DstReg, *MRI, TRI));
 
   assert(DstRC &&
          "Register class not available for LLT, register bank combination");
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index d764eace00800..0770935b749d9 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -11,7 +11,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "RISCVRegisterInfo.h"
-#include "GISel/RISCVRegisterBankInfo.h"
 #include "RISCV.h"
 #include "RISCVSubtarget.h"
 #include "llvm/ADT/SmallSet.h"
@@ -1092,39 +1091,3 @@ RISCVRegisterInfo::findVRegWithEncoding(const TargetRegisterClass &RegClass,
     return Reg;
   return getMatchingSuperReg(Reg, RISCV::sub_vrm1_0, &RegClass);
 }
-
-const TargetRegisterClass *RISCVRegisterInfo::getRegClassForTypeOnBank(
-    LLT Ty, const RegisterBank &RB, const TargetSubtargetInfo *STI) const {
-  assert(STI != nullptr);
-  if (RB.getID() == RISCV::GPRBRegBankID) {
-    if (Ty.getSizeInBits() <= 32 ||
-        (static_cast<const RISCVSubtarget *>(STI)->is64Bit() &&
-         Ty.getSizeInBits() == 64))
-      return &RISCV::GPRRegClass;
-  }
-
-  if (RB.getID() == RISCV::FPRBRegBankID) {
-    if (Ty.getSizeInBits() == 16)
-      return &RISCV::FPR16RegClass;
-    if (Ty.getSizeInBits() == 32)
-      return &RISCV::FPR32RegClass;
-    if (Ty.getSizeInBits() == 64)
-      return &RISCV::FPR64RegClass;
-  }
-
-  if (RB.getID() == RISCV::VRBRegBankID) {
-    if (Ty.getSizeInBits().getKnownMinValue() <= 64)
-      return &RISCV::VRRegClass;
-
-    if (Ty.getSizeInBits().getKnownMinValue() == 128)
-      return &RISCV::VRM2RegClass;
-
-    if (Ty.getSizeInBits().getKnownMinValue() == 256)
-      return &RISCV::VRM4RegClass;
-
-    if (Ty.getSizeInBits().getKnownMinValue() == 512)
-      return &RISCV::VRM8RegClass;
-  }
-
-  return nullptr;
-}
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h
index d98240447454c..f29f85e4987f6 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h
@@ -168,10 +168,6 @@ struct RISCVRegisterInfo : public RISCVGenRegisterInfo {
   static bool isRVVRegClass(const TargetRegisterClass *RC) {
     return RISCVRI::isVRegClass(RC->TSFlags);
   }
-
-  const TargetRegisterClass *
-  getRegClassForTypeOnBank(LLT Ty, const RegisterBank &Bank,
-                           const TargetSubtargetInfo *STI) const override;
 };
 } // namespace llvm
 

>From 766e2707582559b3d978c7a4cd4451d81f13a59a Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Fri, 30 Jan 2026 11:22:36 +0000
Subject: [PATCH 5/6] address comments

---
 .../CodeGen/GlobalISel/InstructionSelect.cpp  | 16 +++++---------
 .../GISel/AArch64InstructionSelector.cpp      | 21 -------------------
 2 files changed, 5 insertions(+), 32 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
index 4b1a8a34ab3fc..5fb31a04e5fd0 100644
--- a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
@@ -356,14 +356,7 @@ bool InstructionSelect::selectInstr(MachineInstr &MI) {
     return true;
   }
 
-  if (MI.getOpcode() == TargetOpcode::G_CONSTANT_FOLD_BARRIER) {
-    // Allow targets to provide custom handling before falling back to the
-    // generic elimination below.
-    if (ISel->select(MI))
-      return true;
-  }
-
-  // Eliminate hints or a remaining G_CONSTANT_FOLD_BARRIER.
+  // Eliminate hints or G_CONSTANT_FOLD_BARRIER.
   if (isPreISelGenericOptimizationHint(MI.getOpcode()) ||
       MI.getOpcode() == TargetOpcode::G_CONSTANT_FOLD_BARRIER) {
     auto [DstReg, SrcReg] = MI.getFirst2Regs();
@@ -373,10 +366,11 @@ bool InstructionSelect::selectInstr(MachineInstr &MI) {
     //
     // Propagate that through to the source register.
     const TargetRegisterClass *DstRC = MRI.getRegClassOrNull(DstReg);
-    if (DstRC)
+    const TargetRegisterClass *SrcRC = MRI.getRegClassOrNull(SrcReg);
+    if (DstRC && SrcRC)
+      MRI.constrainRegClass(SrcReg, DstRC);
+    else if (DstRC)
       MRI.setRegClass(SrcReg, DstRC);
-    assert(canReplaceReg(DstReg, SrcReg, MRI) &&
-           "Must be able to replace dst with src!");
     MI.eraseFromParent();
     MRI.replaceRegWith(DstReg, SrcReg);
     return true;
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 36e2c689aba13..7605bbea51f56 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -2779,27 +2779,6 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     constrainSelectedInstRegOperands(I, TII, TRI, RBI);
     return true;
   }
-  case TargetOpcode::G_CONSTANT_FOLD_BARRIER: {
-    auto ConstrainToRC = [&](Register Reg) {
-      const RegisterBank &RB = *RBI.getRegBank(Reg, MRI, TRI);
-      const TargetRegisterClass *RC =
-          getRegClassForTypeOnBank(MRI.getType(Reg), RB);
-      return RC && RBI.constrainGenericRegister(Reg, *RC, MRI);
-    };
-
-    auto [DstReg, SrcReg] = I.getFirst2Regs();
-    if (!ConstrainToRC(DstReg) || !ConstrainToRC(SrcReg))
-      return false;
-
-    if (const auto *DstRC = MRI.getRegClassOrNull(DstReg))
-      MRI.setRegClass(SrcReg, DstRC);
-
-    assert(canReplaceReg(DstReg, SrcReg, MRI) &&
-           "Must be able to replace dst with src!");
-    I.eraseFromParent();
-    MRI.replaceRegWith(DstReg, SrcReg);
-    return true;
-  }
   case TargetOpcode::G_EXTRACT: {
     Register DstReg = I.getOperand(0).getReg();
     Register SrcReg = I.getOperand(1).getReg();

>From 93d43c9f7fd5ded3f22428291335f31e720146c0 Mon Sep 17 00:00:00 2001
From: Cullen Rhodes <cullen.rhodes at arm.com>
Date: Fri, 30 Jan 2026 13:43:35 +0000
Subject: [PATCH 6/6] address comments

---
 .../CodeGen/AArch64/GlobalISel/166563.mir     | 94 +++++++++----------
 1 file changed, 44 insertions(+), 50 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/166563.mir b/llvm/test/CodeGen/AArch64/GlobalISel/166563.mir
index 7e376f4f3c394..12e362e7b7fd2 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/166563.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/166563.mir
@@ -5,12 +5,9 @@
 
 ---
 name:            pr166563
-alignment:       4
 legalized:       true
 regBankSelected: true
 tracksRegLiveness: true
-liveins:
-  - { reg: '$w0', virtual-reg: '' }
 body:             |
   ; CHECK-LABEL: name: pr166563
   ; CHECK: bb.0:
@@ -67,48 +64,48 @@ body:             |
     successors: %bb.3(0x30000000), %bb.2(0x50000000)
     liveins: $w0
 
-    %2:gpr(s32) = COPY $w0
-    %6:gpr(s64) = G_CONSTANT i64 457873110
-    %36:gpr(s32) = G_CONSTANT i32 1
-    G_BRCOND %36(s32), %bb.3
+    %0:gpr(s32) = COPY $w0
+    %1:gpr(s64) = G_CONSTANT i64 457873110
+    %2:gpr(s32) = G_CONSTANT i32 1
+    G_BRCOND %2(s32), %bb.3
     G_BR %bb.2
 
   bb.2:
     successors: %bb.7(0x80000000)
 
-    %7:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
+    %3:gpr(s64) = G_CONSTANT_FOLD_BARRIER %1
     G_BR %bb.7
 
   bb.3:
     successors: %bb.4(0x40000000), %bb.5(0x40000000)
 
-    %28:gpr(s32) = G_CONSTANT i32 1
-    %29:gpr(s32) = G_XOR %2, %28
-    %26:gpr(s32) = G_AND %29, %28
-    G_BRCOND %26(s32), %bb.5
+    %4:gpr(s32) = G_CONSTANT i32 1
+    %5:gpr(s32) = G_XOR %0, %4
+    %6:gpr(s32) = G_AND %5, %4
+    G_BRCOND %6(s32), %bb.5
     G_BR %bb.4
 
   bb.4:
     successors: %bb.6(0x80000000)
 
-    %14:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
-    %23:gpr(s64) = G_CONSTANT i64 -2
-    %16:gpr(s64) = G_ADD %14, %23
+    %7:gpr(s64) = G_CONSTANT_FOLD_BARRIER %1
+    %8:gpr(s64) = G_CONSTANT i64 -2
+    %9:gpr(s64) = G_ADD %7, %8
     G_BR %bb.6
 
   bb.5:
-    %12:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
-    %24:gpr(s64) = G_CONSTANT i64 0
-    %13:gpr(s64) = G_AND %24, %12
-    $x0 = COPY %13(s64)
+    %10:gpr(s64) = G_CONSTANT_FOLD_BARRIER %1
+    %11:gpr(s64) = G_CONSTANT i64 0
+    %12:gpr(s64) = G_AND %11, %10
+    $x0 = COPY %12(s64)
     RET_ReallyLR implicit $x0
 
   bb.6:
     successors: %bb.6(0x80000000)
 
-    %17:gpr(s64) = G_PHI %16(s64), %bb.4, %19(s64), %bb.6
-    %22:gpr(s64) = G_CONSTANT i64 -1
-    %19:gpr(s64) = G_ADD %17, %22
+    %13:gpr(s64) = G_PHI %9(s64), %bb.4, %15(s64), %bb.6
+    %14:gpr(s64) = G_CONSTANT i64 -1
+    %15:gpr(s64) = G_ADD %13, %14
     G_BR %bb.6
 
   bb.7:
@@ -117,19 +114,16 @@ body:             |
   bb.8:
     successors: %bb.8(0x7c000000), %bb.7(0x04000000)
 
-    %25:gpr(s64) = G_CONSTANT i64 0
-    %32:gpr(s32) = G_ICMP intpred(ugt), %7(s64), %25
-    G_BRCOND %32(s32), %bb.8
+    %16:gpr(s64) = G_CONSTANT i64 0
+    %17:gpr(s32) = G_ICMP intpred(ugt), %3(s64), %16
+    G_BRCOND %17(s32), %bb.8
     G_BR %bb.7
 ...
 ---
 name:            pr166563_commuted_and
-alignment:       4
 legalized:       true
 regBankSelected: true
 tracksRegLiveness: true
-liveins:
-  - { reg: '$w0', virtual-reg: '' }
 body:             |
   ; CHECK-LABEL: name: pr166563_commuted_and
   ; CHECK: bb.0:
@@ -186,48 +180,48 @@ body:             |
     successors: %bb.3(0x30000000), %bb.2(0x50000000)
     liveins: $w0
 
-    %2:gpr(s32) = COPY $w0
-    %6:gpr(s64) = G_CONSTANT i64 457873110
-    %36:gpr(s32) = G_CONSTANT i32 1
-    G_BRCOND %36(s32), %bb.3
+    %0:gpr(s32) = COPY $w0
+    %1:gpr(s64) = G_CONSTANT i64 457873110
+    %2:gpr(s32) = G_CONSTANT i32 1
+    G_BRCOND %2(s32), %bb.3
     G_BR %bb.2
 
   bb.2:
     successors: %bb.7(0x80000000)
 
-    %7:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
+    %3:gpr(s64) = G_CONSTANT_FOLD_BARRIER %1
     G_BR %bb.7
 
   bb.3:
     successors: %bb.4(0x40000000), %bb.5(0x40000000)
 
-    %28:gpr(s32) = G_CONSTANT i32 1
-    %29:gpr(s32) = G_XOR %2, %28
-    %26:gpr(s32) = G_AND %29, %28
-    G_BRCOND %26(s32), %bb.5
+    %4:gpr(s32) = G_CONSTANT i32 1
+    %5:gpr(s32) = G_XOR %0, %4
+    %6:gpr(s32) = G_AND %5, %4
+    G_BRCOND %6(s32), %bb.5
     G_BR %bb.4
 
   bb.4:
     successors: %bb.6(0x80000000)
 
-    %14:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
-    %23:gpr(s64) = G_CONSTANT i64 -2
-    %16:gpr(s64) = G_ADD %14, %23
+    %7:gpr(s64) = G_CONSTANT_FOLD_BARRIER %1
+    %8:gpr(s64) = G_CONSTANT i64 -2
+    %9:gpr(s64) = G_ADD %7, %8
     G_BR %bb.6
 
   bb.5:
-    %12:gpr(s64) = G_CONSTANT_FOLD_BARRIER %6
-    %24:gpr(s64) = G_CONSTANT i64 0
-    %13:gpr(s64) = G_AND %12, %24
-    $x0 = COPY %13(s64)
+    %10:gpr(s64) = G_CONSTANT_FOLD_BARRIER %1
+    %11:gpr(s64) = G_CONSTANT i64 0
+    %12:gpr(s64) = G_AND %10, %11
+    $x0 = COPY %12(s64)
     RET_ReallyLR implicit $x0
 
   bb.6:
     successors: %bb.6(0x80000000)
 
-    %17:gpr(s64) = G_PHI %16(s64), %bb.4, %19(s64), %bb.6
-    %22:gpr(s64) = G_CONSTANT i64 -1
-    %19:gpr(s64) = G_ADD %17, %22
+    %13:gpr(s64) = G_PHI %9(s64), %bb.4, %15(s64), %bb.6
+    %14:gpr(s64) = G_CONSTANT i64 -1
+    %15:gpr(s64) = G_ADD %13, %14
     G_BR %bb.6
 
   bb.7:
@@ -236,8 +230,8 @@ body:             |
   bb.8:
     successors: %bb.8(0x7c000000), %bb.7(0x04000000)
 
-    %25:gpr(s64) = G_CONSTANT i64 0
-    %32:gpr(s32) = G_ICMP intpred(ugt), %7(s64), %25
-    G_BRCOND %32(s32), %bb.8
+    %16:gpr(s64) = G_CONSTANT i64 0
+    %17:gpr(s32) = G_ICMP intpred(ugt), %3(s64), %16
+    G_BRCOND %17(s32), %bb.8
     G_BR %bb.7
 ...



More information about the llvm-commits mailing list