[llvm] [RISCV][P-ext] packed shift-add codegen (PR #201294)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 3 01:23:09 PDT 2026
https://github.com/sihuan created https://github.com/llvm/llvm-project/pull/201294
Add isel patterns for `psh1add`, `pssh1sadd` and the scalar `ssh1sadd`, matching `(a << 1) + b` and `sadd.sat(sadd.sat(a, a), b)`.
>From f11df98e4a263777b70c9caf54242163dd0a9229 Mon Sep 17 00:00:00 2001
From: SiHuaN <liyongtai at iscas.ac.cn>
Date: Wed, 3 Jun 2026 15:45:51 +0800
Subject: [PATCH] [RISCV][P-ext] packed shift-add codegen
Add isel patterns for psh1add, pssh1sadd and the scalar ssh1sadd, matching
(a << 1) + b and sadd.sat(sadd.sat(a, a), b).
---
llvm/lib/Target/RISCV/RISCVInstrInfoP.td | 38 +++++++++
llvm/test/CodeGen/RISCV/rv32p.ll | 10 +++
llvm/test/CodeGen/RISCV/rvp-simd-32.ll | 29 ++++++-
llvm/test/CodeGen/RISCV/rvp-simd-64.ll | 98 +++++++++++++++++++-----
4 files changed, 153 insertions(+), 22 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 4c07d054c2983..11f78a9da256f 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1889,6 +1889,26 @@ def RISCVBuildPairGPRVec : RVSDNode<"BuildPairGPRVec",
SDT_RISCVBuildPairGPRVec>;
def RISCVSplitGPRVec : RVSDNode<"SplitGPRVec", SDT_RISCVSplitGPRVec>;
+// (rs1 << 1) + rs2
+class PatPSh1Add<RVInst Inst, ValueType vt>
+ : Pat<(vt (add (riscv_pshl (vt GPR:$rs1), (XLenVT 1)), (vt GPR:$rs2))),
+ (Inst GPR:$rs1, GPR:$rs2)>;
+class PatPSh1AddPair<RVInst Inst, ValueType vt>
+ : Pat<(vt (add (riscv_pshl (vt GPRPair:$rs1), (XLenVT 1)),
+ (vt GPRPair:$rs2))),
+ (Inst GPRPair:$rs1, GPRPair:$rs2)>;
+
+// Signed-saturating (rs1 << 1) then signed-saturating add rs2; a saturating
+// left-shift-by-1 is a saturating add of the operand with itself.
+class PatPSSh1SAdd<RVInst Inst, ValueType vt>
+ : Pat<(vt (saddsat (saddsat (vt GPR:$rs1), (vt GPR:$rs1)),
+ (vt GPR:$rs2))),
+ (Inst GPR:$rs1, GPR:$rs2)>;
+class PatPSSh1SAddPair<RVInst Inst, ValueType vt>
+ : Pat<(vt (saddsat (saddsat (vt GPRPair:$rs1), (vt GPRPair:$rs1)),
+ (vt GPRPair:$rs2))),
+ (Inst GPRPair:$rs1, GPRPair:$rs2)>;
+
let Predicates = [HasStdExtP] in {
def : PatGpr<abs, ABS>;
@@ -1959,6 +1979,10 @@ let Predicates = [HasStdExtP] in {
def : PatGprGpr<ssubsat, PSSUB_H, XLenVecI16VT>;
def : PatGprGpr<usubsat, PSSUBU_H, XLenVecI16VT>;
+ // 16-bit shift-add patterns
+ def : PatPSh1Add<PSH1ADD_H, XLenVecI16VT>;
+ def : PatPSSh1SAdd<PSSH1SADD_H, XLenVecI16VT>;
+
// 8-bit averaging patterns
def : PatGprGpr<avgfloors, PAADD_B, XLenVecI8VT>;
def : PatGprGpr<avgflooru, PAADDU_B, XLenVecI8VT>;
@@ -2072,6 +2096,8 @@ let append Predicates = [IsRV32] in {
def : PatGprUimmLog2XLen<sshlsat, SSLAI>;
// No SSLLI
+ def : PatPSSh1SAdd<SSH1SADD, XLenVT>;
+
// 32-bit averaging patterns
def : PatGprGpr<avgfloors, AADD, i32>;
def : PatGprGpr<avgflooru, AADDU, i32>;
@@ -2173,6 +2199,14 @@ let append Predicates = [IsRV32] in {
def : PatGprPairGprPair<ssubsat, PSSUB_DW, v2i32>;
def : PatGprPairGprPair<usubsat, PSSUBU_DW, v2i32>;
+ // 16-bit shift-add patterns
+ def : PatPSh1AddPair<PSH1ADD_DH, v4i16>;
+ def : PatPSSh1SAddPair<PSSH1SADD_DH, v4i16>;
+
+ // 32-bit shift-add patterns
+ def : PatPSh1AddPair<PSH1ADD_DW, v2i32>;
+ def : PatPSSh1SAddPair<PSSH1SADD_DW, v2i32>;
+
// 8-bit averaging patterns
def : PatGprPairGprPair<avgfloors, PAADD_DB, v8i8>;
def : PatGprPairGprPair<avgflooru, PAADDU_DB, v8i8>;
@@ -2377,6 +2411,10 @@ let append Predicates = [IsRV64] in {
def : PatGprGpr<ssubsat, PSSUB_W, v2i32>;
def : PatGprGpr<usubsat, PSSUBU_W, v2i32>;
+ // 32-bit shift-add patterns
+ def : PatPSh1Add<PSH1ADD_W, v2i32>;
+ def : PatPSSh1SAdd<PSSH1SADD_W, v2i32>;
+
// 32-bit averaging patterns
def : PatGprGpr<avgfloors, PAADD_W, v2i32>;
def : PatGprGpr<avgflooru, PAADDU_W, v2i32>;
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index e2f6fd7e0192d..e627be54d3a08 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -732,6 +732,16 @@ define i32 @sadd_i32(i32 %x, i32 %y) {
ret i32 %a
}
+define i32 @ssh1sadd_i32(i32 %x, i32 %y) {
+; CHECK-LABEL: ssh1sadd_i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: ssh1sadd a0, a0, a1
+; CHECK-NEXT: ret
+ %shl = call i32 @llvm.sadd.sat.i32(i32 %x, i32 %x)
+ %a = call i32 @llvm.sadd.sat.i32(i32 %shl, i32 %y)
+ ret i32 %a
+}
+
define i8 @ssub_i8(i8 %x, i8 %y) {
; CHECK-LABEL: ssub_i8:
; CHECK: # %bb.0:
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
index f7078dad860f5..a1a386625528c 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
@@ -218,6 +218,27 @@ define <2 x i16> @test_pssubu_h(<2 x i16> %a, <2 x i16> %b) {
ret <2 x i16> %res
}
+; Test shift-add operations for v2i16
+define <2 x i16> @test_psh1add_h(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: test_psh1add_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: psh1add.h a0, a0, a1
+; CHECK-NEXT: ret
+ %shl = shl <2 x i16> %a, splat (i16 1)
+ %res = add <2 x i16> %shl, %b
+ ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pssh1sadd_h(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: test_pssh1sadd_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pssh1sadd.h a0, a0, a1
+; CHECK-NEXT: ret
+ %shl = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %a, <2 x i16> %a)
+ %res = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %shl, <2 x i16> %b)
+ ret <2 x i16> %res
+}
+
; Test saturating add operations for v4i8
define <4 x i8> @test_psadd_b(<4 x i8> %a, <4 x i8> %b) {
; CHECK-LABEL: test_psadd_b:
@@ -2012,10 +2033,10 @@ define <2 x i16> @test_select_v2i16(i1 %cond, <2 x i16> %a, <2 x i16> %b) {
; CHECK: # %bb.0:
; CHECK-NEXT: andi a3, a0, 1
; CHECK-NEXT: mv a0, a1
-; CHECK-NEXT: bnez a3, .LBB144_2
+; CHECK-NEXT: bnez a3, .LBB146_2
; CHECK-NEXT: # %bb.1:
; CHECK-NEXT: mv a0, a2
-; CHECK-NEXT: .LBB144_2:
+; CHECK-NEXT: .LBB146_2:
; CHECK-NEXT: ret
%res = select i1 %cond, <2 x i16> %a, <2 x i16> %b
ret <2 x i16> %res
@@ -2026,10 +2047,10 @@ define <4 x i8> @test_select_v4i8(i1 %cond, <4 x i8> %a, <4 x i8> %b) {
; CHECK: # %bb.0:
; CHECK-NEXT: andi a3, a0, 1
; CHECK-NEXT: mv a0, a1
-; CHECK-NEXT: bnez a3, .LBB145_2
+; CHECK-NEXT: bnez a3, .LBB147_2
; CHECK-NEXT: # %bb.1:
; CHECK-NEXT: mv a0, a2
-; CHECK-NEXT: .LBB145_2:
+; CHECK-NEXT: .LBB147_2:
; CHECK-NEXT: ret
%res = select i1 %cond, <4 x i8> %a, <4 x i8> %b
ret <4 x i8> %res
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
index 8d2d0f278e8c9..0df9a7c0b6fa1 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
@@ -449,6 +449,37 @@ define <4 x i16> @test_pssubu_h(<4 x i16> %a, <4 x i16> %b) {
ret <4 x i16> %res
}
+; Test shift-add operations for v4i16
+define <4 x i16> @test_psh1add_h(<4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_psh1add_h:
+; RV32: # %bb.0:
+; RV32-NEXT: psh1add.dh a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_psh1add_h:
+; RV64: # %bb.0:
+; RV64-NEXT: psh1add.h a0, a0, a1
+; RV64-NEXT: ret
+ %shl = shl <4 x i16> %a, splat (i16 1)
+ %res = add <4 x i16> %shl, %b
+ ret <4 x i16> %res
+}
+
+define <4 x i16> @test_pssh1sadd_h(<4 x i16> %a, <4 x i16> %b) {
+; RV32-LABEL: test_pssh1sadd_h:
+; RV32: # %bb.0:
+; RV32-NEXT: pssh1sadd.dh a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pssh1sadd_h:
+; RV64: # %bb.0:
+; RV64-NEXT: pssh1sadd.h a0, a0, a1
+; RV64-NEXT: ret
+ %shl = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %a, <4 x i16> %a)
+ %res = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %shl, <4 x i16> %b)
+ ret <4 x i16> %res
+}
+
; Test saturating add operations for v8i8
define <8 x i8> @test_psadd_b(<8 x i8> %a, <8 x i8> %b) {
; RV32-LABEL: test_psadd_b:
@@ -1252,6 +1283,37 @@ define <2 x i32> @test_pssubu_w(<2 x i32> %a, <2 x i32> %b) {
ret <2 x i32> %res
}
+; Test shift-add operations for v2i32
+define <2 x i32> @test_psh1add_w(<2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_psh1add_w:
+; RV32: # %bb.0:
+; RV32-NEXT: psh1add.dw a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_psh1add_w:
+; RV64: # %bb.0:
+; RV64-NEXT: psh1add.w a0, a0, a1
+; RV64-NEXT: ret
+ %shl = shl <2 x i32> %a, splat (i32 1)
+ %res = add <2 x i32> %shl, %b
+ ret <2 x i32> %res
+}
+
+define <2 x i32> @test_pssh1sadd_w(<2 x i32> %a, <2 x i32> %b) {
+; RV32-LABEL: test_pssh1sadd_w:
+; RV32: # %bb.0:
+; RV32-NEXT: pssh1sadd.dw a0, a0, a2
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pssh1sadd_w:
+; RV64: # %bb.0:
+; RV64-NEXT: pssh1sadd.w a0, a0, a1
+; RV64-NEXT: ret
+ %shl = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %a, <2 x i32> %a)
+ %res = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %shl, <2 x i32> %b)
+ ret <2 x i32> %res
+}
+
; Test averaging floor signed operations for v2i32 (RV64 only)
; avgfloors pattern: (a + b) arithmetic shift right 1
define <2 x i32> @test_paadd_w(<2 x i32> %a, <2 x i32> %b) {
@@ -3988,12 +4050,12 @@ define <4 x i16> @test_select_v4i16(i1 %cond, <4 x i16> %a, <4 x i16> %b) {
; RV32-LABEL: test_select_v4i16:
; RV32: # %bb.0:
; RV32-NEXT: andi a5, a0, 1
-; RV32-NEXT: bnez a5, .LBB211_2
+; RV32-NEXT: bnez a5, .LBB215_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: mv a0, a3
; RV32-NEXT: mv a1, a4
; RV32-NEXT: ret
-; RV32-NEXT: .LBB211_2:
+; RV32-NEXT: .LBB215_2:
; RV32-NEXT: mv a0, a1
; RV32-NEXT: mv a1, a2
; RV32-NEXT: ret
@@ -4002,10 +4064,10 @@ define <4 x i16> @test_select_v4i16(i1 %cond, <4 x i16> %a, <4 x i16> %b) {
; RV64: # %bb.0:
; RV64-NEXT: andi a3, a0, 1
; RV64-NEXT: mv a0, a1
-; RV64-NEXT: bnez a3, .LBB211_2
+; RV64-NEXT: bnez a3, .LBB215_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: mv a0, a2
-; RV64-NEXT: .LBB211_2:
+; RV64-NEXT: .LBB215_2:
; RV64-NEXT: ret
%res = select i1 %cond, <4 x i16> %a, <4 x i16> %b
ret <4 x i16> %res
@@ -4015,12 +4077,12 @@ define <8 x i8> @test_select_v8i8(i1 %cond, <8 x i8> %a, <8 x i8> %b) {
; RV32-LABEL: test_select_v8i8:
; RV32: # %bb.0:
; RV32-NEXT: andi a5, a0, 1
-; RV32-NEXT: bnez a5, .LBB212_2
+; RV32-NEXT: bnez a5, .LBB216_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: mv a0, a3
; RV32-NEXT: mv a1, a4
; RV32-NEXT: ret
-; RV32-NEXT: .LBB212_2:
+; RV32-NEXT: .LBB216_2:
; RV32-NEXT: mv a0, a1
; RV32-NEXT: mv a1, a2
; RV32-NEXT: ret
@@ -4029,10 +4091,10 @@ define <8 x i8> @test_select_v8i8(i1 %cond, <8 x i8> %a, <8 x i8> %b) {
; RV64: # %bb.0:
; RV64-NEXT: andi a3, a0, 1
; RV64-NEXT: mv a0, a1
-; RV64-NEXT: bnez a3, .LBB212_2
+; RV64-NEXT: bnez a3, .LBB216_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: mv a0, a2
-; RV64-NEXT: .LBB212_2:
+; RV64-NEXT: .LBB216_2:
; RV64-NEXT: ret
%res = select i1 %cond, <8 x i8> %a, <8 x i8> %b
ret <8 x i8> %res
@@ -4042,12 +4104,12 @@ define <2 x i32> @test_select_v2i32(i1 %cond, <2 x i32> %a, <2 x i32> %b) {
; RV32-LABEL: test_select_v2i32:
; RV32: # %bb.0:
; RV32-NEXT: andi a5, a0, 1
-; RV32-NEXT: bnez a5, .LBB213_2
+; RV32-NEXT: bnez a5, .LBB217_2
; RV32-NEXT: # %bb.1:
; RV32-NEXT: mv a0, a3
; RV32-NEXT: mv a1, a4
; RV32-NEXT: ret
-; RV32-NEXT: .LBB213_2:
+; RV32-NEXT: .LBB217_2:
; RV32-NEXT: mv a0, a1
; RV32-NEXT: mv a1, a2
; RV32-NEXT: ret
@@ -4056,10 +4118,10 @@ define <2 x i32> @test_select_v2i32(i1 %cond, <2 x i32> %a, <2 x i32> %b) {
; RV64: # %bb.0:
; RV64-NEXT: andi a3, a0, 1
; RV64-NEXT: mv a0, a1
-; RV64-NEXT: bnez a3, .LBB213_2
+; RV64-NEXT: bnez a3, .LBB217_2
; RV64-NEXT: # %bb.1:
; RV64-NEXT: mv a0, a2
-; RV64-NEXT: .LBB213_2:
+; RV64-NEXT: .LBB217_2:
; RV64-NEXT: ret
%res = select i1 %cond, <2 x i32> %a, <2 x i32> %b
ret <2 x i32> %res
@@ -4107,16 +4169,16 @@ define <2 x i32> @test_vselect_v2i32(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
; RV32: # %bb.0:
; RV32-NEXT: pmslt.dw a6, a2, a0
; RV32-NEXT: mv a0, a4
-; RV32-NEXT: beqz a7, .LBB216_3
+; RV32-NEXT: beqz a7, .LBB220_3
; RV32-NEXT: # %bb.1:
-; RV32-NEXT: beqz a6, .LBB216_4
-; RV32-NEXT: .LBB216_2:
+; RV32-NEXT: beqz a6, .LBB220_4
+; RV32-NEXT: .LBB220_2:
; RV32-NEXT: mv a1, a5
; RV32-NEXT: ret
-; RV32-NEXT: .LBB216_3:
+; RV32-NEXT: .LBB220_3:
; RV32-NEXT: mv a5, a3
-; RV32-NEXT: bnez a6, .LBB216_2
-; RV32-NEXT: .LBB216_4:
+; RV32-NEXT: bnez a6, .LBB220_2
+; RV32-NEXT: .LBB220_4:
; RV32-NEXT: mv a0, a2
; RV32-NEXT: mv a1, a5
; RV32-NEXT: ret
More information about the llvm-commits
mailing list