[llvm] [AArch64][PeepholeOpt] Use correct register class for subreg uses fro… (PR #226595)

David Green via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 14:14:54 PDT 2026


https://github.com/davemgreen created https://github.com/llvm/llvm-project/pull/226595

isCoalescableExtInstr from an instruction like SBFMXri can reuse the def of the instruction. For some targets this is expected to be a gpr32->gpr64 extend, but for AArch64 and PPC is gpr64->gpr64 and we are UseSrcSubIdx and are expecting to generate a subreg copy. The regclass used was for the full register though, not the subreg, generating an invalid copy and INSERT_SUBREG operand (in this case).

Fixes #226352

>From 8cb3bc266b5196af75baa79522204162ffc5a4ea Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Fri, 25 Sep 2026 21:34:46 +0100
Subject: [PATCH] [AArch64][PeepholeOpt] Use correct register class for subreg
 uses from optimizeExtInstr.

isCoalescableExtInstr from an instruction like SBFMXri can reuse the def of the
instruction. For some targets this is expected to be a gpr32->gpr64 extend, but
for AArch64 and PPC is gpr64->gpr64 and we are UseSrcSubIdx and are expecting
to generate a subreg copy. The regclass used was for the full register though,
not the subreg, generating an invalid copy and INSERT_SUBREG operand (in this
case).

Fixes #226352
---
 llvm/lib/CodeGen/PeepholeOptimizer.cpp        | 16 ++++--
 .../CodeGen/AArch64/coalescableextinstr.mir   | 51 +++++++++++++++++++
 .../CodeGen/PowerPC/peephole-subreg-def.mir   |  2 +-
 3 files changed, 63 insertions(+), 6 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/coalescableextinstr.mir

diff --git a/llvm/lib/CodeGen/PeepholeOptimizer.cpp b/llvm/lib/CodeGen/PeepholeOptimizer.cpp
index 5edfc97bab30cb..aeea9ca581d310 100644
--- a/llvm/lib/CodeGen/PeepholeOptimizer.cpp
+++ b/llvm/lib/CodeGen/PeepholeOptimizer.cpp
@@ -922,17 +922,23 @@ bool PeepholeOptimizer::optimizeExtInstr(
       // %6:gprc_and_gprc_nor0 = COPY %1.sub_32:g8rc_and_g8rc_nox0
       // %3:gprc_and_gprc_nor0 = COPY %6:gprc_and_gprc_nor0
       //
-      if (UseSrcSubIdx)
-        RC = MRI->getRegClass(UseMI->getOperand(0).getReg());
+      if (UseSrcSubIdx) {
+        RC = MRI->getRegClass(UseMO->getReg());
+        if (UseMO->getSubReg())
+          RC = TRI->getSubRegisterClass(RC, UseMO->getSubReg());
+      }
 
       Register NewVR = MRI->createVirtualRegister(RC);
-      BuildMI(*UseMBB, UseMI, UseMI->getDebugLoc(),
-              TII->get(TargetOpcode::COPY), NewVR)
-          .addReg(DstReg, {}, SubIdx);
+      [[maybe_unused]] auto Copy = BuildMI(*UseMBB, UseMI, UseMI->getDebugLoc(),
+                                           TII->get(TargetOpcode::COPY), NewVR)
+                                       .addReg(DstReg, {}, SubIdx);
+      LLVM_DEBUG(dbgs() << "  Build new copy: " << *Copy);
+      LLVM_DEBUG(dbgs() << "  Changing: " << *UseMI);
       if (UseSrcSubIdx)
         UseMO->setSubReg(0);
 
       UseMO->setReg(NewVR);
+      LLVM_DEBUG(dbgs() << "        to: " << *UseMI);
       ++NumReuse;
       Changed = true;
     }
diff --git a/llvm/test/CodeGen/AArch64/coalescableextinstr.mir b/llvm/test/CodeGen/AArch64/coalescableextinstr.mir
new file mode 100644
index 00000000000000..9d972b80ba3fb0
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/coalescableextinstr.mir
@@ -0,0 +1,51 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=aarch64 -run-pass=peephole-opt -verify-machineinstrs -o - %s | FileCheck %s
+
+---
+name:            test
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: test
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT:   liveins: $x0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   %0:gpr32 = COPY $x0
+  ; CHECK-NEXT:   B %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   %1:gpr64all = IMPLICIT_DEF
+  ; CHECK-NEXT:   %7:gpr32 = COPY %5.sub_32
+  ; CHECK-NEXT:   %2:gpr64 = INSERT_SUBREG %1, %7, %subreg.sub_32
+  ; CHECK-NEXT:   %4:gpr64common = ANDXri %5, 4096
+  ; CHECK-NEXT:   $w0 = COPY %2
+  ; CHECK-NEXT:   RET_ReallyLR implicit $w0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   $x0 = COPY %0
+  ; CHECK-NEXT:   %6:gpr64 = COPY $x0
+  ; CHECK-NEXT:   %3:gpr32all = COPY %6.sub_32
+  ; CHECK-NEXT:   %5:gpr64 = SBFMXri %6, 0, 31
+  ; CHECK-NEXT:   B %bb.1
+  bb.0:
+    liveins: $x0
+    %6:gpr32 = COPY $x0
+
+    B %bb.2
+
+  bb.1:
+    %3:gpr64all = IMPLICIT_DEF
+    %4:gpr64 = INSERT_SUBREG %3, %1, %subreg.sub_32
+    %5:gpr64common = ANDXri %2, 4096
+    $w0 = COPY %4
+    RET_ReallyLR implicit $w0
+
+  bb.2:
+    $x0 = COPY %6
+    %0:gpr64 = COPY $x0
+    %1:gpr32all = COPY %0.sub_32
+    %2:gpr64 = SBFMXri %0, 0, 31
+    B %bb.1
+...
diff --git a/llvm/test/CodeGen/PowerPC/peephole-subreg-def.mir b/llvm/test/CodeGen/PowerPC/peephole-subreg-def.mir
index 2a234e83f8e9a1..42dec448afc7e2 100644
--- a/llvm/test/CodeGen/PowerPC/peephole-subreg-def.mir
+++ b/llvm/test/CodeGen/PowerPC/peephole-subreg-def.mir
@@ -24,7 +24,7 @@ body:             |
     ; CHECK-NEXT: [[EXTSW:%[0-9]+]]:g8rc_and_g8rc_nox0 = EXTSW [[ADDI8_]]
     ; CHECK-NEXT: [[LI8_:%[0-9]+]]:g8rc = LI8 0
     ; CHECK-NEXT: STB8 [[LI8_]], 0, [[EXTSW]]
-    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gprc_and_gprc_nor0 = COPY [[EXTSW]].sub_32
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gprc = COPY [[EXTSW]].sub_32
     ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gprc_and_gprc_nor0 = COPY [[EXTSW]].sub_32
     ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gprc = ADDI killed [[COPY2]], 1
     ; CHECK-NEXT: [[EXTSW_32_64_:%[0-9]+]]:g8rc_and_g8rc_nox0 = EXTSW_32_64 killed [[ADDI]]



More information about the llvm-commits mailing list