[llvm] [RISCV][IA] Use strided load for one active deinterleaveN(load) (PR #148892)
Philip Reames via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 15 10:05:37 PDT 2025
https://github.com/preames updated https://github.com/llvm/llvm-project/pull/148892
>From 64f5e2da64e1351f633d3ac57abeb5c13734c5e3 Mon Sep 17 00:00:00 2001
From: Philip Reames <preames at rivosinc.com>
Date: Mon, 14 Jul 2025 19:10:15 -0700
Subject: [PATCH 1/2] [RISCV][IA] Use strided load for one active
deinterleaveN(load)
This adds the analogous handling we use for the shuffle lowering to the
deinterleaveN intrinsic path.
---
.../Target/RISCV/RISCVInterleavedAccess.cpp | 33 ++++++++++++++++---
.../RISCV/rvv/vector-deinterleave-load.ll | 11 ++++---
2 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVInterleavedAccess.cpp b/llvm/lib/Target/RISCV/RISCVInterleavedAccess.cpp
index 39603b92cc2f7..947f1cd5e48e7 100644
--- a/llvm/lib/Target/RISCV/RISCVInterleavedAccess.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInterleavedAccess.cpp
@@ -243,20 +243,43 @@ bool RISCVTargetLowering::lowerDeinterleaveIntrinsicToLoad(
assert(LI->isSimple());
IRBuilder<> Builder(LI);
- Value *FirstActive =
- *llvm::find_if(DeinterleaveValues, [](Value *V) { return V != nullptr; });
- VectorType *ResVTy = cast<VectorType>(FirstActive->getType());
+ auto FirstActiveItr =
+ llvm::find_if(DeinterleaveValues, [](Value *V) { return V != nullptr; });
+ VectorType *ResVTy = cast<VectorType>((*FirstActiveItr)->getType());
const DataLayout &DL = LI->getDataLayout();
-
if (!isLegalInterleavedAccessType(ResVTy, Factor, LI->getAlign(),
LI->getPointerAddressSpace(), DL))
return false;
- Value *Return;
Type *PtrTy = LI->getPointerOperandType();
Type *XLenTy = Type::getIntNTy(LI->getContext(), Subtarget.getXLen());
+ // If the segment load is going to be performed segment at a time anyways
+ // and there's only one element used, use a strided load instead. This
+ // will be equally fast, and create less vector register pressure.
+ if (!Subtarget.hasOptimizedSegmentLoadStore(Factor) &&
+ 1 == llvm::count_if(DeinterleaveValues,
+ [](Value *V) { return V != nullptr; })) {
+ unsigned Idx = std::distance(DeinterleaveValues.begin(), FirstActiveItr);
+ unsigned ScalarSizeInBytes = DL.getTypeStoreSize(ResVTy->getElementType());
+ Value *Stride = ConstantInt::get(XLenTy, Factor * ScalarSizeInBytes);
+ Value *Offset = ConstantInt::get(XLenTy, Idx * ScalarSizeInBytes);
+ Value *BasePtr = Builder.CreatePtrAdd(LI->getPointerOperand(), Offset);
+ Value *Mask = Builder.getAllOnesMask(ResVTy->getElementCount());
+ Type *I32 = Type::getIntNTy(LI->getContext(), 32);
+ Value *VL = Builder.CreateElementCount(I32, ResVTy->getElementCount());
+
+ CallInst *CI =
+ Builder.CreateIntrinsic(Intrinsic::experimental_vp_strided_load,
+ {ResVTy, BasePtr->getType(), Stride->getType()},
+ {BasePtr, Stride, Mask, VL});
+ Align A = commonAlignment(LI->getAlign(), Idx * ScalarSizeInBytes);
+ CI->addParamAttr(0, Attribute::getWithAlignment(CI->getContext(), A));
+ (*FirstActiveItr)->replaceAllUsesWith(CI);
+ return true;
+ }
+
if (isa<FixedVectorType>(ResVTy)) {
Value *VL = Builder.CreateElementCount(XLenTy, ResVTy->getElementCount());
Value *Mask = Builder.getAllOnesMask(ResVTy->getElementCount());
diff --git a/llvm/test/CodeGen/RISCV/rvv/vector-deinterleave-load.ll b/llvm/test/CodeGen/RISCV/rvv/vector-deinterleave-load.ll
index 9af92aa995f1f..e28428224c2ec 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vector-deinterleave-load.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vector-deinterleave-load.ll
@@ -407,8 +407,9 @@ define { <vscale x 8 x i8>, <vscale x 8 x i8>, <vscale x 8 x i8>, <vscale x 8 x
define <vscale x 8 x i8> @vector_deinterleave_load_factor4_oneactive(ptr %p) {
; CHECK-LABEL: vector_deinterleave_load_factor4_oneactive:
; CHECK: # %bb.0:
-; CHECK-NEXT: vsetvli a1, zero, e8, m1, ta, ma
-; CHECK-NEXT: vlseg4e8.v v8, (a0)
+; CHECK-NEXT: li a1, 4
+; CHECK-NEXT: vsetvli a2, zero, e8, m1, ta, ma
+; CHECK-NEXT: vlse8.v v8, (a0), a1
; CHECK-NEXT: ret
%vec = load <vscale x 32 x i8>, ptr %p
%d0 = call { <vscale x 8 x i8>, <vscale x 8 x i8>, <vscale x 8 x i8>, <vscale x 8 x i8> } @llvm.vector.deinterleave4(<vscale x 32 x i8> %vec)
@@ -419,8 +420,10 @@ define <vscale x 8 x i8> @vector_deinterleave_load_factor4_oneactive(ptr %p) {
define <vscale x 8 x i8> @vector_deinterleave_load_factor4_oneactive2(ptr %p) {
; CHECK-LABEL: vector_deinterleave_load_factor4_oneactive2:
; CHECK: # %bb.0:
-; CHECK-NEXT: vsetvli a1, zero, e8, m1, ta, ma
-; CHECK-NEXT: vlseg4e8.v v5, (a0)
+; CHECK-NEXT: addi a0, a0, 3
+; CHECK-NEXT: li a1, 4
+; CHECK-NEXT: vsetvli a2, zero, e8, m1, ta, ma
+; CHECK-NEXT: vlse8.v v8, (a0), a1
; CHECK-NEXT: ret
%vec = load <vscale x 32 x i8>, ptr %p
%d0 = call { <vscale x 8 x i8>, <vscale x 8 x i8>, <vscale x 8 x i8>, <vscale x 8 x i8> } @llvm.vector.deinterleave4(<vscale x 32 x i8> %vec)
>From c8fba49addd6fd4329fc37f81077882e67beb7a0 Mon Sep 17 00:00:00 2001
From: Philip Reames <preames at rivosinc.com>
Date: Tue, 15 Jul 2025 10:05:26 -0700
Subject: [PATCH 2/2] Missing from last commit
---
llvm/lib/Target/RISCV/RISCVInterleavedAccess.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/lib/Target/RISCV/RISCVInterleavedAccess.cpp b/llvm/lib/Target/RISCV/RISCVInterleavedAccess.cpp
index 947f1cd5e48e7..7dac87b07e990 100644
--- a/llvm/lib/Target/RISCV/RISCVInterleavedAccess.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInterleavedAccess.cpp
@@ -280,6 +280,7 @@ bool RISCVTargetLowering::lowerDeinterleaveIntrinsicToLoad(
return true;
}
+ Value *Return;
if (isa<FixedVectorType>(ResVTy)) {
Value *VL = Builder.CreateElementCount(XLenTy, ResVTy->getElementCount());
Value *Mask = Builder.getAllOnesMask(ResVTy->getElementCount());
More information about the llvm-commits
mailing list