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