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
.is512BitVector()) {
81 ReplaceUses(SDValue(Node
, 0), Node
->getOperand(0));
82 CurDAG
->RemoveDeadNode(Node
);
89 // Select the default instruction.
93 bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand(
94 const SDValue
&Op
, InlineAsm::ConstraintCode ConstraintID
,
95 std::vector
<SDValue
> &OutOps
) {
98 CurDAG
->getTargetConstant(0, SDLoc(Op
), Subtarget
->getGRLenVT());
99 switch (ConstraintID
) {
101 llvm_unreachable("unexpected asm memory constraint");
102 // Reg+Reg addressing.
103 case InlineAsm::ConstraintCode::k
:
104 Base
= Op
.getOperand(0);
105 Offset
= Op
.getOperand(1);
107 // Reg+simm12 addressing.
108 case InlineAsm::ConstraintCode::m
:
109 if (CurDAG
->isBaseWithConstantOffset(Op
)) {
110 ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Op
.getOperand(1));
111 if (isIntN(12, CN
->getSExtValue())) {
112 Base
= Op
.getOperand(0);
113 Offset
= CurDAG
->getTargetConstant(CN
->getZExtValue(), SDLoc(Op
),
119 case InlineAsm::ConstraintCode::ZB
:
121 // Reg+(simm14<<2) addressing.
122 case InlineAsm::ConstraintCode::ZC
:
123 if (CurDAG
->isBaseWithConstantOffset(Op
)) {
124 ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Op
.getOperand(1));
125 if (isIntN(16, CN
->getSExtValue()) &&
126 isAligned(Align(4ULL), CN
->getZExtValue())) {
127 Base
= Op
.getOperand(0);
128 Offset
= CurDAG
->getTargetConstant(CN
->getZExtValue(), SDLoc(Op
),
134 OutOps
.push_back(Base
);
135 OutOps
.push_back(Offset
);
139 bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr
, SDValue
&Base
) {
140 // If this is FrameIndex, select it directly. Otherwise just let it get
141 // selected to a register independently.
142 if (auto *FIN
= dyn_cast
<FrameIndexSDNode
>(Addr
))
144 CurDAG
->getTargetFrameIndex(FIN
->getIndex(), Subtarget
->getGRLenVT());
150 // Fold constant addresses.
151 bool LoongArchDAGToDAGISel::SelectAddrConstant(SDValue Addr
, SDValue
&Base
,
154 MVT VT
= Addr
.getSimpleValueType();
156 if (!isa
<ConstantSDNode
>(Addr
))
159 // If the constant is a simm12, we can fold the whole constant and use R0 as
161 int64_t CVal
= cast
<ConstantSDNode
>(Addr
)->getSExtValue();
162 if (!isInt
<12>(CVal
))
164 Base
= CurDAG
->getRegister(LoongArch::R0
, VT
);
165 Offset
= CurDAG
->getTargetConstant(SignExtend64
<12>(CVal
), DL
, VT
);
169 bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr
, SDValue
&Base
) {
170 // If this is FrameIndex, don't select it.
171 if (isa
<FrameIndexSDNode
>(Addr
))
177 bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N
, unsigned ShiftWidth
,
179 // Shift instructions on LoongArch only read the lower 5 or 6 bits of the
180 // shift amount. If there is an AND on the shift amount, we can bypass it if
181 // it doesn't affect any of those bits.
182 if (N
.getOpcode() == ISD::AND
&& isa
<ConstantSDNode
>(N
.getOperand(1))) {
183 const APInt
&AndMask
= N
->getConstantOperandAPInt(1);
185 // Since the max shift amount is a power of 2 we can subtract 1 to make a
186 // mask that covers the bits needed to represent all shift amounts.
187 assert(isPowerOf2_32(ShiftWidth
) && "Unexpected max shift amount!");
188 APInt
ShMask(AndMask
.getBitWidth(), ShiftWidth
- 1);
190 if (ShMask
.isSubsetOf(AndMask
)) {
191 ShAmt
= N
.getOperand(0);
195 // SimplifyDemandedBits may have optimized the mask so try restoring any
196 // bits that are known zero.
197 KnownBits Known
= CurDAG
->computeKnownBits(N
->getOperand(0));
198 if (ShMask
.isSubsetOf(AndMask
| Known
.Zero
)) {
199 ShAmt
= N
.getOperand(0);
202 } else if (N
.getOpcode() == LoongArchISD::BSTRPICK
) {
203 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we
205 assert(isPowerOf2_32(ShiftWidth
) && "Unexpected max shift amount!");
206 assert(isa
<ConstantSDNode
>(N
.getOperand(1)) && "Illegal msb operand!");
207 assert(isa
<ConstantSDNode
>(N
.getOperand(2)) && "Illegal lsb operand!");
208 uint64_t msb
= N
.getConstantOperandVal(1), lsb
= N
.getConstantOperandVal(2);
209 if (lsb
== 0 && Log2_32(ShiftWidth
) <= msb
+ 1) {
210 ShAmt
= N
.getOperand(0);
213 } else if (N
.getOpcode() == ISD::SUB
&&
214 isa
<ConstantSDNode
>(N
.getOperand(0))) {
215 uint64_t Imm
= N
.getConstantOperandVal(0);
216 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to
217 // generate a NEG instead of a SUB of a constant.
218 if (Imm
!= 0 && Imm
% ShiftWidth
== 0) {
220 EVT VT
= N
.getValueType();
222 CurDAG
->getCopyFromReg(CurDAG
->getEntryNode(), DL
, LoongArch::R0
, VT
);
223 unsigned NegOpc
= VT
== MVT::i64
? LoongArch::SUB_D
: LoongArch::SUB_W
;
225 CurDAG
->getMachineNode(NegOpc
, DL
, VT
, Zero
, N
.getOperand(1));
226 ShAmt
= SDValue(Neg
, 0);
235 bool LoongArchDAGToDAGISel::selectSExti32(SDValue N
, SDValue
&Val
) {
236 if (N
.getOpcode() == ISD::SIGN_EXTEND_INREG
&&
237 cast
<VTSDNode
>(N
.getOperand(1))->getVT() == MVT::i32
) {
238 Val
= N
.getOperand(0);
241 if (N
.getOpcode() == LoongArchISD::BSTRPICK
&&
242 N
.getConstantOperandVal(1) < UINT64_C(0X1F) &&
243 N
.getConstantOperandVal(2) == UINT64_C(0)) {
247 MVT VT
= N
.getSimpleValueType();
248 if (CurDAG
->ComputeNumSignBits(N
) > (VT
.getSizeInBits() - 32)) {
256 bool LoongArchDAGToDAGISel::selectZExti32(SDValue N
, SDValue
&Val
) {
257 if (N
.getOpcode() == ISD::AND
) {
258 auto *C
= dyn_cast
<ConstantSDNode
>(N
.getOperand(1));
259 if (C
&& C
->getZExtValue() == UINT64_C(0xFFFFFFFF)) {
260 Val
= N
.getOperand(0);
264 MVT VT
= N
.getSimpleValueType();
265 APInt Mask
= APInt::getHighBitsSet(VT
.getSizeInBits(), 32);
266 if (CurDAG
->MaskedValueIsZero(N
, Mask
)) {
274 bool LoongArchDAGToDAGISel::selectVSplat(SDNode
*N
, APInt
&Imm
,
275 unsigned MinSizeInBits
) const {
276 if (!Subtarget
->hasExtLSX())
279 BuildVectorSDNode
*Node
= dyn_cast
<BuildVectorSDNode
>(N
);
284 APInt SplatValue
, SplatUndef
;
285 unsigned SplatBitSize
;
288 if (!Node
->isConstantSplat(SplatValue
, SplatUndef
, SplatBitSize
, HasAnyUndefs
,
289 MinSizeInBits
, /*IsBigEndian=*/false))
297 template <unsigned ImmBitSize
, bool IsSigned
>
298 bool LoongArchDAGToDAGISel::selectVSplatImm(SDValue N
, SDValue
&SplatVal
) {
300 EVT EltTy
= N
->getValueType(0).getVectorElementType();
302 if (N
->getOpcode() == ISD::BITCAST
)
303 N
= N
->getOperand(0);
305 if (selectVSplat(N
.getNode(), ImmValue
, EltTy
.getSizeInBits()) &&
306 ImmValue
.getBitWidth() == EltTy
.getSizeInBits()) {
307 if (IsSigned
&& ImmValue
.isSignedIntN(ImmBitSize
)) {
308 SplatVal
= CurDAG
->getTargetConstant(ImmValue
.getSExtValue(), SDLoc(N
),
309 Subtarget
->getGRLenVT());
312 if (!IsSigned
&& ImmValue
.isIntN(ImmBitSize
)) {
313 SplatVal
= CurDAG
->getTargetConstant(ImmValue
.getZExtValue(), SDLoc(N
),
314 Subtarget
->getGRLenVT());
322 bool LoongArchDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N
,
323 SDValue
&SplatImm
) const {
325 EVT EltTy
= N
->getValueType(0).getVectorElementType();
327 if (N
->getOpcode() == ISD::BITCAST
)
328 N
= N
->getOperand(0);
330 if (selectVSplat(N
.getNode(), ImmValue
, EltTy
.getSizeInBits()) &&
331 ImmValue
.getBitWidth() == EltTy
.getSizeInBits()) {
332 int32_t Log2
= (~ImmValue
).exactLogBase2();
335 SplatImm
= CurDAG
->getTargetConstant(Log2
, SDLoc(N
), EltTy
);
343 bool LoongArchDAGToDAGISel::selectVSplatUimmPow2(SDValue N
,
344 SDValue
&SplatImm
) const {
346 EVT EltTy
= N
->getValueType(0).getVectorElementType();
348 if (N
->getOpcode() == ISD::BITCAST
)
349 N
= N
->getOperand(0);
351 if (selectVSplat(N
.getNode(), ImmValue
, EltTy
.getSizeInBits()) &&
352 ImmValue
.getBitWidth() == EltTy
.getSizeInBits()) {
353 int32_t Log2
= ImmValue
.exactLogBase2();
356 SplatImm
= CurDAG
->getTargetConstant(Log2
, SDLoc(N
), EltTy
);
364 // This pass converts a legalized DAG into a LoongArch-specific DAG, ready
365 // for instruction scheduling.
366 FunctionPass
*llvm::createLoongArchISelDag(LoongArchTargetMachine
&TM
) {
367 return new LoongArchDAGToDAGISel(TM
);