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