-
Notifications
You must be signed in to change notification settings - Fork 13.7k
[RISCV] Select signed bitfield insert for XAndesPerf #143356
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-backend-risc-v Author: Jim Lin (tclin914) ChangesThis patch is similar to #142737 The XAndesPerf extension includes signed bitfield extraction When Lsb == Msb, it is a special case where the Lsb will be set to 0 instead of Full diff: https://github.com/llvm/llvm-project/pull/143356.diff 4 Files Affected:
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 494d6ed03292a..1bed4051c09e6 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -671,6 +671,59 @@ bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) {
return false;
}
+bool RISCVDAGToDAGISel::trySignedBitfieldInsertInSign(SDNode *Node) {
+ // Only supported with XAndesPerf at the moment.
+ if (!Subtarget->hasVendorXAndesPerf())
+ return false;
+
+ auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
+ if (!N1C)
+ return false;
+
+ SDValue N0 = Node->getOperand(0);
+ if (!N0.hasOneUse())
+ return false;
+
+ auto BitfieldInsert = [&](SDValue N0, unsigned Msb, unsigned Lsb, SDLoc DL,
+ MVT VT) {
+ unsigned Opc = RISCV::NDS_BFOS;
+ // If the Lsb is equal to the Msb, then the Lsb should be 0.
+ if (Lsb == Msb)
+ Lsb = 0;
+ return CurDAG->getMachineNode(Opc, DL, VT, N0.getOperand(0),
+ CurDAG->getTargetConstant(Lsb, DL, VT),
+ CurDAG->getTargetConstant(Msb, DL, VT));
+ };
+
+ SDLoc DL(Node);
+ MVT VT = Node->getSimpleValueType(0);
+ const unsigned RightShAmt = N1C->getZExtValue();
+
+ // Transform (sra (shl X, C1) C2) with C1 > C2
+ // -> (NDS.BFOS X, lsb, msb)
+ if (N0.getOpcode() == ISD::SHL) {
+ auto *N01C = dyn_cast<ConstantSDNode>(N0->getOperand(1));
+ if (!N01C)
+ return false;
+
+ const unsigned LeftShAmt = N01C->getZExtValue();
+ // Make sure that this is a bitfield insertion (i.e., the shift-right
+ // amount should be less than the left-shift).
+ if (LeftShAmt <= RightShAmt)
+ return false;
+
+ const unsigned MsbPlusOne = VT.getSizeInBits() - RightShAmt;
+ const unsigned Msb = MsbPlusOne - 1;
+ const unsigned Lsb = LeftShAmt - RightShAmt;
+
+ SDNode *Sbi = BitfieldInsert(N0, Msb, Lsb, DL, VT);
+ ReplaceNode(Node, Sbi);
+ return true;
+ }
+
+ return false;
+}
+
bool RISCVDAGToDAGISel::tryUnsignedBitfieldExtract(SDNode *Node, SDLoc DL,
MVT VT, SDValue X,
unsigned Msb, unsigned Lsb) {
@@ -1191,6 +1244,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
if (trySignedBitfieldExtract(Node))
return;
+ if (trySignedBitfieldInsertInSign(Node))
+ return;
+
// Optimize (sra (sext_inreg X, i16), C) ->
// (srai (slli X, (XLen-16), (XLen-16) + C)
// And (sra (sext_inreg X, i8), C) ->
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
index f199c2031b9a9..80deac2be12fc 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -77,6 +77,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
bool tryShrinkShlLogicImm(SDNode *Node);
bool trySignedBitfieldExtract(SDNode *Node);
+ bool trySignedBitfieldInsertInSign(SDNode *Node);
bool tryUnsignedBitfieldExtract(SDNode *Node, SDLoc DL, MVT VT, SDValue X,
unsigned Msb, unsigned Lsb);
bool tryUnsignedBitfieldInsertInZero(SDNode *Node, SDLoc DL, MVT VT,
diff --git a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
index 3996420d477b2..3e7f09f3d6c22 100644
--- a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
+++ b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
@@ -154,6 +154,32 @@ define i32 @bfos_from_ashr_sexti16_i32(i16 %x) {
ret i32 %ashr
}
+; MSB = 0
+
+define i32 @bfos_from_ashr_shl_with_msb_zero_insert_i32(i32 %x) {
+; CHECK-LABEL: bfos_from_ashr_shl_with_msb_zero_insert_i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: nds.bfos a0, a0, 0, 14
+; CHECK-NEXT: ret
+ %shl = shl i32 %x, 31
+ %lshr = ashr i32 %shl, 17
+ ret i32 %lshr
+}
+
+; MSB < LSB
+
+define i32 @bfos_from_ashr_shl_insert_i32(i32 %x) {
+; CHECK-LABEL: bfos_from_ashr_shl_insert_i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: nds.bfos a0, a0, 18, 20
+; CHECK-NEXT: ret
+ %shl = shl i32 %x, 29
+ %lshr = ashr i32 %shl, 11
+ ret i32 %lshr
+}
+
+; sext
+
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 af7c300a92d1f..98cda42665169 100644
--- a/llvm/test/CodeGen/RISCV/rv64xandesperf.ll
+++ b/llvm/test/CodeGen/RISCV/rv64xandesperf.ll
@@ -212,6 +212,52 @@ define i64 @bfos_from_ashr_sexti16_i64(i16 %x) {
ret i64 %ashr
}
+; MSB = 0
+
+define i32 @bfos_from_ashr_shl_with_msb_zero_insert_i32(i32 %x) {
+; CHECK-LABEL: bfos_from_ashr_shl_with_msb_zero_insert_i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: nds.bfos a0, a0, 0, 14
+; CHECK-NEXT: ret
+ %shl = shl i32 %x, 31
+ %lshr = ashr i32 %shl, 17
+ ret i32 %lshr
+}
+
+define i64 @bfos_from_ashr_shl_with_msb_zero_insert_i64(i64 %x) {
+; CHECK-LABEL: bfos_from_ashr_shl_with_msb_zero_insert_i64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: nds.bfos a0, a0, 0, 46
+; CHECK-NEXT: ret
+ %shl = shl i64 %x, 63
+ %lshr = ashr i64 %shl, 17
+ ret i64 %lshr
+}
+
+; MSB < LSB
+
+define i32 @bfos_from_ashr_shl_insert_i32(i32 %x) {
+; CHECK-LABEL: bfos_from_ashr_shl_insert_i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: nds.bfos a0, a0, 18, 20
+; CHECK-NEXT: ret
+ %shl = shl i32 %x, 29
+ %lshr = ashr i32 %shl, 11
+ ret i32 %lshr
+}
+
+define i64 @bfos_from_ashr_shl_insert_i64(i64 %x) {
+; CHECK-LABEL: bfos_from_ashr_shl_insert_i64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: nds.bfos a0, a0, 18, 52
+; CHECK-NEXT: ret
+ %shl = shl i64 %x, 29
+ %lshr = ashr i64 %shl, 11
+ ret i64 %lshr
+}
+
+; sext
+
define signext i32 @sexti1_i32(i32 signext %a) {
; CHECK-LABEL: sexti1_i32:
; CHECK: # %bb.0:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This patch is similar to #142737
The XAndesPerf extension includes signed bitfield extraction
instruction `NDS.BFOS, which can extract the bits from 0 to Len - 1,
place them starting at bit Lsb, zero-filled the bits from 0 to Lsb -1,
and sign-extend the result.
When Lsb == Msb, it is a special case where the Lsb will be set to 0 instead of
being equal to the Msb.