[llvm] c41691c - [PowerPC] Fix XXPERMDI peephole and ISEL LiveVariables bugs (#172122)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 27 06:44:29 PST 2026
Author: Maryam Moghadas
Date: 2026-01-27T09:44:23-05:00
New Revision: c41691c8b6a86a7703314a556f84b98df92a688c
URL: https://github.com/llvm/llvm-project/commit/c41691c8b6a86a7703314a556f84b98df92a688c
DIFF: https://github.com/llvm/llvm-project/commit/c41691c8b6a86a7703314a556f84b98df92a688c.diff
LOG: [PowerPC] Fix XXPERMDI peephole and ISEL LiveVariables bugs (#172122)
Fixes https://github.com/llvm/llvm-project/issues/159116
Prevent XXPERMDI splat optimization when the splat output register is
used in other instructions, which caused undefined register references.
Also track removed ISEL operands in simplifyToLI to prevent
LiveVariables corruption during ISEL-to-COPY conversion.
Added:
llvm/test/CodeGen/PowerPC/peephole-livevars-tracking.mir
Modified:
llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
llvm/lib/Target/PowerPC/PPCInstrInfo.h
llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
index 959b4e89830ef..278fd37d4c229 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
@@ -3867,7 +3867,8 @@ bool PPCInstrInfo::convertToImmediateForm(MachineInstr &MI,
// If this is not a reg+reg, but the DefMI is LI/LI8, check if its user MI
// can be simpified to LI.
- if (!HasImmForm && simplifyToLI(MI, *DefMI, ForwardingOperand, KilledDef))
+ if (!HasImmForm &&
+ simplifyToLI(MI, *DefMI, ForwardingOperand, KilledDef, &RegsToUpdate))
return true;
return false;
@@ -4634,7 +4635,8 @@ bool PPCInstrInfo::isImmElgibleForForwarding(const MachineOperand &ImmMO,
bool PPCInstrInfo::simplifyToLI(MachineInstr &MI, MachineInstr &DefMI,
unsigned OpNoForForwarding,
- MachineInstr **KilledDef) const {
+ MachineInstr **KilledDef,
+ SmallSet<Register, 4> *RegsToUpdate) const {
if ((DefMI.getOpcode() != PPC::LI && DefMI.getOpcode() != PPC::LI8) ||
!DefMI.getOperand(1).isImm())
return false;
@@ -4702,6 +4704,11 @@ bool PPCInstrInfo::simplifyToLI(MachineInstr &MI, MachineInstr &DefMI,
dbgs() << "Found LI -> CMPI -> ISEL, replacing with a copy.\n");
LLVM_DEBUG(DefMI.dump(); MI.dump(); CompareUseMI.dump());
LLVM_DEBUG(dbgs() << "Is converted to:\n");
+ if (RegsToUpdate) {
+ for (const MachineOperand &MO : CompareUseMI.operands())
+ if (MO.isReg())
+ RegsToUpdate->insert(MO.getReg());
+ }
// Convert to copy and remove unneeded operands.
CompareUseMI.setDesc(get(PPC::COPY));
CompareUseMI.removeOperand(3);
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.h b/llvm/lib/Target/PowerPC/PPCInstrInfo.h
index af7064116ec8b..9fe5706e7b1e0 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.h
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.h
@@ -297,7 +297,8 @@ class PPCInstrInfo : public PPCGenInstrInfo {
// Replace the instruction with single LI if possible. \p DefMI must be LI or
// LI8.
bool simplifyToLI(MachineInstr &MI, MachineInstr &DefMI,
- unsigned OpNoForForwarding, MachineInstr **KilledDef) const;
+ unsigned OpNoForForwarding, MachineInstr **KilledDef,
+ SmallSet<Register, 4> *RegsToUpdate = nullptr) const;
// If the inst is imm-form and its register operand is produced by a ADDI, put
// the imm into the inst directly and remove the ADDI if possible.
bool transformToNewImmFormFedByAdd(MachineInstr &MI, MachineInstr &DefMI,
diff --git a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
index c6d66fefa8734..20df2210e33dd 100644
--- a/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
+++ b/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
@@ -732,6 +732,7 @@ bool PPCMIPeephole::simplifyCode() {
LLVM_DEBUG(dbgs() << "Optimizing swap/swap => copy: ");
LLVM_DEBUG(MI.dump());
addRegToUpdate(MI.getOperand(1).getReg());
+
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY),
MI.getOperand(0).getReg())
.add(DefMI->getOperand(1));
@@ -744,7 +745,9 @@ bool PPCMIPeephole::simplifyCode() {
DefOpc == PPC::XXPERMDIs &&
(DefMI->getOperand(2).getImm() == 0 ||
DefMI->getOperand(2).getImm() == 3)) {
- ToErase = &MI;
+
+ if (!MRI->hasOneNonDBGUser(DefMI->getOperand(0).getReg()))
+ break;
Simplified = true;
// Swap of a splat, convert to copy.
if (Immed == 2) {
@@ -754,10 +757,12 @@ bool PPCMIPeephole::simplifyCode() {
MI.getOperand(0).getReg())
.add(MI.getOperand(1));
addRegToUpdate(MI.getOperand(1).getReg());
+ ToErase = &MI;
break;
}
// Splat fed by another splat - switch the output of the first
// and remove the second.
+ ToErase = &MI;
DefMI->getOperand(0).setReg(MI.getOperand(0).getReg());
LLVM_DEBUG(dbgs() << "Removing redundant splat: ");
LLVM_DEBUG(MI.dump());
diff --git a/llvm/test/CodeGen/PowerPC/peephole-livevars-tracking.mir b/llvm/test/CodeGen/PowerPC/peephole-livevars-tracking.mir
new file mode 100644
index 0000000000000..16df0caa9e899
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/peephole-livevars-tracking.mir
@@ -0,0 +1,83 @@
+# RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux \
+# RUN: -run-pass=ppc-mi-peepholes %s -o - | FileCheck %s
+
+# Test that peephole optimizations correctly update LiveVariables tracking.
+# XXPERMDI splat optimization skipped when splat register has multiple uses.
+# ISEL to COPY conversion tracks removed operand registers to prevent
+# LiveVariables corruption.
+
+---
+name: test_xxpermdi_splat_multiple_uses
+alignment: 16
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: vrrc }
+ - { id: 28, class: vrrc }
+ - { id: 31, class: f8rc }
+ - { id: 34, class: vrrc }
+ - { id: 35, class: vrrc }
+body: |
+ bb.0:
+ liveins: $f1
+
+ %28:vrrc = XXLXORz
+ %31:f8rc = COPY $f1
+ %0:vrrc = XXPERMDIs %31, 0
+ %34:vrrc = XXPERMDI %28, %0, 3
+ %35:vrrc = XXPERMDI %0, %0, 3
+
+ ; CHECK-LABEL: name: test_xxpermdi_splat_multiple_uses
+ ; CHECK: %1:vrrc = XXLXORz
+ ; CHECK-NEXT: %2:f8rc = COPY killed $f1
+ ; CHECK-NEXT: %0:vrrc = XXPERMDIs killed %2, 0
+ ; CHECK-NEXT: %3:vrrc = XXPERMDI killed %1, %0, 3
+ ; CHECK-NEXT: %4:vrrc = XXPERMDI killed %0, %0, 3
+...
+---
+name: test_swap_isel_livevars
+alignment: 16
+tracksRegLiveness: true
+stack:
+ - { id: 0, size: 16, alignment: 16 }
+registers:
+ - { id: 2, class: vrrc }
+ - { id: 3, class: gprc_and_gprc_nor0 }
+ - { id: 4, class: gprc }
+ - { id: 7, class: gprc }
+ - { id: 8, class: gprc }
+ - { id: 21, class: vsrc }
+ - { id: 22, class: g8rc_and_g8rc_nox0 }
+ - { id: 25, class: vsrc }
+ - { id: 26, class: vsrc }
+ - { id: 29, class: crrc }
+ - { id: 31, class: vsrc }
+body: |
+ bb.0:
+ %7:gprc = LI 0
+ %8:gprc = LI 1
+ %21:vsrc = XXLXORz
+ %22:g8rc_and_g8rc_nox0 = ADDI8 %stack.0, 0
+ %29:crrc = CMPLWI %7, 0
+
+ STXVD2X %21, $zero8, %22 :: (store (s128) into %stack.0)
+ %25:vsrc = LXVD2X $zero8, %22 :: (load (s128) from %stack.0)
+ %26:vsrc = XXPERMDI %25, %25, 2
+ %2:vrrc = COPY %26
+ %31:vsrc = XXPERMDI %2, %2, 2
+ %3:gprc_and_gprc_nor0 = LI 0
+ %4:gprc = ISEL %3, %8, %29.sub_eq
+
+ ; CHECK-LABEL: name: test_swap_isel_livevars
+ ; CHECK: %3:gprc = LI 0
+ ; CHECK-NEXT: %4:gprc = LI 1
+ ; CHECK-NEXT: %5:vsrc = XXLXORz
+ ; CHECK-NEXT: %6:g8rc_and_g8rc_nox0 = ADDI8 %stack.0, 0
+ ; CHECK-NEXT: %9:crrc = CMPLWI killed %3, 0
+ ; CHECK-NEXT: STXVD2X killed %5, $zero8, %6
+ ; CHECK-NEXT: %7:vsrc = LXVD2X $zero8, killed %6
+ ; CHECK-NEXT: %8:vsrc = XXPERMDI %7, %7, 2
+ ; CHECK-NEXT: %0:vrrc = COPY killed %8
+ ; CHECK-NEXT: %10:vsrc = COPY killed %7
+ ; CHECK-NEXT: %1:gprc_and_gprc_nor0 = LI 0
+ ; CHECK-NEXT: %2:gprc = COPY killed %1
+...
More information about the llvm-commits
mailing list