[llvm] [RISCV][P-ext] Add mvd alias for padd.dw rd, zero, rs. Use for copy idiom. (PR #205223)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 22 23:12:53 PDT 2026
https://github.com/topperc updated https://github.com/llvm/llvm-project/pull/205223
>From 49bb144054efd0f7bf745b5ace3ea637e7b1280f Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Mon, 22 Jun 2026 15:02:58 -0700
Subject: [PATCH 1/2] [RISCV][P-ext] Add mvd alias for padd.dw rd, zero, rs.
Use for copy idiom.
See https://github.com/riscv/riscv-p-spec/pull/304
I've refactored the MoveMerge code to use a different BuildMI call
for the 2 cases rather than try to manage variables to share the call.
While I fixed the code to not set the kill flag on X0_Pair and to
only set it on one of the operands for the FSGNJ_D_IN32X case. This
matches RISCVInstrInfo::copyPhysReg.
I wonder if we can just use copyPhysReg here?
---
llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 4 +-
llvm/lib/Target/RISCV/RISCVInstrInfoP.td | 2 +
llvm/lib/Target/RISCV/RISCVMoveMerger.cpp | 40 ++++++++-----------
.../RISCV/calling-conv-p-ext-vector.ll | 2 +-
.../CodeGen/RISCV/make-compressible-zilsd.mir | 2 +-
.../CodeGen/RISCV/rv32-merge-non-arg-reg.mir | 4 +-
.../CodeGen/RISCV/rv32-move-merge-crash.ll | 2 +-
llvm/test/CodeGen/RISCV/rv32-move-merge.ll | 2 +-
llvm/test/CodeGen/RISCV/rv32p.ll | 14 +++----
llvm/test/CodeGen/RISCV/rvp-simd-64.ll | 2 +-
llvm/test/MC/RISCV/rv32p-aliases-valid.s | 4 ++
11 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 3636325cead24..62091cd734f54 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -548,8 +548,8 @@ void RISCVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
if (STI.hasStdExtP()) {
// On RV32P, `padd.dw` is a GPR Pair Add
BuildMI(MBB, MBBI, DL, get(RISCV::PADD_DW), DstReg)
- .addReg(SrcReg, KillFlag | getRenamableRegState(RenamableSrc))
- .addReg(RISCV::X0_Pair);
+ .addReg(RISCV::X0_Pair)
+ .addReg(SrcReg, KillFlag | getRenamableRegState(RenamableSrc));
return;
}
}
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index e63eb9ce50e83..df983408004c9 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1730,6 +1730,8 @@ let append Predicates = [IsRV32] in {
def : InstAlias<"pncvt.h $rd, $rs", (PNSRLI_H GPR:$rd, GPRPairRV32:$rs, 0)>;
def : InstAlias<"pncvth.b $rd, $rs", (PNSRLI_B GPR:$rd, GPRPairRV32:$rs, 8)>;
def : InstAlias<"pncvth.h $rd, $rs", (PNSRLI_H GPR:$rd, GPRPairRV32:$rs, 16)>;
+
+ def : InstAlias<"mvd $rd, $rs", (PADD_DW GPRPairRV32:$rd, X0_Pair, GPRPairRV32:$rs)>;
} // append Predicates = [IsRV32]
} // Predicates = [HasStdExtP]
diff --git a/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp b/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
index a242ec3594bd8..a72642aad60ab 100644
--- a/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
+++ b/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
@@ -75,16 +75,6 @@ char RISCVMoveMerge::ID = 0;
INITIALIZE_PASS(RISCVMoveMerge, "riscv-move-merge", RISCV_MOVE_MERGE_NAME,
false, false)
-static unsigned getGPRPairCopyOpcode(const RISCVSubtarget &ST) {
- if (ST.hasStdExtZdinx())
- return RISCV::FSGNJ_D_IN32X;
-
- if (ST.hasStdExtP())
- return RISCV::PADD_DW;
-
- llvm_unreachable("Unhandled subtarget with paired move.");
-}
-
static unsigned getCM_MVOpcode(const RISCVSubtarget &ST, bool MoveFromSToA) {
if (ST.hasStdExtZcmp())
return MoveFromSToA ? RISCV::CM_MVA01S : RISCV::CM_MVSA01;
@@ -186,25 +176,29 @@ RISCVMoveMerge::mergeGPRPairInsns(MachineBasicBlock::iterator I,
// flag.
MachineOperand PairedSource = *SecondPair.Source;
- unsigned Opcode = getGPRPairCopyOpcode(*ST);
for (auto It = std::next(I); It != Paired && PairedSource.isKill(); ++It)
if (It->readsRegister(PairedSource.getReg(), TRI))
PairedSource.setIsKill(false);
- Register SrcReg1, SrcReg2, DestReg;
unsigned GPRPairIdx =
RegPairIsEven ? RISCV::sub_gpr_even : RISCV::sub_gpr_odd;
- SrcReg1 = TRI->getMatchingSuperReg(FirstPair.Source->getReg(), GPRPairIdx,
- &RISCV::GPRPairRegClass);
- SrcReg2 = ST->hasStdExtZdinx() ? SrcReg1 : Register(RISCV::X0_Pair);
- DestReg = TRI->getMatchingSuperReg(FirstPair.Destination->getReg(),
- GPRPairIdx, &RISCV::GPRPairRegClass);
-
- BuildMI(*I->getParent(), I, DL, TII->get(Opcode), DestReg)
- .addReg(SrcReg1, getKillRegState(PairedSource.isKill() &&
- FirstPair.Source->isKill()))
- .addReg(SrcReg2, getKillRegState(PairedSource.isKill() &&
- FirstPair.Source->isKill()));
+ MCRegister SrcReg = TRI->getMatchingSuperReg(
+ FirstPair.Source->getReg(), GPRPairIdx, &RISCV::GPRPairRegClass);
+ MCRegister DestReg = TRI->getMatchingSuperReg(
+ FirstPair.Destination->getReg(), GPRPairIdx, &RISCV::GPRPairRegClass);
+ bool SrcKill = PairedSource.isKill() && FirstPair.Source->isKill();
+
+ if (ST->hasStdExtZdinx()) {
+ BuildMI(*I->getParent(), I, DL, TII->get(RISCV::FSGNJ_D_IN32X), DestReg)
+ .addReg(SrcReg)
+ .addReg(SrcReg, getKillRegState(SrcKill));
+ } else if (ST->hasStdExtP()) {
+ BuildMI(*I->getParent(), I, DL, TII->get(RISCV::PADD_DW), DestReg)
+ .addReg(RISCV::X0_Pair)
+ .addReg(SrcReg, getKillRegState(SrcKill));
+ } else {
+ llvm_unreachable("Unhandled subtarget with paired move.");
+ }
I->eraseFromParent();
Paired->eraseFromParent();
diff --git a/llvm/test/CodeGen/RISCV/calling-conv-p-ext-vector.ll b/llvm/test/CodeGen/RISCV/calling-conv-p-ext-vector.ll
index 30aca1db3ed9c..be096e0b95ce4 100644
--- a/llvm/test/CodeGen/RISCV/calling-conv-p-ext-vector.ll
+++ b/llvm/test/CodeGen/RISCV/calling-conv-p-ext-vector.ll
@@ -206,7 +206,7 @@ define <8 x i8> @test_call_v8i8(<8 x i8> %a, <8 x i8> %b) {
; RV32-NEXT: .cfi_offset ra, -4
; RV32-NEXT: mv a4, a1
; RV32-NEXT: mv a5, a0
-; RV32-NEXT: padd.dw a0, a2, zero
+; RV32-NEXT: mvd a0, a2
; RV32-NEXT: mv a2, a5
; RV32-NEXT: mv a3, a4
; RV32-NEXT: call external_v8i8
diff --git a/llvm/test/CodeGen/RISCV/make-compressible-zilsd.mir b/llvm/test/CodeGen/RISCV/make-compressible-zilsd.mir
index 0c22db20d4a68..9123093ca0128 100644
--- a/llvm/test/CodeGen/RISCV/make-compressible-zilsd.mir
+++ b/llvm/test/CodeGen/RISCV/make-compressible-zilsd.mir
@@ -130,7 +130,7 @@ body: |
; RV32_P-LABEL: name: store_common_value_double
; RV32_P: liveins: $x10, $x11, $x12, $x16, $x17
; RV32_P-NEXT: {{ $}}
- ; RV32_P-NEXT: $x14_x15 = PADD_DW $x16_x17, $x0_pair
+ ; RV32_P-NEXT: $x14_x15 = PADD_DW $x0_pair, $x16_x17
; RV32_P-NEXT: SD_RV32 $x14_x15, killed renamable $x10, 0 :: (store (s64) into %ir.a)
; RV32_P-NEXT: SD_RV32 $x14_x15, killed renamable $x11, 0 :: (store (s64) into %ir.b)
; RV32_P-NEXT: SD_RV32 killed $x14_x15, killed renamable $x12, 0 :: (store (s64) into %ir.c)
diff --git a/llvm/test/CodeGen/RISCV/rv32-merge-non-arg-reg.mir b/llvm/test/CodeGen/RISCV/rv32-merge-non-arg-reg.mir
index ab3de8c8918fa..094c77461a920 100644
--- a/llvm/test/CodeGen/RISCV/rv32-merge-non-arg-reg.mir
+++ b/llvm/test/CodeGen/RISCV/rv32-merge-non-arg-reg.mir
@@ -18,7 +18,7 @@ body: |
; P-EXT-LABEL: name: merge_copy_non_arg_reg
; P-EXT: liveins: $x28, $x29
; P-EXT-NEXT: {{ $}}
- ; P-EXT-NEXT: $x6_x7 = PADD_DW $x28_x29, $x0_pair
+ ; P-EXT-NEXT: $x6_x7 = PADD_DW $x0_pair, $x28_x29
; P-EXT-NEXT: PseudoRET implicit $x6
$x6 = COPY $x28
$x7 = COPY $x29
@@ -40,7 +40,7 @@ body: |
; P-EXT-LABEL: name: merge_copy_non_arg_reg_with_intervening_unrelated_copy
; P-EXT: liveins: $x12, $x28, $x29
; P-EXT-NEXT: {{ $}}
- ; P-EXT-NEXT: $x6_x7 = PADD_DW $x28_x29, $x0_pair
+ ; P-EXT-NEXT: $x6_x7 = PADD_DW $x0_pair, $x28_x29
; P-EXT-NEXT: $x18 = ADDI $x12, 0
; P-EXT-NEXT: PseudoRET implicit $x6
$x6 = COPY $x28
diff --git a/llvm/test/CodeGen/RISCV/rv32-move-merge-crash.ll b/llvm/test/CodeGen/RISCV/rv32-move-merge-crash.ll
index 801de62ce1f54..e25ac02cfad51 100644
--- a/llvm/test/CodeGen/RISCV/rv32-move-merge-crash.ll
+++ b/llvm/test/CodeGen/RISCV/rv32-move-merge-crash.ll
@@ -48,7 +48,7 @@ define void @test(i32 %arg0, i32 %arg1) nounwind {
; ZCMP-P-NEXT: #NO_APP
; ZCMP-P-NEXT: #APP
; ZCMP-P-NEXT: #NO_APP
-; ZCMP-P-NEXT: padd.dw a0, a4, zero
+; ZCMP-P-NEXT: mvd a0, a4
; ZCMP-P-NEXT: tail foo
;
; ZCMP-P64-LABEL: test:
diff --git a/llvm/test/CodeGen/RISCV/rv32-move-merge.ll b/llvm/test/CodeGen/RISCV/rv32-move-merge.ll
index 646cee53d4bcf..2dcda981d8641 100644
--- a/llvm/test/CodeGen/RISCV/rv32-move-merge.ll
+++ b/llvm/test/CodeGen/RISCV/rv32-move-merge.ll
@@ -34,7 +34,7 @@ define i64 @mv_to_fmv(i64 %a, i64 %b) nounwind {
; CHECK32P-NEXT: sw s1, 4(sp) # 4-byte Folded Spill
; CHECK32P-NEXT: addd s0, a0, a2
; CHECK32P-NEXT: call foo
-; CHECK32P-NEXT: padd.dw a0, s0, zero
+; CHECK32P-NEXT: mvd a0, s0
; CHECK32P-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
; CHECK32P-NEXT: lw s0, 8(sp) # 4-byte Folded Reload
; CHECK32P-NEXT: lw s1, 4(sp) # 4-byte Folded Reload
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 0cd07672532dd..aca224c397ad2 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -1122,7 +1122,7 @@ define i64 @wmaccu(i32 %a, i32 %b, i64 %c) nounwind {
; CHECK-LABEL: wmaccu:
; CHECK: # %bb.0:
; CHECK-NEXT: wmaccu a2, a0, a1
-; CHECK-NEXT: padd.dw a0, a2, zero
+; CHECK-NEXT: mvd a0, a2
; CHECK-NEXT: ret
%aext = zext i32 %a to i64
%bext = zext i32 %b to i64
@@ -1135,7 +1135,7 @@ define i64 @wmaccu_commute(i32 %a, i32 %b, i64 %c) nounwind {
; CHECK-LABEL: wmaccu_commute:
; CHECK: # %bb.0:
; CHECK-NEXT: wmaccu a2, a0, a1
-; CHECK-NEXT: padd.dw a0, a2, zero
+; CHECK-NEXT: mvd a0, a2
; CHECK-NEXT: ret
%aext = zext i32 %a to i64
%bext = zext i32 %b to i64
@@ -1148,7 +1148,7 @@ define i64 @wmacc(i32 %a, i32 %b, i64 %c) nounwind {
; CHECK-LABEL: wmacc:
; CHECK: # %bb.0:
; CHECK-NEXT: wmacc a2, a0, a1
-; CHECK-NEXT: padd.dw a0, a2, zero
+; CHECK-NEXT: mvd a0, a2
; CHECK-NEXT: ret
%aext = sext i32 %a to i64
%bext = sext i32 %b to i64
@@ -1161,7 +1161,7 @@ define i64 @wmacc_commute(i32 %a, i32 %b, i64 %c) nounwind {
; CHECK-LABEL: wmacc_commute:
; CHECK: # %bb.0:
; CHECK-NEXT: wmacc a2, a0, a1
-; CHECK-NEXT: padd.dw a0, a2, zero
+; CHECK-NEXT: mvd a0, a2
; CHECK-NEXT: ret
%aext = sext i32 %a to i64
%bext = sext i32 %b to i64
@@ -1174,7 +1174,7 @@ define i64 @wmaccsu(i32 %a, i32 %b, i64 %c) nounwind {
; CHECK-LABEL: wmaccsu:
; CHECK: # %bb.0:
; CHECK-NEXT: wmaccsu a2, a0, a1
-; CHECK-NEXT: padd.dw a0, a2, zero
+; CHECK-NEXT: mvd a0, a2
; CHECK-NEXT: ret
%aext = sext i32 %a to i64
%bext = zext i32 %b to i64
@@ -1187,7 +1187,7 @@ define i64 @wmaccsu_commute(i32 %a, i32 %b, i64 %c) nounwind {
; CHECK-LABEL: wmaccsu_commute:
; CHECK: # %bb.0:
; CHECK-NEXT: wmaccsu a2, a0, a1
-; CHECK-NEXT: padd.dw a0, a2, zero
+; CHECK-NEXT: mvd a0, a2
; CHECK-NEXT: ret
%aext = sext i32 %a to i64
%bext = zext i32 %b to i64
@@ -1467,7 +1467,7 @@ define i64 @wmacc_first_mul_multiple_uses(i32 %a, i32 %b, i32 %c, i32 %d, ptr %o
; CHECK-NEXT: mv a5, a3
; CHECK-NEXT: mv a6, a2
; CHECK-NEXT: wmacc a2, a0, a1
-; CHECK-NEXT: padd.dw a0, a2, zero
+; CHECK-NEXT: mvd a0, a2
; CHECK-NEXT: sw a6, 0(a4)
; CHECK-NEXT: sw a5, 4(a4)
; CHECK-NEXT: ret
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
index 363b1dd33534e..9fa73c77ff864 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
@@ -1863,7 +1863,7 @@ define <4 x i16> @test_pssla_h(<4 x i16> %a, <4 x i16> %b) {
; RV32-NEXT: pack a1, a7, t1
; RV32-NEXT: merge a0, a4, t0
; RV32-NEXT: merge a2, a0, a1
-; RV32-NEXT: padd.dw a0, a2, zero
+; RV32-NEXT: mvd a0, a2
; RV32-NEXT: ret
;
; RV64-LABEL: test_pssla_h:
diff --git a/llvm/test/MC/RISCV/rv32p-aliases-valid.s b/llvm/test/MC/RISCV/rv32p-aliases-valid.s
index c8e517caacc54..a15cb37935df9 100644
--- a/llvm/test/MC/RISCV/rv32p-aliases-valid.s
+++ b/llvm/test/MC/RISCV/rv32p-aliases-valid.s
@@ -286,3 +286,7 @@ li t3, 0x81008100
# CHECK-S-OBJ-NOALIAS: lui t4, 524296
# CHECK-S-OBJ: lui t4, 524296
li t4, 0x80008000
+
+# CHECK-S-OBJ-NOALIAS: padd.dw a0, zero, s0
+# CHECK-S-OBJ: mvd a0, s0
+mvd a0, s0
>From 4777b3cfd979a8e2f1489476ed4ffa5dca202376 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Mon, 22 Jun 2026 23:12:32 -0700
Subject: [PATCH 2/2] fixup! Use copyPhysReg.
---
llvm/lib/Target/RISCV/RISCVMoveMerger.cpp | 16 +++-------------
1 file changed, 3 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp b/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
index a72642aad60ab..ecd991f9ced0f 100644
--- a/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
+++ b/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
@@ -186,19 +186,9 @@ RISCVMoveMerge::mergeGPRPairInsns(MachineBasicBlock::iterator I,
FirstPair.Source->getReg(), GPRPairIdx, &RISCV::GPRPairRegClass);
MCRegister DestReg = TRI->getMatchingSuperReg(
FirstPair.Destination->getReg(), GPRPairIdx, &RISCV::GPRPairRegClass);
- bool SrcKill = PairedSource.isKill() && FirstPair.Source->isKill();
-
- if (ST->hasStdExtZdinx()) {
- BuildMI(*I->getParent(), I, DL, TII->get(RISCV::FSGNJ_D_IN32X), DestReg)
- .addReg(SrcReg)
- .addReg(SrcReg, getKillRegState(SrcKill));
- } else if (ST->hasStdExtP()) {
- BuildMI(*I->getParent(), I, DL, TII->get(RISCV::PADD_DW), DestReg)
- .addReg(RISCV::X0_Pair)
- .addReg(SrcReg, getKillRegState(SrcKill));
- } else {
- llvm_unreachable("Unhandled subtarget with paired move.");
- }
+ bool KillSrc = PairedSource.isKill() && FirstPair.Source->isKill();
+
+ TII->copyPhysReg(*I->getParent(), I, DL, DestReg, SrcReg, KillSrc);
I->eraseFromParent();
Paired->eraseFromParent();
More information about the llvm-commits
mailing list