[llvm] [RISCV][P-ext] Add packed sign and zero extend intrinsics (PR #208685)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 15 01:01:00 PDT 2026
https://github.com/sihuan updated https://github.com/llvm/llvm-project/pull/208685
>From 1e693d58a386cab93bd02986bb53199c636c871e Mon Sep 17 00:00:00 2001
From: SiHuaN <liyongtai at iscas.ac.cn>
Date: Thu, 9 Jul 2026 08:56:31 +0000
Subject: [PATCH 1/2] [RISCV][P-ext] Add packed sign and zero extend combines
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 40 +++++++++--
llvm/lib/Target/RISCV/RISCVInstrInfoP.td | 29 ++++++--
llvm/test/CodeGen/RISCV/rvp-simd-32.ll | 20 ++++++
llvm/test/CodeGen/RISCV/rvp-simd-64.ll | 74 +++++++++++++++++++++
4 files changed, 155 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 738aa6dcf780a..d18e5acd2e700 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -715,11 +715,11 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
{MVT::v4i16, MVT::v2i32}, Legal);
setOperationAction(ISD::ANY_EXTEND_VECTOR_INREG, {MVT::v4i16, MVT::v2i32},
Custom);
- // LegalizeVectorOps uses result VT, LegalizeDAG uses ExtVT.
- setOperationAction(ISD::SIGN_EXTEND_INREG,
- {MVT::v2i16, MVT::v4i8, MVT::v2i32, MVT::v4i16},
- Legal);
}
+ // LegalizeVectorOps uses result VT, LegalizeDAG uses ExtVT.
+ setOperationAction(
+ ISD::SIGN_EXTEND_INREG,
+ {MVT::v2i8, MVT::v4i8, MVT::v2i16, MVT::v4i16, MVT::v2i32}, Legal);
}
if (Subtarget.hasStdExtZfbfmin()) {
@@ -17698,6 +17698,36 @@ static SDValue combineNarrowableShiftedLoad(SDNode *N, SelectionDAG &DAG) {
DAG.getShiftAmountConstant(ShiftAmt, VT, DL));
}
+static SDValue combinePZExt(SDNode *N, SelectionDAG &DAG,
+ const RISCVSubtarget &Subtarget) {
+ EVT VT = N->getValueType(0);
+ if (!VT.isSimple())
+ return SDValue();
+
+ MVT SimpleVT = VT.getSimpleVT();
+ if (!Subtarget.isPExtPackedType(SimpleVT))
+ return SDValue();
+
+ APInt SplatVal;
+ if (!ISD::isConstantSplatVector(N->getOperand(1).getNode(), SplatVal))
+ return SDValue();
+
+ MVT EltVT = SimpleVT.getVectorElementType();
+ bool IsByteToHalf = EltVT == MVT::i16 && SplatVal == 0xff;
+ bool IsHalfToWord = EltVT == MVT::i32 && SplatVal == 0xffff;
+ if (!IsByteToHalf && !IsHalfToWord)
+ return SDValue();
+
+ MVT PPairVT = MVT::getVectorVT(
+ MVT::getIntegerVT(SimpleVT.getScalarSizeInBits() / 2),
+ SimpleVT.getVectorNumElements() * 2);
+ SDLoc DL(N);
+ SDValue Src = DAG.getBitcast(PPairVT, N->getOperand(0));
+ SDValue Res = DAG.getNode(RISCVISD::PPAIRE, DL, PPairVT, Src,
+ DAG.getConstant(0, DL, PPairVT));
+ return DAG.getBitcast(SimpleVT, Res);
+}
+
// Combines two comparison operation and logic operation to one selection
// operation(min, max) and logic operation. Returns new constructed Node if
// conditions for optimization are satisfied.
@@ -17706,6 +17736,8 @@ static SDValue performANDCombine(SDNode *N,
const RISCVSubtarget &Subtarget) {
SelectionDAG &DAG = DCI.DAG;
SDValue N0 = N->getOperand(0);
+ if (SDValue V = combinePZExt(N, DAG, Subtarget))
+ return V;
// Pre-promote (i32 (and (srl X, Y), 1)) on RV64 with Zbs without zero
// extending X. This is safe since we only need the LSB after the shift and
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index f20f0d598dfab..26ccb07895fa7 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -2500,6 +2500,15 @@ let append Predicates = [IsRV32] in {
def : PatGprPair<riscv_psabs, PSABS_DB, v8i8>;
def : PatGprPair<riscv_psabs, PSABS_DH, v4i16>;
+ // Packed sign extend patterns
+ // Sign extend inreg patterns using psext. sext_invec is lowered to
+ // zext_invec+sext_inreg.
+ def : Pat<(v2i16 (sext_inreg GPR:$rs1, v2i8)), (PSEXT_H_B GPR:$rs1)>;
+ def : Pat<(v4i16 (sext_inreg GPRPair:$rs1, v4i8)), (PSEXT_DH_B GPRPair:$rs1)>;
+ def : Pat<(v2i32 (sext_inreg GPRPair:$rs1, v2i8)), (PSEXT_DW_B GPRPair:$rs1)>;
+ def : Pat<(v2i32 (sext_inreg GPRPair:$rs1, v2i16)),
+ (PSEXT_DW_H GPRPair:$rs1)>;
+
// 16-bit bswap patterns
def : Pat<(v4i16 (bswap GPRPair:$rs)),
(PPAIROE_DB GPRPair:$rs, GPRPair:$rs)>;
@@ -2546,8 +2555,12 @@ let append Predicates = [IsRV32] in {
def : Pat<(v2i32 (build_vector (XLenVT GPR:$a), (XLenVT GPR:$b))),
(BuildGPRPair GPR:$a, GPR:$b)>;
+ def : Pat<(v4i8 (riscv_ppaire GPR:$rs1, GPR:$rs2)),
+ (PPAIRE_B GPR:$rs1, GPR:$rs2)>;
def : Pat<(v8i8 (riscv_ppaire GPRPair:$rs1, GPRPair:$rs2)),
(PPAIRE_DB GPRPair:$rs1, GPRPair:$rs2)>;
+ def : Pat<(v4i16 (riscv_ppaire GPRPair:$rs1, GPRPair:$rs2)),
+ (PPAIRE_DH GPRPair:$rs1, GPRPair:$rs2)>;
// Concat vector patterns
def : Pat<(v8i8 (concat_vectors (v4i8 GPR:$a), (v4i8 GPR:$b))),
@@ -2577,6 +2590,11 @@ let append Predicates = [IsRV64] in {
def : PatGpr<bitreverse, REV_RV64>;
+ def : Pat<(v8i8 (riscv_ppaire GPR:$rs1, GPR:$rs2)),
+ (PPAIRE_B GPR:$rs1, GPR:$rs2)>;
+ def : Pat<(v4i16 (riscv_ppaire GPR:$rs1, GPR:$rs2)),
+ (PPAIRE_H GPR:$rs1, GPR:$rs2)>;
+
def : Pat<(XLenVT (riscv_sati GPR:$rs1, timm:$imm)),
(SATI_RV64 GPR:$rs1, (IncImm timm:$imm))>;
def : Pat<(XLenVT (riscv_usati GPR:$rs1, timm:$imm)),
@@ -2736,6 +2754,13 @@ let append Predicates = [IsRV64] in {
def : Pat<(v2i32 (vselect (v2i32 GPR:$mask), GPR:$true_v, GPR:$false_v)),
(MERGE GPR:$mask, GPR:$false_v, GPR:$true_v)>;
+ // Packed sign extend patterns
+ // Sign extend inreg patterns using psext. sext_invec is lowered to
+ // zext_invec+sext_inreg.
+ def : Pat<(v4i16 (sext_inreg GPR:$rs1, v4i8)), (PSEXT_H_B GPR:$rs1)>;
+ def : Pat<(v2i32 (sext_inreg GPR:$rs1, v2i8)), (PSEXT_W_B GPR:$rs1)>;
+ def : Pat<(v2i32 (sext_inreg GPR:$rs1, v2i16)), (PSEXT_W_H GPR:$rs1)>;
+
// 32-bit bswap patterns
def : Pat<(v2i32 (bswap GPR:$rs)),
(PPAIROE_W (REV8_RV64 GPR:$rs), (REV8_RV64 GPR:$rs))>;
@@ -2810,9 +2835,5 @@ let append Predicates = [IsRV64] in {
(ZIP8P GPR:$rs1, GPR:$rs2)>;
def : Pat<(v4i16 (riscv_pzip (v4i16 GPR:$rs1), (v4i16 GPR:$rs2))),
(ZIP16P GPR:$rs1, GPR:$rs2)>;
- // Sign extend inreg patterns using psext. sext_invec is lowered to
- // zext_invec+sext_inreg.
- def : Pat<(v4i16 (sext_inreg GPR:$rs1, v4i8)), (PSEXT_H_B GPR:$rs1)>;
- def : Pat<(v2i32 (sext_inreg GPR:$rs1, v2i16)), (PSEXT_W_H GPR:$rs1)>;
} // append Predicates = [IsRV64]
} // Predicates = [HasStdExtP]
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
index aeb0cc5e921b5..0adbbfd72adb1 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
@@ -2644,6 +2644,26 @@ define <2 x i16> @test_pmerge_mvmn_i16x2(<2 x i16> %rs2, <2 x i16> %rs1, <2 x i1
ret <2 x i16> %res
}
+; Packed sign and zero extend
+define <2 x i16> @test_psext_b_v2i16(<2 x i16> %a) {
+; CHECK-LABEL: test_psext_b_v2i16:
+; CHECK: # %bb.0:
+; CHECK-NEXT: psext.h.b a0, a0
+; CHECK-NEXT: ret
+ %shl = shl <2 x i16> %a, splat (i16 8)
+ %res = ashr <2 x i16> %shl, splat (i16 8)
+ ret <2 x i16> %res
+}
+
+define <2 x i16> @test_pzext_b_v2i16(<2 x i16> %a) {
+; CHECK-LABEL: test_pzext_b_v2i16:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pzext.h.b a0, a0
+; CHECK-NEXT: ret
+ %res = and <2 x i16> %a, splat (i16 255)
+ ret <2 x i16> %res
+}
+
; Packed absolute difference sum
define i32 @test_pabdsumu_u8x4_u32(<4 x i8> %a, <4 x i8> %b) {
; RV32-LABEL: test_pabdsumu_u8x4_u32:
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
index 07893cc51fdf2..cc7eae7db6a73 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
@@ -5779,6 +5779,80 @@ define <2 x i32> @test_pmerge_mvmn_i32x2(<2 x i32> %rs2, <2 x i32> %rs1, <2 x i3
ret <2 x i32> %res
}
+; Packed sign and zero extend
+define <4 x i16> @test_psext_b_v4i16(<4 x i16> %a) {
+; RV32-LABEL: test_psext_b_v4i16:
+; RV32: # %bb.0:
+; RV32-NEXT: psext.dh.b a0, a0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_psext_b_v4i16:
+; RV64: # %bb.0:
+; RV64-NEXT: psext.h.b a0, a0
+; RV64-NEXT: ret
+ %shl = shl <4 x i16> %a, splat (i16 8)
+ %res = ashr <4 x i16> %shl, splat (i16 8)
+ ret <4 x i16> %res
+}
+
+define <2 x i32> @test_psext_b_v2i32(<2 x i32> %a) {
+; RV32-LABEL: test_psext_b_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: psext.dw.b a0, a0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_psext_b_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: psext.w.b a0, a0
+; RV64-NEXT: ret
+ %shl = shl <2 x i32> %a, splat (i32 24)
+ %res = ashr <2 x i32> %shl, splat (i32 24)
+ ret <2 x i32> %res
+}
+
+define <2 x i32> @test_psext_h_v2i32(<2 x i32> %a) {
+; RV32-LABEL: test_psext_h_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: psext.dw.h a0, a0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_psext_h_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: psext.w.h a0, a0
+; RV64-NEXT: ret
+ %shl = shl <2 x i32> %a, splat (i32 16)
+ %res = ashr <2 x i32> %shl, splat (i32 16)
+ ret <2 x i32> %res
+}
+
+define <4 x i16> @test_pzext_b_v4i16(<4 x i16> %a) {
+; RV32-LABEL: test_pzext_b_v4i16:
+; RV32: # %bb.0:
+; RV32-NEXT: pzext.dh.b a0, a0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pzext_b_v4i16:
+; RV64: # %bb.0:
+; RV64-NEXT: pzext.h.b a0, a0
+; RV64-NEXT: ret
+ %res = and <4 x i16> %a, splat (i16 255)
+ ret <4 x i16> %res
+}
+
+define <2 x i32> @test_pzext_h_v2i32(<2 x i32> %a) {
+; RV32-LABEL: test_pzext_h_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: pzext.dw.h a0, a0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_pzext_h_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: pzext.w.h a0, a0
+; RV64-NEXT: ret
+ %res = and <2 x i32> %a, splat (i32 65535)
+ ret <2 x i32> %res
+}
+
; Packed absolute difference sum
define i32 @test_pabdsumu_u8x8_u32(<8 x i8> %a, <8 x i8> %b) {
; RV32-LABEL: test_pabdsumu_u8x8_u32:
>From db9a5e5f266db4935ff3ff83792f97a702822383 Mon Sep 17 00:00:00 2001
From: SiHuaN <liyongtai at iscas.ac.cn>
Date: Tue, 14 Jul 2026 15:11:25 +0000
Subject: [PATCH 2/2] [RISCV][P-ext] Add packed sign and zero extend intrinsics
---
llvm/include/llvm/IR/IntrinsicsRISCV.td | 10 +++
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 80 +++++++++++++++++--
llvm/test/CodeGen/RISCV/rvp-simd-32.ll | 18 +++++
llvm/test/CodeGen/RISCV/rvp-simd-64.ll | 70 ++++++++++++++++
.../RISCV/rvp-simd-intrinsic-invalid.ll | 39 +++++++++
5 files changed, 209 insertions(+), 8 deletions(-)
create mode 100644 llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td b/llvm/include/llvm/IR/IntrinsicsRISCV.td
index 28cde8111241c..eb4c19f150d99 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td
@@ -2085,6 +2085,16 @@ class RVPBinaryIntrinsic
[IntrNoMem, IntrSpeculatable]>;
def int_riscv_pmerge : RVPTernaryIntrinsic;
+ // Packed Sign and Zero Extend.
+ class RVPExtIntrinsic
+ : DefaultAttrsIntrinsic<[llvm_anyvector_ty],
+ [LLVMMatchType<0>],
+ [IntrNoMem, IntrSpeculatable]>;
+ def int_riscv_psext_b : RVPExtIntrinsic;
+ def int_riscv_psext_h : RVPExtIntrinsic;
+ def int_riscv_pzext_b : RVPExtIntrinsic;
+ def int_riscv_pzext_h : RVPExtIntrinsic;
+
// Packed Absolute Difference Sum.
def int_riscv_pabdsumu
: DefaultAttrsIntrinsic<[llvm_anyint_ty],
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index d18e5acd2e700..f98f66c6c6681 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -11939,6 +11939,21 @@ static inline bool isValidEGW(int EGS, EVT VT,
EGS * VT.getScalarSizeInBits();
}
+static SDValue lowerPZExt(SDValue Src, const SDLoc &DL, SelectionDAG &DAG,
+ const RISCVSubtarget &Subtarget) {
+ MVT VT = Src.getSimpleValueType();
+ MVT PPairVT =
+ MVT::getVectorVT(MVT::getIntegerVT(VT.getScalarSizeInBits() / 2),
+ VT.getVectorNumElements() * 2);
+ Src = DAG.getBitcast(PPairVT, Src);
+ unsigned ZeroReg = !Subtarget.is64Bit() && PPairVT.getSizeInBits() == 64
+ ? RISCV::X0_Pair
+ : RISCV::X0;
+ SDValue Res = DAG.getNode(RISCVISD::PPAIRE, DL, PPairVT, Src,
+ DAG.getRegister(ZeroReg, PPairVT));
+ return DAG.getBitcast(VT, Res);
+}
+
SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
SelectionDAG &DAG) const {
unsigned IntNo = Op.getConstantOperandVal(0);
@@ -12107,6 +12122,35 @@ SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
return DAG.getNode(Opc, DL, Op.getValueType(), Op.getOperand(1),
Op.getOperand(2));
}
+ case Intrinsic::riscv_psext_b:
+ case Intrinsic::riscv_psext_h: {
+ EVT VT = Op.getValueType();
+ if (!VT.isSimple() || !Subtarget.isPExtPackedType(VT.getSimpleVT()))
+ reportFatalUsageError("unsupported llvm.riscv.psext intrinsic");
+
+ MVT SimpleVT = VT.getSimpleVT();
+ unsigned SrcEltBits = IntNo == Intrinsic::riscv_psext_b ? 8 : 16;
+ if (SrcEltBits >= SimpleVT.getScalarSizeInBits())
+ reportFatalUsageError("unsupported llvm.riscv.psext intrinsic");
+
+ MVT ExtVT = MVT::getVectorVT(MVT::getIntegerVT(SrcEltBits),
+ SimpleVT.getVectorElementCount());
+ return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, SimpleVT, Op.getOperand(1),
+ DAG.getValueType(ExtVT));
+ }
+ case Intrinsic::riscv_pzext_b:
+ case Intrinsic::riscv_pzext_h: {
+ EVT VT = Op.getValueType();
+ if (!VT.isSimple() || !Subtarget.isPExtPackedType(VT.getSimpleVT()))
+ reportFatalUsageError("unsupported llvm.riscv.pzext intrinsic");
+
+ MVT SimpleVT = VT.getSimpleVT();
+ unsigned SrcEltBits = IntNo == Intrinsic::riscv_pzext_b ? 8 : 16;
+ if (SimpleVT.getScalarSizeInBits() != SrcEltBits * 2)
+ reportFatalUsageError("unsupported llvm.riscv.pzext intrinsic");
+
+ return lowerPZExt(Op.getOperand(1), DL, DAG, Subtarget);
+ }
case Intrinsic::riscv_pabdsumu:
case Intrinsic::riscv_pabdsumau: {
// On RV32 an i32-result absolute difference sum over a 64-bit (GPRPair)
@@ -16123,6 +16167,33 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res));
return;
}
+ case Intrinsic::riscv_psext_h:
+ reportFatalUsageError("unsupported llvm.riscv.psext intrinsic");
+ case Intrinsic::riscv_pzext_h:
+ reportFatalUsageError("unsupported llvm.riscv.pzext intrinsic");
+ case Intrinsic::riscv_psext_b:
+ case Intrinsic::riscv_pzext_b: {
+ bool IsSExt = IntNo == Intrinsic::riscv_psext_b;
+ const char *UnsupportedMsg =
+ IsSExt ? "unsupported llvm.riscv.psext intrinsic"
+ : "unsupported llvm.riscv.pzext intrinsic";
+ EVT VT = N->getValueType(0);
+ if (!Subtarget.is64Bit() || VT != MVT::v2i16)
+ reportFatalUsageError(UnsupportedMsg);
+
+ SDValue Undef = DAG.getUNDEF(VT);
+ SDValue Src = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v4i16,
+ N->getOperand(1), Undef);
+ SDValue Res;
+ if (IsSExt)
+ Res = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::v4i16, Src,
+ DAG.getValueType(MVT::v4i8));
+ else
+ Res = lowerPZExt(Src, DL, DAG, Subtarget);
+ Results.push_back(DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, VT, Res,
+ DAG.getVectorIdxConstant(0, DL)));
+ return;
+ }
case Intrinsic::riscv_paadd:
case Intrinsic::riscv_paaddu:
case Intrinsic::riscv_pasub:
@@ -17718,14 +17789,7 @@ static SDValue combinePZExt(SDNode *N, SelectionDAG &DAG,
if (!IsByteToHalf && !IsHalfToWord)
return SDValue();
- MVT PPairVT = MVT::getVectorVT(
- MVT::getIntegerVT(SimpleVT.getScalarSizeInBits() / 2),
- SimpleVT.getVectorNumElements() * 2);
- SDLoc DL(N);
- SDValue Src = DAG.getBitcast(PPairVT, N->getOperand(0));
- SDValue Res = DAG.getNode(RISCVISD::PPAIRE, DL, PPairVT, Src,
- DAG.getConstant(0, DL, PPairVT));
- return DAG.getBitcast(SimpleVT, Res);
+ return lowerPZExt(N->getOperand(0), SDLoc(N), DAG, Subtarget);
}
// Combines two comparison operation and logic operation to one selection
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
index 0adbbfd72adb1..5928a2cb0d1ea 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
@@ -2664,6 +2664,24 @@ define <2 x i16> @test_pzext_b_v2i16(<2 x i16> %a) {
ret <2 x i16> %res
}
+define <2 x i16> @test_riscv_psext_b_v2i16(<2 x i16> %a) {
+; CHECK-LABEL: test_riscv_psext_b_v2i16:
+; CHECK: # %bb.0:
+; CHECK-NEXT: psext.h.b a0, a0
+; CHECK-NEXT: ret
+ %res = call <2 x i16> @llvm.riscv.psext.b.v2i16(<2 x i16> %a)
+ ret <2 x i16> %res
+}
+
+define <2 x i16> @test_riscv_pzext_b_v2i16(<2 x i16> %a) {
+; CHECK-LABEL: test_riscv_pzext_b_v2i16:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pzext.h.b a0, a0
+; CHECK-NEXT: ret
+ %res = call <2 x i16> @llvm.riscv.pzext.b.v2i16(<2 x i16> %a)
+ ret <2 x i16> %res
+}
+
; Packed absolute difference sum
define i32 @test_pabdsumu_u8x4_u32(<4 x i8> %a, <4 x i8> %b) {
; RV32-LABEL: test_pabdsumu_u8x4_u32:
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
index cc7eae7db6a73..527d0c0fce09c 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
@@ -5853,6 +5853,76 @@ define <2 x i32> @test_pzext_h_v2i32(<2 x i32> %a) {
ret <2 x i32> %res
}
+define <4 x i16> @test_riscv_psext_b_v4i16(<4 x i16> %a) {
+; RV32-LABEL: test_riscv_psext_b_v4i16:
+; RV32: # %bb.0:
+; RV32-NEXT: psext.dh.b a0, a0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_riscv_psext_b_v4i16:
+; RV64: # %bb.0:
+; RV64-NEXT: psext.h.b a0, a0
+; RV64-NEXT: ret
+ %res = call <4 x i16> @llvm.riscv.psext.b.v4i16(<4 x i16> %a)
+ ret <4 x i16> %res
+}
+
+define <2 x i32> @test_riscv_psext_b_v2i32(<2 x i32> %a) {
+; RV32-LABEL: test_riscv_psext_b_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: psext.dw.b a0, a0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_riscv_psext_b_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: psext.w.b a0, a0
+; RV64-NEXT: ret
+ %res = call <2 x i32> @llvm.riscv.psext.b.v2i32(<2 x i32> %a)
+ ret <2 x i32> %res
+}
+
+define <2 x i32> @test_riscv_psext_h_v2i32(<2 x i32> %a) {
+; RV32-LABEL: test_riscv_psext_h_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: psext.dw.h a0, a0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_riscv_psext_h_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: psext.w.h a0, a0
+; RV64-NEXT: ret
+ %res = call <2 x i32> @llvm.riscv.psext.h.v2i32(<2 x i32> %a)
+ ret <2 x i32> %res
+}
+
+define <4 x i16> @test_riscv_pzext_b_v4i16(<4 x i16> %a) {
+; RV32-LABEL: test_riscv_pzext_b_v4i16:
+; RV32: # %bb.0:
+; RV32-NEXT: pzext.dh.b a0, a0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_riscv_pzext_b_v4i16:
+; RV64: # %bb.0:
+; RV64-NEXT: pzext.h.b a0, a0
+; RV64-NEXT: ret
+ %res = call <4 x i16> @llvm.riscv.pzext.b.v4i16(<4 x i16> %a)
+ ret <4 x i16> %res
+}
+
+define <2 x i32> @test_riscv_pzext_h_v2i32(<2 x i32> %a) {
+; RV32-LABEL: test_riscv_pzext_h_v2i32:
+; RV32: # %bb.0:
+; RV32-NEXT: pzext.dw.h a0, a0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test_riscv_pzext_h_v2i32:
+; RV64: # %bb.0:
+; RV64-NEXT: pzext.w.h a0, a0
+; RV64-NEXT: ret
+ %res = call <2 x i32> @llvm.riscv.pzext.h.v2i32(<2 x i32> %a)
+ ret <2 x i32> %res
+}
+
; Packed absolute difference sum
define i32 @test_pabdsumu_u8x8_u32(<8 x i8> %a, <8 x i8> %b) {
; RV32-LABEL: test_pabdsumu_u8x8_u32:
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll b/llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll
new file mode 100644
index 0000000000000..28b1d7c53a6e7
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-intrinsic-invalid.ll
@@ -0,0 +1,39 @@
+; RUN: sed -n '/^; BEGIN-PSEXT-LEGAL$/,/^; END-PSEXT-LEGAL$/p' %s \
+; RUN: | not llc -mtriple=riscv64 -mattr=+experimental-p,+m,+zbb \
+; RUN: -o /dev/null 2>&1 | FileCheck %s --check-prefix=PSEXT
+; RUN: sed -n '/^; BEGIN-PSEXT-WIDEN$/,/^; END-PSEXT-WIDEN$/p' %s \
+; RUN: | not llc -mtriple=riscv64 -mattr=+experimental-p,+m,+zbb \
+; RUN: -o /dev/null 2>&1 | FileCheck %s --check-prefix=PSEXT
+; RUN: sed -n '/^; BEGIN-PZEXT$/,/^; END-PZEXT$/p' %s \
+; RUN: | not llc -mtriple=riscv64 -mattr=+experimental-p,+m,+zbb \
+; RUN: -o /dev/null 2>&1 | FileCheck %s --check-prefix=PZEXT
+
+; PSEXT: LLVM ERROR: unsupported llvm.riscv.psext intrinsic
+; PZEXT: LLVM ERROR: unsupported llvm.riscv.pzext intrinsic
+
+; BEGIN-PSEXT-LEGAL
+define <4 x i16> @bad_psext_legal_type(<4 x i16> %a) {
+ %res = call <4 x i16> @llvm.riscv.psext.h.v4i16(<4 x i16> %a)
+ ret <4 x i16> %res
+}
+
+declare <4 x i16> @llvm.riscv.psext.h.v4i16(<4 x i16>)
+; END-PSEXT-LEGAL
+
+; BEGIN-PSEXT-WIDEN
+define <2 x i16> @bad_psext_widen_type(<2 x i16> %a) {
+ %res = call <2 x i16> @llvm.riscv.psext.h.v2i16(<2 x i16> %a)
+ ret <2 x i16> %res
+}
+
+declare <2 x i16> @llvm.riscv.psext.h.v2i16(<2 x i16>)
+; END-PSEXT-WIDEN
+
+; BEGIN-PZEXT
+define <2 x i32> @bad_pzext(<2 x i32> %a) {
+ %res = call <2 x i32> @llvm.riscv.pzext.b.v2i32(<2 x i32> %a)
+ ret <2 x i32> %res
+}
+
+declare <2 x i32> @llvm.riscv.pzext.b.v2i32(<2 x i32>)
+; END-PZEXT
More information about the llvm-commits
mailing list