[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