[llvm-branch-commits] [llvm] PPC: Fix extsw elimination when the input reads a subregister (PR #208052)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Sep 20 02:14:07 PDT 2026


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/208052

>From 32e27201f4ef6ab67659a5751b2314c6e6b45603 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 7 Jul 2026 17:04:45 +0200
Subject: [PATCH 1/3] PPC: Fix extsw elimination when the input reads a
 subregister

The EXTSW_32_64 sign-extend elimination previously assumed its input
was a full register value. It would then try using that value as the
source of the new (unnecessary) INSERT_SUBREG.

The new test would then hit this verifier error:

```
bb.0:
  liveins: $x3
  %0:g8rc = COPY killed $x3
  %1:g8rc = RLDICL killed %0:g8rc, 0, 33
  %3:g8rc = IMPLICIT_DEF
  %2:g8rc = INSERT_SUBREG %3:g8rc(tied-def 0), %1:g8rc, %subreg.sub_32
  $x3 = COPY killed %2:g8rc
  BLR8 implicit $lr8, implicit $rm, implicit killed $x3

*** Bad machine code: INSERT_SUBREG expected inserted value to have equal or lesser size than the subreg it was inserted into ***
- function:    extsw_elim_subreg_input
- basic block: %bb.0  (0x13c834070)
- instruction: %2:g8rc = INSERT_SUBREG %3:g8rc(tied-def 0), %1:g8rc, %subreg.sub_32
```

This avoids verifier error regressions in a future change.

Co-Authored-By: Claude <noreply at anthropic.com> (Claude Opus 4.8, claude-opus-4-8)
---
 llvm/lib/Target/PowerPC/PPCMIPeephole.cpp     | 39 +++++++++++++------
 .../peephole-elim-extsw-subreg-input.mir      | 30 ++++++++++++++
 2 files changed, 57 insertions(+), 12 deletions(-)
 create mode 100644 llvm/test/CodeGen/PowerPC/peephole-elim-extsw-subreg-input.mir

diff --git a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
index 71a7994750c56..ea56e71eb789a 100644
--- a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
+++ b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
@@ -1016,11 +1016,14 @@ bool PPCMIPeephole::simplifyCode() {
         if (!NarrowReg.isVirtual())
           break;
 
+        unsigned NarrowSubReg = MI.getOperand(1).getSubReg();
+
         MachineInstr *SrcMI = MRI->getVRegDef(NarrowReg);
         unsigned SrcOpcode = SrcMI->getOpcode();
         // If we've used a zero-extending load that we will sign-extend,
         // just do a sign-extending load.
-        if (SrcOpcode == PPC::LWZ || SrcOpcode == PPC::LWZX) {
+        if (!NarrowSubReg &&
+            (SrcOpcode == PPC::LWZ || SrcOpcode == PPC::LWZX)) {
           if (!MRI->hasOneNonDBGUse(SrcMI->getOperand(0).getReg()))
             break;
 
@@ -1088,18 +1091,30 @@ bool PPCMIPeephole::simplifyCode() {
           // chain used to deduce sign extension to eliminate the 'extsw' will
           // need to be promoted to 64-bit pseudo instructions when the 'extsw'
           // is eliminated.
-          TII->promoteInstr32To64ForElimEXTSW(NarrowReg, MRI, 0, LV);
-
           LLVM_DEBUG(dbgs() << "Removing redundant sign-extension\n");
-          Register TmpReg =
-              MF->getRegInfo().createVirtualRegister(&PPC::G8RCRegClass);
-          BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::IMPLICIT_DEF),
-                  TmpReg);
-          BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::INSERT_SUBREG),
-                  MI.getOperand(0).getReg())
-              .addReg(TmpReg)
-              .addReg(NarrowReg)
-              .addImm(PPC::sub_32);
+
+          if (NarrowSubReg) {
+            // The input reads a subregister of a wider register which we can
+            // use directly.
+            assert(NarrowSubReg == PPC::sub_32 &&
+                   "EXTSW_32_64 input must read the sub_32 subregister");
+            BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY),
+                    MI.getOperand(0).getReg())
+                .addReg(NarrowReg);
+            addRegToUpdate(NarrowReg);
+          } else {
+            TII->promoteInstr32To64ForElimEXTSW(NarrowReg, MRI, 0, LV);
+
+            Register TmpReg =
+                MF->getRegInfo().createVirtualRegister(&PPC::G8RCRegClass);
+            BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::IMPLICIT_DEF),
+                    TmpReg);
+            BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::INSERT_SUBREG),
+                    MI.getOperand(0).getReg())
+                .addReg(TmpReg)
+                .addReg(NarrowReg)
+                .addImm(PPC::sub_32);
+          }
           ToErase = &MI;
           Simplified = true;
           NumEliminatedSExt++;
diff --git a/llvm/test/CodeGen/PowerPC/peephole-elim-extsw-subreg-input.mir b/llvm/test/CodeGen/PowerPC/peephole-elim-extsw-subreg-input.mir
new file mode 100644
index 0000000000000..86caff368f3f2
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/peephole-elim-extsw-subreg-input.mir
@@ -0,0 +1,30 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr9 -run-pass=ppc-mi-peepholes -ppc-eliminate-signext -verify-machineinstrs -o - %s | FileCheck %s
+
+# When the EXTSW_32_64 input reads the sub_32 subregister of a 64-bit register
+# that is already sign-extended (here RLDICL with MB >= 33), the high 32 bits of
+# that register already hold the sign extension of the low word, so the result
+# of the sign-extend is the whole 64-bit register. Eliminate the EXTSW by
+# copying that register directly rather than building an INSERT_SUBREG that would
+# use the full register where a 32-bit register is required.
+
+---
+name:            extsw_elim_subreg_input
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $x3
+    ; CHECK-LABEL: name: extsw_elim_subreg_input
+    ; CHECK: liveins: $x3
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc = COPY killed $x3
+    ; CHECK-NEXT: [[RLDICL:%[0-9]+]]:g8rc = RLDICL killed [[COPY]], 0, 33
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:g8rc = COPY killed [[RLDICL]]
+    ; CHECK-NEXT: $x3 = COPY killed [[COPY1]]
+    ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit killed $x3
+    %0:g8rc = COPY $x3
+    %1:g8rc = RLDICL %0, 0, 33
+    %2:g8rc = EXTSW_32_64 %1.sub_32
+    $x3 = COPY %2
+    BLR8 implicit $lr8, implicit $rm, implicit $x3
+...

>From 01992e6ce932b769f42fe9077ed56a39f5706a9b Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 21 Jul 2026 20:03:15 +0200
Subject: [PATCH 2/3] Remove NarrowSubReg check

---
 llvm/lib/Target/PowerPC/PPCMIPeephole.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
index ea56e71eb789a..5372cf8044d56 100644
--- a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
+++ b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
@@ -1022,8 +1022,7 @@ bool PPCMIPeephole::simplifyCode() {
         unsigned SrcOpcode = SrcMI->getOpcode();
         // If we've used a zero-extending load that we will sign-extend,
         // just do a sign-extending load.
-        if (!NarrowSubReg &&
-            (SrcOpcode == PPC::LWZ || SrcOpcode == PPC::LWZX)) {
+        if ((SrcOpcode == PPC::LWZ || SrcOpcode == PPC::LWZX)) {
           if (!MRI->hasOneNonDBGUse(SrcMI->getOperand(0).getReg()))
             break;
 

>From 3ec282d981362bca39e57f20e500faace7be7751 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 20 Sep 2026 10:57:45 +0200
Subject: [PATCH 3/3] review comments

---
 llvm/lib/Target/PowerPC/PPCMIPeephole.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
index 5372cf8044d56..a7c627915a7ca 100644
--- a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
+++ b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
@@ -1016,13 +1016,11 @@ bool PPCMIPeephole::simplifyCode() {
         if (!NarrowReg.isVirtual())
           break;
 
-        unsigned NarrowSubReg = MI.getOperand(1).getSubReg();
-
         MachineInstr *SrcMI = MRI->getVRegDef(NarrowReg);
         unsigned SrcOpcode = SrcMI->getOpcode();
         // If we've used a zero-extending load that we will sign-extend,
         // just do a sign-extending load.
-        if ((SrcOpcode == PPC::LWZ || SrcOpcode == PPC::LWZX)) {
+        if (SrcOpcode == PPC::LWZ || SrcOpcode == PPC::LWZX) {
           if (!MRI->hasOneNonDBGUse(SrcMI->getOperand(0).getReg()))
             break;
 
@@ -1092,9 +1090,10 @@ bool PPCMIPeephole::simplifyCode() {
           // is eliminated.
           LLVM_DEBUG(dbgs() << "Removing redundant sign-extension\n");
 
+          unsigned NarrowSubReg = MI.getOperand(1).getSubReg();
           if (NarrowSubReg) {
             // The input reads a subregister of a wider register which we can
-            // use directly.
+            // use directly by dropping the subreg.
             assert(NarrowSubReg == PPC::sub_32 &&
                    "EXTSW_32_64 input must read the sub_32 subregister");
             BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY),



More information about the llvm-branch-commits mailing list