[llvm] [RISCV] Reduce minimum VL needed for vslidedown.vx in RISCVVLOptimizer (PR #168392)
Luke Lau via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 17 22:09:18 PST 2025
https://github.com/lukel97 updated https://github.com/llvm/llvm-project/pull/168392
>From a64b52e483a2b28f420eafa055e98703f57a0cb2 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Mon, 17 Nov 2025 20:25:23 +0800
Subject: [PATCH 1/3] Precommit tests
---
.../test/CodeGen/RISCV/rvv/vl-opt-live-out.ll | 47 +++++++++++++++++++
llvm/test/CodeGen/RISCV/rvv/vl-opt.mir | 18 +++++++
2 files changed, 65 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/rvv/vl-opt-live-out.ll
diff --git a/llvm/test/CodeGen/RISCV/rvv/vl-opt-live-out.ll b/llvm/test/CodeGen/RISCV/rvv/vl-opt-live-out.ll
new file mode 100644
index 0000000000000..6e40e15bea426
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/vl-opt-live-out.ll
@@ -0,0 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv64 -mattr=+v -verify-machineinstrs < %s | FileCheck %s
+
+define i32 @loop_live_out(ptr %p, i64 %n) {
+; CHECK-LABEL: loop_live_out:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: mv a2, a0
+; CHECK-NEXT: .LBB0_1: # %loop
+; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT: mv a4, a1
+; CHECK-NEXT: vsetvli a3, a1, e8, mf2, ta, ma
+; CHECK-NEXT: vle32.v v8, (a2)
+; CHECK-NEXT: sub a1, a1, a3
+; CHECK-NEXT: vsetvli a5, zero, e32, m2, ta, ma
+; CHECK-NEXT: vadd.vi v8, v8, 1
+; CHECK-NEXT: vsetvli zero, a4, e32, m2, ta, ma
+; CHECK-NEXT: vse32.v v8, (a2)
+; CHECK-NEXT: slli a2, a3, 2
+; CHECK-NEXT: add a2, a0, a2
+; CHECK-NEXT: bnez a1, .LBB0_1
+; CHECK-NEXT: # %bb.2: # %exit
+; CHECK-NEXT: addi a3, a3, -1
+; CHECK-NEXT: vsetivli zero, 1, e32, m2, ta, ma
+; CHECK-NEXT: vslidedown.vx v8, v8, a3
+; CHECK-NEXT: vmv.x.s a0, v8
+; CHECK-NEXT: ret
+entry:
+ br label %loop
+
+loop:
+ %avl = phi i64 [%n, %entry], [%avl.next, %loop]
+ %gep = phi ptr [%p, %entry], [%gep.next, %loop]
+ %vl = call i32 @llvm.experimental.get.vector.length(i64 %avl, i32 4, i1 true)
+ %x = call <vscale x 4 x i32> @llvm.vp.load(ptr %gep, <vscale x 4 x i1> splat (i1 true), i32 %vl)
+ %y = add <vscale x 4 x i32> %x, splat (i32 1)
+ call void @llvm.vp.store(<vscale x 4 x i32> %y, ptr %gep, <vscale x 4 x i1> splat (i1 true), i32 %vl)
+ %vl.zext = zext i32 %vl to i64
+ %avl.next = sub i64 %avl, %vl.zext
+ %gep.next = getelementptr i32, ptr %p, i32 %vl
+ %ec = icmp eq i64 %avl.next, 0
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ %lastidx = sub i64 %vl.zext, 1
+ %lastelt = extractelement <vscale x 4 x i32> %y, i64 %lastidx
+ ret i32 %lastelt
+}
diff --git a/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir b/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir
index 4d6d0e122b1cf..6b053d5650a8d 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir
+++ b/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir
@@ -778,3 +778,21 @@ body: |
; CHECK: DBG_VALUE %0:vr
DBG_VALUE %0:vr
...
+---
+name: vslidedown_vx
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x8
+ ; CHECK-LABEL: name: vslidedown_vx
+ ; CHECK: liveins: $x8
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %x:gpr = COPY $x8
+ ; CHECK-NEXT: %y:gprnox0 = ADDI %x, -1
+ ; CHECK-NEXT: %v:vr = PseudoVADD_VV_M1 $noreg, $noreg, $noreg, -1, 5 /* e32 */, 0 /* tu, mu */
+ ; CHECK-NEXT: %w:vr = PseudoVSLIDEDOWN_VX_M1 $noreg, %v, %y, 1, 5 /* e32 */, 0 /* tu, mu */
+ %x:gpr = COPY $x8
+ %y:gprnox0 = ADDI %x, -1
+ %v:vr = PseudoVADD_VV_M1 $noreg, $noreg, $noreg, -1, 5 /* e32 */, 0 /* tu, mu */
+ %w:vr = PseudoVSLIDEDOWN_VX_M1 $noreg, %v, %y, 1, 5 /* e32 */, 0 /* tu, mu */
+...
>From ce03066e2abb0a7f5fc050bf2da7cb177cbc1538 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Mon, 17 Nov 2025 22:49:47 +0800
Subject: [PATCH 2/3] [RISCV] Reduce minimum VL needed for vslidedown.vx in
RISCVVLOptimizer
---
llvm/lib/Target/RISCV/RISCVVLOptimizer.cpp | 41 ++++++++++++++++++-
.../test/CodeGen/RISCV/rvv/vl-opt-live-out.ll | 5 +--
llvm/test/CodeGen/RISCV/rvv/vl-opt.mir | 4 +-
3 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVVLOptimizer.cpp b/llvm/lib/Target/RISCV/RISCVVLOptimizer.cpp
index 0a8838cbd45c7..5011b178a5770 100644
--- a/llvm/lib/Target/RISCV/RISCVVLOptimizer.cpp
+++ b/llvm/lib/Target/RISCV/RISCVVLOptimizer.cpp
@@ -62,7 +62,7 @@ struct DemandedVL {
};
class RISCVVLOptimizer : public MachineFunctionPass {
- const MachineRegisterInfo *MRI;
+ MachineRegisterInfo *MRI;
const MachineDominatorTree *MDT;
const TargetInstrInfo *TII;
@@ -1392,6 +1392,41 @@ bool RISCVVLOptimizer::isCandidate(const MachineInstr &MI) const {
return true;
}
+/// Given a vslidedown.vx like:
+///
+/// %slideamt = ADDI %x, -1
+/// %v = PseudoVSLIDEDOWN_VX %passthru, %src, %slideamt, avl=1
+///
+/// %v will only read the first %slideamt + 1 lanes of %src, which = %x.
+/// This is a common case when lowering extractelement.
+///
+/// Note that if %x is 0, %slideamt will be all ones. In this case %src will be
+/// completely slid down and none of its lanes will be read (since %slideamt is
+/// greater than the largest VLMAX of 65536) so we can demand any minimum VL.
+static std::optional<DemandedVL>
+getMinimumVLForVSLIDEDOWN_VX(const MachineOperand &UserOp,
+ const MachineRegisterInfo *MRI) {
+ const MachineInstr &MI = *UserOp.getParent();
+ if (RISCV::getRVVMCOpcode(MI.getOpcode()) != RISCV::VSLIDEDOWN_VX)
+ return std::nullopt;
+ // We're looking at what lanes are used from the src operand.
+ if (UserOp.getOperandNo() != 2)
+ return std::nullopt;
+ // For now, the AVL must be 1.
+ const MachineOperand &AVL = MI.getOperand(4);
+ if (!AVL.isImm() || AVL.getImm() != 1)
+ return std::nullopt;
+ // The slide amount must be %x - 1.
+ const MachineOperand &SlideAmt = MI.getOperand(3);
+ if (!SlideAmt.getReg().isVirtual())
+ return std::nullopt;
+ MachineInstr *SlideAmtDef = MRI->getUniqueVRegDef(SlideAmt.getReg());
+ if (SlideAmtDef->getOpcode() != RISCV::ADDI ||
+ SlideAmtDef->getOperand(2).getImm() != -AVL.getImm())
+ return std::nullopt;
+ return SlideAmtDef->getOperand(1);
+}
+
DemandedVL
RISCVVLOptimizer::getMinimumVLForUser(const MachineOperand &UserOp) const {
const MachineInstr &UserMI = *UserOp.getParent();
@@ -1406,6 +1441,9 @@ RISCVVLOptimizer::getMinimumVLForUser(const MachineOperand &UserOp) const {
return DemandedVL::vlmax();
}
+ if (auto VL = getMinimumVLForVSLIDEDOWN_VX(UserOp, MRI))
+ return *VL;
+
if (RISCVII::readsPastVL(
TII->get(RISCV::getRVVMCOpcode(UserMI.getOpcode())).TSFlags)) {
LLVM_DEBUG(dbgs() << " Abort because used by unsafe instruction\n");
@@ -1624,6 +1662,7 @@ bool RISCVVLOptimizer::tryReduceVL(MachineInstr &MI) const {
// All our checks passed. We can reduce VL.
VLOp.ChangeToRegister(CommonVL->getReg(), false);
+ MRI->constrainRegClass(CommonVL->getReg(), &RISCV::GPRNoX0RegClass);
return true;
}
diff --git a/llvm/test/CodeGen/RISCV/rvv/vl-opt-live-out.ll b/llvm/test/CodeGen/RISCV/rvv/vl-opt-live-out.ll
index 6e40e15bea426..cf15fad5533b9 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vl-opt-live-out.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vl-opt-live-out.ll
@@ -7,13 +7,10 @@ define i32 @loop_live_out(ptr %p, i64 %n) {
; CHECK-NEXT: mv a2, a0
; CHECK-NEXT: .LBB0_1: # %loop
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
-; CHECK-NEXT: mv a4, a1
-; CHECK-NEXT: vsetvli a3, a1, e8, mf2, ta, ma
+; CHECK-NEXT: vsetvli a3, a1, e32, m2, ta, ma
; CHECK-NEXT: vle32.v v8, (a2)
; CHECK-NEXT: sub a1, a1, a3
-; CHECK-NEXT: vsetvli a5, zero, e32, m2, ta, ma
; CHECK-NEXT: vadd.vi v8, v8, 1
-; CHECK-NEXT: vsetvli zero, a4, e32, m2, ta, ma
; CHECK-NEXT: vse32.v v8, (a2)
; CHECK-NEXT: slli a2, a3, 2
; CHECK-NEXT: add a2, a0, a2
diff --git a/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir b/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir
index 6b053d5650a8d..ddd23f3d575d8 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir
+++ b/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir
@@ -787,9 +787,9 @@ body: |
; CHECK-LABEL: name: vslidedown_vx
; CHECK: liveins: $x8
; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: %x:gpr = COPY $x8
+ ; CHECK-NEXT: %x:gprnox0 = COPY $x8
; CHECK-NEXT: %y:gprnox0 = ADDI %x, -1
- ; CHECK-NEXT: %v:vr = PseudoVADD_VV_M1 $noreg, $noreg, $noreg, -1, 5 /* e32 */, 0 /* tu, mu */
+ ; CHECK-NEXT: %v:vr = PseudoVADD_VV_M1 $noreg, $noreg, $noreg, %x, 5 /* e32 */, 0 /* tu, mu */
; CHECK-NEXT: %w:vr = PseudoVSLIDEDOWN_VX_M1 $noreg, %v, %y, 1, 5 /* e32 */, 0 /* tu, mu */
%x:gpr = COPY $x8
%y:gprnox0 = ADDI %x, -1
>From 0fa31a4a358c034c7b2c3bff0a241c64ede5b541 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Tue, 18 Nov 2025 02:42:05 +0800
Subject: [PATCH 3/3] Ignore LIs
---
llvm/lib/Target/RISCV/RISCVVLOptimizer.cpp | 3 ++-
llvm/test/CodeGen/RISCV/rvv/vl-opt.mir | 17 +++++++++++++++++
2 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/RISCV/RISCVVLOptimizer.cpp b/llvm/lib/Target/RISCV/RISCVVLOptimizer.cpp
index 5011b178a5770..c742b92416362 100644
--- a/llvm/lib/Target/RISCV/RISCVVLOptimizer.cpp
+++ b/llvm/lib/Target/RISCV/RISCVVLOptimizer.cpp
@@ -1422,7 +1422,8 @@ getMinimumVLForVSLIDEDOWN_VX(const MachineOperand &UserOp,
return std::nullopt;
MachineInstr *SlideAmtDef = MRI->getUniqueVRegDef(SlideAmt.getReg());
if (SlideAmtDef->getOpcode() != RISCV::ADDI ||
- SlideAmtDef->getOperand(2).getImm() != -AVL.getImm())
+ SlideAmtDef->getOperand(2).getImm() != -AVL.getImm() ||
+ !SlideAmtDef->getOperand(1).getReg().isVirtual())
return std::nullopt;
return SlideAmtDef->getOperand(1);
}
diff --git a/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir b/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir
index ddd23f3d575d8..55d1c84d5f8d3 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir
+++ b/llvm/test/CodeGen/RISCV/rvv/vl-opt.mir
@@ -796,3 +796,20 @@ body: |
%v:vr = PseudoVADD_VV_M1 $noreg, $noreg, $noreg, -1, 5 /* e32 */, 0 /* tu, mu */
%w:vr = PseudoVSLIDEDOWN_VX_M1 $noreg, %v, %y, 1, 5 /* e32 */, 0 /* tu, mu */
...
+---
+# Make sure we ignore LIs (ADDI $x0, -1)
+name: vslidedown_vx_li
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x8
+ ; CHECK-LABEL: name: vslidedown_vx_li
+ ; CHECK: liveins: $x8
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %y:gprnox0 = ADDI $x0, -1
+ ; CHECK-NEXT: %v:vr = PseudoVADD_VV_M1 $noreg, $noreg, $noreg, -1, 5 /* e32 */, 0 /* tu, mu */
+ ; CHECK-NEXT: %w:vr = PseudoVSLIDEDOWN_VX_M1 $noreg, %v, %y, 1, 5 /* e32 */, 0 /* tu, mu */
+ %y:gprnox0 = ADDI $x0, -1
+ %v:vr = PseudoVADD_VV_M1 $noreg, $noreg, $noreg, -1, 5 /* e32 */, 0 /* tu, mu */
+ %w:vr = PseudoVSLIDEDOWN_VX_M1 $noreg, %v, %y, 1, 5 /* e32 */, 0 /* tu, mu */
+...
More information about the llvm-commits
mailing list