[llvm] [RISCV][P-ext] Merge paired pli/plui in RISCVMoveMerger (PR #202566)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 18:52:07 PDT 2026
https://github.com/sihuan updated https://github.com/llvm/llvm-project/pull/202566
>From 7dfeab72a6351172f6f00bdb258819244ef2e852 Mon Sep 17 00:00:00 2001
From: SiHuaN <liyongtai at iscas.ac.cn>
Date: Tue, 9 Jun 2026 09:45:01 +0800
Subject: [PATCH] [RISCV][P-ext] Merge paired pli/plui in RISCVMoveMerger
64-bit packed-splat constants are returned as i64, which SelectionDAG
splits into two i32 halves materialized as single-reg pli.b/pli.h/plui.h.
Merge matching pairs writing the two halves of a GPRPair into the paired
pli.db/pli.dh/plui.dh form.
---
llvm/lib/Target/RISCV/RISCVMoveMerger.cpp | 139 +++++++++++++++++++--
llvm/test/CodeGen/RISCV/rv32-move-merge.ll | 94 ++++++++++++++
2 files changed, 224 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp b/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
index b193dd3280478..e6aac66fd51d6 100644
--- a/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
+++ b/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
@@ -37,6 +37,9 @@ struct RISCVMoveMerge : public MachineFunctionPass {
bool isCandidateToMergeMVA01S(const DestSourcePair &RegPair);
bool isCandidateToMergeMVSA01(const DestSourcePair &RegPair);
+
+ bool isPLIPairCandidate(const MachineInstr &MI, bool EvenRegPair);
+
// Merge the two instructions indicated into a single pair instruction.
MachineBasicBlock::iterator
mergeGPRPairInsns(MachineBasicBlock::iterator I,
@@ -44,17 +47,22 @@ struct RISCVMoveMerge : public MachineFunctionPass {
MachineBasicBlock::iterator
mergePairedInsns(MachineBasicBlock::iterator I,
MachineBasicBlock::iterator Paired, bool MoveFromSToA);
+ MachineBasicBlock::iterator mergePLIPair(MachineBasicBlock::iterator I,
+ MachineBasicBlock::iterator Paired,
+ bool RegPairIsEven);
MachineBasicBlock::iterator
- findMatchingInstPair(MachineBasicBlock::iterator &MBBI, bool EvenRegPair,
+ findMatchingGPRPairCopy(MachineBasicBlock::iterator &MBBI, bool EvenRegPair,
const DestSourcePair &RegPair);
// Look for C.MV instruction that can be combined with
// the given instruction into CM.MVA01S or CM.MVSA01. Return the matching
// instruction if one exists.
MachineBasicBlock::iterator
- findMatchingInst(MachineBasicBlock::iterator &MBBI, bool MoveFromSToA,
+ findMatchingSACopy(MachineBasicBlock::iterator &MBBI, bool MoveFromSToA,
const DestSourcePair &RegPair);
- bool mergeMoveSARegPair(MachineBasicBlock &MBB);
+ MachineBasicBlock::iterator findMatchingPLI(MachineBasicBlock::iterator &MBBI,
+ bool EvenRegPair);
+ bool mergeMovePairs(MachineBasicBlock &MBB);
bool runOnMachineFunction(MachineFunction &Fn) override;
StringRef getPassName() const override { return RISCV_MOVE_MERGE_NAME; }
@@ -87,6 +95,20 @@ static unsigned getCM_MVOpcode(const RISCVSubtarget &ST, bool MoveFromSToA) {
llvm_unreachable("Unhandled subtarget with paired move.");
}
+// Returns 0 if Opc has no paired form.
+static unsigned getPairedPLIOpcode(unsigned Opc) {
+ switch (Opc) {
+ case RISCV::PLI_B:
+ return RISCV::PLI_DB;
+ case RISCV::PLI_H:
+ return RISCV::PLI_DH;
+ case RISCV::PLUI_H:
+ return RISCV::PLUI_DH;
+ default:
+ return 0;
+ }
+}
+
bool RISCVMoveMerge::isGPRPairCopyCandidate(const DestSourcePair &RegPair,
bool EvenRegPair) {
Register Destination = RegPair.Destination->getReg();
@@ -132,6 +154,21 @@ bool RISCVMoveMerge::isCandidateToMergeMVSA01(const DestSourcePair &RegPair) {
return false;
}
+// Check if MI is a single-reg pli/plui whose destination is a half of a
+// GPRPair.
+bool RISCVMoveMerge::isPLIPairCandidate(const MachineInstr &MI,
+ bool EvenRegPair) {
+ if (!ST->hasStdExtP() || ST->is64Bit())
+ return false;
+ if (!getPairedPLIOpcode(MI.getOpcode()))
+ return false;
+ unsigned SubIdx = EvenRegPair ? RISCV::sub_gpr_even : RISCV::sub_gpr_odd;
+ return TRI
+ ->getMatchingSuperReg(MI.getOperand(0).getReg(), SubIdx,
+ &RISCV::GPRPairRegClass)
+ .isValid();
+}
+
MachineBasicBlock::iterator
RISCVMoveMerge::mergeGPRPairInsns(MachineBasicBlock::iterator I,
MachineBasicBlock::iterator Paired,
@@ -229,7 +266,32 @@ RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
}
MachineBasicBlock::iterator
-RISCVMoveMerge::findMatchingInstPair(MachineBasicBlock::iterator &MBBI,
+RISCVMoveMerge::mergePLIPair(MachineBasicBlock::iterator I,
+ MachineBasicBlock::iterator Paired,
+ bool RegPairIsEven) {
+ MachineBasicBlock::iterator E = I->getParent()->end();
+ MachineBasicBlock::iterator NextI = next_nodbg(I, E);
+
+ if (NextI == Paired)
+ NextI = next_nodbg(NextI, E);
+ DebugLoc DL = I->getDebugLoc();
+
+ unsigned Opcode = getPairedPLIOpcode(I->getOpcode());
+ unsigned GPRPairIdx =
+ RegPairIsEven ? RISCV::sub_gpr_even : RISCV::sub_gpr_odd;
+ Register DestReg = TRI->getMatchingSuperReg(
+ I->getOperand(0).getReg(), GPRPairIdx, &RISCV::GPRPairRegClass);
+
+ BuildMI(*I->getParent(), I, DL, TII->get(Opcode), DestReg)
+ .addImm(I->getOperand(1).getImm());
+
+ I->eraseFromParent();
+ Paired->eraseFromParent();
+ return NextI;
+}
+
+MachineBasicBlock::iterator
+RISCVMoveMerge::findMatchingGPRPairCopy(MachineBasicBlock::iterator &MBBI,
bool EvenRegPair,
const DestSourcePair &RegPair) {
MachineBasicBlock::iterator E = MBBI->getParent()->end();
@@ -278,7 +340,7 @@ RISCVMoveMerge::findMatchingInstPair(MachineBasicBlock::iterator &MBBI,
}
MachineBasicBlock::iterator
-RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
+RISCVMoveMerge::findMatchingSACopy(MachineBasicBlock::iterator &MBBI,
bool MoveFromSToA,
const DestSourcePair &RegPair) {
MachineBasicBlock::iterator E = MBBI->getParent()->end();
@@ -325,13 +387,72 @@ RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
return E;
}
+// Look for a same-opcode pli/plui writing the other lane of the same GPRPair
+// with the same immediate. Return the matching instruction if one exists.
+MachineBasicBlock::iterator
+RISCVMoveMerge::findMatchingPLI(MachineBasicBlock::iterator &MBBI,
+ bool EvenRegPair) {
+ MachineBasicBlock::iterator E = MBBI->getParent()->end();
+ ModifiedRegUnits.clear();
+ UsedRegUnits.clear();
+ unsigned Opc = MBBI->getOpcode();
+ Register FirstDestReg = MBBI->getOperand(0).getReg();
+ int64_t FirstImm = MBBI->getOperand(1).getImm();
+ unsigned RegPairIdx = EvenRegPair ? RISCV::sub_gpr_even : RISCV::sub_gpr_odd;
+ unsigned SecondPairIdx =
+ !EvenRegPair ? RISCV::sub_gpr_even : RISCV::sub_gpr_odd;
+
+ // Get the expected destination register of the matching lane.
+ Register DestGPRPair = TRI->getMatchingSuperReg(FirstDestReg, RegPairIdx,
+ &RISCV::GPRPairRegClass);
+ Register ExpectedDestReg = TRI->getSubReg(DestGPRPair, SecondPairIdx);
+
+ for (MachineBasicBlock::iterator I = next_nodbg(MBBI, E); I != E;
+ I = next_nodbg(I, E)) {
+
+ MachineInstr &MI = *I;
+
+ if (MI.getOpcode() == Opc) {
+ Register DestReg = MI.getOperand(0).getReg();
+ int64_t Imm = MI.getOperand(1).getImm();
+
+ if (FirstDestReg == DestReg)
+ return E;
+
+ // Check if the second PLI matches the other lane and immediate.
+ if (DestReg == ExpectedDestReg && Imm == FirstImm)
+ return I;
+ }
+ // Update modified / used register units.
+ LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
+ // Once the expected lane register is clobbered/read in-between, we can
+ // stop scanning since the pair cannot be legally merged anymore.
+ if (!ModifiedRegUnits.available(ExpectedDestReg) ||
+ !UsedRegUnits.available(ExpectedDestReg))
+ return E;
+ }
+ return E;
+}
+
// Finds instructions, which could be represented as C.MV instructions and
// merged into CM.MVA01S or CM.MVSA01.
-bool RISCVMoveMerge::mergeMoveSARegPair(MachineBasicBlock &MBB) {
+bool RISCVMoveMerge::mergeMovePairs(MachineBasicBlock &MBB) {
bool Modified = false;
for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
MBBI != E;) {
+ // Try merging a pair of single-reg PLI/PLUI into a paired form.
+ bool IsPLIEven = isPLIPairCandidate(*MBBI, /*EvenRegPair=*/true);
+ bool IsPLIOdd = isPLIPairCandidate(*MBBI, /*EvenRegPair=*/false);
+ if (IsPLIEven != IsPLIOdd) {
+ MachineBasicBlock::iterator Paired = findMatchingPLI(MBBI, IsPLIEven);
+ if (Paired != E) {
+ MBBI = mergePLIPair(MBBI, Paired, IsPLIEven);
+ Modified = true;
+ continue;
+ }
+ }
+
// Check if the instruction can be compressed to C.MV instruction. If it
// can, return Dest/Src register pair.
auto RegPair = TII->isCopyInstrImpl(*MBBI);
@@ -347,7 +468,7 @@ bool RISCVMoveMerge::mergeMoveSARegPair(MachineBasicBlock &MBB) {
MachineBasicBlock::iterator Paired = E;
if (MoveFromSToA || MoveFromAToS) {
- Paired = findMatchingInst(MBBI, MoveFromSToA, *RegPair);
+ Paired = findMatchingSACopy(MBBI, MoveFromSToA, *RegPair);
if (Paired != E) {
MBBI = mergePairedInsns(MBBI, Paired, MoveFromSToA);
Modified = true;
@@ -355,7 +476,7 @@ bool RISCVMoveMerge::mergeMoveSARegPair(MachineBasicBlock &MBB) {
}
}
if (IsEven != IsOdd) {
- Paired = findMatchingInstPair(MBBI, IsEven, *RegPair);
+ Paired = findMatchingGPRPairCopy(MBBI, IsEven, *RegPair);
if (Paired != E) {
MBBI = mergeGPRPairInsns(MBBI, Paired, IsEven);
Modified = true;
@@ -387,7 +508,7 @@ bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) {
UsedRegUnits.init(*TRI);
bool Modified = false;
for (auto &MBB : Fn)
- Modified |= mergeMoveSARegPair(MBB);
+ Modified |= mergeMovePairs(MBB);
return Modified;
}
diff --git a/llvm/test/CodeGen/RISCV/rv32-move-merge.ll b/llvm/test/CodeGen/RISCV/rv32-move-merge.ll
index 34652b5f0782b..9fdc9586d0f38 100644
--- a/llvm/test/CodeGen/RISCV/rv32-move-merge.ll
+++ b/llvm/test/CodeGen/RISCV/rv32-move-merge.ll
@@ -44,3 +44,97 @@ define i64 @mv_to_fmv(i64 %a, i64 %b) nounwind {
call void @foo()
ret i64 %1
}
+
+; RV32 P-ext packed splat constants flow through the ABI as i64, get split
+; by SelectionDAG into two i32 halves materialized as single-reg pli/plui;
+; MoveMerger folds matching pairs into pli.db/pli.dh/plui.dh.
+
+define i64 @pli_b_pair() nounwind {
+; CHECK32ZDINX-LABEL: pli_b_pair:
+; CHECK32ZDINX: # %bb.0:
+; CHECK32ZDINX-NEXT: lui a0, 20560
+; CHECK32ZDINX-NEXT: addi a0, a0, 1285
+; CHECK32ZDINX-NEXT: mv a1, a0
+; CHECK32ZDINX-NEXT: ret
+;
+; CHECK32P-LABEL: pli_b_pair:
+; CHECK32P: # %bb.0:
+; CHECK32P-NEXT: pli.db a0, 5
+; CHECK32P-NEXT: ret
+ ret i64 361700864190383365
+}
+
+define i64 @pli_b_pair_negative() nounwind {
+; CHECK32ZDINX-LABEL: pli_b_pair_negative:
+; CHECK32ZDINX: # %bb.0:
+; CHECK32ZDINX-NEXT: lui a0, 1040352
+; CHECK32ZDINX-NEXT: addi a0, a0, -515
+; CHECK32ZDINX-NEXT: mv a1, a0
+; CHECK32ZDINX-NEXT: ret
+;
+; CHECK32P-LABEL: pli_b_pair_negative:
+; CHECK32P: # %bb.0:
+; CHECK32P-NEXT: pli.db a0, -3
+; CHECK32P-NEXT: ret
+ ret i64 -144680345676153347
+}
+
+define i64 @pli_h_pair() nounwind {
+; CHECK32ZDINX-LABEL: pli_h_pair:
+; CHECK32ZDINX: # %bb.0:
+; CHECK32ZDINX-NEXT: lui a0, 672
+; CHECK32ZDINX-NEXT: addi a0, a0, 42
+; CHECK32ZDINX-NEXT: mv a1, a0
+; CHECK32ZDINX-NEXT: ret
+;
+; CHECK32P-LABEL: pli_h_pair:
+; CHECK32P: # %bb.0:
+; CHECK32P-NEXT: pli.dh a0, 42
+; CHECK32P-NEXT: ret
+ ret i64 11822129413226538
+}
+
+define i64 @pli_h_pair_negative() nounwind {
+; CHECK32ZDINX-LABEL: pli_h_pair_negative:
+; CHECK32ZDINX: # %bb.0:
+; CHECK32ZDINX-NEXT: lui a0, 1048512
+; CHECK32ZDINX-NEXT: addi a0, a0, -5
+; CHECK32ZDINX-NEXT: mv a1, a0
+; CHECK32ZDINX-NEXT: ret
+;
+; CHECK32P-LABEL: pli_h_pair_negative:
+; CHECK32P: # %bb.0:
+; CHECK32P-NEXT: pli.dh a0, -5
+; CHECK32P-NEXT: ret
+ ret i64 -1125917086973957
+}
+
+define i64 @plui_h_pair() nounwind {
+; CHECK32ZDINX-LABEL: plui_h_pair:
+; CHECK32ZDINX: # %bb.0:
+; CHECK32ZDINX-NEXT: lui a0, 221187
+; CHECK32ZDINX-NEXT: addi a0, a0, 1536
+; CHECK32ZDINX-NEXT: mv a1, a0
+; CHECK32ZDINX-NEXT: ret
+;
+; CHECK32P-LABEL: plui_h_pair:
+; CHECK32P: # %bb.0:
+; CHECK32P-NEXT: plui.dh a0, 216
+; CHECK32P-NEXT: ret
+ ret i64 3891169452581991936
+}
+
+define i64 @plui_h_pair_negative() nounwind {
+; CHECK32ZDINX-LABEL: plui_h_pair_negative:
+; CHECK32ZDINX: # %bb.0:
+; CHECK32ZDINX-NEXT: lui a0, 1032208
+; CHECK32ZDINX-NEXT: addi a0, a0, -1024
+; CHECK32ZDINX-NEXT: mv a1, a0
+; CHECK32ZDINX-NEXT: ret
+;
+; CHECK32P-LABEL: plui_h_pair_negative:
+; CHECK32P: # %bb.0:
+; CHECK32P-NEXT: plui.dh a0, -16
+; CHECK32P-NEXT: ret
+ ret i64 -287953294993589248
+}
More information about the llvm-commits
mailing list