Skip to content

Commit 94c2416

Browse files
authored
[RISCV] Select signed bitfield extract for Xqcibm (#143536)
The Xqcibm Bit Manipulation extension has the `qc.ext` instruction that can extract a subset of bits from the source register to the destination register. Unlike the corresponding instructions in `XTHeadbb` and `XAndesPerf` which extract the bits between `Msb` and `Lsb`, the `qc.ext` instruction extracts `width` bits from an offset that is determined by the `shamt`.
1 parent 8f80a37 commit 94c2416

File tree

2 files changed

+70
-10
lines changed

2 files changed

+70
-10
lines changed

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,16 @@ bool RISCVDAGToDAGISel::tryShrinkShlLogicImm(SDNode *Node) {
601601
}
602602

603603
bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) {
604-
// Only supported with XTHeadBb/XAndesPerf at the moment.
605-
if (!Subtarget->hasVendorXTHeadBb() && !Subtarget->hasVendorXAndesPerf())
604+
unsigned Opc;
605+
606+
if (Subtarget->hasVendorXTHeadBb())
607+
Opc = RISCV::TH_EXT;
608+
else if (Subtarget->hasVendorXAndesPerf())
609+
Opc = RISCV::NDS_BFOS;
610+
else if (Subtarget->hasVendorXqcibm())
611+
Opc = RISCV::QC_EXT;
612+
else
613+
// Only supported with XTHeadBb/XAndesPerf/Xqcibm at the moment.
606614
return false;
607615

608616
auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
@@ -615,8 +623,12 @@ bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) {
615623

616624
auto BitfieldExtract = [&](SDValue N0, unsigned Msb, unsigned Lsb,
617625
const SDLoc &DL, MVT VT) {
618-
unsigned Opc =
619-
Subtarget->hasVendorXTHeadBb() ? RISCV::TH_EXT : RISCV::NDS_BFOS;
626+
if (Opc == RISCV::QC_EXT) {
627+
// QC.EXT X, width, shamt
628+
// shamt is the same as Lsb
629+
// width is the number of bits to extract from the Lsb
630+
Msb = Msb - Lsb + 1;
631+
}
620632
return CurDAG->getMachineNode(Opc, DL, VT, N0.getOperand(0),
621633
CurDAG->getTargetConstant(Msb, DL, VT),
622634
CurDAG->getTargetConstant(Lsb, DL, VT));
@@ -627,7 +639,7 @@ bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) {
627639
const unsigned RightShAmt = N1C->getZExtValue();
628640

629641
// Transform (sra (shl X, C1) C2) with C1 < C2
630-
// -> (TH.EXT X, msb, lsb)
642+
// -> (SignedBitfieldExtract X, msb, lsb)
631643
if (N0.getOpcode() == ISD::SHL) {
632644
auto *N01C = dyn_cast<ConstantSDNode>(N0->getOperand(1));
633645
if (!N01C)
@@ -643,13 +655,13 @@ bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) {
643655
const unsigned Msb = MsbPlusOne - 1;
644656
const unsigned Lsb = RightShAmt - LeftShAmt;
645657

646-
SDNode *TH_EXT = BitfieldExtract(N0, Msb, Lsb, DL, VT);
647-
ReplaceNode(Node, TH_EXT);
658+
SDNode *Sbe = BitfieldExtract(N0, Msb, Lsb, DL, VT);
659+
ReplaceNode(Node, Sbe);
648660
return true;
649661
}
650662

651663
// Transform (sra (sext_inreg X, _), C) ->
652-
// (TH.EXT X, msb, lsb)
664+
// (SignedBitfieldExtract X, msb, lsb)
653665
if (N0.getOpcode() == ISD::SIGN_EXTEND_INREG) {
654666
unsigned ExtSize =
655667
cast<VTSDNode>(N0.getOperand(1))->getVT().getSizeInBits();
@@ -663,8 +675,8 @@ bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) {
663675
// the X[Msb] bit and sign-extend it.
664676
const unsigned Lsb = RightShAmt > Msb ? Msb : RightShAmt;
665677

666-
SDNode *TH_EXT = BitfieldExtract(N0, Msb, Lsb, DL, VT);
667-
ReplaceNode(Node, TH_EXT);
678+
SDNode *Sbe = BitfieldExtract(N0, Msb, Lsb, DL, VT);
679+
ReplaceNode(Node, Sbe);
668680
return true;
669681
}
670682

llvm/test/CodeGen/RISCV/xqcibm-extract.ll

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,3 +331,51 @@ define i64 @extu_from_lshr_and_i64(i64 %x) {
331331
%shifted = lshr i64 %masked, 12
332332
ret i64 %shifted
333333
}
334+
335+
define i32 @ext_from_ashr_shl_i32(i32 %x) {
336+
; RV32I-LABEL: ext_from_ashr_shl_i32:
337+
; RV32I: # %bb.0:
338+
; RV32I-NEXT: slli a0, a0, 8
339+
; RV32I-NEXT: srai a0, a0, 24
340+
; RV32I-NEXT: ret
341+
;
342+
; RV32XQCIBM-LABEL: ext_from_ashr_shl_i32:
343+
; RV32XQCIBM: # %bb.0:
344+
; RV32XQCIBM-NEXT: qc.ext a0, a0, 8, 16
345+
; RV32XQCIBM-NEXT: ret
346+
%shl = shl i32 %x, 8
347+
%ashr = ashr i32 %shl, 24
348+
ret i32 %ashr
349+
}
350+
351+
define i32 @ext_from_ashr_sexti8_i32(i8 %x) {
352+
; RV32I-LABEL: ext_from_ashr_sexti8_i32:
353+
; RV32I: # %bb.0:
354+
; RV32I-NEXT: slli a0, a0, 24
355+
; RV32I-NEXT: srai a0, a0, 29
356+
; RV32I-NEXT: ret
357+
;
358+
; RV32XQCIBM-LABEL: ext_from_ashr_sexti8_i32:
359+
; RV32XQCIBM: # %bb.0:
360+
; RV32XQCIBM-NEXT: qc.ext a0, a0, 3, 5
361+
; RV32XQCIBM-NEXT: ret
362+
%sext = sext i8 %x to i32
363+
%ashr = ashr i32 %sext, 5
364+
ret i32 %ashr
365+
}
366+
367+
define i32 @ext_from_ashr_sexti16_i32(i16 %x) {
368+
; RV32I-LABEL: ext_from_ashr_sexti16_i32:
369+
; RV32I: # %bb.0:
370+
; RV32I-NEXT: slli a0, a0, 16
371+
; RV32I-NEXT: srai a0, a0, 31
372+
; RV32I-NEXT: ret
373+
;
374+
; RV32XQCIBM-LABEL: ext_from_ashr_sexti16_i32:
375+
; RV32XQCIBM: # %bb.0:
376+
; RV32XQCIBM-NEXT: qc.ext a0, a0, 1, 15
377+
; RV32XQCIBM-NEXT: ret
378+
%sext = sext i16 %x to i32
379+
%ashr = ashr i32 %sext, 24
380+
ret i32 %ashr
381+
}

0 commit comments

Comments
 (0)