[llvm-branch-commits] [llvm] PPC: Fold 64-bit zero-extending word load feeding extsw subregister (PR #211107)

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


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

>From bfd1ec2846559898d850e9fb5605e5404832c57c Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 21 Jul 2026 19:35:27 +0200
Subject: [PATCH] PPC: Fold 64-bit zero-extending word load feeding extsw
 subregister

A gprc LWZ/LWZX feeding EXTSW_32_64 is rewritten into a sign-extending
LWA/LWAX load. Extend the same fold to the 64-bit zero-extending word
loads LWZ8/LWZX8 when the EXTSW_32_64 reads their sub_32 subregister,
producing a single LWA/LWAX instead of a redundant lwz+extsw pair.

Co-authored-by: Claude (Claude Opus 4.8, claude-opus-4-8) <noreply at anthropic.com>
---
 llvm/lib/Target/PowerPC/PPCMIPeephole.cpp     | 14 ++++++--
 .../peephole-elim-extsw-subreg-input.mir      | 35 +++++++++----------
 2 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
index a7c627915a7ca7..60c8e7c20d8460 100644
--- a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
+++ b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
@@ -1019,8 +1019,15 @@ bool PPCMIPeephole::simplifyCode() {
         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) {
+        // just do a sign-extending load. The source may be a 32-bit gprc load
+        // consumed directly, or a 64-bit g8rc load consumed through its sub_32
+        // subregister.
+        bool SrcIsGPRCWordZextLoad =
+            SrcOpcode == PPC::LWZ || SrcOpcode == PPC::LWZX;
+        bool SrcIsG8RCWordZextLoad =
+            SrcOpcode == PPC::LWZ8 || SrcOpcode == PPC::LWZX8;
+        if ((!NarrowSubReg && SrcIsGPRCWordZextLoad) ||
+            (NarrowSubReg == PPC::sub_32 && SrcIsG8RCWordZextLoad)) {
           if (!MRI->hasOneNonDBGUse(SrcMI->getOperand(0).getReg()))
             break;
 
@@ -1046,7 +1053,8 @@ bool PPCMIPeephole::simplifyCode() {
           // Likewise if the source is X-Form the new opcode should also be
           // X-Form.
           unsigned Opc = PPC::LWA_32;
-          bool SourceIsXForm = SrcOpcode == PPC::LWZX;
+          bool SourceIsXForm =
+              SrcOpcode == PPC::LWZX || SrcOpcode == PPC::LWZX8;
           bool MIIs64Bit = MI.getOpcode() == PPC::EXTSW ||
             MI.getOpcode() == PPC::EXTSW_32_64;
 
diff --git a/llvm/test/CodeGen/PowerPC/peephole-elim-extsw-subreg-input.mir b/llvm/test/CodeGen/PowerPC/peephole-elim-extsw-subreg-input.mir
index 1c7d3c1f87ca74..e57864a196ce49 100644
--- a/llvm/test/CodeGen/PowerPC/peephole-elim-extsw-subreg-input.mir
+++ b/llvm/test/CodeGen/PowerPC/peephole-elim-extsw-subreg-input.mir
@@ -26,10 +26,9 @@ body:             |
     BLR8 implicit $lr8, implicit $rm, implicit $x3
 ...
 
-# FIXME: A 64-bit zero-extending word load (LWZ8/LWZX8) feeding an EXTSW that
-# reads its sub_32 could fold into a sign-extending load, the same way a gprc
-# LWZ/LWZX + EXTSW folds. The load-folding path only matches the 32-bit
-# LWZ/LWZX defs, so these subregister cases are left as a separate load + extsw.
+# A 64-bit zero-extending word load (LWZ8/LWZX8) feeding an EXTSW that reads its
+# sub_32 is folded into a sign-extending load, the same way a gprc LWZ/LWZX +
+# EXTSW folds.
 ---
 name:            extsw_lwz8_subreg_input
 tracksRegLiveness: true
@@ -40,9 +39,9 @@ body:             |
     ; CHECK: liveins: $x3
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc_and_g8rc_nox0 = COPY killed $x3
-    ; CHECK-NEXT: [[LWZ8_:%[0-9]+]]:g8rc = LWZ8 0, killed [[COPY]] :: (load (s32))
-    ; CHECK-NEXT: [[EXTSW_32_64_:%[0-9]+]]:g8rc = EXTSW_32_64 killed [[LWZ8_]].sub_32
-    ; CHECK-NEXT: $x3 = COPY killed [[EXTSW_32_64_]]
+    ; CHECK-NEXT: [[LWA:%[0-9]+]]:g8rc = LWA 0, killed [[COPY]] :: (load (s32))
+    ; CHECK-NEXT: dead [[DEF:%[0-9]+]]:g8rc = IMPLICIT_DEF
+    ; CHECK-NEXT: $x3 = COPY killed [[LWA]]
     ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit killed $x3
     %0:g8rc_and_g8rc_nox0 = COPY $x3
     %1:g8rc = LWZ8 0, %0 :: (load (s32))
@@ -63,9 +62,9 @@ body:             |
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc_and_g8rc_nox0 = COPY killed $x3
     ; CHECK-NEXT: [[COPY1:%[0-9]+]]:g8rc = COPY killed $x4
-    ; CHECK-NEXT: [[LWZX8_:%[0-9]+]]:g8rc = LWZX8 killed [[COPY]], killed [[COPY1]] :: (load (s32))
-    ; CHECK-NEXT: [[EXTSW_32_64_:%[0-9]+]]:g8rc = EXTSW_32_64 killed [[LWZX8_]].sub_32
-    ; CHECK-NEXT: $x3 = COPY killed [[EXTSW_32_64_]]
+    ; CHECK-NEXT: [[LWAX:%[0-9]+]]:g8rc = LWAX killed [[COPY]], killed [[COPY1]] :: (load (s32))
+    ; CHECK-NEXT: dead [[DEF:%[0-9]+]]:g8rc = IMPLICIT_DEF
+    ; CHECK-NEXT: $x3 = COPY killed [[LWAX]]
     ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit killed $x3
     %0:g8rc_and_g8rc_nox0 = COPY $x3
     %3:g8rc = COPY $x4
@@ -86,10 +85,10 @@ body:             |
     ; CHECK: liveins: $x3
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc_and_g8rc_nox0 = COPY killed $x3
-    ; CHECK-NEXT: [[LWZ8_:%[0-9]+]]:g8rc = LWZ8 0, killed [[COPY]] :: (load (s32))
-    ; CHECK-NEXT: [[EXTSW_32_:%[0-9]+]]:gprc = EXTSW_32 killed [[LWZ8_]].sub_32
-    ; CHECK-NEXT: [[DEF:%[0-9]+]]:g8rc = IMPLICIT_DEF
-    ; CHECK-NEXT: [[INSERT_SUBREG:%[0-9]+]]:g8rc = INSERT_SUBREG killed [[DEF]], killed [[EXTSW_32_]], %subreg.sub_32
+    ; CHECK-NEXT: [[LWA_32_:%[0-9]+]]:gprc = LWA_32 0, killed [[COPY]] :: (load (s32))
+    ; CHECK-NEXT: dead [[DEF:%[0-9]+]]:g8rc = IMPLICIT_DEF
+    ; CHECK-NEXT: [[DEF1:%[0-9]+]]:g8rc = IMPLICIT_DEF
+    ; CHECK-NEXT: [[INSERT_SUBREG:%[0-9]+]]:g8rc = INSERT_SUBREG killed [[DEF1]], killed [[LWA_32_]], %subreg.sub_32
     ; CHECK-NEXT: $x3 = COPY killed [[INSERT_SUBREG]]
     ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit killed $x3
     %0:g8rc_and_g8rc_nox0 = COPY $x3
@@ -113,10 +112,10 @@ body:             |
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc_and_g8rc_nox0 = COPY killed $x3
     ; CHECK-NEXT: [[COPY1:%[0-9]+]]:g8rc = COPY killed $x4
-    ; CHECK-NEXT: [[LWZX8_:%[0-9]+]]:g8rc = LWZX8 killed [[COPY]], killed [[COPY1]] :: (load (s32))
-    ; CHECK-NEXT: [[EXTSW_32_:%[0-9]+]]:gprc = EXTSW_32 killed [[LWZX8_]].sub_32
-    ; CHECK-NEXT: [[DEF:%[0-9]+]]:g8rc = IMPLICIT_DEF
-    ; CHECK-NEXT: [[INSERT_SUBREG:%[0-9]+]]:g8rc = INSERT_SUBREG killed [[DEF]], killed [[EXTSW_32_]], %subreg.sub_32
+    ; CHECK-NEXT: [[LWAX_32_:%[0-9]+]]:gprc = LWAX_32 killed [[COPY]], killed [[COPY1]] :: (load (s32))
+    ; CHECK-NEXT: dead [[DEF:%[0-9]+]]:g8rc = IMPLICIT_DEF
+    ; CHECK-NEXT: [[DEF1:%[0-9]+]]:g8rc = IMPLICIT_DEF
+    ; CHECK-NEXT: [[INSERT_SUBREG:%[0-9]+]]:g8rc = INSERT_SUBREG killed [[DEF1]], killed [[LWAX_32_]], %subreg.sub_32
     ; CHECK-NEXT: $x3 = COPY killed [[INSERT_SUBREG]]
     ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit killed $x3
     %0:g8rc_and_g8rc_nox0 = COPY $x3



More information about the llvm-branch-commits mailing list