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 27*0fca6ea1SDimitry Andric LoongArchDAGToDAGISelLegacy::LoongArchDAGToDAGISelLegacy( 28*0fca6ea1SDimitry Andric LoongArchTargetMachine &TM) 29*0fca6ea1SDimitry Andric : SelectionDAGISelLegacy(ID, std::make_unique<LoongArchDAGToDAGISel>(TM)) {} 30*0fca6ea1SDimitry Andric 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 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 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. 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 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 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 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 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 3295f757f3fSDimitry 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> 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 3775f757f3fSDimitry 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 3985f757f3fSDimitry 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. 42181ad6265SDimitry Andric FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) { 422*0fca6ea1SDimitry Andric return new LoongArchDAGToDAGISelLegacy(TM); 42381ad6265SDimitry Andric } 424