[llvm] [RISCV] Support srx/slx for P extension. (PR #173225)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 22 00:06:24 PST 2025


https://github.com/topperc created https://github.com/llvm/llvm-project/pull/173225

These instructions can be used for fshl and fshr respectively.

>From 7ebea8abba565bc26a861e1c22d8dd99408f4346 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sun, 21 Dec 2025 23:40:05 -0800
Subject: [PATCH 1/2] Pre-commit tests

---
 llvm/test/CodeGen/RISCV/rv32p.ll | 56 ++++++++++++++++++++++++++++++++
 llvm/test/CodeGen/RISCV/rv64p.ll | 56 ++++++++++++++++++++++++++++++++
 2 files changed, 112 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index c9111a1a24f98..b942b6ea87970 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -60,3 +60,59 @@ define void @pli_b_store_i32(ptr %p) {
   store i32 u0x41414141, ptr %p
   ret void
 }
+
+define i64 @slx_i64(i64 %x, i64 %y) {
+; CHECK-LABEL: slx_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    sll a1, a1, a2
+; CHECK-NEXT:    srli a3, a0, 1
+; CHECK-NEXT:    andi a4, a2, 31
+; CHECK-NEXT:    xori a4, a4, 31
+; CHECK-NEXT:    srl a3, a3, a4
+; CHECK-NEXT:    or a1, a1, a3
+; CHECK-NEXT:    sll a0, a0, a2
+; CHECK-NEXT:    ret
+  %a = and i64 %y, 31
+  %b = shl i64 %x, %a
+  ret i64 %b
+}
+
+define i64 @slxi_i64(i64 %x) {
+; CHECK-LABEL: slxi_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srli a2, a0, 7
+; CHECK-NEXT:    slli a1, a1, 25
+; CHECK-NEXT:    or a1, a1, a2
+; CHECK-NEXT:    slli a0, a0, 25
+; CHECK-NEXT:    ret
+  %a = shl i64 %x, 25
+  ret i64 %a
+}
+
+define i64 @srx_i64(i64 %x, i64 %y) {
+; CHECK-LABEL: srx_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srl a0, a0, a2
+; CHECK-NEXT:    slli a3, a1, 1
+; CHECK-NEXT:    andi a4, a2, 31
+; CHECK-NEXT:    xori a4, a4, 31
+; CHECK-NEXT:    sll a3, a3, a4
+; CHECK-NEXT:    or a0, a0, a3
+; CHECK-NEXT:    srl a1, a1, a2
+; CHECK-NEXT:    ret
+  %a = and i64 %y, 31
+  %b = lshr i64 %x, %a
+  ret i64 %b
+}
+
+define i64 @srxi_i64(i64 %x) {
+; CHECK-LABEL: srxi_i64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    slli a2, a1, 7
+; CHECK-NEXT:    srli a0, a0, 25
+; CHECK-NEXT:    or a0, a0, a2
+; CHECK-NEXT:    srli a1, a1, 25
+; CHECK-NEXT:    ret
+  %a = lshr i64 %x, 25
+  ret i64 %a
+}
diff --git a/llvm/test/CodeGen/RISCV/rv64p.ll b/llvm/test/CodeGen/RISCV/rv64p.ll
index 22dba6501f68c..269821d152c96 100644
--- a/llvm/test/CodeGen/RISCV/rv64p.ll
+++ b/llvm/test/CodeGen/RISCV/rv64p.ll
@@ -99,3 +99,59 @@ define void @pli_b_store_i32(ptr %p) {
   store i32 u0x41414141, ptr %p
   ret void
 }
+
+define i128 @slx_i128(i128 %x, i128 %y) {
+; CHECK-LABEL: slx_i128:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    sll a1, a1, a2
+; CHECK-NEXT:    srli a3, a0, 1
+; CHECK-NEXT:    andi a4, a2, 63
+; CHECK-NEXT:    xori a4, a4, 63
+; CHECK-NEXT:    srl a3, a3, a4
+; CHECK-NEXT:    or a1, a1, a3
+; CHECK-NEXT:    sll a0, a0, a2
+; CHECK-NEXT:    ret
+  %a = and i128 %y, 63
+  %b = shl i128 %x, %a
+  ret i128 %b
+}
+
+define i128 @slxi_i128(i128 %x) {
+; CHECK-LABEL: slxi_i128:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srli a2, a0, 15
+; CHECK-NEXT:    slli a1, a1, 49
+; CHECK-NEXT:    or a1, a1, a2
+; CHECK-NEXT:    slli a0, a0, 49
+; CHECK-NEXT:    ret
+  %a = shl i128 %x, 49
+  ret i128 %a
+}
+
+define i128 @srx_i128(i128 %x, i128 %y) {
+; CHECK-LABEL: srx_i128:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    srl a0, a0, a2
+; CHECK-NEXT:    slli a3, a1, 1
+; CHECK-NEXT:    andi a4, a2, 63
+; CHECK-NEXT:    xori a4, a4, 63
+; CHECK-NEXT:    sll a3, a3, a4
+; CHECK-NEXT:    or a0, a0, a3
+; CHECK-NEXT:    srl a1, a1, a2
+; CHECK-NEXT:    ret
+  %a = and i128 %y, 63
+  %b = lshr i128 %x, %a
+  ret i128 %b
+}
+
+define i128 @srxi_i128(i128 %x) {
+; CHECK-LABEL: srxi_i128:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    slli a2, a1, 15
+; CHECK-NEXT:    srli a0, a0, 49
+; CHECK-NEXT:    or a0, a0, a2
+; CHECK-NEXT:    srli a1, a1, 49
+; CHECK-NEXT:    ret
+  %a = lshr i128 %x, 49
+  ret i128 %a
+}

>From 5e0d6aaa924c0a474a72e82d257641eaff5888cc Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Mon, 22 Dec 2025 00:03:27 -0800
Subject: [PATCH 2/2] [RISCV] Support srx/slx for P extension.

These instructions can be used for fshl and fshr respectively.
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  3 ++
 llvm/lib/Target/RISCV/RISCVInstrInfoP.td    |  7 ++++-
 llvm/test/CodeGen/RISCV/rv32p.ll            | 33 ++++++++-------------
 llvm/test/CodeGen/RISCV/rv64p.ll            | 33 ++++++++-------------
 4 files changed, 35 insertions(+), 41 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 7dfb5cd0a9e6c..23a24d184e508 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -398,6 +398,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
     setOperationAction({ISD::ROTL, ISD::ROTR}, XLenVT, Expand);
   }
 
+  if (Subtarget.hasStdExtP())
+    setOperationAction({ISD::FSHL, ISD::FSHR}, XLenVT, Legal);
+
   setOperationAction(ISD::BSWAP, XLenVT,
                      Subtarget.hasREV8Like() ? Legal : Expand);
 
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 060161f3a8fa0..92a9c06fc534b 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -690,7 +690,7 @@ let Predicates = [HasStdExtP, IsRV64] in {
 } // Predicates = [HasStdExtP, IsRV64]
 
 let Predicates = [HasStdExtP] in {
-  def SLX          : RVPBinary_rr<0b0001, 0b11, 0b001, "slx">;
+  def SLX          : RVPTernary_rrr<0b0001, 0b11, 0b001, "slx">;
 
   def PMUL_H_B01   : RVPBinary_rr<0b0010, 0b00, 0b001, "pmul.h.b01">;
 
@@ -1474,6 +1474,11 @@ def riscv_pmulhsu : RVSDNode<"PMULHSU", SDT_RISCVPBinOp>;
 let Predicates = [HasStdExtP] in {
   def : PatGpr<abs, ABS>;
 
+  def : Pat<(XLenVT (fshl GPR:$rd, GPR:$rs1, shiftMaskXLen:$rs2)),
+            (SLX GPR:$rd, GPR:$rs1, shiftMaskXLen:$rs2)>;
+  def : Pat<(XLenVT (fshr GPR:$rs1, GPR:$rd, shiftMaskXLen:$rs2)),
+            (SRX GPR:$rd, GPR:$rs1, shiftMaskXLen:$rs2)>;
+
   // Basic 8-bit arithmetic patterns
   def: Pat<(XLenVecI8VT (add GPR:$rs1, GPR:$rs2)), (PADD_B GPR:$rs1, GPR:$rs2)>;
   def: Pat<(XLenVecI8VT (sub GPR:$rs1, GPR:$rs2)), (PSUB_B GPR:$rs1, GPR:$rs2)>;
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index b942b6ea87970..6be18e25086e8 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -64,13 +64,9 @@ define void @pli_b_store_i32(ptr %p) {
 define i64 @slx_i64(i64 %x, i64 %y) {
 ; CHECK-LABEL: slx_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    sll a1, a1, a2
-; CHECK-NEXT:    srli a3, a0, 1
-; CHECK-NEXT:    andi a4, a2, 31
-; CHECK-NEXT:    xori a4, a4, 31
-; CHECK-NEXT:    srl a3, a3, a4
-; CHECK-NEXT:    or a1, a1, a3
-; CHECK-NEXT:    sll a0, a0, a2
+; CHECK-NEXT:    sll a3, a0, a2
+; CHECK-NEXT:    slx a1, a0, a2
+; CHECK-NEXT:    mv a0, a3
 ; CHECK-NEXT:    ret
   %a = and i64 %y, 31
   %b = shl i64 %x, %a
@@ -80,9 +76,8 @@ define i64 @slx_i64(i64 %x, i64 %y) {
 define i64 @slxi_i64(i64 %x) {
 ; CHECK-LABEL: slxi_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srli a2, a0, 7
-; CHECK-NEXT:    slli a1, a1, 25
-; CHECK-NEXT:    or a1, a1, a2
+; CHECK-NEXT:    li a2, 25
+; CHECK-NEXT:    slx a1, a0, a2
 ; CHECK-NEXT:    slli a0, a0, 25
 ; CHECK-NEXT:    ret
   %a = shl i64 %x, 25
@@ -92,26 +87,24 @@ define i64 @slxi_i64(i64 %x) {
 define i64 @srx_i64(i64 %x, i64 %y) {
 ; CHECK-LABEL: srx_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srl a0, a0, a2
-; CHECK-NEXT:    slli a3, a1, 1
-; CHECK-NEXT:    andi a4, a2, 31
-; CHECK-NEXT:    xori a4, a4, 31
-; CHECK-NEXT:    sll a3, a3, a4
-; CHECK-NEXT:    or a0, a0, a3
-; CHECK-NEXT:    srl a1, a1, a2
+; CHECK-NEXT:    srl a3, a1, a2
+; CHECK-NEXT:    srx a0, a1, a2
+; CHECK-NEXT:    mv a1, a3
 ; CHECK-NEXT:    ret
   %a = and i64 %y, 31
   %b = lshr i64 %x, %a
   ret i64 %b
 }
 
+; FIXME: Using srx instead of slx would avoid the mv.
 define i64 @srxi_i64(i64 %x) {
 ; CHECK-LABEL: srxi_i64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    slli a2, a1, 7
-; CHECK-NEXT:    srli a0, a0, 25
-; CHECK-NEXT:    or a0, a0, a2
+; CHECK-NEXT:    mv a2, a1
+; CHECK-NEXT:    li a3, 7
 ; CHECK-NEXT:    srli a1, a1, 25
+; CHECK-NEXT:    slx a2, a0, a3
+; CHECK-NEXT:    mv a0, a2
 ; CHECK-NEXT:    ret
   %a = lshr i64 %x, 25
   ret i64 %a
diff --git a/llvm/test/CodeGen/RISCV/rv64p.ll b/llvm/test/CodeGen/RISCV/rv64p.ll
index 269821d152c96..39902dec66e64 100644
--- a/llvm/test/CodeGen/RISCV/rv64p.ll
+++ b/llvm/test/CodeGen/RISCV/rv64p.ll
@@ -103,13 +103,9 @@ define void @pli_b_store_i32(ptr %p) {
 define i128 @slx_i128(i128 %x, i128 %y) {
 ; CHECK-LABEL: slx_i128:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    sll a1, a1, a2
-; CHECK-NEXT:    srli a3, a0, 1
-; CHECK-NEXT:    andi a4, a2, 63
-; CHECK-NEXT:    xori a4, a4, 63
-; CHECK-NEXT:    srl a3, a3, a4
-; CHECK-NEXT:    or a1, a1, a3
-; CHECK-NEXT:    sll a0, a0, a2
+; CHECK-NEXT:    sll a3, a0, a2
+; CHECK-NEXT:    slx a1, a0, a2
+; CHECK-NEXT:    mv a0, a3
 ; CHECK-NEXT:    ret
   %a = and i128 %y, 63
   %b = shl i128 %x, %a
@@ -119,9 +115,8 @@ define i128 @slx_i128(i128 %x, i128 %y) {
 define i128 @slxi_i128(i128 %x) {
 ; CHECK-LABEL: slxi_i128:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srli a2, a0, 15
-; CHECK-NEXT:    slli a1, a1, 49
-; CHECK-NEXT:    or a1, a1, a2
+; CHECK-NEXT:    li a2, 49
+; CHECK-NEXT:    slx a1, a0, a2
 ; CHECK-NEXT:    slli a0, a0, 49
 ; CHECK-NEXT:    ret
   %a = shl i128 %x, 49
@@ -131,26 +126,24 @@ define i128 @slxi_i128(i128 %x) {
 define i128 @srx_i128(i128 %x, i128 %y) {
 ; CHECK-LABEL: srx_i128:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    srl a0, a0, a2
-; CHECK-NEXT:    slli a3, a1, 1
-; CHECK-NEXT:    andi a4, a2, 63
-; CHECK-NEXT:    xori a4, a4, 63
-; CHECK-NEXT:    sll a3, a3, a4
-; CHECK-NEXT:    or a0, a0, a3
-; CHECK-NEXT:    srl a1, a1, a2
+; CHECK-NEXT:    srl a3, a1, a2
+; CHECK-NEXT:    srx a0, a1, a2
+; CHECK-NEXT:    mv a1, a3
 ; CHECK-NEXT:    ret
   %a = and i128 %y, 63
   %b = lshr i128 %x, %a
   ret i128 %b
 }
 
+; FIXME: Using srx instead of slx would avoid the mv.
 define i128 @srxi_i128(i128 %x) {
 ; CHECK-LABEL: srxi_i128:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    slli a2, a1, 15
-; CHECK-NEXT:    srli a0, a0, 49
-; CHECK-NEXT:    or a0, a0, a2
+; CHECK-NEXT:    mv a2, a1
+; CHECK-NEXT:    li a3, 15
 ; CHECK-NEXT:    srli a1, a1, 49
+; CHECK-NEXT:    slx a2, a0, a3
+; CHECK-NEXT:    mv a0, a2
 ; CHECK-NEXT:    ret
   %a = lshr i128 %x, 49
   ret i128 %a



More information about the llvm-commits mailing list