xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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"
20bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h"
21753f127fSDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h"
2281ad6265SDimitry Andric #include "llvm/ADT/Statistic.h"
23*06c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
2481ad6265SDimitry Andric #include "llvm/CodeGen/ISDOpcodes.h"
25bdd1243dSDimitry Andric #include "llvm/CodeGen/RuntimeLibcalls.h"
26*06c3fb27SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h"
27bdd1243dSDimitry Andric #include "llvm/IR/IRBuilder.h"
28bdd1243dSDimitry Andric #include "llvm/IR/IntrinsicsLoongArch.h"
29*06c3fb27SDimitry Andric #include "llvm/Support/CodeGen.h"
3081ad6265SDimitry Andric #include "llvm/Support/Debug.h"
31*06c3fb27SDimitry Andric #include "llvm/Support/ErrorHandling.h"
32753f127fSDimitry Andric #include "llvm/Support/KnownBits.h"
33bdd1243dSDimitry Andric #include "llvm/Support/MathExtras.h"
3481ad6265SDimitry Andric 
3581ad6265SDimitry Andric using namespace llvm;
3681ad6265SDimitry Andric 
3781ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-isel-lowering"
3881ad6265SDimitry Andric 
39bdd1243dSDimitry Andric STATISTIC(NumTailCalls, "Number of tail calls");
40bdd1243dSDimitry Andric 
41*06c3fb27SDimitry Andric static cl::opt<bool> ZeroDivCheck("loongarch-check-zero-division", cl::Hidden,
42753f127fSDimitry Andric                                   cl::desc("Trap on integer division by zero."),
43753f127fSDimitry Andric                                   cl::init(false));
44753f127fSDimitry Andric 
4581ad6265SDimitry Andric LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
4681ad6265SDimitry Andric                                                  const LoongArchSubtarget &STI)
4781ad6265SDimitry Andric     : TargetLowering(TM), Subtarget(STI) {
4881ad6265SDimitry Andric 
4981ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
5081ad6265SDimitry Andric   // Set up the register classes.
5181ad6265SDimitry Andric   addRegisterClass(GRLenVT, &LoongArch::GPRRegClass);
5281ad6265SDimitry Andric   if (Subtarget.hasBasicF())
5381ad6265SDimitry Andric     addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass);
5481ad6265SDimitry Andric   if (Subtarget.hasBasicD())
5581ad6265SDimitry Andric     addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass);
56*06c3fb27SDimitry Andric   if (Subtarget.hasExtLSX())
57*06c3fb27SDimitry Andric     for (auto VT : {MVT::v4f32, MVT::v2f64, MVT::v16i8, MVT::v8i16, MVT::v4i32,
58*06c3fb27SDimitry Andric                     MVT::v2i64})
59*06c3fb27SDimitry Andric       addRegisterClass(VT, &LoongArch::LSX128RegClass);
60*06c3fb27SDimitry Andric   if (Subtarget.hasExtLASX())
61*06c3fb27SDimitry Andric     for (auto VT : {MVT::v8f32, MVT::v4f64, MVT::v32i8, MVT::v16i16, MVT::v8i32,
62*06c3fb27SDimitry Andric                     MVT::v4i64})
63*06c3fb27SDimitry Andric       addRegisterClass(VT, &LoongArch::LASX256RegClass);
6481ad6265SDimitry Andric 
65753f127fSDimitry Andric   setLoadExtAction({ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}, GRLenVT,
66753f127fSDimitry Andric                    MVT::i1, Promote);
67753f127fSDimitry Andric 
6881ad6265SDimitry Andric   // TODO: add necessary setOperationAction calls later.
6981ad6265SDimitry Andric   setOperationAction(ISD::SHL_PARTS, GRLenVT, Custom);
7081ad6265SDimitry Andric   setOperationAction(ISD::SRA_PARTS, GRLenVT, Custom);
7181ad6265SDimitry Andric   setOperationAction(ISD::SRL_PARTS, GRLenVT, Custom);
72753f127fSDimitry Andric   setOperationAction(ISD::FP_TO_SINT, GRLenVT, Custom);
73bdd1243dSDimitry Andric   setOperationAction(ISD::ROTL, GRLenVT, Expand);
74bdd1243dSDimitry Andric   setOperationAction(ISD::CTPOP, GRLenVT, Expand);
75bdd1243dSDimitry Andric   setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
76bdd1243dSDimitry Andric   setOperationAction(ISD::TRAP, MVT::Other, Legal);
77bdd1243dSDimitry Andric   setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
78bdd1243dSDimitry Andric   setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
79753f127fSDimitry Andric 
80bdd1243dSDimitry Andric   setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool,
81bdd1243dSDimitry Andric                       ISD::JumpTable},
82bdd1243dSDimitry Andric                      GRLenVT, Custom);
83bdd1243dSDimitry Andric 
84bdd1243dSDimitry Andric   setOperationAction(ISD::GlobalTLSAddress, GRLenVT, Custom);
85bdd1243dSDimitry Andric 
86bdd1243dSDimitry Andric   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
87bdd1243dSDimitry Andric 
88bdd1243dSDimitry Andric   setOperationAction(ISD::EH_DWARF_CFA, MVT::i32, Custom);
89bdd1243dSDimitry Andric   if (Subtarget.is64Bit())
90bdd1243dSDimitry Andric     setOperationAction(ISD::EH_DWARF_CFA, MVT::i64, Custom);
91bdd1243dSDimitry Andric 
92bdd1243dSDimitry Andric   setOperationAction(ISD::DYNAMIC_STACKALLOC, GRLenVT, Expand);
93bdd1243dSDimitry Andric   setOperationAction({ISD::STACKSAVE, ISD::STACKRESTORE}, MVT::Other, Expand);
94bdd1243dSDimitry Andric   setOperationAction(ISD::VASTART, MVT::Other, Custom);
95bdd1243dSDimitry Andric   setOperationAction({ISD::VAARG, ISD::VACOPY, ISD::VAEND}, MVT::Other, Expand);
9681ad6265SDimitry Andric 
9781ad6265SDimitry Andric   if (Subtarget.is64Bit()) {
9881ad6265SDimitry Andric     setOperationAction(ISD::SHL, MVT::i32, Custom);
9981ad6265SDimitry Andric     setOperationAction(ISD::SRA, MVT::i32, Custom);
10081ad6265SDimitry Andric     setOperationAction(ISD::SRL, MVT::i32, Custom);
101753f127fSDimitry Andric     setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
102753f127fSDimitry Andric     setOperationAction(ISD::BITCAST, MVT::i32, Custom);
103bdd1243dSDimitry Andric     setOperationAction(ISD::ROTR, MVT::i32, Custom);
104bdd1243dSDimitry Andric     setOperationAction(ISD::ROTL, MVT::i32, Custom);
105bdd1243dSDimitry Andric     setOperationAction(ISD::CTTZ, MVT::i32, Custom);
106bdd1243dSDimitry Andric     setOperationAction(ISD::CTLZ, MVT::i32, Custom);
107bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom);
108bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i32, Custom);
109bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
110bdd1243dSDimitry Andric     setOperationAction(ISD::READ_REGISTER, MVT::i32, Custom);
111bdd1243dSDimitry Andric     setOperationAction(ISD::WRITE_REGISTER, MVT::i32, Custom);
112753f127fSDimitry Andric     if (Subtarget.hasBasicF() && !Subtarget.hasBasicD())
113753f127fSDimitry Andric       setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
114bdd1243dSDimitry Andric     if (Subtarget.hasBasicF())
115bdd1243dSDimitry Andric       setOperationAction(ISD::FRINT, MVT::f32, Legal);
116bdd1243dSDimitry Andric     if (Subtarget.hasBasicD())
117bdd1243dSDimitry Andric       setOperationAction(ISD::FRINT, MVT::f64, Legal);
11881ad6265SDimitry Andric   }
11981ad6265SDimitry Andric 
120bdd1243dSDimitry Andric   // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
121bdd1243dSDimitry Andric   // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
122bdd1243dSDimitry Andric   // and i32 could still be byte-swapped relatively cheaply.
123bdd1243dSDimitry Andric   setOperationAction(ISD::BSWAP, MVT::i16, Custom);
124bdd1243dSDimitry Andric   if (Subtarget.is64Bit()) {
125bdd1243dSDimitry Andric     setOperationAction(ISD::BSWAP, MVT::i32, Custom);
126bdd1243dSDimitry Andric   }
127bdd1243dSDimitry Andric 
128bdd1243dSDimitry Andric   // Expand bitreverse.i16 with native-width bitrev and shift for now, before
129bdd1243dSDimitry Andric   // we get to know which of sll and revb.2h is faster.
130bdd1243dSDimitry Andric   setOperationAction(ISD::BITREVERSE, MVT::i8, Custom);
131bdd1243dSDimitry Andric   if (Subtarget.is64Bit()) {
132bdd1243dSDimitry Andric     setOperationAction(ISD::BITREVERSE, MVT::i32, Custom);
133bdd1243dSDimitry Andric     setOperationAction(ISD::BITREVERSE, MVT::i64, Legal);
134bdd1243dSDimitry Andric   } else {
135bdd1243dSDimitry Andric     setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
136bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom);
137bdd1243dSDimitry Andric     setOperationAction(ISD::READ_REGISTER, MVT::i64, Custom);
138bdd1243dSDimitry Andric     setOperationAction(ISD::WRITE_REGISTER, MVT::i64, Custom);
139bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
140bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_VOID, MVT::i64, Custom);
141bdd1243dSDimitry Andric   }
142bdd1243dSDimitry Andric 
143bdd1243dSDimitry Andric   static const ISD::CondCode FPCCToExpand[] = {
144bdd1243dSDimitry Andric       ISD::SETOGT, ISD::SETOGE, ISD::SETUGT, ISD::SETUGE,
145bdd1243dSDimitry Andric       ISD::SETGE,  ISD::SETNE,  ISD::SETGT};
14681ad6265SDimitry Andric 
14781ad6265SDimitry Andric   if (Subtarget.hasBasicF()) {
14881ad6265SDimitry Andric     setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
14981ad6265SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
150bdd1243dSDimitry Andric     setOperationAction(ISD::BR_CC, MVT::f32, Expand);
151bdd1243dSDimitry Andric     setOperationAction(ISD::FMA, MVT::f32, Legal);
152bdd1243dSDimitry Andric     setOperationAction(ISD::FMINNUM_IEEE, MVT::f32, Legal);
153bdd1243dSDimitry Andric     setOperationAction(ISD::FMAXNUM_IEEE, MVT::f32, Legal);
154bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCCS, MVT::f32, Legal);
155bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCC, MVT::f32, Legal);
156bdd1243dSDimitry Andric     setOperationAction(ISD::FSIN, MVT::f32, Expand);
157bdd1243dSDimitry Andric     setOperationAction(ISD::FCOS, MVT::f32, Expand);
158bdd1243dSDimitry Andric     setOperationAction(ISD::FSINCOS, MVT::f32, Expand);
159bdd1243dSDimitry Andric     setOperationAction(ISD::FPOW, MVT::f32, Expand);
160bdd1243dSDimitry Andric     setOperationAction(ISD::FREM, MVT::f32, Expand);
16181ad6265SDimitry Andric   }
16281ad6265SDimitry Andric   if (Subtarget.hasBasicD()) {
16381ad6265SDimitry Andric     setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
16481ad6265SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f64, Expand);
165bdd1243dSDimitry Andric     setOperationAction(ISD::BR_CC, MVT::f64, Expand);
166bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCCS, MVT::f64, Legal);
167bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCC, MVT::f64, Legal);
168753f127fSDimitry Andric     setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
169bdd1243dSDimitry Andric     setOperationAction(ISD::FMA, MVT::f64, Legal);
170bdd1243dSDimitry Andric     setOperationAction(ISD::FMINNUM_IEEE, MVT::f64, Legal);
171bdd1243dSDimitry Andric     setOperationAction(ISD::FMAXNUM_IEEE, MVT::f64, Legal);
172bdd1243dSDimitry Andric     setOperationAction(ISD::FSIN, MVT::f64, Expand);
173bdd1243dSDimitry Andric     setOperationAction(ISD::FCOS, MVT::f64, Expand);
174bdd1243dSDimitry Andric     setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
175bdd1243dSDimitry Andric     setOperationAction(ISD::FPOW, MVT::f64, Expand);
176bdd1243dSDimitry Andric     setOperationAction(ISD::FREM, MVT::f64, Expand);
177bdd1243dSDimitry Andric     setTruncStoreAction(MVT::f64, MVT::f32, Expand);
17881ad6265SDimitry Andric   }
17981ad6265SDimitry Andric 
180bdd1243dSDimitry Andric   setOperationAction(ISD::BR_JT, MVT::Other, Expand);
181bdd1243dSDimitry Andric 
182753f127fSDimitry Andric   setOperationAction(ISD::BR_CC, GRLenVT, Expand);
18381ad6265SDimitry Andric   setOperationAction(ISD::SELECT_CC, GRLenVT, Expand);
18481ad6265SDimitry Andric   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
185753f127fSDimitry Andric   setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, GRLenVT, Expand);
186753f127fSDimitry Andric   if (!Subtarget.is64Bit())
187753f127fSDimitry Andric     setLibcallName(RTLIB::MUL_I128, nullptr);
188753f127fSDimitry Andric 
189753f127fSDimitry Andric   setOperationAction(ISD::FP_TO_UINT, GRLenVT, Custom);
190bdd1243dSDimitry Andric   setOperationAction(ISD::UINT_TO_FP, GRLenVT, Expand);
191bdd1243dSDimitry Andric   if ((Subtarget.is64Bit() && Subtarget.hasBasicF() &&
192bdd1243dSDimitry Andric        !Subtarget.hasBasicD())) {
193bdd1243dSDimitry Andric     setOperationAction(ISD::SINT_TO_FP, GRLenVT, Custom);
194753f127fSDimitry Andric     setOperationAction(ISD::UINT_TO_FP, GRLenVT, Custom);
195bdd1243dSDimitry Andric   }
19681ad6265SDimitry Andric 
19781ad6265SDimitry Andric   // Compute derived properties from the register classes.
198*06c3fb27SDimitry Andric   computeRegisterProperties(Subtarget.getRegisterInfo());
19981ad6265SDimitry Andric 
20081ad6265SDimitry Andric   setStackPointerRegisterToSaveRestore(LoongArch::R3);
20181ad6265SDimitry Andric 
20281ad6265SDimitry Andric   setBooleanContents(ZeroOrOneBooleanContent);
20381ad6265SDimitry Andric 
204753f127fSDimitry Andric   setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen());
205753f127fSDimitry Andric 
206bdd1243dSDimitry Andric   setMinCmpXchgSizeInBits(32);
207bdd1243dSDimitry Andric 
20881ad6265SDimitry Andric   // Function alignments.
209*06c3fb27SDimitry Andric   setMinFunctionAlignment(Align(4));
210*06c3fb27SDimitry Andric   // Set preferred alignments.
211*06c3fb27SDimitry Andric   setPrefFunctionAlignment(Subtarget.getPrefFunctionAlignment());
212*06c3fb27SDimitry Andric   setPrefLoopAlignment(Subtarget.getPrefLoopAlignment());
213*06c3fb27SDimitry Andric   setMaxBytesForAlignment(Subtarget.getMaxBytesForAlignment());
21481ad6265SDimitry Andric 
21581ad6265SDimitry Andric   setTargetDAGCombine(ISD::AND);
216753f127fSDimitry Andric   setTargetDAGCombine(ISD::OR);
21781ad6265SDimitry Andric   setTargetDAGCombine(ISD::SRL);
21881ad6265SDimitry Andric }
21981ad6265SDimitry Andric 
220bdd1243dSDimitry Andric bool LoongArchTargetLowering::isOffsetFoldingLegal(
221bdd1243dSDimitry Andric     const GlobalAddressSDNode *GA) const {
222bdd1243dSDimitry Andric   // In order to maximise the opportunity for common subexpression elimination,
223bdd1243dSDimitry Andric   // keep a separate ADD node for the global address offset instead of folding
224bdd1243dSDimitry Andric   // it in the global address node. Later peephole optimisations may choose to
225bdd1243dSDimitry Andric   // fold it back in when profitable.
226bdd1243dSDimitry Andric   return false;
227bdd1243dSDimitry Andric }
228bdd1243dSDimitry Andric 
22981ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
23081ad6265SDimitry Andric                                                 SelectionDAG &DAG) const {
23181ad6265SDimitry Andric   switch (Op.getOpcode()) {
232bdd1243dSDimitry Andric   case ISD::EH_DWARF_CFA:
233bdd1243dSDimitry Andric     return lowerEH_DWARF_CFA(Op, DAG);
234753f127fSDimitry Andric   case ISD::GlobalAddress:
235753f127fSDimitry Andric     return lowerGlobalAddress(Op, DAG);
236bdd1243dSDimitry Andric   case ISD::GlobalTLSAddress:
237bdd1243dSDimitry Andric     return lowerGlobalTLSAddress(Op, DAG);
238bdd1243dSDimitry Andric   case ISD::INTRINSIC_WO_CHAIN:
239bdd1243dSDimitry Andric     return lowerINTRINSIC_WO_CHAIN(Op, DAG);
240bdd1243dSDimitry Andric   case ISD::INTRINSIC_W_CHAIN:
241bdd1243dSDimitry Andric     return lowerINTRINSIC_W_CHAIN(Op, DAG);
242bdd1243dSDimitry Andric   case ISD::INTRINSIC_VOID:
243bdd1243dSDimitry Andric     return lowerINTRINSIC_VOID(Op, DAG);
244bdd1243dSDimitry Andric   case ISD::BlockAddress:
245bdd1243dSDimitry Andric     return lowerBlockAddress(Op, DAG);
246bdd1243dSDimitry Andric   case ISD::JumpTable:
247bdd1243dSDimitry Andric     return lowerJumpTable(Op, DAG);
24881ad6265SDimitry Andric   case ISD::SHL_PARTS:
24981ad6265SDimitry Andric     return lowerShiftLeftParts(Op, DAG);
25081ad6265SDimitry Andric   case ISD::SRA_PARTS:
25181ad6265SDimitry Andric     return lowerShiftRightParts(Op, DAG, true);
25281ad6265SDimitry Andric   case ISD::SRL_PARTS:
25381ad6265SDimitry Andric     return lowerShiftRightParts(Op, DAG, false);
254753f127fSDimitry Andric   case ISD::ConstantPool:
255753f127fSDimitry Andric     return lowerConstantPool(Op, DAG);
256753f127fSDimitry Andric   case ISD::FP_TO_SINT:
257753f127fSDimitry Andric     return lowerFP_TO_SINT(Op, DAG);
258753f127fSDimitry Andric   case ISD::BITCAST:
259753f127fSDimitry Andric     return lowerBITCAST(Op, DAG);
260753f127fSDimitry Andric   case ISD::UINT_TO_FP:
261753f127fSDimitry Andric     return lowerUINT_TO_FP(Op, DAG);
262bdd1243dSDimitry Andric   case ISD::SINT_TO_FP:
263bdd1243dSDimitry Andric     return lowerSINT_TO_FP(Op, DAG);
264bdd1243dSDimitry Andric   case ISD::VASTART:
265bdd1243dSDimitry Andric     return lowerVASTART(Op, DAG);
266bdd1243dSDimitry Andric   case ISD::FRAMEADDR:
267bdd1243dSDimitry Andric     return lowerFRAMEADDR(Op, DAG);
268bdd1243dSDimitry Andric   case ISD::RETURNADDR:
269bdd1243dSDimitry Andric     return lowerRETURNADDR(Op, DAG);
270bdd1243dSDimitry Andric   case ISD::WRITE_REGISTER:
271bdd1243dSDimitry Andric     return lowerWRITE_REGISTER(Op, DAG);
27281ad6265SDimitry Andric   }
273bdd1243dSDimitry Andric   return SDValue();
274bdd1243dSDimitry Andric }
275bdd1243dSDimitry Andric 
276bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
277bdd1243dSDimitry Andric                                                      SelectionDAG &DAG) const {
278bdd1243dSDimitry Andric 
279bdd1243dSDimitry Andric   if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
280bdd1243dSDimitry Andric     DAG.getContext()->emitError(
281bdd1243dSDimitry Andric         "On LA64, only 64-bit registers can be written.");
282bdd1243dSDimitry Andric     return Op.getOperand(0);
283bdd1243dSDimitry Andric   }
284bdd1243dSDimitry Andric 
285bdd1243dSDimitry Andric   if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
286bdd1243dSDimitry Andric     DAG.getContext()->emitError(
287bdd1243dSDimitry Andric         "On LA32, only 32-bit registers can be written.");
288bdd1243dSDimitry Andric     return Op.getOperand(0);
289bdd1243dSDimitry Andric   }
290bdd1243dSDimitry Andric 
291bdd1243dSDimitry Andric   return Op;
292bdd1243dSDimitry Andric }
293bdd1243dSDimitry Andric 
294bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
295bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
296bdd1243dSDimitry Andric   if (!isa<ConstantSDNode>(Op.getOperand(0))) {
297bdd1243dSDimitry Andric     DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
298bdd1243dSDimitry Andric                                 "be a constant integer");
299bdd1243dSDimitry Andric     return SDValue();
300bdd1243dSDimitry Andric   }
301bdd1243dSDimitry Andric 
302bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
303bdd1243dSDimitry Andric   MF.getFrameInfo().setFrameAddressIsTaken(true);
304bdd1243dSDimitry Andric   Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
305bdd1243dSDimitry Andric   EVT VT = Op.getValueType();
306bdd1243dSDimitry Andric   SDLoc DL(Op);
307bdd1243dSDimitry Andric   SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
308bdd1243dSDimitry Andric   unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
309bdd1243dSDimitry Andric   int GRLenInBytes = Subtarget.getGRLen() / 8;
310bdd1243dSDimitry Andric 
311bdd1243dSDimitry Andric   while (Depth--) {
312bdd1243dSDimitry Andric     int Offset = -(GRLenInBytes * 2);
313bdd1243dSDimitry Andric     SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
314bdd1243dSDimitry Andric                               DAG.getIntPtrConstant(Offset, DL));
315bdd1243dSDimitry Andric     FrameAddr =
316bdd1243dSDimitry Andric         DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
317bdd1243dSDimitry Andric   }
318bdd1243dSDimitry Andric   return FrameAddr;
319bdd1243dSDimitry Andric }
320bdd1243dSDimitry Andric 
321bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
322bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
323bdd1243dSDimitry Andric   if (verifyReturnAddressArgumentIsConstant(Op, DAG))
324bdd1243dSDimitry Andric     return SDValue();
325bdd1243dSDimitry Andric 
326bdd1243dSDimitry Andric   // Currently only support lowering return address for current frame.
327bdd1243dSDimitry Andric   if (cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() != 0) {
328bdd1243dSDimitry Andric     DAG.getContext()->emitError(
329bdd1243dSDimitry Andric         "return address can only be determined for the current frame");
330bdd1243dSDimitry Andric     return SDValue();
331bdd1243dSDimitry Andric   }
332bdd1243dSDimitry Andric 
333bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
334bdd1243dSDimitry Andric   MF.getFrameInfo().setReturnAddressIsTaken(true);
335bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
336bdd1243dSDimitry Andric 
337bdd1243dSDimitry Andric   // Return the value of the return address register, marking it an implicit
338bdd1243dSDimitry Andric   // live-in.
339bdd1243dSDimitry Andric   Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
340bdd1243dSDimitry Andric                               getRegClassFor(GRLenVT));
341bdd1243dSDimitry Andric   return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
342bdd1243dSDimitry Andric }
343bdd1243dSDimitry Andric 
344bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
345bdd1243dSDimitry Andric                                                    SelectionDAG &DAG) const {
346bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
347bdd1243dSDimitry Andric   auto Size = Subtarget.getGRLen() / 8;
348bdd1243dSDimitry Andric   auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
349bdd1243dSDimitry Andric   return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
350bdd1243dSDimitry Andric }
351bdd1243dSDimitry Andric 
352bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
353bdd1243dSDimitry Andric                                               SelectionDAG &DAG) const {
354bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
355bdd1243dSDimitry Andric   auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
356bdd1243dSDimitry Andric 
357bdd1243dSDimitry Andric   SDLoc DL(Op);
358bdd1243dSDimitry Andric   SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
359bdd1243dSDimitry Andric                                  getPointerTy(MF.getDataLayout()));
360bdd1243dSDimitry Andric 
361bdd1243dSDimitry Andric   // vastart just stores the address of the VarArgsFrameIndex slot into the
362bdd1243dSDimitry Andric   // memory location argument.
363bdd1243dSDimitry Andric   const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
364bdd1243dSDimitry Andric   return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
365bdd1243dSDimitry Andric                       MachinePointerInfo(SV));
36681ad6265SDimitry Andric }
36781ad6265SDimitry Andric 
368753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
369753f127fSDimitry Andric                                                  SelectionDAG &DAG) const {
370bdd1243dSDimitry Andric   assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
371bdd1243dSDimitry Andric          !Subtarget.hasBasicD() && "unexpected target features");
372753f127fSDimitry Andric 
373753f127fSDimitry Andric   SDLoc DL(Op);
374bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
375bdd1243dSDimitry Andric   if (Op0->getOpcode() == ISD::AND) {
376bdd1243dSDimitry Andric     auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
377bdd1243dSDimitry Andric     if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
378753f127fSDimitry Andric       return Op;
379bdd1243dSDimitry Andric   }
380bdd1243dSDimitry Andric 
381bdd1243dSDimitry Andric   if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
382bdd1243dSDimitry Andric       Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
383bdd1243dSDimitry Andric       Op0.getConstantOperandVal(2) == UINT64_C(0))
384bdd1243dSDimitry Andric     return Op;
385bdd1243dSDimitry Andric 
386bdd1243dSDimitry Andric   if (Op0.getOpcode() == ISD::AssertZext &&
387bdd1243dSDimitry Andric       dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
388bdd1243dSDimitry Andric     return Op;
389bdd1243dSDimitry Andric 
390bdd1243dSDimitry Andric   EVT OpVT = Op0.getValueType();
391bdd1243dSDimitry Andric   EVT RetVT = Op.getValueType();
392bdd1243dSDimitry Andric   RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
393bdd1243dSDimitry Andric   MakeLibCallOptions CallOptions;
394bdd1243dSDimitry Andric   CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
395bdd1243dSDimitry Andric   SDValue Chain = SDValue();
396bdd1243dSDimitry Andric   SDValue Result;
397bdd1243dSDimitry Andric   std::tie(Result, Chain) =
398bdd1243dSDimitry Andric       makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
399bdd1243dSDimitry Andric   return Result;
400bdd1243dSDimitry Andric }
401bdd1243dSDimitry Andric 
402bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
403bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
404bdd1243dSDimitry Andric   assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
405bdd1243dSDimitry Andric          !Subtarget.hasBasicD() && "unexpected target features");
406bdd1243dSDimitry Andric 
407bdd1243dSDimitry Andric   SDLoc DL(Op);
408bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
409bdd1243dSDimitry Andric 
410bdd1243dSDimitry Andric   if ((Op0.getOpcode() == ISD::AssertSext ||
411bdd1243dSDimitry Andric        Op0.getOpcode() == ISD::SIGN_EXTEND_INREG) &&
412bdd1243dSDimitry Andric       dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
413bdd1243dSDimitry Andric     return Op;
414bdd1243dSDimitry Andric 
415bdd1243dSDimitry Andric   EVT OpVT = Op0.getValueType();
416bdd1243dSDimitry Andric   EVT RetVT = Op.getValueType();
417bdd1243dSDimitry Andric   RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
418bdd1243dSDimitry Andric   MakeLibCallOptions CallOptions;
419bdd1243dSDimitry Andric   CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
420bdd1243dSDimitry Andric   SDValue Chain = SDValue();
421bdd1243dSDimitry Andric   SDValue Result;
422bdd1243dSDimitry Andric   std::tie(Result, Chain) =
423bdd1243dSDimitry Andric       makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
424bdd1243dSDimitry Andric   return Result;
425753f127fSDimitry Andric }
426753f127fSDimitry Andric 
427753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
428753f127fSDimitry Andric                                               SelectionDAG &DAG) const {
429753f127fSDimitry Andric 
430753f127fSDimitry Andric   SDLoc DL(Op);
431753f127fSDimitry Andric   SDValue Op0 = Op.getOperand(0);
432753f127fSDimitry Andric 
433753f127fSDimitry Andric   if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 &&
434753f127fSDimitry Andric       Subtarget.is64Bit() && Subtarget.hasBasicF()) {
435753f127fSDimitry Andric     SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
436753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
437753f127fSDimitry Andric   }
438753f127fSDimitry Andric   return Op;
439753f127fSDimitry Andric }
440753f127fSDimitry Andric 
441753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
442753f127fSDimitry Andric                                                  SelectionDAG &DAG) const {
443753f127fSDimitry Andric 
444753f127fSDimitry Andric   SDLoc DL(Op);
445753f127fSDimitry Andric 
446753f127fSDimitry Andric   if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
447753f127fSDimitry Andric       !Subtarget.hasBasicD()) {
448753f127fSDimitry Andric     SDValue Dst =
449753f127fSDimitry Andric         DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0));
450753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
451753f127fSDimitry Andric   }
452753f127fSDimitry Andric 
453753f127fSDimitry Andric   EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
454753f127fSDimitry Andric   SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0));
455753f127fSDimitry Andric   return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
456753f127fSDimitry Andric }
457753f127fSDimitry Andric 
458bdd1243dSDimitry Andric static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty,
459bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
460bdd1243dSDimitry Andric   return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
461bdd1243dSDimitry Andric }
462bdd1243dSDimitry Andric 
463bdd1243dSDimitry Andric static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty,
464bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
465bdd1243dSDimitry Andric   return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
466bdd1243dSDimitry Andric                                    Flags);
467bdd1243dSDimitry Andric }
468bdd1243dSDimitry Andric 
469bdd1243dSDimitry Andric static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty,
470bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
471bdd1243dSDimitry Andric   return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
472bdd1243dSDimitry Andric                                    N->getOffset(), Flags);
473bdd1243dSDimitry Andric }
474bdd1243dSDimitry Andric 
475bdd1243dSDimitry Andric static SDValue getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty,
476bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
477bdd1243dSDimitry Andric   return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
478bdd1243dSDimitry Andric }
479bdd1243dSDimitry Andric 
480bdd1243dSDimitry Andric template <class NodeTy>
481bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
482bdd1243dSDimitry Andric                                          bool IsLocal) const {
483bdd1243dSDimitry Andric   SDLoc DL(N);
484bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
485bdd1243dSDimitry Andric   SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
486*06c3fb27SDimitry Andric 
487*06c3fb27SDimitry Andric   switch (DAG.getTarget().getCodeModel()) {
488*06c3fb27SDimitry Andric   default:
489*06c3fb27SDimitry Andric     report_fatal_error("Unsupported code model");
490*06c3fb27SDimitry Andric 
491*06c3fb27SDimitry Andric   case CodeModel::Large: {
492*06c3fb27SDimitry Andric     assert(Subtarget.is64Bit() && "Large code model requires LA64");
493*06c3fb27SDimitry Andric 
494*06c3fb27SDimitry Andric     // This is not actually used, but is necessary for successfully matching
495*06c3fb27SDimitry Andric     // the PseudoLA_*_LARGE nodes.
496*06c3fb27SDimitry Andric     SDValue Tmp = DAG.getConstant(0, DL, Ty);
497*06c3fb27SDimitry Andric     if (IsLocal)
498*06c3fb27SDimitry Andric       // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that
499*06c3fb27SDimitry Andric       // eventually becomes the desired 5-insn code sequence.
500*06c3fb27SDimitry Andric       return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty,
501*06c3fb27SDimitry Andric                                         Tmp, Addr),
502*06c3fb27SDimitry Andric                      0);
503*06c3fb27SDimitry Andric 
504*06c3fb27SDimitry Andric     // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that eventually
505*06c3fb27SDimitry Andric     // becomes the desired 5-insn code sequence.
506*06c3fb27SDimitry Andric     return SDValue(
507*06c3fb27SDimitry Andric         DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr),
508*06c3fb27SDimitry Andric         0);
509*06c3fb27SDimitry Andric   }
510*06c3fb27SDimitry Andric 
511*06c3fb27SDimitry Andric   case CodeModel::Small:
512*06c3fb27SDimitry Andric   case CodeModel::Medium:
513bdd1243dSDimitry Andric     if (IsLocal)
514bdd1243dSDimitry Andric       // This generates the pattern (PseudoLA_PCREL sym), which expands to
515bdd1243dSDimitry Andric       // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
516*06c3fb27SDimitry Andric       return SDValue(
517*06c3fb27SDimitry Andric           DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0);
518bdd1243dSDimitry Andric 
519bdd1243dSDimitry Andric     // This generates the pattern (PseudoLA_GOT sym), which expands to (ld.w/d
520bdd1243dSDimitry Andric     // (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
521*06c3fb27SDimitry Andric     return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr),
522*06c3fb27SDimitry Andric                    0);
523*06c3fb27SDimitry Andric   }
524bdd1243dSDimitry Andric }
525bdd1243dSDimitry Andric 
526bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
527bdd1243dSDimitry Andric                                                    SelectionDAG &DAG) const {
528bdd1243dSDimitry Andric   return getAddr(cast<BlockAddressSDNode>(Op), DAG);
529bdd1243dSDimitry Andric }
530bdd1243dSDimitry Andric 
531bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
532bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
533bdd1243dSDimitry Andric   return getAddr(cast<JumpTableSDNode>(Op), DAG);
534bdd1243dSDimitry Andric }
535bdd1243dSDimitry Andric 
536753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
537753f127fSDimitry Andric                                                    SelectionDAG &DAG) const {
538bdd1243dSDimitry Andric   return getAddr(cast<ConstantPoolSDNode>(Op), DAG);
539753f127fSDimitry Andric }
540753f127fSDimitry Andric 
541753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
542753f127fSDimitry Andric                                                     SelectionDAG &DAG) const {
543bdd1243dSDimitry Andric   GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
544bdd1243dSDimitry Andric   assert(N->getOffset() == 0 && "unexpected offset in global node");
545bdd1243dSDimitry Andric   return getAddr(N, DAG, N->getGlobal()->isDSOLocal());
546bdd1243dSDimitry Andric }
547753f127fSDimitry Andric 
548bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
549bdd1243dSDimitry Andric                                                   SelectionDAG &DAG,
550*06c3fb27SDimitry Andric                                                   unsigned Opc,
551*06c3fb27SDimitry Andric                                                   bool Large) const {
552bdd1243dSDimitry Andric   SDLoc DL(N);
553bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
554bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
555bdd1243dSDimitry Andric 
556*06c3fb27SDimitry Andric   // This is not actually used, but is necessary for successfully matching the
557*06c3fb27SDimitry Andric   // PseudoLA_*_LARGE nodes.
558*06c3fb27SDimitry Andric   SDValue Tmp = DAG.getConstant(0, DL, Ty);
559bdd1243dSDimitry Andric   SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
560*06c3fb27SDimitry Andric   SDValue Offset = Large
561*06c3fb27SDimitry Andric                        ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
562*06c3fb27SDimitry Andric                        : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
563bdd1243dSDimitry Andric 
564bdd1243dSDimitry Andric   // Add the thread pointer.
565bdd1243dSDimitry Andric   return DAG.getNode(ISD::ADD, DL, Ty, Offset,
566bdd1243dSDimitry Andric                      DAG.getRegister(LoongArch::R2, GRLenVT));
567bdd1243dSDimitry Andric }
568bdd1243dSDimitry Andric 
569bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
570bdd1243dSDimitry Andric                                                    SelectionDAG &DAG,
571*06c3fb27SDimitry Andric                                                    unsigned Opc,
572*06c3fb27SDimitry Andric                                                    bool Large) const {
573bdd1243dSDimitry Andric   SDLoc DL(N);
574bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
575bdd1243dSDimitry Andric   IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
576bdd1243dSDimitry Andric 
577*06c3fb27SDimitry Andric   // This is not actually used, but is necessary for successfully matching the
578*06c3fb27SDimitry Andric   // PseudoLA_*_LARGE nodes.
579*06c3fb27SDimitry Andric   SDValue Tmp = DAG.getConstant(0, DL, Ty);
580*06c3fb27SDimitry Andric 
581bdd1243dSDimitry Andric   // Use a PC-relative addressing mode to access the dynamic GOT address.
582bdd1243dSDimitry Andric   SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
583*06c3fb27SDimitry Andric   SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
584*06c3fb27SDimitry Andric                        : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
585bdd1243dSDimitry Andric 
586bdd1243dSDimitry Andric   // Prepare argument list to generate call.
587bdd1243dSDimitry Andric   ArgListTy Args;
588bdd1243dSDimitry Andric   ArgListEntry Entry;
589bdd1243dSDimitry Andric   Entry.Node = Load;
590bdd1243dSDimitry Andric   Entry.Ty = CallTy;
591bdd1243dSDimitry Andric   Args.push_back(Entry);
592bdd1243dSDimitry Andric 
593bdd1243dSDimitry Andric   // Setup call to __tls_get_addr.
594bdd1243dSDimitry Andric   TargetLowering::CallLoweringInfo CLI(DAG);
595bdd1243dSDimitry Andric   CLI.setDebugLoc(DL)
596bdd1243dSDimitry Andric       .setChain(DAG.getEntryNode())
597bdd1243dSDimitry Andric       .setLibCallee(CallingConv::C, CallTy,
598bdd1243dSDimitry Andric                     DAG.getExternalSymbol("__tls_get_addr", Ty),
599bdd1243dSDimitry Andric                     std::move(Args));
600bdd1243dSDimitry Andric 
601bdd1243dSDimitry Andric   return LowerCallTo(CLI).first;
602bdd1243dSDimitry Andric }
603bdd1243dSDimitry Andric 
604bdd1243dSDimitry Andric SDValue
605bdd1243dSDimitry Andric LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
606bdd1243dSDimitry Andric                                                SelectionDAG &DAG) const {
607bdd1243dSDimitry Andric   if (DAG.getMachineFunction().getFunction().getCallingConv() ==
608bdd1243dSDimitry Andric       CallingConv::GHC)
609bdd1243dSDimitry Andric     report_fatal_error("In GHC calling convention TLS is not supported");
610bdd1243dSDimitry Andric 
611*06c3fb27SDimitry Andric   bool Large = DAG.getTarget().getCodeModel() == CodeModel::Large;
612*06c3fb27SDimitry Andric   assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64");
613*06c3fb27SDimitry Andric 
614bdd1243dSDimitry Andric   GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
615bdd1243dSDimitry Andric   assert(N->getOffset() == 0 && "unexpected offset in global node");
616bdd1243dSDimitry Andric 
617bdd1243dSDimitry Andric   SDValue Addr;
618bdd1243dSDimitry Andric   switch (getTargetMachine().getTLSModel(N->getGlobal())) {
619bdd1243dSDimitry Andric   case TLSModel::GeneralDynamic:
620bdd1243dSDimitry Andric     // In this model, application code calls the dynamic linker function
621bdd1243dSDimitry Andric     // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
622bdd1243dSDimitry Andric     // runtime.
623*06c3fb27SDimitry Andric     Addr = getDynamicTLSAddr(N, DAG,
624*06c3fb27SDimitry Andric                              Large ? LoongArch::PseudoLA_TLS_GD_LARGE
625*06c3fb27SDimitry Andric                                    : LoongArch::PseudoLA_TLS_GD,
626*06c3fb27SDimitry Andric                              Large);
627bdd1243dSDimitry Andric     break;
628bdd1243dSDimitry Andric   case TLSModel::LocalDynamic:
629bdd1243dSDimitry Andric     // Same as GeneralDynamic, except for assembly modifiers and relocation
630bdd1243dSDimitry Andric     // records.
631*06c3fb27SDimitry Andric     Addr = getDynamicTLSAddr(N, DAG,
632*06c3fb27SDimitry Andric                              Large ? LoongArch::PseudoLA_TLS_LD_LARGE
633*06c3fb27SDimitry Andric                                    : LoongArch::PseudoLA_TLS_LD,
634*06c3fb27SDimitry Andric                              Large);
635bdd1243dSDimitry Andric     break;
636bdd1243dSDimitry Andric   case TLSModel::InitialExec:
637bdd1243dSDimitry Andric     // This model uses the GOT to resolve TLS offsets.
638*06c3fb27SDimitry Andric     Addr = getStaticTLSAddr(N, DAG,
639*06c3fb27SDimitry Andric                             Large ? LoongArch::PseudoLA_TLS_IE_LARGE
640*06c3fb27SDimitry Andric                                   : LoongArch::PseudoLA_TLS_IE,
641*06c3fb27SDimitry Andric                             Large);
642bdd1243dSDimitry Andric     break;
643bdd1243dSDimitry Andric   case TLSModel::LocalExec:
644bdd1243dSDimitry Andric     // This model is used when static linking as the TLS offsets are resolved
645bdd1243dSDimitry Andric     // during program linking.
646*06c3fb27SDimitry Andric     //
647*06c3fb27SDimitry Andric     // This node doesn't need an extra argument for the large code model.
648bdd1243dSDimitry Andric     Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE);
649bdd1243dSDimitry Andric     break;
650bdd1243dSDimitry Andric   }
651bdd1243dSDimitry Andric 
652753f127fSDimitry Andric   return Addr;
653753f127fSDimitry Andric }
654bdd1243dSDimitry Andric 
655bdd1243dSDimitry Andric SDValue
656bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
657bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
658bdd1243dSDimitry Andric   switch (Op.getConstantOperandVal(0)) {
659bdd1243dSDimitry Andric   default:
660bdd1243dSDimitry Andric     return SDValue(); // Don't custom lower most intrinsics.
661bdd1243dSDimitry Andric   case Intrinsic::thread_pointer: {
662bdd1243dSDimitry Andric     EVT PtrVT = getPointerTy(DAG.getDataLayout());
663bdd1243dSDimitry Andric     return DAG.getRegister(LoongArch::R2, PtrVT);
664bdd1243dSDimitry Andric   }
665bdd1243dSDimitry Andric   }
666bdd1243dSDimitry Andric }
667bdd1243dSDimitry Andric 
668*06c3fb27SDimitry Andric // Helper function that emits error message for intrinsics with chain and return
669*06c3fb27SDimitry Andric // merge values of a UNDEF and the chain.
670bdd1243dSDimitry Andric static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op,
671bdd1243dSDimitry Andric                                                   StringRef ErrorMsg,
672bdd1243dSDimitry Andric                                                   SelectionDAG &DAG) {
673*06c3fb27SDimitry Andric   DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
674bdd1243dSDimitry Andric   return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
675bdd1243dSDimitry Andric                             SDLoc(Op));
676bdd1243dSDimitry Andric }
677bdd1243dSDimitry Andric 
678bdd1243dSDimitry Andric SDValue
679bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
680bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
681bdd1243dSDimitry Andric   SDLoc DL(Op);
682bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
683*06c3fb27SDimitry Andric   EVT VT = Op.getValueType();
684*06c3fb27SDimitry Andric   SDValue Chain = Op.getOperand(0);
685*06c3fb27SDimitry Andric   const StringRef ErrorMsgOOR = "argument out of range";
686*06c3fb27SDimitry Andric   const StringRef ErrorMsgReqLA64 = "requires loongarch64";
687*06c3fb27SDimitry Andric   const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
688bdd1243dSDimitry Andric 
689bdd1243dSDimitry Andric   switch (Op.getConstantOperandVal(1)) {
690bdd1243dSDimitry Andric   default:
691bdd1243dSDimitry Andric     return Op;
692bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_b_w:
693bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_h_w:
694bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_w_w:
695bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_d_w:
696bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_b_w:
697bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_h_w:
698bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_w_w:
699*06c3fb27SDimitry Andric   case Intrinsic::loongarch_crcc_w_d_w:
700*06c3fb27SDimitry Andric     return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG);
701bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrrd_w:
702bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrrd_d: {
703bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
704*06c3fb27SDimitry Andric     return !isUInt<14>(Imm)
705*06c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
706*06c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
707*06c3fb27SDimitry Andric                              {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
708bdd1243dSDimitry Andric   }
709bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrwr_w:
710bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrwr_d: {
711bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
712*06c3fb27SDimitry Andric     return !isUInt<14>(Imm)
713*06c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
714*06c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
715*06c3fb27SDimitry Andric                              {Chain, Op.getOperand(2),
716*06c3fb27SDimitry Andric                               DAG.getConstant(Imm, DL, GRLenVT)});
717bdd1243dSDimitry Andric   }
718bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrxchg_w:
719bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrxchg_d: {
720bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(4))->getZExtValue();
721*06c3fb27SDimitry Andric     return !isUInt<14>(Imm)
722*06c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
723*06c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
724*06c3fb27SDimitry Andric                              {Chain, Op.getOperand(2), Op.getOperand(3),
725*06c3fb27SDimitry Andric                               DAG.getConstant(Imm, DL, GRLenVT)});
726bdd1243dSDimitry Andric   }
727bdd1243dSDimitry Andric   case Intrinsic::loongarch_iocsrrd_d: {
728*06c3fb27SDimitry Andric     return DAG.getNode(
729*06c3fb27SDimitry Andric         LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other},
730*06c3fb27SDimitry Andric         {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))});
731bdd1243dSDimitry Andric   }
732bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE)                                               \
733bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
734*06c3fb27SDimitry Andric     return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other},          \
735*06c3fb27SDimitry Andric                        {Chain, Op.getOperand(2)});                             \
736bdd1243dSDimitry Andric   }
737bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
738bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
739bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
740bdd1243dSDimitry Andric #undef IOCSRRD_CASE
741bdd1243dSDimitry Andric   case Intrinsic::loongarch_cpucfg: {
742*06c3fb27SDimitry Andric     return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
743*06c3fb27SDimitry Andric                        {Chain, Op.getOperand(2)});
744bdd1243dSDimitry Andric   }
745bdd1243dSDimitry Andric   case Intrinsic::loongarch_lddir_d: {
746bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
747*06c3fb27SDimitry Andric     return !isUInt<8>(Imm)
748*06c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
749*06c3fb27SDimitry Andric                : Op;
750bdd1243dSDimitry Andric   }
751bdd1243dSDimitry Andric   case Intrinsic::loongarch_movfcsr2gr: {
752*06c3fb27SDimitry Andric     if (!Subtarget.hasBasicF())
753*06c3fb27SDimitry Andric       return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG);
754bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
755*06c3fb27SDimitry Andric     return !isUInt<2>(Imm)
756*06c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
757*06c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other},
758*06c3fb27SDimitry Andric                              {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
759bdd1243dSDimitry Andric   }
760bdd1243dSDimitry Andric   }
761bdd1243dSDimitry Andric }
762bdd1243dSDimitry Andric 
763bdd1243dSDimitry Andric // Helper function that emits error message for intrinsics with void return
764*06c3fb27SDimitry Andric // value and return the chain.
765bdd1243dSDimitry Andric static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg,
766bdd1243dSDimitry Andric                                          SelectionDAG &DAG) {
767bdd1243dSDimitry Andric 
768*06c3fb27SDimitry Andric   DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
769bdd1243dSDimitry Andric   return Op.getOperand(0);
770bdd1243dSDimitry Andric }
771bdd1243dSDimitry Andric 
772bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
773bdd1243dSDimitry Andric                                                      SelectionDAG &DAG) const {
774bdd1243dSDimitry Andric   SDLoc DL(Op);
775bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
776*06c3fb27SDimitry Andric   SDValue Chain = Op.getOperand(0);
777bdd1243dSDimitry Andric   uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
778bdd1243dSDimitry Andric   SDValue Op2 = Op.getOperand(2);
779*06c3fb27SDimitry Andric   const StringRef ErrorMsgOOR = "argument out of range";
780*06c3fb27SDimitry Andric   const StringRef ErrorMsgReqLA64 = "requires loongarch64";
781*06c3fb27SDimitry Andric   const StringRef ErrorMsgReqLA32 = "requires loongarch32";
782*06c3fb27SDimitry Andric   const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
783bdd1243dSDimitry Andric 
784bdd1243dSDimitry Andric   switch (IntrinsicEnum) {
785bdd1243dSDimitry Andric   default:
786bdd1243dSDimitry Andric     // TODO: Add more Intrinsics.
787bdd1243dSDimitry Andric     return SDValue();
788bdd1243dSDimitry Andric   case Intrinsic::loongarch_cacop_d:
789bdd1243dSDimitry Andric   case Intrinsic::loongarch_cacop_w: {
790*06c3fb27SDimitry Andric     if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit())
791*06c3fb27SDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG);
792*06c3fb27SDimitry Andric     if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit())
793*06c3fb27SDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG);
794bdd1243dSDimitry Andric     // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
795bdd1243dSDimitry Andric     unsigned Imm1 = cast<ConstantSDNode>(Op2)->getZExtValue();
796*06c3fb27SDimitry Andric     int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue();
797*06c3fb27SDimitry Andric     if (!isUInt<5>(Imm1) || !isInt<12>(Imm2))
798bdd1243dSDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
799bdd1243dSDimitry Andric     return Op;
800bdd1243dSDimitry Andric   }
801bdd1243dSDimitry Andric   case Intrinsic::loongarch_dbar: {
802bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
803*06c3fb27SDimitry Andric     return !isUInt<15>(Imm)
804*06c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
805*06c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain,
806bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
807bdd1243dSDimitry Andric   }
808bdd1243dSDimitry Andric   case Intrinsic::loongarch_ibar: {
809bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
810*06c3fb27SDimitry Andric     return !isUInt<15>(Imm)
811*06c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
812*06c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain,
813bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
814bdd1243dSDimitry Andric   }
815bdd1243dSDimitry Andric   case Intrinsic::loongarch_break: {
816bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
817*06c3fb27SDimitry Andric     return !isUInt<15>(Imm)
818*06c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
819*06c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain,
820bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
821bdd1243dSDimitry Andric   }
822bdd1243dSDimitry Andric   case Intrinsic::loongarch_movgr2fcsr: {
823*06c3fb27SDimitry Andric     if (!Subtarget.hasBasicF())
824*06c3fb27SDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG);
825bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
826*06c3fb27SDimitry Andric     return !isUInt<2>(Imm)
827*06c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
828*06c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain,
829bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT),
830*06c3fb27SDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT,
831*06c3fb27SDimitry Andric                                          Op.getOperand(3)));
832bdd1243dSDimitry Andric   }
833bdd1243dSDimitry Andric   case Intrinsic::loongarch_syscall: {
834bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
835*06c3fb27SDimitry Andric     return !isUInt<15>(Imm)
836*06c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
837*06c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain,
838bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
839bdd1243dSDimitry Andric   }
840bdd1243dSDimitry Andric #define IOCSRWR_CASE(NAME, NODE)                                               \
841bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
842bdd1243dSDimitry Andric     SDValue Op3 = Op.getOperand(3);                                            \
843*06c3fb27SDimitry Andric     return Subtarget.is64Bit()                                                 \
844*06c3fb27SDimitry Andric                ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain,        \
845bdd1243dSDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),  \
846*06c3fb27SDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3))  \
847*06c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2,   \
848*06c3fb27SDimitry Andric                              Op3);                                             \
849bdd1243dSDimitry Andric   }
850bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
851bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
852bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
853bdd1243dSDimitry Andric #undef IOCSRWR_CASE
854bdd1243dSDimitry Andric   case Intrinsic::loongarch_iocsrwr_d: {
855*06c3fb27SDimitry Andric     return !Subtarget.is64Bit()
856*06c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
857*06c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain,
858*06c3fb27SDimitry Andric                              Op2,
859*06c3fb27SDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
860*06c3fb27SDimitry Andric                                          Op.getOperand(3)));
861bdd1243dSDimitry Andric   }
862bdd1243dSDimitry Andric #define ASRT_LE_GT_CASE(NAME)                                                  \
863bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
864*06c3fb27SDimitry Andric     return !Subtarget.is64Bit()                                                \
865*06c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)           \
866*06c3fb27SDimitry Andric                : Op;                                                           \
867bdd1243dSDimitry Andric   }
868bdd1243dSDimitry Andric     ASRT_LE_GT_CASE(asrtle_d)
869bdd1243dSDimitry Andric     ASRT_LE_GT_CASE(asrtgt_d)
870bdd1243dSDimitry Andric #undef ASRT_LE_GT_CASE
871bdd1243dSDimitry Andric   case Intrinsic::loongarch_ldpte_d: {
872bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
873*06c3fb27SDimitry Andric     return !Subtarget.is64Bit()
874*06c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
875*06c3fb27SDimitry Andric            : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
876*06c3fb27SDimitry Andric                              : Op;
877bdd1243dSDimitry Andric   }
878bdd1243dSDimitry Andric   }
879753f127fSDimitry Andric }
880753f127fSDimitry Andric 
88181ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
88281ad6265SDimitry Andric                                                      SelectionDAG &DAG) const {
88381ad6265SDimitry Andric   SDLoc DL(Op);
88481ad6265SDimitry Andric   SDValue Lo = Op.getOperand(0);
88581ad6265SDimitry Andric   SDValue Hi = Op.getOperand(1);
88681ad6265SDimitry Andric   SDValue Shamt = Op.getOperand(2);
88781ad6265SDimitry Andric   EVT VT = Lo.getValueType();
88881ad6265SDimitry Andric 
88981ad6265SDimitry Andric   // if Shamt-GRLen < 0: // Shamt < GRLen
89081ad6265SDimitry Andric   //   Lo = Lo << Shamt
89181ad6265SDimitry Andric   //   Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
89281ad6265SDimitry Andric   // else:
89381ad6265SDimitry Andric   //   Lo = 0
89481ad6265SDimitry Andric   //   Hi = Lo << (Shamt-GRLen)
89581ad6265SDimitry Andric 
89681ad6265SDimitry Andric   SDValue Zero = DAG.getConstant(0, DL, VT);
89781ad6265SDimitry Andric   SDValue One = DAG.getConstant(1, DL, VT);
89881ad6265SDimitry Andric   SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
89981ad6265SDimitry Andric   SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
90081ad6265SDimitry Andric   SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
90181ad6265SDimitry Andric   SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
90281ad6265SDimitry Andric 
90381ad6265SDimitry Andric   SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
90481ad6265SDimitry Andric   SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
90581ad6265SDimitry Andric   SDValue ShiftRightLo =
90681ad6265SDimitry Andric       DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
90781ad6265SDimitry Andric   SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
90881ad6265SDimitry Andric   SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
90981ad6265SDimitry Andric   SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
91081ad6265SDimitry Andric 
91181ad6265SDimitry Andric   SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
91281ad6265SDimitry Andric 
91381ad6265SDimitry Andric   Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
91481ad6265SDimitry Andric   Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
91581ad6265SDimitry Andric 
91681ad6265SDimitry Andric   SDValue Parts[2] = {Lo, Hi};
91781ad6265SDimitry Andric   return DAG.getMergeValues(Parts, DL);
91881ad6265SDimitry Andric }
91981ad6265SDimitry Andric 
92081ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
92181ad6265SDimitry Andric                                                       SelectionDAG &DAG,
92281ad6265SDimitry Andric                                                       bool IsSRA) const {
92381ad6265SDimitry Andric   SDLoc DL(Op);
92481ad6265SDimitry Andric   SDValue Lo = Op.getOperand(0);
92581ad6265SDimitry Andric   SDValue Hi = Op.getOperand(1);
92681ad6265SDimitry Andric   SDValue Shamt = Op.getOperand(2);
92781ad6265SDimitry Andric   EVT VT = Lo.getValueType();
92881ad6265SDimitry Andric 
92981ad6265SDimitry Andric   // SRA expansion:
93081ad6265SDimitry Andric   //   if Shamt-GRLen < 0: // Shamt < GRLen
93181ad6265SDimitry Andric   //     Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
93281ad6265SDimitry Andric   //     Hi = Hi >>s Shamt
93381ad6265SDimitry Andric   //   else:
93481ad6265SDimitry Andric   //     Lo = Hi >>s (Shamt-GRLen);
93581ad6265SDimitry Andric   //     Hi = Hi >>s (GRLen-1)
93681ad6265SDimitry Andric   //
93781ad6265SDimitry Andric   // SRL expansion:
93881ad6265SDimitry Andric   //   if Shamt-GRLen < 0: // Shamt < GRLen
93981ad6265SDimitry Andric   //     Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
94081ad6265SDimitry Andric   //     Hi = Hi >>u Shamt
94181ad6265SDimitry Andric   //   else:
94281ad6265SDimitry Andric   //     Lo = Hi >>u (Shamt-GRLen);
94381ad6265SDimitry Andric   //     Hi = 0;
94481ad6265SDimitry Andric 
94581ad6265SDimitry Andric   unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
94681ad6265SDimitry Andric 
94781ad6265SDimitry Andric   SDValue Zero = DAG.getConstant(0, DL, VT);
94881ad6265SDimitry Andric   SDValue One = DAG.getConstant(1, DL, VT);
94981ad6265SDimitry Andric   SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
95081ad6265SDimitry Andric   SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
95181ad6265SDimitry Andric   SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
95281ad6265SDimitry Andric   SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
95381ad6265SDimitry Andric 
95481ad6265SDimitry Andric   SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
95581ad6265SDimitry Andric   SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
95681ad6265SDimitry Andric   SDValue ShiftLeftHi =
95781ad6265SDimitry Andric       DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
95881ad6265SDimitry Andric   SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
95981ad6265SDimitry Andric   SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
96081ad6265SDimitry Andric   SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
96181ad6265SDimitry Andric   SDValue HiFalse =
96281ad6265SDimitry Andric       IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
96381ad6265SDimitry Andric 
96481ad6265SDimitry Andric   SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
96581ad6265SDimitry Andric 
96681ad6265SDimitry Andric   Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
96781ad6265SDimitry Andric   Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
96881ad6265SDimitry Andric 
96981ad6265SDimitry Andric   SDValue Parts[2] = {Lo, Hi};
97081ad6265SDimitry Andric   return DAG.getMergeValues(Parts, DL);
97181ad6265SDimitry Andric }
97281ad6265SDimitry Andric 
97381ad6265SDimitry Andric // Returns the opcode of the target-specific SDNode that implements the 32-bit
97481ad6265SDimitry Andric // form of the given Opcode.
97581ad6265SDimitry Andric static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode) {
97681ad6265SDimitry Andric   switch (Opcode) {
97781ad6265SDimitry Andric   default:
97881ad6265SDimitry Andric     llvm_unreachable("Unexpected opcode");
97981ad6265SDimitry Andric   case ISD::SHL:
98081ad6265SDimitry Andric     return LoongArchISD::SLL_W;
98181ad6265SDimitry Andric   case ISD::SRA:
98281ad6265SDimitry Andric     return LoongArchISD::SRA_W;
98381ad6265SDimitry Andric   case ISD::SRL:
98481ad6265SDimitry Andric     return LoongArchISD::SRL_W;
985bdd1243dSDimitry Andric   case ISD::ROTR:
986bdd1243dSDimitry Andric     return LoongArchISD::ROTR_W;
987bdd1243dSDimitry Andric   case ISD::ROTL:
988bdd1243dSDimitry Andric     return LoongArchISD::ROTL_W;
989bdd1243dSDimitry Andric   case ISD::CTTZ:
990bdd1243dSDimitry Andric     return LoongArchISD::CTZ_W;
991bdd1243dSDimitry Andric   case ISD::CTLZ:
992bdd1243dSDimitry Andric     return LoongArchISD::CLZ_W;
99381ad6265SDimitry Andric   }
99481ad6265SDimitry Andric }
99581ad6265SDimitry Andric 
99681ad6265SDimitry Andric // Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
99781ad6265SDimitry Andric // node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
99881ad6265SDimitry Andric // otherwise be promoted to i64, making it difficult to select the
99981ad6265SDimitry Andric // SLL_W/.../*W later one because the fact the operation was originally of
100081ad6265SDimitry Andric // type i8/i16/i32 is lost.
1001bdd1243dSDimitry Andric static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp,
100281ad6265SDimitry Andric                                    unsigned ExtOpc = ISD::ANY_EXTEND) {
100381ad6265SDimitry Andric   SDLoc DL(N);
100481ad6265SDimitry Andric   LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode());
1005bdd1243dSDimitry Andric   SDValue NewOp0, NewRes;
1006bdd1243dSDimitry Andric 
1007bdd1243dSDimitry Andric   switch (NumOp) {
1008bdd1243dSDimitry Andric   default:
1009bdd1243dSDimitry Andric     llvm_unreachable("Unexpected NumOp");
1010bdd1243dSDimitry Andric   case 1: {
1011bdd1243dSDimitry Andric     NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
1012bdd1243dSDimitry Andric     NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
1013bdd1243dSDimitry Andric     break;
1014bdd1243dSDimitry Andric   }
1015bdd1243dSDimitry Andric   case 2: {
1016bdd1243dSDimitry Andric     NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
101781ad6265SDimitry Andric     SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
1018bdd1243dSDimitry Andric     NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
1019bdd1243dSDimitry Andric     break;
1020bdd1243dSDimitry Andric   }
1021bdd1243dSDimitry Andric     // TODO:Handle more NumOp.
1022bdd1243dSDimitry Andric   }
1023bdd1243dSDimitry Andric 
1024bdd1243dSDimitry Andric   // ReplaceNodeResults requires we maintain the same type for the return
1025bdd1243dSDimitry Andric   // value.
102681ad6265SDimitry Andric   return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
102781ad6265SDimitry Andric }
102881ad6265SDimitry Andric 
1029*06c3fb27SDimitry Andric // Helper function that emits error message for intrinsics with chain and return
1030*06c3fb27SDimitry Andric // a UNDEF and the chain as the results.
1031*06c3fb27SDimitry Andric static void emitErrorAndReplaceIntrinsicWithChainResults(
1032*06c3fb27SDimitry Andric     SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG,
1033*06c3fb27SDimitry Andric     StringRef ErrorMsg) {
1034*06c3fb27SDimitry Andric   DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
1035*06c3fb27SDimitry Andric   Results.push_back(DAG.getUNDEF(N->getValueType(0)));
1036*06c3fb27SDimitry Andric   Results.push_back(N->getOperand(0));
1037*06c3fb27SDimitry Andric }
1038*06c3fb27SDimitry Andric 
103981ad6265SDimitry Andric void LoongArchTargetLowering::ReplaceNodeResults(
104081ad6265SDimitry Andric     SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
104181ad6265SDimitry Andric   SDLoc DL(N);
1042bdd1243dSDimitry Andric   EVT VT = N->getValueType(0);
104381ad6265SDimitry Andric   switch (N->getOpcode()) {
104481ad6265SDimitry Andric   default:
104581ad6265SDimitry Andric     llvm_unreachable("Don't know how to legalize this operation");
104681ad6265SDimitry Andric   case ISD::SHL:
104781ad6265SDimitry Andric   case ISD::SRA:
104881ad6265SDimitry Andric   case ISD::SRL:
1049bdd1243dSDimitry Andric   case ISD::ROTR:
1050bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
105181ad6265SDimitry Andric            "Unexpected custom legalisation");
105281ad6265SDimitry Andric     if (N->getOperand(1).getOpcode() != ISD::Constant) {
1053bdd1243dSDimitry Andric       Results.push_back(customLegalizeToWOp(N, DAG, 2));
1054bdd1243dSDimitry Andric       break;
1055bdd1243dSDimitry Andric     }
1056bdd1243dSDimitry Andric     break;
1057bdd1243dSDimitry Andric   case ISD::ROTL:
1058bdd1243dSDimitry Andric     ConstantSDNode *CN;
1059bdd1243dSDimitry Andric     if ((CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) {
1060bdd1243dSDimitry Andric       Results.push_back(customLegalizeToWOp(N, DAG, 2));
106181ad6265SDimitry Andric       break;
106281ad6265SDimitry Andric     }
106381ad6265SDimitry Andric     break;
1064753f127fSDimitry Andric   case ISD::FP_TO_SINT: {
1065bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1066753f127fSDimitry Andric            "Unexpected custom legalisation");
1067753f127fSDimitry Andric     SDValue Src = N->getOperand(0);
1068bdd1243dSDimitry Andric     EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
1069bdd1243dSDimitry Andric     if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
1070bdd1243dSDimitry Andric         TargetLowering::TypeSoftenFloat) {
1071bdd1243dSDimitry Andric       SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
1072bdd1243dSDimitry Andric       Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
1073bdd1243dSDimitry Andric       return;
1074bdd1243dSDimitry Andric     }
1075bdd1243dSDimitry Andric     // If the FP type needs to be softened, emit a library call using the 'si'
1076bdd1243dSDimitry Andric     // version. If we left it to default legalization we'd end up with 'di'.
1077bdd1243dSDimitry Andric     RTLIB::Libcall LC;
1078bdd1243dSDimitry Andric     LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
1079bdd1243dSDimitry Andric     MakeLibCallOptions CallOptions;
1080bdd1243dSDimitry Andric     EVT OpVT = Src.getValueType();
1081bdd1243dSDimitry Andric     CallOptions.setTypeListBeforeSoften(OpVT, VT, true);
1082bdd1243dSDimitry Andric     SDValue Chain = SDValue();
1083bdd1243dSDimitry Andric     SDValue Result;
1084bdd1243dSDimitry Andric     std::tie(Result, Chain) =
1085bdd1243dSDimitry Andric         makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
1086bdd1243dSDimitry Andric     Results.push_back(Result);
1087753f127fSDimitry Andric     break;
1088753f127fSDimitry Andric   }
1089753f127fSDimitry Andric   case ISD::BITCAST: {
1090753f127fSDimitry Andric     SDValue Src = N->getOperand(0);
1091753f127fSDimitry Andric     EVT SrcVT = Src.getValueType();
1092753f127fSDimitry Andric     if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
1093753f127fSDimitry Andric         Subtarget.hasBasicF()) {
1094753f127fSDimitry Andric       SDValue Dst =
1095753f127fSDimitry Andric           DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
1096753f127fSDimitry Andric       Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
1097753f127fSDimitry Andric     }
1098753f127fSDimitry Andric     break;
1099753f127fSDimitry Andric   }
1100753f127fSDimitry Andric   case ISD::FP_TO_UINT: {
1101bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1102753f127fSDimitry Andric            "Unexpected custom legalisation");
1103753f127fSDimitry Andric     auto &TLI = DAG.getTargetLoweringInfo();
1104753f127fSDimitry Andric     SDValue Tmp1, Tmp2;
1105753f127fSDimitry Andric     TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
1106753f127fSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
1107753f127fSDimitry Andric     break;
1108753f127fSDimitry Andric   }
1109bdd1243dSDimitry Andric   case ISD::BSWAP: {
1110bdd1243dSDimitry Andric     SDValue Src = N->getOperand(0);
1111bdd1243dSDimitry Andric     assert((VT == MVT::i16 || VT == MVT::i32) &&
1112bdd1243dSDimitry Andric            "Unexpected custom legalization");
1113bdd1243dSDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
1114bdd1243dSDimitry Andric     SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1115bdd1243dSDimitry Andric     SDValue Tmp;
1116bdd1243dSDimitry Andric     switch (VT.getSizeInBits()) {
1117bdd1243dSDimitry Andric     default:
1118bdd1243dSDimitry Andric       llvm_unreachable("Unexpected operand width");
1119bdd1243dSDimitry Andric     case 16:
1120bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
1121bdd1243dSDimitry Andric       break;
1122bdd1243dSDimitry Andric     case 32:
1123bdd1243dSDimitry Andric       // Only LA64 will get to here due to the size mismatch between VT and
1124bdd1243dSDimitry Andric       // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
1125bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
1126bdd1243dSDimitry Andric       break;
1127bdd1243dSDimitry Andric     }
1128bdd1243dSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
1129bdd1243dSDimitry Andric     break;
1130bdd1243dSDimitry Andric   }
1131bdd1243dSDimitry Andric   case ISD::BITREVERSE: {
1132bdd1243dSDimitry Andric     SDValue Src = N->getOperand(0);
1133bdd1243dSDimitry Andric     assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
1134bdd1243dSDimitry Andric            "Unexpected custom legalization");
1135bdd1243dSDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
1136bdd1243dSDimitry Andric     SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1137bdd1243dSDimitry Andric     SDValue Tmp;
1138bdd1243dSDimitry Andric     switch (VT.getSizeInBits()) {
1139bdd1243dSDimitry Andric     default:
1140bdd1243dSDimitry Andric       llvm_unreachable("Unexpected operand width");
1141bdd1243dSDimitry Andric     case 8:
1142bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
1143bdd1243dSDimitry Andric       break;
1144bdd1243dSDimitry Andric     case 32:
1145bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
1146bdd1243dSDimitry Andric       break;
1147bdd1243dSDimitry Andric     }
1148bdd1243dSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
1149bdd1243dSDimitry Andric     break;
1150bdd1243dSDimitry Andric   }
1151bdd1243dSDimitry Andric   case ISD::CTLZ:
1152bdd1243dSDimitry Andric   case ISD::CTTZ: {
1153bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1154bdd1243dSDimitry Andric            "Unexpected custom legalisation");
1155bdd1243dSDimitry Andric     Results.push_back(customLegalizeToWOp(N, DAG, 1));
1156bdd1243dSDimitry Andric     break;
1157bdd1243dSDimitry Andric   }
1158bdd1243dSDimitry Andric   case ISD::INTRINSIC_W_CHAIN: {
1159*06c3fb27SDimitry Andric     SDValue Chain = N->getOperand(0);
1160bdd1243dSDimitry Andric     SDValue Op2 = N->getOperand(2);
1161*06c3fb27SDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
1162*06c3fb27SDimitry Andric     const StringRef ErrorMsgOOR = "argument out of range";
1163*06c3fb27SDimitry Andric     const StringRef ErrorMsgReqLA64 = "requires loongarch64";
1164*06c3fb27SDimitry Andric     const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
1165bdd1243dSDimitry Andric 
1166*06c3fb27SDimitry Andric     switch (N->getConstantOperandVal(1)) {
1167bdd1243dSDimitry Andric     default:
1168bdd1243dSDimitry Andric       llvm_unreachable("Unexpected Intrinsic.");
1169*06c3fb27SDimitry Andric     case Intrinsic::loongarch_movfcsr2gr: {
1170*06c3fb27SDimitry Andric       if (!Subtarget.hasBasicF()) {
1171*06c3fb27SDimitry Andric         emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG,
1172*06c3fb27SDimitry Andric                                                      ErrorMsgReqF);
1173*06c3fb27SDimitry Andric         return;
1174*06c3fb27SDimitry Andric       }
1175*06c3fb27SDimitry Andric       unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
1176*06c3fb27SDimitry Andric       if (!isUInt<2>(Imm)) {
1177*06c3fb27SDimitry Andric         emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG,
1178*06c3fb27SDimitry Andric                                                      ErrorMsgOOR);
1179*06c3fb27SDimitry Andric         return;
1180*06c3fb27SDimitry Andric       }
1181*06c3fb27SDimitry Andric       SDValue MOVFCSR2GRResults = DAG.getNode(
1182*06c3fb27SDimitry Andric           LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other},
1183*06c3fb27SDimitry Andric           {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
1184*06c3fb27SDimitry Andric       Results.push_back(
1185*06c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0)));
1186*06c3fb27SDimitry Andric       Results.push_back(MOVFCSR2GRResults.getValue(1));
1187*06c3fb27SDimitry Andric       break;
1188*06c3fb27SDimitry Andric     }
1189bdd1243dSDimitry Andric #define CRC_CASE_EXT_BINARYOP(NAME, NODE)                                      \
1190bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
1191*06c3fb27SDimitry Andric     SDValue NODE = DAG.getNode(                                                \
1192*06c3fb27SDimitry Andric         LoongArchISD::NODE, DL, {MVT::i64, MVT::Other},                        \
1193*06c3fb27SDimitry Andric         {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),               \
1194*06c3fb27SDimitry Andric          DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))});       \
1195*06c3fb27SDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0)));   \
1196*06c3fb27SDimitry Andric     Results.push_back(NODE.getValue(1));                                       \
1197bdd1243dSDimitry Andric     break;                                                                     \
1198bdd1243dSDimitry Andric   }
1199bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
1200bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
1201bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
1202bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
1203bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
1204bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
1205bdd1243dSDimitry Andric #undef CRC_CASE_EXT_BINARYOP
1206bdd1243dSDimitry Andric 
1207bdd1243dSDimitry Andric #define CRC_CASE_EXT_UNARYOP(NAME, NODE)                                       \
1208bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
1209*06c3fb27SDimitry Andric     SDValue NODE = DAG.getNode(                                                \
1210*06c3fb27SDimitry Andric         LoongArchISD::NODE, DL, {MVT::i64, MVT::Other},                        \
1211*06c3fb27SDimitry Andric         {Chain, Op2,                                                           \
1212*06c3fb27SDimitry Andric          DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))});       \
1213*06c3fb27SDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0)));   \
1214*06c3fb27SDimitry Andric     Results.push_back(NODE.getValue(1));                                                  \
1215bdd1243dSDimitry Andric     break;                                                                     \
1216bdd1243dSDimitry Andric   }
1217bdd1243dSDimitry Andric       CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
1218bdd1243dSDimitry Andric       CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
1219bdd1243dSDimitry Andric #undef CRC_CASE_EXT_UNARYOP
1220bdd1243dSDimitry Andric #define CSR_CASE(ID)                                                           \
1221bdd1243dSDimitry Andric   case Intrinsic::loongarch_##ID: {                                            \
1222*06c3fb27SDimitry Andric     if (!Subtarget.is64Bit())                                                  \
1223*06c3fb27SDimitry Andric       emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG,            \
1224*06c3fb27SDimitry Andric                                                    ErrorMsgReqLA64);           \
1225bdd1243dSDimitry Andric     break;                                                                     \
1226bdd1243dSDimitry Andric   }
1227bdd1243dSDimitry Andric       CSR_CASE(csrrd_d);
1228bdd1243dSDimitry Andric       CSR_CASE(csrwr_d);
1229bdd1243dSDimitry Andric       CSR_CASE(csrxchg_d);
1230bdd1243dSDimitry Andric       CSR_CASE(iocsrrd_d);
1231bdd1243dSDimitry Andric #undef CSR_CASE
1232bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrrd_w: {
1233bdd1243dSDimitry Andric       unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
1234bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
1235*06c3fb27SDimitry Andric         emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG,
1236*06c3fb27SDimitry Andric                                                      ErrorMsgOOR);
1237*06c3fb27SDimitry Andric         return;
1238bdd1243dSDimitry Andric       }
1239*06c3fb27SDimitry Andric       SDValue CSRRDResults =
1240*06c3fb27SDimitry Andric           DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
1241*06c3fb27SDimitry Andric                       {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
1242bdd1243dSDimitry Andric       Results.push_back(
1243*06c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0)));
1244*06c3fb27SDimitry Andric       Results.push_back(CSRRDResults.getValue(1));
1245bdd1243dSDimitry Andric       break;
1246bdd1243dSDimitry Andric     }
1247bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrwr_w: {
1248bdd1243dSDimitry Andric       unsigned Imm = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue();
1249bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
1250*06c3fb27SDimitry Andric         emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG,
1251*06c3fb27SDimitry Andric                                                      ErrorMsgOOR);
1252*06c3fb27SDimitry Andric         return;
1253bdd1243dSDimitry Andric       }
1254*06c3fb27SDimitry Andric       SDValue CSRWRResults =
1255*06c3fb27SDimitry Andric           DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
1256*06c3fb27SDimitry Andric                       {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
1257*06c3fb27SDimitry Andric                        DAG.getConstant(Imm, DL, GRLenVT)});
1258*06c3fb27SDimitry Andric       Results.push_back(
1259*06c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0)));
1260*06c3fb27SDimitry Andric       Results.push_back(CSRWRResults.getValue(1));
1261bdd1243dSDimitry Andric       break;
1262bdd1243dSDimitry Andric     }
1263bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrxchg_w: {
1264bdd1243dSDimitry Andric       unsigned Imm = cast<ConstantSDNode>(N->getOperand(4))->getZExtValue();
1265bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
1266*06c3fb27SDimitry Andric         emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG,
1267*06c3fb27SDimitry Andric                                                      ErrorMsgOOR);
1268*06c3fb27SDimitry Andric         return;
1269bdd1243dSDimitry Andric       }
1270*06c3fb27SDimitry Andric       SDValue CSRXCHGResults = DAG.getNode(
1271*06c3fb27SDimitry Andric           LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
1272*06c3fb27SDimitry Andric           {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
1273bdd1243dSDimitry Andric            DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
1274*06c3fb27SDimitry Andric            DAG.getConstant(Imm, DL, GRLenVT)});
1275*06c3fb27SDimitry Andric       Results.push_back(
1276*06c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0)));
1277*06c3fb27SDimitry Andric       Results.push_back(CSRXCHGResults.getValue(1));
1278bdd1243dSDimitry Andric       break;
1279bdd1243dSDimitry Andric     }
1280bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE)                                               \
1281bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
1282*06c3fb27SDimitry Andric     SDValue IOCSRRDResults =                                                   \
1283*06c3fb27SDimitry Andric         DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other},            \
1284*06c3fb27SDimitry Andric                     {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \
1285*06c3fb27SDimitry Andric     Results.push_back(                                                         \
1286*06c3fb27SDimitry Andric         DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0)));       \
1287*06c3fb27SDimitry Andric     Results.push_back(IOCSRRDResults.getValue(1));                             \
1288bdd1243dSDimitry Andric     break;                                                                     \
1289bdd1243dSDimitry Andric   }
1290bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
1291bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
1292bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
1293bdd1243dSDimitry Andric #undef IOCSRRD_CASE
1294bdd1243dSDimitry Andric     case Intrinsic::loongarch_cpucfg: {
1295*06c3fb27SDimitry Andric       SDValue CPUCFGResults =
1296*06c3fb27SDimitry Andric           DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
1297*06c3fb27SDimitry Andric                       {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)});
1298*06c3fb27SDimitry Andric       Results.push_back(
1299*06c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0)));
1300*06c3fb27SDimitry Andric       Results.push_back(CPUCFGResults.getValue(1));
1301bdd1243dSDimitry Andric       break;
1302bdd1243dSDimitry Andric     }
1303bdd1243dSDimitry Andric     case Intrinsic::loongarch_lddir_d: {
1304bdd1243dSDimitry Andric       if (!Subtarget.is64Bit()) {
1305*06c3fb27SDimitry Andric         emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG,
1306*06c3fb27SDimitry Andric                                                      ErrorMsgReqLA64);
1307*06c3fb27SDimitry Andric         return;
1308bdd1243dSDimitry Andric       }
1309bdd1243dSDimitry Andric       break;
1310bdd1243dSDimitry Andric     }
1311bdd1243dSDimitry Andric     }
1312bdd1243dSDimitry Andric     break;
1313bdd1243dSDimitry Andric   }
1314bdd1243dSDimitry Andric   case ISD::READ_REGISTER: {
1315bdd1243dSDimitry Andric     if (Subtarget.is64Bit())
1316bdd1243dSDimitry Andric       DAG.getContext()->emitError(
1317bdd1243dSDimitry Andric           "On LA64, only 64-bit registers can be read.");
1318bdd1243dSDimitry Andric     else
1319bdd1243dSDimitry Andric       DAG.getContext()->emitError(
1320bdd1243dSDimitry Andric           "On LA32, only 32-bit registers can be read.");
1321bdd1243dSDimitry Andric     Results.push_back(DAG.getUNDEF(VT));
1322bdd1243dSDimitry Andric     Results.push_back(N->getOperand(0));
1323bdd1243dSDimitry Andric     break;
1324bdd1243dSDimitry Andric   }
132581ad6265SDimitry Andric   }
132681ad6265SDimitry Andric }
132781ad6265SDimitry Andric 
132881ad6265SDimitry Andric static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG,
132981ad6265SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
133081ad6265SDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
133181ad6265SDimitry Andric   if (DCI.isBeforeLegalizeOps())
133281ad6265SDimitry Andric     return SDValue();
133381ad6265SDimitry Andric 
133481ad6265SDimitry Andric   SDValue FirstOperand = N->getOperand(0);
133581ad6265SDimitry Andric   SDValue SecondOperand = N->getOperand(1);
133681ad6265SDimitry Andric   unsigned FirstOperandOpc = FirstOperand.getOpcode();
133781ad6265SDimitry Andric   EVT ValTy = N->getValueType(0);
133881ad6265SDimitry Andric   SDLoc DL(N);
133981ad6265SDimitry Andric   uint64_t lsb, msb;
134081ad6265SDimitry Andric   unsigned SMIdx, SMLen;
134181ad6265SDimitry Andric   ConstantSDNode *CN;
134281ad6265SDimitry Andric   SDValue NewOperand;
134381ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
134481ad6265SDimitry Andric 
134581ad6265SDimitry Andric   // Op's second operand must be a shifted mask.
134681ad6265SDimitry Andric   if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
134781ad6265SDimitry Andric       !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
134881ad6265SDimitry Andric     return SDValue();
134981ad6265SDimitry Andric 
135081ad6265SDimitry Andric   if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
135181ad6265SDimitry Andric     // Pattern match BSTRPICK.
135281ad6265SDimitry Andric     //  $dst = and ((sra or srl) $src , lsb), (2**len - 1)
135381ad6265SDimitry Andric     //  => BSTRPICK $dst, $src, msb, lsb
135481ad6265SDimitry Andric     //  where msb = lsb + len - 1
135581ad6265SDimitry Andric 
135681ad6265SDimitry Andric     // The second operand of the shift must be an immediate.
135781ad6265SDimitry Andric     if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
135881ad6265SDimitry Andric       return SDValue();
135981ad6265SDimitry Andric 
136081ad6265SDimitry Andric     lsb = CN->getZExtValue();
136181ad6265SDimitry Andric 
136281ad6265SDimitry Andric     // Return if the shifted mask does not start at bit 0 or the sum of its
136381ad6265SDimitry Andric     // length and lsb exceeds the word's size.
136481ad6265SDimitry Andric     if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
136581ad6265SDimitry Andric       return SDValue();
136681ad6265SDimitry Andric 
136781ad6265SDimitry Andric     NewOperand = FirstOperand.getOperand(0);
136881ad6265SDimitry Andric   } else {
136981ad6265SDimitry Andric     // Pattern match BSTRPICK.
137081ad6265SDimitry Andric     //  $dst = and $src, (2**len- 1) , if len > 12
137181ad6265SDimitry Andric     //  => BSTRPICK $dst, $src, msb, lsb
137281ad6265SDimitry Andric     //  where lsb = 0 and msb = len - 1
137381ad6265SDimitry Andric 
137481ad6265SDimitry Andric     // If the mask is <= 0xfff, andi can be used instead.
137581ad6265SDimitry Andric     if (CN->getZExtValue() <= 0xfff)
137681ad6265SDimitry Andric       return SDValue();
137781ad6265SDimitry Andric 
1378*06c3fb27SDimitry Andric     // Return if the MSB exceeds.
1379*06c3fb27SDimitry Andric     if (SMIdx + SMLen > ValTy.getSizeInBits())
138081ad6265SDimitry Andric       return SDValue();
138181ad6265SDimitry Andric 
1382*06c3fb27SDimitry Andric     if (SMIdx > 0) {
1383*06c3fb27SDimitry Andric       // Omit if the constant has more than 2 uses. This a conservative
1384*06c3fb27SDimitry Andric       // decision. Whether it is a win depends on the HW microarchitecture.
1385*06c3fb27SDimitry Andric       // However it should always be better for 1 and 2 uses.
1386*06c3fb27SDimitry Andric       if (CN->use_size() > 2)
1387*06c3fb27SDimitry Andric         return SDValue();
1388*06c3fb27SDimitry Andric       // Return if the constant can be composed by a single LU12I.W.
1389*06c3fb27SDimitry Andric       if ((CN->getZExtValue() & 0xfff) == 0)
1390*06c3fb27SDimitry Andric         return SDValue();
1391*06c3fb27SDimitry Andric       // Return if the constand can be composed by a single ADDI with
1392*06c3fb27SDimitry Andric       // the zero register.
1393*06c3fb27SDimitry Andric       if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
1394*06c3fb27SDimitry Andric         return SDValue();
1395*06c3fb27SDimitry Andric     }
1396*06c3fb27SDimitry Andric 
1397*06c3fb27SDimitry Andric     lsb = SMIdx;
139881ad6265SDimitry Andric     NewOperand = FirstOperand;
139981ad6265SDimitry Andric   }
1400*06c3fb27SDimitry Andric 
140181ad6265SDimitry Andric   msb = lsb + SMLen - 1;
1402*06c3fb27SDimitry Andric   SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
140381ad6265SDimitry Andric                             DAG.getConstant(msb, DL, GRLenVT),
140481ad6265SDimitry Andric                             DAG.getConstant(lsb, DL, GRLenVT));
1405*06c3fb27SDimitry Andric   if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
1406*06c3fb27SDimitry Andric     return NR0;
1407*06c3fb27SDimitry Andric   // Try to optimize to
1408*06c3fb27SDimitry Andric   //   bstrpick $Rd, $Rs, msb, lsb
1409*06c3fb27SDimitry Andric   //   slli     $Rd, $Rd, lsb
1410*06c3fb27SDimitry Andric   return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
1411*06c3fb27SDimitry Andric                      DAG.getConstant(lsb, DL, GRLenVT));
141281ad6265SDimitry Andric }
141381ad6265SDimitry Andric 
141481ad6265SDimitry Andric static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG,
141581ad6265SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
141681ad6265SDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
141781ad6265SDimitry Andric   if (DCI.isBeforeLegalizeOps())
141881ad6265SDimitry Andric     return SDValue();
141981ad6265SDimitry Andric 
142081ad6265SDimitry Andric   // $dst = srl (and $src, Mask), Shamt
142181ad6265SDimitry Andric   // =>
142281ad6265SDimitry Andric   // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
142381ad6265SDimitry Andric   // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
142481ad6265SDimitry Andric   //
142581ad6265SDimitry Andric 
142681ad6265SDimitry Andric   SDValue FirstOperand = N->getOperand(0);
142781ad6265SDimitry Andric   ConstantSDNode *CN;
142881ad6265SDimitry Andric   EVT ValTy = N->getValueType(0);
142981ad6265SDimitry Andric   SDLoc DL(N);
143081ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
143181ad6265SDimitry Andric   unsigned MaskIdx, MaskLen;
143281ad6265SDimitry Andric   uint64_t Shamt;
143381ad6265SDimitry Andric 
143481ad6265SDimitry Andric   // The first operand must be an AND and the second operand of the AND must be
143581ad6265SDimitry Andric   // a shifted mask.
143681ad6265SDimitry Andric   if (FirstOperand.getOpcode() != ISD::AND ||
143781ad6265SDimitry Andric       !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
143881ad6265SDimitry Andric       !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
143981ad6265SDimitry Andric     return SDValue();
144081ad6265SDimitry Andric 
144181ad6265SDimitry Andric   // The second operand (shift amount) must be an immediate.
144281ad6265SDimitry Andric   if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
144381ad6265SDimitry Andric     return SDValue();
144481ad6265SDimitry Andric 
144581ad6265SDimitry Andric   Shamt = CN->getZExtValue();
144681ad6265SDimitry Andric   if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
144781ad6265SDimitry Andric     return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
144881ad6265SDimitry Andric                        FirstOperand->getOperand(0),
144981ad6265SDimitry Andric                        DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
145081ad6265SDimitry Andric                        DAG.getConstant(Shamt, DL, GRLenVT));
145181ad6265SDimitry Andric 
145281ad6265SDimitry Andric   return SDValue();
145381ad6265SDimitry Andric }
145481ad6265SDimitry Andric 
1455753f127fSDimitry Andric static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
1456753f127fSDimitry Andric                                 TargetLowering::DAGCombinerInfo &DCI,
1457753f127fSDimitry Andric                                 const LoongArchSubtarget &Subtarget) {
1458753f127fSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
1459753f127fSDimitry Andric   EVT ValTy = N->getValueType(0);
1460753f127fSDimitry Andric   SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
1461753f127fSDimitry Andric   ConstantSDNode *CN0, *CN1;
1462753f127fSDimitry Andric   SDLoc DL(N);
1463753f127fSDimitry Andric   unsigned ValBits = ValTy.getSizeInBits();
1464753f127fSDimitry Andric   unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
1465753f127fSDimitry Andric   unsigned Shamt;
1466753f127fSDimitry Andric   bool SwapAndRetried = false;
1467753f127fSDimitry Andric 
1468753f127fSDimitry Andric   if (DCI.isBeforeLegalizeOps())
1469753f127fSDimitry Andric     return SDValue();
1470753f127fSDimitry Andric 
1471753f127fSDimitry Andric   if (ValBits != 32 && ValBits != 64)
1472753f127fSDimitry Andric     return SDValue();
1473753f127fSDimitry Andric 
1474753f127fSDimitry Andric Retry:
1475753f127fSDimitry Andric   // 1st pattern to match BSTRINS:
1476753f127fSDimitry Andric   //  R = or (and X, mask0), (and (shl Y, lsb), mask1)
1477753f127fSDimitry Andric   //  where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
1478753f127fSDimitry Andric   //  =>
1479753f127fSDimitry Andric   //  R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
1480753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
1481753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1482753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1483753f127fSDimitry Andric       N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
1484753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1485753f127fSDimitry Andric       isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
1486753f127fSDimitry Andric       MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
1487753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1488753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
1489753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
1490753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
1491753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1492753f127fSDimitry Andric                        N1.getOperand(0).getOperand(0),
1493753f127fSDimitry Andric                        DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1494753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
1495753f127fSDimitry Andric   }
1496753f127fSDimitry Andric 
1497753f127fSDimitry Andric   // 2nd pattern to match BSTRINS:
1498753f127fSDimitry Andric   //  R = or (and X, mask0), (shl (and Y, mask1), lsb)
1499753f127fSDimitry Andric   //  where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
1500753f127fSDimitry Andric   //  =>
1501753f127fSDimitry Andric   //  R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
1502753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
1503753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1504753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1505753f127fSDimitry Andric       N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
1506753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1507753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
1508753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1509753f127fSDimitry Andric       isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
1510753f127fSDimitry Andric       MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
1511753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
1512753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
1513753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1514753f127fSDimitry Andric                        N1.getOperand(0).getOperand(0),
1515753f127fSDimitry Andric                        DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1516753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
1517753f127fSDimitry Andric   }
1518753f127fSDimitry Andric 
1519753f127fSDimitry Andric   // 3rd pattern to match BSTRINS:
1520753f127fSDimitry Andric   //  R = or (and X, mask0), (and Y, mask1)
1521753f127fSDimitry Andric   //  where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
1522753f127fSDimitry Andric   //  =>
1523753f127fSDimitry Andric   //  R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
1524753f127fSDimitry Andric   //  where msb = lsb + size - 1
1525753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
1526753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1527753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1528753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= 64) &&
1529753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
1530753f127fSDimitry Andric       (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
1531753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
1532753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1533753f127fSDimitry Andric                        DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
1534753f127fSDimitry Andric                                    DAG.getConstant(MaskIdx0, DL, GRLenVT)),
1535753f127fSDimitry Andric                        DAG.getConstant(ValBits == 32
1536753f127fSDimitry Andric                                            ? (MaskIdx0 + (MaskLen0 & 31) - 1)
1537753f127fSDimitry Andric                                            : (MaskIdx0 + MaskLen0 - 1),
1538753f127fSDimitry Andric                                        DL, GRLenVT),
1539753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
1540753f127fSDimitry Andric   }
1541753f127fSDimitry Andric 
1542753f127fSDimitry Andric   // 4th pattern to match BSTRINS:
1543753f127fSDimitry Andric   //  R = or (and X, mask), (shl Y, shamt)
1544753f127fSDimitry Andric   //  where mask = (2**shamt - 1)
1545753f127fSDimitry Andric   //  =>
1546753f127fSDimitry Andric   //  R = BSTRINS X, Y, ValBits - 1, shamt
1547753f127fSDimitry Andric   //  where ValBits = 32 or 64
1548753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
1549753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1550753f127fSDimitry Andric       isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
1551753f127fSDimitry Andric       MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1552753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskLen0 &&
1553753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
1554753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
1555753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1556753f127fSDimitry Andric                        N1.getOperand(0),
1557753f127fSDimitry Andric                        DAG.getConstant((ValBits - 1), DL, GRLenVT),
1558753f127fSDimitry Andric                        DAG.getConstant(Shamt, DL, GRLenVT));
1559753f127fSDimitry Andric   }
1560753f127fSDimitry Andric 
1561753f127fSDimitry Andric   // 5th pattern to match BSTRINS:
1562753f127fSDimitry Andric   //  R = or (and X, mask), const
1563753f127fSDimitry Andric   //  where ~mask = (2**size - 1) << lsb, mask & const = 0
1564753f127fSDimitry Andric   //  =>
1565753f127fSDimitry Andric   //  R = BSTRINS X, (const >> lsb), msb, lsb
1566753f127fSDimitry Andric   //  where msb = lsb + size - 1
1567753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
1568753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1569753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1570753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
1571753f127fSDimitry Andric       (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
1572753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
1573753f127fSDimitry Andric     return DAG.getNode(
1574753f127fSDimitry Andric         LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1575753f127fSDimitry Andric         DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
1576753f127fSDimitry Andric         DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1577753f127fSDimitry Andric         DAG.getConstant(MaskIdx0, DL, GRLenVT));
1578753f127fSDimitry Andric   }
1579753f127fSDimitry Andric 
1580753f127fSDimitry Andric   // 6th pattern.
1581753f127fSDimitry Andric   // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
1582753f127fSDimitry Andric   // by the incoming bits are known to be zero.
1583753f127fSDimitry Andric   // =>
1584753f127fSDimitry Andric   // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
1585753f127fSDimitry Andric   //
1586753f127fSDimitry Andric   // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
1587753f127fSDimitry Andric   // pattern is more common than the 1st. So we put the 1st before the 6th in
1588753f127fSDimitry Andric   // order to match as many nodes as possible.
1589753f127fSDimitry Andric   ConstantSDNode *CNMask, *CNShamt;
1590753f127fSDimitry Andric   unsigned MaskIdx, MaskLen;
1591753f127fSDimitry Andric   if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
1592753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1593753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
1594753f127fSDimitry Andric       MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1595753f127fSDimitry Andric       CNShamt->getZExtValue() + MaskLen <= ValBits) {
1596753f127fSDimitry Andric     Shamt = CNShamt->getZExtValue();
1597753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
1598753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1599753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
1600753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1601753f127fSDimitry Andric                          N1.getOperand(0).getOperand(0),
1602753f127fSDimitry Andric                          DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
1603753f127fSDimitry Andric                          DAG.getConstant(Shamt, DL, GRLenVT));
1604753f127fSDimitry Andric     }
1605753f127fSDimitry Andric   }
1606753f127fSDimitry Andric 
1607753f127fSDimitry Andric   // 7th pattern.
1608753f127fSDimitry Andric   // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
1609753f127fSDimitry Andric   // overwritten by the incoming bits are known to be zero.
1610753f127fSDimitry Andric   // =>
1611753f127fSDimitry Andric   // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
1612753f127fSDimitry Andric   //
1613753f127fSDimitry Andric   // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
1614753f127fSDimitry Andric   // before the 7th in order to match as many nodes as possible.
1615753f127fSDimitry Andric   if (N1.getOpcode() == ISD::AND &&
1616753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1617753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
1618753f127fSDimitry Andric       N1.getOperand(0).getOpcode() == ISD::SHL &&
1619753f127fSDimitry Andric       (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1620753f127fSDimitry Andric       CNShamt->getZExtValue() == MaskIdx) {
1621753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue());
1622753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1623753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
1624753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1625753f127fSDimitry Andric                          N1.getOperand(0).getOperand(0),
1626753f127fSDimitry Andric                          DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1627753f127fSDimitry Andric                          DAG.getConstant(MaskIdx, DL, GRLenVT));
1628753f127fSDimitry Andric     }
1629753f127fSDimitry Andric   }
1630753f127fSDimitry Andric 
1631753f127fSDimitry Andric   // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
1632753f127fSDimitry Andric   if (!SwapAndRetried) {
1633753f127fSDimitry Andric     std::swap(N0, N1);
1634753f127fSDimitry Andric     SwapAndRetried = true;
1635753f127fSDimitry Andric     goto Retry;
1636753f127fSDimitry Andric   }
1637753f127fSDimitry Andric 
1638753f127fSDimitry Andric   SwapAndRetried = false;
1639753f127fSDimitry Andric Retry2:
1640753f127fSDimitry Andric   // 8th pattern.
1641753f127fSDimitry Andric   // a = b | (c & shifted_mask), where all positions in b to be overwritten by
1642753f127fSDimitry Andric   // the incoming bits are known to be zero.
1643753f127fSDimitry Andric   // =>
1644753f127fSDimitry Andric   // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
1645753f127fSDimitry Andric   //
1646753f127fSDimitry Andric   // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
1647753f127fSDimitry Andric   // we put it here in order to match as many nodes as possible or generate less
1648753f127fSDimitry Andric   // instructions.
1649753f127fSDimitry Andric   if (N1.getOpcode() == ISD::AND &&
1650753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1651753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
1652753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue());
1653753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1654753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
1655753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1656753f127fSDimitry Andric                          DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
1657753f127fSDimitry Andric                                      N1->getOperand(0),
1658753f127fSDimitry Andric                                      DAG.getConstant(MaskIdx, DL, GRLenVT)),
1659753f127fSDimitry Andric                          DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1660753f127fSDimitry Andric                          DAG.getConstant(MaskIdx, DL, GRLenVT));
1661753f127fSDimitry Andric     }
1662753f127fSDimitry Andric   }
1663753f127fSDimitry Andric   // Swap N0/N1 and retry.
1664753f127fSDimitry Andric   if (!SwapAndRetried) {
1665753f127fSDimitry Andric     std::swap(N0, N1);
1666753f127fSDimitry Andric     SwapAndRetried = true;
1667753f127fSDimitry Andric     goto Retry2;
1668753f127fSDimitry Andric   }
1669753f127fSDimitry Andric 
1670753f127fSDimitry Andric   return SDValue();
1671753f127fSDimitry Andric }
1672753f127fSDimitry Andric 
1673bdd1243dSDimitry Andric // Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
1674bdd1243dSDimitry Andric static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG,
1675bdd1243dSDimitry Andric                                       TargetLowering::DAGCombinerInfo &DCI,
1676bdd1243dSDimitry Andric                                       const LoongArchSubtarget &Subtarget) {
1677bdd1243dSDimitry Andric   if (DCI.isBeforeLegalizeOps())
1678bdd1243dSDimitry Andric     return SDValue();
1679bdd1243dSDimitry Andric 
1680bdd1243dSDimitry Andric   SDValue Src = N->getOperand(0);
1681bdd1243dSDimitry Andric   if (Src.getOpcode() != LoongArchISD::REVB_2W)
1682bdd1243dSDimitry Andric     return SDValue();
1683bdd1243dSDimitry Andric 
1684bdd1243dSDimitry Andric   return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
1685bdd1243dSDimitry Andric                      Src.getOperand(0));
1686bdd1243dSDimitry Andric }
1687bdd1243dSDimitry Andric 
168881ad6265SDimitry Andric SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N,
168981ad6265SDimitry Andric                                                    DAGCombinerInfo &DCI) const {
169081ad6265SDimitry Andric   SelectionDAG &DAG = DCI.DAG;
169181ad6265SDimitry Andric   switch (N->getOpcode()) {
169281ad6265SDimitry Andric   default:
169381ad6265SDimitry Andric     break;
169481ad6265SDimitry Andric   case ISD::AND:
169581ad6265SDimitry Andric     return performANDCombine(N, DAG, DCI, Subtarget);
1696753f127fSDimitry Andric   case ISD::OR:
1697753f127fSDimitry Andric     return performORCombine(N, DAG, DCI, Subtarget);
169881ad6265SDimitry Andric   case ISD::SRL:
169981ad6265SDimitry Andric     return performSRLCombine(N, DAG, DCI, Subtarget);
1700bdd1243dSDimitry Andric   case LoongArchISD::BITREV_W:
1701bdd1243dSDimitry Andric     return performBITREV_WCombine(N, DAG, DCI, Subtarget);
170281ad6265SDimitry Andric   }
170381ad6265SDimitry Andric   return SDValue();
170481ad6265SDimitry Andric }
170581ad6265SDimitry Andric 
1706753f127fSDimitry Andric static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI,
1707bdd1243dSDimitry Andric                                               MachineBasicBlock *MBB) {
1708753f127fSDimitry Andric   if (!ZeroDivCheck)
1709bdd1243dSDimitry Andric     return MBB;
1710753f127fSDimitry Andric 
1711753f127fSDimitry Andric   // Build instructions:
1712bdd1243dSDimitry Andric   // MBB:
1713753f127fSDimitry Andric   //   div(or mod)   $dst, $dividend, $divisor
1714bdd1243dSDimitry Andric   //   bnez          $divisor, SinkMBB
1715bdd1243dSDimitry Andric   // BreakMBB:
1716bdd1243dSDimitry Andric   //   break         7 // BRK_DIVZERO
1717bdd1243dSDimitry Andric   // SinkMBB:
1718753f127fSDimitry Andric   //   fallthrough
1719bdd1243dSDimitry Andric   const BasicBlock *LLVM_BB = MBB->getBasicBlock();
1720bdd1243dSDimitry Andric   MachineFunction::iterator It = ++MBB->getIterator();
1721bdd1243dSDimitry Andric   MachineFunction *MF = MBB->getParent();
1722bdd1243dSDimitry Andric   auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
1723bdd1243dSDimitry Andric   auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
1724bdd1243dSDimitry Andric   MF->insert(It, BreakMBB);
1725bdd1243dSDimitry Andric   MF->insert(It, SinkMBB);
1726bdd1243dSDimitry Andric 
1727bdd1243dSDimitry Andric   // Transfer the remainder of MBB and its successor edges to SinkMBB.
1728bdd1243dSDimitry Andric   SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
1729bdd1243dSDimitry Andric   SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
1730bdd1243dSDimitry Andric 
1731bdd1243dSDimitry Andric   const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
1732bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
1733753f127fSDimitry Andric   MachineOperand &Divisor = MI.getOperand(2);
1734bdd1243dSDimitry Andric   Register DivisorReg = Divisor.getReg();
1735753f127fSDimitry Andric 
1736bdd1243dSDimitry Andric   // MBB:
1737bdd1243dSDimitry Andric   BuildMI(MBB, DL, TII.get(LoongArch::BNEZ))
1738bdd1243dSDimitry Andric       .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
1739bdd1243dSDimitry Andric       .addMBB(SinkMBB);
1740bdd1243dSDimitry Andric   MBB->addSuccessor(BreakMBB);
1741bdd1243dSDimitry Andric   MBB->addSuccessor(SinkMBB);
1742753f127fSDimitry Andric 
1743bdd1243dSDimitry Andric   // BreakMBB:
1744753f127fSDimitry Andric   // See linux header file arch/loongarch/include/uapi/asm/break.h for the
1745753f127fSDimitry Andric   // definition of BRK_DIVZERO.
1746bdd1243dSDimitry Andric   BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
1747bdd1243dSDimitry Andric   BreakMBB->addSuccessor(SinkMBB);
1748753f127fSDimitry Andric 
1749753f127fSDimitry Andric   // Clear Divisor's kill flag.
1750753f127fSDimitry Andric   Divisor.setIsKill(false);
1751753f127fSDimitry Andric 
1752bdd1243dSDimitry Andric   return SinkMBB;
1753753f127fSDimitry Andric }
1754753f127fSDimitry Andric 
1755753f127fSDimitry Andric MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
1756753f127fSDimitry Andric     MachineInstr &MI, MachineBasicBlock *BB) const {
1757bdd1243dSDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
1758bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
1759753f127fSDimitry Andric 
1760753f127fSDimitry Andric   switch (MI.getOpcode()) {
1761753f127fSDimitry Andric   default:
1762753f127fSDimitry Andric     llvm_unreachable("Unexpected instr type to insert");
1763753f127fSDimitry Andric   case LoongArch::DIV_W:
1764753f127fSDimitry Andric   case LoongArch::DIV_WU:
1765753f127fSDimitry Andric   case LoongArch::MOD_W:
1766753f127fSDimitry Andric   case LoongArch::MOD_WU:
1767753f127fSDimitry Andric   case LoongArch::DIV_D:
1768753f127fSDimitry Andric   case LoongArch::DIV_DU:
1769753f127fSDimitry Andric   case LoongArch::MOD_D:
1770753f127fSDimitry Andric   case LoongArch::MOD_DU:
1771bdd1243dSDimitry Andric     return insertDivByZeroTrap(MI, BB);
1772753f127fSDimitry Andric     break;
1773bdd1243dSDimitry Andric   case LoongArch::WRFCSR: {
1774bdd1243dSDimitry Andric     BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
1775bdd1243dSDimitry Andric             LoongArch::FCSR0 + MI.getOperand(0).getImm())
1776bdd1243dSDimitry Andric         .addReg(MI.getOperand(1).getReg());
1777bdd1243dSDimitry Andric     MI.eraseFromParent();
1778bdd1243dSDimitry Andric     return BB;
1779bdd1243dSDimitry Andric   }
1780bdd1243dSDimitry Andric   case LoongArch::RDFCSR: {
1781bdd1243dSDimitry Andric     MachineInstr *ReadFCSR =
1782bdd1243dSDimitry Andric         BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
1783bdd1243dSDimitry Andric                 MI.getOperand(0).getReg())
1784bdd1243dSDimitry Andric             .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
1785bdd1243dSDimitry Andric     ReadFCSR->getOperand(1).setIsUndef();
1786bdd1243dSDimitry Andric     MI.eraseFromParent();
1787bdd1243dSDimitry Andric     return BB;
1788bdd1243dSDimitry Andric   }
1789753f127fSDimitry Andric   }
1790753f127fSDimitry Andric }
1791753f127fSDimitry Andric 
1792*06c3fb27SDimitry Andric bool LoongArchTargetLowering::allowsMisalignedMemoryAccesses(
1793*06c3fb27SDimitry Andric     EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
1794*06c3fb27SDimitry Andric     unsigned *Fast) const {
1795*06c3fb27SDimitry Andric   if (!Subtarget.hasUAL())
1796*06c3fb27SDimitry Andric     return false;
1797*06c3fb27SDimitry Andric 
1798*06c3fb27SDimitry Andric   // TODO: set reasonable speed number.
1799*06c3fb27SDimitry Andric   if (Fast)
1800*06c3fb27SDimitry Andric     *Fast = 1;
1801*06c3fb27SDimitry Andric   return true;
1802*06c3fb27SDimitry Andric }
1803*06c3fb27SDimitry Andric 
180481ad6265SDimitry Andric const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
180581ad6265SDimitry Andric   switch ((LoongArchISD::NodeType)Opcode) {
180681ad6265SDimitry Andric   case LoongArchISD::FIRST_NUMBER:
180781ad6265SDimitry Andric     break;
180881ad6265SDimitry Andric 
180981ad6265SDimitry Andric #define NODE_NAME_CASE(node)                                                   \
181081ad6265SDimitry Andric   case LoongArchISD::node:                                                     \
181181ad6265SDimitry Andric     return "LoongArchISD::" #node;
181281ad6265SDimitry Andric 
181381ad6265SDimitry Andric     // TODO: Add more target-dependent nodes later.
1814753f127fSDimitry Andric     NODE_NAME_CASE(CALL)
181581ad6265SDimitry Andric     NODE_NAME_CASE(RET)
1816bdd1243dSDimitry Andric     NODE_NAME_CASE(TAIL)
181781ad6265SDimitry Andric     NODE_NAME_CASE(SLL_W)
181881ad6265SDimitry Andric     NODE_NAME_CASE(SRA_W)
181981ad6265SDimitry Andric     NODE_NAME_CASE(SRL_W)
1820753f127fSDimitry Andric     NODE_NAME_CASE(BSTRINS)
182181ad6265SDimitry Andric     NODE_NAME_CASE(BSTRPICK)
1822753f127fSDimitry Andric     NODE_NAME_CASE(MOVGR2FR_W_LA64)
1823753f127fSDimitry Andric     NODE_NAME_CASE(MOVFR2GR_S_LA64)
1824753f127fSDimitry Andric     NODE_NAME_CASE(FTINT)
1825bdd1243dSDimitry Andric     NODE_NAME_CASE(REVB_2H)
1826bdd1243dSDimitry Andric     NODE_NAME_CASE(REVB_2W)
1827bdd1243dSDimitry Andric     NODE_NAME_CASE(BITREV_4B)
1828bdd1243dSDimitry Andric     NODE_NAME_CASE(BITREV_W)
1829bdd1243dSDimitry Andric     NODE_NAME_CASE(ROTR_W)
1830bdd1243dSDimitry Andric     NODE_NAME_CASE(ROTL_W)
1831bdd1243dSDimitry Andric     NODE_NAME_CASE(CLZ_W)
1832bdd1243dSDimitry Andric     NODE_NAME_CASE(CTZ_W)
1833bdd1243dSDimitry Andric     NODE_NAME_CASE(DBAR)
1834bdd1243dSDimitry Andric     NODE_NAME_CASE(IBAR)
1835bdd1243dSDimitry Andric     NODE_NAME_CASE(BREAK)
1836bdd1243dSDimitry Andric     NODE_NAME_CASE(SYSCALL)
1837bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_B_W)
1838bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_H_W)
1839bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_W_W)
1840bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_D_W)
1841bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_B_W)
1842bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_H_W)
1843bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_W_W)
1844bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_D_W)
1845bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRRD)
1846bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRWR)
1847bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRXCHG)
1848bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_B)
1849bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_H)
1850bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_W)
1851bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_D)
1852bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_B)
1853bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_H)
1854bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_W)
1855bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_D)
1856bdd1243dSDimitry Andric     NODE_NAME_CASE(CPUCFG)
1857bdd1243dSDimitry Andric     NODE_NAME_CASE(MOVGR2FCSR)
1858bdd1243dSDimitry Andric     NODE_NAME_CASE(MOVFCSR2GR)
1859bdd1243dSDimitry Andric     NODE_NAME_CASE(CACOP_D)
1860bdd1243dSDimitry Andric     NODE_NAME_CASE(CACOP_W)
186181ad6265SDimitry Andric   }
186281ad6265SDimitry Andric #undef NODE_NAME_CASE
186381ad6265SDimitry Andric   return nullptr;
186481ad6265SDimitry Andric }
186581ad6265SDimitry Andric 
186681ad6265SDimitry Andric //===----------------------------------------------------------------------===//
186781ad6265SDimitry Andric //                     Calling Convention Implementation
186881ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1869bdd1243dSDimitry Andric 
1870bdd1243dSDimitry Andric // Eight general-purpose registers a0-a7 used for passing integer arguments,
1871bdd1243dSDimitry Andric // with a0-a1 reused to return values. Generally, the GPRs are used to pass
1872bdd1243dSDimitry Andric // fixed-point arguments, and floating-point arguments when no FPR is available
1873bdd1243dSDimitry Andric // or with soft float ABI.
187481ad6265SDimitry Andric const MCPhysReg ArgGPRs[] = {LoongArch::R4,  LoongArch::R5, LoongArch::R6,
187581ad6265SDimitry Andric                              LoongArch::R7,  LoongArch::R8, LoongArch::R9,
187681ad6265SDimitry Andric                              LoongArch::R10, LoongArch::R11};
1877bdd1243dSDimitry Andric // Eight floating-point registers fa0-fa7 used for passing floating-point
1878bdd1243dSDimitry Andric // arguments, and fa0-fa1 are also used to return values.
187981ad6265SDimitry Andric const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
188081ad6265SDimitry Andric                                LoongArch::F3, LoongArch::F4, LoongArch::F5,
188181ad6265SDimitry Andric                                LoongArch::F6, LoongArch::F7};
1882bdd1243dSDimitry Andric // FPR32 and FPR64 alias each other.
188381ad6265SDimitry Andric const MCPhysReg ArgFPR64s[] = {
188481ad6265SDimitry Andric     LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
188581ad6265SDimitry Andric     LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
188681ad6265SDimitry Andric 
1887bdd1243dSDimitry Andric // Pass a 2*GRLen argument that has been split into two GRLen values through
1888bdd1243dSDimitry Andric // registers or the stack as necessary.
1889bdd1243dSDimitry Andric static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
1890bdd1243dSDimitry Andric                                      CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
1891bdd1243dSDimitry Andric                                      unsigned ValNo2, MVT ValVT2, MVT LocVT2,
1892bdd1243dSDimitry Andric                                      ISD::ArgFlagsTy ArgFlags2) {
1893bdd1243dSDimitry Andric   unsigned GRLenInBytes = GRLen / 8;
1894bdd1243dSDimitry Andric   if (Register Reg = State.AllocateReg(ArgGPRs)) {
1895bdd1243dSDimitry Andric     // At least one half can be passed via register.
1896bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
1897bdd1243dSDimitry Andric                                      VA1.getLocVT(), CCValAssign::Full));
1898bdd1243dSDimitry Andric   } else {
1899bdd1243dSDimitry Andric     // Both halves must be passed on the stack, with proper alignment.
1900bdd1243dSDimitry Andric     Align StackAlign =
1901bdd1243dSDimitry Andric         std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
1902bdd1243dSDimitry Andric     State.addLoc(
1903bdd1243dSDimitry Andric         CCValAssign::getMem(VA1.getValNo(), VA1.getValVT(),
1904bdd1243dSDimitry Andric                             State.AllocateStack(GRLenInBytes, StackAlign),
1905bdd1243dSDimitry Andric                             VA1.getLocVT(), CCValAssign::Full));
1906bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getMem(
1907bdd1243dSDimitry Andric         ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
1908bdd1243dSDimitry Andric         LocVT2, CCValAssign::Full));
1909bdd1243dSDimitry Andric     return false;
1910bdd1243dSDimitry Andric   }
1911bdd1243dSDimitry Andric   if (Register Reg = State.AllocateReg(ArgGPRs)) {
1912bdd1243dSDimitry Andric     // The second half can also be passed via register.
1913bdd1243dSDimitry Andric     State.addLoc(
1914bdd1243dSDimitry Andric         CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
1915bdd1243dSDimitry Andric   } else {
1916bdd1243dSDimitry Andric     // The second half is passed via the stack, without additional alignment.
1917bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getMem(
1918bdd1243dSDimitry Andric         ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
1919bdd1243dSDimitry Andric         LocVT2, CCValAssign::Full));
1920bdd1243dSDimitry Andric   }
192181ad6265SDimitry Andric   return false;
192281ad6265SDimitry Andric }
192381ad6265SDimitry Andric 
1924bdd1243dSDimitry Andric // Implements the LoongArch calling convention. Returns true upon failure.
1925bdd1243dSDimitry Andric static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI,
1926bdd1243dSDimitry Andric                          unsigned ValNo, MVT ValVT,
1927bdd1243dSDimitry Andric                          CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
1928bdd1243dSDimitry Andric                          CCState &State, bool IsFixed, bool IsRet,
1929bdd1243dSDimitry Andric                          Type *OrigTy) {
1930bdd1243dSDimitry Andric   unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
1931bdd1243dSDimitry Andric   assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
1932bdd1243dSDimitry Andric   MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
1933bdd1243dSDimitry Andric   MVT LocVT = ValVT;
1934bdd1243dSDimitry Andric 
1935bdd1243dSDimitry Andric   // Any return value split into more than two values can't be returned
1936bdd1243dSDimitry Andric   // directly.
1937bdd1243dSDimitry Andric   if (IsRet && ValNo > 1)
193881ad6265SDimitry Andric     return true;
1939bdd1243dSDimitry Andric 
1940bdd1243dSDimitry Andric   // If passing a variadic argument, or if no FPR is available.
1941bdd1243dSDimitry Andric   bool UseGPRForFloat = true;
1942bdd1243dSDimitry Andric 
1943bdd1243dSDimitry Andric   switch (ABI) {
1944bdd1243dSDimitry Andric   default:
1945bdd1243dSDimitry Andric     llvm_unreachable("Unexpected ABI");
1946bdd1243dSDimitry Andric   case LoongArchABI::ABI_ILP32S:
1947bdd1243dSDimitry Andric   case LoongArchABI::ABI_ILP32F:
1948bdd1243dSDimitry Andric   case LoongArchABI::ABI_LP64F:
1949bdd1243dSDimitry Andric     report_fatal_error("Unimplemented ABI");
1950bdd1243dSDimitry Andric     break;
1951bdd1243dSDimitry Andric   case LoongArchABI::ABI_ILP32D:
1952bdd1243dSDimitry Andric   case LoongArchABI::ABI_LP64D:
1953bdd1243dSDimitry Andric     UseGPRForFloat = !IsFixed;
1954bdd1243dSDimitry Andric     break;
1955*06c3fb27SDimitry Andric   case LoongArchABI::ABI_LP64S:
1956*06c3fb27SDimitry Andric     break;
1957bdd1243dSDimitry Andric   }
1958bdd1243dSDimitry Andric 
1959bdd1243dSDimitry Andric   // FPR32 and FPR64 alias each other.
1960bdd1243dSDimitry Andric   if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
1961bdd1243dSDimitry Andric     UseGPRForFloat = true;
1962bdd1243dSDimitry Andric 
1963bdd1243dSDimitry Andric   if (UseGPRForFloat && ValVT == MVT::f32) {
1964bdd1243dSDimitry Andric     LocVT = GRLenVT;
1965bdd1243dSDimitry Andric     LocInfo = CCValAssign::BCvt;
1966bdd1243dSDimitry Andric   } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
1967bdd1243dSDimitry Andric     LocVT = MVT::i64;
1968bdd1243dSDimitry Andric     LocInfo = CCValAssign::BCvt;
1969bdd1243dSDimitry Andric   } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
1970bdd1243dSDimitry Andric     // TODO: Handle passing f64 on LA32 with D feature.
1971bdd1243dSDimitry Andric     report_fatal_error("Passing f64 with GPR on LA32 is undefined");
1972bdd1243dSDimitry Andric   }
1973bdd1243dSDimitry Andric 
1974bdd1243dSDimitry Andric   // If this is a variadic argument, the LoongArch calling convention requires
1975bdd1243dSDimitry Andric   // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
1976bdd1243dSDimitry Andric   // byte alignment. An aligned register should be used regardless of whether
1977bdd1243dSDimitry Andric   // the original argument was split during legalisation or not. The argument
1978bdd1243dSDimitry Andric   // will not be passed by registers if the original type is larger than
1979bdd1243dSDimitry Andric   // 2*GRLen, so the register alignment rule does not apply.
1980bdd1243dSDimitry Andric   unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
1981bdd1243dSDimitry Andric   if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
1982bdd1243dSDimitry Andric       DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
1983bdd1243dSDimitry Andric     unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
1984bdd1243dSDimitry Andric     // Skip 'odd' register if necessary.
1985bdd1243dSDimitry Andric     if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
1986bdd1243dSDimitry Andric       State.AllocateReg(ArgGPRs);
1987bdd1243dSDimitry Andric   }
1988bdd1243dSDimitry Andric 
1989bdd1243dSDimitry Andric   SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
1990bdd1243dSDimitry Andric   SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
1991bdd1243dSDimitry Andric       State.getPendingArgFlags();
1992bdd1243dSDimitry Andric 
1993bdd1243dSDimitry Andric   assert(PendingLocs.size() == PendingArgFlags.size() &&
1994bdd1243dSDimitry Andric          "PendingLocs and PendingArgFlags out of sync");
1995bdd1243dSDimitry Andric 
1996bdd1243dSDimitry Andric   // Split arguments might be passed indirectly, so keep track of the pending
1997bdd1243dSDimitry Andric   // values.
1998bdd1243dSDimitry Andric   if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
1999bdd1243dSDimitry Andric     LocVT = GRLenVT;
2000bdd1243dSDimitry Andric     LocInfo = CCValAssign::Indirect;
2001bdd1243dSDimitry Andric     PendingLocs.push_back(
2002bdd1243dSDimitry Andric         CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
2003bdd1243dSDimitry Andric     PendingArgFlags.push_back(ArgFlags);
2004bdd1243dSDimitry Andric     if (!ArgFlags.isSplitEnd()) {
2005bdd1243dSDimitry Andric       return false;
2006bdd1243dSDimitry Andric     }
2007bdd1243dSDimitry Andric   }
2008bdd1243dSDimitry Andric 
2009bdd1243dSDimitry Andric   // If the split argument only had two elements, it should be passed directly
2010bdd1243dSDimitry Andric   // in registers or on the stack.
2011bdd1243dSDimitry Andric   if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
2012bdd1243dSDimitry Andric       PendingLocs.size() <= 2) {
2013bdd1243dSDimitry Andric     assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
2014bdd1243dSDimitry Andric     // Apply the normal calling convention rules to the first half of the
2015bdd1243dSDimitry Andric     // split argument.
2016bdd1243dSDimitry Andric     CCValAssign VA = PendingLocs[0];
2017bdd1243dSDimitry Andric     ISD::ArgFlagsTy AF = PendingArgFlags[0];
2018bdd1243dSDimitry Andric     PendingLocs.clear();
2019bdd1243dSDimitry Andric     PendingArgFlags.clear();
2020bdd1243dSDimitry Andric     return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
2021bdd1243dSDimitry Andric                                     ArgFlags);
2022bdd1243dSDimitry Andric   }
2023bdd1243dSDimitry Andric 
2024bdd1243dSDimitry Andric   // Allocate to a register if possible, or else a stack slot.
2025bdd1243dSDimitry Andric   Register Reg;
2026bdd1243dSDimitry Andric   unsigned StoreSizeBytes = GRLen / 8;
2027bdd1243dSDimitry Andric   Align StackAlign = Align(GRLen / 8);
2028bdd1243dSDimitry Andric 
2029bdd1243dSDimitry Andric   if (ValVT == MVT::f32 && !UseGPRForFloat)
2030bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgFPR32s);
2031bdd1243dSDimitry Andric   else if (ValVT == MVT::f64 && !UseGPRForFloat)
2032bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgFPR64s);
2033bdd1243dSDimitry Andric   else
2034bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgGPRs);
2035bdd1243dSDimitry Andric 
2036bdd1243dSDimitry Andric   unsigned StackOffset =
2037bdd1243dSDimitry Andric       Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
2038bdd1243dSDimitry Andric 
2039bdd1243dSDimitry Andric   // If we reach this point and PendingLocs is non-empty, we must be at the
2040bdd1243dSDimitry Andric   // end of a split argument that must be passed indirectly.
2041bdd1243dSDimitry Andric   if (!PendingLocs.empty()) {
2042bdd1243dSDimitry Andric     assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
2043bdd1243dSDimitry Andric     assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
2044bdd1243dSDimitry Andric     for (auto &It : PendingLocs) {
2045bdd1243dSDimitry Andric       if (Reg)
2046bdd1243dSDimitry Andric         It.convertToReg(Reg);
2047bdd1243dSDimitry Andric       else
2048bdd1243dSDimitry Andric         It.convertToMem(StackOffset);
2049bdd1243dSDimitry Andric       State.addLoc(It);
2050bdd1243dSDimitry Andric     }
2051bdd1243dSDimitry Andric     PendingLocs.clear();
2052bdd1243dSDimitry Andric     PendingArgFlags.clear();
2053bdd1243dSDimitry Andric     return false;
2054bdd1243dSDimitry Andric   }
2055bdd1243dSDimitry Andric   assert((!UseGPRForFloat || LocVT == GRLenVT) &&
2056bdd1243dSDimitry Andric          "Expected an GRLenVT at this stage");
2057bdd1243dSDimitry Andric 
2058bdd1243dSDimitry Andric   if (Reg) {
2059bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2060bdd1243dSDimitry Andric     return false;
2061bdd1243dSDimitry Andric   }
2062bdd1243dSDimitry Andric 
2063bdd1243dSDimitry Andric   // When a floating-point value is passed on the stack, no bit-cast is needed.
2064bdd1243dSDimitry Andric   if (ValVT.isFloatingPoint()) {
2065bdd1243dSDimitry Andric     LocVT = ValVT;
2066bdd1243dSDimitry Andric     LocInfo = CCValAssign::Full;
2067bdd1243dSDimitry Andric   }
2068bdd1243dSDimitry Andric 
2069bdd1243dSDimitry Andric   State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
2070bdd1243dSDimitry Andric   return false;
207181ad6265SDimitry Andric }
207281ad6265SDimitry Andric 
207381ad6265SDimitry Andric void LoongArchTargetLowering::analyzeInputArgs(
2074bdd1243dSDimitry Andric     MachineFunction &MF, CCState &CCInfo,
2075bdd1243dSDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
207681ad6265SDimitry Andric     LoongArchCCAssignFn Fn) const {
2077bdd1243dSDimitry Andric   FunctionType *FType = MF.getFunction().getFunctionType();
207881ad6265SDimitry Andric   for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
207981ad6265SDimitry Andric     MVT ArgVT = Ins[i].VT;
2080bdd1243dSDimitry Andric     Type *ArgTy = nullptr;
2081bdd1243dSDimitry Andric     if (IsRet)
2082bdd1243dSDimitry Andric       ArgTy = FType->getReturnType();
2083bdd1243dSDimitry Andric     else if (Ins[i].isOrigArg())
2084bdd1243dSDimitry Andric       ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
2085bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
2086bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2087bdd1243dSDimitry Andric     if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
2088bdd1243dSDimitry Andric            CCInfo, /*IsFixed=*/true, IsRet, ArgTy)) {
2089*06c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT
2090*06c3fb27SDimitry Andric                         << '\n');
209181ad6265SDimitry Andric       llvm_unreachable("");
209281ad6265SDimitry Andric     }
209381ad6265SDimitry Andric   }
209481ad6265SDimitry Andric }
209581ad6265SDimitry Andric 
209681ad6265SDimitry Andric void LoongArchTargetLowering::analyzeOutputArgs(
2097bdd1243dSDimitry Andric     MachineFunction &MF, CCState &CCInfo,
2098bdd1243dSDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
2099bdd1243dSDimitry Andric     CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
210081ad6265SDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
210181ad6265SDimitry Andric     MVT ArgVT = Outs[i].VT;
2102bdd1243dSDimitry Andric     Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
2103bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
2104bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2105bdd1243dSDimitry Andric     if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
2106bdd1243dSDimitry Andric            CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) {
2107*06c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT
2108*06c3fb27SDimitry Andric                         << "\n");
210981ad6265SDimitry Andric       llvm_unreachable("");
211081ad6265SDimitry Andric     }
211181ad6265SDimitry Andric   }
211281ad6265SDimitry Andric }
211381ad6265SDimitry Andric 
2114bdd1243dSDimitry Andric // Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
2115bdd1243dSDimitry Andric // values.
2116bdd1243dSDimitry Andric static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val,
2117bdd1243dSDimitry Andric                                    const CCValAssign &VA, const SDLoc &DL) {
2118bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
2119bdd1243dSDimitry Andric   default:
2120bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
2121bdd1243dSDimitry Andric   case CCValAssign::Full:
2122bdd1243dSDimitry Andric   case CCValAssign::Indirect:
2123bdd1243dSDimitry Andric     break;
2124bdd1243dSDimitry Andric   case CCValAssign::BCvt:
2125bdd1243dSDimitry Andric     if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
2126bdd1243dSDimitry Andric       Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
2127bdd1243dSDimitry Andric     else
2128bdd1243dSDimitry Andric       Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
2129bdd1243dSDimitry Andric     break;
2130bdd1243dSDimitry Andric   }
2131bdd1243dSDimitry Andric   return Val;
2132bdd1243dSDimitry Andric }
2133bdd1243dSDimitry Andric 
213481ad6265SDimitry Andric static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain,
213581ad6265SDimitry Andric                                 const CCValAssign &VA, const SDLoc &DL,
213681ad6265SDimitry Andric                                 const LoongArchTargetLowering &TLI) {
213781ad6265SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
213881ad6265SDimitry Andric   MachineRegisterInfo &RegInfo = MF.getRegInfo();
213981ad6265SDimitry Andric   EVT LocVT = VA.getLocVT();
2140bdd1243dSDimitry Andric   SDValue Val;
214181ad6265SDimitry Andric   const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
214281ad6265SDimitry Andric   Register VReg = RegInfo.createVirtualRegister(RC);
214381ad6265SDimitry Andric   RegInfo.addLiveIn(VA.getLocReg(), VReg);
2144bdd1243dSDimitry Andric   Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
214581ad6265SDimitry Andric 
2146bdd1243dSDimitry Andric   return convertLocVTToValVT(DAG, Val, VA, DL);
2147bdd1243dSDimitry Andric }
2148bdd1243dSDimitry Andric 
2149bdd1243dSDimitry Andric // The caller is responsible for loading the full value if the argument is
2150bdd1243dSDimitry Andric // passed with CCValAssign::Indirect.
2151bdd1243dSDimitry Andric static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain,
2152bdd1243dSDimitry Andric                                 const CCValAssign &VA, const SDLoc &DL) {
2153bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
2154bdd1243dSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
2155bdd1243dSDimitry Andric   EVT ValVT = VA.getValVT();
2156bdd1243dSDimitry Andric   int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
2157bdd1243dSDimitry Andric                                  /*IsImmutable=*/true);
2158bdd1243dSDimitry Andric   SDValue FIN = DAG.getFrameIndex(
2159bdd1243dSDimitry Andric       FI, MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0)));
2160bdd1243dSDimitry Andric 
2161bdd1243dSDimitry Andric   ISD::LoadExtType ExtType;
2162bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
2163bdd1243dSDimitry Andric   default:
2164bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
2165bdd1243dSDimitry Andric   case CCValAssign::Full:
2166bdd1243dSDimitry Andric   case CCValAssign::Indirect:
2167bdd1243dSDimitry Andric   case CCValAssign::BCvt:
2168bdd1243dSDimitry Andric     ExtType = ISD::NON_EXTLOAD;
2169bdd1243dSDimitry Andric     break;
2170bdd1243dSDimitry Andric   }
2171bdd1243dSDimitry Andric   return DAG.getExtLoad(
2172bdd1243dSDimitry Andric       ExtType, DL, VA.getLocVT(), Chain, FIN,
2173bdd1243dSDimitry Andric       MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT);
2174bdd1243dSDimitry Andric }
2175bdd1243dSDimitry Andric 
2176bdd1243dSDimitry Andric static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
2177bdd1243dSDimitry Andric                                    const CCValAssign &VA, const SDLoc &DL) {
2178bdd1243dSDimitry Andric   EVT LocVT = VA.getLocVT();
2179bdd1243dSDimitry Andric 
2180bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
2181bdd1243dSDimitry Andric   default:
2182bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
2183bdd1243dSDimitry Andric   case CCValAssign::Full:
2184bdd1243dSDimitry Andric     break;
2185bdd1243dSDimitry Andric   case CCValAssign::BCvt:
2186bdd1243dSDimitry Andric     if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
2187bdd1243dSDimitry Andric       Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
2188bdd1243dSDimitry Andric     else
2189bdd1243dSDimitry Andric       Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
2190bdd1243dSDimitry Andric     break;
2191bdd1243dSDimitry Andric   }
2192bdd1243dSDimitry Andric   return Val;
2193bdd1243dSDimitry Andric }
2194bdd1243dSDimitry Andric 
2195bdd1243dSDimitry Andric static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
2196bdd1243dSDimitry Andric                              CCValAssign::LocInfo LocInfo,
2197bdd1243dSDimitry Andric                              ISD::ArgFlagsTy ArgFlags, CCState &State) {
2198bdd1243dSDimitry Andric   if (LocVT == MVT::i32 || LocVT == MVT::i64) {
2199bdd1243dSDimitry Andric     // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
2200bdd1243dSDimitry Andric     //                        s0    s1  s2  s3  s4  s5  s6  s7  s8
2201bdd1243dSDimitry Andric     static const MCPhysReg GPRList[] = {
2202*06c3fb27SDimitry Andric         LoongArch::R23, LoongArch::R24, LoongArch::R25,
2203*06c3fb27SDimitry Andric         LoongArch::R26, LoongArch::R27, LoongArch::R28,
2204*06c3fb27SDimitry Andric         LoongArch::R29, LoongArch::R30, LoongArch::R31};
2205bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(GPRList)) {
2206bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2207bdd1243dSDimitry Andric       return false;
2208bdd1243dSDimitry Andric     }
2209bdd1243dSDimitry Andric   }
2210bdd1243dSDimitry Andric 
2211bdd1243dSDimitry Andric   if (LocVT == MVT::f32) {
2212bdd1243dSDimitry Andric     // Pass in STG registers: F1, F2, F3, F4
2213bdd1243dSDimitry Andric     //                        fs0,fs1,fs2,fs3
2214bdd1243dSDimitry Andric     static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
2215bdd1243dSDimitry Andric                                           LoongArch::F26, LoongArch::F27};
2216bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(FPR32List)) {
2217bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2218bdd1243dSDimitry Andric       return false;
2219bdd1243dSDimitry Andric     }
2220bdd1243dSDimitry Andric   }
2221bdd1243dSDimitry Andric 
2222bdd1243dSDimitry Andric   if (LocVT == MVT::f64) {
2223bdd1243dSDimitry Andric     // Pass in STG registers: D1, D2, D3, D4
2224bdd1243dSDimitry Andric     //                        fs4,fs5,fs6,fs7
2225bdd1243dSDimitry Andric     static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
2226bdd1243dSDimitry Andric                                           LoongArch::F30_64, LoongArch::F31_64};
2227bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(FPR64List)) {
2228bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2229bdd1243dSDimitry Andric       return false;
2230bdd1243dSDimitry Andric     }
2231bdd1243dSDimitry Andric   }
2232bdd1243dSDimitry Andric 
2233bdd1243dSDimitry Andric   report_fatal_error("No registers left in GHC calling convention");
2234bdd1243dSDimitry Andric   return true;
223581ad6265SDimitry Andric }
223681ad6265SDimitry Andric 
223781ad6265SDimitry Andric // Transform physical registers into virtual registers.
223881ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerFormalArguments(
223981ad6265SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
224081ad6265SDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
224181ad6265SDimitry Andric     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
224281ad6265SDimitry Andric 
224381ad6265SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
224481ad6265SDimitry Andric 
224581ad6265SDimitry Andric   switch (CallConv) {
224681ad6265SDimitry Andric   default:
224781ad6265SDimitry Andric     llvm_unreachable("Unsupported calling convention");
224881ad6265SDimitry Andric   case CallingConv::C:
2249bdd1243dSDimitry Andric   case CallingConv::Fast:
225081ad6265SDimitry Andric     break;
2251bdd1243dSDimitry Andric   case CallingConv::GHC:
2252*06c3fb27SDimitry Andric     if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
2253*06c3fb27SDimitry Andric         !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
2254bdd1243dSDimitry Andric       report_fatal_error(
2255bdd1243dSDimitry Andric           "GHC calling convention requires the F and D extensions");
225681ad6265SDimitry Andric   }
225781ad6265SDimitry Andric 
2258bdd1243dSDimitry Andric   EVT PtrVT = getPointerTy(DAG.getDataLayout());
2259bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
2260bdd1243dSDimitry Andric   unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
2261bdd1243dSDimitry Andric   // Used with varargs to acumulate store chains.
2262bdd1243dSDimitry Andric   std::vector<SDValue> OutChains;
2263bdd1243dSDimitry Andric 
226481ad6265SDimitry Andric   // Assign locations to all of the incoming arguments.
226581ad6265SDimitry Andric   SmallVector<CCValAssign> ArgLocs;
226681ad6265SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
226781ad6265SDimitry Andric 
2268bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC)
2269bdd1243dSDimitry Andric     CCInfo.AnalyzeFormalArguments(Ins, CC_LoongArch_GHC);
2270bdd1243dSDimitry Andric   else
2271bdd1243dSDimitry Andric     analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
227281ad6265SDimitry Andric 
2273bdd1243dSDimitry Andric   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
2274bdd1243dSDimitry Andric     CCValAssign &VA = ArgLocs[i];
2275bdd1243dSDimitry Andric     SDValue ArgValue;
2276bdd1243dSDimitry Andric     if (VA.isRegLoc())
2277bdd1243dSDimitry Andric       ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, *this);
2278bdd1243dSDimitry Andric     else
2279bdd1243dSDimitry Andric       ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
2280bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect) {
2281bdd1243dSDimitry Andric       // If the original argument was split and passed by reference, we need to
2282bdd1243dSDimitry Andric       // load all parts of it here (using the same address).
2283bdd1243dSDimitry Andric       InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
2284bdd1243dSDimitry Andric                                    MachinePointerInfo()));
2285bdd1243dSDimitry Andric       unsigned ArgIndex = Ins[i].OrigArgIndex;
2286bdd1243dSDimitry Andric       unsigned ArgPartOffset = Ins[i].PartOffset;
2287bdd1243dSDimitry Andric       assert(ArgPartOffset == 0);
2288bdd1243dSDimitry Andric       while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) {
2289bdd1243dSDimitry Andric         CCValAssign &PartVA = ArgLocs[i + 1];
2290bdd1243dSDimitry Andric         unsigned PartOffset = Ins[i + 1].PartOffset - ArgPartOffset;
2291bdd1243dSDimitry Andric         SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
2292bdd1243dSDimitry Andric         SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
2293bdd1243dSDimitry Andric         InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
2294bdd1243dSDimitry Andric                                      MachinePointerInfo()));
2295bdd1243dSDimitry Andric         ++i;
2296bdd1243dSDimitry Andric       }
2297bdd1243dSDimitry Andric       continue;
2298bdd1243dSDimitry Andric     }
2299bdd1243dSDimitry Andric     InVals.push_back(ArgValue);
2300bdd1243dSDimitry Andric   }
2301bdd1243dSDimitry Andric 
2302bdd1243dSDimitry Andric   if (IsVarArg) {
2303bdd1243dSDimitry Andric     ArrayRef<MCPhysReg> ArgRegs = ArrayRef(ArgGPRs);
2304bdd1243dSDimitry Andric     unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
2305bdd1243dSDimitry Andric     const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
2306bdd1243dSDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
2307bdd1243dSDimitry Andric     MachineRegisterInfo &RegInfo = MF.getRegInfo();
2308bdd1243dSDimitry Andric     auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
2309bdd1243dSDimitry Andric 
2310bdd1243dSDimitry Andric     // Offset of the first variable argument from stack pointer, and size of
2311bdd1243dSDimitry Andric     // the vararg save area. For now, the varargs save area is either zero or
2312bdd1243dSDimitry Andric     // large enough to hold a0-a7.
2313bdd1243dSDimitry Andric     int VaArgOffset, VarArgsSaveSize;
2314bdd1243dSDimitry Andric 
2315bdd1243dSDimitry Andric     // If all registers are allocated, then all varargs must be passed on the
2316bdd1243dSDimitry Andric     // stack and we don't need to save any argregs.
2317bdd1243dSDimitry Andric     if (ArgRegs.size() == Idx) {
2318*06c3fb27SDimitry Andric       VaArgOffset = CCInfo.getStackSize();
2319bdd1243dSDimitry Andric       VarArgsSaveSize = 0;
2320bdd1243dSDimitry Andric     } else {
2321bdd1243dSDimitry Andric       VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
2322bdd1243dSDimitry Andric       VaArgOffset = -VarArgsSaveSize;
2323bdd1243dSDimitry Andric     }
2324bdd1243dSDimitry Andric 
2325bdd1243dSDimitry Andric     // Record the frame index of the first variable argument
2326bdd1243dSDimitry Andric     // which is a value necessary to VASTART.
2327bdd1243dSDimitry Andric     int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
2328bdd1243dSDimitry Andric     LoongArchFI->setVarArgsFrameIndex(FI);
2329bdd1243dSDimitry Andric 
2330bdd1243dSDimitry Andric     // If saving an odd number of registers then create an extra stack slot to
2331bdd1243dSDimitry Andric     // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
2332bdd1243dSDimitry Andric     // offsets to even-numbered registered remain 2*GRLen-aligned.
2333bdd1243dSDimitry Andric     if (Idx % 2) {
2334bdd1243dSDimitry Andric       MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
2335bdd1243dSDimitry Andric                             true);
2336bdd1243dSDimitry Andric       VarArgsSaveSize += GRLenInBytes;
2337bdd1243dSDimitry Andric     }
2338bdd1243dSDimitry Andric 
2339bdd1243dSDimitry Andric     // Copy the integer registers that may have been used for passing varargs
2340bdd1243dSDimitry Andric     // to the vararg save area.
2341bdd1243dSDimitry Andric     for (unsigned I = Idx; I < ArgRegs.size();
2342bdd1243dSDimitry Andric          ++I, VaArgOffset += GRLenInBytes) {
2343bdd1243dSDimitry Andric       const Register Reg = RegInfo.createVirtualRegister(RC);
2344bdd1243dSDimitry Andric       RegInfo.addLiveIn(ArgRegs[I], Reg);
2345bdd1243dSDimitry Andric       SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
2346bdd1243dSDimitry Andric       FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
2347bdd1243dSDimitry Andric       SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
2348bdd1243dSDimitry Andric       SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
2349bdd1243dSDimitry Andric                                    MachinePointerInfo::getFixedStack(MF, FI));
2350bdd1243dSDimitry Andric       cast<StoreSDNode>(Store.getNode())
2351bdd1243dSDimitry Andric           ->getMemOperand()
2352bdd1243dSDimitry Andric           ->setValue((Value *)nullptr);
2353bdd1243dSDimitry Andric       OutChains.push_back(Store);
2354bdd1243dSDimitry Andric     }
2355bdd1243dSDimitry Andric     LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
2356bdd1243dSDimitry Andric   }
2357bdd1243dSDimitry Andric 
2358bdd1243dSDimitry Andric   // All stores are grouped in one node to allow the matching between
2359bdd1243dSDimitry Andric   // the size of Ins and InVals. This only happens for vararg functions.
2360bdd1243dSDimitry Andric   if (!OutChains.empty()) {
2361bdd1243dSDimitry Andric     OutChains.push_back(Chain);
2362bdd1243dSDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
2363bdd1243dSDimitry Andric   }
236481ad6265SDimitry Andric 
236581ad6265SDimitry Andric   return Chain;
236681ad6265SDimitry Andric }
236781ad6265SDimitry Andric 
2368bdd1243dSDimitry Andric bool LoongArchTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
2369bdd1243dSDimitry Andric   return CI->isTailCall();
2370bdd1243dSDimitry Andric }
2371bdd1243dSDimitry Andric 
2372*06c3fb27SDimitry Andric // Check if the return value is used as only a return value, as otherwise
2373*06c3fb27SDimitry Andric // we can't perform a tail-call.
2374*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isUsedByReturnOnly(SDNode *N,
2375*06c3fb27SDimitry Andric                                                  SDValue &Chain) const {
2376*06c3fb27SDimitry Andric   if (N->getNumValues() != 1)
2377*06c3fb27SDimitry Andric     return false;
2378*06c3fb27SDimitry Andric   if (!N->hasNUsesOfValue(1, 0))
2379*06c3fb27SDimitry Andric     return false;
2380*06c3fb27SDimitry Andric 
2381*06c3fb27SDimitry Andric   SDNode *Copy = *N->use_begin();
2382*06c3fb27SDimitry Andric   if (Copy->getOpcode() != ISD::CopyToReg)
2383*06c3fb27SDimitry Andric     return false;
2384*06c3fb27SDimitry Andric 
2385*06c3fb27SDimitry Andric   // If the ISD::CopyToReg has a glue operand, we conservatively assume it
2386*06c3fb27SDimitry Andric   // isn't safe to perform a tail call.
2387*06c3fb27SDimitry Andric   if (Copy->getGluedNode())
2388*06c3fb27SDimitry Andric     return false;
2389*06c3fb27SDimitry Andric 
2390*06c3fb27SDimitry Andric   // The copy must be used by a LoongArchISD::RET, and nothing else.
2391*06c3fb27SDimitry Andric   bool HasRet = false;
2392*06c3fb27SDimitry Andric   for (SDNode *Node : Copy->uses()) {
2393*06c3fb27SDimitry Andric     if (Node->getOpcode() != LoongArchISD::RET)
2394*06c3fb27SDimitry Andric       return false;
2395*06c3fb27SDimitry Andric     HasRet = true;
2396*06c3fb27SDimitry Andric   }
2397*06c3fb27SDimitry Andric 
2398*06c3fb27SDimitry Andric   if (!HasRet)
2399*06c3fb27SDimitry Andric     return false;
2400*06c3fb27SDimitry Andric 
2401*06c3fb27SDimitry Andric   Chain = Copy->getOperand(0);
2402*06c3fb27SDimitry Andric   return true;
2403*06c3fb27SDimitry Andric }
2404*06c3fb27SDimitry Andric 
2405bdd1243dSDimitry Andric // Check whether the call is eligible for tail call optimization.
2406bdd1243dSDimitry Andric bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
2407bdd1243dSDimitry Andric     CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
2408bdd1243dSDimitry Andric     const SmallVectorImpl<CCValAssign> &ArgLocs) const {
2409bdd1243dSDimitry Andric 
2410bdd1243dSDimitry Andric   auto CalleeCC = CLI.CallConv;
2411bdd1243dSDimitry Andric   auto &Outs = CLI.Outs;
2412bdd1243dSDimitry Andric   auto &Caller = MF.getFunction();
2413bdd1243dSDimitry Andric   auto CallerCC = Caller.getCallingConv();
2414bdd1243dSDimitry Andric 
2415bdd1243dSDimitry Andric   // Do not tail call opt if the stack is used to pass parameters.
2416*06c3fb27SDimitry Andric   if (CCInfo.getStackSize() != 0)
2417bdd1243dSDimitry Andric     return false;
2418bdd1243dSDimitry Andric 
2419bdd1243dSDimitry Andric   // Do not tail call opt if any parameters need to be passed indirectly.
2420bdd1243dSDimitry Andric   for (auto &VA : ArgLocs)
2421bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect)
2422bdd1243dSDimitry Andric       return false;
2423bdd1243dSDimitry Andric 
2424bdd1243dSDimitry Andric   // Do not tail call opt if either caller or callee uses struct return
2425bdd1243dSDimitry Andric   // semantics.
2426bdd1243dSDimitry Andric   auto IsCallerStructRet = Caller.hasStructRetAttr();
2427bdd1243dSDimitry Andric   auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
2428bdd1243dSDimitry Andric   if (IsCallerStructRet || IsCalleeStructRet)
2429bdd1243dSDimitry Andric     return false;
2430bdd1243dSDimitry Andric 
2431bdd1243dSDimitry Andric   // Do not tail call opt if either the callee or caller has a byval argument.
2432bdd1243dSDimitry Andric   for (auto &Arg : Outs)
2433bdd1243dSDimitry Andric     if (Arg.Flags.isByVal())
2434bdd1243dSDimitry Andric       return false;
2435bdd1243dSDimitry Andric 
2436bdd1243dSDimitry Andric   // The callee has to preserve all registers the caller needs to preserve.
2437bdd1243dSDimitry Andric   const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
2438bdd1243dSDimitry Andric   const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
2439bdd1243dSDimitry Andric   if (CalleeCC != CallerCC) {
2440bdd1243dSDimitry Andric     const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
2441bdd1243dSDimitry Andric     if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
2442bdd1243dSDimitry Andric       return false;
2443bdd1243dSDimitry Andric   }
2444bdd1243dSDimitry Andric   return true;
2445bdd1243dSDimitry Andric }
2446bdd1243dSDimitry Andric 
2447bdd1243dSDimitry Andric static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG) {
2448bdd1243dSDimitry Andric   return DAG.getDataLayout().getPrefTypeAlign(
2449bdd1243dSDimitry Andric       VT.getTypeForEVT(*DAG.getContext()));
2450bdd1243dSDimitry Andric }
2451bdd1243dSDimitry Andric 
2452753f127fSDimitry Andric // Lower a call to a callseq_start + CALL + callseq_end chain, and add input
2453753f127fSDimitry Andric // and output parameter nodes.
2454753f127fSDimitry Andric SDValue
2455753f127fSDimitry Andric LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
2456753f127fSDimitry Andric                                    SmallVectorImpl<SDValue> &InVals) const {
2457753f127fSDimitry Andric   SelectionDAG &DAG = CLI.DAG;
2458753f127fSDimitry Andric   SDLoc &DL = CLI.DL;
2459753f127fSDimitry Andric   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
2460753f127fSDimitry Andric   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
2461753f127fSDimitry Andric   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
2462753f127fSDimitry Andric   SDValue Chain = CLI.Chain;
2463753f127fSDimitry Andric   SDValue Callee = CLI.Callee;
2464753f127fSDimitry Andric   CallingConv::ID CallConv = CLI.CallConv;
2465753f127fSDimitry Andric   bool IsVarArg = CLI.IsVarArg;
2466753f127fSDimitry Andric   EVT PtrVT = getPointerTy(DAG.getDataLayout());
2467bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
2468bdd1243dSDimitry Andric   bool &IsTailCall = CLI.IsTailCall;
2469753f127fSDimitry Andric 
2470753f127fSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
2471753f127fSDimitry Andric 
2472753f127fSDimitry Andric   // Analyze the operands of the call, assigning locations to each operand.
2473753f127fSDimitry Andric   SmallVector<CCValAssign> ArgLocs;
2474753f127fSDimitry Andric   CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
2475753f127fSDimitry Andric 
2476bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC)
2477bdd1243dSDimitry Andric     ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
2478bdd1243dSDimitry Andric   else
2479bdd1243dSDimitry Andric     analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
2480bdd1243dSDimitry Andric 
2481bdd1243dSDimitry Andric   // Check if it's really possible to do a tail call.
2482bdd1243dSDimitry Andric   if (IsTailCall)
2483bdd1243dSDimitry Andric     IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
2484bdd1243dSDimitry Andric 
2485bdd1243dSDimitry Andric   if (IsTailCall)
2486bdd1243dSDimitry Andric     ++NumTailCalls;
2487bdd1243dSDimitry Andric   else if (CLI.CB && CLI.CB->isMustTailCall())
2488bdd1243dSDimitry Andric     report_fatal_error("failed to perform tail call elimination on a call "
2489bdd1243dSDimitry Andric                        "site marked musttail");
2490753f127fSDimitry Andric 
2491753f127fSDimitry Andric   // Get a count of how many bytes are to be pushed on the stack.
2492*06c3fb27SDimitry Andric   unsigned NumBytes = ArgCCInfo.getStackSize();
2493753f127fSDimitry Andric 
2494bdd1243dSDimitry Andric   // Create local copies for byval args.
2495bdd1243dSDimitry Andric   SmallVector<SDValue> ByValArgs;
2496bdd1243dSDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2497bdd1243dSDimitry Andric     ISD::ArgFlagsTy Flags = Outs[i].Flags;
2498bdd1243dSDimitry Andric     if (!Flags.isByVal())
2499753f127fSDimitry Andric       continue;
2500bdd1243dSDimitry Andric 
2501bdd1243dSDimitry Andric     SDValue Arg = OutVals[i];
2502bdd1243dSDimitry Andric     unsigned Size = Flags.getByValSize();
2503bdd1243dSDimitry Andric     Align Alignment = Flags.getNonZeroByValAlign();
2504bdd1243dSDimitry Andric 
2505bdd1243dSDimitry Andric     int FI =
2506bdd1243dSDimitry Andric         MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
2507bdd1243dSDimitry Andric     SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
2508bdd1243dSDimitry Andric     SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
2509bdd1243dSDimitry Andric 
2510bdd1243dSDimitry Andric     Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment,
2511bdd1243dSDimitry Andric                           /*IsVolatile=*/false,
2512bdd1243dSDimitry Andric                           /*AlwaysInline=*/false, /*isTailCall=*/IsTailCall,
2513bdd1243dSDimitry Andric                           MachinePointerInfo(), MachinePointerInfo());
2514bdd1243dSDimitry Andric     ByValArgs.push_back(FIPtr);
2515753f127fSDimitry Andric   }
2516753f127fSDimitry Andric 
2517bdd1243dSDimitry Andric   if (!IsTailCall)
2518753f127fSDimitry Andric     Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
2519753f127fSDimitry Andric 
2520753f127fSDimitry Andric   // Copy argument values to their designated locations.
2521753f127fSDimitry Andric   SmallVector<std::pair<Register, SDValue>> RegsToPass;
2522bdd1243dSDimitry Andric   SmallVector<SDValue> MemOpChains;
2523bdd1243dSDimitry Andric   SDValue StackPtr;
2524bdd1243dSDimitry Andric   for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) {
2525753f127fSDimitry Andric     CCValAssign &VA = ArgLocs[i];
2526753f127fSDimitry Andric     SDValue ArgValue = OutVals[i];
2527bdd1243dSDimitry Andric     ISD::ArgFlagsTy Flags = Outs[i].Flags;
2528753f127fSDimitry Andric 
2529753f127fSDimitry Andric     // Promote the value if needed.
2530bdd1243dSDimitry Andric     // For now, only handle fully promoted and indirect arguments.
2531bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect) {
2532bdd1243dSDimitry Andric       // Store the argument in a stack slot and pass its address.
2533bdd1243dSDimitry Andric       Align StackAlign =
2534bdd1243dSDimitry Andric           std::max(getPrefTypeAlign(Outs[i].ArgVT, DAG),
2535bdd1243dSDimitry Andric                    getPrefTypeAlign(ArgValue.getValueType(), DAG));
2536bdd1243dSDimitry Andric       TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
2537bdd1243dSDimitry Andric       // If the original argument was split and passed by reference, we need to
2538bdd1243dSDimitry Andric       // store the required parts of it here (and pass just one address).
2539bdd1243dSDimitry Andric       unsigned ArgIndex = Outs[i].OrigArgIndex;
2540bdd1243dSDimitry Andric       unsigned ArgPartOffset = Outs[i].PartOffset;
2541bdd1243dSDimitry Andric       assert(ArgPartOffset == 0);
2542bdd1243dSDimitry Andric       // Calculate the total size to store. We don't have access to what we're
2543bdd1243dSDimitry Andric       // actually storing other than performing the loop and collecting the
2544bdd1243dSDimitry Andric       // info.
2545bdd1243dSDimitry Andric       SmallVector<std::pair<SDValue, SDValue>> Parts;
2546bdd1243dSDimitry Andric       while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) {
2547bdd1243dSDimitry Andric         SDValue PartValue = OutVals[i + 1];
2548bdd1243dSDimitry Andric         unsigned PartOffset = Outs[i + 1].PartOffset - ArgPartOffset;
2549bdd1243dSDimitry Andric         SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
2550bdd1243dSDimitry Andric         EVT PartVT = PartValue.getValueType();
2551bdd1243dSDimitry Andric 
2552bdd1243dSDimitry Andric         StoredSize += PartVT.getStoreSize();
2553bdd1243dSDimitry Andric         StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
2554bdd1243dSDimitry Andric         Parts.push_back(std::make_pair(PartValue, Offset));
2555bdd1243dSDimitry Andric         ++i;
2556bdd1243dSDimitry Andric       }
2557bdd1243dSDimitry Andric       SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
2558bdd1243dSDimitry Andric       int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
2559bdd1243dSDimitry Andric       MemOpChains.push_back(
2560bdd1243dSDimitry Andric           DAG.getStore(Chain, DL, ArgValue, SpillSlot,
2561bdd1243dSDimitry Andric                        MachinePointerInfo::getFixedStack(MF, FI)));
2562bdd1243dSDimitry Andric       for (const auto &Part : Parts) {
2563bdd1243dSDimitry Andric         SDValue PartValue = Part.first;
2564bdd1243dSDimitry Andric         SDValue PartOffset = Part.second;
2565bdd1243dSDimitry Andric         SDValue Address =
2566bdd1243dSDimitry Andric             DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
2567bdd1243dSDimitry Andric         MemOpChains.push_back(
2568bdd1243dSDimitry Andric             DAG.getStore(Chain, DL, PartValue, Address,
2569bdd1243dSDimitry Andric                          MachinePointerInfo::getFixedStack(MF, FI)));
2570bdd1243dSDimitry Andric       }
2571bdd1243dSDimitry Andric       ArgValue = SpillSlot;
2572bdd1243dSDimitry Andric     } else {
2573bdd1243dSDimitry Andric       ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
2574bdd1243dSDimitry Andric     }
2575bdd1243dSDimitry Andric 
2576bdd1243dSDimitry Andric     // Use local copy if it is a byval arg.
2577bdd1243dSDimitry Andric     if (Flags.isByVal())
2578bdd1243dSDimitry Andric       ArgValue = ByValArgs[j++];
2579753f127fSDimitry Andric 
2580753f127fSDimitry Andric     if (VA.isRegLoc()) {
2581753f127fSDimitry Andric       // Queue up the argument copies and emit them at the end.
2582753f127fSDimitry Andric       RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
2583753f127fSDimitry Andric     } else {
2584bdd1243dSDimitry Andric       assert(VA.isMemLoc() && "Argument not register or memory");
2585bdd1243dSDimitry Andric       assert(!IsTailCall && "Tail call not allowed if stack is used "
2586bdd1243dSDimitry Andric                             "for passing parameters");
2587bdd1243dSDimitry Andric 
2588bdd1243dSDimitry Andric       // Work out the address of the stack slot.
2589bdd1243dSDimitry Andric       if (!StackPtr.getNode())
2590bdd1243dSDimitry Andric         StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
2591bdd1243dSDimitry Andric       SDValue Address =
2592bdd1243dSDimitry Andric           DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
2593bdd1243dSDimitry Andric                       DAG.getIntPtrConstant(VA.getLocMemOffset(), DL));
2594bdd1243dSDimitry Andric 
2595bdd1243dSDimitry Andric       // Emit the store.
2596bdd1243dSDimitry Andric       MemOpChains.push_back(
2597bdd1243dSDimitry Andric           DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
2598753f127fSDimitry Andric     }
2599753f127fSDimitry Andric   }
2600753f127fSDimitry Andric 
2601bdd1243dSDimitry Andric   // Join the stores, which are independent of one another.
2602bdd1243dSDimitry Andric   if (!MemOpChains.empty())
2603bdd1243dSDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
2604bdd1243dSDimitry Andric 
2605753f127fSDimitry Andric   SDValue Glue;
2606753f127fSDimitry Andric 
2607753f127fSDimitry Andric   // Build a sequence of copy-to-reg nodes, chained and glued together.
2608753f127fSDimitry Andric   for (auto &Reg : RegsToPass) {
2609753f127fSDimitry Andric     Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
2610753f127fSDimitry Andric     Glue = Chain.getValue(1);
2611753f127fSDimitry Andric   }
2612753f127fSDimitry Andric 
2613753f127fSDimitry Andric   // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
2614753f127fSDimitry Andric   // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
2615753f127fSDimitry Andric   // split it and then direct call can be matched by PseudoCALL.
2616bdd1243dSDimitry Andric   if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
2617bdd1243dSDimitry Andric     const GlobalValue *GV = S->getGlobal();
2618bdd1243dSDimitry Andric     unsigned OpFlags =
2619bdd1243dSDimitry Andric         getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)
2620bdd1243dSDimitry Andric             ? LoongArchII::MO_CALL
2621bdd1243dSDimitry Andric             : LoongArchII::MO_CALL_PLT;
2622bdd1243dSDimitry Andric     Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
2623bdd1243dSDimitry Andric   } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
2624bdd1243dSDimitry Andric     unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(
2625bdd1243dSDimitry Andric                            *MF.getFunction().getParent(), nullptr)
2626bdd1243dSDimitry Andric                            ? LoongArchII::MO_CALL
2627bdd1243dSDimitry Andric                            : LoongArchII::MO_CALL_PLT;
2628bdd1243dSDimitry Andric     Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
2629bdd1243dSDimitry Andric   }
2630753f127fSDimitry Andric 
2631753f127fSDimitry Andric   // The first call operand is the chain and the second is the target address.
2632753f127fSDimitry Andric   SmallVector<SDValue> Ops;
2633753f127fSDimitry Andric   Ops.push_back(Chain);
2634753f127fSDimitry Andric   Ops.push_back(Callee);
2635753f127fSDimitry Andric 
2636753f127fSDimitry Andric   // Add argument registers to the end of the list so that they are
2637753f127fSDimitry Andric   // known live into the call.
2638753f127fSDimitry Andric   for (auto &Reg : RegsToPass)
2639753f127fSDimitry Andric     Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
2640753f127fSDimitry Andric 
2641bdd1243dSDimitry Andric   if (!IsTailCall) {
2642753f127fSDimitry Andric     // Add a register mask operand representing the call-preserved registers.
2643753f127fSDimitry Andric     const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
2644753f127fSDimitry Andric     const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
2645753f127fSDimitry Andric     assert(Mask && "Missing call preserved mask for calling convention");
2646753f127fSDimitry Andric     Ops.push_back(DAG.getRegisterMask(Mask));
2647bdd1243dSDimitry Andric   }
2648753f127fSDimitry Andric 
2649753f127fSDimitry Andric   // Glue the call to the argument copies, if any.
2650753f127fSDimitry Andric   if (Glue.getNode())
2651753f127fSDimitry Andric     Ops.push_back(Glue);
2652753f127fSDimitry Andric 
2653753f127fSDimitry Andric   // Emit the call.
2654753f127fSDimitry Andric   SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
2655753f127fSDimitry Andric 
2656bdd1243dSDimitry Andric   if (IsTailCall) {
2657bdd1243dSDimitry Andric     MF.getFrameInfo().setHasTailCall();
2658*06c3fb27SDimitry Andric     SDValue Ret = DAG.getNode(LoongArchISD::TAIL, DL, NodeTys, Ops);
2659*06c3fb27SDimitry Andric     DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge);
2660*06c3fb27SDimitry Andric     return Ret;
2661bdd1243dSDimitry Andric   }
2662bdd1243dSDimitry Andric 
2663753f127fSDimitry Andric   Chain = DAG.getNode(LoongArchISD::CALL, DL, NodeTys, Ops);
2664753f127fSDimitry Andric   DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
2665753f127fSDimitry Andric   Glue = Chain.getValue(1);
2666753f127fSDimitry Andric 
2667753f127fSDimitry Andric   // Mark the end of the call, which is glued to the call itself.
2668bdd1243dSDimitry Andric   Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
2669753f127fSDimitry Andric   Glue = Chain.getValue(1);
2670753f127fSDimitry Andric 
2671753f127fSDimitry Andric   // Assign locations to each value returned by this call.
2672753f127fSDimitry Andric   SmallVector<CCValAssign> RVLocs;
2673753f127fSDimitry Andric   CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
2674bdd1243dSDimitry Andric   analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
2675753f127fSDimitry Andric 
2676753f127fSDimitry Andric   // Copy all of the result registers out of their specified physreg.
2677753f127fSDimitry Andric   for (auto &VA : RVLocs) {
2678753f127fSDimitry Andric     // Copy the value out.
2679753f127fSDimitry Andric     SDValue RetValue =
2680753f127fSDimitry Andric         DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
2681bdd1243dSDimitry Andric     // Glue the RetValue to the end of the call sequence.
2682753f127fSDimitry Andric     Chain = RetValue.getValue(1);
2683753f127fSDimitry Andric     Glue = RetValue.getValue(2);
2684753f127fSDimitry Andric 
2685bdd1243dSDimitry Andric     RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
2686bdd1243dSDimitry Andric 
2687bdd1243dSDimitry Andric     InVals.push_back(RetValue);
2688753f127fSDimitry Andric   }
2689753f127fSDimitry Andric 
2690753f127fSDimitry Andric   return Chain;
2691753f127fSDimitry Andric }
2692753f127fSDimitry Andric 
269381ad6265SDimitry Andric bool LoongArchTargetLowering::CanLowerReturn(
269481ad6265SDimitry Andric     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
269581ad6265SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
2696bdd1243dSDimitry Andric   SmallVector<CCValAssign> RVLocs;
2697bdd1243dSDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
2698bdd1243dSDimitry Andric 
2699bdd1243dSDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2700bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
2701bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2702bdd1243dSDimitry Andric     if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
2703bdd1243dSDimitry Andric                      Outs[i].Flags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true,
2704bdd1243dSDimitry Andric                      nullptr))
2705bdd1243dSDimitry Andric       return false;
2706bdd1243dSDimitry Andric   }
2707bdd1243dSDimitry Andric   return true;
270881ad6265SDimitry Andric }
270981ad6265SDimitry Andric 
271081ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerReturn(
271181ad6265SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
271281ad6265SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs,
271381ad6265SDimitry Andric     const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
271481ad6265SDimitry Andric     SelectionDAG &DAG) const {
271581ad6265SDimitry Andric   // Stores the assignment of the return value to a location.
271681ad6265SDimitry Andric   SmallVector<CCValAssign> RVLocs;
271781ad6265SDimitry Andric 
271881ad6265SDimitry Andric   // Info about the registers and stack slot.
271981ad6265SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
272081ad6265SDimitry Andric                  *DAG.getContext());
272181ad6265SDimitry Andric 
2722bdd1243dSDimitry Andric   analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
2723bdd1243dSDimitry Andric                     nullptr, CC_LoongArch);
2724bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC && !RVLocs.empty())
2725bdd1243dSDimitry Andric     report_fatal_error("GHC functions return void only");
272681ad6265SDimitry Andric   SDValue Glue;
272781ad6265SDimitry Andric   SmallVector<SDValue, 4> RetOps(1, Chain);
272881ad6265SDimitry Andric 
272981ad6265SDimitry Andric   // Copy the result values into the output registers.
273081ad6265SDimitry Andric   for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) {
273181ad6265SDimitry Andric     CCValAssign &VA = RVLocs[i];
273281ad6265SDimitry Andric     assert(VA.isRegLoc() && "Can only return in registers!");
273381ad6265SDimitry Andric 
273481ad6265SDimitry Andric     // Handle a 'normal' return.
2735bdd1243dSDimitry Andric     SDValue Val = convertValVTToLocVT(DAG, OutVals[i], VA, DL);
2736bdd1243dSDimitry Andric     Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
273781ad6265SDimitry Andric 
273881ad6265SDimitry Andric     // Guarantee that all emitted copies are stuck together.
273981ad6265SDimitry Andric     Glue = Chain.getValue(1);
274081ad6265SDimitry Andric     RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
274181ad6265SDimitry Andric   }
274281ad6265SDimitry Andric 
274381ad6265SDimitry Andric   RetOps[0] = Chain; // Update chain.
274481ad6265SDimitry Andric 
274581ad6265SDimitry Andric   // Add the glue node if we have it.
274681ad6265SDimitry Andric   if (Glue.getNode())
274781ad6265SDimitry Andric     RetOps.push_back(Glue);
274881ad6265SDimitry Andric 
274981ad6265SDimitry Andric   return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
275081ad6265SDimitry Andric }
2751753f127fSDimitry Andric 
2752753f127fSDimitry Andric bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
2753753f127fSDimitry Andric                                            bool ForCodeSize) const {
2754bdd1243dSDimitry Andric   // TODO: Maybe need more checks here after vector extension is supported.
2755753f127fSDimitry Andric   if (VT == MVT::f32 && !Subtarget.hasBasicF())
2756753f127fSDimitry Andric     return false;
2757753f127fSDimitry Andric   if (VT == MVT::f64 && !Subtarget.hasBasicD())
2758753f127fSDimitry Andric     return false;
2759753f127fSDimitry Andric   return (Imm.isZero() || Imm.isExactlyValue(+1.0));
2760753f127fSDimitry Andric }
2761bdd1243dSDimitry Andric 
2762bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCttz(Type *) const {
2763bdd1243dSDimitry Andric   return true;
2764bdd1243dSDimitry Andric }
2765bdd1243dSDimitry Andric 
2766bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCtlz(Type *) const {
2767bdd1243dSDimitry Andric   return true;
2768bdd1243dSDimitry Andric }
2769bdd1243dSDimitry Andric 
2770bdd1243dSDimitry Andric bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
2771bdd1243dSDimitry Andric     const Instruction *I) const {
2772bdd1243dSDimitry Andric   if (!Subtarget.is64Bit())
2773bdd1243dSDimitry Andric     return isa<LoadInst>(I) || isa<StoreInst>(I);
2774bdd1243dSDimitry Andric 
2775bdd1243dSDimitry Andric   if (isa<LoadInst>(I))
2776bdd1243dSDimitry Andric     return true;
2777bdd1243dSDimitry Andric 
2778bdd1243dSDimitry Andric   // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
2779bdd1243dSDimitry Andric   // require fences beacuse we can use amswap_db.[w/d].
2780bdd1243dSDimitry Andric   if (isa<StoreInst>(I)) {
2781bdd1243dSDimitry Andric     unsigned Size = I->getOperand(0)->getType()->getIntegerBitWidth();
2782bdd1243dSDimitry Andric     return (Size == 8 || Size == 16);
2783bdd1243dSDimitry Andric   }
2784bdd1243dSDimitry Andric 
2785bdd1243dSDimitry Andric   return false;
2786bdd1243dSDimitry Andric }
2787bdd1243dSDimitry Andric 
2788bdd1243dSDimitry Andric EVT LoongArchTargetLowering::getSetCCResultType(const DataLayout &DL,
2789bdd1243dSDimitry Andric                                                 LLVMContext &Context,
2790bdd1243dSDimitry Andric                                                 EVT VT) const {
2791bdd1243dSDimitry Andric   if (!VT.isVector())
2792bdd1243dSDimitry Andric     return getPointerTy(DL);
2793bdd1243dSDimitry Andric   return VT.changeVectorElementTypeToInteger();
2794bdd1243dSDimitry Andric }
2795bdd1243dSDimitry Andric 
2796bdd1243dSDimitry Andric bool LoongArchTargetLowering::hasAndNot(SDValue Y) const {
2797bdd1243dSDimitry Andric   // TODO: Support vectors.
2798bdd1243dSDimitry Andric   return Y.getValueType().isScalarInteger() && !isa<ConstantSDNode>(Y);
2799bdd1243dSDimitry Andric }
2800bdd1243dSDimitry Andric 
2801bdd1243dSDimitry Andric bool LoongArchTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
2802bdd1243dSDimitry Andric                                                  const CallInst &I,
2803bdd1243dSDimitry Andric                                                  MachineFunction &MF,
2804bdd1243dSDimitry Andric                                                  unsigned Intrinsic) const {
2805bdd1243dSDimitry Andric   switch (Intrinsic) {
2806bdd1243dSDimitry Andric   default:
2807bdd1243dSDimitry Andric     return false;
2808bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
2809bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_add_i32:
2810bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
2811bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_nand_i32:
2812bdd1243dSDimitry Andric     Info.opc = ISD::INTRINSIC_W_CHAIN;
2813bdd1243dSDimitry Andric     Info.memVT = MVT::i32;
2814bdd1243dSDimitry Andric     Info.ptrVal = I.getArgOperand(0);
2815bdd1243dSDimitry Andric     Info.offset = 0;
2816bdd1243dSDimitry Andric     Info.align = Align(4);
2817bdd1243dSDimitry Andric     Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore |
2818bdd1243dSDimitry Andric                  MachineMemOperand::MOVolatile;
2819bdd1243dSDimitry Andric     return true;
2820bdd1243dSDimitry Andric     // TODO: Add more Intrinsics later.
2821bdd1243dSDimitry Andric   }
2822bdd1243dSDimitry Andric }
2823bdd1243dSDimitry Andric 
2824bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind
2825bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
2826bdd1243dSDimitry Andric   // TODO: Add more AtomicRMWInst that needs to be extended.
2827bdd1243dSDimitry Andric 
2828bdd1243dSDimitry Andric   // Since floating-point operation requires a non-trivial set of data
2829bdd1243dSDimitry Andric   // operations, use CmpXChg to expand.
2830bdd1243dSDimitry Andric   if (AI->isFloatingPointOperation() ||
2831bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::UIncWrap ||
2832bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::UDecWrap)
2833bdd1243dSDimitry Andric     return AtomicExpansionKind::CmpXChg;
2834bdd1243dSDimitry Andric 
2835bdd1243dSDimitry Andric   unsigned Size = AI->getType()->getPrimitiveSizeInBits();
2836bdd1243dSDimitry Andric   if (Size == 8 || Size == 16)
2837bdd1243dSDimitry Andric     return AtomicExpansionKind::MaskedIntrinsic;
2838bdd1243dSDimitry Andric   return AtomicExpansionKind::None;
2839bdd1243dSDimitry Andric }
2840bdd1243dSDimitry Andric 
2841bdd1243dSDimitry Andric static Intrinsic::ID
2842bdd1243dSDimitry Andric getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen,
2843bdd1243dSDimitry Andric                                     AtomicRMWInst::BinOp BinOp) {
2844bdd1243dSDimitry Andric   if (GRLen == 64) {
2845bdd1243dSDimitry Andric     switch (BinOp) {
2846bdd1243dSDimitry Andric     default:
2847bdd1243dSDimitry Andric       llvm_unreachable("Unexpected AtomicRMW BinOp");
2848bdd1243dSDimitry Andric     case AtomicRMWInst::Xchg:
2849bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
2850bdd1243dSDimitry Andric     case AtomicRMWInst::Add:
2851bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_add_i64;
2852bdd1243dSDimitry Andric     case AtomicRMWInst::Sub:
2853bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
2854bdd1243dSDimitry Andric     case AtomicRMWInst::Nand:
2855bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
2856bdd1243dSDimitry Andric     case AtomicRMWInst::UMax:
2857bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
2858bdd1243dSDimitry Andric     case AtomicRMWInst::UMin:
2859bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
2860bdd1243dSDimitry Andric     case AtomicRMWInst::Max:
2861bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_max_i64;
2862bdd1243dSDimitry Andric     case AtomicRMWInst::Min:
2863bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_min_i64;
2864bdd1243dSDimitry Andric       // TODO: support other AtomicRMWInst.
2865bdd1243dSDimitry Andric     }
2866bdd1243dSDimitry Andric   }
2867bdd1243dSDimitry Andric 
2868bdd1243dSDimitry Andric   if (GRLen == 32) {
2869bdd1243dSDimitry Andric     switch (BinOp) {
2870bdd1243dSDimitry Andric     default:
2871bdd1243dSDimitry Andric       llvm_unreachable("Unexpected AtomicRMW BinOp");
2872bdd1243dSDimitry Andric     case AtomicRMWInst::Xchg:
2873bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
2874bdd1243dSDimitry Andric     case AtomicRMWInst::Add:
2875bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_add_i32;
2876bdd1243dSDimitry Andric     case AtomicRMWInst::Sub:
2877bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
2878bdd1243dSDimitry Andric     case AtomicRMWInst::Nand:
2879bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
2880bdd1243dSDimitry Andric       // TODO: support other AtomicRMWInst.
2881bdd1243dSDimitry Andric     }
2882bdd1243dSDimitry Andric   }
2883bdd1243dSDimitry Andric 
2884bdd1243dSDimitry Andric   llvm_unreachable("Unexpected GRLen\n");
2885bdd1243dSDimitry Andric }
2886bdd1243dSDimitry Andric 
2887bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind
2888bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicCmpXchgInIR(
2889bdd1243dSDimitry Andric     AtomicCmpXchgInst *CI) const {
2890bdd1243dSDimitry Andric   unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits();
2891bdd1243dSDimitry Andric   if (Size == 8 || Size == 16)
2892bdd1243dSDimitry Andric     return AtomicExpansionKind::MaskedIntrinsic;
2893bdd1243dSDimitry Andric   return AtomicExpansionKind::None;
2894bdd1243dSDimitry Andric }
2895bdd1243dSDimitry Andric 
2896bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicCmpXchgIntrinsic(
2897bdd1243dSDimitry Andric     IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
2898bdd1243dSDimitry Andric     Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
2899bdd1243dSDimitry Andric   Value *Ordering =
2900bdd1243dSDimitry Andric       Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(Ord));
2901bdd1243dSDimitry Andric 
2902bdd1243dSDimitry Andric   // TODO: Support cmpxchg on LA32.
2903bdd1243dSDimitry Andric   Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
2904bdd1243dSDimitry Andric   CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
2905bdd1243dSDimitry Andric   NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
2906bdd1243dSDimitry Andric   Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
2907bdd1243dSDimitry Andric   Type *Tys[] = {AlignedAddr->getType()};
2908bdd1243dSDimitry Andric   Function *MaskedCmpXchg =
2909bdd1243dSDimitry Andric       Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys);
2910bdd1243dSDimitry Andric   Value *Result = Builder.CreateCall(
2911bdd1243dSDimitry Andric       MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, Ordering});
2912bdd1243dSDimitry Andric   Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
2913bdd1243dSDimitry Andric   return Result;
2914bdd1243dSDimitry Andric }
2915bdd1243dSDimitry Andric 
2916bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicRMWIntrinsic(
2917bdd1243dSDimitry Andric     IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
2918bdd1243dSDimitry Andric     Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
2919bdd1243dSDimitry Andric   unsigned GRLen = Subtarget.getGRLen();
2920bdd1243dSDimitry Andric   Value *Ordering =
2921bdd1243dSDimitry Andric       Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
2922bdd1243dSDimitry Andric   Type *Tys[] = {AlignedAddr->getType()};
2923bdd1243dSDimitry Andric   Function *LlwOpScwLoop = Intrinsic::getDeclaration(
2924bdd1243dSDimitry Andric       AI->getModule(),
2925bdd1243dSDimitry Andric       getIntrinsicForMaskedAtomicRMWBinOp(GRLen, AI->getOperation()), Tys);
2926bdd1243dSDimitry Andric 
2927bdd1243dSDimitry Andric   if (GRLen == 64) {
2928bdd1243dSDimitry Andric     Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
2929bdd1243dSDimitry Andric     Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
2930bdd1243dSDimitry Andric     ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
2931bdd1243dSDimitry Andric   }
2932bdd1243dSDimitry Andric 
2933bdd1243dSDimitry Andric   Value *Result;
2934bdd1243dSDimitry Andric 
2935bdd1243dSDimitry Andric   // Must pass the shift amount needed to sign extend the loaded value prior
2936bdd1243dSDimitry Andric   // to performing a signed comparison for min/max. ShiftAmt is the number of
2937bdd1243dSDimitry Andric   // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
2938bdd1243dSDimitry Andric   // is the number of bits to left+right shift the value in order to
2939bdd1243dSDimitry Andric   // sign-extend.
2940bdd1243dSDimitry Andric   if (AI->getOperation() == AtomicRMWInst::Min ||
2941bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::Max) {
2942bdd1243dSDimitry Andric     const DataLayout &DL = AI->getModule()->getDataLayout();
2943bdd1243dSDimitry Andric     unsigned ValWidth =
2944bdd1243dSDimitry Andric         DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
2945bdd1243dSDimitry Andric     Value *SextShamt =
2946bdd1243dSDimitry Andric         Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
2947bdd1243dSDimitry Andric     Result = Builder.CreateCall(LlwOpScwLoop,
2948bdd1243dSDimitry Andric                                 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
2949bdd1243dSDimitry Andric   } else {
2950bdd1243dSDimitry Andric     Result =
2951bdd1243dSDimitry Andric         Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
2952bdd1243dSDimitry Andric   }
2953bdd1243dSDimitry Andric 
2954bdd1243dSDimitry Andric   if (GRLen == 64)
2955bdd1243dSDimitry Andric     Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
2956bdd1243dSDimitry Andric   return Result;
2957bdd1243dSDimitry Andric }
2958bdd1243dSDimitry Andric 
2959bdd1243dSDimitry Andric bool LoongArchTargetLowering::isFMAFasterThanFMulAndFAdd(
2960bdd1243dSDimitry Andric     const MachineFunction &MF, EVT VT) const {
2961bdd1243dSDimitry Andric   VT = VT.getScalarType();
2962bdd1243dSDimitry Andric 
2963bdd1243dSDimitry Andric   if (!VT.isSimple())
2964bdd1243dSDimitry Andric     return false;
2965bdd1243dSDimitry Andric 
2966bdd1243dSDimitry Andric   switch (VT.getSimpleVT().SimpleTy) {
2967bdd1243dSDimitry Andric   case MVT::f32:
2968bdd1243dSDimitry Andric   case MVT::f64:
2969bdd1243dSDimitry Andric     return true;
2970bdd1243dSDimitry Andric   default:
2971bdd1243dSDimitry Andric     break;
2972bdd1243dSDimitry Andric   }
2973bdd1243dSDimitry Andric 
2974bdd1243dSDimitry Andric   return false;
2975bdd1243dSDimitry Andric }
2976bdd1243dSDimitry Andric 
2977bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionPointerRegister(
2978bdd1243dSDimitry Andric     const Constant *PersonalityFn) const {
2979bdd1243dSDimitry Andric   return LoongArch::R4;
2980bdd1243dSDimitry Andric }
2981bdd1243dSDimitry Andric 
2982bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionSelectorRegister(
2983bdd1243dSDimitry Andric     const Constant *PersonalityFn) const {
2984bdd1243dSDimitry Andric   return LoongArch::R5;
2985bdd1243dSDimitry Andric }
2986bdd1243dSDimitry Andric 
2987bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
2988bdd1243dSDimitry Andric //                           LoongArch Inline Assembly Support
2989bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
2990bdd1243dSDimitry Andric 
2991bdd1243dSDimitry Andric LoongArchTargetLowering::ConstraintType
2992bdd1243dSDimitry Andric LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
2993bdd1243dSDimitry Andric   // LoongArch specific constraints in GCC: config/loongarch/constraints.md
2994bdd1243dSDimitry Andric   //
2995bdd1243dSDimitry Andric   // 'f':  A floating-point register (if available).
2996bdd1243dSDimitry Andric   // 'k':  A memory operand whose address is formed by a base register and
2997bdd1243dSDimitry Andric   //       (optionally scaled) index register.
2998bdd1243dSDimitry Andric   // 'l':  A signed 16-bit constant.
2999bdd1243dSDimitry Andric   // 'm':  A memory operand whose address is formed by a base register and
3000bdd1243dSDimitry Andric   //       offset that is suitable for use in instructions with the same
3001bdd1243dSDimitry Andric   //       addressing mode as st.w and ld.w.
3002bdd1243dSDimitry Andric   // 'I':  A signed 12-bit constant (for arithmetic instructions).
3003bdd1243dSDimitry Andric   // 'J':  Integer zero.
3004bdd1243dSDimitry Andric   // 'K':  An unsigned 12-bit constant (for logic instructions).
3005bdd1243dSDimitry Andric   // "ZB": An address that is held in a general-purpose register. The offset is
3006bdd1243dSDimitry Andric   //       zero.
3007bdd1243dSDimitry Andric   // "ZC": A memory operand whose address is formed by a base register and
3008bdd1243dSDimitry Andric   //       offset that is suitable for use in instructions with the same
3009bdd1243dSDimitry Andric   //       addressing mode as ll.w and sc.w.
3010bdd1243dSDimitry Andric   if (Constraint.size() == 1) {
3011bdd1243dSDimitry Andric     switch (Constraint[0]) {
3012bdd1243dSDimitry Andric     default:
3013bdd1243dSDimitry Andric       break;
3014bdd1243dSDimitry Andric     case 'f':
3015bdd1243dSDimitry Andric       return C_RegisterClass;
3016bdd1243dSDimitry Andric     case 'l':
3017bdd1243dSDimitry Andric     case 'I':
3018bdd1243dSDimitry Andric     case 'J':
3019bdd1243dSDimitry Andric     case 'K':
3020bdd1243dSDimitry Andric       return C_Immediate;
3021bdd1243dSDimitry Andric     case 'k':
3022bdd1243dSDimitry Andric       return C_Memory;
3023bdd1243dSDimitry Andric     }
3024bdd1243dSDimitry Andric   }
3025bdd1243dSDimitry Andric 
3026bdd1243dSDimitry Andric   if (Constraint == "ZC" || Constraint == "ZB")
3027bdd1243dSDimitry Andric     return C_Memory;
3028bdd1243dSDimitry Andric 
3029bdd1243dSDimitry Andric   // 'm' is handled here.
3030bdd1243dSDimitry Andric   return TargetLowering::getConstraintType(Constraint);
3031bdd1243dSDimitry Andric }
3032bdd1243dSDimitry Andric 
3033bdd1243dSDimitry Andric unsigned LoongArchTargetLowering::getInlineAsmMemConstraint(
3034bdd1243dSDimitry Andric     StringRef ConstraintCode) const {
3035bdd1243dSDimitry Andric   return StringSwitch<unsigned>(ConstraintCode)
3036bdd1243dSDimitry Andric       .Case("k", InlineAsm::Constraint_k)
3037bdd1243dSDimitry Andric       .Case("ZB", InlineAsm::Constraint_ZB)
3038bdd1243dSDimitry Andric       .Case("ZC", InlineAsm::Constraint_ZC)
3039bdd1243dSDimitry Andric       .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
3040bdd1243dSDimitry Andric }
3041bdd1243dSDimitry Andric 
3042bdd1243dSDimitry Andric std::pair<unsigned, const TargetRegisterClass *>
3043bdd1243dSDimitry Andric LoongArchTargetLowering::getRegForInlineAsmConstraint(
3044bdd1243dSDimitry Andric     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
3045bdd1243dSDimitry Andric   // First, see if this is a constraint that directly corresponds to a LoongArch
3046bdd1243dSDimitry Andric   // register class.
3047bdd1243dSDimitry Andric   if (Constraint.size() == 1) {
3048bdd1243dSDimitry Andric     switch (Constraint[0]) {
3049bdd1243dSDimitry Andric     case 'r':
3050bdd1243dSDimitry Andric       // TODO: Support fixed vectors up to GRLen?
3051bdd1243dSDimitry Andric       if (VT.isVector())
3052bdd1243dSDimitry Andric         break;
3053bdd1243dSDimitry Andric       return std::make_pair(0U, &LoongArch::GPRRegClass);
3054bdd1243dSDimitry Andric     case 'f':
3055bdd1243dSDimitry Andric       if (Subtarget.hasBasicF() && VT == MVT::f32)
3056bdd1243dSDimitry Andric         return std::make_pair(0U, &LoongArch::FPR32RegClass);
3057bdd1243dSDimitry Andric       if (Subtarget.hasBasicD() && VT == MVT::f64)
3058bdd1243dSDimitry Andric         return std::make_pair(0U, &LoongArch::FPR64RegClass);
3059*06c3fb27SDimitry Andric       if (Subtarget.hasExtLSX() &&
3060*06c3fb27SDimitry Andric           TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
3061*06c3fb27SDimitry Andric         return std::make_pair(0U, &LoongArch::LSX128RegClass);
3062*06c3fb27SDimitry Andric       if (Subtarget.hasExtLASX() &&
3063*06c3fb27SDimitry Andric           TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
3064*06c3fb27SDimitry Andric         return std::make_pair(0U, &LoongArch::LASX256RegClass);
3065bdd1243dSDimitry Andric       break;
3066bdd1243dSDimitry Andric     default:
3067bdd1243dSDimitry Andric       break;
3068bdd1243dSDimitry Andric     }
3069bdd1243dSDimitry Andric   }
3070bdd1243dSDimitry Andric 
3071bdd1243dSDimitry Andric   // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
3072bdd1243dSDimitry Andric   // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
3073bdd1243dSDimitry Andric   // constraints while the official register name is prefixed with a '$'. So we
3074bdd1243dSDimitry Andric   // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
3075bdd1243dSDimitry Andric   // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
3076bdd1243dSDimitry Andric   // case insensitive, so no need to convert the constraint to upper case here.
3077bdd1243dSDimitry Andric   //
3078bdd1243dSDimitry Andric   // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
3079bdd1243dSDimitry Andric   // decode the usage of register name aliases into their official names. And
3080bdd1243dSDimitry Andric   // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
3081bdd1243dSDimitry Andric   // official register names.
3082*06c3fb27SDimitry Andric   if (Constraint.startswith("{$r") || Constraint.startswith("{$f") ||
3083*06c3fb27SDimitry Andric       Constraint.startswith("{$vr") || Constraint.startswith("{$xr")) {
3084bdd1243dSDimitry Andric     bool IsFP = Constraint[2] == 'f';
3085bdd1243dSDimitry Andric     std::pair<StringRef, StringRef> Temp = Constraint.split('$');
3086bdd1243dSDimitry Andric     std::pair<unsigned, const TargetRegisterClass *> R;
3087bdd1243dSDimitry Andric     R = TargetLowering::getRegForInlineAsmConstraint(
3088bdd1243dSDimitry Andric         TRI, join_items("", Temp.first, Temp.second), VT);
3089bdd1243dSDimitry Andric     // Match those names to the widest floating point register type available.
3090bdd1243dSDimitry Andric     if (IsFP) {
3091bdd1243dSDimitry Andric       unsigned RegNo = R.first;
3092bdd1243dSDimitry Andric       if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
3093bdd1243dSDimitry Andric         if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
3094bdd1243dSDimitry Andric           unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
3095bdd1243dSDimitry Andric           return std::make_pair(DReg, &LoongArch::FPR64RegClass);
3096bdd1243dSDimitry Andric         }
3097bdd1243dSDimitry Andric       }
3098bdd1243dSDimitry Andric     }
3099bdd1243dSDimitry Andric     return R;
3100bdd1243dSDimitry Andric   }
3101bdd1243dSDimitry Andric 
3102bdd1243dSDimitry Andric   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
3103bdd1243dSDimitry Andric }
3104bdd1243dSDimitry Andric 
3105bdd1243dSDimitry Andric void LoongArchTargetLowering::LowerAsmOperandForConstraint(
3106bdd1243dSDimitry Andric     SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops,
3107bdd1243dSDimitry Andric     SelectionDAG &DAG) const {
3108bdd1243dSDimitry Andric   // Currently only support length 1 constraints.
3109bdd1243dSDimitry Andric   if (Constraint.length() == 1) {
3110bdd1243dSDimitry Andric     switch (Constraint[0]) {
3111bdd1243dSDimitry Andric     case 'l':
3112bdd1243dSDimitry Andric       // Validate & create a 16-bit signed immediate operand.
3113bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3114bdd1243dSDimitry Andric         uint64_t CVal = C->getSExtValue();
3115bdd1243dSDimitry Andric         if (isInt<16>(CVal))
3116bdd1243dSDimitry Andric           Ops.push_back(
3117bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3118bdd1243dSDimitry Andric       }
3119bdd1243dSDimitry Andric       return;
3120bdd1243dSDimitry Andric     case 'I':
3121bdd1243dSDimitry Andric       // Validate & create a 12-bit signed immediate operand.
3122bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3123bdd1243dSDimitry Andric         uint64_t CVal = C->getSExtValue();
3124bdd1243dSDimitry Andric         if (isInt<12>(CVal))
3125bdd1243dSDimitry Andric           Ops.push_back(
3126bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3127bdd1243dSDimitry Andric       }
3128bdd1243dSDimitry Andric       return;
3129bdd1243dSDimitry Andric     case 'J':
3130bdd1243dSDimitry Andric       // Validate & create an integer zero operand.
3131bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op))
3132bdd1243dSDimitry Andric         if (C->getZExtValue() == 0)
3133bdd1243dSDimitry Andric           Ops.push_back(
3134bdd1243dSDimitry Andric               DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
3135bdd1243dSDimitry Andric       return;
3136bdd1243dSDimitry Andric     case 'K':
3137bdd1243dSDimitry Andric       // Validate & create a 12-bit unsigned immediate operand.
3138bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3139bdd1243dSDimitry Andric         uint64_t CVal = C->getZExtValue();
3140bdd1243dSDimitry Andric         if (isUInt<12>(CVal))
3141bdd1243dSDimitry Andric           Ops.push_back(
3142bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3143bdd1243dSDimitry Andric       }
3144bdd1243dSDimitry Andric       return;
3145bdd1243dSDimitry Andric     default:
3146bdd1243dSDimitry Andric       break;
3147bdd1243dSDimitry Andric     }
3148bdd1243dSDimitry Andric   }
3149bdd1243dSDimitry Andric   TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
3150bdd1243dSDimitry Andric }
3151bdd1243dSDimitry Andric 
3152bdd1243dSDimitry Andric #define GET_REGISTER_MATCHER
3153bdd1243dSDimitry Andric #include "LoongArchGenAsmMatcher.inc"
3154bdd1243dSDimitry Andric 
3155bdd1243dSDimitry Andric Register
3156bdd1243dSDimitry Andric LoongArchTargetLowering::getRegisterByName(const char *RegName, LLT VT,
3157bdd1243dSDimitry Andric                                            const MachineFunction &MF) const {
3158bdd1243dSDimitry Andric   std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
3159bdd1243dSDimitry Andric   std::string NewRegName = Name.second.str();
3160bdd1243dSDimitry Andric   Register Reg = MatchRegisterAltName(NewRegName);
3161bdd1243dSDimitry Andric   if (Reg == LoongArch::NoRegister)
3162bdd1243dSDimitry Andric     Reg = MatchRegisterName(NewRegName);
3163bdd1243dSDimitry Andric   if (Reg == LoongArch::NoRegister)
3164bdd1243dSDimitry Andric     report_fatal_error(
3165bdd1243dSDimitry Andric         Twine("Invalid register name \"" + StringRef(RegName) + "\"."));
3166bdd1243dSDimitry Andric   BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
3167bdd1243dSDimitry Andric   if (!ReservedRegs.test(Reg))
3168bdd1243dSDimitry Andric     report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
3169bdd1243dSDimitry Andric                              StringRef(RegName) + "\"."));
3170bdd1243dSDimitry Andric   return Reg;
3171bdd1243dSDimitry Andric }
3172bdd1243dSDimitry Andric 
3173bdd1243dSDimitry Andric bool LoongArchTargetLowering::decomposeMulByConstant(LLVMContext &Context,
3174bdd1243dSDimitry Andric                                                      EVT VT, SDValue C) const {
3175bdd1243dSDimitry Andric   // TODO: Support vectors.
3176bdd1243dSDimitry Andric   if (!VT.isScalarInteger())
3177bdd1243dSDimitry Andric     return false;
3178bdd1243dSDimitry Andric 
3179bdd1243dSDimitry Andric   // Omit the optimization if the data size exceeds GRLen.
3180bdd1243dSDimitry Andric   if (VT.getSizeInBits() > Subtarget.getGRLen())
3181bdd1243dSDimitry Andric     return false;
3182bdd1243dSDimitry Andric 
3183bdd1243dSDimitry Andric   if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
3184bdd1243dSDimitry Andric     const APInt &Imm = ConstNode->getAPIntValue();
3185*06c3fb27SDimitry Andric     // Break MUL into (SLLI + ADD/SUB) or ALSL.
3186bdd1243dSDimitry Andric     if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
3187bdd1243dSDimitry Andric         (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
3188bdd1243dSDimitry Andric       return true;
3189*06c3fb27SDimitry Andric     // Break MUL into (ALSL x, (SLLI x, imm0), imm1).
3190*06c3fb27SDimitry Andric     if (ConstNode->hasOneUse() &&
3191*06c3fb27SDimitry Andric         ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() ||
3192*06c3fb27SDimitry Andric          (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2()))
3193*06c3fb27SDimitry Andric       return true;
3194*06c3fb27SDimitry Andric     // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)),
3195*06c3fb27SDimitry Andric     // in which the immediate has two set bits. Or Break (MUL x, imm)
3196*06c3fb27SDimitry Andric     // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate
3197*06c3fb27SDimitry Andric     // equals to (1 << s0) - (1 << s1).
3198*06c3fb27SDimitry Andric     if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) {
3199*06c3fb27SDimitry Andric       unsigned Shifts = Imm.countr_zero();
3200*06c3fb27SDimitry Andric       // Reject immediates which can be composed via a single LUI.
3201*06c3fb27SDimitry Andric       if (Shifts >= 12)
3202*06c3fb27SDimitry Andric         return false;
3203*06c3fb27SDimitry Andric       // Reject multiplications can be optimized to
3204*06c3fb27SDimitry Andric       // (SLLI (ALSL x, x, 1/2/3/4), s).
3205*06c3fb27SDimitry Andric       APInt ImmPop = Imm.ashr(Shifts);
3206*06c3fb27SDimitry Andric       if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17)
3207*06c3fb27SDimitry Andric         return false;
3208*06c3fb27SDimitry Andric       // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`,
3209*06c3fb27SDimitry Andric       // since it needs one more instruction than other 3 cases.
3210*06c3fb27SDimitry Andric       APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true);
3211*06c3fb27SDimitry Andric       if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() ||
3212*06c3fb27SDimitry Andric           (ImmSmall - Imm).isPowerOf2())
3213*06c3fb27SDimitry Andric         return true;
3214*06c3fb27SDimitry Andric     }
3215bdd1243dSDimitry Andric   }
3216bdd1243dSDimitry Andric 
3217bdd1243dSDimitry Andric   return false;
3218bdd1243dSDimitry Andric }
3219*06c3fb27SDimitry Andric 
3220*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalAddressingMode(const DataLayout &DL,
3221*06c3fb27SDimitry Andric                                                     const AddrMode &AM,
3222*06c3fb27SDimitry Andric                                                     Type *Ty, unsigned AS,
3223*06c3fb27SDimitry Andric                                                     Instruction *I) const {
3224*06c3fb27SDimitry Andric   // LoongArch has four basic addressing modes:
3225*06c3fb27SDimitry Andric   //  1. reg
3226*06c3fb27SDimitry Andric   //  2. reg + 12-bit signed offset
3227*06c3fb27SDimitry Andric   //  3. reg + 14-bit signed offset left-shifted by 2
3228*06c3fb27SDimitry Andric   //  4. reg1 + reg2
3229*06c3fb27SDimitry Andric   // TODO: Add more checks after support vector extension.
3230*06c3fb27SDimitry Andric 
3231*06c3fb27SDimitry Andric   // No global is ever allowed as a base.
3232*06c3fb27SDimitry Andric   if (AM.BaseGV)
3233*06c3fb27SDimitry Andric     return false;
3234*06c3fb27SDimitry Andric 
3235*06c3fb27SDimitry Andric   // Require a 12 or 14 bit signed offset.
3236*06c3fb27SDimitry Andric   if (!isInt<12>(AM.BaseOffs) || !isShiftedInt<14, 2>(AM.BaseOffs))
3237*06c3fb27SDimitry Andric     return false;
3238*06c3fb27SDimitry Andric 
3239*06c3fb27SDimitry Andric   switch (AM.Scale) {
3240*06c3fb27SDimitry Andric   case 0:
3241*06c3fb27SDimitry Andric     // "i" is not allowed.
3242*06c3fb27SDimitry Andric     if (!AM.HasBaseReg)
3243*06c3fb27SDimitry Andric       return false;
3244*06c3fb27SDimitry Andric     // Otherwise we have "r+i".
3245*06c3fb27SDimitry Andric     break;
3246*06c3fb27SDimitry Andric   case 1:
3247*06c3fb27SDimitry Andric     // "r+r+i" is not allowed.
3248*06c3fb27SDimitry Andric     if (AM.HasBaseReg && AM.BaseOffs != 0)
3249*06c3fb27SDimitry Andric       return false;
3250*06c3fb27SDimitry Andric     // Otherwise we have "r+r" or "r+i".
3251*06c3fb27SDimitry Andric     break;
3252*06c3fb27SDimitry Andric   case 2:
3253*06c3fb27SDimitry Andric     // "2*r+r" or "2*r+i" is not allowed.
3254*06c3fb27SDimitry Andric     if (AM.HasBaseReg || AM.BaseOffs)
3255*06c3fb27SDimitry Andric       return false;
3256*06c3fb27SDimitry Andric     // Otherwise we have "r+r".
3257*06c3fb27SDimitry Andric     break;
3258*06c3fb27SDimitry Andric   default:
3259*06c3fb27SDimitry Andric     return false;
3260*06c3fb27SDimitry Andric   }
3261*06c3fb27SDimitry Andric 
3262*06c3fb27SDimitry Andric   return true;
3263*06c3fb27SDimitry Andric }
3264*06c3fb27SDimitry Andric 
3265*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
3266*06c3fb27SDimitry Andric   return isInt<12>(Imm);
3267*06c3fb27SDimitry Andric }
3268*06c3fb27SDimitry Andric 
3269*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalAddImmediate(int64_t Imm) const {
3270*06c3fb27SDimitry Andric   return isInt<12>(Imm);
3271*06c3fb27SDimitry Andric }
3272*06c3fb27SDimitry Andric 
3273*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isZExtFree(SDValue Val, EVT VT2) const {
3274*06c3fb27SDimitry Andric   // Zexts are free if they can be combined with a load.
3275*06c3fb27SDimitry Andric   // Don't advertise i32->i64 zextload as being free for LA64. It interacts
3276*06c3fb27SDimitry Andric   // poorly with type legalization of compares preferring sext.
3277*06c3fb27SDimitry Andric   if (auto *LD = dyn_cast<LoadSDNode>(Val)) {
3278*06c3fb27SDimitry Andric     EVT MemVT = LD->getMemoryVT();
3279*06c3fb27SDimitry Andric     if ((MemVT == MVT::i8 || MemVT == MVT::i16) &&
3280*06c3fb27SDimitry Andric         (LD->getExtensionType() == ISD::NON_EXTLOAD ||
3281*06c3fb27SDimitry Andric          LD->getExtensionType() == ISD::ZEXTLOAD))
3282*06c3fb27SDimitry Andric       return true;
3283*06c3fb27SDimitry Andric   }
3284*06c3fb27SDimitry Andric 
3285*06c3fb27SDimitry Andric   return TargetLowering::isZExtFree(Val, VT2);
3286*06c3fb27SDimitry Andric }
3287*06c3fb27SDimitry Andric 
3288*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const {
3289*06c3fb27SDimitry Andric   return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64;
3290*06c3fb27SDimitry Andric }
3291*06c3fb27SDimitry Andric 
3292*06c3fb27SDimitry Andric bool LoongArchTargetLowering::hasAndNotCompare(SDValue Y) const {
3293*06c3fb27SDimitry Andric   // TODO: Support vectors.
3294*06c3fb27SDimitry Andric   if (Y.getValueType().isVector())
3295*06c3fb27SDimitry Andric     return false;
3296*06c3fb27SDimitry Andric 
3297*06c3fb27SDimitry Andric   return !isa<ConstantSDNode>(Y);
3298*06c3fb27SDimitry Andric }
3299