[llvm] [RISCV][P-ext] Recognize (select (X >u ((1 << C) - 1), sext(X >s -1), trunc(X)) as usati (PR #190810)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 7 12:28:24 PDT 2026


https://github.com/topperc updated https://github.com/llvm/llvm-project/pull/190810

>From 5b968ed0da64f7ec8023832b3078f96f4641d7a2 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Tue, 7 Apr 2026 08:38:33 -0700
Subject: [PATCH 1/3] Pre-commit tests

---
 llvm/test/CodeGen/RISCV/rv32p.ll | 132 +++++++++++++
 llvm/test/CodeGen/RISCV/rv64p.ll | 312 +++++++++++++++++++++++++++++++
 2 files changed, 444 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 99bd1f7fd31e2..0e510efac0776 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -1795,3 +1795,135 @@ entry:
   %3 = or i32 %1, %2
   ret i32 %3
 }
+
+; Test USATI select patterns.
+define i4 @usati_i4_from_i32(i32 %x) {
+; CHECK-LABEL: usati_i4_from_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, 15
+; CHECK-NEXT:    bgeu a1, a0, .LBB143_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 31
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB143_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i32 %x, 15
+  %cmp2 = icmp sgt i32 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i4
+  %trunc = trunc i32 %x to i4
+  %sel = select i1 %cmp1, i4 %cmp2.ext, i4 %trunc
+  ret i4 %sel
+}
+
+define i8 @usati_i8_from_i32(i32 %x) {
+; CHECK-LABEL: usati_i8_from_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, 255
+; CHECK-NEXT:    bgeu a1, a0, .LBB144_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 31
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB144_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i32 %x, 255
+  %cmp2 = icmp sgt i32 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i8
+  %trunc = trunc i32 %x to i8
+  %sel = select i1 %cmp1, i8 %cmp2.ext, i8 %trunc
+  ret i8 %sel
+}
+
+define i12 @usati_i12_from_i32(i32 %x) {
+; CHECK-LABEL: usati_i12_from_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srli a1, a0, 12
+; CHECK-NEXT:    beqz a1, .LBB145_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 31
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB145_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i32 %x, 4095
+  %cmp2 = icmp sgt i32 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i12
+  %trunc = trunc i32 %x to i12
+  %sel = select i1 %cmp1, i12 %cmp2.ext, i12 %trunc
+  ret i12 %sel
+}
+
+define i16 @usati_i16_from_i32(i32 %x) {
+; CHECK-LABEL: usati_i16_from_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srli a1, a0, 16
+; CHECK-NEXT:    beqz a1, .LBB146_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 31
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB146_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i32 %x, 65535
+  %cmp2 = icmp sgt i32 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i16
+  %trunc = trunc i32 %x to i16
+  %sel = select i1 %cmp1, i16 %cmp2.ext, i16 %trunc
+  ret i16 %sel
+}
+
+define i24 @usati_i24_from_i32(i32 %x) {
+; CHECK-LABEL: usati_i24_from_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srli a1, a0, 24
+; CHECK-NEXT:    beqz a1, .LBB147_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 31
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB147_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i32 %x, 16777215
+  %cmp2 = icmp sgt i32 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i24
+  %trunc = trunc i32 %x to i24
+  %sel = select i1 %cmp1, i24 %cmp2.ext, i24 %trunc
+  ret i24 %sel
+}
+
+; Test USATI with non-XLen source types (now supported by looking through truncates)
+define i4 @usati_i4_from_i8(i8 %x) {
+; CHECK-LABEL: usati_i4_from_i8:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    zext.b a1, a0
+; CHECK-NEXT:    li a2, 15
+; CHECK-NEXT:    bgeu a2, a1, .LBB148_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    slli a0, a0, 24
+; CHECK-NEXT:    srli a0, a0, 31
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB148_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i8 %x, 15
+  %cmp2 = icmp sgt i8 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i4
+  %trunc = trunc i8 %x to i4
+  %sel = select i1 %cmp1, i4 %cmp2.ext, i4 %trunc
+  ret i4 %sel
+}
+
+define i8 @usati_i8_from_i16(i16 %x) {
+; CHECK-LABEL: usati_i8_from_i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    zext.h a1, a0
+; CHECK-NEXT:    li a2, 255
+; CHECK-NEXT:    bgeu a2, a1, .LBB149_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    slli a0, a0, 16
+; CHECK-NEXT:    srli a0, a0, 31
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB149_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i16 %x, 255
+  %cmp2 = icmp sgt i16 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i8
+  %trunc = trunc i16 %x to i8
+  %sel = select i1 %cmp1, i8 %cmp2.ext, i8 %trunc
+  ret i8 %sel
+}
diff --git a/llvm/test/CodeGen/RISCV/rv64p.ll b/llvm/test/CodeGen/RISCV/rv64p.ll
index a05e454a1b5dd..468f6deb85c39 100644
--- a/llvm/test/CodeGen/RISCV/rv64p.ll
+++ b/llvm/test/CodeGen/RISCV/rv64p.ll
@@ -1032,6 +1032,318 @@ entry:
   ret i64 %3
 }
 
+; Test USATI select patterns
+define i3 @usati_i3_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i3_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, 7
+; CHECK-NEXT:    bgeu a1, a0, .LBB87_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB87_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 7
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i3
+  %trunc = trunc i64 %x to i3
+  %sel = select i1 %cmp1, i3 %cmp2.ext, i3 %trunc
+  ret i3 %sel
+}
+
+define i5 @usati_i5_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i5_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, 31
+; CHECK-NEXT:    bgeu a1, a0, .LBB88_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB88_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 31
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i5
+  %trunc = trunc i64 %x to i5
+  %sel = select i1 %cmp1, i5 %cmp2.ext, i5 %trunc
+  ret i5 %sel
+}
+
+define i7 @usati_i7_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i7_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, 127
+; CHECK-NEXT:    bgeu a1, a0, .LBB89_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB89_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 127
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i7
+  %trunc = trunc i64 %x to i7
+  %sel = select i1 %cmp1, i7 %cmp2.ext, i7 %trunc
+  ret i7 %sel
+}
+
+define i8 @usati_i8_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i8_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, 255
+; CHECK-NEXT:    bgeu a1, a0, .LBB90_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB90_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 255
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i8
+  %trunc = trunc i64 %x to i8
+  %sel = select i1 %cmp1, i8 %cmp2.ext, i8 %trunc
+  ret i8 %sel
+}
+
+define i10 @usati_i10_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i10_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, 1023
+; CHECK-NEXT:    bgeu a1, a0, .LBB91_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB91_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 1023
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i10
+  %trunc = trunc i64 %x to i10
+  %sel = select i1 %cmp1, i10 %cmp2.ext, i10 %trunc
+  ret i10 %sel
+}
+
+define i16 @usati_i16_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i16_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srli a1, a0, 16
+; CHECK-NEXT:    beqz a1, .LBB92_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB92_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 65535
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i16
+  %trunc = trunc i64 %x to i16
+  %sel = select i1 %cmp1, i16 %cmp2.ext, i16 %trunc
+  ret i16 %sel
+}
+
+define i20 @usati_i20_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i20_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srli a1, a0, 20
+; CHECK-NEXT:    beqz a1, .LBB93_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB93_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 1048575
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i20
+  %trunc = trunc i64 %x to i20
+  %sel = select i1 %cmp1, i20 %cmp2.ext, i20 %trunc
+  ret i20 %sel
+}
+
+define i32 @usati_i32_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i32_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srli a1, a0, 32
+; CHECK-NEXT:    beqz a1, .LBB94_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB94_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 4294967295
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i32
+  %trunc = trunc i64 %x to i32
+  %sel = select i1 %cmp1, i32 %cmp2.ext, i32 %trunc
+  ret i32 %sel
+}
+
+define i40 @usati_i40_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i40_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srli a1, a0, 40
+; CHECK-NEXT:    beqz a1, .LBB95_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB95_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 1099511627775
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i40
+  %trunc = trunc i64 %x to i40
+  %sel = select i1 %cmp1, i40 %cmp2.ext, i40 %trunc
+  ret i40 %sel
+}
+
+define i48 @usati_i48_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i48_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srli a1, a0, 48
+; CHECK-NEXT:    beqz a1, .LBB96_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB96_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 281474976710655
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i48
+  %trunc = trunc i64 %x to i48
+  %sel = select i1 %cmp1, i48 %cmp2.ext, i48 %trunc
+  ret i48 %sel
+}
+
+define i56 @usati_i56_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i56_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srli a1, a0, 56
+; CHECK-NEXT:    beqz a1, .LBB97_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB97_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 72057594037927935
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i56
+  %trunc = trunc i64 %x to i56
+  %sel = select i1 %cmp1, i56 %cmp2.ext, i56 %trunc
+  ret i56 %sel
+}
+
+define i63 @usati_i63_from_i64(i64 %x) {
+; CHECK-LABEL: usati_i63_from_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    bgez a0, .LBB98_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB98_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i64 %x, 9223372036854775807
+  %cmp2 = icmp sgt i64 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i63
+  %trunc = trunc i64 %x to i63
+  %sel = select i1 %cmp1, i63 %cmp2.ext, i63 %trunc
+  ret i63 %sel
+}
+
+; Test USATI with non-XLen source types (now supported by looking through truncates)
+define i8 @usati_i8_from_i16(i16 %x) {
+; CHECK-LABEL: usati_i8_from_i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    zext.h a1, a0
+; CHECK-NEXT:    li a2, 255
+; CHECK-NEXT:    bgeu a2, a1, .LBB99_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    slli a0, a0, 48
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB99_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i16 %x, 255
+  %cmp2 = icmp sgt i16 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i8
+  %trunc = trunc i16 %x to i8
+  %sel = select i1 %cmp1, i8 %cmp2.ext, i8 %trunc
+  ret i8 %sel
+}
+
+define i8 @usati_i8_from_i32(i32 %x) {
+; CHECK-LABEL: usati_i8_from_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    sext.w a1, a0
+; CHECK-NEXT:    li a2, 255
+; CHECK-NEXT:    bgeu a2, a1, .LBB100_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srliw a0, a0, 31
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB100_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i32 %x, 255
+  %cmp2 = icmp sgt i32 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i8
+  %trunc = trunc i32 %x to i8
+  %sel = select i1 %cmp1, i8 %cmp2.ext, i8 %trunc
+  ret i8 %sel
+}
+
+define i16 @usati_i16_from_i32(i32 %x) {
+; CHECK-LABEL: usati_i16_from_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srliw a1, a0, 16
+; CHECK-NEXT:    beqz a1, .LBB101_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srliw a0, a0, 31
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB101_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i32 %x, 65535
+  %cmp2 = icmp sgt i32 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i16
+  %trunc = trunc i32 %x to i16
+  %sel = select i1 %cmp1, i16 %cmp2.ext, i16 %trunc
+  ret i16 %sel
+}
+
+define i16 @usati_i16_from_i48(i48 %x) {
+; CHECK-LABEL: usati_i16_from_i48:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    slli a1, a0, 16
+; CHECK-NEXT:    srli a2, a1, 32
+; CHECK-NEXT:    beqz a2, .LBB102_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a1, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB102_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i48 %x, 65535
+  %cmp2 = icmp sgt i48 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i16
+  %trunc = trunc i48 %x to i16
+  %sel = select i1 %cmp1, i16 %cmp2.ext, i16 %trunc
+  ret i16 %sel
+}
+
+define i32 @usati_i32_from_i48(i48 %x) {
+; CHECK-LABEL: usati_i32_from_i48:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    slli a1, a0, 16
+; CHECK-NEXT:    srli a2, a1, 48
+; CHECK-NEXT:    beqz a2, .LBB103_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srli a0, a1, 63
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:  .LBB103_2:
+; CHECK-NEXT:    ret
+  %cmp1 = icmp ugt i48 %x, 4294967295
+  %cmp2 = icmp sgt i48 %x, -1
+  %cmp2.ext = sext i1 %cmp2 to i32
+  %trunc = trunc i48 %x to i32
+  %sel = select i1 %cmp1, i32 %cmp2.ext, i32 %trunc
+  ret i32 %sel
+}
+
 define i64 @macc_w00(i64 %rd, i32 %a, i32 %b) nounwind {
 ; CHECK-LABEL: macc_w00:
 ; CHECK:       # %bb.0:

>From 887a4afa8609423850e06bc963d29fc92037988d Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Tue, 7 Apr 2026 08:55:46 -0700
Subject: [PATCH 2/3] [RISCV][P-ext] Recognize (select (X >u ((1 << C) - 1),
 sext(X >s -1), trunc(src)) as usati.

Where the result is a type with C bits. The unsigned compare on the
select treats negative values as large positive values so any value
that isn't in the range [0, (1 << C) - 1] will use the True operand
of the select. The sext(X >s -1) creates all ones for positive values
of X and 0 for negative values of X.

This pattern appears in the picojpeg workload of embench-iot with
an i8 result type.

Assisted-by: Claude Sonnet 4.5
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  66 ++++++++++
 llvm/test/CodeGen/RISCV/rv32p.ll            |  55 ++-------
 llvm/test/CodeGen/RISCV/rv64p.ll            | 130 ++++----------------
 3 files changed, 99 insertions(+), 152 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index f8200826883ef..6196e3ac1826a 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -20280,11 +20280,77 @@ static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG) {
   return DAG.getNode(ISD::ADD, DL, VT, A, NewB);
 }
 
+// Fold (iC (select (src >u ((1 << C) - 1)), sext(src >s -1), trunc(src))) to
+// USATI. This pattern saturates a signed value to an unsigned N-bit range
+// [0, 2^N-1]:
+//   - If src < 0: result = 0
+//       (via the inner comparison src > -1 = false, sext to 0)
+//   - If src > ((1 << C) - 1): result = all 1s
+//       (via sext(true) = -1 = 0xFF...)
+//   - Otherwise: result = src (via trunc(src))
+// The outer comparison is unsigned, so negative values appear as large
+// unsigned values and trigger the saturation to MaxVal path, where the
+// inner signed comparison then produces 0.
+// TODO: Support (select (src <=u ((1 << C) - 1)), trunc(src), sext(src >s -1)).
+static SDValue foldSelectToUSATI(SDNode *N, SelectionDAG &DAG,
+                                 const RISCVSubtarget &Subtarget) {
+  if (!Subtarget.hasStdExtP())
+    return SDValue();
+
+  EVT VT = N->getValueType(0);
+  MVT XLenVT = Subtarget.getXLenVT();
+
+  // Only support scalar integer types smaller than XLenVT
+  if (!VT.isScalarInteger() || VT.bitsGE(XLenVT))
+    return SDValue();
+
+  unsigned SatWidth = VT.getSizeInBits();
+  uint64_t MaxVal = (1ULL << SatWidth) - 1;
+
+  using namespace SDPatternMatch;
+
+  SDValue Src, InnerSetCC, FalseSrc;
+  if (!sd_match(N, m_Select(m_SetCC(m_Value(Src), m_SpecificInt(MaxVal),
+                                    m_SpecificCondCode(ISD::SETUGT)),
+                            m_SExt(m_Value(InnerSetCC)),
+                            m_Trunc(m_Value(FalseSrc)))))
+    return SDValue();
+
+  // Src can't be larger than XLenVT.
+  if (Src.getValueType().bitsGT(XLenVT))
+    return SDValue();
+
+  // Check inner setcc: src > -1 (signed comparison)
+  if (InnerSetCC.getValueType() != MVT::i1 ||
+      !sd_match(InnerSetCC, m_SetCC(m_Specific(Src), m_AllOnes(),
+                                    m_SpecificCondCode(ISD::SETGT))))
+    return SDValue();
+
+  // FalseSrc may have been optimized from a truncate of a truncate. There may
+  // still be a truncate on Src. Look through it so we can compare them.
+  SDValue CmpSrc = Src;
+  if (CmpSrc.getOpcode() == ISD::TRUNCATE)
+    CmpSrc = CmpSrc.getOperand(0);
+
+  if (CmpSrc != FalseSrc)
+    return SDValue();
+
+  // We found a USATI pattern.
+  SDLoc DL(N);
+  Src = DAG.getNode(ISD::SIGN_EXTEND, DL, XLenVT, Src);
+  SDValue USATI = DAG.getNode(RISCVISD::USATI, DL, XLenVT, Src,
+                              DAG.getTargetConstant(SatWidth, DL, XLenVT));
+  return DAG.getNode(ISD::TRUNCATE, DL, VT, USATI);
+}
+
 static SDValue performSELECTCombine(SDNode *N, SelectionDAG &DAG,
                                     const RISCVSubtarget &Subtarget) {
   if (SDValue Folded = foldSelectOfCTTZOrCTLZ(N, DAG))
     return Folded;
 
+  if (SDValue V = foldSelectToUSATI(N, DAG, Subtarget))
+    return V;
+
   if (SDValue V = useInversedSetcc(N, DAG, Subtarget))
     return V;
 
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 0e510efac0776..284e6a75b7be5 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -1800,12 +1800,7 @@ entry:
 define i4 @usati_i4_from_i32(i32 %x) {
 ; CHECK-LABEL: usati_i4_from_i32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 15
-; CHECK-NEXT:    bgeu a1, a0, .LBB143_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 31
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB143_2:
+; CHECK-NEXT:    usati a0, a0, 4
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i32 %x, 15
   %cmp2 = icmp sgt i32 %x, -1
@@ -1818,12 +1813,7 @@ define i4 @usati_i4_from_i32(i32 %x) {
 define i8 @usati_i8_from_i32(i32 %x) {
 ; CHECK-LABEL: usati_i8_from_i32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 255
-; CHECK-NEXT:    bgeu a1, a0, .LBB144_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 31
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB144_2:
+; CHECK-NEXT:    usati a0, a0, 8
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i32 %x, 255
   %cmp2 = icmp sgt i32 %x, -1
@@ -1836,12 +1826,7 @@ define i8 @usati_i8_from_i32(i32 %x) {
 define i12 @usati_i12_from_i32(i32 %x) {
 ; CHECK-LABEL: usati_i12_from_i32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srli a1, a0, 12
-; CHECK-NEXT:    beqz a1, .LBB145_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 31
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB145_2:
+; CHECK-NEXT:    usati a0, a0, 12
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i32 %x, 4095
   %cmp2 = icmp sgt i32 %x, -1
@@ -1854,12 +1839,7 @@ define i12 @usati_i12_from_i32(i32 %x) {
 define i16 @usati_i16_from_i32(i32 %x) {
 ; CHECK-LABEL: usati_i16_from_i32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srli a1, a0, 16
-; CHECK-NEXT:    beqz a1, .LBB146_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 31
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB146_2:
+; CHECK-NEXT:    usati a0, a0, 16
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i32 %x, 65535
   %cmp2 = icmp sgt i32 %x, -1
@@ -1872,12 +1852,7 @@ define i16 @usati_i16_from_i32(i32 %x) {
 define i24 @usati_i24_from_i32(i32 %x) {
 ; CHECK-LABEL: usati_i24_from_i32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srli a1, a0, 24
-; CHECK-NEXT:    beqz a1, .LBB147_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 31
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB147_2:
+; CHECK-NEXT:    usati a0, a0, 24
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i32 %x, 16777215
   %cmp2 = icmp sgt i32 %x, -1
@@ -1891,14 +1866,8 @@ define i24 @usati_i24_from_i32(i32 %x) {
 define i4 @usati_i4_from_i8(i8 %x) {
 ; CHECK-LABEL: usati_i4_from_i8:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    zext.b a1, a0
-; CHECK-NEXT:    li a2, 15
-; CHECK-NEXT:    bgeu a2, a1, .LBB148_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    slli a0, a0, 24
-; CHECK-NEXT:    srli a0, a0, 31
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB148_2:
+; CHECK-NEXT:    sext.b a0, a0
+; CHECK-NEXT:    usati a0, a0, 4
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i8 %x, 15
   %cmp2 = icmp sgt i8 %x, -1
@@ -1911,14 +1880,8 @@ define i4 @usati_i4_from_i8(i8 %x) {
 define i8 @usati_i8_from_i16(i16 %x) {
 ; CHECK-LABEL: usati_i8_from_i16:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    zext.h a1, a0
-; CHECK-NEXT:    li a2, 255
-; CHECK-NEXT:    bgeu a2, a1, .LBB149_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    slli a0, a0, 16
-; CHECK-NEXT:    srli a0, a0, 31
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB149_2:
+; CHECK-NEXT:    sext.h a0, a0
+; CHECK-NEXT:    usati a0, a0, 8
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i16 %x, 255
   %cmp2 = icmp sgt i16 %x, -1
diff --git a/llvm/test/CodeGen/RISCV/rv64p.ll b/llvm/test/CodeGen/RISCV/rv64p.ll
index 468f6deb85c39..0635aaed63117 100644
--- a/llvm/test/CodeGen/RISCV/rv64p.ll
+++ b/llvm/test/CodeGen/RISCV/rv64p.ll
@@ -1036,12 +1036,7 @@ entry:
 define i3 @usati_i3_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i3_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 7
-; CHECK-NEXT:    bgeu a1, a0, .LBB87_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB87_2:
+; CHECK-NEXT:    usati a0, a0, 3
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 7
   %cmp2 = icmp sgt i64 %x, -1
@@ -1054,12 +1049,7 @@ define i3 @usati_i3_from_i64(i64 %x) {
 define i5 @usati_i5_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i5_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 31
-; CHECK-NEXT:    bgeu a1, a0, .LBB88_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB88_2:
+; CHECK-NEXT:    usati a0, a0, 5
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 31
   %cmp2 = icmp sgt i64 %x, -1
@@ -1072,12 +1062,7 @@ define i5 @usati_i5_from_i64(i64 %x) {
 define i7 @usati_i7_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i7_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 127
-; CHECK-NEXT:    bgeu a1, a0, .LBB89_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB89_2:
+; CHECK-NEXT:    usati a0, a0, 7
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 127
   %cmp2 = icmp sgt i64 %x, -1
@@ -1090,12 +1075,7 @@ define i7 @usati_i7_from_i64(i64 %x) {
 define i8 @usati_i8_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i8_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 255
-; CHECK-NEXT:    bgeu a1, a0, .LBB90_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB90_2:
+; CHECK-NEXT:    usati a0, a0, 8
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 255
   %cmp2 = icmp sgt i64 %x, -1
@@ -1108,12 +1088,7 @@ define i8 @usati_i8_from_i64(i64 %x) {
 define i10 @usati_i10_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i10_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 1023
-; CHECK-NEXT:    bgeu a1, a0, .LBB91_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB91_2:
+; CHECK-NEXT:    usati a0, a0, 10
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 1023
   %cmp2 = icmp sgt i64 %x, -1
@@ -1126,12 +1101,7 @@ define i10 @usati_i10_from_i64(i64 %x) {
 define i16 @usati_i16_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i16_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srli a1, a0, 16
-; CHECK-NEXT:    beqz a1, .LBB92_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB92_2:
+; CHECK-NEXT:    usati a0, a0, 16
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 65535
   %cmp2 = icmp sgt i64 %x, -1
@@ -1144,12 +1114,7 @@ define i16 @usati_i16_from_i64(i64 %x) {
 define i20 @usati_i20_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i20_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srli a1, a0, 20
-; CHECK-NEXT:    beqz a1, .LBB93_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB93_2:
+; CHECK-NEXT:    usati a0, a0, 20
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 1048575
   %cmp2 = icmp sgt i64 %x, -1
@@ -1162,12 +1127,7 @@ define i20 @usati_i20_from_i64(i64 %x) {
 define i32 @usati_i32_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i32_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srli a1, a0, 32
-; CHECK-NEXT:    beqz a1, .LBB94_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB94_2:
+; CHECK-NEXT:    usati a0, a0, 32
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 4294967295
   %cmp2 = icmp sgt i64 %x, -1
@@ -1180,12 +1140,7 @@ define i32 @usati_i32_from_i64(i64 %x) {
 define i40 @usati_i40_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i40_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srli a1, a0, 40
-; CHECK-NEXT:    beqz a1, .LBB95_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB95_2:
+; CHECK-NEXT:    usati a0, a0, 40
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 1099511627775
   %cmp2 = icmp sgt i64 %x, -1
@@ -1198,12 +1153,7 @@ define i40 @usati_i40_from_i64(i64 %x) {
 define i48 @usati_i48_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i48_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srli a1, a0, 48
-; CHECK-NEXT:    beqz a1, .LBB96_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB96_2:
+; CHECK-NEXT:    usati a0, a0, 48
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 281474976710655
   %cmp2 = icmp sgt i64 %x, -1
@@ -1216,12 +1166,7 @@ define i48 @usati_i48_from_i64(i64 %x) {
 define i56 @usati_i56_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i56_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srli a1, a0, 56
-; CHECK-NEXT:    beqz a1, .LBB97_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB97_2:
+; CHECK-NEXT:    usati a0, a0, 56
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 72057594037927935
   %cmp2 = icmp sgt i64 %x, -1
@@ -1234,11 +1179,7 @@ define i56 @usati_i56_from_i64(i64 %x) {
 define i63 @usati_i63_from_i64(i64 %x) {
 ; CHECK-LABEL: usati_i63_from_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    bgez a0, .LBB98_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB98_2:
+; CHECK-NEXT:    usati a0, a0, 63
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i64 %x, 9223372036854775807
   %cmp2 = icmp sgt i64 %x, -1
@@ -1252,14 +1193,8 @@ define i63 @usati_i63_from_i64(i64 %x) {
 define i8 @usati_i8_from_i16(i16 %x) {
 ; CHECK-LABEL: usati_i8_from_i16:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    zext.h a1, a0
-; CHECK-NEXT:    li a2, 255
-; CHECK-NEXT:    bgeu a2, a1, .LBB99_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    slli a0, a0, 48
-; CHECK-NEXT:    srli a0, a0, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB99_2:
+; CHECK-NEXT:    sext.h a0, a0
+; CHECK-NEXT:    usati a0, a0, 8
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i16 %x, 255
   %cmp2 = icmp sgt i16 %x, -1
@@ -1272,13 +1207,8 @@ define i8 @usati_i8_from_i16(i16 %x) {
 define i8 @usati_i8_from_i32(i32 %x) {
 ; CHECK-LABEL: usati_i8_from_i32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    sext.w a1, a0
-; CHECK-NEXT:    li a2, 255
-; CHECK-NEXT:    bgeu a2, a1, .LBB100_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srliw a0, a0, 31
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB100_2:
+; CHECK-NEXT:    sext.w a0, a0
+; CHECK-NEXT:    usati a0, a0, 8
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i32 %x, 255
   %cmp2 = icmp sgt i32 %x, -1
@@ -1291,12 +1221,8 @@ define i8 @usati_i8_from_i32(i32 %x) {
 define i16 @usati_i16_from_i32(i32 %x) {
 ; CHECK-LABEL: usati_i16_from_i32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srliw a1, a0, 16
-; CHECK-NEXT:    beqz a1, .LBB101_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srliw a0, a0, 31
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB101_2:
+; CHECK-NEXT:    sext.w a0, a0
+; CHECK-NEXT:    usati a0, a0, 16
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i32 %x, 65535
   %cmp2 = icmp sgt i32 %x, -1
@@ -1309,13 +1235,9 @@ define i16 @usati_i16_from_i32(i32 %x) {
 define i16 @usati_i16_from_i48(i48 %x) {
 ; CHECK-LABEL: usati_i16_from_i48:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    slli a1, a0, 16
-; CHECK-NEXT:    srli a2, a1, 32
-; CHECK-NEXT:    beqz a2, .LBB102_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a1, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB102_2:
+; CHECK-NEXT:    slli a0, a0, 16
+; CHECK-NEXT:    srai a0, a0, 16
+; CHECK-NEXT:    usati a0, a0, 16
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i48 %x, 65535
   %cmp2 = icmp sgt i48 %x, -1
@@ -1328,13 +1250,9 @@ define i16 @usati_i16_from_i48(i48 %x) {
 define i32 @usati_i32_from_i48(i48 %x) {
 ; CHECK-LABEL: usati_i32_from_i48:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    slli a1, a0, 16
-; CHECK-NEXT:    srli a2, a1, 48
-; CHECK-NEXT:    beqz a2, .LBB103_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srli a0, a1, 63
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:  .LBB103_2:
+; CHECK-NEXT:    slli a0, a0, 16
+; CHECK-NEXT:    srai a0, a0, 16
+; CHECK-NEXT:    usati a0, a0, 32
 ; CHECK-NEXT:    ret
   %cmp1 = icmp ugt i48 %x, 4294967295
   %cmp2 = icmp sgt i48 %x, -1

>From 19bb9ce8dc0b91f752cc01d2810ae032b6c0c02f Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Tue, 7 Apr 2026 12:23:02 -0700
Subject: [PATCH 3/3] fixup! Address review comments

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 6196e3ac1826a..f3f0638d51faf 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -20280,7 +20280,7 @@ static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG) {
   return DAG.getNode(ISD::ADD, DL, VT, A, NewB);
 }
 
-// Fold (iC (select (src >u ((1 << C) - 1)), sext(src >s -1), trunc(src))) to
+// Fold (iN (select (src >u ((1 << N) - 1)), sext(src >s -1), trunc(src))) to
 // USATI. This pattern saturates a signed value to an unsigned N-bit range
 // [0, 2^N-1]:
 //   - If src < 0: result = 0
@@ -20321,9 +20321,9 @@ static SDValue foldSelectToUSATI(SDNode *N, SelectionDAG &DAG,
     return SDValue();
 
   // Check inner setcc: src > -1 (signed comparison)
-  if (InnerSetCC.getValueType() != MVT::i1 ||
-      !sd_match(InnerSetCC, m_SetCC(m_Specific(Src), m_AllOnes(),
-                                    m_SpecificCondCode(ISD::SETGT))))
+  if (!sd_match(InnerSetCC,
+                m_SpecificVT(MVT::i1, m_SetCC(m_Specific(Src), m_AllOnes(),
+                                              m_SpecificCondCode(ISD::SETGT)))))
     return SDValue();
 
   // FalseSrc may have been optimized from a truncate of a truncate. There may



More information about the llvm-commits mailing list