Skip to content

Commit 10b7cd6

Browse files
committed
[RISCV] Select signed and unsigned bitfield extracts for XTHeadBb
The XTHeadBb extension hab both signed and unsigned bitfield extraction instructions (TH.EXT and TH.EXTU, respectively) which have previously only been supported for sign extension on byte, halfword, and word-boundaries. This adds the infrastructure to use TH.EXT and TH.EXTU for arbitrary bitfield extraction. Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D144229
1 parent 2f88c07 commit 10b7cd6

File tree

7 files changed

+224
-29
lines changed

7 files changed

+224
-29
lines changed

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,73 @@ bool RISCVDAGToDAGISel::tryShrinkShlLogicImm(SDNode *Node) {
661661
return true;
662662
}
663663

664+
bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) {
665+
// Only supported with XTHeadBb at the moment.
666+
if (!Subtarget->hasVendorXTHeadBb())
667+
return false;
668+
669+
auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
670+
if (!N1C)
671+
return false;
672+
673+
SDValue N0 = Node->getOperand(0);
674+
if (!N0.hasOneUse())
675+
return false;
676+
677+
auto BitfieldExtract = [&](SDValue N0, unsigned Msb, unsigned Lsb, SDLoc DL,
678+
MVT VT) {
679+
return CurDAG->getMachineNode(RISCV::TH_EXT, DL, VT, N0.getOperand(0),
680+
CurDAG->getTargetConstant(Msb, DL, VT),
681+
CurDAG->getTargetConstant(Lsb, DL, VT));
682+
};
683+
684+
SDLoc DL(Node);
685+
MVT VT = Node->getSimpleValueType(0);
686+
const unsigned RightShAmt = N1C->getZExtValue();
687+
688+
// Transform (sra (shl X, C1) C2) with C1 < C2
689+
// -> (TH.EXT X, msb, lsb)
690+
if (N0.getOpcode() == ISD::SHL) {
691+
auto *N01C = dyn_cast<ConstantSDNode>(N0->getOperand(1));
692+
if (!N01C)
693+
return false;
694+
695+
const unsigned LeftShAmt = N01C->getZExtValue();
696+
// Make sure that this is a bitfield extraction (i.e., the shift-right
697+
// amount can not be less than the left-shift).
698+
if (LeftShAmt > RightShAmt)
699+
return false;
700+
701+
const unsigned MsbPlusOne = VT.getSizeInBits() - LeftShAmt;
702+
const unsigned Msb = MsbPlusOne - 1;
703+
const unsigned Lsb = RightShAmt - LeftShAmt;
704+
705+
SDNode *TH_EXT = BitfieldExtract(N0, Msb, Lsb, DL, VT);
706+
ReplaceNode(Node, TH_EXT);
707+
return true;
708+
}
709+
710+
// Transform (sra (sext_inreg X, _), C) ->
711+
// (TH.EXT X, msb, lsb)
712+
if (N0.getOpcode() == ISD::SIGN_EXTEND_INREG) {
713+
unsigned ExtSize =
714+
cast<VTSDNode>(N0.getOperand(1))->getVT().getSizeInBits();
715+
716+
// ExtSize of 32 should use sraiw via tablegen pattern.
717+
if (ExtSize == 32)
718+
return false;
719+
720+
const unsigned Msb = ExtSize - 1;
721+
const unsigned Lsb = RightShAmt;
722+
723+
SDNode *TH_EXT = BitfieldExtract(N0, Msb, Lsb, DL, VT);
724+
ReplaceNode(Node, TH_EXT);
725+
return true;
726+
}
727+
728+
return false;
729+
}
730+
664731
void RISCVDAGToDAGISel::Select(SDNode *Node) {
665732
// If we have a custom node, we have already selected.
666733
if (Node->isMachineOpcode()) {
@@ -846,6 +913,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
846913
return;
847914
}
848915
case ISD::SRA: {
916+
if (trySignedBitfieldExtract(Node))
917+
return;
918+
849919
// Optimize (sra (sext_inreg X, i16), C) ->
850920
// (srai (slli X, (XLen-16), (XLen-16) + C)
851921
// And (sra (sext_inreg X, i8), C) ->
@@ -886,9 +956,25 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
886956
auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
887957
if (!N1C)
888958
break;
959+
uint64_t C1 = N1C->getZExtValue();
960+
const bool isC1Mask = isMask_64(C1);
961+
const bool isC1ANDI = isInt<12>(C1);
889962

890963
SDValue N0 = Node->getOperand(0);
891964

965+
auto tryUnsignedBitfieldExtract = [&](SDNode *Node, SDLoc DL, MVT VT,
966+
SDValue X, unsigned Msb,
967+
unsigned Lsb) {
968+
if (!Subtarget->hasVendorXTHeadBb())
969+
return false;
970+
971+
SDNode *TH_EXTU = CurDAG->getMachineNode(
972+
RISCV::TH_EXTU, DL, VT, X, CurDAG->getTargetConstant(Msb, DL, VT),
973+
CurDAG->getTargetConstant(Lsb, DL, VT));
974+
ReplaceNode(Node, TH_EXTU);
975+
return true;
976+
};
977+
892978
bool LeftShift = N0.getOpcode() == ISD::SHL;
893979
if (LeftShift || N0.getOpcode() == ISD::SRL) {
894980
auto *C = dyn_cast<ConstantSDNode>(N0.getOperand(1));
@@ -898,8 +984,6 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
898984
unsigned XLen = Subtarget->getXLen();
899985
assert((C2 > 0 && C2 < XLen) && "Unexpected shift amount!");
900986

901-
uint64_t C1 = N1C->getZExtValue();
902-
903987
// Keep track of whether this is a c.andi. If we can't use c.andi, the
904988
// shift pair might offer more compression opportunities.
905989
// TODO: We could check for C extension here, but we don't have many lit
@@ -922,7 +1006,7 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
9221006

9231007
// Turn (and (srl x, c2) c1) -> (srli (slli x, c3-c2), c3) if c1 is a mask
9241008
// with c3 leading zeros.
925-
if (!LeftShift && isMask_64(C1)) {
1009+
if (!LeftShift && isC1Mask) {
9261010
unsigned Leading = XLen - llvm::bit_width(C1);
9271011
if (C2 < Leading) {
9281012
// If the number of leading zeros is C2+32 this can be SRLIW.
@@ -951,6 +1035,18 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
9511035
return;
9521036
}
9531037

1038+
// Try to use an unsigned bitfield extract (e.g., th.extu) if
1039+
// available.
1040+
// Transform (and (srl x, C2), C1)
1041+
// -> (<bfextract> x, msb, lsb)
1042+
//
1043+
// Make sure to keep this below the SRLIW cases, as we always want to
1044+
// prefer the more common instruction.
1045+
const unsigned Msb = llvm::bit_width(C1) + C2 - 1;
1046+
const unsigned Lsb = C2;
1047+
if (tryUnsignedBitfieldExtract(Node, DL, VT, X, Msb, Lsb))
1048+
return;
1049+
9541050
// (srli (slli x, c3-c2), c3).
9551051
// Skip if we could use (zext.w (sraiw X, C2)).
9561052
bool Skip = Subtarget->hasStdExtZba() && Leading == 32 &&
@@ -1068,6 +1164,17 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
10681164
}
10691165
}
10701166

1167+
// If C1 masks off the upper bits only (but can't be formed as an
1168+
// ANDI), use an unsigned bitfield extract (e.g., th.extu), if
1169+
// available.
1170+
// Transform (and x, C1)
1171+
// -> (<bfextract> x, msb, lsb)
1172+
if (isC1Mask && !isC1ANDI) {
1173+
const unsigned Msb = llvm::bit_width(C1) - 1;
1174+
if (tryUnsignedBitfieldExtract(Node, DL, VT, N0, Msb, 0))
1175+
return;
1176+
}
1177+
10711178
if (tryShrinkShlLogicImm(Node))
10721179
return;
10731180

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
5151
bool SelectAddrRegImm(SDValue Addr, SDValue &Base, SDValue &Offset);
5252

5353
bool tryShrinkShlLogicImm(SDNode *Node);
54+
bool trySignedBitfieldExtract(SDNode *Node);
5455

5556
bool selectShiftMask(SDValue N, unsigned ShiftWidth, SDValue &ShAmt);
5657
bool selectShiftMaskXLen(SDValue N, SDValue &ShAmt) {

llvm/lib/Target/RISCV/RISCVInstrInfoXTHead.td

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,10 +315,6 @@ def : Pat<(rotr GPR:$rs1, GPR:$rs2),
315315
def : Pat<(rotl GPR:$rs1, GPR:$rs2),
316316
(OR (SLL GPR:$rs1, GPR:$rs2),
317317
(SRL GPR:$rs1, (SUB X0, GPR:$rs2)))>;
318-
//def : Pat<(and GPR:$rs1, 1), (TH_EXTU GPR:$rs1, 0, 0)>;
319-
//def : Pat<(and GPR:$rs1, 0xff), (TH_EXTU GPR:$rs1, 7, 0)>;
320-
def : Pat<(and GPR:$rs1, 0xffff), (TH_EXTU GPR:$rs1, 15, 0)>;
321-
def : Pat<(and GPR:$rs1, 0xffffffff), (TH_EXTU GPR:$rs1, 31, 0)>;
322318
def : Pat<(sext_inreg GPR:$rs1, i32), (TH_EXT GPR:$rs1, 31, 0)>;
323319
def : Pat<(sext_inreg GPR:$rs1, i16), (TH_EXT GPR:$rs1, 15, 0)>;
324320
def : Pat<(sext_inreg GPR:$rs1, i8), (TH_EXT GPR:$rs1, 7, 0)>;

llvm/test/CodeGen/RISCV/bitextract-mac.ll

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,8 @@ define i32 @f(i32 %A, i32 %B, i32 %C) {
4646
; RV32XTHEADBB-LABEL: f:
4747
; RV32XTHEADBB: # %bb.0: # %entry
4848
; RV32XTHEADBB-NEXT: mul a0, a1, a0
49-
; RV32XTHEADBB-NEXT: slli a1, a0, 26
50-
; RV32XTHEADBB-NEXT: srli a1, a1, 28
51-
; RV32XTHEADBB-NEXT: slli a0, a0, 20
52-
; RV32XTHEADBB-NEXT: srli a0, a0, 25
49+
; RV32XTHEADBB-NEXT: th.extu a1, a0, 5, 2
50+
; RV32XTHEADBB-NEXT: th.extu a0, a0, 11, 5
5351
; RV32XTHEADBB-NEXT: mul a0, a1, a0
5452
; RV32XTHEADBB-NEXT: add a0, a0, a2
5553
; RV32XTHEADBB-NEXT: ret
@@ -68,10 +66,8 @@ define i32 @f(i32 %A, i32 %B, i32 %C) {
6866
; RV32XTHEAD-LABEL: f:
6967
; RV32XTHEAD: # %bb.0: # %entry
7068
; RV32XTHEAD-NEXT: mul a0, a1, a0
71-
; RV32XTHEAD-NEXT: slli a1, a0, 26
72-
; RV32XTHEAD-NEXT: srli a1, a1, 28
73-
; RV32XTHEAD-NEXT: slli a0, a0, 20
74-
; RV32XTHEAD-NEXT: srli a0, a0, 25
69+
; RV32XTHEAD-NEXT: th.extu a1, a0, 5, 2
70+
; RV32XTHEAD-NEXT: th.extu a0, a0, 11, 5
7571
; RV32XTHEAD-NEXT: th.mulah a2, a1, a0
7672
; RV32XTHEAD-NEXT: mv a0, a2
7773
; RV32XTHEAD-NEXT: ret
@@ -111,22 +107,18 @@ define i32 @f(i32 %A, i32 %B, i32 %C) {
111107
;
112108
; RV64XTHEADBB-LABEL: f:
113109
; RV64XTHEADBB: # %bb.0: # %entry
114-
; RV64XTHEADBB-NEXT: mulw a0, a1, a0
115-
; RV64XTHEADBB-NEXT: slli a1, a0, 58
116-
; RV64XTHEADBB-NEXT: srli a1, a1, 60
117-
; RV64XTHEADBB-NEXT: slli a0, a0, 52
118-
; RV64XTHEADBB-NEXT: srli a0, a0, 57
110+
; RV64XTHEADBB-NEXT: mul a0, a1, a0
111+
; RV64XTHEADBB-NEXT: th.extu a1, a0, 5, 2
112+
; RV64XTHEADBB-NEXT: th.extu a0, a0, 11, 5
119113
; RV64XTHEADBB-NEXT: mulw a0, a1, a0
120114
; RV64XTHEADBB-NEXT: addw a0, a0, a2
121115
; RV64XTHEADBB-NEXT: ret
122116
;
123117
; RV64XTHEAD-LABEL: f:
124118
; RV64XTHEAD: # %bb.0: # %entry
125-
; RV64XTHEAD-NEXT: mulw a0, a1, a0
126-
; RV64XTHEAD-NEXT: slli a1, a0, 58
127-
; RV64XTHEAD-NEXT: srli a1, a1, 60
128-
; RV64XTHEAD-NEXT: slli a0, a0, 52
129-
; RV64XTHEAD-NEXT: srli a0, a0, 57
119+
; RV64XTHEAD-NEXT: mul a0, a1, a0
120+
; RV64XTHEAD-NEXT: th.extu a1, a0, 5, 2
121+
; RV64XTHEAD-NEXT: th.extu a0, a0, 11, 5
130122
; RV64XTHEAD-NEXT: th.mulah a2, a1, a0
131123
; RV64XTHEAD-NEXT: mv a0, a2
132124
; RV64XTHEAD-NEXT: ret

llvm/test/CodeGen/RISCV/rotl-rotr.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,8 +1623,7 @@ define signext i64 @rotl_64_mask_shared(i64 signext %a, i64 signext %b, i64 sign
16231623
;
16241624
; RV32XTHEADBB-LABEL: rotl_64_mask_shared:
16251625
; RV32XTHEADBB: # %bb.0:
1626-
; RV32XTHEADBB-NEXT: slli a5, a4, 26
1627-
; RV32XTHEADBB-NEXT: srli a5, a5, 31
1626+
; RV32XTHEADBB-NEXT: th.extu a5, a4, 5, 5
16281627
; RV32XTHEADBB-NEXT: mv a7, a0
16291628
; RV32XTHEADBB-NEXT: bnez a5, .LBB17_2
16301629
; RV32XTHEADBB-NEXT: # %bb.1:
@@ -2098,8 +2097,7 @@ define i64 @rotl_64_mask_multiple(i64 %a, i64 %b, i64 %amt) nounwind {
20982097
;
20992098
; RV32XTHEADBB-LABEL: rotl_64_mask_multiple:
21002099
; RV32XTHEADBB: # %bb.0:
2101-
; RV32XTHEADBB-NEXT: slli a5, a4, 26
2102-
; RV32XTHEADBB-NEXT: srli a5, a5, 31
2100+
; RV32XTHEADBB-NEXT: th.extu a5, a4, 5, 5
21032101
; RV32XTHEADBB-NEXT: mv a6, a1
21042102
; RV32XTHEADBB-NEXT: bnez a5, .LBB21_2
21052103
; RV32XTHEADBB-NEXT: # %bb.1:

llvm/test/CodeGen/RISCV/rv32xtheadbb.ll

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,23 @@ define i32 @sexth_i32(i32 %a) nounwind {
338338
ret i32 %shr
339339
}
340340

341+
define i32 @no_sexth_i32(i32 %a) nounwind {
342+
; RV32I-LABEL: no_sexth_i32:
343+
; RV32I: # %bb.0:
344+
; RV32I-NEXT: slli a0, a0, 17
345+
; RV32I-NEXT: srai a0, a0, 16
346+
; RV32I-NEXT: ret
347+
;
348+
; RV32XTHEADBB-LABEL: no_sexth_i32:
349+
; RV32XTHEADBB: # %bb.0:
350+
; RV32XTHEADBB-NEXT: slli a0, a0, 17
351+
; RV32XTHEADBB-NEXT: srai a0, a0, 16
352+
; RV32XTHEADBB-NEXT: ret
353+
%shl = shl i32 %a, 17
354+
%shr = ashr exact i32 %shl, 16
355+
ret i32 %shr
356+
}
357+
341358
define i64 @sexth_i64(i64 %a) nounwind {
342359
; RV32I-LABEL: sexth_i64:
343360
; RV32I: # %bb.0:
@@ -356,6 +373,25 @@ define i64 @sexth_i64(i64 %a) nounwind {
356373
ret i64 %shr
357374
}
358375

376+
define i64 @no_sexth_i64(i64 %a) nounwind {
377+
; RV32I-LABEL: no_sexth_i64:
378+
; RV32I: # %bb.0:
379+
; RV32I-NEXT: slli a1, a0, 17
380+
; RV32I-NEXT: srai a0, a1, 16
381+
; RV32I-NEXT: srai a1, a1, 31
382+
; RV32I-NEXT: ret
383+
;
384+
; RV32XTHEADBB-LABEL: no_sexth_i64:
385+
; RV32XTHEADBB: # %bb.0:
386+
; RV32XTHEADBB-NEXT: slli a1, a0, 17
387+
; RV32XTHEADBB-NEXT: srai a0, a1, 16
388+
; RV32XTHEADBB-NEXT: srai a1, a1, 31
389+
; RV32XTHEADBB-NEXT: ret
390+
%shl = shl i64 %a, 49
391+
%shr = ashr exact i64 %shl, 48
392+
ret i64 %shr
393+
}
394+
359395
define i32 @zexth_i32(i32 %a) nounwind {
360396
; RV32I-LABEL: zexth_i32:
361397
; RV32I: # %bb.0:

llvm/test/CodeGen/RISCV/rv64xtheadbb.ll

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,23 @@ define signext i32 @sexth_i32(i32 signext %a) nounwind {
627627
ret i32 %shr
628628
}
629629

630+
define signext i32 @no_sexth_i32(i32 signext %a) nounwind {
631+
; RV64I-LABEL: no_sexth_i32:
632+
; RV64I: # %bb.0:
633+
; RV64I-NEXT: slli a0, a0, 49
634+
; RV64I-NEXT: srai a0, a0, 48
635+
; RV64I-NEXT: ret
636+
;
637+
; RV64XTHEADBB-LABEL: no_sexth_i32:
638+
; RV64XTHEADBB: # %bb.0:
639+
; RV64XTHEADBB-NEXT: slli a0, a0, 49
640+
; RV64XTHEADBB-NEXT: srai a0, a0, 48
641+
; RV64XTHEADBB-NEXT: ret
642+
%shl = shl i32 %a, 17
643+
%shr = ashr exact i32 %shl, 16
644+
ret i32 %shr
645+
}
646+
630647
define i64 @sexth_i64(i64 %a) nounwind {
631648
; RV64I-LABEL: sexth_i64:
632649
; RV64I: # %bb.0:
@@ -643,6 +660,23 @@ define i64 @sexth_i64(i64 %a) nounwind {
643660
ret i64 %shr
644661
}
645662

663+
define i64 @no_sexth_i64(i64 %a) nounwind {
664+
; RV64I-LABEL: no_sexth_i64:
665+
; RV64I: # %bb.0:
666+
; RV64I-NEXT: slli a0, a0, 49
667+
; RV64I-NEXT: srai a0, a0, 48
668+
; RV64I-NEXT: ret
669+
;
670+
; RV64XTHEADBB-LABEL: no_sexth_i64:
671+
; RV64XTHEADBB: # %bb.0:
672+
; RV64XTHEADBB-NEXT: slli a0, a0, 49
673+
; RV64XTHEADBB-NEXT: srai a0, a0, 48
674+
; RV64XTHEADBB-NEXT: ret
675+
%shl = shl i64 %a, 49
676+
%shr = ashr exact i64 %shl, 48
677+
ret i64 %shr
678+
}
679+
646680
define i32 @zexth_i32(i32 %a) nounwind {
647681
; RV64I-LABEL: zexth_i32:
648682
; RV64I: # %bb.0:
@@ -673,6 +707,37 @@ define i64 @zexth_i64(i64 %a) nounwind {
673707
ret i64 %and
674708
}
675709

710+
define i64 @zext_bf_i64(i64 %a) nounwind {
711+
; RV64I-LABEL: zext_bf_i64:
712+
; RV64I: # %bb.0:
713+
; RV64I-NEXT: slli a0, a0, 47
714+
; RV64I-NEXT: srli a0, a0, 48
715+
; RV64I-NEXT: ret
716+
;
717+
; RV64XTHEADBB-LABEL: zext_bf_i64:
718+
; RV64XTHEADBB: # %bb.0:
719+
; RV64XTHEADBB-NEXT: th.extu a0, a0, 16, 1
720+
; RV64XTHEADBB-NEXT: ret
721+
%1 = lshr i64 %a, 1
722+
%and = and i64 %1, 65535
723+
ret i64 %and
724+
}
725+
726+
define i64 @zext_i64_srliw(i64 %a) nounwind {
727+
; RV64I-LABEL: zext_i64_srliw:
728+
; RV64I: # %bb.0:
729+
; RV64I-NEXT: srliw a0, a0, 16
730+
; RV64I-NEXT: ret
731+
;
732+
; RV64XTHEADBB-LABEL: zext_i64_srliw:
733+
; RV64XTHEADBB: # %bb.0:
734+
; RV64XTHEADBB-NEXT: srliw a0, a0, 16
735+
; RV64XTHEADBB-NEXT: ret
736+
%1 = lshr i64 %a, 16
737+
%and = and i64 %1, 65535
738+
ret i64 %and
739+
}
740+
676741
declare i32 @llvm.bswap.i32(i32)
677742

678743
define signext i32 @bswap_i32(i32 signext %a) nounwind {

0 commit comments

Comments
 (0)