[llvm] [RISCV] Select signed bitfield extracts for XAndesPerf (PR #142303)

via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 1 01:18:07 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v

Author: Jim Lin (tclin914)

<details>
<summary>Changes</summary>

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`

---
Full diff: https://github.com/llvm/llvm-project/pull/142303.diff


3 Files Affected:

- (modified) llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp (+5-3) 
- (modified) llvm/test/CodeGen/RISCV/rv32xandesperf.ll (+80) 
- (modified) llvm/test/CodeGen/RISCV/rv64xandesperf.ll (+60) 


``````````diff
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 72dddddf9f382..af353a1e541fe 100644
--- a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
+++ b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
@@ -70,6 +70,86 @@ 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:    nds.bfos a0, a0, 23, 16
+; 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:    nds.bfos a0, a0, 7, 5
+; 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:    nds.bfos a0, a0, 15, 11
+; 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..260d30be686dc 100644
--- a/llvm/test/CodeGen/RISCV/rv64xandesperf.ll
+++ b/llvm/test/CodeGen/RISCV/rv64xandesperf.ll
@@ -60,6 +60,66 @@ 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:    nds.bfos a0, a0, 23, 16
+; 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:    nds.bfos a0, a0, 55, 16
+; 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:    nds.bfos a0, a0, 7, 5
+; 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:    nds.bfos a0, a0, 7, 5
+; 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:    nds.bfos a0, a0, 15, 11
+; 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:    nds.bfos a0, a0, 15, 11
+; 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:

``````````

</details>


https://github.com/llvm/llvm-project/pull/142303


More information about the llvm-commits mailing list