Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21834,6 +21834,11 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
return N->getOperand(0);
break;
}
case RISCVISD::VSLIDEDOWN_VL:
case RISCVISD::VSLIDEUP_VL:
if (N->getOperand(1)->isUndef())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work with isPoison? isUndef returns true for poison and for undef, but we only tested poison.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

independent from what we test: I think this transformation still holds for undef, right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's valid for undef.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we add an undef test then the undef detector linter will complain.

For the use case in the loop vectorizer just handling poison is fine if we want to avoid isUndef. Are we moving away from it in SelectionDAG?

Copy link
Collaborator

@topperc topperc Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SelectionDAG support for poison is still in an early stage I think. It probably converts ISD::POISON to ISD::UNDEF in many cases still. I wouldn't be surprised if the vector was ISD::UNDEF by the time it gets here. Especially for the fixed vector case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, just want to check then should we add a test case with undef anyway?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please ignore the linter.

return N->getOperand(0);
break;
case RISCVISD::VSLIDE1UP_VL:
case RISCVISD::VFSLIDE1UP_VL: {
using namespace SDPatternMatch;
Expand Down
91 changes: 91 additions & 0 deletions llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vector-splice.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc -mtriple riscv32 -mattr=+v < %s | FileCheck %s
; RUN: llc -mtriple riscv64 -mattr=+v < %s | FileCheck %s
; RUN: llc -mtriple riscv32 -mattr=+v,+vl-dependent-latency < %s | FileCheck %s
; RUN: llc -mtriple riscv64 -mattr=+v,+vl-dependent-latency < %s | FileCheck %s

define <4 x i32> @splice_v4i32_slidedown(<4 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: splice_v4i32_slidedown:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vrgather.vi v9, v8, 3
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OT: We should probably be preferring vslidedown.vi for case where we have a single element in the resulting shuffle mask. vrgather.vi forces the use of an extra register where vslidedown.vi doesn't. (This only works for vslidedown, vslideup does have the register constraint.)

; CHECK-NEXT: vmv.v.v v8, v9
; CHECK-NEXT: ret
%res = call <4 x i32> @llvm.vector.splice(<4 x i32> %a, <4 x i32> poison, i32 3)
ret <4 x i32> %res
}

define <4 x i32> @splice_4i32_slideup(<4 x i32> %a) {
; CHECK-LABEL: splice_4i32_slideup:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vrgather.vi v9, v8, 0
; CHECK-NEXT: vmv.v.v v8, v9
; CHECK-NEXT: ret
%res = call <4 x i32> @llvm.vector.splice(<4 x i32> poison, <4 x i32> %a, i32 -3)
ret <4 x i32> %res
}

define <8 x i32> @splice_v8i32_slidedown(<8 x i32> %a, <8 x i32> %b) {
; CHECK-LABEL: splice_v8i32_slidedown:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 8, e32, m2, ta, ma
; CHECK-NEXT: vslidedown.vi v8, v8, 3
; CHECK-NEXT: ret
%res = call <8 x i32> @llvm.vector.splice(<8 x i32> %a, <8 x i32> poison, i32 3)
ret <8 x i32> %res
}

define <8 x i32> @splice_v8i32_slideup(<8 x i32> %a) {
; CHECK-LABEL: splice_v8i32_slideup:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 8, e32, m2, ta, ma
; CHECK-NEXT: vslideup.vi v10, v8, 3
; CHECK-NEXT: vmv.v.v v8, v10
; CHECK-NEXT: ret
%res = call <8 x i32> @llvm.vector.splice(<8 x i32> poison, <8 x i32> %a, i32 -3)
ret <8 x i32> %res
}

define <4 x i32> @splice_v4i32_slidedown_undef(<4 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: splice_v4i32_slidedown_undef:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vrgather.vi v9, v8, 3
; CHECK-NEXT: vmv.v.v v8, v9
; CHECK-NEXT: ret
%res = call <4 x i32> @llvm.vector.splice(<4 x i32> %a, <4 x i32> undef, i32 3)
ret <4 x i32> %res
}

define <4 x i32> @splice_4i32_slideup_undef(<4 x i32> %a) {
; CHECK-LABEL: splice_4i32_slideup_undef:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vrgather.vi v9, v8, 0
; CHECK-NEXT: vmv.v.v v8, v9
; CHECK-NEXT: ret
%res = call <4 x i32> @llvm.vector.splice(<4 x i32> undef, <4 x i32> %a, i32 -3)
ret <4 x i32> %res
}

define <8 x i32> @splice_v8i32_slidedown_undef(<8 x i32> %a, <8 x i32> %b) {
; CHECK-LABEL: splice_v8i32_slidedown_undef:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 8, e32, m2, ta, ma
; CHECK-NEXT: vslidedown.vi v8, v8, 3
; CHECK-NEXT: ret
%res = call <8 x i32> @llvm.vector.splice(<8 x i32> %a, <8 x i32> undef, i32 3)
ret <8 x i32> %res
}

define <8 x i32> @splice_v8i32_slideup_undef(<8 x i32> %a) {
; CHECK-LABEL: splice_v8i32_slideup_undef:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 8, e32, m2, ta, ma
; CHECK-NEXT: vslideup.vi v10, v8, 3
; CHECK-NEXT: vmv.v.v v8, v10
; CHECK-NEXT: ret
%res = call <8 x i32> @llvm.vector.splice(<8 x i32> undef, <8 x i32> %a, i32 -3)
ret <8 x i32> %res
}
60 changes: 60 additions & 0 deletions llvm/test/CodeGen/RISCV/rvv/vector-splice.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4247,4 +4247,64 @@ define <vscale x 8 x double> @splice_nxv8f64_offset_max(<vscale x 8 x double> %a
ret <vscale x 8 x double> %res
}

define <vscale x 2 x i32> @splice_nxv2i32_slidedown(<vscale x 2 x i32> %a) #0 {
; NOVLDEP-LABEL: splice_nxv2i32_slidedown:
; NOVLDEP: # %bb.0:
; NOVLDEP-NEXT: vsetvli a0, zero, e32, m1, ta, ma
; NOVLDEP-NEXT: vslidedown.vi v8, v8, 3
; NOVLDEP-NEXT: ret
;
; VLDEP-LABEL: splice_nxv2i32_slidedown:
; VLDEP: # %bb.0:
; VLDEP-NEXT: csrr a0, vlenb
; VLDEP-NEXT: srli a0, a0, 2
; VLDEP-NEXT: addi a0, a0, -3
; VLDEP-NEXT: vsetvli zero, a0, e32, m1, ta, ma
; VLDEP-NEXT: vslidedown.vi v8, v8, 3
; VLDEP-NEXT: ret
%res = call <vscale x 2 x i32> @llvm.vector.splice(<vscale x 2 x i32> %a, <vscale x 2 x i32> poison, i32 3)
ret <vscale x 2 x i32> %res
}

define <vscale x 2 x i32> @splice_nxv2i32_slideup(<vscale x 2 x i32> %a) #0 {
; CHECK-LABEL: splice_nxv2i32_slideup:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetvli a0, zero, e32, m1, ta, ma
; CHECK-NEXT: vslideup.vi v9, v8, 3
; CHECK-NEXT: vmv.v.v v8, v9
; CHECK-NEXT: ret
%res = call <vscale x 2 x i32> @llvm.vector.splice(<vscale x 2 x i32> poison, <vscale x 2 x i32> %a, i32 -3)
ret <vscale x 2 x i32> %res
}

define <vscale x 2 x i32> @splice_nxv2i32_slidedown_undef(<vscale x 2 x i32> %a) #0 {
; NOVLDEP-LABEL: splice_nxv2i32_slidedown_undef:
; NOVLDEP: # %bb.0:
; NOVLDEP-NEXT: vsetvli a0, zero, e32, m1, ta, ma
; NOVLDEP-NEXT: vslidedown.vi v8, v8, 3
; NOVLDEP-NEXT: ret
;
; VLDEP-LABEL: splice_nxv2i32_slidedown_undef:
; VLDEP: # %bb.0:
; VLDEP-NEXT: csrr a0, vlenb
; VLDEP-NEXT: srli a0, a0, 2
; VLDEP-NEXT: addi a0, a0, -3
; VLDEP-NEXT: vsetvli zero, a0, e32, m1, ta, ma
; VLDEP-NEXT: vslidedown.vi v8, v8, 3
; VLDEP-NEXT: ret
%res = call <vscale x 2 x i32> @llvm.vector.splice(<vscale x 2 x i32> %a, <vscale x 2 x i32> undef, i32 3)
ret <vscale x 2 x i32> %res
}

define <vscale x 2 x i32> @splice_nxv2i32_slideup_undef(<vscale x 2 x i32> %a) #0 {
; CHECK-LABEL: splice_nxv2i32_slideup_undef:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetvli a0, zero, e32, m1, ta, ma
; CHECK-NEXT: vslideup.vi v9, v8, 3
; CHECK-NEXT: vmv.v.v v8, v9
; CHECK-NEXT: ret
%res = call <vscale x 2 x i32> @llvm.vector.splice(<vscale x 2 x i32> undef, <vscale x 2 x i32> %a, i32 -3)
ret <vscale x 2 x i32> %res
}

attributes #0 = { vscale_range(2,0) }
Loading