xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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*bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h"
21753f127fSDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h"
2281ad6265SDimitry Andric #include "llvm/ADT/Statistic.h"
2381ad6265SDimitry Andric #include "llvm/CodeGen/ISDOpcodes.h"
24*bdd1243dSDimitry Andric #include "llvm/CodeGen/RuntimeLibcalls.h"
25*bdd1243dSDimitry Andric #include "llvm/IR/IRBuilder.h"
26*bdd1243dSDimitry Andric #include "llvm/IR/IntrinsicsLoongArch.h"
2781ad6265SDimitry Andric #include "llvm/Support/Debug.h"
28753f127fSDimitry Andric #include "llvm/Support/KnownBits.h"
29*bdd1243dSDimitry Andric #include "llvm/Support/MathExtras.h"
3081ad6265SDimitry Andric 
3181ad6265SDimitry Andric using namespace llvm;
3281ad6265SDimitry Andric 
3381ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-isel-lowering"
3481ad6265SDimitry Andric 
35*bdd1243dSDimitry Andric STATISTIC(NumTailCalls, "Number of tail calls");
36*bdd1243dSDimitry Andric 
37753f127fSDimitry Andric static cl::opt<bool> ZeroDivCheck(
38753f127fSDimitry Andric     "loongarch-check-zero-division", cl::Hidden,
39753f127fSDimitry Andric     cl::desc("Trap on integer division by zero."),
40753f127fSDimitry Andric     cl::init(false));
41753f127fSDimitry Andric 
4281ad6265SDimitry Andric LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
4381ad6265SDimitry Andric                                                  const LoongArchSubtarget &STI)
4481ad6265SDimitry Andric     : TargetLowering(TM), Subtarget(STI) {
4581ad6265SDimitry Andric 
4681ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
4781ad6265SDimitry Andric   // Set up the register classes.
4881ad6265SDimitry Andric   addRegisterClass(GRLenVT, &LoongArch::GPRRegClass);
4981ad6265SDimitry Andric   if (Subtarget.hasBasicF())
5081ad6265SDimitry Andric     addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass);
5181ad6265SDimitry Andric   if (Subtarget.hasBasicD())
5281ad6265SDimitry Andric     addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass);
5381ad6265SDimitry Andric 
54753f127fSDimitry Andric   setLoadExtAction({ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}, GRLenVT,
55753f127fSDimitry Andric                    MVT::i1, Promote);
56753f127fSDimitry Andric 
5781ad6265SDimitry Andric   // TODO: add necessary setOperationAction calls later.
5881ad6265SDimitry Andric   setOperationAction(ISD::SHL_PARTS, GRLenVT, Custom);
5981ad6265SDimitry Andric   setOperationAction(ISD::SRA_PARTS, GRLenVT, Custom);
6081ad6265SDimitry Andric   setOperationAction(ISD::SRL_PARTS, GRLenVT, Custom);
61753f127fSDimitry Andric   setOperationAction(ISD::FP_TO_SINT, GRLenVT, Custom);
62*bdd1243dSDimitry Andric   setOperationAction(ISD::ROTL, GRLenVT, Expand);
63*bdd1243dSDimitry Andric   setOperationAction(ISD::CTPOP, GRLenVT, Expand);
64*bdd1243dSDimitry Andric   setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
65*bdd1243dSDimitry Andric   setOperationAction(ISD::TRAP, MVT::Other, Legal);
66*bdd1243dSDimitry Andric   setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
67*bdd1243dSDimitry Andric   setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
68753f127fSDimitry Andric 
69*bdd1243dSDimitry Andric   setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool,
70*bdd1243dSDimitry Andric                       ISD::JumpTable},
71*bdd1243dSDimitry Andric                      GRLenVT, Custom);
72*bdd1243dSDimitry Andric 
73*bdd1243dSDimitry Andric   setOperationAction(ISD::GlobalTLSAddress, GRLenVT, Custom);
74*bdd1243dSDimitry Andric 
75*bdd1243dSDimitry Andric   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
76*bdd1243dSDimitry Andric 
77*bdd1243dSDimitry Andric   setOperationAction(ISD::EH_DWARF_CFA, MVT::i32, Custom);
78*bdd1243dSDimitry Andric   if (Subtarget.is64Bit())
79*bdd1243dSDimitry Andric     setOperationAction(ISD::EH_DWARF_CFA, MVT::i64, Custom);
80*bdd1243dSDimitry Andric 
81*bdd1243dSDimitry Andric   setOperationAction(ISD::DYNAMIC_STACKALLOC, GRLenVT, Expand);
82*bdd1243dSDimitry Andric   setOperationAction({ISD::STACKSAVE, ISD::STACKRESTORE}, MVT::Other, Expand);
83*bdd1243dSDimitry Andric   setOperationAction(ISD::VASTART, MVT::Other, Custom);
84*bdd1243dSDimitry Andric   setOperationAction({ISD::VAARG, ISD::VACOPY, ISD::VAEND}, MVT::Other, Expand);
8581ad6265SDimitry Andric 
8681ad6265SDimitry Andric   if (Subtarget.is64Bit()) {
8781ad6265SDimitry Andric     setOperationAction(ISD::SHL, MVT::i32, Custom);
8881ad6265SDimitry Andric     setOperationAction(ISD::SRA, MVT::i32, Custom);
8981ad6265SDimitry Andric     setOperationAction(ISD::SRL, MVT::i32, Custom);
90753f127fSDimitry Andric     setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
91753f127fSDimitry Andric     setOperationAction(ISD::BITCAST, MVT::i32, Custom);
92*bdd1243dSDimitry Andric     setOperationAction(ISD::ROTR, MVT::i32, Custom);
93*bdd1243dSDimitry Andric     setOperationAction(ISD::ROTL, MVT::i32, Custom);
94*bdd1243dSDimitry Andric     setOperationAction(ISD::CTTZ, MVT::i32, Custom);
95*bdd1243dSDimitry Andric     setOperationAction(ISD::CTLZ, MVT::i32, Custom);
96*bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom);
97*bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i32, Custom);
98*bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
99*bdd1243dSDimitry Andric     setOperationAction(ISD::READ_REGISTER, MVT::i32, Custom);
100*bdd1243dSDimitry Andric     setOperationAction(ISD::WRITE_REGISTER, MVT::i32, Custom);
101753f127fSDimitry Andric     if (Subtarget.hasBasicF() && !Subtarget.hasBasicD())
102753f127fSDimitry Andric       setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
103*bdd1243dSDimitry Andric     if (Subtarget.hasBasicF())
104*bdd1243dSDimitry Andric       setOperationAction(ISD::FRINT, MVT::f32, Legal);
105*bdd1243dSDimitry Andric     if (Subtarget.hasBasicD())
106*bdd1243dSDimitry Andric       setOperationAction(ISD::FRINT, MVT::f64, Legal);
10781ad6265SDimitry Andric   }
10881ad6265SDimitry Andric 
109*bdd1243dSDimitry Andric   // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
110*bdd1243dSDimitry Andric   // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
111*bdd1243dSDimitry Andric   // and i32 could still be byte-swapped relatively cheaply.
112*bdd1243dSDimitry Andric   setOperationAction(ISD::BSWAP, MVT::i16, Custom);
113*bdd1243dSDimitry Andric   if (Subtarget.is64Bit()) {
114*bdd1243dSDimitry Andric     setOperationAction(ISD::BSWAP, MVT::i32, Custom);
115*bdd1243dSDimitry Andric   }
116*bdd1243dSDimitry Andric 
117*bdd1243dSDimitry Andric   // Expand bitreverse.i16 with native-width bitrev and shift for now, before
118*bdd1243dSDimitry Andric   // we get to know which of sll and revb.2h is faster.
119*bdd1243dSDimitry Andric   setOperationAction(ISD::BITREVERSE, MVT::i8, Custom);
120*bdd1243dSDimitry Andric   if (Subtarget.is64Bit()) {
121*bdd1243dSDimitry Andric     setOperationAction(ISD::BITREVERSE, MVT::i32, Custom);
122*bdd1243dSDimitry Andric     setOperationAction(ISD::BITREVERSE, MVT::i64, Legal);
123*bdd1243dSDimitry Andric   } else {
124*bdd1243dSDimitry Andric     setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
125*bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom);
126*bdd1243dSDimitry Andric     setOperationAction(ISD::READ_REGISTER, MVT::i64, Custom);
127*bdd1243dSDimitry Andric     setOperationAction(ISD::WRITE_REGISTER, MVT::i64, Custom);
128*bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
129*bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_VOID, MVT::i64, Custom);
130*bdd1243dSDimitry Andric   }
131*bdd1243dSDimitry Andric 
132*bdd1243dSDimitry Andric   static const ISD::CondCode FPCCToExpand[] = {
133*bdd1243dSDimitry Andric       ISD::SETOGT, ISD::SETOGE, ISD::SETUGT, ISD::SETUGE,
134*bdd1243dSDimitry Andric       ISD::SETGE,  ISD::SETNE,  ISD::SETGT};
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric   if (Subtarget.hasBasicF()) {
13781ad6265SDimitry Andric     setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
13881ad6265SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
139*bdd1243dSDimitry Andric     setOperationAction(ISD::BR_CC, MVT::f32, Expand);
140*bdd1243dSDimitry Andric     setOperationAction(ISD::FMA, MVT::f32, Legal);
141*bdd1243dSDimitry Andric     setOperationAction(ISD::FMINNUM_IEEE, MVT::f32, Legal);
142*bdd1243dSDimitry Andric     setOperationAction(ISD::FMAXNUM_IEEE, MVT::f32, Legal);
143*bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCCS, MVT::f32, Legal);
144*bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCC, MVT::f32, Legal);
145*bdd1243dSDimitry Andric     setOperationAction(ISD::FSIN, MVT::f32, Expand);
146*bdd1243dSDimitry Andric     setOperationAction(ISD::FCOS, MVT::f32, Expand);
147*bdd1243dSDimitry Andric     setOperationAction(ISD::FSINCOS, MVT::f32, Expand);
148*bdd1243dSDimitry Andric     setOperationAction(ISD::FPOW, MVT::f32, Expand);
149*bdd1243dSDimitry Andric     setOperationAction(ISD::FREM, MVT::f32, Expand);
15081ad6265SDimitry Andric   }
15181ad6265SDimitry Andric   if (Subtarget.hasBasicD()) {
15281ad6265SDimitry Andric     setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
15381ad6265SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f64, Expand);
154*bdd1243dSDimitry Andric     setOperationAction(ISD::BR_CC, MVT::f64, Expand);
155*bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCCS, MVT::f64, Legal);
156*bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCC, MVT::f64, Legal);
157753f127fSDimitry Andric     setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
158*bdd1243dSDimitry Andric     setOperationAction(ISD::FMA, MVT::f64, Legal);
159*bdd1243dSDimitry Andric     setOperationAction(ISD::FMINNUM_IEEE, MVT::f64, Legal);
160*bdd1243dSDimitry Andric     setOperationAction(ISD::FMAXNUM_IEEE, MVT::f64, Legal);
161*bdd1243dSDimitry Andric     setOperationAction(ISD::FSIN, MVT::f64, Expand);
162*bdd1243dSDimitry Andric     setOperationAction(ISD::FCOS, MVT::f64, Expand);
163*bdd1243dSDimitry Andric     setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
164*bdd1243dSDimitry Andric     setOperationAction(ISD::FPOW, MVT::f64, Expand);
165*bdd1243dSDimitry Andric     setOperationAction(ISD::FREM, MVT::f64, Expand);
166*bdd1243dSDimitry Andric     setTruncStoreAction(MVT::f64, MVT::f32, Expand);
16781ad6265SDimitry Andric   }
16881ad6265SDimitry Andric 
169*bdd1243dSDimitry Andric   setOperationAction(ISD::BR_JT, MVT::Other, Expand);
170*bdd1243dSDimitry Andric 
171753f127fSDimitry Andric   setOperationAction(ISD::BR_CC, GRLenVT, Expand);
17281ad6265SDimitry Andric   setOperationAction(ISD::SELECT_CC, GRLenVT, Expand);
17381ad6265SDimitry Andric   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
174753f127fSDimitry Andric   setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, GRLenVT, Expand);
175753f127fSDimitry Andric   if (!Subtarget.is64Bit())
176753f127fSDimitry Andric     setLibcallName(RTLIB::MUL_I128, nullptr);
177753f127fSDimitry Andric 
178753f127fSDimitry Andric   setOperationAction(ISD::FP_TO_UINT, GRLenVT, Custom);
179*bdd1243dSDimitry Andric   setOperationAction(ISD::UINT_TO_FP, GRLenVT, Expand);
180*bdd1243dSDimitry Andric   if ((Subtarget.is64Bit() && Subtarget.hasBasicF() &&
181*bdd1243dSDimitry Andric        !Subtarget.hasBasicD())) {
182*bdd1243dSDimitry Andric     setOperationAction(ISD::SINT_TO_FP, GRLenVT, Custom);
183753f127fSDimitry Andric     setOperationAction(ISD::UINT_TO_FP, GRLenVT, Custom);
184*bdd1243dSDimitry Andric   }
18581ad6265SDimitry Andric 
18681ad6265SDimitry Andric   // Compute derived properties from the register classes.
18781ad6265SDimitry Andric   computeRegisterProperties(STI.getRegisterInfo());
18881ad6265SDimitry Andric 
18981ad6265SDimitry Andric   setStackPointerRegisterToSaveRestore(LoongArch::R3);
19081ad6265SDimitry Andric 
19181ad6265SDimitry Andric   setBooleanContents(ZeroOrOneBooleanContent);
19281ad6265SDimitry Andric 
193753f127fSDimitry Andric   setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen());
194753f127fSDimitry Andric 
195*bdd1243dSDimitry Andric   setMinCmpXchgSizeInBits(32);
196*bdd1243dSDimitry Andric 
19781ad6265SDimitry Andric   // Function alignments.
19881ad6265SDimitry Andric   const Align FunctionAlignment(4);
19981ad6265SDimitry Andric   setMinFunctionAlignment(FunctionAlignment);
20081ad6265SDimitry Andric 
20181ad6265SDimitry Andric   setTargetDAGCombine(ISD::AND);
202753f127fSDimitry Andric   setTargetDAGCombine(ISD::OR);
20381ad6265SDimitry Andric   setTargetDAGCombine(ISD::SRL);
20481ad6265SDimitry Andric }
20581ad6265SDimitry Andric 
206*bdd1243dSDimitry Andric bool LoongArchTargetLowering::isOffsetFoldingLegal(
207*bdd1243dSDimitry Andric     const GlobalAddressSDNode *GA) const {
208*bdd1243dSDimitry Andric   // In order to maximise the opportunity for common subexpression elimination,
209*bdd1243dSDimitry Andric   // keep a separate ADD node for the global address offset instead of folding
210*bdd1243dSDimitry Andric   // it in the global address node. Later peephole optimisations may choose to
211*bdd1243dSDimitry Andric   // fold it back in when profitable.
212*bdd1243dSDimitry Andric   return false;
213*bdd1243dSDimitry Andric }
214*bdd1243dSDimitry Andric 
21581ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
21681ad6265SDimitry Andric                                                 SelectionDAG &DAG) const {
21781ad6265SDimitry Andric   switch (Op.getOpcode()) {
218*bdd1243dSDimitry Andric   case ISD::EH_DWARF_CFA:
219*bdd1243dSDimitry Andric     return lowerEH_DWARF_CFA(Op, DAG);
220753f127fSDimitry Andric   case ISD::GlobalAddress:
221753f127fSDimitry Andric     return lowerGlobalAddress(Op, DAG);
222*bdd1243dSDimitry Andric   case ISD::GlobalTLSAddress:
223*bdd1243dSDimitry Andric     return lowerGlobalTLSAddress(Op, DAG);
224*bdd1243dSDimitry Andric   case ISD::INTRINSIC_WO_CHAIN:
225*bdd1243dSDimitry Andric     return lowerINTRINSIC_WO_CHAIN(Op, DAG);
226*bdd1243dSDimitry Andric   case ISD::INTRINSIC_W_CHAIN:
227*bdd1243dSDimitry Andric     return lowerINTRINSIC_W_CHAIN(Op, DAG);
228*bdd1243dSDimitry Andric   case ISD::INTRINSIC_VOID:
229*bdd1243dSDimitry Andric     return lowerINTRINSIC_VOID(Op, DAG);
230*bdd1243dSDimitry Andric   case ISD::BlockAddress:
231*bdd1243dSDimitry Andric     return lowerBlockAddress(Op, DAG);
232*bdd1243dSDimitry Andric   case ISD::JumpTable:
233*bdd1243dSDimitry Andric     return lowerJumpTable(Op, DAG);
23481ad6265SDimitry Andric   case ISD::SHL_PARTS:
23581ad6265SDimitry Andric     return lowerShiftLeftParts(Op, DAG);
23681ad6265SDimitry Andric   case ISD::SRA_PARTS:
23781ad6265SDimitry Andric     return lowerShiftRightParts(Op, DAG, true);
23881ad6265SDimitry Andric   case ISD::SRL_PARTS:
23981ad6265SDimitry Andric     return lowerShiftRightParts(Op, DAG, false);
240753f127fSDimitry Andric   case ISD::ConstantPool:
241753f127fSDimitry Andric     return lowerConstantPool(Op, DAG);
242753f127fSDimitry Andric   case ISD::FP_TO_SINT:
243753f127fSDimitry Andric     return lowerFP_TO_SINT(Op, DAG);
244753f127fSDimitry Andric   case ISD::BITCAST:
245753f127fSDimitry Andric     return lowerBITCAST(Op, DAG);
246753f127fSDimitry Andric   case ISD::UINT_TO_FP:
247753f127fSDimitry Andric     return lowerUINT_TO_FP(Op, DAG);
248*bdd1243dSDimitry Andric   case ISD::SINT_TO_FP:
249*bdd1243dSDimitry Andric     return lowerSINT_TO_FP(Op, DAG);
250*bdd1243dSDimitry Andric   case ISD::VASTART:
251*bdd1243dSDimitry Andric     return lowerVASTART(Op, DAG);
252*bdd1243dSDimitry Andric   case ISD::FRAMEADDR:
253*bdd1243dSDimitry Andric     return lowerFRAMEADDR(Op, DAG);
254*bdd1243dSDimitry Andric   case ISD::RETURNADDR:
255*bdd1243dSDimitry Andric     return lowerRETURNADDR(Op, DAG);
256*bdd1243dSDimitry Andric   case ISD::WRITE_REGISTER:
257*bdd1243dSDimitry Andric     return lowerWRITE_REGISTER(Op, DAG);
25881ad6265SDimitry Andric   }
259*bdd1243dSDimitry Andric   return SDValue();
260*bdd1243dSDimitry Andric }
261*bdd1243dSDimitry Andric 
262*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
263*bdd1243dSDimitry Andric                                                      SelectionDAG &DAG) const {
264*bdd1243dSDimitry Andric 
265*bdd1243dSDimitry Andric   if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
266*bdd1243dSDimitry Andric     DAG.getContext()->emitError(
267*bdd1243dSDimitry Andric         "On LA64, only 64-bit registers can be written.");
268*bdd1243dSDimitry Andric     return Op.getOperand(0);
269*bdd1243dSDimitry Andric   }
270*bdd1243dSDimitry Andric 
271*bdd1243dSDimitry Andric   if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
272*bdd1243dSDimitry Andric     DAG.getContext()->emitError(
273*bdd1243dSDimitry Andric         "On LA32, only 32-bit registers can be written.");
274*bdd1243dSDimitry Andric     return Op.getOperand(0);
275*bdd1243dSDimitry Andric   }
276*bdd1243dSDimitry Andric 
277*bdd1243dSDimitry Andric   return Op;
278*bdd1243dSDimitry Andric }
279*bdd1243dSDimitry Andric 
280*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
281*bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
282*bdd1243dSDimitry Andric   if (!isa<ConstantSDNode>(Op.getOperand(0))) {
283*bdd1243dSDimitry Andric     DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
284*bdd1243dSDimitry Andric                                 "be a constant integer");
285*bdd1243dSDimitry Andric     return SDValue();
286*bdd1243dSDimitry Andric   }
287*bdd1243dSDimitry Andric 
288*bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
289*bdd1243dSDimitry Andric   MF.getFrameInfo().setFrameAddressIsTaken(true);
290*bdd1243dSDimitry Andric   Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
291*bdd1243dSDimitry Andric   EVT VT = Op.getValueType();
292*bdd1243dSDimitry Andric   SDLoc DL(Op);
293*bdd1243dSDimitry Andric   SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
294*bdd1243dSDimitry Andric   unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
295*bdd1243dSDimitry Andric   int GRLenInBytes = Subtarget.getGRLen() / 8;
296*bdd1243dSDimitry Andric 
297*bdd1243dSDimitry Andric   while (Depth--) {
298*bdd1243dSDimitry Andric     int Offset = -(GRLenInBytes * 2);
299*bdd1243dSDimitry Andric     SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
300*bdd1243dSDimitry Andric                               DAG.getIntPtrConstant(Offset, DL));
301*bdd1243dSDimitry Andric     FrameAddr =
302*bdd1243dSDimitry Andric         DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
303*bdd1243dSDimitry Andric   }
304*bdd1243dSDimitry Andric   return FrameAddr;
305*bdd1243dSDimitry Andric }
306*bdd1243dSDimitry Andric 
307*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
308*bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
309*bdd1243dSDimitry Andric   if (verifyReturnAddressArgumentIsConstant(Op, DAG))
310*bdd1243dSDimitry Andric     return SDValue();
311*bdd1243dSDimitry Andric 
312*bdd1243dSDimitry Andric   // Currently only support lowering return address for current frame.
313*bdd1243dSDimitry Andric   if (cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() != 0) {
314*bdd1243dSDimitry Andric     DAG.getContext()->emitError(
315*bdd1243dSDimitry Andric         "return address can only be determined for the current frame");
316*bdd1243dSDimitry Andric     return SDValue();
317*bdd1243dSDimitry Andric   }
318*bdd1243dSDimitry Andric 
319*bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
320*bdd1243dSDimitry Andric   MF.getFrameInfo().setReturnAddressIsTaken(true);
321*bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
322*bdd1243dSDimitry Andric 
323*bdd1243dSDimitry Andric   // Return the value of the return address register, marking it an implicit
324*bdd1243dSDimitry Andric   // live-in.
325*bdd1243dSDimitry Andric   Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
326*bdd1243dSDimitry Andric                               getRegClassFor(GRLenVT));
327*bdd1243dSDimitry Andric   return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
328*bdd1243dSDimitry Andric }
329*bdd1243dSDimitry Andric 
330*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
331*bdd1243dSDimitry Andric                                                    SelectionDAG &DAG) const {
332*bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
333*bdd1243dSDimitry Andric   auto Size = Subtarget.getGRLen() / 8;
334*bdd1243dSDimitry Andric   auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
335*bdd1243dSDimitry Andric   return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
336*bdd1243dSDimitry Andric }
337*bdd1243dSDimitry Andric 
338*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
339*bdd1243dSDimitry Andric                                               SelectionDAG &DAG) const {
340*bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
341*bdd1243dSDimitry Andric   auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
342*bdd1243dSDimitry Andric 
343*bdd1243dSDimitry Andric   SDLoc DL(Op);
344*bdd1243dSDimitry Andric   SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
345*bdd1243dSDimitry Andric                                  getPointerTy(MF.getDataLayout()));
346*bdd1243dSDimitry Andric 
347*bdd1243dSDimitry Andric   // vastart just stores the address of the VarArgsFrameIndex slot into the
348*bdd1243dSDimitry Andric   // memory location argument.
349*bdd1243dSDimitry Andric   const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
350*bdd1243dSDimitry Andric   return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
351*bdd1243dSDimitry Andric                       MachinePointerInfo(SV));
35281ad6265SDimitry Andric }
35381ad6265SDimitry Andric 
354753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
355753f127fSDimitry Andric                                                  SelectionDAG &DAG) const {
356*bdd1243dSDimitry Andric   assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
357*bdd1243dSDimitry Andric          !Subtarget.hasBasicD() && "unexpected target features");
358753f127fSDimitry Andric 
359753f127fSDimitry Andric   SDLoc DL(Op);
360*bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
361*bdd1243dSDimitry Andric   if (Op0->getOpcode() == ISD::AND) {
362*bdd1243dSDimitry Andric     auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
363*bdd1243dSDimitry Andric     if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
364753f127fSDimitry Andric       return Op;
365*bdd1243dSDimitry Andric   }
366*bdd1243dSDimitry Andric 
367*bdd1243dSDimitry Andric   if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
368*bdd1243dSDimitry Andric       Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
369*bdd1243dSDimitry Andric       Op0.getConstantOperandVal(2) == UINT64_C(0))
370*bdd1243dSDimitry Andric     return Op;
371*bdd1243dSDimitry Andric 
372*bdd1243dSDimitry Andric   if (Op0.getOpcode() == ISD::AssertZext &&
373*bdd1243dSDimitry Andric       dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
374*bdd1243dSDimitry Andric     return Op;
375*bdd1243dSDimitry Andric 
376*bdd1243dSDimitry Andric   EVT OpVT = Op0.getValueType();
377*bdd1243dSDimitry Andric   EVT RetVT = Op.getValueType();
378*bdd1243dSDimitry Andric   RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
379*bdd1243dSDimitry Andric   MakeLibCallOptions CallOptions;
380*bdd1243dSDimitry Andric   CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
381*bdd1243dSDimitry Andric   SDValue Chain = SDValue();
382*bdd1243dSDimitry Andric   SDValue Result;
383*bdd1243dSDimitry Andric   std::tie(Result, Chain) =
384*bdd1243dSDimitry Andric       makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
385*bdd1243dSDimitry Andric   return Result;
386*bdd1243dSDimitry Andric }
387*bdd1243dSDimitry Andric 
388*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
389*bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
390*bdd1243dSDimitry Andric   assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
391*bdd1243dSDimitry Andric          !Subtarget.hasBasicD() && "unexpected target features");
392*bdd1243dSDimitry Andric 
393*bdd1243dSDimitry Andric   SDLoc DL(Op);
394*bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
395*bdd1243dSDimitry Andric 
396*bdd1243dSDimitry Andric   if ((Op0.getOpcode() == ISD::AssertSext ||
397*bdd1243dSDimitry Andric        Op0.getOpcode() == ISD::SIGN_EXTEND_INREG) &&
398*bdd1243dSDimitry Andric       dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
399*bdd1243dSDimitry Andric     return Op;
400*bdd1243dSDimitry Andric 
401*bdd1243dSDimitry Andric   EVT OpVT = Op0.getValueType();
402*bdd1243dSDimitry Andric   EVT RetVT = Op.getValueType();
403*bdd1243dSDimitry Andric   RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
404*bdd1243dSDimitry Andric   MakeLibCallOptions CallOptions;
405*bdd1243dSDimitry Andric   CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
406*bdd1243dSDimitry Andric   SDValue Chain = SDValue();
407*bdd1243dSDimitry Andric   SDValue Result;
408*bdd1243dSDimitry Andric   std::tie(Result, Chain) =
409*bdd1243dSDimitry Andric       makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
410*bdd1243dSDimitry Andric   return Result;
411753f127fSDimitry Andric }
412753f127fSDimitry Andric 
413753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
414753f127fSDimitry Andric                                               SelectionDAG &DAG) const {
415753f127fSDimitry Andric 
416753f127fSDimitry Andric   SDLoc DL(Op);
417753f127fSDimitry Andric   SDValue Op0 = Op.getOperand(0);
418753f127fSDimitry Andric 
419753f127fSDimitry Andric   if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 &&
420753f127fSDimitry Andric       Subtarget.is64Bit() && Subtarget.hasBasicF()) {
421753f127fSDimitry Andric     SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
422753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
423753f127fSDimitry Andric   }
424753f127fSDimitry Andric   return Op;
425753f127fSDimitry Andric }
426753f127fSDimitry Andric 
427753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
428753f127fSDimitry Andric                                                  SelectionDAG &DAG) const {
429753f127fSDimitry Andric 
430753f127fSDimitry Andric   SDLoc DL(Op);
431753f127fSDimitry Andric 
432753f127fSDimitry Andric   if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
433753f127fSDimitry Andric       !Subtarget.hasBasicD()) {
434753f127fSDimitry Andric     SDValue Dst =
435753f127fSDimitry Andric         DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0));
436753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
437753f127fSDimitry Andric   }
438753f127fSDimitry Andric 
439753f127fSDimitry Andric   EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
440753f127fSDimitry Andric   SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0));
441753f127fSDimitry Andric   return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
442753f127fSDimitry Andric }
443753f127fSDimitry Andric 
444*bdd1243dSDimitry Andric static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty,
445*bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
446*bdd1243dSDimitry Andric   return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
447*bdd1243dSDimitry Andric }
448*bdd1243dSDimitry Andric 
449*bdd1243dSDimitry Andric static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty,
450*bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
451*bdd1243dSDimitry Andric   return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
452*bdd1243dSDimitry Andric                                    Flags);
453*bdd1243dSDimitry Andric }
454*bdd1243dSDimitry Andric 
455*bdd1243dSDimitry Andric static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty,
456*bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
457*bdd1243dSDimitry Andric   return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
458*bdd1243dSDimitry Andric                                    N->getOffset(), Flags);
459*bdd1243dSDimitry Andric }
460*bdd1243dSDimitry Andric 
461*bdd1243dSDimitry Andric static SDValue getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty,
462*bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
463*bdd1243dSDimitry Andric   return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
464*bdd1243dSDimitry Andric }
465*bdd1243dSDimitry Andric 
466*bdd1243dSDimitry Andric template <class NodeTy>
467*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
468*bdd1243dSDimitry Andric                                          bool IsLocal) const {
469*bdd1243dSDimitry Andric   SDLoc DL(N);
470*bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
471*bdd1243dSDimitry Andric   SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
472*bdd1243dSDimitry Andric   // TODO: Check CodeModel.
473*bdd1243dSDimitry Andric   if (IsLocal)
474*bdd1243dSDimitry Andric     // This generates the pattern (PseudoLA_PCREL sym), which expands to
475*bdd1243dSDimitry Andric     // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
476*bdd1243dSDimitry Andric     return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr),
477*bdd1243dSDimitry Andric                    0);
478*bdd1243dSDimitry Andric 
479*bdd1243dSDimitry Andric   // This generates the pattern (PseudoLA_GOT sym), which expands to (ld.w/d
480*bdd1243dSDimitry Andric   // (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
481*bdd1243dSDimitry Andric   return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0);
482*bdd1243dSDimitry Andric }
483*bdd1243dSDimitry Andric 
484*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
485*bdd1243dSDimitry Andric                                                    SelectionDAG &DAG) const {
486*bdd1243dSDimitry Andric   return getAddr(cast<BlockAddressSDNode>(Op), DAG);
487*bdd1243dSDimitry Andric }
488*bdd1243dSDimitry Andric 
489*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
490*bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
491*bdd1243dSDimitry Andric   return getAddr(cast<JumpTableSDNode>(Op), DAG);
492*bdd1243dSDimitry Andric }
493*bdd1243dSDimitry Andric 
494753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
495753f127fSDimitry Andric                                                    SelectionDAG &DAG) const {
496*bdd1243dSDimitry Andric   return getAddr(cast<ConstantPoolSDNode>(Op), DAG);
497753f127fSDimitry Andric }
498753f127fSDimitry Andric 
499753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
500753f127fSDimitry Andric                                                     SelectionDAG &DAG) const {
501*bdd1243dSDimitry Andric   GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
502*bdd1243dSDimitry Andric   assert(N->getOffset() == 0 && "unexpected offset in global node");
503*bdd1243dSDimitry Andric   return getAddr(N, DAG, N->getGlobal()->isDSOLocal());
504*bdd1243dSDimitry Andric }
505753f127fSDimitry Andric 
506*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
507*bdd1243dSDimitry Andric                                                   SelectionDAG &DAG,
508*bdd1243dSDimitry Andric                                                   unsigned Opc) const {
509*bdd1243dSDimitry Andric   SDLoc DL(N);
510*bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
511*bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
512*bdd1243dSDimitry Andric 
513*bdd1243dSDimitry Andric   SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
514*bdd1243dSDimitry Andric   SDValue Offset = SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
515*bdd1243dSDimitry Andric 
516*bdd1243dSDimitry Andric   // Add the thread pointer.
517*bdd1243dSDimitry Andric   return DAG.getNode(ISD::ADD, DL, Ty, Offset,
518*bdd1243dSDimitry Andric                      DAG.getRegister(LoongArch::R2, GRLenVT));
519*bdd1243dSDimitry Andric }
520*bdd1243dSDimitry Andric 
521*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
522*bdd1243dSDimitry Andric                                                    SelectionDAG &DAG,
523*bdd1243dSDimitry Andric                                                    unsigned Opc) const {
524*bdd1243dSDimitry Andric   SDLoc DL(N);
525*bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
526*bdd1243dSDimitry Andric   IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
527*bdd1243dSDimitry Andric 
528*bdd1243dSDimitry Andric   // Use a PC-relative addressing mode to access the dynamic GOT address.
529*bdd1243dSDimitry Andric   SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
530*bdd1243dSDimitry Andric   SDValue Load = SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
531*bdd1243dSDimitry Andric 
532*bdd1243dSDimitry Andric   // Prepare argument list to generate call.
533*bdd1243dSDimitry Andric   ArgListTy Args;
534*bdd1243dSDimitry Andric   ArgListEntry Entry;
535*bdd1243dSDimitry Andric   Entry.Node = Load;
536*bdd1243dSDimitry Andric   Entry.Ty = CallTy;
537*bdd1243dSDimitry Andric   Args.push_back(Entry);
538*bdd1243dSDimitry Andric 
539*bdd1243dSDimitry Andric   // Setup call to __tls_get_addr.
540*bdd1243dSDimitry Andric   TargetLowering::CallLoweringInfo CLI(DAG);
541*bdd1243dSDimitry Andric   CLI.setDebugLoc(DL)
542*bdd1243dSDimitry Andric       .setChain(DAG.getEntryNode())
543*bdd1243dSDimitry Andric       .setLibCallee(CallingConv::C, CallTy,
544*bdd1243dSDimitry Andric                     DAG.getExternalSymbol("__tls_get_addr", Ty),
545*bdd1243dSDimitry Andric                     std::move(Args));
546*bdd1243dSDimitry Andric 
547*bdd1243dSDimitry Andric   return LowerCallTo(CLI).first;
548*bdd1243dSDimitry Andric }
549*bdd1243dSDimitry Andric 
550*bdd1243dSDimitry Andric SDValue
551*bdd1243dSDimitry Andric LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
552*bdd1243dSDimitry Andric                                                SelectionDAG &DAG) const {
553*bdd1243dSDimitry Andric   if (DAG.getMachineFunction().getFunction().getCallingConv() ==
554*bdd1243dSDimitry Andric       CallingConv::GHC)
555*bdd1243dSDimitry Andric     report_fatal_error("In GHC calling convention TLS is not supported");
556*bdd1243dSDimitry Andric 
557*bdd1243dSDimitry Andric   GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
558*bdd1243dSDimitry Andric   assert(N->getOffset() == 0 && "unexpected offset in global node");
559*bdd1243dSDimitry Andric 
560*bdd1243dSDimitry Andric   SDValue Addr;
561*bdd1243dSDimitry Andric   switch (getTargetMachine().getTLSModel(N->getGlobal())) {
562*bdd1243dSDimitry Andric   case TLSModel::GeneralDynamic:
563*bdd1243dSDimitry Andric     // In this model, application code calls the dynamic linker function
564*bdd1243dSDimitry Andric     // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
565*bdd1243dSDimitry Andric     // runtime.
566*bdd1243dSDimitry Andric     Addr = getDynamicTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_GD);
567*bdd1243dSDimitry Andric     break;
568*bdd1243dSDimitry Andric   case TLSModel::LocalDynamic:
569*bdd1243dSDimitry Andric     // Same as GeneralDynamic, except for assembly modifiers and relocation
570*bdd1243dSDimitry Andric     // records.
571*bdd1243dSDimitry Andric     Addr = getDynamicTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LD);
572*bdd1243dSDimitry Andric     break;
573*bdd1243dSDimitry Andric   case TLSModel::InitialExec:
574*bdd1243dSDimitry Andric     // This model uses the GOT to resolve TLS offsets.
575*bdd1243dSDimitry Andric     Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_IE);
576*bdd1243dSDimitry Andric     break;
577*bdd1243dSDimitry Andric   case TLSModel::LocalExec:
578*bdd1243dSDimitry Andric     // This model is used when static linking as the TLS offsets are resolved
579*bdd1243dSDimitry Andric     // during program linking.
580*bdd1243dSDimitry Andric     Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE);
581*bdd1243dSDimitry Andric     break;
582*bdd1243dSDimitry Andric   }
583*bdd1243dSDimitry Andric 
584753f127fSDimitry Andric   return Addr;
585753f127fSDimitry Andric }
586*bdd1243dSDimitry Andric 
587*bdd1243dSDimitry Andric SDValue
588*bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
589*bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
590*bdd1243dSDimitry Andric   switch (Op.getConstantOperandVal(0)) {
591*bdd1243dSDimitry Andric   default:
592*bdd1243dSDimitry Andric     return SDValue(); // Don't custom lower most intrinsics.
593*bdd1243dSDimitry Andric   case Intrinsic::thread_pointer: {
594*bdd1243dSDimitry Andric     EVT PtrVT = getPointerTy(DAG.getDataLayout());
595*bdd1243dSDimitry Andric     return DAG.getRegister(LoongArch::R2, PtrVT);
596*bdd1243dSDimitry Andric   }
597*bdd1243dSDimitry Andric   }
598*bdd1243dSDimitry Andric }
599*bdd1243dSDimitry Andric 
600*bdd1243dSDimitry Andric // Helper function that emits error message for intrinsics with chain.
601*bdd1243dSDimitry Andric static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op,
602*bdd1243dSDimitry Andric                                                   StringRef ErrorMsg,
603*bdd1243dSDimitry Andric                                                   SelectionDAG &DAG) {
604*bdd1243dSDimitry Andric 
605*bdd1243dSDimitry Andric   DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + "' " +
606*bdd1243dSDimitry Andric                               ErrorMsg);
607*bdd1243dSDimitry Andric   return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
608*bdd1243dSDimitry Andric                             SDLoc(Op));
609*bdd1243dSDimitry Andric }
610*bdd1243dSDimitry Andric 
611*bdd1243dSDimitry Andric SDValue
612*bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
613*bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
614*bdd1243dSDimitry Andric   SDLoc DL(Op);
615*bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
616*bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
617*bdd1243dSDimitry Andric   std::string Name = Op->getOperationName(0);
618*bdd1243dSDimitry Andric   const StringRef ErrorMsgOOR = "out of range";
619*bdd1243dSDimitry Andric 
620*bdd1243dSDimitry Andric   switch (Op.getConstantOperandVal(1)) {
621*bdd1243dSDimitry Andric   default:
622*bdd1243dSDimitry Andric     return Op;
623*bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_b_w:
624*bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_h_w:
625*bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_w_w:
626*bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_d_w:
627*bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_b_w:
628*bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_h_w:
629*bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_w_w:
630*bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_d_w: {
631*bdd1243dSDimitry Andric     std::string Name = Op->getOperationName(0);
632*bdd1243dSDimitry Andric     DAG.getContext()->emitError(Name + " requires target: loongarch64");
633*bdd1243dSDimitry Andric     return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL);
634*bdd1243dSDimitry Andric   }
635*bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrrd_w:
636*bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrrd_d: {
637*bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
638*bdd1243dSDimitry Andric     if (!isUInt<14>(Imm))
639*bdd1243dSDimitry Andric       return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
640*bdd1243dSDimitry Andric     return DAG.getMergeValues(
641*bdd1243dSDimitry Andric         {DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0,
642*bdd1243dSDimitry Andric                      DAG.getConstant(Imm, DL, GRLenVT)),
643*bdd1243dSDimitry Andric          Op0},
644*bdd1243dSDimitry Andric         DL);
645*bdd1243dSDimitry Andric   }
646*bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrwr_w:
647*bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrwr_d: {
648*bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
649*bdd1243dSDimitry Andric     if (!isUInt<14>(Imm))
650*bdd1243dSDimitry Andric       return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
651*bdd1243dSDimitry Andric     return DAG.getMergeValues(
652*bdd1243dSDimitry Andric         {DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0, Op.getOperand(2),
653*bdd1243dSDimitry Andric                      DAG.getConstant(Imm, DL, GRLenVT)),
654*bdd1243dSDimitry Andric          Op0},
655*bdd1243dSDimitry Andric         DL);
656*bdd1243dSDimitry Andric   }
657*bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrxchg_w:
658*bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrxchg_d: {
659*bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(4))->getZExtValue();
660*bdd1243dSDimitry Andric     if (!isUInt<14>(Imm))
661*bdd1243dSDimitry Andric       return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
662*bdd1243dSDimitry Andric     return DAG.getMergeValues(
663*bdd1243dSDimitry Andric         {DAG.getNode(LoongArchISD::CSRXCHG, DL, GRLenVT, Op0, Op.getOperand(2),
664*bdd1243dSDimitry Andric                      Op.getOperand(3), DAG.getConstant(Imm, DL, GRLenVT)),
665*bdd1243dSDimitry Andric          Op0},
666*bdd1243dSDimitry Andric         DL);
667*bdd1243dSDimitry Andric   }
668*bdd1243dSDimitry Andric   case Intrinsic::loongarch_iocsrrd_d: {
669*bdd1243dSDimitry Andric     if (Subtarget.is64Bit())
670*bdd1243dSDimitry Andric       return DAG.getMergeValues(
671*bdd1243dSDimitry Andric           {DAG.getNode(
672*bdd1243dSDimitry Andric                LoongArchISD::IOCSRRD_D, DL, GRLenVT, Op0,
673*bdd1243dSDimitry Andric                DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))),
674*bdd1243dSDimitry Andric            Op0},
675*bdd1243dSDimitry Andric           DL);
676*bdd1243dSDimitry Andric     else {
677*bdd1243dSDimitry Andric       DAG.getContext()->emitError(
678*bdd1243dSDimitry Andric           "llvm.loongarch.crc.w.d.w requires target: loongarch64");
679*bdd1243dSDimitry Andric       return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL);
680*bdd1243dSDimitry Andric     }
681*bdd1243dSDimitry Andric   }
682*bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE)                                               \
683*bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
684*bdd1243dSDimitry Andric     return DAG.getMergeValues(                                                 \
685*bdd1243dSDimitry Andric         {DAG.getNode(LoongArchISD::NODE, DL, GRLenVT, Op0, Op.getOperand(2)),  \
686*bdd1243dSDimitry Andric          Op0},                                                                 \
687*bdd1243dSDimitry Andric         DL);                                                                   \
688*bdd1243dSDimitry Andric   }
689*bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
690*bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
691*bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
692*bdd1243dSDimitry Andric #undef IOCSRRD_CASE
693*bdd1243dSDimitry Andric   case Intrinsic::loongarch_cpucfg: {
694*bdd1243dSDimitry Andric     return DAG.getMergeValues(
695*bdd1243dSDimitry Andric         {DAG.getNode(LoongArchISD::CPUCFG, DL, GRLenVT, Op0, Op.getOperand(2)),
696*bdd1243dSDimitry Andric          Op0},
697*bdd1243dSDimitry Andric         DL);
698*bdd1243dSDimitry Andric   }
699*bdd1243dSDimitry Andric   case Intrinsic::loongarch_lddir_d: {
700*bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
701*bdd1243dSDimitry Andric     if (!isUInt<8>(Imm)) {
702*bdd1243dSDimitry Andric       DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) +
703*bdd1243dSDimitry Andric                                   "' out of range");
704*bdd1243dSDimitry Andric       return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL);
705*bdd1243dSDimitry Andric     }
706*bdd1243dSDimitry Andric 
707*bdd1243dSDimitry Andric     return Op;
708*bdd1243dSDimitry Andric   }
709*bdd1243dSDimitry Andric   case Intrinsic::loongarch_movfcsr2gr: {
710*bdd1243dSDimitry Andric     if (!Subtarget.hasBasicF()) {
711*bdd1243dSDimitry Andric       DAG.getContext()->emitError(
712*bdd1243dSDimitry Andric           "llvm.loongarch.movfcsr2gr expects basic f target feature");
713*bdd1243dSDimitry Andric       return DAG.getMergeValues(
714*bdd1243dSDimitry Andric           {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
715*bdd1243dSDimitry Andric     }
716*bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
717*bdd1243dSDimitry Andric     if (!isUInt<2>(Imm)) {
718*bdd1243dSDimitry Andric       DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) +
719*bdd1243dSDimitry Andric                                   "' " + ErrorMsgOOR);
720*bdd1243dSDimitry Andric       return DAG.getMergeValues(
721*bdd1243dSDimitry Andric           {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
722*bdd1243dSDimitry Andric     }
723*bdd1243dSDimitry Andric     return DAG.getMergeValues(
724*bdd1243dSDimitry Andric         {DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, Op.getValueType(),
725*bdd1243dSDimitry Andric                      DAG.getConstant(Imm, DL, GRLenVT)),
726*bdd1243dSDimitry Andric          Op.getOperand(0)},
727*bdd1243dSDimitry Andric         DL);
728*bdd1243dSDimitry Andric   }
729*bdd1243dSDimitry Andric   }
730*bdd1243dSDimitry Andric }
731*bdd1243dSDimitry Andric 
732*bdd1243dSDimitry Andric // Helper function that emits error message for intrinsics with void return
733*bdd1243dSDimitry Andric // value.
734*bdd1243dSDimitry Andric static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg,
735*bdd1243dSDimitry Andric                                          SelectionDAG &DAG) {
736*bdd1243dSDimitry Andric 
737*bdd1243dSDimitry Andric   DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + "' " +
738*bdd1243dSDimitry Andric                               ErrorMsg);
739*bdd1243dSDimitry Andric   return Op.getOperand(0);
740*bdd1243dSDimitry Andric }
741*bdd1243dSDimitry Andric 
742*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
743*bdd1243dSDimitry Andric                                                      SelectionDAG &DAG) const {
744*bdd1243dSDimitry Andric   SDLoc DL(Op);
745*bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
746*bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
747*bdd1243dSDimitry Andric   uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
748*bdd1243dSDimitry Andric   SDValue Op2 = Op.getOperand(2);
749*bdd1243dSDimitry Andric   const StringRef ErrorMsgOOR = "out of range";
750*bdd1243dSDimitry Andric 
751*bdd1243dSDimitry Andric   switch (IntrinsicEnum) {
752*bdd1243dSDimitry Andric   default:
753*bdd1243dSDimitry Andric     // TODO: Add more Intrinsics.
754*bdd1243dSDimitry Andric     return SDValue();
755*bdd1243dSDimitry Andric   case Intrinsic::loongarch_cacop_d:
756*bdd1243dSDimitry Andric   case Intrinsic::loongarch_cacop_w: {
757*bdd1243dSDimitry Andric     if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit()) {
758*bdd1243dSDimitry Andric       DAG.getContext()->emitError(
759*bdd1243dSDimitry Andric           "llvm.loongarch.cacop.d requires target: loongarch64");
760*bdd1243dSDimitry Andric       return Op.getOperand(0);
761*bdd1243dSDimitry Andric     }
762*bdd1243dSDimitry Andric     if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit()) {
763*bdd1243dSDimitry Andric       DAG.getContext()->emitError(
764*bdd1243dSDimitry Andric           "llvm.loongarch.cacop.w requires target: loongarch32");
765*bdd1243dSDimitry Andric       return Op.getOperand(0);
766*bdd1243dSDimitry Andric     }
767*bdd1243dSDimitry Andric     // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
768*bdd1243dSDimitry Andric     unsigned Imm1 = cast<ConstantSDNode>(Op2)->getZExtValue();
769*bdd1243dSDimitry Andric     if (!isUInt<5>(Imm1))
770*bdd1243dSDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
771*bdd1243dSDimitry Andric     SDValue Op4 = Op.getOperand(4);
772*bdd1243dSDimitry Andric     int Imm2 = cast<ConstantSDNode>(Op4)->getSExtValue();
773*bdd1243dSDimitry Andric     if (!isInt<12>(Imm2))
774*bdd1243dSDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
775*bdd1243dSDimitry Andric 
776*bdd1243dSDimitry Andric     return Op;
777*bdd1243dSDimitry Andric   }
778*bdd1243dSDimitry Andric 
779*bdd1243dSDimitry Andric   case Intrinsic::loongarch_dbar: {
780*bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
781*bdd1243dSDimitry Andric     if (!isUInt<15>(Imm))
782*bdd1243dSDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
783*bdd1243dSDimitry Andric 
784*bdd1243dSDimitry Andric     return DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Op0,
785*bdd1243dSDimitry Andric                        DAG.getConstant(Imm, DL, GRLenVT));
786*bdd1243dSDimitry Andric   }
787*bdd1243dSDimitry Andric   case Intrinsic::loongarch_ibar: {
788*bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
789*bdd1243dSDimitry Andric     if (!isUInt<15>(Imm))
790*bdd1243dSDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
791*bdd1243dSDimitry Andric 
792*bdd1243dSDimitry Andric     return DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Op0,
793*bdd1243dSDimitry Andric                        DAG.getConstant(Imm, DL, GRLenVT));
794*bdd1243dSDimitry Andric   }
795*bdd1243dSDimitry Andric   case Intrinsic::loongarch_break: {
796*bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
797*bdd1243dSDimitry Andric     if (!isUInt<15>(Imm))
798*bdd1243dSDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
799*bdd1243dSDimitry Andric 
800*bdd1243dSDimitry Andric     return DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Op0,
801*bdd1243dSDimitry Andric                        DAG.getConstant(Imm, DL, GRLenVT));
802*bdd1243dSDimitry Andric   }
803*bdd1243dSDimitry Andric   case Intrinsic::loongarch_movgr2fcsr: {
804*bdd1243dSDimitry Andric     if (!Subtarget.hasBasicF()) {
805*bdd1243dSDimitry Andric       DAG.getContext()->emitError(
806*bdd1243dSDimitry Andric           "llvm.loongarch.movgr2fcsr expects basic f target feature");
807*bdd1243dSDimitry Andric       return Op0;
808*bdd1243dSDimitry Andric     }
809*bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
810*bdd1243dSDimitry Andric     if (!isUInt<2>(Imm))
811*bdd1243dSDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
812*bdd1243dSDimitry Andric 
813*bdd1243dSDimitry Andric     return DAG.getNode(
814*bdd1243dSDimitry Andric         LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Op0,
815*bdd1243dSDimitry Andric         DAG.getConstant(Imm, DL, GRLenVT),
816*bdd1243dSDimitry Andric         DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Op.getOperand(3)));
817*bdd1243dSDimitry Andric   }
818*bdd1243dSDimitry Andric   case Intrinsic::loongarch_syscall: {
819*bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
820*bdd1243dSDimitry Andric     if (!isUInt<15>(Imm))
821*bdd1243dSDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
822*bdd1243dSDimitry Andric 
823*bdd1243dSDimitry Andric     return DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Op0,
824*bdd1243dSDimitry Andric                        DAG.getConstant(Imm, DL, GRLenVT));
825*bdd1243dSDimitry Andric   }
826*bdd1243dSDimitry Andric #define IOCSRWR_CASE(NAME, NODE)                                               \
827*bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
828*bdd1243dSDimitry Andric     SDValue Op3 = Op.getOperand(3);                                            \
829*bdd1243dSDimitry Andric     if (Subtarget.is64Bit())                                                   \
830*bdd1243dSDimitry Andric       return DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Op0,              \
831*bdd1243dSDimitry Andric                          DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),      \
832*bdd1243dSDimitry Andric                          DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3));     \
833*bdd1243dSDimitry Andric     else                                                                       \
834*bdd1243dSDimitry Andric       return DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Op0, Op2, Op3);   \
835*bdd1243dSDimitry Andric   }
836*bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
837*bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
838*bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
839*bdd1243dSDimitry Andric #undef IOCSRWR_CASE
840*bdd1243dSDimitry Andric   case Intrinsic::loongarch_iocsrwr_d: {
841*bdd1243dSDimitry Andric     if (Subtarget.is64Bit())
842*bdd1243dSDimitry Andric       return DAG.getNode(
843*bdd1243dSDimitry Andric           LoongArchISD::IOCSRWR_D, DL, MVT::Other, Op0, Op2,
844*bdd1243dSDimitry Andric           DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(3)));
845*bdd1243dSDimitry Andric     else {
846*bdd1243dSDimitry Andric       DAG.getContext()->emitError(
847*bdd1243dSDimitry Andric           "llvm.loongarch.iocsrwr.d requires target: loongarch64");
848*bdd1243dSDimitry Andric       return Op.getOperand(0);
849*bdd1243dSDimitry Andric     }
850*bdd1243dSDimitry Andric   }
851*bdd1243dSDimitry Andric #define ASRT_LE_GT_CASE(NAME)                                                  \
852*bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
853*bdd1243dSDimitry Andric     if (!Subtarget.is64Bit()) {                                                \
854*bdd1243dSDimitry Andric       DAG.getContext()->emitError(Op->getOperationName(0) +                    \
855*bdd1243dSDimitry Andric                                   " requires target: loongarch64");            \
856*bdd1243dSDimitry Andric       return Op.getOperand(0);                                                 \
857*bdd1243dSDimitry Andric     }                                                                          \
858*bdd1243dSDimitry Andric     return Op;                                                                 \
859*bdd1243dSDimitry Andric   }
860*bdd1243dSDimitry Andric     ASRT_LE_GT_CASE(asrtle_d)
861*bdd1243dSDimitry Andric     ASRT_LE_GT_CASE(asrtgt_d)
862*bdd1243dSDimitry Andric #undef ASRT_LE_GT_CASE
863*bdd1243dSDimitry Andric   case Intrinsic::loongarch_ldpte_d: {
864*bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
865*bdd1243dSDimitry Andric     if (!isUInt<8>(Imm))
866*bdd1243dSDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
867*bdd1243dSDimitry Andric     if (!Subtarget.is64Bit()) {
868*bdd1243dSDimitry Andric       DAG.getContext()->emitError(Op->getOperationName(0) +
869*bdd1243dSDimitry Andric                                   " requires target: loongarch64");
870*bdd1243dSDimitry Andric       return Op.getOperand(0);
871*bdd1243dSDimitry Andric     }
872*bdd1243dSDimitry Andric     return Op;
873*bdd1243dSDimitry Andric   }
874*bdd1243dSDimitry Andric   }
875753f127fSDimitry Andric }
876753f127fSDimitry Andric 
87781ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
87881ad6265SDimitry Andric                                                      SelectionDAG &DAG) const {
87981ad6265SDimitry Andric   SDLoc DL(Op);
88081ad6265SDimitry Andric   SDValue Lo = Op.getOperand(0);
88181ad6265SDimitry Andric   SDValue Hi = Op.getOperand(1);
88281ad6265SDimitry Andric   SDValue Shamt = Op.getOperand(2);
88381ad6265SDimitry Andric   EVT VT = Lo.getValueType();
88481ad6265SDimitry Andric 
88581ad6265SDimitry Andric   // if Shamt-GRLen < 0: // Shamt < GRLen
88681ad6265SDimitry Andric   //   Lo = Lo << Shamt
88781ad6265SDimitry Andric   //   Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
88881ad6265SDimitry Andric   // else:
88981ad6265SDimitry Andric   //   Lo = 0
89081ad6265SDimitry Andric   //   Hi = Lo << (Shamt-GRLen)
89181ad6265SDimitry Andric 
89281ad6265SDimitry Andric   SDValue Zero = DAG.getConstant(0, DL, VT);
89381ad6265SDimitry Andric   SDValue One = DAG.getConstant(1, DL, VT);
89481ad6265SDimitry Andric   SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
89581ad6265SDimitry Andric   SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
89681ad6265SDimitry Andric   SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
89781ad6265SDimitry Andric   SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
89881ad6265SDimitry Andric 
89981ad6265SDimitry Andric   SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
90081ad6265SDimitry Andric   SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
90181ad6265SDimitry Andric   SDValue ShiftRightLo =
90281ad6265SDimitry Andric       DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
90381ad6265SDimitry Andric   SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
90481ad6265SDimitry Andric   SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
90581ad6265SDimitry Andric   SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
90681ad6265SDimitry Andric 
90781ad6265SDimitry Andric   SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
90881ad6265SDimitry Andric 
90981ad6265SDimitry Andric   Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
91081ad6265SDimitry Andric   Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
91181ad6265SDimitry Andric 
91281ad6265SDimitry Andric   SDValue Parts[2] = {Lo, Hi};
91381ad6265SDimitry Andric   return DAG.getMergeValues(Parts, DL);
91481ad6265SDimitry Andric }
91581ad6265SDimitry Andric 
91681ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
91781ad6265SDimitry Andric                                                       SelectionDAG &DAG,
91881ad6265SDimitry Andric                                                       bool IsSRA) const {
91981ad6265SDimitry Andric   SDLoc DL(Op);
92081ad6265SDimitry Andric   SDValue Lo = Op.getOperand(0);
92181ad6265SDimitry Andric   SDValue Hi = Op.getOperand(1);
92281ad6265SDimitry Andric   SDValue Shamt = Op.getOperand(2);
92381ad6265SDimitry Andric   EVT VT = Lo.getValueType();
92481ad6265SDimitry Andric 
92581ad6265SDimitry Andric   // SRA expansion:
92681ad6265SDimitry Andric   //   if Shamt-GRLen < 0: // Shamt < GRLen
92781ad6265SDimitry Andric   //     Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
92881ad6265SDimitry Andric   //     Hi = Hi >>s Shamt
92981ad6265SDimitry Andric   //   else:
93081ad6265SDimitry Andric   //     Lo = Hi >>s (Shamt-GRLen);
93181ad6265SDimitry Andric   //     Hi = Hi >>s (GRLen-1)
93281ad6265SDimitry Andric   //
93381ad6265SDimitry Andric   // SRL expansion:
93481ad6265SDimitry Andric   //   if Shamt-GRLen < 0: // Shamt < GRLen
93581ad6265SDimitry Andric   //     Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
93681ad6265SDimitry Andric   //     Hi = Hi >>u Shamt
93781ad6265SDimitry Andric   //   else:
93881ad6265SDimitry Andric   //     Lo = Hi >>u (Shamt-GRLen);
93981ad6265SDimitry Andric   //     Hi = 0;
94081ad6265SDimitry Andric 
94181ad6265SDimitry Andric   unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
94281ad6265SDimitry Andric 
94381ad6265SDimitry Andric   SDValue Zero = DAG.getConstant(0, DL, VT);
94481ad6265SDimitry Andric   SDValue One = DAG.getConstant(1, DL, VT);
94581ad6265SDimitry Andric   SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
94681ad6265SDimitry Andric   SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
94781ad6265SDimitry Andric   SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
94881ad6265SDimitry Andric   SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
94981ad6265SDimitry Andric 
95081ad6265SDimitry Andric   SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
95181ad6265SDimitry Andric   SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
95281ad6265SDimitry Andric   SDValue ShiftLeftHi =
95381ad6265SDimitry Andric       DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
95481ad6265SDimitry Andric   SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
95581ad6265SDimitry Andric   SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
95681ad6265SDimitry Andric   SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
95781ad6265SDimitry Andric   SDValue HiFalse =
95881ad6265SDimitry Andric       IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
95981ad6265SDimitry Andric 
96081ad6265SDimitry Andric   SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
96181ad6265SDimitry Andric 
96281ad6265SDimitry Andric   Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
96381ad6265SDimitry Andric   Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
96481ad6265SDimitry Andric 
96581ad6265SDimitry Andric   SDValue Parts[2] = {Lo, Hi};
96681ad6265SDimitry Andric   return DAG.getMergeValues(Parts, DL);
96781ad6265SDimitry Andric }
96881ad6265SDimitry Andric 
96981ad6265SDimitry Andric // Returns the opcode of the target-specific SDNode that implements the 32-bit
97081ad6265SDimitry Andric // form of the given Opcode.
97181ad6265SDimitry Andric static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode) {
97281ad6265SDimitry Andric   switch (Opcode) {
97381ad6265SDimitry Andric   default:
97481ad6265SDimitry Andric     llvm_unreachable("Unexpected opcode");
97581ad6265SDimitry Andric   case ISD::SHL:
97681ad6265SDimitry Andric     return LoongArchISD::SLL_W;
97781ad6265SDimitry Andric   case ISD::SRA:
97881ad6265SDimitry Andric     return LoongArchISD::SRA_W;
97981ad6265SDimitry Andric   case ISD::SRL:
98081ad6265SDimitry Andric     return LoongArchISD::SRL_W;
981*bdd1243dSDimitry Andric   case ISD::ROTR:
982*bdd1243dSDimitry Andric     return LoongArchISD::ROTR_W;
983*bdd1243dSDimitry Andric   case ISD::ROTL:
984*bdd1243dSDimitry Andric     return LoongArchISD::ROTL_W;
985*bdd1243dSDimitry Andric   case ISD::CTTZ:
986*bdd1243dSDimitry Andric     return LoongArchISD::CTZ_W;
987*bdd1243dSDimitry Andric   case ISD::CTLZ:
988*bdd1243dSDimitry Andric     return LoongArchISD::CLZ_W;
98981ad6265SDimitry Andric   }
99081ad6265SDimitry Andric }
99181ad6265SDimitry Andric 
99281ad6265SDimitry Andric // Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
99381ad6265SDimitry Andric // node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
99481ad6265SDimitry Andric // otherwise be promoted to i64, making it difficult to select the
99581ad6265SDimitry Andric // SLL_W/.../*W later one because the fact the operation was originally of
99681ad6265SDimitry Andric // type i8/i16/i32 is lost.
997*bdd1243dSDimitry Andric static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp,
99881ad6265SDimitry Andric                                    unsigned ExtOpc = ISD::ANY_EXTEND) {
99981ad6265SDimitry Andric   SDLoc DL(N);
100081ad6265SDimitry Andric   LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode());
1001*bdd1243dSDimitry Andric   SDValue NewOp0, NewRes;
1002*bdd1243dSDimitry Andric 
1003*bdd1243dSDimitry Andric   switch (NumOp) {
1004*bdd1243dSDimitry Andric   default:
1005*bdd1243dSDimitry Andric     llvm_unreachable("Unexpected NumOp");
1006*bdd1243dSDimitry Andric   case 1: {
1007*bdd1243dSDimitry Andric     NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
1008*bdd1243dSDimitry Andric     NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
1009*bdd1243dSDimitry Andric     break;
1010*bdd1243dSDimitry Andric   }
1011*bdd1243dSDimitry Andric   case 2: {
1012*bdd1243dSDimitry Andric     NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
101381ad6265SDimitry Andric     SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
1014*bdd1243dSDimitry Andric     NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
1015*bdd1243dSDimitry Andric     break;
1016*bdd1243dSDimitry Andric   }
1017*bdd1243dSDimitry Andric     // TODO:Handle more NumOp.
1018*bdd1243dSDimitry Andric   }
1019*bdd1243dSDimitry Andric 
1020*bdd1243dSDimitry Andric   // ReplaceNodeResults requires we maintain the same type for the return
1021*bdd1243dSDimitry Andric   // value.
102281ad6265SDimitry Andric   return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
102381ad6265SDimitry Andric }
102481ad6265SDimitry Andric 
102581ad6265SDimitry Andric void LoongArchTargetLowering::ReplaceNodeResults(
102681ad6265SDimitry Andric     SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
102781ad6265SDimitry Andric   SDLoc DL(N);
1028*bdd1243dSDimitry Andric   EVT VT = N->getValueType(0);
102981ad6265SDimitry Andric   switch (N->getOpcode()) {
103081ad6265SDimitry Andric   default:
103181ad6265SDimitry Andric     llvm_unreachable("Don't know how to legalize this operation");
103281ad6265SDimitry Andric   case ISD::SHL:
103381ad6265SDimitry Andric   case ISD::SRA:
103481ad6265SDimitry Andric   case ISD::SRL:
1035*bdd1243dSDimitry Andric   case ISD::ROTR:
1036*bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
103781ad6265SDimitry Andric            "Unexpected custom legalisation");
103881ad6265SDimitry Andric     if (N->getOperand(1).getOpcode() != ISD::Constant) {
1039*bdd1243dSDimitry Andric       Results.push_back(customLegalizeToWOp(N, DAG, 2));
1040*bdd1243dSDimitry Andric       break;
1041*bdd1243dSDimitry Andric     }
1042*bdd1243dSDimitry Andric     break;
1043*bdd1243dSDimitry Andric   case ISD::ROTL:
1044*bdd1243dSDimitry Andric     ConstantSDNode *CN;
1045*bdd1243dSDimitry Andric     if ((CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) {
1046*bdd1243dSDimitry Andric       Results.push_back(customLegalizeToWOp(N, DAG, 2));
104781ad6265SDimitry Andric       break;
104881ad6265SDimitry Andric     }
104981ad6265SDimitry Andric     break;
1050753f127fSDimitry Andric   case ISD::FP_TO_SINT: {
1051*bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1052753f127fSDimitry Andric            "Unexpected custom legalisation");
1053753f127fSDimitry Andric     SDValue Src = N->getOperand(0);
1054*bdd1243dSDimitry Andric     EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
1055*bdd1243dSDimitry Andric     if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
1056*bdd1243dSDimitry Andric         TargetLowering::TypeSoftenFloat) {
1057*bdd1243dSDimitry Andric       SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
1058*bdd1243dSDimitry Andric       Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
1059*bdd1243dSDimitry Andric       return;
1060*bdd1243dSDimitry Andric     }
1061*bdd1243dSDimitry Andric     // If the FP type needs to be softened, emit a library call using the 'si'
1062*bdd1243dSDimitry Andric     // version. If we left it to default legalization we'd end up with 'di'.
1063*bdd1243dSDimitry Andric     RTLIB::Libcall LC;
1064*bdd1243dSDimitry Andric     LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
1065*bdd1243dSDimitry Andric     MakeLibCallOptions CallOptions;
1066*bdd1243dSDimitry Andric     EVT OpVT = Src.getValueType();
1067*bdd1243dSDimitry Andric     CallOptions.setTypeListBeforeSoften(OpVT, VT, true);
1068*bdd1243dSDimitry Andric     SDValue Chain = SDValue();
1069*bdd1243dSDimitry Andric     SDValue Result;
1070*bdd1243dSDimitry Andric     std::tie(Result, Chain) =
1071*bdd1243dSDimitry Andric         makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
1072*bdd1243dSDimitry Andric     Results.push_back(Result);
1073753f127fSDimitry Andric     break;
1074753f127fSDimitry Andric   }
1075753f127fSDimitry Andric   case ISD::BITCAST: {
1076753f127fSDimitry Andric     SDValue Src = N->getOperand(0);
1077753f127fSDimitry Andric     EVT SrcVT = Src.getValueType();
1078753f127fSDimitry Andric     if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
1079753f127fSDimitry Andric         Subtarget.hasBasicF()) {
1080753f127fSDimitry Andric       SDValue Dst =
1081753f127fSDimitry Andric           DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
1082753f127fSDimitry Andric       Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
1083753f127fSDimitry Andric     }
1084753f127fSDimitry Andric     break;
1085753f127fSDimitry Andric   }
1086753f127fSDimitry Andric   case ISD::FP_TO_UINT: {
1087*bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1088753f127fSDimitry Andric            "Unexpected custom legalisation");
1089753f127fSDimitry Andric     auto &TLI = DAG.getTargetLoweringInfo();
1090753f127fSDimitry Andric     SDValue Tmp1, Tmp2;
1091753f127fSDimitry Andric     TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
1092753f127fSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
1093753f127fSDimitry Andric     break;
1094753f127fSDimitry Andric   }
1095*bdd1243dSDimitry Andric   case ISD::BSWAP: {
1096*bdd1243dSDimitry Andric     SDValue Src = N->getOperand(0);
1097*bdd1243dSDimitry Andric     assert((VT == MVT::i16 || VT == MVT::i32) &&
1098*bdd1243dSDimitry Andric            "Unexpected custom legalization");
1099*bdd1243dSDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
1100*bdd1243dSDimitry Andric     SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1101*bdd1243dSDimitry Andric     SDValue Tmp;
1102*bdd1243dSDimitry Andric     switch (VT.getSizeInBits()) {
1103*bdd1243dSDimitry Andric     default:
1104*bdd1243dSDimitry Andric       llvm_unreachable("Unexpected operand width");
1105*bdd1243dSDimitry Andric     case 16:
1106*bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
1107*bdd1243dSDimitry Andric       break;
1108*bdd1243dSDimitry Andric     case 32:
1109*bdd1243dSDimitry Andric       // Only LA64 will get to here due to the size mismatch between VT and
1110*bdd1243dSDimitry Andric       // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
1111*bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
1112*bdd1243dSDimitry Andric       break;
1113*bdd1243dSDimitry Andric     }
1114*bdd1243dSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
1115*bdd1243dSDimitry Andric     break;
1116*bdd1243dSDimitry Andric   }
1117*bdd1243dSDimitry Andric   case ISD::BITREVERSE: {
1118*bdd1243dSDimitry Andric     SDValue Src = N->getOperand(0);
1119*bdd1243dSDimitry Andric     assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
1120*bdd1243dSDimitry Andric            "Unexpected custom legalization");
1121*bdd1243dSDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
1122*bdd1243dSDimitry Andric     SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1123*bdd1243dSDimitry Andric     SDValue Tmp;
1124*bdd1243dSDimitry Andric     switch (VT.getSizeInBits()) {
1125*bdd1243dSDimitry Andric     default:
1126*bdd1243dSDimitry Andric       llvm_unreachable("Unexpected operand width");
1127*bdd1243dSDimitry Andric     case 8:
1128*bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
1129*bdd1243dSDimitry Andric       break;
1130*bdd1243dSDimitry Andric     case 32:
1131*bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
1132*bdd1243dSDimitry Andric       break;
1133*bdd1243dSDimitry Andric     }
1134*bdd1243dSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
1135*bdd1243dSDimitry Andric     break;
1136*bdd1243dSDimitry Andric   }
1137*bdd1243dSDimitry Andric   case ISD::CTLZ:
1138*bdd1243dSDimitry Andric   case ISD::CTTZ: {
1139*bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1140*bdd1243dSDimitry Andric            "Unexpected custom legalisation");
1141*bdd1243dSDimitry Andric     Results.push_back(customLegalizeToWOp(N, DAG, 1));
1142*bdd1243dSDimitry Andric     break;
1143*bdd1243dSDimitry Andric   }
1144*bdd1243dSDimitry Andric   case ISD::INTRINSIC_W_CHAIN: {
1145*bdd1243dSDimitry Andric     SDValue Op0 = N->getOperand(0);
1146*bdd1243dSDimitry Andric     EVT VT = N->getValueType(0);
1147*bdd1243dSDimitry Andric     uint64_t Op1 = N->getConstantOperandVal(1);
1148*bdd1243dSDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
1149*bdd1243dSDimitry Andric     if (Op1 == Intrinsic::loongarch_movfcsr2gr) {
1150*bdd1243dSDimitry Andric       if (!Subtarget.hasBasicF()) {
1151*bdd1243dSDimitry Andric         DAG.getContext()->emitError(
1152*bdd1243dSDimitry Andric             "llvm.loongarch.movfcsr2gr expects basic f target feature");
1153*bdd1243dSDimitry Andric         Results.push_back(DAG.getMergeValues(
1154*bdd1243dSDimitry Andric             {DAG.getUNDEF(N->getValueType(0)), N->getOperand(0)}, SDLoc(N)));
1155*bdd1243dSDimitry Andric         Results.push_back(N->getOperand(0));
1156*bdd1243dSDimitry Andric         return;
1157*bdd1243dSDimitry Andric       }
1158*bdd1243dSDimitry Andric       unsigned Imm = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue();
1159*bdd1243dSDimitry Andric       if (!isUInt<2>(Imm)) {
1160*bdd1243dSDimitry Andric         DAG.getContext()->emitError("argument to '" + N->getOperationName(0) +
1161*bdd1243dSDimitry Andric                                     "' " + "out of range");
1162*bdd1243dSDimitry Andric         Results.push_back(DAG.getMergeValues(
1163*bdd1243dSDimitry Andric             {DAG.getUNDEF(N->getValueType(0)), N->getOperand(0)}, SDLoc(N)));
1164*bdd1243dSDimitry Andric         Results.push_back(N->getOperand(0));
1165*bdd1243dSDimitry Andric         return;
1166*bdd1243dSDimitry Andric       }
1167*bdd1243dSDimitry Andric       Results.push_back(
1168*bdd1243dSDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT,
1169*bdd1243dSDimitry Andric                       DAG.getNode(LoongArchISD::MOVFCSR2GR, SDLoc(N), MVT::i64,
1170*bdd1243dSDimitry Andric                                   DAG.getConstant(Imm, DL, GRLenVT))));
1171*bdd1243dSDimitry Andric       Results.push_back(N->getOperand(0));
1172*bdd1243dSDimitry Andric       return;
1173*bdd1243dSDimitry Andric     }
1174*bdd1243dSDimitry Andric     SDValue Op2 = N->getOperand(2);
1175*bdd1243dSDimitry Andric     std::string Name = N->getOperationName(0);
1176*bdd1243dSDimitry Andric 
1177*bdd1243dSDimitry Andric     switch (Op1) {
1178*bdd1243dSDimitry Andric     default:
1179*bdd1243dSDimitry Andric       llvm_unreachable("Unexpected Intrinsic.");
1180*bdd1243dSDimitry Andric #define CRC_CASE_EXT_BINARYOP(NAME, NODE)                                      \
1181*bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
1182*bdd1243dSDimitry Andric     Results.push_back(DAG.getNode(                                             \
1183*bdd1243dSDimitry Andric         ISD::TRUNCATE, DL, VT,                                                 \
1184*bdd1243dSDimitry Andric         DAG.getNode(                                                           \
1185*bdd1243dSDimitry Andric             LoongArchISD::NODE, DL, MVT::i64,                                  \
1186*bdd1243dSDimitry Andric             DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),                   \
1187*bdd1243dSDimitry Andric             DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)))));   \
1188*bdd1243dSDimitry Andric     Results.push_back(N->getOperand(0));                                       \
1189*bdd1243dSDimitry Andric     break;                                                                     \
1190*bdd1243dSDimitry Andric   }
1191*bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
1192*bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
1193*bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
1194*bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
1195*bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
1196*bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
1197*bdd1243dSDimitry Andric #undef CRC_CASE_EXT_BINARYOP
1198*bdd1243dSDimitry Andric 
1199*bdd1243dSDimitry Andric #define CRC_CASE_EXT_UNARYOP(NAME, NODE)                                       \
1200*bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
1201*bdd1243dSDimitry Andric     Results.push_back(                                                         \
1202*bdd1243dSDimitry Andric         DAG.getNode(ISD::TRUNCATE, DL, VT,                                     \
1203*bdd1243dSDimitry Andric                     DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op2,         \
1204*bdd1243dSDimitry Andric                                 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,     \
1205*bdd1243dSDimitry Andric                                             N->getOperand(3)))));              \
1206*bdd1243dSDimitry Andric     Results.push_back(N->getOperand(0));                                       \
1207*bdd1243dSDimitry Andric     break;                                                                     \
1208*bdd1243dSDimitry Andric   }
1209*bdd1243dSDimitry Andric       CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
1210*bdd1243dSDimitry Andric       CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
1211*bdd1243dSDimitry Andric #undef CRC_CASE_EXT_UNARYOP
1212*bdd1243dSDimitry Andric #define CSR_CASE(ID)                                                           \
1213*bdd1243dSDimitry Andric   case Intrinsic::loongarch_##ID: {                                            \
1214*bdd1243dSDimitry Andric     if (!Subtarget.is64Bit()) {                                                \
1215*bdd1243dSDimitry Andric       DAG.getContext()->emitError(Name + " requires target: loongarch64");     \
1216*bdd1243dSDimitry Andric       Results.push_back(DAG.getUNDEF(VT));                                     \
1217*bdd1243dSDimitry Andric       Results.push_back(N->getOperand(0));                                     \
1218*bdd1243dSDimitry Andric     }                                                                          \
1219*bdd1243dSDimitry Andric     break;                                                                     \
1220*bdd1243dSDimitry Andric   }
1221*bdd1243dSDimitry Andric       CSR_CASE(csrrd_d);
1222*bdd1243dSDimitry Andric       CSR_CASE(csrwr_d);
1223*bdd1243dSDimitry Andric       CSR_CASE(csrxchg_d);
1224*bdd1243dSDimitry Andric       CSR_CASE(iocsrrd_d);
1225*bdd1243dSDimitry Andric #undef CSR_CASE
1226*bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrrd_w: {
1227*bdd1243dSDimitry Andric       unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
1228*bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
1229*bdd1243dSDimitry Andric         DAG.getContext()->emitError("argument to '" + Name + "' out of range");
1230*bdd1243dSDimitry Andric         Results.push_back(DAG.getUNDEF(VT));
1231*bdd1243dSDimitry Andric         Results.push_back(N->getOperand(0));
1232*bdd1243dSDimitry Andric         break;
1233*bdd1243dSDimitry Andric       }
1234*bdd1243dSDimitry Andric 
1235*bdd1243dSDimitry Andric       Results.push_back(
1236*bdd1243dSDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT,
1237*bdd1243dSDimitry Andric                       DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0,
1238*bdd1243dSDimitry Andric                                   DAG.getConstant(Imm, DL, GRLenVT))));
1239*bdd1243dSDimitry Andric       Results.push_back(N->getOperand(0));
1240*bdd1243dSDimitry Andric       break;
1241*bdd1243dSDimitry Andric     }
1242*bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrwr_w: {
1243*bdd1243dSDimitry Andric       unsigned Imm = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue();
1244*bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
1245*bdd1243dSDimitry Andric         DAG.getContext()->emitError("argument to '" + Name + "' out of range");
1246*bdd1243dSDimitry Andric         Results.push_back(DAG.getUNDEF(VT));
1247*bdd1243dSDimitry Andric         Results.push_back(N->getOperand(0));
1248*bdd1243dSDimitry Andric         break;
1249*bdd1243dSDimitry Andric       }
1250*bdd1243dSDimitry Andric 
1251*bdd1243dSDimitry Andric       Results.push_back(DAG.getNode(
1252*bdd1243dSDimitry Andric           ISD::TRUNCATE, DL, VT,
1253*bdd1243dSDimitry Andric           DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0,
1254*bdd1243dSDimitry Andric                       DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
1255*bdd1243dSDimitry Andric                       DAG.getConstant(Imm, DL, GRLenVT))));
1256*bdd1243dSDimitry Andric       Results.push_back(N->getOperand(0));
1257*bdd1243dSDimitry Andric       break;
1258*bdd1243dSDimitry Andric     }
1259*bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrxchg_w: {
1260*bdd1243dSDimitry Andric       unsigned Imm = cast<ConstantSDNode>(N->getOperand(4))->getZExtValue();
1261*bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
1262*bdd1243dSDimitry Andric         DAG.getContext()->emitError("argument to '" + Name + "' out of range");
1263*bdd1243dSDimitry Andric         Results.push_back(DAG.getUNDEF(VT));
1264*bdd1243dSDimitry Andric         Results.push_back(N->getOperand(0));
1265*bdd1243dSDimitry Andric         break;
1266*bdd1243dSDimitry Andric       }
1267*bdd1243dSDimitry Andric 
1268*bdd1243dSDimitry Andric       Results.push_back(DAG.getNode(
1269*bdd1243dSDimitry Andric           ISD::TRUNCATE, DL, VT,
1270*bdd1243dSDimitry Andric           DAG.getNode(
1271*bdd1243dSDimitry Andric               LoongArchISD::CSRXCHG, DL, GRLenVT, Op0,
1272*bdd1243dSDimitry Andric               DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
1273*bdd1243dSDimitry Andric               DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
1274*bdd1243dSDimitry Andric               DAG.getConstant(Imm, DL, GRLenVT))));
1275*bdd1243dSDimitry Andric       Results.push_back(N->getOperand(0));
1276*bdd1243dSDimitry Andric       break;
1277*bdd1243dSDimitry Andric     }
1278*bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE)                                               \
1279*bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
1280*bdd1243dSDimitry Andric     Results.push_back(DAG.getNode(                                             \
1281*bdd1243dSDimitry Andric         ISD::TRUNCATE, DL, N->getValueType(0),                                 \
1282*bdd1243dSDimitry Andric         DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op0,                     \
1283*bdd1243dSDimitry Andric                     DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2))));        \
1284*bdd1243dSDimitry Andric     Results.push_back(N->getOperand(0));                                       \
1285*bdd1243dSDimitry Andric     break;                                                                     \
1286*bdd1243dSDimitry Andric   }
1287*bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
1288*bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
1289*bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
1290*bdd1243dSDimitry Andric #undef IOCSRRD_CASE
1291*bdd1243dSDimitry Andric     case Intrinsic::loongarch_cpucfg: {
1292*bdd1243dSDimitry Andric       Results.push_back(DAG.getNode(
1293*bdd1243dSDimitry Andric           ISD::TRUNCATE, DL, VT,
1294*bdd1243dSDimitry Andric           DAG.getNode(LoongArchISD::CPUCFG, DL, GRLenVT, Op0,
1295*bdd1243dSDimitry Andric                       DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2))));
1296*bdd1243dSDimitry Andric       Results.push_back(Op0);
1297*bdd1243dSDimitry Andric       break;
1298*bdd1243dSDimitry Andric     }
1299*bdd1243dSDimitry Andric     case Intrinsic::loongarch_lddir_d: {
1300*bdd1243dSDimitry Andric       if (!Subtarget.is64Bit()) {
1301*bdd1243dSDimitry Andric         DAG.getContext()->emitError(N->getOperationName(0) +
1302*bdd1243dSDimitry Andric                                     " requires target: loongarch64");
1303*bdd1243dSDimitry Andric         Results.push_back(DAG.getUNDEF(VT));
1304*bdd1243dSDimitry Andric         Results.push_back(Op0);
1305*bdd1243dSDimitry Andric         break;
1306*bdd1243dSDimitry Andric       }
1307*bdd1243dSDimitry Andric       break;
1308*bdd1243dSDimitry Andric     }
1309*bdd1243dSDimitry Andric     }
1310*bdd1243dSDimitry Andric     break;
1311*bdd1243dSDimitry Andric   }
1312*bdd1243dSDimitry Andric   case ISD::READ_REGISTER: {
1313*bdd1243dSDimitry Andric     if (Subtarget.is64Bit())
1314*bdd1243dSDimitry Andric       DAG.getContext()->emitError(
1315*bdd1243dSDimitry Andric           "On LA64, only 64-bit registers can be read.");
1316*bdd1243dSDimitry Andric     else
1317*bdd1243dSDimitry Andric       DAG.getContext()->emitError(
1318*bdd1243dSDimitry Andric           "On LA32, only 32-bit registers can be read.");
1319*bdd1243dSDimitry Andric     Results.push_back(DAG.getUNDEF(VT));
1320*bdd1243dSDimitry Andric     Results.push_back(N->getOperand(0));
1321*bdd1243dSDimitry Andric     break;
1322*bdd1243dSDimitry Andric   }
132381ad6265SDimitry Andric   }
132481ad6265SDimitry Andric }
132581ad6265SDimitry Andric 
132681ad6265SDimitry Andric static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG,
132781ad6265SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
132881ad6265SDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
132981ad6265SDimitry Andric   if (DCI.isBeforeLegalizeOps())
133081ad6265SDimitry Andric     return SDValue();
133181ad6265SDimitry Andric 
133281ad6265SDimitry Andric   SDValue FirstOperand = N->getOperand(0);
133381ad6265SDimitry Andric   SDValue SecondOperand = N->getOperand(1);
133481ad6265SDimitry Andric   unsigned FirstOperandOpc = FirstOperand.getOpcode();
133581ad6265SDimitry Andric   EVT ValTy = N->getValueType(0);
133681ad6265SDimitry Andric   SDLoc DL(N);
133781ad6265SDimitry Andric   uint64_t lsb, msb;
133881ad6265SDimitry Andric   unsigned SMIdx, SMLen;
133981ad6265SDimitry Andric   ConstantSDNode *CN;
134081ad6265SDimitry Andric   SDValue NewOperand;
134181ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
134281ad6265SDimitry Andric 
134381ad6265SDimitry Andric   // Op's second operand must be a shifted mask.
134481ad6265SDimitry Andric   if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
134581ad6265SDimitry Andric       !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
134681ad6265SDimitry Andric     return SDValue();
134781ad6265SDimitry Andric 
134881ad6265SDimitry Andric   if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
134981ad6265SDimitry Andric     // Pattern match BSTRPICK.
135081ad6265SDimitry Andric     //  $dst = and ((sra or srl) $src , lsb), (2**len - 1)
135181ad6265SDimitry Andric     //  => BSTRPICK $dst, $src, msb, lsb
135281ad6265SDimitry Andric     //  where msb = lsb + len - 1
135381ad6265SDimitry Andric 
135481ad6265SDimitry Andric     // The second operand of the shift must be an immediate.
135581ad6265SDimitry Andric     if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
135681ad6265SDimitry Andric       return SDValue();
135781ad6265SDimitry Andric 
135881ad6265SDimitry Andric     lsb = CN->getZExtValue();
135981ad6265SDimitry Andric 
136081ad6265SDimitry Andric     // Return if the shifted mask does not start at bit 0 or the sum of its
136181ad6265SDimitry Andric     // length and lsb exceeds the word's size.
136281ad6265SDimitry Andric     if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
136381ad6265SDimitry Andric       return SDValue();
136481ad6265SDimitry Andric 
136581ad6265SDimitry Andric     NewOperand = FirstOperand.getOperand(0);
136681ad6265SDimitry Andric   } else {
136781ad6265SDimitry Andric     // Pattern match BSTRPICK.
136881ad6265SDimitry Andric     //  $dst = and $src, (2**len- 1) , if len > 12
136981ad6265SDimitry Andric     //  => BSTRPICK $dst, $src, msb, lsb
137081ad6265SDimitry Andric     //  where lsb = 0 and msb = len - 1
137181ad6265SDimitry Andric 
137281ad6265SDimitry Andric     // If the mask is <= 0xfff, andi can be used instead.
137381ad6265SDimitry Andric     if (CN->getZExtValue() <= 0xfff)
137481ad6265SDimitry Andric       return SDValue();
137581ad6265SDimitry Andric 
137681ad6265SDimitry Andric     // Return if the mask doesn't start at position 0.
137781ad6265SDimitry Andric     if (SMIdx)
137881ad6265SDimitry Andric       return SDValue();
137981ad6265SDimitry Andric 
138081ad6265SDimitry Andric     lsb = 0;
138181ad6265SDimitry Andric     NewOperand = FirstOperand;
138281ad6265SDimitry Andric   }
138381ad6265SDimitry Andric   msb = lsb + SMLen - 1;
138481ad6265SDimitry Andric   return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
138581ad6265SDimitry Andric                      DAG.getConstant(msb, DL, GRLenVT),
138681ad6265SDimitry Andric                      DAG.getConstant(lsb, DL, GRLenVT));
138781ad6265SDimitry Andric }
138881ad6265SDimitry Andric 
138981ad6265SDimitry Andric static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG,
139081ad6265SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
139181ad6265SDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
139281ad6265SDimitry Andric   if (DCI.isBeforeLegalizeOps())
139381ad6265SDimitry Andric     return SDValue();
139481ad6265SDimitry Andric 
139581ad6265SDimitry Andric   // $dst = srl (and $src, Mask), Shamt
139681ad6265SDimitry Andric   // =>
139781ad6265SDimitry Andric   // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
139881ad6265SDimitry Andric   // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
139981ad6265SDimitry Andric   //
140081ad6265SDimitry Andric 
140181ad6265SDimitry Andric   SDValue FirstOperand = N->getOperand(0);
140281ad6265SDimitry Andric   ConstantSDNode *CN;
140381ad6265SDimitry Andric   EVT ValTy = N->getValueType(0);
140481ad6265SDimitry Andric   SDLoc DL(N);
140581ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
140681ad6265SDimitry Andric   unsigned MaskIdx, MaskLen;
140781ad6265SDimitry Andric   uint64_t Shamt;
140881ad6265SDimitry Andric 
140981ad6265SDimitry Andric   // The first operand must be an AND and the second operand of the AND must be
141081ad6265SDimitry Andric   // a shifted mask.
141181ad6265SDimitry Andric   if (FirstOperand.getOpcode() != ISD::AND ||
141281ad6265SDimitry Andric       !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
141381ad6265SDimitry Andric       !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
141481ad6265SDimitry Andric     return SDValue();
141581ad6265SDimitry Andric 
141681ad6265SDimitry Andric   // The second operand (shift amount) must be an immediate.
141781ad6265SDimitry Andric   if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
141881ad6265SDimitry Andric     return SDValue();
141981ad6265SDimitry Andric 
142081ad6265SDimitry Andric   Shamt = CN->getZExtValue();
142181ad6265SDimitry Andric   if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
142281ad6265SDimitry Andric     return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
142381ad6265SDimitry Andric                        FirstOperand->getOperand(0),
142481ad6265SDimitry Andric                        DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
142581ad6265SDimitry Andric                        DAG.getConstant(Shamt, DL, GRLenVT));
142681ad6265SDimitry Andric 
142781ad6265SDimitry Andric   return SDValue();
142881ad6265SDimitry Andric }
142981ad6265SDimitry Andric 
1430753f127fSDimitry Andric static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
1431753f127fSDimitry Andric                                 TargetLowering::DAGCombinerInfo &DCI,
1432753f127fSDimitry Andric                                 const LoongArchSubtarget &Subtarget) {
1433753f127fSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
1434753f127fSDimitry Andric   EVT ValTy = N->getValueType(0);
1435753f127fSDimitry Andric   SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
1436753f127fSDimitry Andric   ConstantSDNode *CN0, *CN1;
1437753f127fSDimitry Andric   SDLoc DL(N);
1438753f127fSDimitry Andric   unsigned ValBits = ValTy.getSizeInBits();
1439753f127fSDimitry Andric   unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
1440753f127fSDimitry Andric   unsigned Shamt;
1441753f127fSDimitry Andric   bool SwapAndRetried = false;
1442753f127fSDimitry Andric 
1443753f127fSDimitry Andric   if (DCI.isBeforeLegalizeOps())
1444753f127fSDimitry Andric     return SDValue();
1445753f127fSDimitry Andric 
1446753f127fSDimitry Andric   if (ValBits != 32 && ValBits != 64)
1447753f127fSDimitry Andric     return SDValue();
1448753f127fSDimitry Andric 
1449753f127fSDimitry Andric Retry:
1450753f127fSDimitry Andric   // 1st pattern to match BSTRINS:
1451753f127fSDimitry Andric   //  R = or (and X, mask0), (and (shl Y, lsb), mask1)
1452753f127fSDimitry Andric   //  where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
1453753f127fSDimitry Andric   //  =>
1454753f127fSDimitry Andric   //  R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
1455753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
1456753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1457753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1458753f127fSDimitry Andric       N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
1459753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1460753f127fSDimitry Andric       isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
1461753f127fSDimitry Andric       MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
1462753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1463753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
1464753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
1465753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
1466753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1467753f127fSDimitry Andric                        N1.getOperand(0).getOperand(0),
1468753f127fSDimitry Andric                        DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1469753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
1470753f127fSDimitry Andric   }
1471753f127fSDimitry Andric 
1472753f127fSDimitry Andric   // 2nd pattern to match BSTRINS:
1473753f127fSDimitry Andric   //  R = or (and X, mask0), (shl (and Y, mask1), lsb)
1474753f127fSDimitry Andric   //  where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
1475753f127fSDimitry Andric   //  =>
1476753f127fSDimitry Andric   //  R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
1477753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
1478753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1479753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1480753f127fSDimitry Andric       N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
1481753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1482753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
1483753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1484753f127fSDimitry Andric       isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
1485753f127fSDimitry Andric       MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
1486753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
1487753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
1488753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1489753f127fSDimitry Andric                        N1.getOperand(0).getOperand(0),
1490753f127fSDimitry Andric                        DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1491753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
1492753f127fSDimitry Andric   }
1493753f127fSDimitry Andric 
1494753f127fSDimitry Andric   // 3rd pattern to match BSTRINS:
1495753f127fSDimitry Andric   //  R = or (and X, mask0), (and Y, mask1)
1496753f127fSDimitry Andric   //  where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
1497753f127fSDimitry Andric   //  =>
1498753f127fSDimitry Andric   //  R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
1499753f127fSDimitry Andric   //  where msb = lsb + size - 1
1500753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
1501753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1502753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1503753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= 64) &&
1504753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
1505753f127fSDimitry Andric       (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
1506753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
1507753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1508753f127fSDimitry Andric                        DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
1509753f127fSDimitry Andric                                    DAG.getConstant(MaskIdx0, DL, GRLenVT)),
1510753f127fSDimitry Andric                        DAG.getConstant(ValBits == 32
1511753f127fSDimitry Andric                                            ? (MaskIdx0 + (MaskLen0 & 31) - 1)
1512753f127fSDimitry Andric                                            : (MaskIdx0 + MaskLen0 - 1),
1513753f127fSDimitry Andric                                        DL, GRLenVT),
1514753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
1515753f127fSDimitry Andric   }
1516753f127fSDimitry Andric 
1517753f127fSDimitry Andric   // 4th pattern to match BSTRINS:
1518753f127fSDimitry Andric   //  R = or (and X, mask), (shl Y, shamt)
1519753f127fSDimitry Andric   //  where mask = (2**shamt - 1)
1520753f127fSDimitry Andric   //  =>
1521753f127fSDimitry Andric   //  R = BSTRINS X, Y, ValBits - 1, shamt
1522753f127fSDimitry Andric   //  where ValBits = 32 or 64
1523753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
1524753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1525753f127fSDimitry Andric       isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
1526753f127fSDimitry Andric       MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1527753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskLen0 &&
1528753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
1529753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
1530753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1531753f127fSDimitry Andric                        N1.getOperand(0),
1532753f127fSDimitry Andric                        DAG.getConstant((ValBits - 1), DL, GRLenVT),
1533753f127fSDimitry Andric                        DAG.getConstant(Shamt, DL, GRLenVT));
1534753f127fSDimitry Andric   }
1535753f127fSDimitry Andric 
1536753f127fSDimitry Andric   // 5th pattern to match BSTRINS:
1537753f127fSDimitry Andric   //  R = or (and X, mask), const
1538753f127fSDimitry Andric   //  where ~mask = (2**size - 1) << lsb, mask & const = 0
1539753f127fSDimitry Andric   //  =>
1540753f127fSDimitry Andric   //  R = BSTRINS X, (const >> lsb), msb, lsb
1541753f127fSDimitry Andric   //  where msb = lsb + size - 1
1542753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
1543753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1544753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1545753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
1546753f127fSDimitry Andric       (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
1547753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
1548753f127fSDimitry Andric     return DAG.getNode(
1549753f127fSDimitry Andric         LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1550753f127fSDimitry Andric         DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
1551753f127fSDimitry Andric         DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1552753f127fSDimitry Andric         DAG.getConstant(MaskIdx0, DL, GRLenVT));
1553753f127fSDimitry Andric   }
1554753f127fSDimitry Andric 
1555753f127fSDimitry Andric   // 6th pattern.
1556753f127fSDimitry Andric   // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
1557753f127fSDimitry Andric   // by the incoming bits are known to be zero.
1558753f127fSDimitry Andric   // =>
1559753f127fSDimitry Andric   // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
1560753f127fSDimitry Andric   //
1561753f127fSDimitry Andric   // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
1562753f127fSDimitry Andric   // pattern is more common than the 1st. So we put the 1st before the 6th in
1563753f127fSDimitry Andric   // order to match as many nodes as possible.
1564753f127fSDimitry Andric   ConstantSDNode *CNMask, *CNShamt;
1565753f127fSDimitry Andric   unsigned MaskIdx, MaskLen;
1566753f127fSDimitry Andric   if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
1567753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1568753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
1569753f127fSDimitry Andric       MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1570753f127fSDimitry Andric       CNShamt->getZExtValue() + MaskLen <= ValBits) {
1571753f127fSDimitry Andric     Shamt = CNShamt->getZExtValue();
1572753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
1573753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1574753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
1575753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1576753f127fSDimitry Andric                          N1.getOperand(0).getOperand(0),
1577753f127fSDimitry Andric                          DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
1578753f127fSDimitry Andric                          DAG.getConstant(Shamt, DL, GRLenVT));
1579753f127fSDimitry Andric     }
1580753f127fSDimitry Andric   }
1581753f127fSDimitry Andric 
1582753f127fSDimitry Andric   // 7th pattern.
1583753f127fSDimitry Andric   // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
1584753f127fSDimitry Andric   // overwritten by the incoming bits are known to be zero.
1585753f127fSDimitry Andric   // =>
1586753f127fSDimitry Andric   // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
1587753f127fSDimitry Andric   //
1588753f127fSDimitry Andric   // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
1589753f127fSDimitry Andric   // before the 7th in order to match as many nodes as possible.
1590753f127fSDimitry Andric   if (N1.getOpcode() == ISD::AND &&
1591753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1592753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
1593753f127fSDimitry Andric       N1.getOperand(0).getOpcode() == ISD::SHL &&
1594753f127fSDimitry Andric       (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1595753f127fSDimitry Andric       CNShamt->getZExtValue() == MaskIdx) {
1596753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue());
1597753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1598753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
1599753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1600753f127fSDimitry Andric                          N1.getOperand(0).getOperand(0),
1601753f127fSDimitry Andric                          DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1602753f127fSDimitry Andric                          DAG.getConstant(MaskIdx, DL, GRLenVT));
1603753f127fSDimitry Andric     }
1604753f127fSDimitry Andric   }
1605753f127fSDimitry Andric 
1606753f127fSDimitry Andric   // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
1607753f127fSDimitry Andric   if (!SwapAndRetried) {
1608753f127fSDimitry Andric     std::swap(N0, N1);
1609753f127fSDimitry Andric     SwapAndRetried = true;
1610753f127fSDimitry Andric     goto Retry;
1611753f127fSDimitry Andric   }
1612753f127fSDimitry Andric 
1613753f127fSDimitry Andric   SwapAndRetried = false;
1614753f127fSDimitry Andric Retry2:
1615753f127fSDimitry Andric   // 8th pattern.
1616753f127fSDimitry Andric   // a = b | (c & shifted_mask), where all positions in b to be overwritten by
1617753f127fSDimitry Andric   // the incoming bits are known to be zero.
1618753f127fSDimitry Andric   // =>
1619753f127fSDimitry Andric   // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
1620753f127fSDimitry Andric   //
1621753f127fSDimitry Andric   // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
1622753f127fSDimitry Andric   // we put it here in order to match as many nodes as possible or generate less
1623753f127fSDimitry Andric   // instructions.
1624753f127fSDimitry Andric   if (N1.getOpcode() == ISD::AND &&
1625753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1626753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
1627753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue());
1628753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1629753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
1630753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1631753f127fSDimitry Andric                          DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
1632753f127fSDimitry Andric                                      N1->getOperand(0),
1633753f127fSDimitry Andric                                      DAG.getConstant(MaskIdx, DL, GRLenVT)),
1634753f127fSDimitry Andric                          DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1635753f127fSDimitry Andric                          DAG.getConstant(MaskIdx, DL, GRLenVT));
1636753f127fSDimitry Andric     }
1637753f127fSDimitry Andric   }
1638753f127fSDimitry Andric   // Swap N0/N1 and retry.
1639753f127fSDimitry Andric   if (!SwapAndRetried) {
1640753f127fSDimitry Andric     std::swap(N0, N1);
1641753f127fSDimitry Andric     SwapAndRetried = true;
1642753f127fSDimitry Andric     goto Retry2;
1643753f127fSDimitry Andric   }
1644753f127fSDimitry Andric 
1645753f127fSDimitry Andric   return SDValue();
1646753f127fSDimitry Andric }
1647753f127fSDimitry Andric 
1648*bdd1243dSDimitry Andric // Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
1649*bdd1243dSDimitry Andric static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG,
1650*bdd1243dSDimitry Andric                                       TargetLowering::DAGCombinerInfo &DCI,
1651*bdd1243dSDimitry Andric                                       const LoongArchSubtarget &Subtarget) {
1652*bdd1243dSDimitry Andric   if (DCI.isBeforeLegalizeOps())
1653*bdd1243dSDimitry Andric     return SDValue();
1654*bdd1243dSDimitry Andric 
1655*bdd1243dSDimitry Andric   SDValue Src = N->getOperand(0);
1656*bdd1243dSDimitry Andric   if (Src.getOpcode() != LoongArchISD::REVB_2W)
1657*bdd1243dSDimitry Andric     return SDValue();
1658*bdd1243dSDimitry Andric 
1659*bdd1243dSDimitry Andric   return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
1660*bdd1243dSDimitry Andric                      Src.getOperand(0));
1661*bdd1243dSDimitry Andric }
1662*bdd1243dSDimitry Andric 
166381ad6265SDimitry Andric SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N,
166481ad6265SDimitry Andric                                                    DAGCombinerInfo &DCI) const {
166581ad6265SDimitry Andric   SelectionDAG &DAG = DCI.DAG;
166681ad6265SDimitry Andric   switch (N->getOpcode()) {
166781ad6265SDimitry Andric   default:
166881ad6265SDimitry Andric     break;
166981ad6265SDimitry Andric   case ISD::AND:
167081ad6265SDimitry Andric     return performANDCombine(N, DAG, DCI, Subtarget);
1671753f127fSDimitry Andric   case ISD::OR:
1672753f127fSDimitry Andric     return performORCombine(N, DAG, DCI, Subtarget);
167381ad6265SDimitry Andric   case ISD::SRL:
167481ad6265SDimitry Andric     return performSRLCombine(N, DAG, DCI, Subtarget);
1675*bdd1243dSDimitry Andric   case LoongArchISD::BITREV_W:
1676*bdd1243dSDimitry Andric     return performBITREV_WCombine(N, DAG, DCI, Subtarget);
167781ad6265SDimitry Andric   }
167881ad6265SDimitry Andric   return SDValue();
167981ad6265SDimitry Andric }
168081ad6265SDimitry Andric 
1681753f127fSDimitry Andric static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI,
1682*bdd1243dSDimitry Andric                                               MachineBasicBlock *MBB) {
1683753f127fSDimitry Andric   if (!ZeroDivCheck)
1684*bdd1243dSDimitry Andric     return MBB;
1685753f127fSDimitry Andric 
1686753f127fSDimitry Andric   // Build instructions:
1687*bdd1243dSDimitry Andric   // MBB:
1688753f127fSDimitry Andric   //   div(or mod)   $dst, $dividend, $divisor
1689*bdd1243dSDimitry Andric   //   bnez          $divisor, SinkMBB
1690*bdd1243dSDimitry Andric   // BreakMBB:
1691*bdd1243dSDimitry Andric   //   break         7 // BRK_DIVZERO
1692*bdd1243dSDimitry Andric   // SinkMBB:
1693753f127fSDimitry Andric   //   fallthrough
1694*bdd1243dSDimitry Andric   const BasicBlock *LLVM_BB = MBB->getBasicBlock();
1695*bdd1243dSDimitry Andric   MachineFunction::iterator It = ++MBB->getIterator();
1696*bdd1243dSDimitry Andric   MachineFunction *MF = MBB->getParent();
1697*bdd1243dSDimitry Andric   auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
1698*bdd1243dSDimitry Andric   auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
1699*bdd1243dSDimitry Andric   MF->insert(It, BreakMBB);
1700*bdd1243dSDimitry Andric   MF->insert(It, SinkMBB);
1701*bdd1243dSDimitry Andric 
1702*bdd1243dSDimitry Andric   // Transfer the remainder of MBB and its successor edges to SinkMBB.
1703*bdd1243dSDimitry Andric   SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
1704*bdd1243dSDimitry Andric   SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
1705*bdd1243dSDimitry Andric 
1706*bdd1243dSDimitry Andric   const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
1707*bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
1708753f127fSDimitry Andric   MachineOperand &Divisor = MI.getOperand(2);
1709*bdd1243dSDimitry Andric   Register DivisorReg = Divisor.getReg();
1710753f127fSDimitry Andric 
1711*bdd1243dSDimitry Andric   // MBB:
1712*bdd1243dSDimitry Andric   BuildMI(MBB, DL, TII.get(LoongArch::BNEZ))
1713*bdd1243dSDimitry Andric       .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
1714*bdd1243dSDimitry Andric       .addMBB(SinkMBB);
1715*bdd1243dSDimitry Andric   MBB->addSuccessor(BreakMBB);
1716*bdd1243dSDimitry Andric   MBB->addSuccessor(SinkMBB);
1717753f127fSDimitry Andric 
1718*bdd1243dSDimitry Andric   // BreakMBB:
1719753f127fSDimitry Andric   // See linux header file arch/loongarch/include/uapi/asm/break.h for the
1720753f127fSDimitry Andric   // definition of BRK_DIVZERO.
1721*bdd1243dSDimitry Andric   BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
1722*bdd1243dSDimitry Andric   BreakMBB->addSuccessor(SinkMBB);
1723753f127fSDimitry Andric 
1724753f127fSDimitry Andric   // Clear Divisor's kill flag.
1725753f127fSDimitry Andric   Divisor.setIsKill(false);
1726753f127fSDimitry Andric 
1727*bdd1243dSDimitry Andric   return SinkMBB;
1728753f127fSDimitry Andric }
1729753f127fSDimitry Andric 
1730753f127fSDimitry Andric MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
1731753f127fSDimitry Andric     MachineInstr &MI, MachineBasicBlock *BB) const {
1732*bdd1243dSDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
1733*bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
1734753f127fSDimitry Andric 
1735753f127fSDimitry Andric   switch (MI.getOpcode()) {
1736753f127fSDimitry Andric   default:
1737753f127fSDimitry Andric     llvm_unreachable("Unexpected instr type to insert");
1738753f127fSDimitry Andric   case LoongArch::DIV_W:
1739753f127fSDimitry Andric   case LoongArch::DIV_WU:
1740753f127fSDimitry Andric   case LoongArch::MOD_W:
1741753f127fSDimitry Andric   case LoongArch::MOD_WU:
1742753f127fSDimitry Andric   case LoongArch::DIV_D:
1743753f127fSDimitry Andric   case LoongArch::DIV_DU:
1744753f127fSDimitry Andric   case LoongArch::MOD_D:
1745753f127fSDimitry Andric   case LoongArch::MOD_DU:
1746*bdd1243dSDimitry Andric     return insertDivByZeroTrap(MI, BB);
1747753f127fSDimitry Andric     break;
1748*bdd1243dSDimitry Andric   case LoongArch::WRFCSR: {
1749*bdd1243dSDimitry Andric     BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
1750*bdd1243dSDimitry Andric             LoongArch::FCSR0 + MI.getOperand(0).getImm())
1751*bdd1243dSDimitry Andric         .addReg(MI.getOperand(1).getReg());
1752*bdd1243dSDimitry Andric     MI.eraseFromParent();
1753*bdd1243dSDimitry Andric     return BB;
1754*bdd1243dSDimitry Andric   }
1755*bdd1243dSDimitry Andric   case LoongArch::RDFCSR: {
1756*bdd1243dSDimitry Andric     MachineInstr *ReadFCSR =
1757*bdd1243dSDimitry Andric         BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
1758*bdd1243dSDimitry Andric                 MI.getOperand(0).getReg())
1759*bdd1243dSDimitry Andric             .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
1760*bdd1243dSDimitry Andric     ReadFCSR->getOperand(1).setIsUndef();
1761*bdd1243dSDimitry Andric     MI.eraseFromParent();
1762*bdd1243dSDimitry Andric     return BB;
1763*bdd1243dSDimitry Andric   }
1764753f127fSDimitry Andric   }
1765753f127fSDimitry Andric }
1766753f127fSDimitry Andric 
176781ad6265SDimitry Andric const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
176881ad6265SDimitry Andric   switch ((LoongArchISD::NodeType)Opcode) {
176981ad6265SDimitry Andric   case LoongArchISD::FIRST_NUMBER:
177081ad6265SDimitry Andric     break;
177181ad6265SDimitry Andric 
177281ad6265SDimitry Andric #define NODE_NAME_CASE(node)                                                   \
177381ad6265SDimitry Andric   case LoongArchISD::node:                                                     \
177481ad6265SDimitry Andric     return "LoongArchISD::" #node;
177581ad6265SDimitry Andric 
177681ad6265SDimitry Andric     // TODO: Add more target-dependent nodes later.
1777753f127fSDimitry Andric     NODE_NAME_CASE(CALL)
177881ad6265SDimitry Andric     NODE_NAME_CASE(RET)
1779*bdd1243dSDimitry Andric     NODE_NAME_CASE(TAIL)
178081ad6265SDimitry Andric     NODE_NAME_CASE(SLL_W)
178181ad6265SDimitry Andric     NODE_NAME_CASE(SRA_W)
178281ad6265SDimitry Andric     NODE_NAME_CASE(SRL_W)
1783753f127fSDimitry Andric     NODE_NAME_CASE(BSTRINS)
178481ad6265SDimitry Andric     NODE_NAME_CASE(BSTRPICK)
1785753f127fSDimitry Andric     NODE_NAME_CASE(MOVGR2FR_W_LA64)
1786753f127fSDimitry Andric     NODE_NAME_CASE(MOVFR2GR_S_LA64)
1787753f127fSDimitry Andric     NODE_NAME_CASE(FTINT)
1788*bdd1243dSDimitry Andric     NODE_NAME_CASE(REVB_2H)
1789*bdd1243dSDimitry Andric     NODE_NAME_CASE(REVB_2W)
1790*bdd1243dSDimitry Andric     NODE_NAME_CASE(BITREV_4B)
1791*bdd1243dSDimitry Andric     NODE_NAME_CASE(BITREV_W)
1792*bdd1243dSDimitry Andric     NODE_NAME_CASE(ROTR_W)
1793*bdd1243dSDimitry Andric     NODE_NAME_CASE(ROTL_W)
1794*bdd1243dSDimitry Andric     NODE_NAME_CASE(CLZ_W)
1795*bdd1243dSDimitry Andric     NODE_NAME_CASE(CTZ_W)
1796*bdd1243dSDimitry Andric     NODE_NAME_CASE(DBAR)
1797*bdd1243dSDimitry Andric     NODE_NAME_CASE(IBAR)
1798*bdd1243dSDimitry Andric     NODE_NAME_CASE(BREAK)
1799*bdd1243dSDimitry Andric     NODE_NAME_CASE(SYSCALL)
1800*bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_B_W)
1801*bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_H_W)
1802*bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_W_W)
1803*bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_D_W)
1804*bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_B_W)
1805*bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_H_W)
1806*bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_W_W)
1807*bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_D_W)
1808*bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRRD)
1809*bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRWR)
1810*bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRXCHG)
1811*bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_B)
1812*bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_H)
1813*bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_W)
1814*bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_D)
1815*bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_B)
1816*bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_H)
1817*bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_W)
1818*bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_D)
1819*bdd1243dSDimitry Andric     NODE_NAME_CASE(CPUCFG)
1820*bdd1243dSDimitry Andric     NODE_NAME_CASE(MOVGR2FCSR)
1821*bdd1243dSDimitry Andric     NODE_NAME_CASE(MOVFCSR2GR)
1822*bdd1243dSDimitry Andric     NODE_NAME_CASE(CACOP_D)
1823*bdd1243dSDimitry Andric     NODE_NAME_CASE(CACOP_W)
182481ad6265SDimitry Andric   }
182581ad6265SDimitry Andric #undef NODE_NAME_CASE
182681ad6265SDimitry Andric   return nullptr;
182781ad6265SDimitry Andric }
182881ad6265SDimitry Andric 
182981ad6265SDimitry Andric //===----------------------------------------------------------------------===//
183081ad6265SDimitry Andric //                     Calling Convention Implementation
183181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1832*bdd1243dSDimitry Andric 
1833*bdd1243dSDimitry Andric // Eight general-purpose registers a0-a7 used for passing integer arguments,
1834*bdd1243dSDimitry Andric // with a0-a1 reused to return values. Generally, the GPRs are used to pass
1835*bdd1243dSDimitry Andric // fixed-point arguments, and floating-point arguments when no FPR is available
1836*bdd1243dSDimitry Andric // or with soft float ABI.
183781ad6265SDimitry Andric const MCPhysReg ArgGPRs[] = {LoongArch::R4,  LoongArch::R5, LoongArch::R6,
183881ad6265SDimitry Andric                              LoongArch::R7,  LoongArch::R8, LoongArch::R9,
183981ad6265SDimitry Andric                              LoongArch::R10, LoongArch::R11};
1840*bdd1243dSDimitry Andric // Eight floating-point registers fa0-fa7 used for passing floating-point
1841*bdd1243dSDimitry Andric // arguments, and fa0-fa1 are also used to return values.
184281ad6265SDimitry Andric const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
184381ad6265SDimitry Andric                                LoongArch::F3, LoongArch::F4, LoongArch::F5,
184481ad6265SDimitry Andric                                LoongArch::F6, LoongArch::F7};
1845*bdd1243dSDimitry Andric // FPR32 and FPR64 alias each other.
184681ad6265SDimitry Andric const MCPhysReg ArgFPR64s[] = {
184781ad6265SDimitry Andric     LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
184881ad6265SDimitry Andric     LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
184981ad6265SDimitry Andric 
1850*bdd1243dSDimitry Andric // Pass a 2*GRLen argument that has been split into two GRLen values through
1851*bdd1243dSDimitry Andric // registers or the stack as necessary.
1852*bdd1243dSDimitry Andric static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
1853*bdd1243dSDimitry Andric                                      CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
1854*bdd1243dSDimitry Andric                                      unsigned ValNo2, MVT ValVT2, MVT LocVT2,
1855*bdd1243dSDimitry Andric                                      ISD::ArgFlagsTy ArgFlags2) {
1856*bdd1243dSDimitry Andric   unsigned GRLenInBytes = GRLen / 8;
1857*bdd1243dSDimitry Andric   if (Register Reg = State.AllocateReg(ArgGPRs)) {
1858*bdd1243dSDimitry Andric     // At least one half can be passed via register.
1859*bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
1860*bdd1243dSDimitry Andric                                      VA1.getLocVT(), CCValAssign::Full));
1861*bdd1243dSDimitry Andric   } else {
1862*bdd1243dSDimitry Andric     // Both halves must be passed on the stack, with proper alignment.
1863*bdd1243dSDimitry Andric     Align StackAlign =
1864*bdd1243dSDimitry Andric         std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
1865*bdd1243dSDimitry Andric     State.addLoc(
1866*bdd1243dSDimitry Andric         CCValAssign::getMem(VA1.getValNo(), VA1.getValVT(),
1867*bdd1243dSDimitry Andric                             State.AllocateStack(GRLenInBytes, StackAlign),
1868*bdd1243dSDimitry Andric                             VA1.getLocVT(), CCValAssign::Full));
1869*bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getMem(
1870*bdd1243dSDimitry Andric         ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
1871*bdd1243dSDimitry Andric         LocVT2, CCValAssign::Full));
1872*bdd1243dSDimitry Andric     return false;
1873*bdd1243dSDimitry Andric   }
1874*bdd1243dSDimitry Andric   if (Register Reg = State.AllocateReg(ArgGPRs)) {
1875*bdd1243dSDimitry Andric     // The second half can also be passed via register.
1876*bdd1243dSDimitry Andric     State.addLoc(
1877*bdd1243dSDimitry Andric         CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
1878*bdd1243dSDimitry Andric   } else {
1879*bdd1243dSDimitry Andric     // The second half is passed via the stack, without additional alignment.
1880*bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getMem(
1881*bdd1243dSDimitry Andric         ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
1882*bdd1243dSDimitry Andric         LocVT2, CCValAssign::Full));
1883*bdd1243dSDimitry Andric   }
188481ad6265SDimitry Andric   return false;
188581ad6265SDimitry Andric }
188681ad6265SDimitry Andric 
1887*bdd1243dSDimitry Andric // Implements the LoongArch calling convention. Returns true upon failure.
1888*bdd1243dSDimitry Andric static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI,
1889*bdd1243dSDimitry Andric                          unsigned ValNo, MVT ValVT,
1890*bdd1243dSDimitry Andric                          CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
1891*bdd1243dSDimitry Andric                          CCState &State, bool IsFixed, bool IsRet,
1892*bdd1243dSDimitry Andric                          Type *OrigTy) {
1893*bdd1243dSDimitry Andric   unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
1894*bdd1243dSDimitry Andric   assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
1895*bdd1243dSDimitry Andric   MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
1896*bdd1243dSDimitry Andric   MVT LocVT = ValVT;
1897*bdd1243dSDimitry Andric 
1898*bdd1243dSDimitry Andric   // Any return value split into more than two values can't be returned
1899*bdd1243dSDimitry Andric   // directly.
1900*bdd1243dSDimitry Andric   if (IsRet && ValNo > 1)
190181ad6265SDimitry Andric     return true;
1902*bdd1243dSDimitry Andric 
1903*bdd1243dSDimitry Andric   // If passing a variadic argument, or if no FPR is available.
1904*bdd1243dSDimitry Andric   bool UseGPRForFloat = true;
1905*bdd1243dSDimitry Andric 
1906*bdd1243dSDimitry Andric   switch (ABI) {
1907*bdd1243dSDimitry Andric   default:
1908*bdd1243dSDimitry Andric     llvm_unreachable("Unexpected ABI");
1909*bdd1243dSDimitry Andric   case LoongArchABI::ABI_ILP32S:
1910*bdd1243dSDimitry Andric   case LoongArchABI::ABI_LP64S:
1911*bdd1243dSDimitry Andric   case LoongArchABI::ABI_ILP32F:
1912*bdd1243dSDimitry Andric   case LoongArchABI::ABI_LP64F:
1913*bdd1243dSDimitry Andric     report_fatal_error("Unimplemented ABI");
1914*bdd1243dSDimitry Andric     break;
1915*bdd1243dSDimitry Andric   case LoongArchABI::ABI_ILP32D:
1916*bdd1243dSDimitry Andric   case LoongArchABI::ABI_LP64D:
1917*bdd1243dSDimitry Andric     UseGPRForFloat = !IsFixed;
1918*bdd1243dSDimitry Andric     break;
1919*bdd1243dSDimitry Andric   }
1920*bdd1243dSDimitry Andric 
1921*bdd1243dSDimitry Andric   // FPR32 and FPR64 alias each other.
1922*bdd1243dSDimitry Andric   if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
1923*bdd1243dSDimitry Andric     UseGPRForFloat = true;
1924*bdd1243dSDimitry Andric 
1925*bdd1243dSDimitry Andric   if (UseGPRForFloat && ValVT == MVT::f32) {
1926*bdd1243dSDimitry Andric     LocVT = GRLenVT;
1927*bdd1243dSDimitry Andric     LocInfo = CCValAssign::BCvt;
1928*bdd1243dSDimitry Andric   } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
1929*bdd1243dSDimitry Andric     LocVT = MVT::i64;
1930*bdd1243dSDimitry Andric     LocInfo = CCValAssign::BCvt;
1931*bdd1243dSDimitry Andric   } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
1932*bdd1243dSDimitry Andric     // TODO: Handle passing f64 on LA32 with D feature.
1933*bdd1243dSDimitry Andric     report_fatal_error("Passing f64 with GPR on LA32 is undefined");
1934*bdd1243dSDimitry Andric   }
1935*bdd1243dSDimitry Andric 
1936*bdd1243dSDimitry Andric   // If this is a variadic argument, the LoongArch calling convention requires
1937*bdd1243dSDimitry Andric   // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
1938*bdd1243dSDimitry Andric   // byte alignment. An aligned register should be used regardless of whether
1939*bdd1243dSDimitry Andric   // the original argument was split during legalisation or not. The argument
1940*bdd1243dSDimitry Andric   // will not be passed by registers if the original type is larger than
1941*bdd1243dSDimitry Andric   // 2*GRLen, so the register alignment rule does not apply.
1942*bdd1243dSDimitry Andric   unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
1943*bdd1243dSDimitry Andric   if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
1944*bdd1243dSDimitry Andric       DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
1945*bdd1243dSDimitry Andric     unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
1946*bdd1243dSDimitry Andric     // Skip 'odd' register if necessary.
1947*bdd1243dSDimitry Andric     if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
1948*bdd1243dSDimitry Andric       State.AllocateReg(ArgGPRs);
1949*bdd1243dSDimitry Andric   }
1950*bdd1243dSDimitry Andric 
1951*bdd1243dSDimitry Andric   SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
1952*bdd1243dSDimitry Andric   SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
1953*bdd1243dSDimitry Andric       State.getPendingArgFlags();
1954*bdd1243dSDimitry Andric 
1955*bdd1243dSDimitry Andric   assert(PendingLocs.size() == PendingArgFlags.size() &&
1956*bdd1243dSDimitry Andric          "PendingLocs and PendingArgFlags out of sync");
1957*bdd1243dSDimitry Andric 
1958*bdd1243dSDimitry Andric   // Split arguments might be passed indirectly, so keep track of the pending
1959*bdd1243dSDimitry Andric   // values.
1960*bdd1243dSDimitry Andric   if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
1961*bdd1243dSDimitry Andric     LocVT = GRLenVT;
1962*bdd1243dSDimitry Andric     LocInfo = CCValAssign::Indirect;
1963*bdd1243dSDimitry Andric     PendingLocs.push_back(
1964*bdd1243dSDimitry Andric         CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
1965*bdd1243dSDimitry Andric     PendingArgFlags.push_back(ArgFlags);
1966*bdd1243dSDimitry Andric     if (!ArgFlags.isSplitEnd()) {
1967*bdd1243dSDimitry Andric       return false;
1968*bdd1243dSDimitry Andric     }
1969*bdd1243dSDimitry Andric   }
1970*bdd1243dSDimitry Andric 
1971*bdd1243dSDimitry Andric   // If the split argument only had two elements, it should be passed directly
1972*bdd1243dSDimitry Andric   // in registers or on the stack.
1973*bdd1243dSDimitry Andric   if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
1974*bdd1243dSDimitry Andric       PendingLocs.size() <= 2) {
1975*bdd1243dSDimitry Andric     assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
1976*bdd1243dSDimitry Andric     // Apply the normal calling convention rules to the first half of the
1977*bdd1243dSDimitry Andric     // split argument.
1978*bdd1243dSDimitry Andric     CCValAssign VA = PendingLocs[0];
1979*bdd1243dSDimitry Andric     ISD::ArgFlagsTy AF = PendingArgFlags[0];
1980*bdd1243dSDimitry Andric     PendingLocs.clear();
1981*bdd1243dSDimitry Andric     PendingArgFlags.clear();
1982*bdd1243dSDimitry Andric     return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
1983*bdd1243dSDimitry Andric                                     ArgFlags);
1984*bdd1243dSDimitry Andric   }
1985*bdd1243dSDimitry Andric 
1986*bdd1243dSDimitry Andric   // Allocate to a register if possible, or else a stack slot.
1987*bdd1243dSDimitry Andric   Register Reg;
1988*bdd1243dSDimitry Andric   unsigned StoreSizeBytes = GRLen / 8;
1989*bdd1243dSDimitry Andric   Align StackAlign = Align(GRLen / 8);
1990*bdd1243dSDimitry Andric 
1991*bdd1243dSDimitry Andric   if (ValVT == MVT::f32 && !UseGPRForFloat)
1992*bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgFPR32s);
1993*bdd1243dSDimitry Andric   else if (ValVT == MVT::f64 && !UseGPRForFloat)
1994*bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgFPR64s);
1995*bdd1243dSDimitry Andric   else
1996*bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgGPRs);
1997*bdd1243dSDimitry Andric 
1998*bdd1243dSDimitry Andric   unsigned StackOffset =
1999*bdd1243dSDimitry Andric       Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
2000*bdd1243dSDimitry Andric 
2001*bdd1243dSDimitry Andric   // If we reach this point and PendingLocs is non-empty, we must be at the
2002*bdd1243dSDimitry Andric   // end of a split argument that must be passed indirectly.
2003*bdd1243dSDimitry Andric   if (!PendingLocs.empty()) {
2004*bdd1243dSDimitry Andric     assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
2005*bdd1243dSDimitry Andric     assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
2006*bdd1243dSDimitry Andric     for (auto &It : PendingLocs) {
2007*bdd1243dSDimitry Andric       if (Reg)
2008*bdd1243dSDimitry Andric         It.convertToReg(Reg);
2009*bdd1243dSDimitry Andric       else
2010*bdd1243dSDimitry Andric         It.convertToMem(StackOffset);
2011*bdd1243dSDimitry Andric       State.addLoc(It);
2012*bdd1243dSDimitry Andric     }
2013*bdd1243dSDimitry Andric     PendingLocs.clear();
2014*bdd1243dSDimitry Andric     PendingArgFlags.clear();
2015*bdd1243dSDimitry Andric     return false;
2016*bdd1243dSDimitry Andric   }
2017*bdd1243dSDimitry Andric   assert((!UseGPRForFloat || LocVT == GRLenVT) &&
2018*bdd1243dSDimitry Andric          "Expected an GRLenVT at this stage");
2019*bdd1243dSDimitry Andric 
2020*bdd1243dSDimitry Andric   if (Reg) {
2021*bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2022*bdd1243dSDimitry Andric     return false;
2023*bdd1243dSDimitry Andric   }
2024*bdd1243dSDimitry Andric 
2025*bdd1243dSDimitry Andric   // When a floating-point value is passed on the stack, no bit-cast is needed.
2026*bdd1243dSDimitry Andric   if (ValVT.isFloatingPoint()) {
2027*bdd1243dSDimitry Andric     LocVT = ValVT;
2028*bdd1243dSDimitry Andric     LocInfo = CCValAssign::Full;
2029*bdd1243dSDimitry Andric   }
2030*bdd1243dSDimitry Andric 
2031*bdd1243dSDimitry Andric   State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
2032*bdd1243dSDimitry Andric   return false;
203381ad6265SDimitry Andric }
203481ad6265SDimitry Andric 
203581ad6265SDimitry Andric void LoongArchTargetLowering::analyzeInputArgs(
2036*bdd1243dSDimitry Andric     MachineFunction &MF, CCState &CCInfo,
2037*bdd1243dSDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
203881ad6265SDimitry Andric     LoongArchCCAssignFn Fn) const {
2039*bdd1243dSDimitry Andric   FunctionType *FType = MF.getFunction().getFunctionType();
204081ad6265SDimitry Andric   for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
204181ad6265SDimitry Andric     MVT ArgVT = Ins[i].VT;
2042*bdd1243dSDimitry Andric     Type *ArgTy = nullptr;
2043*bdd1243dSDimitry Andric     if (IsRet)
2044*bdd1243dSDimitry Andric       ArgTy = FType->getReturnType();
2045*bdd1243dSDimitry Andric     else if (Ins[i].isOrigArg())
2046*bdd1243dSDimitry Andric       ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
2047*bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
2048*bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2049*bdd1243dSDimitry Andric     if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
2050*bdd1243dSDimitry Andric            CCInfo, /*IsFixed=*/true, IsRet, ArgTy)) {
205181ad6265SDimitry Andric       LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type "
205281ad6265SDimitry Andric                         << EVT(ArgVT).getEVTString() << '\n');
205381ad6265SDimitry Andric       llvm_unreachable("");
205481ad6265SDimitry Andric     }
205581ad6265SDimitry Andric   }
205681ad6265SDimitry Andric }
205781ad6265SDimitry Andric 
205881ad6265SDimitry Andric void LoongArchTargetLowering::analyzeOutputArgs(
2059*bdd1243dSDimitry Andric     MachineFunction &MF, CCState &CCInfo,
2060*bdd1243dSDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
2061*bdd1243dSDimitry Andric     CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
206281ad6265SDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
206381ad6265SDimitry Andric     MVT ArgVT = Outs[i].VT;
2064*bdd1243dSDimitry Andric     Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
2065*bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
2066*bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2067*bdd1243dSDimitry Andric     if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
2068*bdd1243dSDimitry Andric            CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) {
206981ad6265SDimitry Andric       LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type "
207081ad6265SDimitry Andric                         << EVT(ArgVT).getEVTString() << "\n");
207181ad6265SDimitry Andric       llvm_unreachable("");
207281ad6265SDimitry Andric     }
207381ad6265SDimitry Andric   }
207481ad6265SDimitry Andric }
207581ad6265SDimitry Andric 
2076*bdd1243dSDimitry Andric // Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
2077*bdd1243dSDimitry Andric // values.
2078*bdd1243dSDimitry Andric static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val,
2079*bdd1243dSDimitry Andric                                    const CCValAssign &VA, const SDLoc &DL) {
2080*bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
2081*bdd1243dSDimitry Andric   default:
2082*bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
2083*bdd1243dSDimitry Andric   case CCValAssign::Full:
2084*bdd1243dSDimitry Andric   case CCValAssign::Indirect:
2085*bdd1243dSDimitry Andric     break;
2086*bdd1243dSDimitry Andric   case CCValAssign::BCvt:
2087*bdd1243dSDimitry Andric     if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
2088*bdd1243dSDimitry Andric       Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
2089*bdd1243dSDimitry Andric     else
2090*bdd1243dSDimitry Andric       Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
2091*bdd1243dSDimitry Andric     break;
2092*bdd1243dSDimitry Andric   }
2093*bdd1243dSDimitry Andric   return Val;
2094*bdd1243dSDimitry Andric }
2095*bdd1243dSDimitry Andric 
209681ad6265SDimitry Andric static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain,
209781ad6265SDimitry Andric                                 const CCValAssign &VA, const SDLoc &DL,
209881ad6265SDimitry Andric                                 const LoongArchTargetLowering &TLI) {
209981ad6265SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
210081ad6265SDimitry Andric   MachineRegisterInfo &RegInfo = MF.getRegInfo();
210181ad6265SDimitry Andric   EVT LocVT = VA.getLocVT();
2102*bdd1243dSDimitry Andric   SDValue Val;
210381ad6265SDimitry Andric   const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
210481ad6265SDimitry Andric   Register VReg = RegInfo.createVirtualRegister(RC);
210581ad6265SDimitry Andric   RegInfo.addLiveIn(VA.getLocReg(), VReg);
2106*bdd1243dSDimitry Andric   Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
210781ad6265SDimitry Andric 
2108*bdd1243dSDimitry Andric   return convertLocVTToValVT(DAG, Val, VA, DL);
2109*bdd1243dSDimitry Andric }
2110*bdd1243dSDimitry Andric 
2111*bdd1243dSDimitry Andric // The caller is responsible for loading the full value if the argument is
2112*bdd1243dSDimitry Andric // passed with CCValAssign::Indirect.
2113*bdd1243dSDimitry Andric static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain,
2114*bdd1243dSDimitry Andric                                 const CCValAssign &VA, const SDLoc &DL) {
2115*bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
2116*bdd1243dSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
2117*bdd1243dSDimitry Andric   EVT ValVT = VA.getValVT();
2118*bdd1243dSDimitry Andric   int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
2119*bdd1243dSDimitry Andric                                  /*IsImmutable=*/true);
2120*bdd1243dSDimitry Andric   SDValue FIN = DAG.getFrameIndex(
2121*bdd1243dSDimitry Andric       FI, MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0)));
2122*bdd1243dSDimitry Andric 
2123*bdd1243dSDimitry Andric   ISD::LoadExtType ExtType;
2124*bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
2125*bdd1243dSDimitry Andric   default:
2126*bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
2127*bdd1243dSDimitry Andric   case CCValAssign::Full:
2128*bdd1243dSDimitry Andric   case CCValAssign::Indirect:
2129*bdd1243dSDimitry Andric   case CCValAssign::BCvt:
2130*bdd1243dSDimitry Andric     ExtType = ISD::NON_EXTLOAD;
2131*bdd1243dSDimitry Andric     break;
2132*bdd1243dSDimitry Andric   }
2133*bdd1243dSDimitry Andric   return DAG.getExtLoad(
2134*bdd1243dSDimitry Andric       ExtType, DL, VA.getLocVT(), Chain, FIN,
2135*bdd1243dSDimitry Andric       MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT);
2136*bdd1243dSDimitry Andric }
2137*bdd1243dSDimitry Andric 
2138*bdd1243dSDimitry Andric static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
2139*bdd1243dSDimitry Andric                                    const CCValAssign &VA, const SDLoc &DL) {
2140*bdd1243dSDimitry Andric   EVT LocVT = VA.getLocVT();
2141*bdd1243dSDimitry Andric 
2142*bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
2143*bdd1243dSDimitry Andric   default:
2144*bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
2145*bdd1243dSDimitry Andric   case CCValAssign::Full:
2146*bdd1243dSDimitry Andric     break;
2147*bdd1243dSDimitry Andric   case CCValAssign::BCvt:
2148*bdd1243dSDimitry Andric     if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
2149*bdd1243dSDimitry Andric       Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
2150*bdd1243dSDimitry Andric     else
2151*bdd1243dSDimitry Andric       Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
2152*bdd1243dSDimitry Andric     break;
2153*bdd1243dSDimitry Andric   }
2154*bdd1243dSDimitry Andric   return Val;
2155*bdd1243dSDimitry Andric }
2156*bdd1243dSDimitry Andric 
2157*bdd1243dSDimitry Andric static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
2158*bdd1243dSDimitry Andric                             CCValAssign::LocInfo LocInfo,
2159*bdd1243dSDimitry Andric                             ISD::ArgFlagsTy ArgFlags, CCState &State) {
2160*bdd1243dSDimitry Andric   if (LocVT == MVT::i32 || LocVT == MVT::i64) {
2161*bdd1243dSDimitry Andric     // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
2162*bdd1243dSDimitry Andric     //                        s0    s1  s2  s3  s4  s5  s6  s7  s8
2163*bdd1243dSDimitry Andric     static const MCPhysReg GPRList[] = {
2164*bdd1243dSDimitry Andric         LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26, LoongArch::R27,
2165*bdd1243dSDimitry Andric         LoongArch::R28, LoongArch::R29, LoongArch::R30, LoongArch::R31};
2166*bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(GPRList)) {
2167*bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2168*bdd1243dSDimitry Andric       return false;
2169*bdd1243dSDimitry Andric     }
2170*bdd1243dSDimitry Andric   }
2171*bdd1243dSDimitry Andric 
2172*bdd1243dSDimitry Andric   if (LocVT == MVT::f32) {
2173*bdd1243dSDimitry Andric     // Pass in STG registers: F1, F2, F3, F4
2174*bdd1243dSDimitry Andric     //                        fs0,fs1,fs2,fs3
2175*bdd1243dSDimitry Andric     static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
2176*bdd1243dSDimitry Andric                                           LoongArch::F26, LoongArch::F27};
2177*bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(FPR32List)) {
2178*bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2179*bdd1243dSDimitry Andric       return false;
2180*bdd1243dSDimitry Andric     }
2181*bdd1243dSDimitry Andric   }
2182*bdd1243dSDimitry Andric 
2183*bdd1243dSDimitry Andric   if (LocVT == MVT::f64) {
2184*bdd1243dSDimitry Andric     // Pass in STG registers: D1, D2, D3, D4
2185*bdd1243dSDimitry Andric     //                        fs4,fs5,fs6,fs7
2186*bdd1243dSDimitry Andric     static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
2187*bdd1243dSDimitry Andric                                           LoongArch::F30_64, LoongArch::F31_64};
2188*bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(FPR64List)) {
2189*bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2190*bdd1243dSDimitry Andric       return false;
2191*bdd1243dSDimitry Andric     }
2192*bdd1243dSDimitry Andric   }
2193*bdd1243dSDimitry Andric 
2194*bdd1243dSDimitry Andric   report_fatal_error("No registers left in GHC calling convention");
2195*bdd1243dSDimitry Andric   return true;
219681ad6265SDimitry Andric }
219781ad6265SDimitry Andric 
219881ad6265SDimitry Andric // Transform physical registers into virtual registers.
219981ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerFormalArguments(
220081ad6265SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
220181ad6265SDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
220281ad6265SDimitry Andric     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
220381ad6265SDimitry Andric 
220481ad6265SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
220581ad6265SDimitry Andric 
220681ad6265SDimitry Andric   switch (CallConv) {
220781ad6265SDimitry Andric   default:
220881ad6265SDimitry Andric     llvm_unreachable("Unsupported calling convention");
220981ad6265SDimitry Andric   case CallingConv::C:
2210*bdd1243dSDimitry Andric   case CallingConv::Fast:
221181ad6265SDimitry Andric     break;
2212*bdd1243dSDimitry Andric   case CallingConv::GHC:
2213*bdd1243dSDimitry Andric     if (!MF.getSubtarget().getFeatureBits()[LoongArch::FeatureBasicF] ||
2214*bdd1243dSDimitry Andric         !MF.getSubtarget().getFeatureBits()[LoongArch::FeatureBasicD])
2215*bdd1243dSDimitry Andric       report_fatal_error(
2216*bdd1243dSDimitry Andric         "GHC calling convention requires the F and D extensions");
221781ad6265SDimitry Andric   }
221881ad6265SDimitry Andric 
2219*bdd1243dSDimitry Andric   EVT PtrVT = getPointerTy(DAG.getDataLayout());
2220*bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
2221*bdd1243dSDimitry Andric   unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
2222*bdd1243dSDimitry Andric   // Used with varargs to acumulate store chains.
2223*bdd1243dSDimitry Andric   std::vector<SDValue> OutChains;
2224*bdd1243dSDimitry Andric 
222581ad6265SDimitry Andric   // Assign locations to all of the incoming arguments.
222681ad6265SDimitry Andric   SmallVector<CCValAssign> ArgLocs;
222781ad6265SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
222881ad6265SDimitry Andric 
2229*bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC)
2230*bdd1243dSDimitry Andric     CCInfo.AnalyzeFormalArguments(Ins, CC_LoongArch_GHC);
2231*bdd1243dSDimitry Andric   else
2232*bdd1243dSDimitry Andric     analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
223381ad6265SDimitry Andric 
2234*bdd1243dSDimitry Andric   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
2235*bdd1243dSDimitry Andric     CCValAssign &VA = ArgLocs[i];
2236*bdd1243dSDimitry Andric     SDValue ArgValue;
2237*bdd1243dSDimitry Andric     if (VA.isRegLoc())
2238*bdd1243dSDimitry Andric       ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, *this);
2239*bdd1243dSDimitry Andric     else
2240*bdd1243dSDimitry Andric       ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
2241*bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect) {
2242*bdd1243dSDimitry Andric       // If the original argument was split and passed by reference, we need to
2243*bdd1243dSDimitry Andric       // load all parts of it here (using the same address).
2244*bdd1243dSDimitry Andric       InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
2245*bdd1243dSDimitry Andric                                    MachinePointerInfo()));
2246*bdd1243dSDimitry Andric       unsigned ArgIndex = Ins[i].OrigArgIndex;
2247*bdd1243dSDimitry Andric       unsigned ArgPartOffset = Ins[i].PartOffset;
2248*bdd1243dSDimitry Andric       assert(ArgPartOffset == 0);
2249*bdd1243dSDimitry Andric       while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) {
2250*bdd1243dSDimitry Andric         CCValAssign &PartVA = ArgLocs[i + 1];
2251*bdd1243dSDimitry Andric         unsigned PartOffset = Ins[i + 1].PartOffset - ArgPartOffset;
2252*bdd1243dSDimitry Andric         SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
2253*bdd1243dSDimitry Andric         SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
2254*bdd1243dSDimitry Andric         InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
2255*bdd1243dSDimitry Andric                                      MachinePointerInfo()));
2256*bdd1243dSDimitry Andric         ++i;
2257*bdd1243dSDimitry Andric       }
2258*bdd1243dSDimitry Andric       continue;
2259*bdd1243dSDimitry Andric     }
2260*bdd1243dSDimitry Andric     InVals.push_back(ArgValue);
2261*bdd1243dSDimitry Andric   }
2262*bdd1243dSDimitry Andric 
2263*bdd1243dSDimitry Andric   if (IsVarArg) {
2264*bdd1243dSDimitry Andric     ArrayRef<MCPhysReg> ArgRegs = ArrayRef(ArgGPRs);
2265*bdd1243dSDimitry Andric     unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
2266*bdd1243dSDimitry Andric     const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
2267*bdd1243dSDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
2268*bdd1243dSDimitry Andric     MachineRegisterInfo &RegInfo = MF.getRegInfo();
2269*bdd1243dSDimitry Andric     auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
2270*bdd1243dSDimitry Andric 
2271*bdd1243dSDimitry Andric     // Offset of the first variable argument from stack pointer, and size of
2272*bdd1243dSDimitry Andric     // the vararg save area. For now, the varargs save area is either zero or
2273*bdd1243dSDimitry Andric     // large enough to hold a0-a7.
2274*bdd1243dSDimitry Andric     int VaArgOffset, VarArgsSaveSize;
2275*bdd1243dSDimitry Andric 
2276*bdd1243dSDimitry Andric     // If all registers are allocated, then all varargs must be passed on the
2277*bdd1243dSDimitry Andric     // stack and we don't need to save any argregs.
2278*bdd1243dSDimitry Andric     if (ArgRegs.size() == Idx) {
2279*bdd1243dSDimitry Andric       VaArgOffset = CCInfo.getNextStackOffset();
2280*bdd1243dSDimitry Andric       VarArgsSaveSize = 0;
2281*bdd1243dSDimitry Andric     } else {
2282*bdd1243dSDimitry Andric       VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
2283*bdd1243dSDimitry Andric       VaArgOffset = -VarArgsSaveSize;
2284*bdd1243dSDimitry Andric     }
2285*bdd1243dSDimitry Andric 
2286*bdd1243dSDimitry Andric     // Record the frame index of the first variable argument
2287*bdd1243dSDimitry Andric     // which is a value necessary to VASTART.
2288*bdd1243dSDimitry Andric     int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
2289*bdd1243dSDimitry Andric     LoongArchFI->setVarArgsFrameIndex(FI);
2290*bdd1243dSDimitry Andric 
2291*bdd1243dSDimitry Andric     // If saving an odd number of registers then create an extra stack slot to
2292*bdd1243dSDimitry Andric     // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
2293*bdd1243dSDimitry Andric     // offsets to even-numbered registered remain 2*GRLen-aligned.
2294*bdd1243dSDimitry Andric     if (Idx % 2) {
2295*bdd1243dSDimitry Andric       MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
2296*bdd1243dSDimitry Andric                             true);
2297*bdd1243dSDimitry Andric       VarArgsSaveSize += GRLenInBytes;
2298*bdd1243dSDimitry Andric     }
2299*bdd1243dSDimitry Andric 
2300*bdd1243dSDimitry Andric     // Copy the integer registers that may have been used for passing varargs
2301*bdd1243dSDimitry Andric     // to the vararg save area.
2302*bdd1243dSDimitry Andric     for (unsigned I = Idx; I < ArgRegs.size();
2303*bdd1243dSDimitry Andric          ++I, VaArgOffset += GRLenInBytes) {
2304*bdd1243dSDimitry Andric       const Register Reg = RegInfo.createVirtualRegister(RC);
2305*bdd1243dSDimitry Andric       RegInfo.addLiveIn(ArgRegs[I], Reg);
2306*bdd1243dSDimitry Andric       SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
2307*bdd1243dSDimitry Andric       FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
2308*bdd1243dSDimitry Andric       SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
2309*bdd1243dSDimitry Andric       SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
2310*bdd1243dSDimitry Andric                                    MachinePointerInfo::getFixedStack(MF, FI));
2311*bdd1243dSDimitry Andric       cast<StoreSDNode>(Store.getNode())
2312*bdd1243dSDimitry Andric           ->getMemOperand()
2313*bdd1243dSDimitry Andric           ->setValue((Value *)nullptr);
2314*bdd1243dSDimitry Andric       OutChains.push_back(Store);
2315*bdd1243dSDimitry Andric     }
2316*bdd1243dSDimitry Andric     LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
2317*bdd1243dSDimitry Andric   }
2318*bdd1243dSDimitry Andric 
2319*bdd1243dSDimitry Andric   // All stores are grouped in one node to allow the matching between
2320*bdd1243dSDimitry Andric   // the size of Ins and InVals. This only happens for vararg functions.
2321*bdd1243dSDimitry Andric   if (!OutChains.empty()) {
2322*bdd1243dSDimitry Andric     OutChains.push_back(Chain);
2323*bdd1243dSDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
2324*bdd1243dSDimitry Andric   }
232581ad6265SDimitry Andric 
232681ad6265SDimitry Andric   return Chain;
232781ad6265SDimitry Andric }
232881ad6265SDimitry Andric 
2329*bdd1243dSDimitry Andric bool LoongArchTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
2330*bdd1243dSDimitry Andric   return CI->isTailCall();
2331*bdd1243dSDimitry Andric }
2332*bdd1243dSDimitry Andric 
2333*bdd1243dSDimitry Andric // Check whether the call is eligible for tail call optimization.
2334*bdd1243dSDimitry Andric bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
2335*bdd1243dSDimitry Andric     CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
2336*bdd1243dSDimitry Andric     const SmallVectorImpl<CCValAssign> &ArgLocs) const {
2337*bdd1243dSDimitry Andric 
2338*bdd1243dSDimitry Andric   auto CalleeCC = CLI.CallConv;
2339*bdd1243dSDimitry Andric   auto &Outs = CLI.Outs;
2340*bdd1243dSDimitry Andric   auto &Caller = MF.getFunction();
2341*bdd1243dSDimitry Andric   auto CallerCC = Caller.getCallingConv();
2342*bdd1243dSDimitry Andric 
2343*bdd1243dSDimitry Andric   // Do not tail call opt if the stack is used to pass parameters.
2344*bdd1243dSDimitry Andric   if (CCInfo.getNextStackOffset() != 0)
2345*bdd1243dSDimitry Andric     return false;
2346*bdd1243dSDimitry Andric 
2347*bdd1243dSDimitry Andric   // Do not tail call opt if any parameters need to be passed indirectly.
2348*bdd1243dSDimitry Andric   for (auto &VA : ArgLocs)
2349*bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect)
2350*bdd1243dSDimitry Andric       return false;
2351*bdd1243dSDimitry Andric 
2352*bdd1243dSDimitry Andric   // Do not tail call opt if either caller or callee uses struct return
2353*bdd1243dSDimitry Andric   // semantics.
2354*bdd1243dSDimitry Andric   auto IsCallerStructRet = Caller.hasStructRetAttr();
2355*bdd1243dSDimitry Andric   auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
2356*bdd1243dSDimitry Andric   if (IsCallerStructRet || IsCalleeStructRet)
2357*bdd1243dSDimitry Andric     return false;
2358*bdd1243dSDimitry Andric 
2359*bdd1243dSDimitry Andric   // Do not tail call opt if either the callee or caller has a byval argument.
2360*bdd1243dSDimitry Andric   for (auto &Arg : Outs)
2361*bdd1243dSDimitry Andric     if (Arg.Flags.isByVal())
2362*bdd1243dSDimitry Andric       return false;
2363*bdd1243dSDimitry Andric 
2364*bdd1243dSDimitry Andric   // The callee has to preserve all registers the caller needs to preserve.
2365*bdd1243dSDimitry Andric   const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
2366*bdd1243dSDimitry Andric   const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
2367*bdd1243dSDimitry Andric   if (CalleeCC != CallerCC) {
2368*bdd1243dSDimitry Andric     const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
2369*bdd1243dSDimitry Andric     if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
2370*bdd1243dSDimitry Andric       return false;
2371*bdd1243dSDimitry Andric   }
2372*bdd1243dSDimitry Andric   return true;
2373*bdd1243dSDimitry Andric }
2374*bdd1243dSDimitry Andric 
2375*bdd1243dSDimitry Andric static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG) {
2376*bdd1243dSDimitry Andric   return DAG.getDataLayout().getPrefTypeAlign(
2377*bdd1243dSDimitry Andric       VT.getTypeForEVT(*DAG.getContext()));
2378*bdd1243dSDimitry Andric }
2379*bdd1243dSDimitry Andric 
2380753f127fSDimitry Andric // Lower a call to a callseq_start + CALL + callseq_end chain, and add input
2381753f127fSDimitry Andric // and output parameter nodes.
2382753f127fSDimitry Andric SDValue
2383753f127fSDimitry Andric LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
2384753f127fSDimitry Andric                                    SmallVectorImpl<SDValue> &InVals) const {
2385753f127fSDimitry Andric   SelectionDAG &DAG = CLI.DAG;
2386753f127fSDimitry Andric   SDLoc &DL = CLI.DL;
2387753f127fSDimitry Andric   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
2388753f127fSDimitry Andric   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
2389753f127fSDimitry Andric   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
2390753f127fSDimitry Andric   SDValue Chain = CLI.Chain;
2391753f127fSDimitry Andric   SDValue Callee = CLI.Callee;
2392753f127fSDimitry Andric   CallingConv::ID CallConv = CLI.CallConv;
2393753f127fSDimitry Andric   bool IsVarArg = CLI.IsVarArg;
2394753f127fSDimitry Andric   EVT PtrVT = getPointerTy(DAG.getDataLayout());
2395*bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
2396*bdd1243dSDimitry Andric   bool &IsTailCall = CLI.IsTailCall;
2397753f127fSDimitry Andric 
2398753f127fSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
2399753f127fSDimitry Andric 
2400753f127fSDimitry Andric   // Analyze the operands of the call, assigning locations to each operand.
2401753f127fSDimitry Andric   SmallVector<CCValAssign> ArgLocs;
2402753f127fSDimitry Andric   CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
2403753f127fSDimitry Andric 
2404*bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC)
2405*bdd1243dSDimitry Andric     ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
2406*bdd1243dSDimitry Andric   else
2407*bdd1243dSDimitry Andric     analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
2408*bdd1243dSDimitry Andric 
2409*bdd1243dSDimitry Andric   // Check if it's really possible to do a tail call.
2410*bdd1243dSDimitry Andric   if (IsTailCall)
2411*bdd1243dSDimitry Andric     IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
2412*bdd1243dSDimitry Andric 
2413*bdd1243dSDimitry Andric   if (IsTailCall)
2414*bdd1243dSDimitry Andric     ++NumTailCalls;
2415*bdd1243dSDimitry Andric   else if (CLI.CB && CLI.CB->isMustTailCall())
2416*bdd1243dSDimitry Andric     report_fatal_error("failed to perform tail call elimination on a call "
2417*bdd1243dSDimitry Andric                        "site marked musttail");
2418753f127fSDimitry Andric 
2419753f127fSDimitry Andric   // Get a count of how many bytes are to be pushed on the stack.
2420753f127fSDimitry Andric   unsigned NumBytes = ArgCCInfo.getNextStackOffset();
2421753f127fSDimitry Andric 
2422*bdd1243dSDimitry Andric   // Create local copies for byval args.
2423*bdd1243dSDimitry Andric   SmallVector<SDValue> ByValArgs;
2424*bdd1243dSDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2425*bdd1243dSDimitry Andric     ISD::ArgFlagsTy Flags = Outs[i].Flags;
2426*bdd1243dSDimitry Andric     if (!Flags.isByVal())
2427753f127fSDimitry Andric       continue;
2428*bdd1243dSDimitry Andric 
2429*bdd1243dSDimitry Andric     SDValue Arg = OutVals[i];
2430*bdd1243dSDimitry Andric     unsigned Size = Flags.getByValSize();
2431*bdd1243dSDimitry Andric     Align Alignment = Flags.getNonZeroByValAlign();
2432*bdd1243dSDimitry Andric 
2433*bdd1243dSDimitry Andric     int FI =
2434*bdd1243dSDimitry Andric         MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
2435*bdd1243dSDimitry Andric     SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
2436*bdd1243dSDimitry Andric     SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
2437*bdd1243dSDimitry Andric 
2438*bdd1243dSDimitry Andric     Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment,
2439*bdd1243dSDimitry Andric                           /*IsVolatile=*/false,
2440*bdd1243dSDimitry Andric                           /*AlwaysInline=*/false, /*isTailCall=*/IsTailCall,
2441*bdd1243dSDimitry Andric                           MachinePointerInfo(), MachinePointerInfo());
2442*bdd1243dSDimitry Andric     ByValArgs.push_back(FIPtr);
2443753f127fSDimitry Andric   }
2444753f127fSDimitry Andric 
2445*bdd1243dSDimitry Andric   if (!IsTailCall)
2446753f127fSDimitry Andric     Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
2447753f127fSDimitry Andric 
2448753f127fSDimitry Andric   // Copy argument values to their designated locations.
2449753f127fSDimitry Andric   SmallVector<std::pair<Register, SDValue>> RegsToPass;
2450*bdd1243dSDimitry Andric   SmallVector<SDValue> MemOpChains;
2451*bdd1243dSDimitry Andric   SDValue StackPtr;
2452*bdd1243dSDimitry Andric   for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) {
2453753f127fSDimitry Andric     CCValAssign &VA = ArgLocs[i];
2454753f127fSDimitry Andric     SDValue ArgValue = OutVals[i];
2455*bdd1243dSDimitry Andric     ISD::ArgFlagsTy Flags = Outs[i].Flags;
2456753f127fSDimitry Andric 
2457753f127fSDimitry Andric     // Promote the value if needed.
2458*bdd1243dSDimitry Andric     // For now, only handle fully promoted and indirect arguments.
2459*bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect) {
2460*bdd1243dSDimitry Andric       // Store the argument in a stack slot and pass its address.
2461*bdd1243dSDimitry Andric       Align StackAlign =
2462*bdd1243dSDimitry Andric           std::max(getPrefTypeAlign(Outs[i].ArgVT, DAG),
2463*bdd1243dSDimitry Andric                    getPrefTypeAlign(ArgValue.getValueType(), DAG));
2464*bdd1243dSDimitry Andric       TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
2465*bdd1243dSDimitry Andric       // If the original argument was split and passed by reference, we need to
2466*bdd1243dSDimitry Andric       // store the required parts of it here (and pass just one address).
2467*bdd1243dSDimitry Andric       unsigned ArgIndex = Outs[i].OrigArgIndex;
2468*bdd1243dSDimitry Andric       unsigned ArgPartOffset = Outs[i].PartOffset;
2469*bdd1243dSDimitry Andric       assert(ArgPartOffset == 0);
2470*bdd1243dSDimitry Andric       // Calculate the total size to store. We don't have access to what we're
2471*bdd1243dSDimitry Andric       // actually storing other than performing the loop and collecting the
2472*bdd1243dSDimitry Andric       // info.
2473*bdd1243dSDimitry Andric       SmallVector<std::pair<SDValue, SDValue>> Parts;
2474*bdd1243dSDimitry Andric       while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) {
2475*bdd1243dSDimitry Andric         SDValue PartValue = OutVals[i + 1];
2476*bdd1243dSDimitry Andric         unsigned PartOffset = Outs[i + 1].PartOffset - ArgPartOffset;
2477*bdd1243dSDimitry Andric         SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
2478*bdd1243dSDimitry Andric         EVT PartVT = PartValue.getValueType();
2479*bdd1243dSDimitry Andric 
2480*bdd1243dSDimitry Andric         StoredSize += PartVT.getStoreSize();
2481*bdd1243dSDimitry Andric         StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
2482*bdd1243dSDimitry Andric         Parts.push_back(std::make_pair(PartValue, Offset));
2483*bdd1243dSDimitry Andric         ++i;
2484*bdd1243dSDimitry Andric       }
2485*bdd1243dSDimitry Andric       SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
2486*bdd1243dSDimitry Andric       int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
2487*bdd1243dSDimitry Andric       MemOpChains.push_back(
2488*bdd1243dSDimitry Andric           DAG.getStore(Chain, DL, ArgValue, SpillSlot,
2489*bdd1243dSDimitry Andric                        MachinePointerInfo::getFixedStack(MF, FI)));
2490*bdd1243dSDimitry Andric       for (const auto &Part : Parts) {
2491*bdd1243dSDimitry Andric         SDValue PartValue = Part.first;
2492*bdd1243dSDimitry Andric         SDValue PartOffset = Part.second;
2493*bdd1243dSDimitry Andric         SDValue Address =
2494*bdd1243dSDimitry Andric             DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
2495*bdd1243dSDimitry Andric         MemOpChains.push_back(
2496*bdd1243dSDimitry Andric             DAG.getStore(Chain, DL, PartValue, Address,
2497*bdd1243dSDimitry Andric                          MachinePointerInfo::getFixedStack(MF, FI)));
2498*bdd1243dSDimitry Andric       }
2499*bdd1243dSDimitry Andric       ArgValue = SpillSlot;
2500*bdd1243dSDimitry Andric     } else {
2501*bdd1243dSDimitry Andric       ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
2502*bdd1243dSDimitry Andric     }
2503*bdd1243dSDimitry Andric 
2504*bdd1243dSDimitry Andric     // Use local copy if it is a byval arg.
2505*bdd1243dSDimitry Andric     if (Flags.isByVal())
2506*bdd1243dSDimitry Andric       ArgValue = ByValArgs[j++];
2507753f127fSDimitry Andric 
2508753f127fSDimitry Andric     if (VA.isRegLoc()) {
2509753f127fSDimitry Andric       // Queue up the argument copies and emit them at the end.
2510753f127fSDimitry Andric       RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
2511753f127fSDimitry Andric     } else {
2512*bdd1243dSDimitry Andric       assert(VA.isMemLoc() && "Argument not register or memory");
2513*bdd1243dSDimitry Andric       assert(!IsTailCall && "Tail call not allowed if stack is used "
2514*bdd1243dSDimitry Andric                             "for passing parameters");
2515*bdd1243dSDimitry Andric 
2516*bdd1243dSDimitry Andric       // Work out the address of the stack slot.
2517*bdd1243dSDimitry Andric       if (!StackPtr.getNode())
2518*bdd1243dSDimitry Andric         StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
2519*bdd1243dSDimitry Andric       SDValue Address =
2520*bdd1243dSDimitry Andric           DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
2521*bdd1243dSDimitry Andric                       DAG.getIntPtrConstant(VA.getLocMemOffset(), DL));
2522*bdd1243dSDimitry Andric 
2523*bdd1243dSDimitry Andric       // Emit the store.
2524*bdd1243dSDimitry Andric       MemOpChains.push_back(
2525*bdd1243dSDimitry Andric           DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
2526753f127fSDimitry Andric     }
2527753f127fSDimitry Andric   }
2528753f127fSDimitry Andric 
2529*bdd1243dSDimitry Andric   // Join the stores, which are independent of one another.
2530*bdd1243dSDimitry Andric   if (!MemOpChains.empty())
2531*bdd1243dSDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
2532*bdd1243dSDimitry Andric 
2533753f127fSDimitry Andric   SDValue Glue;
2534753f127fSDimitry Andric 
2535753f127fSDimitry Andric   // Build a sequence of copy-to-reg nodes, chained and glued together.
2536753f127fSDimitry Andric   for (auto &Reg : RegsToPass) {
2537753f127fSDimitry Andric     Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
2538753f127fSDimitry Andric     Glue = Chain.getValue(1);
2539753f127fSDimitry Andric   }
2540753f127fSDimitry Andric 
2541753f127fSDimitry Andric   // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
2542753f127fSDimitry Andric   // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
2543753f127fSDimitry Andric   // split it and then direct call can be matched by PseudoCALL.
2544*bdd1243dSDimitry Andric   if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
2545*bdd1243dSDimitry Andric     const GlobalValue *GV = S->getGlobal();
2546*bdd1243dSDimitry Andric     unsigned OpFlags =
2547*bdd1243dSDimitry Andric         getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)
2548*bdd1243dSDimitry Andric             ? LoongArchII::MO_CALL
2549*bdd1243dSDimitry Andric             : LoongArchII::MO_CALL_PLT;
2550*bdd1243dSDimitry Andric     Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
2551*bdd1243dSDimitry Andric   } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
2552*bdd1243dSDimitry Andric     unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(
2553*bdd1243dSDimitry Andric                            *MF.getFunction().getParent(), nullptr)
2554*bdd1243dSDimitry Andric                            ? LoongArchII::MO_CALL
2555*bdd1243dSDimitry Andric                            : LoongArchII::MO_CALL_PLT;
2556*bdd1243dSDimitry Andric     Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
2557*bdd1243dSDimitry Andric   }
2558753f127fSDimitry Andric 
2559753f127fSDimitry Andric   // The first call operand is the chain and the second is the target address.
2560753f127fSDimitry Andric   SmallVector<SDValue> Ops;
2561753f127fSDimitry Andric   Ops.push_back(Chain);
2562753f127fSDimitry Andric   Ops.push_back(Callee);
2563753f127fSDimitry Andric 
2564753f127fSDimitry Andric   // Add argument registers to the end of the list so that they are
2565753f127fSDimitry Andric   // known live into the call.
2566753f127fSDimitry Andric   for (auto &Reg : RegsToPass)
2567753f127fSDimitry Andric     Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
2568753f127fSDimitry Andric 
2569*bdd1243dSDimitry Andric   if (!IsTailCall) {
2570753f127fSDimitry Andric     // Add a register mask operand representing the call-preserved registers.
2571753f127fSDimitry Andric     const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
2572753f127fSDimitry Andric     const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
2573753f127fSDimitry Andric     assert(Mask && "Missing call preserved mask for calling convention");
2574753f127fSDimitry Andric     Ops.push_back(DAG.getRegisterMask(Mask));
2575*bdd1243dSDimitry Andric   }
2576753f127fSDimitry Andric 
2577753f127fSDimitry Andric   // Glue the call to the argument copies, if any.
2578753f127fSDimitry Andric   if (Glue.getNode())
2579753f127fSDimitry Andric     Ops.push_back(Glue);
2580753f127fSDimitry Andric 
2581753f127fSDimitry Andric   // Emit the call.
2582753f127fSDimitry Andric   SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
2583753f127fSDimitry Andric 
2584*bdd1243dSDimitry Andric   if (IsTailCall) {
2585*bdd1243dSDimitry Andric     MF.getFrameInfo().setHasTailCall();
2586*bdd1243dSDimitry Andric     return DAG.getNode(LoongArchISD::TAIL, DL, NodeTys, Ops);
2587*bdd1243dSDimitry Andric   }
2588*bdd1243dSDimitry Andric 
2589753f127fSDimitry Andric   Chain = DAG.getNode(LoongArchISD::CALL, DL, NodeTys, Ops);
2590753f127fSDimitry Andric   DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
2591753f127fSDimitry Andric   Glue = Chain.getValue(1);
2592753f127fSDimitry Andric 
2593753f127fSDimitry Andric   // Mark the end of the call, which is glued to the call itself.
2594*bdd1243dSDimitry Andric   Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
2595753f127fSDimitry Andric   Glue = Chain.getValue(1);
2596753f127fSDimitry Andric 
2597753f127fSDimitry Andric   // Assign locations to each value returned by this call.
2598753f127fSDimitry Andric   SmallVector<CCValAssign> RVLocs;
2599753f127fSDimitry Andric   CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
2600*bdd1243dSDimitry Andric   analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
2601753f127fSDimitry Andric 
2602753f127fSDimitry Andric   // Copy all of the result registers out of their specified physreg.
2603753f127fSDimitry Andric   for (auto &VA : RVLocs) {
2604753f127fSDimitry Andric     // Copy the value out.
2605753f127fSDimitry Andric     SDValue RetValue =
2606753f127fSDimitry Andric         DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
2607*bdd1243dSDimitry Andric     // Glue the RetValue to the end of the call sequence.
2608753f127fSDimitry Andric     Chain = RetValue.getValue(1);
2609753f127fSDimitry Andric     Glue = RetValue.getValue(2);
2610753f127fSDimitry Andric 
2611*bdd1243dSDimitry Andric     RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
2612*bdd1243dSDimitry Andric 
2613*bdd1243dSDimitry Andric     InVals.push_back(RetValue);
2614753f127fSDimitry Andric   }
2615753f127fSDimitry Andric 
2616753f127fSDimitry Andric   return Chain;
2617753f127fSDimitry Andric }
2618753f127fSDimitry Andric 
261981ad6265SDimitry Andric bool LoongArchTargetLowering::CanLowerReturn(
262081ad6265SDimitry Andric     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
262181ad6265SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
2622*bdd1243dSDimitry Andric   SmallVector<CCValAssign> RVLocs;
2623*bdd1243dSDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
2624*bdd1243dSDimitry Andric 
2625*bdd1243dSDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2626*bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
2627*bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2628*bdd1243dSDimitry Andric     if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
2629*bdd1243dSDimitry Andric                      Outs[i].Flags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true,
2630*bdd1243dSDimitry Andric                      nullptr))
2631*bdd1243dSDimitry Andric       return false;
2632*bdd1243dSDimitry Andric   }
2633*bdd1243dSDimitry Andric   return true;
263481ad6265SDimitry Andric }
263581ad6265SDimitry Andric 
263681ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerReturn(
263781ad6265SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
263881ad6265SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs,
263981ad6265SDimitry Andric     const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
264081ad6265SDimitry Andric     SelectionDAG &DAG) const {
264181ad6265SDimitry Andric   // Stores the assignment of the return value to a location.
264281ad6265SDimitry Andric   SmallVector<CCValAssign> RVLocs;
264381ad6265SDimitry Andric 
264481ad6265SDimitry Andric   // Info about the registers and stack slot.
264581ad6265SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
264681ad6265SDimitry Andric                  *DAG.getContext());
264781ad6265SDimitry Andric 
2648*bdd1243dSDimitry Andric   analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
2649*bdd1243dSDimitry Andric                     nullptr, CC_LoongArch);
2650*bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC && !RVLocs.empty())
2651*bdd1243dSDimitry Andric     report_fatal_error("GHC functions return void only");
265281ad6265SDimitry Andric   SDValue Glue;
265381ad6265SDimitry Andric   SmallVector<SDValue, 4> RetOps(1, Chain);
265481ad6265SDimitry Andric 
265581ad6265SDimitry Andric   // Copy the result values into the output registers.
265681ad6265SDimitry Andric   for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) {
265781ad6265SDimitry Andric     CCValAssign &VA = RVLocs[i];
265881ad6265SDimitry Andric     assert(VA.isRegLoc() && "Can only return in registers!");
265981ad6265SDimitry Andric 
266081ad6265SDimitry Andric     // Handle a 'normal' return.
2661*bdd1243dSDimitry Andric     SDValue Val = convertValVTToLocVT(DAG, OutVals[i], VA, DL);
2662*bdd1243dSDimitry Andric     Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
266381ad6265SDimitry Andric 
266481ad6265SDimitry Andric     // Guarantee that all emitted copies are stuck together.
266581ad6265SDimitry Andric     Glue = Chain.getValue(1);
266681ad6265SDimitry Andric     RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
266781ad6265SDimitry Andric   }
266881ad6265SDimitry Andric 
266981ad6265SDimitry Andric   RetOps[0] = Chain; // Update chain.
267081ad6265SDimitry Andric 
267181ad6265SDimitry Andric   // Add the glue node if we have it.
267281ad6265SDimitry Andric   if (Glue.getNode())
267381ad6265SDimitry Andric     RetOps.push_back(Glue);
267481ad6265SDimitry Andric 
267581ad6265SDimitry Andric   return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
267681ad6265SDimitry Andric }
2677753f127fSDimitry Andric 
2678753f127fSDimitry Andric bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
2679753f127fSDimitry Andric                                            bool ForCodeSize) const {
2680*bdd1243dSDimitry Andric   // TODO: Maybe need more checks here after vector extension is supported.
2681753f127fSDimitry Andric   if (VT == MVT::f32 && !Subtarget.hasBasicF())
2682753f127fSDimitry Andric     return false;
2683753f127fSDimitry Andric   if (VT == MVT::f64 && !Subtarget.hasBasicD())
2684753f127fSDimitry Andric     return false;
2685753f127fSDimitry Andric   return (Imm.isZero() || Imm.isExactlyValue(+1.0));
2686753f127fSDimitry Andric }
2687*bdd1243dSDimitry Andric 
2688*bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCttz(Type *) const {
2689*bdd1243dSDimitry Andric   return true;
2690*bdd1243dSDimitry Andric }
2691*bdd1243dSDimitry Andric 
2692*bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCtlz(Type *) const {
2693*bdd1243dSDimitry Andric   return true;
2694*bdd1243dSDimitry Andric }
2695*bdd1243dSDimitry Andric 
2696*bdd1243dSDimitry Andric bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
2697*bdd1243dSDimitry Andric     const Instruction *I) const {
2698*bdd1243dSDimitry Andric   if (!Subtarget.is64Bit())
2699*bdd1243dSDimitry Andric     return isa<LoadInst>(I) || isa<StoreInst>(I);
2700*bdd1243dSDimitry Andric 
2701*bdd1243dSDimitry Andric   if (isa<LoadInst>(I))
2702*bdd1243dSDimitry Andric     return true;
2703*bdd1243dSDimitry Andric 
2704*bdd1243dSDimitry Andric   // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
2705*bdd1243dSDimitry Andric   // require fences beacuse we can use amswap_db.[w/d].
2706*bdd1243dSDimitry Andric   if (isa<StoreInst>(I)) {
2707*bdd1243dSDimitry Andric     unsigned Size = I->getOperand(0)->getType()->getIntegerBitWidth();
2708*bdd1243dSDimitry Andric     return (Size == 8 || Size == 16);
2709*bdd1243dSDimitry Andric   }
2710*bdd1243dSDimitry Andric 
2711*bdd1243dSDimitry Andric   return false;
2712*bdd1243dSDimitry Andric }
2713*bdd1243dSDimitry Andric 
2714*bdd1243dSDimitry Andric EVT LoongArchTargetLowering::getSetCCResultType(const DataLayout &DL,
2715*bdd1243dSDimitry Andric                                                 LLVMContext &Context,
2716*bdd1243dSDimitry Andric                                                 EVT VT) const {
2717*bdd1243dSDimitry Andric   if (!VT.isVector())
2718*bdd1243dSDimitry Andric     return getPointerTy(DL);
2719*bdd1243dSDimitry Andric   return VT.changeVectorElementTypeToInteger();
2720*bdd1243dSDimitry Andric }
2721*bdd1243dSDimitry Andric 
2722*bdd1243dSDimitry Andric bool LoongArchTargetLowering::hasAndNot(SDValue Y) const {
2723*bdd1243dSDimitry Andric   // TODO: Support vectors.
2724*bdd1243dSDimitry Andric   return Y.getValueType().isScalarInteger() && !isa<ConstantSDNode>(Y);
2725*bdd1243dSDimitry Andric }
2726*bdd1243dSDimitry Andric 
2727*bdd1243dSDimitry Andric bool LoongArchTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
2728*bdd1243dSDimitry Andric                                                  const CallInst &I,
2729*bdd1243dSDimitry Andric                                                  MachineFunction &MF,
2730*bdd1243dSDimitry Andric                                                  unsigned Intrinsic) const {
2731*bdd1243dSDimitry Andric   switch (Intrinsic) {
2732*bdd1243dSDimitry Andric   default:
2733*bdd1243dSDimitry Andric     return false;
2734*bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
2735*bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_add_i32:
2736*bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
2737*bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_nand_i32:
2738*bdd1243dSDimitry Andric     Info.opc = ISD::INTRINSIC_W_CHAIN;
2739*bdd1243dSDimitry Andric     Info.memVT = MVT::i32;
2740*bdd1243dSDimitry Andric     Info.ptrVal = I.getArgOperand(0);
2741*bdd1243dSDimitry Andric     Info.offset = 0;
2742*bdd1243dSDimitry Andric     Info.align = Align(4);
2743*bdd1243dSDimitry Andric     Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore |
2744*bdd1243dSDimitry Andric                  MachineMemOperand::MOVolatile;
2745*bdd1243dSDimitry Andric     return true;
2746*bdd1243dSDimitry Andric     // TODO: Add more Intrinsics later.
2747*bdd1243dSDimitry Andric   }
2748*bdd1243dSDimitry Andric }
2749*bdd1243dSDimitry Andric 
2750*bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind
2751*bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
2752*bdd1243dSDimitry Andric   // TODO: Add more AtomicRMWInst that needs to be extended.
2753*bdd1243dSDimitry Andric 
2754*bdd1243dSDimitry Andric   // Since floating-point operation requires a non-trivial set of data
2755*bdd1243dSDimitry Andric   // operations, use CmpXChg to expand.
2756*bdd1243dSDimitry Andric   if (AI->isFloatingPointOperation() ||
2757*bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::UIncWrap ||
2758*bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::UDecWrap)
2759*bdd1243dSDimitry Andric     return AtomicExpansionKind::CmpXChg;
2760*bdd1243dSDimitry Andric 
2761*bdd1243dSDimitry Andric   unsigned Size = AI->getType()->getPrimitiveSizeInBits();
2762*bdd1243dSDimitry Andric   if (Size == 8 || Size == 16)
2763*bdd1243dSDimitry Andric     return AtomicExpansionKind::MaskedIntrinsic;
2764*bdd1243dSDimitry Andric   return AtomicExpansionKind::None;
2765*bdd1243dSDimitry Andric }
2766*bdd1243dSDimitry Andric 
2767*bdd1243dSDimitry Andric static Intrinsic::ID
2768*bdd1243dSDimitry Andric getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen,
2769*bdd1243dSDimitry Andric                                     AtomicRMWInst::BinOp BinOp) {
2770*bdd1243dSDimitry Andric   if (GRLen == 64) {
2771*bdd1243dSDimitry Andric     switch (BinOp) {
2772*bdd1243dSDimitry Andric     default:
2773*bdd1243dSDimitry Andric       llvm_unreachable("Unexpected AtomicRMW BinOp");
2774*bdd1243dSDimitry Andric     case AtomicRMWInst::Xchg:
2775*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
2776*bdd1243dSDimitry Andric     case AtomicRMWInst::Add:
2777*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_add_i64;
2778*bdd1243dSDimitry Andric     case AtomicRMWInst::Sub:
2779*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
2780*bdd1243dSDimitry Andric     case AtomicRMWInst::Nand:
2781*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
2782*bdd1243dSDimitry Andric     case AtomicRMWInst::UMax:
2783*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
2784*bdd1243dSDimitry Andric     case AtomicRMWInst::UMin:
2785*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
2786*bdd1243dSDimitry Andric     case AtomicRMWInst::Max:
2787*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_max_i64;
2788*bdd1243dSDimitry Andric     case AtomicRMWInst::Min:
2789*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_min_i64;
2790*bdd1243dSDimitry Andric       // TODO: support other AtomicRMWInst.
2791*bdd1243dSDimitry Andric     }
2792*bdd1243dSDimitry Andric   }
2793*bdd1243dSDimitry Andric 
2794*bdd1243dSDimitry Andric   if (GRLen == 32) {
2795*bdd1243dSDimitry Andric     switch (BinOp) {
2796*bdd1243dSDimitry Andric     default:
2797*bdd1243dSDimitry Andric       llvm_unreachable("Unexpected AtomicRMW BinOp");
2798*bdd1243dSDimitry Andric     case AtomicRMWInst::Xchg:
2799*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
2800*bdd1243dSDimitry Andric     case AtomicRMWInst::Add:
2801*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_add_i32;
2802*bdd1243dSDimitry Andric     case AtomicRMWInst::Sub:
2803*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
2804*bdd1243dSDimitry Andric     case AtomicRMWInst::Nand:
2805*bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
2806*bdd1243dSDimitry Andric       // TODO: support other AtomicRMWInst.
2807*bdd1243dSDimitry Andric     }
2808*bdd1243dSDimitry Andric   }
2809*bdd1243dSDimitry Andric 
2810*bdd1243dSDimitry Andric   llvm_unreachable("Unexpected GRLen\n");
2811*bdd1243dSDimitry Andric }
2812*bdd1243dSDimitry Andric 
2813*bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind
2814*bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicCmpXchgInIR(
2815*bdd1243dSDimitry Andric     AtomicCmpXchgInst *CI) const {
2816*bdd1243dSDimitry Andric   unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits();
2817*bdd1243dSDimitry Andric   if (Size == 8 || Size == 16)
2818*bdd1243dSDimitry Andric     return AtomicExpansionKind::MaskedIntrinsic;
2819*bdd1243dSDimitry Andric   return AtomicExpansionKind::None;
2820*bdd1243dSDimitry Andric }
2821*bdd1243dSDimitry Andric 
2822*bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicCmpXchgIntrinsic(
2823*bdd1243dSDimitry Andric     IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
2824*bdd1243dSDimitry Andric     Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
2825*bdd1243dSDimitry Andric   Value *Ordering =
2826*bdd1243dSDimitry Andric       Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(Ord));
2827*bdd1243dSDimitry Andric 
2828*bdd1243dSDimitry Andric   // TODO: Support cmpxchg on LA32.
2829*bdd1243dSDimitry Andric   Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
2830*bdd1243dSDimitry Andric   CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
2831*bdd1243dSDimitry Andric   NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
2832*bdd1243dSDimitry Andric   Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
2833*bdd1243dSDimitry Andric   Type *Tys[] = {AlignedAddr->getType()};
2834*bdd1243dSDimitry Andric   Function *MaskedCmpXchg =
2835*bdd1243dSDimitry Andric       Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys);
2836*bdd1243dSDimitry Andric   Value *Result = Builder.CreateCall(
2837*bdd1243dSDimitry Andric       MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, Ordering});
2838*bdd1243dSDimitry Andric   Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
2839*bdd1243dSDimitry Andric   return Result;
2840*bdd1243dSDimitry Andric }
2841*bdd1243dSDimitry Andric 
2842*bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicRMWIntrinsic(
2843*bdd1243dSDimitry Andric     IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
2844*bdd1243dSDimitry Andric     Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
2845*bdd1243dSDimitry Andric   unsigned GRLen = Subtarget.getGRLen();
2846*bdd1243dSDimitry Andric   Value *Ordering =
2847*bdd1243dSDimitry Andric       Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
2848*bdd1243dSDimitry Andric   Type *Tys[] = {AlignedAddr->getType()};
2849*bdd1243dSDimitry Andric   Function *LlwOpScwLoop = Intrinsic::getDeclaration(
2850*bdd1243dSDimitry Andric       AI->getModule(),
2851*bdd1243dSDimitry Andric       getIntrinsicForMaskedAtomicRMWBinOp(GRLen, AI->getOperation()), Tys);
2852*bdd1243dSDimitry Andric 
2853*bdd1243dSDimitry Andric   if (GRLen == 64) {
2854*bdd1243dSDimitry Andric     Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
2855*bdd1243dSDimitry Andric     Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
2856*bdd1243dSDimitry Andric     ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
2857*bdd1243dSDimitry Andric   }
2858*bdd1243dSDimitry Andric 
2859*bdd1243dSDimitry Andric   Value *Result;
2860*bdd1243dSDimitry Andric 
2861*bdd1243dSDimitry Andric   // Must pass the shift amount needed to sign extend the loaded value prior
2862*bdd1243dSDimitry Andric   // to performing a signed comparison for min/max. ShiftAmt is the number of
2863*bdd1243dSDimitry Andric   // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
2864*bdd1243dSDimitry Andric   // is the number of bits to left+right shift the value in order to
2865*bdd1243dSDimitry Andric   // sign-extend.
2866*bdd1243dSDimitry Andric   if (AI->getOperation() == AtomicRMWInst::Min ||
2867*bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::Max) {
2868*bdd1243dSDimitry Andric     const DataLayout &DL = AI->getModule()->getDataLayout();
2869*bdd1243dSDimitry Andric     unsigned ValWidth =
2870*bdd1243dSDimitry Andric         DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
2871*bdd1243dSDimitry Andric     Value *SextShamt =
2872*bdd1243dSDimitry Andric         Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
2873*bdd1243dSDimitry Andric     Result = Builder.CreateCall(LlwOpScwLoop,
2874*bdd1243dSDimitry Andric                                 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
2875*bdd1243dSDimitry Andric   } else {
2876*bdd1243dSDimitry Andric     Result =
2877*bdd1243dSDimitry Andric         Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
2878*bdd1243dSDimitry Andric   }
2879*bdd1243dSDimitry Andric 
2880*bdd1243dSDimitry Andric   if (GRLen == 64)
2881*bdd1243dSDimitry Andric     Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
2882*bdd1243dSDimitry Andric   return Result;
2883*bdd1243dSDimitry Andric }
2884*bdd1243dSDimitry Andric 
2885*bdd1243dSDimitry Andric bool LoongArchTargetLowering::isFMAFasterThanFMulAndFAdd(
2886*bdd1243dSDimitry Andric     const MachineFunction &MF, EVT VT) const {
2887*bdd1243dSDimitry Andric   VT = VT.getScalarType();
2888*bdd1243dSDimitry Andric 
2889*bdd1243dSDimitry Andric   if (!VT.isSimple())
2890*bdd1243dSDimitry Andric     return false;
2891*bdd1243dSDimitry Andric 
2892*bdd1243dSDimitry Andric   switch (VT.getSimpleVT().SimpleTy) {
2893*bdd1243dSDimitry Andric   case MVT::f32:
2894*bdd1243dSDimitry Andric   case MVT::f64:
2895*bdd1243dSDimitry Andric     return true;
2896*bdd1243dSDimitry Andric   default:
2897*bdd1243dSDimitry Andric     break;
2898*bdd1243dSDimitry Andric   }
2899*bdd1243dSDimitry Andric 
2900*bdd1243dSDimitry Andric   return false;
2901*bdd1243dSDimitry Andric }
2902*bdd1243dSDimitry Andric 
2903*bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionPointerRegister(
2904*bdd1243dSDimitry Andric     const Constant *PersonalityFn) const {
2905*bdd1243dSDimitry Andric   return LoongArch::R4;
2906*bdd1243dSDimitry Andric }
2907*bdd1243dSDimitry Andric 
2908*bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionSelectorRegister(
2909*bdd1243dSDimitry Andric     const Constant *PersonalityFn) const {
2910*bdd1243dSDimitry Andric   return LoongArch::R5;
2911*bdd1243dSDimitry Andric }
2912*bdd1243dSDimitry Andric 
2913*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
2914*bdd1243dSDimitry Andric //                           LoongArch Inline Assembly Support
2915*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
2916*bdd1243dSDimitry Andric 
2917*bdd1243dSDimitry Andric LoongArchTargetLowering::ConstraintType
2918*bdd1243dSDimitry Andric LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
2919*bdd1243dSDimitry Andric   // LoongArch specific constraints in GCC: config/loongarch/constraints.md
2920*bdd1243dSDimitry Andric   //
2921*bdd1243dSDimitry Andric   // 'f':  A floating-point register (if available).
2922*bdd1243dSDimitry Andric   // 'k':  A memory operand whose address is formed by a base register and
2923*bdd1243dSDimitry Andric   //       (optionally scaled) index register.
2924*bdd1243dSDimitry Andric   // 'l':  A signed 16-bit constant.
2925*bdd1243dSDimitry Andric   // 'm':  A memory operand whose address is formed by a base register and
2926*bdd1243dSDimitry Andric   //       offset that is suitable for use in instructions with the same
2927*bdd1243dSDimitry Andric   //       addressing mode as st.w and ld.w.
2928*bdd1243dSDimitry Andric   // 'I':  A signed 12-bit constant (for arithmetic instructions).
2929*bdd1243dSDimitry Andric   // 'J':  Integer zero.
2930*bdd1243dSDimitry Andric   // 'K':  An unsigned 12-bit constant (for logic instructions).
2931*bdd1243dSDimitry Andric   // "ZB": An address that is held in a general-purpose register. The offset is
2932*bdd1243dSDimitry Andric   //       zero.
2933*bdd1243dSDimitry Andric   // "ZC": A memory operand whose address is formed by a base register and
2934*bdd1243dSDimitry Andric   //       offset that is suitable for use in instructions with the same
2935*bdd1243dSDimitry Andric   //       addressing mode as ll.w and sc.w.
2936*bdd1243dSDimitry Andric   if (Constraint.size() == 1) {
2937*bdd1243dSDimitry Andric     switch (Constraint[0]) {
2938*bdd1243dSDimitry Andric     default:
2939*bdd1243dSDimitry Andric       break;
2940*bdd1243dSDimitry Andric     case 'f':
2941*bdd1243dSDimitry Andric       return C_RegisterClass;
2942*bdd1243dSDimitry Andric     case 'l':
2943*bdd1243dSDimitry Andric     case 'I':
2944*bdd1243dSDimitry Andric     case 'J':
2945*bdd1243dSDimitry Andric     case 'K':
2946*bdd1243dSDimitry Andric       return C_Immediate;
2947*bdd1243dSDimitry Andric     case 'k':
2948*bdd1243dSDimitry Andric       return C_Memory;
2949*bdd1243dSDimitry Andric     }
2950*bdd1243dSDimitry Andric   }
2951*bdd1243dSDimitry Andric 
2952*bdd1243dSDimitry Andric   if (Constraint == "ZC" || Constraint == "ZB")
2953*bdd1243dSDimitry Andric     return C_Memory;
2954*bdd1243dSDimitry Andric 
2955*bdd1243dSDimitry Andric   // 'm' is handled here.
2956*bdd1243dSDimitry Andric   return TargetLowering::getConstraintType(Constraint);
2957*bdd1243dSDimitry Andric }
2958*bdd1243dSDimitry Andric 
2959*bdd1243dSDimitry Andric unsigned LoongArchTargetLowering::getInlineAsmMemConstraint(
2960*bdd1243dSDimitry Andric     StringRef ConstraintCode) const {
2961*bdd1243dSDimitry Andric   return StringSwitch<unsigned>(ConstraintCode)
2962*bdd1243dSDimitry Andric       .Case("k", InlineAsm::Constraint_k)
2963*bdd1243dSDimitry Andric       .Case("ZB", InlineAsm::Constraint_ZB)
2964*bdd1243dSDimitry Andric       .Case("ZC", InlineAsm::Constraint_ZC)
2965*bdd1243dSDimitry Andric       .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
2966*bdd1243dSDimitry Andric }
2967*bdd1243dSDimitry Andric 
2968*bdd1243dSDimitry Andric std::pair<unsigned, const TargetRegisterClass *>
2969*bdd1243dSDimitry Andric LoongArchTargetLowering::getRegForInlineAsmConstraint(
2970*bdd1243dSDimitry Andric     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
2971*bdd1243dSDimitry Andric   // First, see if this is a constraint that directly corresponds to a LoongArch
2972*bdd1243dSDimitry Andric   // register class.
2973*bdd1243dSDimitry Andric   if (Constraint.size() == 1) {
2974*bdd1243dSDimitry Andric     switch (Constraint[0]) {
2975*bdd1243dSDimitry Andric     case 'r':
2976*bdd1243dSDimitry Andric       // TODO: Support fixed vectors up to GRLen?
2977*bdd1243dSDimitry Andric       if (VT.isVector())
2978*bdd1243dSDimitry Andric         break;
2979*bdd1243dSDimitry Andric       return std::make_pair(0U, &LoongArch::GPRRegClass);
2980*bdd1243dSDimitry Andric     case 'f':
2981*bdd1243dSDimitry Andric       if (Subtarget.hasBasicF() && VT == MVT::f32)
2982*bdd1243dSDimitry Andric         return std::make_pair(0U, &LoongArch::FPR32RegClass);
2983*bdd1243dSDimitry Andric       if (Subtarget.hasBasicD() && VT == MVT::f64)
2984*bdd1243dSDimitry Andric         return std::make_pair(0U, &LoongArch::FPR64RegClass);
2985*bdd1243dSDimitry Andric       break;
2986*bdd1243dSDimitry Andric     default:
2987*bdd1243dSDimitry Andric       break;
2988*bdd1243dSDimitry Andric     }
2989*bdd1243dSDimitry Andric   }
2990*bdd1243dSDimitry Andric 
2991*bdd1243dSDimitry Andric   // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
2992*bdd1243dSDimitry Andric   // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
2993*bdd1243dSDimitry Andric   // constraints while the official register name is prefixed with a '$'. So we
2994*bdd1243dSDimitry Andric   // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
2995*bdd1243dSDimitry Andric   // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
2996*bdd1243dSDimitry Andric   // case insensitive, so no need to convert the constraint to upper case here.
2997*bdd1243dSDimitry Andric   //
2998*bdd1243dSDimitry Andric   // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
2999*bdd1243dSDimitry Andric   // decode the usage of register name aliases into their official names. And
3000*bdd1243dSDimitry Andric   // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
3001*bdd1243dSDimitry Andric   // official register names.
3002*bdd1243dSDimitry Andric   if (Constraint.startswith("{$r") || Constraint.startswith("{$f")) {
3003*bdd1243dSDimitry Andric     bool IsFP = Constraint[2] == 'f';
3004*bdd1243dSDimitry Andric     std::pair<StringRef, StringRef> Temp = Constraint.split('$');
3005*bdd1243dSDimitry Andric     std::pair<unsigned, const TargetRegisterClass *> R;
3006*bdd1243dSDimitry Andric     R = TargetLowering::getRegForInlineAsmConstraint(
3007*bdd1243dSDimitry Andric         TRI, join_items("", Temp.first, Temp.second), VT);
3008*bdd1243dSDimitry Andric     // Match those names to the widest floating point register type available.
3009*bdd1243dSDimitry Andric     if (IsFP) {
3010*bdd1243dSDimitry Andric       unsigned RegNo = R.first;
3011*bdd1243dSDimitry Andric       if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
3012*bdd1243dSDimitry Andric         if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
3013*bdd1243dSDimitry Andric           unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
3014*bdd1243dSDimitry Andric           return std::make_pair(DReg, &LoongArch::FPR64RegClass);
3015*bdd1243dSDimitry Andric         }
3016*bdd1243dSDimitry Andric       }
3017*bdd1243dSDimitry Andric     }
3018*bdd1243dSDimitry Andric     return R;
3019*bdd1243dSDimitry Andric   }
3020*bdd1243dSDimitry Andric 
3021*bdd1243dSDimitry Andric   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
3022*bdd1243dSDimitry Andric }
3023*bdd1243dSDimitry Andric 
3024*bdd1243dSDimitry Andric void LoongArchTargetLowering::LowerAsmOperandForConstraint(
3025*bdd1243dSDimitry Andric     SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops,
3026*bdd1243dSDimitry Andric     SelectionDAG &DAG) const {
3027*bdd1243dSDimitry Andric   // Currently only support length 1 constraints.
3028*bdd1243dSDimitry Andric   if (Constraint.length() == 1) {
3029*bdd1243dSDimitry Andric     switch (Constraint[0]) {
3030*bdd1243dSDimitry Andric     case 'l':
3031*bdd1243dSDimitry Andric       // Validate & create a 16-bit signed immediate operand.
3032*bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3033*bdd1243dSDimitry Andric         uint64_t CVal = C->getSExtValue();
3034*bdd1243dSDimitry Andric         if (isInt<16>(CVal))
3035*bdd1243dSDimitry Andric           Ops.push_back(
3036*bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3037*bdd1243dSDimitry Andric       }
3038*bdd1243dSDimitry Andric       return;
3039*bdd1243dSDimitry Andric     case 'I':
3040*bdd1243dSDimitry Andric       // Validate & create a 12-bit signed immediate operand.
3041*bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3042*bdd1243dSDimitry Andric         uint64_t CVal = C->getSExtValue();
3043*bdd1243dSDimitry Andric         if (isInt<12>(CVal))
3044*bdd1243dSDimitry Andric           Ops.push_back(
3045*bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3046*bdd1243dSDimitry Andric       }
3047*bdd1243dSDimitry Andric       return;
3048*bdd1243dSDimitry Andric     case 'J':
3049*bdd1243dSDimitry Andric       // Validate & create an integer zero operand.
3050*bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op))
3051*bdd1243dSDimitry Andric         if (C->getZExtValue() == 0)
3052*bdd1243dSDimitry Andric           Ops.push_back(
3053*bdd1243dSDimitry Andric               DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
3054*bdd1243dSDimitry Andric       return;
3055*bdd1243dSDimitry Andric     case 'K':
3056*bdd1243dSDimitry Andric       // Validate & create a 12-bit unsigned immediate operand.
3057*bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3058*bdd1243dSDimitry Andric         uint64_t CVal = C->getZExtValue();
3059*bdd1243dSDimitry Andric         if (isUInt<12>(CVal))
3060*bdd1243dSDimitry Andric           Ops.push_back(
3061*bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3062*bdd1243dSDimitry Andric       }
3063*bdd1243dSDimitry Andric       return;
3064*bdd1243dSDimitry Andric     default:
3065*bdd1243dSDimitry Andric       break;
3066*bdd1243dSDimitry Andric     }
3067*bdd1243dSDimitry Andric   }
3068*bdd1243dSDimitry Andric   TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
3069*bdd1243dSDimitry Andric }
3070*bdd1243dSDimitry Andric 
3071*bdd1243dSDimitry Andric #define GET_REGISTER_MATCHER
3072*bdd1243dSDimitry Andric #include "LoongArchGenAsmMatcher.inc"
3073*bdd1243dSDimitry Andric 
3074*bdd1243dSDimitry Andric Register
3075*bdd1243dSDimitry Andric LoongArchTargetLowering::getRegisterByName(const char *RegName, LLT VT,
3076*bdd1243dSDimitry Andric                                            const MachineFunction &MF) const {
3077*bdd1243dSDimitry Andric   std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
3078*bdd1243dSDimitry Andric   std::string NewRegName = Name.second.str();
3079*bdd1243dSDimitry Andric   Register Reg = MatchRegisterAltName(NewRegName);
3080*bdd1243dSDimitry Andric   if (Reg == LoongArch::NoRegister)
3081*bdd1243dSDimitry Andric     Reg = MatchRegisterName(NewRegName);
3082*bdd1243dSDimitry Andric   if (Reg == LoongArch::NoRegister)
3083*bdd1243dSDimitry Andric     report_fatal_error(
3084*bdd1243dSDimitry Andric         Twine("Invalid register name \"" + StringRef(RegName) + "\"."));
3085*bdd1243dSDimitry Andric   BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
3086*bdd1243dSDimitry Andric   if (!ReservedRegs.test(Reg))
3087*bdd1243dSDimitry Andric     report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
3088*bdd1243dSDimitry Andric                              StringRef(RegName) + "\"."));
3089*bdd1243dSDimitry Andric   return Reg;
3090*bdd1243dSDimitry Andric }
3091*bdd1243dSDimitry Andric 
3092*bdd1243dSDimitry Andric bool LoongArchTargetLowering::decomposeMulByConstant(LLVMContext &Context,
3093*bdd1243dSDimitry Andric                                                      EVT VT, SDValue C) const {
3094*bdd1243dSDimitry Andric   // TODO: Support vectors.
3095*bdd1243dSDimitry Andric   if (!VT.isScalarInteger())
3096*bdd1243dSDimitry Andric     return false;
3097*bdd1243dSDimitry Andric 
3098*bdd1243dSDimitry Andric   // Omit the optimization if the data size exceeds GRLen.
3099*bdd1243dSDimitry Andric   if (VT.getSizeInBits() > Subtarget.getGRLen())
3100*bdd1243dSDimitry Andric     return false;
3101*bdd1243dSDimitry Andric 
3102*bdd1243dSDimitry Andric   // Break MUL into (SLLI + ADD/SUB) or ALSL.
3103*bdd1243dSDimitry Andric   if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
3104*bdd1243dSDimitry Andric     const APInt &Imm = ConstNode->getAPIntValue();
3105*bdd1243dSDimitry Andric     if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
3106*bdd1243dSDimitry Andric         (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
3107*bdd1243dSDimitry Andric       return true;
3108*bdd1243dSDimitry Andric   }
3109*bdd1243dSDimitry Andric 
3110*bdd1243dSDimitry Andric   return false;
3111*bdd1243dSDimitry Andric }
3112