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