[llvm] PPC: Fix EXTSW elimination promoting a subregister operand (PR #208051)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 4 01:04:59 PDT 2026


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

>From 2087063d8522500872111406c3d6a859919fc0ba Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 7 Jul 2026 17:04:37 +0200
Subject: [PATCH 1/2] PPC: Fix EXTSW elimination promoting a subregister
 operand

promoteInstr32To64ForElimEXTSW copies operands from the 32-bit
instruction verbatim into its promoted 64-bit form. When an operand
reads the sub_32 subregister of a 64-bit register, the promoted
instruction (which takes a full register) ended up with an illegal
subregister use and failed the machine verifier.

Drop the sub_32 subregister and use the original full register, which
provides the low 32 bits the promoted instruction operates on. 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/PPCInstrInfo.cpp      |  7 +++
 .../test/CodeGen/PowerPC/sext_elimination.mir | 46 +++++++++++++++----
 2 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
index bf7f3df6035d8..a31532992b2b3 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
@@ -5495,6 +5495,13 @@ void PPCInstrInfo::promoteInstr32To64ForElimEXTSW(const Register &Reg,
     if (!OperandReg.isVirtual())
       continue;
 
+    // An operand that reads the sub_32 subregister of a 64-bit register already
+    // holds the value in a full 64-bit register.
+    if (Operand.getSubReg() == PPC::sub_32) {
+      PromoteRegs[i] = OperandReg;
+      continue;
+    }
+
     const TargetRegisterClass *NewUsedRegRC =
         RI.getRegClass(MCID.operands()[i].RegClass);
     const TargetRegisterClass *OrgRC = MRI->getRegClass(OperandReg);
diff --git a/llvm/test/CodeGen/PowerPC/sext_elimination.mir b/llvm/test/CodeGen/PowerPC/sext_elimination.mir
index 8c88c8f1b06f3..f6e445718a267 100644
--- a/llvm/test/CodeGen/PowerPC/sext_elimination.mir
+++ b/llvm/test/CodeGen/PowerPC/sext_elimination.mir
@@ -1,15 +1,6 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
-# RUN: llc -run-pass ppc-mi-peepholes -ppc-eliminate-signext -ppc-eliminate-zeroext -verify-machineinstrs -o - %s | FileCheck %s
+# RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -run-pass=ppc-mi-peepholes -ppc-eliminate-signext -ppc-eliminate-zeroext -verify-machineinstrs -o - %s | FileCheck %s
 
---- |
-  target datalayout = "E-m:e-i64:64-n32:64"
-  target triple = "powerpc64le-unknown-linux-gnu"
-  define ptr @func(ptr %a) {
-  entry:
-    ret ptr %a
-  }
-
-...
 ---
 name:            func
 alignment:       4
@@ -85,3 +76,38 @@ body:             |
     %14:g8rc = RLDICL %13:g8rc, 0, 32
 
 ...
+
+# Make sure the verifier does not fail if there is an existing
+# subregister use. When EXTSW_32_64 is eliminated because its source
+# register is already sign-extended, the full %0 value should be used
+# instead of re-extending the subregister, and incorrectly preserving
+# the original subregister.
+---
+name:            elim_extsw_subreg_src
+tracksRegLiveness: true
+liveins:
+  - { reg: '$x3', virtual-reg: '%0' }
+body:             |
+  bb.0:
+    liveins: $x3
+
+
+    ; CHECK-LABEL: name: elim_extsw_subreg_src
+    ; CHECK: liveins: $x3
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc = COPY $x3
+    ; CHECK-NEXT: [[SRAWI8_:%[0-9]+]]:g8rc = SRAWI8 killed [[COPY]], 31, implicit-def $carry, implicit-def dead $carry
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gprc = COPY killed [[SRAWI8_]].sub_32
+    ; CHECK-NEXT: [[DEF:%[0-9]+]]:g8rc = IMPLICIT_DEF
+    ; CHECK-NEXT: [[INSERT_SUBREG:%[0-9]+]]:g8rc = INSERT_SUBREG [[DEF]], [[COPY1]], %subreg.sub_32
+    ; CHECK-NEXT: [[XORI8_:%[0-9]+]]:g8rc = XORI8 killed [[INSERT_SUBREG]], 32767
+    ; CHECK-NEXT: $x3 = COPY [[XORI8_]]
+    ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit $x3
+    %0:g8rc = COPY $x3
+    %2:gprc = SRAWI %0.sub_32, 31, implicit-def dead $carry
+    %3:g8rc = EXTSW_32_64 killed %2
+    %4:g8rc = XORI8 killed %3, 32767
+    $x3 = COPY %4
+    BLR8 implicit $lr8, implicit $rm, implicit $x3
+
+...

>From efe523379c601f63e46e9f2766ea7959c004025d Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 21 Jul 2026 22:09:12 +0200
Subject: [PATCH 2/2] Add assert

---
 llvm/lib/Target/PowerPC/PPCInstrInfo.cpp | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
index a31532992b2b3..ec37b95ac58e9 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
@@ -5495,16 +5495,21 @@ void PPCInstrInfo::promoteInstr32To64ForElimEXTSW(const Register &Reg,
     if (!OperandReg.isVirtual())
       continue;
 
+    const TargetRegisterClass *NewUsedRegRC =
+        RI.getRegClass(MCID.operands()[i].RegClass);
+    const TargetRegisterClass *OrgRC = MRI->getRegClass(OperandReg);
+
     // An operand that reads the sub_32 subregister of a 64-bit register already
-    // holds the value in a full 64-bit register.
+    // holds the value in a full 64-bit register, so it can be used directly by
+    // the promoted instruction.
     if (Operand.getSubReg() == PPC::sub_32) {
+      assert(NewUsedRegRC->hasSubClassEq(OrgRC) &&
+             "sub_32 source register class is incompatible with the promoted "
+             "operand register class");
       PromoteRegs[i] = OperandReg;
       continue;
     }
 
-    const TargetRegisterClass *NewUsedRegRC =
-        RI.getRegClass(MCID.operands()[i].RegClass);
-    const TargetRegisterClass *OrgRC = MRI->getRegClass(OperandReg);
     if (NewUsedRegRC != OrgRC && (OrgRC == &PPC::GPRCRegClass ||
                                   OrgRC == &PPC::GPRC_and_GPRC_NOR0RegClass)) {
       // Promote the used 32-bit register to 64-bit register.



More information about the llvm-commits mailing list