xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
25*0fca6ea1SDimitry Andric #include "llvm/CodeGen/RuntimeLibcallUtil.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();
505f757f3fSDimitry Andric 
5181ad6265SDimitry Andric   // Set up the register classes.
525f757f3fSDimitry 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);
585f757f3fSDimitry Andric 
595f757f3fSDimitry Andric   static const MVT::SimpleValueType LSXVTs[] = {
605f757f3fSDimitry Andric       MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64};
615f757f3fSDimitry Andric   static const MVT::SimpleValueType LASXVTs[] = {
625f757f3fSDimitry Andric       MVT::v32i8, MVT::v16i16, MVT::v8i32, MVT::v4i64, MVT::v8f32, MVT::v4f64};
635f757f3fSDimitry Andric 
6406c3fb27SDimitry Andric   if (Subtarget.hasExtLSX())
655f757f3fSDimitry Andric     for (MVT VT : LSXVTs)
6606c3fb27SDimitry Andric       addRegisterClass(VT, &LoongArch::LSX128RegClass);
675f757f3fSDimitry Andric 
6806c3fb27SDimitry Andric   if (Subtarget.hasExtLASX())
695f757f3fSDimitry Andric     for (MVT VT : LASXVTs)
7006c3fb27SDimitry Andric       addRegisterClass(VT, &LoongArch::LASX256RegClass);
7181ad6265SDimitry Andric 
725f757f3fSDimitry Andric   // Set operations for LA32 and LA64.
735f757f3fSDimitry 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,
855f757f3fSDimitry Andric                       ISD::JumpTable, ISD::GlobalTLSAddress},
86bdd1243dSDimitry Andric                      GRLenVT, Custom);
87bdd1243dSDimitry Andric 
885f757f3fSDimitry 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 
955f757f3fSDimitry Andric   setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
965f757f3fSDimitry Andric   setOperationAction(ISD::TRAP, MVT::Other, Legal);
975f757f3fSDimitry Andric 
985f757f3fSDimitry Andric   setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
995f757f3fSDimitry Andric   setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
1005f757f3fSDimitry Andric   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
1015f757f3fSDimitry Andric 
1025f757f3fSDimitry Andric   // Expand bitreverse.i16 with native-width bitrev and shift for now, before
1035f757f3fSDimitry Andric   // we get to know which of sll and revb.2h is faster.
1045f757f3fSDimitry Andric   setOperationAction(ISD::BITREVERSE, MVT::i8, Custom);
1055f757f3fSDimitry Andric   setOperationAction(ISD::BITREVERSE, GRLenVT, Legal);
1065f757f3fSDimitry Andric 
1075f757f3fSDimitry Andric   // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
1085f757f3fSDimitry Andric   // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
1095f757f3fSDimitry Andric   // and i32 could still be byte-swapped relatively cheaply.
1105f757f3fSDimitry Andric   setOperationAction(ISD::BSWAP, MVT::i16, Custom);
1115f757f3fSDimitry Andric 
1125f757f3fSDimitry Andric   setOperationAction(ISD::BR_JT, MVT::Other, Expand);
1135f757f3fSDimitry Andric   setOperationAction(ISD::BR_CC, GRLenVT, Expand);
1145f757f3fSDimitry Andric   setOperationAction(ISD::SELECT_CC, GRLenVT, Expand);
1155f757f3fSDimitry Andric   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
1165f757f3fSDimitry Andric   setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, GRLenVT, Expand);
1175f757f3fSDimitry Andric 
1185f757f3fSDimitry Andric   setOperationAction(ISD::FP_TO_UINT, GRLenVT, Custom);
1195f757f3fSDimitry Andric   setOperationAction(ISD::UINT_TO_FP, GRLenVT, Expand);
1205f757f3fSDimitry Andric 
1215f757f3fSDimitry Andric   // Set operations for LA64 only.
1225f757f3fSDimitry Andric 
12381ad6265SDimitry Andric   if (Subtarget.is64Bit()) {
124*0fca6ea1SDimitry Andric     setOperationAction(ISD::ADD, MVT::i32, Custom);
125*0fca6ea1SDimitry Andric     setOperationAction(ISD::SUB, MVT::i32, Custom);
12681ad6265SDimitry Andric     setOperationAction(ISD::SHL, MVT::i32, Custom);
12781ad6265SDimitry Andric     setOperationAction(ISD::SRA, MVT::i32, Custom);
12881ad6265SDimitry Andric     setOperationAction(ISD::SRL, MVT::i32, Custom);
129753f127fSDimitry Andric     setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
130753f127fSDimitry Andric     setOperationAction(ISD::BITCAST, MVT::i32, Custom);
131bdd1243dSDimitry Andric     setOperationAction(ISD::ROTR, MVT::i32, Custom);
132bdd1243dSDimitry Andric     setOperationAction(ISD::ROTL, MVT::i32, Custom);
133bdd1243dSDimitry Andric     setOperationAction(ISD::CTTZ, MVT::i32, Custom);
134bdd1243dSDimitry Andric     setOperationAction(ISD::CTLZ, MVT::i32, Custom);
1355f757f3fSDimitry Andric     setOperationAction(ISD::EH_DWARF_CFA, MVT::i32, Custom);
136bdd1243dSDimitry Andric     setOperationAction(ISD::READ_REGISTER, MVT::i32, Custom);
137bdd1243dSDimitry Andric     setOperationAction(ISD::WRITE_REGISTER, MVT::i32, Custom);
1385f757f3fSDimitry Andric     setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom);
1395f757f3fSDimitry Andric     setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i32, Custom);
1405f757f3fSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i32, Custom);
14181ad6265SDimitry Andric 
1425f757f3fSDimitry Andric     setOperationAction(ISD::BITREVERSE, MVT::i32, Custom);
143bdd1243dSDimitry Andric     setOperationAction(ISD::BSWAP, MVT::i32, Custom);
144*0fca6ea1SDimitry Andric     setOperationAction({ISD::UDIV, ISD::UREM}, MVT::i32, Custom);
145bdd1243dSDimitry Andric   }
146bdd1243dSDimitry Andric 
1475f757f3fSDimitry Andric   // Set operations for LA32 only.
1485f757f3fSDimitry Andric 
1495f757f3fSDimitry Andric   if (!Subtarget.is64Bit()) {
150bdd1243dSDimitry Andric     setOperationAction(ISD::READ_REGISTER, MVT::i64, Custom);
151bdd1243dSDimitry Andric     setOperationAction(ISD::WRITE_REGISTER, MVT::i64, Custom);
152bdd1243dSDimitry Andric     setOperationAction(ISD::INTRINSIC_VOID, MVT::i64, Custom);
1535f757f3fSDimitry Andric     setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom);
1545f757f3fSDimitry Andric     setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom);
155bdd1243dSDimitry Andric   }
156bdd1243dSDimitry Andric 
1575f757f3fSDimitry Andric   setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom);
1585f757f3fSDimitry Andric 
159bdd1243dSDimitry Andric   static const ISD::CondCode FPCCToExpand[] = {
160bdd1243dSDimitry Andric       ISD::SETOGT, ISD::SETOGE, ISD::SETUGT, ISD::SETUGE,
161bdd1243dSDimitry Andric       ISD::SETGE,  ISD::SETNE,  ISD::SETGT};
16281ad6265SDimitry Andric 
1635f757f3fSDimitry Andric   // Set operations for 'F' feature.
1645f757f3fSDimitry Andric 
16581ad6265SDimitry Andric   if (Subtarget.hasBasicF()) {
166*0fca6ea1SDimitry Andric     setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand);
167*0fca6ea1SDimitry Andric     setTruncStoreAction(MVT::f32, MVT::f16, Expand);
16881ad6265SDimitry Andric     setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
1695f757f3fSDimitry Andric 
17081ad6265SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
171bdd1243dSDimitry Andric     setOperationAction(ISD::BR_CC, MVT::f32, Expand);
172bdd1243dSDimitry Andric     setOperationAction(ISD::FMA, MVT::f32, Legal);
173bdd1243dSDimitry Andric     setOperationAction(ISD::FMINNUM_IEEE, MVT::f32, Legal);
174bdd1243dSDimitry Andric     setOperationAction(ISD::FMAXNUM_IEEE, MVT::f32, Legal);
175bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCCS, MVT::f32, Legal);
176bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCC, MVT::f32, Legal);
1775f757f3fSDimitry Andric     setOperationAction(ISD::IS_FPCLASS, MVT::f32, Legal);
178bdd1243dSDimitry Andric     setOperationAction(ISD::FSIN, MVT::f32, Expand);
179bdd1243dSDimitry Andric     setOperationAction(ISD::FCOS, MVT::f32, Expand);
180bdd1243dSDimitry Andric     setOperationAction(ISD::FSINCOS, MVT::f32, Expand);
181bdd1243dSDimitry Andric     setOperationAction(ISD::FPOW, MVT::f32, Expand);
182bdd1243dSDimitry Andric     setOperationAction(ISD::FREM, MVT::f32, Expand);
183*0fca6ea1SDimitry Andric     setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand);
184*0fca6ea1SDimitry Andric     setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
1855f757f3fSDimitry Andric 
1865f757f3fSDimitry Andric     if (Subtarget.is64Bit())
1875f757f3fSDimitry Andric       setOperationAction(ISD::FRINT, MVT::f32, Legal);
1885f757f3fSDimitry Andric 
1895f757f3fSDimitry Andric     if (!Subtarget.hasBasicD()) {
1905f757f3fSDimitry Andric       setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
1915f757f3fSDimitry Andric       if (Subtarget.is64Bit()) {
1925f757f3fSDimitry Andric         setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom);
1935f757f3fSDimitry Andric         setOperationAction(ISD::UINT_TO_FP, MVT::i64, Custom);
19481ad6265SDimitry Andric       }
1955f757f3fSDimitry Andric     }
1965f757f3fSDimitry Andric   }
1975f757f3fSDimitry Andric 
1985f757f3fSDimitry Andric   // Set operations for 'D' feature.
1995f757f3fSDimitry Andric 
20081ad6265SDimitry Andric   if (Subtarget.hasBasicD()) {
201*0fca6ea1SDimitry Andric     setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand);
2025f757f3fSDimitry Andric     setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
203*0fca6ea1SDimitry Andric     setTruncStoreAction(MVT::f64, MVT::f16, Expand);
2045f757f3fSDimitry Andric     setTruncStoreAction(MVT::f64, MVT::f32, Expand);
20581ad6265SDimitry Andric     setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
2065f757f3fSDimitry Andric 
20781ad6265SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f64, Expand);
208bdd1243dSDimitry Andric     setOperationAction(ISD::BR_CC, MVT::f64, Expand);
209bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCCS, MVT::f64, Legal);
210bdd1243dSDimitry Andric     setOperationAction(ISD::STRICT_FSETCC, MVT::f64, Legal);
211bdd1243dSDimitry Andric     setOperationAction(ISD::FMA, MVT::f64, Legal);
212bdd1243dSDimitry Andric     setOperationAction(ISD::FMINNUM_IEEE, MVT::f64, Legal);
213bdd1243dSDimitry Andric     setOperationAction(ISD::FMAXNUM_IEEE, MVT::f64, Legal);
2145f757f3fSDimitry Andric     setOperationAction(ISD::IS_FPCLASS, MVT::f64, Legal);
215bdd1243dSDimitry Andric     setOperationAction(ISD::FSIN, MVT::f64, Expand);
216bdd1243dSDimitry Andric     setOperationAction(ISD::FCOS, MVT::f64, Expand);
217bdd1243dSDimitry Andric     setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
218bdd1243dSDimitry Andric     setOperationAction(ISD::FPOW, MVT::f64, Expand);
219bdd1243dSDimitry Andric     setOperationAction(ISD::FREM, MVT::f64, Expand);
220*0fca6ea1SDimitry Andric     setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand);
221*0fca6ea1SDimitry Andric     setOperationAction(ISD::FP_TO_FP16, MVT::f64, Expand);
2225f757f3fSDimitry Andric 
2235f757f3fSDimitry Andric     if (Subtarget.is64Bit())
2245f757f3fSDimitry Andric       setOperationAction(ISD::FRINT, MVT::f64, Legal);
22581ad6265SDimitry Andric   }
22681ad6265SDimitry Andric 
2275f757f3fSDimitry Andric   // Set operations for 'LSX' feature.
228bdd1243dSDimitry Andric 
2295f757f3fSDimitry Andric   if (Subtarget.hasExtLSX()) {
2305f757f3fSDimitry Andric     for (MVT VT : MVT::fixedlen_vector_valuetypes()) {
2315f757f3fSDimitry Andric       // Expand all truncating stores and extending loads.
2325f757f3fSDimitry Andric       for (MVT InnerVT : MVT::fixedlen_vector_valuetypes()) {
2335f757f3fSDimitry Andric         setTruncStoreAction(VT, InnerVT, Expand);
2345f757f3fSDimitry Andric         setLoadExtAction(ISD::SEXTLOAD, VT, InnerVT, Expand);
2355f757f3fSDimitry Andric         setLoadExtAction(ISD::ZEXTLOAD, VT, InnerVT, Expand);
2365f757f3fSDimitry Andric         setLoadExtAction(ISD::EXTLOAD, VT, InnerVT, Expand);
237bdd1243dSDimitry Andric       }
2385f757f3fSDimitry Andric       // By default everything must be expanded. Then we will selectively turn
2395f757f3fSDimitry Andric       // on ones that can be effectively codegen'd.
2405f757f3fSDimitry Andric       for (unsigned Op = 0; Op < ISD::BUILTIN_OP_END; ++Op)
2415f757f3fSDimitry Andric         setOperationAction(Op, VT, Expand);
2425f757f3fSDimitry Andric     }
2435f757f3fSDimitry Andric 
2445f757f3fSDimitry Andric     for (MVT VT : LSXVTs) {
2455f757f3fSDimitry Andric       setOperationAction({ISD::LOAD, ISD::STORE}, VT, Legal);
2465f757f3fSDimitry Andric       setOperationAction(ISD::BITCAST, VT, Legal);
2475f757f3fSDimitry Andric       setOperationAction(ISD::UNDEF, VT, Legal);
2485f757f3fSDimitry Andric 
2495f757f3fSDimitry Andric       setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Custom);
2505f757f3fSDimitry Andric       setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT, Legal);
2515f757f3fSDimitry Andric       setOperationAction(ISD::BUILD_VECTOR, VT, Custom);
2525f757f3fSDimitry Andric 
2535f757f3fSDimitry Andric       setOperationAction(ISD::SETCC, VT, Legal);
2545f757f3fSDimitry Andric       setOperationAction(ISD::VSELECT, VT, Legal);
255*0fca6ea1SDimitry Andric       setOperationAction(ISD::VECTOR_SHUFFLE, VT, Custom);
2565f757f3fSDimitry Andric     }
2575f757f3fSDimitry Andric     for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) {
2585f757f3fSDimitry Andric       setOperationAction({ISD::ADD, ISD::SUB}, VT, Legal);
2595f757f3fSDimitry Andric       setOperationAction({ISD::UMAX, ISD::UMIN, ISD::SMAX, ISD::SMIN}, VT,
2605f757f3fSDimitry Andric                          Legal);
2615f757f3fSDimitry Andric       setOperationAction({ISD::MUL, ISD::SDIV, ISD::SREM, ISD::UDIV, ISD::UREM},
2625f757f3fSDimitry Andric                          VT, Legal);
2635f757f3fSDimitry Andric       setOperationAction({ISD::AND, ISD::OR, ISD::XOR}, VT, Legal);
2645f757f3fSDimitry Andric       setOperationAction({ISD::SHL, ISD::SRA, ISD::SRL}, VT, Legal);
2655f757f3fSDimitry Andric       setOperationAction({ISD::CTPOP, ISD::CTLZ}, VT, Legal);
2665f757f3fSDimitry Andric       setOperationAction({ISD::MULHS, ISD::MULHU}, VT, Legal);
2675f757f3fSDimitry Andric       setCondCodeAction(
2685f757f3fSDimitry Andric           {ISD::SETNE, ISD::SETGE, ISD::SETGT, ISD::SETUGE, ISD::SETUGT}, VT,
2695f757f3fSDimitry Andric           Expand);
2705f757f3fSDimitry Andric     }
2717a6dacacSDimitry Andric     for (MVT VT : {MVT::v4i32, MVT::v2i64}) {
2727a6dacacSDimitry Andric       setOperationAction({ISD::SINT_TO_FP, ISD::UINT_TO_FP}, VT, Legal);
2737a6dacacSDimitry Andric       setOperationAction({ISD::FP_TO_SINT, ISD::FP_TO_UINT}, VT, Legal);
2747a6dacacSDimitry Andric     }
2755f757f3fSDimitry Andric     for (MVT VT : {MVT::v4f32, MVT::v2f64}) {
2765f757f3fSDimitry Andric       setOperationAction({ISD::FADD, ISD::FSUB}, VT, Legal);
2775f757f3fSDimitry Andric       setOperationAction({ISD::FMUL, ISD::FDIV}, VT, Legal);
2785f757f3fSDimitry Andric       setOperationAction(ISD::FMA, VT, Legal);
2795f757f3fSDimitry Andric       setOperationAction(ISD::FSQRT, VT, Legal);
2805f757f3fSDimitry Andric       setOperationAction(ISD::FNEG, VT, Legal);
2815f757f3fSDimitry Andric       setCondCodeAction({ISD::SETGE, ISD::SETGT, ISD::SETOGE, ISD::SETOGT,
2825f757f3fSDimitry Andric                          ISD::SETUGE, ISD::SETUGT},
2835f757f3fSDimitry Andric                         VT, Expand);
2845f757f3fSDimitry Andric     }
2855f757f3fSDimitry Andric   }
2865f757f3fSDimitry Andric 
2875f757f3fSDimitry Andric   // Set operations for 'LASX' feature.
2885f757f3fSDimitry Andric 
2895f757f3fSDimitry Andric   if (Subtarget.hasExtLASX()) {
2905f757f3fSDimitry Andric     for (MVT VT : LASXVTs) {
2915f757f3fSDimitry Andric       setOperationAction({ISD::LOAD, ISD::STORE}, VT, Legal);
2925f757f3fSDimitry Andric       setOperationAction(ISD::BITCAST, VT, Legal);
2935f757f3fSDimitry Andric       setOperationAction(ISD::UNDEF, VT, Legal);
2945f757f3fSDimitry Andric 
2955f757f3fSDimitry Andric       setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Custom);
296647cbc5dSDimitry Andric       setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT, Custom);
2975f757f3fSDimitry Andric       setOperationAction(ISD::BUILD_VECTOR, VT, Custom);
2985f757f3fSDimitry Andric 
2995f757f3fSDimitry Andric       setOperationAction(ISD::SETCC, VT, Legal);
3005f757f3fSDimitry Andric       setOperationAction(ISD::VSELECT, VT, Legal);
301*0fca6ea1SDimitry Andric       setOperationAction(ISD::VECTOR_SHUFFLE, VT, Custom);
3025f757f3fSDimitry Andric     }
3035f757f3fSDimitry Andric     for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16, MVT::v32i8}) {
3045f757f3fSDimitry Andric       setOperationAction({ISD::ADD, ISD::SUB}, VT, Legal);
3055f757f3fSDimitry Andric       setOperationAction({ISD::UMAX, ISD::UMIN, ISD::SMAX, ISD::SMIN}, VT,
3065f757f3fSDimitry Andric                          Legal);
3075f757f3fSDimitry Andric       setOperationAction({ISD::MUL, ISD::SDIV, ISD::SREM, ISD::UDIV, ISD::UREM},
3085f757f3fSDimitry Andric                          VT, Legal);
3095f757f3fSDimitry Andric       setOperationAction({ISD::AND, ISD::OR, ISD::XOR}, VT, Legal);
3105f757f3fSDimitry Andric       setOperationAction({ISD::SHL, ISD::SRA, ISD::SRL}, VT, Legal);
3115f757f3fSDimitry Andric       setOperationAction({ISD::CTPOP, ISD::CTLZ}, VT, Legal);
3125f757f3fSDimitry Andric       setOperationAction({ISD::MULHS, ISD::MULHU}, VT, Legal);
3135f757f3fSDimitry Andric       setCondCodeAction(
3145f757f3fSDimitry Andric           {ISD::SETNE, ISD::SETGE, ISD::SETGT, ISD::SETUGE, ISD::SETUGT}, VT,
3155f757f3fSDimitry Andric           Expand);
3165f757f3fSDimitry Andric     }
3177a6dacacSDimitry Andric     for (MVT VT : {MVT::v8i32, MVT::v4i32, MVT::v4i64}) {
3187a6dacacSDimitry Andric       setOperationAction({ISD::SINT_TO_FP, ISD::UINT_TO_FP}, VT, Legal);
3197a6dacacSDimitry Andric       setOperationAction({ISD::FP_TO_SINT, ISD::FP_TO_UINT}, VT, Legal);
3207a6dacacSDimitry Andric     }
3215f757f3fSDimitry Andric     for (MVT VT : {MVT::v8f32, MVT::v4f64}) {
3225f757f3fSDimitry Andric       setOperationAction({ISD::FADD, ISD::FSUB}, VT, Legal);
3235f757f3fSDimitry Andric       setOperationAction({ISD::FMUL, ISD::FDIV}, VT, Legal);
3245f757f3fSDimitry Andric       setOperationAction(ISD::FMA, VT, Legal);
3255f757f3fSDimitry Andric       setOperationAction(ISD::FSQRT, VT, Legal);
3265f757f3fSDimitry Andric       setOperationAction(ISD::FNEG, VT, Legal);
3275f757f3fSDimitry Andric       setCondCodeAction({ISD::SETGE, ISD::SETGT, ISD::SETOGE, ISD::SETOGT,
3285f757f3fSDimitry Andric                          ISD::SETUGE, ISD::SETUGT},
3295f757f3fSDimitry Andric                         VT, Expand);
3305f757f3fSDimitry Andric     }
3315f757f3fSDimitry Andric   }
3325f757f3fSDimitry Andric 
3335f757f3fSDimitry Andric   // Set DAG combine for LA32 and LA64.
3345f757f3fSDimitry Andric 
3355f757f3fSDimitry Andric   setTargetDAGCombine(ISD::AND);
3365f757f3fSDimitry Andric   setTargetDAGCombine(ISD::OR);
3375f757f3fSDimitry Andric   setTargetDAGCombine(ISD::SRL);
338*0fca6ea1SDimitry Andric   setTargetDAGCombine(ISD::SETCC);
3395f757f3fSDimitry Andric 
3405f757f3fSDimitry Andric   // Set DAG combine for 'LSX' feature.
3415f757f3fSDimitry Andric 
3425f757f3fSDimitry Andric   if (Subtarget.hasExtLSX())
3435f757f3fSDimitry Andric     setTargetDAGCombine(ISD::INTRINSIC_WO_CHAIN);
34481ad6265SDimitry Andric 
34581ad6265SDimitry Andric   // Compute derived properties from the register classes.
34606c3fb27SDimitry Andric   computeRegisterProperties(Subtarget.getRegisterInfo());
34781ad6265SDimitry Andric 
34881ad6265SDimitry Andric   setStackPointerRegisterToSaveRestore(LoongArch::R3);
34981ad6265SDimitry Andric 
35081ad6265SDimitry Andric   setBooleanContents(ZeroOrOneBooleanContent);
3515f757f3fSDimitry Andric   setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
35281ad6265SDimitry Andric 
353753f127fSDimitry Andric   setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen());
354753f127fSDimitry Andric 
355bdd1243dSDimitry Andric   setMinCmpXchgSizeInBits(32);
356bdd1243dSDimitry Andric 
35781ad6265SDimitry Andric   // Function alignments.
35806c3fb27SDimitry Andric   setMinFunctionAlignment(Align(4));
35906c3fb27SDimitry Andric   // Set preferred alignments.
36006c3fb27SDimitry Andric   setPrefFunctionAlignment(Subtarget.getPrefFunctionAlignment());
36106c3fb27SDimitry Andric   setPrefLoopAlignment(Subtarget.getPrefLoopAlignment());
36206c3fb27SDimitry Andric   setMaxBytesForAlignment(Subtarget.getMaxBytesForAlignment());
36381ad6265SDimitry Andric }
36481ad6265SDimitry Andric 
365bdd1243dSDimitry Andric bool LoongArchTargetLowering::isOffsetFoldingLegal(
366bdd1243dSDimitry Andric     const GlobalAddressSDNode *GA) const {
367bdd1243dSDimitry Andric   // In order to maximise the opportunity for common subexpression elimination,
368bdd1243dSDimitry Andric   // keep a separate ADD node for the global address offset instead of folding
369bdd1243dSDimitry Andric   // it in the global address node. Later peephole optimisations may choose to
370bdd1243dSDimitry Andric   // fold it back in when profitable.
371bdd1243dSDimitry Andric   return false;
372bdd1243dSDimitry Andric }
373bdd1243dSDimitry Andric 
37481ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
37581ad6265SDimitry Andric                                                 SelectionDAG &DAG) const {
37681ad6265SDimitry Andric   switch (Op.getOpcode()) {
3775f757f3fSDimitry Andric   case ISD::ATOMIC_FENCE:
3785f757f3fSDimitry Andric     return lowerATOMIC_FENCE(Op, DAG);
379bdd1243dSDimitry Andric   case ISD::EH_DWARF_CFA:
380bdd1243dSDimitry Andric     return lowerEH_DWARF_CFA(Op, DAG);
381753f127fSDimitry Andric   case ISD::GlobalAddress:
382753f127fSDimitry Andric     return lowerGlobalAddress(Op, DAG);
383bdd1243dSDimitry Andric   case ISD::GlobalTLSAddress:
384bdd1243dSDimitry Andric     return lowerGlobalTLSAddress(Op, DAG);
385bdd1243dSDimitry Andric   case ISD::INTRINSIC_WO_CHAIN:
386bdd1243dSDimitry Andric     return lowerINTRINSIC_WO_CHAIN(Op, DAG);
387bdd1243dSDimitry Andric   case ISD::INTRINSIC_W_CHAIN:
388bdd1243dSDimitry Andric     return lowerINTRINSIC_W_CHAIN(Op, DAG);
389bdd1243dSDimitry Andric   case ISD::INTRINSIC_VOID:
390bdd1243dSDimitry Andric     return lowerINTRINSIC_VOID(Op, DAG);
391bdd1243dSDimitry Andric   case ISD::BlockAddress:
392bdd1243dSDimitry Andric     return lowerBlockAddress(Op, DAG);
393bdd1243dSDimitry Andric   case ISD::JumpTable:
394bdd1243dSDimitry Andric     return lowerJumpTable(Op, DAG);
39581ad6265SDimitry Andric   case ISD::SHL_PARTS:
39681ad6265SDimitry Andric     return lowerShiftLeftParts(Op, DAG);
39781ad6265SDimitry Andric   case ISD::SRA_PARTS:
39881ad6265SDimitry Andric     return lowerShiftRightParts(Op, DAG, true);
39981ad6265SDimitry Andric   case ISD::SRL_PARTS:
40081ad6265SDimitry Andric     return lowerShiftRightParts(Op, DAG, false);
401753f127fSDimitry Andric   case ISD::ConstantPool:
402753f127fSDimitry Andric     return lowerConstantPool(Op, DAG);
403753f127fSDimitry Andric   case ISD::FP_TO_SINT:
404753f127fSDimitry Andric     return lowerFP_TO_SINT(Op, DAG);
405753f127fSDimitry Andric   case ISD::BITCAST:
406753f127fSDimitry Andric     return lowerBITCAST(Op, DAG);
407753f127fSDimitry Andric   case ISD::UINT_TO_FP:
408753f127fSDimitry Andric     return lowerUINT_TO_FP(Op, DAG);
409bdd1243dSDimitry Andric   case ISD::SINT_TO_FP:
410bdd1243dSDimitry Andric     return lowerSINT_TO_FP(Op, DAG);
411bdd1243dSDimitry Andric   case ISD::VASTART:
412bdd1243dSDimitry Andric     return lowerVASTART(Op, DAG);
413bdd1243dSDimitry Andric   case ISD::FRAMEADDR:
414bdd1243dSDimitry Andric     return lowerFRAMEADDR(Op, DAG);
415bdd1243dSDimitry Andric   case ISD::RETURNADDR:
416bdd1243dSDimitry Andric     return lowerRETURNADDR(Op, DAG);
417bdd1243dSDimitry Andric   case ISD::WRITE_REGISTER:
418bdd1243dSDimitry Andric     return lowerWRITE_REGISTER(Op, DAG);
4195f757f3fSDimitry Andric   case ISD::INSERT_VECTOR_ELT:
4205f757f3fSDimitry Andric     return lowerINSERT_VECTOR_ELT(Op, DAG);
421647cbc5dSDimitry Andric   case ISD::EXTRACT_VECTOR_ELT:
422647cbc5dSDimitry Andric     return lowerEXTRACT_VECTOR_ELT(Op, DAG);
4235f757f3fSDimitry Andric   case ISD::BUILD_VECTOR:
4245f757f3fSDimitry Andric     return lowerBUILD_VECTOR(Op, DAG);
4255f757f3fSDimitry Andric   case ISD::VECTOR_SHUFFLE:
4265f757f3fSDimitry Andric     return lowerVECTOR_SHUFFLE(Op, DAG);
42781ad6265SDimitry Andric   }
428bdd1243dSDimitry Andric   return SDValue();
429bdd1243dSDimitry Andric }
430bdd1243dSDimitry Andric 
431*0fca6ea1SDimitry Andric /// Determine whether a range fits a regular pattern of values.
432*0fca6ea1SDimitry Andric /// This function accounts for the possibility of jumping over the End iterator.
433*0fca6ea1SDimitry Andric template <typename ValType>
434*0fca6ea1SDimitry Andric static bool
435*0fca6ea1SDimitry Andric fitsRegularPattern(typename SmallVectorImpl<ValType>::const_iterator Begin,
436*0fca6ea1SDimitry Andric                    unsigned CheckStride,
437*0fca6ea1SDimitry Andric                    typename SmallVectorImpl<ValType>::const_iterator End,
438*0fca6ea1SDimitry Andric                    ValType ExpectedIndex, unsigned ExpectedIndexStride) {
439*0fca6ea1SDimitry Andric   auto &I = Begin;
440*0fca6ea1SDimitry Andric 
441*0fca6ea1SDimitry Andric   while (I != End) {
442*0fca6ea1SDimitry Andric     if (*I != -1 && *I != ExpectedIndex)
443*0fca6ea1SDimitry Andric       return false;
444*0fca6ea1SDimitry Andric     ExpectedIndex += ExpectedIndexStride;
445*0fca6ea1SDimitry Andric 
446*0fca6ea1SDimitry Andric     // Incrementing past End is undefined behaviour so we must increment one
447*0fca6ea1SDimitry Andric     // step at a time and check for End at each step.
448*0fca6ea1SDimitry Andric     for (unsigned n = 0; n < CheckStride && I != End; ++n, ++I)
449*0fca6ea1SDimitry Andric       ; // Empty loop body.
450*0fca6ea1SDimitry Andric   }
451*0fca6ea1SDimitry Andric   return true;
452*0fca6ea1SDimitry Andric }
453*0fca6ea1SDimitry Andric 
454*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
455*0fca6ea1SDimitry Andric ///
456*0fca6ea1SDimitry Andric /// VREPLVEI performs vector broadcast based on an element specified by an
457*0fca6ea1SDimitry Andric /// integer immediate, with its mask being similar to:
458*0fca6ea1SDimitry Andric ///   <x, x, x, ...>
459*0fca6ea1SDimitry Andric /// where x is any valid index.
460*0fca6ea1SDimitry Andric ///
461*0fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever
462*0fca6ea1SDimitry Andric /// value is necessary in order to fit the above form.
463*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VREPLVEI(const SDLoc &DL, ArrayRef<int> Mask,
464*0fca6ea1SDimitry Andric                                             MVT VT, SDValue V1, SDValue V2,
465*0fca6ea1SDimitry Andric                                             SelectionDAG &DAG) {
466*0fca6ea1SDimitry Andric   int SplatIndex = -1;
467*0fca6ea1SDimitry Andric   for (const auto &M : Mask) {
468*0fca6ea1SDimitry Andric     if (M != -1) {
469*0fca6ea1SDimitry Andric       SplatIndex = M;
470*0fca6ea1SDimitry Andric       break;
471*0fca6ea1SDimitry Andric     }
472*0fca6ea1SDimitry Andric   }
473*0fca6ea1SDimitry Andric 
474*0fca6ea1SDimitry Andric   if (SplatIndex == -1)
475*0fca6ea1SDimitry Andric     return DAG.getUNDEF(VT);
476*0fca6ea1SDimitry Andric 
477*0fca6ea1SDimitry Andric   assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
478*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Mask.begin(), 1, Mask.end(), SplatIndex, 0)) {
479*0fca6ea1SDimitry Andric     APInt Imm(64, SplatIndex);
480*0fca6ea1SDimitry Andric     return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
481*0fca6ea1SDimitry Andric                        DAG.getConstant(Imm, DL, MVT::i64));
482*0fca6ea1SDimitry Andric   }
483*0fca6ea1SDimitry Andric 
484*0fca6ea1SDimitry Andric   return SDValue();
485*0fca6ea1SDimitry Andric }
486*0fca6ea1SDimitry Andric 
487*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VSHUF4I (if possible).
488*0fca6ea1SDimitry Andric ///
489*0fca6ea1SDimitry Andric /// VSHUF4I splits the vector into blocks of four elements, then shuffles these
490*0fca6ea1SDimitry Andric /// elements according to a <4 x i2> constant (encoded as an integer immediate).
491*0fca6ea1SDimitry Andric ///
492*0fca6ea1SDimitry Andric /// It is therefore possible to lower into VSHUF4I when the mask takes the form:
493*0fca6ea1SDimitry Andric ///   <a, b, c, d, a+4, b+4, c+4, d+4, a+8, b+8, c+8, d+8, ...>
494*0fca6ea1SDimitry Andric /// When undef's appear they are treated as if they were whatever value is
495*0fca6ea1SDimitry Andric /// necessary in order to fit the above forms.
496*0fca6ea1SDimitry Andric ///
497*0fca6ea1SDimitry Andric /// For example:
498*0fca6ea1SDimitry Andric ///   %2 = shufflevector <8 x i16> %0, <8 x i16> undef,
499*0fca6ea1SDimitry Andric ///                      <8 x i32> <i32 3, i32 2, i32 1, i32 0,
500*0fca6ea1SDimitry Andric ///                                 i32 7, i32 6, i32 5, i32 4>
501*0fca6ea1SDimitry Andric /// is lowered to:
502*0fca6ea1SDimitry Andric ///   (VSHUF4I_H $v0, $v1, 27)
503*0fca6ea1SDimitry Andric /// where the 27 comes from:
504*0fca6ea1SDimitry Andric ///   3 + (2 << 2) + (1 << 4) + (0 << 6)
505*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VSHUF4I(const SDLoc &DL, ArrayRef<int> Mask,
506*0fca6ea1SDimitry Andric                                            MVT VT, SDValue V1, SDValue V2,
507*0fca6ea1SDimitry Andric                                            SelectionDAG &DAG) {
508*0fca6ea1SDimitry Andric 
509*0fca6ea1SDimitry Andric   // When the size is less than 4, lower cost instructions may be used.
510*0fca6ea1SDimitry Andric   if (Mask.size() < 4)
511*0fca6ea1SDimitry Andric     return SDValue();
512*0fca6ea1SDimitry Andric 
513*0fca6ea1SDimitry Andric   int SubMask[4] = {-1, -1, -1, -1};
514*0fca6ea1SDimitry Andric   for (unsigned i = 0; i < 4; ++i) {
515*0fca6ea1SDimitry Andric     for (unsigned j = i; j < Mask.size(); j += 4) {
516*0fca6ea1SDimitry Andric       int Idx = Mask[j];
517*0fca6ea1SDimitry Andric 
518*0fca6ea1SDimitry Andric       // Convert from vector index to 4-element subvector index
519*0fca6ea1SDimitry Andric       // If an index refers to an element outside of the subvector then give up
520*0fca6ea1SDimitry Andric       if (Idx != -1) {
521*0fca6ea1SDimitry Andric         Idx -= 4 * (j / 4);
522*0fca6ea1SDimitry Andric         if (Idx < 0 || Idx >= 4)
523*0fca6ea1SDimitry Andric           return SDValue();
524*0fca6ea1SDimitry Andric       }
525*0fca6ea1SDimitry Andric 
526*0fca6ea1SDimitry Andric       // If the mask has an undef, replace it with the current index.
527*0fca6ea1SDimitry Andric       // Note that it might still be undef if the current index is also undef
528*0fca6ea1SDimitry Andric       if (SubMask[i] == -1)
529*0fca6ea1SDimitry Andric         SubMask[i] = Idx;
530*0fca6ea1SDimitry Andric       // Check that non-undef values are the same as in the mask. If they
531*0fca6ea1SDimitry Andric       // aren't then give up
532*0fca6ea1SDimitry Andric       else if (Idx != -1 && Idx != SubMask[i])
533*0fca6ea1SDimitry Andric         return SDValue();
534*0fca6ea1SDimitry Andric     }
535*0fca6ea1SDimitry Andric   }
536*0fca6ea1SDimitry Andric 
537*0fca6ea1SDimitry Andric   // Calculate the immediate. Replace any remaining undefs with zero
538*0fca6ea1SDimitry Andric   APInt Imm(64, 0);
539*0fca6ea1SDimitry Andric   for (int i = 3; i >= 0; --i) {
540*0fca6ea1SDimitry Andric     int Idx = SubMask[i];
541*0fca6ea1SDimitry Andric 
542*0fca6ea1SDimitry Andric     if (Idx == -1)
543*0fca6ea1SDimitry Andric       Idx = 0;
544*0fca6ea1SDimitry Andric 
545*0fca6ea1SDimitry Andric     Imm <<= 2;
546*0fca6ea1SDimitry Andric     Imm |= Idx & 0x3;
547*0fca6ea1SDimitry Andric   }
548*0fca6ea1SDimitry Andric 
549*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT, V1,
550*0fca6ea1SDimitry Andric                      DAG.getConstant(Imm, DL, MVT::i64));
551*0fca6ea1SDimitry Andric }
552*0fca6ea1SDimitry Andric 
553*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VPACKEV (if possible).
554*0fca6ea1SDimitry Andric ///
555*0fca6ea1SDimitry Andric /// VPACKEV interleaves the even elements from each vector.
556*0fca6ea1SDimitry Andric ///
557*0fca6ea1SDimitry Andric /// It is possible to lower into VPACKEV when the mask consists of two of the
558*0fca6ea1SDimitry Andric /// following forms interleaved:
559*0fca6ea1SDimitry Andric ///   <0, 2, 4, ...>
560*0fca6ea1SDimitry Andric ///   <n, n+2, n+4, ...>
561*0fca6ea1SDimitry Andric /// where n is the number of elements in the vector.
562*0fca6ea1SDimitry Andric /// For example:
563*0fca6ea1SDimitry Andric ///   <0, 0, 2, 2, 4, 4, ...>
564*0fca6ea1SDimitry Andric ///   <0, n, 2, n+2, 4, n+4, ...>
565*0fca6ea1SDimitry Andric ///
566*0fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever
567*0fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms.
568*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VPACKEV(const SDLoc &DL, ArrayRef<int> Mask,
569*0fca6ea1SDimitry Andric                                            MVT VT, SDValue V1, SDValue V2,
570*0fca6ea1SDimitry Andric                                            SelectionDAG &DAG) {
571*0fca6ea1SDimitry Andric 
572*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
573*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
574*0fca6ea1SDimitry Andric   SDValue OriV1 = V1, OriV2 = V2;
575*0fca6ea1SDimitry Andric 
576*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin, 2, End, 0, 2))
577*0fca6ea1SDimitry Andric     V1 = OriV1;
578*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 2))
579*0fca6ea1SDimitry Andric     V1 = OriV2;
580*0fca6ea1SDimitry Andric   else
581*0fca6ea1SDimitry Andric     return SDValue();
582*0fca6ea1SDimitry Andric 
583*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 2))
584*0fca6ea1SDimitry Andric     V2 = OriV1;
585*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 2))
586*0fca6ea1SDimitry Andric     V2 = OriV2;
587*0fca6ea1SDimitry Andric   else
588*0fca6ea1SDimitry Andric     return SDValue();
589*0fca6ea1SDimitry Andric 
590*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VPACKEV, DL, VT, V2, V1);
591*0fca6ea1SDimitry Andric }
592*0fca6ea1SDimitry Andric 
593*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VPACKOD (if possible).
594*0fca6ea1SDimitry Andric ///
595*0fca6ea1SDimitry Andric /// VPACKOD interleaves the odd elements from each vector.
596*0fca6ea1SDimitry Andric ///
597*0fca6ea1SDimitry Andric /// It is possible to lower into VPACKOD when the mask consists of two of the
598*0fca6ea1SDimitry Andric /// following forms interleaved:
599*0fca6ea1SDimitry Andric ///   <1, 3, 5, ...>
600*0fca6ea1SDimitry Andric ///   <n+1, n+3, n+5, ...>
601*0fca6ea1SDimitry Andric /// where n is the number of elements in the vector.
602*0fca6ea1SDimitry Andric /// For example:
603*0fca6ea1SDimitry Andric ///   <1, 1, 3, 3, 5, 5, ...>
604*0fca6ea1SDimitry Andric ///   <1, n+1, 3, n+3, 5, n+5, ...>
605*0fca6ea1SDimitry Andric ///
606*0fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever
607*0fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms.
608*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VPACKOD(const SDLoc &DL, ArrayRef<int> Mask,
609*0fca6ea1SDimitry Andric                                            MVT VT, SDValue V1, SDValue V2,
610*0fca6ea1SDimitry Andric                                            SelectionDAG &DAG) {
611*0fca6ea1SDimitry Andric 
612*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
613*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
614*0fca6ea1SDimitry Andric   SDValue OriV1 = V1, OriV2 = V2;
615*0fca6ea1SDimitry Andric 
616*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin, 2, End, 1, 2))
617*0fca6ea1SDimitry Andric     V1 = OriV1;
618*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + 1, 2))
619*0fca6ea1SDimitry Andric     V1 = OriV2;
620*0fca6ea1SDimitry Andric   else
621*0fca6ea1SDimitry Andric     return SDValue();
622*0fca6ea1SDimitry Andric 
623*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin + 1, 2, End, 1, 2))
624*0fca6ea1SDimitry Andric     V2 = OriV1;
625*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + 1, 2))
626*0fca6ea1SDimitry Andric     V2 = OriV2;
627*0fca6ea1SDimitry Andric   else
628*0fca6ea1SDimitry Andric     return SDValue();
629*0fca6ea1SDimitry Andric 
630*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VPACKOD, DL, VT, V2, V1);
631*0fca6ea1SDimitry Andric }
632*0fca6ea1SDimitry Andric 
633*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VILVH (if possible).
634*0fca6ea1SDimitry Andric ///
635*0fca6ea1SDimitry Andric /// VILVH interleaves consecutive elements from the left (highest-indexed) half
636*0fca6ea1SDimitry Andric /// of each vector.
637*0fca6ea1SDimitry Andric ///
638*0fca6ea1SDimitry Andric /// It is possible to lower into VILVH when the mask consists of two of the
639*0fca6ea1SDimitry Andric /// following forms interleaved:
640*0fca6ea1SDimitry Andric ///   <x, x+1, x+2, ...>
641*0fca6ea1SDimitry Andric ///   <n+x, n+x+1, n+x+2, ...>
642*0fca6ea1SDimitry Andric /// where n is the number of elements in the vector and x is half n.
643*0fca6ea1SDimitry Andric /// For example:
644*0fca6ea1SDimitry Andric ///   <x, x, x+1, x+1, x+2, x+2, ...>
645*0fca6ea1SDimitry Andric ///   <x, n+x, x+1, n+x+1, x+2, n+x+2, ...>
646*0fca6ea1SDimitry Andric ///
647*0fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever
648*0fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms.
649*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VILVH(const SDLoc &DL, ArrayRef<int> Mask,
650*0fca6ea1SDimitry Andric                                          MVT VT, SDValue V1, SDValue V2,
651*0fca6ea1SDimitry Andric                                          SelectionDAG &DAG) {
652*0fca6ea1SDimitry Andric 
653*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
654*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
655*0fca6ea1SDimitry Andric   unsigned HalfSize = Mask.size() / 2;
656*0fca6ea1SDimitry Andric   SDValue OriV1 = V1, OriV2 = V2;
657*0fca6ea1SDimitry Andric 
658*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin, 2, End, HalfSize, 1))
659*0fca6ea1SDimitry Andric     V1 = OriV1;
660*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + HalfSize, 1))
661*0fca6ea1SDimitry Andric     V1 = OriV2;
662*0fca6ea1SDimitry Andric   else
663*0fca6ea1SDimitry Andric     return SDValue();
664*0fca6ea1SDimitry Andric 
665*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin + 1, 2, End, HalfSize, 1))
666*0fca6ea1SDimitry Andric     V2 = OriV1;
667*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + HalfSize,
668*0fca6ea1SDimitry Andric                                    1))
669*0fca6ea1SDimitry Andric     V2 = OriV2;
670*0fca6ea1SDimitry Andric   else
671*0fca6ea1SDimitry Andric     return SDValue();
672*0fca6ea1SDimitry Andric 
673*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
674*0fca6ea1SDimitry Andric }
675*0fca6ea1SDimitry Andric 
676*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VILVL (if possible).
677*0fca6ea1SDimitry Andric ///
678*0fca6ea1SDimitry Andric /// VILVL interleaves consecutive elements from the right (lowest-indexed) half
679*0fca6ea1SDimitry Andric /// of each vector.
680*0fca6ea1SDimitry Andric ///
681*0fca6ea1SDimitry Andric /// It is possible to lower into VILVL when the mask consists of two of the
682*0fca6ea1SDimitry Andric /// following forms interleaved:
683*0fca6ea1SDimitry Andric ///   <0, 1, 2, ...>
684*0fca6ea1SDimitry Andric ///   <n, n+1, n+2, ...>
685*0fca6ea1SDimitry Andric /// where n is the number of elements in the vector.
686*0fca6ea1SDimitry Andric /// For example:
687*0fca6ea1SDimitry Andric ///   <0, 0, 1, 1, 2, 2, ...>
688*0fca6ea1SDimitry Andric ///   <0, n, 1, n+1, 2, n+2, ...>
689*0fca6ea1SDimitry Andric ///
690*0fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever
691*0fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms.
692*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VILVL(const SDLoc &DL, ArrayRef<int> Mask,
693*0fca6ea1SDimitry Andric                                          MVT VT, SDValue V1, SDValue V2,
694*0fca6ea1SDimitry Andric                                          SelectionDAG &DAG) {
695*0fca6ea1SDimitry Andric 
696*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
697*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
698*0fca6ea1SDimitry Andric   SDValue OriV1 = V1, OriV2 = V2;
699*0fca6ea1SDimitry Andric 
700*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin, 2, End, 0, 1))
701*0fca6ea1SDimitry Andric     V1 = OriV1;
702*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 1))
703*0fca6ea1SDimitry Andric     V1 = OriV2;
704*0fca6ea1SDimitry Andric   else
705*0fca6ea1SDimitry Andric     return SDValue();
706*0fca6ea1SDimitry Andric 
707*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 1))
708*0fca6ea1SDimitry Andric     V2 = OriV1;
709*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 1))
710*0fca6ea1SDimitry Andric     V2 = OriV2;
711*0fca6ea1SDimitry Andric   else
712*0fca6ea1SDimitry Andric     return SDValue();
713*0fca6ea1SDimitry Andric 
714*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
715*0fca6ea1SDimitry Andric }
716*0fca6ea1SDimitry Andric 
717*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VPICKEV (if possible).
718*0fca6ea1SDimitry Andric ///
719*0fca6ea1SDimitry Andric /// VPICKEV copies the even elements of each vector into the result vector.
720*0fca6ea1SDimitry Andric ///
721*0fca6ea1SDimitry Andric /// It is possible to lower into VPICKEV when the mask consists of two of the
722*0fca6ea1SDimitry Andric /// following forms concatenated:
723*0fca6ea1SDimitry Andric ///   <0, 2, 4, ...>
724*0fca6ea1SDimitry Andric ///   <n, n+2, n+4, ...>
725*0fca6ea1SDimitry Andric /// where n is the number of elements in the vector.
726*0fca6ea1SDimitry Andric /// For example:
727*0fca6ea1SDimitry Andric ///   <0, 2, 4, ..., 0, 2, 4, ...>
728*0fca6ea1SDimitry Andric ///   <0, 2, 4, ..., n, n+2, n+4, ...>
729*0fca6ea1SDimitry Andric ///
730*0fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever
731*0fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms.
732*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VPICKEV(const SDLoc &DL, ArrayRef<int> Mask,
733*0fca6ea1SDimitry Andric                                            MVT VT, SDValue V1, SDValue V2,
734*0fca6ea1SDimitry Andric                                            SelectionDAG &DAG) {
735*0fca6ea1SDimitry Andric 
736*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
737*0fca6ea1SDimitry Andric   const auto &Mid = Mask.begin() + Mask.size() / 2;
738*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
739*0fca6ea1SDimitry Andric   SDValue OriV1 = V1, OriV2 = V2;
740*0fca6ea1SDimitry Andric 
741*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin, 1, Mid, 0, 2))
742*0fca6ea1SDimitry Andric     V1 = OriV1;
743*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size(), 2))
744*0fca6ea1SDimitry Andric     V1 = OriV2;
745*0fca6ea1SDimitry Andric   else
746*0fca6ea1SDimitry Andric     return SDValue();
747*0fca6ea1SDimitry Andric 
748*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Mid, 1, End, 0, 2))
749*0fca6ea1SDimitry Andric     V2 = OriV1;
750*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size(), 2))
751*0fca6ea1SDimitry Andric     V2 = OriV2;
752*0fca6ea1SDimitry Andric 
753*0fca6ea1SDimitry Andric   else
754*0fca6ea1SDimitry Andric     return SDValue();
755*0fca6ea1SDimitry Andric 
756*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
757*0fca6ea1SDimitry Andric }
758*0fca6ea1SDimitry Andric 
759*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VPICKOD (if possible).
760*0fca6ea1SDimitry Andric ///
761*0fca6ea1SDimitry Andric /// VPICKOD copies the odd elements of each vector into the result vector.
762*0fca6ea1SDimitry Andric ///
763*0fca6ea1SDimitry Andric /// It is possible to lower into VPICKOD when the mask consists of two of the
764*0fca6ea1SDimitry Andric /// following forms concatenated:
765*0fca6ea1SDimitry Andric ///   <1, 3, 5, ...>
766*0fca6ea1SDimitry Andric ///   <n+1, n+3, n+5, ...>
767*0fca6ea1SDimitry Andric /// where n is the number of elements in the vector.
768*0fca6ea1SDimitry Andric /// For example:
769*0fca6ea1SDimitry Andric ///   <1, 3, 5, ..., 1, 3, 5, ...>
770*0fca6ea1SDimitry Andric ///   <1, 3, 5, ..., n+1, n+3, n+5, ...>
771*0fca6ea1SDimitry Andric ///
772*0fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever
773*0fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms.
774*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VPICKOD(const SDLoc &DL, ArrayRef<int> Mask,
775*0fca6ea1SDimitry Andric                                            MVT VT, SDValue V1, SDValue V2,
776*0fca6ea1SDimitry Andric                                            SelectionDAG &DAG) {
777*0fca6ea1SDimitry Andric 
778*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
779*0fca6ea1SDimitry Andric   const auto &Mid = Mask.begin() + Mask.size() / 2;
780*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
781*0fca6ea1SDimitry Andric   SDValue OriV1 = V1, OriV2 = V2;
782*0fca6ea1SDimitry Andric 
783*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin, 1, Mid, 1, 2))
784*0fca6ea1SDimitry Andric     V1 = OriV1;
785*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size() + 1, 2))
786*0fca6ea1SDimitry Andric     V1 = OriV2;
787*0fca6ea1SDimitry Andric   else
788*0fca6ea1SDimitry Andric     return SDValue();
789*0fca6ea1SDimitry Andric 
790*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Mid, 1, End, 1, 2))
791*0fca6ea1SDimitry Andric     V2 = OriV1;
792*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size() + 1, 2))
793*0fca6ea1SDimitry Andric     V2 = OriV2;
794*0fca6ea1SDimitry Andric   else
795*0fca6ea1SDimitry Andric     return SDValue();
796*0fca6ea1SDimitry Andric 
797*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
798*0fca6ea1SDimitry Andric }
799*0fca6ea1SDimitry Andric 
800*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VSHUF.
801*0fca6ea1SDimitry Andric ///
802*0fca6ea1SDimitry Andric /// This mostly consists of converting the shuffle mask into a BUILD_VECTOR and
803*0fca6ea1SDimitry Andric /// adding it as an operand to the resulting VSHUF.
804*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VSHUF(const SDLoc &DL, ArrayRef<int> Mask,
805*0fca6ea1SDimitry Andric                                          MVT VT, SDValue V1, SDValue V2,
806*0fca6ea1SDimitry Andric                                          SelectionDAG &DAG) {
807*0fca6ea1SDimitry Andric 
808*0fca6ea1SDimitry Andric   SmallVector<SDValue, 16> Ops;
809*0fca6ea1SDimitry Andric   for (auto M : Mask)
810*0fca6ea1SDimitry Andric     Ops.push_back(DAG.getConstant(M, DL, MVT::i64));
811*0fca6ea1SDimitry Andric 
812*0fca6ea1SDimitry Andric   EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
813*0fca6ea1SDimitry Andric   SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, Ops);
814*0fca6ea1SDimitry Andric 
815*0fca6ea1SDimitry Andric   // VECTOR_SHUFFLE concatenates the vectors in an vectorwise fashion.
816*0fca6ea1SDimitry Andric   // <0b00, 0b01> + <0b10, 0b11> -> <0b00, 0b01, 0b10, 0b11>
817*0fca6ea1SDimitry Andric   // VSHF concatenates the vectors in a bitwise fashion:
818*0fca6ea1SDimitry Andric   // <0b00, 0b01> + <0b10, 0b11> ->
819*0fca6ea1SDimitry Andric   // 0b0100       + 0b1110       -> 0b01001110
820*0fca6ea1SDimitry Andric   //                                <0b10, 0b11, 0b00, 0b01>
821*0fca6ea1SDimitry Andric   // We must therefore swap the operands to get the correct result.
822*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
823*0fca6ea1SDimitry Andric }
824*0fca6ea1SDimitry Andric 
825*0fca6ea1SDimitry Andric /// Dispatching routine to lower various 128-bit LoongArch vector shuffles.
826*0fca6ea1SDimitry Andric ///
827*0fca6ea1SDimitry Andric /// This routine breaks down the specific type of 128-bit shuffle and
828*0fca6ea1SDimitry Andric /// dispatches to the lowering routines accordingly.
829*0fca6ea1SDimitry Andric static SDValue lower128BitShuffle(const SDLoc &DL, ArrayRef<int> Mask, MVT VT,
830*0fca6ea1SDimitry Andric                                   SDValue V1, SDValue V2, SelectionDAG &DAG) {
831*0fca6ea1SDimitry Andric   assert((VT.SimpleTy == MVT::v16i8 || VT.SimpleTy == MVT::v8i16 ||
832*0fca6ea1SDimitry Andric           VT.SimpleTy == MVT::v4i32 || VT.SimpleTy == MVT::v2i64 ||
833*0fca6ea1SDimitry Andric           VT.SimpleTy == MVT::v4f32 || VT.SimpleTy == MVT::v2f64) &&
834*0fca6ea1SDimitry Andric          "Vector type is unsupported for lsx!");
835*0fca6ea1SDimitry Andric   assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
836*0fca6ea1SDimitry Andric          "Two operands have different types!");
837*0fca6ea1SDimitry Andric   assert(VT.getVectorNumElements() == Mask.size() &&
838*0fca6ea1SDimitry Andric          "Unexpected mask size for shuffle!");
839*0fca6ea1SDimitry Andric   assert(Mask.size() % 2 == 0 && "Expected even mask size.");
840*0fca6ea1SDimitry Andric 
841*0fca6ea1SDimitry Andric   SDValue Result;
842*0fca6ea1SDimitry Andric   // TODO: Add more comparison patterns.
843*0fca6ea1SDimitry Andric   if (V2.isUndef()) {
844*0fca6ea1SDimitry Andric     if ((Result = lowerVECTOR_SHUFFLE_VREPLVEI(DL, Mask, VT, V1, V2, DAG)))
845*0fca6ea1SDimitry Andric       return Result;
846*0fca6ea1SDimitry Andric     if ((Result = lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG)))
847*0fca6ea1SDimitry Andric       return Result;
848*0fca6ea1SDimitry Andric 
849*0fca6ea1SDimitry Andric     // TODO: This comment may be enabled in the future to better match the
850*0fca6ea1SDimitry Andric     // pattern for instruction selection.
851*0fca6ea1SDimitry Andric     /* V2 = V1; */
852*0fca6ea1SDimitry Andric   }
853*0fca6ea1SDimitry Andric 
854*0fca6ea1SDimitry Andric   // It is recommended not to change the pattern comparison order for better
855*0fca6ea1SDimitry Andric   // performance.
856*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG)))
857*0fca6ea1SDimitry Andric     return Result;
858*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG)))
859*0fca6ea1SDimitry Andric     return Result;
860*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_VILVH(DL, Mask, VT, V1, V2, DAG)))
861*0fca6ea1SDimitry Andric     return Result;
862*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_VILVL(DL, Mask, VT, V1, V2, DAG)))
863*0fca6ea1SDimitry Andric     return Result;
864*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_VPICKEV(DL, Mask, VT, V1, V2, DAG)))
865*0fca6ea1SDimitry Andric     return Result;
866*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_VPICKOD(DL, Mask, VT, V1, V2, DAG)))
867*0fca6ea1SDimitry Andric     return Result;
868*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_VSHUF(DL, Mask, VT, V1, V2, DAG)))
869*0fca6ea1SDimitry Andric     return Result;
870*0fca6ea1SDimitry Andric 
871*0fca6ea1SDimitry Andric   return SDValue();
872*0fca6ea1SDimitry Andric }
873*0fca6ea1SDimitry Andric 
874*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVREPLVEI (if possible).
875*0fca6ea1SDimitry Andric ///
876*0fca6ea1SDimitry Andric /// It is a XVREPLVEI when the mask is:
877*0fca6ea1SDimitry Andric ///   <x, x, x, ..., x+n, x+n, x+n, ...>
878*0fca6ea1SDimitry Andric /// where the number of x is equal to n and n is half the length of vector.
879*0fca6ea1SDimitry Andric ///
880*0fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever
881*0fca6ea1SDimitry Andric /// value is necessary in order to fit the above form.
882*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVREPLVEI(const SDLoc &DL,
883*0fca6ea1SDimitry Andric                                              ArrayRef<int> Mask, MVT VT,
884*0fca6ea1SDimitry Andric                                              SDValue V1, SDValue V2,
885*0fca6ea1SDimitry Andric                                              SelectionDAG &DAG) {
886*0fca6ea1SDimitry Andric   int SplatIndex = -1;
887*0fca6ea1SDimitry Andric   for (const auto &M : Mask) {
888*0fca6ea1SDimitry Andric     if (M != -1) {
889*0fca6ea1SDimitry Andric       SplatIndex = M;
890*0fca6ea1SDimitry Andric       break;
891*0fca6ea1SDimitry Andric     }
892*0fca6ea1SDimitry Andric   }
893*0fca6ea1SDimitry Andric 
894*0fca6ea1SDimitry Andric   if (SplatIndex == -1)
895*0fca6ea1SDimitry Andric     return DAG.getUNDEF(VT);
896*0fca6ea1SDimitry Andric 
897*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
898*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
899*0fca6ea1SDimitry Andric   unsigned HalfSize = Mask.size() / 2;
900*0fca6ea1SDimitry Andric 
901*0fca6ea1SDimitry Andric   assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
902*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin, 1, End - HalfSize, SplatIndex, 0) &&
903*0fca6ea1SDimitry Andric       fitsRegularPattern<int>(Begin + HalfSize, 1, End, SplatIndex + HalfSize,
904*0fca6ea1SDimitry Andric                               0)) {
905*0fca6ea1SDimitry Andric     APInt Imm(64, SplatIndex);
906*0fca6ea1SDimitry Andric     return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
907*0fca6ea1SDimitry Andric                        DAG.getConstant(Imm, DL, MVT::i64));
908*0fca6ea1SDimitry Andric   }
909*0fca6ea1SDimitry Andric 
910*0fca6ea1SDimitry Andric   return SDValue();
911*0fca6ea1SDimitry Andric }
912*0fca6ea1SDimitry Andric 
913*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVSHUF4I (if possible).
914*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVSHUF4I(const SDLoc &DL, ArrayRef<int> Mask,
915*0fca6ea1SDimitry Andric                                             MVT VT, SDValue V1, SDValue V2,
916*0fca6ea1SDimitry Andric                                             SelectionDAG &DAG) {
917*0fca6ea1SDimitry Andric   // When the size is less than or equal to 4, lower cost instructions may be
918*0fca6ea1SDimitry Andric   // used.
919*0fca6ea1SDimitry Andric   if (Mask.size() <= 4)
920*0fca6ea1SDimitry Andric     return SDValue();
921*0fca6ea1SDimitry Andric   return lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG);
922*0fca6ea1SDimitry Andric }
923*0fca6ea1SDimitry Andric 
924*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVPACKEV (if possible).
925*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVPACKEV(const SDLoc &DL, ArrayRef<int> Mask,
926*0fca6ea1SDimitry Andric                                             MVT VT, SDValue V1, SDValue V2,
927*0fca6ea1SDimitry Andric                                             SelectionDAG &DAG) {
928*0fca6ea1SDimitry Andric   return lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG);
929*0fca6ea1SDimitry Andric }
930*0fca6ea1SDimitry Andric 
931*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVPACKOD (if possible).
932*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVPACKOD(const SDLoc &DL, ArrayRef<int> Mask,
933*0fca6ea1SDimitry Andric                                             MVT VT, SDValue V1, SDValue V2,
934*0fca6ea1SDimitry Andric                                             SelectionDAG &DAG) {
935*0fca6ea1SDimitry Andric   return lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG);
936*0fca6ea1SDimitry Andric }
937*0fca6ea1SDimitry Andric 
938*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVILVH (if possible).
939*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVILVH(const SDLoc &DL, ArrayRef<int> Mask,
940*0fca6ea1SDimitry Andric                                           MVT VT, SDValue V1, SDValue V2,
941*0fca6ea1SDimitry Andric                                           SelectionDAG &DAG) {
942*0fca6ea1SDimitry Andric 
943*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
944*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
945*0fca6ea1SDimitry Andric   unsigned HalfSize = Mask.size() / 2;
946*0fca6ea1SDimitry Andric   unsigned LeftSize = HalfSize / 2;
947*0fca6ea1SDimitry Andric   SDValue OriV1 = V1, OriV2 = V2;
948*0fca6ea1SDimitry Andric 
949*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, HalfSize - LeftSize,
950*0fca6ea1SDimitry Andric                               1) &&
951*0fca6ea1SDimitry Andric       fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize + LeftSize, 1))
952*0fca6ea1SDimitry Andric     V1 = OriV1;
953*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize,
954*0fca6ea1SDimitry Andric                                    Mask.size() + HalfSize - LeftSize, 1) &&
955*0fca6ea1SDimitry Andric            fitsRegularPattern<int>(Begin + HalfSize, 2, End,
956*0fca6ea1SDimitry Andric                                    Mask.size() + HalfSize + LeftSize, 1))
957*0fca6ea1SDimitry Andric     V1 = OriV2;
958*0fca6ea1SDimitry Andric   else
959*0fca6ea1SDimitry Andric     return SDValue();
960*0fca6ea1SDimitry Andric 
961*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, HalfSize - LeftSize,
962*0fca6ea1SDimitry Andric                               1) &&
963*0fca6ea1SDimitry Andric       fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize + LeftSize,
964*0fca6ea1SDimitry Andric                               1))
965*0fca6ea1SDimitry Andric     V2 = OriV1;
966*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize,
967*0fca6ea1SDimitry Andric                                    Mask.size() + HalfSize - LeftSize, 1) &&
968*0fca6ea1SDimitry Andric            fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
969*0fca6ea1SDimitry Andric                                    Mask.size() + HalfSize + LeftSize, 1))
970*0fca6ea1SDimitry Andric     V2 = OriV2;
971*0fca6ea1SDimitry Andric   else
972*0fca6ea1SDimitry Andric     return SDValue();
973*0fca6ea1SDimitry Andric 
974*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
975*0fca6ea1SDimitry Andric }
976*0fca6ea1SDimitry Andric 
977*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVILVL (if possible).
978*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVILVL(const SDLoc &DL, ArrayRef<int> Mask,
979*0fca6ea1SDimitry Andric                                           MVT VT, SDValue V1, SDValue V2,
980*0fca6ea1SDimitry Andric                                           SelectionDAG &DAG) {
981*0fca6ea1SDimitry Andric 
982*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
983*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
984*0fca6ea1SDimitry Andric   unsigned HalfSize = Mask.size() / 2;
985*0fca6ea1SDimitry Andric   SDValue OriV1 = V1, OriV2 = V2;
986*0fca6ea1SDimitry Andric 
987*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, 0, 1) &&
988*0fca6ea1SDimitry Andric       fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize, 1))
989*0fca6ea1SDimitry Andric     V1 = OriV1;
990*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, Mask.size(), 1) &&
991*0fca6ea1SDimitry Andric            fitsRegularPattern<int>(Begin + HalfSize, 2, End,
992*0fca6ea1SDimitry Andric                                    Mask.size() + HalfSize, 1))
993*0fca6ea1SDimitry Andric     V1 = OriV2;
994*0fca6ea1SDimitry Andric   else
995*0fca6ea1SDimitry Andric     return SDValue();
996*0fca6ea1SDimitry Andric 
997*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, 0, 1) &&
998*0fca6ea1SDimitry Andric       fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize, 1))
999*0fca6ea1SDimitry Andric     V2 = OriV1;
1000*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, Mask.size(),
1001*0fca6ea1SDimitry Andric                                    1) &&
1002*0fca6ea1SDimitry Andric            fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
1003*0fca6ea1SDimitry Andric                                    Mask.size() + HalfSize, 1))
1004*0fca6ea1SDimitry Andric     V2 = OriV2;
1005*0fca6ea1SDimitry Andric   else
1006*0fca6ea1SDimitry Andric     return SDValue();
1007*0fca6ea1SDimitry Andric 
1008*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
1009*0fca6ea1SDimitry Andric }
1010*0fca6ea1SDimitry Andric 
1011*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVPICKEV (if possible).
1012*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVPICKEV(const SDLoc &DL, ArrayRef<int> Mask,
1013*0fca6ea1SDimitry Andric                                             MVT VT, SDValue V1, SDValue V2,
1014*0fca6ea1SDimitry Andric                                             SelectionDAG &DAG) {
1015*0fca6ea1SDimitry Andric 
1016*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
1017*0fca6ea1SDimitry Andric   const auto &LeftMid = Mask.begin() + Mask.size() / 4;
1018*0fca6ea1SDimitry Andric   const auto &Mid = Mask.begin() + Mask.size() / 2;
1019*0fca6ea1SDimitry Andric   const auto &RightMid = Mask.end() - Mask.size() / 4;
1020*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
1021*0fca6ea1SDimitry Andric   unsigned HalfSize = Mask.size() / 2;
1022*0fca6ea1SDimitry Andric   SDValue OriV1 = V1, OriV2 = V2;
1023*0fca6ea1SDimitry Andric 
1024*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin, 1, LeftMid, 0, 2) &&
1025*0fca6ea1SDimitry Andric       fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize, 2))
1026*0fca6ea1SDimitry Andric     V1 = OriV1;
1027*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size(), 2) &&
1028*0fca6ea1SDimitry Andric            fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize, 2))
1029*0fca6ea1SDimitry Andric     V1 = OriV2;
1030*0fca6ea1SDimitry Andric   else
1031*0fca6ea1SDimitry Andric     return SDValue();
1032*0fca6ea1SDimitry Andric 
1033*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(LeftMid, 1, Mid, 0, 2) &&
1034*0fca6ea1SDimitry Andric       fitsRegularPattern<int>(RightMid, 1, End, HalfSize, 2))
1035*0fca6ea1SDimitry Andric     V2 = OriV1;
1036*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size(), 2) &&
1037*0fca6ea1SDimitry Andric            fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize, 2))
1038*0fca6ea1SDimitry Andric     V2 = OriV2;
1039*0fca6ea1SDimitry Andric 
1040*0fca6ea1SDimitry Andric   else
1041*0fca6ea1SDimitry Andric     return SDValue();
1042*0fca6ea1SDimitry Andric 
1043*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
1044*0fca6ea1SDimitry Andric }
1045*0fca6ea1SDimitry Andric 
1046*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVPICKOD (if possible).
1047*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVPICKOD(const SDLoc &DL, ArrayRef<int> Mask,
1048*0fca6ea1SDimitry Andric                                             MVT VT, SDValue V1, SDValue V2,
1049*0fca6ea1SDimitry Andric                                             SelectionDAG &DAG) {
1050*0fca6ea1SDimitry Andric 
1051*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
1052*0fca6ea1SDimitry Andric   const auto &LeftMid = Mask.begin() + Mask.size() / 4;
1053*0fca6ea1SDimitry Andric   const auto &Mid = Mask.begin() + Mask.size() / 2;
1054*0fca6ea1SDimitry Andric   const auto &RightMid = Mask.end() - Mask.size() / 4;
1055*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
1056*0fca6ea1SDimitry Andric   unsigned HalfSize = Mask.size() / 2;
1057*0fca6ea1SDimitry Andric   SDValue OriV1 = V1, OriV2 = V2;
1058*0fca6ea1SDimitry Andric 
1059*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(Begin, 1, LeftMid, 1, 2) &&
1060*0fca6ea1SDimitry Andric       fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize + 1, 2))
1061*0fca6ea1SDimitry Andric     V1 = OriV1;
1062*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size() + 1, 2) &&
1063*0fca6ea1SDimitry Andric            fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize + 1,
1064*0fca6ea1SDimitry Andric                                    2))
1065*0fca6ea1SDimitry Andric     V1 = OriV2;
1066*0fca6ea1SDimitry Andric   else
1067*0fca6ea1SDimitry Andric     return SDValue();
1068*0fca6ea1SDimitry Andric 
1069*0fca6ea1SDimitry Andric   if (fitsRegularPattern<int>(LeftMid, 1, Mid, 1, 2) &&
1070*0fca6ea1SDimitry Andric       fitsRegularPattern<int>(RightMid, 1, End, HalfSize + 1, 2))
1071*0fca6ea1SDimitry Andric     V2 = OriV1;
1072*0fca6ea1SDimitry Andric   else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size() + 1, 2) &&
1073*0fca6ea1SDimitry Andric            fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize + 1,
1074*0fca6ea1SDimitry Andric                                    2))
1075*0fca6ea1SDimitry Andric     V2 = OriV2;
1076*0fca6ea1SDimitry Andric   else
1077*0fca6ea1SDimitry Andric     return SDValue();
1078*0fca6ea1SDimitry Andric 
1079*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
1080*0fca6ea1SDimitry Andric }
1081*0fca6ea1SDimitry Andric 
1082*0fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVSHUF (if possible).
1083*0fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVSHUF(const SDLoc &DL, ArrayRef<int> Mask,
1084*0fca6ea1SDimitry Andric                                           MVT VT, SDValue V1, SDValue V2,
1085*0fca6ea1SDimitry Andric                                           SelectionDAG &DAG) {
1086*0fca6ea1SDimitry Andric 
1087*0fca6ea1SDimitry Andric   int MaskSize = Mask.size();
1088*0fca6ea1SDimitry Andric   int HalfSize = Mask.size() / 2;
1089*0fca6ea1SDimitry Andric   const auto &Begin = Mask.begin();
1090*0fca6ea1SDimitry Andric   const auto &Mid = Mask.begin() + HalfSize;
1091*0fca6ea1SDimitry Andric   const auto &End = Mask.end();
1092*0fca6ea1SDimitry Andric 
1093*0fca6ea1SDimitry Andric   // VECTOR_SHUFFLE concatenates the vectors:
1094*0fca6ea1SDimitry Andric   //  <0, 1, 2, 3, 4, 5, 6, 7> + <8, 9, 10, 11, 12, 13, 14, 15>
1095*0fca6ea1SDimitry Andric   //  shuffling ->
1096*0fca6ea1SDimitry Andric   //  <0, 1, 2, 3, 8, 9, 10, 11> <4, 5, 6, 7, 12, 13, 14, 15>
1097*0fca6ea1SDimitry Andric   //
1098*0fca6ea1SDimitry Andric   // XVSHUF concatenates the vectors:
1099*0fca6ea1SDimitry Andric   //  <a0, a1, a2, a3, b0, b1, b2, b3> + <a4, a5, a6, a7, b4, b5, b6, b7>
1100*0fca6ea1SDimitry Andric   //  shuffling ->
1101*0fca6ea1SDimitry Andric   //  <a0, a1, a2, a3, a4, a5, a6, a7> + <b0, b1, b2, b3, b4, b5, b6, b7>
1102*0fca6ea1SDimitry Andric   SmallVector<SDValue, 8> MaskAlloc;
1103*0fca6ea1SDimitry Andric   for (auto it = Begin; it < Mid; it++) {
1104*0fca6ea1SDimitry Andric     if (*it < 0) // UNDEF
1105*0fca6ea1SDimitry Andric       MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
1106*0fca6ea1SDimitry Andric     else if ((*it >= 0 && *it < HalfSize) ||
1107*0fca6ea1SDimitry Andric              (*it >= MaskSize && *it <= MaskSize + HalfSize)) {
1108*0fca6ea1SDimitry Andric       int M = *it < HalfSize ? *it : *it - HalfSize;
1109*0fca6ea1SDimitry Andric       MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
1110*0fca6ea1SDimitry Andric     } else
1111*0fca6ea1SDimitry Andric       return SDValue();
1112*0fca6ea1SDimitry Andric   }
1113*0fca6ea1SDimitry Andric   assert((int)MaskAlloc.size() == HalfSize && "xvshuf convert failed!");
1114*0fca6ea1SDimitry Andric 
1115*0fca6ea1SDimitry Andric   for (auto it = Mid; it < End; it++) {
1116*0fca6ea1SDimitry Andric     if (*it < 0) // UNDEF
1117*0fca6ea1SDimitry Andric       MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
1118*0fca6ea1SDimitry Andric     else if ((*it >= HalfSize && *it < MaskSize) ||
1119*0fca6ea1SDimitry Andric              (*it >= MaskSize + HalfSize && *it < MaskSize * 2)) {
1120*0fca6ea1SDimitry Andric       int M = *it < MaskSize ? *it - HalfSize : *it - MaskSize;
1121*0fca6ea1SDimitry Andric       MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
1122*0fca6ea1SDimitry Andric     } else
1123*0fca6ea1SDimitry Andric       return SDValue();
1124*0fca6ea1SDimitry Andric   }
1125*0fca6ea1SDimitry Andric   assert((int)MaskAlloc.size() == MaskSize && "xvshuf convert failed!");
1126*0fca6ea1SDimitry Andric 
1127*0fca6ea1SDimitry Andric   EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
1128*0fca6ea1SDimitry Andric   SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, MaskAlloc);
1129*0fca6ea1SDimitry Andric   return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
1130*0fca6ea1SDimitry Andric }
1131*0fca6ea1SDimitry Andric 
1132*0fca6ea1SDimitry Andric /// Shuffle vectors by lane to generate more optimized instructions.
1133*0fca6ea1SDimitry Andric /// 256-bit shuffles are always considered as 2-lane 128-bit shuffles.
1134*0fca6ea1SDimitry Andric ///
1135*0fca6ea1SDimitry Andric /// Therefore, except for the following four cases, other cases are regarded
1136*0fca6ea1SDimitry Andric /// as cross-lane shuffles, where optimization is relatively limited.
1137*0fca6ea1SDimitry Andric ///
1138*0fca6ea1SDimitry Andric /// - Shuffle high, low lanes of two inputs vector
1139*0fca6ea1SDimitry Andric ///   <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 3, 6>
1140*0fca6ea1SDimitry Andric /// - Shuffle low, high lanes of two inputs vector
1141*0fca6ea1SDimitry Andric ///   <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 0, 5>
1142*0fca6ea1SDimitry Andric /// - Shuffle low, low lanes of two inputs vector
1143*0fca6ea1SDimitry Andric ///   <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 3, 6>
1144*0fca6ea1SDimitry Andric /// - Shuffle high, high lanes of two inputs vector
1145*0fca6ea1SDimitry Andric ///   <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 0, 5>
1146*0fca6ea1SDimitry Andric ///
1147*0fca6ea1SDimitry Andric /// The first case is the closest to LoongArch instructions and the other
1148*0fca6ea1SDimitry Andric /// cases need to be converted to it for processing.
1149*0fca6ea1SDimitry Andric ///
1150*0fca6ea1SDimitry Andric /// This function may modify V1, V2 and Mask
1151*0fca6ea1SDimitry Andric static void canonicalizeShuffleVectorByLane(const SDLoc &DL,
1152*0fca6ea1SDimitry Andric                                             MutableArrayRef<int> Mask, MVT VT,
1153*0fca6ea1SDimitry Andric                                             SDValue &V1, SDValue &V2,
1154*0fca6ea1SDimitry Andric                                             SelectionDAG &DAG) {
1155*0fca6ea1SDimitry Andric 
1156*0fca6ea1SDimitry Andric   enum HalfMaskType { HighLaneTy, LowLaneTy, None };
1157*0fca6ea1SDimitry Andric 
1158*0fca6ea1SDimitry Andric   int MaskSize = Mask.size();
1159*0fca6ea1SDimitry Andric   int HalfSize = Mask.size() / 2;
1160*0fca6ea1SDimitry Andric 
1161*0fca6ea1SDimitry Andric   HalfMaskType preMask = None, postMask = None;
1162*0fca6ea1SDimitry Andric 
1163*0fca6ea1SDimitry Andric   if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
1164*0fca6ea1SDimitry Andric         return M < 0 || (M >= 0 && M < HalfSize) ||
1165*0fca6ea1SDimitry Andric                (M >= MaskSize && M < MaskSize + HalfSize);
1166*0fca6ea1SDimitry Andric       }))
1167*0fca6ea1SDimitry Andric     preMask = HighLaneTy;
1168*0fca6ea1SDimitry Andric   else if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
1169*0fca6ea1SDimitry Andric              return M < 0 || (M >= HalfSize && M < MaskSize) ||
1170*0fca6ea1SDimitry Andric                     (M >= MaskSize + HalfSize && M < MaskSize * 2);
1171*0fca6ea1SDimitry Andric            }))
1172*0fca6ea1SDimitry Andric     preMask = LowLaneTy;
1173*0fca6ea1SDimitry Andric 
1174*0fca6ea1SDimitry Andric   if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
1175*0fca6ea1SDimitry Andric         return M < 0 || (M >= 0 && M < HalfSize) ||
1176*0fca6ea1SDimitry Andric                (M >= MaskSize && M < MaskSize + HalfSize);
1177*0fca6ea1SDimitry Andric       }))
1178*0fca6ea1SDimitry Andric     postMask = HighLaneTy;
1179*0fca6ea1SDimitry Andric   else if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
1180*0fca6ea1SDimitry Andric              return M < 0 || (M >= HalfSize && M < MaskSize) ||
1181*0fca6ea1SDimitry Andric                     (M >= MaskSize + HalfSize && M < MaskSize * 2);
1182*0fca6ea1SDimitry Andric            }))
1183*0fca6ea1SDimitry Andric     postMask = LowLaneTy;
1184*0fca6ea1SDimitry Andric 
1185*0fca6ea1SDimitry Andric   // The pre-half of mask is high lane type, and the post-half of mask
1186*0fca6ea1SDimitry Andric   // is low lane type, which is closest to the LoongArch instructions.
1187*0fca6ea1SDimitry Andric   //
1188*0fca6ea1SDimitry Andric   // Note: In the LoongArch architecture, the high lane of mask corresponds
1189*0fca6ea1SDimitry Andric   // to the lower 128-bit of vector register, and the low lane of mask
1190*0fca6ea1SDimitry Andric   // corresponds the higher 128-bit of vector register.
1191*0fca6ea1SDimitry Andric   if (preMask == HighLaneTy && postMask == LowLaneTy) {
1192*0fca6ea1SDimitry Andric     return;
1193*0fca6ea1SDimitry Andric   }
1194*0fca6ea1SDimitry Andric   if (preMask == LowLaneTy && postMask == HighLaneTy) {
1195*0fca6ea1SDimitry Andric     V1 = DAG.getBitcast(MVT::v4i64, V1);
1196*0fca6ea1SDimitry Andric     V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
1197*0fca6ea1SDimitry Andric                      DAG.getConstant(0b01001110, DL, MVT::i64));
1198*0fca6ea1SDimitry Andric     V1 = DAG.getBitcast(VT, V1);
1199*0fca6ea1SDimitry Andric 
1200*0fca6ea1SDimitry Andric     if (!V2.isUndef()) {
1201*0fca6ea1SDimitry Andric       V2 = DAG.getBitcast(MVT::v4i64, V2);
1202*0fca6ea1SDimitry Andric       V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
1203*0fca6ea1SDimitry Andric                        DAG.getConstant(0b01001110, DL, MVT::i64));
1204*0fca6ea1SDimitry Andric       V2 = DAG.getBitcast(VT, V2);
1205*0fca6ea1SDimitry Andric     }
1206*0fca6ea1SDimitry Andric 
1207*0fca6ea1SDimitry Andric     for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
1208*0fca6ea1SDimitry Andric       *it = *it < 0 ? *it : *it - HalfSize;
1209*0fca6ea1SDimitry Andric     }
1210*0fca6ea1SDimitry Andric     for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
1211*0fca6ea1SDimitry Andric       *it = *it < 0 ? *it : *it + HalfSize;
1212*0fca6ea1SDimitry Andric     }
1213*0fca6ea1SDimitry Andric   } else if (preMask == LowLaneTy && postMask == LowLaneTy) {
1214*0fca6ea1SDimitry Andric     V1 = DAG.getBitcast(MVT::v4i64, V1);
1215*0fca6ea1SDimitry Andric     V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
1216*0fca6ea1SDimitry Andric                      DAG.getConstant(0b11101110, DL, MVT::i64));
1217*0fca6ea1SDimitry Andric     V1 = DAG.getBitcast(VT, V1);
1218*0fca6ea1SDimitry Andric 
1219*0fca6ea1SDimitry Andric     if (!V2.isUndef()) {
1220*0fca6ea1SDimitry Andric       V2 = DAG.getBitcast(MVT::v4i64, V2);
1221*0fca6ea1SDimitry Andric       V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
1222*0fca6ea1SDimitry Andric                        DAG.getConstant(0b11101110, DL, MVT::i64));
1223*0fca6ea1SDimitry Andric       V2 = DAG.getBitcast(VT, V2);
1224*0fca6ea1SDimitry Andric     }
1225*0fca6ea1SDimitry Andric 
1226*0fca6ea1SDimitry Andric     for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
1227*0fca6ea1SDimitry Andric       *it = *it < 0 ? *it : *it - HalfSize;
1228*0fca6ea1SDimitry Andric     }
1229*0fca6ea1SDimitry Andric   } else if (preMask == HighLaneTy && postMask == HighLaneTy) {
1230*0fca6ea1SDimitry Andric     V1 = DAG.getBitcast(MVT::v4i64, V1);
1231*0fca6ea1SDimitry Andric     V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
1232*0fca6ea1SDimitry Andric                      DAG.getConstant(0b01000100, DL, MVT::i64));
1233*0fca6ea1SDimitry Andric     V1 = DAG.getBitcast(VT, V1);
1234*0fca6ea1SDimitry Andric 
1235*0fca6ea1SDimitry Andric     if (!V2.isUndef()) {
1236*0fca6ea1SDimitry Andric       V2 = DAG.getBitcast(MVT::v4i64, V2);
1237*0fca6ea1SDimitry Andric       V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
1238*0fca6ea1SDimitry Andric                        DAG.getConstant(0b01000100, DL, MVT::i64));
1239*0fca6ea1SDimitry Andric       V2 = DAG.getBitcast(VT, V2);
1240*0fca6ea1SDimitry Andric     }
1241*0fca6ea1SDimitry Andric 
1242*0fca6ea1SDimitry Andric     for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
1243*0fca6ea1SDimitry Andric       *it = *it < 0 ? *it : *it + HalfSize;
1244*0fca6ea1SDimitry Andric     }
1245*0fca6ea1SDimitry Andric   } else { // cross-lane
1246*0fca6ea1SDimitry Andric     return;
1247*0fca6ea1SDimitry Andric   }
1248*0fca6ea1SDimitry Andric }
1249*0fca6ea1SDimitry Andric 
1250*0fca6ea1SDimitry Andric /// Dispatching routine to lower various 256-bit LoongArch vector shuffles.
1251*0fca6ea1SDimitry Andric ///
1252*0fca6ea1SDimitry Andric /// This routine breaks down the specific type of 256-bit shuffle and
1253*0fca6ea1SDimitry Andric /// dispatches to the lowering routines accordingly.
1254*0fca6ea1SDimitry Andric static SDValue lower256BitShuffle(const SDLoc &DL, ArrayRef<int> Mask, MVT VT,
1255*0fca6ea1SDimitry Andric                                   SDValue V1, SDValue V2, SelectionDAG &DAG) {
1256*0fca6ea1SDimitry Andric   assert((VT.SimpleTy == MVT::v32i8 || VT.SimpleTy == MVT::v16i16 ||
1257*0fca6ea1SDimitry Andric           VT.SimpleTy == MVT::v8i32 || VT.SimpleTy == MVT::v4i64 ||
1258*0fca6ea1SDimitry Andric           VT.SimpleTy == MVT::v8f32 || VT.SimpleTy == MVT::v4f64) &&
1259*0fca6ea1SDimitry Andric          "Vector type is unsupported for lasx!");
1260*0fca6ea1SDimitry Andric   assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
1261*0fca6ea1SDimitry Andric          "Two operands have different types!");
1262*0fca6ea1SDimitry Andric   assert(VT.getVectorNumElements() == Mask.size() &&
1263*0fca6ea1SDimitry Andric          "Unexpected mask size for shuffle!");
1264*0fca6ea1SDimitry Andric   assert(Mask.size() % 2 == 0 && "Expected even mask size.");
1265*0fca6ea1SDimitry Andric   assert(Mask.size() >= 4 && "Mask size is less than 4.");
1266*0fca6ea1SDimitry Andric 
1267*0fca6ea1SDimitry Andric   // canonicalize non cross-lane shuffle vector
1268*0fca6ea1SDimitry Andric   SmallVector<int> NewMask(Mask);
1269*0fca6ea1SDimitry Andric   canonicalizeShuffleVectorByLane(DL, NewMask, VT, V1, V2, DAG);
1270*0fca6ea1SDimitry Andric 
1271*0fca6ea1SDimitry Andric   SDValue Result;
1272*0fca6ea1SDimitry Andric   // TODO: Add more comparison patterns.
1273*0fca6ea1SDimitry Andric   if (V2.isUndef()) {
1274*0fca6ea1SDimitry Andric     if ((Result = lowerVECTOR_SHUFFLE_XVREPLVEI(DL, NewMask, VT, V1, V2, DAG)))
1275*0fca6ea1SDimitry Andric       return Result;
1276*0fca6ea1SDimitry Andric     if ((Result = lowerVECTOR_SHUFFLE_XVSHUF4I(DL, NewMask, VT, V1, V2, DAG)))
1277*0fca6ea1SDimitry Andric       return Result;
1278*0fca6ea1SDimitry Andric 
1279*0fca6ea1SDimitry Andric     // TODO: This comment may be enabled in the future to better match the
1280*0fca6ea1SDimitry Andric     // pattern for instruction selection.
1281*0fca6ea1SDimitry Andric     /* V2 = V1; */
1282*0fca6ea1SDimitry Andric   }
1283*0fca6ea1SDimitry Andric 
1284*0fca6ea1SDimitry Andric   // It is recommended not to change the pattern comparison order for better
1285*0fca6ea1SDimitry Andric   // performance.
1286*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_XVPACKEV(DL, NewMask, VT, V1, V2, DAG)))
1287*0fca6ea1SDimitry Andric     return Result;
1288*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_XVPACKOD(DL, NewMask, VT, V1, V2, DAG)))
1289*0fca6ea1SDimitry Andric     return Result;
1290*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_XVILVH(DL, NewMask, VT, V1, V2, DAG)))
1291*0fca6ea1SDimitry Andric     return Result;
1292*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_XVILVL(DL, NewMask, VT, V1, V2, DAG)))
1293*0fca6ea1SDimitry Andric     return Result;
1294*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_XVPICKEV(DL, NewMask, VT, V1, V2, DAG)))
1295*0fca6ea1SDimitry Andric     return Result;
1296*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_XVPICKOD(DL, NewMask, VT, V1, V2, DAG)))
1297*0fca6ea1SDimitry Andric     return Result;
1298*0fca6ea1SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_XVSHUF(DL, NewMask, VT, V1, V2, DAG)))
1299*0fca6ea1SDimitry Andric     return Result;
1300*0fca6ea1SDimitry Andric 
1301*0fca6ea1SDimitry Andric   return SDValue();
1302*0fca6ea1SDimitry Andric }
1303*0fca6ea1SDimitry Andric 
13045f757f3fSDimitry Andric SDValue LoongArchTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
13055f757f3fSDimitry Andric                                                      SelectionDAG &DAG) const {
1306*0fca6ea1SDimitry Andric   ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(Op);
1307*0fca6ea1SDimitry Andric   ArrayRef<int> OrigMask = SVOp->getMask();
1308*0fca6ea1SDimitry Andric   SDValue V1 = Op.getOperand(0);
1309*0fca6ea1SDimitry Andric   SDValue V2 = Op.getOperand(1);
1310*0fca6ea1SDimitry Andric   MVT VT = Op.getSimpleValueType();
1311*0fca6ea1SDimitry Andric   int NumElements = VT.getVectorNumElements();
1312*0fca6ea1SDimitry Andric   SDLoc DL(Op);
1313*0fca6ea1SDimitry Andric 
1314*0fca6ea1SDimitry Andric   bool V1IsUndef = V1.isUndef();
1315*0fca6ea1SDimitry Andric   bool V2IsUndef = V2.isUndef();
1316*0fca6ea1SDimitry Andric   if (V1IsUndef && V2IsUndef)
1317*0fca6ea1SDimitry Andric     return DAG.getUNDEF(VT);
1318*0fca6ea1SDimitry Andric 
1319*0fca6ea1SDimitry Andric   // When we create a shuffle node we put the UNDEF node to second operand,
1320*0fca6ea1SDimitry Andric   // but in some cases the first operand may be transformed to UNDEF.
1321*0fca6ea1SDimitry Andric   // In this case we should just commute the node.
1322*0fca6ea1SDimitry Andric   if (V1IsUndef)
1323*0fca6ea1SDimitry Andric     return DAG.getCommutedVectorShuffle(*SVOp);
1324*0fca6ea1SDimitry Andric 
1325*0fca6ea1SDimitry Andric   // Check for non-undef masks pointing at an undef vector and make the masks
1326*0fca6ea1SDimitry Andric   // undef as well. This makes it easier to match the shuffle based solely on
1327*0fca6ea1SDimitry Andric   // the mask.
1328*0fca6ea1SDimitry Andric   if (V2IsUndef &&
1329*0fca6ea1SDimitry Andric       any_of(OrigMask, [NumElements](int M) { return M >= NumElements; })) {
1330*0fca6ea1SDimitry Andric     SmallVector<int, 8> NewMask(OrigMask);
1331*0fca6ea1SDimitry Andric     for (int &M : NewMask)
1332*0fca6ea1SDimitry Andric       if (M >= NumElements)
1333*0fca6ea1SDimitry Andric         M = -1;
1334*0fca6ea1SDimitry Andric     return DAG.getVectorShuffle(VT, DL, V1, V2, NewMask);
1335*0fca6ea1SDimitry Andric   }
1336*0fca6ea1SDimitry Andric 
1337*0fca6ea1SDimitry Andric   // Check for illegal shuffle mask element index values.
1338*0fca6ea1SDimitry Andric   int MaskUpperLimit = OrigMask.size() * (V2IsUndef ? 1 : 2);
1339*0fca6ea1SDimitry Andric   (void)MaskUpperLimit;
1340*0fca6ea1SDimitry Andric   assert(llvm::all_of(OrigMask,
1341*0fca6ea1SDimitry Andric                       [&](int M) { return -1 <= M && M < MaskUpperLimit; }) &&
1342*0fca6ea1SDimitry Andric          "Out of bounds shuffle index");
1343*0fca6ea1SDimitry Andric 
1344*0fca6ea1SDimitry Andric   // For each vector width, delegate to a specialized lowering routine.
1345*0fca6ea1SDimitry Andric   if (VT.is128BitVector())
1346*0fca6ea1SDimitry Andric     return lower128BitShuffle(DL, OrigMask, VT, V1, V2, DAG);
1347*0fca6ea1SDimitry Andric 
1348*0fca6ea1SDimitry Andric   if (VT.is256BitVector())
1349*0fca6ea1SDimitry Andric     return lower256BitShuffle(DL, OrigMask, VT, V1, V2, DAG);
1350*0fca6ea1SDimitry Andric 
13515f757f3fSDimitry Andric   return SDValue();
13525f757f3fSDimitry Andric }
13535f757f3fSDimitry Andric 
13545f757f3fSDimitry Andric static bool isConstantOrUndef(const SDValue Op) {
13555f757f3fSDimitry Andric   if (Op->isUndef())
13565f757f3fSDimitry Andric     return true;
13575f757f3fSDimitry Andric   if (isa<ConstantSDNode>(Op))
13585f757f3fSDimitry Andric     return true;
13595f757f3fSDimitry Andric   if (isa<ConstantFPSDNode>(Op))
13605f757f3fSDimitry Andric     return true;
13615f757f3fSDimitry Andric   return false;
13625f757f3fSDimitry Andric }
13635f757f3fSDimitry Andric 
13645f757f3fSDimitry Andric static bool isConstantOrUndefBUILD_VECTOR(const BuildVectorSDNode *Op) {
13655f757f3fSDimitry Andric   for (unsigned i = 0; i < Op->getNumOperands(); ++i)
13665f757f3fSDimitry Andric     if (isConstantOrUndef(Op->getOperand(i)))
13675f757f3fSDimitry Andric       return true;
13685f757f3fSDimitry Andric   return false;
13695f757f3fSDimitry Andric }
13705f757f3fSDimitry Andric 
13715f757f3fSDimitry Andric SDValue LoongArchTargetLowering::lowerBUILD_VECTOR(SDValue Op,
13725f757f3fSDimitry Andric                                                    SelectionDAG &DAG) const {
13735f757f3fSDimitry Andric   BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op);
13745f757f3fSDimitry Andric   EVT ResTy = Op->getValueType(0);
13755f757f3fSDimitry Andric   SDLoc DL(Op);
13765f757f3fSDimitry Andric   APInt SplatValue, SplatUndef;
13775f757f3fSDimitry Andric   unsigned SplatBitSize;
13785f757f3fSDimitry Andric   bool HasAnyUndefs;
13795f757f3fSDimitry Andric   bool Is128Vec = ResTy.is128BitVector();
13805f757f3fSDimitry Andric   bool Is256Vec = ResTy.is256BitVector();
13815f757f3fSDimitry Andric 
13825f757f3fSDimitry Andric   if ((!Subtarget.hasExtLSX() || !Is128Vec) &&
13835f757f3fSDimitry Andric       (!Subtarget.hasExtLASX() || !Is256Vec))
13845f757f3fSDimitry Andric     return SDValue();
13855f757f3fSDimitry Andric 
13865f757f3fSDimitry Andric   if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
13875f757f3fSDimitry Andric                             /*MinSplatBits=*/8) &&
13885f757f3fSDimitry Andric       SplatBitSize <= 64) {
13895f757f3fSDimitry Andric     // We can only cope with 8, 16, 32, or 64-bit elements.
13905f757f3fSDimitry Andric     if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 &&
13915f757f3fSDimitry Andric         SplatBitSize != 64)
13925f757f3fSDimitry Andric       return SDValue();
13935f757f3fSDimitry Andric 
13945f757f3fSDimitry Andric     EVT ViaVecTy;
13955f757f3fSDimitry Andric 
13965f757f3fSDimitry Andric     switch (SplatBitSize) {
13975f757f3fSDimitry Andric     default:
13985f757f3fSDimitry Andric       return SDValue();
13995f757f3fSDimitry Andric     case 8:
14005f757f3fSDimitry Andric       ViaVecTy = Is128Vec ? MVT::v16i8 : MVT::v32i8;
14015f757f3fSDimitry Andric       break;
14025f757f3fSDimitry Andric     case 16:
14035f757f3fSDimitry Andric       ViaVecTy = Is128Vec ? MVT::v8i16 : MVT::v16i16;
14045f757f3fSDimitry Andric       break;
14055f757f3fSDimitry Andric     case 32:
14065f757f3fSDimitry Andric       ViaVecTy = Is128Vec ? MVT::v4i32 : MVT::v8i32;
14075f757f3fSDimitry Andric       break;
14085f757f3fSDimitry Andric     case 64:
14095f757f3fSDimitry Andric       ViaVecTy = Is128Vec ? MVT::v2i64 : MVT::v4i64;
14105f757f3fSDimitry Andric       break;
14115f757f3fSDimitry Andric     }
14125f757f3fSDimitry Andric 
14135f757f3fSDimitry Andric     // SelectionDAG::getConstant will promote SplatValue appropriately.
14145f757f3fSDimitry Andric     SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy);
14155f757f3fSDimitry Andric 
14165f757f3fSDimitry Andric     // Bitcast to the type we originally wanted.
14175f757f3fSDimitry Andric     if (ViaVecTy != ResTy)
14185f757f3fSDimitry Andric       Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result);
14195f757f3fSDimitry Andric 
14205f757f3fSDimitry Andric     return Result;
14215f757f3fSDimitry Andric   }
14225f757f3fSDimitry Andric 
14235f757f3fSDimitry Andric   if (DAG.isSplatValue(Op, /*AllowUndefs=*/false))
14245f757f3fSDimitry Andric     return Op;
14255f757f3fSDimitry Andric 
14265f757f3fSDimitry Andric   if (!isConstantOrUndefBUILD_VECTOR(Node)) {
14275f757f3fSDimitry Andric     // Use INSERT_VECTOR_ELT operations rather than expand to stores.
14285f757f3fSDimitry Andric     // The resulting code is the same length as the expansion, but it doesn't
14295f757f3fSDimitry Andric     // use memory operations.
14305f757f3fSDimitry Andric     EVT ResTy = Node->getValueType(0);
14315f757f3fSDimitry Andric 
14325f757f3fSDimitry Andric     assert(ResTy.isVector());
14335f757f3fSDimitry Andric 
14345f757f3fSDimitry Andric     unsigned NumElts = ResTy.getVectorNumElements();
14355f757f3fSDimitry Andric     SDValue Vector = DAG.getUNDEF(ResTy);
14365f757f3fSDimitry Andric     for (unsigned i = 0; i < NumElts; ++i) {
14375f757f3fSDimitry Andric       Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector,
14385f757f3fSDimitry Andric                            Node->getOperand(i),
14395f757f3fSDimitry Andric                            DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
14405f757f3fSDimitry Andric     }
14415f757f3fSDimitry Andric     return Vector;
14425f757f3fSDimitry Andric   }
14435f757f3fSDimitry Andric 
14445f757f3fSDimitry Andric   return SDValue();
14455f757f3fSDimitry Andric }
14465f757f3fSDimitry Andric 
14475f757f3fSDimitry Andric SDValue
1448647cbc5dSDimitry Andric LoongArchTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,
1449647cbc5dSDimitry Andric                                                  SelectionDAG &DAG) const {
1450647cbc5dSDimitry Andric   EVT VecTy = Op->getOperand(0)->getValueType(0);
1451647cbc5dSDimitry Andric   SDValue Idx = Op->getOperand(1);
1452647cbc5dSDimitry Andric   EVT EltTy = VecTy.getVectorElementType();
1453647cbc5dSDimitry Andric   unsigned NumElts = VecTy.getVectorNumElements();
1454647cbc5dSDimitry Andric 
1455647cbc5dSDimitry Andric   if (isa<ConstantSDNode>(Idx) &&
1456647cbc5dSDimitry Andric       (EltTy == MVT::i32 || EltTy == MVT::i64 || EltTy == MVT::f32 ||
14571db9f3b2SDimitry Andric        EltTy == MVT::f64 || Idx->getAsZExtVal() < NumElts / 2))
1458647cbc5dSDimitry Andric     return Op;
1459647cbc5dSDimitry Andric 
1460647cbc5dSDimitry Andric   return SDValue();
1461647cbc5dSDimitry Andric }
1462647cbc5dSDimitry Andric 
1463647cbc5dSDimitry Andric SDValue
14645f757f3fSDimitry Andric LoongArchTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
14655f757f3fSDimitry Andric                                                 SelectionDAG &DAG) const {
14665f757f3fSDimitry Andric   if (isa<ConstantSDNode>(Op->getOperand(2)))
14675f757f3fSDimitry Andric     return Op;
14685f757f3fSDimitry Andric   return SDValue();
14695f757f3fSDimitry Andric }
14705f757f3fSDimitry Andric 
14715f757f3fSDimitry Andric SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op,
14725f757f3fSDimitry Andric                                                    SelectionDAG &DAG) const {
14735f757f3fSDimitry Andric   SDLoc DL(Op);
14745f757f3fSDimitry Andric   SyncScope::ID FenceSSID =
14755f757f3fSDimitry Andric       static_cast<SyncScope::ID>(Op.getConstantOperandVal(2));
14765f757f3fSDimitry Andric 
14775f757f3fSDimitry Andric   // singlethread fences only synchronize with signal handlers on the same
14785f757f3fSDimitry Andric   // thread and thus only need to preserve instruction order, not actually
14795f757f3fSDimitry Andric   // enforce memory ordering.
14805f757f3fSDimitry Andric   if (FenceSSID == SyncScope::SingleThread)
14815f757f3fSDimitry Andric     // MEMBARRIER is a compiler barrier; it codegens to a no-op.
14825f757f3fSDimitry Andric     return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
14835f757f3fSDimitry Andric 
14845f757f3fSDimitry Andric   return Op;
14855f757f3fSDimitry Andric }
14865f757f3fSDimitry Andric 
1487bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
1488bdd1243dSDimitry Andric                                                      SelectionDAG &DAG) const {
1489bdd1243dSDimitry Andric 
1490bdd1243dSDimitry Andric   if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
1491bdd1243dSDimitry Andric     DAG.getContext()->emitError(
1492bdd1243dSDimitry Andric         "On LA64, only 64-bit registers can be written.");
1493bdd1243dSDimitry Andric     return Op.getOperand(0);
1494bdd1243dSDimitry Andric   }
1495bdd1243dSDimitry Andric 
1496bdd1243dSDimitry Andric   if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
1497bdd1243dSDimitry Andric     DAG.getContext()->emitError(
1498bdd1243dSDimitry Andric         "On LA32, only 32-bit registers can be written.");
1499bdd1243dSDimitry Andric     return Op.getOperand(0);
1500bdd1243dSDimitry Andric   }
1501bdd1243dSDimitry Andric 
1502bdd1243dSDimitry Andric   return Op;
1503bdd1243dSDimitry Andric }
1504bdd1243dSDimitry Andric 
1505bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
1506bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
1507bdd1243dSDimitry Andric   if (!isa<ConstantSDNode>(Op.getOperand(0))) {
1508bdd1243dSDimitry Andric     DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
1509bdd1243dSDimitry Andric                                 "be a constant integer");
1510bdd1243dSDimitry Andric     return SDValue();
1511bdd1243dSDimitry Andric   }
1512bdd1243dSDimitry Andric 
1513bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
1514bdd1243dSDimitry Andric   MF.getFrameInfo().setFrameAddressIsTaken(true);
1515bdd1243dSDimitry Andric   Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
1516bdd1243dSDimitry Andric   EVT VT = Op.getValueType();
1517bdd1243dSDimitry Andric   SDLoc DL(Op);
1518bdd1243dSDimitry Andric   SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
1519647cbc5dSDimitry Andric   unsigned Depth = Op.getConstantOperandVal(0);
1520bdd1243dSDimitry Andric   int GRLenInBytes = Subtarget.getGRLen() / 8;
1521bdd1243dSDimitry Andric 
1522bdd1243dSDimitry Andric   while (Depth--) {
1523bdd1243dSDimitry Andric     int Offset = -(GRLenInBytes * 2);
1524bdd1243dSDimitry Andric     SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
1525bdd1243dSDimitry Andric                               DAG.getIntPtrConstant(Offset, DL));
1526bdd1243dSDimitry Andric     FrameAddr =
1527bdd1243dSDimitry Andric         DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
1528bdd1243dSDimitry Andric   }
1529bdd1243dSDimitry Andric   return FrameAddr;
1530bdd1243dSDimitry Andric }
1531bdd1243dSDimitry Andric 
1532bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
1533bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
1534bdd1243dSDimitry Andric   if (verifyReturnAddressArgumentIsConstant(Op, DAG))
1535bdd1243dSDimitry Andric     return SDValue();
1536bdd1243dSDimitry Andric 
1537bdd1243dSDimitry Andric   // Currently only support lowering return address for current frame.
1538647cbc5dSDimitry Andric   if (Op.getConstantOperandVal(0) != 0) {
1539bdd1243dSDimitry Andric     DAG.getContext()->emitError(
1540bdd1243dSDimitry Andric         "return address can only be determined for the current frame");
1541bdd1243dSDimitry Andric     return SDValue();
1542bdd1243dSDimitry Andric   }
1543bdd1243dSDimitry Andric 
1544bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
1545bdd1243dSDimitry Andric   MF.getFrameInfo().setReturnAddressIsTaken(true);
1546bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
1547bdd1243dSDimitry Andric 
1548bdd1243dSDimitry Andric   // Return the value of the return address register, marking it an implicit
1549bdd1243dSDimitry Andric   // live-in.
1550bdd1243dSDimitry Andric   Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
1551bdd1243dSDimitry Andric                               getRegClassFor(GRLenVT));
1552bdd1243dSDimitry Andric   return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
1553bdd1243dSDimitry Andric }
1554bdd1243dSDimitry Andric 
1555bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
1556bdd1243dSDimitry Andric                                                    SelectionDAG &DAG) const {
1557bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
1558bdd1243dSDimitry Andric   auto Size = Subtarget.getGRLen() / 8;
1559bdd1243dSDimitry Andric   auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
1560bdd1243dSDimitry Andric   return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
1561bdd1243dSDimitry Andric }
1562bdd1243dSDimitry Andric 
1563bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
1564bdd1243dSDimitry Andric                                               SelectionDAG &DAG) const {
1565bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
1566bdd1243dSDimitry Andric   auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
1567bdd1243dSDimitry Andric 
1568bdd1243dSDimitry Andric   SDLoc DL(Op);
1569bdd1243dSDimitry Andric   SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
1570bdd1243dSDimitry Andric                                  getPointerTy(MF.getDataLayout()));
1571bdd1243dSDimitry Andric 
1572bdd1243dSDimitry Andric   // vastart just stores the address of the VarArgsFrameIndex slot into the
1573bdd1243dSDimitry Andric   // memory location argument.
1574bdd1243dSDimitry Andric   const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
1575bdd1243dSDimitry Andric   return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
1576bdd1243dSDimitry Andric                       MachinePointerInfo(SV));
157781ad6265SDimitry Andric }
157881ad6265SDimitry Andric 
1579753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
1580753f127fSDimitry Andric                                                  SelectionDAG &DAG) const {
1581bdd1243dSDimitry Andric   assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
1582bdd1243dSDimitry Andric          !Subtarget.hasBasicD() && "unexpected target features");
1583753f127fSDimitry Andric 
1584753f127fSDimitry Andric   SDLoc DL(Op);
1585bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
1586bdd1243dSDimitry Andric   if (Op0->getOpcode() == ISD::AND) {
1587bdd1243dSDimitry Andric     auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
1588bdd1243dSDimitry Andric     if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
1589753f127fSDimitry Andric       return Op;
1590bdd1243dSDimitry Andric   }
1591bdd1243dSDimitry Andric 
1592bdd1243dSDimitry Andric   if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
1593bdd1243dSDimitry Andric       Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
1594bdd1243dSDimitry Andric       Op0.getConstantOperandVal(2) == UINT64_C(0))
1595bdd1243dSDimitry Andric     return Op;
1596bdd1243dSDimitry Andric 
1597bdd1243dSDimitry Andric   if (Op0.getOpcode() == ISD::AssertZext &&
1598bdd1243dSDimitry Andric       dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
1599bdd1243dSDimitry Andric     return Op;
1600bdd1243dSDimitry Andric 
1601bdd1243dSDimitry Andric   EVT OpVT = Op0.getValueType();
1602bdd1243dSDimitry Andric   EVT RetVT = Op.getValueType();
1603bdd1243dSDimitry Andric   RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
1604bdd1243dSDimitry Andric   MakeLibCallOptions CallOptions;
1605bdd1243dSDimitry Andric   CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
1606bdd1243dSDimitry Andric   SDValue Chain = SDValue();
1607bdd1243dSDimitry Andric   SDValue Result;
1608bdd1243dSDimitry Andric   std::tie(Result, Chain) =
1609bdd1243dSDimitry Andric       makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
1610bdd1243dSDimitry Andric   return Result;
1611bdd1243dSDimitry Andric }
1612bdd1243dSDimitry Andric 
1613bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
1614bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
1615bdd1243dSDimitry Andric   assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
1616bdd1243dSDimitry Andric          !Subtarget.hasBasicD() && "unexpected target features");
1617bdd1243dSDimitry Andric 
1618bdd1243dSDimitry Andric   SDLoc DL(Op);
1619bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
1620bdd1243dSDimitry Andric 
1621bdd1243dSDimitry Andric   if ((Op0.getOpcode() == ISD::AssertSext ||
1622bdd1243dSDimitry Andric        Op0.getOpcode() == ISD::SIGN_EXTEND_INREG) &&
1623bdd1243dSDimitry Andric       dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
1624bdd1243dSDimitry Andric     return Op;
1625bdd1243dSDimitry Andric 
1626bdd1243dSDimitry Andric   EVT OpVT = Op0.getValueType();
1627bdd1243dSDimitry Andric   EVT RetVT = Op.getValueType();
1628bdd1243dSDimitry Andric   RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
1629bdd1243dSDimitry Andric   MakeLibCallOptions CallOptions;
1630bdd1243dSDimitry Andric   CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
1631bdd1243dSDimitry Andric   SDValue Chain = SDValue();
1632bdd1243dSDimitry Andric   SDValue Result;
1633bdd1243dSDimitry Andric   std::tie(Result, Chain) =
1634bdd1243dSDimitry Andric       makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
1635bdd1243dSDimitry Andric   return Result;
1636753f127fSDimitry Andric }
1637753f127fSDimitry Andric 
1638753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
1639753f127fSDimitry Andric                                               SelectionDAG &DAG) const {
1640753f127fSDimitry Andric 
1641753f127fSDimitry Andric   SDLoc DL(Op);
1642753f127fSDimitry Andric   SDValue Op0 = Op.getOperand(0);
1643753f127fSDimitry Andric 
1644753f127fSDimitry Andric   if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 &&
1645753f127fSDimitry Andric       Subtarget.is64Bit() && Subtarget.hasBasicF()) {
1646753f127fSDimitry Andric     SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
1647753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
1648753f127fSDimitry Andric   }
1649753f127fSDimitry Andric   return Op;
1650753f127fSDimitry Andric }
1651753f127fSDimitry Andric 
1652753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
1653753f127fSDimitry Andric                                                  SelectionDAG &DAG) const {
1654753f127fSDimitry Andric 
1655753f127fSDimitry Andric   SDLoc DL(Op);
1656753f127fSDimitry Andric 
1657753f127fSDimitry Andric   if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
1658753f127fSDimitry Andric       !Subtarget.hasBasicD()) {
1659753f127fSDimitry Andric     SDValue Dst =
1660753f127fSDimitry Andric         DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0));
1661753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
1662753f127fSDimitry Andric   }
1663753f127fSDimitry Andric 
1664753f127fSDimitry Andric   EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
1665753f127fSDimitry Andric   SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0));
1666753f127fSDimitry Andric   return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
1667753f127fSDimitry Andric }
1668753f127fSDimitry Andric 
1669bdd1243dSDimitry Andric static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty,
1670bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
1671bdd1243dSDimitry Andric   return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
1672bdd1243dSDimitry Andric }
1673bdd1243dSDimitry Andric 
1674bdd1243dSDimitry Andric static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty,
1675bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
1676bdd1243dSDimitry Andric   return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
1677bdd1243dSDimitry Andric                                    Flags);
1678bdd1243dSDimitry Andric }
1679bdd1243dSDimitry Andric 
1680bdd1243dSDimitry Andric static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty,
1681bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
1682bdd1243dSDimitry Andric   return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
1683bdd1243dSDimitry Andric                                    N->getOffset(), Flags);
1684bdd1243dSDimitry Andric }
1685bdd1243dSDimitry Andric 
1686bdd1243dSDimitry Andric static SDValue getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty,
1687bdd1243dSDimitry Andric                              SelectionDAG &DAG, unsigned Flags) {
1688bdd1243dSDimitry Andric   return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
1689bdd1243dSDimitry Andric }
1690bdd1243dSDimitry Andric 
1691bdd1243dSDimitry Andric template <class NodeTy>
1692bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
16931db9f3b2SDimitry Andric                                          CodeModel::Model M,
1694bdd1243dSDimitry Andric                                          bool IsLocal) const {
1695bdd1243dSDimitry Andric   SDLoc DL(N);
1696bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
1697bdd1243dSDimitry Andric   SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
1698*0fca6ea1SDimitry Andric   SDValue Load;
169906c3fb27SDimitry Andric 
17001db9f3b2SDimitry Andric   switch (M) {
170106c3fb27SDimitry Andric   default:
170206c3fb27SDimitry Andric     report_fatal_error("Unsupported code model");
170306c3fb27SDimitry Andric 
170406c3fb27SDimitry Andric   case CodeModel::Large: {
170506c3fb27SDimitry Andric     assert(Subtarget.is64Bit() && "Large code model requires LA64");
170606c3fb27SDimitry Andric 
170706c3fb27SDimitry Andric     // This is not actually used, but is necessary for successfully matching
170806c3fb27SDimitry Andric     // the PseudoLA_*_LARGE nodes.
170906c3fb27SDimitry Andric     SDValue Tmp = DAG.getConstant(0, DL, Ty);
1710*0fca6ea1SDimitry Andric     if (IsLocal) {
171106c3fb27SDimitry Andric       // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that
171206c3fb27SDimitry Andric       // eventually becomes the desired 5-insn code sequence.
1713*0fca6ea1SDimitry Andric       Load = SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty,
171406c3fb27SDimitry Andric                                         Tmp, Addr),
171506c3fb27SDimitry Andric                      0);
1716*0fca6ea1SDimitry Andric     } else {
1717*0fca6ea1SDimitry Andric       // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that
1718*0fca6ea1SDimitry Andric       // eventually becomes the desired 5-insn code sequence.
1719*0fca6ea1SDimitry Andric       Load = SDValue(
172006c3fb27SDimitry Andric           DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr),
172106c3fb27SDimitry Andric           0);
172206c3fb27SDimitry Andric     }
1723*0fca6ea1SDimitry Andric     break;
1724*0fca6ea1SDimitry Andric   }
172506c3fb27SDimitry Andric 
172606c3fb27SDimitry Andric   case CodeModel::Small:
172706c3fb27SDimitry Andric   case CodeModel::Medium:
1728*0fca6ea1SDimitry Andric     if (IsLocal) {
1729bdd1243dSDimitry Andric       // This generates the pattern (PseudoLA_PCREL sym), which expands to
1730bdd1243dSDimitry Andric       // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
1731*0fca6ea1SDimitry Andric       Load = SDValue(
173206c3fb27SDimitry Andric           DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0);
1733*0fca6ea1SDimitry Andric     } else {
1734bdd1243dSDimitry Andric       // This generates the pattern (PseudoLA_GOT sym), which expands to (ld.w/d
1735bdd1243dSDimitry Andric       // (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
1736*0fca6ea1SDimitry Andric       Load =
1737*0fca6ea1SDimitry Andric           SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0);
173806c3fb27SDimitry Andric     }
1739bdd1243dSDimitry Andric   }
1740bdd1243dSDimitry Andric 
1741*0fca6ea1SDimitry Andric   if (!IsLocal) {
1742*0fca6ea1SDimitry Andric     // Mark the load instruction as invariant to enable hoisting in MachineLICM.
1743*0fca6ea1SDimitry Andric     MachineFunction &MF = DAG.getMachineFunction();
1744*0fca6ea1SDimitry Andric     MachineMemOperand *MemOp = MF.getMachineMemOperand(
1745*0fca6ea1SDimitry Andric         MachinePointerInfo::getGOT(MF),
1746*0fca6ea1SDimitry Andric         MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |
1747*0fca6ea1SDimitry Andric             MachineMemOperand::MOInvariant,
1748*0fca6ea1SDimitry Andric         LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
1749*0fca6ea1SDimitry Andric     DAG.setNodeMemRefs(cast<MachineSDNode>(Load.getNode()), {MemOp});
1750*0fca6ea1SDimitry Andric   }
1751*0fca6ea1SDimitry Andric 
1752*0fca6ea1SDimitry Andric   return Load;
1753*0fca6ea1SDimitry Andric }
1754*0fca6ea1SDimitry Andric 
1755bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
1756bdd1243dSDimitry Andric                                                    SelectionDAG &DAG) const {
17571db9f3b2SDimitry Andric   return getAddr(cast<BlockAddressSDNode>(Op), DAG,
17581db9f3b2SDimitry Andric                  DAG.getTarget().getCodeModel());
1759bdd1243dSDimitry Andric }
1760bdd1243dSDimitry Andric 
1761bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
1762bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
17631db9f3b2SDimitry Andric   return getAddr(cast<JumpTableSDNode>(Op), DAG,
17641db9f3b2SDimitry Andric                  DAG.getTarget().getCodeModel());
1765bdd1243dSDimitry Andric }
1766bdd1243dSDimitry Andric 
1767753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
1768753f127fSDimitry Andric                                                    SelectionDAG &DAG) const {
17691db9f3b2SDimitry Andric   return getAddr(cast<ConstantPoolSDNode>(Op), DAG,
17701db9f3b2SDimitry Andric                  DAG.getTarget().getCodeModel());
1771753f127fSDimitry Andric }
1772753f127fSDimitry Andric 
1773753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
1774753f127fSDimitry Andric                                                     SelectionDAG &DAG) const {
1775bdd1243dSDimitry Andric   GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
1776bdd1243dSDimitry Andric   assert(N->getOffset() == 0 && "unexpected offset in global node");
17771db9f3b2SDimitry Andric   auto CM = DAG.getTarget().getCodeModel();
17781db9f3b2SDimitry Andric   const GlobalValue *GV = N->getGlobal();
17791db9f3b2SDimitry Andric 
17801db9f3b2SDimitry Andric   if (GV->isDSOLocal() && isa<GlobalVariable>(GV)) {
17811db9f3b2SDimitry Andric     if (auto GCM = dyn_cast<GlobalVariable>(GV)->getCodeModel())
17821db9f3b2SDimitry Andric       CM = *GCM;
17831db9f3b2SDimitry Andric   }
17841db9f3b2SDimitry Andric 
17851db9f3b2SDimitry Andric   return getAddr(N, DAG, CM, GV->isDSOLocal());
1786bdd1243dSDimitry Andric }
1787753f127fSDimitry Andric 
1788bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
1789bdd1243dSDimitry Andric                                                   SelectionDAG &DAG,
1790*0fca6ea1SDimitry Andric                                                   unsigned Opc, bool UseGOT,
179106c3fb27SDimitry Andric                                                   bool Large) const {
1792bdd1243dSDimitry Andric   SDLoc DL(N);
1793bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
1794bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
1795bdd1243dSDimitry Andric 
179606c3fb27SDimitry Andric   // This is not actually used, but is necessary for successfully matching the
179706c3fb27SDimitry Andric   // PseudoLA_*_LARGE nodes.
179806c3fb27SDimitry Andric   SDValue Tmp = DAG.getConstant(0, DL, Ty);
1799bdd1243dSDimitry Andric   SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
180006c3fb27SDimitry Andric   SDValue Offset = Large
180106c3fb27SDimitry Andric                        ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
180206c3fb27SDimitry Andric                        : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
1803*0fca6ea1SDimitry Andric   if (UseGOT) {
1804*0fca6ea1SDimitry Andric     // Mark the load instruction as invariant to enable hoisting in MachineLICM.
1805*0fca6ea1SDimitry Andric     MachineFunction &MF = DAG.getMachineFunction();
1806*0fca6ea1SDimitry Andric     MachineMemOperand *MemOp = MF.getMachineMemOperand(
1807*0fca6ea1SDimitry Andric         MachinePointerInfo::getGOT(MF),
1808*0fca6ea1SDimitry Andric         MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |
1809*0fca6ea1SDimitry Andric             MachineMemOperand::MOInvariant,
1810*0fca6ea1SDimitry Andric         LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
1811*0fca6ea1SDimitry Andric     DAG.setNodeMemRefs(cast<MachineSDNode>(Offset.getNode()), {MemOp});
1812*0fca6ea1SDimitry Andric   }
1813bdd1243dSDimitry Andric 
1814bdd1243dSDimitry Andric   // Add the thread pointer.
1815bdd1243dSDimitry Andric   return DAG.getNode(ISD::ADD, DL, Ty, Offset,
1816bdd1243dSDimitry Andric                      DAG.getRegister(LoongArch::R2, GRLenVT));
1817bdd1243dSDimitry Andric }
1818bdd1243dSDimitry Andric 
1819bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
1820bdd1243dSDimitry Andric                                                    SelectionDAG &DAG,
182106c3fb27SDimitry Andric                                                    unsigned Opc,
182206c3fb27SDimitry Andric                                                    bool Large) const {
1823bdd1243dSDimitry Andric   SDLoc DL(N);
1824bdd1243dSDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
1825bdd1243dSDimitry Andric   IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
1826bdd1243dSDimitry Andric 
182706c3fb27SDimitry Andric   // This is not actually used, but is necessary for successfully matching the
182806c3fb27SDimitry Andric   // PseudoLA_*_LARGE nodes.
182906c3fb27SDimitry Andric   SDValue Tmp = DAG.getConstant(0, DL, Ty);
183006c3fb27SDimitry Andric 
1831bdd1243dSDimitry Andric   // Use a PC-relative addressing mode to access the dynamic GOT address.
1832bdd1243dSDimitry Andric   SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
183306c3fb27SDimitry Andric   SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
183406c3fb27SDimitry Andric                        : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
1835bdd1243dSDimitry Andric 
1836bdd1243dSDimitry Andric   // Prepare argument list to generate call.
1837bdd1243dSDimitry Andric   ArgListTy Args;
1838bdd1243dSDimitry Andric   ArgListEntry Entry;
1839bdd1243dSDimitry Andric   Entry.Node = Load;
1840bdd1243dSDimitry Andric   Entry.Ty = CallTy;
1841bdd1243dSDimitry Andric   Args.push_back(Entry);
1842bdd1243dSDimitry Andric 
1843bdd1243dSDimitry Andric   // Setup call to __tls_get_addr.
1844bdd1243dSDimitry Andric   TargetLowering::CallLoweringInfo CLI(DAG);
1845bdd1243dSDimitry Andric   CLI.setDebugLoc(DL)
1846bdd1243dSDimitry Andric       .setChain(DAG.getEntryNode())
1847bdd1243dSDimitry Andric       .setLibCallee(CallingConv::C, CallTy,
1848bdd1243dSDimitry Andric                     DAG.getExternalSymbol("__tls_get_addr", Ty),
1849bdd1243dSDimitry Andric                     std::move(Args));
1850bdd1243dSDimitry Andric 
1851bdd1243dSDimitry Andric   return LowerCallTo(CLI).first;
1852bdd1243dSDimitry Andric }
1853bdd1243dSDimitry Andric 
1854*0fca6ea1SDimitry Andric SDValue LoongArchTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N,
1855*0fca6ea1SDimitry Andric                                                 SelectionDAG &DAG, unsigned Opc,
1856*0fca6ea1SDimitry Andric                                                 bool Large) const {
1857*0fca6ea1SDimitry Andric   SDLoc DL(N);
1858*0fca6ea1SDimitry Andric   EVT Ty = getPointerTy(DAG.getDataLayout());
1859*0fca6ea1SDimitry Andric   const GlobalValue *GV = N->getGlobal();
1860*0fca6ea1SDimitry Andric 
1861*0fca6ea1SDimitry Andric   // This is not actually used, but is necessary for successfully matching the
1862*0fca6ea1SDimitry Andric   // PseudoLA_*_LARGE nodes.
1863*0fca6ea1SDimitry Andric   SDValue Tmp = DAG.getConstant(0, DL, Ty);
1864*0fca6ea1SDimitry Andric 
1865*0fca6ea1SDimitry Andric   // Use a PC-relative addressing mode to access the global dynamic GOT address.
1866*0fca6ea1SDimitry Andric   // This generates the pattern (PseudoLA_TLS_DESC_PC{,LARGE} sym).
1867*0fca6ea1SDimitry Andric   SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0);
1868*0fca6ea1SDimitry Andric   return Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
1869*0fca6ea1SDimitry Andric                : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
1870*0fca6ea1SDimitry Andric }
1871*0fca6ea1SDimitry Andric 
1872bdd1243dSDimitry Andric SDValue
1873bdd1243dSDimitry Andric LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
1874bdd1243dSDimitry Andric                                                SelectionDAG &DAG) const {
1875bdd1243dSDimitry Andric   if (DAG.getMachineFunction().getFunction().getCallingConv() ==
1876bdd1243dSDimitry Andric       CallingConv::GHC)
1877bdd1243dSDimitry Andric     report_fatal_error("In GHC calling convention TLS is not supported");
1878bdd1243dSDimitry Andric 
187906c3fb27SDimitry Andric   bool Large = DAG.getTarget().getCodeModel() == CodeModel::Large;
188006c3fb27SDimitry Andric   assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64");
188106c3fb27SDimitry Andric 
1882bdd1243dSDimitry Andric   GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
1883bdd1243dSDimitry Andric   assert(N->getOffset() == 0 && "unexpected offset in global node");
1884bdd1243dSDimitry Andric 
1885*0fca6ea1SDimitry Andric   if (DAG.getTarget().useEmulatedTLS())
1886*0fca6ea1SDimitry Andric     report_fatal_error("the emulated TLS is prohibited",
1887*0fca6ea1SDimitry Andric                        /*GenCrashDiag=*/false);
1888*0fca6ea1SDimitry Andric 
1889*0fca6ea1SDimitry Andric   bool IsDesc = DAG.getTarget().useTLSDESC();
1890*0fca6ea1SDimitry Andric 
1891bdd1243dSDimitry Andric   switch (getTargetMachine().getTLSModel(N->getGlobal())) {
1892bdd1243dSDimitry Andric   case TLSModel::GeneralDynamic:
1893bdd1243dSDimitry Andric     // In this model, application code calls the dynamic linker function
1894bdd1243dSDimitry Andric     // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
1895bdd1243dSDimitry Andric     // runtime.
1896*0fca6ea1SDimitry Andric     if (!IsDesc)
1897*0fca6ea1SDimitry Andric       return getDynamicTLSAddr(N, DAG,
189806c3fb27SDimitry Andric                                Large ? LoongArch::PseudoLA_TLS_GD_LARGE
189906c3fb27SDimitry Andric                                      : LoongArch::PseudoLA_TLS_GD,
190006c3fb27SDimitry Andric                                Large);
1901bdd1243dSDimitry Andric     break;
1902bdd1243dSDimitry Andric   case TLSModel::LocalDynamic:
1903bdd1243dSDimitry Andric     // Same as GeneralDynamic, except for assembly modifiers and relocation
1904bdd1243dSDimitry Andric     // records.
1905*0fca6ea1SDimitry Andric     if (!IsDesc)
1906*0fca6ea1SDimitry Andric       return getDynamicTLSAddr(N, DAG,
190706c3fb27SDimitry Andric                                Large ? LoongArch::PseudoLA_TLS_LD_LARGE
190806c3fb27SDimitry Andric                                      : LoongArch::PseudoLA_TLS_LD,
190906c3fb27SDimitry Andric                                Large);
1910bdd1243dSDimitry Andric     break;
1911bdd1243dSDimitry Andric   case TLSModel::InitialExec:
1912bdd1243dSDimitry Andric     // This model uses the GOT to resolve TLS offsets.
1913*0fca6ea1SDimitry Andric     return getStaticTLSAddr(N, DAG,
191406c3fb27SDimitry Andric                             Large ? LoongArch::PseudoLA_TLS_IE_LARGE
191506c3fb27SDimitry Andric                                   : LoongArch::PseudoLA_TLS_IE,
1916*0fca6ea1SDimitry Andric                             /*UseGOT=*/true, Large);
1917bdd1243dSDimitry Andric   case TLSModel::LocalExec:
1918bdd1243dSDimitry Andric     // This model is used when static linking as the TLS offsets are resolved
1919bdd1243dSDimitry Andric     // during program linking.
192006c3fb27SDimitry Andric     //
192106c3fb27SDimitry Andric     // This node doesn't need an extra argument for the large code model.
1922*0fca6ea1SDimitry Andric     return getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE,
1923*0fca6ea1SDimitry Andric                             /*UseGOT=*/false);
1924bdd1243dSDimitry Andric   }
1925bdd1243dSDimitry Andric 
1926*0fca6ea1SDimitry Andric   return getTLSDescAddr(N, DAG,
1927*0fca6ea1SDimitry Andric                         Large ? LoongArch::PseudoLA_TLS_DESC_PC_LARGE
1928*0fca6ea1SDimitry Andric                               : LoongArch::PseudoLA_TLS_DESC_PC,
1929*0fca6ea1SDimitry Andric                         Large);
1930753f127fSDimitry Andric }
1931bdd1243dSDimitry Andric 
19325f757f3fSDimitry Andric template <unsigned N>
19335f757f3fSDimitry Andric static SDValue checkIntrinsicImmArg(SDValue Op, unsigned ImmOp,
19345f757f3fSDimitry Andric                                     SelectionDAG &DAG, bool IsSigned = false) {
19355f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Op->getOperand(ImmOp));
19365f757f3fSDimitry Andric   // Check the ImmArg.
19375f757f3fSDimitry Andric   if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
19385f757f3fSDimitry Andric       (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
19395f757f3fSDimitry Andric     DAG.getContext()->emitError(Op->getOperationName(0) +
19405f757f3fSDimitry Andric                                 ": argument out of range.");
19415f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, SDLoc(Op), Op.getValueType());
19425f757f3fSDimitry Andric   }
19435f757f3fSDimitry Andric   return SDValue();
19445f757f3fSDimitry Andric }
19455f757f3fSDimitry Andric 
1946bdd1243dSDimitry Andric SDValue
1947bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
1948bdd1243dSDimitry Andric                                                  SelectionDAG &DAG) const {
19495f757f3fSDimitry Andric   SDLoc DL(Op);
1950bdd1243dSDimitry Andric   switch (Op.getConstantOperandVal(0)) {
1951bdd1243dSDimitry Andric   default:
1952bdd1243dSDimitry Andric     return SDValue(); // Don't custom lower most intrinsics.
1953bdd1243dSDimitry Andric   case Intrinsic::thread_pointer: {
1954bdd1243dSDimitry Andric     EVT PtrVT = getPointerTy(DAG.getDataLayout());
1955bdd1243dSDimitry Andric     return DAG.getRegister(LoongArch::R2, PtrVT);
1956bdd1243dSDimitry Andric   }
19575f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_d:
19585f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_du:
19595f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplvei_d:
19605f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepl128vei_d:
19615f757f3fSDimitry Andric     return checkIntrinsicImmArg<1>(Op, 2, DAG);
19625f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplvei_w:
19635f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepl128vei_w:
19645f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve2gr_d:
19655f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve2gr_du:
19665f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve_d:
19675f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve_d_f:
19685f757f3fSDimitry Andric     return checkIntrinsicImmArg<2>(Op, 2, DAG);
19695f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvinsve0_d:
19705f757f3fSDimitry Andric     return checkIntrinsicImmArg<2>(Op, 3, DAG);
19715f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_b:
19725f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_bu:
19735f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrotri_b:
19745f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_h_b:
19755f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_hu_bu:
19765f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlri_b:
19775f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrari_b:
19785f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplvei_h:
19795f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_b:
19805f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_bu:
19815f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrotri_b:
19825f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_h_b:
19835f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_hu_bu:
19845f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlri_b:
19855f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrari_b:
19865f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepl128vei_h:
19875f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve_w:
19885f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve_w_f:
19895f757f3fSDimitry Andric     return checkIntrinsicImmArg<3>(Op, 2, DAG);
19905f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvinsve0_w:
19915f757f3fSDimitry Andric     return checkIntrinsicImmArg<3>(Op, 3, DAG);
19925f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_h:
19935f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_hu:
19945f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrotri_h:
19955f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_w_h:
19965f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_wu_hu:
19975f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlri_h:
19985f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrari_h:
19995f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplvei_b:
20005f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_h:
20015f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_hu:
20025f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrotri_h:
20035f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_w_h:
20045f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_wu_hu:
20055f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlri_h:
20065f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrari_h:
20075f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepl128vei_b:
20085f757f3fSDimitry Andric     return checkIntrinsicImmArg<4>(Op, 2, DAG);
20095f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlni_b_h:
20105f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrani_b_h:
20115f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlrni_b_h:
20125f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrarni_b_h:
20135f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_b_h:
20145f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_b_h:
20155f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_bu_h:
20165f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_bu_h:
20175f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_b_h:
20185f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_b_h:
20195f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_bu_h:
20205f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_bu_h:
20215f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlni_b_h:
20225f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrani_b_h:
20235f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlrni_b_h:
20245f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrarni_b_h:
20255f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_b_h:
20265f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_b_h:
20275f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_bu_h:
20285f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_bu_h:
20295f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_b_h:
20305f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_b_h:
20315f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_bu_h:
20325f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_bu_h:
20335f757f3fSDimitry Andric     return checkIntrinsicImmArg<4>(Op, 3, DAG);
20345f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_w:
20355f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_wu:
20365f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrotri_w:
20375f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_d_w:
20385f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsllwil_du_wu:
20395f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlri_w:
20405f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrari_w:
20415f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_bu:
20425f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_hu:
20435f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_wu:
20445f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_du:
20455f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_bu:
20465f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_hu:
20475f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_wu:
20485f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_du:
20495f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbsll_v:
20505f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbsrl_v:
20515f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_w:
20525f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_wu:
20535f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrotri_w:
20545f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_d_w:
20555f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsllwil_du_wu:
20565f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlri_w:
20575f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrari_w:
20585f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_bu:
20595f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_hu:
20605f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_wu:
20615f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_du:
20625f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_bu:
20635f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_hu:
20645f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_wu:
20655f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_du:
20665f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbsll_v:
20675f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbsrl_v:
20685f757f3fSDimitry Andric     return checkIntrinsicImmArg<5>(Op, 2, DAG);
20695f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vseqi_b:
20705f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vseqi_h:
20715f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vseqi_w:
20725f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vseqi_d:
20735f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_b:
20745f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_h:
20755f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_w:
20765f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslei_d:
20775f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_b:
20785f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_h:
20795f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_w:
20805f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslti_d:
20815f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvseqi_b:
20825f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvseqi_h:
20835f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvseqi_w:
20845f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvseqi_d:
20855f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_b:
20865f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_h:
20875f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_w:
20885f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslei_d:
20895f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_b:
20905f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_h:
20915f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_w:
20925f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslti_d:
20935f757f3fSDimitry Andric     return checkIntrinsicImmArg<5>(Op, 2, DAG, /*IsSigned=*/true);
20945f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlni_h_w:
20955f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrani_h_w:
20965f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlrni_h_w:
20975f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrarni_h_w:
20985f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_h_w:
20995f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_h_w:
21005f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_hu_w:
21015f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_hu_w:
21025f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_h_w:
21035f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_h_w:
21045f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_hu_w:
21055f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_hu_w:
21065f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfrstpi_b:
21075f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfrstpi_h:
21085f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlni_h_w:
21095f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrani_h_w:
21105f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlrni_h_w:
21115f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrarni_h_w:
21125f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_h_w:
21135f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_h_w:
21145f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_hu_w:
21155f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_hu_w:
21165f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_h_w:
21175f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_h_w:
21185f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_hu_w:
21195f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_hu_w:
21205f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfrstpi_b:
21215f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfrstpi_h:
21225f757f3fSDimitry Andric     return checkIntrinsicImmArg<5>(Op, 3, DAG);
21235f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_d:
21245f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsat_du:
21255f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrotri_d:
21265f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlri_d:
21275f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrari_d:
21285f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_d:
21295f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsat_du:
21305f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrotri_d:
21315f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlri_d:
21325f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrari_d:
21335f757f3fSDimitry Andric     return checkIntrinsicImmArg<6>(Op, 2, DAG);
21345f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlni_w_d:
21355f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrani_w_d:
21365f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlrni_w_d:
21375f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrarni_w_d:
21385f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_w_d:
21395f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_w_d:
21405f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_wu_d:
21415f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_wu_d:
21425f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_w_d:
21435f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_w_d:
21445f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_wu_d:
21455f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_wu_d:
21465f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlni_w_d:
21475f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrani_w_d:
21485f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlrni_w_d:
21495f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrarni_w_d:
21505f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_w_d:
21515f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_w_d:
21525f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_wu_d:
21535f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_wu_d:
21545f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_w_d:
21555f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_w_d:
21565f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_wu_d:
21575f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_wu_d:
21585f757f3fSDimitry Andric     return checkIntrinsicImmArg<6>(Op, 3, DAG);
21595f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlni_d_q:
21605f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrani_d_q:
21615f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrlrni_d_q:
21625f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrarni_d_q:
21635f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_d_q:
21645f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_d_q:
21655f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlni_du_q:
21665f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrani_du_q:
21675f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_d_q:
21685f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_d_q:
21695f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrlrni_du_q:
21705f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vssrarni_du_q:
21715f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlni_d_q:
21725f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrani_d_q:
21735f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrlrni_d_q:
21745f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrarni_d_q:
21755f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_d_q:
21765f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_d_q:
21775f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlni_du_q:
21785f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrani_du_q:
21795f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_d_q:
21805f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_d_q:
21815f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrlrni_du_q:
21825f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvssrarni_du_q:
21835f757f3fSDimitry Andric     return checkIntrinsicImmArg<7>(Op, 3, DAG);
21845f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vnori_b:
21855f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vshuf4i_b:
21865f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vshuf4i_h:
21875f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vshuf4i_w:
21885f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvnori_b:
21895f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvshuf4i_b:
21905f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvshuf4i_h:
21915f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvshuf4i_w:
21925f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpermi_d:
21935f757f3fSDimitry Andric     return checkIntrinsicImmArg<8>(Op, 2, DAG);
21945f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vshuf4i_d:
21955f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpermi_w:
21965f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitseli_b:
21975f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vextrins_b:
21985f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vextrins_h:
21995f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vextrins_w:
22005f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vextrins_d:
22015f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvshuf4i_d:
22025f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpermi_w:
22035f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpermi_q:
22045f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitseli_b:
22055f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvextrins_b:
22065f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvextrins_h:
22075f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvextrins_w:
22085f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvextrins_d:
22095f757f3fSDimitry Andric     return checkIntrinsicImmArg<8>(Op, 3, DAG);
22105f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrepli_b:
22115f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrepli_h:
22125f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrepli_w:
22135f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vrepli_d:
22145f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepli_b:
22155f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepli_h:
22165f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepli_w:
22175f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvrepli_d:
22185f757f3fSDimitry Andric     return checkIntrinsicImmArg<10>(Op, 1, DAG, /*IsSigned=*/true);
22195f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vldi:
22205f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvldi:
22215f757f3fSDimitry Andric     return checkIntrinsicImmArg<13>(Op, 1, DAG, /*IsSigned=*/true);
2222bdd1243dSDimitry Andric   }
2223bdd1243dSDimitry Andric }
2224bdd1243dSDimitry Andric 
222506c3fb27SDimitry Andric // Helper function that emits error message for intrinsics with chain and return
222606c3fb27SDimitry Andric // merge values of a UNDEF and the chain.
2227bdd1243dSDimitry Andric static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op,
2228bdd1243dSDimitry Andric                                                   StringRef ErrorMsg,
2229bdd1243dSDimitry Andric                                                   SelectionDAG &DAG) {
223006c3fb27SDimitry Andric   DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
2231bdd1243dSDimitry Andric   return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
2232bdd1243dSDimitry Andric                             SDLoc(Op));
2233bdd1243dSDimitry Andric }
2234bdd1243dSDimitry Andric 
2235bdd1243dSDimitry Andric SDValue
2236bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
2237bdd1243dSDimitry Andric                                                 SelectionDAG &DAG) const {
2238bdd1243dSDimitry Andric   SDLoc DL(Op);
2239bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
224006c3fb27SDimitry Andric   EVT VT = Op.getValueType();
224106c3fb27SDimitry Andric   SDValue Chain = Op.getOperand(0);
224206c3fb27SDimitry Andric   const StringRef ErrorMsgOOR = "argument out of range";
224306c3fb27SDimitry Andric   const StringRef ErrorMsgReqLA64 = "requires loongarch64";
224406c3fb27SDimitry Andric   const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
2245bdd1243dSDimitry Andric 
2246bdd1243dSDimitry Andric   switch (Op.getConstantOperandVal(1)) {
2247bdd1243dSDimitry Andric   default:
2248bdd1243dSDimitry Andric     return Op;
2249bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_b_w:
2250bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_h_w:
2251bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_w_w:
2252bdd1243dSDimitry Andric   case Intrinsic::loongarch_crc_w_d_w:
2253bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_b_w:
2254bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_h_w:
2255bdd1243dSDimitry Andric   case Intrinsic::loongarch_crcc_w_w_w:
225606c3fb27SDimitry Andric   case Intrinsic::loongarch_crcc_w_d_w:
225706c3fb27SDimitry Andric     return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG);
2258bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrrd_w:
2259bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrrd_d: {
2260647cbc5dSDimitry Andric     unsigned Imm = Op.getConstantOperandVal(2);
226106c3fb27SDimitry Andric     return !isUInt<14>(Imm)
226206c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
226306c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
226406c3fb27SDimitry Andric                              {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
2265bdd1243dSDimitry Andric   }
2266bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrwr_w:
2267bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrwr_d: {
2268647cbc5dSDimitry Andric     unsigned Imm = Op.getConstantOperandVal(3);
226906c3fb27SDimitry Andric     return !isUInt<14>(Imm)
227006c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
227106c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
227206c3fb27SDimitry Andric                              {Chain, Op.getOperand(2),
227306c3fb27SDimitry Andric                               DAG.getConstant(Imm, DL, GRLenVT)});
2274bdd1243dSDimitry Andric   }
2275bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrxchg_w:
2276bdd1243dSDimitry Andric   case Intrinsic::loongarch_csrxchg_d: {
2277647cbc5dSDimitry Andric     unsigned Imm = Op.getConstantOperandVal(4);
227806c3fb27SDimitry Andric     return !isUInt<14>(Imm)
227906c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
228006c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
228106c3fb27SDimitry Andric                              {Chain, Op.getOperand(2), Op.getOperand(3),
228206c3fb27SDimitry Andric                               DAG.getConstant(Imm, DL, GRLenVT)});
2283bdd1243dSDimitry Andric   }
2284bdd1243dSDimitry Andric   case Intrinsic::loongarch_iocsrrd_d: {
228506c3fb27SDimitry Andric     return DAG.getNode(
228606c3fb27SDimitry Andric         LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other},
228706c3fb27SDimitry Andric         {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))});
2288bdd1243dSDimitry Andric   }
2289bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE)                                               \
2290bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
229106c3fb27SDimitry Andric     return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other},          \
229206c3fb27SDimitry Andric                        {Chain, Op.getOperand(2)});                             \
2293bdd1243dSDimitry Andric   }
2294bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
2295bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
2296bdd1243dSDimitry Andric     IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
2297bdd1243dSDimitry Andric #undef IOCSRRD_CASE
2298bdd1243dSDimitry Andric   case Intrinsic::loongarch_cpucfg: {
229906c3fb27SDimitry Andric     return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
230006c3fb27SDimitry Andric                        {Chain, Op.getOperand(2)});
2301bdd1243dSDimitry Andric   }
2302bdd1243dSDimitry Andric   case Intrinsic::loongarch_lddir_d: {
2303647cbc5dSDimitry Andric     unsigned Imm = Op.getConstantOperandVal(3);
230406c3fb27SDimitry Andric     return !isUInt<8>(Imm)
230506c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
230606c3fb27SDimitry Andric                : Op;
2307bdd1243dSDimitry Andric   }
2308bdd1243dSDimitry Andric   case Intrinsic::loongarch_movfcsr2gr: {
230906c3fb27SDimitry Andric     if (!Subtarget.hasBasicF())
231006c3fb27SDimitry Andric       return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG);
2311647cbc5dSDimitry Andric     unsigned Imm = Op.getConstantOperandVal(2);
231206c3fb27SDimitry Andric     return !isUInt<2>(Imm)
231306c3fb27SDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
231406c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other},
231506c3fb27SDimitry Andric                              {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
2316bdd1243dSDimitry Andric   }
23175f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vld:
23185f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vldrepl_b:
23195f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvld:
23205f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvldrepl_b:
23215f757f3fSDimitry Andric     return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
23225f757f3fSDimitry Andric                ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
23235f757f3fSDimitry Andric                : SDValue();
23245f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vldrepl_h:
23255f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvldrepl_h:
23265f757f3fSDimitry Andric     return !isShiftedInt<11, 1>(
23275f757f3fSDimitry Andric                cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
23285f757f3fSDimitry Andric                ? emitIntrinsicWithChainErrorMessage(
23295f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 2", DAG)
23305f757f3fSDimitry Andric                : SDValue();
23315f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vldrepl_w:
23325f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvldrepl_w:
23335f757f3fSDimitry Andric     return !isShiftedInt<10, 2>(
23345f757f3fSDimitry Andric                cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
23355f757f3fSDimitry Andric                ? emitIntrinsicWithChainErrorMessage(
23365f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 4", DAG)
23375f757f3fSDimitry Andric                : SDValue();
23385f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vldrepl_d:
23395f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvldrepl_d:
23405f757f3fSDimitry Andric     return !isShiftedInt<9, 3>(
23415f757f3fSDimitry Andric                cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
23425f757f3fSDimitry Andric                ? emitIntrinsicWithChainErrorMessage(
23435f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 8", DAG)
23445f757f3fSDimitry Andric                : SDValue();
2345bdd1243dSDimitry Andric   }
2346bdd1243dSDimitry Andric }
2347bdd1243dSDimitry Andric 
2348bdd1243dSDimitry Andric // Helper function that emits error message for intrinsics with void return
234906c3fb27SDimitry Andric // value and return the chain.
2350bdd1243dSDimitry Andric static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg,
2351bdd1243dSDimitry Andric                                          SelectionDAG &DAG) {
2352bdd1243dSDimitry Andric 
235306c3fb27SDimitry Andric   DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
2354bdd1243dSDimitry Andric   return Op.getOperand(0);
2355bdd1243dSDimitry Andric }
2356bdd1243dSDimitry Andric 
2357bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
2358bdd1243dSDimitry Andric                                                      SelectionDAG &DAG) const {
2359bdd1243dSDimitry Andric   SDLoc DL(Op);
2360bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
236106c3fb27SDimitry Andric   SDValue Chain = Op.getOperand(0);
2362bdd1243dSDimitry Andric   uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
2363bdd1243dSDimitry Andric   SDValue Op2 = Op.getOperand(2);
236406c3fb27SDimitry Andric   const StringRef ErrorMsgOOR = "argument out of range";
236506c3fb27SDimitry Andric   const StringRef ErrorMsgReqLA64 = "requires loongarch64";
236606c3fb27SDimitry Andric   const StringRef ErrorMsgReqLA32 = "requires loongarch32";
236706c3fb27SDimitry Andric   const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
2368bdd1243dSDimitry Andric 
2369bdd1243dSDimitry Andric   switch (IntrinsicEnum) {
2370bdd1243dSDimitry Andric   default:
2371bdd1243dSDimitry Andric     // TODO: Add more Intrinsics.
2372bdd1243dSDimitry Andric     return SDValue();
2373bdd1243dSDimitry Andric   case Intrinsic::loongarch_cacop_d:
2374bdd1243dSDimitry Andric   case Intrinsic::loongarch_cacop_w: {
237506c3fb27SDimitry Andric     if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit())
237606c3fb27SDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG);
237706c3fb27SDimitry Andric     if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit())
237806c3fb27SDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG);
2379bdd1243dSDimitry Andric     // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
23801db9f3b2SDimitry Andric     unsigned Imm1 = Op2->getAsZExtVal();
238106c3fb27SDimitry Andric     int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue();
238206c3fb27SDimitry Andric     if (!isUInt<5>(Imm1) || !isInt<12>(Imm2))
2383bdd1243dSDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
2384bdd1243dSDimitry Andric     return Op;
2385bdd1243dSDimitry Andric   }
2386bdd1243dSDimitry Andric   case Intrinsic::loongarch_dbar: {
23871db9f3b2SDimitry Andric     unsigned Imm = Op2->getAsZExtVal();
238806c3fb27SDimitry Andric     return !isUInt<15>(Imm)
238906c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
239006c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain,
2391bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
2392bdd1243dSDimitry Andric   }
2393bdd1243dSDimitry Andric   case Intrinsic::loongarch_ibar: {
23941db9f3b2SDimitry Andric     unsigned Imm = Op2->getAsZExtVal();
239506c3fb27SDimitry Andric     return !isUInt<15>(Imm)
239606c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
239706c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain,
2398bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
2399bdd1243dSDimitry Andric   }
2400bdd1243dSDimitry Andric   case Intrinsic::loongarch_break: {
24011db9f3b2SDimitry Andric     unsigned Imm = Op2->getAsZExtVal();
240206c3fb27SDimitry Andric     return !isUInt<15>(Imm)
240306c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
240406c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain,
2405bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
2406bdd1243dSDimitry Andric   }
2407bdd1243dSDimitry Andric   case Intrinsic::loongarch_movgr2fcsr: {
240806c3fb27SDimitry Andric     if (!Subtarget.hasBasicF())
240906c3fb27SDimitry Andric       return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG);
24101db9f3b2SDimitry Andric     unsigned Imm = Op2->getAsZExtVal();
241106c3fb27SDimitry Andric     return !isUInt<2>(Imm)
241206c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
241306c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain,
2414bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT),
241506c3fb27SDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT,
241606c3fb27SDimitry Andric                                          Op.getOperand(3)));
2417bdd1243dSDimitry Andric   }
2418bdd1243dSDimitry Andric   case Intrinsic::loongarch_syscall: {
24191db9f3b2SDimitry Andric     unsigned Imm = Op2->getAsZExtVal();
242006c3fb27SDimitry Andric     return !isUInt<15>(Imm)
242106c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
242206c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain,
2423bdd1243dSDimitry Andric                              DAG.getConstant(Imm, DL, GRLenVT));
2424bdd1243dSDimitry Andric   }
2425bdd1243dSDimitry Andric #define IOCSRWR_CASE(NAME, NODE)                                               \
2426bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
2427bdd1243dSDimitry Andric     SDValue Op3 = Op.getOperand(3);                                            \
242806c3fb27SDimitry Andric     return Subtarget.is64Bit()                                                 \
242906c3fb27SDimitry Andric                ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain,        \
2430bdd1243dSDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),  \
243106c3fb27SDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3))  \
243206c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2,   \
243306c3fb27SDimitry Andric                              Op3);                                             \
2434bdd1243dSDimitry Andric   }
2435bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
2436bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
2437bdd1243dSDimitry Andric     IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
2438bdd1243dSDimitry Andric #undef IOCSRWR_CASE
2439bdd1243dSDimitry Andric   case Intrinsic::loongarch_iocsrwr_d: {
244006c3fb27SDimitry Andric     return !Subtarget.is64Bit()
244106c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
244206c3fb27SDimitry Andric                : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain,
244306c3fb27SDimitry Andric                              Op2,
244406c3fb27SDimitry Andric                              DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
244506c3fb27SDimitry Andric                                          Op.getOperand(3)));
2446bdd1243dSDimitry Andric   }
2447bdd1243dSDimitry Andric #define ASRT_LE_GT_CASE(NAME)                                                  \
2448bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
244906c3fb27SDimitry Andric     return !Subtarget.is64Bit()                                                \
245006c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)           \
245106c3fb27SDimitry Andric                : Op;                                                           \
2452bdd1243dSDimitry Andric   }
2453bdd1243dSDimitry Andric     ASRT_LE_GT_CASE(asrtle_d)
2454bdd1243dSDimitry Andric     ASRT_LE_GT_CASE(asrtgt_d)
2455bdd1243dSDimitry Andric #undef ASRT_LE_GT_CASE
2456bdd1243dSDimitry Andric   case Intrinsic::loongarch_ldpte_d: {
2457647cbc5dSDimitry Andric     unsigned Imm = Op.getConstantOperandVal(3);
245806c3fb27SDimitry Andric     return !Subtarget.is64Bit()
245906c3fb27SDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
246006c3fb27SDimitry Andric            : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
246106c3fb27SDimitry Andric                              : Op;
2462bdd1243dSDimitry Andric   }
24635f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vst:
24645f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvst:
24655f757f3fSDimitry Andric     return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue())
24665f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
24675f757f3fSDimitry Andric                : SDValue();
24685f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvstelm_b:
24695f757f3fSDimitry Andric     return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
2470647cbc5dSDimitry Andric             !isUInt<5>(Op.getConstantOperandVal(5)))
24715f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
24725f757f3fSDimitry Andric                : SDValue();
24735f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vstelm_b:
24745f757f3fSDimitry Andric     return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
2475647cbc5dSDimitry Andric             !isUInt<4>(Op.getConstantOperandVal(5)))
24765f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
24775f757f3fSDimitry Andric                : SDValue();
24785f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvstelm_h:
24795f757f3fSDimitry Andric     return (!isShiftedInt<8, 1>(
24805f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
2481647cbc5dSDimitry Andric             !isUInt<4>(Op.getConstantOperandVal(5)))
24825f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
24835f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 2", DAG)
24845f757f3fSDimitry Andric                : SDValue();
24855f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vstelm_h:
24865f757f3fSDimitry Andric     return (!isShiftedInt<8, 1>(
24875f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
2488647cbc5dSDimitry Andric             !isUInt<3>(Op.getConstantOperandVal(5)))
24895f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
24905f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 2", DAG)
24915f757f3fSDimitry Andric                : SDValue();
24925f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvstelm_w:
24935f757f3fSDimitry Andric     return (!isShiftedInt<8, 2>(
24945f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
2495647cbc5dSDimitry Andric             !isUInt<3>(Op.getConstantOperandVal(5)))
24965f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
24975f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 4", DAG)
24985f757f3fSDimitry Andric                : SDValue();
24995f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vstelm_w:
25005f757f3fSDimitry Andric     return (!isShiftedInt<8, 2>(
25015f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
2502647cbc5dSDimitry Andric             !isUInt<2>(Op.getConstantOperandVal(5)))
25035f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
25045f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 4", DAG)
25055f757f3fSDimitry Andric                : SDValue();
25065f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvstelm_d:
25075f757f3fSDimitry Andric     return (!isShiftedInt<8, 3>(
25085f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
2509647cbc5dSDimitry Andric             !isUInt<2>(Op.getConstantOperandVal(5)))
25105f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
25115f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 8", DAG)
25125f757f3fSDimitry Andric                : SDValue();
25135f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vstelm_d:
25145f757f3fSDimitry Andric     return (!isShiftedInt<8, 3>(
25155f757f3fSDimitry Andric                 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
2516647cbc5dSDimitry Andric             !isUInt<1>(Op.getConstantOperandVal(5)))
25175f757f3fSDimitry Andric                ? emitIntrinsicErrorMessage(
25185f757f3fSDimitry Andric                      Op, "argument out of range or not a multiple of 8", DAG)
25195f757f3fSDimitry Andric                : SDValue();
2520bdd1243dSDimitry Andric   }
2521753f127fSDimitry Andric }
2522753f127fSDimitry Andric 
252381ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
252481ad6265SDimitry Andric                                                      SelectionDAG &DAG) const {
252581ad6265SDimitry Andric   SDLoc DL(Op);
252681ad6265SDimitry Andric   SDValue Lo = Op.getOperand(0);
252781ad6265SDimitry Andric   SDValue Hi = Op.getOperand(1);
252881ad6265SDimitry Andric   SDValue Shamt = Op.getOperand(2);
252981ad6265SDimitry Andric   EVT VT = Lo.getValueType();
253081ad6265SDimitry Andric 
253181ad6265SDimitry Andric   // if Shamt-GRLen < 0: // Shamt < GRLen
253281ad6265SDimitry Andric   //   Lo = Lo << Shamt
253381ad6265SDimitry Andric   //   Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
253481ad6265SDimitry Andric   // else:
253581ad6265SDimitry Andric   //   Lo = 0
253681ad6265SDimitry Andric   //   Hi = Lo << (Shamt-GRLen)
253781ad6265SDimitry Andric 
253881ad6265SDimitry Andric   SDValue Zero = DAG.getConstant(0, DL, VT);
253981ad6265SDimitry Andric   SDValue One = DAG.getConstant(1, DL, VT);
254081ad6265SDimitry Andric   SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
254181ad6265SDimitry Andric   SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
254281ad6265SDimitry Andric   SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
254381ad6265SDimitry Andric   SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
254481ad6265SDimitry Andric 
254581ad6265SDimitry Andric   SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
254681ad6265SDimitry Andric   SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
254781ad6265SDimitry Andric   SDValue ShiftRightLo =
254881ad6265SDimitry Andric       DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
254981ad6265SDimitry Andric   SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
255081ad6265SDimitry Andric   SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
255181ad6265SDimitry Andric   SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
255281ad6265SDimitry Andric 
255381ad6265SDimitry Andric   SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
255481ad6265SDimitry Andric 
255581ad6265SDimitry Andric   Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
255681ad6265SDimitry Andric   Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
255781ad6265SDimitry Andric 
255881ad6265SDimitry Andric   SDValue Parts[2] = {Lo, Hi};
255981ad6265SDimitry Andric   return DAG.getMergeValues(Parts, DL);
256081ad6265SDimitry Andric }
256181ad6265SDimitry Andric 
256281ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
256381ad6265SDimitry Andric                                                       SelectionDAG &DAG,
256481ad6265SDimitry Andric                                                       bool IsSRA) const {
256581ad6265SDimitry Andric   SDLoc DL(Op);
256681ad6265SDimitry Andric   SDValue Lo = Op.getOperand(0);
256781ad6265SDimitry Andric   SDValue Hi = Op.getOperand(1);
256881ad6265SDimitry Andric   SDValue Shamt = Op.getOperand(2);
256981ad6265SDimitry Andric   EVT VT = Lo.getValueType();
257081ad6265SDimitry Andric 
257181ad6265SDimitry Andric   // SRA expansion:
257281ad6265SDimitry Andric   //   if Shamt-GRLen < 0: // Shamt < GRLen
257381ad6265SDimitry Andric   //     Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
257481ad6265SDimitry Andric   //     Hi = Hi >>s Shamt
257581ad6265SDimitry Andric   //   else:
257681ad6265SDimitry Andric   //     Lo = Hi >>s (Shamt-GRLen);
257781ad6265SDimitry Andric   //     Hi = Hi >>s (GRLen-1)
257881ad6265SDimitry Andric   //
257981ad6265SDimitry Andric   // SRL expansion:
258081ad6265SDimitry Andric   //   if Shamt-GRLen < 0: // Shamt < GRLen
258181ad6265SDimitry Andric   //     Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
258281ad6265SDimitry Andric   //     Hi = Hi >>u Shamt
258381ad6265SDimitry Andric   //   else:
258481ad6265SDimitry Andric   //     Lo = Hi >>u (Shamt-GRLen);
258581ad6265SDimitry Andric   //     Hi = 0;
258681ad6265SDimitry Andric 
258781ad6265SDimitry Andric   unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
258881ad6265SDimitry Andric 
258981ad6265SDimitry Andric   SDValue Zero = DAG.getConstant(0, DL, VT);
259081ad6265SDimitry Andric   SDValue One = DAG.getConstant(1, DL, VT);
259181ad6265SDimitry Andric   SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
259281ad6265SDimitry Andric   SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
259381ad6265SDimitry Andric   SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
259481ad6265SDimitry Andric   SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
259581ad6265SDimitry Andric 
259681ad6265SDimitry Andric   SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
259781ad6265SDimitry Andric   SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
259881ad6265SDimitry Andric   SDValue ShiftLeftHi =
259981ad6265SDimitry Andric       DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
260081ad6265SDimitry Andric   SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
260181ad6265SDimitry Andric   SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
260281ad6265SDimitry Andric   SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
260381ad6265SDimitry Andric   SDValue HiFalse =
260481ad6265SDimitry Andric       IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
260581ad6265SDimitry Andric 
260681ad6265SDimitry Andric   SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
260781ad6265SDimitry Andric 
260881ad6265SDimitry Andric   Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
260981ad6265SDimitry Andric   Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
261081ad6265SDimitry Andric 
261181ad6265SDimitry Andric   SDValue Parts[2] = {Lo, Hi};
261281ad6265SDimitry Andric   return DAG.getMergeValues(Parts, DL);
261381ad6265SDimitry Andric }
261481ad6265SDimitry Andric 
261581ad6265SDimitry Andric // Returns the opcode of the target-specific SDNode that implements the 32-bit
261681ad6265SDimitry Andric // form of the given Opcode.
261781ad6265SDimitry Andric static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode) {
261881ad6265SDimitry Andric   switch (Opcode) {
261981ad6265SDimitry Andric   default:
262081ad6265SDimitry Andric     llvm_unreachable("Unexpected opcode");
2621*0fca6ea1SDimitry Andric   case ISD::UDIV:
2622*0fca6ea1SDimitry Andric     return LoongArchISD::DIV_WU;
2623*0fca6ea1SDimitry Andric   case ISD::UREM:
2624*0fca6ea1SDimitry Andric     return LoongArchISD::MOD_WU;
262581ad6265SDimitry Andric   case ISD::SHL:
262681ad6265SDimitry Andric     return LoongArchISD::SLL_W;
262781ad6265SDimitry Andric   case ISD::SRA:
262881ad6265SDimitry Andric     return LoongArchISD::SRA_W;
262981ad6265SDimitry Andric   case ISD::SRL:
263081ad6265SDimitry Andric     return LoongArchISD::SRL_W;
2631*0fca6ea1SDimitry Andric   case ISD::ROTL:
2632bdd1243dSDimitry Andric   case ISD::ROTR:
2633bdd1243dSDimitry Andric     return LoongArchISD::ROTR_W;
2634bdd1243dSDimitry Andric   case ISD::CTTZ:
2635bdd1243dSDimitry Andric     return LoongArchISD::CTZ_W;
2636bdd1243dSDimitry Andric   case ISD::CTLZ:
2637bdd1243dSDimitry Andric     return LoongArchISD::CLZ_W;
263881ad6265SDimitry Andric   }
263981ad6265SDimitry Andric }
264081ad6265SDimitry Andric 
264181ad6265SDimitry Andric // Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
264281ad6265SDimitry Andric // node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
264381ad6265SDimitry Andric // otherwise be promoted to i64, making it difficult to select the
264481ad6265SDimitry Andric // SLL_W/.../*W later one because the fact the operation was originally of
264581ad6265SDimitry Andric // type i8/i16/i32 is lost.
2646bdd1243dSDimitry Andric static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp,
264781ad6265SDimitry Andric                                    unsigned ExtOpc = ISD::ANY_EXTEND) {
264881ad6265SDimitry Andric   SDLoc DL(N);
264981ad6265SDimitry Andric   LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode());
2650bdd1243dSDimitry Andric   SDValue NewOp0, NewRes;
2651bdd1243dSDimitry Andric 
2652bdd1243dSDimitry Andric   switch (NumOp) {
2653bdd1243dSDimitry Andric   default:
2654bdd1243dSDimitry Andric     llvm_unreachable("Unexpected NumOp");
2655bdd1243dSDimitry Andric   case 1: {
2656bdd1243dSDimitry Andric     NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
2657bdd1243dSDimitry Andric     NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
2658bdd1243dSDimitry Andric     break;
2659bdd1243dSDimitry Andric   }
2660bdd1243dSDimitry Andric   case 2: {
2661bdd1243dSDimitry Andric     NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
266281ad6265SDimitry Andric     SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
2663*0fca6ea1SDimitry Andric     if (N->getOpcode() == ISD::ROTL) {
2664*0fca6ea1SDimitry Andric       SDValue TmpOp = DAG.getConstant(32, DL, MVT::i64);
2665*0fca6ea1SDimitry Andric       NewOp1 = DAG.getNode(ISD::SUB, DL, MVT::i64, TmpOp, NewOp1);
2666*0fca6ea1SDimitry Andric     }
2667bdd1243dSDimitry Andric     NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
2668bdd1243dSDimitry Andric     break;
2669bdd1243dSDimitry Andric   }
2670bdd1243dSDimitry Andric     // TODO:Handle more NumOp.
2671bdd1243dSDimitry Andric   }
2672bdd1243dSDimitry Andric 
2673bdd1243dSDimitry Andric   // ReplaceNodeResults requires we maintain the same type for the return
2674bdd1243dSDimitry Andric   // value.
267581ad6265SDimitry Andric   return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
267681ad6265SDimitry Andric }
267781ad6265SDimitry Andric 
2678*0fca6ea1SDimitry Andric // Converts the given 32-bit operation to a i64 operation with signed extension
2679*0fca6ea1SDimitry Andric // semantic to reduce the signed extension instructions.
2680*0fca6ea1SDimitry Andric static SDValue customLegalizeToWOpWithSExt(SDNode *N, SelectionDAG &DAG) {
2681*0fca6ea1SDimitry Andric   SDLoc DL(N);
2682*0fca6ea1SDimitry Andric   SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0));
2683*0fca6ea1SDimitry Andric   SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
2684*0fca6ea1SDimitry Andric   SDValue NewWOp = DAG.getNode(N->getOpcode(), DL, MVT::i64, NewOp0, NewOp1);
2685*0fca6ea1SDimitry Andric   SDValue NewRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, NewWOp,
2686*0fca6ea1SDimitry Andric                                DAG.getValueType(MVT::i32));
2687*0fca6ea1SDimitry Andric   return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes);
2688*0fca6ea1SDimitry Andric }
2689*0fca6ea1SDimitry Andric 
26905f757f3fSDimitry Andric // Helper function that emits error message for intrinsics with/without chain
26915f757f3fSDimitry Andric // and return a UNDEF or and the chain as the results.
26925f757f3fSDimitry Andric static void emitErrorAndReplaceIntrinsicResults(
269306c3fb27SDimitry Andric     SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG,
26945f757f3fSDimitry Andric     StringRef ErrorMsg, bool WithChain = true) {
269506c3fb27SDimitry Andric   DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
269606c3fb27SDimitry Andric   Results.push_back(DAG.getUNDEF(N->getValueType(0)));
26975f757f3fSDimitry Andric   if (!WithChain)
26985f757f3fSDimitry Andric     return;
269906c3fb27SDimitry Andric   Results.push_back(N->getOperand(0));
270006c3fb27SDimitry Andric }
270106c3fb27SDimitry Andric 
27025f757f3fSDimitry Andric template <unsigned N>
27035f757f3fSDimitry Andric static void
27045f757f3fSDimitry Andric replaceVPICKVE2GRResults(SDNode *Node, SmallVectorImpl<SDValue> &Results,
27055f757f3fSDimitry Andric                          SelectionDAG &DAG, const LoongArchSubtarget &Subtarget,
27065f757f3fSDimitry Andric                          unsigned ResOp) {
27075f757f3fSDimitry Andric   const StringRef ErrorMsgOOR = "argument out of range";
2708647cbc5dSDimitry Andric   unsigned Imm = Node->getConstantOperandVal(2);
27095f757f3fSDimitry Andric   if (!isUInt<N>(Imm)) {
27105f757f3fSDimitry Andric     emitErrorAndReplaceIntrinsicResults(Node, Results, DAG, ErrorMsgOOR,
27115f757f3fSDimitry Andric                                         /*WithChain=*/false);
27125f757f3fSDimitry Andric     return;
27135f757f3fSDimitry Andric   }
27145f757f3fSDimitry Andric   SDLoc DL(Node);
27155f757f3fSDimitry Andric   SDValue Vec = Node->getOperand(1);
27165f757f3fSDimitry Andric 
27175f757f3fSDimitry Andric   SDValue PickElt =
27185f757f3fSDimitry Andric       DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec,
27195f757f3fSDimitry Andric                   DAG.getConstant(Imm, DL, Subtarget.getGRLenVT()),
27205f757f3fSDimitry Andric                   DAG.getValueType(Vec.getValueType().getVectorElementType()));
27215f757f3fSDimitry Andric   Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, Node->getValueType(0),
27225f757f3fSDimitry Andric                                 PickElt.getValue(0)));
27235f757f3fSDimitry Andric }
27245f757f3fSDimitry Andric 
27255f757f3fSDimitry Andric static void replaceVecCondBranchResults(SDNode *N,
27265f757f3fSDimitry Andric                                         SmallVectorImpl<SDValue> &Results,
27275f757f3fSDimitry Andric                                         SelectionDAG &DAG,
27285f757f3fSDimitry Andric                                         const LoongArchSubtarget &Subtarget,
27295f757f3fSDimitry Andric                                         unsigned ResOp) {
27305f757f3fSDimitry Andric   SDLoc DL(N);
27315f757f3fSDimitry Andric   SDValue Vec = N->getOperand(1);
27325f757f3fSDimitry Andric 
27335f757f3fSDimitry Andric   SDValue CB = DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec);
27345f757f3fSDimitry Andric   Results.push_back(
27355f757f3fSDimitry Andric       DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), CB.getValue(0)));
27365f757f3fSDimitry Andric }
27375f757f3fSDimitry Andric 
27385f757f3fSDimitry Andric static void
27395f757f3fSDimitry Andric replaceINTRINSIC_WO_CHAINResults(SDNode *N, SmallVectorImpl<SDValue> &Results,
27405f757f3fSDimitry Andric                                  SelectionDAG &DAG,
27415f757f3fSDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
27425f757f3fSDimitry Andric   switch (N->getConstantOperandVal(0)) {
27435f757f3fSDimitry Andric   default:
27445f757f3fSDimitry Andric     llvm_unreachable("Unexpected Intrinsic.");
27455f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_b:
27465f757f3fSDimitry Andric     replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
27475f757f3fSDimitry Andric                                 LoongArchISD::VPICK_SEXT_ELT);
27485f757f3fSDimitry Andric     break;
27495f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_h:
27505f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve2gr_w:
27515f757f3fSDimitry Andric     replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
27525f757f3fSDimitry Andric                                 LoongArchISD::VPICK_SEXT_ELT);
27535f757f3fSDimitry Andric     break;
27545f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_w:
27555f757f3fSDimitry Andric     replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
27565f757f3fSDimitry Andric                                 LoongArchISD::VPICK_SEXT_ELT);
27575f757f3fSDimitry Andric     break;
27585f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_bu:
27595f757f3fSDimitry Andric     replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
27605f757f3fSDimitry Andric                                 LoongArchISD::VPICK_ZEXT_ELT);
27615f757f3fSDimitry Andric     break;
27625f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_hu:
27635f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
27645f757f3fSDimitry Andric     replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
27655f757f3fSDimitry Andric                                 LoongArchISD::VPICK_ZEXT_ELT);
27665f757f3fSDimitry Andric     break;
27675f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpickve2gr_wu:
27685f757f3fSDimitry Andric     replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
27695f757f3fSDimitry Andric                                 LoongArchISD::VPICK_ZEXT_ELT);
27705f757f3fSDimitry Andric     break;
27715f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bz_b:
27725f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bz_h:
27735f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bz_w:
27745f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bz_d:
27755f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbz_b:
27765f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbz_h:
27775f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbz_w:
27785f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbz_d:
27795f757f3fSDimitry Andric     replaceVecCondBranchResults(N, Results, DAG, Subtarget,
27805f757f3fSDimitry Andric                                 LoongArchISD::VALL_ZERO);
27815f757f3fSDimitry Andric     break;
27825f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bz_v:
27835f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbz_v:
27845f757f3fSDimitry Andric     replaceVecCondBranchResults(N, Results, DAG, Subtarget,
27855f757f3fSDimitry Andric                                 LoongArchISD::VANY_ZERO);
27865f757f3fSDimitry Andric     break;
27875f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bnz_b:
27885f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bnz_h:
27895f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bnz_w:
27905f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bnz_d:
27915f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbnz_b:
27925f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbnz_h:
27935f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbnz_w:
27945f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbnz_d:
27955f757f3fSDimitry Andric     replaceVecCondBranchResults(N, Results, DAG, Subtarget,
27965f757f3fSDimitry Andric                                 LoongArchISD::VALL_NONZERO);
27975f757f3fSDimitry Andric     break;
27985f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_bnz_v:
27995f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xbnz_v:
28005f757f3fSDimitry Andric     replaceVecCondBranchResults(N, Results, DAG, Subtarget,
28015f757f3fSDimitry Andric                                 LoongArchISD::VANY_NONZERO);
28025f757f3fSDimitry Andric     break;
28035f757f3fSDimitry Andric   }
28045f757f3fSDimitry Andric }
28055f757f3fSDimitry Andric 
280681ad6265SDimitry Andric void LoongArchTargetLowering::ReplaceNodeResults(
280781ad6265SDimitry Andric     SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
280881ad6265SDimitry Andric   SDLoc DL(N);
2809bdd1243dSDimitry Andric   EVT VT = N->getValueType(0);
281081ad6265SDimitry Andric   switch (N->getOpcode()) {
281181ad6265SDimitry Andric   default:
281281ad6265SDimitry Andric     llvm_unreachable("Don't know how to legalize this operation");
2813*0fca6ea1SDimitry Andric   case ISD::ADD:
2814*0fca6ea1SDimitry Andric   case ISD::SUB:
2815*0fca6ea1SDimitry Andric     assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
2816*0fca6ea1SDimitry Andric            "Unexpected custom legalisation");
2817*0fca6ea1SDimitry Andric     Results.push_back(customLegalizeToWOpWithSExt(N, DAG));
2818*0fca6ea1SDimitry Andric     break;
2819*0fca6ea1SDimitry Andric   case ISD::UDIV:
2820*0fca6ea1SDimitry Andric   case ISD::UREM:
2821*0fca6ea1SDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
2822*0fca6ea1SDimitry Andric            "Unexpected custom legalisation");
2823*0fca6ea1SDimitry Andric     Results.push_back(customLegalizeToWOp(N, DAG, 2, ISD::SIGN_EXTEND));
2824*0fca6ea1SDimitry Andric     break;
282581ad6265SDimitry Andric   case ISD::SHL:
282681ad6265SDimitry Andric   case ISD::SRA:
282781ad6265SDimitry Andric   case ISD::SRL:
2828bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
282981ad6265SDimitry Andric            "Unexpected custom legalisation");
283081ad6265SDimitry Andric     if (N->getOperand(1).getOpcode() != ISD::Constant) {
2831bdd1243dSDimitry Andric       Results.push_back(customLegalizeToWOp(N, DAG, 2));
2832bdd1243dSDimitry Andric       break;
2833bdd1243dSDimitry Andric     }
2834bdd1243dSDimitry Andric     break;
2835bdd1243dSDimitry Andric   case ISD::ROTL:
2836*0fca6ea1SDimitry Andric   case ISD::ROTR:
2837*0fca6ea1SDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
2838*0fca6ea1SDimitry Andric            "Unexpected custom legalisation");
2839bdd1243dSDimitry Andric     Results.push_back(customLegalizeToWOp(N, DAG, 2));
284081ad6265SDimitry Andric     break;
2841753f127fSDimitry Andric   case ISD::FP_TO_SINT: {
2842bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
2843753f127fSDimitry Andric            "Unexpected custom legalisation");
2844753f127fSDimitry Andric     SDValue Src = N->getOperand(0);
2845bdd1243dSDimitry Andric     EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
2846bdd1243dSDimitry Andric     if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
2847bdd1243dSDimitry Andric         TargetLowering::TypeSoftenFloat) {
2848bdd1243dSDimitry Andric       SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
2849bdd1243dSDimitry Andric       Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
2850bdd1243dSDimitry Andric       return;
2851bdd1243dSDimitry Andric     }
2852bdd1243dSDimitry Andric     // If the FP type needs to be softened, emit a library call using the 'si'
2853bdd1243dSDimitry Andric     // version. If we left it to default legalization we'd end up with 'di'.
2854bdd1243dSDimitry Andric     RTLIB::Libcall LC;
2855bdd1243dSDimitry Andric     LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
2856bdd1243dSDimitry Andric     MakeLibCallOptions CallOptions;
2857bdd1243dSDimitry Andric     EVT OpVT = Src.getValueType();
2858bdd1243dSDimitry Andric     CallOptions.setTypeListBeforeSoften(OpVT, VT, true);
2859bdd1243dSDimitry Andric     SDValue Chain = SDValue();
2860bdd1243dSDimitry Andric     SDValue Result;
2861bdd1243dSDimitry Andric     std::tie(Result, Chain) =
2862bdd1243dSDimitry Andric         makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
2863bdd1243dSDimitry Andric     Results.push_back(Result);
2864753f127fSDimitry Andric     break;
2865753f127fSDimitry Andric   }
2866753f127fSDimitry Andric   case ISD::BITCAST: {
2867753f127fSDimitry Andric     SDValue Src = N->getOperand(0);
2868753f127fSDimitry Andric     EVT SrcVT = Src.getValueType();
2869753f127fSDimitry Andric     if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
2870753f127fSDimitry Andric         Subtarget.hasBasicF()) {
2871753f127fSDimitry Andric       SDValue Dst =
2872753f127fSDimitry Andric           DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
2873753f127fSDimitry Andric       Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
2874753f127fSDimitry Andric     }
2875753f127fSDimitry Andric     break;
2876753f127fSDimitry Andric   }
2877753f127fSDimitry Andric   case ISD::FP_TO_UINT: {
2878bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
2879753f127fSDimitry Andric            "Unexpected custom legalisation");
2880753f127fSDimitry Andric     auto &TLI = DAG.getTargetLoweringInfo();
2881753f127fSDimitry Andric     SDValue Tmp1, Tmp2;
2882753f127fSDimitry Andric     TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
2883753f127fSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
2884753f127fSDimitry Andric     break;
2885753f127fSDimitry Andric   }
2886bdd1243dSDimitry Andric   case ISD::BSWAP: {
2887bdd1243dSDimitry Andric     SDValue Src = N->getOperand(0);
2888bdd1243dSDimitry Andric     assert((VT == MVT::i16 || VT == MVT::i32) &&
2889bdd1243dSDimitry Andric            "Unexpected custom legalization");
2890bdd1243dSDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
2891bdd1243dSDimitry Andric     SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
2892bdd1243dSDimitry Andric     SDValue Tmp;
2893bdd1243dSDimitry Andric     switch (VT.getSizeInBits()) {
2894bdd1243dSDimitry Andric     default:
2895bdd1243dSDimitry Andric       llvm_unreachable("Unexpected operand width");
2896bdd1243dSDimitry Andric     case 16:
2897bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
2898bdd1243dSDimitry Andric       break;
2899bdd1243dSDimitry Andric     case 32:
2900bdd1243dSDimitry Andric       // Only LA64 will get to here due to the size mismatch between VT and
2901bdd1243dSDimitry Andric       // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
2902bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
2903bdd1243dSDimitry Andric       break;
2904bdd1243dSDimitry Andric     }
2905bdd1243dSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
2906bdd1243dSDimitry Andric     break;
2907bdd1243dSDimitry Andric   }
2908bdd1243dSDimitry Andric   case ISD::BITREVERSE: {
2909bdd1243dSDimitry Andric     SDValue Src = N->getOperand(0);
2910bdd1243dSDimitry Andric     assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
2911bdd1243dSDimitry Andric            "Unexpected custom legalization");
2912bdd1243dSDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
2913bdd1243dSDimitry Andric     SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
2914bdd1243dSDimitry Andric     SDValue Tmp;
2915bdd1243dSDimitry Andric     switch (VT.getSizeInBits()) {
2916bdd1243dSDimitry Andric     default:
2917bdd1243dSDimitry Andric       llvm_unreachable("Unexpected operand width");
2918bdd1243dSDimitry Andric     case 8:
2919bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
2920bdd1243dSDimitry Andric       break;
2921bdd1243dSDimitry Andric     case 32:
2922bdd1243dSDimitry Andric       Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
2923bdd1243dSDimitry Andric       break;
2924bdd1243dSDimitry Andric     }
2925bdd1243dSDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
2926bdd1243dSDimitry Andric     break;
2927bdd1243dSDimitry Andric   }
2928bdd1243dSDimitry Andric   case ISD::CTLZ:
2929bdd1243dSDimitry Andric   case ISD::CTTZ: {
2930bdd1243dSDimitry Andric     assert(VT == MVT::i32 && Subtarget.is64Bit() &&
2931bdd1243dSDimitry Andric            "Unexpected custom legalisation");
2932bdd1243dSDimitry Andric     Results.push_back(customLegalizeToWOp(N, DAG, 1));
2933bdd1243dSDimitry Andric     break;
2934bdd1243dSDimitry Andric   }
2935bdd1243dSDimitry Andric   case ISD::INTRINSIC_W_CHAIN: {
293606c3fb27SDimitry Andric     SDValue Chain = N->getOperand(0);
2937bdd1243dSDimitry Andric     SDValue Op2 = N->getOperand(2);
293806c3fb27SDimitry Andric     MVT GRLenVT = Subtarget.getGRLenVT();
293906c3fb27SDimitry Andric     const StringRef ErrorMsgOOR = "argument out of range";
294006c3fb27SDimitry Andric     const StringRef ErrorMsgReqLA64 = "requires loongarch64";
294106c3fb27SDimitry Andric     const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
2942bdd1243dSDimitry Andric 
294306c3fb27SDimitry Andric     switch (N->getConstantOperandVal(1)) {
2944bdd1243dSDimitry Andric     default:
2945bdd1243dSDimitry Andric       llvm_unreachable("Unexpected Intrinsic.");
294606c3fb27SDimitry Andric     case Intrinsic::loongarch_movfcsr2gr: {
294706c3fb27SDimitry Andric       if (!Subtarget.hasBasicF()) {
29485f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqF);
294906c3fb27SDimitry Andric         return;
295006c3fb27SDimitry Andric       }
29511db9f3b2SDimitry Andric       unsigned Imm = Op2->getAsZExtVal();
295206c3fb27SDimitry Andric       if (!isUInt<2>(Imm)) {
29535f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
295406c3fb27SDimitry Andric         return;
295506c3fb27SDimitry Andric       }
295606c3fb27SDimitry Andric       SDValue MOVFCSR2GRResults = DAG.getNode(
295706c3fb27SDimitry Andric           LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other},
295806c3fb27SDimitry Andric           {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
295906c3fb27SDimitry Andric       Results.push_back(
296006c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0)));
296106c3fb27SDimitry Andric       Results.push_back(MOVFCSR2GRResults.getValue(1));
296206c3fb27SDimitry Andric       break;
296306c3fb27SDimitry Andric     }
2964bdd1243dSDimitry Andric #define CRC_CASE_EXT_BINARYOP(NAME, NODE)                                      \
2965bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
296606c3fb27SDimitry Andric     SDValue NODE = DAG.getNode(                                                \
296706c3fb27SDimitry Andric         LoongArchISD::NODE, DL, {MVT::i64, MVT::Other},                        \
296806c3fb27SDimitry Andric         {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),               \
296906c3fb27SDimitry Andric          DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))});       \
297006c3fb27SDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0)));   \
297106c3fb27SDimitry Andric     Results.push_back(NODE.getValue(1));                                       \
2972bdd1243dSDimitry Andric     break;                                                                     \
2973bdd1243dSDimitry Andric   }
2974bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
2975bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
2976bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
2977bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
2978bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
2979bdd1243dSDimitry Andric       CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
2980bdd1243dSDimitry Andric #undef CRC_CASE_EXT_BINARYOP
2981bdd1243dSDimitry Andric 
2982bdd1243dSDimitry Andric #define CRC_CASE_EXT_UNARYOP(NAME, NODE)                                       \
2983bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
298406c3fb27SDimitry Andric     SDValue NODE = DAG.getNode(                                                \
298506c3fb27SDimitry Andric         LoongArchISD::NODE, DL, {MVT::i64, MVT::Other},                        \
298606c3fb27SDimitry Andric         {Chain, Op2,                                                           \
298706c3fb27SDimitry Andric          DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))});       \
298806c3fb27SDimitry Andric     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0)));   \
298906c3fb27SDimitry Andric     Results.push_back(NODE.getValue(1));                                       \
2990bdd1243dSDimitry Andric     break;                                                                     \
2991bdd1243dSDimitry Andric   }
2992bdd1243dSDimitry Andric       CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
2993bdd1243dSDimitry Andric       CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
2994bdd1243dSDimitry Andric #undef CRC_CASE_EXT_UNARYOP
2995bdd1243dSDimitry Andric #define CSR_CASE(ID)                                                           \
2996bdd1243dSDimitry Andric   case Intrinsic::loongarch_##ID: {                                            \
299706c3fb27SDimitry Andric     if (!Subtarget.is64Bit())                                                  \
29985f757f3fSDimitry Andric       emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64);   \
2999bdd1243dSDimitry Andric     break;                                                                     \
3000bdd1243dSDimitry Andric   }
3001bdd1243dSDimitry Andric       CSR_CASE(csrrd_d);
3002bdd1243dSDimitry Andric       CSR_CASE(csrwr_d);
3003bdd1243dSDimitry Andric       CSR_CASE(csrxchg_d);
3004bdd1243dSDimitry Andric       CSR_CASE(iocsrrd_d);
3005bdd1243dSDimitry Andric #undef CSR_CASE
3006bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrrd_w: {
30071db9f3b2SDimitry Andric       unsigned Imm = Op2->getAsZExtVal();
3008bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
30095f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
301006c3fb27SDimitry Andric         return;
3011bdd1243dSDimitry Andric       }
301206c3fb27SDimitry Andric       SDValue CSRRDResults =
301306c3fb27SDimitry Andric           DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
301406c3fb27SDimitry Andric                       {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
3015bdd1243dSDimitry Andric       Results.push_back(
301606c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0)));
301706c3fb27SDimitry Andric       Results.push_back(CSRRDResults.getValue(1));
3018bdd1243dSDimitry Andric       break;
3019bdd1243dSDimitry Andric     }
3020bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrwr_w: {
3021647cbc5dSDimitry Andric       unsigned Imm = N->getConstantOperandVal(3);
3022bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
30235f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
302406c3fb27SDimitry Andric         return;
3025bdd1243dSDimitry Andric       }
302606c3fb27SDimitry Andric       SDValue CSRWRResults =
302706c3fb27SDimitry Andric           DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
302806c3fb27SDimitry Andric                       {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
302906c3fb27SDimitry Andric                        DAG.getConstant(Imm, DL, GRLenVT)});
303006c3fb27SDimitry Andric       Results.push_back(
303106c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0)));
303206c3fb27SDimitry Andric       Results.push_back(CSRWRResults.getValue(1));
3033bdd1243dSDimitry Andric       break;
3034bdd1243dSDimitry Andric     }
3035bdd1243dSDimitry Andric     case Intrinsic::loongarch_csrxchg_w: {
3036647cbc5dSDimitry Andric       unsigned Imm = N->getConstantOperandVal(4);
3037bdd1243dSDimitry Andric       if (!isUInt<14>(Imm)) {
30385f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
303906c3fb27SDimitry Andric         return;
3040bdd1243dSDimitry Andric       }
304106c3fb27SDimitry Andric       SDValue CSRXCHGResults = DAG.getNode(
304206c3fb27SDimitry Andric           LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
304306c3fb27SDimitry Andric           {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
3044bdd1243dSDimitry Andric            DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
304506c3fb27SDimitry Andric            DAG.getConstant(Imm, DL, GRLenVT)});
304606c3fb27SDimitry Andric       Results.push_back(
304706c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0)));
304806c3fb27SDimitry Andric       Results.push_back(CSRXCHGResults.getValue(1));
3049bdd1243dSDimitry Andric       break;
3050bdd1243dSDimitry Andric     }
3051bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE)                                               \
3052bdd1243dSDimitry Andric   case Intrinsic::loongarch_##NAME: {                                          \
305306c3fb27SDimitry Andric     SDValue IOCSRRDResults =                                                   \
305406c3fb27SDimitry Andric         DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other},            \
305506c3fb27SDimitry Andric                     {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \
305606c3fb27SDimitry Andric     Results.push_back(                                                         \
305706c3fb27SDimitry Andric         DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0)));       \
305806c3fb27SDimitry Andric     Results.push_back(IOCSRRDResults.getValue(1));                             \
3059bdd1243dSDimitry Andric     break;                                                                     \
3060bdd1243dSDimitry Andric   }
3061bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
3062bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
3063bdd1243dSDimitry Andric       IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
3064bdd1243dSDimitry Andric #undef IOCSRRD_CASE
3065bdd1243dSDimitry Andric     case Intrinsic::loongarch_cpucfg: {
306606c3fb27SDimitry Andric       SDValue CPUCFGResults =
306706c3fb27SDimitry Andric           DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
306806c3fb27SDimitry Andric                       {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)});
306906c3fb27SDimitry Andric       Results.push_back(
307006c3fb27SDimitry Andric           DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0)));
307106c3fb27SDimitry Andric       Results.push_back(CPUCFGResults.getValue(1));
3072bdd1243dSDimitry Andric       break;
3073bdd1243dSDimitry Andric     }
3074bdd1243dSDimitry Andric     case Intrinsic::loongarch_lddir_d: {
3075bdd1243dSDimitry Andric       if (!Subtarget.is64Bit()) {
30765f757f3fSDimitry Andric         emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64);
307706c3fb27SDimitry Andric         return;
3078bdd1243dSDimitry Andric       }
3079bdd1243dSDimitry Andric       break;
3080bdd1243dSDimitry Andric     }
3081bdd1243dSDimitry Andric     }
3082bdd1243dSDimitry Andric     break;
3083bdd1243dSDimitry Andric   }
3084bdd1243dSDimitry Andric   case ISD::READ_REGISTER: {
3085bdd1243dSDimitry Andric     if (Subtarget.is64Bit())
3086bdd1243dSDimitry Andric       DAG.getContext()->emitError(
3087bdd1243dSDimitry Andric           "On LA64, only 64-bit registers can be read.");
3088bdd1243dSDimitry Andric     else
3089bdd1243dSDimitry Andric       DAG.getContext()->emitError(
3090bdd1243dSDimitry Andric           "On LA32, only 32-bit registers can be read.");
3091bdd1243dSDimitry Andric     Results.push_back(DAG.getUNDEF(VT));
3092bdd1243dSDimitry Andric     Results.push_back(N->getOperand(0));
3093bdd1243dSDimitry Andric     break;
3094bdd1243dSDimitry Andric   }
30955f757f3fSDimitry Andric   case ISD::INTRINSIC_WO_CHAIN: {
30965f757f3fSDimitry Andric     replaceINTRINSIC_WO_CHAINResults(N, Results, DAG, Subtarget);
30975f757f3fSDimitry Andric     break;
30985f757f3fSDimitry Andric   }
309981ad6265SDimitry Andric   }
310081ad6265SDimitry Andric }
310181ad6265SDimitry Andric 
310281ad6265SDimitry Andric static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG,
310381ad6265SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
310481ad6265SDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
310581ad6265SDimitry Andric   if (DCI.isBeforeLegalizeOps())
310681ad6265SDimitry Andric     return SDValue();
310781ad6265SDimitry Andric 
310881ad6265SDimitry Andric   SDValue FirstOperand = N->getOperand(0);
310981ad6265SDimitry Andric   SDValue SecondOperand = N->getOperand(1);
311081ad6265SDimitry Andric   unsigned FirstOperandOpc = FirstOperand.getOpcode();
311181ad6265SDimitry Andric   EVT ValTy = N->getValueType(0);
311281ad6265SDimitry Andric   SDLoc DL(N);
311381ad6265SDimitry Andric   uint64_t lsb, msb;
311481ad6265SDimitry Andric   unsigned SMIdx, SMLen;
311581ad6265SDimitry Andric   ConstantSDNode *CN;
311681ad6265SDimitry Andric   SDValue NewOperand;
311781ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
311881ad6265SDimitry Andric 
311981ad6265SDimitry Andric   // Op's second operand must be a shifted mask.
312081ad6265SDimitry Andric   if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
312181ad6265SDimitry Andric       !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
312281ad6265SDimitry Andric     return SDValue();
312381ad6265SDimitry Andric 
312481ad6265SDimitry Andric   if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
312581ad6265SDimitry Andric     // Pattern match BSTRPICK.
312681ad6265SDimitry Andric     //  $dst = and ((sra or srl) $src , lsb), (2**len - 1)
312781ad6265SDimitry Andric     //  => BSTRPICK $dst, $src, msb, lsb
312881ad6265SDimitry Andric     //  where msb = lsb + len - 1
312981ad6265SDimitry Andric 
313081ad6265SDimitry Andric     // The second operand of the shift must be an immediate.
313181ad6265SDimitry Andric     if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
313281ad6265SDimitry Andric       return SDValue();
313381ad6265SDimitry Andric 
313481ad6265SDimitry Andric     lsb = CN->getZExtValue();
313581ad6265SDimitry Andric 
313681ad6265SDimitry Andric     // Return if the shifted mask does not start at bit 0 or the sum of its
313781ad6265SDimitry Andric     // length and lsb exceeds the word's size.
313881ad6265SDimitry Andric     if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
313981ad6265SDimitry Andric       return SDValue();
314081ad6265SDimitry Andric 
314181ad6265SDimitry Andric     NewOperand = FirstOperand.getOperand(0);
314281ad6265SDimitry Andric   } else {
314381ad6265SDimitry Andric     // Pattern match BSTRPICK.
314481ad6265SDimitry Andric     //  $dst = and $src, (2**len- 1) , if len > 12
314581ad6265SDimitry Andric     //  => BSTRPICK $dst, $src, msb, lsb
314681ad6265SDimitry Andric     //  where lsb = 0 and msb = len - 1
314781ad6265SDimitry Andric 
314881ad6265SDimitry Andric     // If the mask is <= 0xfff, andi can be used instead.
314981ad6265SDimitry Andric     if (CN->getZExtValue() <= 0xfff)
315081ad6265SDimitry Andric       return SDValue();
315181ad6265SDimitry Andric 
315206c3fb27SDimitry Andric     // Return if the MSB exceeds.
315306c3fb27SDimitry Andric     if (SMIdx + SMLen > ValTy.getSizeInBits())
315481ad6265SDimitry Andric       return SDValue();
315581ad6265SDimitry Andric 
315606c3fb27SDimitry Andric     if (SMIdx > 0) {
315706c3fb27SDimitry Andric       // Omit if the constant has more than 2 uses. This a conservative
315806c3fb27SDimitry Andric       // decision. Whether it is a win depends on the HW microarchitecture.
315906c3fb27SDimitry Andric       // However it should always be better for 1 and 2 uses.
316006c3fb27SDimitry Andric       if (CN->use_size() > 2)
316106c3fb27SDimitry Andric         return SDValue();
316206c3fb27SDimitry Andric       // Return if the constant can be composed by a single LU12I.W.
316306c3fb27SDimitry Andric       if ((CN->getZExtValue() & 0xfff) == 0)
316406c3fb27SDimitry Andric         return SDValue();
316506c3fb27SDimitry Andric       // Return if the constand can be composed by a single ADDI with
316606c3fb27SDimitry Andric       // the zero register.
316706c3fb27SDimitry Andric       if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
316806c3fb27SDimitry Andric         return SDValue();
316906c3fb27SDimitry Andric     }
317006c3fb27SDimitry Andric 
317106c3fb27SDimitry Andric     lsb = SMIdx;
317281ad6265SDimitry Andric     NewOperand = FirstOperand;
317381ad6265SDimitry Andric   }
317406c3fb27SDimitry Andric 
317581ad6265SDimitry Andric   msb = lsb + SMLen - 1;
317606c3fb27SDimitry Andric   SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
317781ad6265SDimitry Andric                             DAG.getConstant(msb, DL, GRLenVT),
317881ad6265SDimitry Andric                             DAG.getConstant(lsb, DL, GRLenVT));
317906c3fb27SDimitry Andric   if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
318006c3fb27SDimitry Andric     return NR0;
318106c3fb27SDimitry Andric   // Try to optimize to
318206c3fb27SDimitry Andric   //   bstrpick $Rd, $Rs, msb, lsb
318306c3fb27SDimitry Andric   //   slli     $Rd, $Rd, lsb
318406c3fb27SDimitry Andric   return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
318506c3fb27SDimitry Andric                      DAG.getConstant(lsb, DL, GRLenVT));
318681ad6265SDimitry Andric }
318781ad6265SDimitry Andric 
318881ad6265SDimitry Andric static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG,
318981ad6265SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
319081ad6265SDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
319181ad6265SDimitry Andric   if (DCI.isBeforeLegalizeOps())
319281ad6265SDimitry Andric     return SDValue();
319381ad6265SDimitry Andric 
319481ad6265SDimitry Andric   // $dst = srl (and $src, Mask), Shamt
319581ad6265SDimitry Andric   // =>
319681ad6265SDimitry Andric   // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
319781ad6265SDimitry Andric   // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
319881ad6265SDimitry Andric   //
319981ad6265SDimitry Andric 
320081ad6265SDimitry Andric   SDValue FirstOperand = N->getOperand(0);
320181ad6265SDimitry Andric   ConstantSDNode *CN;
320281ad6265SDimitry Andric   EVT ValTy = N->getValueType(0);
320381ad6265SDimitry Andric   SDLoc DL(N);
320481ad6265SDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
320581ad6265SDimitry Andric   unsigned MaskIdx, MaskLen;
320681ad6265SDimitry Andric   uint64_t Shamt;
320781ad6265SDimitry Andric 
320881ad6265SDimitry Andric   // The first operand must be an AND and the second operand of the AND must be
320981ad6265SDimitry Andric   // a shifted mask.
321081ad6265SDimitry Andric   if (FirstOperand.getOpcode() != ISD::AND ||
321181ad6265SDimitry Andric       !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
321281ad6265SDimitry Andric       !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
321381ad6265SDimitry Andric     return SDValue();
321481ad6265SDimitry Andric 
321581ad6265SDimitry Andric   // The second operand (shift amount) must be an immediate.
321681ad6265SDimitry Andric   if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
321781ad6265SDimitry Andric     return SDValue();
321881ad6265SDimitry Andric 
321981ad6265SDimitry Andric   Shamt = CN->getZExtValue();
322081ad6265SDimitry Andric   if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
322181ad6265SDimitry Andric     return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
322281ad6265SDimitry Andric                        FirstOperand->getOperand(0),
322381ad6265SDimitry Andric                        DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
322481ad6265SDimitry Andric                        DAG.getConstant(Shamt, DL, GRLenVT));
322581ad6265SDimitry Andric 
322681ad6265SDimitry Andric   return SDValue();
322781ad6265SDimitry Andric }
322881ad6265SDimitry Andric 
3229753f127fSDimitry Andric static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
3230753f127fSDimitry Andric                                 TargetLowering::DAGCombinerInfo &DCI,
3231753f127fSDimitry Andric                                 const LoongArchSubtarget &Subtarget) {
3232753f127fSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
3233753f127fSDimitry Andric   EVT ValTy = N->getValueType(0);
3234753f127fSDimitry Andric   SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
3235753f127fSDimitry Andric   ConstantSDNode *CN0, *CN1;
3236753f127fSDimitry Andric   SDLoc DL(N);
3237753f127fSDimitry Andric   unsigned ValBits = ValTy.getSizeInBits();
3238753f127fSDimitry Andric   unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
3239753f127fSDimitry Andric   unsigned Shamt;
3240753f127fSDimitry Andric   bool SwapAndRetried = false;
3241753f127fSDimitry Andric 
3242753f127fSDimitry Andric   if (DCI.isBeforeLegalizeOps())
3243753f127fSDimitry Andric     return SDValue();
3244753f127fSDimitry Andric 
3245753f127fSDimitry Andric   if (ValBits != 32 && ValBits != 64)
3246753f127fSDimitry Andric     return SDValue();
3247753f127fSDimitry Andric 
3248753f127fSDimitry Andric Retry:
3249753f127fSDimitry Andric   // 1st pattern to match BSTRINS:
3250753f127fSDimitry Andric   //  R = or (and X, mask0), (and (shl Y, lsb), mask1)
3251753f127fSDimitry Andric   //  where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
3252753f127fSDimitry Andric   //  =>
3253753f127fSDimitry Andric   //  R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
3254753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
3255753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
3256753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
3257753f127fSDimitry Andric       N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
3258753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
3259753f127fSDimitry Andric       isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
3260753f127fSDimitry Andric       MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
3261753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
3262753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
3263753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
3264753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
3265753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
3266753f127fSDimitry Andric                        N1.getOperand(0).getOperand(0),
3267753f127fSDimitry Andric                        DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
3268753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
3269753f127fSDimitry Andric   }
3270753f127fSDimitry Andric 
3271753f127fSDimitry Andric   // 2nd pattern to match BSTRINS:
3272753f127fSDimitry Andric   //  R = or (and X, mask0), (shl (and Y, mask1), lsb)
3273753f127fSDimitry Andric   //  where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
3274753f127fSDimitry Andric   //  =>
3275753f127fSDimitry Andric   //  R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
3276753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
3277753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
3278753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
3279753f127fSDimitry Andric       N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
3280753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
3281753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
3282753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
3283753f127fSDimitry Andric       isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
3284753f127fSDimitry Andric       MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
3285753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
3286753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
3287753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
3288753f127fSDimitry Andric                        N1.getOperand(0).getOperand(0),
3289753f127fSDimitry Andric                        DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
3290753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
3291753f127fSDimitry Andric   }
3292753f127fSDimitry Andric 
3293753f127fSDimitry Andric   // 3rd pattern to match BSTRINS:
3294753f127fSDimitry Andric   //  R = or (and X, mask0), (and Y, mask1)
3295753f127fSDimitry Andric   //  where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
3296753f127fSDimitry Andric   //  =>
3297753f127fSDimitry Andric   //  R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
3298753f127fSDimitry Andric   //  where msb = lsb + size - 1
3299753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
3300753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
3301753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
3302753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= 64) &&
3303753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
3304753f127fSDimitry Andric       (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
3305753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
3306753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
3307753f127fSDimitry Andric                        DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
3308753f127fSDimitry Andric                                    DAG.getConstant(MaskIdx0, DL, GRLenVT)),
3309753f127fSDimitry Andric                        DAG.getConstant(ValBits == 32
3310753f127fSDimitry Andric                                            ? (MaskIdx0 + (MaskLen0 & 31) - 1)
3311753f127fSDimitry Andric                                            : (MaskIdx0 + MaskLen0 - 1),
3312753f127fSDimitry Andric                                        DL, GRLenVT),
3313753f127fSDimitry Andric                        DAG.getConstant(MaskIdx0, DL, GRLenVT));
3314753f127fSDimitry Andric   }
3315753f127fSDimitry Andric 
3316753f127fSDimitry Andric   // 4th pattern to match BSTRINS:
3317753f127fSDimitry Andric   //  R = or (and X, mask), (shl Y, shamt)
3318753f127fSDimitry Andric   //  where mask = (2**shamt - 1)
3319753f127fSDimitry Andric   //  =>
3320753f127fSDimitry Andric   //  R = BSTRINS X, Y, ValBits - 1, shamt
3321753f127fSDimitry Andric   //  where ValBits = 32 or 64
3322753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
3323753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
3324753f127fSDimitry Andric       isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
3325753f127fSDimitry Andric       MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
3326753f127fSDimitry Andric       (Shamt = CN1->getZExtValue()) == MaskLen0 &&
3327753f127fSDimitry Andric       (MaskIdx0 + MaskLen0 <= ValBits)) {
3328753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
3329753f127fSDimitry Andric     return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
3330753f127fSDimitry Andric                        N1.getOperand(0),
3331753f127fSDimitry Andric                        DAG.getConstant((ValBits - 1), DL, GRLenVT),
3332753f127fSDimitry Andric                        DAG.getConstant(Shamt, DL, GRLenVT));
3333753f127fSDimitry Andric   }
3334753f127fSDimitry Andric 
3335753f127fSDimitry Andric   // 5th pattern to match BSTRINS:
3336753f127fSDimitry Andric   //  R = or (and X, mask), const
3337753f127fSDimitry Andric   //  where ~mask = (2**size - 1) << lsb, mask & const = 0
3338753f127fSDimitry Andric   //  =>
3339753f127fSDimitry Andric   //  R = BSTRINS X, (const >> lsb), msb, lsb
3340753f127fSDimitry Andric   //  where msb = lsb + size - 1
3341753f127fSDimitry Andric   if (N0.getOpcode() == ISD::AND &&
3342753f127fSDimitry Andric       (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
3343753f127fSDimitry Andric       isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
3344753f127fSDimitry Andric       (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
3345753f127fSDimitry Andric       (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
3346753f127fSDimitry Andric     LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
3347753f127fSDimitry Andric     return DAG.getNode(
3348753f127fSDimitry Andric         LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
3349753f127fSDimitry Andric         DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
3350439352acSDimitry Andric         DAG.getConstant(ValBits == 32 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
3351439352acSDimitry Andric                                       : (MaskIdx0 + MaskLen0 - 1),
3352439352acSDimitry Andric                         DL, GRLenVT),
3353753f127fSDimitry Andric         DAG.getConstant(MaskIdx0, DL, GRLenVT));
3354753f127fSDimitry Andric   }
3355753f127fSDimitry Andric 
3356753f127fSDimitry Andric   // 6th pattern.
3357753f127fSDimitry Andric   // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
3358753f127fSDimitry Andric   // by the incoming bits are known to be zero.
3359753f127fSDimitry Andric   // =>
3360753f127fSDimitry Andric   // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
3361753f127fSDimitry Andric   //
3362753f127fSDimitry Andric   // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
3363753f127fSDimitry Andric   // pattern is more common than the 1st. So we put the 1st before the 6th in
3364753f127fSDimitry Andric   // order to match as many nodes as possible.
3365753f127fSDimitry Andric   ConstantSDNode *CNMask, *CNShamt;
3366753f127fSDimitry Andric   unsigned MaskIdx, MaskLen;
3367753f127fSDimitry Andric   if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
3368753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
3369753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
3370753f127fSDimitry Andric       MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
3371753f127fSDimitry Andric       CNShamt->getZExtValue() + MaskLen <= ValBits) {
3372753f127fSDimitry Andric     Shamt = CNShamt->getZExtValue();
3373753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
3374753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
3375753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
3376753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
3377753f127fSDimitry Andric                          N1.getOperand(0).getOperand(0),
3378753f127fSDimitry Andric                          DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
3379753f127fSDimitry Andric                          DAG.getConstant(Shamt, DL, GRLenVT));
3380753f127fSDimitry Andric     }
3381753f127fSDimitry Andric   }
3382753f127fSDimitry Andric 
3383753f127fSDimitry Andric   // 7th pattern.
3384753f127fSDimitry Andric   // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
3385753f127fSDimitry Andric   // overwritten by the incoming bits are known to be zero.
3386753f127fSDimitry Andric   // =>
3387753f127fSDimitry Andric   // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
3388753f127fSDimitry Andric   //
3389753f127fSDimitry Andric   // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
3390753f127fSDimitry Andric   // before the 7th in order to match as many nodes as possible.
3391753f127fSDimitry Andric   if (N1.getOpcode() == ISD::AND &&
3392753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
3393753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
3394753f127fSDimitry Andric       N1.getOperand(0).getOpcode() == ISD::SHL &&
3395753f127fSDimitry Andric       (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
3396753f127fSDimitry Andric       CNShamt->getZExtValue() == MaskIdx) {
3397753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue());
3398753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
3399753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
3400753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
3401753f127fSDimitry Andric                          N1.getOperand(0).getOperand(0),
3402753f127fSDimitry Andric                          DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
3403753f127fSDimitry Andric                          DAG.getConstant(MaskIdx, DL, GRLenVT));
3404753f127fSDimitry Andric     }
3405753f127fSDimitry Andric   }
3406753f127fSDimitry Andric 
3407753f127fSDimitry Andric   // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
3408753f127fSDimitry Andric   if (!SwapAndRetried) {
3409753f127fSDimitry Andric     std::swap(N0, N1);
3410753f127fSDimitry Andric     SwapAndRetried = true;
3411753f127fSDimitry Andric     goto Retry;
3412753f127fSDimitry Andric   }
3413753f127fSDimitry Andric 
3414753f127fSDimitry Andric   SwapAndRetried = false;
3415753f127fSDimitry Andric Retry2:
3416753f127fSDimitry Andric   // 8th pattern.
3417753f127fSDimitry Andric   // a = b | (c & shifted_mask), where all positions in b to be overwritten by
3418753f127fSDimitry Andric   // the incoming bits are known to be zero.
3419753f127fSDimitry Andric   // =>
3420753f127fSDimitry Andric   // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
3421753f127fSDimitry Andric   //
3422753f127fSDimitry Andric   // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
3423753f127fSDimitry Andric   // we put it here in order to match as many nodes as possible or generate less
3424753f127fSDimitry Andric   // instructions.
3425753f127fSDimitry Andric   if (N1.getOpcode() == ISD::AND &&
3426753f127fSDimitry Andric       (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
3427753f127fSDimitry Andric       isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
3428753f127fSDimitry Andric     APInt ShMask(ValBits, CNMask->getZExtValue());
3429753f127fSDimitry Andric     if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
3430753f127fSDimitry Andric       LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
3431753f127fSDimitry Andric       return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
3432753f127fSDimitry Andric                          DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
3433753f127fSDimitry Andric                                      N1->getOperand(0),
3434753f127fSDimitry Andric                                      DAG.getConstant(MaskIdx, DL, GRLenVT)),
3435753f127fSDimitry Andric                          DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
3436753f127fSDimitry Andric                          DAG.getConstant(MaskIdx, DL, GRLenVT));
3437753f127fSDimitry Andric     }
3438753f127fSDimitry Andric   }
3439753f127fSDimitry Andric   // Swap N0/N1 and retry.
3440753f127fSDimitry Andric   if (!SwapAndRetried) {
3441753f127fSDimitry Andric     std::swap(N0, N1);
3442753f127fSDimitry Andric     SwapAndRetried = true;
3443753f127fSDimitry Andric     goto Retry2;
3444753f127fSDimitry Andric   }
3445753f127fSDimitry Andric 
3446753f127fSDimitry Andric   return SDValue();
3447753f127fSDimitry Andric }
3448753f127fSDimitry Andric 
3449*0fca6ea1SDimitry Andric static bool checkValueWidth(SDValue V, ISD::LoadExtType &ExtType) {
3450*0fca6ea1SDimitry Andric   ExtType = ISD::NON_EXTLOAD;
3451*0fca6ea1SDimitry Andric 
3452*0fca6ea1SDimitry Andric   switch (V.getNode()->getOpcode()) {
3453*0fca6ea1SDimitry Andric   case ISD::LOAD: {
3454*0fca6ea1SDimitry Andric     LoadSDNode *LoadNode = cast<LoadSDNode>(V.getNode());
3455*0fca6ea1SDimitry Andric     if ((LoadNode->getMemoryVT() == MVT::i8) ||
3456*0fca6ea1SDimitry Andric         (LoadNode->getMemoryVT() == MVT::i16)) {
3457*0fca6ea1SDimitry Andric       ExtType = LoadNode->getExtensionType();
3458*0fca6ea1SDimitry Andric       return true;
3459*0fca6ea1SDimitry Andric     }
3460*0fca6ea1SDimitry Andric     return false;
3461*0fca6ea1SDimitry Andric   }
3462*0fca6ea1SDimitry Andric   case ISD::AssertSext: {
3463*0fca6ea1SDimitry Andric     VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
3464*0fca6ea1SDimitry Andric     if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
3465*0fca6ea1SDimitry Andric       ExtType = ISD::SEXTLOAD;
3466*0fca6ea1SDimitry Andric       return true;
3467*0fca6ea1SDimitry Andric     }
3468*0fca6ea1SDimitry Andric     return false;
3469*0fca6ea1SDimitry Andric   }
3470*0fca6ea1SDimitry Andric   case ISD::AssertZext: {
3471*0fca6ea1SDimitry Andric     VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
3472*0fca6ea1SDimitry Andric     if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
3473*0fca6ea1SDimitry Andric       ExtType = ISD::ZEXTLOAD;
3474*0fca6ea1SDimitry Andric       return true;
3475*0fca6ea1SDimitry Andric     }
3476*0fca6ea1SDimitry Andric     return false;
3477*0fca6ea1SDimitry Andric   }
3478*0fca6ea1SDimitry Andric   default:
3479*0fca6ea1SDimitry Andric     return false;
3480*0fca6ea1SDimitry Andric   }
3481*0fca6ea1SDimitry Andric 
3482*0fca6ea1SDimitry Andric   return false;
3483*0fca6ea1SDimitry Andric }
3484*0fca6ea1SDimitry Andric 
3485*0fca6ea1SDimitry Andric // Eliminate redundant truncation and zero-extension nodes.
3486*0fca6ea1SDimitry Andric // * Case 1:
3487*0fca6ea1SDimitry Andric //  +------------+ +------------+ +------------+
3488*0fca6ea1SDimitry Andric //  |   Input1   | |   Input2   | |     CC     |
3489*0fca6ea1SDimitry Andric //  +------------+ +------------+ +------------+
3490*0fca6ea1SDimitry Andric //         |              |              |
3491*0fca6ea1SDimitry Andric //         V              V              +----+
3492*0fca6ea1SDimitry Andric //  +------------+ +------------+             |
3493*0fca6ea1SDimitry Andric //  |  TRUNCATE  | |  TRUNCATE  |             |
3494*0fca6ea1SDimitry Andric //  +------------+ +------------+             |
3495*0fca6ea1SDimitry Andric //         |              |                   |
3496*0fca6ea1SDimitry Andric //         V              V                   |
3497*0fca6ea1SDimitry Andric //  +------------+ +------------+             |
3498*0fca6ea1SDimitry Andric //  |  ZERO_EXT  | |  ZERO_EXT  |             |
3499*0fca6ea1SDimitry Andric //  +------------+ +------------+             |
3500*0fca6ea1SDimitry Andric //         |              |                   |
3501*0fca6ea1SDimitry Andric //         |              +-------------+     |
3502*0fca6ea1SDimitry Andric //         V              V             |     |
3503*0fca6ea1SDimitry Andric //        +----------------+            |     |
3504*0fca6ea1SDimitry Andric //        |      AND       |            |     |
3505*0fca6ea1SDimitry Andric //        +----------------+            |     |
3506*0fca6ea1SDimitry Andric //                |                     |     |
3507*0fca6ea1SDimitry Andric //                +---------------+     |     |
3508*0fca6ea1SDimitry Andric //                                |     |     |
3509*0fca6ea1SDimitry Andric //                                V     V     V
3510*0fca6ea1SDimitry Andric //                               +-------------+
3511*0fca6ea1SDimitry Andric //                               |     CMP     |
3512*0fca6ea1SDimitry Andric //                               +-------------+
3513*0fca6ea1SDimitry Andric // * Case 2:
3514*0fca6ea1SDimitry Andric //  +------------+ +------------+ +-------------+ +------------+ +------------+
3515*0fca6ea1SDimitry Andric //  |   Input1   | |   Input2   | | Constant -1 | | Constant 0 | |     CC     |
3516*0fca6ea1SDimitry Andric //  +------------+ +------------+ +-------------+ +------------+ +------------+
3517*0fca6ea1SDimitry Andric //         |              |             |               |               |
3518*0fca6ea1SDimitry Andric //         V              |             |               |               |
3519*0fca6ea1SDimitry Andric //  +------------+        |             |               |               |
3520*0fca6ea1SDimitry Andric //  |     XOR    |<---------------------+               |               |
3521*0fca6ea1SDimitry Andric //  +------------+        |                             |               |
3522*0fca6ea1SDimitry Andric //         |              |                             |               |
3523*0fca6ea1SDimitry Andric //         V              V             +---------------+               |
3524*0fca6ea1SDimitry Andric //  +------------+ +------------+       |                               |
3525*0fca6ea1SDimitry Andric //  |  TRUNCATE  | |  TRUNCATE  |       |     +-------------------------+
3526*0fca6ea1SDimitry Andric //  +------------+ +------------+       |     |
3527*0fca6ea1SDimitry Andric //         |              |             |     |
3528*0fca6ea1SDimitry Andric //         V              V             |     |
3529*0fca6ea1SDimitry Andric //  +------------+ +------------+       |     |
3530*0fca6ea1SDimitry Andric //  |  ZERO_EXT  | |  ZERO_EXT  |       |     |
3531*0fca6ea1SDimitry Andric //  +------------+ +------------+       |     |
3532*0fca6ea1SDimitry Andric //         |              |             |     |
3533*0fca6ea1SDimitry Andric //         V              V             |     |
3534*0fca6ea1SDimitry Andric //        +----------------+            |     |
3535*0fca6ea1SDimitry Andric //        |      AND       |            |     |
3536*0fca6ea1SDimitry Andric //        +----------------+            |     |
3537*0fca6ea1SDimitry Andric //                |                     |     |
3538*0fca6ea1SDimitry Andric //                +---------------+     |     |
3539*0fca6ea1SDimitry Andric //                                |     |     |
3540*0fca6ea1SDimitry Andric //                                V     V     V
3541*0fca6ea1SDimitry Andric //                               +-------------+
3542*0fca6ea1SDimitry Andric //                               |     CMP     |
3543*0fca6ea1SDimitry Andric //                               +-------------+
3544*0fca6ea1SDimitry Andric static SDValue performSETCCCombine(SDNode *N, SelectionDAG &DAG,
3545*0fca6ea1SDimitry Andric                                    TargetLowering::DAGCombinerInfo &DCI,
3546*0fca6ea1SDimitry Andric                                    const LoongArchSubtarget &Subtarget) {
3547*0fca6ea1SDimitry Andric   ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
3548*0fca6ea1SDimitry Andric 
3549*0fca6ea1SDimitry Andric   SDNode *AndNode = N->getOperand(0).getNode();
3550*0fca6ea1SDimitry Andric   if (AndNode->getOpcode() != ISD::AND)
3551*0fca6ea1SDimitry Andric     return SDValue();
3552*0fca6ea1SDimitry Andric 
3553*0fca6ea1SDimitry Andric   SDValue AndInputValue2 = AndNode->getOperand(1);
3554*0fca6ea1SDimitry Andric   if (AndInputValue2.getOpcode() != ISD::ZERO_EXTEND)
3555*0fca6ea1SDimitry Andric     return SDValue();
3556*0fca6ea1SDimitry Andric 
3557*0fca6ea1SDimitry Andric   SDValue CmpInputValue = N->getOperand(1);
3558*0fca6ea1SDimitry Andric   SDValue AndInputValue1 = AndNode->getOperand(0);
3559*0fca6ea1SDimitry Andric   if (AndInputValue1.getOpcode() == ISD::XOR) {
3560*0fca6ea1SDimitry Andric     if (CC != ISD::SETEQ && CC != ISD::SETNE)
3561*0fca6ea1SDimitry Andric       return SDValue();
3562*0fca6ea1SDimitry Andric     ConstantSDNode *CN = dyn_cast<ConstantSDNode>(AndInputValue1.getOperand(1));
3563*0fca6ea1SDimitry Andric     if (!CN || CN->getSExtValue() != -1)
3564*0fca6ea1SDimitry Andric       return SDValue();
3565*0fca6ea1SDimitry Andric     CN = dyn_cast<ConstantSDNode>(CmpInputValue);
3566*0fca6ea1SDimitry Andric     if (!CN || CN->getSExtValue() != 0)
3567*0fca6ea1SDimitry Andric       return SDValue();
3568*0fca6ea1SDimitry Andric     AndInputValue1 = AndInputValue1.getOperand(0);
3569*0fca6ea1SDimitry Andric     if (AndInputValue1.getOpcode() != ISD::ZERO_EXTEND)
3570*0fca6ea1SDimitry Andric       return SDValue();
3571*0fca6ea1SDimitry Andric   } else if (AndInputValue1.getOpcode() == ISD::ZERO_EXTEND) {
3572*0fca6ea1SDimitry Andric     if (AndInputValue2 != CmpInputValue)
3573*0fca6ea1SDimitry Andric       return SDValue();
3574*0fca6ea1SDimitry Andric   } else {
3575*0fca6ea1SDimitry Andric     return SDValue();
3576*0fca6ea1SDimitry Andric   }
3577*0fca6ea1SDimitry Andric 
3578*0fca6ea1SDimitry Andric   SDValue TruncValue1 = AndInputValue1.getNode()->getOperand(0);
3579*0fca6ea1SDimitry Andric   if (TruncValue1.getOpcode() != ISD::TRUNCATE)
3580*0fca6ea1SDimitry Andric     return SDValue();
3581*0fca6ea1SDimitry Andric 
3582*0fca6ea1SDimitry Andric   SDValue TruncValue2 = AndInputValue2.getNode()->getOperand(0);
3583*0fca6ea1SDimitry Andric   if (TruncValue2.getOpcode() != ISD::TRUNCATE)
3584*0fca6ea1SDimitry Andric     return SDValue();
3585*0fca6ea1SDimitry Andric 
3586*0fca6ea1SDimitry Andric   SDValue TruncInputValue1 = TruncValue1.getNode()->getOperand(0);
3587*0fca6ea1SDimitry Andric   SDValue TruncInputValue2 = TruncValue2.getNode()->getOperand(0);
3588*0fca6ea1SDimitry Andric   ISD::LoadExtType ExtType1;
3589*0fca6ea1SDimitry Andric   ISD::LoadExtType ExtType2;
3590*0fca6ea1SDimitry Andric 
3591*0fca6ea1SDimitry Andric   if (!checkValueWidth(TruncInputValue1, ExtType1) ||
3592*0fca6ea1SDimitry Andric       !checkValueWidth(TruncInputValue2, ExtType2))
3593*0fca6ea1SDimitry Andric     return SDValue();
3594*0fca6ea1SDimitry Andric 
3595*0fca6ea1SDimitry Andric   if (TruncInputValue1->getValueType(0) != TruncInputValue2->getValueType(0) ||
3596*0fca6ea1SDimitry Andric       AndNode->getValueType(0) != TruncInputValue1->getValueType(0))
3597*0fca6ea1SDimitry Andric     return SDValue();
3598*0fca6ea1SDimitry Andric 
3599*0fca6ea1SDimitry Andric   if ((ExtType2 != ISD::ZEXTLOAD) &&
3600*0fca6ea1SDimitry Andric       ((ExtType2 != ISD::SEXTLOAD) && (ExtType1 != ISD::SEXTLOAD)))
3601*0fca6ea1SDimitry Andric     return SDValue();
3602*0fca6ea1SDimitry Andric 
3603*0fca6ea1SDimitry Andric   // These truncation and zero-extension nodes are not necessary, remove them.
3604*0fca6ea1SDimitry Andric   SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N), AndNode->getValueType(0),
3605*0fca6ea1SDimitry Andric                                TruncInputValue1, TruncInputValue2);
3606*0fca6ea1SDimitry Andric   SDValue NewSetCC =
3607*0fca6ea1SDimitry Andric       DAG.getSetCC(SDLoc(N), N->getValueType(0), NewAnd, TruncInputValue2, CC);
3608*0fca6ea1SDimitry Andric   DAG.ReplaceAllUsesWith(N, NewSetCC.getNode());
3609*0fca6ea1SDimitry Andric   return SDValue(N, 0);
3610*0fca6ea1SDimitry Andric }
3611*0fca6ea1SDimitry Andric 
3612bdd1243dSDimitry Andric // Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
3613bdd1243dSDimitry Andric static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG,
3614bdd1243dSDimitry Andric                                       TargetLowering::DAGCombinerInfo &DCI,
3615bdd1243dSDimitry Andric                                       const LoongArchSubtarget &Subtarget) {
3616bdd1243dSDimitry Andric   if (DCI.isBeforeLegalizeOps())
3617bdd1243dSDimitry Andric     return SDValue();
3618bdd1243dSDimitry Andric 
3619bdd1243dSDimitry Andric   SDValue Src = N->getOperand(0);
3620bdd1243dSDimitry Andric   if (Src.getOpcode() != LoongArchISD::REVB_2W)
3621bdd1243dSDimitry Andric     return SDValue();
3622bdd1243dSDimitry Andric 
3623bdd1243dSDimitry Andric   return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
3624bdd1243dSDimitry Andric                      Src.getOperand(0));
3625bdd1243dSDimitry Andric }
3626bdd1243dSDimitry Andric 
36275f757f3fSDimitry Andric template <unsigned N>
36285f757f3fSDimitry Andric static SDValue legalizeIntrinsicImmArg(SDNode *Node, unsigned ImmOp,
36295f757f3fSDimitry Andric                                        SelectionDAG &DAG,
36305f757f3fSDimitry Andric                                        const LoongArchSubtarget &Subtarget,
36315f757f3fSDimitry Andric                                        bool IsSigned = false) {
36325f757f3fSDimitry Andric   SDLoc DL(Node);
36335f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
36345f757f3fSDimitry Andric   // Check the ImmArg.
36355f757f3fSDimitry Andric   if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
36365f757f3fSDimitry Andric       (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
36375f757f3fSDimitry Andric     DAG.getContext()->emitError(Node->getOperationName(0) +
36385f757f3fSDimitry Andric                                 ": argument out of range.");
36395f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, DL, Subtarget.getGRLenVT());
36405f757f3fSDimitry Andric   }
36415f757f3fSDimitry Andric   return DAG.getConstant(CImm->getZExtValue(), DL, Subtarget.getGRLenVT());
36425f757f3fSDimitry Andric }
36435f757f3fSDimitry Andric 
36445f757f3fSDimitry Andric template <unsigned N>
36455f757f3fSDimitry Andric static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp,
36465f757f3fSDimitry Andric                                    SelectionDAG &DAG, bool IsSigned = false) {
36475f757f3fSDimitry Andric   SDLoc DL(Node);
36485f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
36495f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
36505f757f3fSDimitry Andric 
36515f757f3fSDimitry Andric   // Check the ImmArg.
36525f757f3fSDimitry Andric   if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
36535f757f3fSDimitry Andric       (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
36545f757f3fSDimitry Andric     DAG.getContext()->emitError(Node->getOperationName(0) +
36555f757f3fSDimitry Andric                                 ": argument out of range.");
36565f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, DL, ResTy);
36575f757f3fSDimitry Andric   }
36585f757f3fSDimitry Andric   return DAG.getConstant(
36595f757f3fSDimitry Andric       APInt(ResTy.getScalarType().getSizeInBits(),
36605f757f3fSDimitry Andric             IsSigned ? CImm->getSExtValue() : CImm->getZExtValue(), IsSigned),
36615f757f3fSDimitry Andric       DL, ResTy);
36625f757f3fSDimitry Andric }
36635f757f3fSDimitry Andric 
36645f757f3fSDimitry Andric static SDValue truncateVecElts(SDNode *Node, SelectionDAG &DAG) {
36655f757f3fSDimitry Andric   SDLoc DL(Node);
36665f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
36675f757f3fSDimitry Andric   SDValue Vec = Node->getOperand(2);
36685f757f3fSDimitry Andric   SDValue Mask = DAG.getConstant(Vec.getScalarValueSizeInBits() - 1, DL, ResTy);
36695f757f3fSDimitry Andric   return DAG.getNode(ISD::AND, DL, ResTy, Vec, Mask);
36705f757f3fSDimitry Andric }
36715f757f3fSDimitry Andric 
36725f757f3fSDimitry Andric static SDValue lowerVectorBitClear(SDNode *Node, SelectionDAG &DAG) {
36735f757f3fSDimitry Andric   SDLoc DL(Node);
36745f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
36755f757f3fSDimitry Andric   SDValue One = DAG.getConstant(1, DL, ResTy);
36765f757f3fSDimitry Andric   SDValue Bit =
36775f757f3fSDimitry Andric       DAG.getNode(ISD::SHL, DL, ResTy, One, truncateVecElts(Node, DAG));
36785f757f3fSDimitry Andric 
36795f757f3fSDimitry Andric   return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1),
36805f757f3fSDimitry Andric                      DAG.getNOT(DL, Bit, ResTy));
36815f757f3fSDimitry Andric }
36825f757f3fSDimitry Andric 
36835f757f3fSDimitry Andric template <unsigned N>
36845f757f3fSDimitry Andric static SDValue lowerVectorBitClearImm(SDNode *Node, SelectionDAG &DAG) {
36855f757f3fSDimitry Andric   SDLoc DL(Node);
36865f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
36875f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
36885f757f3fSDimitry Andric   // Check the unsigned ImmArg.
36895f757f3fSDimitry Andric   if (!isUInt<N>(CImm->getZExtValue())) {
36905f757f3fSDimitry Andric     DAG.getContext()->emitError(Node->getOperationName(0) +
36915f757f3fSDimitry Andric                                 ": argument out of range.");
36925f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, DL, ResTy);
36935f757f3fSDimitry Andric   }
36945f757f3fSDimitry Andric 
36955f757f3fSDimitry Andric   APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
36965f757f3fSDimitry Andric   SDValue Mask = DAG.getConstant(~BitImm, DL, ResTy);
36975f757f3fSDimitry Andric 
36985f757f3fSDimitry Andric   return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1), Mask);
36995f757f3fSDimitry Andric }
37005f757f3fSDimitry Andric 
37015f757f3fSDimitry Andric template <unsigned N>
37025f757f3fSDimitry Andric static SDValue lowerVectorBitSetImm(SDNode *Node, SelectionDAG &DAG) {
37035f757f3fSDimitry Andric   SDLoc DL(Node);
37045f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
37055f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
37065f757f3fSDimitry Andric   // Check the unsigned ImmArg.
37075f757f3fSDimitry Andric   if (!isUInt<N>(CImm->getZExtValue())) {
37085f757f3fSDimitry Andric     DAG.getContext()->emitError(Node->getOperationName(0) +
37095f757f3fSDimitry Andric                                 ": argument out of range.");
37105f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, DL, ResTy);
37115f757f3fSDimitry Andric   }
37125f757f3fSDimitry Andric 
37135f757f3fSDimitry Andric   APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
37145f757f3fSDimitry Andric   SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
37155f757f3fSDimitry Andric   return DAG.getNode(ISD::OR, DL, ResTy, Node->getOperand(1), BitImm);
37165f757f3fSDimitry Andric }
37175f757f3fSDimitry Andric 
37185f757f3fSDimitry Andric template <unsigned N>
37195f757f3fSDimitry Andric static SDValue lowerVectorBitRevImm(SDNode *Node, SelectionDAG &DAG) {
37205f757f3fSDimitry Andric   SDLoc DL(Node);
37215f757f3fSDimitry Andric   EVT ResTy = Node->getValueType(0);
37225f757f3fSDimitry Andric   auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
37235f757f3fSDimitry Andric   // Check the unsigned ImmArg.
37245f757f3fSDimitry Andric   if (!isUInt<N>(CImm->getZExtValue())) {
37255f757f3fSDimitry Andric     DAG.getContext()->emitError(Node->getOperationName(0) +
37265f757f3fSDimitry Andric                                 ": argument out of range.");
37275f757f3fSDimitry Andric     return DAG.getNode(ISD::UNDEF, DL, ResTy);
37285f757f3fSDimitry Andric   }
37295f757f3fSDimitry Andric 
37305f757f3fSDimitry Andric   APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
37315f757f3fSDimitry Andric   SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
37325f757f3fSDimitry Andric   return DAG.getNode(ISD::XOR, DL, ResTy, Node->getOperand(1), BitImm);
37335f757f3fSDimitry Andric }
37345f757f3fSDimitry Andric 
37355f757f3fSDimitry Andric static SDValue
37365f757f3fSDimitry Andric performINTRINSIC_WO_CHAINCombine(SDNode *N, SelectionDAG &DAG,
37375f757f3fSDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
37385f757f3fSDimitry Andric                                  const LoongArchSubtarget &Subtarget) {
37395f757f3fSDimitry Andric   SDLoc DL(N);
37405f757f3fSDimitry Andric   switch (N->getConstantOperandVal(0)) {
37415f757f3fSDimitry Andric   default:
37425f757f3fSDimitry Andric     break;
37435f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vadd_b:
37445f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vadd_h:
37455f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vadd_w:
37465f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vadd_d:
37475f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvadd_b:
37485f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvadd_h:
37495f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvadd_w:
37505f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvadd_d:
37515f757f3fSDimitry Andric     return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
37525f757f3fSDimitry Andric                        N->getOperand(2));
37535f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vaddi_bu:
37545f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vaddi_hu:
37555f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vaddi_wu:
37565f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vaddi_du:
37575f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvaddi_bu:
37585f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvaddi_hu:
37595f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvaddi_wu:
37605f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvaddi_du:
37615f757f3fSDimitry Andric     return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
37625f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
37635f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsub_b:
37645f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsub_h:
37655f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsub_w:
37665f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsub_d:
37675f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsub_b:
37685f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsub_h:
37695f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsub_w:
37705f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsub_d:
37715f757f3fSDimitry Andric     return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
37725f757f3fSDimitry Andric                        N->getOperand(2));
37735f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsubi_bu:
37745f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsubi_hu:
37755f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsubi_wu:
37765f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsubi_du:
37775f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsubi_bu:
37785f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsubi_hu:
37795f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsubi_wu:
37805f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsubi_du:
37815f757f3fSDimitry Andric     return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
37825f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
37835f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vneg_b:
37845f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vneg_h:
37855f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vneg_w:
37865f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vneg_d:
37875f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvneg_b:
37885f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvneg_h:
37895f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvneg_w:
37905f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvneg_d:
37915f757f3fSDimitry Andric     return DAG.getNode(
37925f757f3fSDimitry Andric         ISD::SUB, DL, N->getValueType(0),
37935f757f3fSDimitry Andric         DAG.getConstant(
37945f757f3fSDimitry Andric             APInt(N->getValueType(0).getScalarType().getSizeInBits(), 0,
37955f757f3fSDimitry Andric                   /*isSigned=*/true),
37965f757f3fSDimitry Andric             SDLoc(N), N->getValueType(0)),
37975f757f3fSDimitry Andric         N->getOperand(1));
37985f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_b:
37995f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_h:
38005f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_w:
38015f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_d:
38025f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_b:
38035f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_h:
38045f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_w:
38055f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_d:
38065f757f3fSDimitry Andric     return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
38075f757f3fSDimitry Andric                        N->getOperand(2));
38085f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_bu:
38095f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_hu:
38105f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_wu:
38115f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmax_du:
38125f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_bu:
38135f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_hu:
38145f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_wu:
38155f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmax_du:
38165f757f3fSDimitry Andric     return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
38175f757f3fSDimitry Andric                        N->getOperand(2));
38185f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_b:
38195f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_h:
38205f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_w:
38215f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_d:
38225f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_b:
38235f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_h:
38245f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_w:
38255f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_d:
38265f757f3fSDimitry Andric     return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
38275f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
38285f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_bu:
38295f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_hu:
38305f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_wu:
38315f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmaxi_du:
38325f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_bu:
38335f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_hu:
38345f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_wu:
38355f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmaxi_du:
38365f757f3fSDimitry Andric     return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
38375f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
38385f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_b:
38395f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_h:
38405f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_w:
38415f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_d:
38425f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_b:
38435f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_h:
38445f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_w:
38455f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_d:
38465f757f3fSDimitry Andric     return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
38475f757f3fSDimitry Andric                        N->getOperand(2));
38485f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_bu:
38495f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_hu:
38505f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_wu:
38515f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmin_du:
38525f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_bu:
38535f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_hu:
38545f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_wu:
38555f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmin_du:
38565f757f3fSDimitry Andric     return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
38575f757f3fSDimitry Andric                        N->getOperand(2));
38585f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_b:
38595f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_h:
38605f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_w:
38615f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_d:
38625f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_b:
38635f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_h:
38645f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_w:
38655f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_d:
38665f757f3fSDimitry Andric     return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
38675f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
38685f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_bu:
38695f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_hu:
38705f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_wu:
38715f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmini_du:
38725f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_bu:
38735f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_hu:
38745f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_wu:
38755f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmini_du:
38765f757f3fSDimitry Andric     return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
38775f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
38785f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmul_b:
38795f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmul_h:
38805f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmul_w:
38815f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmul_d:
38825f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmul_b:
38835f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmul_h:
38845f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmul_w:
38855f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmul_d:
38865f757f3fSDimitry Andric     return DAG.getNode(ISD::MUL, DL, N->getValueType(0), N->getOperand(1),
38875f757f3fSDimitry Andric                        N->getOperand(2));
38885f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmadd_b:
38895f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmadd_h:
38905f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmadd_w:
38915f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmadd_d:
38925f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmadd_b:
38935f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmadd_h:
38945f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmadd_w:
38955f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmadd_d: {
38965f757f3fSDimitry Andric     EVT ResTy = N->getValueType(0);
38975f757f3fSDimitry Andric     return DAG.getNode(ISD::ADD, SDLoc(N), ResTy, N->getOperand(1),
38985f757f3fSDimitry Andric                        DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
38995f757f3fSDimitry Andric                                    N->getOperand(3)));
39005f757f3fSDimitry Andric   }
39015f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmsub_b:
39025f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmsub_h:
39035f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmsub_w:
39045f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmsub_d:
39055f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmsub_b:
39065f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmsub_h:
39075f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmsub_w:
39085f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmsub_d: {
39095f757f3fSDimitry Andric     EVT ResTy = N->getValueType(0);
39105f757f3fSDimitry Andric     return DAG.getNode(ISD::SUB, SDLoc(N), ResTy, N->getOperand(1),
39115f757f3fSDimitry Andric                        DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
39125f757f3fSDimitry Andric                                    N->getOperand(3)));
39135f757f3fSDimitry Andric   }
39145f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_b:
39155f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_h:
39165f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_w:
39175f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_d:
39185f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_b:
39195f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_h:
39205f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_w:
39215f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_d:
39225f757f3fSDimitry Andric     return DAG.getNode(ISD::SDIV, DL, N->getValueType(0), N->getOperand(1),
39235f757f3fSDimitry Andric                        N->getOperand(2));
39245f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_bu:
39255f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_hu:
39265f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_wu:
39275f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vdiv_du:
39285f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_bu:
39295f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_hu:
39305f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_wu:
39315f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvdiv_du:
39325f757f3fSDimitry Andric     return DAG.getNode(ISD::UDIV, DL, N->getValueType(0), N->getOperand(1),
39335f757f3fSDimitry Andric                        N->getOperand(2));
39345f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_b:
39355f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_h:
39365f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_w:
39375f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_d:
39385f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_b:
39395f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_h:
39405f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_w:
39415f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_d:
39425f757f3fSDimitry Andric     return DAG.getNode(ISD::SREM, DL, N->getValueType(0), N->getOperand(1),
39435f757f3fSDimitry Andric                        N->getOperand(2));
39445f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_bu:
39455f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_hu:
39465f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_wu:
39475f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vmod_du:
39485f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_bu:
39495f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_hu:
39505f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_wu:
39515f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvmod_du:
39525f757f3fSDimitry Andric     return DAG.getNode(ISD::UREM, DL, N->getValueType(0), N->getOperand(1),
39535f757f3fSDimitry Andric                        N->getOperand(2));
39545f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vand_v:
39555f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvand_v:
39565f757f3fSDimitry Andric     return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
39575f757f3fSDimitry Andric                        N->getOperand(2));
39585f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vor_v:
39595f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvor_v:
39605f757f3fSDimitry Andric     return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
39615f757f3fSDimitry Andric                        N->getOperand(2));
39625f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vxor_v:
39635f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvxor_v:
39645f757f3fSDimitry Andric     return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
39655f757f3fSDimitry Andric                        N->getOperand(2));
39665f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vnor_v:
39675f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvnor_v: {
39685f757f3fSDimitry Andric     SDValue Res = DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
39695f757f3fSDimitry Andric                               N->getOperand(2));
39705f757f3fSDimitry Andric     return DAG.getNOT(DL, Res, Res->getValueType(0));
39715f757f3fSDimitry Andric   }
39725f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vandi_b:
39735f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvandi_b:
39745f757f3fSDimitry Andric     return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
39755f757f3fSDimitry Andric                        lowerVectorSplatImm<8>(N, 2, DAG));
39765f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vori_b:
39775f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvori_b:
39785f757f3fSDimitry Andric     return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
39795f757f3fSDimitry Andric                        lowerVectorSplatImm<8>(N, 2, DAG));
39805f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vxori_b:
39815f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvxori_b:
39825f757f3fSDimitry Andric     return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
39835f757f3fSDimitry Andric                        lowerVectorSplatImm<8>(N, 2, DAG));
39845f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsll_b:
39855f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsll_h:
39865f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsll_w:
39875f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsll_d:
39885f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsll_b:
39895f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsll_h:
39905f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsll_w:
39915f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsll_d:
39925f757f3fSDimitry Andric     return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
39935f757f3fSDimitry Andric                        truncateVecElts(N, DAG));
39945f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslli_b:
39955f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslli_b:
39965f757f3fSDimitry Andric     return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
39975f757f3fSDimitry Andric                        lowerVectorSplatImm<3>(N, 2, DAG));
39985f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslli_h:
39995f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslli_h:
40005f757f3fSDimitry Andric     return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
40015f757f3fSDimitry Andric                        lowerVectorSplatImm<4>(N, 2, DAG));
40025f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslli_w:
40035f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslli_w:
40045f757f3fSDimitry Andric     return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
40055f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
40065f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vslli_d:
40075f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvslli_d:
40085f757f3fSDimitry Andric     return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
40095f757f3fSDimitry Andric                        lowerVectorSplatImm<6>(N, 2, DAG));
40105f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrl_b:
40115f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrl_h:
40125f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrl_w:
40135f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrl_d:
40145f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrl_b:
40155f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrl_h:
40165f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrl_w:
40175f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrl_d:
40185f757f3fSDimitry Andric     return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
40195f757f3fSDimitry Andric                        truncateVecElts(N, DAG));
40205f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrli_b:
40215f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrli_b:
40225f757f3fSDimitry Andric     return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
40235f757f3fSDimitry Andric                        lowerVectorSplatImm<3>(N, 2, DAG));
40245f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrli_h:
40255f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrli_h:
40265f757f3fSDimitry Andric     return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
40275f757f3fSDimitry Andric                        lowerVectorSplatImm<4>(N, 2, DAG));
40285f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrli_w:
40295f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrli_w:
40305f757f3fSDimitry Andric     return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
40315f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
40325f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrli_d:
40335f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrli_d:
40345f757f3fSDimitry Andric     return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
40355f757f3fSDimitry Andric                        lowerVectorSplatImm<6>(N, 2, DAG));
40365f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsra_b:
40375f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsra_h:
40385f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsra_w:
40395f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsra_d:
40405f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsra_b:
40415f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsra_h:
40425f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsra_w:
40435f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsra_d:
40445f757f3fSDimitry Andric     return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
40455f757f3fSDimitry Andric                        truncateVecElts(N, DAG));
40465f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrai_b:
40475f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrai_b:
40485f757f3fSDimitry Andric     return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
40495f757f3fSDimitry Andric                        lowerVectorSplatImm<3>(N, 2, DAG));
40505f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrai_h:
40515f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrai_h:
40525f757f3fSDimitry Andric     return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
40535f757f3fSDimitry Andric                        lowerVectorSplatImm<4>(N, 2, DAG));
40545f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrai_w:
40555f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrai_w:
40565f757f3fSDimitry Andric     return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
40575f757f3fSDimitry Andric                        lowerVectorSplatImm<5>(N, 2, DAG));
40585f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vsrai_d:
40595f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvsrai_d:
40605f757f3fSDimitry Andric     return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
40615f757f3fSDimitry Andric                        lowerVectorSplatImm<6>(N, 2, DAG));
40625f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vclz_b:
40635f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vclz_h:
40645f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vclz_w:
40655f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vclz_d:
40665f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvclz_b:
40675f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvclz_h:
40685f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvclz_w:
40695f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvclz_d:
40705f757f3fSDimitry Andric     return DAG.getNode(ISD::CTLZ, DL, N->getValueType(0), N->getOperand(1));
40715f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpcnt_b:
40725f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpcnt_h:
40735f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpcnt_w:
40745f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vpcnt_d:
40755f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpcnt_b:
40765f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpcnt_h:
40775f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpcnt_w:
40785f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvpcnt_d:
40795f757f3fSDimitry Andric     return DAG.getNode(ISD::CTPOP, DL, N->getValueType(0), N->getOperand(1));
40805f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclr_b:
40815f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclr_h:
40825f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclr_w:
40835f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclr_d:
40845f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclr_b:
40855f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclr_h:
40865f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclr_w:
40875f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclr_d:
40885f757f3fSDimitry Andric     return lowerVectorBitClear(N, DAG);
40895f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclri_b:
40905f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclri_b:
40915f757f3fSDimitry Andric     return lowerVectorBitClearImm<3>(N, DAG);
40925f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclri_h:
40935f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclri_h:
40945f757f3fSDimitry Andric     return lowerVectorBitClearImm<4>(N, DAG);
40955f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclri_w:
40965f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclri_w:
40975f757f3fSDimitry Andric     return lowerVectorBitClearImm<5>(N, DAG);
40985f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitclri_d:
40995f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitclri_d:
41005f757f3fSDimitry Andric     return lowerVectorBitClearImm<6>(N, DAG);
41015f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitset_b:
41025f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitset_h:
41035f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitset_w:
41045f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitset_d:
41055f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitset_b:
41065f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitset_h:
41075f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitset_w:
41085f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitset_d: {
41095f757f3fSDimitry Andric     EVT VecTy = N->getValueType(0);
41105f757f3fSDimitry Andric     SDValue One = DAG.getConstant(1, DL, VecTy);
41115f757f3fSDimitry Andric     return DAG.getNode(
41125f757f3fSDimitry Andric         ISD::OR, DL, VecTy, N->getOperand(1),
41135f757f3fSDimitry Andric         DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
41145f757f3fSDimitry Andric   }
41155f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitseti_b:
41165f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitseti_b:
41175f757f3fSDimitry Andric     return lowerVectorBitSetImm<3>(N, DAG);
41185f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitseti_h:
41195f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitseti_h:
41205f757f3fSDimitry Andric     return lowerVectorBitSetImm<4>(N, DAG);
41215f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitseti_w:
41225f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitseti_w:
41235f757f3fSDimitry Andric     return lowerVectorBitSetImm<5>(N, DAG);
41245f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitseti_d:
41255f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitseti_d:
41265f757f3fSDimitry Andric     return lowerVectorBitSetImm<6>(N, DAG);
41275f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrev_b:
41285f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrev_h:
41295f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrev_w:
41305f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrev_d:
41315f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrev_b:
41325f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrev_h:
41335f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrev_w:
41345f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrev_d: {
41355f757f3fSDimitry Andric     EVT VecTy = N->getValueType(0);
41365f757f3fSDimitry Andric     SDValue One = DAG.getConstant(1, DL, VecTy);
41375f757f3fSDimitry Andric     return DAG.getNode(
41385f757f3fSDimitry Andric         ISD::XOR, DL, VecTy, N->getOperand(1),
41395f757f3fSDimitry Andric         DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
41405f757f3fSDimitry Andric   }
41415f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrevi_b:
41425f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrevi_b:
41435f757f3fSDimitry Andric     return lowerVectorBitRevImm<3>(N, DAG);
41445f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrevi_h:
41455f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrevi_h:
41465f757f3fSDimitry Andric     return lowerVectorBitRevImm<4>(N, DAG);
41475f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrevi_w:
41485f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrevi_w:
41495f757f3fSDimitry Andric     return lowerVectorBitRevImm<5>(N, DAG);
41505f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vbitrevi_d:
41515f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvbitrevi_d:
41525f757f3fSDimitry Andric     return lowerVectorBitRevImm<6>(N, DAG);
41535f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfadd_s:
41545f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfadd_d:
41555f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfadd_s:
41565f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfadd_d:
41575f757f3fSDimitry Andric     return DAG.getNode(ISD::FADD, DL, N->getValueType(0), N->getOperand(1),
41585f757f3fSDimitry Andric                        N->getOperand(2));
41595f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfsub_s:
41605f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfsub_d:
41615f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfsub_s:
41625f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfsub_d:
41635f757f3fSDimitry Andric     return DAG.getNode(ISD::FSUB, DL, N->getValueType(0), N->getOperand(1),
41645f757f3fSDimitry Andric                        N->getOperand(2));
41655f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfmul_s:
41665f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfmul_d:
41675f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfmul_s:
41685f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfmul_d:
41695f757f3fSDimitry Andric     return DAG.getNode(ISD::FMUL, DL, N->getValueType(0), N->getOperand(1),
41705f757f3fSDimitry Andric                        N->getOperand(2));
41715f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfdiv_s:
41725f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfdiv_d:
41735f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfdiv_s:
41745f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfdiv_d:
41755f757f3fSDimitry Andric     return DAG.getNode(ISD::FDIV, DL, N->getValueType(0), N->getOperand(1),
41765f757f3fSDimitry Andric                        N->getOperand(2));
41775f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfmadd_s:
41785f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vfmadd_d:
41795f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfmadd_s:
41805f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvfmadd_d:
41815f757f3fSDimitry Andric     return DAG.getNode(ISD::FMA, DL, N->getValueType(0), N->getOperand(1),
41825f757f3fSDimitry Andric                        N->getOperand(2), N->getOperand(3));
41835f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vinsgr2vr_b:
41845f757f3fSDimitry Andric     return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
41855f757f3fSDimitry Andric                        N->getOperand(1), N->getOperand(2),
41865f757f3fSDimitry Andric                        legalizeIntrinsicImmArg<4>(N, 3, DAG, Subtarget));
41875f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vinsgr2vr_h:
41885f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvinsgr2vr_w:
41895f757f3fSDimitry Andric     return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
41905f757f3fSDimitry Andric                        N->getOperand(1), N->getOperand(2),
41915f757f3fSDimitry Andric                        legalizeIntrinsicImmArg<3>(N, 3, DAG, Subtarget));
41925f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vinsgr2vr_w:
41935f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvinsgr2vr_d:
41945f757f3fSDimitry Andric     return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
41955f757f3fSDimitry Andric                        N->getOperand(1), N->getOperand(2),
41965f757f3fSDimitry Andric                        legalizeIntrinsicImmArg<2>(N, 3, DAG, Subtarget));
41975f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vinsgr2vr_d:
41985f757f3fSDimitry Andric     return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
41995f757f3fSDimitry Andric                        N->getOperand(1), N->getOperand(2),
42005f757f3fSDimitry Andric                        legalizeIntrinsicImmArg<1>(N, 3, DAG, Subtarget));
42015f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplgr2vr_b:
42025f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplgr2vr_h:
42035f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplgr2vr_w:
42045f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplgr2vr_d:
42055f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplgr2vr_b:
42065f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplgr2vr_h:
42075f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplgr2vr_w:
42085f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplgr2vr_d: {
42095f757f3fSDimitry Andric     EVT ResTy = N->getValueType(0);
42105f757f3fSDimitry Andric     SmallVector<SDValue> Ops(ResTy.getVectorNumElements(), N->getOperand(1));
42115f757f3fSDimitry Andric     return DAG.getBuildVector(ResTy, DL, Ops);
42125f757f3fSDimitry Andric   }
42135f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplve_b:
42145f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplve_h:
42155f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplve_w:
42165f757f3fSDimitry Andric   case Intrinsic::loongarch_lsx_vreplve_d:
42175f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplve_b:
42185f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplve_h:
42195f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplve_w:
42205f757f3fSDimitry Andric   case Intrinsic::loongarch_lasx_xvreplve_d:
42215f757f3fSDimitry Andric     return DAG.getNode(LoongArchISD::VREPLVE, DL, N->getValueType(0),
42225f757f3fSDimitry Andric                        N->getOperand(1),
42235f757f3fSDimitry Andric                        DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
42245f757f3fSDimitry Andric                                    N->getOperand(2)));
42255f757f3fSDimitry Andric   }
42265f757f3fSDimitry Andric   return SDValue();
42275f757f3fSDimitry Andric }
42285f757f3fSDimitry Andric 
422981ad6265SDimitry Andric SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N,
423081ad6265SDimitry Andric                                                    DAGCombinerInfo &DCI) const {
423181ad6265SDimitry Andric   SelectionDAG &DAG = DCI.DAG;
423281ad6265SDimitry Andric   switch (N->getOpcode()) {
423381ad6265SDimitry Andric   default:
423481ad6265SDimitry Andric     break;
423581ad6265SDimitry Andric   case ISD::AND:
423681ad6265SDimitry Andric     return performANDCombine(N, DAG, DCI, Subtarget);
4237753f127fSDimitry Andric   case ISD::OR:
4238753f127fSDimitry Andric     return performORCombine(N, DAG, DCI, Subtarget);
4239*0fca6ea1SDimitry Andric   case ISD::SETCC:
4240*0fca6ea1SDimitry Andric     return performSETCCCombine(N, DAG, DCI, Subtarget);
424181ad6265SDimitry Andric   case ISD::SRL:
424281ad6265SDimitry Andric     return performSRLCombine(N, DAG, DCI, Subtarget);
4243bdd1243dSDimitry Andric   case LoongArchISD::BITREV_W:
4244bdd1243dSDimitry Andric     return performBITREV_WCombine(N, DAG, DCI, Subtarget);
42455f757f3fSDimitry Andric   case ISD::INTRINSIC_WO_CHAIN:
42465f757f3fSDimitry Andric     return performINTRINSIC_WO_CHAINCombine(N, DAG, DCI, Subtarget);
424781ad6265SDimitry Andric   }
424881ad6265SDimitry Andric   return SDValue();
424981ad6265SDimitry Andric }
425081ad6265SDimitry Andric 
4251753f127fSDimitry Andric static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI,
4252bdd1243dSDimitry Andric                                               MachineBasicBlock *MBB) {
4253753f127fSDimitry Andric   if (!ZeroDivCheck)
4254bdd1243dSDimitry Andric     return MBB;
4255753f127fSDimitry Andric 
4256753f127fSDimitry Andric   // Build instructions:
4257bdd1243dSDimitry Andric   // MBB:
4258753f127fSDimitry Andric   //   div(or mod)   $dst, $dividend, $divisor
4259bdd1243dSDimitry Andric   //   bnez          $divisor, SinkMBB
4260bdd1243dSDimitry Andric   // BreakMBB:
4261bdd1243dSDimitry Andric   //   break         7 // BRK_DIVZERO
4262bdd1243dSDimitry Andric   // SinkMBB:
4263753f127fSDimitry Andric   //   fallthrough
4264bdd1243dSDimitry Andric   const BasicBlock *LLVM_BB = MBB->getBasicBlock();
4265bdd1243dSDimitry Andric   MachineFunction::iterator It = ++MBB->getIterator();
4266bdd1243dSDimitry Andric   MachineFunction *MF = MBB->getParent();
4267bdd1243dSDimitry Andric   auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
4268bdd1243dSDimitry Andric   auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
4269bdd1243dSDimitry Andric   MF->insert(It, BreakMBB);
4270bdd1243dSDimitry Andric   MF->insert(It, SinkMBB);
4271bdd1243dSDimitry Andric 
4272bdd1243dSDimitry Andric   // Transfer the remainder of MBB and its successor edges to SinkMBB.
4273bdd1243dSDimitry Andric   SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
4274bdd1243dSDimitry Andric   SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
4275bdd1243dSDimitry Andric 
4276bdd1243dSDimitry Andric   const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
4277bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
4278753f127fSDimitry Andric   MachineOperand &Divisor = MI.getOperand(2);
4279bdd1243dSDimitry Andric   Register DivisorReg = Divisor.getReg();
4280753f127fSDimitry Andric 
4281bdd1243dSDimitry Andric   // MBB:
4282bdd1243dSDimitry Andric   BuildMI(MBB, DL, TII.get(LoongArch::BNEZ))
4283bdd1243dSDimitry Andric       .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
4284bdd1243dSDimitry Andric       .addMBB(SinkMBB);
4285bdd1243dSDimitry Andric   MBB->addSuccessor(BreakMBB);
4286bdd1243dSDimitry Andric   MBB->addSuccessor(SinkMBB);
4287753f127fSDimitry Andric 
4288bdd1243dSDimitry Andric   // BreakMBB:
4289753f127fSDimitry Andric   // See linux header file arch/loongarch/include/uapi/asm/break.h for the
4290753f127fSDimitry Andric   // definition of BRK_DIVZERO.
4291bdd1243dSDimitry Andric   BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
4292bdd1243dSDimitry Andric   BreakMBB->addSuccessor(SinkMBB);
4293753f127fSDimitry Andric 
4294753f127fSDimitry Andric   // Clear Divisor's kill flag.
4295753f127fSDimitry Andric   Divisor.setIsKill(false);
4296753f127fSDimitry Andric 
4297bdd1243dSDimitry Andric   return SinkMBB;
4298753f127fSDimitry Andric }
4299753f127fSDimitry Andric 
43005f757f3fSDimitry Andric static MachineBasicBlock *
43015f757f3fSDimitry Andric emitVecCondBranchPseudo(MachineInstr &MI, MachineBasicBlock *BB,
43025f757f3fSDimitry Andric                         const LoongArchSubtarget &Subtarget) {
43035f757f3fSDimitry Andric   unsigned CondOpc;
43045f757f3fSDimitry Andric   switch (MI.getOpcode()) {
43055f757f3fSDimitry Andric   default:
43065f757f3fSDimitry Andric     llvm_unreachable("Unexpected opcode");
43075f757f3fSDimitry Andric   case LoongArch::PseudoVBZ:
43085f757f3fSDimitry Andric     CondOpc = LoongArch::VSETEQZ_V;
43095f757f3fSDimitry Andric     break;
43105f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_B:
43115f757f3fSDimitry Andric     CondOpc = LoongArch::VSETANYEQZ_B;
43125f757f3fSDimitry Andric     break;
43135f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_H:
43145f757f3fSDimitry Andric     CondOpc = LoongArch::VSETANYEQZ_H;
43155f757f3fSDimitry Andric     break;
43165f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_W:
43175f757f3fSDimitry Andric     CondOpc = LoongArch::VSETANYEQZ_W;
43185f757f3fSDimitry Andric     break;
43195f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_D:
43205f757f3fSDimitry Andric     CondOpc = LoongArch::VSETANYEQZ_D;
43215f757f3fSDimitry Andric     break;
43225f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ:
43235f757f3fSDimitry Andric     CondOpc = LoongArch::VSETNEZ_V;
43245f757f3fSDimitry Andric     break;
43255f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_B:
43265f757f3fSDimitry Andric     CondOpc = LoongArch::VSETALLNEZ_B;
43275f757f3fSDimitry Andric     break;
43285f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_H:
43295f757f3fSDimitry Andric     CondOpc = LoongArch::VSETALLNEZ_H;
43305f757f3fSDimitry Andric     break;
43315f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_W:
43325f757f3fSDimitry Andric     CondOpc = LoongArch::VSETALLNEZ_W;
43335f757f3fSDimitry Andric     break;
43345f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_D:
43355f757f3fSDimitry Andric     CondOpc = LoongArch::VSETALLNEZ_D;
43365f757f3fSDimitry Andric     break;
43375f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ:
43385f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETEQZ_V;
43395f757f3fSDimitry Andric     break;
43405f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_B:
43415f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETANYEQZ_B;
43425f757f3fSDimitry Andric     break;
43435f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_H:
43445f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETANYEQZ_H;
43455f757f3fSDimitry Andric     break;
43465f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_W:
43475f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETANYEQZ_W;
43485f757f3fSDimitry Andric     break;
43495f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_D:
43505f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETANYEQZ_D;
43515f757f3fSDimitry Andric     break;
43525f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ:
43535f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETNEZ_V;
43545f757f3fSDimitry Andric     break;
43555f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_B:
43565f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETALLNEZ_B;
43575f757f3fSDimitry Andric     break;
43585f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_H:
43595f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETALLNEZ_H;
43605f757f3fSDimitry Andric     break;
43615f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_W:
43625f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETALLNEZ_W;
43635f757f3fSDimitry Andric     break;
43645f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_D:
43655f757f3fSDimitry Andric     CondOpc = LoongArch::XVSETALLNEZ_D;
43665f757f3fSDimitry Andric     break;
43675f757f3fSDimitry Andric   }
43685f757f3fSDimitry Andric 
43695f757f3fSDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
43705f757f3fSDimitry Andric   const BasicBlock *LLVM_BB = BB->getBasicBlock();
43715f757f3fSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
43725f757f3fSDimitry Andric   MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
43735f757f3fSDimitry Andric   MachineFunction::iterator It = ++BB->getIterator();
43745f757f3fSDimitry Andric 
43755f757f3fSDimitry Andric   MachineFunction *F = BB->getParent();
43765f757f3fSDimitry Andric   MachineBasicBlock *FalseBB = F->CreateMachineBasicBlock(LLVM_BB);
43775f757f3fSDimitry Andric   MachineBasicBlock *TrueBB = F->CreateMachineBasicBlock(LLVM_BB);
43785f757f3fSDimitry Andric   MachineBasicBlock *SinkBB = F->CreateMachineBasicBlock(LLVM_BB);
43795f757f3fSDimitry Andric 
43805f757f3fSDimitry Andric   F->insert(It, FalseBB);
43815f757f3fSDimitry Andric   F->insert(It, TrueBB);
43825f757f3fSDimitry Andric   F->insert(It, SinkBB);
43835f757f3fSDimitry Andric 
43845f757f3fSDimitry Andric   // Transfer the remainder of MBB and its successor edges to Sink.
43855f757f3fSDimitry Andric   SinkBB->splice(SinkBB->end(), BB, std::next(MI.getIterator()), BB->end());
43865f757f3fSDimitry Andric   SinkBB->transferSuccessorsAndUpdatePHIs(BB);
43875f757f3fSDimitry Andric 
43885f757f3fSDimitry Andric   // Insert the real instruction to BB.
43895f757f3fSDimitry Andric   Register FCC = MRI.createVirtualRegister(&LoongArch::CFRRegClass);
43905f757f3fSDimitry Andric   BuildMI(BB, DL, TII->get(CondOpc), FCC).addReg(MI.getOperand(1).getReg());
43915f757f3fSDimitry Andric 
43925f757f3fSDimitry Andric   // Insert branch.
43935f757f3fSDimitry Andric   BuildMI(BB, DL, TII->get(LoongArch::BCNEZ)).addReg(FCC).addMBB(TrueBB);
43945f757f3fSDimitry Andric   BB->addSuccessor(FalseBB);
43955f757f3fSDimitry Andric   BB->addSuccessor(TrueBB);
43965f757f3fSDimitry Andric 
43975f757f3fSDimitry Andric   // FalseBB.
43985f757f3fSDimitry Andric   Register RD1 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
43995f757f3fSDimitry Andric   BuildMI(FalseBB, DL, TII->get(LoongArch::ADDI_W), RD1)
44005f757f3fSDimitry Andric       .addReg(LoongArch::R0)
44015f757f3fSDimitry Andric       .addImm(0);
44025f757f3fSDimitry Andric   BuildMI(FalseBB, DL, TII->get(LoongArch::PseudoBR)).addMBB(SinkBB);
44035f757f3fSDimitry Andric   FalseBB->addSuccessor(SinkBB);
44045f757f3fSDimitry Andric 
44055f757f3fSDimitry Andric   // TrueBB.
44065f757f3fSDimitry Andric   Register RD2 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
44075f757f3fSDimitry Andric   BuildMI(TrueBB, DL, TII->get(LoongArch::ADDI_W), RD2)
44085f757f3fSDimitry Andric       .addReg(LoongArch::R0)
44095f757f3fSDimitry Andric       .addImm(1);
44105f757f3fSDimitry Andric   TrueBB->addSuccessor(SinkBB);
44115f757f3fSDimitry Andric 
44125f757f3fSDimitry Andric   // SinkBB: merge the results.
44135f757f3fSDimitry Andric   BuildMI(*SinkBB, SinkBB->begin(), DL, TII->get(LoongArch::PHI),
44145f757f3fSDimitry Andric           MI.getOperand(0).getReg())
44155f757f3fSDimitry Andric       .addReg(RD1)
44165f757f3fSDimitry Andric       .addMBB(FalseBB)
44175f757f3fSDimitry Andric       .addReg(RD2)
44185f757f3fSDimitry Andric       .addMBB(TrueBB);
44195f757f3fSDimitry Andric 
44205f757f3fSDimitry Andric   // The pseudo instruction is gone now.
44215f757f3fSDimitry Andric   MI.eraseFromParent();
44225f757f3fSDimitry Andric   return SinkBB;
44235f757f3fSDimitry Andric }
44245f757f3fSDimitry Andric 
44255f757f3fSDimitry Andric static MachineBasicBlock *
44265f757f3fSDimitry Andric emitPseudoXVINSGR2VR(MachineInstr &MI, MachineBasicBlock *BB,
44275f757f3fSDimitry Andric                      const LoongArchSubtarget &Subtarget) {
44285f757f3fSDimitry Andric   unsigned InsOp;
44295f757f3fSDimitry Andric   unsigned HalfSize;
44305f757f3fSDimitry Andric   switch (MI.getOpcode()) {
44315f757f3fSDimitry Andric   default:
44325f757f3fSDimitry Andric     llvm_unreachable("Unexpected opcode");
44335f757f3fSDimitry Andric   case LoongArch::PseudoXVINSGR2VR_B:
44345f757f3fSDimitry Andric     HalfSize = 16;
44355f757f3fSDimitry Andric     InsOp = LoongArch::VINSGR2VR_B;
44365f757f3fSDimitry Andric     break;
44375f757f3fSDimitry Andric   case LoongArch::PseudoXVINSGR2VR_H:
44385f757f3fSDimitry Andric     HalfSize = 8;
44395f757f3fSDimitry Andric     InsOp = LoongArch::VINSGR2VR_H;
44405f757f3fSDimitry Andric     break;
44415f757f3fSDimitry Andric   }
44425f757f3fSDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
44435f757f3fSDimitry Andric   const TargetRegisterClass *RC = &LoongArch::LASX256RegClass;
44445f757f3fSDimitry Andric   const TargetRegisterClass *SubRC = &LoongArch::LSX128RegClass;
44455f757f3fSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
44465f757f3fSDimitry Andric   MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
44475f757f3fSDimitry Andric   // XDst = vector_insert XSrc, Elt, Idx
44485f757f3fSDimitry Andric   Register XDst = MI.getOperand(0).getReg();
44495f757f3fSDimitry Andric   Register XSrc = MI.getOperand(1).getReg();
44505f757f3fSDimitry Andric   Register Elt = MI.getOperand(2).getReg();
44515f757f3fSDimitry Andric   unsigned Idx = MI.getOperand(3).getImm();
44525f757f3fSDimitry Andric 
44535f757f3fSDimitry Andric   Register ScratchReg1 = XSrc;
44545f757f3fSDimitry Andric   if (Idx >= HalfSize) {
44555f757f3fSDimitry Andric     ScratchReg1 = MRI.createVirtualRegister(RC);
44565f757f3fSDimitry Andric     BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), ScratchReg1)
44575f757f3fSDimitry Andric         .addReg(XSrc)
44585f757f3fSDimitry Andric         .addReg(XSrc)
44595f757f3fSDimitry Andric         .addImm(1);
44605f757f3fSDimitry Andric   }
44615f757f3fSDimitry Andric 
44625f757f3fSDimitry Andric   Register ScratchSubReg1 = MRI.createVirtualRegister(SubRC);
44635f757f3fSDimitry Andric   Register ScratchSubReg2 = MRI.createVirtualRegister(SubRC);
44645f757f3fSDimitry Andric   BuildMI(*BB, MI, DL, TII->get(LoongArch::COPY), ScratchSubReg1)
44655f757f3fSDimitry Andric       .addReg(ScratchReg1, 0, LoongArch::sub_128);
44665f757f3fSDimitry Andric   BuildMI(*BB, MI, DL, TII->get(InsOp), ScratchSubReg2)
44675f757f3fSDimitry Andric       .addReg(ScratchSubReg1)
44685f757f3fSDimitry Andric       .addReg(Elt)
44695f757f3fSDimitry Andric       .addImm(Idx >= HalfSize ? Idx - HalfSize : Idx);
44705f757f3fSDimitry Andric 
44715f757f3fSDimitry Andric   Register ScratchReg2 = XDst;
44725f757f3fSDimitry Andric   if (Idx >= HalfSize)
44735f757f3fSDimitry Andric     ScratchReg2 = MRI.createVirtualRegister(RC);
44745f757f3fSDimitry Andric 
44755f757f3fSDimitry Andric   BuildMI(*BB, MI, DL, TII->get(LoongArch::SUBREG_TO_REG), ScratchReg2)
44765f757f3fSDimitry Andric       .addImm(0)
44775f757f3fSDimitry Andric       .addReg(ScratchSubReg2)
44785f757f3fSDimitry Andric       .addImm(LoongArch::sub_128);
44795f757f3fSDimitry Andric 
44805f757f3fSDimitry Andric   if (Idx >= HalfSize)
44815f757f3fSDimitry Andric     BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), XDst)
44825f757f3fSDimitry Andric         .addReg(XSrc)
44835f757f3fSDimitry Andric         .addReg(ScratchReg2)
44845f757f3fSDimitry Andric         .addImm(2);
44855f757f3fSDimitry Andric 
44865f757f3fSDimitry Andric   MI.eraseFromParent();
44875f757f3fSDimitry Andric   return BB;
44885f757f3fSDimitry Andric }
44895f757f3fSDimitry Andric 
4490753f127fSDimitry Andric MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
4491753f127fSDimitry Andric     MachineInstr &MI, MachineBasicBlock *BB) const {
4492bdd1243dSDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
4493bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
4494753f127fSDimitry Andric 
4495753f127fSDimitry Andric   switch (MI.getOpcode()) {
4496753f127fSDimitry Andric   default:
4497753f127fSDimitry Andric     llvm_unreachable("Unexpected instr type to insert");
4498753f127fSDimitry Andric   case LoongArch::DIV_W:
4499753f127fSDimitry Andric   case LoongArch::DIV_WU:
4500753f127fSDimitry Andric   case LoongArch::MOD_W:
4501753f127fSDimitry Andric   case LoongArch::MOD_WU:
4502753f127fSDimitry Andric   case LoongArch::DIV_D:
4503753f127fSDimitry Andric   case LoongArch::DIV_DU:
4504753f127fSDimitry Andric   case LoongArch::MOD_D:
4505753f127fSDimitry Andric   case LoongArch::MOD_DU:
4506bdd1243dSDimitry Andric     return insertDivByZeroTrap(MI, BB);
4507753f127fSDimitry Andric     break;
4508bdd1243dSDimitry Andric   case LoongArch::WRFCSR: {
4509bdd1243dSDimitry Andric     BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
4510bdd1243dSDimitry Andric             LoongArch::FCSR0 + MI.getOperand(0).getImm())
4511bdd1243dSDimitry Andric         .addReg(MI.getOperand(1).getReg());
4512bdd1243dSDimitry Andric     MI.eraseFromParent();
4513bdd1243dSDimitry Andric     return BB;
4514bdd1243dSDimitry Andric   }
4515bdd1243dSDimitry Andric   case LoongArch::RDFCSR: {
4516bdd1243dSDimitry Andric     MachineInstr *ReadFCSR =
4517bdd1243dSDimitry Andric         BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
4518bdd1243dSDimitry Andric                 MI.getOperand(0).getReg())
4519bdd1243dSDimitry Andric             .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
4520bdd1243dSDimitry Andric     ReadFCSR->getOperand(1).setIsUndef();
4521bdd1243dSDimitry Andric     MI.eraseFromParent();
4522bdd1243dSDimitry Andric     return BB;
4523bdd1243dSDimitry Andric   }
45245f757f3fSDimitry Andric   case LoongArch::PseudoVBZ:
45255f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_B:
45265f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_H:
45275f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_W:
45285f757f3fSDimitry Andric   case LoongArch::PseudoVBZ_D:
45295f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ:
45305f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_B:
45315f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_H:
45325f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_W:
45335f757f3fSDimitry Andric   case LoongArch::PseudoVBNZ_D:
45345f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ:
45355f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_B:
45365f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_H:
45375f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_W:
45385f757f3fSDimitry Andric   case LoongArch::PseudoXVBZ_D:
45395f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ:
45405f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_B:
45415f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_H:
45425f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_W:
45435f757f3fSDimitry Andric   case LoongArch::PseudoXVBNZ_D:
45445f757f3fSDimitry Andric     return emitVecCondBranchPseudo(MI, BB, Subtarget);
45455f757f3fSDimitry Andric   case LoongArch::PseudoXVINSGR2VR_B:
45465f757f3fSDimitry Andric   case LoongArch::PseudoXVINSGR2VR_H:
45475f757f3fSDimitry Andric     return emitPseudoXVINSGR2VR(MI, BB, Subtarget);
4548753f127fSDimitry Andric   }
4549753f127fSDimitry Andric }
4550753f127fSDimitry Andric 
455106c3fb27SDimitry Andric bool LoongArchTargetLowering::allowsMisalignedMemoryAccesses(
455206c3fb27SDimitry Andric     EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
455306c3fb27SDimitry Andric     unsigned *Fast) const {
455406c3fb27SDimitry Andric   if (!Subtarget.hasUAL())
455506c3fb27SDimitry Andric     return false;
455606c3fb27SDimitry Andric 
455706c3fb27SDimitry Andric   // TODO: set reasonable speed number.
455806c3fb27SDimitry Andric   if (Fast)
455906c3fb27SDimitry Andric     *Fast = 1;
456006c3fb27SDimitry Andric   return true;
456106c3fb27SDimitry Andric }
456206c3fb27SDimitry Andric 
456381ad6265SDimitry Andric const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
456481ad6265SDimitry Andric   switch ((LoongArchISD::NodeType)Opcode) {
456581ad6265SDimitry Andric   case LoongArchISD::FIRST_NUMBER:
456681ad6265SDimitry Andric     break;
456781ad6265SDimitry Andric 
456881ad6265SDimitry Andric #define NODE_NAME_CASE(node)                                                   \
456981ad6265SDimitry Andric   case LoongArchISD::node:                                                     \
457081ad6265SDimitry Andric     return "LoongArchISD::" #node;
457181ad6265SDimitry Andric 
457281ad6265SDimitry Andric     // TODO: Add more target-dependent nodes later.
4573753f127fSDimitry Andric     NODE_NAME_CASE(CALL)
45741db9f3b2SDimitry Andric     NODE_NAME_CASE(CALL_MEDIUM)
45751db9f3b2SDimitry Andric     NODE_NAME_CASE(CALL_LARGE)
457681ad6265SDimitry Andric     NODE_NAME_CASE(RET)
4577bdd1243dSDimitry Andric     NODE_NAME_CASE(TAIL)
45781db9f3b2SDimitry Andric     NODE_NAME_CASE(TAIL_MEDIUM)
45791db9f3b2SDimitry Andric     NODE_NAME_CASE(TAIL_LARGE)
458081ad6265SDimitry Andric     NODE_NAME_CASE(SLL_W)
458181ad6265SDimitry Andric     NODE_NAME_CASE(SRA_W)
458281ad6265SDimitry Andric     NODE_NAME_CASE(SRL_W)
4583753f127fSDimitry Andric     NODE_NAME_CASE(BSTRINS)
458481ad6265SDimitry Andric     NODE_NAME_CASE(BSTRPICK)
4585753f127fSDimitry Andric     NODE_NAME_CASE(MOVGR2FR_W_LA64)
4586753f127fSDimitry Andric     NODE_NAME_CASE(MOVFR2GR_S_LA64)
4587753f127fSDimitry Andric     NODE_NAME_CASE(FTINT)
4588bdd1243dSDimitry Andric     NODE_NAME_CASE(REVB_2H)
4589bdd1243dSDimitry Andric     NODE_NAME_CASE(REVB_2W)
4590bdd1243dSDimitry Andric     NODE_NAME_CASE(BITREV_4B)
4591bdd1243dSDimitry Andric     NODE_NAME_CASE(BITREV_W)
4592bdd1243dSDimitry Andric     NODE_NAME_CASE(ROTR_W)
4593bdd1243dSDimitry Andric     NODE_NAME_CASE(ROTL_W)
4594*0fca6ea1SDimitry Andric     NODE_NAME_CASE(DIV_WU)
4595*0fca6ea1SDimitry Andric     NODE_NAME_CASE(MOD_WU)
4596bdd1243dSDimitry Andric     NODE_NAME_CASE(CLZ_W)
4597bdd1243dSDimitry Andric     NODE_NAME_CASE(CTZ_W)
4598bdd1243dSDimitry Andric     NODE_NAME_CASE(DBAR)
4599bdd1243dSDimitry Andric     NODE_NAME_CASE(IBAR)
4600bdd1243dSDimitry Andric     NODE_NAME_CASE(BREAK)
4601bdd1243dSDimitry Andric     NODE_NAME_CASE(SYSCALL)
4602bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_B_W)
4603bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_H_W)
4604bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_W_W)
4605bdd1243dSDimitry Andric     NODE_NAME_CASE(CRC_W_D_W)
4606bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_B_W)
4607bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_H_W)
4608bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_W_W)
4609bdd1243dSDimitry Andric     NODE_NAME_CASE(CRCC_W_D_W)
4610bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRRD)
4611bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRWR)
4612bdd1243dSDimitry Andric     NODE_NAME_CASE(CSRXCHG)
4613bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_B)
4614bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_H)
4615bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_W)
4616bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRRD_D)
4617bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_B)
4618bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_H)
4619bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_W)
4620bdd1243dSDimitry Andric     NODE_NAME_CASE(IOCSRWR_D)
4621bdd1243dSDimitry Andric     NODE_NAME_CASE(CPUCFG)
4622bdd1243dSDimitry Andric     NODE_NAME_CASE(MOVGR2FCSR)
4623bdd1243dSDimitry Andric     NODE_NAME_CASE(MOVFCSR2GR)
4624bdd1243dSDimitry Andric     NODE_NAME_CASE(CACOP_D)
4625bdd1243dSDimitry Andric     NODE_NAME_CASE(CACOP_W)
4626*0fca6ea1SDimitry Andric     NODE_NAME_CASE(VSHUF)
4627*0fca6ea1SDimitry Andric     NODE_NAME_CASE(VPICKEV)
4628*0fca6ea1SDimitry Andric     NODE_NAME_CASE(VPICKOD)
4629*0fca6ea1SDimitry Andric     NODE_NAME_CASE(VPACKEV)
4630*0fca6ea1SDimitry Andric     NODE_NAME_CASE(VPACKOD)
4631*0fca6ea1SDimitry Andric     NODE_NAME_CASE(VILVL)
4632*0fca6ea1SDimitry Andric     NODE_NAME_CASE(VILVH)
4633*0fca6ea1SDimitry Andric     NODE_NAME_CASE(VSHUF4I)
4634*0fca6ea1SDimitry Andric     NODE_NAME_CASE(VREPLVEI)
4635*0fca6ea1SDimitry Andric     NODE_NAME_CASE(XVPERMI)
46365f757f3fSDimitry Andric     NODE_NAME_CASE(VPICK_SEXT_ELT)
46375f757f3fSDimitry Andric     NODE_NAME_CASE(VPICK_ZEXT_ELT)
46385f757f3fSDimitry Andric     NODE_NAME_CASE(VREPLVE)
46395f757f3fSDimitry Andric     NODE_NAME_CASE(VALL_ZERO)
46405f757f3fSDimitry Andric     NODE_NAME_CASE(VANY_ZERO)
46415f757f3fSDimitry Andric     NODE_NAME_CASE(VALL_NONZERO)
46425f757f3fSDimitry Andric     NODE_NAME_CASE(VANY_NONZERO)
464381ad6265SDimitry Andric   }
464481ad6265SDimitry Andric #undef NODE_NAME_CASE
464581ad6265SDimitry Andric   return nullptr;
464681ad6265SDimitry Andric }
464781ad6265SDimitry Andric 
464881ad6265SDimitry Andric //===----------------------------------------------------------------------===//
464981ad6265SDimitry Andric //                     Calling Convention Implementation
465081ad6265SDimitry Andric //===----------------------------------------------------------------------===//
4651bdd1243dSDimitry Andric 
4652bdd1243dSDimitry Andric // Eight general-purpose registers a0-a7 used for passing integer arguments,
4653bdd1243dSDimitry Andric // with a0-a1 reused to return values. Generally, the GPRs are used to pass
4654bdd1243dSDimitry Andric // fixed-point arguments, and floating-point arguments when no FPR is available
4655bdd1243dSDimitry Andric // or with soft float ABI.
465681ad6265SDimitry Andric const MCPhysReg ArgGPRs[] = {LoongArch::R4,  LoongArch::R5, LoongArch::R6,
465781ad6265SDimitry Andric                              LoongArch::R7,  LoongArch::R8, LoongArch::R9,
465881ad6265SDimitry Andric                              LoongArch::R10, LoongArch::R11};
4659bdd1243dSDimitry Andric // Eight floating-point registers fa0-fa7 used for passing floating-point
4660bdd1243dSDimitry Andric // arguments, and fa0-fa1 are also used to return values.
466181ad6265SDimitry Andric const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
466281ad6265SDimitry Andric                                LoongArch::F3, LoongArch::F4, LoongArch::F5,
466381ad6265SDimitry Andric                                LoongArch::F6, LoongArch::F7};
4664bdd1243dSDimitry Andric // FPR32 and FPR64 alias each other.
466581ad6265SDimitry Andric const MCPhysReg ArgFPR64s[] = {
466681ad6265SDimitry Andric     LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
466781ad6265SDimitry Andric     LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
466881ad6265SDimitry Andric 
46695f757f3fSDimitry Andric const MCPhysReg ArgVRs[] = {LoongArch::VR0, LoongArch::VR1, LoongArch::VR2,
46705f757f3fSDimitry Andric                             LoongArch::VR3, LoongArch::VR4, LoongArch::VR5,
46715f757f3fSDimitry Andric                             LoongArch::VR6, LoongArch::VR7};
46725f757f3fSDimitry Andric 
46735f757f3fSDimitry Andric const MCPhysReg ArgXRs[] = {LoongArch::XR0, LoongArch::XR1, LoongArch::XR2,
46745f757f3fSDimitry Andric                             LoongArch::XR3, LoongArch::XR4, LoongArch::XR5,
46755f757f3fSDimitry Andric                             LoongArch::XR6, LoongArch::XR7};
46765f757f3fSDimitry Andric 
4677bdd1243dSDimitry Andric // Pass a 2*GRLen argument that has been split into two GRLen values through
4678bdd1243dSDimitry Andric // registers or the stack as necessary.
4679bdd1243dSDimitry Andric static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
4680bdd1243dSDimitry Andric                                      CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
4681bdd1243dSDimitry Andric                                      unsigned ValNo2, MVT ValVT2, MVT LocVT2,
4682bdd1243dSDimitry Andric                                      ISD::ArgFlagsTy ArgFlags2) {
4683bdd1243dSDimitry Andric   unsigned GRLenInBytes = GRLen / 8;
4684bdd1243dSDimitry Andric   if (Register Reg = State.AllocateReg(ArgGPRs)) {
4685bdd1243dSDimitry Andric     // At least one half can be passed via register.
4686bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
4687bdd1243dSDimitry Andric                                      VA1.getLocVT(), CCValAssign::Full));
4688bdd1243dSDimitry Andric   } else {
4689bdd1243dSDimitry Andric     // Both halves must be passed on the stack, with proper alignment.
4690bdd1243dSDimitry Andric     Align StackAlign =
4691bdd1243dSDimitry Andric         std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
4692bdd1243dSDimitry Andric     State.addLoc(
4693bdd1243dSDimitry Andric         CCValAssign::getMem(VA1.getValNo(), VA1.getValVT(),
4694bdd1243dSDimitry Andric                             State.AllocateStack(GRLenInBytes, StackAlign),
4695bdd1243dSDimitry Andric                             VA1.getLocVT(), CCValAssign::Full));
4696bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getMem(
4697bdd1243dSDimitry Andric         ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
4698bdd1243dSDimitry Andric         LocVT2, CCValAssign::Full));
4699bdd1243dSDimitry Andric     return false;
4700bdd1243dSDimitry Andric   }
4701bdd1243dSDimitry Andric   if (Register Reg = State.AllocateReg(ArgGPRs)) {
4702bdd1243dSDimitry Andric     // The second half can also be passed via register.
4703bdd1243dSDimitry Andric     State.addLoc(
4704bdd1243dSDimitry Andric         CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
4705bdd1243dSDimitry Andric   } else {
4706bdd1243dSDimitry Andric     // The second half is passed via the stack, without additional alignment.
4707bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getMem(
4708bdd1243dSDimitry Andric         ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
4709bdd1243dSDimitry Andric         LocVT2, CCValAssign::Full));
4710bdd1243dSDimitry Andric   }
471181ad6265SDimitry Andric   return false;
471281ad6265SDimitry Andric }
471381ad6265SDimitry Andric 
4714bdd1243dSDimitry Andric // Implements the LoongArch calling convention. Returns true upon failure.
4715bdd1243dSDimitry Andric static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI,
4716bdd1243dSDimitry Andric                          unsigned ValNo, MVT ValVT,
4717bdd1243dSDimitry Andric                          CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
4718bdd1243dSDimitry Andric                          CCState &State, bool IsFixed, bool IsRet,
4719bdd1243dSDimitry Andric                          Type *OrigTy) {
4720bdd1243dSDimitry Andric   unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
4721bdd1243dSDimitry Andric   assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
4722bdd1243dSDimitry Andric   MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
4723bdd1243dSDimitry Andric   MVT LocVT = ValVT;
4724bdd1243dSDimitry Andric 
4725bdd1243dSDimitry Andric   // Any return value split into more than two values can't be returned
4726bdd1243dSDimitry Andric   // directly.
4727bdd1243dSDimitry Andric   if (IsRet && ValNo > 1)
472881ad6265SDimitry Andric     return true;
4729bdd1243dSDimitry Andric 
4730bdd1243dSDimitry Andric   // If passing a variadic argument, or if no FPR is available.
4731bdd1243dSDimitry Andric   bool UseGPRForFloat = true;
4732bdd1243dSDimitry Andric 
4733bdd1243dSDimitry Andric   switch (ABI) {
4734bdd1243dSDimitry Andric   default:
4735bdd1243dSDimitry Andric     llvm_unreachable("Unexpected ABI");
4736*0fca6ea1SDimitry Andric     break;
4737bdd1243dSDimitry Andric   case LoongArchABI::ABI_ILP32F:
4738bdd1243dSDimitry Andric   case LoongArchABI::ABI_LP64F:
4739bdd1243dSDimitry Andric   case LoongArchABI::ABI_ILP32D:
4740bdd1243dSDimitry Andric   case LoongArchABI::ABI_LP64D:
4741bdd1243dSDimitry Andric     UseGPRForFloat = !IsFixed;
4742bdd1243dSDimitry Andric     break;
4743*0fca6ea1SDimitry Andric   case LoongArchABI::ABI_ILP32S:
474406c3fb27SDimitry Andric   case LoongArchABI::ABI_LP64S:
474506c3fb27SDimitry Andric     break;
4746bdd1243dSDimitry Andric   }
4747bdd1243dSDimitry Andric 
4748bdd1243dSDimitry Andric   // FPR32 and FPR64 alias each other.
4749bdd1243dSDimitry Andric   if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
4750bdd1243dSDimitry Andric     UseGPRForFloat = true;
4751bdd1243dSDimitry Andric 
4752bdd1243dSDimitry Andric   if (UseGPRForFloat && ValVT == MVT::f32) {
4753bdd1243dSDimitry Andric     LocVT = GRLenVT;
4754bdd1243dSDimitry Andric     LocInfo = CCValAssign::BCvt;
4755bdd1243dSDimitry Andric   } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
4756bdd1243dSDimitry Andric     LocVT = MVT::i64;
4757bdd1243dSDimitry Andric     LocInfo = CCValAssign::BCvt;
4758bdd1243dSDimitry Andric   } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
4759bdd1243dSDimitry Andric     // TODO: Handle passing f64 on LA32 with D feature.
4760bdd1243dSDimitry Andric     report_fatal_error("Passing f64 with GPR on LA32 is undefined");
4761bdd1243dSDimitry Andric   }
4762bdd1243dSDimitry Andric 
4763bdd1243dSDimitry Andric   // If this is a variadic argument, the LoongArch calling convention requires
4764bdd1243dSDimitry Andric   // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
4765bdd1243dSDimitry Andric   // byte alignment. An aligned register should be used regardless of whether
4766bdd1243dSDimitry Andric   // the original argument was split during legalisation or not. The argument
4767bdd1243dSDimitry Andric   // will not be passed by registers if the original type is larger than
4768bdd1243dSDimitry Andric   // 2*GRLen, so the register alignment rule does not apply.
4769bdd1243dSDimitry Andric   unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
4770bdd1243dSDimitry Andric   if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
4771bdd1243dSDimitry Andric       DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
4772bdd1243dSDimitry Andric     unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
4773bdd1243dSDimitry Andric     // Skip 'odd' register if necessary.
4774bdd1243dSDimitry Andric     if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
4775bdd1243dSDimitry Andric       State.AllocateReg(ArgGPRs);
4776bdd1243dSDimitry Andric   }
4777bdd1243dSDimitry Andric 
4778bdd1243dSDimitry Andric   SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
4779bdd1243dSDimitry Andric   SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
4780bdd1243dSDimitry Andric       State.getPendingArgFlags();
4781bdd1243dSDimitry Andric 
4782bdd1243dSDimitry Andric   assert(PendingLocs.size() == PendingArgFlags.size() &&
4783bdd1243dSDimitry Andric          "PendingLocs and PendingArgFlags out of sync");
4784bdd1243dSDimitry Andric 
4785bdd1243dSDimitry Andric   // Split arguments might be passed indirectly, so keep track of the pending
4786bdd1243dSDimitry Andric   // values.
4787bdd1243dSDimitry Andric   if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
4788bdd1243dSDimitry Andric     LocVT = GRLenVT;
4789bdd1243dSDimitry Andric     LocInfo = CCValAssign::Indirect;
4790bdd1243dSDimitry Andric     PendingLocs.push_back(
4791bdd1243dSDimitry Andric         CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
4792bdd1243dSDimitry Andric     PendingArgFlags.push_back(ArgFlags);
4793bdd1243dSDimitry Andric     if (!ArgFlags.isSplitEnd()) {
4794bdd1243dSDimitry Andric       return false;
4795bdd1243dSDimitry Andric     }
4796bdd1243dSDimitry Andric   }
4797bdd1243dSDimitry Andric 
4798bdd1243dSDimitry Andric   // If the split argument only had two elements, it should be passed directly
4799bdd1243dSDimitry Andric   // in registers or on the stack.
4800bdd1243dSDimitry Andric   if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
4801bdd1243dSDimitry Andric       PendingLocs.size() <= 2) {
4802bdd1243dSDimitry Andric     assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
4803bdd1243dSDimitry Andric     // Apply the normal calling convention rules to the first half of the
4804bdd1243dSDimitry Andric     // split argument.
4805bdd1243dSDimitry Andric     CCValAssign VA = PendingLocs[0];
4806bdd1243dSDimitry Andric     ISD::ArgFlagsTy AF = PendingArgFlags[0];
4807bdd1243dSDimitry Andric     PendingLocs.clear();
4808bdd1243dSDimitry Andric     PendingArgFlags.clear();
4809bdd1243dSDimitry Andric     return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
4810bdd1243dSDimitry Andric                                     ArgFlags);
4811bdd1243dSDimitry Andric   }
4812bdd1243dSDimitry Andric 
4813bdd1243dSDimitry Andric   // Allocate to a register if possible, or else a stack slot.
4814bdd1243dSDimitry Andric   Register Reg;
4815bdd1243dSDimitry Andric   unsigned StoreSizeBytes = GRLen / 8;
4816bdd1243dSDimitry Andric   Align StackAlign = Align(GRLen / 8);
4817bdd1243dSDimitry Andric 
4818bdd1243dSDimitry Andric   if (ValVT == MVT::f32 && !UseGPRForFloat)
4819bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgFPR32s);
4820bdd1243dSDimitry Andric   else if (ValVT == MVT::f64 && !UseGPRForFloat)
4821bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgFPR64s);
48225f757f3fSDimitry Andric   else if (ValVT.is128BitVector())
48235f757f3fSDimitry Andric     Reg = State.AllocateReg(ArgVRs);
48245f757f3fSDimitry Andric   else if (ValVT.is256BitVector())
48255f757f3fSDimitry Andric     Reg = State.AllocateReg(ArgXRs);
4826bdd1243dSDimitry Andric   else
4827bdd1243dSDimitry Andric     Reg = State.AllocateReg(ArgGPRs);
4828bdd1243dSDimitry Andric 
4829bdd1243dSDimitry Andric   unsigned StackOffset =
4830bdd1243dSDimitry Andric       Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
4831bdd1243dSDimitry Andric 
4832bdd1243dSDimitry Andric   // If we reach this point and PendingLocs is non-empty, we must be at the
4833bdd1243dSDimitry Andric   // end of a split argument that must be passed indirectly.
4834bdd1243dSDimitry Andric   if (!PendingLocs.empty()) {
4835bdd1243dSDimitry Andric     assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
4836bdd1243dSDimitry Andric     assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
4837bdd1243dSDimitry Andric     for (auto &It : PendingLocs) {
4838bdd1243dSDimitry Andric       if (Reg)
4839bdd1243dSDimitry Andric         It.convertToReg(Reg);
4840bdd1243dSDimitry Andric       else
4841bdd1243dSDimitry Andric         It.convertToMem(StackOffset);
4842bdd1243dSDimitry Andric       State.addLoc(It);
4843bdd1243dSDimitry Andric     }
4844bdd1243dSDimitry Andric     PendingLocs.clear();
4845bdd1243dSDimitry Andric     PendingArgFlags.clear();
4846bdd1243dSDimitry Andric     return false;
4847bdd1243dSDimitry Andric   }
4848bdd1243dSDimitry Andric   assert((!UseGPRForFloat || LocVT == GRLenVT) &&
4849bdd1243dSDimitry Andric          "Expected an GRLenVT at this stage");
4850bdd1243dSDimitry Andric 
4851bdd1243dSDimitry Andric   if (Reg) {
4852bdd1243dSDimitry Andric     State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
4853bdd1243dSDimitry Andric     return false;
4854bdd1243dSDimitry Andric   }
4855bdd1243dSDimitry Andric 
4856bdd1243dSDimitry Andric   // When a floating-point value is passed on the stack, no bit-cast is needed.
4857bdd1243dSDimitry Andric   if (ValVT.isFloatingPoint()) {
4858bdd1243dSDimitry Andric     LocVT = ValVT;
4859bdd1243dSDimitry Andric     LocInfo = CCValAssign::Full;
4860bdd1243dSDimitry Andric   }
4861bdd1243dSDimitry Andric 
4862bdd1243dSDimitry Andric   State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
4863bdd1243dSDimitry Andric   return false;
486481ad6265SDimitry Andric }
486581ad6265SDimitry Andric 
486681ad6265SDimitry Andric void LoongArchTargetLowering::analyzeInputArgs(
4867bdd1243dSDimitry Andric     MachineFunction &MF, CCState &CCInfo,
4868bdd1243dSDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
486981ad6265SDimitry Andric     LoongArchCCAssignFn Fn) const {
4870bdd1243dSDimitry Andric   FunctionType *FType = MF.getFunction().getFunctionType();
487181ad6265SDimitry Andric   for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
487281ad6265SDimitry Andric     MVT ArgVT = Ins[i].VT;
4873bdd1243dSDimitry Andric     Type *ArgTy = nullptr;
4874bdd1243dSDimitry Andric     if (IsRet)
4875bdd1243dSDimitry Andric       ArgTy = FType->getReturnType();
4876bdd1243dSDimitry Andric     else if (Ins[i].isOrigArg())
4877bdd1243dSDimitry Andric       ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
4878bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
4879bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
4880bdd1243dSDimitry Andric     if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
4881bdd1243dSDimitry Andric            CCInfo, /*IsFixed=*/true, IsRet, ArgTy)) {
488206c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT
488306c3fb27SDimitry Andric                         << '\n');
488481ad6265SDimitry Andric       llvm_unreachable("");
488581ad6265SDimitry Andric     }
488681ad6265SDimitry Andric   }
488781ad6265SDimitry Andric }
488881ad6265SDimitry Andric 
488981ad6265SDimitry Andric void LoongArchTargetLowering::analyzeOutputArgs(
4890bdd1243dSDimitry Andric     MachineFunction &MF, CCState &CCInfo,
4891bdd1243dSDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
4892bdd1243dSDimitry Andric     CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
489381ad6265SDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
489481ad6265SDimitry Andric     MVT ArgVT = Outs[i].VT;
4895bdd1243dSDimitry Andric     Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
4896bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
4897bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
4898bdd1243dSDimitry Andric     if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
4899bdd1243dSDimitry Andric            CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) {
490006c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT
490106c3fb27SDimitry Andric                         << "\n");
490281ad6265SDimitry Andric       llvm_unreachable("");
490381ad6265SDimitry Andric     }
490481ad6265SDimitry Andric   }
490581ad6265SDimitry Andric }
490681ad6265SDimitry Andric 
4907bdd1243dSDimitry Andric // Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
4908bdd1243dSDimitry Andric // values.
4909bdd1243dSDimitry Andric static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val,
4910bdd1243dSDimitry Andric                                    const CCValAssign &VA, const SDLoc &DL) {
4911bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
4912bdd1243dSDimitry Andric   default:
4913bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
4914bdd1243dSDimitry Andric   case CCValAssign::Full:
4915bdd1243dSDimitry Andric   case CCValAssign::Indirect:
4916bdd1243dSDimitry Andric     break;
4917bdd1243dSDimitry Andric   case CCValAssign::BCvt:
4918bdd1243dSDimitry Andric     if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
4919bdd1243dSDimitry Andric       Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
4920bdd1243dSDimitry Andric     else
4921bdd1243dSDimitry Andric       Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
4922bdd1243dSDimitry Andric     break;
4923bdd1243dSDimitry Andric   }
4924bdd1243dSDimitry Andric   return Val;
4925bdd1243dSDimitry Andric }
4926bdd1243dSDimitry Andric 
492781ad6265SDimitry Andric static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain,
492881ad6265SDimitry Andric                                 const CCValAssign &VA, const SDLoc &DL,
4929*0fca6ea1SDimitry Andric                                 const ISD::InputArg &In,
493081ad6265SDimitry Andric                                 const LoongArchTargetLowering &TLI) {
493181ad6265SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
493281ad6265SDimitry Andric   MachineRegisterInfo &RegInfo = MF.getRegInfo();
493381ad6265SDimitry Andric   EVT LocVT = VA.getLocVT();
4934bdd1243dSDimitry Andric   SDValue Val;
493581ad6265SDimitry Andric   const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
493681ad6265SDimitry Andric   Register VReg = RegInfo.createVirtualRegister(RC);
493781ad6265SDimitry Andric   RegInfo.addLiveIn(VA.getLocReg(), VReg);
4938bdd1243dSDimitry Andric   Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
493981ad6265SDimitry Andric 
4940*0fca6ea1SDimitry Andric   // If input is sign extended from 32 bits, note it for the OptW pass.
4941*0fca6ea1SDimitry Andric   if (In.isOrigArg()) {
4942*0fca6ea1SDimitry Andric     Argument *OrigArg = MF.getFunction().getArg(In.getOrigArgIndex());
4943*0fca6ea1SDimitry Andric     if (OrigArg->getType()->isIntegerTy()) {
4944*0fca6ea1SDimitry Andric       unsigned BitWidth = OrigArg->getType()->getIntegerBitWidth();
4945*0fca6ea1SDimitry Andric       // An input zero extended from i31 can also be considered sign extended.
4946*0fca6ea1SDimitry Andric       if ((BitWidth <= 32 && In.Flags.isSExt()) ||
4947*0fca6ea1SDimitry Andric           (BitWidth < 32 && In.Flags.isZExt())) {
4948*0fca6ea1SDimitry Andric         LoongArchMachineFunctionInfo *LAFI =
4949*0fca6ea1SDimitry Andric             MF.getInfo<LoongArchMachineFunctionInfo>();
4950*0fca6ea1SDimitry Andric         LAFI->addSExt32Register(VReg);
4951*0fca6ea1SDimitry Andric       }
4952*0fca6ea1SDimitry Andric     }
4953*0fca6ea1SDimitry Andric   }
4954*0fca6ea1SDimitry Andric 
4955bdd1243dSDimitry Andric   return convertLocVTToValVT(DAG, Val, VA, DL);
4956bdd1243dSDimitry Andric }
4957bdd1243dSDimitry Andric 
4958bdd1243dSDimitry Andric // The caller is responsible for loading the full value if the argument is
4959bdd1243dSDimitry Andric // passed with CCValAssign::Indirect.
4960bdd1243dSDimitry Andric static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain,
4961bdd1243dSDimitry Andric                                 const CCValAssign &VA, const SDLoc &DL) {
4962bdd1243dSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
4963bdd1243dSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
4964bdd1243dSDimitry Andric   EVT ValVT = VA.getValVT();
4965bdd1243dSDimitry Andric   int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
4966bdd1243dSDimitry Andric                                  /*IsImmutable=*/true);
4967bdd1243dSDimitry Andric   SDValue FIN = DAG.getFrameIndex(
4968bdd1243dSDimitry Andric       FI, MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0)));
4969bdd1243dSDimitry Andric 
4970bdd1243dSDimitry Andric   ISD::LoadExtType ExtType;
4971bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
4972bdd1243dSDimitry Andric   default:
4973bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
4974bdd1243dSDimitry Andric   case CCValAssign::Full:
4975bdd1243dSDimitry Andric   case CCValAssign::Indirect:
4976bdd1243dSDimitry Andric   case CCValAssign::BCvt:
4977bdd1243dSDimitry Andric     ExtType = ISD::NON_EXTLOAD;
4978bdd1243dSDimitry Andric     break;
4979bdd1243dSDimitry Andric   }
4980bdd1243dSDimitry Andric   return DAG.getExtLoad(
4981bdd1243dSDimitry Andric       ExtType, DL, VA.getLocVT(), Chain, FIN,
4982bdd1243dSDimitry Andric       MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT);
4983bdd1243dSDimitry Andric }
4984bdd1243dSDimitry Andric 
4985bdd1243dSDimitry Andric static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
4986bdd1243dSDimitry Andric                                    const CCValAssign &VA, const SDLoc &DL) {
4987bdd1243dSDimitry Andric   EVT LocVT = VA.getLocVT();
4988bdd1243dSDimitry Andric 
4989bdd1243dSDimitry Andric   switch (VA.getLocInfo()) {
4990bdd1243dSDimitry Andric   default:
4991bdd1243dSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
4992bdd1243dSDimitry Andric   case CCValAssign::Full:
4993bdd1243dSDimitry Andric     break;
4994bdd1243dSDimitry Andric   case CCValAssign::BCvt:
4995bdd1243dSDimitry Andric     if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
4996bdd1243dSDimitry Andric       Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
4997bdd1243dSDimitry Andric     else
4998bdd1243dSDimitry Andric       Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
4999bdd1243dSDimitry Andric     break;
5000bdd1243dSDimitry Andric   }
5001bdd1243dSDimitry Andric   return Val;
5002bdd1243dSDimitry Andric }
5003bdd1243dSDimitry Andric 
5004bdd1243dSDimitry Andric static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
5005bdd1243dSDimitry Andric                              CCValAssign::LocInfo LocInfo,
5006bdd1243dSDimitry Andric                              ISD::ArgFlagsTy ArgFlags, CCState &State) {
5007bdd1243dSDimitry Andric   if (LocVT == MVT::i32 || LocVT == MVT::i64) {
5008bdd1243dSDimitry Andric     // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
5009bdd1243dSDimitry Andric     //                        s0    s1  s2  s3  s4  s5  s6  s7  s8
5010bdd1243dSDimitry Andric     static const MCPhysReg GPRList[] = {
501106c3fb27SDimitry Andric         LoongArch::R23, LoongArch::R24, LoongArch::R25,
501206c3fb27SDimitry Andric         LoongArch::R26, LoongArch::R27, LoongArch::R28,
501306c3fb27SDimitry Andric         LoongArch::R29, LoongArch::R30, LoongArch::R31};
5014bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(GPRList)) {
5015bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
5016bdd1243dSDimitry Andric       return false;
5017bdd1243dSDimitry Andric     }
5018bdd1243dSDimitry Andric   }
5019bdd1243dSDimitry Andric 
5020bdd1243dSDimitry Andric   if (LocVT == MVT::f32) {
5021bdd1243dSDimitry Andric     // Pass in STG registers: F1, F2, F3, F4
5022bdd1243dSDimitry Andric     //                        fs0,fs1,fs2,fs3
5023bdd1243dSDimitry Andric     static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
5024bdd1243dSDimitry Andric                                           LoongArch::F26, LoongArch::F27};
5025bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(FPR32List)) {
5026bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
5027bdd1243dSDimitry Andric       return false;
5028bdd1243dSDimitry Andric     }
5029bdd1243dSDimitry Andric   }
5030bdd1243dSDimitry Andric 
5031bdd1243dSDimitry Andric   if (LocVT == MVT::f64) {
5032bdd1243dSDimitry Andric     // Pass in STG registers: D1, D2, D3, D4
5033bdd1243dSDimitry Andric     //                        fs4,fs5,fs6,fs7
5034bdd1243dSDimitry Andric     static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
5035bdd1243dSDimitry Andric                                           LoongArch::F30_64, LoongArch::F31_64};
5036bdd1243dSDimitry Andric     if (unsigned Reg = State.AllocateReg(FPR64List)) {
5037bdd1243dSDimitry Andric       State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
5038bdd1243dSDimitry Andric       return false;
5039bdd1243dSDimitry Andric     }
5040bdd1243dSDimitry Andric   }
5041bdd1243dSDimitry Andric 
5042bdd1243dSDimitry Andric   report_fatal_error("No registers left in GHC calling convention");
5043bdd1243dSDimitry Andric   return true;
504481ad6265SDimitry Andric }
504581ad6265SDimitry Andric 
504681ad6265SDimitry Andric // Transform physical registers into virtual registers.
504781ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerFormalArguments(
504881ad6265SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
504981ad6265SDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
505081ad6265SDimitry Andric     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
505181ad6265SDimitry Andric 
505281ad6265SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
505381ad6265SDimitry Andric 
505481ad6265SDimitry Andric   switch (CallConv) {
505581ad6265SDimitry Andric   default:
505681ad6265SDimitry Andric     llvm_unreachable("Unsupported calling convention");
505781ad6265SDimitry Andric   case CallingConv::C:
5058bdd1243dSDimitry Andric   case CallingConv::Fast:
505981ad6265SDimitry Andric     break;
5060bdd1243dSDimitry Andric   case CallingConv::GHC:
506106c3fb27SDimitry Andric     if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
506206c3fb27SDimitry Andric         !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
5063bdd1243dSDimitry Andric       report_fatal_error(
5064bdd1243dSDimitry Andric           "GHC calling convention requires the F and D extensions");
506581ad6265SDimitry Andric   }
506681ad6265SDimitry Andric 
5067bdd1243dSDimitry Andric   EVT PtrVT = getPointerTy(DAG.getDataLayout());
5068bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
5069bdd1243dSDimitry Andric   unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
5070bdd1243dSDimitry Andric   // Used with varargs to acumulate store chains.
5071bdd1243dSDimitry Andric   std::vector<SDValue> OutChains;
5072bdd1243dSDimitry Andric 
507381ad6265SDimitry Andric   // Assign locations to all of the incoming arguments.
507481ad6265SDimitry Andric   SmallVector<CCValAssign> ArgLocs;
507581ad6265SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
507681ad6265SDimitry Andric 
5077bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC)
5078bdd1243dSDimitry Andric     CCInfo.AnalyzeFormalArguments(Ins, CC_LoongArch_GHC);
5079bdd1243dSDimitry Andric   else
5080bdd1243dSDimitry Andric     analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
508181ad6265SDimitry Andric 
5082bdd1243dSDimitry Andric   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
5083bdd1243dSDimitry Andric     CCValAssign &VA = ArgLocs[i];
5084bdd1243dSDimitry Andric     SDValue ArgValue;
5085bdd1243dSDimitry Andric     if (VA.isRegLoc())
5086*0fca6ea1SDimitry Andric       ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, Ins[i], *this);
5087bdd1243dSDimitry Andric     else
5088bdd1243dSDimitry Andric       ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
5089bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect) {
5090bdd1243dSDimitry Andric       // If the original argument was split and passed by reference, we need to
5091bdd1243dSDimitry Andric       // load all parts of it here (using the same address).
5092bdd1243dSDimitry Andric       InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
5093bdd1243dSDimitry Andric                                    MachinePointerInfo()));
5094bdd1243dSDimitry Andric       unsigned ArgIndex = Ins[i].OrigArgIndex;
5095bdd1243dSDimitry Andric       unsigned ArgPartOffset = Ins[i].PartOffset;
5096bdd1243dSDimitry Andric       assert(ArgPartOffset == 0);
5097bdd1243dSDimitry Andric       while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) {
5098bdd1243dSDimitry Andric         CCValAssign &PartVA = ArgLocs[i + 1];
5099bdd1243dSDimitry Andric         unsigned PartOffset = Ins[i + 1].PartOffset - ArgPartOffset;
5100bdd1243dSDimitry Andric         SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
5101bdd1243dSDimitry Andric         SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
5102bdd1243dSDimitry Andric         InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
5103bdd1243dSDimitry Andric                                      MachinePointerInfo()));
5104bdd1243dSDimitry Andric         ++i;
5105bdd1243dSDimitry Andric       }
5106bdd1243dSDimitry Andric       continue;
5107bdd1243dSDimitry Andric     }
5108bdd1243dSDimitry Andric     InVals.push_back(ArgValue);
5109bdd1243dSDimitry Andric   }
5110bdd1243dSDimitry Andric 
5111bdd1243dSDimitry Andric   if (IsVarArg) {
5112bdd1243dSDimitry Andric     ArrayRef<MCPhysReg> ArgRegs = ArrayRef(ArgGPRs);
5113bdd1243dSDimitry Andric     unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
5114bdd1243dSDimitry Andric     const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
5115bdd1243dSDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
5116bdd1243dSDimitry Andric     MachineRegisterInfo &RegInfo = MF.getRegInfo();
5117bdd1243dSDimitry Andric     auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
5118bdd1243dSDimitry Andric 
5119bdd1243dSDimitry Andric     // Offset of the first variable argument from stack pointer, and size of
5120bdd1243dSDimitry Andric     // the vararg save area. For now, the varargs save area is either zero or
5121bdd1243dSDimitry Andric     // large enough to hold a0-a7.
5122bdd1243dSDimitry Andric     int VaArgOffset, VarArgsSaveSize;
5123bdd1243dSDimitry Andric 
5124bdd1243dSDimitry Andric     // If all registers are allocated, then all varargs must be passed on the
5125bdd1243dSDimitry Andric     // stack and we don't need to save any argregs.
5126bdd1243dSDimitry Andric     if (ArgRegs.size() == Idx) {
512706c3fb27SDimitry Andric       VaArgOffset = CCInfo.getStackSize();
5128bdd1243dSDimitry Andric       VarArgsSaveSize = 0;
5129bdd1243dSDimitry Andric     } else {
5130bdd1243dSDimitry Andric       VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
5131bdd1243dSDimitry Andric       VaArgOffset = -VarArgsSaveSize;
5132bdd1243dSDimitry Andric     }
5133bdd1243dSDimitry Andric 
5134bdd1243dSDimitry Andric     // Record the frame index of the first variable argument
5135bdd1243dSDimitry Andric     // which is a value necessary to VASTART.
5136bdd1243dSDimitry Andric     int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
5137bdd1243dSDimitry Andric     LoongArchFI->setVarArgsFrameIndex(FI);
5138bdd1243dSDimitry Andric 
5139bdd1243dSDimitry Andric     // If saving an odd number of registers then create an extra stack slot to
5140bdd1243dSDimitry Andric     // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
5141bdd1243dSDimitry Andric     // offsets to even-numbered registered remain 2*GRLen-aligned.
5142bdd1243dSDimitry Andric     if (Idx % 2) {
5143bdd1243dSDimitry Andric       MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
5144bdd1243dSDimitry Andric                             true);
5145bdd1243dSDimitry Andric       VarArgsSaveSize += GRLenInBytes;
5146bdd1243dSDimitry Andric     }
5147bdd1243dSDimitry Andric 
5148bdd1243dSDimitry Andric     // Copy the integer registers that may have been used for passing varargs
5149bdd1243dSDimitry Andric     // to the vararg save area.
5150bdd1243dSDimitry Andric     for (unsigned I = Idx; I < ArgRegs.size();
5151bdd1243dSDimitry Andric          ++I, VaArgOffset += GRLenInBytes) {
5152bdd1243dSDimitry Andric       const Register Reg = RegInfo.createVirtualRegister(RC);
5153bdd1243dSDimitry Andric       RegInfo.addLiveIn(ArgRegs[I], Reg);
5154bdd1243dSDimitry Andric       SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
5155bdd1243dSDimitry Andric       FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
5156bdd1243dSDimitry Andric       SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
5157bdd1243dSDimitry Andric       SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
5158bdd1243dSDimitry Andric                                    MachinePointerInfo::getFixedStack(MF, FI));
5159bdd1243dSDimitry Andric       cast<StoreSDNode>(Store.getNode())
5160bdd1243dSDimitry Andric           ->getMemOperand()
5161bdd1243dSDimitry Andric           ->setValue((Value *)nullptr);
5162bdd1243dSDimitry Andric       OutChains.push_back(Store);
5163bdd1243dSDimitry Andric     }
5164bdd1243dSDimitry Andric     LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
5165bdd1243dSDimitry Andric   }
5166bdd1243dSDimitry Andric 
5167bdd1243dSDimitry Andric   // All stores are grouped in one node to allow the matching between
5168bdd1243dSDimitry Andric   // the size of Ins and InVals. This only happens for vararg functions.
5169bdd1243dSDimitry Andric   if (!OutChains.empty()) {
5170bdd1243dSDimitry Andric     OutChains.push_back(Chain);
5171bdd1243dSDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
5172bdd1243dSDimitry Andric   }
517381ad6265SDimitry Andric 
517481ad6265SDimitry Andric   return Chain;
517581ad6265SDimitry Andric }
517681ad6265SDimitry Andric 
5177bdd1243dSDimitry Andric bool LoongArchTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
5178bdd1243dSDimitry Andric   return CI->isTailCall();
5179bdd1243dSDimitry Andric }
5180bdd1243dSDimitry Andric 
518106c3fb27SDimitry Andric // Check if the return value is used as only a return value, as otherwise
518206c3fb27SDimitry Andric // we can't perform a tail-call.
518306c3fb27SDimitry Andric bool LoongArchTargetLowering::isUsedByReturnOnly(SDNode *N,
518406c3fb27SDimitry Andric                                                  SDValue &Chain) const {
518506c3fb27SDimitry Andric   if (N->getNumValues() != 1)
518606c3fb27SDimitry Andric     return false;
518706c3fb27SDimitry Andric   if (!N->hasNUsesOfValue(1, 0))
518806c3fb27SDimitry Andric     return false;
518906c3fb27SDimitry Andric 
519006c3fb27SDimitry Andric   SDNode *Copy = *N->use_begin();
519106c3fb27SDimitry Andric   if (Copy->getOpcode() != ISD::CopyToReg)
519206c3fb27SDimitry Andric     return false;
519306c3fb27SDimitry Andric 
519406c3fb27SDimitry Andric   // If the ISD::CopyToReg has a glue operand, we conservatively assume it
519506c3fb27SDimitry Andric   // isn't safe to perform a tail call.
519606c3fb27SDimitry Andric   if (Copy->getGluedNode())
519706c3fb27SDimitry Andric     return false;
519806c3fb27SDimitry Andric 
519906c3fb27SDimitry Andric   // The copy must be used by a LoongArchISD::RET, and nothing else.
520006c3fb27SDimitry Andric   bool HasRet = false;
520106c3fb27SDimitry Andric   for (SDNode *Node : Copy->uses()) {
520206c3fb27SDimitry Andric     if (Node->getOpcode() != LoongArchISD::RET)
520306c3fb27SDimitry Andric       return false;
520406c3fb27SDimitry Andric     HasRet = true;
520506c3fb27SDimitry Andric   }
520606c3fb27SDimitry Andric 
520706c3fb27SDimitry Andric   if (!HasRet)
520806c3fb27SDimitry Andric     return false;
520906c3fb27SDimitry Andric 
521006c3fb27SDimitry Andric   Chain = Copy->getOperand(0);
521106c3fb27SDimitry Andric   return true;
521206c3fb27SDimitry Andric }
521306c3fb27SDimitry Andric 
5214bdd1243dSDimitry Andric // Check whether the call is eligible for tail call optimization.
5215bdd1243dSDimitry Andric bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
5216bdd1243dSDimitry Andric     CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
5217bdd1243dSDimitry Andric     const SmallVectorImpl<CCValAssign> &ArgLocs) const {
5218bdd1243dSDimitry Andric 
5219bdd1243dSDimitry Andric   auto CalleeCC = CLI.CallConv;
5220bdd1243dSDimitry Andric   auto &Outs = CLI.Outs;
5221bdd1243dSDimitry Andric   auto &Caller = MF.getFunction();
5222bdd1243dSDimitry Andric   auto CallerCC = Caller.getCallingConv();
5223bdd1243dSDimitry Andric 
5224bdd1243dSDimitry Andric   // Do not tail call opt if the stack is used to pass parameters.
522506c3fb27SDimitry Andric   if (CCInfo.getStackSize() != 0)
5226bdd1243dSDimitry Andric     return false;
5227bdd1243dSDimitry Andric 
5228bdd1243dSDimitry Andric   // Do not tail call opt if any parameters need to be passed indirectly.
5229bdd1243dSDimitry Andric   for (auto &VA : ArgLocs)
5230bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect)
5231bdd1243dSDimitry Andric       return false;
5232bdd1243dSDimitry Andric 
5233bdd1243dSDimitry Andric   // Do not tail call opt if either caller or callee uses struct return
5234bdd1243dSDimitry Andric   // semantics.
5235bdd1243dSDimitry Andric   auto IsCallerStructRet = Caller.hasStructRetAttr();
5236bdd1243dSDimitry Andric   auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
5237bdd1243dSDimitry Andric   if (IsCallerStructRet || IsCalleeStructRet)
5238bdd1243dSDimitry Andric     return false;
5239bdd1243dSDimitry Andric 
5240bdd1243dSDimitry Andric   // Do not tail call opt if either the callee or caller has a byval argument.
5241bdd1243dSDimitry Andric   for (auto &Arg : Outs)
5242bdd1243dSDimitry Andric     if (Arg.Flags.isByVal())
5243bdd1243dSDimitry Andric       return false;
5244bdd1243dSDimitry Andric 
5245bdd1243dSDimitry Andric   // The callee has to preserve all registers the caller needs to preserve.
5246bdd1243dSDimitry Andric   const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
5247bdd1243dSDimitry Andric   const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
5248bdd1243dSDimitry Andric   if (CalleeCC != CallerCC) {
5249bdd1243dSDimitry Andric     const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
5250bdd1243dSDimitry Andric     if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
5251bdd1243dSDimitry Andric       return false;
5252bdd1243dSDimitry Andric   }
5253bdd1243dSDimitry Andric   return true;
5254bdd1243dSDimitry Andric }
5255bdd1243dSDimitry Andric 
5256bdd1243dSDimitry Andric static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG) {
5257bdd1243dSDimitry Andric   return DAG.getDataLayout().getPrefTypeAlign(
5258bdd1243dSDimitry Andric       VT.getTypeForEVT(*DAG.getContext()));
5259bdd1243dSDimitry Andric }
5260bdd1243dSDimitry Andric 
5261753f127fSDimitry Andric // Lower a call to a callseq_start + CALL + callseq_end chain, and add input
5262753f127fSDimitry Andric // and output parameter nodes.
5263753f127fSDimitry Andric SDValue
5264753f127fSDimitry Andric LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
5265753f127fSDimitry Andric                                    SmallVectorImpl<SDValue> &InVals) const {
5266753f127fSDimitry Andric   SelectionDAG &DAG = CLI.DAG;
5267753f127fSDimitry Andric   SDLoc &DL = CLI.DL;
5268753f127fSDimitry Andric   SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
5269753f127fSDimitry Andric   SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
5270753f127fSDimitry Andric   SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
5271753f127fSDimitry Andric   SDValue Chain = CLI.Chain;
5272753f127fSDimitry Andric   SDValue Callee = CLI.Callee;
5273753f127fSDimitry Andric   CallingConv::ID CallConv = CLI.CallConv;
5274753f127fSDimitry Andric   bool IsVarArg = CLI.IsVarArg;
5275753f127fSDimitry Andric   EVT PtrVT = getPointerTy(DAG.getDataLayout());
5276bdd1243dSDimitry Andric   MVT GRLenVT = Subtarget.getGRLenVT();
5277bdd1243dSDimitry Andric   bool &IsTailCall = CLI.IsTailCall;
5278753f127fSDimitry Andric 
5279753f127fSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
5280753f127fSDimitry Andric 
5281753f127fSDimitry Andric   // Analyze the operands of the call, assigning locations to each operand.
5282753f127fSDimitry Andric   SmallVector<CCValAssign> ArgLocs;
5283753f127fSDimitry Andric   CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
5284753f127fSDimitry Andric 
5285bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC)
5286bdd1243dSDimitry Andric     ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
5287bdd1243dSDimitry Andric   else
5288bdd1243dSDimitry Andric     analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
5289bdd1243dSDimitry Andric 
5290bdd1243dSDimitry Andric   // Check if it's really possible to do a tail call.
5291bdd1243dSDimitry Andric   if (IsTailCall)
5292bdd1243dSDimitry Andric     IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
5293bdd1243dSDimitry Andric 
5294bdd1243dSDimitry Andric   if (IsTailCall)
5295bdd1243dSDimitry Andric     ++NumTailCalls;
5296bdd1243dSDimitry Andric   else if (CLI.CB && CLI.CB->isMustTailCall())
5297bdd1243dSDimitry Andric     report_fatal_error("failed to perform tail call elimination on a call "
5298bdd1243dSDimitry Andric                        "site marked musttail");
5299753f127fSDimitry Andric 
5300753f127fSDimitry Andric   // Get a count of how many bytes are to be pushed on the stack.
530106c3fb27SDimitry Andric   unsigned NumBytes = ArgCCInfo.getStackSize();
5302753f127fSDimitry Andric 
5303bdd1243dSDimitry Andric   // Create local copies for byval args.
5304bdd1243dSDimitry Andric   SmallVector<SDValue> ByValArgs;
5305bdd1243dSDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
5306bdd1243dSDimitry Andric     ISD::ArgFlagsTy Flags = Outs[i].Flags;
5307bdd1243dSDimitry Andric     if (!Flags.isByVal())
5308753f127fSDimitry Andric       continue;
5309bdd1243dSDimitry Andric 
5310bdd1243dSDimitry Andric     SDValue Arg = OutVals[i];
5311bdd1243dSDimitry Andric     unsigned Size = Flags.getByValSize();
5312bdd1243dSDimitry Andric     Align Alignment = Flags.getNonZeroByValAlign();
5313bdd1243dSDimitry Andric 
5314bdd1243dSDimitry Andric     int FI =
5315bdd1243dSDimitry Andric         MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
5316bdd1243dSDimitry Andric     SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
5317bdd1243dSDimitry Andric     SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
5318bdd1243dSDimitry Andric 
5319bdd1243dSDimitry Andric     Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment,
5320bdd1243dSDimitry Andric                           /*IsVolatile=*/false,
5321*0fca6ea1SDimitry Andric                           /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt,
5322bdd1243dSDimitry Andric                           MachinePointerInfo(), MachinePointerInfo());
5323bdd1243dSDimitry Andric     ByValArgs.push_back(FIPtr);
5324753f127fSDimitry Andric   }
5325753f127fSDimitry Andric 
5326bdd1243dSDimitry Andric   if (!IsTailCall)
5327753f127fSDimitry Andric     Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
5328753f127fSDimitry Andric 
5329753f127fSDimitry Andric   // Copy argument values to their designated locations.
5330753f127fSDimitry Andric   SmallVector<std::pair<Register, SDValue>> RegsToPass;
5331bdd1243dSDimitry Andric   SmallVector<SDValue> MemOpChains;
5332bdd1243dSDimitry Andric   SDValue StackPtr;
5333bdd1243dSDimitry Andric   for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) {
5334753f127fSDimitry Andric     CCValAssign &VA = ArgLocs[i];
5335753f127fSDimitry Andric     SDValue ArgValue = OutVals[i];
5336bdd1243dSDimitry Andric     ISD::ArgFlagsTy Flags = Outs[i].Flags;
5337753f127fSDimitry Andric 
5338753f127fSDimitry Andric     // Promote the value if needed.
5339bdd1243dSDimitry Andric     // For now, only handle fully promoted and indirect arguments.
5340bdd1243dSDimitry Andric     if (VA.getLocInfo() == CCValAssign::Indirect) {
5341bdd1243dSDimitry Andric       // Store the argument in a stack slot and pass its address.
5342bdd1243dSDimitry Andric       Align StackAlign =
5343bdd1243dSDimitry Andric           std::max(getPrefTypeAlign(Outs[i].ArgVT, DAG),
5344bdd1243dSDimitry Andric                    getPrefTypeAlign(ArgValue.getValueType(), DAG));
5345bdd1243dSDimitry Andric       TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
5346bdd1243dSDimitry Andric       // If the original argument was split and passed by reference, we need to
5347bdd1243dSDimitry Andric       // store the required parts of it here (and pass just one address).
5348bdd1243dSDimitry Andric       unsigned ArgIndex = Outs[i].OrigArgIndex;
5349bdd1243dSDimitry Andric       unsigned ArgPartOffset = Outs[i].PartOffset;
5350bdd1243dSDimitry Andric       assert(ArgPartOffset == 0);
5351bdd1243dSDimitry Andric       // Calculate the total size to store. We don't have access to what we're
5352bdd1243dSDimitry Andric       // actually storing other than performing the loop and collecting the
5353bdd1243dSDimitry Andric       // info.
5354bdd1243dSDimitry Andric       SmallVector<std::pair<SDValue, SDValue>> Parts;
5355bdd1243dSDimitry Andric       while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) {
5356bdd1243dSDimitry Andric         SDValue PartValue = OutVals[i + 1];
5357bdd1243dSDimitry Andric         unsigned PartOffset = Outs[i + 1].PartOffset - ArgPartOffset;
5358bdd1243dSDimitry Andric         SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
5359bdd1243dSDimitry Andric         EVT PartVT = PartValue.getValueType();
5360bdd1243dSDimitry Andric 
5361bdd1243dSDimitry Andric         StoredSize += PartVT.getStoreSize();
5362bdd1243dSDimitry Andric         StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
5363bdd1243dSDimitry Andric         Parts.push_back(std::make_pair(PartValue, Offset));
5364bdd1243dSDimitry Andric         ++i;
5365bdd1243dSDimitry Andric       }
5366bdd1243dSDimitry Andric       SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
5367bdd1243dSDimitry Andric       int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
5368bdd1243dSDimitry Andric       MemOpChains.push_back(
5369bdd1243dSDimitry Andric           DAG.getStore(Chain, DL, ArgValue, SpillSlot,
5370bdd1243dSDimitry Andric                        MachinePointerInfo::getFixedStack(MF, FI)));
5371bdd1243dSDimitry Andric       for (const auto &Part : Parts) {
5372bdd1243dSDimitry Andric         SDValue PartValue = Part.first;
5373bdd1243dSDimitry Andric         SDValue PartOffset = Part.second;
5374bdd1243dSDimitry Andric         SDValue Address =
5375bdd1243dSDimitry Andric             DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
5376bdd1243dSDimitry Andric         MemOpChains.push_back(
5377bdd1243dSDimitry Andric             DAG.getStore(Chain, DL, PartValue, Address,
5378bdd1243dSDimitry Andric                          MachinePointerInfo::getFixedStack(MF, FI)));
5379bdd1243dSDimitry Andric       }
5380bdd1243dSDimitry Andric       ArgValue = SpillSlot;
5381bdd1243dSDimitry Andric     } else {
5382bdd1243dSDimitry Andric       ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
5383bdd1243dSDimitry Andric     }
5384bdd1243dSDimitry Andric 
5385bdd1243dSDimitry Andric     // Use local copy if it is a byval arg.
5386bdd1243dSDimitry Andric     if (Flags.isByVal())
5387bdd1243dSDimitry Andric       ArgValue = ByValArgs[j++];
5388753f127fSDimitry Andric 
5389753f127fSDimitry Andric     if (VA.isRegLoc()) {
5390753f127fSDimitry Andric       // Queue up the argument copies and emit them at the end.
5391753f127fSDimitry Andric       RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
5392753f127fSDimitry Andric     } else {
5393bdd1243dSDimitry Andric       assert(VA.isMemLoc() && "Argument not register or memory");
5394bdd1243dSDimitry Andric       assert(!IsTailCall && "Tail call not allowed if stack is used "
5395bdd1243dSDimitry Andric                             "for passing parameters");
5396bdd1243dSDimitry Andric 
5397bdd1243dSDimitry Andric       // Work out the address of the stack slot.
5398bdd1243dSDimitry Andric       if (!StackPtr.getNode())
5399bdd1243dSDimitry Andric         StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
5400bdd1243dSDimitry Andric       SDValue Address =
5401bdd1243dSDimitry Andric           DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
5402bdd1243dSDimitry Andric                       DAG.getIntPtrConstant(VA.getLocMemOffset(), DL));
5403bdd1243dSDimitry Andric 
5404bdd1243dSDimitry Andric       // Emit the store.
5405bdd1243dSDimitry Andric       MemOpChains.push_back(
5406bdd1243dSDimitry Andric           DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
5407753f127fSDimitry Andric     }
5408753f127fSDimitry Andric   }
5409753f127fSDimitry Andric 
5410bdd1243dSDimitry Andric   // Join the stores, which are independent of one another.
5411bdd1243dSDimitry Andric   if (!MemOpChains.empty())
5412bdd1243dSDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
5413bdd1243dSDimitry Andric 
5414753f127fSDimitry Andric   SDValue Glue;
5415753f127fSDimitry Andric 
5416753f127fSDimitry Andric   // Build a sequence of copy-to-reg nodes, chained and glued together.
5417753f127fSDimitry Andric   for (auto &Reg : RegsToPass) {
5418753f127fSDimitry Andric     Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
5419753f127fSDimitry Andric     Glue = Chain.getValue(1);
5420753f127fSDimitry Andric   }
5421753f127fSDimitry Andric 
5422753f127fSDimitry Andric   // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
5423753f127fSDimitry Andric   // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
5424753f127fSDimitry Andric   // split it and then direct call can be matched by PseudoCALL.
5425bdd1243dSDimitry Andric   if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
5426bdd1243dSDimitry Andric     const GlobalValue *GV = S->getGlobal();
5427*0fca6ea1SDimitry Andric     unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(GV)
5428bdd1243dSDimitry Andric                            ? LoongArchII::MO_CALL
5429bdd1243dSDimitry Andric                            : LoongArchII::MO_CALL_PLT;
5430bdd1243dSDimitry Andric     Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
5431bdd1243dSDimitry Andric   } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
5432*0fca6ea1SDimitry Andric     unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(nullptr)
5433bdd1243dSDimitry Andric                            ? LoongArchII::MO_CALL
5434bdd1243dSDimitry Andric                            : LoongArchII::MO_CALL_PLT;
5435bdd1243dSDimitry Andric     Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
5436bdd1243dSDimitry Andric   }
5437753f127fSDimitry Andric 
5438753f127fSDimitry Andric   // The first call operand is the chain and the second is the target address.
5439753f127fSDimitry Andric   SmallVector<SDValue> Ops;
5440753f127fSDimitry Andric   Ops.push_back(Chain);
5441753f127fSDimitry Andric   Ops.push_back(Callee);
5442753f127fSDimitry Andric 
5443753f127fSDimitry Andric   // Add argument registers to the end of the list so that they are
5444753f127fSDimitry Andric   // known live into the call.
5445753f127fSDimitry Andric   for (auto &Reg : RegsToPass)
5446753f127fSDimitry Andric     Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
5447753f127fSDimitry Andric 
5448bdd1243dSDimitry Andric   if (!IsTailCall) {
5449753f127fSDimitry Andric     // Add a register mask operand representing the call-preserved registers.
5450753f127fSDimitry Andric     const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
5451753f127fSDimitry Andric     const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
5452753f127fSDimitry Andric     assert(Mask && "Missing call preserved mask for calling convention");
5453753f127fSDimitry Andric     Ops.push_back(DAG.getRegisterMask(Mask));
5454bdd1243dSDimitry Andric   }
5455753f127fSDimitry Andric 
5456753f127fSDimitry Andric   // Glue the call to the argument copies, if any.
5457753f127fSDimitry Andric   if (Glue.getNode())
5458753f127fSDimitry Andric     Ops.push_back(Glue);
5459753f127fSDimitry Andric 
5460753f127fSDimitry Andric   // Emit the call.
5461753f127fSDimitry Andric   SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
54621db9f3b2SDimitry Andric   unsigned Op;
54631db9f3b2SDimitry Andric   switch (DAG.getTarget().getCodeModel()) {
54641db9f3b2SDimitry Andric   default:
54651db9f3b2SDimitry Andric     report_fatal_error("Unsupported code model");
54661db9f3b2SDimitry Andric   case CodeModel::Small:
54671db9f3b2SDimitry Andric     Op = IsTailCall ? LoongArchISD::TAIL : LoongArchISD::CALL;
54681db9f3b2SDimitry Andric     break;
54691db9f3b2SDimitry Andric   case CodeModel::Medium:
54701db9f3b2SDimitry Andric     assert(Subtarget.is64Bit() && "Medium code model requires LA64");
54711db9f3b2SDimitry Andric     Op = IsTailCall ? LoongArchISD::TAIL_MEDIUM : LoongArchISD::CALL_MEDIUM;
54721db9f3b2SDimitry Andric     break;
54731db9f3b2SDimitry Andric   case CodeModel::Large:
54741db9f3b2SDimitry Andric     assert(Subtarget.is64Bit() && "Large code model requires LA64");
54751db9f3b2SDimitry Andric     Op = IsTailCall ? LoongArchISD::TAIL_LARGE : LoongArchISD::CALL_LARGE;
54761db9f3b2SDimitry Andric     break;
54771db9f3b2SDimitry Andric   }
5478753f127fSDimitry Andric 
5479bdd1243dSDimitry Andric   if (IsTailCall) {
5480bdd1243dSDimitry Andric     MF.getFrameInfo().setHasTailCall();
54811db9f3b2SDimitry Andric     SDValue Ret = DAG.getNode(Op, DL, NodeTys, Ops);
548206c3fb27SDimitry Andric     DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge);
548306c3fb27SDimitry Andric     return Ret;
5484bdd1243dSDimitry Andric   }
5485bdd1243dSDimitry Andric 
54861db9f3b2SDimitry Andric   Chain = DAG.getNode(Op, DL, NodeTys, Ops);
5487753f127fSDimitry Andric   DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
5488753f127fSDimitry Andric   Glue = Chain.getValue(1);
5489753f127fSDimitry Andric 
5490753f127fSDimitry Andric   // Mark the end of the call, which is glued to the call itself.
5491bdd1243dSDimitry Andric   Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
5492753f127fSDimitry Andric   Glue = Chain.getValue(1);
5493753f127fSDimitry Andric 
5494753f127fSDimitry Andric   // Assign locations to each value returned by this call.
5495753f127fSDimitry Andric   SmallVector<CCValAssign> RVLocs;
5496753f127fSDimitry Andric   CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
5497bdd1243dSDimitry Andric   analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
5498753f127fSDimitry Andric 
5499753f127fSDimitry Andric   // Copy all of the result registers out of their specified physreg.
5500753f127fSDimitry Andric   for (auto &VA : RVLocs) {
5501753f127fSDimitry Andric     // Copy the value out.
5502753f127fSDimitry Andric     SDValue RetValue =
5503753f127fSDimitry Andric         DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
5504bdd1243dSDimitry Andric     // Glue the RetValue to the end of the call sequence.
5505753f127fSDimitry Andric     Chain = RetValue.getValue(1);
5506753f127fSDimitry Andric     Glue = RetValue.getValue(2);
5507753f127fSDimitry Andric 
5508bdd1243dSDimitry Andric     RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
5509bdd1243dSDimitry Andric 
5510bdd1243dSDimitry Andric     InVals.push_back(RetValue);
5511753f127fSDimitry Andric   }
5512753f127fSDimitry Andric 
5513753f127fSDimitry Andric   return Chain;
5514753f127fSDimitry Andric }
5515753f127fSDimitry Andric 
551681ad6265SDimitry Andric bool LoongArchTargetLowering::CanLowerReturn(
551781ad6265SDimitry Andric     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
551881ad6265SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
5519bdd1243dSDimitry Andric   SmallVector<CCValAssign> RVLocs;
5520bdd1243dSDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
5521bdd1243dSDimitry Andric 
5522bdd1243dSDimitry Andric   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
5523bdd1243dSDimitry Andric     LoongArchABI::ABI ABI =
5524bdd1243dSDimitry Andric         MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
5525bdd1243dSDimitry Andric     if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
5526bdd1243dSDimitry Andric                      Outs[i].Flags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true,
5527bdd1243dSDimitry Andric                      nullptr))
5528bdd1243dSDimitry Andric       return false;
5529bdd1243dSDimitry Andric   }
5530bdd1243dSDimitry Andric   return true;
553181ad6265SDimitry Andric }
553281ad6265SDimitry Andric 
553381ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerReturn(
553481ad6265SDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
553581ad6265SDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs,
553681ad6265SDimitry Andric     const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
553781ad6265SDimitry Andric     SelectionDAG &DAG) const {
553881ad6265SDimitry Andric   // Stores the assignment of the return value to a location.
553981ad6265SDimitry Andric   SmallVector<CCValAssign> RVLocs;
554081ad6265SDimitry Andric 
554181ad6265SDimitry Andric   // Info about the registers and stack slot.
554281ad6265SDimitry Andric   CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
554381ad6265SDimitry Andric                  *DAG.getContext());
554481ad6265SDimitry Andric 
5545bdd1243dSDimitry Andric   analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
5546bdd1243dSDimitry Andric                     nullptr, CC_LoongArch);
5547bdd1243dSDimitry Andric   if (CallConv == CallingConv::GHC && !RVLocs.empty())
5548bdd1243dSDimitry Andric     report_fatal_error("GHC functions return void only");
554981ad6265SDimitry Andric   SDValue Glue;
555081ad6265SDimitry Andric   SmallVector<SDValue, 4> RetOps(1, Chain);
555181ad6265SDimitry Andric 
555281ad6265SDimitry Andric   // Copy the result values into the output registers.
555381ad6265SDimitry Andric   for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) {
555481ad6265SDimitry Andric     CCValAssign &VA = RVLocs[i];
555581ad6265SDimitry Andric     assert(VA.isRegLoc() && "Can only return in registers!");
555681ad6265SDimitry Andric 
555781ad6265SDimitry Andric     // Handle a 'normal' return.
5558bdd1243dSDimitry Andric     SDValue Val = convertValVTToLocVT(DAG, OutVals[i], VA, DL);
5559bdd1243dSDimitry Andric     Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
556081ad6265SDimitry Andric 
556181ad6265SDimitry Andric     // Guarantee that all emitted copies are stuck together.
556281ad6265SDimitry Andric     Glue = Chain.getValue(1);
556381ad6265SDimitry Andric     RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
556481ad6265SDimitry Andric   }
556581ad6265SDimitry Andric 
556681ad6265SDimitry Andric   RetOps[0] = Chain; // Update chain.
556781ad6265SDimitry Andric 
556881ad6265SDimitry Andric   // Add the glue node if we have it.
556981ad6265SDimitry Andric   if (Glue.getNode())
557081ad6265SDimitry Andric     RetOps.push_back(Glue);
557181ad6265SDimitry Andric 
557281ad6265SDimitry Andric   return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
557381ad6265SDimitry Andric }
5574753f127fSDimitry Andric 
5575753f127fSDimitry Andric bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
5576753f127fSDimitry Andric                                            bool ForCodeSize) const {
5577bdd1243dSDimitry Andric   // TODO: Maybe need more checks here after vector extension is supported.
5578753f127fSDimitry Andric   if (VT == MVT::f32 && !Subtarget.hasBasicF())
5579753f127fSDimitry Andric     return false;
5580753f127fSDimitry Andric   if (VT == MVT::f64 && !Subtarget.hasBasicD())
5581753f127fSDimitry Andric     return false;
5582753f127fSDimitry Andric   return (Imm.isZero() || Imm.isExactlyValue(+1.0));
5583753f127fSDimitry Andric }
5584bdd1243dSDimitry Andric 
5585bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCttz(Type *) const {
5586bdd1243dSDimitry Andric   return true;
5587bdd1243dSDimitry Andric }
5588bdd1243dSDimitry Andric 
5589bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCtlz(Type *) const {
5590bdd1243dSDimitry Andric   return true;
5591bdd1243dSDimitry Andric }
5592bdd1243dSDimitry Andric 
5593bdd1243dSDimitry Andric bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
5594bdd1243dSDimitry Andric     const Instruction *I) const {
5595bdd1243dSDimitry Andric   if (!Subtarget.is64Bit())
5596bdd1243dSDimitry Andric     return isa<LoadInst>(I) || isa<StoreInst>(I);
5597bdd1243dSDimitry Andric 
5598bdd1243dSDimitry Andric   if (isa<LoadInst>(I))
5599bdd1243dSDimitry Andric     return true;
5600bdd1243dSDimitry Andric 
5601bdd1243dSDimitry Andric   // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
5602bdd1243dSDimitry Andric   // require fences beacuse we can use amswap_db.[w/d].
5603bdd1243dSDimitry Andric   if (isa<StoreInst>(I)) {
5604bdd1243dSDimitry Andric     unsigned Size = I->getOperand(0)->getType()->getIntegerBitWidth();
5605bdd1243dSDimitry Andric     return (Size == 8 || Size == 16);
5606bdd1243dSDimitry Andric   }
5607bdd1243dSDimitry Andric 
5608bdd1243dSDimitry Andric   return false;
5609bdd1243dSDimitry Andric }
5610bdd1243dSDimitry Andric 
5611bdd1243dSDimitry Andric EVT LoongArchTargetLowering::getSetCCResultType(const DataLayout &DL,
5612bdd1243dSDimitry Andric                                                 LLVMContext &Context,
5613bdd1243dSDimitry Andric                                                 EVT VT) const {
5614bdd1243dSDimitry Andric   if (!VT.isVector())
5615bdd1243dSDimitry Andric     return getPointerTy(DL);
5616bdd1243dSDimitry Andric   return VT.changeVectorElementTypeToInteger();
5617bdd1243dSDimitry Andric }
5618bdd1243dSDimitry Andric 
5619bdd1243dSDimitry Andric bool LoongArchTargetLowering::hasAndNot(SDValue Y) const {
5620bdd1243dSDimitry Andric   // TODO: Support vectors.
5621bdd1243dSDimitry Andric   return Y.getValueType().isScalarInteger() && !isa<ConstantSDNode>(Y);
5622bdd1243dSDimitry Andric }
5623bdd1243dSDimitry Andric 
5624bdd1243dSDimitry Andric bool LoongArchTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
5625bdd1243dSDimitry Andric                                                  const CallInst &I,
5626bdd1243dSDimitry Andric                                                  MachineFunction &MF,
5627bdd1243dSDimitry Andric                                                  unsigned Intrinsic) const {
5628bdd1243dSDimitry Andric   switch (Intrinsic) {
5629bdd1243dSDimitry Andric   default:
5630bdd1243dSDimitry Andric     return false;
5631bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
5632bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_add_i32:
5633bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
5634bdd1243dSDimitry Andric   case Intrinsic::loongarch_masked_atomicrmw_nand_i32:
5635bdd1243dSDimitry Andric     Info.opc = ISD::INTRINSIC_W_CHAIN;
5636bdd1243dSDimitry Andric     Info.memVT = MVT::i32;
5637bdd1243dSDimitry Andric     Info.ptrVal = I.getArgOperand(0);
5638bdd1243dSDimitry Andric     Info.offset = 0;
5639bdd1243dSDimitry Andric     Info.align = Align(4);
5640bdd1243dSDimitry Andric     Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore |
5641bdd1243dSDimitry Andric                  MachineMemOperand::MOVolatile;
5642bdd1243dSDimitry Andric     return true;
5643bdd1243dSDimitry Andric     // TODO: Add more Intrinsics later.
5644bdd1243dSDimitry Andric   }
5645bdd1243dSDimitry Andric }
5646bdd1243dSDimitry Andric 
5647bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind
5648bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
5649bdd1243dSDimitry Andric   // TODO: Add more AtomicRMWInst that needs to be extended.
5650bdd1243dSDimitry Andric 
5651bdd1243dSDimitry Andric   // Since floating-point operation requires a non-trivial set of data
5652bdd1243dSDimitry Andric   // operations, use CmpXChg to expand.
5653bdd1243dSDimitry Andric   if (AI->isFloatingPointOperation() ||
5654bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::UIncWrap ||
5655bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::UDecWrap)
5656bdd1243dSDimitry Andric     return AtomicExpansionKind::CmpXChg;
5657bdd1243dSDimitry Andric 
5658bdd1243dSDimitry Andric   unsigned Size = AI->getType()->getPrimitiveSizeInBits();
5659bdd1243dSDimitry Andric   if (Size == 8 || Size == 16)
5660bdd1243dSDimitry Andric     return AtomicExpansionKind::MaskedIntrinsic;
5661bdd1243dSDimitry Andric   return AtomicExpansionKind::None;
5662bdd1243dSDimitry Andric }
5663bdd1243dSDimitry Andric 
5664bdd1243dSDimitry Andric static Intrinsic::ID
5665bdd1243dSDimitry Andric getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen,
5666bdd1243dSDimitry Andric                                     AtomicRMWInst::BinOp BinOp) {
5667bdd1243dSDimitry Andric   if (GRLen == 64) {
5668bdd1243dSDimitry Andric     switch (BinOp) {
5669bdd1243dSDimitry Andric     default:
5670bdd1243dSDimitry Andric       llvm_unreachable("Unexpected AtomicRMW BinOp");
5671bdd1243dSDimitry Andric     case AtomicRMWInst::Xchg:
5672bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
5673bdd1243dSDimitry Andric     case AtomicRMWInst::Add:
5674bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_add_i64;
5675bdd1243dSDimitry Andric     case AtomicRMWInst::Sub:
5676bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
5677bdd1243dSDimitry Andric     case AtomicRMWInst::Nand:
5678bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
5679bdd1243dSDimitry Andric     case AtomicRMWInst::UMax:
5680bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
5681bdd1243dSDimitry Andric     case AtomicRMWInst::UMin:
5682bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
5683bdd1243dSDimitry Andric     case AtomicRMWInst::Max:
5684bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_max_i64;
5685bdd1243dSDimitry Andric     case AtomicRMWInst::Min:
5686bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_min_i64;
5687bdd1243dSDimitry Andric       // TODO: support other AtomicRMWInst.
5688bdd1243dSDimitry Andric     }
5689bdd1243dSDimitry Andric   }
5690bdd1243dSDimitry Andric 
5691bdd1243dSDimitry Andric   if (GRLen == 32) {
5692bdd1243dSDimitry Andric     switch (BinOp) {
5693bdd1243dSDimitry Andric     default:
5694bdd1243dSDimitry Andric       llvm_unreachable("Unexpected AtomicRMW BinOp");
5695bdd1243dSDimitry Andric     case AtomicRMWInst::Xchg:
5696bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
5697bdd1243dSDimitry Andric     case AtomicRMWInst::Add:
5698bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_add_i32;
5699bdd1243dSDimitry Andric     case AtomicRMWInst::Sub:
5700bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
5701bdd1243dSDimitry Andric     case AtomicRMWInst::Nand:
5702bdd1243dSDimitry Andric       return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
5703bdd1243dSDimitry Andric       // TODO: support other AtomicRMWInst.
5704bdd1243dSDimitry Andric     }
5705bdd1243dSDimitry Andric   }
5706bdd1243dSDimitry Andric 
5707bdd1243dSDimitry Andric   llvm_unreachable("Unexpected GRLen\n");
5708bdd1243dSDimitry Andric }
5709bdd1243dSDimitry Andric 
5710bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind
5711bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicCmpXchgInIR(
5712bdd1243dSDimitry Andric     AtomicCmpXchgInst *CI) const {
5713bdd1243dSDimitry Andric   unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits();
5714bdd1243dSDimitry Andric   if (Size == 8 || Size == 16)
5715bdd1243dSDimitry Andric     return AtomicExpansionKind::MaskedIntrinsic;
5716bdd1243dSDimitry Andric   return AtomicExpansionKind::None;
5717bdd1243dSDimitry Andric }
5718bdd1243dSDimitry Andric 
5719bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicCmpXchgIntrinsic(
5720bdd1243dSDimitry Andric     IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
5721bdd1243dSDimitry Andric     Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
57225f757f3fSDimitry Andric   AtomicOrdering FailOrd = CI->getFailureOrdering();
57235f757f3fSDimitry Andric   Value *FailureOrdering =
57245f757f3fSDimitry Andric       Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(FailOrd));
5725bdd1243dSDimitry Andric 
5726bdd1243dSDimitry Andric   // TODO: Support cmpxchg on LA32.
5727bdd1243dSDimitry Andric   Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
5728bdd1243dSDimitry Andric   CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
5729bdd1243dSDimitry Andric   NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
5730bdd1243dSDimitry Andric   Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
5731bdd1243dSDimitry Andric   Type *Tys[] = {AlignedAddr->getType()};
5732bdd1243dSDimitry Andric   Function *MaskedCmpXchg =
5733bdd1243dSDimitry Andric       Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys);
5734bdd1243dSDimitry Andric   Value *Result = Builder.CreateCall(
57355f757f3fSDimitry Andric       MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, FailureOrdering});
5736bdd1243dSDimitry Andric   Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
5737bdd1243dSDimitry Andric   return Result;
5738bdd1243dSDimitry Andric }
5739bdd1243dSDimitry Andric 
5740bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicRMWIntrinsic(
5741bdd1243dSDimitry Andric     IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
5742bdd1243dSDimitry Andric     Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
57435f757f3fSDimitry Andric   // In the case of an atomicrmw xchg with a constant 0/-1 operand, replace
57445f757f3fSDimitry Andric   // the atomic instruction with an AtomicRMWInst::And/Or with appropriate
57455f757f3fSDimitry Andric   // mask, as this produces better code than the LL/SC loop emitted by
57465f757f3fSDimitry Andric   // int_loongarch_masked_atomicrmw_xchg.
57475f757f3fSDimitry Andric   if (AI->getOperation() == AtomicRMWInst::Xchg &&
57485f757f3fSDimitry Andric       isa<ConstantInt>(AI->getValOperand())) {
57495f757f3fSDimitry Andric     ConstantInt *CVal = cast<ConstantInt>(AI->getValOperand());
57505f757f3fSDimitry Andric     if (CVal->isZero())
57515f757f3fSDimitry Andric       return Builder.CreateAtomicRMW(AtomicRMWInst::And, AlignedAddr,
57525f757f3fSDimitry Andric                                      Builder.CreateNot(Mask, "Inv_Mask"),
57535f757f3fSDimitry Andric                                      AI->getAlign(), Ord);
57545f757f3fSDimitry Andric     if (CVal->isMinusOne())
57555f757f3fSDimitry Andric       return Builder.CreateAtomicRMW(AtomicRMWInst::Or, AlignedAddr, Mask,
57565f757f3fSDimitry Andric                                      AI->getAlign(), Ord);
57575f757f3fSDimitry Andric   }
57585f757f3fSDimitry Andric 
5759bdd1243dSDimitry Andric   unsigned GRLen = Subtarget.getGRLen();
5760bdd1243dSDimitry Andric   Value *Ordering =
5761bdd1243dSDimitry Andric       Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
5762bdd1243dSDimitry Andric   Type *Tys[] = {AlignedAddr->getType()};
5763bdd1243dSDimitry Andric   Function *LlwOpScwLoop = Intrinsic::getDeclaration(
5764bdd1243dSDimitry Andric       AI->getModule(),
5765bdd1243dSDimitry Andric       getIntrinsicForMaskedAtomicRMWBinOp(GRLen, AI->getOperation()), Tys);
5766bdd1243dSDimitry Andric 
5767bdd1243dSDimitry Andric   if (GRLen == 64) {
5768bdd1243dSDimitry Andric     Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
5769bdd1243dSDimitry Andric     Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
5770bdd1243dSDimitry Andric     ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
5771bdd1243dSDimitry Andric   }
5772bdd1243dSDimitry Andric 
5773bdd1243dSDimitry Andric   Value *Result;
5774bdd1243dSDimitry Andric 
5775bdd1243dSDimitry Andric   // Must pass the shift amount needed to sign extend the loaded value prior
5776bdd1243dSDimitry Andric   // to performing a signed comparison for min/max. ShiftAmt is the number of
5777bdd1243dSDimitry Andric   // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
5778bdd1243dSDimitry Andric   // is the number of bits to left+right shift the value in order to
5779bdd1243dSDimitry Andric   // sign-extend.
5780bdd1243dSDimitry Andric   if (AI->getOperation() == AtomicRMWInst::Min ||
5781bdd1243dSDimitry Andric       AI->getOperation() == AtomicRMWInst::Max) {
5782*0fca6ea1SDimitry Andric     const DataLayout &DL = AI->getDataLayout();
5783bdd1243dSDimitry Andric     unsigned ValWidth =
5784bdd1243dSDimitry Andric         DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
5785bdd1243dSDimitry Andric     Value *SextShamt =
5786bdd1243dSDimitry Andric         Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
5787bdd1243dSDimitry Andric     Result = Builder.CreateCall(LlwOpScwLoop,
5788bdd1243dSDimitry Andric                                 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
5789bdd1243dSDimitry Andric   } else {
5790bdd1243dSDimitry Andric     Result =
5791bdd1243dSDimitry Andric         Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
5792bdd1243dSDimitry Andric   }
5793bdd1243dSDimitry Andric 
5794bdd1243dSDimitry Andric   if (GRLen == 64)
5795bdd1243dSDimitry Andric     Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
5796bdd1243dSDimitry Andric   return Result;
5797bdd1243dSDimitry Andric }
5798bdd1243dSDimitry Andric 
5799bdd1243dSDimitry Andric bool LoongArchTargetLowering::isFMAFasterThanFMulAndFAdd(
5800bdd1243dSDimitry Andric     const MachineFunction &MF, EVT VT) const {
5801bdd1243dSDimitry Andric   VT = VT.getScalarType();
5802bdd1243dSDimitry Andric 
5803bdd1243dSDimitry Andric   if (!VT.isSimple())
5804bdd1243dSDimitry Andric     return false;
5805bdd1243dSDimitry Andric 
5806bdd1243dSDimitry Andric   switch (VT.getSimpleVT().SimpleTy) {
5807bdd1243dSDimitry Andric   case MVT::f32:
5808bdd1243dSDimitry Andric   case MVT::f64:
5809bdd1243dSDimitry Andric     return true;
5810bdd1243dSDimitry Andric   default:
5811bdd1243dSDimitry Andric     break;
5812bdd1243dSDimitry Andric   }
5813bdd1243dSDimitry Andric 
5814bdd1243dSDimitry Andric   return false;
5815bdd1243dSDimitry Andric }
5816bdd1243dSDimitry Andric 
5817bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionPointerRegister(
5818bdd1243dSDimitry Andric     const Constant *PersonalityFn) const {
5819bdd1243dSDimitry Andric   return LoongArch::R4;
5820bdd1243dSDimitry Andric }
5821bdd1243dSDimitry Andric 
5822bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionSelectorRegister(
5823bdd1243dSDimitry Andric     const Constant *PersonalityFn) const {
5824bdd1243dSDimitry Andric   return LoongArch::R5;
5825bdd1243dSDimitry Andric }
5826bdd1243dSDimitry Andric 
5827bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
5828bdd1243dSDimitry Andric //                           LoongArch Inline Assembly Support
5829bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
5830bdd1243dSDimitry Andric 
5831bdd1243dSDimitry Andric LoongArchTargetLowering::ConstraintType
5832bdd1243dSDimitry Andric LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
5833bdd1243dSDimitry Andric   // LoongArch specific constraints in GCC: config/loongarch/constraints.md
5834bdd1243dSDimitry Andric   //
5835bdd1243dSDimitry Andric   // 'f':  A floating-point register (if available).
5836bdd1243dSDimitry Andric   // 'k':  A memory operand whose address is formed by a base register and
5837bdd1243dSDimitry Andric   //       (optionally scaled) index register.
5838bdd1243dSDimitry Andric   // 'l':  A signed 16-bit constant.
5839bdd1243dSDimitry Andric   // 'm':  A memory operand whose address is formed by a base register and
5840bdd1243dSDimitry Andric   //       offset that is suitable for use in instructions with the same
5841bdd1243dSDimitry Andric   //       addressing mode as st.w and ld.w.
5842bdd1243dSDimitry Andric   // 'I':  A signed 12-bit constant (for arithmetic instructions).
5843bdd1243dSDimitry Andric   // 'J':  Integer zero.
5844bdd1243dSDimitry Andric   // 'K':  An unsigned 12-bit constant (for logic instructions).
5845bdd1243dSDimitry Andric   // "ZB": An address that is held in a general-purpose register. The offset is
5846bdd1243dSDimitry Andric   //       zero.
5847bdd1243dSDimitry Andric   // "ZC": A memory operand whose address is formed by a base register and
5848bdd1243dSDimitry Andric   //       offset that is suitable for use in instructions with the same
5849bdd1243dSDimitry Andric   //       addressing mode as ll.w and sc.w.
5850bdd1243dSDimitry Andric   if (Constraint.size() == 1) {
5851bdd1243dSDimitry Andric     switch (Constraint[0]) {
5852bdd1243dSDimitry Andric     default:
5853bdd1243dSDimitry Andric       break;
5854bdd1243dSDimitry Andric     case 'f':
5855bdd1243dSDimitry Andric       return C_RegisterClass;
5856bdd1243dSDimitry Andric     case 'l':
5857bdd1243dSDimitry Andric     case 'I':
5858bdd1243dSDimitry Andric     case 'J':
5859bdd1243dSDimitry Andric     case 'K':
5860bdd1243dSDimitry Andric       return C_Immediate;
5861bdd1243dSDimitry Andric     case 'k':
5862bdd1243dSDimitry Andric       return C_Memory;
5863bdd1243dSDimitry Andric     }
5864bdd1243dSDimitry Andric   }
5865bdd1243dSDimitry Andric 
5866bdd1243dSDimitry Andric   if (Constraint == "ZC" || Constraint == "ZB")
5867bdd1243dSDimitry Andric     return C_Memory;
5868bdd1243dSDimitry Andric 
5869bdd1243dSDimitry Andric   // 'm' is handled here.
5870bdd1243dSDimitry Andric   return TargetLowering::getConstraintType(Constraint);
5871bdd1243dSDimitry Andric }
5872bdd1243dSDimitry Andric 
58735f757f3fSDimitry Andric InlineAsm::ConstraintCode LoongArchTargetLowering::getInlineAsmMemConstraint(
5874bdd1243dSDimitry Andric     StringRef ConstraintCode) const {
58755f757f3fSDimitry Andric   return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
58765f757f3fSDimitry Andric       .Case("k", InlineAsm::ConstraintCode::k)
58775f757f3fSDimitry Andric       .Case("ZB", InlineAsm::ConstraintCode::ZB)
58785f757f3fSDimitry Andric       .Case("ZC", InlineAsm::ConstraintCode::ZC)
5879bdd1243dSDimitry Andric       .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
5880bdd1243dSDimitry Andric }
5881bdd1243dSDimitry Andric 
5882bdd1243dSDimitry Andric std::pair<unsigned, const TargetRegisterClass *>
5883bdd1243dSDimitry Andric LoongArchTargetLowering::getRegForInlineAsmConstraint(
5884bdd1243dSDimitry Andric     const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
5885bdd1243dSDimitry Andric   // First, see if this is a constraint that directly corresponds to a LoongArch
5886bdd1243dSDimitry Andric   // register class.
5887bdd1243dSDimitry Andric   if (Constraint.size() == 1) {
5888bdd1243dSDimitry Andric     switch (Constraint[0]) {
5889bdd1243dSDimitry Andric     case 'r':
5890bdd1243dSDimitry Andric       // TODO: Support fixed vectors up to GRLen?
5891bdd1243dSDimitry Andric       if (VT.isVector())
5892bdd1243dSDimitry Andric         break;
5893bdd1243dSDimitry Andric       return std::make_pair(0U, &LoongArch::GPRRegClass);
5894bdd1243dSDimitry Andric     case 'f':
5895bdd1243dSDimitry Andric       if (Subtarget.hasBasicF() && VT == MVT::f32)
5896bdd1243dSDimitry Andric         return std::make_pair(0U, &LoongArch::FPR32RegClass);
5897bdd1243dSDimitry Andric       if (Subtarget.hasBasicD() && VT == MVT::f64)
5898bdd1243dSDimitry Andric         return std::make_pair(0U, &LoongArch::FPR64RegClass);
589906c3fb27SDimitry Andric       if (Subtarget.hasExtLSX() &&
590006c3fb27SDimitry Andric           TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
590106c3fb27SDimitry Andric         return std::make_pair(0U, &LoongArch::LSX128RegClass);
590206c3fb27SDimitry Andric       if (Subtarget.hasExtLASX() &&
590306c3fb27SDimitry Andric           TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
590406c3fb27SDimitry Andric         return std::make_pair(0U, &LoongArch::LASX256RegClass);
5905bdd1243dSDimitry Andric       break;
5906bdd1243dSDimitry Andric     default:
5907bdd1243dSDimitry Andric       break;
5908bdd1243dSDimitry Andric     }
5909bdd1243dSDimitry Andric   }
5910bdd1243dSDimitry Andric 
5911bdd1243dSDimitry Andric   // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
5912bdd1243dSDimitry Andric   // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
5913bdd1243dSDimitry Andric   // constraints while the official register name is prefixed with a '$'. So we
5914bdd1243dSDimitry Andric   // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
5915bdd1243dSDimitry Andric   // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
5916bdd1243dSDimitry Andric   // case insensitive, so no need to convert the constraint to upper case here.
5917bdd1243dSDimitry Andric   //
5918bdd1243dSDimitry Andric   // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
5919bdd1243dSDimitry Andric   // decode the usage of register name aliases into their official names. And
5920bdd1243dSDimitry Andric   // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
5921bdd1243dSDimitry Andric   // official register names.
59225f757f3fSDimitry Andric   if (Constraint.starts_with("{$r") || Constraint.starts_with("{$f") ||
59235f757f3fSDimitry Andric       Constraint.starts_with("{$vr") || Constraint.starts_with("{$xr")) {
5924bdd1243dSDimitry Andric     bool IsFP = Constraint[2] == 'f';
5925bdd1243dSDimitry Andric     std::pair<StringRef, StringRef> Temp = Constraint.split('$');
5926bdd1243dSDimitry Andric     std::pair<unsigned, const TargetRegisterClass *> R;
5927bdd1243dSDimitry Andric     R = TargetLowering::getRegForInlineAsmConstraint(
5928bdd1243dSDimitry Andric         TRI, join_items("", Temp.first, Temp.second), VT);
5929bdd1243dSDimitry Andric     // Match those names to the widest floating point register type available.
5930bdd1243dSDimitry Andric     if (IsFP) {
5931bdd1243dSDimitry Andric       unsigned RegNo = R.first;
5932bdd1243dSDimitry Andric       if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
5933bdd1243dSDimitry Andric         if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
5934bdd1243dSDimitry Andric           unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
5935bdd1243dSDimitry Andric           return std::make_pair(DReg, &LoongArch::FPR64RegClass);
5936bdd1243dSDimitry Andric         }
5937bdd1243dSDimitry Andric       }
5938bdd1243dSDimitry Andric     }
5939bdd1243dSDimitry Andric     return R;
5940bdd1243dSDimitry Andric   }
5941bdd1243dSDimitry Andric 
5942bdd1243dSDimitry Andric   return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
5943bdd1243dSDimitry Andric }
5944bdd1243dSDimitry Andric 
5945bdd1243dSDimitry Andric void LoongArchTargetLowering::LowerAsmOperandForConstraint(
59465f757f3fSDimitry Andric     SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops,
5947bdd1243dSDimitry Andric     SelectionDAG &DAG) const {
5948bdd1243dSDimitry Andric   // Currently only support length 1 constraints.
59495f757f3fSDimitry Andric   if (Constraint.size() == 1) {
5950bdd1243dSDimitry Andric     switch (Constraint[0]) {
5951bdd1243dSDimitry Andric     case 'l':
5952bdd1243dSDimitry Andric       // Validate & create a 16-bit signed immediate operand.
5953bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
5954bdd1243dSDimitry Andric         uint64_t CVal = C->getSExtValue();
5955bdd1243dSDimitry Andric         if (isInt<16>(CVal))
5956bdd1243dSDimitry Andric           Ops.push_back(
5957bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
5958bdd1243dSDimitry Andric       }
5959bdd1243dSDimitry Andric       return;
5960bdd1243dSDimitry Andric     case 'I':
5961bdd1243dSDimitry Andric       // Validate & create a 12-bit signed immediate operand.
5962bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
5963bdd1243dSDimitry Andric         uint64_t CVal = C->getSExtValue();
5964bdd1243dSDimitry Andric         if (isInt<12>(CVal))
5965bdd1243dSDimitry Andric           Ops.push_back(
5966bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
5967bdd1243dSDimitry Andric       }
5968bdd1243dSDimitry Andric       return;
5969bdd1243dSDimitry Andric     case 'J':
5970bdd1243dSDimitry Andric       // Validate & create an integer zero operand.
5971bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op))
5972bdd1243dSDimitry Andric         if (C->getZExtValue() == 0)
5973bdd1243dSDimitry Andric           Ops.push_back(
5974bdd1243dSDimitry Andric               DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
5975bdd1243dSDimitry Andric       return;
5976bdd1243dSDimitry Andric     case 'K':
5977bdd1243dSDimitry Andric       // Validate & create a 12-bit unsigned immediate operand.
5978bdd1243dSDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
5979bdd1243dSDimitry Andric         uint64_t CVal = C->getZExtValue();
5980bdd1243dSDimitry Andric         if (isUInt<12>(CVal))
5981bdd1243dSDimitry Andric           Ops.push_back(
5982bdd1243dSDimitry Andric               DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
5983bdd1243dSDimitry Andric       }
5984bdd1243dSDimitry Andric       return;
5985bdd1243dSDimitry Andric     default:
5986bdd1243dSDimitry Andric       break;
5987bdd1243dSDimitry Andric     }
5988bdd1243dSDimitry Andric   }
5989bdd1243dSDimitry Andric   TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
5990bdd1243dSDimitry Andric }
5991bdd1243dSDimitry Andric 
5992bdd1243dSDimitry Andric #define GET_REGISTER_MATCHER
5993bdd1243dSDimitry Andric #include "LoongArchGenAsmMatcher.inc"
5994bdd1243dSDimitry Andric 
5995bdd1243dSDimitry Andric Register
5996bdd1243dSDimitry Andric LoongArchTargetLowering::getRegisterByName(const char *RegName, LLT VT,
5997bdd1243dSDimitry Andric                                            const MachineFunction &MF) const {
5998bdd1243dSDimitry Andric   std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
5999bdd1243dSDimitry Andric   std::string NewRegName = Name.second.str();
6000bdd1243dSDimitry Andric   Register Reg = MatchRegisterAltName(NewRegName);
6001bdd1243dSDimitry Andric   if (Reg == LoongArch::NoRegister)
6002bdd1243dSDimitry Andric     Reg = MatchRegisterName(NewRegName);
6003bdd1243dSDimitry Andric   if (Reg == LoongArch::NoRegister)
6004bdd1243dSDimitry Andric     report_fatal_error(
6005bdd1243dSDimitry Andric         Twine("Invalid register name \"" + StringRef(RegName) + "\"."));
6006bdd1243dSDimitry Andric   BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
6007bdd1243dSDimitry Andric   if (!ReservedRegs.test(Reg))
6008bdd1243dSDimitry Andric     report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
6009bdd1243dSDimitry Andric                              StringRef(RegName) + "\"."));
6010bdd1243dSDimitry Andric   return Reg;
6011bdd1243dSDimitry Andric }
6012bdd1243dSDimitry Andric 
6013bdd1243dSDimitry Andric bool LoongArchTargetLowering::decomposeMulByConstant(LLVMContext &Context,
6014bdd1243dSDimitry Andric                                                      EVT VT, SDValue C) const {
6015bdd1243dSDimitry Andric   // TODO: Support vectors.
6016bdd1243dSDimitry Andric   if (!VT.isScalarInteger())
6017bdd1243dSDimitry Andric     return false;
6018bdd1243dSDimitry Andric 
6019bdd1243dSDimitry Andric   // Omit the optimization if the data size exceeds GRLen.
6020bdd1243dSDimitry Andric   if (VT.getSizeInBits() > Subtarget.getGRLen())
6021bdd1243dSDimitry Andric     return false;
6022bdd1243dSDimitry Andric 
6023bdd1243dSDimitry Andric   if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
6024bdd1243dSDimitry Andric     const APInt &Imm = ConstNode->getAPIntValue();
602506c3fb27SDimitry Andric     // Break MUL into (SLLI + ADD/SUB) or ALSL.
6026bdd1243dSDimitry Andric     if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
6027bdd1243dSDimitry Andric         (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
6028bdd1243dSDimitry Andric       return true;
602906c3fb27SDimitry Andric     // Break MUL into (ALSL x, (SLLI x, imm0), imm1).
603006c3fb27SDimitry Andric     if (ConstNode->hasOneUse() &&
603106c3fb27SDimitry Andric         ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() ||
603206c3fb27SDimitry Andric          (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2()))
603306c3fb27SDimitry Andric       return true;
603406c3fb27SDimitry Andric     // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)),
603506c3fb27SDimitry Andric     // in which the immediate has two set bits. Or Break (MUL x, imm)
603606c3fb27SDimitry Andric     // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate
603706c3fb27SDimitry Andric     // equals to (1 << s0) - (1 << s1).
603806c3fb27SDimitry Andric     if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) {
603906c3fb27SDimitry Andric       unsigned Shifts = Imm.countr_zero();
604006c3fb27SDimitry Andric       // Reject immediates which can be composed via a single LUI.
604106c3fb27SDimitry Andric       if (Shifts >= 12)
604206c3fb27SDimitry Andric         return false;
604306c3fb27SDimitry Andric       // Reject multiplications can be optimized to
604406c3fb27SDimitry Andric       // (SLLI (ALSL x, x, 1/2/3/4), s).
604506c3fb27SDimitry Andric       APInt ImmPop = Imm.ashr(Shifts);
604606c3fb27SDimitry Andric       if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17)
604706c3fb27SDimitry Andric         return false;
604806c3fb27SDimitry Andric       // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`,
604906c3fb27SDimitry Andric       // since it needs one more instruction than other 3 cases.
605006c3fb27SDimitry Andric       APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true);
605106c3fb27SDimitry Andric       if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() ||
605206c3fb27SDimitry Andric           (ImmSmall - Imm).isPowerOf2())
605306c3fb27SDimitry Andric         return true;
605406c3fb27SDimitry Andric     }
6055bdd1243dSDimitry Andric   }
6056bdd1243dSDimitry Andric 
6057bdd1243dSDimitry Andric   return false;
6058bdd1243dSDimitry Andric }
605906c3fb27SDimitry Andric 
606006c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalAddressingMode(const DataLayout &DL,
606106c3fb27SDimitry Andric                                                     const AddrMode &AM,
606206c3fb27SDimitry Andric                                                     Type *Ty, unsigned AS,
606306c3fb27SDimitry Andric                                                     Instruction *I) const {
606406c3fb27SDimitry Andric   // LoongArch has four basic addressing modes:
606506c3fb27SDimitry Andric   //  1. reg
606606c3fb27SDimitry Andric   //  2. reg + 12-bit signed offset
606706c3fb27SDimitry Andric   //  3. reg + 14-bit signed offset left-shifted by 2
606806c3fb27SDimitry Andric   //  4. reg1 + reg2
606906c3fb27SDimitry Andric   // TODO: Add more checks after support vector extension.
607006c3fb27SDimitry Andric 
607106c3fb27SDimitry Andric   // No global is ever allowed as a base.
607206c3fb27SDimitry Andric   if (AM.BaseGV)
607306c3fb27SDimitry Andric     return false;
607406c3fb27SDimitry Andric 
6075*0fca6ea1SDimitry Andric   // Require a 12-bit signed offset or 14-bit signed offset left-shifted by 2
6076*0fca6ea1SDimitry Andric   // with `UAL` feature.
6077*0fca6ea1SDimitry Andric   if (!isInt<12>(AM.BaseOffs) &&
6078*0fca6ea1SDimitry Andric       !(isShiftedInt<14, 2>(AM.BaseOffs) && Subtarget.hasUAL()))
607906c3fb27SDimitry Andric     return false;
608006c3fb27SDimitry Andric 
608106c3fb27SDimitry Andric   switch (AM.Scale) {
608206c3fb27SDimitry Andric   case 0:
6083*0fca6ea1SDimitry Andric     // "r+i" or just "i", depending on HasBaseReg.
608406c3fb27SDimitry Andric     break;
608506c3fb27SDimitry Andric   case 1:
608606c3fb27SDimitry Andric     // "r+r+i" is not allowed.
6087*0fca6ea1SDimitry Andric     if (AM.HasBaseReg && AM.BaseOffs)
608806c3fb27SDimitry Andric       return false;
608906c3fb27SDimitry Andric     // Otherwise we have "r+r" or "r+i".
609006c3fb27SDimitry Andric     break;
609106c3fb27SDimitry Andric   case 2:
609206c3fb27SDimitry Andric     // "2*r+r" or "2*r+i" is not allowed.
609306c3fb27SDimitry Andric     if (AM.HasBaseReg || AM.BaseOffs)
609406c3fb27SDimitry Andric       return false;
6095*0fca6ea1SDimitry Andric     // Allow "2*r" as "r+r".
609606c3fb27SDimitry Andric     break;
609706c3fb27SDimitry Andric   default:
609806c3fb27SDimitry Andric     return false;
609906c3fb27SDimitry Andric   }
610006c3fb27SDimitry Andric 
610106c3fb27SDimitry Andric   return true;
610206c3fb27SDimitry Andric }
610306c3fb27SDimitry Andric 
610406c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
610506c3fb27SDimitry Andric   return isInt<12>(Imm);
610606c3fb27SDimitry Andric }
610706c3fb27SDimitry Andric 
610806c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalAddImmediate(int64_t Imm) const {
610906c3fb27SDimitry Andric   return isInt<12>(Imm);
611006c3fb27SDimitry Andric }
611106c3fb27SDimitry Andric 
611206c3fb27SDimitry Andric bool LoongArchTargetLowering::isZExtFree(SDValue Val, EVT VT2) const {
611306c3fb27SDimitry Andric   // Zexts are free if they can be combined with a load.
611406c3fb27SDimitry Andric   // Don't advertise i32->i64 zextload as being free for LA64. It interacts
611506c3fb27SDimitry Andric   // poorly with type legalization of compares preferring sext.
611606c3fb27SDimitry Andric   if (auto *LD = dyn_cast<LoadSDNode>(Val)) {
611706c3fb27SDimitry Andric     EVT MemVT = LD->getMemoryVT();
611806c3fb27SDimitry Andric     if ((MemVT == MVT::i8 || MemVT == MVT::i16) &&
611906c3fb27SDimitry Andric         (LD->getExtensionType() == ISD::NON_EXTLOAD ||
612006c3fb27SDimitry Andric          LD->getExtensionType() == ISD::ZEXTLOAD))
612106c3fb27SDimitry Andric       return true;
612206c3fb27SDimitry Andric   }
612306c3fb27SDimitry Andric 
612406c3fb27SDimitry Andric   return TargetLowering::isZExtFree(Val, VT2);
612506c3fb27SDimitry Andric }
612606c3fb27SDimitry Andric 
6127*0fca6ea1SDimitry Andric bool LoongArchTargetLowering::isSExtCheaperThanZExt(EVT SrcVT,
6128*0fca6ea1SDimitry Andric                                                     EVT DstVT) const {
612906c3fb27SDimitry Andric   return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64;
613006c3fb27SDimitry Andric }
613106c3fb27SDimitry Andric 
6132*0fca6ea1SDimitry Andric bool LoongArchTargetLowering::signExtendConstant(const ConstantInt *CI) const {
6133*0fca6ea1SDimitry Andric   return Subtarget.is64Bit() && CI->getType()->isIntegerTy(32);
6134*0fca6ea1SDimitry Andric }
6135*0fca6ea1SDimitry Andric 
613606c3fb27SDimitry Andric bool LoongArchTargetLowering::hasAndNotCompare(SDValue Y) const {
613706c3fb27SDimitry Andric   // TODO: Support vectors.
613806c3fb27SDimitry Andric   if (Y.getValueType().isVector())
613906c3fb27SDimitry Andric     return false;
614006c3fb27SDimitry Andric 
614106c3fb27SDimitry Andric   return !isa<ConstantSDNode>(Y);
614206c3fb27SDimitry Andric }
6143439352acSDimitry Andric 
6144439352acSDimitry Andric ISD::NodeType LoongArchTargetLowering::getExtendForAtomicCmpSwapArg() const {
6145439352acSDimitry Andric   // TODO: LAMCAS will use amcas{_DB,}.[bhwd] which does not require extension.
6146439352acSDimitry Andric   return ISD::SIGN_EXTEND;
6147439352acSDimitry Andric }
6148*0fca6ea1SDimitry Andric 
6149*0fca6ea1SDimitry Andric bool LoongArchTargetLowering::shouldSignExtendTypeInLibCall(
6150*0fca6ea1SDimitry Andric     EVT Type, bool IsSigned) const {
6151*0fca6ea1SDimitry Andric   if (Subtarget.is64Bit() && Type == MVT::i32)
6152*0fca6ea1SDimitry Andric     return true;
6153*0fca6ea1SDimitry Andric 
6154*0fca6ea1SDimitry Andric   return IsSigned;
6155*0fca6ea1SDimitry Andric }
6156*0fca6ea1SDimitry Andric 
6157*0fca6ea1SDimitry Andric bool LoongArchTargetLowering::shouldExtendTypeInLibCall(EVT Type) const {
6158*0fca6ea1SDimitry Andric   // Return false to suppress the unnecessary extensions if the LibCall
6159*0fca6ea1SDimitry Andric   // arguments or return value is a float narrower than GRLEN on a soft FP ABI.
6160*0fca6ea1SDimitry Andric   if (Subtarget.isSoftFPABI() && (Type.isFloatingPoint() && !Type.isVector() &&
6161*0fca6ea1SDimitry Andric                                   Type.getSizeInBits() < Subtarget.getGRLen()))
6162*0fca6ea1SDimitry Andric     return false;
6163*0fca6ea1SDimitry Andric   return true;
6164*0fca6ea1SDimitry Andric }
6165