[llvm] [RISCV] Select signed bitfield extracts for XAndesPerf (PR #142303)
Jim Lin via llvm-commits
llvm-commits at lists.llvm.org
Sun Jun 1 01:17:31 PDT 2025
https://github.com/tclin914 created https://github.com/llvm/llvm-project/pull/142303
The XAndesPerf extension includes signed bitfield extraction
instruction `NDS.BFOS`, which can extract the bits from LSB to MSB,
places them starting at bit 0, and sign-extends the result.
The testcase includes the two patterns that can be selected as
signed bitfield extracts: `ashr+shl` and `ashr+sext_inreg`
>From deb0edce4b0459a7c86045af4dcfe27ef63160ac Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Sun, 1 Jun 2025 10:33:58 +0800
Subject: [PATCH 1/2] [RISCV] Pre-commit
---
llvm/test/CodeGen/RISCV/rv32xandesperf.ll | 83 +++++++++++++++++++++++
llvm/test/CodeGen/RISCV/rv64xandesperf.ll | 66 ++++++++++++++++++
2 files changed, 149 insertions(+)
diff --git a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
index 72dddddf9f382..60d4ce58ecaa9 100644
--- a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
+++ b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
@@ -70,6 +70,89 @@ define i64 @bfoz_from_lshr_and_i64(i64 %x) {
ret i64 %shifted
}
+define i32 @bfos_from_ashr_shl_i32(i32 %x) {
+; CHECK-LABEL: bfos_from_ashr_shl_i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: slli a0, a0, 8
+; CHECK-NEXT: srai a0, a0, 24
+; CHECK-NEXT: ret
+ %shl = shl i32 %x, 8
+ %ashr = ashr i32 %shl, 24
+ ret i32 %ashr
+}
+
+define i64 @bfos_from_ashr_shl_i64(i64 %x) {
+; CHECK-LABEL: bfos_from_ashr_shl_i64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: # kill: def $x12 killed $x11
+; CHECK-NEXT: # kill: def $x12 killed $x10
+; CHECK-NEXT: srli a2, a0, 24
+; CHECK-NEXT: slli a1, a1, 8
+; CHECK-NEXT: or a2, a1, a2
+; CHECK-NEXT: slli a2, a2, 8
+; CHECK-NEXT: nds.bfoz a0, a0, 23, 16
+; CHECK-NEXT: or a0, a0, a2
+; CHECK-NEXT: srai a1, a1, 24
+; CHECK-NEXT: ret
+ %shl = shl i64 %x, 8
+ %ashr = ashr i64 %shl, 24
+ ret i64 %ashr
+}
+
+define i32 @bfos_from_ashr_sexti8_i32(i8 %x) {
+; CHECK-LABEL: bfos_from_ashr_sexti8_i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: # kill: def $x11 killed $x10
+; CHECK-NEXT: slli a0, a0, 24
+; CHECK-NEXT: srai a0, a0, 29
+; CHECK-NEXT: ret
+ %sext = sext i8 %x to i32
+ %ashr = ashr i32 %sext, 5
+ ret i32 %ashr
+}
+
+define i64 @bfos_from_ashr_sexti8_i64(i8 %x) {
+; CHECK-LABEL: bfos_from_ashr_sexti8_i64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: # kill: def $x11 killed $x10
+; CHECK-NEXT: nds.bfos a0, a0, 7, 0
+; CHECK-NEXT: srai a1, a0, 31
+; CHECK-NEXT: srli a0, a0, 5
+; CHECK-NEXT: slli a2, a1, 27
+; CHECK-NEXT: or a0, a0, a2
+; CHECK-NEXT: ret
+ %sext = sext i8 %x to i64
+ %ashr = ashr i64 %sext, 5
+ ret i64 %ashr
+}
+
+define i32 @bfos_from_ashr_sexti16_i32(i16 %x) {
+; CHECK-LABEL: bfos_from_ashr_sexti16_i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: # kill: def $x11 killed $x10
+; CHECK-NEXT: slli a0, a0, 16
+; CHECK-NEXT: srai a0, a0, 27
+; CHECK-NEXT: ret
+ %sext = sext i16 %x to i32
+ %ashr = ashr i32 %sext, 11
+ ret i32 %ashr
+}
+
+define i64 @bfos_from_ashr_sexti16_i64(i16 %x) {
+; CHECK-LABEL: bfos_from_ashr_sexti16_i64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: # kill: def $x11 killed $x10
+; CHECK-NEXT: nds.bfos a0, a0, 15, 0
+; CHECK-NEXT: srai a1, a0, 31
+; CHECK-NEXT: srli a0, a0, 11
+; CHECK-NEXT: slli a2, a1, 21
+; CHECK-NEXT: or a0, a0, a2
+; CHECK-NEXT: ret
+ %sext = sext i16 %x to i64
+ %ashr = ashr i64 %sext, 11
+ ret i64 %ashr
+}
+
define i32 @sexti1_i32(i32 %a) {
; CHECK-LABEL: sexti1_i32:
; CHECK: # %bb.0:
diff --git a/llvm/test/CodeGen/RISCV/rv64xandesperf.ll b/llvm/test/CodeGen/RISCV/rv64xandesperf.ll
index 13c2234071eb1..6c83d46647c90 100644
--- a/llvm/test/CodeGen/RISCV/rv64xandesperf.ll
+++ b/llvm/test/CodeGen/RISCV/rv64xandesperf.ll
@@ -60,6 +60,72 @@ define i64 @bfoz_from_lshr_and_i64(i64 %x) {
ret i64 %shifted
}
+define i32 @bfos_from_ashr_shl_i32(i32 %x) {
+; CHECK-LABEL: bfos_from_ashr_shl_i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: slli a0, a0, 40
+; CHECK-NEXT: srai a0, a0, 56
+; CHECK-NEXT: ret
+ %shl = shl i32 %x, 8
+ %ashr = ashr i32 %shl, 24
+ ret i32 %ashr
+}
+
+define i64 @bfos_from_ashr_shl_i64(i64 %x) {
+; CHECK-LABEL: bfos_from_ashr_shl_i64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: slli a0, a0, 8
+; CHECK-NEXT: srai a0, a0, 24
+; CHECK-NEXT: ret
+ %shl = shl i64 %x, 8
+ %ashr = ashr i64 %shl, 24
+ ret i64 %ashr
+}
+
+define i32 @bfos_from_ashr_sexti8_i32(i8 %x) {
+; CHECK-LABEL: bfos_from_ashr_sexti8_i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: slli a0, a0, 56
+; CHECK-NEXT: srai a0, a0, 61
+; CHECK-NEXT: ret
+ %sext = sext i8 %x to i32
+ %ashr = ashr i32 %sext, 5
+ ret i32 %ashr
+}
+
+define i64 @bfos_from_ashr_sexti8_i64(i8 %x) {
+; CHECK-LABEL: bfos_from_ashr_sexti8_i64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: slli a0, a0, 56
+; CHECK-NEXT: srai a0, a0, 61
+; CHECK-NEXT: ret
+ %sext = sext i8 %x to i64
+ %ashr = ashr i64 %sext, 5
+ ret i64 %ashr
+}
+
+define i32 @bfos_from_ashr_sexti16_i32(i16 %x) {
+; CHECK-LABEL: bfos_from_ashr_sexti16_i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: slli a0, a0, 48
+; CHECK-NEXT: srai a0, a0, 59
+; CHECK-NEXT: ret
+ %sext = sext i16 %x to i32
+ %ashr = ashr i32 %sext, 11
+ ret i32 %ashr
+}
+
+define i64 @bfos_from_ashr_sexti16_i64(i16 %x) {
+; CHECK-LABEL: bfos_from_ashr_sexti16_i64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: slli a0, a0, 48
+; CHECK-NEXT: srai a0, a0, 59
+; CHECK-NEXT: ret
+ %sext = sext i16 %x to i64
+ %ashr = ashr i64 %sext, 11
+ ret i64 %ashr
+}
+
define signext i32 @sexti1_i32(i32 signext %a) {
; CHECK-LABEL: sexti1_i32:
; CHECK: # %bb.0:
>From 36a3d516303e1d7799ac7c23ad9a8b6cf9429eca Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Sun, 1 Jun 2025 10:34:29 +0800
Subject: [PATCH 2/2] [RISCV] Select signed bitfield extracts for XAndesPerf
The XAndesPerf extension includes signed bitfield extraction
instruction `NDS.BFOS`, which can extract the bits from LSB to MSB,
places them starting at bit 0, and sign-extends the result.
The testcase includes the two patterns that can be selected as
signed bitfield extracts: `ashr+shl` and `ashr+sext_inreg`
---
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 8 +++++---
llvm/test/CodeGen/RISCV/rv32xandesperf.ll | 9 +++------
llvm/test/CodeGen/RISCV/rv64xandesperf.ll | 18 ++++++------------
3 files changed, 14 insertions(+), 21 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 2de22ee165aea..4f6aa41d1e03b 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -601,8 +601,8 @@ bool RISCVDAGToDAGISel::tryShrinkShlLogicImm(SDNode *Node) {
}
bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) {
- // Only supported with XTHeadBb at the moment.
- if (!Subtarget->hasVendorXTHeadBb())
+ // Only supported with XTHeadBb/XAndesPerf at the moment.
+ if (!Subtarget->hasVendorXTHeadBb() && !Subtarget->hasVendorXAndesPerf())
return false;
auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
@@ -615,7 +615,9 @@ bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) {
auto BitfieldExtract = [&](SDValue N0, unsigned Msb, unsigned Lsb, SDLoc DL,
MVT VT) {
- return CurDAG->getMachineNode(RISCV::TH_EXT, DL, VT, N0.getOperand(0),
+ unsigned Opc =
+ Subtarget->hasVendorXTHeadBb() ? RISCV::TH_EXT : RISCV::NDS_BFOS;
+ return CurDAG->getMachineNode(Opc, DL, VT, N0.getOperand(0),
CurDAG->getTargetConstant(Msb, DL, VT),
CurDAG->getTargetConstant(Lsb, DL, VT));
};
diff --git a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
index 60d4ce58ecaa9..af353a1e541fe 100644
--- a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
+++ b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
@@ -73,8 +73,7 @@ define i64 @bfoz_from_lshr_and_i64(i64 %x) {
define i32 @bfos_from_ashr_shl_i32(i32 %x) {
; CHECK-LABEL: bfos_from_ashr_shl_i32:
; CHECK: # %bb.0:
-; CHECK-NEXT: slli a0, a0, 8
-; CHECK-NEXT: srai a0, a0, 24
+; CHECK-NEXT: nds.bfos a0, a0, 23, 16
; CHECK-NEXT: ret
%shl = shl i32 %x, 8
%ashr = ashr i32 %shl, 24
@@ -103,8 +102,7 @@ define i32 @bfos_from_ashr_sexti8_i32(i8 %x) {
; CHECK-LABEL: bfos_from_ashr_sexti8_i32:
; CHECK: # %bb.0:
; CHECK-NEXT: # kill: def $x11 killed $x10
-; CHECK-NEXT: slli a0, a0, 24
-; CHECK-NEXT: srai a0, a0, 29
+; CHECK-NEXT: nds.bfos a0, a0, 7, 5
; CHECK-NEXT: ret
%sext = sext i8 %x to i32
%ashr = ashr i32 %sext, 5
@@ -130,8 +128,7 @@ define i32 @bfos_from_ashr_sexti16_i32(i16 %x) {
; CHECK-LABEL: bfos_from_ashr_sexti16_i32:
; CHECK: # %bb.0:
; CHECK-NEXT: # kill: def $x11 killed $x10
-; CHECK-NEXT: slli a0, a0, 16
-; CHECK-NEXT: srai a0, a0, 27
+; CHECK-NEXT: nds.bfos a0, a0, 15, 11
; CHECK-NEXT: ret
%sext = sext i16 %x to i32
%ashr = ashr i32 %sext, 11
diff --git a/llvm/test/CodeGen/RISCV/rv64xandesperf.ll b/llvm/test/CodeGen/RISCV/rv64xandesperf.ll
index 6c83d46647c90..260d30be686dc 100644
--- a/llvm/test/CodeGen/RISCV/rv64xandesperf.ll
+++ b/llvm/test/CodeGen/RISCV/rv64xandesperf.ll
@@ -63,8 +63,7 @@ define i64 @bfoz_from_lshr_and_i64(i64 %x) {
define i32 @bfos_from_ashr_shl_i32(i32 %x) {
; CHECK-LABEL: bfos_from_ashr_shl_i32:
; CHECK: # %bb.0:
-; CHECK-NEXT: slli a0, a0, 40
-; CHECK-NEXT: srai a0, a0, 56
+; CHECK-NEXT: nds.bfos a0, a0, 23, 16
; CHECK-NEXT: ret
%shl = shl i32 %x, 8
%ashr = ashr i32 %shl, 24
@@ -74,8 +73,7 @@ define i32 @bfos_from_ashr_shl_i32(i32 %x) {
define i64 @bfos_from_ashr_shl_i64(i64 %x) {
; CHECK-LABEL: bfos_from_ashr_shl_i64:
; CHECK: # %bb.0:
-; CHECK-NEXT: slli a0, a0, 8
-; CHECK-NEXT: srai a0, a0, 24
+; CHECK-NEXT: nds.bfos a0, a0, 55, 16
; CHECK-NEXT: ret
%shl = shl i64 %x, 8
%ashr = ashr i64 %shl, 24
@@ -85,8 +83,7 @@ define i64 @bfos_from_ashr_shl_i64(i64 %x) {
define i32 @bfos_from_ashr_sexti8_i32(i8 %x) {
; CHECK-LABEL: bfos_from_ashr_sexti8_i32:
; CHECK: # %bb.0:
-; CHECK-NEXT: slli a0, a0, 56
-; CHECK-NEXT: srai a0, a0, 61
+; CHECK-NEXT: nds.bfos a0, a0, 7, 5
; CHECK-NEXT: ret
%sext = sext i8 %x to i32
%ashr = ashr i32 %sext, 5
@@ -96,8 +93,7 @@ define i32 @bfos_from_ashr_sexti8_i32(i8 %x) {
define i64 @bfos_from_ashr_sexti8_i64(i8 %x) {
; CHECK-LABEL: bfos_from_ashr_sexti8_i64:
; CHECK: # %bb.0:
-; CHECK-NEXT: slli a0, a0, 56
-; CHECK-NEXT: srai a0, a0, 61
+; CHECK-NEXT: nds.bfos a0, a0, 7, 5
; CHECK-NEXT: ret
%sext = sext i8 %x to i64
%ashr = ashr i64 %sext, 5
@@ -107,8 +103,7 @@ define i64 @bfos_from_ashr_sexti8_i64(i8 %x) {
define i32 @bfos_from_ashr_sexti16_i32(i16 %x) {
; CHECK-LABEL: bfos_from_ashr_sexti16_i32:
; CHECK: # %bb.0:
-; CHECK-NEXT: slli a0, a0, 48
-; CHECK-NEXT: srai a0, a0, 59
+; CHECK-NEXT: nds.bfos a0, a0, 15, 11
; CHECK-NEXT: ret
%sext = sext i16 %x to i32
%ashr = ashr i32 %sext, 11
@@ -118,8 +113,7 @@ define i32 @bfos_from_ashr_sexti16_i32(i16 %x) {
define i64 @bfos_from_ashr_sexti16_i64(i16 %x) {
; CHECK-LABEL: bfos_from_ashr_sexti16_i64:
; CHECK: # %bb.0:
-; CHECK-NEXT: slli a0, a0, 48
-; CHECK-NEXT: srai a0, a0, 59
+; CHECK-NEXT: nds.bfos a0, a0, 15, 11
; CHECK-NEXT: ret
%sext = sext i16 %x to i64
%ashr = ashr i64 %sext, 11
More information about the llvm-commits
mailing list