xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //=- LoongArchISelDAGToDAG.cpp - A dag to dag inst selector for LoongArch -===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file defines an instruction selector for the LoongArch target.
1081ad6265SDimitry Andric //
1181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1281ad6265SDimitry Andric 
1381ad6265SDimitry Andric #include "LoongArchISelDAGToDAG.h"
1481ad6265SDimitry Andric #include "LoongArchISelLowering.h"
1581ad6265SDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h"
1681ad6265SDimitry Andric #include "MCTargetDesc/LoongArchMatInt.h"
1781ad6265SDimitry Andric #include "llvm/Support/KnownBits.h"
185f757f3fSDimitry Andric #include "llvm/Support/raw_ostream.h"
1981ad6265SDimitry Andric 
2081ad6265SDimitry Andric using namespace llvm;
2181ad6265SDimitry Andric 
2281ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-isel"
23bdd1243dSDimitry Andric #define PASS_NAME "LoongArch DAG->DAG Pattern Instruction Selection"
24bdd1243dSDimitry Andric 
25*0fca6ea1SDimitry Andric char LoongArchDAGToDAGISelLegacy::ID;
26bdd1243dSDimitry Andric 
LoongArchDAGToDAGISelLegacy(LoongArchTargetMachine & TM)27*0fca6ea1SDimitry Andric LoongArchDAGToDAGISelLegacy::LoongArchDAGToDAGISelLegacy(
28*0fca6ea1SDimitry Andric     LoongArchTargetMachine &TM)
29*0fca6ea1SDimitry Andric     : SelectionDAGISelLegacy(ID, std::make_unique<LoongArchDAGToDAGISel>(TM)) {}
30*0fca6ea1SDimitry Andric 
INITIALIZE_PASS(LoongArchDAGToDAGISelLegacy,DEBUG_TYPE,PASS_NAME,false,false)31*0fca6ea1SDimitry Andric INITIALIZE_PASS(LoongArchDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false,
32*0fca6ea1SDimitry Andric                 false)
3381ad6265SDimitry Andric 
3481ad6265SDimitry Andric void LoongArchDAGToDAGISel::Select(SDNode *Node) {
3581ad6265SDimitry Andric   // If we have a custom node, we have already selected.
3681ad6265SDimitry Andric   if (Node->isMachineOpcode()) {
3781ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
3881ad6265SDimitry Andric     Node->setNodeId(-1);
3981ad6265SDimitry Andric     return;
4081ad6265SDimitry Andric   }
4181ad6265SDimitry Andric 
4281ad6265SDimitry Andric   // Instruction Selection not handled by the auto-generated tablegen selection
4381ad6265SDimitry Andric   // should be handled here.
4481ad6265SDimitry Andric   unsigned Opcode = Node->getOpcode();
4581ad6265SDimitry Andric   MVT GRLenVT = Subtarget->getGRLenVT();
4681ad6265SDimitry Andric   SDLoc DL(Node);
47753f127fSDimitry Andric   MVT VT = Node->getSimpleValueType(0);
4881ad6265SDimitry Andric 
4981ad6265SDimitry Andric   switch (Opcode) {
5081ad6265SDimitry Andric   default:
5181ad6265SDimitry Andric     break;
5281ad6265SDimitry Andric   case ISD::Constant: {
5381ad6265SDimitry Andric     int64_t Imm = cast<ConstantSDNode>(Node)->getSExtValue();
54753f127fSDimitry Andric     if (Imm == 0 && VT == GRLenVT) {
5581ad6265SDimitry Andric       SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL,
5681ad6265SDimitry Andric                                            LoongArch::R0, GRLenVT);
5781ad6265SDimitry Andric       ReplaceNode(Node, New.getNode());
5881ad6265SDimitry Andric       return;
5981ad6265SDimitry Andric     }
6081ad6265SDimitry Andric     SDNode *Result = nullptr;
6181ad6265SDimitry Andric     SDValue SrcReg = CurDAG->getRegister(LoongArch::R0, GRLenVT);
6281ad6265SDimitry Andric     // The instructions in the sequence are handled here.
6381ad6265SDimitry Andric     for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) {
6481ad6265SDimitry Andric       SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, GRLenVT);
6581ad6265SDimitry Andric       if (Inst.Opc == LoongArch::LU12I_W)
6681ad6265SDimitry Andric         Result = CurDAG->getMachineNode(LoongArch::LU12I_W, DL, GRLenVT, SDImm);
6781ad6265SDimitry Andric       else
6881ad6265SDimitry Andric         Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm);
6981ad6265SDimitry Andric       SrcReg = SDValue(Result, 0);
7081ad6265SDimitry Andric     }
7181ad6265SDimitry Andric 
7281ad6265SDimitry Andric     ReplaceNode(Node, Result);
7381ad6265SDimitry Andric     return;
7481ad6265SDimitry Andric   }
75753f127fSDimitry Andric   case ISD::FrameIndex: {
76753f127fSDimitry Andric     SDValue Imm = CurDAG->getTargetConstant(0, DL, GRLenVT);
77753f127fSDimitry Andric     int FI = cast<FrameIndexSDNode>(Node)->getIndex();
78753f127fSDimitry Andric     SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
79753f127fSDimitry Andric     unsigned ADDIOp =
80753f127fSDimitry Andric         Subtarget->is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
81753f127fSDimitry Andric     ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm));
82753f127fSDimitry Andric     return;
83753f127fSDimitry Andric   }
845f757f3fSDimitry Andric   case ISD::BITCAST: {
855f757f3fSDimitry Andric     if (VT.is128BitVector() || VT.is256BitVector()) {
865f757f3fSDimitry Andric       ReplaceUses(SDValue(Node, 0), Node->getOperand(0));
875f757f3fSDimitry Andric       CurDAG->RemoveDeadNode(Node);
885f757f3fSDimitry Andric       return;
895f757f3fSDimitry Andric     }
905f757f3fSDimitry Andric     break;
915f757f3fSDimitry Andric   }
925f757f3fSDimitry Andric   case ISD::BUILD_VECTOR: {
935f757f3fSDimitry Andric     // Select appropriate [x]vrepli.[bhwd] instructions for constant splats of
945f757f3fSDimitry Andric     // 128/256-bit when LSX/LASX is enabled.
955f757f3fSDimitry Andric     BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Node);
965f757f3fSDimitry Andric     APInt SplatValue, SplatUndef;
975f757f3fSDimitry Andric     unsigned SplatBitSize;
985f757f3fSDimitry Andric     bool HasAnyUndefs;
995f757f3fSDimitry Andric     unsigned Op;
1005f757f3fSDimitry Andric     EVT ViaVecTy;
1015f757f3fSDimitry Andric     bool Is128Vec = BVN->getValueType(0).is128BitVector();
1025f757f3fSDimitry Andric     bool Is256Vec = BVN->getValueType(0).is256BitVector();
1035f757f3fSDimitry Andric 
1045f757f3fSDimitry Andric     if (!Subtarget->hasExtLSX() || (!Is128Vec && !Is256Vec))
1055f757f3fSDimitry Andric       break;
1065f757f3fSDimitry Andric     if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
1075f757f3fSDimitry Andric                               HasAnyUndefs, 8))
1085f757f3fSDimitry Andric       break;
1095f757f3fSDimitry Andric 
1105f757f3fSDimitry Andric     switch (SplatBitSize) {
1115f757f3fSDimitry Andric     default:
1125f757f3fSDimitry Andric       break;
1135f757f3fSDimitry Andric     case 8:
1145f757f3fSDimitry Andric       Op = Is256Vec ? LoongArch::PseudoXVREPLI_B : LoongArch::PseudoVREPLI_B;
1155f757f3fSDimitry Andric       ViaVecTy = Is256Vec ? MVT::v32i8 : MVT::v16i8;
1165f757f3fSDimitry Andric       break;
1175f757f3fSDimitry Andric     case 16:
1185f757f3fSDimitry Andric       Op = Is256Vec ? LoongArch::PseudoXVREPLI_H : LoongArch::PseudoVREPLI_H;
1195f757f3fSDimitry Andric       ViaVecTy = Is256Vec ? MVT::v16i16 : MVT::v8i16;
1205f757f3fSDimitry Andric       break;
1215f757f3fSDimitry Andric     case 32:
1225f757f3fSDimitry Andric       Op = Is256Vec ? LoongArch::PseudoXVREPLI_W : LoongArch::PseudoVREPLI_W;
1235f757f3fSDimitry Andric       ViaVecTy = Is256Vec ? MVT::v8i32 : MVT::v4i32;
1245f757f3fSDimitry Andric       break;
1255f757f3fSDimitry Andric     case 64:
1265f757f3fSDimitry Andric       Op = Is256Vec ? LoongArch::PseudoXVREPLI_D : LoongArch::PseudoVREPLI_D;
1275f757f3fSDimitry Andric       ViaVecTy = Is256Vec ? MVT::v4i64 : MVT::v2i64;
1285f757f3fSDimitry Andric       break;
1295f757f3fSDimitry Andric     }
1305f757f3fSDimitry Andric 
1315f757f3fSDimitry Andric     SDNode *Res;
1325f757f3fSDimitry Andric     // If we have a signed 10 bit integer, we can splat it directly.
1335f757f3fSDimitry Andric     if (SplatValue.isSignedIntN(10)) {
1345f757f3fSDimitry Andric       SDValue Imm = CurDAG->getTargetConstant(SplatValue, DL,
1355f757f3fSDimitry Andric                                               ViaVecTy.getVectorElementType());
1365f757f3fSDimitry Andric       Res = CurDAG->getMachineNode(Op, DL, ViaVecTy, Imm);
1375f757f3fSDimitry Andric       ReplaceNode(Node, Res);
1385f757f3fSDimitry Andric       return;
1395f757f3fSDimitry Andric     }
1405f757f3fSDimitry Andric     break;
1415f757f3fSDimitry Andric   }
14281ad6265SDimitry Andric   }
14381ad6265SDimitry Andric 
14481ad6265SDimitry Andric   // Select the default instruction.
14581ad6265SDimitry Andric   SelectCode(Node);
14681ad6265SDimitry Andric }
14781ad6265SDimitry Andric 
SelectInlineAsmMemoryOperand(const SDValue & Op,InlineAsm::ConstraintCode ConstraintID,std::vector<SDValue> & OutOps)148bdd1243dSDimitry Andric bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand(
1495f757f3fSDimitry Andric     const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
1505f757f3fSDimitry Andric     std::vector<SDValue> &OutOps) {
151bdd1243dSDimitry Andric   SDValue Base = Op;
152bdd1243dSDimitry Andric   SDValue Offset =
153bdd1243dSDimitry Andric       CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT());
154bdd1243dSDimitry Andric   switch (ConstraintID) {
155bdd1243dSDimitry Andric   default:
156bdd1243dSDimitry Andric     llvm_unreachable("unexpected asm memory constraint");
157bdd1243dSDimitry Andric   // Reg+Reg addressing.
1585f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::k:
159bdd1243dSDimitry Andric     Base = Op.getOperand(0);
160bdd1243dSDimitry Andric     Offset = Op.getOperand(1);
161bdd1243dSDimitry Andric     break;
162bdd1243dSDimitry Andric   // Reg+simm12 addressing.
1635f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::m:
164bdd1243dSDimitry Andric     if (CurDAG->isBaseWithConstantOffset(Op)) {
165bdd1243dSDimitry Andric       ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
166bdd1243dSDimitry Andric       if (isIntN(12, CN->getSExtValue())) {
167bdd1243dSDimitry Andric         Base = Op.getOperand(0);
168bdd1243dSDimitry Andric         Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),
169bdd1243dSDimitry Andric                                            Op.getValueType());
170bdd1243dSDimitry Andric       }
171bdd1243dSDimitry Andric     }
172bdd1243dSDimitry Andric     break;
173bdd1243dSDimitry Andric   // Reg+0 addressing.
1745f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::ZB:
175bdd1243dSDimitry Andric     break;
176bdd1243dSDimitry Andric   // Reg+(simm14<<2) addressing.
1775f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::ZC:
178bdd1243dSDimitry Andric     if (CurDAG->isBaseWithConstantOffset(Op)) {
179bdd1243dSDimitry Andric       ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));
180bdd1243dSDimitry Andric       if (isIntN(16, CN->getSExtValue()) &&
181bdd1243dSDimitry Andric           isAligned(Align(4ULL), CN->getZExtValue())) {
182bdd1243dSDimitry Andric         Base = Op.getOperand(0);
183bdd1243dSDimitry Andric         Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),
184bdd1243dSDimitry Andric                                            Op.getValueType());
185bdd1243dSDimitry Andric       }
186bdd1243dSDimitry Andric     }
187bdd1243dSDimitry Andric     break;
188bdd1243dSDimitry Andric   }
189bdd1243dSDimitry Andric   OutOps.push_back(Base);
190bdd1243dSDimitry Andric   OutOps.push_back(Offset);
191bdd1243dSDimitry Andric   return false;
192bdd1243dSDimitry Andric }
193bdd1243dSDimitry Andric 
SelectBaseAddr(SDValue Addr,SDValue & Base)194753f127fSDimitry Andric bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) {
195753f127fSDimitry Andric   // If this is FrameIndex, select it directly. Otherwise just let it get
196753f127fSDimitry Andric   // selected to a register independently.
197753f127fSDimitry Andric   if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr))
198753f127fSDimitry Andric     Base =
199753f127fSDimitry Andric         CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT());
200753f127fSDimitry Andric   else
201753f127fSDimitry Andric     Base = Addr;
202753f127fSDimitry Andric   return true;
203753f127fSDimitry Andric }
204753f127fSDimitry Andric 
20506c3fb27SDimitry Andric // Fold constant addresses.
SelectAddrConstant(SDValue Addr,SDValue & Base,SDValue & Offset)20606c3fb27SDimitry Andric bool LoongArchDAGToDAGISel::SelectAddrConstant(SDValue Addr, SDValue &Base,
20706c3fb27SDimitry Andric                                                SDValue &Offset) {
20806c3fb27SDimitry Andric   SDLoc DL(Addr);
20906c3fb27SDimitry Andric   MVT VT = Addr.getSimpleValueType();
21006c3fb27SDimitry Andric 
21106c3fb27SDimitry Andric   if (!isa<ConstantSDNode>(Addr))
21206c3fb27SDimitry Andric     return false;
21306c3fb27SDimitry Andric 
21406c3fb27SDimitry Andric   // If the constant is a simm12, we can fold the whole constant and use R0 as
21506c3fb27SDimitry Andric   // the base.
21606c3fb27SDimitry Andric   int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue();
21706c3fb27SDimitry Andric   if (!isInt<12>(CVal))
21806c3fb27SDimitry Andric     return false;
21906c3fb27SDimitry Andric   Base = CurDAG->getRegister(LoongArch::R0, VT);
22006c3fb27SDimitry Andric   Offset = CurDAG->getTargetConstant(SignExtend64<12>(CVal), DL, VT);
22106c3fb27SDimitry Andric   return true;
22206c3fb27SDimitry Andric }
22306c3fb27SDimitry Andric 
selectNonFIBaseAddr(SDValue Addr,SDValue & Base)224bdd1243dSDimitry Andric bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) {
225bdd1243dSDimitry Andric   // If this is FrameIndex, don't select it.
226bdd1243dSDimitry Andric   if (isa<FrameIndexSDNode>(Addr))
227bdd1243dSDimitry Andric     return false;
228bdd1243dSDimitry Andric   Base = Addr;
229bdd1243dSDimitry Andric   return true;
230bdd1243dSDimitry Andric }
231bdd1243dSDimitry Andric 
selectShiftMask(SDValue N,unsigned ShiftWidth,SDValue & ShAmt)23281ad6265SDimitry Andric bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
23381ad6265SDimitry Andric                                             SDValue &ShAmt) {
23481ad6265SDimitry Andric   // Shift instructions on LoongArch only read the lower 5 or 6 bits of the
23581ad6265SDimitry Andric   // shift amount. If there is an AND on the shift amount, we can bypass it if
23681ad6265SDimitry Andric   // it doesn't affect any of those bits.
23781ad6265SDimitry Andric   if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) {
23881ad6265SDimitry Andric     const APInt &AndMask = N->getConstantOperandAPInt(1);
23981ad6265SDimitry Andric 
24081ad6265SDimitry Andric     // Since the max shift amount is a power of 2 we can subtract 1 to make a
24181ad6265SDimitry Andric     // mask that covers the bits needed to represent all shift amounts.
24281ad6265SDimitry Andric     assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
24381ad6265SDimitry Andric     APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
24481ad6265SDimitry Andric 
24581ad6265SDimitry Andric     if (ShMask.isSubsetOf(AndMask)) {
24681ad6265SDimitry Andric       ShAmt = N.getOperand(0);
24781ad6265SDimitry Andric       return true;
24881ad6265SDimitry Andric     }
24981ad6265SDimitry Andric 
25081ad6265SDimitry Andric     // SimplifyDemandedBits may have optimized the mask so try restoring any
25181ad6265SDimitry Andric     // bits that are known zero.
25281ad6265SDimitry Andric     KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0));
25381ad6265SDimitry Andric     if (ShMask.isSubsetOf(AndMask | Known.Zero)) {
25481ad6265SDimitry Andric       ShAmt = N.getOperand(0);
25581ad6265SDimitry Andric       return true;
25681ad6265SDimitry Andric     }
25781ad6265SDimitry Andric   } else if (N.getOpcode() == LoongArchISD::BSTRPICK) {
25881ad6265SDimitry Andric     // Similar to the above AND, if there is a BSTRPICK on the shift amount, we
25981ad6265SDimitry Andric     // can bypass it.
26081ad6265SDimitry Andric     assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
26181ad6265SDimitry Andric     assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!");
26281ad6265SDimitry Andric     assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!");
26381ad6265SDimitry Andric     uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2);
26481ad6265SDimitry Andric     if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) {
26581ad6265SDimitry Andric       ShAmt = N.getOperand(0);
26681ad6265SDimitry Andric       return true;
26781ad6265SDimitry Andric     }
26881ad6265SDimitry Andric   } else if (N.getOpcode() == ISD::SUB &&
26981ad6265SDimitry Andric              isa<ConstantSDNode>(N.getOperand(0))) {
27081ad6265SDimitry Andric     uint64_t Imm = N.getConstantOperandVal(0);
27181ad6265SDimitry Andric     // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to
27281ad6265SDimitry Andric     // generate a NEG instead of a SUB of a constant.
27381ad6265SDimitry Andric     if (Imm != 0 && Imm % ShiftWidth == 0) {
27481ad6265SDimitry Andric       SDLoc DL(N);
27581ad6265SDimitry Andric       EVT VT = N.getValueType();
27681ad6265SDimitry Andric       SDValue Zero =
27781ad6265SDimitry Andric           CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT);
27881ad6265SDimitry Andric       unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W;
27981ad6265SDimitry Andric       MachineSDNode *Neg =
28081ad6265SDimitry Andric           CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1));
28181ad6265SDimitry Andric       ShAmt = SDValue(Neg, 0);
28281ad6265SDimitry Andric       return true;
28381ad6265SDimitry Andric     }
28481ad6265SDimitry Andric   }
28581ad6265SDimitry Andric 
28681ad6265SDimitry Andric   ShAmt = N;
28781ad6265SDimitry Andric   return true;
28881ad6265SDimitry Andric }
28981ad6265SDimitry Andric 
selectSExti32(SDValue N,SDValue & Val)290753f127fSDimitry Andric bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) {
291753f127fSDimitry Andric   if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
292753f127fSDimitry Andric       cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {
293753f127fSDimitry Andric     Val = N.getOperand(0);
294753f127fSDimitry Andric     return true;
295753f127fSDimitry Andric   }
296bdd1243dSDimitry Andric   if (N.getOpcode() == LoongArchISD::BSTRPICK &&
297bdd1243dSDimitry Andric       N.getConstantOperandVal(1) < UINT64_C(0X1F) &&
298bdd1243dSDimitry Andric       N.getConstantOperandVal(2) == UINT64_C(0)) {
299bdd1243dSDimitry Andric     Val = N;
300bdd1243dSDimitry Andric     return true;
301bdd1243dSDimitry Andric   }
302753f127fSDimitry Andric   MVT VT = N.getSimpleValueType();
303753f127fSDimitry Andric   if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {
304753f127fSDimitry Andric     Val = N;
305753f127fSDimitry Andric     return true;
306753f127fSDimitry Andric   }
307753f127fSDimitry Andric 
308753f127fSDimitry Andric   return false;
309753f127fSDimitry Andric }
310753f127fSDimitry Andric 
selectZExti32(SDValue N,SDValue & Val)311753f127fSDimitry Andric bool LoongArchDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) {
312753f127fSDimitry Andric   if (N.getOpcode() == ISD::AND) {
313753f127fSDimitry Andric     auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1));
314753f127fSDimitry Andric     if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) {
315753f127fSDimitry Andric       Val = N.getOperand(0);
316753f127fSDimitry Andric       return true;
317753f127fSDimitry Andric     }
318753f127fSDimitry Andric   }
319753f127fSDimitry Andric   MVT VT = N.getSimpleValueType();
320753f127fSDimitry Andric   APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32);
321753f127fSDimitry Andric   if (CurDAG->MaskedValueIsZero(N, Mask)) {
322753f127fSDimitry Andric     Val = N;
323753f127fSDimitry Andric     return true;
324753f127fSDimitry Andric   }
325753f127fSDimitry Andric 
326753f127fSDimitry Andric   return false;
327753f127fSDimitry Andric }
328753f127fSDimitry Andric 
selectVSplat(SDNode * N,APInt & Imm,unsigned MinSizeInBits) const3295f757f3fSDimitry Andric bool LoongArchDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm,
3305f757f3fSDimitry Andric                                          unsigned MinSizeInBits) const {
3315f757f3fSDimitry Andric   if (!Subtarget->hasExtLSX())
3325f757f3fSDimitry Andric     return false;
3335f757f3fSDimitry Andric 
3345f757f3fSDimitry Andric   BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N);
3355f757f3fSDimitry Andric 
3365f757f3fSDimitry Andric   if (!Node)
3375f757f3fSDimitry Andric     return false;
3385f757f3fSDimitry Andric 
3395f757f3fSDimitry Andric   APInt SplatValue, SplatUndef;
3405f757f3fSDimitry Andric   unsigned SplatBitSize;
3415f757f3fSDimitry Andric   bool HasAnyUndefs;
3425f757f3fSDimitry Andric 
3435f757f3fSDimitry Andric   if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
3445f757f3fSDimitry Andric                              MinSizeInBits, /*IsBigEndian=*/false))
3455f757f3fSDimitry Andric     return false;
3465f757f3fSDimitry Andric 
3475f757f3fSDimitry Andric   Imm = SplatValue;
3485f757f3fSDimitry Andric 
3495f757f3fSDimitry Andric   return true;
3505f757f3fSDimitry Andric }
3515f757f3fSDimitry Andric 
3525f757f3fSDimitry Andric template <unsigned ImmBitSize, bool IsSigned>
selectVSplatImm(SDValue N,SDValue & SplatVal)3535f757f3fSDimitry Andric bool LoongArchDAGToDAGISel::selectVSplatImm(SDValue N, SDValue &SplatVal) {
3545f757f3fSDimitry Andric   APInt ImmValue;
3555f757f3fSDimitry Andric   EVT EltTy = N->getValueType(0).getVectorElementType();
3565f757f3fSDimitry Andric 
3575f757f3fSDimitry Andric   if (N->getOpcode() == ISD::BITCAST)
3585f757f3fSDimitry Andric     N = N->getOperand(0);
3595f757f3fSDimitry Andric 
3605f757f3fSDimitry Andric   if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
3615f757f3fSDimitry Andric       ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
3625f757f3fSDimitry Andric     if (IsSigned && ImmValue.isSignedIntN(ImmBitSize)) {
3635f757f3fSDimitry Andric       SplatVal = CurDAG->getTargetConstant(ImmValue.getSExtValue(), SDLoc(N),
3645f757f3fSDimitry Andric                                            Subtarget->getGRLenVT());
3655f757f3fSDimitry Andric       return true;
3665f757f3fSDimitry Andric     }
3675f757f3fSDimitry Andric     if (!IsSigned && ImmValue.isIntN(ImmBitSize)) {
3685f757f3fSDimitry Andric       SplatVal = CurDAG->getTargetConstant(ImmValue.getZExtValue(), SDLoc(N),
3695f757f3fSDimitry Andric                                            Subtarget->getGRLenVT());
3705f757f3fSDimitry Andric       return true;
3715f757f3fSDimitry Andric     }
3725f757f3fSDimitry Andric   }
3735f757f3fSDimitry Andric 
3745f757f3fSDimitry Andric   return false;
3755f757f3fSDimitry Andric }
3765f757f3fSDimitry Andric 
selectVSplatUimmInvPow2(SDValue N,SDValue & SplatImm) const3775f757f3fSDimitry Andric bool LoongArchDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N,
3785f757f3fSDimitry Andric                                                     SDValue &SplatImm) const {
3795f757f3fSDimitry Andric   APInt ImmValue;
3805f757f3fSDimitry Andric   EVT EltTy = N->getValueType(0).getVectorElementType();
3815f757f3fSDimitry Andric 
3825f757f3fSDimitry Andric   if (N->getOpcode() == ISD::BITCAST)
3835f757f3fSDimitry Andric     N = N->getOperand(0);
3845f757f3fSDimitry Andric 
3855f757f3fSDimitry Andric   if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
3865f757f3fSDimitry Andric       ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
3875f757f3fSDimitry Andric     int32_t Log2 = (~ImmValue).exactLogBase2();
3885f757f3fSDimitry Andric 
3895f757f3fSDimitry Andric     if (Log2 != -1) {
3905f757f3fSDimitry Andric       SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
3915f757f3fSDimitry Andric       return true;
3925f757f3fSDimitry Andric     }
3935f757f3fSDimitry Andric   }
3945f757f3fSDimitry Andric 
3955f757f3fSDimitry Andric   return false;
3965f757f3fSDimitry Andric }
3975f757f3fSDimitry Andric 
selectVSplatUimmPow2(SDValue N,SDValue & SplatImm) const3985f757f3fSDimitry Andric bool LoongArchDAGToDAGISel::selectVSplatUimmPow2(SDValue N,
3995f757f3fSDimitry Andric                                                  SDValue &SplatImm) const {
4005f757f3fSDimitry Andric   APInt ImmValue;
4015f757f3fSDimitry Andric   EVT EltTy = N->getValueType(0).getVectorElementType();
4025f757f3fSDimitry Andric 
4035f757f3fSDimitry Andric   if (N->getOpcode() == ISD::BITCAST)
4045f757f3fSDimitry Andric     N = N->getOperand(0);
4055f757f3fSDimitry Andric 
4065f757f3fSDimitry Andric   if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
4075f757f3fSDimitry Andric       ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
4085f757f3fSDimitry Andric     int32_t Log2 = ImmValue.exactLogBase2();
4095f757f3fSDimitry Andric 
4105f757f3fSDimitry Andric     if (Log2 != -1) {
4115f757f3fSDimitry Andric       SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
4125f757f3fSDimitry Andric       return true;
4135f757f3fSDimitry Andric     }
4145f757f3fSDimitry Andric   }
4155f757f3fSDimitry Andric 
4165f757f3fSDimitry Andric   return false;
4175f757f3fSDimitry Andric }
4185f757f3fSDimitry Andric 
41981ad6265SDimitry Andric // This pass converts a legalized DAG into a LoongArch-specific DAG, ready
42081ad6265SDimitry Andric // for instruction scheduling.
createLoongArchISelDag(LoongArchTargetMachine & TM)42181ad6265SDimitry Andric FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) {
422*0fca6ea1SDimitry Andric   return new LoongArchDAGToDAGISelLegacy(TM);
42381ad6265SDimitry Andric }
424