Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / lib / Target / LoongArch / LoongArchISelDAGToDAG.cpp
blob0cfee60252188847a5d7903ae1d6437c410f6352
1 //=- LoongArchISelDAGToDAG.cpp - A dag to dag inst selector for LoongArch -===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
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"
20 using namespace llvm;
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");
33 Node->setNodeId(-1);
34 return;
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();
41 SDLoc DL(Node);
42 MVT VT = Node->getSimpleValueType(0);
44 switch (Opcode) {
45 default:
46 break;
47 case ISD::Constant: {
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());
53 return;
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);
62 else
63 Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm);
64 SrcReg = SDValue(Result, 0);
67 ReplaceNode(Node, Result);
68 return;
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);
74 unsigned ADDIOp =
75 Subtarget->is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
76 ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm));
77 return;
79 case ISD::BITCAST: {
80 if (VT.is128BitVector() || VT.is512BitVector()) {
81 ReplaceUses(SDValue(Node, 0), Node->getOperand(0));
82 CurDAG->RemoveDeadNode(Node);
83 return;
85 break;
89 // Select the default instruction.
90 SelectCode(Node);
93 bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand(
94 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
95 std::vector<SDValue> &OutOps) {
96 SDValue Base = Op;
97 SDValue Offset =
98 CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT());
99 switch (ConstraintID) {
100 default:
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);
106 break;
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),
114 Op.getValueType());
117 break;
118 // Reg+0 addressing.
119 case InlineAsm::ConstraintCode::ZB:
120 break;
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),
129 Op.getValueType());
132 break;
134 OutOps.push_back(Base);
135 OutOps.push_back(Offset);
136 return false;
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))
143 Base =
144 CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT());
145 else
146 Base = Addr;
147 return true;
150 // Fold constant addresses.
151 bool LoongArchDAGToDAGISel::SelectAddrConstant(SDValue Addr, SDValue &Base,
152 SDValue &Offset) {
153 SDLoc DL(Addr);
154 MVT VT = Addr.getSimpleValueType();
156 if (!isa<ConstantSDNode>(Addr))
157 return false;
159 // If the constant is a simm12, we can fold the whole constant and use R0 as
160 // the base.
161 int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue();
162 if (!isInt<12>(CVal))
163 return false;
164 Base = CurDAG->getRegister(LoongArch::R0, VT);
165 Offset = CurDAG->getTargetConstant(SignExtend64<12>(CVal), DL, VT);
166 return true;
169 bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) {
170 // If this is FrameIndex, don't select it.
171 if (isa<FrameIndexSDNode>(Addr))
172 return false;
173 Base = Addr;
174 return true;
177 bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
178 SDValue &ShAmt) {
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);
192 return true;
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);
200 return true;
202 } else if (N.getOpcode() == LoongArchISD::BSTRPICK) {
203 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we
204 // can bypass it.
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);
211 return true;
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) {
219 SDLoc DL(N);
220 EVT VT = N.getValueType();
221 SDValue Zero =
222 CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT);
223 unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W;
224 MachineSDNode *Neg =
225 CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1));
226 ShAmt = SDValue(Neg, 0);
227 return true;
231 ShAmt = N;
232 return true;
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);
239 return true;
241 if (N.getOpcode() == LoongArchISD::BSTRPICK &&
242 N.getConstantOperandVal(1) < UINT64_C(0X1F) &&
243 N.getConstantOperandVal(2) == UINT64_C(0)) {
244 Val = N;
245 return true;
247 MVT VT = N.getSimpleValueType();
248 if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {
249 Val = N;
250 return true;
253 return false;
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);
261 return true;
264 MVT VT = N.getSimpleValueType();
265 APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32);
266 if (CurDAG->MaskedValueIsZero(N, Mask)) {
267 Val = N;
268 return true;
271 return false;
274 bool LoongArchDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm,
275 unsigned MinSizeInBits) const {
276 if (!Subtarget->hasExtLSX())
277 return false;
279 BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N);
281 if (!Node)
282 return false;
284 APInt SplatValue, SplatUndef;
285 unsigned SplatBitSize;
286 bool HasAnyUndefs;
288 if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
289 MinSizeInBits, /*IsBigEndian=*/false))
290 return false;
292 Imm = SplatValue;
294 return true;
297 template <unsigned ImmBitSize, bool IsSigned>
298 bool LoongArchDAGToDAGISel::selectVSplatImm(SDValue N, SDValue &SplatVal) {
299 APInt ImmValue;
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());
310 return true;
312 if (!IsSigned && ImmValue.isIntN(ImmBitSize)) {
313 SplatVal = CurDAG->getTargetConstant(ImmValue.getZExtValue(), SDLoc(N),
314 Subtarget->getGRLenVT());
315 return true;
319 return false;
322 bool LoongArchDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N,
323 SDValue &SplatImm) const {
324 APInt ImmValue;
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();
334 if (Log2 != -1) {
335 SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
336 return true;
340 return false;
343 bool LoongArchDAGToDAGISel::selectVSplatUimmPow2(SDValue N,
344 SDValue &SplatImm) const {
345 APInt ImmValue;
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();
355 if (Log2 != -1) {
356 SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
357 return true;
361 return false;
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);