[llvm] [DAGCombiner] Fold min/max vscale, C -> C (PR #174708)

Luke Lau via llvm-commits llvm-commits at lists.llvm.org
Sat Jan 10 00:06:34 PST 2026


https://github.com/lukel97 updated https://github.com/llvm/llvm-project/pull/174708

>From c4e467032ffc81aab2f842c5a2ff3f57d70b59db Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Wed, 7 Jan 2026 12:40:51 +0800
Subject: [PATCH 1/4] Precommit tests

---
 .../AArch64/named-vector-shuffles-sve.ll      |   4 +-
 llvm/test/CodeGen/RISCV/rvv/rvv-vscale.i64.ll | 238 ++++++++++++++++++
 2 files changed, 240 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/named-vector-shuffles-sve.ll b/llvm/test/CodeGen/AArch64/named-vector-shuffles-sve.ll
index 2aef74a91c056..930f40dcfb0ec 100644
--- a/llvm/test/CodeGen/AArch64/named-vector-shuffles-sve.ll
+++ b/llvm/test/CodeGen/AArch64/named-vector-shuffles-sve.ll
@@ -459,7 +459,7 @@ define <vscale x 2 x i8> @splice_nxv2i8_idx(<vscale x 2 x i8> %a, <vscale x 2 x
 }
 
 ; Verify splitvec type legalisation works as expected.
-define <vscale x 8 x i32> @splice_nxv8i32_idx(<vscale x 8 x i32> %a, <vscale x 8 x i32> %b) #0 {
+define <vscale x 8 x i32> @splice_nxv8i32_idx(<vscale x 8 x i32> %a, <vscale x 8 x i32> %b) vscale_range(1,16) #0 {
 ; CHECK-LABEL: splice_nxv8i32_idx:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    str x29, [sp, #-16]! // 8-byte Folded Spill
@@ -1057,7 +1057,7 @@ define <vscale x 2 x i8> @splice_nxv2i8(<vscale x 2 x i8> %a, <vscale x 2 x i8>
 }
 
 ; Verify splitvec type legalisation works as expected.
-define <vscale x 8 x i32> @splice_nxv8i32(<vscale x 8 x i32> %a, <vscale x 8 x i32> %b) #0 {
+define <vscale x 8 x i32> @splice_nxv8i32(<vscale x 8 x i32> %a, <vscale x 8 x i32> %b) vscale_range(1,16) #0 {
 ; CHECK-LABEL: splice_nxv8i32:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    str x29, [sp, #-16]! // 8-byte Folded Spill
diff --git a/llvm/test/CodeGen/RISCV/rvv/rvv-vscale.i64.ll b/llvm/test/CodeGen/RISCV/rvv/rvv-vscale.i64.ll
index 6b8822d998344..67ebda76de50d 100644
--- a/llvm/test/CodeGen/RISCV/rvv/rvv-vscale.i64.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/rvv-vscale.i64.ll
@@ -199,3 +199,241 @@ entry:
   ret i64 %1
 }
 
+define i64 @vscale_umin() vscale_range(4,1024) nounwind {
+; RV64-VLENUNK-LABEL: vscale_umin:
+; RV64-VLENUNK:       # %bb.0: # %entry
+; RV64-VLENUNK-NEXT:    csrr a0, vlenb
+; RV64-VLENUNK-NEXT:    srli a0, a0, 1
+; RV64-VLENUNK-NEXT:    li a1, 4
+; RV64-VLENUNK-NEXT:    bltu a0, a1, .LBB7_2
+; RV64-VLENUNK-NEXT:  # %bb.1: # %entry
+; RV64-VLENUNK-NEXT:    li a0, 4
+; RV64-VLENUNK-NEXT:  .LBB7_2: # %entry
+; RV64-VLENUNK-NEXT:    ret
+;
+; RV32-LABEL: vscale_umin:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    csrr a0, vlenb
+; RV32-NEXT:    srli a0, a0, 1
+; RV32-NEXT:    li a1, 4
+; RV32-NEXT:    bltu a0, a1, .LBB7_2
+; RV32-NEXT:  # %bb.1: # %entry
+; RV32-NEXT:    li a0, 4
+; RV32-NEXT:  .LBB7_2: # %entry
+; RV32-NEXT:    li a1, 0
+; RV32-NEXT:    ret
+;
+; RV64-VLEN256MIN-LABEL: vscale_umin:
+; RV64-VLEN256MIN:       # %bb.0: # %entry
+; RV64-VLEN256MIN-NEXT:    csrr a0, vlenb
+; RV64-VLEN256MIN-NEXT:    srli a0, a0, 1
+; RV64-VLEN256MIN-NEXT:    li a1, 4
+; RV64-VLEN256MIN-NEXT:    bltu a0, a1, .LBB7_2
+; RV64-VLEN256MIN-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256MIN-NEXT:    li a0, 4
+; RV64-VLEN256MIN-NEXT:  .LBB7_2: # %entry
+; RV64-VLEN256MIN-NEXT:    ret
+;
+; RV64-VLEN256MAX-LABEL: vscale_umin:
+; RV64-VLEN256MAX:       # %bb.0: # %entry
+; RV64-VLEN256MAX-NEXT:    li a0, 16
+; RV64-VLEN256MAX-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256MAX-NEXT:    li a0, 4
+; RV64-VLEN256MAX-NEXT:  # %bb.2: # %entry
+; RV64-VLEN256MAX-NEXT:    ret
+;
+; RV64-VLEN256EXACT-LABEL: vscale_umin:
+; RV64-VLEN256EXACT:       # %bb.0: # %entry
+; RV64-VLEN256EXACT-NEXT:    li a0, 16
+; RV64-VLEN256EXACT-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256EXACT-NEXT:    li a0, 4
+; RV64-VLEN256EXACT-NEXT:  # %bb.2: # %entry
+; RV64-VLEN256EXACT-NEXT:    ret
+entry:
+  %0 = call i64 @llvm.vscale.i64()
+  %1 = mul i64 %0, 4
+  %2 = call i64 @llvm.umin(i64 %1, i64 4)
+  ret i64 %2
+}
+
+
+define i64 @vscale_umax() vscale_range(4,1024) nounwind {
+; RV64-VLENUNK-LABEL: vscale_umax:
+; RV64-VLENUNK:       # %bb.0: # %entry
+; RV64-VLENUNK-NEXT:    csrr a0, vlenb
+; RV64-VLENUNK-NEXT:    srli a0, a0, 1
+; RV64-VLENUNK-NEXT:    lui a1, 1
+; RV64-VLENUNK-NEXT:    bltu a1, a0, .LBB8_2
+; RV64-VLENUNK-NEXT:  # %bb.1: # %entry
+; RV64-VLENUNK-NEXT:    lui a0, 1
+; RV64-VLENUNK-NEXT:  .LBB8_2: # %entry
+; RV64-VLENUNK-NEXT:    ret
+;
+; RV32-LABEL: vscale_umax:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    csrr a0, vlenb
+; RV32-NEXT:    srli a0, a0, 1
+; RV32-NEXT:    lui a1, 1
+; RV32-NEXT:    bltu a1, a0, .LBB8_2
+; RV32-NEXT:  # %bb.1: # %entry
+; RV32-NEXT:    lui a0, 1
+; RV32-NEXT:  .LBB8_2: # %entry
+; RV32-NEXT:    li a1, 0
+; RV32-NEXT:    ret
+;
+; RV64-VLEN256MIN-LABEL: vscale_umax:
+; RV64-VLEN256MIN:       # %bb.0: # %entry
+; RV64-VLEN256MIN-NEXT:    csrr a0, vlenb
+; RV64-VLEN256MIN-NEXT:    srli a0, a0, 1
+; RV64-VLEN256MIN-NEXT:    lui a1, 1
+; RV64-VLEN256MIN-NEXT:    bltu a1, a0, .LBB8_2
+; RV64-VLEN256MIN-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256MIN-NEXT:    lui a0, 1
+; RV64-VLEN256MIN-NEXT:  .LBB8_2: # %entry
+; RV64-VLEN256MIN-NEXT:    ret
+;
+; RV64-VLEN256MAX-LABEL: vscale_umax:
+; RV64-VLEN256MAX:       # %bb.0: # %entry
+; RV64-VLEN256MAX-NEXT:    li a0, 16
+; RV64-VLEN256MAX-NEXT:    lui a1, 1
+; RV64-VLEN256MAX-NEXT:    bltu a1, a0, .LBB8_2
+; RV64-VLEN256MAX-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256MAX-NEXT:    lui a0, 1
+; RV64-VLEN256MAX-NEXT:  .LBB8_2: # %entry
+; RV64-VLEN256MAX-NEXT:    ret
+;
+; RV64-VLEN256EXACT-LABEL: vscale_umax:
+; RV64-VLEN256EXACT:       # %bb.0: # %entry
+; RV64-VLEN256EXACT-NEXT:    li a0, 16
+; RV64-VLEN256EXACT-NEXT:    lui a1, 1
+; RV64-VLEN256EXACT-NEXT:    bltu a1, a0, .LBB8_2
+; RV64-VLEN256EXACT-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256EXACT-NEXT:    lui a0, 1
+; RV64-VLEN256EXACT-NEXT:  .LBB8_2: # %entry
+; RV64-VLEN256EXACT-NEXT:    ret
+entry:
+  %0 = call i64 @llvm.vscale.i64()
+  %1 = mul i64 %0, 4
+  %2 = call i64 @llvm.umax(i64 %1, i64 4096)
+  ret i64 %2
+}
+
+
+define i64 @vscale_smin() vscale_range(4,1024) nounwind {
+; RV64-VLENUNK-LABEL: vscale_smin:
+; RV64-VLENUNK:       # %bb.0: # %entry
+; RV64-VLENUNK-NEXT:    csrr a0, vlenb
+; RV64-VLENUNK-NEXT:    srli a0, a0, 1
+; RV64-VLENUNK-NEXT:    li a1, 4
+; RV64-VLENUNK-NEXT:    blt a0, a1, .LBB9_2
+; RV64-VLENUNK-NEXT:  # %bb.1: # %entry
+; RV64-VLENUNK-NEXT:    li a0, 4
+; RV64-VLENUNK-NEXT:  .LBB9_2: # %entry
+; RV64-VLENUNK-NEXT:    ret
+;
+; RV32-LABEL: vscale_smin:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    csrr a0, vlenb
+; RV32-NEXT:    srli a0, a0, 1
+; RV32-NEXT:    li a1, 4
+; RV32-NEXT:    blt a0, a1, .LBB9_2
+; RV32-NEXT:  # %bb.1: # %entry
+; RV32-NEXT:    li a0, 4
+; RV32-NEXT:  .LBB9_2: # %entry
+; RV32-NEXT:    li a1, 0
+; RV32-NEXT:    ret
+;
+; RV64-VLEN256MIN-LABEL: vscale_smin:
+; RV64-VLEN256MIN:       # %bb.0: # %entry
+; RV64-VLEN256MIN-NEXT:    csrr a0, vlenb
+; RV64-VLEN256MIN-NEXT:    srli a0, a0, 1
+; RV64-VLEN256MIN-NEXT:    li a1, 4
+; RV64-VLEN256MIN-NEXT:    blt a0, a1, .LBB9_2
+; RV64-VLEN256MIN-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256MIN-NEXT:    li a0, 4
+; RV64-VLEN256MIN-NEXT:  .LBB9_2: # %entry
+; RV64-VLEN256MIN-NEXT:    ret
+;
+; RV64-VLEN256MAX-LABEL: vscale_smin:
+; RV64-VLEN256MAX:       # %bb.0: # %entry
+; RV64-VLEN256MAX-NEXT:    li a0, 16
+; RV64-VLEN256MAX-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256MAX-NEXT:    li a0, 4
+; RV64-VLEN256MAX-NEXT:  # %bb.2: # %entry
+; RV64-VLEN256MAX-NEXT:    ret
+;
+; RV64-VLEN256EXACT-LABEL: vscale_smin:
+; RV64-VLEN256EXACT:       # %bb.0: # %entry
+; RV64-VLEN256EXACT-NEXT:    li a0, 16
+; RV64-VLEN256EXACT-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256EXACT-NEXT:    li a0, 4
+; RV64-VLEN256EXACT-NEXT:  # %bb.2: # %entry
+; RV64-VLEN256EXACT-NEXT:    ret
+entry:
+  %0 = call i64 @llvm.vscale.i64()
+  %1 = mul i64 %0, 4
+  %2 = call i64 @llvm.smin(i64 %1, i64 4)
+  ret i64 %2
+}
+
+
+define i64 @vscale_smax() vscale_range(4,1024) nounwind {
+; RV64-VLENUNK-LABEL: vscale_smax:
+; RV64-VLENUNK:       # %bb.0: # %entry
+; RV64-VLENUNK-NEXT:    csrr a0, vlenb
+; RV64-VLENUNK-NEXT:    srli a0, a0, 1
+; RV64-VLENUNK-NEXT:    lui a1, 1
+; RV64-VLENUNK-NEXT:    blt a1, a0, .LBB10_2
+; RV64-VLENUNK-NEXT:  # %bb.1: # %entry
+; RV64-VLENUNK-NEXT:    lui a0, 1
+; RV64-VLENUNK-NEXT:  .LBB10_2: # %entry
+; RV64-VLENUNK-NEXT:    ret
+;
+; RV32-LABEL: vscale_smax:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    csrr a0, vlenb
+; RV32-NEXT:    srli a0, a0, 1
+; RV32-NEXT:    lui a1, 1
+; RV32-NEXT:    blt a1, a0, .LBB10_2
+; RV32-NEXT:  # %bb.1: # %entry
+; RV32-NEXT:    lui a0, 1
+; RV32-NEXT:  .LBB10_2: # %entry
+; RV32-NEXT:    li a1, 0
+; RV32-NEXT:    ret
+;
+; RV64-VLEN256MIN-LABEL: vscale_smax:
+; RV64-VLEN256MIN:       # %bb.0: # %entry
+; RV64-VLEN256MIN-NEXT:    csrr a0, vlenb
+; RV64-VLEN256MIN-NEXT:    srli a0, a0, 1
+; RV64-VLEN256MIN-NEXT:    lui a1, 1
+; RV64-VLEN256MIN-NEXT:    blt a1, a0, .LBB10_2
+; RV64-VLEN256MIN-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256MIN-NEXT:    lui a0, 1
+; RV64-VLEN256MIN-NEXT:  .LBB10_2: # %entry
+; RV64-VLEN256MIN-NEXT:    ret
+;
+; RV64-VLEN256MAX-LABEL: vscale_smax:
+; RV64-VLEN256MAX:       # %bb.0: # %entry
+; RV64-VLEN256MAX-NEXT:    li a0, 16
+; RV64-VLEN256MAX-NEXT:    lui a1, 1
+; RV64-VLEN256MAX-NEXT:    blt a1, a0, .LBB10_2
+; RV64-VLEN256MAX-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256MAX-NEXT:    lui a0, 1
+; RV64-VLEN256MAX-NEXT:  .LBB10_2: # %entry
+; RV64-VLEN256MAX-NEXT:    ret
+;
+; RV64-VLEN256EXACT-LABEL: vscale_smax:
+; RV64-VLEN256EXACT:       # %bb.0: # %entry
+; RV64-VLEN256EXACT-NEXT:    li a0, 16
+; RV64-VLEN256EXACT-NEXT:    lui a1, 1
+; RV64-VLEN256EXACT-NEXT:    blt a1, a0, .LBB10_2
+; RV64-VLEN256EXACT-NEXT:  # %bb.1: # %entry
+; RV64-VLEN256EXACT-NEXT:    lui a0, 1
+; RV64-VLEN256EXACT-NEXT:  .LBB10_2: # %entry
+; RV64-VLEN256EXACT-NEXT:    ret
+entry:
+  %0 = call i64 @llvm.vscale.i64()
+  %1 = mul i64 %0, 4
+  %2 = call i64 @llvm.smax(i64 %1, i64 4096)
+  ret i64 %2
+}

>From d9d4deed411fdbc2296c7b57156509586d537211 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Wed, 7 Jan 2026 12:44:00 +0800
Subject: [PATCH 2/4] [DAGCombiner] fold min/max vscale, c

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp |  18 ++
 .../AArch64/named-vector-shuffles-sve.ll      |  13 +-
 llvm/test/CodeGen/RISCV/rvv/rvv-vscale.i64.ll | 176 ++----------------
 3 files changed, 40 insertions(+), 167 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index ee28260a74127..589ddda71f194 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6192,6 +6192,24 @@ SDValue DAGCombiner::visitIMINMAX(SDNode *N) {
       return C0 > C1 ? N1 : N0;
   }
 
+  // If we know the range of vscale, see if we can fold it given a constant.
+  if (N0.getOpcode() == ISD::VSCALE) {
+    if (auto *C1 = dyn_cast<ConstantSDNode>(N1)) {
+      const Function &F = DAG.getMachineFunction().getFunction();
+      ConstantRange Range =
+          getVScaleRange(&F, VT.getScalarSizeInBits())
+              .multiply(ConstantRange(N0.getConstantOperandAPInt(0)));
+
+      const APInt &C1V = C1->getAPIntValue();
+      if ((Opcode == ISD::UMAX && Range.getUnsignedMax().ule(C1V)) ||
+          (Opcode == ISD::UMIN && Range.getUnsignedMin().uge(C1V)) ||
+          (Opcode == ISD::SMAX && Range.getSignedMax().sle(C1V)) ||
+          (Opcode == ISD::SMIN && Range.getSignedMin().sge(C1V))) {
+        return N1;
+      }
+    }
+  }
+
   // canonicalize constant to RHS
   if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
       !DAG.isConstantIntBuildVectorOrConstantInt(N1))
diff --git a/llvm/test/CodeGen/AArch64/named-vector-shuffles-sve.ll b/llvm/test/CodeGen/AArch64/named-vector-shuffles-sve.ll
index 930f40dcfb0ec..d702e1f9816c2 100644
--- a/llvm/test/CodeGen/AArch64/named-vector-shuffles-sve.ll
+++ b/llvm/test/CodeGen/AArch64/named-vector-shuffles-sve.ll
@@ -1088,21 +1088,20 @@ define <vscale x 16 x float> @splice_nxv16f32_neg17(<vscale x 16 x float> %a, <v
 ; CHECK-NEXT:    str x29, [sp, #-16]! // 8-byte Folded Spill
 ; CHECK-NEXT:    addvl sp, sp, #-8
 ; CHECK-NEXT:    rdvl x8, #4
-; CHECK-NEXT:    mov w9, #68 // =0x44
-; CHECK-NEXT:    mov x10, sp
-; CHECK-NEXT:    cmp x8, #68
+; CHECK-NEXT:    mov x9, sp
+; CHECK-NEXT:    ptrue p0.s
 ; CHECK-NEXT:    str z3, [sp, #3, mul vl]
-; CHECK-NEXT:    csel x9, x8, x9, lo
-; CHECK-NEXT:    add x8, x10, x8
+; CHECK-NEXT:    add x8, x9, x8
+; CHECK-NEXT:    mov x9, #-17 // =0xffffffffffffffef
 ; CHECK-NEXT:    str z2, [sp, #2, mul vl]
 ; CHECK-NEXT:    str z1, [sp, #1, mul vl]
-; CHECK-NEXT:    sub x8, x8, x9
 ; CHECK-NEXT:    str z0, [sp]
 ; CHECK-NEXT:    str z7, [sp, #7, mul vl]
 ; CHECK-NEXT:    str z4, [sp, #4, mul vl]
 ; CHECK-NEXT:    str z5, [sp, #5, mul vl]
 ; CHECK-NEXT:    str z6, [sp, #6, mul vl]
-; CHECK-NEXT:    ldr z0, [x8]
+; CHECK-NEXT:    ld1w { z0.s }, p0/z, [x8, x9, lsl #2]
+; CHECK-NEXT:    sub x8, x8, #68
 ; CHECK-NEXT:    ldr z1, [x8, #1, mul vl]
 ; CHECK-NEXT:    ldr z2, [x8, #2, mul vl]
 ; CHECK-NEXT:    ldr z3, [x8, #3, mul vl]
diff --git a/llvm/test/CodeGen/RISCV/rvv/rvv-vscale.i64.ll b/llvm/test/CodeGen/RISCV/rvv/rvv-vscale.i64.ll
index 67ebda76de50d..1c6d10c1ad013 100644
--- a/llvm/test/CodeGen/RISCV/rvv/rvv-vscale.i64.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/rvv-vscale.i64.ll
@@ -200,54 +200,20 @@ entry:
 }
 
 define i64 @vscale_umin() vscale_range(4,1024) nounwind {
-; RV64-VLENUNK-LABEL: vscale_umin:
-; RV64-VLENUNK:       # %bb.0: # %entry
-; RV64-VLENUNK-NEXT:    csrr a0, vlenb
-; RV64-VLENUNK-NEXT:    srli a0, a0, 1
-; RV64-VLENUNK-NEXT:    li a1, 4
-; RV64-VLENUNK-NEXT:    bltu a0, a1, .LBB7_2
-; RV64-VLENUNK-NEXT:  # %bb.1: # %entry
-; RV64-VLENUNK-NEXT:    li a0, 4
-; RV64-VLENUNK-NEXT:  .LBB7_2: # %entry
-; RV64-VLENUNK-NEXT:    ret
+; RV64-LABEL: vscale_umin:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    li a0, 4
+; RV64-NEXT:    ret
 ;
 ; RV32-LABEL: vscale_umin:
 ; RV32:       # %bb.0: # %entry
-; RV32-NEXT:    csrr a0, vlenb
-; RV32-NEXT:    srli a0, a0, 1
-; RV32-NEXT:    li a1, 4
-; RV32-NEXT:    bltu a0, a1, .LBB7_2
-; RV32-NEXT:  # %bb.1: # %entry
 ; RV32-NEXT:    li a0, 4
-; RV32-NEXT:  .LBB7_2: # %entry
 ; RV32-NEXT:    li a1, 0
 ; RV32-NEXT:    ret
 ;
-; RV64-VLEN256MIN-LABEL: vscale_umin:
-; RV64-VLEN256MIN:       # %bb.0: # %entry
-; RV64-VLEN256MIN-NEXT:    csrr a0, vlenb
-; RV64-VLEN256MIN-NEXT:    srli a0, a0, 1
-; RV64-VLEN256MIN-NEXT:    li a1, 4
-; RV64-VLEN256MIN-NEXT:    bltu a0, a1, .LBB7_2
-; RV64-VLEN256MIN-NEXT:  # %bb.1: # %entry
-; RV64-VLEN256MIN-NEXT:    li a0, 4
-; RV64-VLEN256MIN-NEXT:  .LBB7_2: # %entry
-; RV64-VLEN256MIN-NEXT:    ret
-;
-; RV64-VLEN256MAX-LABEL: vscale_umin:
-; RV64-VLEN256MAX:       # %bb.0: # %entry
-; RV64-VLEN256MAX-NEXT:    li a0, 16
-; RV64-VLEN256MAX-NEXT:  # %bb.1: # %entry
-; RV64-VLEN256MAX-NEXT:    li a0, 4
-; RV64-VLEN256MAX-NEXT:  # %bb.2: # %entry
-; RV64-VLEN256MAX-NEXT:    ret
-;
 ; RV64-VLEN256EXACT-LABEL: vscale_umin:
 ; RV64-VLEN256EXACT:       # %bb.0: # %entry
-; RV64-VLEN256EXACT-NEXT:    li a0, 16
-; RV64-VLEN256EXACT-NEXT:  # %bb.1: # %entry
 ; RV64-VLEN256EXACT-NEXT:    li a0, 4
-; RV64-VLEN256EXACT-NEXT:  # %bb.2: # %entry
 ; RV64-VLEN256EXACT-NEXT:    ret
 entry:
   %0 = call i64 @llvm.vscale.i64()
@@ -258,58 +224,20 @@ entry:
 
 
 define i64 @vscale_umax() vscale_range(4,1024) nounwind {
-; RV64-VLENUNK-LABEL: vscale_umax:
-; RV64-VLENUNK:       # %bb.0: # %entry
-; RV64-VLENUNK-NEXT:    csrr a0, vlenb
-; RV64-VLENUNK-NEXT:    srli a0, a0, 1
-; RV64-VLENUNK-NEXT:    lui a1, 1
-; RV64-VLENUNK-NEXT:    bltu a1, a0, .LBB8_2
-; RV64-VLENUNK-NEXT:  # %bb.1: # %entry
-; RV64-VLENUNK-NEXT:    lui a0, 1
-; RV64-VLENUNK-NEXT:  .LBB8_2: # %entry
-; RV64-VLENUNK-NEXT:    ret
+; RV64-LABEL: vscale_umax:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lui a0, 1
+; RV64-NEXT:    ret
 ;
 ; RV32-LABEL: vscale_umax:
 ; RV32:       # %bb.0: # %entry
-; RV32-NEXT:    csrr a0, vlenb
-; RV32-NEXT:    srli a0, a0, 1
-; RV32-NEXT:    lui a1, 1
-; RV32-NEXT:    bltu a1, a0, .LBB8_2
-; RV32-NEXT:  # %bb.1: # %entry
 ; RV32-NEXT:    lui a0, 1
-; RV32-NEXT:  .LBB8_2: # %entry
 ; RV32-NEXT:    li a1, 0
 ; RV32-NEXT:    ret
 ;
-; RV64-VLEN256MIN-LABEL: vscale_umax:
-; RV64-VLEN256MIN:       # %bb.0: # %entry
-; RV64-VLEN256MIN-NEXT:    csrr a0, vlenb
-; RV64-VLEN256MIN-NEXT:    srli a0, a0, 1
-; RV64-VLEN256MIN-NEXT:    lui a1, 1
-; RV64-VLEN256MIN-NEXT:    bltu a1, a0, .LBB8_2
-; RV64-VLEN256MIN-NEXT:  # %bb.1: # %entry
-; RV64-VLEN256MIN-NEXT:    lui a0, 1
-; RV64-VLEN256MIN-NEXT:  .LBB8_2: # %entry
-; RV64-VLEN256MIN-NEXT:    ret
-;
-; RV64-VLEN256MAX-LABEL: vscale_umax:
-; RV64-VLEN256MAX:       # %bb.0: # %entry
-; RV64-VLEN256MAX-NEXT:    li a0, 16
-; RV64-VLEN256MAX-NEXT:    lui a1, 1
-; RV64-VLEN256MAX-NEXT:    bltu a1, a0, .LBB8_2
-; RV64-VLEN256MAX-NEXT:  # %bb.1: # %entry
-; RV64-VLEN256MAX-NEXT:    lui a0, 1
-; RV64-VLEN256MAX-NEXT:  .LBB8_2: # %entry
-; RV64-VLEN256MAX-NEXT:    ret
-;
 ; RV64-VLEN256EXACT-LABEL: vscale_umax:
 ; RV64-VLEN256EXACT:       # %bb.0: # %entry
-; RV64-VLEN256EXACT-NEXT:    li a0, 16
-; RV64-VLEN256EXACT-NEXT:    lui a1, 1
-; RV64-VLEN256EXACT-NEXT:    bltu a1, a0, .LBB8_2
-; RV64-VLEN256EXACT-NEXT:  # %bb.1: # %entry
 ; RV64-VLEN256EXACT-NEXT:    lui a0, 1
-; RV64-VLEN256EXACT-NEXT:  .LBB8_2: # %entry
 ; RV64-VLEN256EXACT-NEXT:    ret
 entry:
   %0 = call i64 @llvm.vscale.i64()
@@ -320,54 +248,20 @@ entry:
 
 
 define i64 @vscale_smin() vscale_range(4,1024) nounwind {
-; RV64-VLENUNK-LABEL: vscale_smin:
-; RV64-VLENUNK:       # %bb.0: # %entry
-; RV64-VLENUNK-NEXT:    csrr a0, vlenb
-; RV64-VLENUNK-NEXT:    srli a0, a0, 1
-; RV64-VLENUNK-NEXT:    li a1, 4
-; RV64-VLENUNK-NEXT:    blt a0, a1, .LBB9_2
-; RV64-VLENUNK-NEXT:  # %bb.1: # %entry
-; RV64-VLENUNK-NEXT:    li a0, 4
-; RV64-VLENUNK-NEXT:  .LBB9_2: # %entry
-; RV64-VLENUNK-NEXT:    ret
+; RV64-LABEL: vscale_smin:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    li a0, 4
+; RV64-NEXT:    ret
 ;
 ; RV32-LABEL: vscale_smin:
 ; RV32:       # %bb.0: # %entry
-; RV32-NEXT:    csrr a0, vlenb
-; RV32-NEXT:    srli a0, a0, 1
-; RV32-NEXT:    li a1, 4
-; RV32-NEXT:    blt a0, a1, .LBB9_2
-; RV32-NEXT:  # %bb.1: # %entry
 ; RV32-NEXT:    li a0, 4
-; RV32-NEXT:  .LBB9_2: # %entry
 ; RV32-NEXT:    li a1, 0
 ; RV32-NEXT:    ret
 ;
-; RV64-VLEN256MIN-LABEL: vscale_smin:
-; RV64-VLEN256MIN:       # %bb.0: # %entry
-; RV64-VLEN256MIN-NEXT:    csrr a0, vlenb
-; RV64-VLEN256MIN-NEXT:    srli a0, a0, 1
-; RV64-VLEN256MIN-NEXT:    li a1, 4
-; RV64-VLEN256MIN-NEXT:    blt a0, a1, .LBB9_2
-; RV64-VLEN256MIN-NEXT:  # %bb.1: # %entry
-; RV64-VLEN256MIN-NEXT:    li a0, 4
-; RV64-VLEN256MIN-NEXT:  .LBB9_2: # %entry
-; RV64-VLEN256MIN-NEXT:    ret
-;
-; RV64-VLEN256MAX-LABEL: vscale_smin:
-; RV64-VLEN256MAX:       # %bb.0: # %entry
-; RV64-VLEN256MAX-NEXT:    li a0, 16
-; RV64-VLEN256MAX-NEXT:  # %bb.1: # %entry
-; RV64-VLEN256MAX-NEXT:    li a0, 4
-; RV64-VLEN256MAX-NEXT:  # %bb.2: # %entry
-; RV64-VLEN256MAX-NEXT:    ret
-;
 ; RV64-VLEN256EXACT-LABEL: vscale_smin:
 ; RV64-VLEN256EXACT:       # %bb.0: # %entry
-; RV64-VLEN256EXACT-NEXT:    li a0, 16
-; RV64-VLEN256EXACT-NEXT:  # %bb.1: # %entry
 ; RV64-VLEN256EXACT-NEXT:    li a0, 4
-; RV64-VLEN256EXACT-NEXT:  # %bb.2: # %entry
 ; RV64-VLEN256EXACT-NEXT:    ret
 entry:
   %0 = call i64 @llvm.vscale.i64()
@@ -378,58 +272,20 @@ entry:
 
 
 define i64 @vscale_smax() vscale_range(4,1024) nounwind {
-; RV64-VLENUNK-LABEL: vscale_smax:
-; RV64-VLENUNK:       # %bb.0: # %entry
-; RV64-VLENUNK-NEXT:    csrr a0, vlenb
-; RV64-VLENUNK-NEXT:    srli a0, a0, 1
-; RV64-VLENUNK-NEXT:    lui a1, 1
-; RV64-VLENUNK-NEXT:    blt a1, a0, .LBB10_2
-; RV64-VLENUNK-NEXT:  # %bb.1: # %entry
-; RV64-VLENUNK-NEXT:    lui a0, 1
-; RV64-VLENUNK-NEXT:  .LBB10_2: # %entry
-; RV64-VLENUNK-NEXT:    ret
+; RV64-LABEL: vscale_smax:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lui a0, 1
+; RV64-NEXT:    ret
 ;
 ; RV32-LABEL: vscale_smax:
 ; RV32:       # %bb.0: # %entry
-; RV32-NEXT:    csrr a0, vlenb
-; RV32-NEXT:    srli a0, a0, 1
-; RV32-NEXT:    lui a1, 1
-; RV32-NEXT:    blt a1, a0, .LBB10_2
-; RV32-NEXT:  # %bb.1: # %entry
 ; RV32-NEXT:    lui a0, 1
-; RV32-NEXT:  .LBB10_2: # %entry
 ; RV32-NEXT:    li a1, 0
 ; RV32-NEXT:    ret
 ;
-; RV64-VLEN256MIN-LABEL: vscale_smax:
-; RV64-VLEN256MIN:       # %bb.0: # %entry
-; RV64-VLEN256MIN-NEXT:    csrr a0, vlenb
-; RV64-VLEN256MIN-NEXT:    srli a0, a0, 1
-; RV64-VLEN256MIN-NEXT:    lui a1, 1
-; RV64-VLEN256MIN-NEXT:    blt a1, a0, .LBB10_2
-; RV64-VLEN256MIN-NEXT:  # %bb.1: # %entry
-; RV64-VLEN256MIN-NEXT:    lui a0, 1
-; RV64-VLEN256MIN-NEXT:  .LBB10_2: # %entry
-; RV64-VLEN256MIN-NEXT:    ret
-;
-; RV64-VLEN256MAX-LABEL: vscale_smax:
-; RV64-VLEN256MAX:       # %bb.0: # %entry
-; RV64-VLEN256MAX-NEXT:    li a0, 16
-; RV64-VLEN256MAX-NEXT:    lui a1, 1
-; RV64-VLEN256MAX-NEXT:    blt a1, a0, .LBB10_2
-; RV64-VLEN256MAX-NEXT:  # %bb.1: # %entry
-; RV64-VLEN256MAX-NEXT:    lui a0, 1
-; RV64-VLEN256MAX-NEXT:  .LBB10_2: # %entry
-; RV64-VLEN256MAX-NEXT:    ret
-;
 ; RV64-VLEN256EXACT-LABEL: vscale_smax:
 ; RV64-VLEN256EXACT:       # %bb.0: # %entry
-; RV64-VLEN256EXACT-NEXT:    li a0, 16
-; RV64-VLEN256EXACT-NEXT:    lui a1, 1
-; RV64-VLEN256EXACT-NEXT:    blt a1, a0, .LBB10_2
-; RV64-VLEN256EXACT-NEXT:  # %bb.1: # %entry
 ; RV64-VLEN256EXACT-NEXT:    lui a0, 1
-; RV64-VLEN256EXACT-NEXT:  .LBB10_2: # %entry
 ; RV64-VLEN256EXACT-NEXT:    ret
 entry:
   %0 = call i64 @llvm.vscale.i64()

>From 1304b246c6136c828066a397f7c7086223a7abf9 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Wed, 7 Jan 2026 18:12:33 +0800
Subject: [PATCH 3/4] Move vscale folds to end

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 56 +++++++++----------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 589ddda71f194..9f957354b3ee9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6182,34 +6182,6 @@ SDValue DAGCombiner::visitIMINMAX(SDNode *N) {
   if (N0 == N1)
     return N0;
 
-  // Fold operation with vscale operands.
-  if (N0.getOpcode() == ISD::VSCALE && N1.getOpcode() == ISD::VSCALE) {
-    uint64_t C0 = N0->getConstantOperandVal(0);
-    uint64_t C1 = N1->getConstantOperandVal(0);
-    if (Opcode == ISD::UMAX)
-      return C0 > C1 ? N0 : N1;
-    else if (Opcode == ISD::UMIN)
-      return C0 > C1 ? N1 : N0;
-  }
-
-  // If we know the range of vscale, see if we can fold it given a constant.
-  if (N0.getOpcode() == ISD::VSCALE) {
-    if (auto *C1 = dyn_cast<ConstantSDNode>(N1)) {
-      const Function &F = DAG.getMachineFunction().getFunction();
-      ConstantRange Range =
-          getVScaleRange(&F, VT.getScalarSizeInBits())
-              .multiply(ConstantRange(N0.getConstantOperandAPInt(0)));
-
-      const APInt &C1V = C1->getAPIntValue();
-      if ((Opcode == ISD::UMAX && Range.getUnsignedMax().ule(C1V)) ||
-          (Opcode == ISD::UMIN && Range.getUnsignedMin().uge(C1V)) ||
-          (Opcode == ISD::SMAX && Range.getSignedMax().sle(C1V)) ||
-          (Opcode == ISD::SMIN && Range.getSignedMin().sge(C1V))) {
-        return N1;
-      }
-    }
-  }
-
   // canonicalize constant to RHS
   if (DAG.isConstantIntBuildVectorOrConstantInt(N0) &&
       !DAG.isConstantIntBuildVectorOrConstantInt(N1))
@@ -6271,6 +6243,34 @@ SDValue DAGCombiner::visitIMINMAX(SDNode *N) {
                                         SDLoc(N), VT, N0, N1))
     return SD;
 
+  // Fold operation with vscale operands.
+  if (N0.getOpcode() == ISD::VSCALE && N1.getOpcode() == ISD::VSCALE) {
+    uint64_t C0 = N0->getConstantOperandVal(0);
+    uint64_t C1 = N1->getConstantOperandVal(0);
+    if (Opcode == ISD::UMAX)
+      return C0 > C1 ? N0 : N1;
+    else if (Opcode == ISD::UMIN)
+      return C0 > C1 ? N1 : N0;
+  }
+
+  // If we know the range of vscale, see if we can fold it given a constant.
+  if (N0.getOpcode() == ISD::VSCALE) {
+    if (auto *C1 = dyn_cast<ConstantSDNode>(N1)) {
+      const Function &F = DAG.getMachineFunction().getFunction();
+      ConstantRange Range =
+          getVScaleRange(&F, VT.getScalarSizeInBits())
+              .multiply(ConstantRange(N0.getConstantOperandAPInt(0)));
+
+      const APInt &C1V = C1->getAPIntValue();
+      if ((Opcode == ISD::UMAX && Range.getUnsignedMax().ule(C1V)) ||
+          (Opcode == ISD::UMIN && Range.getUnsignedMin().uge(C1V)) ||
+          (Opcode == ISD::SMAX && Range.getSignedMax().sle(C1V)) ||
+          (Opcode == ISD::SMIN && Range.getSignedMin().sge(C1V))) {
+        return N1;
+      }
+    }
+  }
+
   // Simplify the operands using demanded-bits information.
   if (SimplifyDemandedBits(SDValue(N, 0)))
     return SDValue(N, 0);

>From ddf062b01ba55e47d1a5d06c31aa4fd9f08432b9 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Sat, 10 Jan 2026 16:06:12 +0800
Subject: [PATCH 4/4] Add TODO for computeConstantRange

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 9f957354b3ee9..c06498d69588a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6254,6 +6254,7 @@ SDValue DAGCombiner::visitIMINMAX(SDNode *N) {
   }
 
   // If we know the range of vscale, see if we can fold it given a constant.
+  // TODO: Generalize this to other nodes by adding computeConstantRange
   if (N0.getOpcode() == ISD::VSCALE) {
     if (auto *C1 = dyn_cast<ConstantSDNode>(N1)) {
       const Function &F = DAG.getMachineFunction().getFunction();



More information about the llvm-commits mailing list