1 //=- LoongArchISelDAGToDAG.cpp - A dag to dag inst selector for LoongArch -===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file defines an instruction selector for the LoongArch target.
11 //===----------------------------------------------------------------------===//
13 #include "LoongArchISelDAGToDAG.h"
14 #include "LoongArchISelLowering.h"
15 #include "MCTargetDesc/LoongArchMCTargetDesc.h"
16 #include "MCTargetDesc/LoongArchMatInt.h"
17 #include "llvm/Support/KnownBits.h"
18 #include "llvm/Support/raw_ostream.h"
22 #define DEBUG_TYPE "loongarch-isel"
23 #define PASS_NAME "LoongArch DAG->DAG Pattern Instruction Selection"
25 char LoongArchDAGToDAGISel::ID
;
27 INITIALIZE_PASS(LoongArchDAGToDAGISel
, DEBUG_TYPE
, PASS_NAME
, false, false)
29 void LoongArchDAGToDAGISel::Select(SDNode
*Node
) {
30 // If we have a custom node, we have already selected.
31 if (Node
->isMachineOpcode()) {
32 LLVM_DEBUG(dbgs() << "== "; Node
->dump(CurDAG
); dbgs() << "\n");
37 // Instruction Selection not handled by the auto-generated tablegen selection
38 // should be handled here.
39 unsigned Opcode
= Node
->getOpcode();
40 MVT GRLenVT
= Subtarget
->getGRLenVT();
42 MVT VT
= Node
->getSimpleValueType(0);
48 int64_t Imm
= cast
<ConstantSDNode
>(Node
)->getSExtValue();
49 if (Imm
== 0 && VT
== GRLenVT
) {
50 SDValue New
= CurDAG
->getCopyFromReg(CurDAG
->getEntryNode(), DL
,
51 LoongArch::R0
, GRLenVT
);
52 ReplaceNode(Node
, New
.getNode());
55 SDNode
*Result
= nullptr;
56 SDValue SrcReg
= CurDAG
->getRegister(LoongArch::R0
, GRLenVT
);
57 // The instructions in the sequence are handled here.
58 for (LoongArchMatInt::Inst
&Inst
: LoongArchMatInt::generateInstSeq(Imm
)) {
59 SDValue SDImm
= CurDAG
->getTargetConstant(Inst
.Imm
, DL
, GRLenVT
);
60 if (Inst
.Opc
== LoongArch::LU12I_W
)
61 Result
= CurDAG
->getMachineNode(LoongArch::LU12I_W
, DL
, GRLenVT
, SDImm
);
63 Result
= CurDAG
->getMachineNode(Inst
.Opc
, DL
, GRLenVT
, SrcReg
, SDImm
);
64 SrcReg
= SDValue(Result
, 0);
67 ReplaceNode(Node
, Result
);
70 case ISD::FrameIndex
: {
71 SDValue Imm
= CurDAG
->getTargetConstant(0, DL
, GRLenVT
);
72 int FI
= cast
<FrameIndexSDNode
>(Node
)->getIndex();
73 SDValue TFI
= CurDAG
->getTargetFrameIndex(FI
, VT
);
75 Subtarget
->is64Bit() ? LoongArch::ADDI_D
: LoongArch::ADDI_W
;
76 ReplaceNode(Node
, CurDAG
->getMachineNode(ADDIOp
, DL
, VT
, TFI
, Imm
));
80 if (VT
.is128BitVector() || VT
.is256BitVector()) {
81 ReplaceUses(SDValue(Node
, 0), Node
->getOperand(0));
82 CurDAG
->RemoveDeadNode(Node
);
87 case ISD::BUILD_VECTOR
: {
88 // Select appropriate [x]vrepli.[bhwd] instructions for constant splats of
89 // 128/256-bit when LSX/LASX is enabled.
90 BuildVectorSDNode
*BVN
= cast
<BuildVectorSDNode
>(Node
);
91 APInt SplatValue
, SplatUndef
;
92 unsigned SplatBitSize
;
96 bool Is128Vec
= BVN
->getValueType(0).is128BitVector();
97 bool Is256Vec
= BVN
->getValueType(0).is256BitVector();
99 if (!Subtarget
->hasExtLSX() || (!Is128Vec
&& !Is256Vec
))
101 if (!BVN
->isConstantSplat(SplatValue
, SplatUndef
, SplatBitSize
,
105 switch (SplatBitSize
) {
109 Op
= Is256Vec
? LoongArch::PseudoXVREPLI_B
: LoongArch::PseudoVREPLI_B
;
110 ViaVecTy
= Is256Vec
? MVT::v32i8
: MVT::v16i8
;
113 Op
= Is256Vec
? LoongArch::PseudoXVREPLI_H
: LoongArch::PseudoVREPLI_H
;
114 ViaVecTy
= Is256Vec
? MVT::v16i16
: MVT::v8i16
;
117 Op
= Is256Vec
? LoongArch::PseudoXVREPLI_W
: LoongArch::PseudoVREPLI_W
;
118 ViaVecTy
= Is256Vec
? MVT::v8i32
: MVT::v4i32
;
121 Op
= Is256Vec
? LoongArch::PseudoXVREPLI_D
: LoongArch::PseudoVREPLI_D
;
122 ViaVecTy
= Is256Vec
? MVT::v4i64
: MVT::v2i64
;
127 // If we have a signed 10 bit integer, we can splat it directly.
128 if (SplatValue
.isSignedIntN(10)) {
129 SDValue Imm
= CurDAG
->getTargetConstant(SplatValue
, DL
,
130 ViaVecTy
.getVectorElementType());
131 Res
= CurDAG
->getMachineNode(Op
, DL
, ViaVecTy
, Imm
);
132 ReplaceNode(Node
, Res
);
139 // Select the default instruction.
143 bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand(
144 const SDValue
&Op
, InlineAsm::ConstraintCode ConstraintID
,
145 std::vector
<SDValue
> &OutOps
) {
148 CurDAG
->getTargetConstant(0, SDLoc(Op
), Subtarget
->getGRLenVT());
149 switch (ConstraintID
) {
151 llvm_unreachable("unexpected asm memory constraint");
152 // Reg+Reg addressing.
153 case InlineAsm::ConstraintCode::k
:
154 Base
= Op
.getOperand(0);
155 Offset
= Op
.getOperand(1);
157 // Reg+simm12 addressing.
158 case InlineAsm::ConstraintCode::m
:
159 if (CurDAG
->isBaseWithConstantOffset(Op
)) {
160 ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Op
.getOperand(1));
161 if (isIntN(12, CN
->getSExtValue())) {
162 Base
= Op
.getOperand(0);
163 Offset
= CurDAG
->getTargetConstant(CN
->getZExtValue(), SDLoc(Op
),
169 case InlineAsm::ConstraintCode::ZB
:
171 // Reg+(simm14<<2) addressing.
172 case InlineAsm::ConstraintCode::ZC
:
173 if (CurDAG
->isBaseWithConstantOffset(Op
)) {
174 ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Op
.getOperand(1));
175 if (isIntN(16, CN
->getSExtValue()) &&
176 isAligned(Align(4ULL), CN
->getZExtValue())) {
177 Base
= Op
.getOperand(0);
178 Offset
= CurDAG
->getTargetConstant(CN
->getZExtValue(), SDLoc(Op
),
184 OutOps
.push_back(Base
);
185 OutOps
.push_back(Offset
);
189 bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr
, SDValue
&Base
) {
190 // If this is FrameIndex, select it directly. Otherwise just let it get
191 // selected to a register independently.
192 if (auto *FIN
= dyn_cast
<FrameIndexSDNode
>(Addr
))
194 CurDAG
->getTargetFrameIndex(FIN
->getIndex(), Subtarget
->getGRLenVT());
200 // Fold constant addresses.
201 bool LoongArchDAGToDAGISel::SelectAddrConstant(SDValue Addr
, SDValue
&Base
,
204 MVT VT
= Addr
.getSimpleValueType();
206 if (!isa
<ConstantSDNode
>(Addr
))
209 // If the constant is a simm12, we can fold the whole constant and use R0 as
211 int64_t CVal
= cast
<ConstantSDNode
>(Addr
)->getSExtValue();
212 if (!isInt
<12>(CVal
))
214 Base
= CurDAG
->getRegister(LoongArch::R0
, VT
);
215 Offset
= CurDAG
->getTargetConstant(SignExtend64
<12>(CVal
), DL
, VT
);
219 bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr
, SDValue
&Base
) {
220 // If this is FrameIndex, don't select it.
221 if (isa
<FrameIndexSDNode
>(Addr
))
227 bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N
, unsigned ShiftWidth
,
229 // Shift instructions on LoongArch only read the lower 5 or 6 bits of the
230 // shift amount. If there is an AND on the shift amount, we can bypass it if
231 // it doesn't affect any of those bits.
232 if (N
.getOpcode() == ISD::AND
&& isa
<ConstantSDNode
>(N
.getOperand(1))) {
233 const APInt
&AndMask
= N
->getConstantOperandAPInt(1);
235 // Since the max shift amount is a power of 2 we can subtract 1 to make a
236 // mask that covers the bits needed to represent all shift amounts.
237 assert(isPowerOf2_32(ShiftWidth
) && "Unexpected max shift amount!");
238 APInt
ShMask(AndMask
.getBitWidth(), ShiftWidth
- 1);
240 if (ShMask
.isSubsetOf(AndMask
)) {
241 ShAmt
= N
.getOperand(0);
245 // SimplifyDemandedBits may have optimized the mask so try restoring any
246 // bits that are known zero.
247 KnownBits Known
= CurDAG
->computeKnownBits(N
->getOperand(0));
248 if (ShMask
.isSubsetOf(AndMask
| Known
.Zero
)) {
249 ShAmt
= N
.getOperand(0);
252 } else if (N
.getOpcode() == LoongArchISD::BSTRPICK
) {
253 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we
255 assert(isPowerOf2_32(ShiftWidth
) && "Unexpected max shift amount!");
256 assert(isa
<ConstantSDNode
>(N
.getOperand(1)) && "Illegal msb operand!");
257 assert(isa
<ConstantSDNode
>(N
.getOperand(2)) && "Illegal lsb operand!");
258 uint64_t msb
= N
.getConstantOperandVal(1), lsb
= N
.getConstantOperandVal(2);
259 if (lsb
== 0 && Log2_32(ShiftWidth
) <= msb
+ 1) {
260 ShAmt
= N
.getOperand(0);
263 } else if (N
.getOpcode() == ISD::SUB
&&
264 isa
<ConstantSDNode
>(N
.getOperand(0))) {
265 uint64_t Imm
= N
.getConstantOperandVal(0);
266 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to
267 // generate a NEG instead of a SUB of a constant.
268 if (Imm
!= 0 && Imm
% ShiftWidth
== 0) {
270 EVT VT
= N
.getValueType();
272 CurDAG
->getCopyFromReg(CurDAG
->getEntryNode(), DL
, LoongArch::R0
, VT
);
273 unsigned NegOpc
= VT
== MVT::i64
? LoongArch::SUB_D
: LoongArch::SUB_W
;
275 CurDAG
->getMachineNode(NegOpc
, DL
, VT
, Zero
, N
.getOperand(1));
276 ShAmt
= SDValue(Neg
, 0);
285 bool LoongArchDAGToDAGISel::selectSExti32(SDValue N
, SDValue
&Val
) {
286 if (N
.getOpcode() == ISD::SIGN_EXTEND_INREG
&&
287 cast
<VTSDNode
>(N
.getOperand(1))->getVT() == MVT::i32
) {
288 Val
= N
.getOperand(0);
291 if (N
.getOpcode() == LoongArchISD::BSTRPICK
&&
292 N
.getConstantOperandVal(1) < UINT64_C(0X1F) &&
293 N
.getConstantOperandVal(2) == UINT64_C(0)) {
297 MVT VT
= N
.getSimpleValueType();
298 if (CurDAG
->ComputeNumSignBits(N
) > (VT
.getSizeInBits() - 32)) {
306 bool LoongArchDAGToDAGISel::selectZExti32(SDValue N
, SDValue
&Val
) {
307 if (N
.getOpcode() == ISD::AND
) {
308 auto *C
= dyn_cast
<ConstantSDNode
>(N
.getOperand(1));
309 if (C
&& C
->getZExtValue() == UINT64_C(0xFFFFFFFF)) {
310 Val
= N
.getOperand(0);
314 MVT VT
= N
.getSimpleValueType();
315 APInt Mask
= APInt::getHighBitsSet(VT
.getSizeInBits(), 32);
316 if (CurDAG
->MaskedValueIsZero(N
, Mask
)) {
324 bool LoongArchDAGToDAGISel::selectVSplat(SDNode
*N
, APInt
&Imm
,
325 unsigned MinSizeInBits
) const {
326 if (!Subtarget
->hasExtLSX())
329 BuildVectorSDNode
*Node
= dyn_cast
<BuildVectorSDNode
>(N
);
334 APInt SplatValue
, SplatUndef
;
335 unsigned SplatBitSize
;
338 if (!Node
->isConstantSplat(SplatValue
, SplatUndef
, SplatBitSize
, HasAnyUndefs
,
339 MinSizeInBits
, /*IsBigEndian=*/false))
347 template <unsigned ImmBitSize
, bool IsSigned
>
348 bool LoongArchDAGToDAGISel::selectVSplatImm(SDValue N
, SDValue
&SplatVal
) {
350 EVT EltTy
= N
->getValueType(0).getVectorElementType();
352 if (N
->getOpcode() == ISD::BITCAST
)
353 N
= N
->getOperand(0);
355 if (selectVSplat(N
.getNode(), ImmValue
, EltTy
.getSizeInBits()) &&
356 ImmValue
.getBitWidth() == EltTy
.getSizeInBits()) {
357 if (IsSigned
&& ImmValue
.isSignedIntN(ImmBitSize
)) {
358 SplatVal
= CurDAG
->getTargetConstant(ImmValue
.getSExtValue(), SDLoc(N
),
359 Subtarget
->getGRLenVT());
362 if (!IsSigned
&& ImmValue
.isIntN(ImmBitSize
)) {
363 SplatVal
= CurDAG
->getTargetConstant(ImmValue
.getZExtValue(), SDLoc(N
),
364 Subtarget
->getGRLenVT());
372 bool LoongArchDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N
,
373 SDValue
&SplatImm
) const {
375 EVT EltTy
= N
->getValueType(0).getVectorElementType();
377 if (N
->getOpcode() == ISD::BITCAST
)
378 N
= N
->getOperand(0);
380 if (selectVSplat(N
.getNode(), ImmValue
, EltTy
.getSizeInBits()) &&
381 ImmValue
.getBitWidth() == EltTy
.getSizeInBits()) {
382 int32_t Log2
= (~ImmValue
).exactLogBase2();
385 SplatImm
= CurDAG
->getTargetConstant(Log2
, SDLoc(N
), EltTy
);
393 bool LoongArchDAGToDAGISel::selectVSplatUimmPow2(SDValue N
,
394 SDValue
&SplatImm
) const {
396 EVT EltTy
= N
->getValueType(0).getVectorElementType();
398 if (N
->getOpcode() == ISD::BITCAST
)
399 N
= N
->getOperand(0);
401 if (selectVSplat(N
.getNode(), ImmValue
, EltTy
.getSizeInBits()) &&
402 ImmValue
.getBitWidth() == EltTy
.getSizeInBits()) {
403 int32_t Log2
= ImmValue
.exactLogBase2();
406 SplatImm
= CurDAG
->getTargetConstant(Log2
, SDLoc(N
), EltTy
);
414 // This pass converts a legalized DAG into a LoongArch-specific DAG, ready
415 // for instruction scheduling.
416 FunctionPass
*llvm::createLoongArchISelDag(LoongArchTargetMachine
&TM
) {
417 return new LoongArchDAGToDAGISel(TM
);