[llvm] [RISCV] Support i32 SSHLAT for rv32ip. (PR #173687)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 26 12:37:17 PST 2025


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

>From a3152e8bcdf6ab7a388d51bba77759a20ce526cb Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Fri, 26 Dec 2025 11:22:26 -0800
Subject: [PATCH 1/3] Pre-commit tests

---
 llvm/test/CodeGen/RISCV/rv32p.ll | 56 ++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 0e1aa18b5a9dc..6f07e80578f15 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -146,3 +146,59 @@ define i64 @srxi_i64(i64 %x) {
   %a = lshr i64 %x, 25
   ret i64 %a
 }
+
+define i8 @shlsat_i8(i8 %a, i8 %b) {
+; CHECK-LABEL: shlsat_i8:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    slli a2, a0, 24
+; CHECK-NEXT:    sll a0, a2, a1
+; CHECK-NEXT:    sra a1, a0, a1
+; CHECK-NEXT:    beq a2, a1, .LBB13_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srai a2, a2, 31
+; CHECK-NEXT:    lui a0, 524288
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:    xor a0, a2, a0
+; CHECK-NEXT:  .LBB13_2:
+; CHECK-NEXT:    srai a0, a0, 24
+; CHECK-NEXT:    ret
+ %sshlsat = tail call i8 @llvm.sshl.sat.i8(i8 %a,i8 %b)
+ ret i8 %sshlsat
+}
+
+define i16 @shlsat_i16(i16 %a, i16 %b) {
+; CHECK-LABEL: shlsat_i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    slli a2, a0, 16
+; CHECK-NEXT:    sll a0, a2, a1
+; CHECK-NEXT:    sra a1, a0, a1
+; CHECK-NEXT:    beq a2, a1, .LBB14_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srai a2, a2, 31
+; CHECK-NEXT:    lui a0, 524288
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:    xor a0, a2, a0
+; CHECK-NEXT:  .LBB14_2:
+; CHECK-NEXT:    srai a0, a0, 16
+; CHECK-NEXT:    ret
+ %sshlsat = tail call i16 @llvm.sshl.sat.i16(i16 %a,i16 %b)
+ ret i16 %sshlsat
+}
+
+define i32 @shlsat_i32(i32 %a, i32 %b) {
+; CHECK-LABEL: shlsat_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    mv a2, a0
+; CHECK-NEXT:    sll a0, a0, a1
+; CHECK-NEXT:    sra a1, a0, a1
+; CHECK-NEXT:    beq a2, a1, .LBB15_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    srai a2, a2, 31
+; CHECK-NEXT:    lui a0, 524288
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:    xor a0, a2, a0
+; CHECK-NEXT:  .LBB15_2:
+; CHECK-NEXT:    ret
+ %sshlsat = tail call i32 @llvm.sshl.sat.i32(i32 %a,i32 %b)
+ ret i32 %sshlsat
+}

>From 562175db8ad0a1a08d1a24909e0971e182fe36dd Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Fri, 26 Dec 2025 11:37:43 -0800
Subject: [PATCH 2/3] [RISCV] Support i32 SSHLAT rv32ip.

The rv32ip ssha instruction treats the lower byte of rs2 as signed shift
amount. If the byte is positive, it is a saturating shift left. If the
byte is negative, it is an arithmetic shift right.

Since out of bounds shift amounts are poison in LLVM semantics, we
can assume the shift amount is a positive number and use ssha to
implement sshlsat.
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  4 +++
 llvm/lib/Target/RISCV/RISCVInstrInfoP.td    |  2 ++
 llvm/test/CodeGen/RISCV/rv32p.ll            | 38 +++++----------------
 3 files changed, 14 insertions(+), 30 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 04ff1a978a131..707e42ce93cfc 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -471,6 +471,10 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
     setOperationAction(ISD::SSUBSAT, MVT::i32, Legal);
     setOperationAction(ISD::SSHLSAT, MVT::i32, Legal);
     setOperationAction(ISD::USHLSAT, MVT::i32, Legal);
+  } else if (Subtarget.hasStdExtP() && !Subtarget.is64Bit()) {
+    // FIXME: Support i32 on RV64 by inserting into a v2i32 vector, doing
+    // pssha.w and extracting.
+    setOperationAction(ISD::SSHLSAT, MVT::i32, Legal);
   }
 
   static const unsigned FPLegalNodeTypes[] = {
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 92a9c06fc534b..31cc1c3fde7f8 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1585,6 +1585,8 @@ let Predicates = [HasStdExtP] in {
 } // Predicates = [HasStdExtP]
 
 let Predicates = [HasStdExtP, IsRV32] in {
+  def : PatGprGpr<sshlsat, SSHA>;
+
   // Load/Store patterns
   def : StPat<store, SW, GPR, v4i8>;
   def : StPat<store, SW, GPR, v2i16>;
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 6f07e80578f15..8f776bc0ff827 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -150,16 +150,9 @@ define i64 @srxi_i64(i64 %x) {
 define i8 @shlsat_i8(i8 %a, i8 %b) {
 ; CHECK-LABEL: shlsat_i8:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    slli a2, a0, 24
-; CHECK-NEXT:    sll a0, a2, a1
-; CHECK-NEXT:    sra a1, a0, a1
-; CHECK-NEXT:    beq a2, a1, .LBB13_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srai a2, a2, 31
-; CHECK-NEXT:    lui a0, 524288
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:    xor a0, a2, a0
-; CHECK-NEXT:  .LBB13_2:
+; CHECK-NEXT:    zext.b a1, a1
+; CHECK-NEXT:    slli a0, a0, 24
+; CHECK-NEXT:    ssha a0, a0, a1
 ; CHECK-NEXT:    srai a0, a0, 24
 ; CHECK-NEXT:    ret
  %sshlsat = tail call i8 @llvm.sshl.sat.i8(i8 %a,i8 %b)
@@ -169,16 +162,10 @@ define i8 @shlsat_i8(i8 %a, i8 %b) {
 define i16 @shlsat_i16(i16 %a, i16 %b) {
 ; CHECK-LABEL: shlsat_i16:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    slli a2, a0, 16
-; CHECK-NEXT:    sll a0, a2, a1
-; CHECK-NEXT:    sra a1, a0, a1
-; CHECK-NEXT:    beq a2, a1, .LBB14_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srai a2, a2, 31
-; CHECK-NEXT:    lui a0, 524288
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:    xor a0, a2, a0
-; CHECK-NEXT:  .LBB14_2:
+; CHECK-NEXT:    slli a0, a0, 16
+; CHECK-NEXT:    slli a1, a1, 16
+; CHECK-NEXT:    srli a1, a1, 16
+; CHECK-NEXT:    ssha a0, a0, a1
 ; CHECK-NEXT:    srai a0, a0, 16
 ; CHECK-NEXT:    ret
  %sshlsat = tail call i16 @llvm.sshl.sat.i16(i16 %a,i16 %b)
@@ -188,16 +175,7 @@ define i16 @shlsat_i16(i16 %a, i16 %b) {
 define i32 @shlsat_i32(i32 %a, i32 %b) {
 ; CHECK-LABEL: shlsat_i32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    mv a2, a0
-; CHECK-NEXT:    sll a0, a0, a1
-; CHECK-NEXT:    sra a1, a0, a1
-; CHECK-NEXT:    beq a2, a1, .LBB15_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    srai a2, a2, 31
-; CHECK-NEXT:    lui a0, 524288
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:    xor a0, a2, a0
-; CHECK-NEXT:  .LBB15_2:
+; CHECK-NEXT:    ssha a0, a0, a1
 ; CHECK-NEXT:    ret
  %sshlsat = tail call i32 @llvm.sshl.sat.i32(i32 %a,i32 %b)
  ret i32 %sshlsat

>From c4fb4c9b9c6cf633e4e2b7d6a25d17a42a47c381 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Fri, 26 Dec 2025 12:37:01 -0800
Subject: [PATCH 3/3] fixup! Merge with Xqcia code.

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

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 707e42ce93cfc..c5cf35dce2c10 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -469,10 +469,12 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
     setOperationAction(ISD::SADDSAT, MVT::i32, Legal);
     setOperationAction(ISD::USUBSAT, MVT::i32, Legal);
     setOperationAction(ISD::SSUBSAT, MVT::i32, Legal);
-    setOperationAction(ISD::SSHLSAT, MVT::i32, Legal);
     setOperationAction(ISD::USHLSAT, MVT::i32, Legal);
-  } else if (Subtarget.hasStdExtP() && !Subtarget.is64Bit()) {
-    // FIXME: Support i32 on RV64 by inserting into a v2i32 vector, doing
+  }
+
+  if ((Subtarget.hasStdExtP() || Subtarget.hasVendorXqcia()) &&
+      !Subtarget.is64Bit()) {
+    // FIXME: Support i32 on RV64+P by inserting into a v2i32 vector, doing
     // pssha.w and extracting.
     setOperationAction(ISD::SSHLSAT, MVT::i32, Legal);
   }



More information about the llvm-commits mailing list