[llvm] acfd1da - [RISCV] Add further constraints on vsetvli intrinsics range (#219417)

via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 30 21:07:56 PDT 2026


Author: Luke Lau
Date: 2026-08-31T04:07:51Z
New Revision: acfd1da182f4794a782d629698d8fd3a4fdc0f7d

URL: https://github.com/llvm/llvm-project/commit/acfd1da182f4794a782d629698d8fd3a4fdc0f7d
DIFF: https://github.com/llvm/llvm-project/commit/acfd1da182f4794a782d629698d8fd3a4fdc0f7d.diff

LOG: [RISCV] Add further constraints on vsetvli intrinsics range (#219417)

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.

Added: 
    

Modified: 
    llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
    llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-range.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
index f51e47895c4bb..cd14ff3d2dded 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
@@ -3786,21 +3786,36 @@ 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, /*ForSigned=*/false,
+          IC.getSimplifyQuery().getWithInstruction(&II));
+
+      // 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..f74ec414077ab 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
@@ -124,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]] {
@@ -136,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