[llvm] [RISCV] Add further constraints on vsetvli intrinsics range (PR #219417)
Luke Lau via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 28 02:35:59 PDT 2026
https://github.com/lukel97 updated https://github.com/llvm/llvm-project/pull/219417
>From f29494ceedb8047d5d10804122336878960eee20 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Fri, 28 Aug 2026 16:38:21 +0800
Subject: [PATCH 1/2] [RISCV] Add further constraints on vsetvli intrinsics
range
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The spec also mandates:
- `ceil(AVL / 2) ≤ vl ≤ VLMAX if AVL < (2 * VLMAX)`
- `vl = VLMAX if AVL ≥ (2 * VLMAX)`
This also reworks the constraints to be based on ConstantRange so `vl = AVL if AVL ≤ VLMAX` is no longer restricted to constants.
---
.../Target/RISCV/RISCVTargetTransformInfo.cpp | 40 +++++++++++++------
.../InstCombine/RISCV/riscv-vsetvli-range.ll | 19 +++++----
2 files changed, 39 insertions(+), 20 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
index f51e47895c4bb..55129d1e87dfc 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
@@ -3786,21 +3786,35 @@ RISCVTTIImpl::instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const {
// only the VLMAX upper bound is sound.
ConstantRange VLRange = VLMAXRange;
if (HasAVL) {
- APInt MaxVL = VLMAXRange.getUnsignedMax();
+ // vl ≤ VLMAX
+ VLRange =
+ ConstantRange::makeAllowedICmpRegion(CmpInst::ICMP_ULE, VLMAXRange);
+
Value *AVL = II.getArgOperand(0);
+ ConstantRange AVLRange =
+ computeConstantRangeIncludingKnownBits(AVL, false, DL);
+
+ // vl = AVL if AVL ≤ VLMAX
+ if (AVLRange.icmp(CmpInst::ICMP_ULE, VLMAXRange))
+ return IC.replaceInstUsesWith(II, AVL);
+
+ // vl ≤ AVL
+ VLRange = VLRange.umin(AVLRange.getUnsignedMax());
+
// vl > 0 if AVL > 0
- APInt MinVL = APInt(BitWidth, isKnownNonZero(AVL, DL) ? 1 : 0);
- if (auto *AVLC = dyn_cast<ConstantInt>(AVL)) {
- const APInt &C = AVLC->getValue();
- // A constant AVL not exceeding the smallest possible VLMAX means vl is
- // exactly AVL, so replace the intrinsic with that constant.
- if (C.ule(VLMAXRange.getUnsignedMin()))
- return IC.replaceInstUsesWith(II, ConstantInt::get(II.getType(), C));
- VLRange =
- ConstantRange::getNonEmpty(MinVL, APIntOps::umin(C, MaxVL) + 1);
- } else {
- VLRange = ConstantRange::getNonEmpty(MinVL, MaxVL + 1);
- }
+ if (AVLRange.icmp(CmpInst::ICMP_UGT, APInt::getZero(BitWidth)))
+ VLRange = VLRange.umax(APInt(BitWidth, 1));
+
+ // vl = VLMAX if AVL ≥ (2 * VLMAX)
+ ConstantRange TwoVLMAX = VLMAXRange.multiply(APInt(BitWidth, 2));
+ if (AVLRange.icmp(CmpInst::ICMP_UGE, TwoVLMAX))
+ VLRange = VLRange.intersectWith(VLMAXRange);
+
+ // ceil(AVL / 2) ≤ vl ≤ VLMAX if AVL < (2 * VLMAX)
+ if (AVLRange.icmp(CmpInst::ICMP_ULT, TwoVLMAX))
+ VLRange = VLRange.umax(APIntOps::RoundingUDiv(AVLRange.getUnsignedMin(),
+ APInt(BitWidth, 2),
+ APInt::Rounding::UP));
}
ConstantRange OldRange =
diff --git a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-range.ll b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-range.ll
index 837ae6a9eb702..63e6c40cbf4b4 100644
--- a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-range.ll
+++ b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-range.ll
@@ -34,11 +34,11 @@ define i64 @vsetvli_const_avl_at_min128() {
}
; AVL == 20 sits in (MinVLMAX, ...) at VLEN128, so vl is only known to be
-; [0, 20]; at VLEN512 it is still below VLMAX (64), so vl == 20 folds.
+; [10, 20]; at VLEN512 it is still below VLMAX (64), so vl == 20 folds.
define i64 @vsetvli_const_avl_mid() {
; VLEN128-LABEL: define i64 @vsetvli_const_avl_mid(
; VLEN128-SAME: ) #[[ATTR0]] {
-; VLEN128-NEXT: [[VL:%.*]] = call range(i64 1, 21) i64 @llvm.riscv.vsetvli.i64(i64 20, i64 0, i64 0)
+; VLEN128-NEXT: [[VL:%.*]] = call range(i64 10, 21) i64 @llvm.riscv.vsetvli.i64(i64 20, i64 0, i64 0)
; VLEN128-NEXT: ret i64 [[VL]]
;
; VLEN512-LABEL: define i64 @vsetvli_const_avl_mid(
@@ -50,12 +50,17 @@ define i64 @vsetvli_const_avl_mid() {
}
; AVL far above the largest VLMAX (8192): vl is capped by VLMAX, giving the
-; VLEN-independent range [0, 8192].
+; VLEN-independent range [MinVLMAX, 8192].
define i64 @vsetvli_const_avl_above_max() {
-; CHECK-LABEL: define i64 @vsetvli_const_avl_above_max(
-; CHECK-SAME: ) #[[ATTR0]] {
-; CHECK-NEXT: [[VL:%.*]] = call range(i64 1, 8193) i64 @llvm.riscv.vsetvli.i64(i64 100000, i64 0, i64 0)
-; CHECK-NEXT: ret i64 [[VL]]
+; VLEN128-LABEL: define i64 @vsetvli_const_avl_above_max(
+; VLEN128-SAME: ) #[[ATTR0]] {
+; VLEN128-NEXT: [[VL:%.*]] = call range(i64 16, 8193) i64 @llvm.riscv.vsetvli.i64(i64 100000, i64 0, i64 0)
+; VLEN128-NEXT: ret i64 [[VL]]
+;
+; VLEN512-LABEL: define i64 @vsetvli_const_avl_above_max(
+; VLEN512-SAME: ) #[[ATTR0]] {
+; VLEN512-NEXT: [[VL:%.*]] = call range(i64 64, 8193) i64 @llvm.riscv.vsetvli.i64(i64 100000, i64 0, i64 0)
+; VLEN512-NEXT: ret i64 [[VL]]
;
%vl = call i64 @llvm.riscv.vsetvli.i64(i64 100000, i64 0, i64 0)
ret i64 %vl
>From b2aa3232cd18df332dda92a200a2f68f0cf6aaf6 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Fri, 28 Aug 2026 17:35:09 +0800
Subject: [PATCH 2/2] Pass full simplifyquery, add a test for a non-constant
avl <= vlmax
---
llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp | 4 ++--
.../InstCombine/RISCV/riscv-vsetvli-range.ll | 14 +++++++++++++-
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
index 55129d1e87dfc..902cf875de1df 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
@@ -3791,8 +3791,8 @@ RISCVTTIImpl::instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const {
ConstantRange::makeAllowedICmpRegion(CmpInst::ICMP_ULE, VLMAXRange);
Value *AVL = II.getArgOperand(0);
- ConstantRange AVLRange =
- computeConstantRangeIncludingKnownBits(AVL, false, DL);
+ ConstantRange AVLRange = computeConstantRangeIncludingKnownBits(
+ AVL, false, IC.getSimplifyQuery().getWithInstruction(&II));
// vl = AVL if AVL ≤ VLMAX
if (AVLRange.icmp(CmpInst::ICMP_ULE, VLMAXRange))
diff --git a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-range.ll b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-range.ll
index 63e6c40cbf4b4..f74ec414077ab 100644
--- a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-range.ll
+++ b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-range.ll
@@ -129,7 +129,7 @@ define i1 @vsetvli_runtime_avl_gt_max_folds(i64 %avl) {
ret i1 %c
}
-; vl known > 0, so range must be > 0
+; avl known > 0, so range must be > 0
define i64 @vsetvli_vl_known_nonzero(i64 %x) {
; CHECK-LABEL: define i64 @vsetvli_vl_known_nonzero(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
@@ -141,3 +141,15 @@ define i64 @vsetvli_vl_known_nonzero(i64 %x) {
%vl = call i64 @llvm.riscv.vsetvli.i64(i64 %avl, i64 0, i64 0)
ret i64 %vl
}
+
+; avl known <= vlmax, so vl = avl
+define i64 @vsetvli_avl_known_lt_vlmax(i64 %x) {
+; CHECK-LABEL: define i64 @vsetvli_avl_known_lt_vlmax(
+; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[VL:%.*]] = and i64 [[X]], 7
+; CHECK-NEXT: ret i64 [[VL]]
+;
+ %avl = and i64 %x, 7
+ %vl = call i64 @llvm.riscv.vsetvli.i64(i64 %avl, i64 0, i64 0)
+ ret i64 %vl
+}
More information about the llvm-commits
mailing list