Skip to content

Commit 2ef7c4c

Browse files
committed
[LoongArch] Perform and combination with a shifted mask
Differential Revision: https://reviews.llvm.org/D127206
1 parent 709e4ad commit 2ef7c4c

File tree

7 files changed

+210
-6
lines changed

7 files changed

+210
-6
lines changed

llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "LoongArchISelDAGToDAG.h"
14+
#include "LoongArchISelLowering.h"
1415
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
1516
#include "MCTargetDesc/LoongArchMatInt.h"
1617
#include "llvm/Support/KnownBits.h"
@@ -91,6 +92,17 @@ bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
9192
ShAmt = N.getOperand(0);
9293
return true;
9394
}
95+
} else if (N.getOpcode() == LoongArchISD::BSTRPICK) {
96+
// Similar to the above AND, if there is a BSTRPICK on the shift amount, we
97+
// can bypass it.
98+
assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
99+
assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!");
100+
assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!");
101+
uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2);
102+
if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) {
103+
ShAmt = N.getOperand(0);
104+
return true;
105+
}
94106
} else if (N.getOpcode() == ISD::SUB &&
95107
isa<ConstantSDNode>(N.getOperand(0))) {
96108
uint64_t Imm = N.getConstantOperandVal(0);

llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
7272
// Function alignments.
7373
const Align FunctionAlignment(4);
7474
setMinFunctionAlignment(FunctionAlignment);
75+
76+
setTargetDAGCombine(ISD::AND);
7577
}
7678

7779
SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
@@ -237,6 +239,81 @@ void LoongArchTargetLowering::ReplaceNodeResults(
237239
}
238240
}
239241

242+
static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG,
243+
TargetLowering::DAGCombinerInfo &DCI,
244+
const LoongArchSubtarget &Subtarget) {
245+
if (DCI.isBeforeLegalizeOps())
246+
return SDValue();
247+
248+
SDValue FirstOperand = N->getOperand(0);
249+
SDValue SecondOperand = N->getOperand(1);
250+
unsigned FirstOperandOpc = FirstOperand.getOpcode();
251+
EVT ValTy = N->getValueType(0);
252+
SDLoc DL(N);
253+
uint64_t lsb, msb;
254+
unsigned SMIdx, SMLen;
255+
ConstantSDNode *CN;
256+
SDValue NewOperand;
257+
MVT GRLenVT = Subtarget.getGRLenVT();
258+
259+
// Op's second operand must be a shifted mask.
260+
if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
261+
!isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
262+
return SDValue();
263+
264+
if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
265+
// Pattern match BSTRPICK.
266+
// $dst = and ((sra or srl) $src , lsb), (2**len - 1)
267+
// => BSTRPICK $dst, $src, msb, lsb
268+
// where msb = lsb + len - 1
269+
270+
// The second operand of the shift must be an immediate.
271+
if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
272+
return SDValue();
273+
274+
lsb = CN->getZExtValue();
275+
276+
// Return if the shifted mask does not start at bit 0 or the sum of its
277+
// length and lsb exceeds the word's size.
278+
if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
279+
return SDValue();
280+
281+
NewOperand = FirstOperand.getOperand(0);
282+
} else {
283+
// Pattern match BSTRPICK.
284+
// $dst = and $src, (2**len- 1) , if len > 12
285+
// => BSTRPICK $dst, $src, msb, lsb
286+
// where lsb = 0 and msb = len - 1
287+
288+
// If the mask is <= 0xfff, andi can be used instead.
289+
if (CN->getZExtValue() <= 0xfff)
290+
return SDValue();
291+
292+
// Return if the mask doesn't start at position 0.
293+
if (SMIdx)
294+
return SDValue();
295+
296+
lsb = 0;
297+
NewOperand = FirstOperand;
298+
}
299+
msb = lsb + SMLen - 1;
300+
return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
301+
DAG.getConstant(msb, DL, GRLenVT),
302+
DAG.getConstant(lsb, DL, GRLenVT));
303+
}
304+
305+
SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N,
306+
DAGCombinerInfo &DCI) const {
307+
SelectionDAG &DAG = DCI.DAG;
308+
switch (N->getOpcode()) {
309+
default:
310+
break;
311+
case ISD::AND:
312+
return performANDCombine(N, DAG, DCI, Subtarget);
313+
}
314+
return SDValue();
315+
}
316+
240317
const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
241318
switch ((LoongArchISD::NodeType)Opcode) {
242319
case LoongArchISD::FIRST_NUMBER:
@@ -251,6 +328,7 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
251328
NODE_NAME_CASE(SLL_W)
252329
NODE_NAME_CASE(SRA_W)
253330
NODE_NAME_CASE(SRL_W)
331+
NODE_NAME_CASE(BSTRPICK)
254332
}
255333
#undef NODE_NAME_CASE
256334
return nullptr;

llvm/lib/Target/LoongArch/LoongArchISelLowering.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ enum NodeType : unsigned {
3434
SRA_W,
3535
SRL_W,
3636

37+
BSTRPICK,
38+
3739
};
3840
} // namespace LoongArchISD
3941

@@ -51,6 +53,8 @@ class LoongArchTargetLowering : public TargetLowering {
5153
void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue> &Results,
5254
SelectionDAG &DAG) const override;
5355

56+
SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override;
57+
5458
// This method returns the name of a target specific DAG node.
5559
const char *getTargetNodeName(unsigned Opcode) const override;
5660

llvm/lib/Target/LoongArch/LoongArchInstrInfo.td

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,19 @@ def SDT_LoongArchIntBinOpW : SDTypeProfile<1, 2, [
1919
SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisVT<0, i64>
2020
]>;
2121

22+
def SDT_LoongArchBStrPick: SDTypeProfile<1, 3, [
23+
SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisInt<2>, SDTCisSameAs<2, 3>
24+
]>;
25+
2226
// TODO: Add LoongArch specific DAG Nodes
2327
// Target-dependent nodes.
2428
def loongarch_ret : SDNode<"LoongArchISD::RET", SDTNone,
2529
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
2630
def loongarch_sll_w : SDNode<"LoongArchISD::SLL_W", SDT_LoongArchIntBinOpW>;
2731
def loongarch_sra_w : SDNode<"LoongArchISD::SRA_W", SDT_LoongArchIntBinOpW>;
2832
def loongarch_srl_w : SDNode<"LoongArchISD::SRL_W", SDT_LoongArchIntBinOpW>;
33+
def loongarch_bstrpick
34+
: SDNode<"LoongArchISD::BSTRPICK", SDT_LoongArchBStrPick>;
2935

3036
//===----------------------------------------------------------------------===//
3137
// Operand and SDNode transformation definitions.
@@ -647,6 +653,16 @@ let isBarrier = 1, isReturn = 1, isTerminator = 1 in
647653
def PseudoRET : Pseudo<(outs), (ins), [(loongarch_ret)]>,
648654
PseudoInstExpansion<(JIRL R0, R1, 0)>;
649655

656+
/// BSTRPICK
657+
658+
let Predicates = [IsLA32] in
659+
def : Pat<(loongarch_bstrpick GPR:$rj, uimm5:$msbd, uimm5:$lsbd),
660+
(BSTRPICK_W GPR:$rj, uimm5:$msbd, uimm5:$lsbd)>;
661+
662+
let Predicates = [IsLA64] in
663+
def : Pat<(loongarch_bstrpick GPR:$rj, uimm6:$msbd, uimm6:$lsbd),
664+
(BSTRPICK_D GPR:$rj, uimm6:$msbd, uimm6:$lsbd)>;
665+
650666
//===----------------------------------------------------------------------===//
651667
// Assembler Pseudo Instructions
652668
//===----------------------------------------------------------------------===//
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s
2+
3+
define i64 @lshr40_and255(i64 %a) {
4+
; CHECK-LABEL: lshr40_and255:
5+
; CHECK: # %bb.0:
6+
; CHECK-NEXT: bstrpick.d $a0, $a0, 47, 40
7+
; CHECK-NEXT: jirl $zero, $ra, 0
8+
%shr = lshr i64 %a, 40
9+
%and = and i64 %shr, 255
10+
ret i64 %and
11+
}
12+
13+
define i64 @ashr50_and511(i64 %a) {
14+
; CHECK-LABEL: ashr50_and511:
15+
; CHECK: # %bb.0:
16+
; CHECK-NEXT: bstrpick.d $a0, $a0, 58, 50
17+
; CHECK-NEXT: jirl $zero, $ra, 0
18+
%shr = ashr i64 %a, 50
19+
%and = and i64 %shr, 511
20+
ret i64 %and
21+
}
22+
23+
define i64 @zext_i32_to_i64(i32 %a) {
24+
; CHECK-LABEL: zext_i32_to_i64:
25+
; CHECK: # %bb.0:
26+
; CHECK-NEXT: bstrpick.d $a0, $a0, 31, 0
27+
; CHECK-NEXT: jirl $zero, $ra, 0
28+
%res = zext i32 %a to i64
29+
ret i64 %res
30+
}
31+
32+
define i64 @and8191(i64 %a) {
33+
; CHECK-LABEL: and8191:
34+
; CHECK: # %bb.0:
35+
; CHECK-NEXT: bstrpick.d $a0, $a0, 12, 0
36+
; CHECK-NEXT: jirl $zero, $ra, 0
37+
%and = and i64 %a, 8191
38+
ret i64 %and
39+
}
40+
41+
;; Check that andi but not bstrpick.d is generated.
42+
define i64 @and4095(i64 %a) {
43+
; CHECK-LABEL: and4095:
44+
; CHECK: # %bb.0:
45+
; CHECK-NEXT: andi $a0, $a0, 4095
46+
; CHECK-NEXT: jirl $zero, $ra, 0
47+
%and = and i64 %a, 4095
48+
ret i64 %and
49+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
; RUN: llc --mtriple=loongarch32 < %s | FileCheck %s
2+
3+
define i32 @lshr40_and255(i32 %a) {
4+
; CHECK-LABEL: lshr40_and255:
5+
; CHECK: # %bb.0:
6+
; CHECK-NEXT: bstrpick.w $a0, $a0, 17, 10
7+
; CHECK-NEXT: jirl $zero, $ra, 0
8+
%shr = lshr i32 %a, 10
9+
%and = and i32 %shr, 255
10+
ret i32 %and
11+
}
12+
13+
define i32 @ashr50_and511(i32 %a) {
14+
; CHECK-LABEL: ashr50_and511:
15+
; CHECK: # %bb.0:
16+
; CHECK-NEXT: bstrpick.w $a0, $a0, 28, 20
17+
; CHECK-NEXT: jirl $zero, $ra, 0
18+
%shr = ashr i32 %a, 20
19+
%and = and i32 %shr, 511
20+
ret i32 %and
21+
}
22+
23+
define i32 @zext_i16_to_i32(i16 %a) {
24+
; CHECK-LABEL: zext_i16_to_i32:
25+
; CHECK: # %bb.0:
26+
; CHECK-NEXT: bstrpick.w $a0, $a0, 15, 0
27+
; CHECK-NEXT: jirl $zero, $ra, 0
28+
%res = zext i16 %a to i32
29+
ret i32 %res
30+
}
31+
32+
define i32 @and8191(i32 %a) {
33+
; CHECK-LABEL: and8191:
34+
; CHECK: # %bb.0:
35+
; CHECK-NEXT: bstrpick.w $a0, $a0, 12, 0
36+
; CHECK-NEXT: jirl $zero, $ra, 0
37+
%and = and i32 %a, 8191
38+
ret i32 %and
39+
}
40+
41+
;; Check that andi but not bstrpick.d is generated.
42+
define i32 @and4095(i32 %a) {
43+
; CHECK-LABEL: and4095:
44+
; CHECK: # %bb.0:
45+
; CHECK-NEXT: andi $a0, $a0, 4095
46+
; CHECK-NEXT: jirl $zero, $ra, 0
47+
%and = and i32 %a, 4095
48+
ret i32 %and
49+
}

llvm/test/CodeGen/LoongArch/ir-instruction/lshr.ll

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,13 @@ define i8 @lshr_i8(i8 %x, i8 %y) {
3434
define i16 @lshr_i16(i16 %x, i16 %y) {
3535
; LA32-LABEL: lshr_i16:
3636
; LA32: # %bb.0:
37-
; LA32-NEXT: lu12i.w $a2, 15
38-
; LA32-NEXT: ori $a2, $a2, 4095
39-
; LA32-NEXT: and $a0, $a0, $a2
37+
; LA32-NEXT: bstrpick.w $a0, $a0, 15, 0
4038
; LA32-NEXT: srl.w $a0, $a0, $a1
4139
; LA32-NEXT: jirl $zero, $ra, 0
4240
;
4341
; LA64-LABEL: lshr_i16:
4442
; LA64: # %bb.0:
45-
; LA64-NEXT: lu12i.w $a2, 15
46-
; LA64-NEXT: ori $a2, $a2, 4095
47-
; LA64-NEXT: and $a0, $a0, $a2
43+
; LA64-NEXT: bstrpick.d $a0, $a0, 15, 0
4844
; LA64-NEXT: srl.d $a0, $a0, $a1
4945
; LA64-NEXT: jirl $zero, $ra, 0
5046
%lshr = lshr i16 %x, %y

0 commit comments

Comments
 (0)