xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (revision 753f127f3ace09432b2baeffd71a308760641a62)
181ad6265SDimitry Andric //=- LoongArchISelLowering.cpp - LoongArch DAG Lowering Implementation  ---===//
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 the interfaces that LoongArch uses to lower LLVM code into
1081ad6265SDimitry Andric // a selection DAG.
1181ad6265SDimitry Andric //
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric #include "LoongArchISelLowering.h"
1581ad6265SDimitry Andric #include "LoongArch.h"
1681ad6265SDimitry Andric #include "LoongArchMachineFunctionInfo.h"
1781ad6265SDimitry Andric #include "LoongArchRegisterInfo.h"
1881ad6265SDimitry Andric #include "LoongArchSubtarget.h"
1981ad6265SDimitry Andric #include "LoongArchTargetMachine.h"
20*753f127fSDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h"
2181ad6265SDimitry Andric #include "llvm/ADT/Statistic.h"
2281ad6265SDimitry Andric #include "llvm/CodeGen/ISDOpcodes.h"
2381ad6265SDimitry Andric #include "llvm/Support/Debug.h"
24*753f127fSDimitry Andric #include "llvm/Support/KnownBits.h"
2581ad6265SDimitry Andric 
2681ad6265SDimitry Andric using namespace llvm;
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-isel-lowering"
2981ad6265SDimitry Andric 
30*753f127fSDimitry Andric static cl::opt<bool> ZeroDivCheck(
31*753f127fSDimitry Andric     "loongarch-check-zero-division", cl::Hidden,
32*753f127fSDimitry Andric     cl::desc("Trap on integer division by zero."),
33*753f127fSDimitry Andric     cl::init(false));
34*753f127fSDimitry Andric 
3581ad6265SDimitry Andric LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
3681ad6265SDimitry Andric                                                  const LoongArchSubtarget &STI)
3781ad6265SDimitry Andric     : TargetLowering(TM), Subtarget(STI) {
3881ad6265SDimitry Andric 
3981ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
4081ad6265SDimitry Andric   // Set up the register classes.
4181ad6265SDimitry Andric   addRegisterClass(GRLenVT, &LoongArch::GPRRegClass);
4281ad6265SDimitry Andric   if (Subtarget.hasBasicF())
4381ad6265SDimitry Andric     addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass);
4481ad6265SDimitry Andric   if (Subtarget.hasBasicD())
4581ad6265SDimitry Andric     addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass);
4681ad6265SDimitry Andric 
47*753f127fSDimitry Andric   setLoadExtAction({ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}, GRLenVT,
48*753f127fSDimitry Andric                    MVT::i1, Promote);
49*753f127fSDimitry Andric 
5081ad6265SDimitry Andric   // TODO: add necessary setOperationAction calls later.
5181ad6265SDimitry Andric   setOperationAction(ISD::SHL_PARTS, GRLenVT, Custom);
5281ad6265SDimitry Andric   setOperationAction(ISD::SRA_PARTS, GRLenVT, Custom);
5381ad6265SDimitry Andric   setOperationAction(ISD::SRL_PARTS, GRLenVT, Custom);
54*753f127fSDimitry Andric   setOperationAction(ISD::FP_TO_SINT, GRLenVT, Custom);
55*753f127fSDimitry Andric 
56*753f127fSDimitry Andric   setOperationAction({ISD::GlobalAddress, ISD::ConstantPool}, GRLenVT, Custom);
5781ad6265SDimitry Andric 
5881ad6265SDimitry Andric   if (Subtarget.is64Bit()) {
5981ad6265SDimitry Andric     setOperationAction(ISD::SHL, MVT::i32, Custom);
6081ad6265SDimitry Andric     setOperationAction(ISD::SRA, MVT::i32, Custom);
6181ad6265SDimitry Andric     setOperationAction(ISD::SRL, MVT::i32, Custom);
62*753f127fSDimitry Andric     setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
63*753f127fSDimitry Andric     setOperationAction(ISD::BITCAST, MVT::i32, Custom);
64*753f127fSDimitry Andric     if (Subtarget.hasBasicF() && !Subtarget.hasBasicD())
65*753f127fSDimitry Andric       setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
6681ad6265SDimitry Andric   }
6781ad6265SDimitry Andric 
6881ad6265SDimitry Andric   static const ISD::CondCode FPCCToExpand[] = {ISD::SETOGT, ISD::SETOGE,
6981ad6265SDimitry Andric                                                ISD::SETUGT, ISD::SETUGE};
7081ad6265SDimitry Andric 
7181ad6265SDimitry Andric   if (Subtarget.hasBasicF()) {
7281ad6265SDimitry Andric     setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
7381ad6265SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
7481ad6265SDimitry Andric   }
7581ad6265SDimitry Andric   if (Subtarget.hasBasicD()) {
7681ad6265SDimitry Andric     setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
7781ad6265SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f64, Expand);
78*753f127fSDimitry Andric     setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
79*753f127fSDimitry Andric     setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
8081ad6265SDimitry Andric   }
8181ad6265SDimitry Andric 
82*753f127fSDimitry Andric   setOperationAction(ISD::BR_CC, GRLenVT, Expand);
8381ad6265SDimitry Andric   setOperationAction(ISD::SELECT_CC, GRLenVT, Expand);
8481ad6265SDimitry Andric   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
85*753f127fSDimitry Andric   setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, GRLenVT, Expand);
86*753f127fSDimitry Andric   if (!Subtarget.is64Bit())
87*753f127fSDimitry Andric     setLibcallName(RTLIB::MUL_I128, nullptr);
88*753f127fSDimitry Andric 
89*753f127fSDimitry Andric   setOperationAction(ISD::FP_TO_UINT, GRLenVT, Custom);
90*753f127fSDimitry Andric   setOperationAction(ISD::UINT_TO_FP, GRLenVT, Custom);
9181ad6265SDimitry Andric 
9281ad6265SDimitry Andric   // Compute derived properties from the register classes.
9381ad6265SDimitry Andric   computeRegisterProperties(STI.getRegisterInfo());
9481ad6265SDimitry Andric 
9581ad6265SDimitry Andric   setStackPointerRegisterToSaveRestore(LoongArch::R3);
9681ad6265SDimitry Andric 
9781ad6265SDimitry Andric   setBooleanContents(ZeroOrOneBooleanContent);
9881ad6265SDimitry Andric 
99*753f127fSDimitry Andric   setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen());
100*753f127fSDimitry Andric 
10181ad6265SDimitry Andric   // Function alignments.
10281ad6265SDimitry Andric   const Align FunctionAlignment(4);
10381ad6265SDimitry Andric   setMinFunctionAlignment(FunctionAlignment);
10481ad6265SDimitry Andric 
10581ad6265SDimitry Andric   setTargetDAGCombine(ISD::AND);
106*753f127fSDimitry Andric   setTargetDAGCombine(ISD::OR);
10781ad6265SDimitry Andric   setTargetDAGCombine(ISD::SRL);
10881ad6265SDimitry Andric }
10981ad6265SDimitry Andric 
11081ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
11181ad6265SDimitry Andric                                                 SelectionDAG &DAG) const {
11281ad6265SDimitry Andric   switch (Op.getOpcode()) {
11381ad6265SDimitry Andric   default:
11481ad6265SDimitry Andric     report_fatal_error("unimplemented operand");
115*753f127fSDimitry Andric   case ISD::GlobalAddress:
116*753f127fSDimitry Andric     return lowerGlobalAddress(Op, DAG);
11781ad6265SDimitry Andric   case ISD::SHL_PARTS:
11881ad6265SDimitry Andric     return lowerShiftLeftParts(Op, DAG);
11981ad6265SDimitry Andric   case ISD::SRA_PARTS:
12081ad6265SDimitry Andric     return lowerShiftRightParts(Op, DAG, true);
12181ad6265SDimitry Andric   case ISD::SRL_PARTS:
12281ad6265SDimitry Andric     return lowerShiftRightParts(Op, DAG, false);
12381ad6265SDimitry Andric   case ISD::SHL:
12481ad6265SDimitry Andric   case ISD::SRA:
12581ad6265SDimitry Andric   case ISD::SRL:
12681ad6265SDimitry Andric     // This can be called for an i32 shift amount that needs to be promoted.
12781ad6265SDimitry Andric     assert(Op.getOperand(1).getValueType() == MVT::i32 && Subtarget.is64Bit() &&
12881ad6265SDimitry Andric            "Unexpected custom legalisation");
12981ad6265SDimitry Andric     return SDValue();
130*753f127fSDimitry Andric   case ISD::ConstantPool:
131*753f127fSDimitry Andric     return lowerConstantPool(Op, DAG);
132*753f127fSDimitry Andric   case ISD::FP_TO_SINT:
133*753f127fSDimitry Andric     return lowerFP_TO_SINT(Op, DAG);
134*753f127fSDimitry Andric   case ISD::BITCAST:
135*753f127fSDimitry Andric     return lowerBITCAST(Op, DAG);
136*753f127fSDimitry Andric   case ISD::FP_TO_UINT:
137*753f127fSDimitry Andric     return SDValue();
138*753f127fSDimitry Andric   case ISD::UINT_TO_FP:
139*753f127fSDimitry Andric     return lowerUINT_TO_FP(Op, DAG);
14081ad6265SDimitry Andric   }
14181ad6265SDimitry Andric }
14281ad6265SDimitry Andric 
143*753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
144*753f127fSDimitry Andric                                                  SelectionDAG &DAG) const {
145*753f127fSDimitry Andric 
146*753f127fSDimitry Andric   SDLoc DL(Op);
147*753f127fSDimitry Andric   auto &TLI = DAG.getTargetLoweringInfo();
148*753f127fSDimitry Andric   SDValue Tmp1, Tmp2;
149*753f127fSDimitry Andric   SDValue Op1 = Op.getOperand(0);
150*753f127fSDimitry Andric   if (Op1->getOpcode() == ISD::AssertZext ||
151*753f127fSDimitry Andric       Op1->getOpcode() == ISD::AssertSext)
152*753f127fSDimitry Andric     return Op;
153*753f127fSDimitry Andric   SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Op.getOperand(0));
154*753f127fSDimitry Andric   SDValue Res = DAG.getNode(ISD::UINT_TO_FP, DL, MVT::f64, Trunc);
155*753f127fSDimitry Andric   SDNode *N = Res.getNode();
156*753f127fSDimitry Andric   TLI.expandUINT_TO_FP(N, Tmp1, Tmp2, DAG);
157*753f127fSDimitry Andric   return Tmp1;
158*753f127fSDimitry Andric }
159*753f127fSDimitry Andric 
160*753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
161*753f127fSDimitry Andric                                               SelectionDAG &DAG) const {
162*753f127fSDimitry Andric 
163*753f127fSDimitry Andric   SDLoc DL(Op);
164*753f127fSDimitry Andric   SDValue Op0 = Op.getOperand(0);
165*753f127fSDimitry Andric 
166*753f127fSDimitry Andric   if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 &&
167*753f127fSDimitry Andric       Subtarget.is64Bit() && Subtarget.hasBasicF()) {
168*753f127fSDimitry Andric     SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
169*753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
170*753f127fSDimitry Andric   }
171*753f127fSDimitry Andric   return Op;
172*753f127fSDimitry Andric }
173*753f127fSDimitry Andric 
174*753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
175*753f127fSDimitry Andric                                                  SelectionDAG &DAG) const {
176*753f127fSDimitry Andric 
177*753f127fSDimitry Andric   SDLoc DL(Op);
178*753f127fSDimitry Andric 
179*753f127fSDimitry Andric   if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
180*753f127fSDimitry Andric       !Subtarget.hasBasicD()) {
181*753f127fSDimitry Andric     SDValue Dst =
182*753f127fSDimitry Andric         DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0));
183*753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
184*753f127fSDimitry Andric   }
185*753f127fSDimitry Andric 
186*753f127fSDimitry Andric   EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
187*753f127fSDimitry Andric   SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0));
188*753f127fSDimitry Andric   return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
189*753f127fSDimitry Andric }
190*753f127fSDimitry Andric 
191*753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
192*753f127fSDimitry Andric                                                    SelectionDAG &DAG) const {
193*753f127fSDimitry Andric   SDLoc DL(Op);
194*753f127fSDimitry Andric   EVT Ty = Op.getValueType();
195*753f127fSDimitry Andric   ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op);
196*753f127fSDimitry Andric 
197*753f127fSDimitry Andric   // FIXME: Only support PC-relative addressing to access the symbol.
198*753f127fSDimitry Andric   // Target flags will be added later.
199*753f127fSDimitry Andric   if (!isPositionIndependent()) {
200*753f127fSDimitry Andric     SDValue ConstantN = DAG.getTargetConstantPool(
201*753f127fSDimitry Andric         N->getConstVal(), Ty, N->getAlign(), N->getOffset());
202*753f127fSDimitry Andric     SDValue AddrHi(DAG.getMachineNode(LoongArch::PCALAU12I, DL, Ty, ConstantN),
203*753f127fSDimitry Andric                    0);
204*753f127fSDimitry Andric     SDValue Addr(DAG.getMachineNode(Subtarget.is64Bit() ? LoongArch::ADDI_D
205*753f127fSDimitry Andric                                                         : LoongArch::ADDI_W,
206*753f127fSDimitry Andric                                     DL, Ty, AddrHi, ConstantN),
207*753f127fSDimitry Andric                  0);
208*753f127fSDimitry Andric     return Addr;
209*753f127fSDimitry Andric   }
210*753f127fSDimitry Andric   report_fatal_error("Unable to lower ConstantPool");
211*753f127fSDimitry Andric }
212*753f127fSDimitry Andric 
213*753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
214*753f127fSDimitry Andric                                                     SelectionDAG &DAG) const {
215*753f127fSDimitry Andric   SDLoc DL(Op);
216*753f127fSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
217*753f127fSDimitry Andric   const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
218*753f127fSDimitry Andric   unsigned ADDIOp = Subtarget.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
219*753f127fSDimitry Andric 
220*753f127fSDimitry Andric   // FIXME: Only support PC-relative addressing to access the symbol.
221*753f127fSDimitry Andric   // TODO: Add target flags.
222*753f127fSDimitry Andric   if (!isPositionIndependent()) {
223*753f127fSDimitry Andric     SDValue GA = DAG.getTargetGlobalAddress(GV, DL, Ty);
224*753f127fSDimitry Andric     SDValue AddrHi(DAG.getMachineNode(LoongArch::PCALAU12I, DL, Ty, GA), 0);
225*753f127fSDimitry Andric     SDValue Addr(DAG.getMachineNode(ADDIOp, DL, Ty, AddrHi, GA), 0);
226*753f127fSDimitry Andric     return Addr;
227*753f127fSDimitry Andric   }
228*753f127fSDimitry Andric   report_fatal_error("Unable to lowerGlobalAddress");
229*753f127fSDimitry Andric }
230*753f127fSDimitry Andric 
23181ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
23281ad6265SDimitry Andric                                                      SelectionDAG &DAG) const {
23381ad6265SDimitry Andric   SDLoc DL(Op);
23481ad6265SDimitry Andric   SDValue Lo = Op.getOperand(0);
23581ad6265SDimitry Andric   SDValue Hi = Op.getOperand(1);
23681ad6265SDimitry Andric   SDValue Shamt = Op.getOperand(2);
23781ad6265SDimitry Andric   EVT VT = Lo.getValueType();
23881ad6265SDimitry Andric 
23981ad6265SDimitry Andric   // if Shamt-GRLen < 0: // Shamt < GRLen
24081ad6265SDimitry Andric   //   Lo = Lo << Shamt
24181ad6265SDimitry Andric   //   Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
24281ad6265SDimitry Andric   // else:
24381ad6265SDimitry Andric   //   Lo = 0
24481ad6265SDimitry Andric   //   Hi = Lo << (Shamt-GRLen)
24581ad6265SDimitry Andric 
24681ad6265SDimitry Andric   SDValue Zero = DAG.getConstant(0, DL, VT);
24781ad6265SDimitry Andric   SDValue One = DAG.getConstant(1, DL, VT);
24881ad6265SDimitry Andric   SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
24981ad6265SDimitry Andric   SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
25081ad6265SDimitry Andric   SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
25181ad6265SDimitry Andric   SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
25281ad6265SDimitry Andric 
25381ad6265SDimitry Andric   SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
25481ad6265SDimitry Andric   SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
25581ad6265SDimitry Andric   SDValue ShiftRightLo =
25681ad6265SDimitry Andric       DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
25781ad6265SDimitry Andric   SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
25881ad6265SDimitry Andric   SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
25981ad6265SDimitry Andric   SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
26081ad6265SDimitry Andric 
26181ad6265SDimitry Andric   SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
26281ad6265SDimitry Andric 
26381ad6265SDimitry Andric   Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
26481ad6265SDimitry Andric   Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
26581ad6265SDimitry Andric 
26681ad6265SDimitry Andric   SDValue Parts[2] = {Lo, Hi};
26781ad6265SDimitry Andric   return DAG.getMergeValues(Parts, DL);
26881ad6265SDimitry Andric }
26981ad6265SDimitry Andric 
27081ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
27181ad6265SDimitry Andric                                                       SelectionDAG &DAG,
27281ad6265SDimitry Andric                                                       bool IsSRA) const {
27381ad6265SDimitry Andric   SDLoc DL(Op);
27481ad6265SDimitry Andric   SDValue Lo = Op.getOperand(0);
27581ad6265SDimitry Andric   SDValue Hi = Op.getOperand(1);
27681ad6265SDimitry Andric   SDValue Shamt = Op.getOperand(2);
27781ad6265SDimitry Andric   EVT VT = Lo.getValueType();
27881ad6265SDimitry Andric 
27981ad6265SDimitry Andric   // SRA expansion:
28081ad6265SDimitry Andric   //   if Shamt-GRLen < 0: // Shamt < GRLen
28181ad6265SDimitry Andric   //     Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
28281ad6265SDimitry Andric   //     Hi = Hi >>s Shamt
28381ad6265SDimitry Andric   //   else:
28481ad6265SDimitry Andric   //     Lo = Hi >>s (Shamt-GRLen);
28581ad6265SDimitry Andric   //     Hi = Hi >>s (GRLen-1)
28681ad6265SDimitry Andric   //
28781ad6265SDimitry Andric   // SRL expansion:
28881ad6265SDimitry Andric   //   if Shamt-GRLen < 0: // Shamt < GRLen
28981ad6265SDimitry Andric   //     Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
29081ad6265SDimitry Andric   //     Hi = Hi >>u Shamt
29181ad6265SDimitry Andric   //   else:
29281ad6265SDimitry Andric   //     Lo = Hi >>u (Shamt-GRLen);
29381ad6265SDimitry Andric   //     Hi = 0;
29481ad6265SDimitry Andric 
29581ad6265SDimitry Andric   unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
29681ad6265SDimitry Andric 
29781ad6265SDimitry Andric   SDValue Zero = DAG.getConstant(0, DL, VT);
29881ad6265SDimitry Andric   SDValue One = DAG.getConstant(1, DL, VT);
29981ad6265SDimitry Andric   SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
30081ad6265SDimitry Andric   SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
30181ad6265SDimitry Andric   SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
30281ad6265SDimitry Andric   SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
30381ad6265SDimitry Andric 
30481ad6265SDimitry Andric   SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
30581ad6265SDimitry Andric   SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
30681ad6265SDimitry Andric   SDValue ShiftLeftHi =
30781ad6265SDimitry Andric       DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
30881ad6265SDimitry Andric   SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
30981ad6265SDimitry Andric   SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
31081ad6265SDimitry Andric   SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
31181ad6265SDimitry Andric   SDValue HiFalse =
31281ad6265SDimitry Andric       IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
31381ad6265SDimitry Andric 
31481ad6265SDimitry Andric   SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
31581ad6265SDimitry Andric 
31681ad6265SDimitry Andric   Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
31781ad6265SDimitry Andric   Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
31881ad6265SDimitry Andric 
31981ad6265SDimitry Andric   SDValue Parts[2] = {Lo, Hi};
32081ad6265SDimitry Andric   return DAG.getMergeValues(Parts, DL);
32181ad6265SDimitry Andric }
32281ad6265SDimitry Andric 
32381ad6265SDimitry Andric // Returns the opcode of the target-specific SDNode that implements the 32-bit
32481ad6265SDimitry Andric // form of the given Opcode.
32581ad6265SDimitry Andric static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode) {
32681ad6265SDimitry Andric   switch (Opcode) {
32781ad6265SDimitry Andric   default:
32881ad6265SDimitry Andric     llvm_unreachable("Unexpected opcode");
32981ad6265SDimitry Andric   case ISD::SHL:
33081ad6265SDimitry Andric     return LoongArchISD::SLL_W;
33181ad6265SDimitry Andric   case ISD::SRA:
33281ad6265SDimitry Andric     return LoongArchISD::SRA_W;
33381ad6265SDimitry Andric   case ISD::SRL:
33481ad6265SDimitry Andric     return LoongArchISD::SRL_W;
33581ad6265SDimitry Andric   }
33681ad6265SDimitry Andric }
33781ad6265SDimitry Andric 
33881ad6265SDimitry Andric // Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
33981ad6265SDimitry Andric // node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
34081ad6265SDimitry Andric // otherwise be promoted to i64, making it difficult to select the
34181ad6265SDimitry Andric // SLL_W/.../*W later one because the fact the operation was originally of
34281ad6265SDimitry Andric // type i8/i16/i32 is lost.
34381ad6265SDimitry Andric static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG,
34481ad6265SDimitry Andric                                    unsigned ExtOpc = ISD::ANY_EXTEND) {
34581ad6265SDimitry Andric   SDLoc DL(N);
34681ad6265SDimitry Andric   LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode());
34781ad6265SDimitry Andric   SDValue NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
34881ad6265SDimitry Andric   SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
34981ad6265SDimitry Andric   SDValue NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
35081ad6265SDimitry Andric   // ReplaceNodeResults requires we maintain the same type for the return value.
35181ad6265SDimitry Andric   return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
35281ad6265SDimitry Andric }
35381ad6265SDimitry Andric 
35481ad6265SDimitry Andric void LoongArchTargetLowering::ReplaceNodeResults(
35581ad6265SDimitry Andric     SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
35681ad6265SDimitry Andric   SDLoc DL(N);
35781ad6265SDimitry Andric   switch (N->getOpcode()) {
35881ad6265SDimitry Andric   default:
35981ad6265SDimitry Andric     llvm_unreachable("Don't know how to legalize this operation");
36081ad6265SDimitry Andric   case ISD::SHL:
36181ad6265SDimitry Andric   case ISD::SRA:
36281ad6265SDimitry Andric   case ISD::SRL:
36381ad6265SDimitry Andric     assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
36481ad6265SDimitry Andric            "Unexpected custom legalisation");
36581ad6265SDimitry Andric     if (N->getOperand(1).getOpcode() != ISD::Constant) {
36681ad6265SDimitry Andric       Results.push_back(customLegalizeToWOp(N, DAG));
36781ad6265SDimitry Andric       break;
36881ad6265SDimitry Andric     }
36981ad6265SDimitry Andric     break;
370*753f127fSDimitry Andric   case ISD::FP_TO_SINT: {
371*753f127fSDimitry Andric     assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
372*753f127fSDimitry Andric            "Unexpected custom legalisation");
373*753f127fSDimitry Andric     SDValue Src = N->getOperand(0);
374*753f127fSDimitry Andric     EVT VT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
375*753f127fSDimitry Andric     SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, VT, Src);
376*753f127fSDimitry Andric     Results.push_back(DAG.getNode(ISD::BITCAST, DL, N->getValueType(0), Dst));
377*753f127fSDimitry Andric     break;
378*753f127fSDimitry Andric   }
379*753f127fSDimitry Andric   case ISD::BITCAST: {
380*753f127fSDimitry Andric     EVT VT = N->getValueType(0);
381*753f127fSDimitry Andric     SDValue Src = N->getOperand(0);
382*753f127fSDimitry Andric     EVT SrcVT = Src.getValueType();
383*753f127fSDimitry Andric     if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
384*753f127fSDimitry Andric         Subtarget.hasBasicF()) {
385*753f127fSDimitry Andric       SDValue Dst =
386*753f127fSDimitry Andric           DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
387*753f127fSDimitry Andric       Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
388*753f127fSDimitry Andric     }
389*753f127fSDimitry Andric     break;
390*753f127fSDimitry Andric   }
391*753f127fSDimitry Andric   case ISD::FP_TO_UINT: {
392*753f127fSDimitry Andric     assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
393*753f127fSDimitry Andric            "Unexpected custom legalisation");
394*753f127fSDimitry Andric     auto &TLI = DAG.getTargetLoweringInfo();
395*753f127fSDimitry Andric     SDValue Tmp1, Tmp2;
396*753f127fSDimitry Andric     TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
397*753f127fSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
398*753f127fSDimitry Andric     break;
399*753f127fSDimitry Andric   }
40081ad6265SDimitry Andric   }
40181ad6265SDimitry Andric }
40281ad6265SDimitry Andric 
40381ad6265SDimitry Andric static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG,
40481ad6265SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
40581ad6265SDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
40681ad6265SDimitry Andric   if (DCI.isBeforeLegalizeOps())
40781ad6265SDimitry Andric     return SDValue();
40881ad6265SDimitry Andric 
40981ad6265SDimitry Andric   SDValue FirstOperand = N->getOperand(0);
41081ad6265SDimitry Andric   SDValue SecondOperand = N->getOperand(1);
41181ad6265SDimitry Andric   unsigned FirstOperandOpc = FirstOperand.getOpcode();
41281ad6265SDimitry Andric   EVT ValTy = N->getValueType(0);
41381ad6265SDimitry Andric   SDLoc DL(N);
41481ad6265SDimitry Andric   uint64_t lsb, msb;
41581ad6265SDimitry Andric   unsigned SMIdx, SMLen;
41681ad6265SDimitry Andric   ConstantSDNode *CN;
41781ad6265SDimitry Andric   SDValue NewOperand;
41881ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
41981ad6265SDimitry Andric 
42081ad6265SDimitry Andric   // Op's second operand must be a shifted mask.
42181ad6265SDimitry Andric   if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
42281ad6265SDimitry Andric       !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
42381ad6265SDimitry Andric     return SDValue();
42481ad6265SDimitry Andric 
42581ad6265SDimitry Andric   if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
42681ad6265SDimitry Andric     // Pattern match BSTRPICK.
42781ad6265SDimitry Andric     //  $dst = and ((sra or srl) $src , lsb), (2**len - 1)
42881ad6265SDimitry Andric     //  => BSTRPICK $dst, $src, msb, lsb
42981ad6265SDimitry Andric     //  where msb = lsb + len - 1
43081ad6265SDimitry Andric 
43181ad6265SDimitry Andric     // The second operand of the shift must be an immediate.
43281ad6265SDimitry Andric     if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
43381ad6265SDimitry Andric       return SDValue();
43481ad6265SDimitry Andric 
43581ad6265SDimitry Andric     lsb = CN->getZExtValue();
43681ad6265SDimitry Andric 
43781ad6265SDimitry Andric     // Return if the shifted mask does not start at bit 0 or the sum of its
43881ad6265SDimitry Andric     // length and lsb exceeds the word's size.
43981ad6265SDimitry Andric     if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
44081ad6265SDimitry Andric       return SDValue();
44181ad6265SDimitry Andric 
44281ad6265SDimitry Andric     NewOperand = FirstOperand.getOperand(0);
44381ad6265SDimitry Andric   } else {
44481ad6265SDimitry Andric     // Pattern match BSTRPICK.
44581ad6265SDimitry Andric     //  $dst = and $src, (2**len- 1) , if len > 12
44681ad6265SDimitry Andric     //  => BSTRPICK $dst, $src, msb, lsb
44781ad6265SDimitry Andric     //  where lsb = 0 and msb = len - 1
44881ad6265SDimitry Andric 
44981ad6265SDimitry Andric     // If the mask is <= 0xfff, andi can be used instead.
45081ad6265SDimitry Andric     if (CN->getZExtValue() <= 0xfff)
45181ad6265SDimitry Andric       return SDValue();
45281ad6265SDimitry Andric 
45381ad6265SDimitry Andric     // Return if the mask doesn't start at position 0.
45481ad6265SDimitry Andric     if (SMIdx)
45581ad6265SDimitry Andric       return SDValue();
45681ad6265SDimitry Andric 
45781ad6265SDimitry Andric     lsb = 0;
45881ad6265SDimitry Andric     NewOperand = FirstOperand;
45981ad6265SDimitry Andric   }
46081ad6265SDimitry Andric   msb = lsb + SMLen - 1;
46181ad6265SDimitry Andric   return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
46281ad6265SDimitry Andric                      DAG.getConstant(msb, DL, GRLenVT),
46381ad6265SDimitry Andric                      DAG.getConstant(lsb, DL, GRLenVT));
46481ad6265SDimitry Andric }
46581ad6265SDimitry Andric 
46681ad6265SDimitry Andric static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG,
46781ad6265SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
46881ad6265SDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
46981ad6265SDimitry Andric   if (DCI.isBeforeLegalizeOps())
47081ad6265SDimitry Andric     return SDValue();
47181ad6265SDimitry Andric 
47281ad6265SDimitry Andric   // $dst = srl (and $src, Mask), Shamt
47381ad6265SDimitry Andric   // =>
47481ad6265SDimitry Andric   // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
47581ad6265SDimitry Andric   // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
47681ad6265SDimitry Andric   //
47781ad6265SDimitry Andric 
47881ad6265SDimitry Andric   SDValue FirstOperand = N->getOperand(0);
47981ad6265SDimitry Andric   ConstantSDNode *CN;
48081ad6265SDimitry Andric   EVT ValTy = N->getValueType(0);
48181ad6265SDimitry Andric   SDLoc DL(N);
48281ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
48381ad6265SDimitry Andric   unsigned MaskIdx, MaskLen;
48481ad6265SDimitry Andric   uint64_t Shamt;
48581ad6265SDimitry Andric 
48681ad6265SDimitry Andric   // The first operand must be an AND and the second operand of the AND must be
48781ad6265SDimitry Andric   // a shifted mask.
48881ad6265SDimitry Andric   if (FirstOperand.getOpcode() != ISD::AND ||
48981ad6265SDimitry Andric       !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
49081ad6265SDimitry Andric       !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
49181ad6265SDimitry Andric     return SDValue();
49281ad6265SDimitry Andric 
49381ad6265SDimitry Andric   // The second operand (shift amount) must be an immediate.
49481ad6265SDimitry Andric   if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
49581ad6265SDimitry Andric     return SDValue();
49681ad6265SDimitry Andric 
49781ad6265SDimitry Andric   Shamt = CN->getZExtValue();
49881ad6265SDimitry Andric   if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
49981ad6265SDimitry Andric     return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
50081ad6265SDimitry Andric                        FirstOperand->getOperand(0),
50181ad6265SDimitry Andric                        DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
50281ad6265SDimitry Andric                        DAG.getConstant(Shamt, DL, GRLenVT));
50381ad6265SDimitry Andric 
50481ad6265SDimitry Andric   return SDValue();
50581ad6265SDimitry Andric }
50681ad6265SDimitry Andric 
507*753f127fSDimitry Andric static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
508*753f127fSDimitry Andric                                 TargetLowering::DAGCombinerInfo &DCI,
509*753f127fSDimitry Andric                                 const LoongArchSubtarget &Subtarget) {
510*753f127fSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
511*753f127fSDimitry Andric   EVT ValTy = N->getValueType(0);
512*753f127fSDimitry Andric   SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
513*753f127fSDimitry Andric   ConstantSDNode *CN0, *CN1;
514*753f127fSDimitry Andric   SDLoc DL(N);
515*753f127fSDimitry Andric   unsigned ValBits = ValTy.getSizeInBits();
516*753f127fSDimitry Andric   unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
517*753f127fSDimitry Andric   unsigned Shamt;
518*753f127fSDimitry Andric   bool SwapAndRetried = false;
519*753f127fSDimitry Andric 
520*753f127fSDimitry Andric   if (DCI.isBeforeLegalizeOps())
521*753f127fSDimitry Andric     return SDValue();
522*753f127fSDimitry Andric 
523*753f127fSDimitry Andric   if (ValBits != 32 && ValBits != 64)
524*753f127fSDimitry Andric     return SDValue();
525*753f127fSDimitry Andric 
526*753f127fSDimitry Andric Retry:
527*753f127fSDimitry Andric   // 1st pattern to match BSTRINS:
528*753f127fSDimitry Andric   //  R = or (and X, mask0), (and (shl Y, lsb), mask1)
529*753f127fSDimitry Andric   //  where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
530*753f127fSDimitry Andric   //  =>
531*753f127fSDimitry Andric   //  R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
532*753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
533*753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
534*753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
535*753f127fSDimitry Andric       N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
536*753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
537*753f127fSDimitry Andric       isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
538*753f127fSDimitry Andric       MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
539*753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
540*753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
541*753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
542*753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
543*753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
544*753f127fSDimitry Andric                        N1.getOperand(0).getOperand(0),
545*753f127fSDimitry Andric                        DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
546*753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
547*753f127fSDimitry Andric   }
548*753f127fSDimitry Andric 
549*753f127fSDimitry Andric   // 2nd pattern to match BSTRINS:
550*753f127fSDimitry Andric   //  R = or (and X, mask0), (shl (and Y, mask1), lsb)
551*753f127fSDimitry Andric   //  where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
552*753f127fSDimitry Andric   //  =>
553*753f127fSDimitry Andric   //  R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
554*753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
555*753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
556*753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
557*753f127fSDimitry Andric       N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
558*753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
559*753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
560*753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
561*753f127fSDimitry Andric       isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
562*753f127fSDimitry Andric       MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
563*753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
564*753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
565*753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
566*753f127fSDimitry Andric                        N1.getOperand(0).getOperand(0),
567*753f127fSDimitry Andric                        DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
568*753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
569*753f127fSDimitry Andric   }
570*753f127fSDimitry Andric 
571*753f127fSDimitry Andric   // 3rd pattern to match BSTRINS:
572*753f127fSDimitry Andric   //  R = or (and X, mask0), (and Y, mask1)
573*753f127fSDimitry Andric   //  where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
574*753f127fSDimitry Andric   //  =>
575*753f127fSDimitry Andric   //  R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
576*753f127fSDimitry Andric   //  where msb = lsb + size - 1
577*753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
578*753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
579*753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
580*753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= 64) &&
581*753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
582*753f127fSDimitry Andric       (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
583*753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
584*753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
585*753f127fSDimitry Andric                        DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
586*753f127fSDimitry Andric                                    DAG.getConstant(MaskIdx0, DL, GRLenVT)),
587*753f127fSDimitry Andric                        DAG.getConstant(ValBits == 32
588*753f127fSDimitry Andric                                            ? (MaskIdx0 + (MaskLen0 & 31) - 1)
589*753f127fSDimitry Andric                                            : (MaskIdx0 + MaskLen0 - 1),
590*753f127fSDimitry Andric                                        DL, GRLenVT),
591*753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
592*753f127fSDimitry Andric   }
593*753f127fSDimitry Andric 
594*753f127fSDimitry Andric   // 4th pattern to match BSTRINS:
595*753f127fSDimitry Andric   //  R = or (and X, mask), (shl Y, shamt)
596*753f127fSDimitry Andric   //  where mask = (2**shamt - 1)
597*753f127fSDimitry Andric   //  =>
598*753f127fSDimitry Andric   //  R = BSTRINS X, Y, ValBits - 1, shamt
599*753f127fSDimitry Andric   //  where ValBits = 32 or 64
600*753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
601*753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
602*753f127fSDimitry Andric       isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
603*753f127fSDimitry Andric       MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
604*753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskLen0 &&
605*753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
606*753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
607*753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
608*753f127fSDimitry Andric                        N1.getOperand(0),
609*753f127fSDimitry Andric                        DAG.getConstant((ValBits - 1), DL, GRLenVT),
610*753f127fSDimitry Andric                        DAG.getConstant(Shamt, DL, GRLenVT));
611*753f127fSDimitry Andric   }
612*753f127fSDimitry Andric 
613*753f127fSDimitry Andric   // 5th pattern to match BSTRINS:
614*753f127fSDimitry Andric   //  R = or (and X, mask), const
615*753f127fSDimitry Andric   //  where ~mask = (2**size - 1) << lsb, mask & const = 0
616*753f127fSDimitry Andric   //  =>
617*753f127fSDimitry Andric   //  R = BSTRINS X, (const >> lsb), msb, lsb
618*753f127fSDimitry Andric   //  where msb = lsb + size - 1
619*753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
620*753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
621*753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
622*753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
623*753f127fSDimitry Andric       (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
624*753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
625*753f127fSDimitry Andric     return DAG.getNode(
626*753f127fSDimitry Andric         LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
627*753f127fSDimitry Andric         DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
628*753f127fSDimitry Andric         DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
629*753f127fSDimitry Andric         DAG.getConstant(MaskIdx0, DL, GRLenVT));
630*753f127fSDimitry Andric   }
631*753f127fSDimitry Andric 
632*753f127fSDimitry Andric   // 6th pattern.
633*753f127fSDimitry Andric   // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
634*753f127fSDimitry Andric   // by the incoming bits are known to be zero.
635*753f127fSDimitry Andric   // =>
636*753f127fSDimitry Andric   // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
637*753f127fSDimitry Andric   //
638*753f127fSDimitry Andric   // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
639*753f127fSDimitry Andric   // pattern is more common than the 1st. So we put the 1st before the 6th in
640*753f127fSDimitry Andric   // order to match as many nodes as possible.
641*753f127fSDimitry Andric   ConstantSDNode *CNMask, *CNShamt;
642*753f127fSDimitry Andric   unsigned MaskIdx, MaskLen;
643*753f127fSDimitry Andric   if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
644*753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
645*753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
646*753f127fSDimitry Andric       MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
647*753f127fSDimitry Andric       CNShamt->getZExtValue() + MaskLen <= ValBits) {
648*753f127fSDimitry Andric     Shamt = CNShamt->getZExtValue();
649*753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
650*753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
651*753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
652*753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
653*753f127fSDimitry Andric                          N1.getOperand(0).getOperand(0),
654*753f127fSDimitry Andric                          DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
655*753f127fSDimitry Andric                          DAG.getConstant(Shamt, DL, GRLenVT));
656*753f127fSDimitry Andric     }
657*753f127fSDimitry Andric   }
658*753f127fSDimitry Andric 
659*753f127fSDimitry Andric   // 7th pattern.
660*753f127fSDimitry Andric   // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
661*753f127fSDimitry Andric   // overwritten by the incoming bits are known to be zero.
662*753f127fSDimitry Andric   // =>
663*753f127fSDimitry Andric   // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
664*753f127fSDimitry Andric   //
665*753f127fSDimitry Andric   // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
666*753f127fSDimitry Andric   // before the 7th in order to match as many nodes as possible.
667*753f127fSDimitry Andric   if (N1.getOpcode() == ISD::AND &&
668*753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
669*753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
670*753f127fSDimitry Andric       N1.getOperand(0).getOpcode() == ISD::SHL &&
671*753f127fSDimitry Andric       (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
672*753f127fSDimitry Andric       CNShamt->getZExtValue() == MaskIdx) {
673*753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue());
674*753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
675*753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
676*753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
677*753f127fSDimitry Andric                          N1.getOperand(0).getOperand(0),
678*753f127fSDimitry Andric                          DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
679*753f127fSDimitry Andric                          DAG.getConstant(MaskIdx, DL, GRLenVT));
680*753f127fSDimitry Andric     }
681*753f127fSDimitry Andric   }
682*753f127fSDimitry Andric 
683*753f127fSDimitry Andric   // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
684*753f127fSDimitry Andric   if (!SwapAndRetried) {
685*753f127fSDimitry Andric     std::swap(N0, N1);
686*753f127fSDimitry Andric     SwapAndRetried = true;
687*753f127fSDimitry Andric     goto Retry;
688*753f127fSDimitry Andric   }
689*753f127fSDimitry Andric 
690*753f127fSDimitry Andric   SwapAndRetried = false;
691*753f127fSDimitry Andric Retry2:
692*753f127fSDimitry Andric   // 8th pattern.
693*753f127fSDimitry Andric   // a = b | (c & shifted_mask), where all positions in b to be overwritten by
694*753f127fSDimitry Andric   // the incoming bits are known to be zero.
695*753f127fSDimitry Andric   // =>
696*753f127fSDimitry Andric   // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
697*753f127fSDimitry Andric   //
698*753f127fSDimitry Andric   // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
699*753f127fSDimitry Andric   // we put it here in order to match as many nodes as possible or generate less
700*753f127fSDimitry Andric   // instructions.
701*753f127fSDimitry Andric   if (N1.getOpcode() == ISD::AND &&
702*753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
703*753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
704*753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue());
705*753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
706*753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
707*753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
708*753f127fSDimitry Andric                          DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
709*753f127fSDimitry Andric                                      N1->getOperand(0),
710*753f127fSDimitry Andric                                      DAG.getConstant(MaskIdx, DL, GRLenVT)),
711*753f127fSDimitry Andric                          DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
712*753f127fSDimitry Andric                          DAG.getConstant(MaskIdx, DL, GRLenVT));
713*753f127fSDimitry Andric     }
714*753f127fSDimitry Andric   }
715*753f127fSDimitry Andric   // Swap N0/N1 and retry.
716*753f127fSDimitry Andric   if (!SwapAndRetried) {
717*753f127fSDimitry Andric     std::swap(N0, N1);
718*753f127fSDimitry Andric     SwapAndRetried = true;
719*753f127fSDimitry Andric     goto Retry2;
720*753f127fSDimitry Andric   }
721*753f127fSDimitry Andric 
722*753f127fSDimitry Andric   return SDValue();
723*753f127fSDimitry Andric }
724*753f127fSDimitry Andric 
72581ad6265SDimitry Andric SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N,
72681ad6265SDimitry Andric                                                    DAGCombinerInfo &DCI) const {
72781ad6265SDimitry Andric   SelectionDAG &DAG = DCI.DAG;
72881ad6265SDimitry Andric   switch (N->getOpcode()) {
72981ad6265SDimitry Andric   default:
73081ad6265SDimitry Andric     break;
73181ad6265SDimitry Andric   case ISD::AND:
73281ad6265SDimitry Andric     return performANDCombine(N, DAG, DCI, Subtarget);
733*753f127fSDimitry Andric   case ISD::OR:
734*753f127fSDimitry Andric     return performORCombine(N, DAG, DCI, Subtarget);
73581ad6265SDimitry Andric   case ISD::SRL:
73681ad6265SDimitry Andric     return performSRLCombine(N, DAG, DCI, Subtarget);
73781ad6265SDimitry Andric   }
73881ad6265SDimitry Andric   return SDValue();
73981ad6265SDimitry Andric }
74081ad6265SDimitry Andric 
741*753f127fSDimitry Andric static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI,
742*753f127fSDimitry Andric                                               MachineBasicBlock &MBB,
743*753f127fSDimitry Andric                                               const TargetInstrInfo &TII) {
744*753f127fSDimitry Andric   if (!ZeroDivCheck)
745*753f127fSDimitry Andric     return &MBB;
746*753f127fSDimitry Andric 
747*753f127fSDimitry Andric   // Build instructions:
748*753f127fSDimitry Andric   //   div(or mod)   $dst, $dividend, $divisor
749*753f127fSDimitry Andric   //   bnez          $divisor, 8
750*753f127fSDimitry Andric   //   break         7
751*753f127fSDimitry Andric   //   fallthrough
752*753f127fSDimitry Andric   MachineOperand &Divisor = MI.getOperand(2);
753*753f127fSDimitry Andric   auto FallThrough = std::next(MI.getIterator());
754*753f127fSDimitry Andric 
755*753f127fSDimitry Andric   BuildMI(MBB, FallThrough, MI.getDebugLoc(), TII.get(LoongArch::BNEZ))
756*753f127fSDimitry Andric       .addReg(Divisor.getReg(), getKillRegState(Divisor.isKill()))
757*753f127fSDimitry Andric       .addImm(8);
758*753f127fSDimitry Andric 
759*753f127fSDimitry Andric   // See linux header file arch/loongarch/include/uapi/asm/break.h for the
760*753f127fSDimitry Andric   // definition of BRK_DIVZERO.
761*753f127fSDimitry Andric   BuildMI(MBB, FallThrough, MI.getDebugLoc(), TII.get(LoongArch::BREAK))
762*753f127fSDimitry Andric       .addImm(7/*BRK_DIVZERO*/);
763*753f127fSDimitry Andric 
764*753f127fSDimitry Andric   // Clear Divisor's kill flag.
765*753f127fSDimitry Andric   Divisor.setIsKill(false);
766*753f127fSDimitry Andric 
767*753f127fSDimitry Andric   return &MBB;
768*753f127fSDimitry Andric }
769*753f127fSDimitry Andric 
770*753f127fSDimitry Andric MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
771*753f127fSDimitry Andric     MachineInstr &MI, MachineBasicBlock *BB) const {
772*753f127fSDimitry Andric 
773*753f127fSDimitry Andric   switch (MI.getOpcode()) {
774*753f127fSDimitry Andric   default:
775*753f127fSDimitry Andric     llvm_unreachable("Unexpected instr type to insert");
776*753f127fSDimitry Andric   case LoongArch::DIV_W:
777*753f127fSDimitry Andric   case LoongArch::DIV_WU:
778*753f127fSDimitry Andric   case LoongArch::MOD_W:
779*753f127fSDimitry Andric   case LoongArch::MOD_WU:
780*753f127fSDimitry Andric   case LoongArch::DIV_D:
781*753f127fSDimitry Andric   case LoongArch::DIV_DU:
782*753f127fSDimitry Andric   case LoongArch::MOD_D:
783*753f127fSDimitry Andric   case LoongArch::MOD_DU:
784*753f127fSDimitry Andric     return insertDivByZeroTrap(MI, *BB, *Subtarget.getInstrInfo());
785*753f127fSDimitry Andric     break;
786*753f127fSDimitry Andric   }
787*753f127fSDimitry Andric }
788*753f127fSDimitry Andric 
78981ad6265SDimitry Andric const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
79081ad6265SDimitry Andric   switch ((LoongArchISD::NodeType)Opcode) {
79181ad6265SDimitry Andric   case LoongArchISD::FIRST_NUMBER:
79281ad6265SDimitry Andric     break;
79381ad6265SDimitry Andric 
79481ad6265SDimitry Andric #define NODE_NAME_CASE(node)                                                   \
79581ad6265SDimitry Andric   case LoongArchISD::node:                                                     \
79681ad6265SDimitry Andric     return "LoongArchISD::" #node;
79781ad6265SDimitry Andric 
79881ad6265SDimitry Andric     // TODO: Add more target-dependent nodes later.
799*753f127fSDimitry Andric     NODE_NAME_CASE(CALL)
80081ad6265SDimitry Andric     NODE_NAME_CASE(RET)
80181ad6265SDimitry Andric     NODE_NAME_CASE(SLL_W)
80281ad6265SDimitry Andric     NODE_NAME_CASE(SRA_W)
80381ad6265SDimitry Andric     NODE_NAME_CASE(SRL_W)
804*753f127fSDimitry Andric     NODE_NAME_CASE(BSTRINS)
80581ad6265SDimitry Andric     NODE_NAME_CASE(BSTRPICK)
806*753f127fSDimitry Andric     NODE_NAME_CASE(MOVGR2FR_W_LA64)
807*753f127fSDimitry Andric     NODE_NAME_CASE(MOVFR2GR_S_LA64)
808*753f127fSDimitry Andric     NODE_NAME_CASE(FTINT)
80981ad6265SDimitry Andric   }
81081ad6265SDimitry Andric #undef NODE_NAME_CASE
81181ad6265SDimitry Andric   return nullptr;
81281ad6265SDimitry Andric }
81381ad6265SDimitry Andric 
81481ad6265SDimitry Andric //===----------------------------------------------------------------------===//
81581ad6265SDimitry Andric //                     Calling Convention Implementation
81681ad6265SDimitry Andric //===----------------------------------------------------------------------===//
81781ad6265SDimitry Andric // FIXME: Now, we only support CallingConv::C with fixed arguments which are
81881ad6265SDimitry Andric // passed with integer or floating-point registers.
81981ad6265SDimitry Andric const MCPhysReg ArgGPRs[] = {LoongArch::R4,  LoongArch::R5, LoongArch::R6,
82081ad6265SDimitry Andric                              LoongArch::R7,  LoongArch::R8, LoongArch::R9,
82181ad6265SDimitry Andric                              LoongArch::R10, LoongArch::R11};
82281ad6265SDimitry Andric const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
82381ad6265SDimitry Andric                                LoongArch::F3, LoongArch::F4, LoongArch::F5,
82481ad6265SDimitry Andric                                LoongArch::F6, LoongArch::F7};
82581ad6265SDimitry Andric const MCPhysReg ArgFPR64s[] = {
82681ad6265SDimitry Andric     LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
82781ad6265SDimitry Andric     LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
82881ad6265SDimitry Andric 
82981ad6265SDimitry Andric // Implements the LoongArch calling convention. Returns true upon failure.
83081ad6265SDimitry Andric static bool CC_LoongArch(unsigned ValNo, MVT ValVT,
83181ad6265SDimitry Andric                          CCValAssign::LocInfo LocInfo, CCState &State) {
83281ad6265SDimitry Andric   // Allocate to a register if possible.
83381ad6265SDimitry Andric   Register Reg;
83481ad6265SDimitry Andric 
83581ad6265SDimitry Andric   if (ValVT == MVT::f32)
83681ad6265SDimitry Andric     Reg = State.AllocateReg(ArgFPR32s);
83781ad6265SDimitry Andric   else if (ValVT == MVT::f64)
83881ad6265SDimitry Andric     Reg = State.AllocateReg(ArgFPR64s);
83981ad6265SDimitry Andric   else
84081ad6265SDimitry Andric     Reg = State.AllocateReg(ArgGPRs);
84181ad6265SDimitry Andric   if (Reg) {
84281ad6265SDimitry Andric     State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, ValVT, LocInfo));
84381ad6265SDimitry Andric     return false;
84481ad6265SDimitry Andric   }
84581ad6265SDimitry Andric 
84681ad6265SDimitry Andric   // TODO: Handle arguments passed without register.
84781ad6265SDimitry Andric   return true;
84881ad6265SDimitry Andric }
84981ad6265SDimitry Andric 
85081ad6265SDimitry Andric void LoongArchTargetLowering::analyzeInputArgs(
85181ad6265SDimitry Andric     CCState &CCInfo, const SmallVectorImpl<ISD::InputArg> &Ins,
85281ad6265SDimitry Andric     LoongArchCCAssignFn Fn) const {
85381ad6265SDimitry Andric   for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
85481ad6265SDimitry Andric     MVT ArgVT = Ins[i].VT;
85581ad6265SDimitry Andric 
85681ad6265SDimitry Andric     if (Fn(i, ArgVT, CCValAssign::Full, CCInfo)) {
85781ad6265SDimitry Andric       LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type "
85881ad6265SDimitry Andric                         << EVT(ArgVT).getEVTString() << '\n');
85981ad6265SDimitry Andric       llvm_unreachable("");
86081ad6265SDimitry Andric     }
86181ad6265SDimitry Andric   }
86281ad6265SDimitry Andric }
86381ad6265SDimitry Andric 
86481ad6265SDimitry Andric void LoongArchTargetLowering::analyzeOutputArgs(
86581ad6265SDimitry Andric     CCState &CCInfo, const SmallVectorImpl<ISD::OutputArg> &Outs,
86681ad6265SDimitry Andric     LoongArchCCAssignFn Fn) const {
86781ad6265SDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
86881ad6265SDimitry Andric     MVT ArgVT = Outs[i].VT;
86981ad6265SDimitry Andric 
87081ad6265SDimitry Andric     if (Fn(i, ArgVT, CCValAssign::Full, CCInfo)) {
87181ad6265SDimitry Andric       LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type "
87281ad6265SDimitry Andric                         << EVT(ArgVT).getEVTString() << "\n");
87381ad6265SDimitry Andric       llvm_unreachable("");
87481ad6265SDimitry Andric     }
87581ad6265SDimitry Andric   }
87681ad6265SDimitry Andric }
87781ad6265SDimitry Andric 
87881ad6265SDimitry Andric static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain,
87981ad6265SDimitry Andric                                 const CCValAssign &VA, const SDLoc &DL,
88081ad6265SDimitry Andric                                 const LoongArchTargetLowering &TLI) {
88181ad6265SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
88281ad6265SDimitry Andric   MachineRegisterInfo &RegInfo = MF.getRegInfo();
88381ad6265SDimitry Andric   EVT LocVT = VA.getLocVT();
88481ad6265SDimitry Andric   const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
88581ad6265SDimitry Andric   Register VReg = RegInfo.createVirtualRegister(RC);
88681ad6265SDimitry Andric   RegInfo.addLiveIn(VA.getLocReg(), VReg);
88781ad6265SDimitry Andric 
88881ad6265SDimitry Andric   return DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
88981ad6265SDimitry Andric }
89081ad6265SDimitry Andric 
89181ad6265SDimitry Andric // Transform physical registers into virtual registers.
89281ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerFormalArguments(
89381ad6265SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
89481ad6265SDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
89581ad6265SDimitry Andric     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
89681ad6265SDimitry Andric 
89781ad6265SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
89881ad6265SDimitry Andric 
89981ad6265SDimitry Andric   switch (CallConv) {
90081ad6265SDimitry Andric   default:
90181ad6265SDimitry Andric     llvm_unreachable("Unsupported calling convention");
90281ad6265SDimitry Andric   case CallingConv::C:
90381ad6265SDimitry Andric     break;
90481ad6265SDimitry Andric   }
90581ad6265SDimitry Andric 
90681ad6265SDimitry Andric   // Assign locations to all of the incoming arguments.
90781ad6265SDimitry Andric   SmallVector<CCValAssign> ArgLocs;
90881ad6265SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
90981ad6265SDimitry Andric 
91081ad6265SDimitry Andric   analyzeInputArgs(CCInfo, Ins, CC_LoongArch);
91181ad6265SDimitry Andric 
91281ad6265SDimitry Andric   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i)
91381ad6265SDimitry Andric     InVals.push_back(unpackFromRegLoc(DAG, Chain, ArgLocs[i], DL, *this));
91481ad6265SDimitry Andric 
91581ad6265SDimitry Andric   return Chain;
91681ad6265SDimitry Andric }
91781ad6265SDimitry Andric 
918*753f127fSDimitry Andric // Lower a call to a callseq_start + CALL + callseq_end chain, and add input
919*753f127fSDimitry Andric // and output parameter nodes.
920*753f127fSDimitry Andric SDValue
921*753f127fSDimitry Andric LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
922*753f127fSDimitry Andric                                    SmallVectorImpl<SDValue> &InVals) const {
923*753f127fSDimitry Andric   SelectionDAG &DAG = CLI.DAG;
924*753f127fSDimitry Andric   SDLoc &DL = CLI.DL;
925*753f127fSDimitry Andric   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
926*753f127fSDimitry Andric   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
927*753f127fSDimitry Andric   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
928*753f127fSDimitry Andric   SDValue Chain = CLI.Chain;
929*753f127fSDimitry Andric   SDValue Callee = CLI.Callee;
930*753f127fSDimitry Andric   CallingConv::ID CallConv = CLI.CallConv;
931*753f127fSDimitry Andric   bool IsVarArg = CLI.IsVarArg;
932*753f127fSDimitry Andric   EVT PtrVT = getPointerTy(DAG.getDataLayout());
933*753f127fSDimitry Andric   CLI.IsTailCall = false;
934*753f127fSDimitry Andric 
935*753f127fSDimitry Andric   if (IsVarArg)
936*753f127fSDimitry Andric     report_fatal_error("LowerCall with varargs not implemented");
937*753f127fSDimitry Andric 
938*753f127fSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
939*753f127fSDimitry Andric 
940*753f127fSDimitry Andric   // Analyze the operands of the call, assigning locations to each operand.
941*753f127fSDimitry Andric   SmallVector<CCValAssign> ArgLocs;
942*753f127fSDimitry Andric   CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
943*753f127fSDimitry Andric 
944*753f127fSDimitry Andric   analyzeOutputArgs(ArgCCInfo, Outs, CC_LoongArch);
945*753f127fSDimitry Andric 
946*753f127fSDimitry Andric   // Get a count of how many bytes are to be pushed on the stack.
947*753f127fSDimitry Andric   unsigned NumBytes = ArgCCInfo.getNextStackOffset();
948*753f127fSDimitry Andric 
949*753f127fSDimitry Andric   for (auto &Arg : Outs) {
950*753f127fSDimitry Andric     if (!Arg.Flags.isByVal())
951*753f127fSDimitry Andric       continue;
952*753f127fSDimitry Andric     report_fatal_error("Passing arguments byval not implemented");
953*753f127fSDimitry Andric   }
954*753f127fSDimitry Andric 
955*753f127fSDimitry Andric   Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
956*753f127fSDimitry Andric 
957*753f127fSDimitry Andric   // Copy argument values to their designated locations.
958*753f127fSDimitry Andric   SmallVector<std::pair<Register, SDValue>> RegsToPass;
959*753f127fSDimitry Andric   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
960*753f127fSDimitry Andric     CCValAssign &VA = ArgLocs[i];
961*753f127fSDimitry Andric     SDValue ArgValue = OutVals[i];
962*753f127fSDimitry Andric 
963*753f127fSDimitry Andric     // Promote the value if needed.
964*753f127fSDimitry Andric     // For now, only handle fully promoted arguments.
965*753f127fSDimitry Andric     if (VA.getLocInfo() != CCValAssign::Full)
966*753f127fSDimitry Andric       report_fatal_error("Unknown loc info");
967*753f127fSDimitry Andric 
968*753f127fSDimitry Andric     if (VA.isRegLoc()) {
969*753f127fSDimitry Andric       // Queue up the argument copies and emit them at the end.
970*753f127fSDimitry Andric       RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
971*753f127fSDimitry Andric     } else {
972*753f127fSDimitry Andric       report_fatal_error("Passing arguments via the stack not implemented");
973*753f127fSDimitry Andric     }
974*753f127fSDimitry Andric   }
975*753f127fSDimitry Andric 
976*753f127fSDimitry Andric   SDValue Glue;
977*753f127fSDimitry Andric 
978*753f127fSDimitry Andric   // Build a sequence of copy-to-reg nodes, chained and glued together.
979*753f127fSDimitry Andric   for (auto &Reg : RegsToPass) {
980*753f127fSDimitry Andric     Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
981*753f127fSDimitry Andric     Glue = Chain.getValue(1);
982*753f127fSDimitry Andric   }
983*753f127fSDimitry Andric 
984*753f127fSDimitry Andric   // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
985*753f127fSDimitry Andric   // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
986*753f127fSDimitry Andric   // split it and then direct call can be matched by PseudoCALL.
987*753f127fSDimitry Andric   // FIXME: Add target flags for relocation.
988*753f127fSDimitry Andric   if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee))
989*753f127fSDimitry Andric     Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT);
990*753f127fSDimitry Andric   else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
991*753f127fSDimitry Andric     Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT);
992*753f127fSDimitry Andric 
993*753f127fSDimitry Andric   // The first call operand is the chain and the second is the target address.
994*753f127fSDimitry Andric   SmallVector<SDValue> Ops;
995*753f127fSDimitry Andric   Ops.push_back(Chain);
996*753f127fSDimitry Andric   Ops.push_back(Callee);
997*753f127fSDimitry Andric 
998*753f127fSDimitry Andric   // Add argument registers to the end of the list so that they are
999*753f127fSDimitry Andric   // known live into the call.
1000*753f127fSDimitry Andric   for (auto &Reg : RegsToPass)
1001*753f127fSDimitry Andric     Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
1002*753f127fSDimitry Andric 
1003*753f127fSDimitry Andric   // Add a register mask operand representing the call-preserved registers.
1004*753f127fSDimitry Andric   const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
1005*753f127fSDimitry Andric   const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
1006*753f127fSDimitry Andric   assert(Mask && "Missing call preserved mask for calling convention");
1007*753f127fSDimitry Andric   Ops.push_back(DAG.getRegisterMask(Mask));
1008*753f127fSDimitry Andric 
1009*753f127fSDimitry Andric   // Glue the call to the argument copies, if any.
1010*753f127fSDimitry Andric   if (Glue.getNode())
1011*753f127fSDimitry Andric     Ops.push_back(Glue);
1012*753f127fSDimitry Andric 
1013*753f127fSDimitry Andric   // Emit the call.
1014*753f127fSDimitry Andric   SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
1015*753f127fSDimitry Andric 
1016*753f127fSDimitry Andric   Chain = DAG.getNode(LoongArchISD::CALL, DL, NodeTys, Ops);
1017*753f127fSDimitry Andric   DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
1018*753f127fSDimitry Andric   Glue = Chain.getValue(1);
1019*753f127fSDimitry Andric 
1020*753f127fSDimitry Andric   // Mark the end of the call, which is glued to the call itself.
1021*753f127fSDimitry Andric   Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, DL, PtrVT, true),
1022*753f127fSDimitry Andric                              DAG.getConstant(0, DL, PtrVT, true), Glue, DL);
1023*753f127fSDimitry Andric   Glue = Chain.getValue(1);
1024*753f127fSDimitry Andric 
1025*753f127fSDimitry Andric   // Assign locations to each value returned by this call.
1026*753f127fSDimitry Andric   SmallVector<CCValAssign> RVLocs;
1027*753f127fSDimitry Andric   CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
1028*753f127fSDimitry Andric   analyzeInputArgs(RetCCInfo, Ins, CC_LoongArch);
1029*753f127fSDimitry Andric 
1030*753f127fSDimitry Andric   // Copy all of the result registers out of their specified physreg.
1031*753f127fSDimitry Andric   for (auto &VA : RVLocs) {
1032*753f127fSDimitry Andric     // Copy the value out.
1033*753f127fSDimitry Andric     SDValue RetValue =
1034*753f127fSDimitry Andric         DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
1035*753f127fSDimitry Andric     Chain = RetValue.getValue(1);
1036*753f127fSDimitry Andric     Glue = RetValue.getValue(2);
1037*753f127fSDimitry Andric 
1038*753f127fSDimitry Andric     InVals.push_back(Chain.getValue(0));
1039*753f127fSDimitry Andric   }
1040*753f127fSDimitry Andric 
1041*753f127fSDimitry Andric   return Chain;
1042*753f127fSDimitry Andric }
1043*753f127fSDimitry Andric 
104481ad6265SDimitry Andric bool LoongArchTargetLowering::CanLowerReturn(
104581ad6265SDimitry Andric     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
104681ad6265SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
104781ad6265SDimitry Andric   // Any return value split in to more than two values can't be returned
104881ad6265SDimitry Andric   // directly.
104981ad6265SDimitry Andric   return Outs.size() <= 2;
105081ad6265SDimitry Andric }
105181ad6265SDimitry Andric 
105281ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerReturn(
105381ad6265SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
105481ad6265SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs,
105581ad6265SDimitry Andric     const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
105681ad6265SDimitry Andric     SelectionDAG &DAG) const {
105781ad6265SDimitry Andric   // Stores the assignment of the return value to a location.
105881ad6265SDimitry Andric   SmallVector<CCValAssign> RVLocs;
105981ad6265SDimitry Andric 
106081ad6265SDimitry Andric   // Info about the registers and stack slot.
106181ad6265SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
106281ad6265SDimitry Andric                  *DAG.getContext());
106381ad6265SDimitry Andric 
106481ad6265SDimitry Andric   analyzeOutputArgs(CCInfo, Outs, CC_LoongArch);
106581ad6265SDimitry Andric 
106681ad6265SDimitry Andric   SDValue Glue;
106781ad6265SDimitry Andric   SmallVector<SDValue, 4> RetOps(1, Chain);
106881ad6265SDimitry Andric 
106981ad6265SDimitry Andric   // Copy the result values into the output registers.
107081ad6265SDimitry Andric   for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) {
107181ad6265SDimitry Andric     CCValAssign &VA = RVLocs[i];
107281ad6265SDimitry Andric     assert(VA.isRegLoc() && "Can only return in registers!");
107381ad6265SDimitry Andric 
107481ad6265SDimitry Andric     // Handle a 'normal' return.
107581ad6265SDimitry Andric     Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Glue);
107681ad6265SDimitry Andric 
107781ad6265SDimitry Andric     // Guarantee that all emitted copies are stuck together.
107881ad6265SDimitry Andric     Glue = Chain.getValue(1);
107981ad6265SDimitry Andric     RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
108081ad6265SDimitry Andric   }
108181ad6265SDimitry Andric 
108281ad6265SDimitry Andric   RetOps[0] = Chain; // Update chain.
108381ad6265SDimitry Andric 
108481ad6265SDimitry Andric   // Add the glue node if we have it.
108581ad6265SDimitry Andric   if (Glue.getNode())
108681ad6265SDimitry Andric     RetOps.push_back(Glue);
108781ad6265SDimitry Andric 
108881ad6265SDimitry Andric   return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
108981ad6265SDimitry Andric }
1090*753f127fSDimitry Andric 
1091*753f127fSDimitry Andric bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
1092*753f127fSDimitry Andric                                            bool ForCodeSize) const {
1093*753f127fSDimitry Andric   assert((VT == MVT::f32 || VT == MVT::f64) && "Unexpected VT");
1094*753f127fSDimitry Andric 
1095*753f127fSDimitry Andric   if (VT == MVT::f32 && !Subtarget.hasBasicF())
1096*753f127fSDimitry Andric     return false;
1097*753f127fSDimitry Andric   if (VT == MVT::f64 && !Subtarget.hasBasicD())
1098*753f127fSDimitry Andric     return false;
1099*753f127fSDimitry Andric   return (Imm.isZero() || Imm.isExactlyValue(+1.0));
1100*753f127fSDimitry Andric }
1101