xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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"
2306c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
2481ad6265SDimitry Andric #include "llvm/CodeGen/ISDOpcodes.h"
25bdd1243dSDimitry Andric #include "llvm/CodeGen/RuntimeLibcalls.h"
2606c3fb27SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h"
27bdd1243dSDimitry Andric #include "llvm/IR/IRBuilder.h"
28bdd1243dSDimitry Andric #include "llvm/IR/IntrinsicsLoongArch.h"
2906c3fb27SDimitry Andric #include "llvm/Support/CodeGen.h"
3081ad6265SDimitry Andric #include "llvm/Support/Debug.h"
3106c3fb27SDimitry 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 
4106c3fb27SDimitry 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();
50*5f757f3fSDimitry Andric 
5181ad6265SDimitry Andric   // Set up the register classes.
52*5f757f3fSDimitry Andric 
5381ad6265SDimitry Andric   addRegisterClass(GRLenVT, &LoongArch::GPRRegClass);
5481ad6265SDimitry Andric   if (Subtarget.hasBasicF())
5581ad6265SDimitry Andric     addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass);
5681ad6265SDimitry Andric   if (Subtarget.hasBasicD())
5781ad6265SDimitry Andric     addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass);
58*5f757f3fSDimitry Andric 
59*5f757f3fSDimitry Andric   static const MVT::SimpleValueType LSXVTs[] = {
60*5f757f3fSDimitry Andric       MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64};
61*5f757f3fSDimitry Andric   static const MVT::SimpleValueType LASXVTs[] = {
62*5f757f3fSDimitry Andric       MVT::v32i8, MVT::v16i16, MVT::v8i32, MVT::v4i64, MVT::v8f32, MVT::v4f64};
63*5f757f3fSDimitry Andric 
6406c3fb27SDimitry Andric   if (Subtarget.hasExtLSX())
65*5f757f3fSDimitry Andric     for (MVT VT : LSXVTs)
6606c3fb27SDimitry Andric       addRegisterClass(VT, &LoongArch::LSX128RegClass);
67*5f757f3fSDimitry Andric 
6806c3fb27SDimitry Andric   if (Subtarget.hasExtLASX())
69*5f757f3fSDimitry Andric     for (MVT VT : LASXVTs)
7006c3fb27SDimitry Andric       addRegisterClass(VT, &LoongArch::LASX256RegClass);
7181ad6265SDimitry Andric 
72*5f757f3fSDimitry Andric   // Set operations for LA32 and LA64.
73*5f757f3fSDimitry Andric 
74753f127fSDimitry Andric   setLoadExtAction({ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}, GRLenVT,
75753f127fSDimitry Andric                    MVT::i1, Promote);
76753f127fSDimitry Andric 
7781ad6265SDimitry Andric   setOperationAction(ISD::SHL_PARTS, GRLenVT, Custom);
7881ad6265SDimitry Andric   setOperationAction(ISD::SRA_PARTS, GRLenVT, Custom);
7981ad6265SDimitry Andric   setOperationAction(ISD::SRL_PARTS, GRLenVT, Custom);
80753f127fSDimitry Andric   setOperationAction(ISD::FP_TO_SINT, GRLenVT, Custom);
81bdd1243dSDimitry Andric   setOperationAction(ISD::ROTL, GRLenVT, Expand);
82bdd1243dSDimitry Andric   setOperationAction(ISD::CTPOP, GRLenVT, Expand);
83753f127fSDimitry Andric 
84bdd1243dSDimitry Andric   setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool,
85*5f757f3fSDimitry Andric                       ISD::JumpTable, ISD::GlobalTLSAddress},
86bdd1243dSDimitry Andric                      GRLenVT, Custom);
87bdd1243dSDimitry Andric 
88*5f757f3fSDimitry Andric   setOperationAction(ISD::EH_DWARF_CFA, GRLenVT, Custom);
89bdd1243dSDimitry Andric 
90bdd1243dSDimitry Andric   setOperationAction(ISD::DYNAMIC_STACKALLOC, GRLenVT, Expand);
91bdd1243dSDimitry Andric   setOperationAction({ISD::STACKSAVE, ISD::STACKRESTORE}, MVT::Other, Expand);
92bdd1243dSDimitry Andric   setOperationAction(ISD::VASTART, MVT::Other, Custom);
93bdd1243dSDimitry Andric   setOperationAction({ISD::VAARG, ISD::VACOPY, ISD::VAEND}, MVT::Other, Expand);
9481ad6265SDimitry Andric 
95*5f757f3fSDimitry Andric   setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
96*5f757f3fSDimitry Andric   setOperationAction(ISD::TRAP, MVT::Other, Legal);
97*5f757f3fSDimitry Andric 
98*5f757f3fSDimitry Andric   setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
99*5f757f3fSDimitry Andric   setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
100*5f757f3fSDimitry Andric   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
101*5f757f3fSDimitry Andric 
102*5f757f3fSDimitry Andric   // Expand bitreverse.i16 with native-width bitrev and shift for now, before
103*5f757f3fSDimitry Andric   // we get to know which of sll and revb.2h is faster.
104*5f757f3fSDimitry Andric   setOperationAction(ISD::BITREVERSE, MVT::i8, Custom);
105*5f757f3fSDimitry Andric   setOperationAction(ISD::BITREVERSE, GRLenVT, Legal);
106*5f757f3fSDimitry Andric 
107*5f757f3fSDimitry Andric   // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
108*5f757f3fSDimitry Andric   // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
109*5f757f3fSDimitry Andric   // and i32 could still be byte-swapped relatively cheaply.
110*5f757f3fSDimitry Andric   setOperationAction(ISD::BSWAP, MVT::i16, Custom);
111*5f757f3fSDimitry Andric 
112*5f757f3fSDimitry Andric   setOperationAction(ISD::BR_JT, MVT::Other, Expand);
113*5f757f3fSDimitry Andric   setOperationAction(ISD::BR_CC, GRLenVT, Expand);
114*5f757f3fSDimitry Andric   setOperationAction(ISD::SELECT_CC, GRLenVT, Expand);
115*5f757f3fSDimitry Andric   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
116*5f757f3fSDimitry Andric   setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, GRLenVT, Expand);
117*5f757f3fSDimitry Andric 
118*5f757f3fSDimitry Andric   setOperationAction(ISD::FP_TO_UINT, GRLenVT, Custom);
119*5f757f3fSDimitry Andric   setOperationAction(ISD::UINT_TO_FP, GRLenVT, Expand);
120*5f757f3fSDimitry Andric 
121*5f757f3fSDimitry Andric   // Set operations for LA64 only.
122*5f757f3fSDimitry Andric 
12381ad6265SDimitry Andric   if (Subtarget.is64Bit()) {
12481ad6265SDimitry Andric     setOperationAction(ISD::SHL, MVT::i32, Custom);
12581ad6265SDimitry Andric     setOperationAction(ISD::SRA, MVT::i32, Custom);
12681ad6265SDimitry Andric     setOperationAction(ISD::SRL, MVT::i32, Custom);
127753f127fSDimitry Andric     setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
128753f127fSDimitry Andric     setOperationAction(ISD::BITCAST, MVT::i32, Custom);
129bdd1243dSDimitry Andric     setOperationAction(ISD::ROTR, MVT::i32, Custom);
130bdd1243dSDimitry Andric     setOperationAction(ISD::ROTL, MVT::i32, Custom);
131bdd1243dSDimitry Andric     setOperationAction(ISD::CTTZ, MVT::i32, Custom);
132bdd1243dSDimitry Andric     setOperationAction(ISD::CTLZ, MVT::i32, Custom);
133*5f757f3fSDimitry Andric     setOperationAction(ISD::EH_DWARF_CFA, MVT::i32, Custom);
134bdd1243dSDimitry Andric     setOperationAction(ISD::READ_REGISTER, MVT::i32, Custom);
135bdd1243dSDimitry Andric     setOperationAction(ISD::WRITE_REGISTER, MVT::i32, Custom);
136*5f757f3fSDimitry Andric     setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom);
137*5f757f3fSDimitry Andric     setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i32, Custom);
138*5f757f3fSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i32, Custom);
13981ad6265SDimitry Andric 
140*5f757f3fSDimitry Andric     setOperationAction(ISD::BITREVERSE, MVT::i32, Custom);
141bdd1243dSDimitry Andric     setOperationAction(ISD::BSWAP, MVT::i32, Custom);
142bdd1243dSDimitry Andric   }
143bdd1243dSDimitry Andric 
144*5f757f3fSDimitry Andric   // Set operations for LA32 only.
145*5f757f3fSDimitry Andric 
146*5f757f3fSDimitry Andric   if (!Subtarget.is64Bit()) {
147bdd1243dSDimitry Andric     setOperationAction(ISD::READ_REGISTER, MVT::i64, Custom);
148bdd1243dSDimitry Andric     setOperationAction(ISD::WRITE_REGISTER, MVT::i64, Custom);
149bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_VOID, MVT::i64, Custom);
150*5f757f3fSDimitry Andric     setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom);
151*5f757f3fSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom);
152*5f757f3fSDimitry Andric 
153*5f757f3fSDimitry Andric     // Set libcalls.
154*5f757f3fSDimitry Andric     setLibcallName(RTLIB::MUL_I128, nullptr);
155*5f757f3fSDimitry Andric     // The MULO libcall is not part of libgcc, only compiler-rt.
156*5f757f3fSDimitry Andric     setLibcallName(RTLIB::MULO_I64, nullptr);
157bdd1243dSDimitry Andric   }
158bdd1243dSDimitry Andric 
159*5f757f3fSDimitry Andric   // The MULO libcall is not part of libgcc, only compiler-rt.
160*5f757f3fSDimitry Andric   setLibcallName(RTLIB::MULO_I128, nullptr);
161*5f757f3fSDimitry Andric 
162*5f757f3fSDimitry Andric   setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom);
163*5f757f3fSDimitry Andric 
164bdd1243dSDimitry Andric   static const ISD::CondCode FPCCToExpand[] = {
165bdd1243dSDimitry Andric       ISD::SETOGT, ISD::SETOGE, ISD::SETUGT, ISD::SETUGE,
166bdd1243dSDimitry Andric       ISD::SETGE,  ISD::SETNE,  ISD::SETGT};
16781ad6265SDimitry Andric 
168*5f757f3fSDimitry Andric   // Set operations for 'F' feature.
169*5f757f3fSDimitry Andric 
17081ad6265SDimitry Andric   if (Subtarget.hasBasicF()) {
17181ad6265SDimitry Andric     setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
172*5f757f3fSDimitry Andric 
17381ad6265SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
174bdd1243dSDimitry Andric     setOperationAction(ISD::BR_CC, MVT::f32, Expand);
175bdd1243dSDimitry Andric     setOperationAction(ISD::FMA, MVT::f32, Legal);
176bdd1243dSDimitry Andric     setOperationAction(ISD::FMINNUM_IEEE, MVT::f32, Legal);
177bdd1243dSDimitry Andric     setOperationAction(ISD::FMAXNUM_IEEE, MVT::f32, Legal);
178bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCCS, MVT::f32, Legal);
179bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCC, MVT::f32, Legal);
180*5f757f3fSDimitry Andric     setOperationAction(ISD::IS_FPCLASS, MVT::f32, Legal);
181bdd1243dSDimitry Andric     setOperationAction(ISD::FSIN, MVT::f32, Expand);
182bdd1243dSDimitry Andric     setOperationAction(ISD::FCOS, MVT::f32, Expand);
183bdd1243dSDimitry Andric     setOperationAction(ISD::FSINCOS, MVT::f32, Expand);
184bdd1243dSDimitry Andric     setOperationAction(ISD::FPOW, MVT::f32, Expand);
185bdd1243dSDimitry Andric     setOperationAction(ISD::FREM, MVT::f32, Expand);
186*5f757f3fSDimitry Andric 
187*5f757f3fSDimitry Andric     if (Subtarget.is64Bit())
188*5f757f3fSDimitry Andric       setOperationAction(ISD::FRINT, MVT::f32, Legal);
189*5f757f3fSDimitry Andric 
190*5f757f3fSDimitry Andric     if (!Subtarget.hasBasicD()) {
191*5f757f3fSDimitry Andric       setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
192*5f757f3fSDimitry Andric       if (Subtarget.is64Bit()) {
193*5f757f3fSDimitry Andric         setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom);
194*5f757f3fSDimitry Andric         setOperationAction(ISD::UINT_TO_FP, MVT::i64, Custom);
19581ad6265SDimitry Andric       }
196*5f757f3fSDimitry Andric     }
197*5f757f3fSDimitry Andric   }
198*5f757f3fSDimitry Andric 
199*5f757f3fSDimitry Andric   // Set operations for 'D' feature.
200*5f757f3fSDimitry Andric 
20181ad6265SDimitry Andric   if (Subtarget.hasBasicD()) {
202*5f757f3fSDimitry Andric     setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
203*5f757f3fSDimitry Andric     setTruncStoreAction(MVT::f64, MVT::f32, Expand);
20481ad6265SDimitry Andric     setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
205*5f757f3fSDimitry Andric 
20681ad6265SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f64, Expand);
207bdd1243dSDimitry Andric     setOperationAction(ISD::BR_CC, MVT::f64, Expand);
208bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCCS, MVT::f64, Legal);
209bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCC, MVT::f64, Legal);
210bdd1243dSDimitry Andric     setOperationAction(ISD::FMA, MVT::f64, Legal);
211bdd1243dSDimitry Andric     setOperationAction(ISD::FMINNUM_IEEE, MVT::f64, Legal);
212bdd1243dSDimitry Andric     setOperationAction(ISD::FMAXNUM_IEEE, MVT::f64, Legal);
213*5f757f3fSDimitry Andric     setOperationAction(ISD::IS_FPCLASS, MVT::f64, Legal);
214bdd1243dSDimitry Andric     setOperationAction(ISD::FSIN, MVT::f64, Expand);
215bdd1243dSDimitry Andric     setOperationAction(ISD::FCOS, MVT::f64, Expand);
216bdd1243dSDimitry Andric     setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
217bdd1243dSDimitry Andric     setOperationAction(ISD::FPOW, MVT::f64, Expand);
218bdd1243dSDimitry Andric     setOperationAction(ISD::FREM, MVT::f64, Expand);
219*5f757f3fSDimitry Andric 
220*5f757f3fSDimitry Andric     if (Subtarget.is64Bit())
221*5f757f3fSDimitry Andric       setOperationAction(ISD::FRINT, MVT::f64, Legal);
22281ad6265SDimitry Andric   }
22381ad6265SDimitry Andric 
224*5f757f3fSDimitry Andric   // Set operations for 'LSX' feature.
225bdd1243dSDimitry Andric 
226*5f757f3fSDimitry Andric   if (Subtarget.hasExtLSX()) {
227*5f757f3fSDimitry Andric     for (MVT VT : MVT::fixedlen_vector_valuetypes()) {
228*5f757f3fSDimitry Andric       // Expand all truncating stores and extending loads.
229*5f757f3fSDimitry Andric       for (MVT InnerVT : MVT::fixedlen_vector_valuetypes()) {
230*5f757f3fSDimitry Andric         setTruncStoreAction(VT, InnerVT, Expand);
231*5f757f3fSDimitry Andric         setLoadExtAction(ISD::SEXTLOAD, VT, InnerVT, Expand);
232*5f757f3fSDimitry Andric         setLoadExtAction(ISD::ZEXTLOAD, VT, InnerVT, Expand);
233*5f757f3fSDimitry Andric         setLoadExtAction(ISD::EXTLOAD, VT, InnerVT, Expand);
234bdd1243dSDimitry Andric       }
235*5f757f3fSDimitry Andric       // By default everything must be expanded. Then we will selectively turn
236*5f757f3fSDimitry Andric       // on ones that can be effectively codegen'd.
237*5f757f3fSDimitry Andric       for (unsigned Op = 0; Op < ISD::BUILTIN_OP_END; ++Op)
238*5f757f3fSDimitry Andric         setOperationAction(Op, VT, Expand);
239*5f757f3fSDimitry Andric     }
240*5f757f3fSDimitry Andric 
241*5f757f3fSDimitry Andric     for (MVT VT : LSXVTs) {
242*5f757f3fSDimitry Andric       setOperationAction({ISD::LOAD, ISD::STORE}, VT, Legal);
243*5f757f3fSDimitry Andric       setOperationAction(ISD::BITCAST, VT, Legal);
244*5f757f3fSDimitry Andric       setOperationAction(ISD::UNDEF, VT, Legal);
245*5f757f3fSDimitry Andric 
246*5f757f3fSDimitry Andric       setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Custom);
247*5f757f3fSDimitry Andric       setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT, Legal);
248*5f757f3fSDimitry Andric       setOperationAction(ISD::BUILD_VECTOR, VT, Custom);
249*5f757f3fSDimitry Andric 
250*5f757f3fSDimitry Andric       setOperationAction(ISD::SETCC, VT, Legal);
251*5f757f3fSDimitry Andric       setOperationAction(ISD::VSELECT, VT, Legal);
252*5f757f3fSDimitry Andric     }
253*5f757f3fSDimitry Andric     for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) {
254*5f757f3fSDimitry Andric       setOperationAction(ISD::VECTOR_SHUFFLE, VT, Custom);
255*5f757f3fSDimitry Andric       setOperationAction({ISD::ADD, ISD::SUB}, VT, Legal);
256*5f757f3fSDimitry Andric       setOperationAction({ISD::UMAX, ISD::UMIN, ISD::SMAX, ISD::SMIN}, VT,
257*5f757f3fSDimitry Andric                          Legal);
258*5f757f3fSDimitry Andric       setOperationAction({ISD::MUL, ISD::SDIV, ISD::SREM, ISD::UDIV, ISD::UREM},
259*5f757f3fSDimitry Andric                          VT, Legal);
260*5f757f3fSDimitry Andric       setOperationAction({ISD::AND, ISD::OR, ISD::XOR}, VT, Legal);
261*5f757f3fSDimitry Andric       setOperationAction({ISD::SHL, ISD::SRA, ISD::SRL}, VT, Legal);
262*5f757f3fSDimitry Andric       setOperationAction({ISD::CTPOP, ISD::CTLZ}, VT, Legal);
263*5f757f3fSDimitry Andric       setOperationAction({ISD::MULHS, ISD::MULHU}, VT, Legal);
264*5f757f3fSDimitry Andric       setCondCodeAction(
265*5f757f3fSDimitry Andric           {ISD::SETNE, ISD::SETGE, ISD::SETGT, ISD::SETUGE, ISD::SETUGT}, VT,
266*5f757f3fSDimitry Andric           Expand);
267*5f757f3fSDimitry Andric     }
268*5f757f3fSDimitry Andric     for (MVT VT : {MVT::v4f32, MVT::v2f64}) {
269*5f757f3fSDimitry Andric       setOperationAction({ISD::FADD, ISD::FSUB}, VT, Legal);
270*5f757f3fSDimitry Andric       setOperationAction({ISD::FMUL, ISD::FDIV}, VT, Legal);
271*5f757f3fSDimitry Andric       setOperationAction(ISD::FMA, VT, Legal);
272*5f757f3fSDimitry Andric       setOperationAction(ISD::FSQRT, VT, Legal);
273*5f757f3fSDimitry Andric       setOperationAction(ISD::FNEG, VT, Legal);
274*5f757f3fSDimitry Andric       setCondCodeAction({ISD::SETGE, ISD::SETGT, ISD::SETOGE, ISD::SETOGT,
275*5f757f3fSDimitry Andric                          ISD::SETUGE, ISD::SETUGT},
276*5f757f3fSDimitry Andric                         VT, Expand);
277*5f757f3fSDimitry Andric     }
278*5f757f3fSDimitry Andric   }
279*5f757f3fSDimitry Andric 
280*5f757f3fSDimitry Andric   // Set operations for 'LASX' feature.
281*5f757f3fSDimitry Andric 
282*5f757f3fSDimitry Andric   if (Subtarget.hasExtLASX()) {
283*5f757f3fSDimitry Andric     for (MVT VT : LASXVTs) {
284*5f757f3fSDimitry Andric       setOperationAction({ISD::LOAD, ISD::STORE}, VT, Legal);
285*5f757f3fSDimitry Andric       setOperationAction(ISD::BITCAST, VT, Legal);
286*5f757f3fSDimitry Andric       setOperationAction(ISD::UNDEF, VT, Legal);
287*5f757f3fSDimitry Andric 
288*5f757f3fSDimitry Andric       setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Custom);
289*5f757f3fSDimitry Andric       setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT, Legal);
290*5f757f3fSDimitry Andric       setOperationAction(ISD::BUILD_VECTOR, VT, Custom);
291*5f757f3fSDimitry Andric 
292*5f757f3fSDimitry Andric       setOperationAction(ISD::SETCC, VT, Legal);
293*5f757f3fSDimitry Andric       setOperationAction(ISD::VSELECT, VT, Legal);
294*5f757f3fSDimitry Andric     }
295*5f757f3fSDimitry Andric     for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16, MVT::v32i8}) {
296*5f757f3fSDimitry Andric       setOperationAction(ISD::VECTOR_SHUFFLE, VT, Custom);
297*5f757f3fSDimitry Andric       setOperationAction({ISD::ADD, ISD::SUB}, VT, Legal);
298*5f757f3fSDimitry Andric       setOperationAction({ISD::UMAX, ISD::UMIN, ISD::SMAX, ISD::SMIN}, VT,
299*5f757f3fSDimitry Andric                          Legal);
300*5f757f3fSDimitry Andric       setOperationAction({ISD::MUL, ISD::SDIV, ISD::SREM, ISD::UDIV, ISD::UREM},
301*5f757f3fSDimitry Andric                          VT, Legal);
302*5f757f3fSDimitry Andric       setOperationAction({ISD::AND, ISD::OR, ISD::XOR}, VT, Legal);
303*5f757f3fSDimitry Andric       setOperationAction({ISD::SHL, ISD::SRA, ISD::SRL}, VT, Legal);
304*5f757f3fSDimitry Andric       setOperationAction({ISD::CTPOP, ISD::CTLZ}, VT, Legal);
305*5f757f3fSDimitry Andric       setOperationAction({ISD::MULHS, ISD::MULHU}, VT, Legal);
306*5f757f3fSDimitry Andric       setCondCodeAction(
307*5f757f3fSDimitry Andric           {ISD::SETNE, ISD::SETGE, ISD::SETGT, ISD::SETUGE, ISD::SETUGT}, VT,
308*5f757f3fSDimitry Andric           Expand);
309*5f757f3fSDimitry Andric     }
310*5f757f3fSDimitry Andric     for (MVT VT : {MVT::v8f32, MVT::v4f64}) {
311*5f757f3fSDimitry Andric       setOperationAction({ISD::FADD, ISD::FSUB}, VT, Legal);
312*5f757f3fSDimitry Andric       setOperationAction({ISD::FMUL, ISD::FDIV}, VT, Legal);
313*5f757f3fSDimitry Andric       setOperationAction(ISD::FMA, VT, Legal);
314*5f757f3fSDimitry Andric       setOperationAction(ISD::FSQRT, VT, Legal);
315*5f757f3fSDimitry Andric       setOperationAction(ISD::FNEG, VT, Legal);
316*5f757f3fSDimitry Andric       setCondCodeAction({ISD::SETGE, ISD::SETGT, ISD::SETOGE, ISD::SETOGT,
317*5f757f3fSDimitry Andric                          ISD::SETUGE, ISD::SETUGT},
318*5f757f3fSDimitry Andric                         VT, Expand);
319*5f757f3fSDimitry Andric     }
320*5f757f3fSDimitry Andric   }
321*5f757f3fSDimitry Andric 
322*5f757f3fSDimitry Andric   // Set DAG combine for LA32 and LA64.
323*5f757f3fSDimitry Andric 
324*5f757f3fSDimitry Andric   setTargetDAGCombine(ISD::AND);
325*5f757f3fSDimitry Andric   setTargetDAGCombine(ISD::OR);
326*5f757f3fSDimitry Andric   setTargetDAGCombine(ISD::SRL);
327*5f757f3fSDimitry Andric 
328*5f757f3fSDimitry Andric   // Set DAG combine for 'LSX' feature.
329*5f757f3fSDimitry Andric 
330*5f757f3fSDimitry Andric   if (Subtarget.hasExtLSX())
331*5f757f3fSDimitry Andric     setTargetDAGCombine(ISD::INTRINSIC_WO_CHAIN);
33281ad6265SDimitry Andric 
33381ad6265SDimitry Andric   // Compute derived properties from the register classes.
33406c3fb27SDimitry Andric   computeRegisterProperties(Subtarget.getRegisterInfo());
33581ad6265SDimitry Andric 
33681ad6265SDimitry Andric   setStackPointerRegisterToSaveRestore(LoongArch::R3);
33781ad6265SDimitry Andric 
33881ad6265SDimitry Andric   setBooleanContents(ZeroOrOneBooleanContent);
339*5f757f3fSDimitry Andric   setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
34081ad6265SDimitry Andric 
341753f127fSDimitry Andric   setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen());
342753f127fSDimitry Andric 
343bdd1243dSDimitry Andric   setMinCmpXchgSizeInBits(32);
344bdd1243dSDimitry Andric 
34581ad6265SDimitry Andric   // Function alignments.
34606c3fb27SDimitry Andric   setMinFunctionAlignment(Align(4));
34706c3fb27SDimitry Andric   // Set preferred alignments.
34806c3fb27SDimitry Andric   setPrefFunctionAlignment(Subtarget.getPrefFunctionAlignment());
34906c3fb27SDimitry Andric   setPrefLoopAlignment(Subtarget.getPrefLoopAlignment());
35006c3fb27SDimitry Andric   setMaxBytesForAlignment(Subtarget.getMaxBytesForAlignment());
35181ad6265SDimitry Andric }
35281ad6265SDimitry Andric 
353bdd1243dSDimitry Andric bool LoongArchTargetLowering::isOffsetFoldingLegal(
354bdd1243dSDimitry Andric     const GlobalAddressSDNode *GA) const {
355bdd1243dSDimitry Andric   // In order to maximise the opportunity for common subexpression elimination,
356bdd1243dSDimitry Andric   // keep a separate ADD node for the global address offset instead of folding
357bdd1243dSDimitry Andric   // it in the global address node. Later peephole optimisations may choose to
358bdd1243dSDimitry Andric   // fold it back in when profitable.
359bdd1243dSDimitry Andric   return false;
360bdd1243dSDimitry Andric }
361bdd1243dSDimitry Andric 
36281ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
36381ad6265SDimitry Andric                                                 SelectionDAG &DAG) const {
36481ad6265SDimitry Andric   switch (Op.getOpcode()) {
365*5f757f3fSDimitry Andric   case ISD::ATOMIC_FENCE:
366*5f757f3fSDimitry Andric     return lowerATOMIC_FENCE(Op, DAG);
367bdd1243dSDimitry Andric   case ISD::EH_DWARF_CFA:
368bdd1243dSDimitry Andric     return lowerEH_DWARF_CFA(Op, DAG);
369753f127fSDimitry Andric   case ISD::GlobalAddress:
370753f127fSDimitry Andric     return lowerGlobalAddress(Op, DAG);
371bdd1243dSDimitry Andric   case ISD::GlobalTLSAddress:
372bdd1243dSDimitry Andric     return lowerGlobalTLSAddress(Op, DAG);
373bdd1243dSDimitry Andric   case ISD::INTRINSIC_WO_CHAIN:
374bdd1243dSDimitry Andric     return lowerINTRINSIC_WO_CHAIN(Op, DAG);
375bdd1243dSDimitry Andric   case ISD::INTRINSIC_W_CHAIN:
376bdd1243dSDimitry Andric     return lowerINTRINSIC_W_CHAIN(Op, DAG);
377bdd1243dSDimitry Andric   case ISD::INTRINSIC_VOID:
378bdd1243dSDimitry Andric     return lowerINTRINSIC_VOID(Op, DAG);
379bdd1243dSDimitry Andric   case ISD::BlockAddress:
380bdd1243dSDimitry Andric     return lowerBlockAddress(Op, DAG);
381bdd1243dSDimitry Andric   case ISD::JumpTable:
382bdd1243dSDimitry Andric     return lowerJumpTable(Op, DAG);
38381ad6265SDimitry Andric   case ISD::SHL_PARTS:
38481ad6265SDimitry Andric     return lowerShiftLeftParts(Op, DAG);
38581ad6265SDimitry Andric   case ISD::SRA_PARTS:
38681ad6265SDimitry Andric     return lowerShiftRightParts(Op, DAG, true);
38781ad6265SDimitry Andric   case ISD::SRL_PARTS:
38881ad6265SDimitry Andric     return lowerShiftRightParts(Op, DAG, false);
389753f127fSDimitry Andric   case ISD::ConstantPool:
390753f127fSDimitry Andric     return lowerConstantPool(Op, DAG);
391753f127fSDimitry Andric   case ISD::FP_TO_SINT:
392753f127fSDimitry Andric     return lowerFP_TO_SINT(Op, DAG);
393753f127fSDimitry Andric   case ISD::BITCAST:
394753f127fSDimitry Andric     return lowerBITCAST(Op, DAG);
395753f127fSDimitry Andric   case ISD::UINT_TO_FP:
396753f127fSDimitry Andric     return lowerUINT_TO_FP(Op, DAG);
397bdd1243dSDimitry Andric   case ISD::SINT_TO_FP:
398bdd1243dSDimitry Andric     return lowerSINT_TO_FP(Op, DAG);
399bdd1243dSDimitry Andric   case ISD::VASTART:
400bdd1243dSDimitry Andric     return lowerVASTART(Op, DAG);
401bdd1243dSDimitry Andric   case ISD::FRAMEADDR:
402bdd1243dSDimitry Andric     return lowerFRAMEADDR(Op, DAG);
403bdd1243dSDimitry Andric   case ISD::RETURNADDR:
404bdd1243dSDimitry Andric     return lowerRETURNADDR(Op, DAG);
405bdd1243dSDimitry Andric   case ISD::WRITE_REGISTER:
406bdd1243dSDimitry Andric     return lowerWRITE_REGISTER(Op, DAG);
407*5f757f3fSDimitry Andric   case ISD::INSERT_VECTOR_ELT:
408*5f757f3fSDimitry Andric     return lowerINSERT_VECTOR_ELT(Op, DAG);
409*5f757f3fSDimitry Andric   case ISD::BUILD_VECTOR:
410*5f757f3fSDimitry Andric     return lowerBUILD_VECTOR(Op, DAG);
411*5f757f3fSDimitry Andric   case ISD::VECTOR_SHUFFLE:
412*5f757f3fSDimitry Andric     return lowerVECTOR_SHUFFLE(Op, DAG);
41381ad6265SDimitry Andric   }
414bdd1243dSDimitry Andric   return SDValue();
415bdd1243dSDimitry Andric }
416bdd1243dSDimitry Andric 
417*5f757f3fSDimitry Andric SDValue LoongArchTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
418*5f757f3fSDimitry Andric                                                      SelectionDAG &DAG) const {
419*5f757f3fSDimitry Andric   // TODO: custom shuffle.
420*5f757f3fSDimitry Andric   return SDValue();
421*5f757f3fSDimitry Andric }
422*5f757f3fSDimitry Andric 
423*5f757f3fSDimitry Andric static bool isConstantOrUndef(const SDValue Op) {
424*5f757f3fSDimitry Andric   if (Op->isUndef())
425*5f757f3fSDimitry Andric     return true;
426*5f757f3fSDimitry Andric   if (isa<ConstantSDNode>(Op))
427*5f757f3fSDimitry Andric     return true;
428*5f757f3fSDimitry Andric   if (isa<ConstantFPSDNode>(Op))
429*5f757f3fSDimitry Andric     return true;
430*5f757f3fSDimitry Andric   return false;
431*5f757f3fSDimitry Andric }
432*5f757f3fSDimitry Andric 
433*5f757f3fSDimitry Andric static bool isConstantOrUndefBUILD_VECTOR(const BuildVectorSDNode *Op) {
434*5f757f3fSDimitry Andric   for (unsigned i = 0; i < Op->getNumOperands(); ++i)
435*5f757f3fSDimitry Andric     if (isConstantOrUndef(Op->getOperand(i)))
436*5f757f3fSDimitry Andric       return true;
437*5f757f3fSDimitry Andric   return false;
438*5f757f3fSDimitry Andric }
439*5f757f3fSDimitry Andric 
440*5f757f3fSDimitry Andric SDValue LoongArchTargetLowering::lowerBUILD_VECTOR(SDValue Op,
441*5f757f3fSDimitry Andric                                                    SelectionDAG &DAG) const {
442*5f757f3fSDimitry Andric   BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op);
443*5f757f3fSDimitry Andric   EVT ResTy = Op->getValueType(0);
444*5f757f3fSDimitry Andric   SDLoc DL(Op);
445*5f757f3fSDimitry Andric   APInt SplatValue, SplatUndef;
446*5f757f3fSDimitry Andric   unsigned SplatBitSize;
447*5f757f3fSDimitry Andric   bool HasAnyUndefs;
448*5f757f3fSDimitry Andric   bool Is128Vec = ResTy.is128BitVector();
449*5f757f3fSDimitry Andric   bool Is256Vec = ResTy.is256BitVector();
450*5f757f3fSDimitry Andric 
451*5f757f3fSDimitry Andric   if ((!Subtarget.hasExtLSX() || !Is128Vec) &&
452*5f757f3fSDimitry Andric       (!Subtarget.hasExtLASX() || !Is256Vec))
453*5f757f3fSDimitry Andric     return SDValue();
454*5f757f3fSDimitry Andric 
455*5f757f3fSDimitry Andric   if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
456*5f757f3fSDimitry Andric                             /*MinSplatBits=*/8) &&
457*5f757f3fSDimitry Andric       SplatBitSize <= 64) {
458*5f757f3fSDimitry Andric     // We can only cope with 8, 16, 32, or 64-bit elements.
459*5f757f3fSDimitry Andric     if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 &&
460*5f757f3fSDimitry Andric         SplatBitSize != 64)
461*5f757f3fSDimitry Andric       return SDValue();
462*5f757f3fSDimitry Andric 
463*5f757f3fSDimitry Andric     EVT ViaVecTy;
464*5f757f3fSDimitry Andric 
465*5f757f3fSDimitry Andric     switch (SplatBitSize) {
466*5f757f3fSDimitry Andric     default:
467*5f757f3fSDimitry Andric       return SDValue();
468*5f757f3fSDimitry Andric     case 8:
469*5f757f3fSDimitry Andric       ViaVecTy = Is128Vec ? MVT::v16i8 : MVT::v32i8;
470*5f757f3fSDimitry Andric       break;
471*5f757f3fSDimitry Andric     case 16:
472*5f757f3fSDimitry Andric       ViaVecTy = Is128Vec ? MVT::v8i16 : MVT::v16i16;
473*5f757f3fSDimitry Andric       break;
474*5f757f3fSDimitry Andric     case 32:
475*5f757f3fSDimitry Andric       ViaVecTy = Is128Vec ? MVT::v4i32 : MVT::v8i32;
476*5f757f3fSDimitry Andric       break;
477*5f757f3fSDimitry Andric     case 64:
478*5f757f3fSDimitry Andric       ViaVecTy = Is128Vec ? MVT::v2i64 : MVT::v4i64;
479*5f757f3fSDimitry Andric       break;
480*5f757f3fSDimitry Andric     }
481*5f757f3fSDimitry Andric 
482*5f757f3fSDimitry Andric     // SelectionDAG::getConstant will promote SplatValue appropriately.
483*5f757f3fSDimitry Andric     SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy);
484*5f757f3fSDimitry Andric 
485*5f757f3fSDimitry Andric     // Bitcast to the type we originally wanted.
486*5f757f3fSDimitry Andric     if (ViaVecTy != ResTy)
487*5f757f3fSDimitry Andric       Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result);
488*5f757f3fSDimitry Andric 
489*5f757f3fSDimitry Andric     return Result;
490*5f757f3fSDimitry Andric   }
491*5f757f3fSDimitry Andric 
492*5f757f3fSDimitry Andric   if (DAG.isSplatValue(Op, /*AllowUndefs=*/false))
493*5f757f3fSDimitry Andric     return Op;
494*5f757f3fSDimitry Andric 
495*5f757f3fSDimitry Andric   if (!isConstantOrUndefBUILD_VECTOR(Node)) {
496*5f757f3fSDimitry Andric     // Use INSERT_VECTOR_ELT operations rather than expand to stores.
497*5f757f3fSDimitry Andric     // The resulting code is the same length as the expansion, but it doesn't
498*5f757f3fSDimitry Andric     // use memory operations.
499*5f757f3fSDimitry Andric     EVT ResTy = Node->getValueType(0);
500*5f757f3fSDimitry Andric 
501*5f757f3fSDimitry Andric     assert(ResTy.isVector());
502*5f757f3fSDimitry Andric 
503*5f757f3fSDimitry Andric     unsigned NumElts = ResTy.getVectorNumElements();
504*5f757f3fSDimitry Andric     SDValue Vector = DAG.getUNDEF(ResTy);
505*5f757f3fSDimitry Andric     for (unsigned i = 0; i < NumElts; ++i) {
506*5f757f3fSDimitry Andric       Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector,
507*5f757f3fSDimitry Andric                            Node->getOperand(i),
508*5f757f3fSDimitry Andric                            DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
509*5f757f3fSDimitry Andric     }
510*5f757f3fSDimitry Andric     return Vector;
511*5f757f3fSDimitry Andric   }
512*5f757f3fSDimitry Andric 
513*5f757f3fSDimitry Andric   return SDValue();
514*5f757f3fSDimitry Andric }
515*5f757f3fSDimitry Andric 
516*5f757f3fSDimitry Andric SDValue
517*5f757f3fSDimitry Andric LoongArchTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
518*5f757f3fSDimitry Andric                                                 SelectionDAG &DAG) const {
519*5f757f3fSDimitry Andric   if (isa<ConstantSDNode>(Op->getOperand(2)))
520*5f757f3fSDimitry Andric     return Op;
521*5f757f3fSDimitry Andric   return SDValue();
522*5f757f3fSDimitry Andric }
523*5f757f3fSDimitry Andric 
524*5f757f3fSDimitry Andric SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op,
525*5f757f3fSDimitry Andric                                                    SelectionDAG &DAG) const {
526*5f757f3fSDimitry Andric   SDLoc DL(Op);
527*5f757f3fSDimitry Andric   SyncScope::ID FenceSSID =
528*5f757f3fSDimitry Andric       static_cast<SyncScope::ID>(Op.getConstantOperandVal(2));
529*5f757f3fSDimitry Andric 
530*5f757f3fSDimitry Andric   // singlethread fences only synchronize with signal handlers on the same
531*5f757f3fSDimitry Andric   // thread and thus only need to preserve instruction order, not actually
532*5f757f3fSDimitry Andric   // enforce memory ordering.
533*5f757f3fSDimitry Andric   if (FenceSSID == SyncScope::SingleThread)
534*5f757f3fSDimitry Andric     // MEMBARRIER is a compiler barrier; it codegens to a no-op.
535*5f757f3fSDimitry Andric     return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
536*5f757f3fSDimitry Andric 
537*5f757f3fSDimitry Andric   return Op;
538*5f757f3fSDimitry Andric }
539*5f757f3fSDimitry Andric 
540bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
541bdd1243dSDimitry Andric                                                      SelectionDAG &DAG) const {
542bdd1243dSDimitry Andric 
543bdd1243dSDimitry Andric   if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
544bdd1243dSDimitry Andric     DAG.getContext()->emitError(
545bdd1243dSDimitry Andric         "On LA64, only 64-bit registers can be written.");
546bdd1243dSDimitry Andric     return Op.getOperand(0);
547bdd1243dSDimitry Andric   }
548bdd1243dSDimitry Andric 
549bdd1243dSDimitry Andric   if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
550bdd1243dSDimitry Andric     DAG.getContext()->emitError(
551bdd1243dSDimitry Andric         "On LA32, only 32-bit registers can be written.");
552bdd1243dSDimitry Andric     return Op.getOperand(0);
553bdd1243dSDimitry Andric   }
554bdd1243dSDimitry Andric 
555bdd1243dSDimitry Andric   return Op;
556bdd1243dSDimitry Andric }
557bdd1243dSDimitry Andric 
558bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
559bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
560bdd1243dSDimitry Andric   if (!isa<ConstantSDNode>(Op.getOperand(0))) {
561bdd1243dSDimitry Andric     DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
562bdd1243dSDimitry Andric                                 "be a constant integer");
563bdd1243dSDimitry Andric     return SDValue();
564bdd1243dSDimitry Andric   }
565bdd1243dSDimitry Andric 
566bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
567bdd1243dSDimitry Andric   MF.getFrameInfo().setFrameAddressIsTaken(true);
568bdd1243dSDimitry Andric   Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
569bdd1243dSDimitry Andric   EVT VT = Op.getValueType();
570bdd1243dSDimitry Andric   SDLoc DL(Op);
571bdd1243dSDimitry Andric   SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
572bdd1243dSDimitry Andric   unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
573bdd1243dSDimitry Andric   int GRLenInBytes = Subtarget.getGRLen() / 8;
574bdd1243dSDimitry Andric 
575bdd1243dSDimitry Andric   while (Depth--) {
576bdd1243dSDimitry Andric     int Offset = -(GRLenInBytes * 2);
577bdd1243dSDimitry Andric     SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
578bdd1243dSDimitry Andric                               DAG.getIntPtrConstant(Offset, DL));
579bdd1243dSDimitry Andric     FrameAddr =
580bdd1243dSDimitry Andric         DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
581bdd1243dSDimitry Andric   }
582bdd1243dSDimitry Andric   return FrameAddr;
583bdd1243dSDimitry Andric }
584bdd1243dSDimitry Andric 
585bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
586bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
587bdd1243dSDimitry Andric   if (verifyReturnAddressArgumentIsConstant(Op, DAG))
588bdd1243dSDimitry Andric     return SDValue();
589bdd1243dSDimitry Andric 
590bdd1243dSDimitry Andric   // Currently only support lowering return address for current frame.
591bdd1243dSDimitry Andric   if (cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() != 0) {
592bdd1243dSDimitry Andric     DAG.getContext()->emitError(
593bdd1243dSDimitry Andric         "return address can only be determined for the current frame");
594bdd1243dSDimitry Andric     return SDValue();
595bdd1243dSDimitry Andric   }
596bdd1243dSDimitry Andric 
597bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
598bdd1243dSDimitry Andric   MF.getFrameInfo().setReturnAddressIsTaken(true);
599bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
600bdd1243dSDimitry Andric 
601bdd1243dSDimitry Andric   // Return the value of the return address register, marking it an implicit
602bdd1243dSDimitry Andric   // live-in.
603bdd1243dSDimitry Andric   Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
604bdd1243dSDimitry Andric                               getRegClassFor(GRLenVT));
605bdd1243dSDimitry Andric   return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
606bdd1243dSDimitry Andric }
607bdd1243dSDimitry Andric 
608bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
609bdd1243dSDimitry Andric                                                    SelectionDAG &DAG) const {
610bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
611bdd1243dSDimitry Andric   auto Size = Subtarget.getGRLen() / 8;
612bdd1243dSDimitry Andric   auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
613bdd1243dSDimitry Andric   return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
614bdd1243dSDimitry Andric }
615bdd1243dSDimitry Andric 
616bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
617bdd1243dSDimitry Andric                                               SelectionDAG &DAG) const {
618bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
619bdd1243dSDimitry Andric   auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
620bdd1243dSDimitry Andric 
621bdd1243dSDimitry Andric   SDLoc DL(Op);
622bdd1243dSDimitry Andric   SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
623bdd1243dSDimitry Andric                                  getPointerTy(MF.getDataLayout()));
624bdd1243dSDimitry Andric 
625bdd1243dSDimitry Andric   // vastart just stores the address of the VarArgsFrameIndex slot into the
626bdd1243dSDimitry Andric   // memory location argument.
627bdd1243dSDimitry Andric   const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
628bdd1243dSDimitry Andric   return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
629bdd1243dSDimitry Andric                       MachinePointerInfo(SV));
63081ad6265SDimitry Andric }
63181ad6265SDimitry Andric 
632753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
633753f127fSDimitry Andric                                                  SelectionDAG &DAG) const {
634bdd1243dSDimitry Andric   assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
635bdd1243dSDimitry Andric          !Subtarget.hasBasicD() && "unexpected target features");
636753f127fSDimitry Andric 
637753f127fSDimitry Andric   SDLoc DL(Op);
638bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
639bdd1243dSDimitry Andric   if (Op0->getOpcode() == ISD::AND) {
640bdd1243dSDimitry Andric     auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
641bdd1243dSDimitry Andric     if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
642753f127fSDimitry Andric       return Op;
643bdd1243dSDimitry Andric   }
644bdd1243dSDimitry Andric 
645bdd1243dSDimitry Andric   if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
646bdd1243dSDimitry Andric       Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
647bdd1243dSDimitry Andric       Op0.getConstantOperandVal(2) == UINT64_C(0))
648bdd1243dSDimitry Andric     return Op;
649bdd1243dSDimitry Andric 
650bdd1243dSDimitry Andric   if (Op0.getOpcode() == ISD::AssertZext &&
651bdd1243dSDimitry Andric       dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
652bdd1243dSDimitry Andric     return Op;
653bdd1243dSDimitry Andric 
654bdd1243dSDimitry Andric   EVT OpVT = Op0.getValueType();
655bdd1243dSDimitry Andric   EVT RetVT = Op.getValueType();
656bdd1243dSDimitry Andric   RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
657bdd1243dSDimitry Andric   MakeLibCallOptions CallOptions;
658bdd1243dSDimitry Andric   CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
659bdd1243dSDimitry Andric   SDValue Chain = SDValue();
660bdd1243dSDimitry Andric   SDValue Result;
661bdd1243dSDimitry Andric   std::tie(Result, Chain) =
662bdd1243dSDimitry Andric       makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
663bdd1243dSDimitry Andric   return Result;
664bdd1243dSDimitry Andric }
665bdd1243dSDimitry Andric 
666bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
667bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
668bdd1243dSDimitry Andric   assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
669bdd1243dSDimitry Andric          !Subtarget.hasBasicD() && "unexpected target features");
670bdd1243dSDimitry Andric 
671bdd1243dSDimitry Andric   SDLoc DL(Op);
672bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
673bdd1243dSDimitry Andric 
674bdd1243dSDimitry Andric   if ((Op0.getOpcode() == ISD::AssertSext ||
675bdd1243dSDimitry Andric        Op0.getOpcode() == ISD::SIGN_EXTEND_INREG) &&
676bdd1243dSDimitry Andric       dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
677bdd1243dSDimitry Andric     return Op;
678bdd1243dSDimitry Andric 
679bdd1243dSDimitry Andric   EVT OpVT = Op0.getValueType();
680bdd1243dSDimitry Andric   EVT RetVT = Op.getValueType();
681bdd1243dSDimitry Andric   RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
682bdd1243dSDimitry Andric   MakeLibCallOptions CallOptions;
683bdd1243dSDimitry Andric   CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
684bdd1243dSDimitry Andric   SDValue Chain = SDValue();
685bdd1243dSDimitry Andric   SDValue Result;
686bdd1243dSDimitry Andric   std::tie(Result, Chain) =
687bdd1243dSDimitry Andric       makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
688bdd1243dSDimitry Andric   return Result;
689753f127fSDimitry Andric }
690753f127fSDimitry Andric 
691753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
692753f127fSDimitry Andric                                               SelectionDAG &DAG) const {
693753f127fSDimitry Andric 
694753f127fSDimitry Andric   SDLoc DL(Op);
695753f127fSDimitry Andric   SDValue Op0 = Op.getOperand(0);
696753f127fSDimitry Andric 
697753f127fSDimitry Andric   if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 &&
698753f127fSDimitry Andric       Subtarget.is64Bit() && Subtarget.hasBasicF()) {
699753f127fSDimitry Andric     SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
700753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
701753f127fSDimitry Andric   }
702753f127fSDimitry Andric   return Op;
703753f127fSDimitry Andric }
704753f127fSDimitry Andric 
705753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
706753f127fSDimitry Andric                                                  SelectionDAG &DAG) const {
707753f127fSDimitry Andric 
708753f127fSDimitry Andric   SDLoc DL(Op);
709753f127fSDimitry Andric 
710753f127fSDimitry Andric   if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
711753f127fSDimitry Andric       !Subtarget.hasBasicD()) {
712753f127fSDimitry Andric     SDValue Dst =
713753f127fSDimitry Andric         DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0));
714753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
715753f127fSDimitry Andric   }
716753f127fSDimitry Andric 
717753f127fSDimitry Andric   EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
718753f127fSDimitry Andric   SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0));
719753f127fSDimitry Andric   return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
720753f127fSDimitry Andric }
721753f127fSDimitry Andric 
722bdd1243dSDimitry Andric static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty,
723bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
724bdd1243dSDimitry Andric   return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
725bdd1243dSDimitry Andric }
726bdd1243dSDimitry Andric 
727bdd1243dSDimitry Andric static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty,
728bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
729bdd1243dSDimitry Andric   return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
730bdd1243dSDimitry Andric                                    Flags);
731bdd1243dSDimitry Andric }
732bdd1243dSDimitry Andric 
733bdd1243dSDimitry Andric static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty,
734bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
735bdd1243dSDimitry Andric   return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
736bdd1243dSDimitry Andric                                    N->getOffset(), Flags);
737bdd1243dSDimitry Andric }
738bdd1243dSDimitry Andric 
739bdd1243dSDimitry Andric static SDValue getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty,
740bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
741bdd1243dSDimitry Andric   return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
742bdd1243dSDimitry Andric }
743bdd1243dSDimitry Andric 
744bdd1243dSDimitry Andric template <class NodeTy>
745bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
746bdd1243dSDimitry Andric                                          bool IsLocal) const {
747bdd1243dSDimitry Andric   SDLoc DL(N);
748bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
749bdd1243dSDimitry Andric   SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
75006c3fb27SDimitry Andric 
75106c3fb27SDimitry Andric   switch (DAG.getTarget().getCodeModel()) {
75206c3fb27SDimitry Andric   default:
75306c3fb27SDimitry Andric     report_fatal_error("Unsupported code model");
75406c3fb27SDimitry Andric 
75506c3fb27SDimitry Andric   case CodeModel::Large: {
75606c3fb27SDimitry Andric     assert(Subtarget.is64Bit() && "Large code model requires LA64");
75706c3fb27SDimitry Andric 
75806c3fb27SDimitry Andric     // This is not actually used, but is necessary for successfully matching
75906c3fb27SDimitry Andric     // the PseudoLA_*_LARGE nodes.
76006c3fb27SDimitry Andric     SDValue Tmp = DAG.getConstant(0, DL, Ty);
76106c3fb27SDimitry Andric     if (IsLocal)
76206c3fb27SDimitry Andric       // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that
76306c3fb27SDimitry Andric       // eventually becomes the desired 5-insn code sequence.
76406c3fb27SDimitry Andric       return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty,
76506c3fb27SDimitry Andric                                         Tmp, Addr),
76606c3fb27SDimitry Andric                      0);
76706c3fb27SDimitry Andric 
76806c3fb27SDimitry Andric     // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that eventually
76906c3fb27SDimitry Andric     // becomes the desired 5-insn code sequence.
77006c3fb27SDimitry Andric     return SDValue(
77106c3fb27SDimitry Andric         DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr),
77206c3fb27SDimitry Andric         0);
77306c3fb27SDimitry Andric   }
77406c3fb27SDimitry Andric 
77506c3fb27SDimitry Andric   case CodeModel::Small:
77606c3fb27SDimitry Andric   case CodeModel::Medium:
777bdd1243dSDimitry Andric     if (IsLocal)
778bdd1243dSDimitry Andric       // This generates the pattern (PseudoLA_PCREL sym), which expands to
779bdd1243dSDimitry Andric       // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
78006c3fb27SDimitry Andric       return SDValue(
78106c3fb27SDimitry Andric           DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0);
782bdd1243dSDimitry Andric 
783bdd1243dSDimitry Andric     // This generates the pattern (PseudoLA_GOT sym), which expands to (ld.w/d
784bdd1243dSDimitry Andric     // (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
78506c3fb27SDimitry Andric     return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr),
78606c3fb27SDimitry Andric                    0);
78706c3fb27SDimitry Andric   }
788bdd1243dSDimitry Andric }
789bdd1243dSDimitry Andric 
790bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
791bdd1243dSDimitry Andric                                                    SelectionDAG &DAG) const {
792bdd1243dSDimitry Andric   return getAddr(cast<BlockAddressSDNode>(Op), DAG);
793bdd1243dSDimitry Andric }
794bdd1243dSDimitry Andric 
795bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
796bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
797bdd1243dSDimitry Andric   return getAddr(cast<JumpTableSDNode>(Op), DAG);
798bdd1243dSDimitry Andric }
799bdd1243dSDimitry Andric 
800753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
801753f127fSDimitry Andric                                                    SelectionDAG &DAG) const {
802bdd1243dSDimitry Andric   return getAddr(cast<ConstantPoolSDNode>(Op), DAG);
803753f127fSDimitry Andric }
804753f127fSDimitry Andric 
805753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
806753f127fSDimitry Andric                                                     SelectionDAG &DAG) const {
807bdd1243dSDimitry Andric   GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
808bdd1243dSDimitry Andric   assert(N->getOffset() == 0 && "unexpected offset in global node");
809bdd1243dSDimitry Andric   return getAddr(N, DAG, N->getGlobal()->isDSOLocal());
810bdd1243dSDimitry Andric }
811753f127fSDimitry Andric 
812bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
813bdd1243dSDimitry Andric                                                   SelectionDAG &DAG,
81406c3fb27SDimitry Andric                                                   unsigned Opc,
81506c3fb27SDimitry Andric                                                   bool Large) const {
816bdd1243dSDimitry Andric   SDLoc DL(N);
817bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
818bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
819bdd1243dSDimitry Andric 
82006c3fb27SDimitry Andric   // This is not actually used, but is necessary for successfully matching the
82106c3fb27SDimitry Andric   // PseudoLA_*_LARGE nodes.
82206c3fb27SDimitry Andric   SDValue Tmp = DAG.getConstant(0, DL, Ty);
823bdd1243dSDimitry Andric   SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
82406c3fb27SDimitry Andric   SDValue Offset = Large
82506c3fb27SDimitry Andric                        ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
82606c3fb27SDimitry Andric                        : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
827bdd1243dSDimitry Andric 
828bdd1243dSDimitry Andric   // Add the thread pointer.
829bdd1243dSDimitry Andric   return DAG.getNode(ISD::ADD, DL, Ty, Offset,
830bdd1243dSDimitry Andric                      DAG.getRegister(LoongArch::R2, GRLenVT));
831bdd1243dSDimitry Andric }
832bdd1243dSDimitry Andric 
833bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
834bdd1243dSDimitry Andric                                                    SelectionDAG &DAG,
83506c3fb27SDimitry Andric                                                    unsigned Opc,
83606c3fb27SDimitry Andric                                                    bool Large) const {
837bdd1243dSDimitry Andric   SDLoc DL(N);
838bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
839bdd1243dSDimitry Andric   IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
840bdd1243dSDimitry Andric 
84106c3fb27SDimitry Andric   // This is not actually used, but is necessary for successfully matching the
84206c3fb27SDimitry Andric   // PseudoLA_*_LARGE nodes.
84306c3fb27SDimitry Andric   SDValue Tmp = DAG.getConstant(0, DL, Ty);
84406c3fb27SDimitry Andric 
845bdd1243dSDimitry Andric   // Use a PC-relative addressing mode to access the dynamic GOT address.
846bdd1243dSDimitry Andric   SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
84706c3fb27SDimitry Andric   SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
84806c3fb27SDimitry Andric                        : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
849bdd1243dSDimitry Andric 
850bdd1243dSDimitry Andric   // Prepare argument list to generate call.
851bdd1243dSDimitry Andric   ArgListTy Args;
852bdd1243dSDimitry Andric   ArgListEntry Entry;
853bdd1243dSDimitry Andric   Entry.Node = Load;
854bdd1243dSDimitry Andric   Entry.Ty = CallTy;
855bdd1243dSDimitry Andric   Args.push_back(Entry);
856bdd1243dSDimitry Andric 
857bdd1243dSDimitry Andric   // Setup call to __tls_get_addr.
858bdd1243dSDimitry Andric   TargetLowering::CallLoweringInfo CLI(DAG);
859bdd1243dSDimitry Andric   CLI.setDebugLoc(DL)
860bdd1243dSDimitry Andric       .setChain(DAG.getEntryNode())
861bdd1243dSDimitry Andric       .setLibCallee(CallingConv::C, CallTy,
862bdd1243dSDimitry Andric                     DAG.getExternalSymbol("__tls_get_addr", Ty),
863bdd1243dSDimitry Andric                     std::move(Args));
864bdd1243dSDimitry Andric 
865bdd1243dSDimitry Andric   return LowerCallTo(CLI).first;
866bdd1243dSDimitry Andric }
867bdd1243dSDimitry Andric 
868bdd1243dSDimitry Andric SDValue
869bdd1243dSDimitry Andric LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
870bdd1243dSDimitry Andric                                                SelectionDAG &DAG) const {
871bdd1243dSDimitry Andric   if (DAG.getMachineFunction().getFunction().getCallingConv() ==
872bdd1243dSDimitry Andric       CallingConv::GHC)
873bdd1243dSDimitry Andric     report_fatal_error("In GHC calling convention TLS is not supported");
874bdd1243dSDimitry Andric 
87506c3fb27SDimitry Andric   bool Large = DAG.getTarget().getCodeModel() == CodeModel::Large;
87606c3fb27SDimitry Andric   assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64");
87706c3fb27SDimitry Andric 
878bdd1243dSDimitry Andric   GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
879bdd1243dSDimitry Andric   assert(N->getOffset() == 0 && "unexpected offset in global node");
880bdd1243dSDimitry Andric 
881bdd1243dSDimitry Andric   SDValue Addr;
882bdd1243dSDimitry Andric   switch (getTargetMachine().getTLSModel(N->getGlobal())) {
883bdd1243dSDimitry Andric   case TLSModel::GeneralDynamic:
884bdd1243dSDimitry Andric     // In this model, application code calls the dynamic linker function
885bdd1243dSDimitry Andric     // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
886bdd1243dSDimitry Andric     // runtime.
88706c3fb27SDimitry Andric     Addr = getDynamicTLSAddr(N, DAG,
88806c3fb27SDimitry Andric                              Large ? LoongArch::PseudoLA_TLS_GD_LARGE
88906c3fb27SDimitry Andric                                    : LoongArch::PseudoLA_TLS_GD,
89006c3fb27SDimitry Andric                              Large);
891bdd1243dSDimitry Andric     break;
892bdd1243dSDimitry Andric   case TLSModel::LocalDynamic:
893bdd1243dSDimitry Andric     // Same as GeneralDynamic, except for assembly modifiers and relocation
894bdd1243dSDimitry Andric     // records.
89506c3fb27SDimitry Andric     Addr = getDynamicTLSAddr(N, DAG,
89606c3fb27SDimitry Andric                              Large ? LoongArch::PseudoLA_TLS_LD_LARGE
89706c3fb27SDimitry Andric                                    : LoongArch::PseudoLA_TLS_LD,
89806c3fb27SDimitry Andric                              Large);
899bdd1243dSDimitry Andric     break;
900bdd1243dSDimitry Andric   case TLSModel::InitialExec:
901bdd1243dSDimitry Andric     // This model uses the GOT to resolve TLS offsets.
90206c3fb27SDimitry Andric     Addr = getStaticTLSAddr(N, DAG,
90306c3fb27SDimitry Andric                             Large ? LoongArch::PseudoLA_TLS_IE_LARGE
90406c3fb27SDimitry Andric                                   : LoongArch::PseudoLA_TLS_IE,
90506c3fb27SDimitry Andric                             Large);
906bdd1243dSDimitry Andric     break;
907bdd1243dSDimitry Andric   case TLSModel::LocalExec:
908bdd1243dSDimitry Andric     // This model is used when static linking as the TLS offsets are resolved
909bdd1243dSDimitry Andric     // during program linking.
91006c3fb27SDimitry Andric     //
91106c3fb27SDimitry Andric     // This node doesn't need an extra argument for the large code model.
912bdd1243dSDimitry Andric     Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE);
913bdd1243dSDimitry Andric     break;
914bdd1243dSDimitry Andric   }
915bdd1243dSDimitry Andric 
916753f127fSDimitry Andric   return Addr;
917753f127fSDimitry Andric }
918bdd1243dSDimitry Andric 
919*5f757f3fSDimitry Andric template <unsigned N>
920*5f757f3fSDimitry Andric static SDValue checkIntrinsicImmArg(SDValue Op, unsigned ImmOp,
921*5f757f3fSDimitry Andric                                     SelectionDAG &DAG, bool IsSigned = false) {
922*5f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Op->getOperand(ImmOp));
923*5f757f3fSDimitry Andric   // Check the ImmArg.
924*5f757f3fSDimitry Andric   if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
925*5f757f3fSDimitry Andric       (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
926*5f757f3fSDimitry Andric     DAG.getContext()->emitError(Op->getOperationName(0) +
927*5f757f3fSDimitry Andric                                 ": argument out of range.");
928*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, SDLoc(Op), Op.getValueType());
929*5f757f3fSDimitry Andric   }
930*5f757f3fSDimitry Andric   return SDValue();
931*5f757f3fSDimitry Andric }
932*5f757f3fSDimitry Andric 
933bdd1243dSDimitry Andric SDValue
934bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
935bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
936*5f757f3fSDimitry Andric   SDLoc DL(Op);
937bdd1243dSDimitry Andric   switch (Op.getConstantOperandVal(0)) {
938bdd1243dSDimitry Andric   default:
939bdd1243dSDimitry Andric     return SDValue(); // Don't custom lower most intrinsics.
940bdd1243dSDimitry Andric   case Intrinsic::thread_pointer: {
941bdd1243dSDimitry Andric     EVT PtrVT = getPointerTy(DAG.getDataLayout());
942bdd1243dSDimitry Andric     return DAG.getRegister(LoongArch::R2, PtrVT);
943bdd1243dSDimitry Andric   }
944*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_d:
945*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_du:
946*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplvei_d:
947*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepl128vei_d:
948*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<1>(Op, 2, DAG);
949*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplvei_w:
950*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepl128vei_w:
951*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve2gr_d:
952*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve2gr_du:
953*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve_d:
954*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve_d_f:
955*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<2>(Op, 2, DAG);
956*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvinsve0_d:
957*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<2>(Op, 3, DAG);
958*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_b:
959*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_bu:
960*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrotri_b:
961*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_h_b:
962*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_hu_bu:
963*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlri_b:
964*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrari_b:
965*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplvei_h:
966*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_b:
967*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_bu:
968*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrotri_b:
969*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_h_b:
970*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_hu_bu:
971*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlri_b:
972*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrari_b:
973*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepl128vei_h:
974*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve_w:
975*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve_w_f:
976*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<3>(Op, 2, DAG);
977*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvinsve0_w:
978*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<3>(Op, 3, DAG);
979*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_h:
980*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_hu:
981*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrotri_h:
982*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_w_h:
983*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_wu_hu:
984*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlri_h:
985*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrari_h:
986*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplvei_b:
987*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_h:
988*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_hu:
989*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrotri_h:
990*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_w_h:
991*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_wu_hu:
992*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlri_h:
993*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrari_h:
994*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepl128vei_b:
995*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<4>(Op, 2, DAG);
996*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlni_b_h:
997*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrani_b_h:
998*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlrni_b_h:
999*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrarni_b_h:
1000*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_b_h:
1001*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_b_h:
1002*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_bu_h:
1003*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_bu_h:
1004*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_b_h:
1005*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_b_h:
1006*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_bu_h:
1007*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_bu_h:
1008*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlni_b_h:
1009*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrani_b_h:
1010*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlrni_b_h:
1011*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrarni_b_h:
1012*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_b_h:
1013*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_b_h:
1014*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_bu_h:
1015*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_bu_h:
1016*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_b_h:
1017*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_b_h:
1018*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_bu_h:
1019*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_bu_h:
1020*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<4>(Op, 3, DAG);
1021*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_w:
1022*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_wu:
1023*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrotri_w:
1024*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_d_w:
1025*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_du_wu:
1026*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlri_w:
1027*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrari_w:
1028*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_bu:
1029*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_hu:
1030*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_wu:
1031*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_du:
1032*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_bu:
1033*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_hu:
1034*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_wu:
1035*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_du:
1036*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbsll_v:
1037*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbsrl_v:
1038*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_w:
1039*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_wu:
1040*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrotri_w:
1041*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_d_w:
1042*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_du_wu:
1043*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlri_w:
1044*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrari_w:
1045*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_bu:
1046*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_hu:
1047*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_wu:
1048*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_du:
1049*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_bu:
1050*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_hu:
1051*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_wu:
1052*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_du:
1053*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbsll_v:
1054*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbsrl_v:
1055*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<5>(Op, 2, DAG);
1056*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vseqi_b:
1057*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vseqi_h:
1058*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vseqi_w:
1059*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vseqi_d:
1060*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_b:
1061*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_h:
1062*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_w:
1063*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_d:
1064*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_b:
1065*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_h:
1066*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_w:
1067*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_d:
1068*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvseqi_b:
1069*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvseqi_h:
1070*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvseqi_w:
1071*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvseqi_d:
1072*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_b:
1073*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_h:
1074*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_w:
1075*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_d:
1076*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_b:
1077*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_h:
1078*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_w:
1079*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_d:
1080*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<5>(Op, 2, DAG, /*IsSigned=*/true);
1081*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlni_h_w:
1082*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrani_h_w:
1083*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlrni_h_w:
1084*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrarni_h_w:
1085*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_h_w:
1086*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_h_w:
1087*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_hu_w:
1088*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_hu_w:
1089*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_h_w:
1090*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_h_w:
1091*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_hu_w:
1092*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_hu_w:
1093*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfrstpi_b:
1094*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfrstpi_h:
1095*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlni_h_w:
1096*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrani_h_w:
1097*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlrni_h_w:
1098*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrarni_h_w:
1099*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_h_w:
1100*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_h_w:
1101*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_hu_w:
1102*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_hu_w:
1103*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_h_w:
1104*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_h_w:
1105*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_hu_w:
1106*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_hu_w:
1107*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfrstpi_b:
1108*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfrstpi_h:
1109*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<5>(Op, 3, DAG);
1110*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_d:
1111*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_du:
1112*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrotri_d:
1113*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlri_d:
1114*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrari_d:
1115*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_d:
1116*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_du:
1117*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrotri_d:
1118*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlri_d:
1119*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrari_d:
1120*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<6>(Op, 2, DAG);
1121*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlni_w_d:
1122*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrani_w_d:
1123*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlrni_w_d:
1124*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrarni_w_d:
1125*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_w_d:
1126*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_w_d:
1127*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_wu_d:
1128*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_wu_d:
1129*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_w_d:
1130*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_w_d:
1131*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_wu_d:
1132*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_wu_d:
1133*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlni_w_d:
1134*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrani_w_d:
1135*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlrni_w_d:
1136*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrarni_w_d:
1137*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_w_d:
1138*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_w_d:
1139*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_wu_d:
1140*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_wu_d:
1141*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_w_d:
1142*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_w_d:
1143*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_wu_d:
1144*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_wu_d:
1145*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<6>(Op, 3, DAG);
1146*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlni_d_q:
1147*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrani_d_q:
1148*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlrni_d_q:
1149*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrarni_d_q:
1150*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_d_q:
1151*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_d_q:
1152*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_du_q:
1153*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_du_q:
1154*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_d_q:
1155*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_d_q:
1156*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_du_q:
1157*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_du_q:
1158*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlni_d_q:
1159*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrani_d_q:
1160*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlrni_d_q:
1161*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrarni_d_q:
1162*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_d_q:
1163*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_d_q:
1164*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_du_q:
1165*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_du_q:
1166*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_d_q:
1167*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_d_q:
1168*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_du_q:
1169*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_du_q:
1170*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<7>(Op, 3, DAG);
1171*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vnori_b:
1172*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vshuf4i_b:
1173*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vshuf4i_h:
1174*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vshuf4i_w:
1175*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvnori_b:
1176*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvshuf4i_b:
1177*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvshuf4i_h:
1178*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvshuf4i_w:
1179*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpermi_d:
1180*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<8>(Op, 2, DAG);
1181*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vshuf4i_d:
1182*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpermi_w:
1183*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitseli_b:
1184*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vextrins_b:
1185*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vextrins_h:
1186*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vextrins_w:
1187*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vextrins_d:
1188*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvshuf4i_d:
1189*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpermi_w:
1190*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpermi_q:
1191*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitseli_b:
1192*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvextrins_b:
1193*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvextrins_h:
1194*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvextrins_w:
1195*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvextrins_d:
1196*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<8>(Op, 3, DAG);
1197*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrepli_b:
1198*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrepli_h:
1199*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrepli_w:
1200*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrepli_d:
1201*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepli_b:
1202*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepli_h:
1203*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepli_w:
1204*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepli_d:
1205*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<10>(Op, 1, DAG, /*IsSigned=*/true);
1206*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vldi:
1207*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvldi:
1208*5f757f3fSDimitry Andric     return checkIntrinsicImmArg<13>(Op, 1, DAG, /*IsSigned=*/true);
1209bdd1243dSDimitry Andric   }
1210bdd1243dSDimitry Andric }
1211bdd1243dSDimitry Andric 
121206c3fb27SDimitry Andric // Helper function that emits error message for intrinsics with chain and return
121306c3fb27SDimitry Andric // merge values of a UNDEF and the chain.
1214bdd1243dSDimitry Andric static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op,
1215bdd1243dSDimitry Andric                                                   StringRef ErrorMsg,
1216bdd1243dSDimitry Andric                                                   SelectionDAG &DAG) {
121706c3fb27SDimitry Andric   DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
1218bdd1243dSDimitry Andric   return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
1219bdd1243dSDimitry Andric                             SDLoc(Op));
1220bdd1243dSDimitry Andric }
1221bdd1243dSDimitry Andric 
1222bdd1243dSDimitry Andric SDValue
1223bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
1224bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
1225bdd1243dSDimitry Andric   SDLoc DL(Op);
1226bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
122706c3fb27SDimitry Andric   EVT VT = Op.getValueType();
122806c3fb27SDimitry Andric   SDValue Chain = Op.getOperand(0);
122906c3fb27SDimitry Andric   const StringRef ErrorMsgOOR = "argument out of range";
123006c3fb27SDimitry Andric   const StringRef ErrorMsgReqLA64 = "requires loongarch64";
123106c3fb27SDimitry Andric   const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
1232bdd1243dSDimitry Andric 
1233bdd1243dSDimitry Andric   switch (Op.getConstantOperandVal(1)) {
1234bdd1243dSDimitry Andric   default:
1235bdd1243dSDimitry Andric     return Op;
1236bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_b_w:
1237bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_h_w:
1238bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_w_w:
1239bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_d_w:
1240bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_b_w:
1241bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_h_w:
1242bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_w_w:
124306c3fb27SDimitry Andric   case Intrinsic::loongarch_crcc_w_d_w:
124406c3fb27SDimitry Andric     return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG);
1245bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrrd_w:
1246bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrrd_d: {
1247bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
124806c3fb27SDimitry Andric     return !isUInt<14>(Imm)
124906c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
125006c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
125106c3fb27SDimitry Andric                              {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
1252bdd1243dSDimitry Andric   }
1253bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrwr_w:
1254bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrwr_d: {
1255bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
125606c3fb27SDimitry Andric     return !isUInt<14>(Imm)
125706c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
125806c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
125906c3fb27SDimitry Andric                              {Chain, Op.getOperand(2),
126006c3fb27SDimitry Andric                               DAG.getConstant(Imm, DL, GRLenVT)});
1261bdd1243dSDimitry Andric   }
1262bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrxchg_w:
1263bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrxchg_d: {
1264bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(4))->getZExtValue();
126506c3fb27SDimitry Andric     return !isUInt<14>(Imm)
126606c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
126706c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
126806c3fb27SDimitry Andric                              {Chain, Op.getOperand(2), Op.getOperand(3),
126906c3fb27SDimitry Andric                               DAG.getConstant(Imm, DL, GRLenVT)});
1270bdd1243dSDimitry Andric   }
1271bdd1243dSDimitry Andric   case Intrinsic::loongarch_iocsrrd_d: {
127206c3fb27SDimitry Andric     return DAG.getNode(
127306c3fb27SDimitry Andric         LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other},
127406c3fb27SDimitry Andric         {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))});
1275bdd1243dSDimitry Andric   }
1276bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE)                                               \
1277bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
127806c3fb27SDimitry Andric     return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other},          \
127906c3fb27SDimitry Andric                        {Chain, Op.getOperand(2)});                             \
1280bdd1243dSDimitry Andric   }
1281bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
1282bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
1283bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
1284bdd1243dSDimitry Andric #undef IOCSRRD_CASE
1285bdd1243dSDimitry Andric   case Intrinsic::loongarch_cpucfg: {
128606c3fb27SDimitry Andric     return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
128706c3fb27SDimitry Andric                        {Chain, Op.getOperand(2)});
1288bdd1243dSDimitry Andric   }
1289bdd1243dSDimitry Andric   case Intrinsic::loongarch_lddir_d: {
1290bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
129106c3fb27SDimitry Andric     return !isUInt<8>(Imm)
129206c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
129306c3fb27SDimitry Andric                : Op;
1294bdd1243dSDimitry Andric   }
1295bdd1243dSDimitry Andric   case Intrinsic::loongarch_movfcsr2gr: {
129606c3fb27SDimitry Andric     if (!Subtarget.hasBasicF())
129706c3fb27SDimitry Andric       return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG);
1298bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
129906c3fb27SDimitry Andric     return !isUInt<2>(Imm)
130006c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
130106c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other},
130206c3fb27SDimitry Andric                              {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
1303bdd1243dSDimitry Andric   }
1304*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vld:
1305*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vldrepl_b:
1306*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvld:
1307*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvldrepl_b:
1308*5f757f3fSDimitry Andric     return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
1309*5f757f3fSDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
1310*5f757f3fSDimitry Andric                : SDValue();
1311*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vldrepl_h:
1312*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvldrepl_h:
1313*5f757f3fSDimitry Andric     return !isShiftedInt<11, 1>(
1314*5f757f3fSDimitry Andric                cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
1315*5f757f3fSDimitry Andric                ? emitIntrinsicWithChainErrorMessage(
1316*5f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 2", DAG)
1317*5f757f3fSDimitry Andric                : SDValue();
1318*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vldrepl_w:
1319*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvldrepl_w:
1320*5f757f3fSDimitry Andric     return !isShiftedInt<10, 2>(
1321*5f757f3fSDimitry Andric                cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
1322*5f757f3fSDimitry Andric                ? emitIntrinsicWithChainErrorMessage(
1323*5f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 4", DAG)
1324*5f757f3fSDimitry Andric                : SDValue();
1325*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vldrepl_d:
1326*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvldrepl_d:
1327*5f757f3fSDimitry Andric     return !isShiftedInt<9, 3>(
1328*5f757f3fSDimitry Andric                cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
1329*5f757f3fSDimitry Andric                ? emitIntrinsicWithChainErrorMessage(
1330*5f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 8", DAG)
1331*5f757f3fSDimitry Andric                : SDValue();
1332bdd1243dSDimitry Andric   }
1333bdd1243dSDimitry Andric }
1334bdd1243dSDimitry Andric 
1335bdd1243dSDimitry Andric // Helper function that emits error message for intrinsics with void return
133606c3fb27SDimitry Andric // value and return the chain.
1337bdd1243dSDimitry Andric static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg,
1338bdd1243dSDimitry Andric                                          SelectionDAG &DAG) {
1339bdd1243dSDimitry Andric 
134006c3fb27SDimitry Andric   DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
1341bdd1243dSDimitry Andric   return Op.getOperand(0);
1342bdd1243dSDimitry Andric }
1343bdd1243dSDimitry Andric 
1344bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
1345bdd1243dSDimitry Andric                                                      SelectionDAG &DAG) const {
1346bdd1243dSDimitry Andric   SDLoc DL(Op);
1347bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
134806c3fb27SDimitry Andric   SDValue Chain = Op.getOperand(0);
1349bdd1243dSDimitry Andric   uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
1350bdd1243dSDimitry Andric   SDValue Op2 = Op.getOperand(2);
135106c3fb27SDimitry Andric   const StringRef ErrorMsgOOR = "argument out of range";
135206c3fb27SDimitry Andric   const StringRef ErrorMsgReqLA64 = "requires loongarch64";
135306c3fb27SDimitry Andric   const StringRef ErrorMsgReqLA32 = "requires loongarch32";
135406c3fb27SDimitry Andric   const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
1355bdd1243dSDimitry Andric 
1356bdd1243dSDimitry Andric   switch (IntrinsicEnum) {
1357bdd1243dSDimitry Andric   default:
1358bdd1243dSDimitry Andric     // TODO: Add more Intrinsics.
1359bdd1243dSDimitry Andric     return SDValue();
1360bdd1243dSDimitry Andric   case Intrinsic::loongarch_cacop_d:
1361bdd1243dSDimitry Andric   case Intrinsic::loongarch_cacop_w: {
136206c3fb27SDimitry Andric     if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit())
136306c3fb27SDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG);
136406c3fb27SDimitry Andric     if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit())
136506c3fb27SDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG);
1366bdd1243dSDimitry Andric     // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
1367bdd1243dSDimitry Andric     unsigned Imm1 = cast<ConstantSDNode>(Op2)->getZExtValue();
136806c3fb27SDimitry Andric     int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue();
136906c3fb27SDimitry Andric     if (!isUInt<5>(Imm1) || !isInt<12>(Imm2))
1370bdd1243dSDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
1371bdd1243dSDimitry Andric     return Op;
1372bdd1243dSDimitry Andric   }
1373bdd1243dSDimitry Andric   case Intrinsic::loongarch_dbar: {
1374bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
137506c3fb27SDimitry Andric     return !isUInt<15>(Imm)
137606c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
137706c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain,
1378bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
1379bdd1243dSDimitry Andric   }
1380bdd1243dSDimitry Andric   case Intrinsic::loongarch_ibar: {
1381bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
138206c3fb27SDimitry Andric     return !isUInt<15>(Imm)
138306c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
138406c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain,
1385bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
1386bdd1243dSDimitry Andric   }
1387bdd1243dSDimitry Andric   case Intrinsic::loongarch_break: {
1388bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
138906c3fb27SDimitry Andric     return !isUInt<15>(Imm)
139006c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
139106c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain,
1392bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
1393bdd1243dSDimitry Andric   }
1394bdd1243dSDimitry Andric   case Intrinsic::loongarch_movgr2fcsr: {
139506c3fb27SDimitry Andric     if (!Subtarget.hasBasicF())
139606c3fb27SDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG);
1397bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
139806c3fb27SDimitry Andric     return !isUInt<2>(Imm)
139906c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
140006c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain,
1401bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT),
140206c3fb27SDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT,
140306c3fb27SDimitry Andric                                          Op.getOperand(3)));
1404bdd1243dSDimitry Andric   }
1405bdd1243dSDimitry Andric   case Intrinsic::loongarch_syscall: {
1406bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
140706c3fb27SDimitry Andric     return !isUInt<15>(Imm)
140806c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
140906c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain,
1410bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
1411bdd1243dSDimitry Andric   }
1412bdd1243dSDimitry Andric #define IOCSRWR_CASE(NAME, NODE)                                               \
1413bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
1414bdd1243dSDimitry Andric     SDValue Op3 = Op.getOperand(3);                                            \
141506c3fb27SDimitry Andric     return Subtarget.is64Bit()                                                 \
141606c3fb27SDimitry Andric                ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain,        \
1417bdd1243dSDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),  \
141806c3fb27SDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3))  \
141906c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2,   \
142006c3fb27SDimitry Andric                              Op3);                                             \
1421bdd1243dSDimitry Andric   }
1422bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
1423bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
1424bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
1425bdd1243dSDimitry Andric #undef IOCSRWR_CASE
1426bdd1243dSDimitry Andric   case Intrinsic::loongarch_iocsrwr_d: {
142706c3fb27SDimitry Andric     return !Subtarget.is64Bit()
142806c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
142906c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain,
143006c3fb27SDimitry Andric                              Op2,
143106c3fb27SDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
143206c3fb27SDimitry Andric                                          Op.getOperand(3)));
1433bdd1243dSDimitry Andric   }
1434bdd1243dSDimitry Andric #define ASRT_LE_GT_CASE(NAME)                                                  \
1435bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
143606c3fb27SDimitry Andric     return !Subtarget.is64Bit()                                                \
143706c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)           \
143806c3fb27SDimitry Andric                : Op;                                                           \
1439bdd1243dSDimitry Andric   }
1440bdd1243dSDimitry Andric     ASRT_LE_GT_CASE(asrtle_d)
1441bdd1243dSDimitry Andric     ASRT_LE_GT_CASE(asrtgt_d)
1442bdd1243dSDimitry Andric #undef ASRT_LE_GT_CASE
1443bdd1243dSDimitry Andric   case Intrinsic::loongarch_ldpte_d: {
1444bdd1243dSDimitry Andric     unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
144506c3fb27SDimitry Andric     return !Subtarget.is64Bit()
144606c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
144706c3fb27SDimitry Andric            : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
144806c3fb27SDimitry Andric                              : Op;
1449bdd1243dSDimitry Andric   }
1450*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vst:
1451*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvst:
1452*5f757f3fSDimitry Andric     return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue())
1453*5f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1454*5f757f3fSDimitry Andric                : SDValue();
1455*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvstelm_b:
1456*5f757f3fSDimitry Andric     return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1457*5f757f3fSDimitry Andric             !isUInt<5>(cast<ConstantSDNode>(Op.getOperand(5))->getZExtValue()))
1458*5f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1459*5f757f3fSDimitry Andric                : SDValue();
1460*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vstelm_b:
1461*5f757f3fSDimitry Andric     return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1462*5f757f3fSDimitry Andric             !isUInt<4>(cast<ConstantSDNode>(Op.getOperand(5))->getZExtValue()))
1463*5f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1464*5f757f3fSDimitry Andric                : SDValue();
1465*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvstelm_h:
1466*5f757f3fSDimitry Andric     return (!isShiftedInt<8, 1>(
1467*5f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1468*5f757f3fSDimitry Andric             !isUInt<4>(cast<ConstantSDNode>(Op.getOperand(5))->getZExtValue()))
1469*5f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
1470*5f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 2", DAG)
1471*5f757f3fSDimitry Andric                : SDValue();
1472*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vstelm_h:
1473*5f757f3fSDimitry Andric     return (!isShiftedInt<8, 1>(
1474*5f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1475*5f757f3fSDimitry Andric             !isUInt<3>(cast<ConstantSDNode>(Op.getOperand(5))->getZExtValue()))
1476*5f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
1477*5f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 2", DAG)
1478*5f757f3fSDimitry Andric                : SDValue();
1479*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvstelm_w:
1480*5f757f3fSDimitry Andric     return (!isShiftedInt<8, 2>(
1481*5f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1482*5f757f3fSDimitry Andric             !isUInt<3>(cast<ConstantSDNode>(Op.getOperand(5))->getZExtValue()))
1483*5f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
1484*5f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 4", DAG)
1485*5f757f3fSDimitry Andric                : SDValue();
1486*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vstelm_w:
1487*5f757f3fSDimitry Andric     return (!isShiftedInt<8, 2>(
1488*5f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1489*5f757f3fSDimitry Andric             !isUInt<2>(cast<ConstantSDNode>(Op.getOperand(5))->getZExtValue()))
1490*5f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
1491*5f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 4", DAG)
1492*5f757f3fSDimitry Andric                : SDValue();
1493*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvstelm_d:
1494*5f757f3fSDimitry Andric     return (!isShiftedInt<8, 3>(
1495*5f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1496*5f757f3fSDimitry Andric             !isUInt<2>(cast<ConstantSDNode>(Op.getOperand(5))->getZExtValue()))
1497*5f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
1498*5f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 8", DAG)
1499*5f757f3fSDimitry Andric                : SDValue();
1500*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vstelm_d:
1501*5f757f3fSDimitry Andric     return (!isShiftedInt<8, 3>(
1502*5f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1503*5f757f3fSDimitry Andric             !isUInt<1>(cast<ConstantSDNode>(Op.getOperand(5))->getZExtValue()))
1504*5f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
1505*5f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 8", DAG)
1506*5f757f3fSDimitry Andric                : SDValue();
1507bdd1243dSDimitry Andric   }
1508753f127fSDimitry Andric }
1509753f127fSDimitry Andric 
151081ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
151181ad6265SDimitry Andric                                                      SelectionDAG &DAG) const {
151281ad6265SDimitry Andric   SDLoc DL(Op);
151381ad6265SDimitry Andric   SDValue Lo = Op.getOperand(0);
151481ad6265SDimitry Andric   SDValue Hi = Op.getOperand(1);
151581ad6265SDimitry Andric   SDValue Shamt = Op.getOperand(2);
151681ad6265SDimitry Andric   EVT VT = Lo.getValueType();
151781ad6265SDimitry Andric 
151881ad6265SDimitry Andric   // if Shamt-GRLen < 0: // Shamt < GRLen
151981ad6265SDimitry Andric   //   Lo = Lo << Shamt
152081ad6265SDimitry Andric   //   Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
152181ad6265SDimitry Andric   // else:
152281ad6265SDimitry Andric   //   Lo = 0
152381ad6265SDimitry Andric   //   Hi = Lo << (Shamt-GRLen)
152481ad6265SDimitry Andric 
152581ad6265SDimitry Andric   SDValue Zero = DAG.getConstant(0, DL, VT);
152681ad6265SDimitry Andric   SDValue One = DAG.getConstant(1, DL, VT);
152781ad6265SDimitry Andric   SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
152881ad6265SDimitry Andric   SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
152981ad6265SDimitry Andric   SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
153081ad6265SDimitry Andric   SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
153181ad6265SDimitry Andric 
153281ad6265SDimitry Andric   SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
153381ad6265SDimitry Andric   SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
153481ad6265SDimitry Andric   SDValue ShiftRightLo =
153581ad6265SDimitry Andric       DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
153681ad6265SDimitry Andric   SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
153781ad6265SDimitry Andric   SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
153881ad6265SDimitry Andric   SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
153981ad6265SDimitry Andric 
154081ad6265SDimitry Andric   SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
154181ad6265SDimitry Andric 
154281ad6265SDimitry Andric   Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
154381ad6265SDimitry Andric   Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
154481ad6265SDimitry Andric 
154581ad6265SDimitry Andric   SDValue Parts[2] = {Lo, Hi};
154681ad6265SDimitry Andric   return DAG.getMergeValues(Parts, DL);
154781ad6265SDimitry Andric }
154881ad6265SDimitry Andric 
154981ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
155081ad6265SDimitry Andric                                                       SelectionDAG &DAG,
155181ad6265SDimitry Andric                                                       bool IsSRA) const {
155281ad6265SDimitry Andric   SDLoc DL(Op);
155381ad6265SDimitry Andric   SDValue Lo = Op.getOperand(0);
155481ad6265SDimitry Andric   SDValue Hi = Op.getOperand(1);
155581ad6265SDimitry Andric   SDValue Shamt = Op.getOperand(2);
155681ad6265SDimitry Andric   EVT VT = Lo.getValueType();
155781ad6265SDimitry Andric 
155881ad6265SDimitry Andric   // SRA expansion:
155981ad6265SDimitry Andric   //   if Shamt-GRLen < 0: // Shamt < GRLen
156081ad6265SDimitry Andric   //     Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
156181ad6265SDimitry Andric   //     Hi = Hi >>s Shamt
156281ad6265SDimitry Andric   //   else:
156381ad6265SDimitry Andric   //     Lo = Hi >>s (Shamt-GRLen);
156481ad6265SDimitry Andric   //     Hi = Hi >>s (GRLen-1)
156581ad6265SDimitry Andric   //
156681ad6265SDimitry Andric   // SRL expansion:
156781ad6265SDimitry Andric   //   if Shamt-GRLen < 0: // Shamt < GRLen
156881ad6265SDimitry Andric   //     Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
156981ad6265SDimitry Andric   //     Hi = Hi >>u Shamt
157081ad6265SDimitry Andric   //   else:
157181ad6265SDimitry Andric   //     Lo = Hi >>u (Shamt-GRLen);
157281ad6265SDimitry Andric   //     Hi = 0;
157381ad6265SDimitry Andric 
157481ad6265SDimitry Andric   unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
157581ad6265SDimitry Andric 
157681ad6265SDimitry Andric   SDValue Zero = DAG.getConstant(0, DL, VT);
157781ad6265SDimitry Andric   SDValue One = DAG.getConstant(1, DL, VT);
157881ad6265SDimitry Andric   SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
157981ad6265SDimitry Andric   SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
158081ad6265SDimitry Andric   SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
158181ad6265SDimitry Andric   SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
158281ad6265SDimitry Andric 
158381ad6265SDimitry Andric   SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
158481ad6265SDimitry Andric   SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
158581ad6265SDimitry Andric   SDValue ShiftLeftHi =
158681ad6265SDimitry Andric       DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
158781ad6265SDimitry Andric   SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
158881ad6265SDimitry Andric   SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
158981ad6265SDimitry Andric   SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
159081ad6265SDimitry Andric   SDValue HiFalse =
159181ad6265SDimitry Andric       IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
159281ad6265SDimitry Andric 
159381ad6265SDimitry Andric   SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
159481ad6265SDimitry Andric 
159581ad6265SDimitry Andric   Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
159681ad6265SDimitry Andric   Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
159781ad6265SDimitry Andric 
159881ad6265SDimitry Andric   SDValue Parts[2] = {Lo, Hi};
159981ad6265SDimitry Andric   return DAG.getMergeValues(Parts, DL);
160081ad6265SDimitry Andric }
160181ad6265SDimitry Andric 
160281ad6265SDimitry Andric // Returns the opcode of the target-specific SDNode that implements the 32-bit
160381ad6265SDimitry Andric // form of the given Opcode.
160481ad6265SDimitry Andric static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode) {
160581ad6265SDimitry Andric   switch (Opcode) {
160681ad6265SDimitry Andric   default:
160781ad6265SDimitry Andric     llvm_unreachable("Unexpected opcode");
160881ad6265SDimitry Andric   case ISD::SHL:
160981ad6265SDimitry Andric     return LoongArchISD::SLL_W;
161081ad6265SDimitry Andric   case ISD::SRA:
161181ad6265SDimitry Andric     return LoongArchISD::SRA_W;
161281ad6265SDimitry Andric   case ISD::SRL:
161381ad6265SDimitry Andric     return LoongArchISD::SRL_W;
1614bdd1243dSDimitry Andric   case ISD::ROTR:
1615bdd1243dSDimitry Andric     return LoongArchISD::ROTR_W;
1616bdd1243dSDimitry Andric   case ISD::ROTL:
1617bdd1243dSDimitry Andric     return LoongArchISD::ROTL_W;
1618bdd1243dSDimitry Andric   case ISD::CTTZ:
1619bdd1243dSDimitry Andric     return LoongArchISD::CTZ_W;
1620bdd1243dSDimitry Andric   case ISD::CTLZ:
1621bdd1243dSDimitry Andric     return LoongArchISD::CLZ_W;
162281ad6265SDimitry Andric   }
162381ad6265SDimitry Andric }
162481ad6265SDimitry Andric 
162581ad6265SDimitry Andric // Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
162681ad6265SDimitry Andric // node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
162781ad6265SDimitry Andric // otherwise be promoted to i64, making it difficult to select the
162881ad6265SDimitry Andric // SLL_W/.../*W later one because the fact the operation was originally of
162981ad6265SDimitry Andric // type i8/i16/i32 is lost.
1630bdd1243dSDimitry Andric static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp,
163181ad6265SDimitry Andric                                    unsigned ExtOpc = ISD::ANY_EXTEND) {
163281ad6265SDimitry Andric   SDLoc DL(N);
163381ad6265SDimitry Andric   LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode());
1634bdd1243dSDimitry Andric   SDValue NewOp0, NewRes;
1635bdd1243dSDimitry Andric 
1636bdd1243dSDimitry Andric   switch (NumOp) {
1637bdd1243dSDimitry Andric   default:
1638bdd1243dSDimitry Andric     llvm_unreachable("Unexpected NumOp");
1639bdd1243dSDimitry Andric   case 1: {
1640bdd1243dSDimitry Andric     NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
1641bdd1243dSDimitry Andric     NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
1642bdd1243dSDimitry Andric     break;
1643bdd1243dSDimitry Andric   }
1644bdd1243dSDimitry Andric   case 2: {
1645bdd1243dSDimitry Andric     NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
164681ad6265SDimitry Andric     SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
1647bdd1243dSDimitry Andric     NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
1648bdd1243dSDimitry Andric     break;
1649bdd1243dSDimitry Andric   }
1650bdd1243dSDimitry Andric     // TODO:Handle more NumOp.
1651bdd1243dSDimitry Andric   }
1652bdd1243dSDimitry Andric 
1653bdd1243dSDimitry Andric   // ReplaceNodeResults requires we maintain the same type for the return
1654bdd1243dSDimitry Andric   // value.
165581ad6265SDimitry Andric   return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
165681ad6265SDimitry Andric }
165781ad6265SDimitry Andric 
1658*5f757f3fSDimitry Andric // Helper function that emits error message for intrinsics with/without chain
1659*5f757f3fSDimitry Andric // and return a UNDEF or and the chain as the results.
1660*5f757f3fSDimitry Andric static void emitErrorAndReplaceIntrinsicResults(
166106c3fb27SDimitry Andric     SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG,
1662*5f757f3fSDimitry Andric     StringRef ErrorMsg, bool WithChain = true) {
166306c3fb27SDimitry Andric   DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
166406c3fb27SDimitry Andric   Results.push_back(DAG.getUNDEF(N->getValueType(0)));
1665*5f757f3fSDimitry Andric   if (!WithChain)
1666*5f757f3fSDimitry Andric     return;
166706c3fb27SDimitry Andric   Results.push_back(N->getOperand(0));
166806c3fb27SDimitry Andric }
166906c3fb27SDimitry Andric 
1670*5f757f3fSDimitry Andric template <unsigned N>
1671*5f757f3fSDimitry Andric static void
1672*5f757f3fSDimitry Andric replaceVPICKVE2GRResults(SDNode *Node, SmallVectorImpl<SDValue> &Results,
1673*5f757f3fSDimitry Andric                          SelectionDAG &DAG, const LoongArchSubtarget &Subtarget,
1674*5f757f3fSDimitry Andric                          unsigned ResOp) {
1675*5f757f3fSDimitry Andric   const StringRef ErrorMsgOOR = "argument out of range";
1676*5f757f3fSDimitry Andric   unsigned Imm = cast<ConstantSDNode>(Node->getOperand(2))->getZExtValue();
1677*5f757f3fSDimitry Andric   if (!isUInt<N>(Imm)) {
1678*5f757f3fSDimitry Andric     emitErrorAndReplaceIntrinsicResults(Node, Results, DAG, ErrorMsgOOR,
1679*5f757f3fSDimitry Andric                                         /*WithChain=*/false);
1680*5f757f3fSDimitry Andric     return;
1681*5f757f3fSDimitry Andric   }
1682*5f757f3fSDimitry Andric   SDLoc DL(Node);
1683*5f757f3fSDimitry Andric   SDValue Vec = Node->getOperand(1);
1684*5f757f3fSDimitry Andric 
1685*5f757f3fSDimitry Andric   SDValue PickElt =
1686*5f757f3fSDimitry Andric       DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec,
1687*5f757f3fSDimitry Andric                   DAG.getConstant(Imm, DL, Subtarget.getGRLenVT()),
1688*5f757f3fSDimitry Andric                   DAG.getValueType(Vec.getValueType().getVectorElementType()));
1689*5f757f3fSDimitry Andric   Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, Node->getValueType(0),
1690*5f757f3fSDimitry Andric                                 PickElt.getValue(0)));
1691*5f757f3fSDimitry Andric }
1692*5f757f3fSDimitry Andric 
1693*5f757f3fSDimitry Andric static void replaceVecCondBranchResults(SDNode *N,
1694*5f757f3fSDimitry Andric                                         SmallVectorImpl<SDValue> &Results,
1695*5f757f3fSDimitry Andric                                         SelectionDAG &DAG,
1696*5f757f3fSDimitry Andric                                         const LoongArchSubtarget &Subtarget,
1697*5f757f3fSDimitry Andric                                         unsigned ResOp) {
1698*5f757f3fSDimitry Andric   SDLoc DL(N);
1699*5f757f3fSDimitry Andric   SDValue Vec = N->getOperand(1);
1700*5f757f3fSDimitry Andric 
1701*5f757f3fSDimitry Andric   SDValue CB = DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec);
1702*5f757f3fSDimitry Andric   Results.push_back(
1703*5f757f3fSDimitry Andric       DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), CB.getValue(0)));
1704*5f757f3fSDimitry Andric }
1705*5f757f3fSDimitry Andric 
1706*5f757f3fSDimitry Andric static void
1707*5f757f3fSDimitry Andric replaceINTRINSIC_WO_CHAINResults(SDNode *N, SmallVectorImpl<SDValue> &Results,
1708*5f757f3fSDimitry Andric                                  SelectionDAG &DAG,
1709*5f757f3fSDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
1710*5f757f3fSDimitry Andric   switch (N->getConstantOperandVal(0)) {
1711*5f757f3fSDimitry Andric   default:
1712*5f757f3fSDimitry Andric     llvm_unreachable("Unexpected Intrinsic.");
1713*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_b:
1714*5f757f3fSDimitry Andric     replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
1715*5f757f3fSDimitry Andric                                 LoongArchISD::VPICK_SEXT_ELT);
1716*5f757f3fSDimitry Andric     break;
1717*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_h:
1718*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve2gr_w:
1719*5f757f3fSDimitry Andric     replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
1720*5f757f3fSDimitry Andric                                 LoongArchISD::VPICK_SEXT_ELT);
1721*5f757f3fSDimitry Andric     break;
1722*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_w:
1723*5f757f3fSDimitry Andric     replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
1724*5f757f3fSDimitry Andric                                 LoongArchISD::VPICK_SEXT_ELT);
1725*5f757f3fSDimitry Andric     break;
1726*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_bu:
1727*5f757f3fSDimitry Andric     replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
1728*5f757f3fSDimitry Andric                                 LoongArchISD::VPICK_ZEXT_ELT);
1729*5f757f3fSDimitry Andric     break;
1730*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_hu:
1731*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
1732*5f757f3fSDimitry Andric     replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
1733*5f757f3fSDimitry Andric                                 LoongArchISD::VPICK_ZEXT_ELT);
1734*5f757f3fSDimitry Andric     break;
1735*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_wu:
1736*5f757f3fSDimitry Andric     replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
1737*5f757f3fSDimitry Andric                                 LoongArchISD::VPICK_ZEXT_ELT);
1738*5f757f3fSDimitry Andric     break;
1739*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bz_b:
1740*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bz_h:
1741*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bz_w:
1742*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bz_d:
1743*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbz_b:
1744*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbz_h:
1745*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbz_w:
1746*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbz_d:
1747*5f757f3fSDimitry Andric     replaceVecCondBranchResults(N, Results, DAG, Subtarget,
1748*5f757f3fSDimitry Andric                                 LoongArchISD::VALL_ZERO);
1749*5f757f3fSDimitry Andric     break;
1750*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bz_v:
1751*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbz_v:
1752*5f757f3fSDimitry Andric     replaceVecCondBranchResults(N, Results, DAG, Subtarget,
1753*5f757f3fSDimitry Andric                                 LoongArchISD::VANY_ZERO);
1754*5f757f3fSDimitry Andric     break;
1755*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bnz_b:
1756*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bnz_h:
1757*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bnz_w:
1758*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bnz_d:
1759*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbnz_b:
1760*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbnz_h:
1761*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbnz_w:
1762*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbnz_d:
1763*5f757f3fSDimitry Andric     replaceVecCondBranchResults(N, Results, DAG, Subtarget,
1764*5f757f3fSDimitry Andric                                 LoongArchISD::VALL_NONZERO);
1765*5f757f3fSDimitry Andric     break;
1766*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bnz_v:
1767*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbnz_v:
1768*5f757f3fSDimitry Andric     replaceVecCondBranchResults(N, Results, DAG, Subtarget,
1769*5f757f3fSDimitry Andric                                 LoongArchISD::VANY_NONZERO);
1770*5f757f3fSDimitry Andric     break;
1771*5f757f3fSDimitry Andric   }
1772*5f757f3fSDimitry Andric }
1773*5f757f3fSDimitry Andric 
177481ad6265SDimitry Andric void LoongArchTargetLowering::ReplaceNodeResults(
177581ad6265SDimitry Andric     SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
177681ad6265SDimitry Andric   SDLoc DL(N);
1777bdd1243dSDimitry Andric   EVT VT = N->getValueType(0);
177881ad6265SDimitry Andric   switch (N->getOpcode()) {
177981ad6265SDimitry Andric   default:
178081ad6265SDimitry Andric     llvm_unreachable("Don't know how to legalize this operation");
178181ad6265SDimitry Andric   case ISD::SHL:
178281ad6265SDimitry Andric   case ISD::SRA:
178381ad6265SDimitry Andric   case ISD::SRL:
1784bdd1243dSDimitry Andric   case ISD::ROTR:
1785bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
178681ad6265SDimitry Andric            "Unexpected custom legalisation");
178781ad6265SDimitry Andric     if (N->getOperand(1).getOpcode() != ISD::Constant) {
1788bdd1243dSDimitry Andric       Results.push_back(customLegalizeToWOp(N, DAG, 2));
1789bdd1243dSDimitry Andric       break;
1790bdd1243dSDimitry Andric     }
1791bdd1243dSDimitry Andric     break;
1792bdd1243dSDimitry Andric   case ISD::ROTL:
1793bdd1243dSDimitry Andric     ConstantSDNode *CN;
1794bdd1243dSDimitry Andric     if ((CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) {
1795bdd1243dSDimitry Andric       Results.push_back(customLegalizeToWOp(N, DAG, 2));
179681ad6265SDimitry Andric       break;
179781ad6265SDimitry Andric     }
179881ad6265SDimitry Andric     break;
1799753f127fSDimitry Andric   case ISD::FP_TO_SINT: {
1800bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1801753f127fSDimitry Andric            "Unexpected custom legalisation");
1802753f127fSDimitry Andric     SDValue Src = N->getOperand(0);
1803bdd1243dSDimitry Andric     EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
1804bdd1243dSDimitry Andric     if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
1805bdd1243dSDimitry Andric         TargetLowering::TypeSoftenFloat) {
1806bdd1243dSDimitry Andric       SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
1807bdd1243dSDimitry Andric       Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
1808bdd1243dSDimitry Andric       return;
1809bdd1243dSDimitry Andric     }
1810bdd1243dSDimitry Andric     // If the FP type needs to be softened, emit a library call using the 'si'
1811bdd1243dSDimitry Andric     // version. If we left it to default legalization we'd end up with 'di'.
1812bdd1243dSDimitry Andric     RTLIB::Libcall LC;
1813bdd1243dSDimitry Andric     LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
1814bdd1243dSDimitry Andric     MakeLibCallOptions CallOptions;
1815bdd1243dSDimitry Andric     EVT OpVT = Src.getValueType();
1816bdd1243dSDimitry Andric     CallOptions.setTypeListBeforeSoften(OpVT, VT, true);
1817bdd1243dSDimitry Andric     SDValue Chain = SDValue();
1818bdd1243dSDimitry Andric     SDValue Result;
1819bdd1243dSDimitry Andric     std::tie(Result, Chain) =
1820bdd1243dSDimitry Andric         makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
1821bdd1243dSDimitry Andric     Results.push_back(Result);
1822753f127fSDimitry Andric     break;
1823753f127fSDimitry Andric   }
1824753f127fSDimitry Andric   case ISD::BITCAST: {
1825753f127fSDimitry Andric     SDValue Src = N->getOperand(0);
1826753f127fSDimitry Andric     EVT SrcVT = Src.getValueType();
1827753f127fSDimitry Andric     if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
1828753f127fSDimitry Andric         Subtarget.hasBasicF()) {
1829753f127fSDimitry Andric       SDValue Dst =
1830753f127fSDimitry Andric           DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
1831753f127fSDimitry Andric       Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
1832753f127fSDimitry Andric     }
1833753f127fSDimitry Andric     break;
1834753f127fSDimitry Andric   }
1835753f127fSDimitry Andric   case ISD::FP_TO_UINT: {
1836bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1837753f127fSDimitry Andric            "Unexpected custom legalisation");
1838753f127fSDimitry Andric     auto &TLI = DAG.getTargetLoweringInfo();
1839753f127fSDimitry Andric     SDValue Tmp1, Tmp2;
1840753f127fSDimitry Andric     TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
1841753f127fSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
1842753f127fSDimitry Andric     break;
1843753f127fSDimitry Andric   }
1844bdd1243dSDimitry Andric   case ISD::BSWAP: {
1845bdd1243dSDimitry Andric     SDValue Src = N->getOperand(0);
1846bdd1243dSDimitry Andric     assert((VT == MVT::i16 || VT == MVT::i32) &&
1847bdd1243dSDimitry Andric            "Unexpected custom legalization");
1848bdd1243dSDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
1849bdd1243dSDimitry Andric     SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1850bdd1243dSDimitry Andric     SDValue Tmp;
1851bdd1243dSDimitry Andric     switch (VT.getSizeInBits()) {
1852bdd1243dSDimitry Andric     default:
1853bdd1243dSDimitry Andric       llvm_unreachable("Unexpected operand width");
1854bdd1243dSDimitry Andric     case 16:
1855bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
1856bdd1243dSDimitry Andric       break;
1857bdd1243dSDimitry Andric     case 32:
1858bdd1243dSDimitry Andric       // Only LA64 will get to here due to the size mismatch between VT and
1859bdd1243dSDimitry Andric       // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
1860bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
1861bdd1243dSDimitry Andric       break;
1862bdd1243dSDimitry Andric     }
1863bdd1243dSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
1864bdd1243dSDimitry Andric     break;
1865bdd1243dSDimitry Andric   }
1866bdd1243dSDimitry Andric   case ISD::BITREVERSE: {
1867bdd1243dSDimitry Andric     SDValue Src = N->getOperand(0);
1868bdd1243dSDimitry Andric     assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
1869bdd1243dSDimitry Andric            "Unexpected custom legalization");
1870bdd1243dSDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
1871bdd1243dSDimitry Andric     SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1872bdd1243dSDimitry Andric     SDValue Tmp;
1873bdd1243dSDimitry Andric     switch (VT.getSizeInBits()) {
1874bdd1243dSDimitry Andric     default:
1875bdd1243dSDimitry Andric       llvm_unreachable("Unexpected operand width");
1876bdd1243dSDimitry Andric     case 8:
1877bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
1878bdd1243dSDimitry Andric       break;
1879bdd1243dSDimitry Andric     case 32:
1880bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
1881bdd1243dSDimitry Andric       break;
1882bdd1243dSDimitry Andric     }
1883bdd1243dSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
1884bdd1243dSDimitry Andric     break;
1885bdd1243dSDimitry Andric   }
1886bdd1243dSDimitry Andric   case ISD::CTLZ:
1887bdd1243dSDimitry Andric   case ISD::CTTZ: {
1888bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1889bdd1243dSDimitry Andric            "Unexpected custom legalisation");
1890bdd1243dSDimitry Andric     Results.push_back(customLegalizeToWOp(N, DAG, 1));
1891bdd1243dSDimitry Andric     break;
1892bdd1243dSDimitry Andric   }
1893bdd1243dSDimitry Andric   case ISD::INTRINSIC_W_CHAIN: {
189406c3fb27SDimitry Andric     SDValue Chain = N->getOperand(0);
1895bdd1243dSDimitry Andric     SDValue Op2 = N->getOperand(2);
189606c3fb27SDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
189706c3fb27SDimitry Andric     const StringRef ErrorMsgOOR = "argument out of range";
189806c3fb27SDimitry Andric     const StringRef ErrorMsgReqLA64 = "requires loongarch64";
189906c3fb27SDimitry Andric     const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
1900bdd1243dSDimitry Andric 
190106c3fb27SDimitry Andric     switch (N->getConstantOperandVal(1)) {
1902bdd1243dSDimitry Andric     default:
1903bdd1243dSDimitry Andric       llvm_unreachable("Unexpected Intrinsic.");
190406c3fb27SDimitry Andric     case Intrinsic::loongarch_movfcsr2gr: {
190506c3fb27SDimitry Andric       if (!Subtarget.hasBasicF()) {
1906*5f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqF);
190706c3fb27SDimitry Andric         return;
190806c3fb27SDimitry Andric       }
190906c3fb27SDimitry Andric       unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
191006c3fb27SDimitry Andric       if (!isUInt<2>(Imm)) {
1911*5f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
191206c3fb27SDimitry Andric         return;
191306c3fb27SDimitry Andric       }
191406c3fb27SDimitry Andric       SDValue MOVFCSR2GRResults = DAG.getNode(
191506c3fb27SDimitry Andric           LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other},
191606c3fb27SDimitry Andric           {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
191706c3fb27SDimitry Andric       Results.push_back(
191806c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0)));
191906c3fb27SDimitry Andric       Results.push_back(MOVFCSR2GRResults.getValue(1));
192006c3fb27SDimitry Andric       break;
192106c3fb27SDimitry Andric     }
1922bdd1243dSDimitry Andric #define CRC_CASE_EXT_BINARYOP(NAME, NODE)                                      \
1923bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
192406c3fb27SDimitry Andric     SDValue NODE = DAG.getNode(                                                \
192506c3fb27SDimitry Andric         LoongArchISD::NODE, DL, {MVT::i64, MVT::Other},                        \
192606c3fb27SDimitry Andric         {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),               \
192706c3fb27SDimitry Andric          DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))});       \
192806c3fb27SDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0)));   \
192906c3fb27SDimitry Andric     Results.push_back(NODE.getValue(1));                                       \
1930bdd1243dSDimitry Andric     break;                                                                     \
1931bdd1243dSDimitry Andric   }
1932bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
1933bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
1934bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
1935bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
1936bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
1937bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
1938bdd1243dSDimitry Andric #undef CRC_CASE_EXT_BINARYOP
1939bdd1243dSDimitry Andric 
1940bdd1243dSDimitry Andric #define CRC_CASE_EXT_UNARYOP(NAME, NODE)                                       \
1941bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
194206c3fb27SDimitry Andric     SDValue NODE = DAG.getNode(                                                \
194306c3fb27SDimitry Andric         LoongArchISD::NODE, DL, {MVT::i64, MVT::Other},                        \
194406c3fb27SDimitry Andric         {Chain, Op2,                                                           \
194506c3fb27SDimitry Andric          DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))});       \
194606c3fb27SDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0)));   \
194706c3fb27SDimitry Andric     Results.push_back(NODE.getValue(1));                                       \
1948bdd1243dSDimitry Andric     break;                                                                     \
1949bdd1243dSDimitry Andric   }
1950bdd1243dSDimitry Andric       CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
1951bdd1243dSDimitry Andric       CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
1952bdd1243dSDimitry Andric #undef CRC_CASE_EXT_UNARYOP
1953bdd1243dSDimitry Andric #define CSR_CASE(ID)                                                           \
1954bdd1243dSDimitry Andric   case Intrinsic::loongarch_##ID: {                                            \
195506c3fb27SDimitry Andric     if (!Subtarget.is64Bit())                                                  \
1956*5f757f3fSDimitry Andric       emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64);   \
1957bdd1243dSDimitry Andric     break;                                                                     \
1958bdd1243dSDimitry Andric   }
1959bdd1243dSDimitry Andric       CSR_CASE(csrrd_d);
1960bdd1243dSDimitry Andric       CSR_CASE(csrwr_d);
1961bdd1243dSDimitry Andric       CSR_CASE(csrxchg_d);
1962bdd1243dSDimitry Andric       CSR_CASE(iocsrrd_d);
1963bdd1243dSDimitry Andric #undef CSR_CASE
1964bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrrd_w: {
1965bdd1243dSDimitry Andric       unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
1966bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
1967*5f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
196806c3fb27SDimitry Andric         return;
1969bdd1243dSDimitry Andric       }
197006c3fb27SDimitry Andric       SDValue CSRRDResults =
197106c3fb27SDimitry Andric           DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
197206c3fb27SDimitry Andric                       {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
1973bdd1243dSDimitry Andric       Results.push_back(
197406c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0)));
197506c3fb27SDimitry Andric       Results.push_back(CSRRDResults.getValue(1));
1976bdd1243dSDimitry Andric       break;
1977bdd1243dSDimitry Andric     }
1978bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrwr_w: {
1979bdd1243dSDimitry Andric       unsigned Imm = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue();
1980bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
1981*5f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
198206c3fb27SDimitry Andric         return;
1983bdd1243dSDimitry Andric       }
198406c3fb27SDimitry Andric       SDValue CSRWRResults =
198506c3fb27SDimitry Andric           DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
198606c3fb27SDimitry Andric                       {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
198706c3fb27SDimitry Andric                        DAG.getConstant(Imm, DL, GRLenVT)});
198806c3fb27SDimitry Andric       Results.push_back(
198906c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0)));
199006c3fb27SDimitry Andric       Results.push_back(CSRWRResults.getValue(1));
1991bdd1243dSDimitry Andric       break;
1992bdd1243dSDimitry Andric     }
1993bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrxchg_w: {
1994bdd1243dSDimitry Andric       unsigned Imm = cast<ConstantSDNode>(N->getOperand(4))->getZExtValue();
1995bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
1996*5f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
199706c3fb27SDimitry Andric         return;
1998bdd1243dSDimitry Andric       }
199906c3fb27SDimitry Andric       SDValue CSRXCHGResults = DAG.getNode(
200006c3fb27SDimitry Andric           LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
200106c3fb27SDimitry Andric           {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
2002bdd1243dSDimitry Andric            DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
200306c3fb27SDimitry Andric            DAG.getConstant(Imm, DL, GRLenVT)});
200406c3fb27SDimitry Andric       Results.push_back(
200506c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0)));
200606c3fb27SDimitry Andric       Results.push_back(CSRXCHGResults.getValue(1));
2007bdd1243dSDimitry Andric       break;
2008bdd1243dSDimitry Andric     }
2009bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE)                                               \
2010bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
201106c3fb27SDimitry Andric     SDValue IOCSRRDResults =                                                   \
201206c3fb27SDimitry Andric         DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other},            \
201306c3fb27SDimitry Andric                     {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \
201406c3fb27SDimitry Andric     Results.push_back(                                                         \
201506c3fb27SDimitry Andric         DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0)));       \
201606c3fb27SDimitry Andric     Results.push_back(IOCSRRDResults.getValue(1));                             \
2017bdd1243dSDimitry Andric     break;                                                                     \
2018bdd1243dSDimitry Andric   }
2019bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
2020bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
2021bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
2022bdd1243dSDimitry Andric #undef IOCSRRD_CASE
2023bdd1243dSDimitry Andric     case Intrinsic::loongarch_cpucfg: {
202406c3fb27SDimitry Andric       SDValue CPUCFGResults =
202506c3fb27SDimitry Andric           DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
202606c3fb27SDimitry Andric                       {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)});
202706c3fb27SDimitry Andric       Results.push_back(
202806c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0)));
202906c3fb27SDimitry Andric       Results.push_back(CPUCFGResults.getValue(1));
2030bdd1243dSDimitry Andric       break;
2031bdd1243dSDimitry Andric     }
2032bdd1243dSDimitry Andric     case Intrinsic::loongarch_lddir_d: {
2033bdd1243dSDimitry Andric       if (!Subtarget.is64Bit()) {
2034*5f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64);
203506c3fb27SDimitry Andric         return;
2036bdd1243dSDimitry Andric       }
2037bdd1243dSDimitry Andric       break;
2038bdd1243dSDimitry Andric     }
2039bdd1243dSDimitry Andric     }
2040bdd1243dSDimitry Andric     break;
2041bdd1243dSDimitry Andric   }
2042bdd1243dSDimitry Andric   case ISD::READ_REGISTER: {
2043bdd1243dSDimitry Andric     if (Subtarget.is64Bit())
2044bdd1243dSDimitry Andric       DAG.getContext()->emitError(
2045bdd1243dSDimitry Andric           "On LA64, only 64-bit registers can be read.");
2046bdd1243dSDimitry Andric     else
2047bdd1243dSDimitry Andric       DAG.getContext()->emitError(
2048bdd1243dSDimitry Andric           "On LA32, only 32-bit registers can be read.");
2049bdd1243dSDimitry Andric     Results.push_back(DAG.getUNDEF(VT));
2050bdd1243dSDimitry Andric     Results.push_back(N->getOperand(0));
2051bdd1243dSDimitry Andric     break;
2052bdd1243dSDimitry Andric   }
2053*5f757f3fSDimitry Andric   case ISD::INTRINSIC_WO_CHAIN: {
2054*5f757f3fSDimitry Andric     replaceINTRINSIC_WO_CHAINResults(N, Results, DAG, Subtarget);
2055*5f757f3fSDimitry Andric     break;
2056*5f757f3fSDimitry Andric   }
205781ad6265SDimitry Andric   }
205881ad6265SDimitry Andric }
205981ad6265SDimitry Andric 
206081ad6265SDimitry Andric static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG,
206181ad6265SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
206281ad6265SDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
206381ad6265SDimitry Andric   if (DCI.isBeforeLegalizeOps())
206481ad6265SDimitry Andric     return SDValue();
206581ad6265SDimitry Andric 
206681ad6265SDimitry Andric   SDValue FirstOperand = N->getOperand(0);
206781ad6265SDimitry Andric   SDValue SecondOperand = N->getOperand(1);
206881ad6265SDimitry Andric   unsigned FirstOperandOpc = FirstOperand.getOpcode();
206981ad6265SDimitry Andric   EVT ValTy = N->getValueType(0);
207081ad6265SDimitry Andric   SDLoc DL(N);
207181ad6265SDimitry Andric   uint64_t lsb, msb;
207281ad6265SDimitry Andric   unsigned SMIdx, SMLen;
207381ad6265SDimitry Andric   ConstantSDNode *CN;
207481ad6265SDimitry Andric   SDValue NewOperand;
207581ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
207681ad6265SDimitry Andric 
207781ad6265SDimitry Andric   // Op's second operand must be a shifted mask.
207881ad6265SDimitry Andric   if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
207981ad6265SDimitry Andric       !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
208081ad6265SDimitry Andric     return SDValue();
208181ad6265SDimitry Andric 
208281ad6265SDimitry Andric   if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
208381ad6265SDimitry Andric     // Pattern match BSTRPICK.
208481ad6265SDimitry Andric     //  $dst = and ((sra or srl) $src , lsb), (2**len - 1)
208581ad6265SDimitry Andric     //  => BSTRPICK $dst, $src, msb, lsb
208681ad6265SDimitry Andric     //  where msb = lsb + len - 1
208781ad6265SDimitry Andric 
208881ad6265SDimitry Andric     // The second operand of the shift must be an immediate.
208981ad6265SDimitry Andric     if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
209081ad6265SDimitry Andric       return SDValue();
209181ad6265SDimitry Andric 
209281ad6265SDimitry Andric     lsb = CN->getZExtValue();
209381ad6265SDimitry Andric 
209481ad6265SDimitry Andric     // Return if the shifted mask does not start at bit 0 or the sum of its
209581ad6265SDimitry Andric     // length and lsb exceeds the word's size.
209681ad6265SDimitry Andric     if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
209781ad6265SDimitry Andric       return SDValue();
209881ad6265SDimitry Andric 
209981ad6265SDimitry Andric     NewOperand = FirstOperand.getOperand(0);
210081ad6265SDimitry Andric   } else {
210181ad6265SDimitry Andric     // Pattern match BSTRPICK.
210281ad6265SDimitry Andric     //  $dst = and $src, (2**len- 1) , if len > 12
210381ad6265SDimitry Andric     //  => BSTRPICK $dst, $src, msb, lsb
210481ad6265SDimitry Andric     //  where lsb = 0 and msb = len - 1
210581ad6265SDimitry Andric 
210681ad6265SDimitry Andric     // If the mask is <= 0xfff, andi can be used instead.
210781ad6265SDimitry Andric     if (CN->getZExtValue() <= 0xfff)
210881ad6265SDimitry Andric       return SDValue();
210981ad6265SDimitry Andric 
211006c3fb27SDimitry Andric     // Return if the MSB exceeds.
211106c3fb27SDimitry Andric     if (SMIdx + SMLen > ValTy.getSizeInBits())
211281ad6265SDimitry Andric       return SDValue();
211381ad6265SDimitry Andric 
211406c3fb27SDimitry Andric     if (SMIdx > 0) {
211506c3fb27SDimitry Andric       // Omit if the constant has more than 2 uses. This a conservative
211606c3fb27SDimitry Andric       // decision. Whether it is a win depends on the HW microarchitecture.
211706c3fb27SDimitry Andric       // However it should always be better for 1 and 2 uses.
211806c3fb27SDimitry Andric       if (CN->use_size() > 2)
211906c3fb27SDimitry Andric         return SDValue();
212006c3fb27SDimitry Andric       // Return if the constant can be composed by a single LU12I.W.
212106c3fb27SDimitry Andric       if ((CN->getZExtValue() & 0xfff) == 0)
212206c3fb27SDimitry Andric         return SDValue();
212306c3fb27SDimitry Andric       // Return if the constand can be composed by a single ADDI with
212406c3fb27SDimitry Andric       // the zero register.
212506c3fb27SDimitry Andric       if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
212606c3fb27SDimitry Andric         return SDValue();
212706c3fb27SDimitry Andric     }
212806c3fb27SDimitry Andric 
212906c3fb27SDimitry Andric     lsb = SMIdx;
213081ad6265SDimitry Andric     NewOperand = FirstOperand;
213181ad6265SDimitry Andric   }
213206c3fb27SDimitry Andric 
213381ad6265SDimitry Andric   msb = lsb + SMLen - 1;
213406c3fb27SDimitry Andric   SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
213581ad6265SDimitry Andric                             DAG.getConstant(msb, DL, GRLenVT),
213681ad6265SDimitry Andric                             DAG.getConstant(lsb, DL, GRLenVT));
213706c3fb27SDimitry Andric   if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
213806c3fb27SDimitry Andric     return NR0;
213906c3fb27SDimitry Andric   // Try to optimize to
214006c3fb27SDimitry Andric   //   bstrpick $Rd, $Rs, msb, lsb
214106c3fb27SDimitry Andric   //   slli     $Rd, $Rd, lsb
214206c3fb27SDimitry Andric   return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
214306c3fb27SDimitry Andric                      DAG.getConstant(lsb, DL, GRLenVT));
214481ad6265SDimitry Andric }
214581ad6265SDimitry Andric 
214681ad6265SDimitry Andric static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG,
214781ad6265SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
214881ad6265SDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
214981ad6265SDimitry Andric   if (DCI.isBeforeLegalizeOps())
215081ad6265SDimitry Andric     return SDValue();
215181ad6265SDimitry Andric 
215281ad6265SDimitry Andric   // $dst = srl (and $src, Mask), Shamt
215381ad6265SDimitry Andric   // =>
215481ad6265SDimitry Andric   // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
215581ad6265SDimitry Andric   // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
215681ad6265SDimitry Andric   //
215781ad6265SDimitry Andric 
215881ad6265SDimitry Andric   SDValue FirstOperand = N->getOperand(0);
215981ad6265SDimitry Andric   ConstantSDNode *CN;
216081ad6265SDimitry Andric   EVT ValTy = N->getValueType(0);
216181ad6265SDimitry Andric   SDLoc DL(N);
216281ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
216381ad6265SDimitry Andric   unsigned MaskIdx, MaskLen;
216481ad6265SDimitry Andric   uint64_t Shamt;
216581ad6265SDimitry Andric 
216681ad6265SDimitry Andric   // The first operand must be an AND and the second operand of the AND must be
216781ad6265SDimitry Andric   // a shifted mask.
216881ad6265SDimitry Andric   if (FirstOperand.getOpcode() != ISD::AND ||
216981ad6265SDimitry Andric       !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
217081ad6265SDimitry Andric       !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
217181ad6265SDimitry Andric     return SDValue();
217281ad6265SDimitry Andric 
217381ad6265SDimitry Andric   // The second operand (shift amount) must be an immediate.
217481ad6265SDimitry Andric   if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
217581ad6265SDimitry Andric     return SDValue();
217681ad6265SDimitry Andric 
217781ad6265SDimitry Andric   Shamt = CN->getZExtValue();
217881ad6265SDimitry Andric   if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
217981ad6265SDimitry Andric     return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
218081ad6265SDimitry Andric                        FirstOperand->getOperand(0),
218181ad6265SDimitry Andric                        DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
218281ad6265SDimitry Andric                        DAG.getConstant(Shamt, DL, GRLenVT));
218381ad6265SDimitry Andric 
218481ad6265SDimitry Andric   return SDValue();
218581ad6265SDimitry Andric }
218681ad6265SDimitry Andric 
2187753f127fSDimitry Andric static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
2188753f127fSDimitry Andric                                 TargetLowering::DAGCombinerInfo &DCI,
2189753f127fSDimitry Andric                                 const LoongArchSubtarget &Subtarget) {
2190753f127fSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
2191753f127fSDimitry Andric   EVT ValTy = N->getValueType(0);
2192753f127fSDimitry Andric   SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
2193753f127fSDimitry Andric   ConstantSDNode *CN0, *CN1;
2194753f127fSDimitry Andric   SDLoc DL(N);
2195753f127fSDimitry Andric   unsigned ValBits = ValTy.getSizeInBits();
2196753f127fSDimitry Andric   unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
2197753f127fSDimitry Andric   unsigned Shamt;
2198753f127fSDimitry Andric   bool SwapAndRetried = false;
2199753f127fSDimitry Andric 
2200753f127fSDimitry Andric   if (DCI.isBeforeLegalizeOps())
2201753f127fSDimitry Andric     return SDValue();
2202753f127fSDimitry Andric 
2203753f127fSDimitry Andric   if (ValBits != 32 && ValBits != 64)
2204753f127fSDimitry Andric     return SDValue();
2205753f127fSDimitry Andric 
2206753f127fSDimitry Andric Retry:
2207753f127fSDimitry Andric   // 1st pattern to match BSTRINS:
2208753f127fSDimitry Andric   //  R = or (and X, mask0), (and (shl Y, lsb), mask1)
2209753f127fSDimitry Andric   //  where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
2210753f127fSDimitry Andric   //  =>
2211753f127fSDimitry Andric   //  R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
2212753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
2213753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
2214753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
2215753f127fSDimitry Andric       N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
2216753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2217753f127fSDimitry Andric       isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
2218753f127fSDimitry Andric       MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
2219753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
2220753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
2221753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
2222753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
2223753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
2224753f127fSDimitry Andric                        N1.getOperand(0).getOperand(0),
2225753f127fSDimitry Andric                        DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
2226753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
2227753f127fSDimitry Andric   }
2228753f127fSDimitry Andric 
2229753f127fSDimitry Andric   // 2nd pattern to match BSTRINS:
2230753f127fSDimitry Andric   //  R = or (and X, mask0), (shl (and Y, mask1), lsb)
2231753f127fSDimitry Andric   //  where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
2232753f127fSDimitry Andric   //  =>
2233753f127fSDimitry Andric   //  R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
2234753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
2235753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
2236753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
2237753f127fSDimitry Andric       N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
2238753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2239753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
2240753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
2241753f127fSDimitry Andric       isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
2242753f127fSDimitry Andric       MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
2243753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
2244753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
2245753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
2246753f127fSDimitry Andric                        N1.getOperand(0).getOperand(0),
2247753f127fSDimitry Andric                        DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
2248753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
2249753f127fSDimitry Andric   }
2250753f127fSDimitry Andric 
2251753f127fSDimitry Andric   // 3rd pattern to match BSTRINS:
2252753f127fSDimitry Andric   //  R = or (and X, mask0), (and Y, mask1)
2253753f127fSDimitry Andric   //  where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
2254753f127fSDimitry Andric   //  =>
2255753f127fSDimitry Andric   //  R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
2256753f127fSDimitry Andric   //  where msb = lsb + size - 1
2257753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
2258753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
2259753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
2260753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= 64) &&
2261753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
2262753f127fSDimitry Andric       (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
2263753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
2264753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
2265753f127fSDimitry Andric                        DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
2266753f127fSDimitry Andric                                    DAG.getConstant(MaskIdx0, DL, GRLenVT)),
2267753f127fSDimitry Andric                        DAG.getConstant(ValBits == 32
2268753f127fSDimitry Andric                                            ? (MaskIdx0 + (MaskLen0 & 31) - 1)
2269753f127fSDimitry Andric                                            : (MaskIdx0 + MaskLen0 - 1),
2270753f127fSDimitry Andric                                        DL, GRLenVT),
2271753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
2272753f127fSDimitry Andric   }
2273753f127fSDimitry Andric 
2274753f127fSDimitry Andric   // 4th pattern to match BSTRINS:
2275753f127fSDimitry Andric   //  R = or (and X, mask), (shl Y, shamt)
2276753f127fSDimitry Andric   //  where mask = (2**shamt - 1)
2277753f127fSDimitry Andric   //  =>
2278753f127fSDimitry Andric   //  R = BSTRINS X, Y, ValBits - 1, shamt
2279753f127fSDimitry Andric   //  where ValBits = 32 or 64
2280753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
2281753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
2282753f127fSDimitry Andric       isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
2283753f127fSDimitry Andric       MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2284753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskLen0 &&
2285753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
2286753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
2287753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
2288753f127fSDimitry Andric                        N1.getOperand(0),
2289753f127fSDimitry Andric                        DAG.getConstant((ValBits - 1), DL, GRLenVT),
2290753f127fSDimitry Andric                        DAG.getConstant(Shamt, DL, GRLenVT));
2291753f127fSDimitry Andric   }
2292753f127fSDimitry Andric 
2293753f127fSDimitry Andric   // 5th pattern to match BSTRINS:
2294753f127fSDimitry Andric   //  R = or (and X, mask), const
2295753f127fSDimitry Andric   //  where ~mask = (2**size - 1) << lsb, mask & const = 0
2296753f127fSDimitry Andric   //  =>
2297753f127fSDimitry Andric   //  R = BSTRINS X, (const >> lsb), msb, lsb
2298753f127fSDimitry Andric   //  where msb = lsb + size - 1
2299753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
2300753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
2301753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
2302753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
2303753f127fSDimitry Andric       (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
2304753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
2305753f127fSDimitry Andric     return DAG.getNode(
2306753f127fSDimitry Andric         LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
2307753f127fSDimitry Andric         DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
2308753f127fSDimitry Andric         DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
2309753f127fSDimitry Andric         DAG.getConstant(MaskIdx0, DL, GRLenVT));
2310753f127fSDimitry Andric   }
2311753f127fSDimitry Andric 
2312753f127fSDimitry Andric   // 6th pattern.
2313753f127fSDimitry Andric   // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
2314753f127fSDimitry Andric   // by the incoming bits are known to be zero.
2315753f127fSDimitry Andric   // =>
2316753f127fSDimitry Andric   // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
2317753f127fSDimitry Andric   //
2318753f127fSDimitry Andric   // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
2319753f127fSDimitry Andric   // pattern is more common than the 1st. So we put the 1st before the 6th in
2320753f127fSDimitry Andric   // order to match as many nodes as possible.
2321753f127fSDimitry Andric   ConstantSDNode *CNMask, *CNShamt;
2322753f127fSDimitry Andric   unsigned MaskIdx, MaskLen;
2323753f127fSDimitry Andric   if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
2324753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
2325753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
2326753f127fSDimitry Andric       MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2327753f127fSDimitry Andric       CNShamt->getZExtValue() + MaskLen <= ValBits) {
2328753f127fSDimitry Andric     Shamt = CNShamt->getZExtValue();
2329753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
2330753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
2331753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
2332753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
2333753f127fSDimitry Andric                          N1.getOperand(0).getOperand(0),
2334753f127fSDimitry Andric                          DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
2335753f127fSDimitry Andric                          DAG.getConstant(Shamt, DL, GRLenVT));
2336753f127fSDimitry Andric     }
2337753f127fSDimitry Andric   }
2338753f127fSDimitry Andric 
2339753f127fSDimitry Andric   // 7th pattern.
2340753f127fSDimitry Andric   // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
2341753f127fSDimitry Andric   // overwritten by the incoming bits are known to be zero.
2342753f127fSDimitry Andric   // =>
2343753f127fSDimitry Andric   // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
2344753f127fSDimitry Andric   //
2345753f127fSDimitry Andric   // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
2346753f127fSDimitry Andric   // before the 7th in order to match as many nodes as possible.
2347753f127fSDimitry Andric   if (N1.getOpcode() == ISD::AND &&
2348753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2349753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
2350753f127fSDimitry Andric       N1.getOperand(0).getOpcode() == ISD::SHL &&
2351753f127fSDimitry Andric       (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
2352753f127fSDimitry Andric       CNShamt->getZExtValue() == MaskIdx) {
2353753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue());
2354753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
2355753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
2356753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
2357753f127fSDimitry Andric                          N1.getOperand(0).getOperand(0),
2358753f127fSDimitry Andric                          DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
2359753f127fSDimitry Andric                          DAG.getConstant(MaskIdx, DL, GRLenVT));
2360753f127fSDimitry Andric     }
2361753f127fSDimitry Andric   }
2362753f127fSDimitry Andric 
2363753f127fSDimitry Andric   // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
2364753f127fSDimitry Andric   if (!SwapAndRetried) {
2365753f127fSDimitry Andric     std::swap(N0, N1);
2366753f127fSDimitry Andric     SwapAndRetried = true;
2367753f127fSDimitry Andric     goto Retry;
2368753f127fSDimitry Andric   }
2369753f127fSDimitry Andric 
2370753f127fSDimitry Andric   SwapAndRetried = false;
2371753f127fSDimitry Andric Retry2:
2372753f127fSDimitry Andric   // 8th pattern.
2373753f127fSDimitry Andric   // a = b | (c & shifted_mask), where all positions in b to be overwritten by
2374753f127fSDimitry Andric   // the incoming bits are known to be zero.
2375753f127fSDimitry Andric   // =>
2376753f127fSDimitry Andric   // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
2377753f127fSDimitry Andric   //
2378753f127fSDimitry Andric   // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
2379753f127fSDimitry Andric   // we put it here in order to match as many nodes as possible or generate less
2380753f127fSDimitry Andric   // instructions.
2381753f127fSDimitry Andric   if (N1.getOpcode() == ISD::AND &&
2382753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2383753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
2384753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue());
2385753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
2386753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
2387753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
2388753f127fSDimitry Andric                          DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
2389753f127fSDimitry Andric                                      N1->getOperand(0),
2390753f127fSDimitry Andric                                      DAG.getConstant(MaskIdx, DL, GRLenVT)),
2391753f127fSDimitry Andric                          DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
2392753f127fSDimitry Andric                          DAG.getConstant(MaskIdx, DL, GRLenVT));
2393753f127fSDimitry Andric     }
2394753f127fSDimitry Andric   }
2395753f127fSDimitry Andric   // Swap N0/N1 and retry.
2396753f127fSDimitry Andric   if (!SwapAndRetried) {
2397753f127fSDimitry Andric     std::swap(N0, N1);
2398753f127fSDimitry Andric     SwapAndRetried = true;
2399753f127fSDimitry Andric     goto Retry2;
2400753f127fSDimitry Andric   }
2401753f127fSDimitry Andric 
2402753f127fSDimitry Andric   return SDValue();
2403753f127fSDimitry Andric }
2404753f127fSDimitry Andric 
2405bdd1243dSDimitry Andric // Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
2406bdd1243dSDimitry Andric static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG,
2407bdd1243dSDimitry Andric                                       TargetLowering::DAGCombinerInfo &DCI,
2408bdd1243dSDimitry Andric                                       const LoongArchSubtarget &Subtarget) {
2409bdd1243dSDimitry Andric   if (DCI.isBeforeLegalizeOps())
2410bdd1243dSDimitry Andric     return SDValue();
2411bdd1243dSDimitry Andric 
2412bdd1243dSDimitry Andric   SDValue Src = N->getOperand(0);
2413bdd1243dSDimitry Andric   if (Src.getOpcode() != LoongArchISD::REVB_2W)
2414bdd1243dSDimitry Andric     return SDValue();
2415bdd1243dSDimitry Andric 
2416bdd1243dSDimitry Andric   return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
2417bdd1243dSDimitry Andric                      Src.getOperand(0));
2418bdd1243dSDimitry Andric }
2419bdd1243dSDimitry Andric 
2420*5f757f3fSDimitry Andric template <unsigned N>
2421*5f757f3fSDimitry Andric static SDValue legalizeIntrinsicImmArg(SDNode *Node, unsigned ImmOp,
2422*5f757f3fSDimitry Andric                                        SelectionDAG &DAG,
2423*5f757f3fSDimitry Andric                                        const LoongArchSubtarget &Subtarget,
2424*5f757f3fSDimitry Andric                                        bool IsSigned = false) {
2425*5f757f3fSDimitry Andric   SDLoc DL(Node);
2426*5f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
2427*5f757f3fSDimitry Andric   // Check the ImmArg.
2428*5f757f3fSDimitry Andric   if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
2429*5f757f3fSDimitry Andric       (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
2430*5f757f3fSDimitry Andric     DAG.getContext()->emitError(Node->getOperationName(0) +
2431*5f757f3fSDimitry Andric                                 ": argument out of range.");
2432*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, DL, Subtarget.getGRLenVT());
2433*5f757f3fSDimitry Andric   }
2434*5f757f3fSDimitry Andric   return DAG.getConstant(CImm->getZExtValue(), DL, Subtarget.getGRLenVT());
2435*5f757f3fSDimitry Andric }
2436*5f757f3fSDimitry Andric 
2437*5f757f3fSDimitry Andric template <unsigned N>
2438*5f757f3fSDimitry Andric static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp,
2439*5f757f3fSDimitry Andric                                    SelectionDAG &DAG, bool IsSigned = false) {
2440*5f757f3fSDimitry Andric   SDLoc DL(Node);
2441*5f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
2442*5f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
2443*5f757f3fSDimitry Andric 
2444*5f757f3fSDimitry Andric   // Check the ImmArg.
2445*5f757f3fSDimitry Andric   if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
2446*5f757f3fSDimitry Andric       (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
2447*5f757f3fSDimitry Andric     DAG.getContext()->emitError(Node->getOperationName(0) +
2448*5f757f3fSDimitry Andric                                 ": argument out of range.");
2449*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, DL, ResTy);
2450*5f757f3fSDimitry Andric   }
2451*5f757f3fSDimitry Andric   return DAG.getConstant(
2452*5f757f3fSDimitry Andric       APInt(ResTy.getScalarType().getSizeInBits(),
2453*5f757f3fSDimitry Andric             IsSigned ? CImm->getSExtValue() : CImm->getZExtValue(), IsSigned),
2454*5f757f3fSDimitry Andric       DL, ResTy);
2455*5f757f3fSDimitry Andric }
2456*5f757f3fSDimitry Andric 
2457*5f757f3fSDimitry Andric static SDValue truncateVecElts(SDNode *Node, SelectionDAG &DAG) {
2458*5f757f3fSDimitry Andric   SDLoc DL(Node);
2459*5f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
2460*5f757f3fSDimitry Andric   SDValue Vec = Node->getOperand(2);
2461*5f757f3fSDimitry Andric   SDValue Mask = DAG.getConstant(Vec.getScalarValueSizeInBits() - 1, DL, ResTy);
2462*5f757f3fSDimitry Andric   return DAG.getNode(ISD::AND, DL, ResTy, Vec, Mask);
2463*5f757f3fSDimitry Andric }
2464*5f757f3fSDimitry Andric 
2465*5f757f3fSDimitry Andric static SDValue lowerVectorBitClear(SDNode *Node, SelectionDAG &DAG) {
2466*5f757f3fSDimitry Andric   SDLoc DL(Node);
2467*5f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
2468*5f757f3fSDimitry Andric   SDValue One = DAG.getConstant(1, DL, ResTy);
2469*5f757f3fSDimitry Andric   SDValue Bit =
2470*5f757f3fSDimitry Andric       DAG.getNode(ISD::SHL, DL, ResTy, One, truncateVecElts(Node, DAG));
2471*5f757f3fSDimitry Andric 
2472*5f757f3fSDimitry Andric   return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1),
2473*5f757f3fSDimitry Andric                      DAG.getNOT(DL, Bit, ResTy));
2474*5f757f3fSDimitry Andric }
2475*5f757f3fSDimitry Andric 
2476*5f757f3fSDimitry Andric template <unsigned N>
2477*5f757f3fSDimitry Andric static SDValue lowerVectorBitClearImm(SDNode *Node, SelectionDAG &DAG) {
2478*5f757f3fSDimitry Andric   SDLoc DL(Node);
2479*5f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
2480*5f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
2481*5f757f3fSDimitry Andric   // Check the unsigned ImmArg.
2482*5f757f3fSDimitry Andric   if (!isUInt<N>(CImm->getZExtValue())) {
2483*5f757f3fSDimitry Andric     DAG.getContext()->emitError(Node->getOperationName(0) +
2484*5f757f3fSDimitry Andric                                 ": argument out of range.");
2485*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, DL, ResTy);
2486*5f757f3fSDimitry Andric   }
2487*5f757f3fSDimitry Andric 
2488*5f757f3fSDimitry Andric   APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
2489*5f757f3fSDimitry Andric   SDValue Mask = DAG.getConstant(~BitImm, DL, ResTy);
2490*5f757f3fSDimitry Andric 
2491*5f757f3fSDimitry Andric   return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1), Mask);
2492*5f757f3fSDimitry Andric }
2493*5f757f3fSDimitry Andric 
2494*5f757f3fSDimitry Andric template <unsigned N>
2495*5f757f3fSDimitry Andric static SDValue lowerVectorBitSetImm(SDNode *Node, SelectionDAG &DAG) {
2496*5f757f3fSDimitry Andric   SDLoc DL(Node);
2497*5f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
2498*5f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
2499*5f757f3fSDimitry Andric   // Check the unsigned ImmArg.
2500*5f757f3fSDimitry Andric   if (!isUInt<N>(CImm->getZExtValue())) {
2501*5f757f3fSDimitry Andric     DAG.getContext()->emitError(Node->getOperationName(0) +
2502*5f757f3fSDimitry Andric                                 ": argument out of range.");
2503*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, DL, ResTy);
2504*5f757f3fSDimitry Andric   }
2505*5f757f3fSDimitry Andric 
2506*5f757f3fSDimitry Andric   APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
2507*5f757f3fSDimitry Andric   SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
2508*5f757f3fSDimitry Andric   return DAG.getNode(ISD::OR, DL, ResTy, Node->getOperand(1), BitImm);
2509*5f757f3fSDimitry Andric }
2510*5f757f3fSDimitry Andric 
2511*5f757f3fSDimitry Andric template <unsigned N>
2512*5f757f3fSDimitry Andric static SDValue lowerVectorBitRevImm(SDNode *Node, SelectionDAG &DAG) {
2513*5f757f3fSDimitry Andric   SDLoc DL(Node);
2514*5f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
2515*5f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
2516*5f757f3fSDimitry Andric   // Check the unsigned ImmArg.
2517*5f757f3fSDimitry Andric   if (!isUInt<N>(CImm->getZExtValue())) {
2518*5f757f3fSDimitry Andric     DAG.getContext()->emitError(Node->getOperationName(0) +
2519*5f757f3fSDimitry Andric                                 ": argument out of range.");
2520*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, DL, ResTy);
2521*5f757f3fSDimitry Andric   }
2522*5f757f3fSDimitry Andric 
2523*5f757f3fSDimitry Andric   APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
2524*5f757f3fSDimitry Andric   SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
2525*5f757f3fSDimitry Andric   return DAG.getNode(ISD::XOR, DL, ResTy, Node->getOperand(1), BitImm);
2526*5f757f3fSDimitry Andric }
2527*5f757f3fSDimitry Andric 
2528*5f757f3fSDimitry Andric static SDValue
2529*5f757f3fSDimitry Andric performINTRINSIC_WO_CHAINCombine(SDNode *N, SelectionDAG &DAG,
2530*5f757f3fSDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
2531*5f757f3fSDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
2532*5f757f3fSDimitry Andric   SDLoc DL(N);
2533*5f757f3fSDimitry Andric   switch (N->getConstantOperandVal(0)) {
2534*5f757f3fSDimitry Andric   default:
2535*5f757f3fSDimitry Andric     break;
2536*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vadd_b:
2537*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vadd_h:
2538*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vadd_w:
2539*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vadd_d:
2540*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvadd_b:
2541*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvadd_h:
2542*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvadd_w:
2543*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvadd_d:
2544*5f757f3fSDimitry Andric     return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
2545*5f757f3fSDimitry Andric                        N->getOperand(2));
2546*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vaddi_bu:
2547*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vaddi_hu:
2548*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vaddi_wu:
2549*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vaddi_du:
2550*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvaddi_bu:
2551*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvaddi_hu:
2552*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvaddi_wu:
2553*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvaddi_du:
2554*5f757f3fSDimitry Andric     return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
2555*5f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
2556*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsub_b:
2557*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsub_h:
2558*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsub_w:
2559*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsub_d:
2560*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsub_b:
2561*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsub_h:
2562*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsub_w:
2563*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsub_d:
2564*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
2565*5f757f3fSDimitry Andric                        N->getOperand(2));
2566*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsubi_bu:
2567*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsubi_hu:
2568*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsubi_wu:
2569*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsubi_du:
2570*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsubi_bu:
2571*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsubi_hu:
2572*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsubi_wu:
2573*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsubi_du:
2574*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
2575*5f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
2576*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vneg_b:
2577*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vneg_h:
2578*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vneg_w:
2579*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vneg_d:
2580*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvneg_b:
2581*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvneg_h:
2582*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvneg_w:
2583*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvneg_d:
2584*5f757f3fSDimitry Andric     return DAG.getNode(
2585*5f757f3fSDimitry Andric         ISD::SUB, DL, N->getValueType(0),
2586*5f757f3fSDimitry Andric         DAG.getConstant(
2587*5f757f3fSDimitry Andric             APInt(N->getValueType(0).getScalarType().getSizeInBits(), 0,
2588*5f757f3fSDimitry Andric                   /*isSigned=*/true),
2589*5f757f3fSDimitry Andric             SDLoc(N), N->getValueType(0)),
2590*5f757f3fSDimitry Andric         N->getOperand(1));
2591*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_b:
2592*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_h:
2593*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_w:
2594*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_d:
2595*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_b:
2596*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_h:
2597*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_w:
2598*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_d:
2599*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
2600*5f757f3fSDimitry Andric                        N->getOperand(2));
2601*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_bu:
2602*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_hu:
2603*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_wu:
2604*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_du:
2605*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_bu:
2606*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_hu:
2607*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_wu:
2608*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_du:
2609*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
2610*5f757f3fSDimitry Andric                        N->getOperand(2));
2611*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_b:
2612*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_h:
2613*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_w:
2614*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_d:
2615*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_b:
2616*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_h:
2617*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_w:
2618*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_d:
2619*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
2620*5f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
2621*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_bu:
2622*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_hu:
2623*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_wu:
2624*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_du:
2625*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_bu:
2626*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_hu:
2627*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_wu:
2628*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_du:
2629*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
2630*5f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
2631*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_b:
2632*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_h:
2633*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_w:
2634*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_d:
2635*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_b:
2636*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_h:
2637*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_w:
2638*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_d:
2639*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
2640*5f757f3fSDimitry Andric                        N->getOperand(2));
2641*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_bu:
2642*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_hu:
2643*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_wu:
2644*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_du:
2645*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_bu:
2646*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_hu:
2647*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_wu:
2648*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_du:
2649*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
2650*5f757f3fSDimitry Andric                        N->getOperand(2));
2651*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_b:
2652*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_h:
2653*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_w:
2654*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_d:
2655*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_b:
2656*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_h:
2657*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_w:
2658*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_d:
2659*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
2660*5f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
2661*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_bu:
2662*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_hu:
2663*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_wu:
2664*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_du:
2665*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_bu:
2666*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_hu:
2667*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_wu:
2668*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_du:
2669*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
2670*5f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
2671*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmul_b:
2672*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmul_h:
2673*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmul_w:
2674*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmul_d:
2675*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmul_b:
2676*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmul_h:
2677*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmul_w:
2678*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmul_d:
2679*5f757f3fSDimitry Andric     return DAG.getNode(ISD::MUL, DL, N->getValueType(0), N->getOperand(1),
2680*5f757f3fSDimitry Andric                        N->getOperand(2));
2681*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmadd_b:
2682*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmadd_h:
2683*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmadd_w:
2684*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmadd_d:
2685*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmadd_b:
2686*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmadd_h:
2687*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmadd_w:
2688*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmadd_d: {
2689*5f757f3fSDimitry Andric     EVT ResTy = N->getValueType(0);
2690*5f757f3fSDimitry Andric     return DAG.getNode(ISD::ADD, SDLoc(N), ResTy, N->getOperand(1),
2691*5f757f3fSDimitry Andric                        DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
2692*5f757f3fSDimitry Andric                                    N->getOperand(3)));
2693*5f757f3fSDimitry Andric   }
2694*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmsub_b:
2695*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmsub_h:
2696*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmsub_w:
2697*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmsub_d:
2698*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmsub_b:
2699*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmsub_h:
2700*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmsub_w:
2701*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmsub_d: {
2702*5f757f3fSDimitry Andric     EVT ResTy = N->getValueType(0);
2703*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SUB, SDLoc(N), ResTy, N->getOperand(1),
2704*5f757f3fSDimitry Andric                        DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
2705*5f757f3fSDimitry Andric                                    N->getOperand(3)));
2706*5f757f3fSDimitry Andric   }
2707*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_b:
2708*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_h:
2709*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_w:
2710*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_d:
2711*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_b:
2712*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_h:
2713*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_w:
2714*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_d:
2715*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SDIV, DL, N->getValueType(0), N->getOperand(1),
2716*5f757f3fSDimitry Andric                        N->getOperand(2));
2717*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_bu:
2718*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_hu:
2719*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_wu:
2720*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_du:
2721*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_bu:
2722*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_hu:
2723*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_wu:
2724*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_du:
2725*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UDIV, DL, N->getValueType(0), N->getOperand(1),
2726*5f757f3fSDimitry Andric                        N->getOperand(2));
2727*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_b:
2728*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_h:
2729*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_w:
2730*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_d:
2731*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_b:
2732*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_h:
2733*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_w:
2734*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_d:
2735*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SREM, DL, N->getValueType(0), N->getOperand(1),
2736*5f757f3fSDimitry Andric                        N->getOperand(2));
2737*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_bu:
2738*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_hu:
2739*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_wu:
2740*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_du:
2741*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_bu:
2742*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_hu:
2743*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_wu:
2744*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_du:
2745*5f757f3fSDimitry Andric     return DAG.getNode(ISD::UREM, DL, N->getValueType(0), N->getOperand(1),
2746*5f757f3fSDimitry Andric                        N->getOperand(2));
2747*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vand_v:
2748*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvand_v:
2749*5f757f3fSDimitry Andric     return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
2750*5f757f3fSDimitry Andric                        N->getOperand(2));
2751*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vor_v:
2752*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvor_v:
2753*5f757f3fSDimitry Andric     return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
2754*5f757f3fSDimitry Andric                        N->getOperand(2));
2755*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vxor_v:
2756*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvxor_v:
2757*5f757f3fSDimitry Andric     return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
2758*5f757f3fSDimitry Andric                        N->getOperand(2));
2759*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vnor_v:
2760*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvnor_v: {
2761*5f757f3fSDimitry Andric     SDValue Res = DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
2762*5f757f3fSDimitry Andric                               N->getOperand(2));
2763*5f757f3fSDimitry Andric     return DAG.getNOT(DL, Res, Res->getValueType(0));
2764*5f757f3fSDimitry Andric   }
2765*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vandi_b:
2766*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvandi_b:
2767*5f757f3fSDimitry Andric     return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
2768*5f757f3fSDimitry Andric                        lowerVectorSplatImm<8>(N, 2, DAG));
2769*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vori_b:
2770*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvori_b:
2771*5f757f3fSDimitry Andric     return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
2772*5f757f3fSDimitry Andric                        lowerVectorSplatImm<8>(N, 2, DAG));
2773*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vxori_b:
2774*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvxori_b:
2775*5f757f3fSDimitry Andric     return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
2776*5f757f3fSDimitry Andric                        lowerVectorSplatImm<8>(N, 2, DAG));
2777*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsll_b:
2778*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsll_h:
2779*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsll_w:
2780*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsll_d:
2781*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsll_b:
2782*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsll_h:
2783*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsll_w:
2784*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsll_d:
2785*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
2786*5f757f3fSDimitry Andric                        truncateVecElts(N, DAG));
2787*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslli_b:
2788*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslli_b:
2789*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
2790*5f757f3fSDimitry Andric                        lowerVectorSplatImm<3>(N, 2, DAG));
2791*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslli_h:
2792*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslli_h:
2793*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
2794*5f757f3fSDimitry Andric                        lowerVectorSplatImm<4>(N, 2, DAG));
2795*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslli_w:
2796*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslli_w:
2797*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
2798*5f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
2799*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslli_d:
2800*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslli_d:
2801*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
2802*5f757f3fSDimitry Andric                        lowerVectorSplatImm<6>(N, 2, DAG));
2803*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrl_b:
2804*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrl_h:
2805*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrl_w:
2806*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrl_d:
2807*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrl_b:
2808*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrl_h:
2809*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrl_w:
2810*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrl_d:
2811*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
2812*5f757f3fSDimitry Andric                        truncateVecElts(N, DAG));
2813*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrli_b:
2814*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrli_b:
2815*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
2816*5f757f3fSDimitry Andric                        lowerVectorSplatImm<3>(N, 2, DAG));
2817*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrli_h:
2818*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrli_h:
2819*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
2820*5f757f3fSDimitry Andric                        lowerVectorSplatImm<4>(N, 2, DAG));
2821*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrli_w:
2822*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrli_w:
2823*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
2824*5f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
2825*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrli_d:
2826*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrli_d:
2827*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
2828*5f757f3fSDimitry Andric                        lowerVectorSplatImm<6>(N, 2, DAG));
2829*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsra_b:
2830*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsra_h:
2831*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsra_w:
2832*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsra_d:
2833*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsra_b:
2834*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsra_h:
2835*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsra_w:
2836*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsra_d:
2837*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
2838*5f757f3fSDimitry Andric                        truncateVecElts(N, DAG));
2839*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrai_b:
2840*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrai_b:
2841*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
2842*5f757f3fSDimitry Andric                        lowerVectorSplatImm<3>(N, 2, DAG));
2843*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrai_h:
2844*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrai_h:
2845*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
2846*5f757f3fSDimitry Andric                        lowerVectorSplatImm<4>(N, 2, DAG));
2847*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrai_w:
2848*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrai_w:
2849*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
2850*5f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
2851*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrai_d:
2852*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrai_d:
2853*5f757f3fSDimitry Andric     return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
2854*5f757f3fSDimitry Andric                        lowerVectorSplatImm<6>(N, 2, DAG));
2855*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vclz_b:
2856*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vclz_h:
2857*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vclz_w:
2858*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vclz_d:
2859*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvclz_b:
2860*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvclz_h:
2861*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvclz_w:
2862*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvclz_d:
2863*5f757f3fSDimitry Andric     return DAG.getNode(ISD::CTLZ, DL, N->getValueType(0), N->getOperand(1));
2864*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpcnt_b:
2865*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpcnt_h:
2866*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpcnt_w:
2867*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpcnt_d:
2868*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpcnt_b:
2869*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpcnt_h:
2870*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpcnt_w:
2871*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpcnt_d:
2872*5f757f3fSDimitry Andric     return DAG.getNode(ISD::CTPOP, DL, N->getValueType(0), N->getOperand(1));
2873*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclr_b:
2874*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclr_h:
2875*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclr_w:
2876*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclr_d:
2877*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclr_b:
2878*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclr_h:
2879*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclr_w:
2880*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclr_d:
2881*5f757f3fSDimitry Andric     return lowerVectorBitClear(N, DAG);
2882*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclri_b:
2883*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclri_b:
2884*5f757f3fSDimitry Andric     return lowerVectorBitClearImm<3>(N, DAG);
2885*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclri_h:
2886*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclri_h:
2887*5f757f3fSDimitry Andric     return lowerVectorBitClearImm<4>(N, DAG);
2888*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclri_w:
2889*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclri_w:
2890*5f757f3fSDimitry Andric     return lowerVectorBitClearImm<5>(N, DAG);
2891*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclri_d:
2892*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclri_d:
2893*5f757f3fSDimitry Andric     return lowerVectorBitClearImm<6>(N, DAG);
2894*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitset_b:
2895*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitset_h:
2896*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitset_w:
2897*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitset_d:
2898*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitset_b:
2899*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitset_h:
2900*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitset_w:
2901*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitset_d: {
2902*5f757f3fSDimitry Andric     EVT VecTy = N->getValueType(0);
2903*5f757f3fSDimitry Andric     SDValue One = DAG.getConstant(1, DL, VecTy);
2904*5f757f3fSDimitry Andric     return DAG.getNode(
2905*5f757f3fSDimitry Andric         ISD::OR, DL, VecTy, N->getOperand(1),
2906*5f757f3fSDimitry Andric         DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
2907*5f757f3fSDimitry Andric   }
2908*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitseti_b:
2909*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitseti_b:
2910*5f757f3fSDimitry Andric     return lowerVectorBitSetImm<3>(N, DAG);
2911*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitseti_h:
2912*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitseti_h:
2913*5f757f3fSDimitry Andric     return lowerVectorBitSetImm<4>(N, DAG);
2914*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitseti_w:
2915*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitseti_w:
2916*5f757f3fSDimitry Andric     return lowerVectorBitSetImm<5>(N, DAG);
2917*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitseti_d:
2918*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitseti_d:
2919*5f757f3fSDimitry Andric     return lowerVectorBitSetImm<6>(N, DAG);
2920*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrev_b:
2921*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrev_h:
2922*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrev_w:
2923*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrev_d:
2924*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrev_b:
2925*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrev_h:
2926*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrev_w:
2927*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrev_d: {
2928*5f757f3fSDimitry Andric     EVT VecTy = N->getValueType(0);
2929*5f757f3fSDimitry Andric     SDValue One = DAG.getConstant(1, DL, VecTy);
2930*5f757f3fSDimitry Andric     return DAG.getNode(
2931*5f757f3fSDimitry Andric         ISD::XOR, DL, VecTy, N->getOperand(1),
2932*5f757f3fSDimitry Andric         DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
2933*5f757f3fSDimitry Andric   }
2934*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrevi_b:
2935*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrevi_b:
2936*5f757f3fSDimitry Andric     return lowerVectorBitRevImm<3>(N, DAG);
2937*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrevi_h:
2938*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrevi_h:
2939*5f757f3fSDimitry Andric     return lowerVectorBitRevImm<4>(N, DAG);
2940*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrevi_w:
2941*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrevi_w:
2942*5f757f3fSDimitry Andric     return lowerVectorBitRevImm<5>(N, DAG);
2943*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrevi_d:
2944*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrevi_d:
2945*5f757f3fSDimitry Andric     return lowerVectorBitRevImm<6>(N, DAG);
2946*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfadd_s:
2947*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfadd_d:
2948*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfadd_s:
2949*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfadd_d:
2950*5f757f3fSDimitry Andric     return DAG.getNode(ISD::FADD, DL, N->getValueType(0), N->getOperand(1),
2951*5f757f3fSDimitry Andric                        N->getOperand(2));
2952*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfsub_s:
2953*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfsub_d:
2954*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfsub_s:
2955*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfsub_d:
2956*5f757f3fSDimitry Andric     return DAG.getNode(ISD::FSUB, DL, N->getValueType(0), N->getOperand(1),
2957*5f757f3fSDimitry Andric                        N->getOperand(2));
2958*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfmul_s:
2959*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfmul_d:
2960*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfmul_s:
2961*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfmul_d:
2962*5f757f3fSDimitry Andric     return DAG.getNode(ISD::FMUL, DL, N->getValueType(0), N->getOperand(1),
2963*5f757f3fSDimitry Andric                        N->getOperand(2));
2964*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfdiv_s:
2965*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfdiv_d:
2966*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfdiv_s:
2967*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfdiv_d:
2968*5f757f3fSDimitry Andric     return DAG.getNode(ISD::FDIV, DL, N->getValueType(0), N->getOperand(1),
2969*5f757f3fSDimitry Andric                        N->getOperand(2));
2970*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfmadd_s:
2971*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfmadd_d:
2972*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfmadd_s:
2973*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfmadd_d:
2974*5f757f3fSDimitry Andric     return DAG.getNode(ISD::FMA, DL, N->getValueType(0), N->getOperand(1),
2975*5f757f3fSDimitry Andric                        N->getOperand(2), N->getOperand(3));
2976*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vinsgr2vr_b:
2977*5f757f3fSDimitry Andric     return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
2978*5f757f3fSDimitry Andric                        N->getOperand(1), N->getOperand(2),
2979*5f757f3fSDimitry Andric                        legalizeIntrinsicImmArg<4>(N, 3, DAG, Subtarget));
2980*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vinsgr2vr_h:
2981*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvinsgr2vr_w:
2982*5f757f3fSDimitry Andric     return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
2983*5f757f3fSDimitry Andric                        N->getOperand(1), N->getOperand(2),
2984*5f757f3fSDimitry Andric                        legalizeIntrinsicImmArg<3>(N, 3, DAG, Subtarget));
2985*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vinsgr2vr_w:
2986*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvinsgr2vr_d:
2987*5f757f3fSDimitry Andric     return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
2988*5f757f3fSDimitry Andric                        N->getOperand(1), N->getOperand(2),
2989*5f757f3fSDimitry Andric                        legalizeIntrinsicImmArg<2>(N, 3, DAG, Subtarget));
2990*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vinsgr2vr_d:
2991*5f757f3fSDimitry Andric     return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
2992*5f757f3fSDimitry Andric                        N->getOperand(1), N->getOperand(2),
2993*5f757f3fSDimitry Andric                        legalizeIntrinsicImmArg<1>(N, 3, DAG, Subtarget));
2994*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplgr2vr_b:
2995*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplgr2vr_h:
2996*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplgr2vr_w:
2997*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplgr2vr_d:
2998*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplgr2vr_b:
2999*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplgr2vr_h:
3000*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplgr2vr_w:
3001*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplgr2vr_d: {
3002*5f757f3fSDimitry Andric     EVT ResTy = N->getValueType(0);
3003*5f757f3fSDimitry Andric     SmallVector<SDValue> Ops(ResTy.getVectorNumElements(), N->getOperand(1));
3004*5f757f3fSDimitry Andric     return DAG.getBuildVector(ResTy, DL, Ops);
3005*5f757f3fSDimitry Andric   }
3006*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplve_b:
3007*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplve_h:
3008*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplve_w:
3009*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplve_d:
3010*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplve_b:
3011*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplve_h:
3012*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplve_w:
3013*5f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplve_d:
3014*5f757f3fSDimitry Andric     return DAG.getNode(LoongArchISD::VREPLVE, DL, N->getValueType(0),
3015*5f757f3fSDimitry Andric                        N->getOperand(1),
3016*5f757f3fSDimitry Andric                        DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
3017*5f757f3fSDimitry Andric                                    N->getOperand(2)));
3018*5f757f3fSDimitry Andric   }
3019*5f757f3fSDimitry Andric   return SDValue();
3020*5f757f3fSDimitry Andric }
3021*5f757f3fSDimitry Andric 
302281ad6265SDimitry Andric SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N,
302381ad6265SDimitry Andric                                                    DAGCombinerInfo &DCI) const {
302481ad6265SDimitry Andric   SelectionDAG &DAG = DCI.DAG;
302581ad6265SDimitry Andric   switch (N->getOpcode()) {
302681ad6265SDimitry Andric   default:
302781ad6265SDimitry Andric     break;
302881ad6265SDimitry Andric   case ISD::AND:
302981ad6265SDimitry Andric     return performANDCombine(N, DAG, DCI, Subtarget);
3030753f127fSDimitry Andric   case ISD::OR:
3031753f127fSDimitry Andric     return performORCombine(N, DAG, DCI, Subtarget);
303281ad6265SDimitry Andric   case ISD::SRL:
303381ad6265SDimitry Andric     return performSRLCombine(N, DAG, DCI, Subtarget);
3034bdd1243dSDimitry Andric   case LoongArchISD::BITREV_W:
3035bdd1243dSDimitry Andric     return performBITREV_WCombine(N, DAG, DCI, Subtarget);
3036*5f757f3fSDimitry Andric   case ISD::INTRINSIC_WO_CHAIN:
3037*5f757f3fSDimitry Andric     return performINTRINSIC_WO_CHAINCombine(N, DAG, DCI, Subtarget);
303881ad6265SDimitry Andric   }
303981ad6265SDimitry Andric   return SDValue();
304081ad6265SDimitry Andric }
304181ad6265SDimitry Andric 
3042753f127fSDimitry Andric static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI,
3043bdd1243dSDimitry Andric                                               MachineBasicBlock *MBB) {
3044753f127fSDimitry Andric   if (!ZeroDivCheck)
3045bdd1243dSDimitry Andric     return MBB;
3046753f127fSDimitry Andric 
3047753f127fSDimitry Andric   // Build instructions:
3048bdd1243dSDimitry Andric   // MBB:
3049753f127fSDimitry Andric   //   div(or mod)   $dst, $dividend, $divisor
3050bdd1243dSDimitry Andric   //   bnez          $divisor, SinkMBB
3051bdd1243dSDimitry Andric   // BreakMBB:
3052bdd1243dSDimitry Andric   //   break         7 // BRK_DIVZERO
3053bdd1243dSDimitry Andric   // SinkMBB:
3054753f127fSDimitry Andric   //   fallthrough
3055bdd1243dSDimitry Andric   const BasicBlock *LLVM_BB = MBB->getBasicBlock();
3056bdd1243dSDimitry Andric   MachineFunction::iterator It = ++MBB->getIterator();
3057bdd1243dSDimitry Andric   MachineFunction *MF = MBB->getParent();
3058bdd1243dSDimitry Andric   auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
3059bdd1243dSDimitry Andric   auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
3060bdd1243dSDimitry Andric   MF->insert(It, BreakMBB);
3061bdd1243dSDimitry Andric   MF->insert(It, SinkMBB);
3062bdd1243dSDimitry Andric 
3063bdd1243dSDimitry Andric   // Transfer the remainder of MBB and its successor edges to SinkMBB.
3064bdd1243dSDimitry Andric   SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
3065bdd1243dSDimitry Andric   SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
3066bdd1243dSDimitry Andric 
3067bdd1243dSDimitry Andric   const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
3068bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
3069753f127fSDimitry Andric   MachineOperand &Divisor = MI.getOperand(2);
3070bdd1243dSDimitry Andric   Register DivisorReg = Divisor.getReg();
3071753f127fSDimitry Andric 
3072bdd1243dSDimitry Andric   // MBB:
3073bdd1243dSDimitry Andric   BuildMI(MBB, DL, TII.get(LoongArch::BNEZ))
3074bdd1243dSDimitry Andric       .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
3075bdd1243dSDimitry Andric       .addMBB(SinkMBB);
3076bdd1243dSDimitry Andric   MBB->addSuccessor(BreakMBB);
3077bdd1243dSDimitry Andric   MBB->addSuccessor(SinkMBB);
3078753f127fSDimitry Andric 
3079bdd1243dSDimitry Andric   // BreakMBB:
3080753f127fSDimitry Andric   // See linux header file arch/loongarch/include/uapi/asm/break.h for the
3081753f127fSDimitry Andric   // definition of BRK_DIVZERO.
3082bdd1243dSDimitry Andric   BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
3083bdd1243dSDimitry Andric   BreakMBB->addSuccessor(SinkMBB);
3084753f127fSDimitry Andric 
3085753f127fSDimitry Andric   // Clear Divisor's kill flag.
3086753f127fSDimitry Andric   Divisor.setIsKill(false);
3087753f127fSDimitry Andric 
3088bdd1243dSDimitry Andric   return SinkMBB;
3089753f127fSDimitry Andric }
3090753f127fSDimitry Andric 
3091*5f757f3fSDimitry Andric static MachineBasicBlock *
3092*5f757f3fSDimitry Andric emitVecCondBranchPseudo(MachineInstr &MI, MachineBasicBlock *BB,
3093*5f757f3fSDimitry Andric                         const LoongArchSubtarget &Subtarget) {
3094*5f757f3fSDimitry Andric   unsigned CondOpc;
3095*5f757f3fSDimitry Andric   switch (MI.getOpcode()) {
3096*5f757f3fSDimitry Andric   default:
3097*5f757f3fSDimitry Andric     llvm_unreachable("Unexpected opcode");
3098*5f757f3fSDimitry Andric   case LoongArch::PseudoVBZ:
3099*5f757f3fSDimitry Andric     CondOpc = LoongArch::VSETEQZ_V;
3100*5f757f3fSDimitry Andric     break;
3101*5f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_B:
3102*5f757f3fSDimitry Andric     CondOpc = LoongArch::VSETANYEQZ_B;
3103*5f757f3fSDimitry Andric     break;
3104*5f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_H:
3105*5f757f3fSDimitry Andric     CondOpc = LoongArch::VSETANYEQZ_H;
3106*5f757f3fSDimitry Andric     break;
3107*5f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_W:
3108*5f757f3fSDimitry Andric     CondOpc = LoongArch::VSETANYEQZ_W;
3109*5f757f3fSDimitry Andric     break;
3110*5f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_D:
3111*5f757f3fSDimitry Andric     CondOpc = LoongArch::VSETANYEQZ_D;
3112*5f757f3fSDimitry Andric     break;
3113*5f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ:
3114*5f757f3fSDimitry Andric     CondOpc = LoongArch::VSETNEZ_V;
3115*5f757f3fSDimitry Andric     break;
3116*5f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_B:
3117*5f757f3fSDimitry Andric     CondOpc = LoongArch::VSETALLNEZ_B;
3118*5f757f3fSDimitry Andric     break;
3119*5f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_H:
3120*5f757f3fSDimitry Andric     CondOpc = LoongArch::VSETALLNEZ_H;
3121*5f757f3fSDimitry Andric     break;
3122*5f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_W:
3123*5f757f3fSDimitry Andric     CondOpc = LoongArch::VSETALLNEZ_W;
3124*5f757f3fSDimitry Andric     break;
3125*5f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_D:
3126*5f757f3fSDimitry Andric     CondOpc = LoongArch::VSETALLNEZ_D;
3127*5f757f3fSDimitry Andric     break;
3128*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ:
3129*5f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETEQZ_V;
3130*5f757f3fSDimitry Andric     break;
3131*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_B:
3132*5f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETANYEQZ_B;
3133*5f757f3fSDimitry Andric     break;
3134*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_H:
3135*5f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETANYEQZ_H;
3136*5f757f3fSDimitry Andric     break;
3137*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_W:
3138*5f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETANYEQZ_W;
3139*5f757f3fSDimitry Andric     break;
3140*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_D:
3141*5f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETANYEQZ_D;
3142*5f757f3fSDimitry Andric     break;
3143*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ:
3144*5f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETNEZ_V;
3145*5f757f3fSDimitry Andric     break;
3146*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_B:
3147*5f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETALLNEZ_B;
3148*5f757f3fSDimitry Andric     break;
3149*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_H:
3150*5f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETALLNEZ_H;
3151*5f757f3fSDimitry Andric     break;
3152*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_W:
3153*5f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETALLNEZ_W;
3154*5f757f3fSDimitry Andric     break;
3155*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_D:
3156*5f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETALLNEZ_D;
3157*5f757f3fSDimitry Andric     break;
3158*5f757f3fSDimitry Andric   }
3159*5f757f3fSDimitry Andric 
3160*5f757f3fSDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
3161*5f757f3fSDimitry Andric   const BasicBlock *LLVM_BB = BB->getBasicBlock();
3162*5f757f3fSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
3163*5f757f3fSDimitry Andric   MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
3164*5f757f3fSDimitry Andric   MachineFunction::iterator It = ++BB->getIterator();
3165*5f757f3fSDimitry Andric 
3166*5f757f3fSDimitry Andric   MachineFunction *F = BB->getParent();
3167*5f757f3fSDimitry Andric   MachineBasicBlock *FalseBB = F->CreateMachineBasicBlock(LLVM_BB);
3168*5f757f3fSDimitry Andric   MachineBasicBlock *TrueBB = F->CreateMachineBasicBlock(LLVM_BB);
3169*5f757f3fSDimitry Andric   MachineBasicBlock *SinkBB = F->CreateMachineBasicBlock(LLVM_BB);
3170*5f757f3fSDimitry Andric 
3171*5f757f3fSDimitry Andric   F->insert(It, FalseBB);
3172*5f757f3fSDimitry Andric   F->insert(It, TrueBB);
3173*5f757f3fSDimitry Andric   F->insert(It, SinkBB);
3174*5f757f3fSDimitry Andric 
3175*5f757f3fSDimitry Andric   // Transfer the remainder of MBB and its successor edges to Sink.
3176*5f757f3fSDimitry Andric   SinkBB->splice(SinkBB->end(), BB, std::next(MI.getIterator()), BB->end());
3177*5f757f3fSDimitry Andric   SinkBB->transferSuccessorsAndUpdatePHIs(BB);
3178*5f757f3fSDimitry Andric 
3179*5f757f3fSDimitry Andric   // Insert the real instruction to BB.
3180*5f757f3fSDimitry Andric   Register FCC = MRI.createVirtualRegister(&LoongArch::CFRRegClass);
3181*5f757f3fSDimitry Andric   BuildMI(BB, DL, TII->get(CondOpc), FCC).addReg(MI.getOperand(1).getReg());
3182*5f757f3fSDimitry Andric 
3183*5f757f3fSDimitry Andric   // Insert branch.
3184*5f757f3fSDimitry Andric   BuildMI(BB, DL, TII->get(LoongArch::BCNEZ)).addReg(FCC).addMBB(TrueBB);
3185*5f757f3fSDimitry Andric   BB->addSuccessor(FalseBB);
3186*5f757f3fSDimitry Andric   BB->addSuccessor(TrueBB);
3187*5f757f3fSDimitry Andric 
3188*5f757f3fSDimitry Andric   // FalseBB.
3189*5f757f3fSDimitry Andric   Register RD1 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
3190*5f757f3fSDimitry Andric   BuildMI(FalseBB, DL, TII->get(LoongArch::ADDI_W), RD1)
3191*5f757f3fSDimitry Andric       .addReg(LoongArch::R0)
3192*5f757f3fSDimitry Andric       .addImm(0);
3193*5f757f3fSDimitry Andric   BuildMI(FalseBB, DL, TII->get(LoongArch::PseudoBR)).addMBB(SinkBB);
3194*5f757f3fSDimitry Andric   FalseBB->addSuccessor(SinkBB);
3195*5f757f3fSDimitry Andric 
3196*5f757f3fSDimitry Andric   // TrueBB.
3197*5f757f3fSDimitry Andric   Register RD2 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
3198*5f757f3fSDimitry Andric   BuildMI(TrueBB, DL, TII->get(LoongArch::ADDI_W), RD2)
3199*5f757f3fSDimitry Andric       .addReg(LoongArch::R0)
3200*5f757f3fSDimitry Andric       .addImm(1);
3201*5f757f3fSDimitry Andric   TrueBB->addSuccessor(SinkBB);
3202*5f757f3fSDimitry Andric 
3203*5f757f3fSDimitry Andric   // SinkBB: merge the results.
3204*5f757f3fSDimitry Andric   BuildMI(*SinkBB, SinkBB->begin(), DL, TII->get(LoongArch::PHI),
3205*5f757f3fSDimitry Andric           MI.getOperand(0).getReg())
3206*5f757f3fSDimitry Andric       .addReg(RD1)
3207*5f757f3fSDimitry Andric       .addMBB(FalseBB)
3208*5f757f3fSDimitry Andric       .addReg(RD2)
3209*5f757f3fSDimitry Andric       .addMBB(TrueBB);
3210*5f757f3fSDimitry Andric 
3211*5f757f3fSDimitry Andric   // The pseudo instruction is gone now.
3212*5f757f3fSDimitry Andric   MI.eraseFromParent();
3213*5f757f3fSDimitry Andric   return SinkBB;
3214*5f757f3fSDimitry Andric }
3215*5f757f3fSDimitry Andric 
3216*5f757f3fSDimitry Andric static MachineBasicBlock *
3217*5f757f3fSDimitry Andric emitPseudoXVINSGR2VR(MachineInstr &MI, MachineBasicBlock *BB,
3218*5f757f3fSDimitry Andric                      const LoongArchSubtarget &Subtarget) {
3219*5f757f3fSDimitry Andric   unsigned InsOp;
3220*5f757f3fSDimitry Andric   unsigned HalfSize;
3221*5f757f3fSDimitry Andric   switch (MI.getOpcode()) {
3222*5f757f3fSDimitry Andric   default:
3223*5f757f3fSDimitry Andric     llvm_unreachable("Unexpected opcode");
3224*5f757f3fSDimitry Andric   case LoongArch::PseudoXVINSGR2VR_B:
3225*5f757f3fSDimitry Andric     HalfSize = 16;
3226*5f757f3fSDimitry Andric     InsOp = LoongArch::VINSGR2VR_B;
3227*5f757f3fSDimitry Andric     break;
3228*5f757f3fSDimitry Andric   case LoongArch::PseudoXVINSGR2VR_H:
3229*5f757f3fSDimitry Andric     HalfSize = 8;
3230*5f757f3fSDimitry Andric     InsOp = LoongArch::VINSGR2VR_H;
3231*5f757f3fSDimitry Andric     break;
3232*5f757f3fSDimitry Andric   }
3233*5f757f3fSDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
3234*5f757f3fSDimitry Andric   const TargetRegisterClass *RC = &LoongArch::LASX256RegClass;
3235*5f757f3fSDimitry Andric   const TargetRegisterClass *SubRC = &LoongArch::LSX128RegClass;
3236*5f757f3fSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
3237*5f757f3fSDimitry Andric   MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
3238*5f757f3fSDimitry Andric   // XDst = vector_insert XSrc, Elt, Idx
3239*5f757f3fSDimitry Andric   Register XDst = MI.getOperand(0).getReg();
3240*5f757f3fSDimitry Andric   Register XSrc = MI.getOperand(1).getReg();
3241*5f757f3fSDimitry Andric   Register Elt = MI.getOperand(2).getReg();
3242*5f757f3fSDimitry Andric   unsigned Idx = MI.getOperand(3).getImm();
3243*5f757f3fSDimitry Andric 
3244*5f757f3fSDimitry Andric   Register ScratchReg1 = XSrc;
3245*5f757f3fSDimitry Andric   if (Idx >= HalfSize) {
3246*5f757f3fSDimitry Andric     ScratchReg1 = MRI.createVirtualRegister(RC);
3247*5f757f3fSDimitry Andric     BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), ScratchReg1)
3248*5f757f3fSDimitry Andric         .addReg(XSrc)
3249*5f757f3fSDimitry Andric         .addReg(XSrc)
3250*5f757f3fSDimitry Andric         .addImm(1);
3251*5f757f3fSDimitry Andric   }
3252*5f757f3fSDimitry Andric 
3253*5f757f3fSDimitry Andric   Register ScratchSubReg1 = MRI.createVirtualRegister(SubRC);
3254*5f757f3fSDimitry Andric   Register ScratchSubReg2 = MRI.createVirtualRegister(SubRC);
3255*5f757f3fSDimitry Andric   BuildMI(*BB, MI, DL, TII->get(LoongArch::COPY), ScratchSubReg1)
3256*5f757f3fSDimitry Andric       .addReg(ScratchReg1, 0, LoongArch::sub_128);
3257*5f757f3fSDimitry Andric   BuildMI(*BB, MI, DL, TII->get(InsOp), ScratchSubReg2)
3258*5f757f3fSDimitry Andric       .addReg(ScratchSubReg1)
3259*5f757f3fSDimitry Andric       .addReg(Elt)
3260*5f757f3fSDimitry Andric       .addImm(Idx >= HalfSize ? Idx - HalfSize : Idx);
3261*5f757f3fSDimitry Andric 
3262*5f757f3fSDimitry Andric   Register ScratchReg2 = XDst;
3263*5f757f3fSDimitry Andric   if (Idx >= HalfSize)
3264*5f757f3fSDimitry Andric     ScratchReg2 = MRI.createVirtualRegister(RC);
3265*5f757f3fSDimitry Andric 
3266*5f757f3fSDimitry Andric   BuildMI(*BB, MI, DL, TII->get(LoongArch::SUBREG_TO_REG), ScratchReg2)
3267*5f757f3fSDimitry Andric       .addImm(0)
3268*5f757f3fSDimitry Andric       .addReg(ScratchSubReg2)
3269*5f757f3fSDimitry Andric       .addImm(LoongArch::sub_128);
3270*5f757f3fSDimitry Andric 
3271*5f757f3fSDimitry Andric   if (Idx >= HalfSize)
3272*5f757f3fSDimitry Andric     BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), XDst)
3273*5f757f3fSDimitry Andric         .addReg(XSrc)
3274*5f757f3fSDimitry Andric         .addReg(ScratchReg2)
3275*5f757f3fSDimitry Andric         .addImm(2);
3276*5f757f3fSDimitry Andric 
3277*5f757f3fSDimitry Andric   MI.eraseFromParent();
3278*5f757f3fSDimitry Andric   return BB;
3279*5f757f3fSDimitry Andric }
3280*5f757f3fSDimitry Andric 
3281753f127fSDimitry Andric MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
3282753f127fSDimitry Andric     MachineInstr &MI, MachineBasicBlock *BB) const {
3283bdd1243dSDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
3284bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
3285753f127fSDimitry Andric 
3286753f127fSDimitry Andric   switch (MI.getOpcode()) {
3287753f127fSDimitry Andric   default:
3288753f127fSDimitry Andric     llvm_unreachable("Unexpected instr type to insert");
3289753f127fSDimitry Andric   case LoongArch::DIV_W:
3290753f127fSDimitry Andric   case LoongArch::DIV_WU:
3291753f127fSDimitry Andric   case LoongArch::MOD_W:
3292753f127fSDimitry Andric   case LoongArch::MOD_WU:
3293753f127fSDimitry Andric   case LoongArch::DIV_D:
3294753f127fSDimitry Andric   case LoongArch::DIV_DU:
3295753f127fSDimitry Andric   case LoongArch::MOD_D:
3296753f127fSDimitry Andric   case LoongArch::MOD_DU:
3297bdd1243dSDimitry Andric     return insertDivByZeroTrap(MI, BB);
3298753f127fSDimitry Andric     break;
3299bdd1243dSDimitry Andric   case LoongArch::WRFCSR: {
3300bdd1243dSDimitry Andric     BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
3301bdd1243dSDimitry Andric             LoongArch::FCSR0 + MI.getOperand(0).getImm())
3302bdd1243dSDimitry Andric         .addReg(MI.getOperand(1).getReg());
3303bdd1243dSDimitry Andric     MI.eraseFromParent();
3304bdd1243dSDimitry Andric     return BB;
3305bdd1243dSDimitry Andric   }
3306bdd1243dSDimitry Andric   case LoongArch::RDFCSR: {
3307bdd1243dSDimitry Andric     MachineInstr *ReadFCSR =
3308bdd1243dSDimitry Andric         BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
3309bdd1243dSDimitry Andric                 MI.getOperand(0).getReg())
3310bdd1243dSDimitry Andric             .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
3311bdd1243dSDimitry Andric     ReadFCSR->getOperand(1).setIsUndef();
3312bdd1243dSDimitry Andric     MI.eraseFromParent();
3313bdd1243dSDimitry Andric     return BB;
3314bdd1243dSDimitry Andric   }
3315*5f757f3fSDimitry Andric   case LoongArch::PseudoVBZ:
3316*5f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_B:
3317*5f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_H:
3318*5f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_W:
3319*5f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_D:
3320*5f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ:
3321*5f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_B:
3322*5f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_H:
3323*5f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_W:
3324*5f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_D:
3325*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ:
3326*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_B:
3327*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_H:
3328*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_W:
3329*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_D:
3330*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ:
3331*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_B:
3332*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_H:
3333*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_W:
3334*5f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_D:
3335*5f757f3fSDimitry Andric     return emitVecCondBranchPseudo(MI, BB, Subtarget);
3336*5f757f3fSDimitry Andric   case LoongArch::PseudoXVINSGR2VR_B:
3337*5f757f3fSDimitry Andric   case LoongArch::PseudoXVINSGR2VR_H:
3338*5f757f3fSDimitry Andric     return emitPseudoXVINSGR2VR(MI, BB, Subtarget);
3339753f127fSDimitry Andric   }
3340753f127fSDimitry Andric }
3341753f127fSDimitry Andric 
334206c3fb27SDimitry Andric bool LoongArchTargetLowering::allowsMisalignedMemoryAccesses(
334306c3fb27SDimitry Andric     EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
334406c3fb27SDimitry Andric     unsigned *Fast) const {
334506c3fb27SDimitry Andric   if (!Subtarget.hasUAL())
334606c3fb27SDimitry Andric     return false;
334706c3fb27SDimitry Andric 
334806c3fb27SDimitry Andric   // TODO: set reasonable speed number.
334906c3fb27SDimitry Andric   if (Fast)
335006c3fb27SDimitry Andric     *Fast = 1;
335106c3fb27SDimitry Andric   return true;
335206c3fb27SDimitry Andric }
335306c3fb27SDimitry Andric 
335481ad6265SDimitry Andric const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
335581ad6265SDimitry Andric   switch ((LoongArchISD::NodeType)Opcode) {
335681ad6265SDimitry Andric   case LoongArchISD::FIRST_NUMBER:
335781ad6265SDimitry Andric     break;
335881ad6265SDimitry Andric 
335981ad6265SDimitry Andric #define NODE_NAME_CASE(node)                                                   \
336081ad6265SDimitry Andric   case LoongArchISD::node:                                                     \
336181ad6265SDimitry Andric     return "LoongArchISD::" #node;
336281ad6265SDimitry Andric 
336381ad6265SDimitry Andric     // TODO: Add more target-dependent nodes later.
3364753f127fSDimitry Andric     NODE_NAME_CASE(CALL)
336581ad6265SDimitry Andric     NODE_NAME_CASE(RET)
3366bdd1243dSDimitry Andric     NODE_NAME_CASE(TAIL)
336781ad6265SDimitry Andric     NODE_NAME_CASE(SLL_W)
336881ad6265SDimitry Andric     NODE_NAME_CASE(SRA_W)
336981ad6265SDimitry Andric     NODE_NAME_CASE(SRL_W)
3370753f127fSDimitry Andric     NODE_NAME_CASE(BSTRINS)
337181ad6265SDimitry Andric     NODE_NAME_CASE(BSTRPICK)
3372753f127fSDimitry Andric     NODE_NAME_CASE(MOVGR2FR_W_LA64)
3373753f127fSDimitry Andric     NODE_NAME_CASE(MOVFR2GR_S_LA64)
3374753f127fSDimitry Andric     NODE_NAME_CASE(FTINT)
3375bdd1243dSDimitry Andric     NODE_NAME_CASE(REVB_2H)
3376bdd1243dSDimitry Andric     NODE_NAME_CASE(REVB_2W)
3377bdd1243dSDimitry Andric     NODE_NAME_CASE(BITREV_4B)
3378bdd1243dSDimitry Andric     NODE_NAME_CASE(BITREV_W)
3379bdd1243dSDimitry Andric     NODE_NAME_CASE(ROTR_W)
3380bdd1243dSDimitry Andric     NODE_NAME_CASE(ROTL_W)
3381bdd1243dSDimitry Andric     NODE_NAME_CASE(CLZ_W)
3382bdd1243dSDimitry Andric     NODE_NAME_CASE(CTZ_W)
3383bdd1243dSDimitry Andric     NODE_NAME_CASE(DBAR)
3384bdd1243dSDimitry Andric     NODE_NAME_CASE(IBAR)
3385bdd1243dSDimitry Andric     NODE_NAME_CASE(BREAK)
3386bdd1243dSDimitry Andric     NODE_NAME_CASE(SYSCALL)
3387bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_B_W)
3388bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_H_W)
3389bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_W_W)
3390bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_D_W)
3391bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_B_W)
3392bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_H_W)
3393bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_W_W)
3394bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_D_W)
3395bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRRD)
3396bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRWR)
3397bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRXCHG)
3398bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_B)
3399bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_H)
3400bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_W)
3401bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_D)
3402bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_B)
3403bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_H)
3404bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_W)
3405bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_D)
3406bdd1243dSDimitry Andric     NODE_NAME_CASE(CPUCFG)
3407bdd1243dSDimitry Andric     NODE_NAME_CASE(MOVGR2FCSR)
3408bdd1243dSDimitry Andric     NODE_NAME_CASE(MOVFCSR2GR)
3409bdd1243dSDimitry Andric     NODE_NAME_CASE(CACOP_D)
3410bdd1243dSDimitry Andric     NODE_NAME_CASE(CACOP_W)
3411*5f757f3fSDimitry Andric     NODE_NAME_CASE(VPICK_SEXT_ELT)
3412*5f757f3fSDimitry Andric     NODE_NAME_CASE(VPICK_ZEXT_ELT)
3413*5f757f3fSDimitry Andric     NODE_NAME_CASE(VREPLVE)
3414*5f757f3fSDimitry Andric     NODE_NAME_CASE(VALL_ZERO)
3415*5f757f3fSDimitry Andric     NODE_NAME_CASE(VANY_ZERO)
3416*5f757f3fSDimitry Andric     NODE_NAME_CASE(VALL_NONZERO)
3417*5f757f3fSDimitry Andric     NODE_NAME_CASE(VANY_NONZERO)
341881ad6265SDimitry Andric   }
341981ad6265SDimitry Andric #undef NODE_NAME_CASE
342081ad6265SDimitry Andric   return nullptr;
342181ad6265SDimitry Andric }
342281ad6265SDimitry Andric 
342381ad6265SDimitry Andric //===----------------------------------------------------------------------===//
342481ad6265SDimitry Andric //                     Calling Convention Implementation
342581ad6265SDimitry Andric //===----------------------------------------------------------------------===//
3426bdd1243dSDimitry Andric 
3427bdd1243dSDimitry Andric // Eight general-purpose registers a0-a7 used for passing integer arguments,
3428bdd1243dSDimitry Andric // with a0-a1 reused to return values. Generally, the GPRs are used to pass
3429bdd1243dSDimitry Andric // fixed-point arguments, and floating-point arguments when no FPR is available
3430bdd1243dSDimitry Andric // or with soft float ABI.
343181ad6265SDimitry Andric const MCPhysReg ArgGPRs[] = {LoongArch::R4,  LoongArch::R5, LoongArch::R6,
343281ad6265SDimitry Andric                              LoongArch::R7,  LoongArch::R8, LoongArch::R9,
343381ad6265SDimitry Andric                              LoongArch::R10, LoongArch::R11};
3434bdd1243dSDimitry Andric // Eight floating-point registers fa0-fa7 used for passing floating-point
3435bdd1243dSDimitry Andric // arguments, and fa0-fa1 are also used to return values.
343681ad6265SDimitry Andric const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
343781ad6265SDimitry Andric                                LoongArch::F3, LoongArch::F4, LoongArch::F5,
343881ad6265SDimitry Andric                                LoongArch::F6, LoongArch::F7};
3439bdd1243dSDimitry Andric // FPR32 and FPR64 alias each other.
344081ad6265SDimitry Andric const MCPhysReg ArgFPR64s[] = {
344181ad6265SDimitry Andric     LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
344281ad6265SDimitry Andric     LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
344381ad6265SDimitry Andric 
3444*5f757f3fSDimitry Andric const MCPhysReg ArgVRs[] = {LoongArch::VR0, LoongArch::VR1, LoongArch::VR2,
3445*5f757f3fSDimitry Andric                             LoongArch::VR3, LoongArch::VR4, LoongArch::VR5,
3446*5f757f3fSDimitry Andric                             LoongArch::VR6, LoongArch::VR7};
3447*5f757f3fSDimitry Andric 
3448*5f757f3fSDimitry Andric const MCPhysReg ArgXRs[] = {LoongArch::XR0, LoongArch::XR1, LoongArch::XR2,
3449*5f757f3fSDimitry Andric                             LoongArch::XR3, LoongArch::XR4, LoongArch::XR5,
3450*5f757f3fSDimitry Andric                             LoongArch::XR6, LoongArch::XR7};
3451*5f757f3fSDimitry Andric 
3452bdd1243dSDimitry Andric // Pass a 2*GRLen argument that has been split into two GRLen values through
3453bdd1243dSDimitry Andric // registers or the stack as necessary.
3454bdd1243dSDimitry Andric static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
3455bdd1243dSDimitry Andric                                      CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
3456bdd1243dSDimitry Andric                                      unsigned ValNo2, MVT ValVT2, MVT LocVT2,
3457bdd1243dSDimitry Andric                                      ISD::ArgFlagsTy ArgFlags2) {
3458bdd1243dSDimitry Andric   unsigned GRLenInBytes = GRLen / 8;
3459bdd1243dSDimitry Andric   if (Register Reg = State.AllocateReg(ArgGPRs)) {
3460bdd1243dSDimitry Andric     // At least one half can be passed via register.
3461bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
3462bdd1243dSDimitry Andric                                      VA1.getLocVT(), CCValAssign::Full));
3463bdd1243dSDimitry Andric   } else {
3464bdd1243dSDimitry Andric     // Both halves must be passed on the stack, with proper alignment.
3465bdd1243dSDimitry Andric     Align StackAlign =
3466bdd1243dSDimitry Andric         std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
3467bdd1243dSDimitry Andric     State.addLoc(
3468bdd1243dSDimitry Andric         CCValAssign::getMem(VA1.getValNo(), VA1.getValVT(),
3469bdd1243dSDimitry Andric                             State.AllocateStack(GRLenInBytes, StackAlign),
3470bdd1243dSDimitry Andric                             VA1.getLocVT(), CCValAssign::Full));
3471bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getMem(
3472bdd1243dSDimitry Andric         ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
3473bdd1243dSDimitry Andric         LocVT2, CCValAssign::Full));
3474bdd1243dSDimitry Andric     return false;
3475bdd1243dSDimitry Andric   }
3476bdd1243dSDimitry Andric   if (Register Reg = State.AllocateReg(ArgGPRs)) {
3477bdd1243dSDimitry Andric     // The second half can also be passed via register.
3478bdd1243dSDimitry Andric     State.addLoc(
3479bdd1243dSDimitry Andric         CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
3480bdd1243dSDimitry Andric   } else {
3481bdd1243dSDimitry Andric     // The second half is passed via the stack, without additional alignment.
3482bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getMem(
3483bdd1243dSDimitry Andric         ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
3484bdd1243dSDimitry Andric         LocVT2, CCValAssign::Full));
3485bdd1243dSDimitry Andric   }
348681ad6265SDimitry Andric   return false;
348781ad6265SDimitry Andric }
348881ad6265SDimitry Andric 
3489bdd1243dSDimitry Andric // Implements the LoongArch calling convention. Returns true upon failure.
3490bdd1243dSDimitry Andric static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI,
3491bdd1243dSDimitry Andric                          unsigned ValNo, MVT ValVT,
3492bdd1243dSDimitry Andric                          CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
3493bdd1243dSDimitry Andric                          CCState &State, bool IsFixed, bool IsRet,
3494bdd1243dSDimitry Andric                          Type *OrigTy) {
3495bdd1243dSDimitry Andric   unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
3496bdd1243dSDimitry Andric   assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
3497bdd1243dSDimitry Andric   MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
3498bdd1243dSDimitry Andric   MVT LocVT = ValVT;
3499bdd1243dSDimitry Andric 
3500bdd1243dSDimitry Andric   // Any return value split into more than two values can't be returned
3501bdd1243dSDimitry Andric   // directly.
3502bdd1243dSDimitry Andric   if (IsRet && ValNo > 1)
350381ad6265SDimitry Andric     return true;
3504bdd1243dSDimitry Andric 
3505bdd1243dSDimitry Andric   // If passing a variadic argument, or if no FPR is available.
3506bdd1243dSDimitry Andric   bool UseGPRForFloat = true;
3507bdd1243dSDimitry Andric 
3508bdd1243dSDimitry Andric   switch (ABI) {
3509bdd1243dSDimitry Andric   default:
3510bdd1243dSDimitry Andric     llvm_unreachable("Unexpected ABI");
3511bdd1243dSDimitry Andric   case LoongArchABI::ABI_ILP32S:
3512bdd1243dSDimitry Andric   case LoongArchABI::ABI_ILP32F:
3513bdd1243dSDimitry Andric   case LoongArchABI::ABI_LP64F:
3514bdd1243dSDimitry Andric     report_fatal_error("Unimplemented ABI");
3515bdd1243dSDimitry Andric     break;
3516bdd1243dSDimitry Andric   case LoongArchABI::ABI_ILP32D:
3517bdd1243dSDimitry Andric   case LoongArchABI::ABI_LP64D:
3518bdd1243dSDimitry Andric     UseGPRForFloat = !IsFixed;
3519bdd1243dSDimitry Andric     break;
352006c3fb27SDimitry Andric   case LoongArchABI::ABI_LP64S:
352106c3fb27SDimitry Andric     break;
3522bdd1243dSDimitry Andric   }
3523bdd1243dSDimitry Andric 
3524bdd1243dSDimitry Andric   // FPR32 and FPR64 alias each other.
3525bdd1243dSDimitry Andric   if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
3526bdd1243dSDimitry Andric     UseGPRForFloat = true;
3527bdd1243dSDimitry Andric 
3528bdd1243dSDimitry Andric   if (UseGPRForFloat && ValVT == MVT::f32) {
3529bdd1243dSDimitry Andric     LocVT = GRLenVT;
3530bdd1243dSDimitry Andric     LocInfo = CCValAssign::BCvt;
3531bdd1243dSDimitry Andric   } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
3532bdd1243dSDimitry Andric     LocVT = MVT::i64;
3533bdd1243dSDimitry Andric     LocInfo = CCValAssign::BCvt;
3534bdd1243dSDimitry Andric   } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
3535bdd1243dSDimitry Andric     // TODO: Handle passing f64 on LA32 with D feature.
3536bdd1243dSDimitry Andric     report_fatal_error("Passing f64 with GPR on LA32 is undefined");
3537bdd1243dSDimitry Andric   }
3538bdd1243dSDimitry Andric 
3539bdd1243dSDimitry Andric   // If this is a variadic argument, the LoongArch calling convention requires
3540bdd1243dSDimitry Andric   // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
3541bdd1243dSDimitry Andric   // byte alignment. An aligned register should be used regardless of whether
3542bdd1243dSDimitry Andric   // the original argument was split during legalisation or not. The argument
3543bdd1243dSDimitry Andric   // will not be passed by registers if the original type is larger than
3544bdd1243dSDimitry Andric   // 2*GRLen, so the register alignment rule does not apply.
3545bdd1243dSDimitry Andric   unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
3546bdd1243dSDimitry Andric   if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
3547bdd1243dSDimitry Andric       DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
3548bdd1243dSDimitry Andric     unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
3549bdd1243dSDimitry Andric     // Skip 'odd' register if necessary.
3550bdd1243dSDimitry Andric     if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
3551bdd1243dSDimitry Andric       State.AllocateReg(ArgGPRs);
3552bdd1243dSDimitry Andric   }
3553bdd1243dSDimitry Andric 
3554bdd1243dSDimitry Andric   SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
3555bdd1243dSDimitry Andric   SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
3556bdd1243dSDimitry Andric       State.getPendingArgFlags();
3557bdd1243dSDimitry Andric 
3558bdd1243dSDimitry Andric   assert(PendingLocs.size() == PendingArgFlags.size() &&
3559bdd1243dSDimitry Andric          "PendingLocs and PendingArgFlags out of sync");
3560bdd1243dSDimitry Andric 
3561bdd1243dSDimitry Andric   // Split arguments might be passed indirectly, so keep track of the pending
3562bdd1243dSDimitry Andric   // values.
3563bdd1243dSDimitry Andric   if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
3564bdd1243dSDimitry Andric     LocVT = GRLenVT;
3565bdd1243dSDimitry Andric     LocInfo = CCValAssign::Indirect;
3566bdd1243dSDimitry Andric     PendingLocs.push_back(
3567bdd1243dSDimitry Andric         CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
3568bdd1243dSDimitry Andric     PendingArgFlags.push_back(ArgFlags);
3569bdd1243dSDimitry Andric     if (!ArgFlags.isSplitEnd()) {
3570bdd1243dSDimitry Andric       return false;
3571bdd1243dSDimitry Andric     }
3572bdd1243dSDimitry Andric   }
3573bdd1243dSDimitry Andric 
3574bdd1243dSDimitry Andric   // If the split argument only had two elements, it should be passed directly
3575bdd1243dSDimitry Andric   // in registers or on the stack.
3576bdd1243dSDimitry Andric   if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
3577bdd1243dSDimitry Andric       PendingLocs.size() <= 2) {
3578bdd1243dSDimitry Andric     assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
3579bdd1243dSDimitry Andric     // Apply the normal calling convention rules to the first half of the
3580bdd1243dSDimitry Andric     // split argument.
3581bdd1243dSDimitry Andric     CCValAssign VA = PendingLocs[0];
3582bdd1243dSDimitry Andric     ISD::ArgFlagsTy AF = PendingArgFlags[0];
3583bdd1243dSDimitry Andric     PendingLocs.clear();
3584bdd1243dSDimitry Andric     PendingArgFlags.clear();
3585bdd1243dSDimitry Andric     return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
3586bdd1243dSDimitry Andric                                     ArgFlags);
3587bdd1243dSDimitry Andric   }
3588bdd1243dSDimitry Andric 
3589bdd1243dSDimitry Andric   // Allocate to a register if possible, or else a stack slot.
3590bdd1243dSDimitry Andric   Register Reg;
3591bdd1243dSDimitry Andric   unsigned StoreSizeBytes = GRLen / 8;
3592bdd1243dSDimitry Andric   Align StackAlign = Align(GRLen / 8);
3593bdd1243dSDimitry Andric 
3594bdd1243dSDimitry Andric   if (ValVT == MVT::f32 && !UseGPRForFloat)
3595bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgFPR32s);
3596bdd1243dSDimitry Andric   else if (ValVT == MVT::f64 && !UseGPRForFloat)
3597bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgFPR64s);
3598*5f757f3fSDimitry Andric   else if (ValVT.is128BitVector())
3599*5f757f3fSDimitry Andric     Reg = State.AllocateReg(ArgVRs);
3600*5f757f3fSDimitry Andric   else if (ValVT.is256BitVector())
3601*5f757f3fSDimitry Andric     Reg = State.AllocateReg(ArgXRs);
3602bdd1243dSDimitry Andric   else
3603bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgGPRs);
3604bdd1243dSDimitry Andric 
3605bdd1243dSDimitry Andric   unsigned StackOffset =
3606bdd1243dSDimitry Andric       Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
3607bdd1243dSDimitry Andric 
3608bdd1243dSDimitry Andric   // If we reach this point and PendingLocs is non-empty, we must be at the
3609bdd1243dSDimitry Andric   // end of a split argument that must be passed indirectly.
3610bdd1243dSDimitry Andric   if (!PendingLocs.empty()) {
3611bdd1243dSDimitry Andric     assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
3612bdd1243dSDimitry Andric     assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
3613bdd1243dSDimitry Andric     for (auto &It : PendingLocs) {
3614bdd1243dSDimitry Andric       if (Reg)
3615bdd1243dSDimitry Andric         It.convertToReg(Reg);
3616bdd1243dSDimitry Andric       else
3617bdd1243dSDimitry Andric         It.convertToMem(StackOffset);
3618bdd1243dSDimitry Andric       State.addLoc(It);
3619bdd1243dSDimitry Andric     }
3620bdd1243dSDimitry Andric     PendingLocs.clear();
3621bdd1243dSDimitry Andric     PendingArgFlags.clear();
3622bdd1243dSDimitry Andric     return false;
3623bdd1243dSDimitry Andric   }
3624bdd1243dSDimitry Andric   assert((!UseGPRForFloat || LocVT == GRLenVT) &&
3625bdd1243dSDimitry Andric          "Expected an GRLenVT at this stage");
3626bdd1243dSDimitry Andric 
3627bdd1243dSDimitry Andric   if (Reg) {
3628bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
3629bdd1243dSDimitry Andric     return false;
3630bdd1243dSDimitry Andric   }
3631bdd1243dSDimitry Andric 
3632bdd1243dSDimitry Andric   // When a floating-point value is passed on the stack, no bit-cast is needed.
3633bdd1243dSDimitry Andric   if (ValVT.isFloatingPoint()) {
3634bdd1243dSDimitry Andric     LocVT = ValVT;
3635bdd1243dSDimitry Andric     LocInfo = CCValAssign::Full;
3636bdd1243dSDimitry Andric   }
3637bdd1243dSDimitry Andric 
3638bdd1243dSDimitry Andric   State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
3639bdd1243dSDimitry Andric   return false;
364081ad6265SDimitry Andric }
364181ad6265SDimitry Andric 
364281ad6265SDimitry Andric void LoongArchTargetLowering::analyzeInputArgs(
3643bdd1243dSDimitry Andric     MachineFunction &MF, CCState &CCInfo,
3644bdd1243dSDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
364581ad6265SDimitry Andric     LoongArchCCAssignFn Fn) const {
3646bdd1243dSDimitry Andric   FunctionType *FType = MF.getFunction().getFunctionType();
364781ad6265SDimitry Andric   for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
364881ad6265SDimitry Andric     MVT ArgVT = Ins[i].VT;
3649bdd1243dSDimitry Andric     Type *ArgTy = nullptr;
3650bdd1243dSDimitry Andric     if (IsRet)
3651bdd1243dSDimitry Andric       ArgTy = FType->getReturnType();
3652bdd1243dSDimitry Andric     else if (Ins[i].isOrigArg())
3653bdd1243dSDimitry Andric       ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
3654bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
3655bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
3656bdd1243dSDimitry Andric     if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
3657bdd1243dSDimitry Andric            CCInfo, /*IsFixed=*/true, IsRet, ArgTy)) {
365806c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT
365906c3fb27SDimitry Andric                         << '\n');
366081ad6265SDimitry Andric       llvm_unreachable("");
366181ad6265SDimitry Andric     }
366281ad6265SDimitry Andric   }
366381ad6265SDimitry Andric }
366481ad6265SDimitry Andric 
366581ad6265SDimitry Andric void LoongArchTargetLowering::analyzeOutputArgs(
3666bdd1243dSDimitry Andric     MachineFunction &MF, CCState &CCInfo,
3667bdd1243dSDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
3668bdd1243dSDimitry Andric     CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
366981ad6265SDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
367081ad6265SDimitry Andric     MVT ArgVT = Outs[i].VT;
3671bdd1243dSDimitry Andric     Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
3672bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
3673bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
3674bdd1243dSDimitry Andric     if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
3675bdd1243dSDimitry Andric            CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) {
367606c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT
367706c3fb27SDimitry Andric                         << "\n");
367881ad6265SDimitry Andric       llvm_unreachable("");
367981ad6265SDimitry Andric     }
368081ad6265SDimitry Andric   }
368181ad6265SDimitry Andric }
368281ad6265SDimitry Andric 
3683bdd1243dSDimitry Andric // Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
3684bdd1243dSDimitry Andric // values.
3685bdd1243dSDimitry Andric static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val,
3686bdd1243dSDimitry Andric                                    const CCValAssign &VA, const SDLoc &DL) {
3687bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
3688bdd1243dSDimitry Andric   default:
3689bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
3690bdd1243dSDimitry Andric   case CCValAssign::Full:
3691bdd1243dSDimitry Andric   case CCValAssign::Indirect:
3692bdd1243dSDimitry Andric     break;
3693bdd1243dSDimitry Andric   case CCValAssign::BCvt:
3694bdd1243dSDimitry Andric     if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
3695bdd1243dSDimitry Andric       Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
3696bdd1243dSDimitry Andric     else
3697bdd1243dSDimitry Andric       Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
3698bdd1243dSDimitry Andric     break;
3699bdd1243dSDimitry Andric   }
3700bdd1243dSDimitry Andric   return Val;
3701bdd1243dSDimitry Andric }
3702bdd1243dSDimitry Andric 
370381ad6265SDimitry Andric static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain,
370481ad6265SDimitry Andric                                 const CCValAssign &VA, const SDLoc &DL,
370581ad6265SDimitry Andric                                 const LoongArchTargetLowering &TLI) {
370681ad6265SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
370781ad6265SDimitry Andric   MachineRegisterInfo &RegInfo = MF.getRegInfo();
370881ad6265SDimitry Andric   EVT LocVT = VA.getLocVT();
3709bdd1243dSDimitry Andric   SDValue Val;
371081ad6265SDimitry Andric   const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
371181ad6265SDimitry Andric   Register VReg = RegInfo.createVirtualRegister(RC);
371281ad6265SDimitry Andric   RegInfo.addLiveIn(VA.getLocReg(), VReg);
3713bdd1243dSDimitry Andric   Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
371481ad6265SDimitry Andric 
3715bdd1243dSDimitry Andric   return convertLocVTToValVT(DAG, Val, VA, DL);
3716bdd1243dSDimitry Andric }
3717bdd1243dSDimitry Andric 
3718bdd1243dSDimitry Andric // The caller is responsible for loading the full value if the argument is
3719bdd1243dSDimitry Andric // passed with CCValAssign::Indirect.
3720bdd1243dSDimitry Andric static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain,
3721bdd1243dSDimitry Andric                                 const CCValAssign &VA, const SDLoc &DL) {
3722bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
3723bdd1243dSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
3724bdd1243dSDimitry Andric   EVT ValVT = VA.getValVT();
3725bdd1243dSDimitry Andric   int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
3726bdd1243dSDimitry Andric                                  /*IsImmutable=*/true);
3727bdd1243dSDimitry Andric   SDValue FIN = DAG.getFrameIndex(
3728bdd1243dSDimitry Andric       FI, MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0)));
3729bdd1243dSDimitry Andric 
3730bdd1243dSDimitry Andric   ISD::LoadExtType ExtType;
3731bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
3732bdd1243dSDimitry Andric   default:
3733bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
3734bdd1243dSDimitry Andric   case CCValAssign::Full:
3735bdd1243dSDimitry Andric   case CCValAssign::Indirect:
3736bdd1243dSDimitry Andric   case CCValAssign::BCvt:
3737bdd1243dSDimitry Andric     ExtType = ISD::NON_EXTLOAD;
3738bdd1243dSDimitry Andric     break;
3739bdd1243dSDimitry Andric   }
3740bdd1243dSDimitry Andric   return DAG.getExtLoad(
3741bdd1243dSDimitry Andric       ExtType, DL, VA.getLocVT(), Chain, FIN,
3742bdd1243dSDimitry Andric       MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT);
3743bdd1243dSDimitry Andric }
3744bdd1243dSDimitry Andric 
3745bdd1243dSDimitry Andric static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
3746bdd1243dSDimitry Andric                                    const CCValAssign &VA, const SDLoc &DL) {
3747bdd1243dSDimitry Andric   EVT LocVT = VA.getLocVT();
3748bdd1243dSDimitry Andric 
3749bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
3750bdd1243dSDimitry Andric   default:
3751bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
3752bdd1243dSDimitry Andric   case CCValAssign::Full:
3753bdd1243dSDimitry Andric     break;
3754bdd1243dSDimitry Andric   case CCValAssign::BCvt:
3755bdd1243dSDimitry Andric     if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
3756bdd1243dSDimitry Andric       Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
3757bdd1243dSDimitry Andric     else
3758bdd1243dSDimitry Andric       Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
3759bdd1243dSDimitry Andric     break;
3760bdd1243dSDimitry Andric   }
3761bdd1243dSDimitry Andric   return Val;
3762bdd1243dSDimitry Andric }
3763bdd1243dSDimitry Andric 
3764bdd1243dSDimitry Andric static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
3765bdd1243dSDimitry Andric                              CCValAssign::LocInfo LocInfo,
3766bdd1243dSDimitry Andric                              ISD::ArgFlagsTy ArgFlags, CCState &State) {
3767bdd1243dSDimitry Andric   if (LocVT == MVT::i32 || LocVT == MVT::i64) {
3768bdd1243dSDimitry Andric     // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
3769bdd1243dSDimitry Andric     //                        s0    s1  s2  s3  s4  s5  s6  s7  s8
3770bdd1243dSDimitry Andric     static const MCPhysReg GPRList[] = {
377106c3fb27SDimitry Andric         LoongArch::R23, LoongArch::R24, LoongArch::R25,
377206c3fb27SDimitry Andric         LoongArch::R26, LoongArch::R27, LoongArch::R28,
377306c3fb27SDimitry Andric         LoongArch::R29, LoongArch::R30, LoongArch::R31};
3774bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(GPRList)) {
3775bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
3776bdd1243dSDimitry Andric       return false;
3777bdd1243dSDimitry Andric     }
3778bdd1243dSDimitry Andric   }
3779bdd1243dSDimitry Andric 
3780bdd1243dSDimitry Andric   if (LocVT == MVT::f32) {
3781bdd1243dSDimitry Andric     // Pass in STG registers: F1, F2, F3, F4
3782bdd1243dSDimitry Andric     //                        fs0,fs1,fs2,fs3
3783bdd1243dSDimitry Andric     static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
3784bdd1243dSDimitry Andric                                           LoongArch::F26, LoongArch::F27};
3785bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(FPR32List)) {
3786bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
3787bdd1243dSDimitry Andric       return false;
3788bdd1243dSDimitry Andric     }
3789bdd1243dSDimitry Andric   }
3790bdd1243dSDimitry Andric 
3791bdd1243dSDimitry Andric   if (LocVT == MVT::f64) {
3792bdd1243dSDimitry Andric     // Pass in STG registers: D1, D2, D3, D4
3793bdd1243dSDimitry Andric     //                        fs4,fs5,fs6,fs7
3794bdd1243dSDimitry Andric     static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
3795bdd1243dSDimitry Andric                                           LoongArch::F30_64, LoongArch::F31_64};
3796bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(FPR64List)) {
3797bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
3798bdd1243dSDimitry Andric       return false;
3799bdd1243dSDimitry Andric     }
3800bdd1243dSDimitry Andric   }
3801bdd1243dSDimitry Andric 
3802bdd1243dSDimitry Andric   report_fatal_error("No registers left in GHC calling convention");
3803bdd1243dSDimitry Andric   return true;
380481ad6265SDimitry Andric }
380581ad6265SDimitry Andric 
380681ad6265SDimitry Andric // Transform physical registers into virtual registers.
380781ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerFormalArguments(
380881ad6265SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
380981ad6265SDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
381081ad6265SDimitry Andric     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
381181ad6265SDimitry Andric 
381281ad6265SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
381381ad6265SDimitry Andric 
381481ad6265SDimitry Andric   switch (CallConv) {
381581ad6265SDimitry Andric   default:
381681ad6265SDimitry Andric     llvm_unreachable("Unsupported calling convention");
381781ad6265SDimitry Andric   case CallingConv::C:
3818bdd1243dSDimitry Andric   case CallingConv::Fast:
381981ad6265SDimitry Andric     break;
3820bdd1243dSDimitry Andric   case CallingConv::GHC:
382106c3fb27SDimitry Andric     if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
382206c3fb27SDimitry Andric         !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
3823bdd1243dSDimitry Andric       report_fatal_error(
3824bdd1243dSDimitry Andric           "GHC calling convention requires the F and D extensions");
382581ad6265SDimitry Andric   }
382681ad6265SDimitry Andric 
3827bdd1243dSDimitry Andric   EVT PtrVT = getPointerTy(DAG.getDataLayout());
3828bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
3829bdd1243dSDimitry Andric   unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
3830bdd1243dSDimitry Andric   // Used with varargs to acumulate store chains.
3831bdd1243dSDimitry Andric   std::vector<SDValue> OutChains;
3832bdd1243dSDimitry Andric 
383381ad6265SDimitry Andric   // Assign locations to all of the incoming arguments.
383481ad6265SDimitry Andric   SmallVector<CCValAssign> ArgLocs;
383581ad6265SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
383681ad6265SDimitry Andric 
3837bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC)
3838bdd1243dSDimitry Andric     CCInfo.AnalyzeFormalArguments(Ins, CC_LoongArch_GHC);
3839bdd1243dSDimitry Andric   else
3840bdd1243dSDimitry Andric     analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
384181ad6265SDimitry Andric 
3842bdd1243dSDimitry Andric   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
3843bdd1243dSDimitry Andric     CCValAssign &VA = ArgLocs[i];
3844bdd1243dSDimitry Andric     SDValue ArgValue;
3845bdd1243dSDimitry Andric     if (VA.isRegLoc())
3846bdd1243dSDimitry Andric       ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, *this);
3847bdd1243dSDimitry Andric     else
3848bdd1243dSDimitry Andric       ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
3849bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect) {
3850bdd1243dSDimitry Andric       // If the original argument was split and passed by reference, we need to
3851bdd1243dSDimitry Andric       // load all parts of it here (using the same address).
3852bdd1243dSDimitry Andric       InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
3853bdd1243dSDimitry Andric                                    MachinePointerInfo()));
3854bdd1243dSDimitry Andric       unsigned ArgIndex = Ins[i].OrigArgIndex;
3855bdd1243dSDimitry Andric       unsigned ArgPartOffset = Ins[i].PartOffset;
3856bdd1243dSDimitry Andric       assert(ArgPartOffset == 0);
3857bdd1243dSDimitry Andric       while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) {
3858bdd1243dSDimitry Andric         CCValAssign &PartVA = ArgLocs[i + 1];
3859bdd1243dSDimitry Andric         unsigned PartOffset = Ins[i + 1].PartOffset - ArgPartOffset;
3860bdd1243dSDimitry Andric         SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
3861bdd1243dSDimitry Andric         SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
3862bdd1243dSDimitry Andric         InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
3863bdd1243dSDimitry Andric                                      MachinePointerInfo()));
3864bdd1243dSDimitry Andric         ++i;
3865bdd1243dSDimitry Andric       }
3866bdd1243dSDimitry Andric       continue;
3867bdd1243dSDimitry Andric     }
3868bdd1243dSDimitry Andric     InVals.push_back(ArgValue);
3869bdd1243dSDimitry Andric   }
3870bdd1243dSDimitry Andric 
3871bdd1243dSDimitry Andric   if (IsVarArg) {
3872bdd1243dSDimitry Andric     ArrayRef<MCPhysReg> ArgRegs = ArrayRef(ArgGPRs);
3873bdd1243dSDimitry Andric     unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
3874bdd1243dSDimitry Andric     const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
3875bdd1243dSDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
3876bdd1243dSDimitry Andric     MachineRegisterInfo &RegInfo = MF.getRegInfo();
3877bdd1243dSDimitry Andric     auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
3878bdd1243dSDimitry Andric 
3879bdd1243dSDimitry Andric     // Offset of the first variable argument from stack pointer, and size of
3880bdd1243dSDimitry Andric     // the vararg save area. For now, the varargs save area is either zero or
3881bdd1243dSDimitry Andric     // large enough to hold a0-a7.
3882bdd1243dSDimitry Andric     int VaArgOffset, VarArgsSaveSize;
3883bdd1243dSDimitry Andric 
3884bdd1243dSDimitry Andric     // If all registers are allocated, then all varargs must be passed on the
3885bdd1243dSDimitry Andric     // stack and we don't need to save any argregs.
3886bdd1243dSDimitry Andric     if (ArgRegs.size() == Idx) {
388706c3fb27SDimitry Andric       VaArgOffset = CCInfo.getStackSize();
3888bdd1243dSDimitry Andric       VarArgsSaveSize = 0;
3889bdd1243dSDimitry Andric     } else {
3890bdd1243dSDimitry Andric       VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
3891bdd1243dSDimitry Andric       VaArgOffset = -VarArgsSaveSize;
3892bdd1243dSDimitry Andric     }
3893bdd1243dSDimitry Andric 
3894bdd1243dSDimitry Andric     // Record the frame index of the first variable argument
3895bdd1243dSDimitry Andric     // which is a value necessary to VASTART.
3896bdd1243dSDimitry Andric     int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
3897bdd1243dSDimitry Andric     LoongArchFI->setVarArgsFrameIndex(FI);
3898bdd1243dSDimitry Andric 
3899bdd1243dSDimitry Andric     // If saving an odd number of registers then create an extra stack slot to
3900bdd1243dSDimitry Andric     // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
3901bdd1243dSDimitry Andric     // offsets to even-numbered registered remain 2*GRLen-aligned.
3902bdd1243dSDimitry Andric     if (Idx % 2) {
3903bdd1243dSDimitry Andric       MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
3904bdd1243dSDimitry Andric                             true);
3905bdd1243dSDimitry Andric       VarArgsSaveSize += GRLenInBytes;
3906bdd1243dSDimitry Andric     }
3907bdd1243dSDimitry Andric 
3908bdd1243dSDimitry Andric     // Copy the integer registers that may have been used for passing varargs
3909bdd1243dSDimitry Andric     // to the vararg save area.
3910bdd1243dSDimitry Andric     for (unsigned I = Idx; I < ArgRegs.size();
3911bdd1243dSDimitry Andric          ++I, VaArgOffset += GRLenInBytes) {
3912bdd1243dSDimitry Andric       const Register Reg = RegInfo.createVirtualRegister(RC);
3913bdd1243dSDimitry Andric       RegInfo.addLiveIn(ArgRegs[I], Reg);
3914bdd1243dSDimitry Andric       SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
3915bdd1243dSDimitry Andric       FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
3916bdd1243dSDimitry Andric       SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
3917bdd1243dSDimitry Andric       SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
3918bdd1243dSDimitry Andric                                    MachinePointerInfo::getFixedStack(MF, FI));
3919bdd1243dSDimitry Andric       cast<StoreSDNode>(Store.getNode())
3920bdd1243dSDimitry Andric           ->getMemOperand()
3921bdd1243dSDimitry Andric           ->setValue((Value *)nullptr);
3922bdd1243dSDimitry Andric       OutChains.push_back(Store);
3923bdd1243dSDimitry Andric     }
3924bdd1243dSDimitry Andric     LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
3925bdd1243dSDimitry Andric   }
3926bdd1243dSDimitry Andric 
3927bdd1243dSDimitry Andric   // All stores are grouped in one node to allow the matching between
3928bdd1243dSDimitry Andric   // the size of Ins and InVals. This only happens for vararg functions.
3929bdd1243dSDimitry Andric   if (!OutChains.empty()) {
3930bdd1243dSDimitry Andric     OutChains.push_back(Chain);
3931bdd1243dSDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
3932bdd1243dSDimitry Andric   }
393381ad6265SDimitry Andric 
393481ad6265SDimitry Andric   return Chain;
393581ad6265SDimitry Andric }
393681ad6265SDimitry Andric 
3937bdd1243dSDimitry Andric bool LoongArchTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
3938bdd1243dSDimitry Andric   return CI->isTailCall();
3939bdd1243dSDimitry Andric }
3940bdd1243dSDimitry Andric 
394106c3fb27SDimitry Andric // Check if the return value is used as only a return value, as otherwise
394206c3fb27SDimitry Andric // we can't perform a tail-call.
394306c3fb27SDimitry Andric bool LoongArchTargetLowering::isUsedByReturnOnly(SDNode *N,
394406c3fb27SDimitry Andric                                                  SDValue &Chain) const {
394506c3fb27SDimitry Andric   if (N->getNumValues() != 1)
394606c3fb27SDimitry Andric     return false;
394706c3fb27SDimitry Andric   if (!N->hasNUsesOfValue(1, 0))
394806c3fb27SDimitry Andric     return false;
394906c3fb27SDimitry Andric 
395006c3fb27SDimitry Andric   SDNode *Copy = *N->use_begin();
395106c3fb27SDimitry Andric   if (Copy->getOpcode() != ISD::CopyToReg)
395206c3fb27SDimitry Andric     return false;
395306c3fb27SDimitry Andric 
395406c3fb27SDimitry Andric   // If the ISD::CopyToReg has a glue operand, we conservatively assume it
395506c3fb27SDimitry Andric   // isn't safe to perform a tail call.
395606c3fb27SDimitry Andric   if (Copy->getGluedNode())
395706c3fb27SDimitry Andric     return false;
395806c3fb27SDimitry Andric 
395906c3fb27SDimitry Andric   // The copy must be used by a LoongArchISD::RET, and nothing else.
396006c3fb27SDimitry Andric   bool HasRet = false;
396106c3fb27SDimitry Andric   for (SDNode *Node : Copy->uses()) {
396206c3fb27SDimitry Andric     if (Node->getOpcode() != LoongArchISD::RET)
396306c3fb27SDimitry Andric       return false;
396406c3fb27SDimitry Andric     HasRet = true;
396506c3fb27SDimitry Andric   }
396606c3fb27SDimitry Andric 
396706c3fb27SDimitry Andric   if (!HasRet)
396806c3fb27SDimitry Andric     return false;
396906c3fb27SDimitry Andric 
397006c3fb27SDimitry Andric   Chain = Copy->getOperand(0);
397106c3fb27SDimitry Andric   return true;
397206c3fb27SDimitry Andric }
397306c3fb27SDimitry Andric 
3974bdd1243dSDimitry Andric // Check whether the call is eligible for tail call optimization.
3975bdd1243dSDimitry Andric bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
3976bdd1243dSDimitry Andric     CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
3977bdd1243dSDimitry Andric     const SmallVectorImpl<CCValAssign> &ArgLocs) const {
3978bdd1243dSDimitry Andric 
3979bdd1243dSDimitry Andric   auto CalleeCC = CLI.CallConv;
3980bdd1243dSDimitry Andric   auto &Outs = CLI.Outs;
3981bdd1243dSDimitry Andric   auto &Caller = MF.getFunction();
3982bdd1243dSDimitry Andric   auto CallerCC = Caller.getCallingConv();
3983bdd1243dSDimitry Andric 
3984bdd1243dSDimitry Andric   // Do not tail call opt if the stack is used to pass parameters.
398506c3fb27SDimitry Andric   if (CCInfo.getStackSize() != 0)
3986bdd1243dSDimitry Andric     return false;
3987bdd1243dSDimitry Andric 
3988bdd1243dSDimitry Andric   // Do not tail call opt if any parameters need to be passed indirectly.
3989bdd1243dSDimitry Andric   for (auto &VA : ArgLocs)
3990bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect)
3991bdd1243dSDimitry Andric       return false;
3992bdd1243dSDimitry Andric 
3993bdd1243dSDimitry Andric   // Do not tail call opt if either caller or callee uses struct return
3994bdd1243dSDimitry Andric   // semantics.
3995bdd1243dSDimitry Andric   auto IsCallerStructRet = Caller.hasStructRetAttr();
3996bdd1243dSDimitry Andric   auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
3997bdd1243dSDimitry Andric   if (IsCallerStructRet || IsCalleeStructRet)
3998bdd1243dSDimitry Andric     return false;
3999bdd1243dSDimitry Andric 
4000bdd1243dSDimitry Andric   // Do not tail call opt if either the callee or caller has a byval argument.
4001bdd1243dSDimitry Andric   for (auto &Arg : Outs)
4002bdd1243dSDimitry Andric     if (Arg.Flags.isByVal())
4003bdd1243dSDimitry Andric       return false;
4004bdd1243dSDimitry Andric 
4005bdd1243dSDimitry Andric   // The callee has to preserve all registers the caller needs to preserve.
4006bdd1243dSDimitry Andric   const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
4007bdd1243dSDimitry Andric   const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
4008bdd1243dSDimitry Andric   if (CalleeCC != CallerCC) {
4009bdd1243dSDimitry Andric     const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
4010bdd1243dSDimitry Andric     if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
4011bdd1243dSDimitry Andric       return false;
4012bdd1243dSDimitry Andric   }
4013bdd1243dSDimitry Andric   return true;
4014bdd1243dSDimitry Andric }
4015bdd1243dSDimitry Andric 
4016bdd1243dSDimitry Andric static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG) {
4017bdd1243dSDimitry Andric   return DAG.getDataLayout().getPrefTypeAlign(
4018bdd1243dSDimitry Andric       VT.getTypeForEVT(*DAG.getContext()));
4019bdd1243dSDimitry Andric }
4020bdd1243dSDimitry Andric 
4021753f127fSDimitry Andric // Lower a call to a callseq_start + CALL + callseq_end chain, and add input
4022753f127fSDimitry Andric // and output parameter nodes.
4023753f127fSDimitry Andric SDValue
4024753f127fSDimitry Andric LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
4025753f127fSDimitry Andric                                    SmallVectorImpl<SDValue> &InVals) const {
4026753f127fSDimitry Andric   SelectionDAG &DAG = CLI.DAG;
4027753f127fSDimitry Andric   SDLoc &DL = CLI.DL;
4028753f127fSDimitry Andric   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
4029753f127fSDimitry Andric   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
4030753f127fSDimitry Andric   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
4031753f127fSDimitry Andric   SDValue Chain = CLI.Chain;
4032753f127fSDimitry Andric   SDValue Callee = CLI.Callee;
4033753f127fSDimitry Andric   CallingConv::ID CallConv = CLI.CallConv;
4034753f127fSDimitry Andric   bool IsVarArg = CLI.IsVarArg;
4035753f127fSDimitry Andric   EVT PtrVT = getPointerTy(DAG.getDataLayout());
4036bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
4037bdd1243dSDimitry Andric   bool &IsTailCall = CLI.IsTailCall;
4038753f127fSDimitry Andric 
4039753f127fSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
4040753f127fSDimitry Andric 
4041753f127fSDimitry Andric   // Analyze the operands of the call, assigning locations to each operand.
4042753f127fSDimitry Andric   SmallVector<CCValAssign> ArgLocs;
4043753f127fSDimitry Andric   CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
4044753f127fSDimitry Andric 
4045bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC)
4046bdd1243dSDimitry Andric     ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
4047bdd1243dSDimitry Andric   else
4048bdd1243dSDimitry Andric     analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
4049bdd1243dSDimitry Andric 
4050bdd1243dSDimitry Andric   // Check if it's really possible to do a tail call.
4051bdd1243dSDimitry Andric   if (IsTailCall)
4052bdd1243dSDimitry Andric     IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
4053bdd1243dSDimitry Andric 
4054bdd1243dSDimitry Andric   if (IsTailCall)
4055bdd1243dSDimitry Andric     ++NumTailCalls;
4056bdd1243dSDimitry Andric   else if (CLI.CB && CLI.CB->isMustTailCall())
4057bdd1243dSDimitry Andric     report_fatal_error("failed to perform tail call elimination on a call "
4058bdd1243dSDimitry Andric                        "site marked musttail");
4059753f127fSDimitry Andric 
4060753f127fSDimitry Andric   // Get a count of how many bytes are to be pushed on the stack.
406106c3fb27SDimitry Andric   unsigned NumBytes = ArgCCInfo.getStackSize();
4062753f127fSDimitry Andric 
4063bdd1243dSDimitry Andric   // Create local copies for byval args.
4064bdd1243dSDimitry Andric   SmallVector<SDValue> ByValArgs;
4065bdd1243dSDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
4066bdd1243dSDimitry Andric     ISD::ArgFlagsTy Flags = Outs[i].Flags;
4067bdd1243dSDimitry Andric     if (!Flags.isByVal())
4068753f127fSDimitry Andric       continue;
4069bdd1243dSDimitry Andric 
4070bdd1243dSDimitry Andric     SDValue Arg = OutVals[i];
4071bdd1243dSDimitry Andric     unsigned Size = Flags.getByValSize();
4072bdd1243dSDimitry Andric     Align Alignment = Flags.getNonZeroByValAlign();
4073bdd1243dSDimitry Andric 
4074bdd1243dSDimitry Andric     int FI =
4075bdd1243dSDimitry Andric         MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
4076bdd1243dSDimitry Andric     SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
4077bdd1243dSDimitry Andric     SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
4078bdd1243dSDimitry Andric 
4079bdd1243dSDimitry Andric     Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment,
4080bdd1243dSDimitry Andric                           /*IsVolatile=*/false,
4081bdd1243dSDimitry Andric                           /*AlwaysInline=*/false, /*isTailCall=*/IsTailCall,
4082bdd1243dSDimitry Andric                           MachinePointerInfo(), MachinePointerInfo());
4083bdd1243dSDimitry Andric     ByValArgs.push_back(FIPtr);
4084753f127fSDimitry Andric   }
4085753f127fSDimitry Andric 
4086bdd1243dSDimitry Andric   if (!IsTailCall)
4087753f127fSDimitry Andric     Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
4088753f127fSDimitry Andric 
4089753f127fSDimitry Andric   // Copy argument values to their designated locations.
4090753f127fSDimitry Andric   SmallVector<std::pair<Register, SDValue>> RegsToPass;
4091bdd1243dSDimitry Andric   SmallVector<SDValue> MemOpChains;
4092bdd1243dSDimitry Andric   SDValue StackPtr;
4093bdd1243dSDimitry Andric   for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) {
4094753f127fSDimitry Andric     CCValAssign &VA = ArgLocs[i];
4095753f127fSDimitry Andric     SDValue ArgValue = OutVals[i];
4096bdd1243dSDimitry Andric     ISD::ArgFlagsTy Flags = Outs[i].Flags;
4097753f127fSDimitry Andric 
4098753f127fSDimitry Andric     // Promote the value if needed.
4099bdd1243dSDimitry Andric     // For now, only handle fully promoted and indirect arguments.
4100bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect) {
4101bdd1243dSDimitry Andric       // Store the argument in a stack slot and pass its address.
4102bdd1243dSDimitry Andric       Align StackAlign =
4103bdd1243dSDimitry Andric           std::max(getPrefTypeAlign(Outs[i].ArgVT, DAG),
4104bdd1243dSDimitry Andric                    getPrefTypeAlign(ArgValue.getValueType(), DAG));
4105bdd1243dSDimitry Andric       TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
4106bdd1243dSDimitry Andric       // If the original argument was split and passed by reference, we need to
4107bdd1243dSDimitry Andric       // store the required parts of it here (and pass just one address).
4108bdd1243dSDimitry Andric       unsigned ArgIndex = Outs[i].OrigArgIndex;
4109bdd1243dSDimitry Andric       unsigned ArgPartOffset = Outs[i].PartOffset;
4110bdd1243dSDimitry Andric       assert(ArgPartOffset == 0);
4111bdd1243dSDimitry Andric       // Calculate the total size to store. We don't have access to what we're
4112bdd1243dSDimitry Andric       // actually storing other than performing the loop and collecting the
4113bdd1243dSDimitry Andric       // info.
4114bdd1243dSDimitry Andric       SmallVector<std::pair<SDValue, SDValue>> Parts;
4115bdd1243dSDimitry Andric       while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) {
4116bdd1243dSDimitry Andric         SDValue PartValue = OutVals[i + 1];
4117bdd1243dSDimitry Andric         unsigned PartOffset = Outs[i + 1].PartOffset - ArgPartOffset;
4118bdd1243dSDimitry Andric         SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
4119bdd1243dSDimitry Andric         EVT PartVT = PartValue.getValueType();
4120bdd1243dSDimitry Andric 
4121bdd1243dSDimitry Andric         StoredSize += PartVT.getStoreSize();
4122bdd1243dSDimitry Andric         StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
4123bdd1243dSDimitry Andric         Parts.push_back(std::make_pair(PartValue, Offset));
4124bdd1243dSDimitry Andric         ++i;
4125bdd1243dSDimitry Andric       }
4126bdd1243dSDimitry Andric       SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
4127bdd1243dSDimitry Andric       int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
4128bdd1243dSDimitry Andric       MemOpChains.push_back(
4129bdd1243dSDimitry Andric           DAG.getStore(Chain, DL, ArgValue, SpillSlot,
4130bdd1243dSDimitry Andric                        MachinePointerInfo::getFixedStack(MF, FI)));
4131bdd1243dSDimitry Andric       for (const auto &Part : Parts) {
4132bdd1243dSDimitry Andric         SDValue PartValue = Part.first;
4133bdd1243dSDimitry Andric         SDValue PartOffset = Part.second;
4134bdd1243dSDimitry Andric         SDValue Address =
4135bdd1243dSDimitry Andric             DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
4136bdd1243dSDimitry Andric         MemOpChains.push_back(
4137bdd1243dSDimitry Andric             DAG.getStore(Chain, DL, PartValue, Address,
4138bdd1243dSDimitry Andric                          MachinePointerInfo::getFixedStack(MF, FI)));
4139bdd1243dSDimitry Andric       }
4140bdd1243dSDimitry Andric       ArgValue = SpillSlot;
4141bdd1243dSDimitry Andric     } else {
4142bdd1243dSDimitry Andric       ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
4143bdd1243dSDimitry Andric     }
4144bdd1243dSDimitry Andric 
4145bdd1243dSDimitry Andric     // Use local copy if it is a byval arg.
4146bdd1243dSDimitry Andric     if (Flags.isByVal())
4147bdd1243dSDimitry Andric       ArgValue = ByValArgs[j++];
4148753f127fSDimitry Andric 
4149753f127fSDimitry Andric     if (VA.isRegLoc()) {
4150753f127fSDimitry Andric       // Queue up the argument copies and emit them at the end.
4151753f127fSDimitry Andric       RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
4152753f127fSDimitry Andric     } else {
4153bdd1243dSDimitry Andric       assert(VA.isMemLoc() && "Argument not register or memory");
4154bdd1243dSDimitry Andric       assert(!IsTailCall && "Tail call not allowed if stack is used "
4155bdd1243dSDimitry Andric                             "for passing parameters");
4156bdd1243dSDimitry Andric 
4157bdd1243dSDimitry Andric       // Work out the address of the stack slot.
4158bdd1243dSDimitry Andric       if (!StackPtr.getNode())
4159bdd1243dSDimitry Andric         StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
4160bdd1243dSDimitry Andric       SDValue Address =
4161bdd1243dSDimitry Andric           DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
4162bdd1243dSDimitry Andric                       DAG.getIntPtrConstant(VA.getLocMemOffset(), DL));
4163bdd1243dSDimitry Andric 
4164bdd1243dSDimitry Andric       // Emit the store.
4165bdd1243dSDimitry Andric       MemOpChains.push_back(
4166bdd1243dSDimitry Andric           DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
4167753f127fSDimitry Andric     }
4168753f127fSDimitry Andric   }
4169753f127fSDimitry Andric 
4170bdd1243dSDimitry Andric   // Join the stores, which are independent of one another.
4171bdd1243dSDimitry Andric   if (!MemOpChains.empty())
4172bdd1243dSDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
4173bdd1243dSDimitry Andric 
4174753f127fSDimitry Andric   SDValue Glue;
4175753f127fSDimitry Andric 
4176753f127fSDimitry Andric   // Build a sequence of copy-to-reg nodes, chained and glued together.
4177753f127fSDimitry Andric   for (auto &Reg : RegsToPass) {
4178753f127fSDimitry Andric     Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
4179753f127fSDimitry Andric     Glue = Chain.getValue(1);
4180753f127fSDimitry Andric   }
4181753f127fSDimitry Andric 
4182753f127fSDimitry Andric   // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
4183753f127fSDimitry Andric   // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
4184753f127fSDimitry Andric   // split it and then direct call can be matched by PseudoCALL.
4185bdd1243dSDimitry Andric   if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
4186bdd1243dSDimitry Andric     const GlobalValue *GV = S->getGlobal();
4187bdd1243dSDimitry Andric     unsigned OpFlags =
4188bdd1243dSDimitry Andric         getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)
4189bdd1243dSDimitry Andric             ? LoongArchII::MO_CALL
4190bdd1243dSDimitry Andric             : LoongArchII::MO_CALL_PLT;
4191bdd1243dSDimitry Andric     Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
4192bdd1243dSDimitry Andric   } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
4193bdd1243dSDimitry Andric     unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(
4194bdd1243dSDimitry Andric                            *MF.getFunction().getParent(), nullptr)
4195bdd1243dSDimitry Andric                            ? LoongArchII::MO_CALL
4196bdd1243dSDimitry Andric                            : LoongArchII::MO_CALL_PLT;
4197bdd1243dSDimitry Andric     Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
4198bdd1243dSDimitry Andric   }
4199753f127fSDimitry Andric 
4200753f127fSDimitry Andric   // The first call operand is the chain and the second is the target address.
4201753f127fSDimitry Andric   SmallVector<SDValue> Ops;
4202753f127fSDimitry Andric   Ops.push_back(Chain);
4203753f127fSDimitry Andric   Ops.push_back(Callee);
4204753f127fSDimitry Andric 
4205753f127fSDimitry Andric   // Add argument registers to the end of the list so that they are
4206753f127fSDimitry Andric   // known live into the call.
4207753f127fSDimitry Andric   for (auto &Reg : RegsToPass)
4208753f127fSDimitry Andric     Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
4209753f127fSDimitry Andric 
4210bdd1243dSDimitry Andric   if (!IsTailCall) {
4211753f127fSDimitry Andric     // Add a register mask operand representing the call-preserved registers.
4212753f127fSDimitry Andric     const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
4213753f127fSDimitry Andric     const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
4214753f127fSDimitry Andric     assert(Mask && "Missing call preserved mask for calling convention");
4215753f127fSDimitry Andric     Ops.push_back(DAG.getRegisterMask(Mask));
4216bdd1243dSDimitry Andric   }
4217753f127fSDimitry Andric 
4218753f127fSDimitry Andric   // Glue the call to the argument copies, if any.
4219753f127fSDimitry Andric   if (Glue.getNode())
4220753f127fSDimitry Andric     Ops.push_back(Glue);
4221753f127fSDimitry Andric 
4222753f127fSDimitry Andric   // Emit the call.
4223753f127fSDimitry Andric   SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
4224753f127fSDimitry Andric 
4225bdd1243dSDimitry Andric   if (IsTailCall) {
4226bdd1243dSDimitry Andric     MF.getFrameInfo().setHasTailCall();
422706c3fb27SDimitry Andric     SDValue Ret = DAG.getNode(LoongArchISD::TAIL, DL, NodeTys, Ops);
422806c3fb27SDimitry Andric     DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge);
422906c3fb27SDimitry Andric     return Ret;
4230bdd1243dSDimitry Andric   }
4231bdd1243dSDimitry Andric 
4232753f127fSDimitry Andric   Chain = DAG.getNode(LoongArchISD::CALL, DL, NodeTys, Ops);
4233753f127fSDimitry Andric   DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
4234753f127fSDimitry Andric   Glue = Chain.getValue(1);
4235753f127fSDimitry Andric 
4236753f127fSDimitry Andric   // Mark the end of the call, which is glued to the call itself.
4237bdd1243dSDimitry Andric   Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
4238753f127fSDimitry Andric   Glue = Chain.getValue(1);
4239753f127fSDimitry Andric 
4240753f127fSDimitry Andric   // Assign locations to each value returned by this call.
4241753f127fSDimitry Andric   SmallVector<CCValAssign> RVLocs;
4242753f127fSDimitry Andric   CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
4243bdd1243dSDimitry Andric   analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
4244753f127fSDimitry Andric 
4245753f127fSDimitry Andric   // Copy all of the result registers out of their specified physreg.
4246753f127fSDimitry Andric   for (auto &VA : RVLocs) {
4247753f127fSDimitry Andric     // Copy the value out.
4248753f127fSDimitry Andric     SDValue RetValue =
4249753f127fSDimitry Andric         DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
4250bdd1243dSDimitry Andric     // Glue the RetValue to the end of the call sequence.
4251753f127fSDimitry Andric     Chain = RetValue.getValue(1);
4252753f127fSDimitry Andric     Glue = RetValue.getValue(2);
4253753f127fSDimitry Andric 
4254bdd1243dSDimitry Andric     RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
4255bdd1243dSDimitry Andric 
4256bdd1243dSDimitry Andric     InVals.push_back(RetValue);
4257753f127fSDimitry Andric   }
4258753f127fSDimitry Andric 
4259753f127fSDimitry Andric   return Chain;
4260753f127fSDimitry Andric }
4261753f127fSDimitry Andric 
426281ad6265SDimitry Andric bool LoongArchTargetLowering::CanLowerReturn(
426381ad6265SDimitry Andric     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
426481ad6265SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
4265bdd1243dSDimitry Andric   SmallVector<CCValAssign> RVLocs;
4266bdd1243dSDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
4267bdd1243dSDimitry Andric 
4268bdd1243dSDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
4269bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
4270bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
4271bdd1243dSDimitry Andric     if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
4272bdd1243dSDimitry Andric                      Outs[i].Flags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true,
4273bdd1243dSDimitry Andric                      nullptr))
4274bdd1243dSDimitry Andric       return false;
4275bdd1243dSDimitry Andric   }
4276bdd1243dSDimitry Andric   return true;
427781ad6265SDimitry Andric }
427881ad6265SDimitry Andric 
427981ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerReturn(
428081ad6265SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
428181ad6265SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs,
428281ad6265SDimitry Andric     const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
428381ad6265SDimitry Andric     SelectionDAG &DAG) const {
428481ad6265SDimitry Andric   // Stores the assignment of the return value to a location.
428581ad6265SDimitry Andric   SmallVector<CCValAssign> RVLocs;
428681ad6265SDimitry Andric 
428781ad6265SDimitry Andric   // Info about the registers and stack slot.
428881ad6265SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
428981ad6265SDimitry Andric                  *DAG.getContext());
429081ad6265SDimitry Andric 
4291bdd1243dSDimitry Andric   analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
4292bdd1243dSDimitry Andric                     nullptr, CC_LoongArch);
4293bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC && !RVLocs.empty())
4294bdd1243dSDimitry Andric     report_fatal_error("GHC functions return void only");
429581ad6265SDimitry Andric   SDValue Glue;
429681ad6265SDimitry Andric   SmallVector<SDValue, 4> RetOps(1, Chain);
429781ad6265SDimitry Andric 
429881ad6265SDimitry Andric   // Copy the result values into the output registers.
429981ad6265SDimitry Andric   for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) {
430081ad6265SDimitry Andric     CCValAssign &VA = RVLocs[i];
430181ad6265SDimitry Andric     assert(VA.isRegLoc() && "Can only return in registers!");
430281ad6265SDimitry Andric 
430381ad6265SDimitry Andric     // Handle a 'normal' return.
4304bdd1243dSDimitry Andric     SDValue Val = convertValVTToLocVT(DAG, OutVals[i], VA, DL);
4305bdd1243dSDimitry Andric     Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
430681ad6265SDimitry Andric 
430781ad6265SDimitry Andric     // Guarantee that all emitted copies are stuck together.
430881ad6265SDimitry Andric     Glue = Chain.getValue(1);
430981ad6265SDimitry Andric     RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
431081ad6265SDimitry Andric   }
431181ad6265SDimitry Andric 
431281ad6265SDimitry Andric   RetOps[0] = Chain; // Update chain.
431381ad6265SDimitry Andric 
431481ad6265SDimitry Andric   // Add the glue node if we have it.
431581ad6265SDimitry Andric   if (Glue.getNode())
431681ad6265SDimitry Andric     RetOps.push_back(Glue);
431781ad6265SDimitry Andric 
431881ad6265SDimitry Andric   return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
431981ad6265SDimitry Andric }
4320753f127fSDimitry Andric 
4321753f127fSDimitry Andric bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
4322753f127fSDimitry Andric                                            bool ForCodeSize) const {
4323bdd1243dSDimitry Andric   // TODO: Maybe need more checks here after vector extension is supported.
4324753f127fSDimitry Andric   if (VT == MVT::f32 && !Subtarget.hasBasicF())
4325753f127fSDimitry Andric     return false;
4326753f127fSDimitry Andric   if (VT == MVT::f64 && !Subtarget.hasBasicD())
4327753f127fSDimitry Andric     return false;
4328753f127fSDimitry Andric   return (Imm.isZero() || Imm.isExactlyValue(+1.0));
4329753f127fSDimitry Andric }
4330bdd1243dSDimitry Andric 
4331bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCttz(Type *) const {
4332bdd1243dSDimitry Andric   return true;
4333bdd1243dSDimitry Andric }
4334bdd1243dSDimitry Andric 
4335bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCtlz(Type *) const {
4336bdd1243dSDimitry Andric   return true;
4337bdd1243dSDimitry Andric }
4338bdd1243dSDimitry Andric 
4339bdd1243dSDimitry Andric bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
4340bdd1243dSDimitry Andric     const Instruction *I) const {
4341bdd1243dSDimitry Andric   if (!Subtarget.is64Bit())
4342bdd1243dSDimitry Andric     return isa<LoadInst>(I) || isa<StoreInst>(I);
4343bdd1243dSDimitry Andric 
4344bdd1243dSDimitry Andric   if (isa<LoadInst>(I))
4345bdd1243dSDimitry Andric     return true;
4346bdd1243dSDimitry Andric 
4347bdd1243dSDimitry Andric   // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
4348bdd1243dSDimitry Andric   // require fences beacuse we can use amswap_db.[w/d].
4349bdd1243dSDimitry Andric   if (isa<StoreInst>(I)) {
4350bdd1243dSDimitry Andric     unsigned Size = I->getOperand(0)->getType()->getIntegerBitWidth();
4351bdd1243dSDimitry Andric     return (Size == 8 || Size == 16);
4352bdd1243dSDimitry Andric   }
4353bdd1243dSDimitry Andric 
4354bdd1243dSDimitry Andric   return false;
4355bdd1243dSDimitry Andric }
4356bdd1243dSDimitry Andric 
4357bdd1243dSDimitry Andric EVT LoongArchTargetLowering::getSetCCResultType(const DataLayout &DL,
4358bdd1243dSDimitry Andric                                                 LLVMContext &Context,
4359bdd1243dSDimitry Andric                                                 EVT VT) const {
4360bdd1243dSDimitry Andric   if (!VT.isVector())
4361bdd1243dSDimitry Andric     return getPointerTy(DL);
4362bdd1243dSDimitry Andric   return VT.changeVectorElementTypeToInteger();
4363bdd1243dSDimitry Andric }
4364bdd1243dSDimitry Andric 
4365bdd1243dSDimitry Andric bool LoongArchTargetLowering::hasAndNot(SDValue Y) const {
4366bdd1243dSDimitry Andric   // TODO: Support vectors.
4367bdd1243dSDimitry Andric   return Y.getValueType().isScalarInteger() && !isa<ConstantSDNode>(Y);
4368bdd1243dSDimitry Andric }
4369bdd1243dSDimitry Andric 
4370bdd1243dSDimitry Andric bool LoongArchTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
4371bdd1243dSDimitry Andric                                                  const CallInst &I,
4372bdd1243dSDimitry Andric                                                  MachineFunction &MF,
4373bdd1243dSDimitry Andric                                                  unsigned Intrinsic) const {
4374bdd1243dSDimitry Andric   switch (Intrinsic) {
4375bdd1243dSDimitry Andric   default:
4376bdd1243dSDimitry Andric     return false;
4377bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
4378bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_add_i32:
4379bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
4380bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_nand_i32:
4381bdd1243dSDimitry Andric     Info.opc = ISD::INTRINSIC_W_CHAIN;
4382bdd1243dSDimitry Andric     Info.memVT = MVT::i32;
4383bdd1243dSDimitry Andric     Info.ptrVal = I.getArgOperand(0);
4384bdd1243dSDimitry Andric     Info.offset = 0;
4385bdd1243dSDimitry Andric     Info.align = Align(4);
4386bdd1243dSDimitry Andric     Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore |
4387bdd1243dSDimitry Andric                  MachineMemOperand::MOVolatile;
4388bdd1243dSDimitry Andric     return true;
4389bdd1243dSDimitry Andric     // TODO: Add more Intrinsics later.
4390bdd1243dSDimitry Andric   }
4391bdd1243dSDimitry Andric }
4392bdd1243dSDimitry Andric 
4393bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind
4394bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
4395bdd1243dSDimitry Andric   // TODO: Add more AtomicRMWInst that needs to be extended.
4396bdd1243dSDimitry Andric 
4397bdd1243dSDimitry Andric   // Since floating-point operation requires a non-trivial set of data
4398bdd1243dSDimitry Andric   // operations, use CmpXChg to expand.
4399bdd1243dSDimitry Andric   if (AI->isFloatingPointOperation() ||
4400bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::UIncWrap ||
4401bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::UDecWrap)
4402bdd1243dSDimitry Andric     return AtomicExpansionKind::CmpXChg;
4403bdd1243dSDimitry Andric 
4404bdd1243dSDimitry Andric   unsigned Size = AI->getType()->getPrimitiveSizeInBits();
4405bdd1243dSDimitry Andric   if (Size == 8 || Size == 16)
4406bdd1243dSDimitry Andric     return AtomicExpansionKind::MaskedIntrinsic;
4407bdd1243dSDimitry Andric   return AtomicExpansionKind::None;
4408bdd1243dSDimitry Andric }
4409bdd1243dSDimitry Andric 
4410bdd1243dSDimitry Andric static Intrinsic::ID
4411bdd1243dSDimitry Andric getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen,
4412bdd1243dSDimitry Andric                                     AtomicRMWInst::BinOp BinOp) {
4413bdd1243dSDimitry Andric   if (GRLen == 64) {
4414bdd1243dSDimitry Andric     switch (BinOp) {
4415bdd1243dSDimitry Andric     default:
4416bdd1243dSDimitry Andric       llvm_unreachable("Unexpected AtomicRMW BinOp");
4417bdd1243dSDimitry Andric     case AtomicRMWInst::Xchg:
4418bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
4419bdd1243dSDimitry Andric     case AtomicRMWInst::Add:
4420bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_add_i64;
4421bdd1243dSDimitry Andric     case AtomicRMWInst::Sub:
4422bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
4423bdd1243dSDimitry Andric     case AtomicRMWInst::Nand:
4424bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
4425bdd1243dSDimitry Andric     case AtomicRMWInst::UMax:
4426bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
4427bdd1243dSDimitry Andric     case AtomicRMWInst::UMin:
4428bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
4429bdd1243dSDimitry Andric     case AtomicRMWInst::Max:
4430bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_max_i64;
4431bdd1243dSDimitry Andric     case AtomicRMWInst::Min:
4432bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_min_i64;
4433bdd1243dSDimitry Andric       // TODO: support other AtomicRMWInst.
4434bdd1243dSDimitry Andric     }
4435bdd1243dSDimitry Andric   }
4436bdd1243dSDimitry Andric 
4437bdd1243dSDimitry Andric   if (GRLen == 32) {
4438bdd1243dSDimitry Andric     switch (BinOp) {
4439bdd1243dSDimitry Andric     default:
4440bdd1243dSDimitry Andric       llvm_unreachable("Unexpected AtomicRMW BinOp");
4441bdd1243dSDimitry Andric     case AtomicRMWInst::Xchg:
4442bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
4443bdd1243dSDimitry Andric     case AtomicRMWInst::Add:
4444bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_add_i32;
4445bdd1243dSDimitry Andric     case AtomicRMWInst::Sub:
4446bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
4447bdd1243dSDimitry Andric     case AtomicRMWInst::Nand:
4448bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
4449bdd1243dSDimitry Andric       // TODO: support other AtomicRMWInst.
4450bdd1243dSDimitry Andric     }
4451bdd1243dSDimitry Andric   }
4452bdd1243dSDimitry Andric 
4453bdd1243dSDimitry Andric   llvm_unreachable("Unexpected GRLen\n");
4454bdd1243dSDimitry Andric }
4455bdd1243dSDimitry Andric 
4456bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind
4457bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicCmpXchgInIR(
4458bdd1243dSDimitry Andric     AtomicCmpXchgInst *CI) const {
4459bdd1243dSDimitry Andric   unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits();
4460bdd1243dSDimitry Andric   if (Size == 8 || Size == 16)
4461bdd1243dSDimitry Andric     return AtomicExpansionKind::MaskedIntrinsic;
4462bdd1243dSDimitry Andric   return AtomicExpansionKind::None;
4463bdd1243dSDimitry Andric }
4464bdd1243dSDimitry Andric 
4465bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicCmpXchgIntrinsic(
4466bdd1243dSDimitry Andric     IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
4467bdd1243dSDimitry Andric     Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
4468*5f757f3fSDimitry Andric   AtomicOrdering FailOrd = CI->getFailureOrdering();
4469*5f757f3fSDimitry Andric   Value *FailureOrdering =
4470*5f757f3fSDimitry Andric       Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(FailOrd));
4471bdd1243dSDimitry Andric 
4472bdd1243dSDimitry Andric   // TODO: Support cmpxchg on LA32.
4473bdd1243dSDimitry Andric   Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
4474bdd1243dSDimitry Andric   CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
4475bdd1243dSDimitry Andric   NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
4476bdd1243dSDimitry Andric   Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
4477bdd1243dSDimitry Andric   Type *Tys[] = {AlignedAddr->getType()};
4478bdd1243dSDimitry Andric   Function *MaskedCmpXchg =
4479bdd1243dSDimitry Andric       Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys);
4480bdd1243dSDimitry Andric   Value *Result = Builder.CreateCall(
4481*5f757f3fSDimitry Andric       MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, FailureOrdering});
4482bdd1243dSDimitry Andric   Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
4483bdd1243dSDimitry Andric   return Result;
4484bdd1243dSDimitry Andric }
4485bdd1243dSDimitry Andric 
4486bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicRMWIntrinsic(
4487bdd1243dSDimitry Andric     IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
4488bdd1243dSDimitry Andric     Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
4489*5f757f3fSDimitry Andric   // In the case of an atomicrmw xchg with a constant 0/-1 operand, replace
4490*5f757f3fSDimitry Andric   // the atomic instruction with an AtomicRMWInst::And/Or with appropriate
4491*5f757f3fSDimitry Andric   // mask, as this produces better code than the LL/SC loop emitted by
4492*5f757f3fSDimitry Andric   // int_loongarch_masked_atomicrmw_xchg.
4493*5f757f3fSDimitry Andric   if (AI->getOperation() == AtomicRMWInst::Xchg &&
4494*5f757f3fSDimitry Andric       isa<ConstantInt>(AI->getValOperand())) {
4495*5f757f3fSDimitry Andric     ConstantInt *CVal = cast<ConstantInt>(AI->getValOperand());
4496*5f757f3fSDimitry Andric     if (CVal->isZero())
4497*5f757f3fSDimitry Andric       return Builder.CreateAtomicRMW(AtomicRMWInst::And, AlignedAddr,
4498*5f757f3fSDimitry Andric                                      Builder.CreateNot(Mask, "Inv_Mask"),
4499*5f757f3fSDimitry Andric                                      AI->getAlign(), Ord);
4500*5f757f3fSDimitry Andric     if (CVal->isMinusOne())
4501*5f757f3fSDimitry Andric       return Builder.CreateAtomicRMW(AtomicRMWInst::Or, AlignedAddr, Mask,
4502*5f757f3fSDimitry Andric                                      AI->getAlign(), Ord);
4503*5f757f3fSDimitry Andric   }
4504*5f757f3fSDimitry Andric 
4505bdd1243dSDimitry Andric   unsigned GRLen = Subtarget.getGRLen();
4506bdd1243dSDimitry Andric   Value *Ordering =
4507bdd1243dSDimitry Andric       Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
4508bdd1243dSDimitry Andric   Type *Tys[] = {AlignedAddr->getType()};
4509bdd1243dSDimitry Andric   Function *LlwOpScwLoop = Intrinsic::getDeclaration(
4510bdd1243dSDimitry Andric       AI->getModule(),
4511bdd1243dSDimitry Andric       getIntrinsicForMaskedAtomicRMWBinOp(GRLen, AI->getOperation()), Tys);
4512bdd1243dSDimitry Andric 
4513bdd1243dSDimitry Andric   if (GRLen == 64) {
4514bdd1243dSDimitry Andric     Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
4515bdd1243dSDimitry Andric     Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
4516bdd1243dSDimitry Andric     ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
4517bdd1243dSDimitry Andric   }
4518bdd1243dSDimitry Andric 
4519bdd1243dSDimitry Andric   Value *Result;
4520bdd1243dSDimitry Andric 
4521bdd1243dSDimitry Andric   // Must pass the shift amount needed to sign extend the loaded value prior
4522bdd1243dSDimitry Andric   // to performing a signed comparison for min/max. ShiftAmt is the number of
4523bdd1243dSDimitry Andric   // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
4524bdd1243dSDimitry Andric   // is the number of bits to left+right shift the value in order to
4525bdd1243dSDimitry Andric   // sign-extend.
4526bdd1243dSDimitry Andric   if (AI->getOperation() == AtomicRMWInst::Min ||
4527bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::Max) {
4528bdd1243dSDimitry Andric     const DataLayout &DL = AI->getModule()->getDataLayout();
4529bdd1243dSDimitry Andric     unsigned ValWidth =
4530bdd1243dSDimitry Andric         DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
4531bdd1243dSDimitry Andric     Value *SextShamt =
4532bdd1243dSDimitry Andric         Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
4533bdd1243dSDimitry Andric     Result = Builder.CreateCall(LlwOpScwLoop,
4534bdd1243dSDimitry Andric                                 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
4535bdd1243dSDimitry Andric   } else {
4536bdd1243dSDimitry Andric     Result =
4537bdd1243dSDimitry Andric         Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
4538bdd1243dSDimitry Andric   }
4539bdd1243dSDimitry Andric 
4540bdd1243dSDimitry Andric   if (GRLen == 64)
4541bdd1243dSDimitry Andric     Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
4542bdd1243dSDimitry Andric   return Result;
4543bdd1243dSDimitry Andric }
4544bdd1243dSDimitry Andric 
4545bdd1243dSDimitry Andric bool LoongArchTargetLowering::isFMAFasterThanFMulAndFAdd(
4546bdd1243dSDimitry Andric     const MachineFunction &MF, EVT VT) const {
4547bdd1243dSDimitry Andric   VT = VT.getScalarType();
4548bdd1243dSDimitry Andric 
4549bdd1243dSDimitry Andric   if (!VT.isSimple())
4550bdd1243dSDimitry Andric     return false;
4551bdd1243dSDimitry Andric 
4552bdd1243dSDimitry Andric   switch (VT.getSimpleVT().SimpleTy) {
4553bdd1243dSDimitry Andric   case MVT::f32:
4554bdd1243dSDimitry Andric   case MVT::f64:
4555bdd1243dSDimitry Andric     return true;
4556bdd1243dSDimitry Andric   default:
4557bdd1243dSDimitry Andric     break;
4558bdd1243dSDimitry Andric   }
4559bdd1243dSDimitry Andric 
4560bdd1243dSDimitry Andric   return false;
4561bdd1243dSDimitry Andric }
4562bdd1243dSDimitry Andric 
4563bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionPointerRegister(
4564bdd1243dSDimitry Andric     const Constant *PersonalityFn) const {
4565bdd1243dSDimitry Andric   return LoongArch::R4;
4566bdd1243dSDimitry Andric }
4567bdd1243dSDimitry Andric 
4568bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionSelectorRegister(
4569bdd1243dSDimitry Andric     const Constant *PersonalityFn) const {
4570bdd1243dSDimitry Andric   return LoongArch::R5;
4571bdd1243dSDimitry Andric }
4572bdd1243dSDimitry Andric 
4573bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
4574bdd1243dSDimitry Andric //                           LoongArch Inline Assembly Support
4575bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
4576bdd1243dSDimitry Andric 
4577bdd1243dSDimitry Andric LoongArchTargetLowering::ConstraintType
4578bdd1243dSDimitry Andric LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
4579bdd1243dSDimitry Andric   // LoongArch specific constraints in GCC: config/loongarch/constraints.md
4580bdd1243dSDimitry Andric   //
4581bdd1243dSDimitry Andric   // 'f':  A floating-point register (if available).
4582bdd1243dSDimitry Andric   // 'k':  A memory operand whose address is formed by a base register and
4583bdd1243dSDimitry Andric   //       (optionally scaled) index register.
4584bdd1243dSDimitry Andric   // 'l':  A signed 16-bit constant.
4585bdd1243dSDimitry Andric   // 'm':  A memory operand whose address is formed by a base register and
4586bdd1243dSDimitry Andric   //       offset that is suitable for use in instructions with the same
4587bdd1243dSDimitry Andric   //       addressing mode as st.w and ld.w.
4588bdd1243dSDimitry Andric   // 'I':  A signed 12-bit constant (for arithmetic instructions).
4589bdd1243dSDimitry Andric   // 'J':  Integer zero.
4590bdd1243dSDimitry Andric   // 'K':  An unsigned 12-bit constant (for logic instructions).
4591bdd1243dSDimitry Andric   // "ZB": An address that is held in a general-purpose register. The offset is
4592bdd1243dSDimitry Andric   //       zero.
4593bdd1243dSDimitry Andric   // "ZC": A memory operand whose address is formed by a base register and
4594bdd1243dSDimitry Andric   //       offset that is suitable for use in instructions with the same
4595bdd1243dSDimitry Andric   //       addressing mode as ll.w and sc.w.
4596bdd1243dSDimitry Andric   if (Constraint.size() == 1) {
4597bdd1243dSDimitry Andric     switch (Constraint[0]) {
4598bdd1243dSDimitry Andric     default:
4599bdd1243dSDimitry Andric       break;
4600bdd1243dSDimitry Andric     case 'f':
4601bdd1243dSDimitry Andric       return C_RegisterClass;
4602bdd1243dSDimitry Andric     case 'l':
4603bdd1243dSDimitry Andric     case 'I':
4604bdd1243dSDimitry Andric     case 'J':
4605bdd1243dSDimitry Andric     case 'K':
4606bdd1243dSDimitry Andric       return C_Immediate;
4607bdd1243dSDimitry Andric     case 'k':
4608bdd1243dSDimitry Andric       return C_Memory;
4609bdd1243dSDimitry Andric     }
4610bdd1243dSDimitry Andric   }
4611bdd1243dSDimitry Andric 
4612bdd1243dSDimitry Andric   if (Constraint == "ZC" || Constraint == "ZB")
4613bdd1243dSDimitry Andric     return C_Memory;
4614bdd1243dSDimitry Andric 
4615bdd1243dSDimitry Andric   // 'm' is handled here.
4616bdd1243dSDimitry Andric   return TargetLowering::getConstraintType(Constraint);
4617bdd1243dSDimitry Andric }
4618bdd1243dSDimitry Andric 
4619*5f757f3fSDimitry Andric InlineAsm::ConstraintCode LoongArchTargetLowering::getInlineAsmMemConstraint(
4620bdd1243dSDimitry Andric     StringRef ConstraintCode) const {
4621*5f757f3fSDimitry Andric   return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
4622*5f757f3fSDimitry Andric       .Case("k", InlineAsm::ConstraintCode::k)
4623*5f757f3fSDimitry Andric       .Case("ZB", InlineAsm::ConstraintCode::ZB)
4624*5f757f3fSDimitry Andric       .Case("ZC", InlineAsm::ConstraintCode::ZC)
4625bdd1243dSDimitry Andric       .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
4626bdd1243dSDimitry Andric }
4627bdd1243dSDimitry Andric 
4628bdd1243dSDimitry Andric std::pair<unsigned, const TargetRegisterClass *>
4629bdd1243dSDimitry Andric LoongArchTargetLowering::getRegForInlineAsmConstraint(
4630bdd1243dSDimitry Andric     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
4631bdd1243dSDimitry Andric   // First, see if this is a constraint that directly corresponds to a LoongArch
4632bdd1243dSDimitry Andric   // register class.
4633bdd1243dSDimitry Andric   if (Constraint.size() == 1) {
4634bdd1243dSDimitry Andric     switch (Constraint[0]) {
4635bdd1243dSDimitry Andric     case 'r':
4636bdd1243dSDimitry Andric       // TODO: Support fixed vectors up to GRLen?
4637bdd1243dSDimitry Andric       if (VT.isVector())
4638bdd1243dSDimitry Andric         break;
4639bdd1243dSDimitry Andric       return std::make_pair(0U, &LoongArch::GPRRegClass);
4640bdd1243dSDimitry Andric     case 'f':
4641bdd1243dSDimitry Andric       if (Subtarget.hasBasicF() && VT == MVT::f32)
4642bdd1243dSDimitry Andric         return std::make_pair(0U, &LoongArch::FPR32RegClass);
4643bdd1243dSDimitry Andric       if (Subtarget.hasBasicD() && VT == MVT::f64)
4644bdd1243dSDimitry Andric         return std::make_pair(0U, &LoongArch::FPR64RegClass);
464506c3fb27SDimitry Andric       if (Subtarget.hasExtLSX() &&
464606c3fb27SDimitry Andric           TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
464706c3fb27SDimitry Andric         return std::make_pair(0U, &LoongArch::LSX128RegClass);
464806c3fb27SDimitry Andric       if (Subtarget.hasExtLASX() &&
464906c3fb27SDimitry Andric           TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
465006c3fb27SDimitry Andric         return std::make_pair(0U, &LoongArch::LASX256RegClass);
4651bdd1243dSDimitry Andric       break;
4652bdd1243dSDimitry Andric     default:
4653bdd1243dSDimitry Andric       break;
4654bdd1243dSDimitry Andric     }
4655bdd1243dSDimitry Andric   }
4656bdd1243dSDimitry Andric 
4657bdd1243dSDimitry Andric   // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
4658bdd1243dSDimitry Andric   // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
4659bdd1243dSDimitry Andric   // constraints while the official register name is prefixed with a '$'. So we
4660bdd1243dSDimitry Andric   // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
4661bdd1243dSDimitry Andric   // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
4662bdd1243dSDimitry Andric   // case insensitive, so no need to convert the constraint to upper case here.
4663bdd1243dSDimitry Andric   //
4664bdd1243dSDimitry Andric   // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
4665bdd1243dSDimitry Andric   // decode the usage of register name aliases into their official names. And
4666bdd1243dSDimitry Andric   // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
4667bdd1243dSDimitry Andric   // official register names.
4668*5f757f3fSDimitry Andric   if (Constraint.starts_with("{$r") || Constraint.starts_with("{$f") ||
4669*5f757f3fSDimitry Andric       Constraint.starts_with("{$vr") || Constraint.starts_with("{$xr")) {
4670bdd1243dSDimitry Andric     bool IsFP = Constraint[2] == 'f';
4671bdd1243dSDimitry Andric     std::pair<StringRef, StringRef> Temp = Constraint.split('$');
4672bdd1243dSDimitry Andric     std::pair<unsigned, const TargetRegisterClass *> R;
4673bdd1243dSDimitry Andric     R = TargetLowering::getRegForInlineAsmConstraint(
4674bdd1243dSDimitry Andric         TRI, join_items("", Temp.first, Temp.second), VT);
4675bdd1243dSDimitry Andric     // Match those names to the widest floating point register type available.
4676bdd1243dSDimitry Andric     if (IsFP) {
4677bdd1243dSDimitry Andric       unsigned RegNo = R.first;
4678bdd1243dSDimitry Andric       if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
4679bdd1243dSDimitry Andric         if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
4680bdd1243dSDimitry Andric           unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
4681bdd1243dSDimitry Andric           return std::make_pair(DReg, &LoongArch::FPR64RegClass);
4682bdd1243dSDimitry Andric         }
4683bdd1243dSDimitry Andric       }
4684bdd1243dSDimitry Andric     }
4685bdd1243dSDimitry Andric     return R;
4686bdd1243dSDimitry Andric   }
4687bdd1243dSDimitry Andric 
4688bdd1243dSDimitry Andric   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
4689bdd1243dSDimitry Andric }
4690bdd1243dSDimitry Andric 
4691bdd1243dSDimitry Andric void LoongArchTargetLowering::LowerAsmOperandForConstraint(
4692*5f757f3fSDimitry Andric     SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops,
4693bdd1243dSDimitry Andric     SelectionDAG &DAG) const {
4694bdd1243dSDimitry Andric   // Currently only support length 1 constraints.
4695*5f757f3fSDimitry Andric   if (Constraint.size() == 1) {
4696bdd1243dSDimitry Andric     switch (Constraint[0]) {
4697bdd1243dSDimitry Andric     case 'l':
4698bdd1243dSDimitry Andric       // Validate & create a 16-bit signed immediate operand.
4699bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
4700bdd1243dSDimitry Andric         uint64_t CVal = C->getSExtValue();
4701bdd1243dSDimitry Andric         if (isInt<16>(CVal))
4702bdd1243dSDimitry Andric           Ops.push_back(
4703bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
4704bdd1243dSDimitry Andric       }
4705bdd1243dSDimitry Andric       return;
4706bdd1243dSDimitry Andric     case 'I':
4707bdd1243dSDimitry Andric       // Validate & create a 12-bit signed immediate operand.
4708bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
4709bdd1243dSDimitry Andric         uint64_t CVal = C->getSExtValue();
4710bdd1243dSDimitry Andric         if (isInt<12>(CVal))
4711bdd1243dSDimitry Andric           Ops.push_back(
4712bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
4713bdd1243dSDimitry Andric       }
4714bdd1243dSDimitry Andric       return;
4715bdd1243dSDimitry Andric     case 'J':
4716bdd1243dSDimitry Andric       // Validate & create an integer zero operand.
4717bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op))
4718bdd1243dSDimitry Andric         if (C->getZExtValue() == 0)
4719bdd1243dSDimitry Andric           Ops.push_back(
4720bdd1243dSDimitry Andric               DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
4721bdd1243dSDimitry Andric       return;
4722bdd1243dSDimitry Andric     case 'K':
4723bdd1243dSDimitry Andric       // Validate & create a 12-bit unsigned immediate operand.
4724bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
4725bdd1243dSDimitry Andric         uint64_t CVal = C->getZExtValue();
4726bdd1243dSDimitry Andric         if (isUInt<12>(CVal))
4727bdd1243dSDimitry Andric           Ops.push_back(
4728bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
4729bdd1243dSDimitry Andric       }
4730bdd1243dSDimitry Andric       return;
4731bdd1243dSDimitry Andric     default:
4732bdd1243dSDimitry Andric       break;
4733bdd1243dSDimitry Andric     }
4734bdd1243dSDimitry Andric   }
4735bdd1243dSDimitry Andric   TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
4736bdd1243dSDimitry Andric }
4737bdd1243dSDimitry Andric 
4738bdd1243dSDimitry Andric #define GET_REGISTER_MATCHER
4739bdd1243dSDimitry Andric #include "LoongArchGenAsmMatcher.inc"
4740bdd1243dSDimitry Andric 
4741bdd1243dSDimitry Andric Register
4742bdd1243dSDimitry Andric LoongArchTargetLowering::getRegisterByName(const char *RegName, LLT VT,
4743bdd1243dSDimitry Andric                                            const MachineFunction &MF) const {
4744bdd1243dSDimitry Andric   std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
4745bdd1243dSDimitry Andric   std::string NewRegName = Name.second.str();
4746bdd1243dSDimitry Andric   Register Reg = MatchRegisterAltName(NewRegName);
4747bdd1243dSDimitry Andric   if (Reg == LoongArch::NoRegister)
4748bdd1243dSDimitry Andric     Reg = MatchRegisterName(NewRegName);
4749bdd1243dSDimitry Andric   if (Reg == LoongArch::NoRegister)
4750bdd1243dSDimitry Andric     report_fatal_error(
4751bdd1243dSDimitry Andric         Twine("Invalid register name \"" + StringRef(RegName) + "\"."));
4752bdd1243dSDimitry Andric   BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
4753bdd1243dSDimitry Andric   if (!ReservedRegs.test(Reg))
4754bdd1243dSDimitry Andric     report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
4755bdd1243dSDimitry Andric                              StringRef(RegName) + "\"."));
4756bdd1243dSDimitry Andric   return Reg;
4757bdd1243dSDimitry Andric }
4758bdd1243dSDimitry Andric 
4759bdd1243dSDimitry Andric bool LoongArchTargetLowering::decomposeMulByConstant(LLVMContext &Context,
4760bdd1243dSDimitry Andric                                                      EVT VT, SDValue C) const {
4761bdd1243dSDimitry Andric   // TODO: Support vectors.
4762bdd1243dSDimitry Andric   if (!VT.isScalarInteger())
4763bdd1243dSDimitry Andric     return false;
4764bdd1243dSDimitry Andric 
4765bdd1243dSDimitry Andric   // Omit the optimization if the data size exceeds GRLen.
4766bdd1243dSDimitry Andric   if (VT.getSizeInBits() > Subtarget.getGRLen())
4767bdd1243dSDimitry Andric     return false;
4768bdd1243dSDimitry Andric 
4769bdd1243dSDimitry Andric   if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
4770bdd1243dSDimitry Andric     const APInt &Imm = ConstNode->getAPIntValue();
477106c3fb27SDimitry Andric     // Break MUL into (SLLI + ADD/SUB) or ALSL.
4772bdd1243dSDimitry Andric     if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
4773bdd1243dSDimitry Andric         (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
4774bdd1243dSDimitry Andric       return true;
477506c3fb27SDimitry Andric     // Break MUL into (ALSL x, (SLLI x, imm0), imm1).
477606c3fb27SDimitry Andric     if (ConstNode->hasOneUse() &&
477706c3fb27SDimitry Andric         ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() ||
477806c3fb27SDimitry Andric          (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2()))
477906c3fb27SDimitry Andric       return true;
478006c3fb27SDimitry Andric     // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)),
478106c3fb27SDimitry Andric     // in which the immediate has two set bits. Or Break (MUL x, imm)
478206c3fb27SDimitry Andric     // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate
478306c3fb27SDimitry Andric     // equals to (1 << s0) - (1 << s1).
478406c3fb27SDimitry Andric     if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) {
478506c3fb27SDimitry Andric       unsigned Shifts = Imm.countr_zero();
478606c3fb27SDimitry Andric       // Reject immediates which can be composed via a single LUI.
478706c3fb27SDimitry Andric       if (Shifts >= 12)
478806c3fb27SDimitry Andric         return false;
478906c3fb27SDimitry Andric       // Reject multiplications can be optimized to
479006c3fb27SDimitry Andric       // (SLLI (ALSL x, x, 1/2/3/4), s).
479106c3fb27SDimitry Andric       APInt ImmPop = Imm.ashr(Shifts);
479206c3fb27SDimitry Andric       if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17)
479306c3fb27SDimitry Andric         return false;
479406c3fb27SDimitry Andric       // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`,
479506c3fb27SDimitry Andric       // since it needs one more instruction than other 3 cases.
479606c3fb27SDimitry Andric       APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true);
479706c3fb27SDimitry Andric       if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() ||
479806c3fb27SDimitry Andric           (ImmSmall - Imm).isPowerOf2())
479906c3fb27SDimitry Andric         return true;
480006c3fb27SDimitry Andric     }
4801bdd1243dSDimitry Andric   }
4802bdd1243dSDimitry Andric 
4803bdd1243dSDimitry Andric   return false;
4804bdd1243dSDimitry Andric }
480506c3fb27SDimitry Andric 
480606c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalAddressingMode(const DataLayout &DL,
480706c3fb27SDimitry Andric                                                     const AddrMode &AM,
480806c3fb27SDimitry Andric                                                     Type *Ty, unsigned AS,
480906c3fb27SDimitry Andric                                                     Instruction *I) const {
481006c3fb27SDimitry Andric   // LoongArch has four basic addressing modes:
481106c3fb27SDimitry Andric   //  1. reg
481206c3fb27SDimitry Andric   //  2. reg + 12-bit signed offset
481306c3fb27SDimitry Andric   //  3. reg + 14-bit signed offset left-shifted by 2
481406c3fb27SDimitry Andric   //  4. reg1 + reg2
481506c3fb27SDimitry Andric   // TODO: Add more checks after support vector extension.
481606c3fb27SDimitry Andric 
481706c3fb27SDimitry Andric   // No global is ever allowed as a base.
481806c3fb27SDimitry Andric   if (AM.BaseGV)
481906c3fb27SDimitry Andric     return false;
482006c3fb27SDimitry Andric 
482106c3fb27SDimitry Andric   // Require a 12 or 14 bit signed offset.
482206c3fb27SDimitry Andric   if (!isInt<12>(AM.BaseOffs) || !isShiftedInt<14, 2>(AM.BaseOffs))
482306c3fb27SDimitry Andric     return false;
482406c3fb27SDimitry Andric 
482506c3fb27SDimitry Andric   switch (AM.Scale) {
482606c3fb27SDimitry Andric   case 0:
482706c3fb27SDimitry Andric     // "i" is not allowed.
482806c3fb27SDimitry Andric     if (!AM.HasBaseReg)
482906c3fb27SDimitry Andric       return false;
483006c3fb27SDimitry Andric     // Otherwise we have "r+i".
483106c3fb27SDimitry Andric     break;
483206c3fb27SDimitry Andric   case 1:
483306c3fb27SDimitry Andric     // "r+r+i" is not allowed.
483406c3fb27SDimitry Andric     if (AM.HasBaseReg && AM.BaseOffs != 0)
483506c3fb27SDimitry Andric       return false;
483606c3fb27SDimitry Andric     // Otherwise we have "r+r" or "r+i".
483706c3fb27SDimitry Andric     break;
483806c3fb27SDimitry Andric   case 2:
483906c3fb27SDimitry Andric     // "2*r+r" or "2*r+i" is not allowed.
484006c3fb27SDimitry Andric     if (AM.HasBaseReg || AM.BaseOffs)
484106c3fb27SDimitry Andric       return false;
484206c3fb27SDimitry Andric     // Otherwise we have "r+r".
484306c3fb27SDimitry Andric     break;
484406c3fb27SDimitry Andric   default:
484506c3fb27SDimitry Andric     return false;
484606c3fb27SDimitry Andric   }
484706c3fb27SDimitry Andric 
484806c3fb27SDimitry Andric   return true;
484906c3fb27SDimitry Andric }
485006c3fb27SDimitry Andric 
485106c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
485206c3fb27SDimitry Andric   return isInt<12>(Imm);
485306c3fb27SDimitry Andric }
485406c3fb27SDimitry Andric 
485506c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalAddImmediate(int64_t Imm) const {
485606c3fb27SDimitry Andric   return isInt<12>(Imm);
485706c3fb27SDimitry Andric }
485806c3fb27SDimitry Andric 
485906c3fb27SDimitry Andric bool LoongArchTargetLowering::isZExtFree(SDValue Val, EVT VT2) const {
486006c3fb27SDimitry Andric   // Zexts are free if they can be combined with a load.
486106c3fb27SDimitry Andric   // Don't advertise i32->i64 zextload as being free for LA64. It interacts
486206c3fb27SDimitry Andric   // poorly with type legalization of compares preferring sext.
486306c3fb27SDimitry Andric   if (auto *LD = dyn_cast<LoadSDNode>(Val)) {
486406c3fb27SDimitry Andric     EVT MemVT = LD->getMemoryVT();
486506c3fb27SDimitry Andric     if ((MemVT == MVT::i8 || MemVT == MVT::i16) &&
486606c3fb27SDimitry Andric         (LD->getExtensionType() == ISD::NON_EXTLOAD ||
486706c3fb27SDimitry Andric          LD->getExtensionType() == ISD::ZEXTLOAD))
486806c3fb27SDimitry Andric       return true;
486906c3fb27SDimitry Andric   }
487006c3fb27SDimitry Andric 
487106c3fb27SDimitry Andric   return TargetLowering::isZExtFree(Val, VT2);
487206c3fb27SDimitry Andric }
487306c3fb27SDimitry Andric 
487406c3fb27SDimitry Andric bool LoongArchTargetLowering::isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const {
487506c3fb27SDimitry Andric   return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64;
487606c3fb27SDimitry Andric }
487706c3fb27SDimitry Andric 
487806c3fb27SDimitry Andric bool LoongArchTargetLowering::hasAndNotCompare(SDValue Y) const {
487906c3fb27SDimitry Andric   // TODO: Support vectors.
488006c3fb27SDimitry Andric   if (Y.getValueType().isVector())
488106c3fb27SDimitry Andric     return false;
488206c3fb27SDimitry Andric 
488306c3fb27SDimitry Andric   return !isa<ConstantSDNode>(Y);
488406c3fb27SDimitry Andric }
4885