[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