[llvm] [RISCV][P-ext] Fold packed insert-into-zero to zero-extend (PR #208006)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 14 03:14:18 PDT 2026
https://github.com/sihuan updated https://github.com/llvm/llvm-project/pull/208006
>From b7bf2107555f176899df3563b4a5ca5c6ed8736d Mon Sep 17 00:00:00 2001
From: SiHuaN <liyongtai at iscas.ac.cn>
Date: Tue, 7 Jul 2026 06:21:02 +0000
Subject: [PATCH 1/3] [RISCV][P-ext] Fold packed insert-into-zero to
zero-extend
An insert_subvector of a 32-bit packed type (v4i8/v2i16) into a zero-filled
64-bit packed vector at index 0 is a zero-extend. Fold it so RV64 emits a
single zext.w instead of scalarizing into a byte-wise repack; RV32 concatenates
with a zero half into the GPRPair.
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 29 ++++++++++++
.../CodeGen/RISCV/rvp-insert-subvector.ll | 45 +++++++++++++++++++
2 files changed, 74 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 77b9b9d6bc3c4..1bc5e1e11838e 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -1983,6 +1983,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
setTargetDAGCombine({ISD::LOAD, ISD::STORE});
if (Subtarget.useRVVForFixedLengthVectors() || Subtarget.hasStdExtP())
setTargetDAGCombine(ISD::BITCAST);
+ if (Subtarget.hasStdExtP())
+ setTargetDAGCombine(ISD::INSERT_SUBVECTOR);
setMaxDivRemBitWidthSupported(Subtarget.is64Bit() ? 128 : 64);
@@ -20983,6 +20985,29 @@ static SDValue performINSERT_VECTOR_ELTCombine(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, ConcatOps);
}
+// Fold insert of a 32-bit packed type into a zero-filled 64-bit packed vector
+// at index 0 (a zero-extend) to avoid scalarizing it into a byte-wise repack.
+static SDValue performINSERT_SUBVECTORCombine(SDNode *N, SelectionDAG &DAG,
+ const RISCVSubtarget &Subtarget) {
+ MVT VT = N->getSimpleValueType(0);
+ SDValue Sub = N->getOperand(1);
+ // Result must be a 64-bit packed type. The subvector shares its element type
+ // (insert_subvector invariant), so a 32-bit one is exactly VT's low half.
+ if (!Subtarget.isPExtPackedType(VT) || VT.getSizeInBits() != 64 ||
+ Sub.getValueSizeInBits() != 32)
+ return SDValue();
+ if (!isNullConstant(N->getOperand(2)) ||
+ !ISD::isConstantSplatVectorAllZeros(N->getOperand(0).getNode()))
+ return SDValue();
+ SDLoc DL(N);
+ // RV32 keeps the 32-bit type in a full GPR (concat a zero half into the
+ // GPRPair); RV64 has it in a GPR's low half (a plain zext.w).
+ if (!Subtarget.is64Bit())
+ return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Sub,
+ DAG.getConstant(0, DL, Sub.getSimpleValueType()));
+ return widenPackedVectorWithZeros(DAG, DL, Sub, VT);
+}
+
// If we're concatenating a series of vector loads like
// concat_vectors (load v4i8, p+0), (load v4i8, p+n), (load v4i8, p+n*2) ...
// Then we can turn this into a strided load by widening the vector elements
@@ -22982,6 +23007,10 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
if (SDValue V = performBUILD_VECTORCombine(N, DAG, Subtarget, *this))
return V;
break;
+ case ISD::INSERT_SUBVECTOR:
+ if (SDValue V = performINSERT_SUBVECTORCombine(N, DAG, Subtarget))
+ return V;
+ break;
case ISD::CONCAT_VECTORS:
if (SDValue V = performCONCAT_VECTORSCombine(N, DAG, Subtarget, *this))
return V;
diff --git a/llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll b/llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll
new file mode 100644
index 0000000000000..d993c163acecb
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll
@@ -0,0 +1,45 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-p,+m,+zbb -verify-machineinstrs < %s | FileCheck %s --check-prefixes=RV32
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-p,+m,+zbb -verify-machineinstrs < %s | FileCheck %s --check-prefixes=RV64
+
+define <8 x i8> @insert_zero_v4i8(<4 x i8> %v) {
+; RV32-LABEL: insert_zero_v4i8:
+; RV32: # %bb.0:
+; RV32-NEXT: li a1, 0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: insert_zero_v4i8:
+; RV64: # %bb.0:
+; RV64-NEXT: zext.w a0, a0
+; RV64-NEXT: ret
+ %r = call <8 x i8> @llvm.vector.insert.v8i8.v4i8(<8 x i8> zeroinitializer, <4 x i8> %v, i64 0)
+ ret <8 x i8> %r
+}
+
+define <4 x i16> @insert_zero_v2i16(<2 x i16> %v) {
+; RV32-LABEL: insert_zero_v2i16:
+; RV32: # %bb.0:
+; RV32-NEXT: li a1, 0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: insert_zero_v2i16:
+; RV64: # %bb.0:
+; RV64-NEXT: zext.w a0, a0
+; RV64-NEXT: ret
+ %r = call <4 x i16> @llvm.vector.insert.v4i16.v2i16(<4 x i16> zeroinitializer, <2 x i16> %v, i64 0)
+ ret <4 x i16> %r
+}
+
+define <2 x i32> @insert_zero_v1i32(<1 x i32> %v) {
+; RV32-LABEL: insert_zero_v1i32:
+; RV32: # %bb.0:
+; RV32-NEXT: li a1, 0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: insert_zero_v1i32:
+; RV64: # %bb.0:
+; RV64-NEXT: zext.w a0, a0
+; RV64-NEXT: ret
+ %r = call <2 x i32> @llvm.vector.insert.v2i32.v1i32(<2 x i32> zeroinitializer, <1 x i32> %v, i64 0)
+ ret <2 x i32> %r
+}
>From 47ed04d5a9d45a328bbdda4cb08195a24b15bbe9 Mon Sep 17 00:00:00 2001
From: SiHuaN <liyongtai at iscas.ac.cn>
Date: Mon, 13 Jul 2026 15:15:55 +0000
Subject: [PATCH 2/3] [RISCV] Custom lower P-ext INSERT_SUBVECTOR
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 59 ++++++++++---------
.../CodeGen/RISCV/rvp-insert-subvector.ll | 14 -----
2 files changed, 30 insertions(+), 43 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 7aabd74adb61d..2c7f9db157fa2 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -560,6 +560,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
{MVT::v2i16, MVT::v4i8}, Custom);
setOperationAction(ISD::INTRINSIC_WO_CHAIN, {MVT::v2i16, MVT::v4i8},
Custom);
+ // Operand legalization queries the action using the illegal subvector.
+ setOperationAction(ISD::INSERT_SUBVECTOR, {MVT::v2i16, MVT::v4i8},
+ Custom);
} else {
VTs = P32VecVTs;
}
@@ -674,6 +677,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
{ISD::SETGE, ISD::SETUGT, ISD::SETUGE, ISD::SETULE, ISD::SETLE},
P64VecVTs, Expand);
setCondCodeAction({ISD::SETNE, ISD::SETGT}, P64VecVTs, Custom);
+ // Operation legalization queries the action using the result type.
+ setOperationAction(ISD::INSERT_SUBVECTOR, {MVT::v4i16, MVT::v8i8},
+ Custom);
} else {
setOperationAction({ISD::MUL, ISD::MULHS, ISD::MULHU}, P64VecVTs, Legal);
setOperationAction(ISD::ZERO_EXTEND_VECTOR_INREG,
@@ -1987,8 +1993,6 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
setTargetDAGCombine({ISD::LOAD, ISD::STORE});
if (Subtarget.useRVVForFixedLengthVectors() || Subtarget.hasStdExtP())
setTargetDAGCombine(ISD::BITCAST);
- if (Subtarget.hasStdExtP())
- setTargetDAGCombine(ISD::INSERT_SUBVECTOR);
setMaxDivRemBitWidthSupported(Subtarget.is64Bit() ? 128 : 64);
@@ -12796,6 +12800,9 @@ SDValue RISCVTargetLowering::lowerVPREDUCE(SDValue Op,
DAG.getConstantFP(APFloat::getNaN(ResVT.getFltSemantics()), DL, ResVT));
}
+static SDValue widenPackedVectorWithZeros(SelectionDAG &DAG, const SDLoc &DL,
+ SDValue V, MVT WideVT);
+
SDValue RISCVTargetLowering::lowerINSERT_SUBVECTOR(SDValue Op,
SelectionDAG &DAG) const {
SDValue Vec = Op.getOperand(0);
@@ -12808,6 +12815,27 @@ SDValue RISCVTargetLowering::lowerINSERT_SUBVECTOR(SDValue Op,
unsigned OrigIdx = Op.getConstantOperandVal(2);
const RISCVRegisterInfo *TRI = Subtarget.getRegisterInfo();
+ bool IsPExtInsert =
+ Subtarget.hasStdExtP() &&
+ ((Subtarget.is64Bit() &&
+ (SubVecVT == MVT::v2i16 || SubVecVT == MVT::v4i8)) ||
+ (!Subtarget.is64Bit() && (VecVT == MVT::v4i16 || VecVT == MVT::v8i8)));
+
+ // Fold insert of a 32-bit packed type into a zero-filled 64-bit packed vector
+ // at index 0 (a zero-extend) to avoid scalarizing it into a byte-wise repack.
+ if (IsPExtInsert) {
+ if ((VecVT != MVT::v4i16 && VecVT != MVT::v8i8) ||
+ SubVecVT.getSizeInBits() != 32 || OrigIdx != 0 ||
+ !ISD::isConstantSplatVectorAllZeros(Vec.getNode()))
+ return SDValue();
+
+ if (!Subtarget.is64Bit()) {
+ SDValue Zero = DAG.getBitcast(SubVecVT, DAG.getConstant(0, DL, MVT::i32));
+ return DAG.getNode(ISD::CONCAT_VECTORS, DL, VecVT, SubVec, Zero);
+ }
+ return widenPackedVectorWithZeros(DAG, DL, SubVec, VecVT);
+ }
+
if (OrigIdx == 0 && Vec.isUndef())
return Op;
@@ -21101,29 +21129,6 @@ static SDValue performINSERT_VECTOR_ELTCombine(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, ConcatOps);
}
-// Fold insert of a 32-bit packed type into a zero-filled 64-bit packed vector
-// at index 0 (a zero-extend) to avoid scalarizing it into a byte-wise repack.
-static SDValue performINSERT_SUBVECTORCombine(SDNode *N, SelectionDAG &DAG,
- const RISCVSubtarget &Subtarget) {
- MVT VT = N->getSimpleValueType(0);
- SDValue Sub = N->getOperand(1);
- // Result must be a 64-bit packed type. The subvector shares its element type
- // (insert_subvector invariant), so a 32-bit one is exactly VT's low half.
- if (!Subtarget.isPExtPackedType(VT) || VT.getSizeInBits() != 64 ||
- Sub.getValueSizeInBits() != 32)
- return SDValue();
- if (!isNullConstant(N->getOperand(2)) ||
- !ISD::isConstantSplatVectorAllZeros(N->getOperand(0).getNode()))
- return SDValue();
- SDLoc DL(N);
- // RV32 keeps the 32-bit type in a full GPR (concat a zero half into the
- // GPRPair); RV64 has it in a GPR's low half (a plain zext.w).
- if (!Subtarget.is64Bit())
- return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Sub,
- DAG.getConstant(0, DL, Sub.getSimpleValueType()));
- return widenPackedVectorWithZeros(DAG, DL, Sub, VT);
-}
-
// If we're concatenating a series of vector loads like
// concat_vectors (load v4i8, p+0), (load v4i8, p+n), (load v4i8, p+n*2) ...
// Then we can turn this into a strided load by widening the vector elements
@@ -23123,10 +23128,6 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
if (SDValue V = performBUILD_VECTORCombine(N, DAG, Subtarget, *this))
return V;
break;
- case ISD::INSERT_SUBVECTOR:
- if (SDValue V = performINSERT_SUBVECTORCombine(N, DAG, Subtarget))
- return V;
- break;
case ISD::CONCAT_VECTORS:
if (SDValue V = performCONCAT_VECTORSCombine(N, DAG, Subtarget, *this))
return V;
diff --git a/llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll b/llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll
index d993c163acecb..3beb2d4007b0c 100644
--- a/llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll
@@ -29,17 +29,3 @@ define <4 x i16> @insert_zero_v2i16(<2 x i16> %v) {
%r = call <4 x i16> @llvm.vector.insert.v4i16.v2i16(<4 x i16> zeroinitializer, <2 x i16> %v, i64 0)
ret <4 x i16> %r
}
-
-define <2 x i32> @insert_zero_v1i32(<1 x i32> %v) {
-; RV32-LABEL: insert_zero_v1i32:
-; RV32: # %bb.0:
-; RV32-NEXT: li a1, 0
-; RV32-NEXT: ret
-;
-; RV64-LABEL: insert_zero_v1i32:
-; RV64: # %bb.0:
-; RV64-NEXT: zext.w a0, a0
-; RV64-NEXT: ret
- %r = call <2 x i32> @llvm.vector.insert.v2i32.v1i32(<2 x i32> zeroinitializer, <1 x i32> %v, i64 0)
- ret <2 x i32> %r
-}
>From c59b917a650d4291ffcaf63df3253201e2a94ee8 Mon Sep 17 00:00:00 2001
From: SiHuaN <liyongtai at iscas.ac.cn>
Date: Tue, 14 Jul 2026 10:14:04 +0000
Subject: [PATCH 3/3] [RISCV] Add v2i32 INSERT_SUBVECTOR test coverage
---
llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll b/llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll
index 3beb2d4007b0c..07a54badc04e9 100644
--- a/llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-insert-subvector.ll
@@ -29,3 +29,17 @@ define <4 x i16> @insert_zero_v2i16(<2 x i16> %v) {
%r = call <4 x i16> @llvm.vector.insert.v4i16.v2i16(<4 x i16> zeroinitializer, <2 x i16> %v, i64 0)
ret <4 x i16> %r
}
+
+define <2 x i32> @insert_zero_v1i32(<1 x i32> %v) {
+; RV32-LABEL: insert_zero_v1i32:
+; RV32: # %bb.0:
+; RV32-NEXT: li a1, 0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: insert_zero_v1i32:
+; RV64: # %bb.0:
+; RV64-NEXT: pack a0, a0, zero
+; RV64-NEXT: ret
+ %r = call <2 x i32> @llvm.vector.insert.v2i32.v1i32(<2 x i32> zeroinitializer, <1 x i32> %v, i64 0)
+ ret <2 x i32> %r
+}
More information about the llvm-commits
mailing list