Skip to content

[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

Merged
merged 3 commits into from
Jun 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,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,
const 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,
const SDLoc &DL, MVT VT,
SDValue X, unsigned Msb,
Expand Down Expand Up @@ -1214,6 +1267,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) ->
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {

bool tryShrinkShlLogicImm(SDNode *Node);
bool trySignedBitfieldExtract(SDNode *Node);
bool trySignedBitfieldInsertInSign(SDNode *Node);
bool tryUnsignedBitfieldExtract(SDNode *Node, const SDLoc &DL, MVT VT,
SDValue X, unsigned Msb, unsigned Lsb);
bool tryUnsignedBitfieldInsertInZero(SDNode *Node, const SDLoc &DL, MVT VT,
Expand Down
26 changes: 26 additions & 0 deletions llvm/test/CodeGen/RISCV/rv32xandesperf.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
46 changes: 46 additions & 0 deletions llvm/test/CodeGen/RISCV/rv64xandesperf.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading