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.
10//
11//===----------------------------------------------------------------------===//
12
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"
19
20using namespace llvm;
21
22#define DEBUG_TYPE "loongarch-isel"
23#define PASS_NAME "LoongArch DAG->DAG Pattern Instruction Selection"
24
25char LoongArchDAGToDAGISel::ID;
26
27INITIALIZE_PASS(LoongArchDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false)
28
29void 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;
35  }
36
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);
43
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;
54    }
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);
65    }
66
67    ReplaceNode(Node, Result);
68    return;
69  }
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;
78  }
79  case ISD::BITCAST: {
80    if (VT.is128BitVector() || VT.is256BitVector()) {
81      ReplaceUses(SDValue(Node, 0), Node->getOperand(0));
82      CurDAG->RemoveDeadNode(Node);
83      return;
84    }
85    break;
86  }
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;
93    bool HasAnyUndefs;
94    unsigned Op;
95    EVT ViaVecTy;
96    bool Is128Vec = BVN->getValueType(0).is128BitVector();
97    bool Is256Vec = BVN->getValueType(0).is256BitVector();
98
99    if (!Subtarget->hasExtLSX() || (!Is128Vec && !Is256Vec))
100      break;
101    if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
102                              HasAnyUndefs, 8))
103      break;
104
105    switch (SplatBitSize) {
106    default:
107      break;
108    case 8:
109      Op = Is256Vec ? LoongArch::PseudoXVREPLI_B : LoongArch::PseudoVREPLI_B;
110      ViaVecTy = Is256Vec ? MVT::v32i8 : MVT::v16i8;
111      break;
112    case 16:
113      Op = Is256Vec ? LoongArch::PseudoXVREPLI_H : LoongArch::PseudoVREPLI_H;
114      ViaVecTy = Is256Vec ? MVT::v16i16 : MVT::v8i16;
115      break;
116    case 32:
117      Op = Is256Vec ? LoongArch::PseudoXVREPLI_W : LoongArch::PseudoVREPLI_W;
118      ViaVecTy = Is256Vec ? MVT::v8i32 : MVT::v4i32;
119      break;
120    case 64:
121      Op = Is256Vec ? LoongArch::PseudoXVREPLI_D : LoongArch::PseudoVREPLI_D;
122      ViaVecTy = Is256Vec ? MVT::v4i64 : MVT::v2i64;
123      break;
124    }
125
126    SDNode *Res;
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);
133      return;
134    }
135    break;
136  }
137  }
138
139  // Select the default instruction.
140  SelectCode(Node);
141}
142
143bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand(
144    const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
145    std::vector<SDValue> &OutOps) {
146  SDValue Base = Op;
147  SDValue Offset =
148      CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT());
149  switch (ConstraintID) {
150  default:
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);
156    break;
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),
164                                           Op.getValueType());
165      }
166    }
167    break;
168  // Reg+0 addressing.
169  case InlineAsm::ConstraintCode::ZB:
170    break;
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),
179                                           Op.getValueType());
180      }
181    }
182    break;
183  }
184  OutOps.push_back(Base);
185  OutOps.push_back(Offset);
186  return false;
187}
188
189bool 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))
193    Base =
194        CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT());
195  else
196    Base = Addr;
197  return true;
198}
199
200// Fold constant addresses.
201bool LoongArchDAGToDAGISel::SelectAddrConstant(SDValue Addr, SDValue &Base,
202                                               SDValue &Offset) {
203  SDLoc DL(Addr);
204  MVT VT = Addr.getSimpleValueType();
205
206  if (!isa<ConstantSDNode>(Addr))
207    return false;
208
209  // If the constant is a simm12, we can fold the whole constant and use R0 as
210  // the base.
211  int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue();
212  if (!isInt<12>(CVal))
213    return false;
214  Base = CurDAG->getRegister(LoongArch::R0, VT);
215  Offset = CurDAG->getTargetConstant(SignExtend64<12>(CVal), DL, VT);
216  return true;
217}
218
219bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) {
220  // If this is FrameIndex, don't select it.
221  if (isa<FrameIndexSDNode>(Addr))
222    return false;
223  Base = Addr;
224  return true;
225}
226
227bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
228                                            SDValue &ShAmt) {
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);
234
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);
239
240    if (ShMask.isSubsetOf(AndMask)) {
241      ShAmt = N.getOperand(0);
242      return true;
243    }
244
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);
250      return true;
251    }
252  } else if (N.getOpcode() == LoongArchISD::BSTRPICK) {
253    // Similar to the above AND, if there is a BSTRPICK on the shift amount, we
254    // can bypass it.
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);
261      return true;
262    }
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) {
269      SDLoc DL(N);
270      EVT VT = N.getValueType();
271      SDValue Zero =
272          CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT);
273      unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W;
274      MachineSDNode *Neg =
275          CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1));
276      ShAmt = SDValue(Neg, 0);
277      return true;
278    }
279  }
280
281  ShAmt = N;
282  return true;
283}
284
285bool 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);
289    return true;
290  }
291  if (N.getOpcode() == LoongArchISD::BSTRPICK &&
292      N.getConstantOperandVal(1) < UINT64_C(0X1F) &&
293      N.getConstantOperandVal(2) == UINT64_C(0)) {
294    Val = N;
295    return true;
296  }
297  MVT VT = N.getSimpleValueType();
298  if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {
299    Val = N;
300    return true;
301  }
302
303  return false;
304}
305
306bool 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);
311      return true;
312    }
313  }
314  MVT VT = N.getSimpleValueType();
315  APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32);
316  if (CurDAG->MaskedValueIsZero(N, Mask)) {
317    Val = N;
318    return true;
319  }
320
321  return false;
322}
323
324bool LoongArchDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm,
325                                         unsigned MinSizeInBits) const {
326  if (!Subtarget->hasExtLSX())
327    return false;
328
329  BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N);
330
331  if (!Node)
332    return false;
333
334  APInt SplatValue, SplatUndef;
335  unsigned SplatBitSize;
336  bool HasAnyUndefs;
337
338  if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
339                             MinSizeInBits, /*IsBigEndian=*/false))
340    return false;
341
342  Imm = SplatValue;
343
344  return true;
345}
346
347template <unsigned ImmBitSize, bool IsSigned>
348bool LoongArchDAGToDAGISel::selectVSplatImm(SDValue N, SDValue &SplatVal) {
349  APInt ImmValue;
350  EVT EltTy = N->getValueType(0).getVectorElementType();
351
352  if (N->getOpcode() == ISD::BITCAST)
353    N = N->getOperand(0);
354
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());
360      return true;
361    }
362    if (!IsSigned && ImmValue.isIntN(ImmBitSize)) {
363      SplatVal = CurDAG->getTargetConstant(ImmValue.getZExtValue(), SDLoc(N),
364                                           Subtarget->getGRLenVT());
365      return true;
366    }
367  }
368
369  return false;
370}
371
372bool LoongArchDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N,
373                                                    SDValue &SplatImm) const {
374  APInt ImmValue;
375  EVT EltTy = N->getValueType(0).getVectorElementType();
376
377  if (N->getOpcode() == ISD::BITCAST)
378    N = N->getOperand(0);
379
380  if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
381      ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
382    int32_t Log2 = (~ImmValue).exactLogBase2();
383
384    if (Log2 != -1) {
385      SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
386      return true;
387    }
388  }
389
390  return false;
391}
392
393bool LoongArchDAGToDAGISel::selectVSplatUimmPow2(SDValue N,
394                                                 SDValue &SplatImm) const {
395  APInt ImmValue;
396  EVT EltTy = N->getValueType(0).getVectorElementType();
397
398  if (N->getOpcode() == ISD::BITCAST)
399    N = N->getOperand(0);
400
401  if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
402      ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
403    int32_t Log2 = ImmValue.exactLogBase2();
404
405    if (Log2 != -1) {
406      SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
407      return true;
408    }
409  }
410
411  return false;
412}
413
414// This pass converts a legalized DAG into a LoongArch-specific DAG, ready
415// for instruction scheduling.
416FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) {
417  return new LoongArchDAGToDAGISel(TM);
418}
419