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" 250fca6ea1SDimitry 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()) { 1240fca6ea1SDimitry Andric setOperationAction(ISD::ADD, MVT::i32, Custom); 1250fca6ea1SDimitry 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); 1440fca6ea1SDimitry 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()) { 1660fca6ea1SDimitry Andric setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand); 1670fca6ea1SDimitry 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); 1830fca6ea1SDimitry Andric setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand); 1840fca6ea1SDimitry 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()) { 2010fca6ea1SDimitry Andric setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand); 2025f757f3fSDimitry Andric setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); 2030fca6ea1SDimitry 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); 2200fca6ea1SDimitry Andric setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand); 2210fca6ea1SDimitry 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); 2550fca6ea1SDimitry 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); 298*6e516c87SDimitry Andric setOperationAction(ISD::CONCAT_VECTORS, VT, Legal); 2995f757f3fSDimitry Andric 3005f757f3fSDimitry Andric setOperationAction(ISD::SETCC, VT, Legal); 3015f757f3fSDimitry Andric setOperationAction(ISD::VSELECT, VT, Legal); 3020fca6ea1SDimitry Andric setOperationAction(ISD::VECTOR_SHUFFLE, VT, Custom); 3035f757f3fSDimitry Andric } 3045f757f3fSDimitry Andric for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16, MVT::v32i8}) { 3055f757f3fSDimitry Andric setOperationAction({ISD::ADD, ISD::SUB}, VT, Legal); 3065f757f3fSDimitry Andric setOperationAction({ISD::UMAX, ISD::UMIN, ISD::SMAX, ISD::SMIN}, VT, 3075f757f3fSDimitry Andric Legal); 3085f757f3fSDimitry Andric setOperationAction({ISD::MUL, ISD::SDIV, ISD::SREM, ISD::UDIV, ISD::UREM}, 3095f757f3fSDimitry Andric VT, Legal); 3105f757f3fSDimitry Andric setOperationAction({ISD::AND, ISD::OR, ISD::XOR}, VT, Legal); 3115f757f3fSDimitry Andric setOperationAction({ISD::SHL, ISD::SRA, ISD::SRL}, VT, Legal); 3125f757f3fSDimitry Andric setOperationAction({ISD::CTPOP, ISD::CTLZ}, VT, Legal); 3135f757f3fSDimitry Andric setOperationAction({ISD::MULHS, ISD::MULHU}, VT, Legal); 3145f757f3fSDimitry Andric setCondCodeAction( 3155f757f3fSDimitry Andric {ISD::SETNE, ISD::SETGE, ISD::SETGT, ISD::SETUGE, ISD::SETUGT}, VT, 3165f757f3fSDimitry Andric Expand); 3175f757f3fSDimitry Andric } 3187a6dacacSDimitry Andric for (MVT VT : {MVT::v8i32, MVT::v4i32, MVT::v4i64}) { 3197a6dacacSDimitry Andric setOperationAction({ISD::SINT_TO_FP, ISD::UINT_TO_FP}, VT, Legal); 3207a6dacacSDimitry Andric setOperationAction({ISD::FP_TO_SINT, ISD::FP_TO_UINT}, VT, Legal); 3217a6dacacSDimitry Andric } 3225f757f3fSDimitry Andric for (MVT VT : {MVT::v8f32, MVT::v4f64}) { 3235f757f3fSDimitry Andric setOperationAction({ISD::FADD, ISD::FSUB}, VT, Legal); 3245f757f3fSDimitry Andric setOperationAction({ISD::FMUL, ISD::FDIV}, VT, Legal); 3255f757f3fSDimitry Andric setOperationAction(ISD::FMA, VT, Legal); 3265f757f3fSDimitry Andric setOperationAction(ISD::FSQRT, VT, Legal); 3275f757f3fSDimitry Andric setOperationAction(ISD::FNEG, VT, Legal); 3285f757f3fSDimitry Andric setCondCodeAction({ISD::SETGE, ISD::SETGT, ISD::SETOGE, ISD::SETOGT, 3295f757f3fSDimitry Andric ISD::SETUGE, ISD::SETUGT}, 3305f757f3fSDimitry Andric VT, Expand); 3315f757f3fSDimitry Andric } 3325f757f3fSDimitry Andric } 3335f757f3fSDimitry Andric 3345f757f3fSDimitry Andric // Set DAG combine for LA32 and LA64. 3355f757f3fSDimitry Andric 3365f757f3fSDimitry Andric setTargetDAGCombine(ISD::AND); 3375f757f3fSDimitry Andric setTargetDAGCombine(ISD::OR); 3385f757f3fSDimitry Andric setTargetDAGCombine(ISD::SRL); 3390fca6ea1SDimitry Andric setTargetDAGCombine(ISD::SETCC); 3405f757f3fSDimitry Andric 3415f757f3fSDimitry Andric // Set DAG combine for 'LSX' feature. 3425f757f3fSDimitry Andric 3435f757f3fSDimitry Andric if (Subtarget.hasExtLSX()) 3445f757f3fSDimitry Andric setTargetDAGCombine(ISD::INTRINSIC_WO_CHAIN); 34581ad6265SDimitry Andric 34681ad6265SDimitry Andric // Compute derived properties from the register classes. 34706c3fb27SDimitry Andric computeRegisterProperties(Subtarget.getRegisterInfo()); 34881ad6265SDimitry Andric 34981ad6265SDimitry Andric setStackPointerRegisterToSaveRestore(LoongArch::R3); 35081ad6265SDimitry Andric 35181ad6265SDimitry Andric setBooleanContents(ZeroOrOneBooleanContent); 3525f757f3fSDimitry Andric setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); 35381ad6265SDimitry Andric 354753f127fSDimitry Andric setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen()); 355753f127fSDimitry Andric 356bdd1243dSDimitry Andric setMinCmpXchgSizeInBits(32); 357bdd1243dSDimitry Andric 35881ad6265SDimitry Andric // Function alignments. 35906c3fb27SDimitry Andric setMinFunctionAlignment(Align(4)); 36006c3fb27SDimitry Andric // Set preferred alignments. 36106c3fb27SDimitry Andric setPrefFunctionAlignment(Subtarget.getPrefFunctionAlignment()); 36206c3fb27SDimitry Andric setPrefLoopAlignment(Subtarget.getPrefLoopAlignment()); 36306c3fb27SDimitry Andric setMaxBytesForAlignment(Subtarget.getMaxBytesForAlignment()); 36481ad6265SDimitry Andric } 36581ad6265SDimitry Andric 366bdd1243dSDimitry Andric bool LoongArchTargetLowering::isOffsetFoldingLegal( 367bdd1243dSDimitry Andric const GlobalAddressSDNode *GA) const { 368bdd1243dSDimitry Andric // In order to maximise the opportunity for common subexpression elimination, 369bdd1243dSDimitry Andric // keep a separate ADD node for the global address offset instead of folding 370bdd1243dSDimitry Andric // it in the global address node. Later peephole optimisations may choose to 371bdd1243dSDimitry Andric // fold it back in when profitable. 372bdd1243dSDimitry Andric return false; 373bdd1243dSDimitry Andric } 374bdd1243dSDimitry Andric 37581ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerOperation(SDValue Op, 37681ad6265SDimitry Andric SelectionDAG &DAG) const { 37781ad6265SDimitry Andric switch (Op.getOpcode()) { 3785f757f3fSDimitry Andric case ISD::ATOMIC_FENCE: 3795f757f3fSDimitry Andric return lowerATOMIC_FENCE(Op, DAG); 380bdd1243dSDimitry Andric case ISD::EH_DWARF_CFA: 381bdd1243dSDimitry Andric return lowerEH_DWARF_CFA(Op, DAG); 382753f127fSDimitry Andric case ISD::GlobalAddress: 383753f127fSDimitry Andric return lowerGlobalAddress(Op, DAG); 384bdd1243dSDimitry Andric case ISD::GlobalTLSAddress: 385bdd1243dSDimitry Andric return lowerGlobalTLSAddress(Op, DAG); 386bdd1243dSDimitry Andric case ISD::INTRINSIC_WO_CHAIN: 387bdd1243dSDimitry Andric return lowerINTRINSIC_WO_CHAIN(Op, DAG); 388bdd1243dSDimitry Andric case ISD::INTRINSIC_W_CHAIN: 389bdd1243dSDimitry Andric return lowerINTRINSIC_W_CHAIN(Op, DAG); 390bdd1243dSDimitry Andric case ISD::INTRINSIC_VOID: 391bdd1243dSDimitry Andric return lowerINTRINSIC_VOID(Op, DAG); 392bdd1243dSDimitry Andric case ISD::BlockAddress: 393bdd1243dSDimitry Andric return lowerBlockAddress(Op, DAG); 394bdd1243dSDimitry Andric case ISD::JumpTable: 395bdd1243dSDimitry Andric return lowerJumpTable(Op, DAG); 39681ad6265SDimitry Andric case ISD::SHL_PARTS: 39781ad6265SDimitry Andric return lowerShiftLeftParts(Op, DAG); 39881ad6265SDimitry Andric case ISD::SRA_PARTS: 39981ad6265SDimitry Andric return lowerShiftRightParts(Op, DAG, true); 40081ad6265SDimitry Andric case ISD::SRL_PARTS: 40181ad6265SDimitry Andric return lowerShiftRightParts(Op, DAG, false); 402753f127fSDimitry Andric case ISD::ConstantPool: 403753f127fSDimitry Andric return lowerConstantPool(Op, DAG); 404753f127fSDimitry Andric case ISD::FP_TO_SINT: 405753f127fSDimitry Andric return lowerFP_TO_SINT(Op, DAG); 406753f127fSDimitry Andric case ISD::BITCAST: 407753f127fSDimitry Andric return lowerBITCAST(Op, DAG); 408753f127fSDimitry Andric case ISD::UINT_TO_FP: 409753f127fSDimitry Andric return lowerUINT_TO_FP(Op, DAG); 410bdd1243dSDimitry Andric case ISD::SINT_TO_FP: 411bdd1243dSDimitry Andric return lowerSINT_TO_FP(Op, DAG); 412bdd1243dSDimitry Andric case ISD::VASTART: 413bdd1243dSDimitry Andric return lowerVASTART(Op, DAG); 414bdd1243dSDimitry Andric case ISD::FRAMEADDR: 415bdd1243dSDimitry Andric return lowerFRAMEADDR(Op, DAG); 416bdd1243dSDimitry Andric case ISD::RETURNADDR: 417bdd1243dSDimitry Andric return lowerRETURNADDR(Op, DAG); 418bdd1243dSDimitry Andric case ISD::WRITE_REGISTER: 419bdd1243dSDimitry Andric return lowerWRITE_REGISTER(Op, DAG); 4205f757f3fSDimitry Andric case ISD::INSERT_VECTOR_ELT: 4215f757f3fSDimitry Andric return lowerINSERT_VECTOR_ELT(Op, DAG); 422647cbc5dSDimitry Andric case ISD::EXTRACT_VECTOR_ELT: 423647cbc5dSDimitry Andric return lowerEXTRACT_VECTOR_ELT(Op, DAG); 4245f757f3fSDimitry Andric case ISD::BUILD_VECTOR: 4255f757f3fSDimitry Andric return lowerBUILD_VECTOR(Op, DAG); 4265f757f3fSDimitry Andric case ISD::VECTOR_SHUFFLE: 4275f757f3fSDimitry Andric return lowerVECTOR_SHUFFLE(Op, DAG); 42881ad6265SDimitry Andric } 429bdd1243dSDimitry Andric return SDValue(); 430bdd1243dSDimitry Andric } 431bdd1243dSDimitry Andric 4320fca6ea1SDimitry Andric /// Determine whether a range fits a regular pattern of values. 4330fca6ea1SDimitry Andric /// This function accounts for the possibility of jumping over the End iterator. 4340fca6ea1SDimitry Andric template <typename ValType> 4350fca6ea1SDimitry Andric static bool 4360fca6ea1SDimitry Andric fitsRegularPattern(typename SmallVectorImpl<ValType>::const_iterator Begin, 4370fca6ea1SDimitry Andric unsigned CheckStride, 4380fca6ea1SDimitry Andric typename SmallVectorImpl<ValType>::const_iterator End, 4390fca6ea1SDimitry Andric ValType ExpectedIndex, unsigned ExpectedIndexStride) { 4400fca6ea1SDimitry Andric auto &I = Begin; 4410fca6ea1SDimitry Andric 4420fca6ea1SDimitry Andric while (I != End) { 4430fca6ea1SDimitry Andric if (*I != -1 && *I != ExpectedIndex) 4440fca6ea1SDimitry Andric return false; 4450fca6ea1SDimitry Andric ExpectedIndex += ExpectedIndexStride; 4460fca6ea1SDimitry Andric 4470fca6ea1SDimitry Andric // Incrementing past End is undefined behaviour so we must increment one 4480fca6ea1SDimitry Andric // step at a time and check for End at each step. 4490fca6ea1SDimitry Andric for (unsigned n = 0; n < CheckStride && I != End; ++n, ++I) 4500fca6ea1SDimitry Andric ; // Empty loop body. 4510fca6ea1SDimitry Andric } 4520fca6ea1SDimitry Andric return true; 4530fca6ea1SDimitry Andric } 4540fca6ea1SDimitry Andric 4550fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VREPLVEI (if possible). 4560fca6ea1SDimitry Andric /// 4570fca6ea1SDimitry Andric /// VREPLVEI performs vector broadcast based on an element specified by an 4580fca6ea1SDimitry Andric /// integer immediate, with its mask being similar to: 4590fca6ea1SDimitry Andric /// <x, x, x, ...> 4600fca6ea1SDimitry Andric /// where x is any valid index. 4610fca6ea1SDimitry Andric /// 4620fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever 4630fca6ea1SDimitry Andric /// value is necessary in order to fit the above form. 4640fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VREPLVEI(const SDLoc &DL, ArrayRef<int> Mask, 4650fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 4660fca6ea1SDimitry Andric SelectionDAG &DAG) { 4670fca6ea1SDimitry Andric int SplatIndex = -1; 4680fca6ea1SDimitry Andric for (const auto &M : Mask) { 4690fca6ea1SDimitry Andric if (M != -1) { 4700fca6ea1SDimitry Andric SplatIndex = M; 4710fca6ea1SDimitry Andric break; 4720fca6ea1SDimitry Andric } 4730fca6ea1SDimitry Andric } 4740fca6ea1SDimitry Andric 4750fca6ea1SDimitry Andric if (SplatIndex == -1) 4760fca6ea1SDimitry Andric return DAG.getUNDEF(VT); 4770fca6ea1SDimitry Andric 4780fca6ea1SDimitry Andric assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index"); 4790fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Mask.begin(), 1, Mask.end(), SplatIndex, 0)) { 4800fca6ea1SDimitry Andric APInt Imm(64, SplatIndex); 4810fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1, 4820fca6ea1SDimitry Andric DAG.getConstant(Imm, DL, MVT::i64)); 4830fca6ea1SDimitry Andric } 4840fca6ea1SDimitry Andric 4850fca6ea1SDimitry Andric return SDValue(); 4860fca6ea1SDimitry Andric } 4870fca6ea1SDimitry Andric 4880fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VSHUF4I (if possible). 4890fca6ea1SDimitry Andric /// 4900fca6ea1SDimitry Andric /// VSHUF4I splits the vector into blocks of four elements, then shuffles these 4910fca6ea1SDimitry Andric /// elements according to a <4 x i2> constant (encoded as an integer immediate). 4920fca6ea1SDimitry Andric /// 4930fca6ea1SDimitry Andric /// It is therefore possible to lower into VSHUF4I when the mask takes the form: 4940fca6ea1SDimitry Andric /// <a, b, c, d, a+4, b+4, c+4, d+4, a+8, b+8, c+8, d+8, ...> 4950fca6ea1SDimitry Andric /// When undef's appear they are treated as if they were whatever value is 4960fca6ea1SDimitry Andric /// necessary in order to fit the above forms. 4970fca6ea1SDimitry Andric /// 4980fca6ea1SDimitry Andric /// For example: 4990fca6ea1SDimitry Andric /// %2 = shufflevector <8 x i16> %0, <8 x i16> undef, 5000fca6ea1SDimitry Andric /// <8 x i32> <i32 3, i32 2, i32 1, i32 0, 5010fca6ea1SDimitry Andric /// i32 7, i32 6, i32 5, i32 4> 5020fca6ea1SDimitry Andric /// is lowered to: 5030fca6ea1SDimitry Andric /// (VSHUF4I_H $v0, $v1, 27) 5040fca6ea1SDimitry Andric /// where the 27 comes from: 5050fca6ea1SDimitry Andric /// 3 + (2 << 2) + (1 << 4) + (0 << 6) 5060fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VSHUF4I(const SDLoc &DL, ArrayRef<int> Mask, 5070fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 5080fca6ea1SDimitry Andric SelectionDAG &DAG) { 5090fca6ea1SDimitry Andric 5100fca6ea1SDimitry Andric // When the size is less than 4, lower cost instructions may be used. 5110fca6ea1SDimitry Andric if (Mask.size() < 4) 5120fca6ea1SDimitry Andric return SDValue(); 5130fca6ea1SDimitry Andric 5140fca6ea1SDimitry Andric int SubMask[4] = {-1, -1, -1, -1}; 5150fca6ea1SDimitry Andric for (unsigned i = 0; i < 4; ++i) { 5160fca6ea1SDimitry Andric for (unsigned j = i; j < Mask.size(); j += 4) { 5170fca6ea1SDimitry Andric int Idx = Mask[j]; 5180fca6ea1SDimitry Andric 5190fca6ea1SDimitry Andric // Convert from vector index to 4-element subvector index 5200fca6ea1SDimitry Andric // If an index refers to an element outside of the subvector then give up 5210fca6ea1SDimitry Andric if (Idx != -1) { 5220fca6ea1SDimitry Andric Idx -= 4 * (j / 4); 5230fca6ea1SDimitry Andric if (Idx < 0 || Idx >= 4) 5240fca6ea1SDimitry Andric return SDValue(); 5250fca6ea1SDimitry Andric } 5260fca6ea1SDimitry Andric 5270fca6ea1SDimitry Andric // If the mask has an undef, replace it with the current index. 5280fca6ea1SDimitry Andric // Note that it might still be undef if the current index is also undef 5290fca6ea1SDimitry Andric if (SubMask[i] == -1) 5300fca6ea1SDimitry Andric SubMask[i] = Idx; 5310fca6ea1SDimitry Andric // Check that non-undef values are the same as in the mask. If they 5320fca6ea1SDimitry Andric // aren't then give up 5330fca6ea1SDimitry Andric else if (Idx != -1 && Idx != SubMask[i]) 5340fca6ea1SDimitry Andric return SDValue(); 5350fca6ea1SDimitry Andric } 5360fca6ea1SDimitry Andric } 5370fca6ea1SDimitry Andric 5380fca6ea1SDimitry Andric // Calculate the immediate. Replace any remaining undefs with zero 5390fca6ea1SDimitry Andric APInt Imm(64, 0); 5400fca6ea1SDimitry Andric for (int i = 3; i >= 0; --i) { 5410fca6ea1SDimitry Andric int Idx = SubMask[i]; 5420fca6ea1SDimitry Andric 5430fca6ea1SDimitry Andric if (Idx == -1) 5440fca6ea1SDimitry Andric Idx = 0; 5450fca6ea1SDimitry Andric 5460fca6ea1SDimitry Andric Imm <<= 2; 5470fca6ea1SDimitry Andric Imm |= Idx & 0x3; 5480fca6ea1SDimitry Andric } 5490fca6ea1SDimitry Andric 5500fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT, V1, 5510fca6ea1SDimitry Andric DAG.getConstant(Imm, DL, MVT::i64)); 5520fca6ea1SDimitry Andric } 5530fca6ea1SDimitry Andric 5540fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VPACKEV (if possible). 5550fca6ea1SDimitry Andric /// 5560fca6ea1SDimitry Andric /// VPACKEV interleaves the even elements from each vector. 5570fca6ea1SDimitry Andric /// 5580fca6ea1SDimitry Andric /// It is possible to lower into VPACKEV when the mask consists of two of the 5590fca6ea1SDimitry Andric /// following forms interleaved: 5600fca6ea1SDimitry Andric /// <0, 2, 4, ...> 5610fca6ea1SDimitry Andric /// <n, n+2, n+4, ...> 5620fca6ea1SDimitry Andric /// where n is the number of elements in the vector. 5630fca6ea1SDimitry Andric /// For example: 5640fca6ea1SDimitry Andric /// <0, 0, 2, 2, 4, 4, ...> 5650fca6ea1SDimitry Andric /// <0, n, 2, n+2, 4, n+4, ...> 5660fca6ea1SDimitry Andric /// 5670fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever 5680fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms. 5690fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VPACKEV(const SDLoc &DL, ArrayRef<int> Mask, 5700fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 5710fca6ea1SDimitry Andric SelectionDAG &DAG) { 5720fca6ea1SDimitry Andric 5730fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 5740fca6ea1SDimitry Andric const auto &End = Mask.end(); 5750fca6ea1SDimitry Andric SDValue OriV1 = V1, OriV2 = V2; 5760fca6ea1SDimitry Andric 5770fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin, 2, End, 0, 2)) 5780fca6ea1SDimitry Andric V1 = OriV1; 5790fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 2)) 5800fca6ea1SDimitry Andric V1 = OriV2; 5810fca6ea1SDimitry Andric else 5820fca6ea1SDimitry Andric return SDValue(); 5830fca6ea1SDimitry Andric 5840fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 2)) 5850fca6ea1SDimitry Andric V2 = OriV1; 5860fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 2)) 5870fca6ea1SDimitry Andric V2 = OriV2; 5880fca6ea1SDimitry Andric else 5890fca6ea1SDimitry Andric return SDValue(); 5900fca6ea1SDimitry Andric 5910fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VPACKEV, DL, VT, V2, V1); 5920fca6ea1SDimitry Andric } 5930fca6ea1SDimitry Andric 5940fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VPACKOD (if possible). 5950fca6ea1SDimitry Andric /// 5960fca6ea1SDimitry Andric /// VPACKOD interleaves the odd elements from each vector. 5970fca6ea1SDimitry Andric /// 5980fca6ea1SDimitry Andric /// It is possible to lower into VPACKOD when the mask consists of two of the 5990fca6ea1SDimitry Andric /// following forms interleaved: 6000fca6ea1SDimitry Andric /// <1, 3, 5, ...> 6010fca6ea1SDimitry Andric /// <n+1, n+3, n+5, ...> 6020fca6ea1SDimitry Andric /// where n is the number of elements in the vector. 6030fca6ea1SDimitry Andric /// For example: 6040fca6ea1SDimitry Andric /// <1, 1, 3, 3, 5, 5, ...> 6050fca6ea1SDimitry Andric /// <1, n+1, 3, n+3, 5, n+5, ...> 6060fca6ea1SDimitry Andric /// 6070fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever 6080fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms. 6090fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VPACKOD(const SDLoc &DL, ArrayRef<int> Mask, 6100fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 6110fca6ea1SDimitry Andric SelectionDAG &DAG) { 6120fca6ea1SDimitry Andric 6130fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 6140fca6ea1SDimitry Andric const auto &End = Mask.end(); 6150fca6ea1SDimitry Andric SDValue OriV1 = V1, OriV2 = V2; 6160fca6ea1SDimitry Andric 6170fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin, 2, End, 1, 2)) 6180fca6ea1SDimitry Andric V1 = OriV1; 6190fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + 1, 2)) 6200fca6ea1SDimitry Andric V1 = OriV2; 6210fca6ea1SDimitry Andric else 6220fca6ea1SDimitry Andric return SDValue(); 6230fca6ea1SDimitry Andric 6240fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin + 1, 2, End, 1, 2)) 6250fca6ea1SDimitry Andric V2 = OriV1; 6260fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + 1, 2)) 6270fca6ea1SDimitry Andric V2 = OriV2; 6280fca6ea1SDimitry Andric else 6290fca6ea1SDimitry Andric return SDValue(); 6300fca6ea1SDimitry Andric 6310fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VPACKOD, DL, VT, V2, V1); 6320fca6ea1SDimitry Andric } 6330fca6ea1SDimitry Andric 6340fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VILVH (if possible). 6350fca6ea1SDimitry Andric /// 6360fca6ea1SDimitry Andric /// VILVH interleaves consecutive elements from the left (highest-indexed) half 6370fca6ea1SDimitry Andric /// of each vector. 6380fca6ea1SDimitry Andric /// 6390fca6ea1SDimitry Andric /// It is possible to lower into VILVH when the mask consists of two of the 6400fca6ea1SDimitry Andric /// following forms interleaved: 6410fca6ea1SDimitry Andric /// <x, x+1, x+2, ...> 6420fca6ea1SDimitry Andric /// <n+x, n+x+1, n+x+2, ...> 6430fca6ea1SDimitry Andric /// where n is the number of elements in the vector and x is half n. 6440fca6ea1SDimitry Andric /// For example: 6450fca6ea1SDimitry Andric /// <x, x, x+1, x+1, x+2, x+2, ...> 6460fca6ea1SDimitry Andric /// <x, n+x, x+1, n+x+1, x+2, n+x+2, ...> 6470fca6ea1SDimitry Andric /// 6480fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever 6490fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms. 6500fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VILVH(const SDLoc &DL, ArrayRef<int> Mask, 6510fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 6520fca6ea1SDimitry Andric SelectionDAG &DAG) { 6530fca6ea1SDimitry Andric 6540fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 6550fca6ea1SDimitry Andric const auto &End = Mask.end(); 6560fca6ea1SDimitry Andric unsigned HalfSize = Mask.size() / 2; 6570fca6ea1SDimitry Andric SDValue OriV1 = V1, OriV2 = V2; 6580fca6ea1SDimitry Andric 6590fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin, 2, End, HalfSize, 1)) 6600fca6ea1SDimitry Andric V1 = OriV1; 6610fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + HalfSize, 1)) 6620fca6ea1SDimitry Andric V1 = OriV2; 6630fca6ea1SDimitry Andric else 6640fca6ea1SDimitry Andric return SDValue(); 6650fca6ea1SDimitry Andric 6660fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin + 1, 2, End, HalfSize, 1)) 6670fca6ea1SDimitry Andric V2 = OriV1; 6680fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + HalfSize, 6690fca6ea1SDimitry Andric 1)) 6700fca6ea1SDimitry Andric V2 = OriV2; 6710fca6ea1SDimitry Andric else 6720fca6ea1SDimitry Andric return SDValue(); 6730fca6ea1SDimitry Andric 6740fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1); 6750fca6ea1SDimitry Andric } 6760fca6ea1SDimitry Andric 6770fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VILVL (if possible). 6780fca6ea1SDimitry Andric /// 6790fca6ea1SDimitry Andric /// VILVL interleaves consecutive elements from the right (lowest-indexed) half 6800fca6ea1SDimitry Andric /// of each vector. 6810fca6ea1SDimitry Andric /// 6820fca6ea1SDimitry Andric /// It is possible to lower into VILVL when the mask consists of two of the 6830fca6ea1SDimitry Andric /// following forms interleaved: 6840fca6ea1SDimitry Andric /// <0, 1, 2, ...> 6850fca6ea1SDimitry Andric /// <n, n+1, n+2, ...> 6860fca6ea1SDimitry Andric /// where n is the number of elements in the vector. 6870fca6ea1SDimitry Andric /// For example: 6880fca6ea1SDimitry Andric /// <0, 0, 1, 1, 2, 2, ...> 6890fca6ea1SDimitry Andric /// <0, n, 1, n+1, 2, n+2, ...> 6900fca6ea1SDimitry Andric /// 6910fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever 6920fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms. 6930fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VILVL(const SDLoc &DL, ArrayRef<int> Mask, 6940fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 6950fca6ea1SDimitry Andric SelectionDAG &DAG) { 6960fca6ea1SDimitry Andric 6970fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 6980fca6ea1SDimitry Andric const auto &End = Mask.end(); 6990fca6ea1SDimitry Andric SDValue OriV1 = V1, OriV2 = V2; 7000fca6ea1SDimitry Andric 7010fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin, 2, End, 0, 1)) 7020fca6ea1SDimitry Andric V1 = OriV1; 7030fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 1)) 7040fca6ea1SDimitry Andric V1 = OriV2; 7050fca6ea1SDimitry Andric else 7060fca6ea1SDimitry Andric return SDValue(); 7070fca6ea1SDimitry Andric 7080fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 1)) 7090fca6ea1SDimitry Andric V2 = OriV1; 7100fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 1)) 7110fca6ea1SDimitry Andric V2 = OriV2; 7120fca6ea1SDimitry Andric else 7130fca6ea1SDimitry Andric return SDValue(); 7140fca6ea1SDimitry Andric 7150fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1); 7160fca6ea1SDimitry Andric } 7170fca6ea1SDimitry Andric 7180fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VPICKEV (if possible). 7190fca6ea1SDimitry Andric /// 7200fca6ea1SDimitry Andric /// VPICKEV copies the even elements of each vector into the result vector. 7210fca6ea1SDimitry Andric /// 7220fca6ea1SDimitry Andric /// It is possible to lower into VPICKEV when the mask consists of two of the 7230fca6ea1SDimitry Andric /// following forms concatenated: 7240fca6ea1SDimitry Andric /// <0, 2, 4, ...> 7250fca6ea1SDimitry Andric /// <n, n+2, n+4, ...> 7260fca6ea1SDimitry Andric /// where n is the number of elements in the vector. 7270fca6ea1SDimitry Andric /// For example: 7280fca6ea1SDimitry Andric /// <0, 2, 4, ..., 0, 2, 4, ...> 7290fca6ea1SDimitry Andric /// <0, 2, 4, ..., n, n+2, n+4, ...> 7300fca6ea1SDimitry Andric /// 7310fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever 7320fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms. 7330fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VPICKEV(const SDLoc &DL, ArrayRef<int> Mask, 7340fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 7350fca6ea1SDimitry Andric SelectionDAG &DAG) { 7360fca6ea1SDimitry Andric 7370fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 7380fca6ea1SDimitry Andric const auto &Mid = Mask.begin() + Mask.size() / 2; 7390fca6ea1SDimitry Andric const auto &End = Mask.end(); 7400fca6ea1SDimitry Andric SDValue OriV1 = V1, OriV2 = V2; 7410fca6ea1SDimitry Andric 7420fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin, 1, Mid, 0, 2)) 7430fca6ea1SDimitry Andric V1 = OriV1; 7440fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size(), 2)) 7450fca6ea1SDimitry Andric V1 = OriV2; 7460fca6ea1SDimitry Andric else 7470fca6ea1SDimitry Andric return SDValue(); 7480fca6ea1SDimitry Andric 7490fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Mid, 1, End, 0, 2)) 7500fca6ea1SDimitry Andric V2 = OriV1; 7510fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size(), 2)) 7520fca6ea1SDimitry Andric V2 = OriV2; 7530fca6ea1SDimitry Andric 7540fca6ea1SDimitry Andric else 7550fca6ea1SDimitry Andric return SDValue(); 7560fca6ea1SDimitry Andric 7570fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1); 7580fca6ea1SDimitry Andric } 7590fca6ea1SDimitry Andric 7600fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VPICKOD (if possible). 7610fca6ea1SDimitry Andric /// 7620fca6ea1SDimitry Andric /// VPICKOD copies the odd elements of each vector into the result vector. 7630fca6ea1SDimitry Andric /// 7640fca6ea1SDimitry Andric /// It is possible to lower into VPICKOD when the mask consists of two of the 7650fca6ea1SDimitry Andric /// following forms concatenated: 7660fca6ea1SDimitry Andric /// <1, 3, 5, ...> 7670fca6ea1SDimitry Andric /// <n+1, n+3, n+5, ...> 7680fca6ea1SDimitry Andric /// where n is the number of elements in the vector. 7690fca6ea1SDimitry Andric /// For example: 7700fca6ea1SDimitry Andric /// <1, 3, 5, ..., 1, 3, 5, ...> 7710fca6ea1SDimitry Andric /// <1, 3, 5, ..., n+1, n+3, n+5, ...> 7720fca6ea1SDimitry Andric /// 7730fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever 7740fca6ea1SDimitry Andric /// value is necessary in order to fit the above forms. 7750fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VPICKOD(const SDLoc &DL, ArrayRef<int> Mask, 7760fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 7770fca6ea1SDimitry Andric SelectionDAG &DAG) { 7780fca6ea1SDimitry Andric 7790fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 7800fca6ea1SDimitry Andric const auto &Mid = Mask.begin() + Mask.size() / 2; 7810fca6ea1SDimitry Andric const auto &End = Mask.end(); 7820fca6ea1SDimitry Andric SDValue OriV1 = V1, OriV2 = V2; 7830fca6ea1SDimitry Andric 7840fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin, 1, Mid, 1, 2)) 7850fca6ea1SDimitry Andric V1 = OriV1; 7860fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size() + 1, 2)) 7870fca6ea1SDimitry Andric V1 = OriV2; 7880fca6ea1SDimitry Andric else 7890fca6ea1SDimitry Andric return SDValue(); 7900fca6ea1SDimitry Andric 7910fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Mid, 1, End, 1, 2)) 7920fca6ea1SDimitry Andric V2 = OriV1; 7930fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size() + 1, 2)) 7940fca6ea1SDimitry Andric V2 = OriV2; 7950fca6ea1SDimitry Andric else 7960fca6ea1SDimitry Andric return SDValue(); 7970fca6ea1SDimitry Andric 7980fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1); 7990fca6ea1SDimitry Andric } 8000fca6ea1SDimitry Andric 8010fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into VSHUF. 8020fca6ea1SDimitry Andric /// 8030fca6ea1SDimitry Andric /// This mostly consists of converting the shuffle mask into a BUILD_VECTOR and 8040fca6ea1SDimitry Andric /// adding it as an operand to the resulting VSHUF. 8050fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VSHUF(const SDLoc &DL, ArrayRef<int> Mask, 8060fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 8070fca6ea1SDimitry Andric SelectionDAG &DAG) { 8080fca6ea1SDimitry Andric 8090fca6ea1SDimitry Andric SmallVector<SDValue, 16> Ops; 8100fca6ea1SDimitry Andric for (auto M : Mask) 8110fca6ea1SDimitry Andric Ops.push_back(DAG.getConstant(M, DL, MVT::i64)); 8120fca6ea1SDimitry Andric 8130fca6ea1SDimitry Andric EVT MaskVecTy = VT.changeVectorElementTypeToInteger(); 8140fca6ea1SDimitry Andric SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, Ops); 8150fca6ea1SDimitry Andric 8160fca6ea1SDimitry Andric // VECTOR_SHUFFLE concatenates the vectors in an vectorwise fashion. 8170fca6ea1SDimitry Andric // <0b00, 0b01> + <0b10, 0b11> -> <0b00, 0b01, 0b10, 0b11> 8180fca6ea1SDimitry Andric // VSHF concatenates the vectors in a bitwise fashion: 8190fca6ea1SDimitry Andric // <0b00, 0b01> + <0b10, 0b11> -> 8200fca6ea1SDimitry Andric // 0b0100 + 0b1110 -> 0b01001110 8210fca6ea1SDimitry Andric // <0b10, 0b11, 0b00, 0b01> 8220fca6ea1SDimitry Andric // We must therefore swap the operands to get the correct result. 8230fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1); 8240fca6ea1SDimitry Andric } 8250fca6ea1SDimitry Andric 8260fca6ea1SDimitry Andric /// Dispatching routine to lower various 128-bit LoongArch vector shuffles. 8270fca6ea1SDimitry Andric /// 8280fca6ea1SDimitry Andric /// This routine breaks down the specific type of 128-bit shuffle and 8290fca6ea1SDimitry Andric /// dispatches to the lowering routines accordingly. 8300fca6ea1SDimitry Andric static SDValue lower128BitShuffle(const SDLoc &DL, ArrayRef<int> Mask, MVT VT, 8310fca6ea1SDimitry Andric SDValue V1, SDValue V2, SelectionDAG &DAG) { 8320fca6ea1SDimitry Andric assert((VT.SimpleTy == MVT::v16i8 || VT.SimpleTy == MVT::v8i16 || 8330fca6ea1SDimitry Andric VT.SimpleTy == MVT::v4i32 || VT.SimpleTy == MVT::v2i64 || 8340fca6ea1SDimitry Andric VT.SimpleTy == MVT::v4f32 || VT.SimpleTy == MVT::v2f64) && 8350fca6ea1SDimitry Andric "Vector type is unsupported for lsx!"); 8360fca6ea1SDimitry Andric assert(V1.getSimpleValueType() == V2.getSimpleValueType() && 8370fca6ea1SDimitry Andric "Two operands have different types!"); 8380fca6ea1SDimitry Andric assert(VT.getVectorNumElements() == Mask.size() && 8390fca6ea1SDimitry Andric "Unexpected mask size for shuffle!"); 8400fca6ea1SDimitry Andric assert(Mask.size() % 2 == 0 && "Expected even mask size."); 8410fca6ea1SDimitry Andric 8420fca6ea1SDimitry Andric SDValue Result; 8430fca6ea1SDimitry Andric // TODO: Add more comparison patterns. 8440fca6ea1SDimitry Andric if (V2.isUndef()) { 8450fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_VREPLVEI(DL, Mask, VT, V1, V2, DAG))) 8460fca6ea1SDimitry Andric return Result; 8470fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG))) 8480fca6ea1SDimitry Andric return Result; 8490fca6ea1SDimitry Andric 8500fca6ea1SDimitry Andric // TODO: This comment may be enabled in the future to better match the 8510fca6ea1SDimitry Andric // pattern for instruction selection. 8520fca6ea1SDimitry Andric /* V2 = V1; */ 8530fca6ea1SDimitry Andric } 8540fca6ea1SDimitry Andric 8550fca6ea1SDimitry Andric // It is recommended not to change the pattern comparison order for better 8560fca6ea1SDimitry Andric // performance. 8570fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG))) 8580fca6ea1SDimitry Andric return Result; 8590fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG))) 8600fca6ea1SDimitry Andric return Result; 8610fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_VILVH(DL, Mask, VT, V1, V2, DAG))) 8620fca6ea1SDimitry Andric return Result; 8630fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_VILVL(DL, Mask, VT, V1, V2, DAG))) 8640fca6ea1SDimitry Andric return Result; 8650fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_VPICKEV(DL, Mask, VT, V1, V2, DAG))) 8660fca6ea1SDimitry Andric return Result; 8670fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_VPICKOD(DL, Mask, VT, V1, V2, DAG))) 8680fca6ea1SDimitry Andric return Result; 8690fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_VSHUF(DL, Mask, VT, V1, V2, DAG))) 8700fca6ea1SDimitry Andric return Result; 8710fca6ea1SDimitry Andric 8720fca6ea1SDimitry Andric return SDValue(); 8730fca6ea1SDimitry Andric } 8740fca6ea1SDimitry Andric 8750fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVREPLVEI (if possible). 8760fca6ea1SDimitry Andric /// 8770fca6ea1SDimitry Andric /// It is a XVREPLVEI when the mask is: 8780fca6ea1SDimitry Andric /// <x, x, x, ..., x+n, x+n, x+n, ...> 8790fca6ea1SDimitry Andric /// where the number of x is equal to n and n is half the length of vector. 8800fca6ea1SDimitry Andric /// 8810fca6ea1SDimitry Andric /// When undef's appear in the mask they are treated as if they were whatever 8820fca6ea1SDimitry Andric /// value is necessary in order to fit the above form. 8830fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVREPLVEI(const SDLoc &DL, 8840fca6ea1SDimitry Andric ArrayRef<int> Mask, MVT VT, 8850fca6ea1SDimitry Andric SDValue V1, SDValue V2, 8860fca6ea1SDimitry Andric SelectionDAG &DAG) { 8870fca6ea1SDimitry Andric int SplatIndex = -1; 8880fca6ea1SDimitry Andric for (const auto &M : Mask) { 8890fca6ea1SDimitry Andric if (M != -1) { 8900fca6ea1SDimitry Andric SplatIndex = M; 8910fca6ea1SDimitry Andric break; 8920fca6ea1SDimitry Andric } 8930fca6ea1SDimitry Andric } 8940fca6ea1SDimitry Andric 8950fca6ea1SDimitry Andric if (SplatIndex == -1) 8960fca6ea1SDimitry Andric return DAG.getUNDEF(VT); 8970fca6ea1SDimitry Andric 8980fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 8990fca6ea1SDimitry Andric const auto &End = Mask.end(); 9000fca6ea1SDimitry Andric unsigned HalfSize = Mask.size() / 2; 9010fca6ea1SDimitry Andric 9020fca6ea1SDimitry Andric assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index"); 9030fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin, 1, End - HalfSize, SplatIndex, 0) && 9040fca6ea1SDimitry Andric fitsRegularPattern<int>(Begin + HalfSize, 1, End, SplatIndex + HalfSize, 9050fca6ea1SDimitry Andric 0)) { 9060fca6ea1SDimitry Andric APInt Imm(64, SplatIndex); 9070fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1, 9080fca6ea1SDimitry Andric DAG.getConstant(Imm, DL, MVT::i64)); 9090fca6ea1SDimitry Andric } 9100fca6ea1SDimitry Andric 9110fca6ea1SDimitry Andric return SDValue(); 9120fca6ea1SDimitry Andric } 9130fca6ea1SDimitry Andric 9140fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVSHUF4I (if possible). 9150fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVSHUF4I(const SDLoc &DL, ArrayRef<int> Mask, 9160fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 9170fca6ea1SDimitry Andric SelectionDAG &DAG) { 9180fca6ea1SDimitry Andric // When the size is less than or equal to 4, lower cost instructions may be 9190fca6ea1SDimitry Andric // used. 9200fca6ea1SDimitry Andric if (Mask.size() <= 4) 9210fca6ea1SDimitry Andric return SDValue(); 9220fca6ea1SDimitry Andric return lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG); 9230fca6ea1SDimitry Andric } 9240fca6ea1SDimitry Andric 9250fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVPACKEV (if possible). 9260fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVPACKEV(const SDLoc &DL, ArrayRef<int> Mask, 9270fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 9280fca6ea1SDimitry Andric SelectionDAG &DAG) { 9290fca6ea1SDimitry Andric return lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG); 9300fca6ea1SDimitry Andric } 9310fca6ea1SDimitry Andric 9320fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVPACKOD (if possible). 9330fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVPACKOD(const SDLoc &DL, ArrayRef<int> Mask, 9340fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 9350fca6ea1SDimitry Andric SelectionDAG &DAG) { 9360fca6ea1SDimitry Andric return lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG); 9370fca6ea1SDimitry Andric } 9380fca6ea1SDimitry Andric 9390fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVILVH (if possible). 9400fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVILVH(const SDLoc &DL, ArrayRef<int> Mask, 9410fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 9420fca6ea1SDimitry Andric SelectionDAG &DAG) { 9430fca6ea1SDimitry Andric 9440fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 9450fca6ea1SDimitry Andric const auto &End = Mask.end(); 9460fca6ea1SDimitry Andric unsigned HalfSize = Mask.size() / 2; 9470fca6ea1SDimitry Andric unsigned LeftSize = HalfSize / 2; 9480fca6ea1SDimitry Andric SDValue OriV1 = V1, OriV2 = V2; 9490fca6ea1SDimitry Andric 9500fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, HalfSize - LeftSize, 9510fca6ea1SDimitry Andric 1) && 9520fca6ea1SDimitry Andric fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize + LeftSize, 1)) 9530fca6ea1SDimitry Andric V1 = OriV1; 9540fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, 9550fca6ea1SDimitry Andric Mask.size() + HalfSize - LeftSize, 1) && 9560fca6ea1SDimitry Andric fitsRegularPattern<int>(Begin + HalfSize, 2, End, 9570fca6ea1SDimitry Andric Mask.size() + HalfSize + LeftSize, 1)) 9580fca6ea1SDimitry Andric V1 = OriV2; 9590fca6ea1SDimitry Andric else 9600fca6ea1SDimitry Andric return SDValue(); 9610fca6ea1SDimitry Andric 9620fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, HalfSize - LeftSize, 9630fca6ea1SDimitry Andric 1) && 9640fca6ea1SDimitry Andric fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize + LeftSize, 9650fca6ea1SDimitry Andric 1)) 9660fca6ea1SDimitry Andric V2 = OriV1; 9670fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, 9680fca6ea1SDimitry Andric Mask.size() + HalfSize - LeftSize, 1) && 9690fca6ea1SDimitry Andric fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, 9700fca6ea1SDimitry Andric Mask.size() + HalfSize + LeftSize, 1)) 9710fca6ea1SDimitry Andric V2 = OriV2; 9720fca6ea1SDimitry Andric else 9730fca6ea1SDimitry Andric return SDValue(); 9740fca6ea1SDimitry Andric 9750fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1); 9760fca6ea1SDimitry Andric } 9770fca6ea1SDimitry Andric 9780fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVILVL (if possible). 9790fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVILVL(const SDLoc &DL, ArrayRef<int> Mask, 9800fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 9810fca6ea1SDimitry Andric SelectionDAG &DAG) { 9820fca6ea1SDimitry Andric 9830fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 9840fca6ea1SDimitry Andric const auto &End = Mask.end(); 9850fca6ea1SDimitry Andric unsigned HalfSize = Mask.size() / 2; 9860fca6ea1SDimitry Andric SDValue OriV1 = V1, OriV2 = V2; 9870fca6ea1SDimitry Andric 9880fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, 0, 1) && 9890fca6ea1SDimitry Andric fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize, 1)) 9900fca6ea1SDimitry Andric V1 = OriV1; 9910fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, Mask.size(), 1) && 9920fca6ea1SDimitry Andric fitsRegularPattern<int>(Begin + HalfSize, 2, End, 9930fca6ea1SDimitry Andric Mask.size() + HalfSize, 1)) 9940fca6ea1SDimitry Andric V1 = OriV2; 9950fca6ea1SDimitry Andric else 9960fca6ea1SDimitry Andric return SDValue(); 9970fca6ea1SDimitry Andric 9980fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, 0, 1) && 9990fca6ea1SDimitry Andric fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize, 1)) 10000fca6ea1SDimitry Andric V2 = OriV1; 10010fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, Mask.size(), 10020fca6ea1SDimitry Andric 1) && 10030fca6ea1SDimitry Andric fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, 10040fca6ea1SDimitry Andric Mask.size() + HalfSize, 1)) 10050fca6ea1SDimitry Andric V2 = OriV2; 10060fca6ea1SDimitry Andric else 10070fca6ea1SDimitry Andric return SDValue(); 10080fca6ea1SDimitry Andric 10090fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1); 10100fca6ea1SDimitry Andric } 10110fca6ea1SDimitry Andric 10120fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVPICKEV (if possible). 10130fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVPICKEV(const SDLoc &DL, ArrayRef<int> Mask, 10140fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 10150fca6ea1SDimitry Andric SelectionDAG &DAG) { 10160fca6ea1SDimitry Andric 10170fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 10180fca6ea1SDimitry Andric const auto &LeftMid = Mask.begin() + Mask.size() / 4; 10190fca6ea1SDimitry Andric const auto &Mid = Mask.begin() + Mask.size() / 2; 10200fca6ea1SDimitry Andric const auto &RightMid = Mask.end() - Mask.size() / 4; 10210fca6ea1SDimitry Andric const auto &End = Mask.end(); 10220fca6ea1SDimitry Andric unsigned HalfSize = Mask.size() / 2; 10230fca6ea1SDimitry Andric SDValue OriV1 = V1, OriV2 = V2; 10240fca6ea1SDimitry Andric 10250fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin, 1, LeftMid, 0, 2) && 10260fca6ea1SDimitry Andric fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize, 2)) 10270fca6ea1SDimitry Andric V1 = OriV1; 10280fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size(), 2) && 10290fca6ea1SDimitry Andric fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize, 2)) 10300fca6ea1SDimitry Andric V1 = OriV2; 10310fca6ea1SDimitry Andric else 10320fca6ea1SDimitry Andric return SDValue(); 10330fca6ea1SDimitry Andric 10340fca6ea1SDimitry Andric if (fitsRegularPattern<int>(LeftMid, 1, Mid, 0, 2) && 10350fca6ea1SDimitry Andric fitsRegularPattern<int>(RightMid, 1, End, HalfSize, 2)) 10360fca6ea1SDimitry Andric V2 = OriV1; 10370fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size(), 2) && 10380fca6ea1SDimitry Andric fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize, 2)) 10390fca6ea1SDimitry Andric V2 = OriV2; 10400fca6ea1SDimitry Andric 10410fca6ea1SDimitry Andric else 10420fca6ea1SDimitry Andric return SDValue(); 10430fca6ea1SDimitry Andric 10440fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1); 10450fca6ea1SDimitry Andric } 10460fca6ea1SDimitry Andric 10470fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVPICKOD (if possible). 10480fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVPICKOD(const SDLoc &DL, ArrayRef<int> Mask, 10490fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 10500fca6ea1SDimitry Andric SelectionDAG &DAG) { 10510fca6ea1SDimitry Andric 10520fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 10530fca6ea1SDimitry Andric const auto &LeftMid = Mask.begin() + Mask.size() / 4; 10540fca6ea1SDimitry Andric const auto &Mid = Mask.begin() + Mask.size() / 2; 10550fca6ea1SDimitry Andric const auto &RightMid = Mask.end() - Mask.size() / 4; 10560fca6ea1SDimitry Andric const auto &End = Mask.end(); 10570fca6ea1SDimitry Andric unsigned HalfSize = Mask.size() / 2; 10580fca6ea1SDimitry Andric SDValue OriV1 = V1, OriV2 = V2; 10590fca6ea1SDimitry Andric 10600fca6ea1SDimitry Andric if (fitsRegularPattern<int>(Begin, 1, LeftMid, 1, 2) && 10610fca6ea1SDimitry Andric fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize + 1, 2)) 10620fca6ea1SDimitry Andric V1 = OriV1; 10630fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size() + 1, 2) && 10640fca6ea1SDimitry Andric fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize + 1, 10650fca6ea1SDimitry Andric 2)) 10660fca6ea1SDimitry Andric V1 = OriV2; 10670fca6ea1SDimitry Andric else 10680fca6ea1SDimitry Andric return SDValue(); 10690fca6ea1SDimitry Andric 10700fca6ea1SDimitry Andric if (fitsRegularPattern<int>(LeftMid, 1, Mid, 1, 2) && 10710fca6ea1SDimitry Andric fitsRegularPattern<int>(RightMid, 1, End, HalfSize + 1, 2)) 10720fca6ea1SDimitry Andric V2 = OriV1; 10730fca6ea1SDimitry Andric else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size() + 1, 2) && 10740fca6ea1SDimitry Andric fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize + 1, 10750fca6ea1SDimitry Andric 2)) 10760fca6ea1SDimitry Andric V2 = OriV2; 10770fca6ea1SDimitry Andric else 10780fca6ea1SDimitry Andric return SDValue(); 10790fca6ea1SDimitry Andric 10800fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1); 10810fca6ea1SDimitry Andric } 10820fca6ea1SDimitry Andric 10830fca6ea1SDimitry Andric /// Lower VECTOR_SHUFFLE into XVSHUF (if possible). 10840fca6ea1SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_XVSHUF(const SDLoc &DL, ArrayRef<int> Mask, 10850fca6ea1SDimitry Andric MVT VT, SDValue V1, SDValue V2, 10860fca6ea1SDimitry Andric SelectionDAG &DAG) { 10870fca6ea1SDimitry Andric 10880fca6ea1SDimitry Andric int MaskSize = Mask.size(); 10890fca6ea1SDimitry Andric int HalfSize = Mask.size() / 2; 10900fca6ea1SDimitry Andric const auto &Begin = Mask.begin(); 10910fca6ea1SDimitry Andric const auto &Mid = Mask.begin() + HalfSize; 10920fca6ea1SDimitry Andric const auto &End = Mask.end(); 10930fca6ea1SDimitry Andric 10940fca6ea1SDimitry Andric // VECTOR_SHUFFLE concatenates the vectors: 10950fca6ea1SDimitry Andric // <0, 1, 2, 3, 4, 5, 6, 7> + <8, 9, 10, 11, 12, 13, 14, 15> 10960fca6ea1SDimitry Andric // shuffling -> 10970fca6ea1SDimitry Andric // <0, 1, 2, 3, 8, 9, 10, 11> <4, 5, 6, 7, 12, 13, 14, 15> 10980fca6ea1SDimitry Andric // 10990fca6ea1SDimitry Andric // XVSHUF concatenates the vectors: 11000fca6ea1SDimitry Andric // <a0, a1, a2, a3, b0, b1, b2, b3> + <a4, a5, a6, a7, b4, b5, b6, b7> 11010fca6ea1SDimitry Andric // shuffling -> 11020fca6ea1SDimitry Andric // <a0, a1, a2, a3, a4, a5, a6, a7> + <b0, b1, b2, b3, b4, b5, b6, b7> 11030fca6ea1SDimitry Andric SmallVector<SDValue, 8> MaskAlloc; 11040fca6ea1SDimitry Andric for (auto it = Begin; it < Mid; it++) { 11050fca6ea1SDimitry Andric if (*it < 0) // UNDEF 11060fca6ea1SDimitry Andric MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64)); 11070fca6ea1SDimitry Andric else if ((*it >= 0 && *it < HalfSize) || 11080fca6ea1SDimitry Andric (*it >= MaskSize && *it <= MaskSize + HalfSize)) { 11090fca6ea1SDimitry Andric int M = *it < HalfSize ? *it : *it - HalfSize; 11100fca6ea1SDimitry Andric MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64)); 11110fca6ea1SDimitry Andric } else 11120fca6ea1SDimitry Andric return SDValue(); 11130fca6ea1SDimitry Andric } 11140fca6ea1SDimitry Andric assert((int)MaskAlloc.size() == HalfSize && "xvshuf convert failed!"); 11150fca6ea1SDimitry Andric 11160fca6ea1SDimitry Andric for (auto it = Mid; it < End; it++) { 11170fca6ea1SDimitry Andric if (*it < 0) // UNDEF 11180fca6ea1SDimitry Andric MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64)); 11190fca6ea1SDimitry Andric else if ((*it >= HalfSize && *it < MaskSize) || 11200fca6ea1SDimitry Andric (*it >= MaskSize + HalfSize && *it < MaskSize * 2)) { 11210fca6ea1SDimitry Andric int M = *it < MaskSize ? *it - HalfSize : *it - MaskSize; 11220fca6ea1SDimitry Andric MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64)); 11230fca6ea1SDimitry Andric } else 11240fca6ea1SDimitry Andric return SDValue(); 11250fca6ea1SDimitry Andric } 11260fca6ea1SDimitry Andric assert((int)MaskAlloc.size() == MaskSize && "xvshuf convert failed!"); 11270fca6ea1SDimitry Andric 11280fca6ea1SDimitry Andric EVT MaskVecTy = VT.changeVectorElementTypeToInteger(); 11290fca6ea1SDimitry Andric SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, MaskAlloc); 11300fca6ea1SDimitry Andric return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1); 11310fca6ea1SDimitry Andric } 11320fca6ea1SDimitry Andric 11330fca6ea1SDimitry Andric /// Shuffle vectors by lane to generate more optimized instructions. 11340fca6ea1SDimitry Andric /// 256-bit shuffles are always considered as 2-lane 128-bit shuffles. 11350fca6ea1SDimitry Andric /// 11360fca6ea1SDimitry Andric /// Therefore, except for the following four cases, other cases are regarded 11370fca6ea1SDimitry Andric /// as cross-lane shuffles, where optimization is relatively limited. 11380fca6ea1SDimitry Andric /// 11390fca6ea1SDimitry Andric /// - Shuffle high, low lanes of two inputs vector 11400fca6ea1SDimitry Andric /// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 3, 6> 11410fca6ea1SDimitry Andric /// - Shuffle low, high lanes of two inputs vector 11420fca6ea1SDimitry Andric /// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 0, 5> 11430fca6ea1SDimitry Andric /// - Shuffle low, low lanes of two inputs vector 11440fca6ea1SDimitry Andric /// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 3, 6> 11450fca6ea1SDimitry Andric /// - Shuffle high, high lanes of two inputs vector 11460fca6ea1SDimitry Andric /// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 0, 5> 11470fca6ea1SDimitry Andric /// 11480fca6ea1SDimitry Andric /// The first case is the closest to LoongArch instructions and the other 11490fca6ea1SDimitry Andric /// cases need to be converted to it for processing. 11500fca6ea1SDimitry Andric /// 11510fca6ea1SDimitry Andric /// This function may modify V1, V2 and Mask 11520fca6ea1SDimitry Andric static void canonicalizeShuffleVectorByLane(const SDLoc &DL, 11530fca6ea1SDimitry Andric MutableArrayRef<int> Mask, MVT VT, 11540fca6ea1SDimitry Andric SDValue &V1, SDValue &V2, 11550fca6ea1SDimitry Andric SelectionDAG &DAG) { 11560fca6ea1SDimitry Andric 11570fca6ea1SDimitry Andric enum HalfMaskType { HighLaneTy, LowLaneTy, None }; 11580fca6ea1SDimitry Andric 11590fca6ea1SDimitry Andric int MaskSize = Mask.size(); 11600fca6ea1SDimitry Andric int HalfSize = Mask.size() / 2; 11610fca6ea1SDimitry Andric 11620fca6ea1SDimitry Andric HalfMaskType preMask = None, postMask = None; 11630fca6ea1SDimitry Andric 11640fca6ea1SDimitry Andric if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) { 11650fca6ea1SDimitry Andric return M < 0 || (M >= 0 && M < HalfSize) || 11660fca6ea1SDimitry Andric (M >= MaskSize && M < MaskSize + HalfSize); 11670fca6ea1SDimitry Andric })) 11680fca6ea1SDimitry Andric preMask = HighLaneTy; 11690fca6ea1SDimitry Andric else if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) { 11700fca6ea1SDimitry Andric return M < 0 || (M >= HalfSize && M < MaskSize) || 11710fca6ea1SDimitry Andric (M >= MaskSize + HalfSize && M < MaskSize * 2); 11720fca6ea1SDimitry Andric })) 11730fca6ea1SDimitry Andric preMask = LowLaneTy; 11740fca6ea1SDimitry Andric 11750fca6ea1SDimitry Andric if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) { 11760fca6ea1SDimitry Andric return M < 0 || (M >= 0 && M < HalfSize) || 11770fca6ea1SDimitry Andric (M >= MaskSize && M < MaskSize + HalfSize); 11780fca6ea1SDimitry Andric })) 11790fca6ea1SDimitry Andric postMask = HighLaneTy; 11800fca6ea1SDimitry Andric else if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) { 11810fca6ea1SDimitry Andric return M < 0 || (M >= HalfSize && M < MaskSize) || 11820fca6ea1SDimitry Andric (M >= MaskSize + HalfSize && M < MaskSize * 2); 11830fca6ea1SDimitry Andric })) 11840fca6ea1SDimitry Andric postMask = LowLaneTy; 11850fca6ea1SDimitry Andric 11860fca6ea1SDimitry Andric // The pre-half of mask is high lane type, and the post-half of mask 11870fca6ea1SDimitry Andric // is low lane type, which is closest to the LoongArch instructions. 11880fca6ea1SDimitry Andric // 11890fca6ea1SDimitry Andric // Note: In the LoongArch architecture, the high lane of mask corresponds 11900fca6ea1SDimitry Andric // to the lower 128-bit of vector register, and the low lane of mask 11910fca6ea1SDimitry Andric // corresponds the higher 128-bit of vector register. 11920fca6ea1SDimitry Andric if (preMask == HighLaneTy && postMask == LowLaneTy) { 11930fca6ea1SDimitry Andric return; 11940fca6ea1SDimitry Andric } 11950fca6ea1SDimitry Andric if (preMask == LowLaneTy && postMask == HighLaneTy) { 11960fca6ea1SDimitry Andric V1 = DAG.getBitcast(MVT::v4i64, V1); 11970fca6ea1SDimitry Andric V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1, 11980fca6ea1SDimitry Andric DAG.getConstant(0b01001110, DL, MVT::i64)); 11990fca6ea1SDimitry Andric V1 = DAG.getBitcast(VT, V1); 12000fca6ea1SDimitry Andric 12010fca6ea1SDimitry Andric if (!V2.isUndef()) { 12020fca6ea1SDimitry Andric V2 = DAG.getBitcast(MVT::v4i64, V2); 12030fca6ea1SDimitry Andric V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2, 12040fca6ea1SDimitry Andric DAG.getConstant(0b01001110, DL, MVT::i64)); 12050fca6ea1SDimitry Andric V2 = DAG.getBitcast(VT, V2); 12060fca6ea1SDimitry Andric } 12070fca6ea1SDimitry Andric 12080fca6ea1SDimitry Andric for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) { 12090fca6ea1SDimitry Andric *it = *it < 0 ? *it : *it - HalfSize; 12100fca6ea1SDimitry Andric } 12110fca6ea1SDimitry Andric for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) { 12120fca6ea1SDimitry Andric *it = *it < 0 ? *it : *it + HalfSize; 12130fca6ea1SDimitry Andric } 12140fca6ea1SDimitry Andric } else if (preMask == LowLaneTy && postMask == LowLaneTy) { 12150fca6ea1SDimitry Andric V1 = DAG.getBitcast(MVT::v4i64, V1); 12160fca6ea1SDimitry Andric V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1, 12170fca6ea1SDimitry Andric DAG.getConstant(0b11101110, DL, MVT::i64)); 12180fca6ea1SDimitry Andric V1 = DAG.getBitcast(VT, V1); 12190fca6ea1SDimitry Andric 12200fca6ea1SDimitry Andric if (!V2.isUndef()) { 12210fca6ea1SDimitry Andric V2 = DAG.getBitcast(MVT::v4i64, V2); 12220fca6ea1SDimitry Andric V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2, 12230fca6ea1SDimitry Andric DAG.getConstant(0b11101110, DL, MVT::i64)); 12240fca6ea1SDimitry Andric V2 = DAG.getBitcast(VT, V2); 12250fca6ea1SDimitry Andric } 12260fca6ea1SDimitry Andric 12270fca6ea1SDimitry Andric for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) { 12280fca6ea1SDimitry Andric *it = *it < 0 ? *it : *it - HalfSize; 12290fca6ea1SDimitry Andric } 12300fca6ea1SDimitry Andric } else if (preMask == HighLaneTy && postMask == HighLaneTy) { 12310fca6ea1SDimitry Andric V1 = DAG.getBitcast(MVT::v4i64, V1); 12320fca6ea1SDimitry Andric V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1, 12330fca6ea1SDimitry Andric DAG.getConstant(0b01000100, DL, MVT::i64)); 12340fca6ea1SDimitry Andric V1 = DAG.getBitcast(VT, V1); 12350fca6ea1SDimitry Andric 12360fca6ea1SDimitry Andric if (!V2.isUndef()) { 12370fca6ea1SDimitry Andric V2 = DAG.getBitcast(MVT::v4i64, V2); 12380fca6ea1SDimitry Andric V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2, 12390fca6ea1SDimitry Andric DAG.getConstant(0b01000100, DL, MVT::i64)); 12400fca6ea1SDimitry Andric V2 = DAG.getBitcast(VT, V2); 12410fca6ea1SDimitry Andric } 12420fca6ea1SDimitry Andric 12430fca6ea1SDimitry Andric for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) { 12440fca6ea1SDimitry Andric *it = *it < 0 ? *it : *it + HalfSize; 12450fca6ea1SDimitry Andric } 12460fca6ea1SDimitry Andric } else { // cross-lane 12470fca6ea1SDimitry Andric return; 12480fca6ea1SDimitry Andric } 12490fca6ea1SDimitry Andric } 12500fca6ea1SDimitry Andric 12510fca6ea1SDimitry Andric /// Dispatching routine to lower various 256-bit LoongArch vector shuffles. 12520fca6ea1SDimitry Andric /// 12530fca6ea1SDimitry Andric /// This routine breaks down the specific type of 256-bit shuffle and 12540fca6ea1SDimitry Andric /// dispatches to the lowering routines accordingly. 12550fca6ea1SDimitry Andric static SDValue lower256BitShuffle(const SDLoc &DL, ArrayRef<int> Mask, MVT VT, 12560fca6ea1SDimitry Andric SDValue V1, SDValue V2, SelectionDAG &DAG) { 12570fca6ea1SDimitry Andric assert((VT.SimpleTy == MVT::v32i8 || VT.SimpleTy == MVT::v16i16 || 12580fca6ea1SDimitry Andric VT.SimpleTy == MVT::v8i32 || VT.SimpleTy == MVT::v4i64 || 12590fca6ea1SDimitry Andric VT.SimpleTy == MVT::v8f32 || VT.SimpleTy == MVT::v4f64) && 12600fca6ea1SDimitry Andric "Vector type is unsupported for lasx!"); 12610fca6ea1SDimitry Andric assert(V1.getSimpleValueType() == V2.getSimpleValueType() && 12620fca6ea1SDimitry Andric "Two operands have different types!"); 12630fca6ea1SDimitry Andric assert(VT.getVectorNumElements() == Mask.size() && 12640fca6ea1SDimitry Andric "Unexpected mask size for shuffle!"); 12650fca6ea1SDimitry Andric assert(Mask.size() % 2 == 0 && "Expected even mask size."); 12660fca6ea1SDimitry Andric assert(Mask.size() >= 4 && "Mask size is less than 4."); 12670fca6ea1SDimitry Andric 12680fca6ea1SDimitry Andric // canonicalize non cross-lane shuffle vector 12690fca6ea1SDimitry Andric SmallVector<int> NewMask(Mask); 12700fca6ea1SDimitry Andric canonicalizeShuffleVectorByLane(DL, NewMask, VT, V1, V2, DAG); 12710fca6ea1SDimitry Andric 12720fca6ea1SDimitry Andric SDValue Result; 12730fca6ea1SDimitry Andric // TODO: Add more comparison patterns. 12740fca6ea1SDimitry Andric if (V2.isUndef()) { 12750fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_XVREPLVEI(DL, NewMask, VT, V1, V2, DAG))) 12760fca6ea1SDimitry Andric return Result; 12770fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_XVSHUF4I(DL, NewMask, VT, V1, V2, DAG))) 12780fca6ea1SDimitry Andric return Result; 12790fca6ea1SDimitry Andric 12800fca6ea1SDimitry Andric // TODO: This comment may be enabled in the future to better match the 12810fca6ea1SDimitry Andric // pattern for instruction selection. 12820fca6ea1SDimitry Andric /* V2 = V1; */ 12830fca6ea1SDimitry Andric } 12840fca6ea1SDimitry Andric 12850fca6ea1SDimitry Andric // It is recommended not to change the pattern comparison order for better 12860fca6ea1SDimitry Andric // performance. 12870fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_XVPACKEV(DL, NewMask, VT, V1, V2, DAG))) 12880fca6ea1SDimitry Andric return Result; 12890fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_XVPACKOD(DL, NewMask, VT, V1, V2, DAG))) 12900fca6ea1SDimitry Andric return Result; 12910fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_XVILVH(DL, NewMask, VT, V1, V2, DAG))) 12920fca6ea1SDimitry Andric return Result; 12930fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_XVILVL(DL, NewMask, VT, V1, V2, DAG))) 12940fca6ea1SDimitry Andric return Result; 12950fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_XVPICKEV(DL, NewMask, VT, V1, V2, DAG))) 12960fca6ea1SDimitry Andric return Result; 12970fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_XVPICKOD(DL, NewMask, VT, V1, V2, DAG))) 12980fca6ea1SDimitry Andric return Result; 12990fca6ea1SDimitry Andric if ((Result = lowerVECTOR_SHUFFLE_XVSHUF(DL, NewMask, VT, V1, V2, DAG))) 13000fca6ea1SDimitry Andric return Result; 13010fca6ea1SDimitry Andric 13020fca6ea1SDimitry Andric return SDValue(); 13030fca6ea1SDimitry Andric } 13040fca6ea1SDimitry Andric 13055f757f3fSDimitry Andric SDValue LoongArchTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op, 13065f757f3fSDimitry Andric SelectionDAG &DAG) const { 13070fca6ea1SDimitry Andric ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(Op); 13080fca6ea1SDimitry Andric ArrayRef<int> OrigMask = SVOp->getMask(); 13090fca6ea1SDimitry Andric SDValue V1 = Op.getOperand(0); 13100fca6ea1SDimitry Andric SDValue V2 = Op.getOperand(1); 13110fca6ea1SDimitry Andric MVT VT = Op.getSimpleValueType(); 13120fca6ea1SDimitry Andric int NumElements = VT.getVectorNumElements(); 13130fca6ea1SDimitry Andric SDLoc DL(Op); 13140fca6ea1SDimitry Andric 13150fca6ea1SDimitry Andric bool V1IsUndef = V1.isUndef(); 13160fca6ea1SDimitry Andric bool V2IsUndef = V2.isUndef(); 13170fca6ea1SDimitry Andric if (V1IsUndef && V2IsUndef) 13180fca6ea1SDimitry Andric return DAG.getUNDEF(VT); 13190fca6ea1SDimitry Andric 13200fca6ea1SDimitry Andric // When we create a shuffle node we put the UNDEF node to second operand, 13210fca6ea1SDimitry Andric // but in some cases the first operand may be transformed to UNDEF. 13220fca6ea1SDimitry Andric // In this case we should just commute the node. 13230fca6ea1SDimitry Andric if (V1IsUndef) 13240fca6ea1SDimitry Andric return DAG.getCommutedVectorShuffle(*SVOp); 13250fca6ea1SDimitry Andric 13260fca6ea1SDimitry Andric // Check for non-undef masks pointing at an undef vector and make the masks 13270fca6ea1SDimitry Andric // undef as well. This makes it easier to match the shuffle based solely on 13280fca6ea1SDimitry Andric // the mask. 13290fca6ea1SDimitry Andric if (V2IsUndef && 13300fca6ea1SDimitry Andric any_of(OrigMask, [NumElements](int M) { return M >= NumElements; })) { 13310fca6ea1SDimitry Andric SmallVector<int, 8> NewMask(OrigMask); 13320fca6ea1SDimitry Andric for (int &M : NewMask) 13330fca6ea1SDimitry Andric if (M >= NumElements) 13340fca6ea1SDimitry Andric M = -1; 13350fca6ea1SDimitry Andric return DAG.getVectorShuffle(VT, DL, V1, V2, NewMask); 13360fca6ea1SDimitry Andric } 13370fca6ea1SDimitry Andric 13380fca6ea1SDimitry Andric // Check for illegal shuffle mask element index values. 13390fca6ea1SDimitry Andric int MaskUpperLimit = OrigMask.size() * (V2IsUndef ? 1 : 2); 13400fca6ea1SDimitry Andric (void)MaskUpperLimit; 13410fca6ea1SDimitry Andric assert(llvm::all_of(OrigMask, 13420fca6ea1SDimitry Andric [&](int M) { return -1 <= M && M < MaskUpperLimit; }) && 13430fca6ea1SDimitry Andric "Out of bounds shuffle index"); 13440fca6ea1SDimitry Andric 13450fca6ea1SDimitry Andric // For each vector width, delegate to a specialized lowering routine. 13460fca6ea1SDimitry Andric if (VT.is128BitVector()) 13470fca6ea1SDimitry Andric return lower128BitShuffle(DL, OrigMask, VT, V1, V2, DAG); 13480fca6ea1SDimitry Andric 13490fca6ea1SDimitry Andric if (VT.is256BitVector()) 13500fca6ea1SDimitry Andric return lower256BitShuffle(DL, OrigMask, VT, V1, V2, DAG); 13510fca6ea1SDimitry Andric 13525f757f3fSDimitry Andric return SDValue(); 13535f757f3fSDimitry Andric } 13545f757f3fSDimitry Andric 13555f757f3fSDimitry Andric static bool isConstantOrUndef(const SDValue Op) { 13565f757f3fSDimitry Andric if (Op->isUndef()) 13575f757f3fSDimitry Andric return true; 13585f757f3fSDimitry Andric if (isa<ConstantSDNode>(Op)) 13595f757f3fSDimitry Andric return true; 13605f757f3fSDimitry Andric if (isa<ConstantFPSDNode>(Op)) 13615f757f3fSDimitry Andric return true; 13625f757f3fSDimitry Andric return false; 13635f757f3fSDimitry Andric } 13645f757f3fSDimitry Andric 13655f757f3fSDimitry Andric static bool isConstantOrUndefBUILD_VECTOR(const BuildVectorSDNode *Op) { 13665f757f3fSDimitry Andric for (unsigned i = 0; i < Op->getNumOperands(); ++i) 13675f757f3fSDimitry Andric if (isConstantOrUndef(Op->getOperand(i))) 13685f757f3fSDimitry Andric return true; 13695f757f3fSDimitry Andric return false; 13705f757f3fSDimitry Andric } 13715f757f3fSDimitry Andric 13725f757f3fSDimitry Andric SDValue LoongArchTargetLowering::lowerBUILD_VECTOR(SDValue Op, 13735f757f3fSDimitry Andric SelectionDAG &DAG) const { 13745f757f3fSDimitry Andric BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op); 13755f757f3fSDimitry Andric EVT ResTy = Op->getValueType(0); 13765f757f3fSDimitry Andric SDLoc DL(Op); 13775f757f3fSDimitry Andric APInt SplatValue, SplatUndef; 13785f757f3fSDimitry Andric unsigned SplatBitSize; 13795f757f3fSDimitry Andric bool HasAnyUndefs; 13805f757f3fSDimitry Andric bool Is128Vec = ResTy.is128BitVector(); 13815f757f3fSDimitry Andric bool Is256Vec = ResTy.is256BitVector(); 13825f757f3fSDimitry Andric 13835f757f3fSDimitry Andric if ((!Subtarget.hasExtLSX() || !Is128Vec) && 13845f757f3fSDimitry Andric (!Subtarget.hasExtLASX() || !Is256Vec)) 13855f757f3fSDimitry Andric return SDValue(); 13865f757f3fSDimitry Andric 13875f757f3fSDimitry Andric if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, 13885f757f3fSDimitry Andric /*MinSplatBits=*/8) && 13895f757f3fSDimitry Andric SplatBitSize <= 64) { 13905f757f3fSDimitry Andric // We can only cope with 8, 16, 32, or 64-bit elements. 13915f757f3fSDimitry Andric if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 && 13925f757f3fSDimitry Andric SplatBitSize != 64) 13935f757f3fSDimitry Andric return SDValue(); 13945f757f3fSDimitry Andric 13955f757f3fSDimitry Andric EVT ViaVecTy; 13965f757f3fSDimitry Andric 13975f757f3fSDimitry Andric switch (SplatBitSize) { 13985f757f3fSDimitry Andric default: 13995f757f3fSDimitry Andric return SDValue(); 14005f757f3fSDimitry Andric case 8: 14015f757f3fSDimitry Andric ViaVecTy = Is128Vec ? MVT::v16i8 : MVT::v32i8; 14025f757f3fSDimitry Andric break; 14035f757f3fSDimitry Andric case 16: 14045f757f3fSDimitry Andric ViaVecTy = Is128Vec ? MVT::v8i16 : MVT::v16i16; 14055f757f3fSDimitry Andric break; 14065f757f3fSDimitry Andric case 32: 14075f757f3fSDimitry Andric ViaVecTy = Is128Vec ? MVT::v4i32 : MVT::v8i32; 14085f757f3fSDimitry Andric break; 14095f757f3fSDimitry Andric case 64: 14105f757f3fSDimitry Andric ViaVecTy = Is128Vec ? MVT::v2i64 : MVT::v4i64; 14115f757f3fSDimitry Andric break; 14125f757f3fSDimitry Andric } 14135f757f3fSDimitry Andric 14145f757f3fSDimitry Andric // SelectionDAG::getConstant will promote SplatValue appropriately. 14155f757f3fSDimitry Andric SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy); 14165f757f3fSDimitry Andric 14175f757f3fSDimitry Andric // Bitcast to the type we originally wanted. 14185f757f3fSDimitry Andric if (ViaVecTy != ResTy) 14195f757f3fSDimitry Andric Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result); 14205f757f3fSDimitry Andric 14215f757f3fSDimitry Andric return Result; 14225f757f3fSDimitry Andric } 14235f757f3fSDimitry Andric 14245f757f3fSDimitry Andric if (DAG.isSplatValue(Op, /*AllowUndefs=*/false)) 14255f757f3fSDimitry Andric return Op; 14265f757f3fSDimitry Andric 14275f757f3fSDimitry Andric if (!isConstantOrUndefBUILD_VECTOR(Node)) { 14285f757f3fSDimitry Andric // Use INSERT_VECTOR_ELT operations rather than expand to stores. 14295f757f3fSDimitry Andric // The resulting code is the same length as the expansion, but it doesn't 14305f757f3fSDimitry Andric // use memory operations. 14315f757f3fSDimitry Andric EVT ResTy = Node->getValueType(0); 14325f757f3fSDimitry Andric 14335f757f3fSDimitry Andric assert(ResTy.isVector()); 14345f757f3fSDimitry Andric 14355f757f3fSDimitry Andric unsigned NumElts = ResTy.getVectorNumElements(); 14365f757f3fSDimitry Andric SDValue Vector = DAG.getUNDEF(ResTy); 14375f757f3fSDimitry Andric for (unsigned i = 0; i < NumElts; ++i) { 14385f757f3fSDimitry Andric Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector, 14395f757f3fSDimitry Andric Node->getOperand(i), 14405f757f3fSDimitry Andric DAG.getConstant(i, DL, Subtarget.getGRLenVT())); 14415f757f3fSDimitry Andric } 14425f757f3fSDimitry Andric return Vector; 14435f757f3fSDimitry Andric } 14445f757f3fSDimitry Andric 14455f757f3fSDimitry Andric return SDValue(); 14465f757f3fSDimitry Andric } 14475f757f3fSDimitry Andric 14485f757f3fSDimitry Andric SDValue 1449647cbc5dSDimitry Andric LoongArchTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op, 1450647cbc5dSDimitry Andric SelectionDAG &DAG) const { 1451647cbc5dSDimitry Andric EVT VecTy = Op->getOperand(0)->getValueType(0); 1452647cbc5dSDimitry Andric SDValue Idx = Op->getOperand(1); 1453647cbc5dSDimitry Andric EVT EltTy = VecTy.getVectorElementType(); 1454647cbc5dSDimitry Andric unsigned NumElts = VecTy.getVectorNumElements(); 1455647cbc5dSDimitry Andric 1456647cbc5dSDimitry Andric if (isa<ConstantSDNode>(Idx) && 1457647cbc5dSDimitry Andric (EltTy == MVT::i32 || EltTy == MVT::i64 || EltTy == MVT::f32 || 14581db9f3b2SDimitry Andric EltTy == MVT::f64 || Idx->getAsZExtVal() < NumElts / 2)) 1459647cbc5dSDimitry Andric return Op; 1460647cbc5dSDimitry Andric 1461647cbc5dSDimitry Andric return SDValue(); 1462647cbc5dSDimitry Andric } 1463647cbc5dSDimitry Andric 1464647cbc5dSDimitry Andric SDValue 14655f757f3fSDimitry Andric LoongArchTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op, 14665f757f3fSDimitry Andric SelectionDAG &DAG) const { 14675f757f3fSDimitry Andric if (isa<ConstantSDNode>(Op->getOperand(2))) 14685f757f3fSDimitry Andric return Op; 14695f757f3fSDimitry Andric return SDValue(); 14705f757f3fSDimitry Andric } 14715f757f3fSDimitry Andric 14725f757f3fSDimitry Andric SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op, 14735f757f3fSDimitry Andric SelectionDAG &DAG) const { 14745f757f3fSDimitry Andric SDLoc DL(Op); 14755f757f3fSDimitry Andric SyncScope::ID FenceSSID = 14765f757f3fSDimitry Andric static_cast<SyncScope::ID>(Op.getConstantOperandVal(2)); 14775f757f3fSDimitry Andric 14785f757f3fSDimitry Andric // singlethread fences only synchronize with signal handlers on the same 14795f757f3fSDimitry Andric // thread and thus only need to preserve instruction order, not actually 14805f757f3fSDimitry Andric // enforce memory ordering. 14815f757f3fSDimitry Andric if (FenceSSID == SyncScope::SingleThread) 14825f757f3fSDimitry Andric // MEMBARRIER is a compiler barrier; it codegens to a no-op. 14835f757f3fSDimitry Andric return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0)); 14845f757f3fSDimitry Andric 14855f757f3fSDimitry Andric return Op; 14865f757f3fSDimitry Andric } 14875f757f3fSDimitry Andric 1488bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op, 1489bdd1243dSDimitry Andric SelectionDAG &DAG) const { 1490bdd1243dSDimitry Andric 1491bdd1243dSDimitry Andric if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) { 1492bdd1243dSDimitry Andric DAG.getContext()->emitError( 1493bdd1243dSDimitry Andric "On LA64, only 64-bit registers can be written."); 1494bdd1243dSDimitry Andric return Op.getOperand(0); 1495bdd1243dSDimitry Andric } 1496bdd1243dSDimitry Andric 1497bdd1243dSDimitry Andric if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) { 1498bdd1243dSDimitry Andric DAG.getContext()->emitError( 1499bdd1243dSDimitry Andric "On LA32, only 32-bit registers can be written."); 1500bdd1243dSDimitry Andric return Op.getOperand(0); 1501bdd1243dSDimitry Andric } 1502bdd1243dSDimitry Andric 1503bdd1243dSDimitry Andric return Op; 1504bdd1243dSDimitry Andric } 1505bdd1243dSDimitry Andric 1506bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op, 1507bdd1243dSDimitry Andric SelectionDAG &DAG) const { 1508bdd1243dSDimitry Andric if (!isa<ConstantSDNode>(Op.getOperand(0))) { 1509bdd1243dSDimitry Andric DAG.getContext()->emitError("argument to '__builtin_frame_address' must " 1510bdd1243dSDimitry Andric "be a constant integer"); 1511bdd1243dSDimitry Andric return SDValue(); 1512bdd1243dSDimitry Andric } 1513bdd1243dSDimitry Andric 1514bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 1515bdd1243dSDimitry Andric MF.getFrameInfo().setFrameAddressIsTaken(true); 1516bdd1243dSDimitry Andric Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF); 1517bdd1243dSDimitry Andric EVT VT = Op.getValueType(); 1518bdd1243dSDimitry Andric SDLoc DL(Op); 1519bdd1243dSDimitry Andric SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT); 1520647cbc5dSDimitry Andric unsigned Depth = Op.getConstantOperandVal(0); 1521bdd1243dSDimitry Andric int GRLenInBytes = Subtarget.getGRLen() / 8; 1522bdd1243dSDimitry Andric 1523bdd1243dSDimitry Andric while (Depth--) { 1524bdd1243dSDimitry Andric int Offset = -(GRLenInBytes * 2); 1525bdd1243dSDimitry Andric SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr, 1526bdd1243dSDimitry Andric DAG.getIntPtrConstant(Offset, DL)); 1527bdd1243dSDimitry Andric FrameAddr = 1528bdd1243dSDimitry Andric DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo()); 1529bdd1243dSDimitry Andric } 1530bdd1243dSDimitry Andric return FrameAddr; 1531bdd1243dSDimitry Andric } 1532bdd1243dSDimitry Andric 1533bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op, 1534bdd1243dSDimitry Andric SelectionDAG &DAG) const { 1535bdd1243dSDimitry Andric if (verifyReturnAddressArgumentIsConstant(Op, DAG)) 1536bdd1243dSDimitry Andric return SDValue(); 1537bdd1243dSDimitry Andric 1538bdd1243dSDimitry Andric // Currently only support lowering return address for current frame. 1539647cbc5dSDimitry Andric if (Op.getConstantOperandVal(0) != 0) { 1540bdd1243dSDimitry Andric DAG.getContext()->emitError( 1541bdd1243dSDimitry Andric "return address can only be determined for the current frame"); 1542bdd1243dSDimitry Andric return SDValue(); 1543bdd1243dSDimitry Andric } 1544bdd1243dSDimitry Andric 1545bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 1546bdd1243dSDimitry Andric MF.getFrameInfo().setReturnAddressIsTaken(true); 1547bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 1548bdd1243dSDimitry Andric 1549bdd1243dSDimitry Andric // Return the value of the return address register, marking it an implicit 1550bdd1243dSDimitry Andric // live-in. 1551bdd1243dSDimitry Andric Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(), 1552bdd1243dSDimitry Andric getRegClassFor(GRLenVT)); 1553bdd1243dSDimitry Andric return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT); 1554bdd1243dSDimitry Andric } 1555bdd1243dSDimitry Andric 1556bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op, 1557bdd1243dSDimitry Andric SelectionDAG &DAG) const { 1558bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 1559bdd1243dSDimitry Andric auto Size = Subtarget.getGRLen() / 8; 1560bdd1243dSDimitry Andric auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false); 1561bdd1243dSDimitry Andric return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 1562bdd1243dSDimitry Andric } 1563bdd1243dSDimitry Andric 1564bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op, 1565bdd1243dSDimitry Andric SelectionDAG &DAG) const { 1566bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 1567bdd1243dSDimitry Andric auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>(); 1568bdd1243dSDimitry Andric 1569bdd1243dSDimitry Andric SDLoc DL(Op); 1570bdd1243dSDimitry Andric SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), 1571bdd1243dSDimitry Andric getPointerTy(MF.getDataLayout())); 1572bdd1243dSDimitry Andric 1573bdd1243dSDimitry Andric // vastart just stores the address of the VarArgsFrameIndex slot into the 1574bdd1243dSDimitry Andric // memory location argument. 1575bdd1243dSDimitry Andric const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); 1576bdd1243dSDimitry Andric return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1), 1577bdd1243dSDimitry Andric MachinePointerInfo(SV)); 157881ad6265SDimitry Andric } 157981ad6265SDimitry Andric 1580753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op, 1581753f127fSDimitry Andric SelectionDAG &DAG) const { 1582bdd1243dSDimitry Andric assert(Subtarget.is64Bit() && Subtarget.hasBasicF() && 1583bdd1243dSDimitry Andric !Subtarget.hasBasicD() && "unexpected target features"); 1584753f127fSDimitry Andric 1585753f127fSDimitry Andric SDLoc DL(Op); 1586bdd1243dSDimitry Andric SDValue Op0 = Op.getOperand(0); 1587bdd1243dSDimitry Andric if (Op0->getOpcode() == ISD::AND) { 1588bdd1243dSDimitry Andric auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1)); 1589bdd1243dSDimitry Andric if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF)) 1590753f127fSDimitry Andric return Op; 1591bdd1243dSDimitry Andric } 1592bdd1243dSDimitry Andric 1593bdd1243dSDimitry Andric if (Op0->getOpcode() == LoongArchISD::BSTRPICK && 1594bdd1243dSDimitry Andric Op0.getConstantOperandVal(1) < UINT64_C(0X1F) && 1595bdd1243dSDimitry Andric Op0.getConstantOperandVal(2) == UINT64_C(0)) 1596bdd1243dSDimitry Andric return Op; 1597bdd1243dSDimitry Andric 1598bdd1243dSDimitry Andric if (Op0.getOpcode() == ISD::AssertZext && 1599bdd1243dSDimitry Andric dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32)) 1600bdd1243dSDimitry Andric return Op; 1601bdd1243dSDimitry Andric 1602bdd1243dSDimitry Andric EVT OpVT = Op0.getValueType(); 1603bdd1243dSDimitry Andric EVT RetVT = Op.getValueType(); 1604bdd1243dSDimitry Andric RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT); 1605bdd1243dSDimitry Andric MakeLibCallOptions CallOptions; 1606bdd1243dSDimitry Andric CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true); 1607bdd1243dSDimitry Andric SDValue Chain = SDValue(); 1608bdd1243dSDimitry Andric SDValue Result; 1609bdd1243dSDimitry Andric std::tie(Result, Chain) = 1610bdd1243dSDimitry Andric makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain); 1611bdd1243dSDimitry Andric return Result; 1612bdd1243dSDimitry Andric } 1613bdd1243dSDimitry Andric 1614bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op, 1615bdd1243dSDimitry Andric SelectionDAG &DAG) const { 1616bdd1243dSDimitry Andric assert(Subtarget.is64Bit() && Subtarget.hasBasicF() && 1617bdd1243dSDimitry Andric !Subtarget.hasBasicD() && "unexpected target features"); 1618bdd1243dSDimitry Andric 1619bdd1243dSDimitry Andric SDLoc DL(Op); 1620bdd1243dSDimitry Andric SDValue Op0 = Op.getOperand(0); 1621bdd1243dSDimitry Andric 1622bdd1243dSDimitry Andric if ((Op0.getOpcode() == ISD::AssertSext || 1623bdd1243dSDimitry Andric Op0.getOpcode() == ISD::SIGN_EXTEND_INREG) && 1624bdd1243dSDimitry Andric dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32)) 1625bdd1243dSDimitry Andric return Op; 1626bdd1243dSDimitry Andric 1627bdd1243dSDimitry Andric EVT OpVT = Op0.getValueType(); 1628bdd1243dSDimitry Andric EVT RetVT = Op.getValueType(); 1629bdd1243dSDimitry Andric RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT); 1630bdd1243dSDimitry Andric MakeLibCallOptions CallOptions; 1631bdd1243dSDimitry Andric CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true); 1632bdd1243dSDimitry Andric SDValue Chain = SDValue(); 1633bdd1243dSDimitry Andric SDValue Result; 1634bdd1243dSDimitry Andric std::tie(Result, Chain) = 1635bdd1243dSDimitry Andric makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain); 1636bdd1243dSDimitry Andric return Result; 1637753f127fSDimitry Andric } 1638753f127fSDimitry Andric 1639753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op, 1640753f127fSDimitry Andric SelectionDAG &DAG) const { 1641753f127fSDimitry Andric 1642753f127fSDimitry Andric SDLoc DL(Op); 1643753f127fSDimitry Andric SDValue Op0 = Op.getOperand(0); 1644753f127fSDimitry Andric 1645753f127fSDimitry Andric if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 && 1646753f127fSDimitry Andric Subtarget.is64Bit() && Subtarget.hasBasicF()) { 1647753f127fSDimitry Andric SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0); 1648753f127fSDimitry Andric return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0); 1649753f127fSDimitry Andric } 1650753f127fSDimitry Andric return Op; 1651753f127fSDimitry Andric } 1652753f127fSDimitry Andric 1653753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op, 1654753f127fSDimitry Andric SelectionDAG &DAG) const { 1655753f127fSDimitry Andric 1656753f127fSDimitry Andric SDLoc DL(Op); 1657753f127fSDimitry Andric 1658753f127fSDimitry Andric if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() && 1659753f127fSDimitry Andric !Subtarget.hasBasicD()) { 1660753f127fSDimitry Andric SDValue Dst = 1661753f127fSDimitry Andric DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0)); 1662753f127fSDimitry Andric return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst); 1663753f127fSDimitry Andric } 1664753f127fSDimitry Andric 1665753f127fSDimitry Andric EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits()); 1666753f127fSDimitry Andric SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0)); 1667753f127fSDimitry Andric return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc); 1668753f127fSDimitry Andric } 1669753f127fSDimitry Andric 1670bdd1243dSDimitry Andric static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty, 1671bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 1672bdd1243dSDimitry Andric return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags); 1673bdd1243dSDimitry Andric } 1674bdd1243dSDimitry Andric 1675bdd1243dSDimitry Andric static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty, 1676bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 1677bdd1243dSDimitry Andric return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(), 1678bdd1243dSDimitry Andric Flags); 1679bdd1243dSDimitry Andric } 1680bdd1243dSDimitry Andric 1681bdd1243dSDimitry Andric static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty, 1682bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 1683bdd1243dSDimitry Andric return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(), 1684bdd1243dSDimitry Andric N->getOffset(), Flags); 1685bdd1243dSDimitry Andric } 1686bdd1243dSDimitry Andric 1687bdd1243dSDimitry Andric static SDValue getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty, 1688bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 1689bdd1243dSDimitry Andric return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags); 1690bdd1243dSDimitry Andric } 1691bdd1243dSDimitry Andric 1692bdd1243dSDimitry Andric template <class NodeTy> 1693bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG, 16941db9f3b2SDimitry Andric CodeModel::Model M, 1695bdd1243dSDimitry Andric bool IsLocal) const { 1696bdd1243dSDimitry Andric SDLoc DL(N); 1697bdd1243dSDimitry Andric EVT Ty = getPointerTy(DAG.getDataLayout()); 1698bdd1243dSDimitry Andric SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0); 16990fca6ea1SDimitry Andric SDValue Load; 170006c3fb27SDimitry Andric 17011db9f3b2SDimitry Andric switch (M) { 170206c3fb27SDimitry Andric default: 170306c3fb27SDimitry Andric report_fatal_error("Unsupported code model"); 170406c3fb27SDimitry Andric 170506c3fb27SDimitry Andric case CodeModel::Large: { 170606c3fb27SDimitry Andric assert(Subtarget.is64Bit() && "Large code model requires LA64"); 170706c3fb27SDimitry Andric 170806c3fb27SDimitry Andric // This is not actually used, but is necessary for successfully matching 170906c3fb27SDimitry Andric // the PseudoLA_*_LARGE nodes. 171006c3fb27SDimitry Andric SDValue Tmp = DAG.getConstant(0, DL, Ty); 17110fca6ea1SDimitry Andric if (IsLocal) { 171206c3fb27SDimitry Andric // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that 171306c3fb27SDimitry Andric // eventually becomes the desired 5-insn code sequence. 17140fca6ea1SDimitry Andric Load = SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty, 171506c3fb27SDimitry Andric Tmp, Addr), 171606c3fb27SDimitry Andric 0); 17170fca6ea1SDimitry Andric } else { 17180fca6ea1SDimitry Andric // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that 17190fca6ea1SDimitry Andric // eventually becomes the desired 5-insn code sequence. 17200fca6ea1SDimitry Andric Load = SDValue( 172106c3fb27SDimitry Andric DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr), 172206c3fb27SDimitry Andric 0); 172306c3fb27SDimitry Andric } 17240fca6ea1SDimitry Andric break; 17250fca6ea1SDimitry Andric } 172606c3fb27SDimitry Andric 172706c3fb27SDimitry Andric case CodeModel::Small: 172806c3fb27SDimitry Andric case CodeModel::Medium: 17290fca6ea1SDimitry Andric if (IsLocal) { 1730bdd1243dSDimitry Andric // This generates the pattern (PseudoLA_PCREL sym), which expands to 1731bdd1243dSDimitry Andric // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)). 17320fca6ea1SDimitry Andric Load = SDValue( 173306c3fb27SDimitry Andric DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0); 17340fca6ea1SDimitry Andric } else { 1735bdd1243dSDimitry Andric // This generates the pattern (PseudoLA_GOT sym), which expands to (ld.w/d 1736bdd1243dSDimitry Andric // (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)). 17370fca6ea1SDimitry Andric Load = 17380fca6ea1SDimitry Andric SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0); 173906c3fb27SDimitry Andric } 1740bdd1243dSDimitry Andric } 1741bdd1243dSDimitry Andric 17420fca6ea1SDimitry Andric if (!IsLocal) { 17430fca6ea1SDimitry Andric // Mark the load instruction as invariant to enable hoisting in MachineLICM. 17440fca6ea1SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 17450fca6ea1SDimitry Andric MachineMemOperand *MemOp = MF.getMachineMemOperand( 17460fca6ea1SDimitry Andric MachinePointerInfo::getGOT(MF), 17470fca6ea1SDimitry Andric MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable | 17480fca6ea1SDimitry Andric MachineMemOperand::MOInvariant, 17490fca6ea1SDimitry Andric LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8)); 17500fca6ea1SDimitry Andric DAG.setNodeMemRefs(cast<MachineSDNode>(Load.getNode()), {MemOp}); 17510fca6ea1SDimitry Andric } 17520fca6ea1SDimitry Andric 17530fca6ea1SDimitry Andric return Load; 17540fca6ea1SDimitry Andric } 17550fca6ea1SDimitry Andric 1756bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op, 1757bdd1243dSDimitry Andric SelectionDAG &DAG) const { 17581db9f3b2SDimitry Andric return getAddr(cast<BlockAddressSDNode>(Op), DAG, 17591db9f3b2SDimitry Andric DAG.getTarget().getCodeModel()); 1760bdd1243dSDimitry Andric } 1761bdd1243dSDimitry Andric 1762bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op, 1763bdd1243dSDimitry Andric SelectionDAG &DAG) const { 17641db9f3b2SDimitry Andric return getAddr(cast<JumpTableSDNode>(Op), DAG, 17651db9f3b2SDimitry Andric DAG.getTarget().getCodeModel()); 1766bdd1243dSDimitry Andric } 1767bdd1243dSDimitry Andric 1768753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op, 1769753f127fSDimitry Andric SelectionDAG &DAG) const { 17701db9f3b2SDimitry Andric return getAddr(cast<ConstantPoolSDNode>(Op), DAG, 17711db9f3b2SDimitry Andric DAG.getTarget().getCodeModel()); 1772753f127fSDimitry Andric } 1773753f127fSDimitry Andric 1774753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op, 1775753f127fSDimitry Andric SelectionDAG &DAG) const { 1776bdd1243dSDimitry Andric GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); 1777bdd1243dSDimitry Andric assert(N->getOffset() == 0 && "unexpected offset in global node"); 17781db9f3b2SDimitry Andric auto CM = DAG.getTarget().getCodeModel(); 17791db9f3b2SDimitry Andric const GlobalValue *GV = N->getGlobal(); 17801db9f3b2SDimitry Andric 17811db9f3b2SDimitry Andric if (GV->isDSOLocal() && isa<GlobalVariable>(GV)) { 17821db9f3b2SDimitry Andric if (auto GCM = dyn_cast<GlobalVariable>(GV)->getCodeModel()) 17831db9f3b2SDimitry Andric CM = *GCM; 17841db9f3b2SDimitry Andric } 17851db9f3b2SDimitry Andric 17861db9f3b2SDimitry Andric return getAddr(N, DAG, CM, GV->isDSOLocal()); 1787bdd1243dSDimitry Andric } 1788753f127fSDimitry Andric 1789bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N, 1790bdd1243dSDimitry Andric SelectionDAG &DAG, 17910fca6ea1SDimitry Andric unsigned Opc, bool UseGOT, 179206c3fb27SDimitry Andric bool Large) const { 1793bdd1243dSDimitry Andric SDLoc DL(N); 1794bdd1243dSDimitry Andric EVT Ty = getPointerTy(DAG.getDataLayout()); 1795bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 1796bdd1243dSDimitry Andric 179706c3fb27SDimitry Andric // This is not actually used, but is necessary for successfully matching the 179806c3fb27SDimitry Andric // PseudoLA_*_LARGE nodes. 179906c3fb27SDimitry Andric SDValue Tmp = DAG.getConstant(0, DL, Ty); 1800bdd1243dSDimitry Andric SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0); 180106c3fb27SDimitry Andric SDValue Offset = Large 180206c3fb27SDimitry Andric ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0) 180306c3fb27SDimitry Andric : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0); 18040fca6ea1SDimitry Andric if (UseGOT) { 18050fca6ea1SDimitry Andric // Mark the load instruction as invariant to enable hoisting in MachineLICM. 18060fca6ea1SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 18070fca6ea1SDimitry Andric MachineMemOperand *MemOp = MF.getMachineMemOperand( 18080fca6ea1SDimitry Andric MachinePointerInfo::getGOT(MF), 18090fca6ea1SDimitry Andric MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable | 18100fca6ea1SDimitry Andric MachineMemOperand::MOInvariant, 18110fca6ea1SDimitry Andric LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8)); 18120fca6ea1SDimitry Andric DAG.setNodeMemRefs(cast<MachineSDNode>(Offset.getNode()), {MemOp}); 18130fca6ea1SDimitry Andric } 1814bdd1243dSDimitry Andric 1815bdd1243dSDimitry Andric // Add the thread pointer. 1816bdd1243dSDimitry Andric return DAG.getNode(ISD::ADD, DL, Ty, Offset, 1817bdd1243dSDimitry Andric DAG.getRegister(LoongArch::R2, GRLenVT)); 1818bdd1243dSDimitry Andric } 1819bdd1243dSDimitry Andric 1820bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N, 1821bdd1243dSDimitry Andric SelectionDAG &DAG, 182206c3fb27SDimitry Andric unsigned Opc, 182306c3fb27SDimitry Andric bool Large) const { 1824bdd1243dSDimitry Andric SDLoc DL(N); 1825bdd1243dSDimitry Andric EVT Ty = getPointerTy(DAG.getDataLayout()); 1826bdd1243dSDimitry Andric IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits()); 1827bdd1243dSDimitry Andric 182806c3fb27SDimitry Andric // This is not actually used, but is necessary for successfully matching the 182906c3fb27SDimitry Andric // PseudoLA_*_LARGE nodes. 183006c3fb27SDimitry Andric SDValue Tmp = DAG.getConstant(0, DL, Ty); 183106c3fb27SDimitry Andric 1832bdd1243dSDimitry Andric // Use a PC-relative addressing mode to access the dynamic GOT address. 1833bdd1243dSDimitry Andric SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0); 183406c3fb27SDimitry Andric SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0) 183506c3fb27SDimitry Andric : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0); 1836bdd1243dSDimitry Andric 1837bdd1243dSDimitry Andric // Prepare argument list to generate call. 1838bdd1243dSDimitry Andric ArgListTy Args; 1839bdd1243dSDimitry Andric ArgListEntry Entry; 1840bdd1243dSDimitry Andric Entry.Node = Load; 1841bdd1243dSDimitry Andric Entry.Ty = CallTy; 1842bdd1243dSDimitry Andric Args.push_back(Entry); 1843bdd1243dSDimitry Andric 1844bdd1243dSDimitry Andric // Setup call to __tls_get_addr. 1845bdd1243dSDimitry Andric TargetLowering::CallLoweringInfo CLI(DAG); 1846bdd1243dSDimitry Andric CLI.setDebugLoc(DL) 1847bdd1243dSDimitry Andric .setChain(DAG.getEntryNode()) 1848bdd1243dSDimitry Andric .setLibCallee(CallingConv::C, CallTy, 1849bdd1243dSDimitry Andric DAG.getExternalSymbol("__tls_get_addr", Ty), 1850bdd1243dSDimitry Andric std::move(Args)); 1851bdd1243dSDimitry Andric 1852bdd1243dSDimitry Andric return LowerCallTo(CLI).first; 1853bdd1243dSDimitry Andric } 1854bdd1243dSDimitry Andric 18550fca6ea1SDimitry Andric SDValue LoongArchTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N, 18560fca6ea1SDimitry Andric SelectionDAG &DAG, unsigned Opc, 18570fca6ea1SDimitry Andric bool Large) const { 18580fca6ea1SDimitry Andric SDLoc DL(N); 18590fca6ea1SDimitry Andric EVT Ty = getPointerTy(DAG.getDataLayout()); 18600fca6ea1SDimitry Andric const GlobalValue *GV = N->getGlobal(); 18610fca6ea1SDimitry Andric 18620fca6ea1SDimitry Andric // This is not actually used, but is necessary for successfully matching the 18630fca6ea1SDimitry Andric // PseudoLA_*_LARGE nodes. 18640fca6ea1SDimitry Andric SDValue Tmp = DAG.getConstant(0, DL, Ty); 18650fca6ea1SDimitry Andric 18660fca6ea1SDimitry Andric // Use a PC-relative addressing mode to access the global dynamic GOT address. 18670fca6ea1SDimitry Andric // This generates the pattern (PseudoLA_TLS_DESC_PC{,LARGE} sym). 18680fca6ea1SDimitry Andric SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0); 18690fca6ea1SDimitry Andric return Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0) 18700fca6ea1SDimitry Andric : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0); 18710fca6ea1SDimitry Andric } 18720fca6ea1SDimitry Andric 1873bdd1243dSDimitry Andric SDValue 1874bdd1243dSDimitry Andric LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op, 1875bdd1243dSDimitry Andric SelectionDAG &DAG) const { 1876bdd1243dSDimitry Andric if (DAG.getMachineFunction().getFunction().getCallingConv() == 1877bdd1243dSDimitry Andric CallingConv::GHC) 1878bdd1243dSDimitry Andric report_fatal_error("In GHC calling convention TLS is not supported"); 1879bdd1243dSDimitry Andric 188006c3fb27SDimitry Andric bool Large = DAG.getTarget().getCodeModel() == CodeModel::Large; 188106c3fb27SDimitry Andric assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64"); 188206c3fb27SDimitry Andric 1883bdd1243dSDimitry Andric GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); 1884bdd1243dSDimitry Andric assert(N->getOffset() == 0 && "unexpected offset in global node"); 1885bdd1243dSDimitry Andric 18860fca6ea1SDimitry Andric if (DAG.getTarget().useEmulatedTLS()) 18870fca6ea1SDimitry Andric report_fatal_error("the emulated TLS is prohibited", 18880fca6ea1SDimitry Andric /*GenCrashDiag=*/false); 18890fca6ea1SDimitry Andric 18900fca6ea1SDimitry Andric bool IsDesc = DAG.getTarget().useTLSDESC(); 18910fca6ea1SDimitry Andric 1892bdd1243dSDimitry Andric switch (getTargetMachine().getTLSModel(N->getGlobal())) { 1893bdd1243dSDimitry Andric case TLSModel::GeneralDynamic: 1894bdd1243dSDimitry Andric // In this model, application code calls the dynamic linker function 1895bdd1243dSDimitry Andric // __tls_get_addr to locate TLS offsets into the dynamic thread vector at 1896bdd1243dSDimitry Andric // runtime. 18970fca6ea1SDimitry Andric if (!IsDesc) 18980fca6ea1SDimitry Andric return getDynamicTLSAddr(N, DAG, 189906c3fb27SDimitry Andric Large ? LoongArch::PseudoLA_TLS_GD_LARGE 190006c3fb27SDimitry Andric : LoongArch::PseudoLA_TLS_GD, 190106c3fb27SDimitry Andric Large); 1902bdd1243dSDimitry Andric break; 1903bdd1243dSDimitry Andric case TLSModel::LocalDynamic: 1904bdd1243dSDimitry Andric // Same as GeneralDynamic, except for assembly modifiers and relocation 1905bdd1243dSDimitry Andric // records. 19060fca6ea1SDimitry Andric if (!IsDesc) 19070fca6ea1SDimitry Andric return getDynamicTLSAddr(N, DAG, 190806c3fb27SDimitry Andric Large ? LoongArch::PseudoLA_TLS_LD_LARGE 190906c3fb27SDimitry Andric : LoongArch::PseudoLA_TLS_LD, 191006c3fb27SDimitry Andric Large); 1911bdd1243dSDimitry Andric break; 1912bdd1243dSDimitry Andric case TLSModel::InitialExec: 1913bdd1243dSDimitry Andric // This model uses the GOT to resolve TLS offsets. 19140fca6ea1SDimitry Andric return getStaticTLSAddr(N, DAG, 191506c3fb27SDimitry Andric Large ? LoongArch::PseudoLA_TLS_IE_LARGE 191606c3fb27SDimitry Andric : LoongArch::PseudoLA_TLS_IE, 19170fca6ea1SDimitry Andric /*UseGOT=*/true, Large); 1918bdd1243dSDimitry Andric case TLSModel::LocalExec: 1919bdd1243dSDimitry Andric // This model is used when static linking as the TLS offsets are resolved 1920bdd1243dSDimitry Andric // during program linking. 192106c3fb27SDimitry Andric // 192206c3fb27SDimitry Andric // This node doesn't need an extra argument for the large code model. 19230fca6ea1SDimitry Andric return getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE, 19240fca6ea1SDimitry Andric /*UseGOT=*/false); 1925bdd1243dSDimitry Andric } 1926bdd1243dSDimitry Andric 19270fca6ea1SDimitry Andric return getTLSDescAddr(N, DAG, 19280fca6ea1SDimitry Andric Large ? LoongArch::PseudoLA_TLS_DESC_PC_LARGE 19290fca6ea1SDimitry Andric : LoongArch::PseudoLA_TLS_DESC_PC, 19300fca6ea1SDimitry Andric Large); 1931753f127fSDimitry Andric } 1932bdd1243dSDimitry Andric 19335f757f3fSDimitry Andric template <unsigned N> 19345f757f3fSDimitry Andric static SDValue checkIntrinsicImmArg(SDValue Op, unsigned ImmOp, 19355f757f3fSDimitry Andric SelectionDAG &DAG, bool IsSigned = false) { 19365f757f3fSDimitry Andric auto *CImm = cast<ConstantSDNode>(Op->getOperand(ImmOp)); 19375f757f3fSDimitry Andric // Check the ImmArg. 19385f757f3fSDimitry Andric if ((IsSigned && !isInt<N>(CImm->getSExtValue())) || 19395f757f3fSDimitry Andric (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) { 19405f757f3fSDimitry Andric DAG.getContext()->emitError(Op->getOperationName(0) + 19415f757f3fSDimitry Andric ": argument out of range."); 19425f757f3fSDimitry Andric return DAG.getNode(ISD::UNDEF, SDLoc(Op), Op.getValueType()); 19435f757f3fSDimitry Andric } 19445f757f3fSDimitry Andric return SDValue(); 19455f757f3fSDimitry Andric } 19465f757f3fSDimitry Andric 1947bdd1243dSDimitry Andric SDValue 1948bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, 1949bdd1243dSDimitry Andric SelectionDAG &DAG) const { 19505f757f3fSDimitry Andric SDLoc DL(Op); 1951bdd1243dSDimitry Andric switch (Op.getConstantOperandVal(0)) { 1952bdd1243dSDimitry Andric default: 1953bdd1243dSDimitry Andric return SDValue(); // Don't custom lower most intrinsics. 1954bdd1243dSDimitry Andric case Intrinsic::thread_pointer: { 1955bdd1243dSDimitry Andric EVT PtrVT = getPointerTy(DAG.getDataLayout()); 1956bdd1243dSDimitry Andric return DAG.getRegister(LoongArch::R2, PtrVT); 1957bdd1243dSDimitry Andric } 19585f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpickve2gr_d: 19595f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpickve2gr_du: 19605f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplvei_d: 19615f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrepl128vei_d: 19625f757f3fSDimitry Andric return checkIntrinsicImmArg<1>(Op, 2, DAG); 19635f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplvei_w: 19645f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrepl128vei_w: 19655f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpickve2gr_d: 19665f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpickve2gr_du: 19675f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpickve_d: 19685f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpickve_d_f: 19695f757f3fSDimitry Andric return checkIntrinsicImmArg<2>(Op, 2, DAG); 19705f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvinsve0_d: 19715f757f3fSDimitry Andric return checkIntrinsicImmArg<2>(Op, 3, DAG); 19725f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsat_b: 19735f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsat_bu: 19745f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vrotri_b: 19755f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsllwil_h_b: 19765f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsllwil_hu_bu: 19775f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlri_b: 19785f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrari_b: 19795f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplvei_h: 19805f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsat_b: 19815f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsat_bu: 19825f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrotri_b: 19835f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsllwil_h_b: 19845f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsllwil_hu_bu: 19855f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlri_b: 19865f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrari_b: 19875f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrepl128vei_h: 19885f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpickve_w: 19895f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpickve_w_f: 19905f757f3fSDimitry Andric return checkIntrinsicImmArg<3>(Op, 2, DAG); 19915f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvinsve0_w: 19925f757f3fSDimitry Andric return checkIntrinsicImmArg<3>(Op, 3, DAG); 19935f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsat_h: 19945f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsat_hu: 19955f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vrotri_h: 19965f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsllwil_w_h: 19975f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsllwil_wu_hu: 19985f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlri_h: 19995f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrari_h: 20005f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplvei_b: 20015f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsat_h: 20025f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsat_hu: 20035f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrotri_h: 20045f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsllwil_w_h: 20055f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsllwil_wu_hu: 20065f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlri_h: 20075f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrari_h: 20085f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrepl128vei_b: 20095f757f3fSDimitry Andric return checkIntrinsicImmArg<4>(Op, 2, DAG); 20105f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlni_b_h: 20115f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrani_b_h: 20125f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlrni_b_h: 20135f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrarni_b_h: 20145f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlni_b_h: 20155f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrani_b_h: 20165f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlni_bu_h: 20175f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrani_bu_h: 20185f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlrni_b_h: 20195f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrarni_b_h: 20205f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlrni_bu_h: 20215f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrarni_bu_h: 20225f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlni_b_h: 20235f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrani_b_h: 20245f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlrni_b_h: 20255f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrarni_b_h: 20265f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlni_b_h: 20275f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrani_b_h: 20285f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlni_bu_h: 20295f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrani_bu_h: 20305f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlrni_b_h: 20315f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrarni_b_h: 20325f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlrni_bu_h: 20335f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrarni_bu_h: 20345f757f3fSDimitry Andric return checkIntrinsicImmArg<4>(Op, 3, DAG); 20355f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsat_w: 20365f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsat_wu: 20375f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vrotri_w: 20385f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsllwil_d_w: 20395f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsllwil_du_wu: 20405f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlri_w: 20415f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrari_w: 20425f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslei_bu: 20435f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslei_hu: 20445f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslei_wu: 20455f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslei_du: 20465f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslti_bu: 20475f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslti_hu: 20485f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslti_wu: 20495f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslti_du: 20505f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbsll_v: 20515f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbsrl_v: 20525f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsat_w: 20535f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsat_wu: 20545f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrotri_w: 20555f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsllwil_d_w: 20565f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsllwil_du_wu: 20575f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlri_w: 20585f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrari_w: 20595f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslei_bu: 20605f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslei_hu: 20615f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslei_wu: 20625f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslei_du: 20635f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslti_bu: 20645f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslti_hu: 20655f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslti_wu: 20665f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslti_du: 20675f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbsll_v: 20685f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbsrl_v: 20695f757f3fSDimitry Andric return checkIntrinsicImmArg<5>(Op, 2, DAG); 20705f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vseqi_b: 20715f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vseqi_h: 20725f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vseqi_w: 20735f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vseqi_d: 20745f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslei_b: 20755f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslei_h: 20765f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslei_w: 20775f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslei_d: 20785f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslti_b: 20795f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslti_h: 20805f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslti_w: 20815f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslti_d: 20825f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvseqi_b: 20835f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvseqi_h: 20845f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvseqi_w: 20855f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvseqi_d: 20865f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslei_b: 20875f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslei_h: 20885f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslei_w: 20895f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslei_d: 20905f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslti_b: 20915f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslti_h: 20925f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslti_w: 20935f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslti_d: 20945f757f3fSDimitry Andric return checkIntrinsicImmArg<5>(Op, 2, DAG, /*IsSigned=*/true); 20955f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlni_h_w: 20965f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrani_h_w: 20975f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlrni_h_w: 20985f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrarni_h_w: 20995f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlni_h_w: 21005f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrani_h_w: 21015f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlni_hu_w: 21025f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrani_hu_w: 21035f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlrni_h_w: 21045f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrarni_h_w: 21055f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlrni_hu_w: 21065f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrarni_hu_w: 21075f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfrstpi_b: 21085f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfrstpi_h: 21095f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlni_h_w: 21105f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrani_h_w: 21115f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlrni_h_w: 21125f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrarni_h_w: 21135f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlni_h_w: 21145f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrani_h_w: 21155f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlni_hu_w: 21165f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrani_hu_w: 21175f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlrni_h_w: 21185f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrarni_h_w: 21195f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlrni_hu_w: 21205f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrarni_hu_w: 21215f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfrstpi_b: 21225f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfrstpi_h: 21235f757f3fSDimitry Andric return checkIntrinsicImmArg<5>(Op, 3, DAG); 21245f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsat_d: 21255f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsat_du: 21265f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vrotri_d: 21275f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlri_d: 21285f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrari_d: 21295f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsat_d: 21305f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsat_du: 21315f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrotri_d: 21325f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlri_d: 21335f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrari_d: 21345f757f3fSDimitry Andric return checkIntrinsicImmArg<6>(Op, 2, DAG); 21355f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlni_w_d: 21365f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrani_w_d: 21375f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlrni_w_d: 21385f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrarni_w_d: 21395f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlni_w_d: 21405f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrani_w_d: 21415f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlni_wu_d: 21425f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrani_wu_d: 21435f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlrni_w_d: 21445f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrarni_w_d: 21455f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlrni_wu_d: 21465f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrarni_wu_d: 21475f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlni_w_d: 21485f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrani_w_d: 21495f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlrni_w_d: 21505f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrarni_w_d: 21515f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlni_w_d: 21525f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrani_w_d: 21535f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlni_wu_d: 21545f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrani_wu_d: 21555f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlrni_w_d: 21565f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrarni_w_d: 21575f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlrni_wu_d: 21585f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrarni_wu_d: 21595f757f3fSDimitry Andric return checkIntrinsicImmArg<6>(Op, 3, DAG); 21605f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlni_d_q: 21615f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrani_d_q: 21625f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrlrni_d_q: 21635f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrarni_d_q: 21645f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlni_d_q: 21655f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrani_d_q: 21665f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlni_du_q: 21675f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrani_du_q: 21685f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlrni_d_q: 21695f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrarni_d_q: 21705f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrlrni_du_q: 21715f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vssrarni_du_q: 21725f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlni_d_q: 21735f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrani_d_q: 21745f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrlrni_d_q: 21755f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrarni_d_q: 21765f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlni_d_q: 21775f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrani_d_q: 21785f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlni_du_q: 21795f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrani_du_q: 21805f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlrni_d_q: 21815f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrarni_d_q: 21825f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrlrni_du_q: 21835f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvssrarni_du_q: 21845f757f3fSDimitry Andric return checkIntrinsicImmArg<7>(Op, 3, DAG); 21855f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vnori_b: 21865f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vshuf4i_b: 21875f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vshuf4i_h: 21885f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vshuf4i_w: 21895f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvnori_b: 21905f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvshuf4i_b: 21915f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvshuf4i_h: 21925f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvshuf4i_w: 21935f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpermi_d: 21945f757f3fSDimitry Andric return checkIntrinsicImmArg<8>(Op, 2, DAG); 21955f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vshuf4i_d: 21965f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpermi_w: 21975f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitseli_b: 21985f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vextrins_b: 21995f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vextrins_h: 22005f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vextrins_w: 22015f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vextrins_d: 22025f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvshuf4i_d: 22035f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpermi_w: 22045f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpermi_q: 22055f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitseli_b: 22065f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvextrins_b: 22075f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvextrins_h: 22085f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvextrins_w: 22095f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvextrins_d: 22105f757f3fSDimitry Andric return checkIntrinsicImmArg<8>(Op, 3, DAG); 22115f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vrepli_b: 22125f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vrepli_h: 22135f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vrepli_w: 22145f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vrepli_d: 22155f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrepli_b: 22165f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrepli_h: 22175f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrepli_w: 22185f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvrepli_d: 22195f757f3fSDimitry Andric return checkIntrinsicImmArg<10>(Op, 1, DAG, /*IsSigned=*/true); 22205f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vldi: 22215f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvldi: 22225f757f3fSDimitry Andric return checkIntrinsicImmArg<13>(Op, 1, DAG, /*IsSigned=*/true); 2223bdd1243dSDimitry Andric } 2224bdd1243dSDimitry Andric } 2225bdd1243dSDimitry Andric 222606c3fb27SDimitry Andric // Helper function that emits error message for intrinsics with chain and return 222706c3fb27SDimitry Andric // merge values of a UNDEF and the chain. 2228bdd1243dSDimitry Andric static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op, 2229bdd1243dSDimitry Andric StringRef ErrorMsg, 2230bdd1243dSDimitry Andric SelectionDAG &DAG) { 223106c3fb27SDimitry Andric DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + "."); 2232bdd1243dSDimitry Andric return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, 2233bdd1243dSDimitry Andric SDLoc(Op)); 2234bdd1243dSDimitry Andric } 2235bdd1243dSDimitry Andric 2236bdd1243dSDimitry Andric SDValue 2237bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op, 2238bdd1243dSDimitry Andric SelectionDAG &DAG) const { 2239bdd1243dSDimitry Andric SDLoc DL(Op); 2240bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 224106c3fb27SDimitry Andric EVT VT = Op.getValueType(); 224206c3fb27SDimitry Andric SDValue Chain = Op.getOperand(0); 224306c3fb27SDimitry Andric const StringRef ErrorMsgOOR = "argument out of range"; 224406c3fb27SDimitry Andric const StringRef ErrorMsgReqLA64 = "requires loongarch64"; 224506c3fb27SDimitry Andric const StringRef ErrorMsgReqF = "requires basic 'f' target feature"; 2246bdd1243dSDimitry Andric 2247bdd1243dSDimitry Andric switch (Op.getConstantOperandVal(1)) { 2248bdd1243dSDimitry Andric default: 2249bdd1243dSDimitry Andric return Op; 2250bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_b_w: 2251bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_h_w: 2252bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_w_w: 2253bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_d_w: 2254bdd1243dSDimitry Andric case Intrinsic::loongarch_crcc_w_b_w: 2255bdd1243dSDimitry Andric case Intrinsic::loongarch_crcc_w_h_w: 2256bdd1243dSDimitry Andric case Intrinsic::loongarch_crcc_w_w_w: 225706c3fb27SDimitry Andric case Intrinsic::loongarch_crcc_w_d_w: 225806c3fb27SDimitry Andric return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG); 2259bdd1243dSDimitry Andric case Intrinsic::loongarch_csrrd_w: 2260bdd1243dSDimitry Andric case Intrinsic::loongarch_csrrd_d: { 2261647cbc5dSDimitry Andric unsigned Imm = Op.getConstantOperandVal(2); 226206c3fb27SDimitry Andric return !isUInt<14>(Imm) 226306c3fb27SDimitry Andric ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG) 226406c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other}, 226506c3fb27SDimitry Andric {Chain, DAG.getConstant(Imm, DL, GRLenVT)}); 2266bdd1243dSDimitry Andric } 2267bdd1243dSDimitry Andric case Intrinsic::loongarch_csrwr_w: 2268bdd1243dSDimitry Andric case Intrinsic::loongarch_csrwr_d: { 2269647cbc5dSDimitry Andric unsigned Imm = Op.getConstantOperandVal(3); 227006c3fb27SDimitry Andric return !isUInt<14>(Imm) 227106c3fb27SDimitry Andric ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG) 227206c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other}, 227306c3fb27SDimitry Andric {Chain, Op.getOperand(2), 227406c3fb27SDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)}); 2275bdd1243dSDimitry Andric } 2276bdd1243dSDimitry Andric case Intrinsic::loongarch_csrxchg_w: 2277bdd1243dSDimitry Andric case Intrinsic::loongarch_csrxchg_d: { 2278647cbc5dSDimitry Andric unsigned Imm = Op.getConstantOperandVal(4); 227906c3fb27SDimitry Andric return !isUInt<14>(Imm) 228006c3fb27SDimitry Andric ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG) 228106c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other}, 228206c3fb27SDimitry Andric {Chain, Op.getOperand(2), Op.getOperand(3), 228306c3fb27SDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)}); 2284bdd1243dSDimitry Andric } 2285bdd1243dSDimitry Andric case Intrinsic::loongarch_iocsrrd_d: { 228606c3fb27SDimitry Andric return DAG.getNode( 228706c3fb27SDimitry Andric LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other}, 228806c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))}); 2289bdd1243dSDimitry Andric } 2290bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE) \ 2291bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 229206c3fb27SDimitry Andric return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other}, \ 229306c3fb27SDimitry Andric {Chain, Op.getOperand(2)}); \ 2294bdd1243dSDimitry Andric } 2295bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B); 2296bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H); 2297bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W); 2298bdd1243dSDimitry Andric #undef IOCSRRD_CASE 2299bdd1243dSDimitry Andric case Intrinsic::loongarch_cpucfg: { 230006c3fb27SDimitry Andric return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other}, 230106c3fb27SDimitry Andric {Chain, Op.getOperand(2)}); 2302bdd1243dSDimitry Andric } 2303bdd1243dSDimitry Andric case Intrinsic::loongarch_lddir_d: { 2304647cbc5dSDimitry Andric unsigned Imm = Op.getConstantOperandVal(3); 230506c3fb27SDimitry Andric return !isUInt<8>(Imm) 230606c3fb27SDimitry Andric ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG) 230706c3fb27SDimitry Andric : Op; 2308bdd1243dSDimitry Andric } 2309bdd1243dSDimitry Andric case Intrinsic::loongarch_movfcsr2gr: { 231006c3fb27SDimitry Andric if (!Subtarget.hasBasicF()) 231106c3fb27SDimitry Andric return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG); 2312647cbc5dSDimitry Andric unsigned Imm = Op.getConstantOperandVal(2); 231306c3fb27SDimitry Andric return !isUInt<2>(Imm) 231406c3fb27SDimitry Andric ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG) 231506c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other}, 231606c3fb27SDimitry Andric {Chain, DAG.getConstant(Imm, DL, GRLenVT)}); 2317bdd1243dSDimitry Andric } 23185f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vld: 23195f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vldrepl_b: 23205f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvld: 23215f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvldrepl_b: 23225f757f3fSDimitry Andric return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue()) 23235f757f3fSDimitry Andric ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG) 23245f757f3fSDimitry Andric : SDValue(); 23255f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vldrepl_h: 23265f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvldrepl_h: 23275f757f3fSDimitry Andric return !isShiftedInt<11, 1>( 23285f757f3fSDimitry Andric cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue()) 23295f757f3fSDimitry Andric ? emitIntrinsicWithChainErrorMessage( 23305f757f3fSDimitry Andric Op, "argument out of range or not a multiple of 2", DAG) 23315f757f3fSDimitry Andric : SDValue(); 23325f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vldrepl_w: 23335f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvldrepl_w: 23345f757f3fSDimitry Andric return !isShiftedInt<10, 2>( 23355f757f3fSDimitry Andric cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue()) 23365f757f3fSDimitry Andric ? emitIntrinsicWithChainErrorMessage( 23375f757f3fSDimitry Andric Op, "argument out of range or not a multiple of 4", DAG) 23385f757f3fSDimitry Andric : SDValue(); 23395f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vldrepl_d: 23405f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvldrepl_d: 23415f757f3fSDimitry Andric return !isShiftedInt<9, 3>( 23425f757f3fSDimitry Andric cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue()) 23435f757f3fSDimitry Andric ? emitIntrinsicWithChainErrorMessage( 23445f757f3fSDimitry Andric Op, "argument out of range or not a multiple of 8", DAG) 23455f757f3fSDimitry Andric : SDValue(); 2346bdd1243dSDimitry Andric } 2347bdd1243dSDimitry Andric } 2348bdd1243dSDimitry Andric 2349bdd1243dSDimitry Andric // Helper function that emits error message for intrinsics with void return 235006c3fb27SDimitry Andric // value and return the chain. 2351bdd1243dSDimitry Andric static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg, 2352bdd1243dSDimitry Andric SelectionDAG &DAG) { 2353bdd1243dSDimitry Andric 235406c3fb27SDimitry Andric DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + "."); 2355bdd1243dSDimitry Andric return Op.getOperand(0); 2356bdd1243dSDimitry Andric } 2357bdd1243dSDimitry Andric 2358bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op, 2359bdd1243dSDimitry Andric SelectionDAG &DAG) const { 2360bdd1243dSDimitry Andric SDLoc DL(Op); 2361bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 236206c3fb27SDimitry Andric SDValue Chain = Op.getOperand(0); 2363bdd1243dSDimitry Andric uint64_t IntrinsicEnum = Op.getConstantOperandVal(1); 2364bdd1243dSDimitry Andric SDValue Op2 = Op.getOperand(2); 236506c3fb27SDimitry Andric const StringRef ErrorMsgOOR = "argument out of range"; 236606c3fb27SDimitry Andric const StringRef ErrorMsgReqLA64 = "requires loongarch64"; 236706c3fb27SDimitry Andric const StringRef ErrorMsgReqLA32 = "requires loongarch32"; 236806c3fb27SDimitry Andric const StringRef ErrorMsgReqF = "requires basic 'f' target feature"; 2369bdd1243dSDimitry Andric 2370bdd1243dSDimitry Andric switch (IntrinsicEnum) { 2371bdd1243dSDimitry Andric default: 2372bdd1243dSDimitry Andric // TODO: Add more Intrinsics. 2373bdd1243dSDimitry Andric return SDValue(); 2374bdd1243dSDimitry Andric case Intrinsic::loongarch_cacop_d: 2375bdd1243dSDimitry Andric case Intrinsic::loongarch_cacop_w: { 237606c3fb27SDimitry Andric if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit()) 237706c3fb27SDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG); 237806c3fb27SDimitry Andric if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit()) 237906c3fb27SDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG); 2380bdd1243dSDimitry Andric // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12) 23811db9f3b2SDimitry Andric unsigned Imm1 = Op2->getAsZExtVal(); 238206c3fb27SDimitry Andric int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue(); 238306c3fb27SDimitry Andric if (!isUInt<5>(Imm1) || !isInt<12>(Imm2)) 2384bdd1243dSDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG); 2385bdd1243dSDimitry Andric return Op; 2386bdd1243dSDimitry Andric } 2387bdd1243dSDimitry Andric case Intrinsic::loongarch_dbar: { 23881db9f3b2SDimitry Andric unsigned Imm = Op2->getAsZExtVal(); 238906c3fb27SDimitry Andric return !isUInt<15>(Imm) 239006c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 239106c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain, 2392bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 2393bdd1243dSDimitry Andric } 2394bdd1243dSDimitry Andric case Intrinsic::loongarch_ibar: { 23951db9f3b2SDimitry Andric unsigned Imm = Op2->getAsZExtVal(); 239606c3fb27SDimitry Andric return !isUInt<15>(Imm) 239706c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 239806c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain, 2399bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 2400bdd1243dSDimitry Andric } 2401bdd1243dSDimitry Andric case Intrinsic::loongarch_break: { 24021db9f3b2SDimitry Andric unsigned Imm = Op2->getAsZExtVal(); 240306c3fb27SDimitry Andric return !isUInt<15>(Imm) 240406c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 240506c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain, 2406bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 2407bdd1243dSDimitry Andric } 2408bdd1243dSDimitry Andric case Intrinsic::loongarch_movgr2fcsr: { 240906c3fb27SDimitry Andric if (!Subtarget.hasBasicF()) 241006c3fb27SDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG); 24111db9f3b2SDimitry Andric unsigned Imm = Op2->getAsZExtVal(); 241206c3fb27SDimitry Andric return !isUInt<2>(Imm) 241306c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 241406c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain, 2415bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT), 241606c3fb27SDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, 241706c3fb27SDimitry Andric Op.getOperand(3))); 2418bdd1243dSDimitry Andric } 2419bdd1243dSDimitry Andric case Intrinsic::loongarch_syscall: { 24201db9f3b2SDimitry Andric unsigned Imm = Op2->getAsZExtVal(); 242106c3fb27SDimitry Andric return !isUInt<15>(Imm) 242206c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 242306c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain, 2424bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 2425bdd1243dSDimitry Andric } 2426bdd1243dSDimitry Andric #define IOCSRWR_CASE(NAME, NODE) \ 2427bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 2428bdd1243dSDimitry Andric SDValue Op3 = Op.getOperand(3); \ 242906c3fb27SDimitry Andric return Subtarget.is64Bit() \ 243006c3fb27SDimitry Andric ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, \ 2431bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \ 243206c3fb27SDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)) \ 243306c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2, \ 243406c3fb27SDimitry Andric Op3); \ 2435bdd1243dSDimitry Andric } 2436bdd1243dSDimitry Andric IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B); 2437bdd1243dSDimitry Andric IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H); 2438bdd1243dSDimitry Andric IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W); 2439bdd1243dSDimitry Andric #undef IOCSRWR_CASE 2440bdd1243dSDimitry Andric case Intrinsic::loongarch_iocsrwr_d: { 244106c3fb27SDimitry Andric return !Subtarget.is64Bit() 244206c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) 244306c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain, 244406c3fb27SDimitry Andric Op2, 244506c3fb27SDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, 244606c3fb27SDimitry Andric Op.getOperand(3))); 2447bdd1243dSDimitry Andric } 2448bdd1243dSDimitry Andric #define ASRT_LE_GT_CASE(NAME) \ 2449bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 245006c3fb27SDimitry Andric return !Subtarget.is64Bit() \ 245106c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) \ 245206c3fb27SDimitry Andric : Op; \ 2453bdd1243dSDimitry Andric } 2454bdd1243dSDimitry Andric ASRT_LE_GT_CASE(asrtle_d) 2455bdd1243dSDimitry Andric ASRT_LE_GT_CASE(asrtgt_d) 2456bdd1243dSDimitry Andric #undef ASRT_LE_GT_CASE 2457bdd1243dSDimitry Andric case Intrinsic::loongarch_ldpte_d: { 2458647cbc5dSDimitry Andric unsigned Imm = Op.getConstantOperandVal(3); 245906c3fb27SDimitry Andric return !Subtarget.is64Bit() 246006c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) 246106c3fb27SDimitry Andric : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 246206c3fb27SDimitry Andric : Op; 2463bdd1243dSDimitry Andric } 24645f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vst: 24655f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvst: 24665f757f3fSDimitry Andric return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) 24675f757f3fSDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 24685f757f3fSDimitry Andric : SDValue(); 24695f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvstelm_b: 24705f757f3fSDimitry Andric return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) || 2471647cbc5dSDimitry Andric !isUInt<5>(Op.getConstantOperandVal(5))) 24725f757f3fSDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 24735f757f3fSDimitry Andric : SDValue(); 24745f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vstelm_b: 24755f757f3fSDimitry Andric return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) || 2476647cbc5dSDimitry Andric !isUInt<4>(Op.getConstantOperandVal(5))) 24775f757f3fSDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 24785f757f3fSDimitry Andric : SDValue(); 24795f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvstelm_h: 24805f757f3fSDimitry Andric return (!isShiftedInt<8, 1>( 24815f757f3fSDimitry Andric cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) || 2482647cbc5dSDimitry Andric !isUInt<4>(Op.getConstantOperandVal(5))) 24835f757f3fSDimitry Andric ? emitIntrinsicErrorMessage( 24845f757f3fSDimitry Andric Op, "argument out of range or not a multiple of 2", DAG) 24855f757f3fSDimitry Andric : SDValue(); 24865f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vstelm_h: 24875f757f3fSDimitry Andric return (!isShiftedInt<8, 1>( 24885f757f3fSDimitry Andric cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) || 2489647cbc5dSDimitry Andric !isUInt<3>(Op.getConstantOperandVal(5))) 24905f757f3fSDimitry Andric ? emitIntrinsicErrorMessage( 24915f757f3fSDimitry Andric Op, "argument out of range or not a multiple of 2", DAG) 24925f757f3fSDimitry Andric : SDValue(); 24935f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvstelm_w: 24945f757f3fSDimitry Andric return (!isShiftedInt<8, 2>( 24955f757f3fSDimitry Andric cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) || 2496647cbc5dSDimitry Andric !isUInt<3>(Op.getConstantOperandVal(5))) 24975f757f3fSDimitry Andric ? emitIntrinsicErrorMessage( 24985f757f3fSDimitry Andric Op, "argument out of range or not a multiple of 4", DAG) 24995f757f3fSDimitry Andric : SDValue(); 25005f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vstelm_w: 25015f757f3fSDimitry Andric return (!isShiftedInt<8, 2>( 25025f757f3fSDimitry Andric cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) || 2503647cbc5dSDimitry Andric !isUInt<2>(Op.getConstantOperandVal(5))) 25045f757f3fSDimitry Andric ? emitIntrinsicErrorMessage( 25055f757f3fSDimitry Andric Op, "argument out of range or not a multiple of 4", DAG) 25065f757f3fSDimitry Andric : SDValue(); 25075f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvstelm_d: 25085f757f3fSDimitry Andric return (!isShiftedInt<8, 3>( 25095f757f3fSDimitry Andric cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) || 2510647cbc5dSDimitry Andric !isUInt<2>(Op.getConstantOperandVal(5))) 25115f757f3fSDimitry Andric ? emitIntrinsicErrorMessage( 25125f757f3fSDimitry Andric Op, "argument out of range or not a multiple of 8", DAG) 25135f757f3fSDimitry Andric : SDValue(); 25145f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vstelm_d: 25155f757f3fSDimitry Andric return (!isShiftedInt<8, 3>( 25165f757f3fSDimitry Andric cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) || 2517647cbc5dSDimitry Andric !isUInt<1>(Op.getConstantOperandVal(5))) 25185f757f3fSDimitry Andric ? emitIntrinsicErrorMessage( 25195f757f3fSDimitry Andric Op, "argument out of range or not a multiple of 8", DAG) 25205f757f3fSDimitry Andric : SDValue(); 2521bdd1243dSDimitry Andric } 2522753f127fSDimitry Andric } 2523753f127fSDimitry Andric 252481ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op, 252581ad6265SDimitry Andric SelectionDAG &DAG) const { 252681ad6265SDimitry Andric SDLoc DL(Op); 252781ad6265SDimitry Andric SDValue Lo = Op.getOperand(0); 252881ad6265SDimitry Andric SDValue Hi = Op.getOperand(1); 252981ad6265SDimitry Andric SDValue Shamt = Op.getOperand(2); 253081ad6265SDimitry Andric EVT VT = Lo.getValueType(); 253181ad6265SDimitry Andric 253281ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 253381ad6265SDimitry Andric // Lo = Lo << Shamt 253481ad6265SDimitry Andric // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt)) 253581ad6265SDimitry Andric // else: 253681ad6265SDimitry Andric // Lo = 0 253781ad6265SDimitry Andric // Hi = Lo << (Shamt-GRLen) 253881ad6265SDimitry Andric 253981ad6265SDimitry Andric SDValue Zero = DAG.getConstant(0, DL, VT); 254081ad6265SDimitry Andric SDValue One = DAG.getConstant(1, DL, VT); 254181ad6265SDimitry Andric SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT); 254281ad6265SDimitry Andric SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT); 254381ad6265SDimitry Andric SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen); 254481ad6265SDimitry Andric SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1); 254581ad6265SDimitry Andric 254681ad6265SDimitry Andric SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt); 254781ad6265SDimitry Andric SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One); 254881ad6265SDimitry Andric SDValue ShiftRightLo = 254981ad6265SDimitry Andric DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt); 255081ad6265SDimitry Andric SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt); 255181ad6265SDimitry Andric SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo); 255281ad6265SDimitry Andric SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen); 255381ad6265SDimitry Andric 255481ad6265SDimitry Andric SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT); 255581ad6265SDimitry Andric 255681ad6265SDimitry Andric Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero); 255781ad6265SDimitry Andric Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); 255881ad6265SDimitry Andric 255981ad6265SDimitry Andric SDValue Parts[2] = {Lo, Hi}; 256081ad6265SDimitry Andric return DAG.getMergeValues(Parts, DL); 256181ad6265SDimitry Andric } 256281ad6265SDimitry Andric 256381ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op, 256481ad6265SDimitry Andric SelectionDAG &DAG, 256581ad6265SDimitry Andric bool IsSRA) const { 256681ad6265SDimitry Andric SDLoc DL(Op); 256781ad6265SDimitry Andric SDValue Lo = Op.getOperand(0); 256881ad6265SDimitry Andric SDValue Hi = Op.getOperand(1); 256981ad6265SDimitry Andric SDValue Shamt = Op.getOperand(2); 257081ad6265SDimitry Andric EVT VT = Lo.getValueType(); 257181ad6265SDimitry Andric 257281ad6265SDimitry Andric // SRA expansion: 257381ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 257481ad6265SDimitry Andric // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1)) 257581ad6265SDimitry Andric // Hi = Hi >>s Shamt 257681ad6265SDimitry Andric // else: 257781ad6265SDimitry Andric // Lo = Hi >>s (Shamt-GRLen); 257881ad6265SDimitry Andric // Hi = Hi >>s (GRLen-1) 257981ad6265SDimitry Andric // 258081ad6265SDimitry Andric // SRL expansion: 258181ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 258281ad6265SDimitry Andric // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1)) 258381ad6265SDimitry Andric // Hi = Hi >>u Shamt 258481ad6265SDimitry Andric // else: 258581ad6265SDimitry Andric // Lo = Hi >>u (Shamt-GRLen); 258681ad6265SDimitry Andric // Hi = 0; 258781ad6265SDimitry Andric 258881ad6265SDimitry Andric unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL; 258981ad6265SDimitry Andric 259081ad6265SDimitry Andric SDValue Zero = DAG.getConstant(0, DL, VT); 259181ad6265SDimitry Andric SDValue One = DAG.getConstant(1, DL, VT); 259281ad6265SDimitry Andric SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT); 259381ad6265SDimitry Andric SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT); 259481ad6265SDimitry Andric SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen); 259581ad6265SDimitry Andric SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1); 259681ad6265SDimitry Andric 259781ad6265SDimitry Andric SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt); 259881ad6265SDimitry Andric SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One); 259981ad6265SDimitry Andric SDValue ShiftLeftHi = 260081ad6265SDimitry Andric DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt); 260181ad6265SDimitry Andric SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi); 260281ad6265SDimitry Andric SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt); 260381ad6265SDimitry Andric SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen); 260481ad6265SDimitry Andric SDValue HiFalse = 260581ad6265SDimitry Andric IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero; 260681ad6265SDimitry Andric 260781ad6265SDimitry Andric SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT); 260881ad6265SDimitry Andric 260981ad6265SDimitry Andric Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse); 261081ad6265SDimitry Andric Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); 261181ad6265SDimitry Andric 261281ad6265SDimitry Andric SDValue Parts[2] = {Lo, Hi}; 261381ad6265SDimitry Andric return DAG.getMergeValues(Parts, DL); 261481ad6265SDimitry Andric } 261581ad6265SDimitry Andric 261681ad6265SDimitry Andric // Returns the opcode of the target-specific SDNode that implements the 32-bit 261781ad6265SDimitry Andric // form of the given Opcode. 261881ad6265SDimitry Andric static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode) { 261981ad6265SDimitry Andric switch (Opcode) { 262081ad6265SDimitry Andric default: 262181ad6265SDimitry Andric llvm_unreachable("Unexpected opcode"); 26220fca6ea1SDimitry Andric case ISD::UDIV: 26230fca6ea1SDimitry Andric return LoongArchISD::DIV_WU; 26240fca6ea1SDimitry Andric case ISD::UREM: 26250fca6ea1SDimitry Andric return LoongArchISD::MOD_WU; 262681ad6265SDimitry Andric case ISD::SHL: 262781ad6265SDimitry Andric return LoongArchISD::SLL_W; 262881ad6265SDimitry Andric case ISD::SRA: 262981ad6265SDimitry Andric return LoongArchISD::SRA_W; 263081ad6265SDimitry Andric case ISD::SRL: 263181ad6265SDimitry Andric return LoongArchISD::SRL_W; 26320fca6ea1SDimitry Andric case ISD::ROTL: 2633bdd1243dSDimitry Andric case ISD::ROTR: 2634bdd1243dSDimitry Andric return LoongArchISD::ROTR_W; 2635bdd1243dSDimitry Andric case ISD::CTTZ: 2636bdd1243dSDimitry Andric return LoongArchISD::CTZ_W; 2637bdd1243dSDimitry Andric case ISD::CTLZ: 2638bdd1243dSDimitry Andric return LoongArchISD::CLZ_W; 263981ad6265SDimitry Andric } 264081ad6265SDimitry Andric } 264181ad6265SDimitry Andric 264281ad6265SDimitry Andric // Converts the given i8/i16/i32 operation to a target-specific SelectionDAG 264381ad6265SDimitry Andric // node. Because i8/i16/i32 isn't a legal type for LA64, these operations would 264481ad6265SDimitry Andric // otherwise be promoted to i64, making it difficult to select the 264581ad6265SDimitry Andric // SLL_W/.../*W later one because the fact the operation was originally of 264681ad6265SDimitry Andric // type i8/i16/i32 is lost. 2647bdd1243dSDimitry Andric static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp, 264881ad6265SDimitry Andric unsigned ExtOpc = ISD::ANY_EXTEND) { 264981ad6265SDimitry Andric SDLoc DL(N); 265081ad6265SDimitry Andric LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode()); 2651bdd1243dSDimitry Andric SDValue NewOp0, NewRes; 2652bdd1243dSDimitry Andric 2653bdd1243dSDimitry Andric switch (NumOp) { 2654bdd1243dSDimitry Andric default: 2655bdd1243dSDimitry Andric llvm_unreachable("Unexpected NumOp"); 2656bdd1243dSDimitry Andric case 1: { 2657bdd1243dSDimitry Andric NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0)); 2658bdd1243dSDimitry Andric NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0); 2659bdd1243dSDimitry Andric break; 2660bdd1243dSDimitry Andric } 2661bdd1243dSDimitry Andric case 2: { 2662bdd1243dSDimitry Andric NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0)); 266381ad6265SDimitry Andric SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1)); 26640fca6ea1SDimitry Andric if (N->getOpcode() == ISD::ROTL) { 26650fca6ea1SDimitry Andric SDValue TmpOp = DAG.getConstant(32, DL, MVT::i64); 26660fca6ea1SDimitry Andric NewOp1 = DAG.getNode(ISD::SUB, DL, MVT::i64, TmpOp, NewOp1); 26670fca6ea1SDimitry Andric } 2668bdd1243dSDimitry Andric NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1); 2669bdd1243dSDimitry Andric break; 2670bdd1243dSDimitry Andric } 2671bdd1243dSDimitry Andric // TODO:Handle more NumOp. 2672bdd1243dSDimitry Andric } 2673bdd1243dSDimitry Andric 2674bdd1243dSDimitry Andric // ReplaceNodeResults requires we maintain the same type for the return 2675bdd1243dSDimitry Andric // value. 267681ad6265SDimitry Andric return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes); 267781ad6265SDimitry Andric } 267881ad6265SDimitry Andric 26790fca6ea1SDimitry Andric // Converts the given 32-bit operation to a i64 operation with signed extension 26800fca6ea1SDimitry Andric // semantic to reduce the signed extension instructions. 26810fca6ea1SDimitry Andric static SDValue customLegalizeToWOpWithSExt(SDNode *N, SelectionDAG &DAG) { 26820fca6ea1SDimitry Andric SDLoc DL(N); 26830fca6ea1SDimitry Andric SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0)); 26840fca6ea1SDimitry Andric SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1)); 26850fca6ea1SDimitry Andric SDValue NewWOp = DAG.getNode(N->getOpcode(), DL, MVT::i64, NewOp0, NewOp1); 26860fca6ea1SDimitry Andric SDValue NewRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, NewWOp, 26870fca6ea1SDimitry Andric DAG.getValueType(MVT::i32)); 26880fca6ea1SDimitry Andric return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes); 26890fca6ea1SDimitry Andric } 26900fca6ea1SDimitry Andric 26915f757f3fSDimitry Andric // Helper function that emits error message for intrinsics with/without chain 26925f757f3fSDimitry Andric // and return a UNDEF or and the chain as the results. 26935f757f3fSDimitry Andric static void emitErrorAndReplaceIntrinsicResults( 269406c3fb27SDimitry Andric SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG, 26955f757f3fSDimitry Andric StringRef ErrorMsg, bool WithChain = true) { 269606c3fb27SDimitry Andric DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + "."); 269706c3fb27SDimitry Andric Results.push_back(DAG.getUNDEF(N->getValueType(0))); 26985f757f3fSDimitry Andric if (!WithChain) 26995f757f3fSDimitry Andric return; 270006c3fb27SDimitry Andric Results.push_back(N->getOperand(0)); 270106c3fb27SDimitry Andric } 270206c3fb27SDimitry Andric 27035f757f3fSDimitry Andric template <unsigned N> 27045f757f3fSDimitry Andric static void 27055f757f3fSDimitry Andric replaceVPICKVE2GRResults(SDNode *Node, SmallVectorImpl<SDValue> &Results, 27065f757f3fSDimitry Andric SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, 27075f757f3fSDimitry Andric unsigned ResOp) { 27085f757f3fSDimitry Andric const StringRef ErrorMsgOOR = "argument out of range"; 2709647cbc5dSDimitry Andric unsigned Imm = Node->getConstantOperandVal(2); 27105f757f3fSDimitry Andric if (!isUInt<N>(Imm)) { 27115f757f3fSDimitry Andric emitErrorAndReplaceIntrinsicResults(Node, Results, DAG, ErrorMsgOOR, 27125f757f3fSDimitry Andric /*WithChain=*/false); 27135f757f3fSDimitry Andric return; 27145f757f3fSDimitry Andric } 27155f757f3fSDimitry Andric SDLoc DL(Node); 27165f757f3fSDimitry Andric SDValue Vec = Node->getOperand(1); 27175f757f3fSDimitry Andric 27185f757f3fSDimitry Andric SDValue PickElt = 27195f757f3fSDimitry Andric DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec, 27205f757f3fSDimitry Andric DAG.getConstant(Imm, DL, Subtarget.getGRLenVT()), 27215f757f3fSDimitry Andric DAG.getValueType(Vec.getValueType().getVectorElementType())); 27225f757f3fSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, Node->getValueType(0), 27235f757f3fSDimitry Andric PickElt.getValue(0))); 27245f757f3fSDimitry Andric } 27255f757f3fSDimitry Andric 27265f757f3fSDimitry Andric static void replaceVecCondBranchResults(SDNode *N, 27275f757f3fSDimitry Andric SmallVectorImpl<SDValue> &Results, 27285f757f3fSDimitry Andric SelectionDAG &DAG, 27295f757f3fSDimitry Andric const LoongArchSubtarget &Subtarget, 27305f757f3fSDimitry Andric unsigned ResOp) { 27315f757f3fSDimitry Andric SDLoc DL(N); 27325f757f3fSDimitry Andric SDValue Vec = N->getOperand(1); 27335f757f3fSDimitry Andric 27345f757f3fSDimitry Andric SDValue CB = DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec); 27355f757f3fSDimitry Andric Results.push_back( 27365f757f3fSDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), CB.getValue(0))); 27375f757f3fSDimitry Andric } 27385f757f3fSDimitry Andric 27395f757f3fSDimitry Andric static void 27405f757f3fSDimitry Andric replaceINTRINSIC_WO_CHAINResults(SDNode *N, SmallVectorImpl<SDValue> &Results, 27415f757f3fSDimitry Andric SelectionDAG &DAG, 27425f757f3fSDimitry Andric const LoongArchSubtarget &Subtarget) { 27435f757f3fSDimitry Andric switch (N->getConstantOperandVal(0)) { 27445f757f3fSDimitry Andric default: 27455f757f3fSDimitry Andric llvm_unreachable("Unexpected Intrinsic."); 27465f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpickve2gr_b: 27475f757f3fSDimitry Andric replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget, 27485f757f3fSDimitry Andric LoongArchISD::VPICK_SEXT_ELT); 27495f757f3fSDimitry Andric break; 27505f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpickve2gr_h: 27515f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpickve2gr_w: 27525f757f3fSDimitry Andric replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget, 27535f757f3fSDimitry Andric LoongArchISD::VPICK_SEXT_ELT); 27545f757f3fSDimitry Andric break; 27555f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpickve2gr_w: 27565f757f3fSDimitry Andric replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget, 27575f757f3fSDimitry Andric LoongArchISD::VPICK_SEXT_ELT); 27585f757f3fSDimitry Andric break; 27595f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpickve2gr_bu: 27605f757f3fSDimitry Andric replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget, 27615f757f3fSDimitry Andric LoongArchISD::VPICK_ZEXT_ELT); 27625f757f3fSDimitry Andric break; 27635f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpickve2gr_hu: 27645f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpickve2gr_wu: 27655f757f3fSDimitry Andric replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget, 27665f757f3fSDimitry Andric LoongArchISD::VPICK_ZEXT_ELT); 27675f757f3fSDimitry Andric break; 27685f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpickve2gr_wu: 27695f757f3fSDimitry Andric replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget, 27705f757f3fSDimitry Andric LoongArchISD::VPICK_ZEXT_ELT); 27715f757f3fSDimitry Andric break; 27725f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_bz_b: 27735f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_bz_h: 27745f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_bz_w: 27755f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_bz_d: 27765f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xbz_b: 27775f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xbz_h: 27785f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xbz_w: 27795f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xbz_d: 27805f757f3fSDimitry Andric replaceVecCondBranchResults(N, Results, DAG, Subtarget, 27815f757f3fSDimitry Andric LoongArchISD::VALL_ZERO); 27825f757f3fSDimitry Andric break; 27835f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_bz_v: 27845f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xbz_v: 27855f757f3fSDimitry Andric replaceVecCondBranchResults(N, Results, DAG, Subtarget, 27865f757f3fSDimitry Andric LoongArchISD::VANY_ZERO); 27875f757f3fSDimitry Andric break; 27885f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_bnz_b: 27895f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_bnz_h: 27905f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_bnz_w: 27915f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_bnz_d: 27925f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xbnz_b: 27935f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xbnz_h: 27945f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xbnz_w: 27955f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xbnz_d: 27965f757f3fSDimitry Andric replaceVecCondBranchResults(N, Results, DAG, Subtarget, 27975f757f3fSDimitry Andric LoongArchISD::VALL_NONZERO); 27985f757f3fSDimitry Andric break; 27995f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_bnz_v: 28005f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xbnz_v: 28015f757f3fSDimitry Andric replaceVecCondBranchResults(N, Results, DAG, Subtarget, 28025f757f3fSDimitry Andric LoongArchISD::VANY_NONZERO); 28035f757f3fSDimitry Andric break; 28045f757f3fSDimitry Andric } 28055f757f3fSDimitry Andric } 28065f757f3fSDimitry Andric 280781ad6265SDimitry Andric void LoongArchTargetLowering::ReplaceNodeResults( 280881ad6265SDimitry Andric SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const { 280981ad6265SDimitry Andric SDLoc DL(N); 2810bdd1243dSDimitry Andric EVT VT = N->getValueType(0); 281181ad6265SDimitry Andric switch (N->getOpcode()) { 281281ad6265SDimitry Andric default: 281381ad6265SDimitry Andric llvm_unreachable("Don't know how to legalize this operation"); 28140fca6ea1SDimitry Andric case ISD::ADD: 28150fca6ea1SDimitry Andric case ISD::SUB: 28160fca6ea1SDimitry Andric assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && 28170fca6ea1SDimitry Andric "Unexpected custom legalisation"); 28180fca6ea1SDimitry Andric Results.push_back(customLegalizeToWOpWithSExt(N, DAG)); 28190fca6ea1SDimitry Andric break; 28200fca6ea1SDimitry Andric case ISD::UDIV: 28210fca6ea1SDimitry Andric case ISD::UREM: 28220fca6ea1SDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 28230fca6ea1SDimitry Andric "Unexpected custom legalisation"); 28240fca6ea1SDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG, 2, ISD::SIGN_EXTEND)); 28250fca6ea1SDimitry Andric break; 282681ad6265SDimitry Andric case ISD::SHL: 282781ad6265SDimitry Andric case ISD::SRA: 282881ad6265SDimitry Andric case ISD::SRL: 2829bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 283081ad6265SDimitry Andric "Unexpected custom legalisation"); 283181ad6265SDimitry Andric if (N->getOperand(1).getOpcode() != ISD::Constant) { 2832bdd1243dSDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG, 2)); 2833bdd1243dSDimitry Andric break; 2834bdd1243dSDimitry Andric } 2835bdd1243dSDimitry Andric break; 2836bdd1243dSDimitry Andric case ISD::ROTL: 28370fca6ea1SDimitry Andric case ISD::ROTR: 28380fca6ea1SDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 28390fca6ea1SDimitry Andric "Unexpected custom legalisation"); 2840bdd1243dSDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG, 2)); 284181ad6265SDimitry Andric break; 2842753f127fSDimitry Andric case ISD::FP_TO_SINT: { 2843bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 2844753f127fSDimitry Andric "Unexpected custom legalisation"); 2845753f127fSDimitry Andric SDValue Src = N->getOperand(0); 2846bdd1243dSDimitry Andric EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0)); 2847bdd1243dSDimitry Andric if (getTypeAction(*DAG.getContext(), Src.getValueType()) != 2848bdd1243dSDimitry Andric TargetLowering::TypeSoftenFloat) { 2849bdd1243dSDimitry Andric SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src); 2850bdd1243dSDimitry Andric Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst)); 2851bdd1243dSDimitry Andric return; 2852bdd1243dSDimitry Andric } 2853bdd1243dSDimitry Andric // If the FP type needs to be softened, emit a library call using the 'si' 2854bdd1243dSDimitry Andric // version. If we left it to default legalization we'd end up with 'di'. 2855bdd1243dSDimitry Andric RTLIB::Libcall LC; 2856bdd1243dSDimitry Andric LC = RTLIB::getFPTOSINT(Src.getValueType(), VT); 2857bdd1243dSDimitry Andric MakeLibCallOptions CallOptions; 2858bdd1243dSDimitry Andric EVT OpVT = Src.getValueType(); 2859bdd1243dSDimitry Andric CallOptions.setTypeListBeforeSoften(OpVT, VT, true); 2860bdd1243dSDimitry Andric SDValue Chain = SDValue(); 2861bdd1243dSDimitry Andric SDValue Result; 2862bdd1243dSDimitry Andric std::tie(Result, Chain) = 2863bdd1243dSDimitry Andric makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain); 2864bdd1243dSDimitry Andric Results.push_back(Result); 2865753f127fSDimitry Andric break; 2866753f127fSDimitry Andric } 2867753f127fSDimitry Andric case ISD::BITCAST: { 2868753f127fSDimitry Andric SDValue Src = N->getOperand(0); 2869753f127fSDimitry Andric EVT SrcVT = Src.getValueType(); 2870753f127fSDimitry Andric if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() && 2871753f127fSDimitry Andric Subtarget.hasBasicF()) { 2872753f127fSDimitry Andric SDValue Dst = 2873753f127fSDimitry Andric DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src); 2874753f127fSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst)); 2875753f127fSDimitry Andric } 2876753f127fSDimitry Andric break; 2877753f127fSDimitry Andric } 2878753f127fSDimitry Andric case ISD::FP_TO_UINT: { 2879bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 2880753f127fSDimitry Andric "Unexpected custom legalisation"); 2881753f127fSDimitry Andric auto &TLI = DAG.getTargetLoweringInfo(); 2882753f127fSDimitry Andric SDValue Tmp1, Tmp2; 2883753f127fSDimitry Andric TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG); 2884753f127fSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1)); 2885753f127fSDimitry Andric break; 2886753f127fSDimitry Andric } 2887bdd1243dSDimitry Andric case ISD::BSWAP: { 2888bdd1243dSDimitry Andric SDValue Src = N->getOperand(0); 2889bdd1243dSDimitry Andric assert((VT == MVT::i16 || VT == MVT::i32) && 2890bdd1243dSDimitry Andric "Unexpected custom legalization"); 2891bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 2892bdd1243dSDimitry Andric SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src); 2893bdd1243dSDimitry Andric SDValue Tmp; 2894bdd1243dSDimitry Andric switch (VT.getSizeInBits()) { 2895bdd1243dSDimitry Andric default: 2896bdd1243dSDimitry Andric llvm_unreachable("Unexpected operand width"); 2897bdd1243dSDimitry Andric case 16: 2898bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc); 2899bdd1243dSDimitry Andric break; 2900bdd1243dSDimitry Andric case 32: 2901bdd1243dSDimitry Andric // Only LA64 will get to here due to the size mismatch between VT and 2902bdd1243dSDimitry Andric // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo. 2903bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc); 2904bdd1243dSDimitry Andric break; 2905bdd1243dSDimitry Andric } 2906bdd1243dSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp)); 2907bdd1243dSDimitry Andric break; 2908bdd1243dSDimitry Andric } 2909bdd1243dSDimitry Andric case ISD::BITREVERSE: { 2910bdd1243dSDimitry Andric SDValue Src = N->getOperand(0); 2911bdd1243dSDimitry Andric assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) && 2912bdd1243dSDimitry Andric "Unexpected custom legalization"); 2913bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 2914bdd1243dSDimitry Andric SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src); 2915bdd1243dSDimitry Andric SDValue Tmp; 2916bdd1243dSDimitry Andric switch (VT.getSizeInBits()) { 2917bdd1243dSDimitry Andric default: 2918bdd1243dSDimitry Andric llvm_unreachable("Unexpected operand width"); 2919bdd1243dSDimitry Andric case 8: 2920bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc); 2921bdd1243dSDimitry Andric break; 2922bdd1243dSDimitry Andric case 32: 2923bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc); 2924bdd1243dSDimitry Andric break; 2925bdd1243dSDimitry Andric } 2926bdd1243dSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp)); 2927bdd1243dSDimitry Andric break; 2928bdd1243dSDimitry Andric } 2929bdd1243dSDimitry Andric case ISD::CTLZ: 2930bdd1243dSDimitry Andric case ISD::CTTZ: { 2931bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 2932bdd1243dSDimitry Andric "Unexpected custom legalisation"); 2933bdd1243dSDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG, 1)); 2934bdd1243dSDimitry Andric break; 2935bdd1243dSDimitry Andric } 2936bdd1243dSDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 293706c3fb27SDimitry Andric SDValue Chain = N->getOperand(0); 2938bdd1243dSDimitry Andric SDValue Op2 = N->getOperand(2); 293906c3fb27SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 294006c3fb27SDimitry Andric const StringRef ErrorMsgOOR = "argument out of range"; 294106c3fb27SDimitry Andric const StringRef ErrorMsgReqLA64 = "requires loongarch64"; 294206c3fb27SDimitry Andric const StringRef ErrorMsgReqF = "requires basic 'f' target feature"; 2943bdd1243dSDimitry Andric 294406c3fb27SDimitry Andric switch (N->getConstantOperandVal(1)) { 2945bdd1243dSDimitry Andric default: 2946bdd1243dSDimitry Andric llvm_unreachable("Unexpected Intrinsic."); 294706c3fb27SDimitry Andric case Intrinsic::loongarch_movfcsr2gr: { 294806c3fb27SDimitry Andric if (!Subtarget.hasBasicF()) { 29495f757f3fSDimitry Andric emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqF); 295006c3fb27SDimitry Andric return; 295106c3fb27SDimitry Andric } 29521db9f3b2SDimitry Andric unsigned Imm = Op2->getAsZExtVal(); 295306c3fb27SDimitry Andric if (!isUInt<2>(Imm)) { 29545f757f3fSDimitry Andric emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR); 295506c3fb27SDimitry Andric return; 295606c3fb27SDimitry Andric } 295706c3fb27SDimitry Andric SDValue MOVFCSR2GRResults = DAG.getNode( 295806c3fb27SDimitry Andric LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other}, 295906c3fb27SDimitry Andric {Chain, DAG.getConstant(Imm, DL, GRLenVT)}); 296006c3fb27SDimitry Andric Results.push_back( 296106c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0))); 296206c3fb27SDimitry Andric Results.push_back(MOVFCSR2GRResults.getValue(1)); 296306c3fb27SDimitry Andric break; 296406c3fb27SDimitry Andric } 2965bdd1243dSDimitry Andric #define CRC_CASE_EXT_BINARYOP(NAME, NODE) \ 2966bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 296706c3fb27SDimitry Andric SDValue NODE = DAG.getNode( \ 296806c3fb27SDimitry Andric LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \ 296906c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \ 297006c3fb27SDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \ 297106c3fb27SDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \ 297206c3fb27SDimitry Andric Results.push_back(NODE.getValue(1)); \ 2973bdd1243dSDimitry Andric break; \ 2974bdd1243dSDimitry Andric } 2975bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W) 2976bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W) 2977bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W) 2978bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W) 2979bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W) 2980bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W) 2981bdd1243dSDimitry Andric #undef CRC_CASE_EXT_BINARYOP 2982bdd1243dSDimitry Andric 2983bdd1243dSDimitry Andric #define CRC_CASE_EXT_UNARYOP(NAME, NODE) \ 2984bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 298506c3fb27SDimitry Andric SDValue NODE = DAG.getNode( \ 298606c3fb27SDimitry Andric LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \ 298706c3fb27SDimitry Andric {Chain, Op2, \ 298806c3fb27SDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \ 298906c3fb27SDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \ 299006c3fb27SDimitry Andric Results.push_back(NODE.getValue(1)); \ 2991bdd1243dSDimitry Andric break; \ 2992bdd1243dSDimitry Andric } 2993bdd1243dSDimitry Andric CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W) 2994bdd1243dSDimitry Andric CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W) 2995bdd1243dSDimitry Andric #undef CRC_CASE_EXT_UNARYOP 2996bdd1243dSDimitry Andric #define CSR_CASE(ID) \ 2997bdd1243dSDimitry Andric case Intrinsic::loongarch_##ID: { \ 299806c3fb27SDimitry Andric if (!Subtarget.is64Bit()) \ 29995f757f3fSDimitry Andric emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64); \ 3000bdd1243dSDimitry Andric break; \ 3001bdd1243dSDimitry Andric } 3002bdd1243dSDimitry Andric CSR_CASE(csrrd_d); 3003bdd1243dSDimitry Andric CSR_CASE(csrwr_d); 3004bdd1243dSDimitry Andric CSR_CASE(csrxchg_d); 3005bdd1243dSDimitry Andric CSR_CASE(iocsrrd_d); 3006bdd1243dSDimitry Andric #undef CSR_CASE 3007bdd1243dSDimitry Andric case Intrinsic::loongarch_csrrd_w: { 30081db9f3b2SDimitry Andric unsigned Imm = Op2->getAsZExtVal(); 3009bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) { 30105f757f3fSDimitry Andric emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR); 301106c3fb27SDimitry Andric return; 3012bdd1243dSDimitry Andric } 301306c3fb27SDimitry Andric SDValue CSRRDResults = 301406c3fb27SDimitry Andric DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other}, 301506c3fb27SDimitry Andric {Chain, DAG.getConstant(Imm, DL, GRLenVT)}); 3016bdd1243dSDimitry Andric Results.push_back( 301706c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0))); 301806c3fb27SDimitry Andric Results.push_back(CSRRDResults.getValue(1)); 3019bdd1243dSDimitry Andric break; 3020bdd1243dSDimitry Andric } 3021bdd1243dSDimitry Andric case Intrinsic::loongarch_csrwr_w: { 3022647cbc5dSDimitry Andric unsigned Imm = N->getConstantOperandVal(3); 3023bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) { 30245f757f3fSDimitry Andric emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR); 302506c3fb27SDimitry Andric return; 3026bdd1243dSDimitry Andric } 302706c3fb27SDimitry Andric SDValue CSRWRResults = 302806c3fb27SDimitry Andric DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other}, 302906c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), 303006c3fb27SDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)}); 303106c3fb27SDimitry Andric Results.push_back( 303206c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0))); 303306c3fb27SDimitry Andric Results.push_back(CSRWRResults.getValue(1)); 3034bdd1243dSDimitry Andric break; 3035bdd1243dSDimitry Andric } 3036bdd1243dSDimitry Andric case Intrinsic::loongarch_csrxchg_w: { 3037647cbc5dSDimitry Andric unsigned Imm = N->getConstantOperandVal(4); 3038bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) { 30395f757f3fSDimitry Andric emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR); 304006c3fb27SDimitry Andric return; 3041bdd1243dSDimitry Andric } 304206c3fb27SDimitry Andric SDValue CSRXCHGResults = DAG.getNode( 304306c3fb27SDimitry Andric LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other}, 304406c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), 3045bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)), 304606c3fb27SDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)}); 304706c3fb27SDimitry Andric Results.push_back( 304806c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0))); 304906c3fb27SDimitry Andric Results.push_back(CSRXCHGResults.getValue(1)); 3050bdd1243dSDimitry Andric break; 3051bdd1243dSDimitry Andric } 3052bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE) \ 3053bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 305406c3fb27SDimitry Andric SDValue IOCSRRDResults = \ 305506c3fb27SDimitry Andric DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \ 305606c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \ 305706c3fb27SDimitry Andric Results.push_back( \ 305806c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0))); \ 305906c3fb27SDimitry Andric Results.push_back(IOCSRRDResults.getValue(1)); \ 3060bdd1243dSDimitry Andric break; \ 3061bdd1243dSDimitry Andric } 3062bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B); 3063bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H); 3064bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W); 3065bdd1243dSDimitry Andric #undef IOCSRRD_CASE 3066bdd1243dSDimitry Andric case Intrinsic::loongarch_cpucfg: { 306706c3fb27SDimitry Andric SDValue CPUCFGResults = 306806c3fb27SDimitry Andric DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other}, 306906c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); 307006c3fb27SDimitry Andric Results.push_back( 307106c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0))); 307206c3fb27SDimitry Andric Results.push_back(CPUCFGResults.getValue(1)); 3073bdd1243dSDimitry Andric break; 3074bdd1243dSDimitry Andric } 3075bdd1243dSDimitry Andric case Intrinsic::loongarch_lddir_d: { 3076bdd1243dSDimitry Andric if (!Subtarget.is64Bit()) { 30775f757f3fSDimitry Andric emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64); 307806c3fb27SDimitry Andric return; 3079bdd1243dSDimitry Andric } 3080bdd1243dSDimitry Andric break; 3081bdd1243dSDimitry Andric } 3082bdd1243dSDimitry Andric } 3083bdd1243dSDimitry Andric break; 3084bdd1243dSDimitry Andric } 3085bdd1243dSDimitry Andric case ISD::READ_REGISTER: { 3086bdd1243dSDimitry Andric if (Subtarget.is64Bit()) 3087bdd1243dSDimitry Andric DAG.getContext()->emitError( 3088bdd1243dSDimitry Andric "On LA64, only 64-bit registers can be read."); 3089bdd1243dSDimitry Andric else 3090bdd1243dSDimitry Andric DAG.getContext()->emitError( 3091bdd1243dSDimitry Andric "On LA32, only 32-bit registers can be read."); 3092bdd1243dSDimitry Andric Results.push_back(DAG.getUNDEF(VT)); 3093bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 3094bdd1243dSDimitry Andric break; 3095bdd1243dSDimitry Andric } 30965f757f3fSDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 30975f757f3fSDimitry Andric replaceINTRINSIC_WO_CHAINResults(N, Results, DAG, Subtarget); 30985f757f3fSDimitry Andric break; 30995f757f3fSDimitry Andric } 310081ad6265SDimitry Andric } 310181ad6265SDimitry Andric } 310281ad6265SDimitry Andric 310381ad6265SDimitry Andric static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, 310481ad6265SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 310581ad6265SDimitry Andric const LoongArchSubtarget &Subtarget) { 310681ad6265SDimitry Andric if (DCI.isBeforeLegalizeOps()) 310781ad6265SDimitry Andric return SDValue(); 310881ad6265SDimitry Andric 310981ad6265SDimitry Andric SDValue FirstOperand = N->getOperand(0); 311081ad6265SDimitry Andric SDValue SecondOperand = N->getOperand(1); 311181ad6265SDimitry Andric unsigned FirstOperandOpc = FirstOperand.getOpcode(); 311281ad6265SDimitry Andric EVT ValTy = N->getValueType(0); 311381ad6265SDimitry Andric SDLoc DL(N); 311481ad6265SDimitry Andric uint64_t lsb, msb; 311581ad6265SDimitry Andric unsigned SMIdx, SMLen; 311681ad6265SDimitry Andric ConstantSDNode *CN; 311781ad6265SDimitry Andric SDValue NewOperand; 311881ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 311981ad6265SDimitry Andric 312081ad6265SDimitry Andric // Op's second operand must be a shifted mask. 312181ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) || 312281ad6265SDimitry Andric !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen)) 312381ad6265SDimitry Andric return SDValue(); 312481ad6265SDimitry Andric 312581ad6265SDimitry Andric if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) { 312681ad6265SDimitry Andric // Pattern match BSTRPICK. 312781ad6265SDimitry Andric // $dst = and ((sra or srl) $src , lsb), (2**len - 1) 312881ad6265SDimitry Andric // => BSTRPICK $dst, $src, msb, lsb 312981ad6265SDimitry Andric // where msb = lsb + len - 1 313081ad6265SDimitry Andric 313181ad6265SDimitry Andric // The second operand of the shift must be an immediate. 313281ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1)))) 313381ad6265SDimitry Andric return SDValue(); 313481ad6265SDimitry Andric 313581ad6265SDimitry Andric lsb = CN->getZExtValue(); 313681ad6265SDimitry Andric 313781ad6265SDimitry Andric // Return if the shifted mask does not start at bit 0 or the sum of its 313881ad6265SDimitry Andric // length and lsb exceeds the word's size. 313981ad6265SDimitry Andric if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits()) 314081ad6265SDimitry Andric return SDValue(); 314181ad6265SDimitry Andric 314281ad6265SDimitry Andric NewOperand = FirstOperand.getOperand(0); 314381ad6265SDimitry Andric } else { 314481ad6265SDimitry Andric // Pattern match BSTRPICK. 314581ad6265SDimitry Andric // $dst = and $src, (2**len- 1) , if len > 12 314681ad6265SDimitry Andric // => BSTRPICK $dst, $src, msb, lsb 314781ad6265SDimitry Andric // where lsb = 0 and msb = len - 1 314881ad6265SDimitry Andric 314981ad6265SDimitry Andric // If the mask is <= 0xfff, andi can be used instead. 315081ad6265SDimitry Andric if (CN->getZExtValue() <= 0xfff) 315181ad6265SDimitry Andric return SDValue(); 315281ad6265SDimitry Andric 315306c3fb27SDimitry Andric // Return if the MSB exceeds. 315406c3fb27SDimitry Andric if (SMIdx + SMLen > ValTy.getSizeInBits()) 315581ad6265SDimitry Andric return SDValue(); 315681ad6265SDimitry Andric 315706c3fb27SDimitry Andric if (SMIdx > 0) { 315806c3fb27SDimitry Andric // Omit if the constant has more than 2 uses. This a conservative 315906c3fb27SDimitry Andric // decision. Whether it is a win depends on the HW microarchitecture. 316006c3fb27SDimitry Andric // However it should always be better for 1 and 2 uses. 316106c3fb27SDimitry Andric if (CN->use_size() > 2) 316206c3fb27SDimitry Andric return SDValue(); 316306c3fb27SDimitry Andric // Return if the constant can be composed by a single LU12I.W. 316406c3fb27SDimitry Andric if ((CN->getZExtValue() & 0xfff) == 0) 316506c3fb27SDimitry Andric return SDValue(); 316606c3fb27SDimitry Andric // Return if the constand can be composed by a single ADDI with 316706c3fb27SDimitry Andric // the zero register. 316806c3fb27SDimitry Andric if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0) 316906c3fb27SDimitry Andric return SDValue(); 317006c3fb27SDimitry Andric } 317106c3fb27SDimitry Andric 317206c3fb27SDimitry Andric lsb = SMIdx; 317381ad6265SDimitry Andric NewOperand = FirstOperand; 317481ad6265SDimitry Andric } 317506c3fb27SDimitry Andric 317681ad6265SDimitry Andric msb = lsb + SMLen - 1; 317706c3fb27SDimitry Andric SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand, 317881ad6265SDimitry Andric DAG.getConstant(msb, DL, GRLenVT), 317981ad6265SDimitry Andric DAG.getConstant(lsb, DL, GRLenVT)); 318006c3fb27SDimitry Andric if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0) 318106c3fb27SDimitry Andric return NR0; 318206c3fb27SDimitry Andric // Try to optimize to 318306c3fb27SDimitry Andric // bstrpick $Rd, $Rs, msb, lsb 318406c3fb27SDimitry Andric // slli $Rd, $Rd, lsb 318506c3fb27SDimitry Andric return DAG.getNode(ISD::SHL, DL, ValTy, NR0, 318606c3fb27SDimitry Andric DAG.getConstant(lsb, DL, GRLenVT)); 318781ad6265SDimitry Andric } 318881ad6265SDimitry Andric 318981ad6265SDimitry Andric static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, 319081ad6265SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 319181ad6265SDimitry Andric const LoongArchSubtarget &Subtarget) { 319281ad6265SDimitry Andric if (DCI.isBeforeLegalizeOps()) 319381ad6265SDimitry Andric return SDValue(); 319481ad6265SDimitry Andric 319581ad6265SDimitry Andric // $dst = srl (and $src, Mask), Shamt 319681ad6265SDimitry Andric // => 319781ad6265SDimitry Andric // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt 319881ad6265SDimitry Andric // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1 319981ad6265SDimitry Andric // 320081ad6265SDimitry Andric 320181ad6265SDimitry Andric SDValue FirstOperand = N->getOperand(0); 320281ad6265SDimitry Andric ConstantSDNode *CN; 320381ad6265SDimitry Andric EVT ValTy = N->getValueType(0); 320481ad6265SDimitry Andric SDLoc DL(N); 320581ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 320681ad6265SDimitry Andric unsigned MaskIdx, MaskLen; 320781ad6265SDimitry Andric uint64_t Shamt; 320881ad6265SDimitry Andric 320981ad6265SDimitry Andric // The first operand must be an AND and the second operand of the AND must be 321081ad6265SDimitry Andric // a shifted mask. 321181ad6265SDimitry Andric if (FirstOperand.getOpcode() != ISD::AND || 321281ad6265SDimitry Andric !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) || 321381ad6265SDimitry Andric !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen)) 321481ad6265SDimitry Andric return SDValue(); 321581ad6265SDimitry Andric 321681ad6265SDimitry Andric // The second operand (shift amount) must be an immediate. 321781ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) 321881ad6265SDimitry Andric return SDValue(); 321981ad6265SDimitry Andric 322081ad6265SDimitry Andric Shamt = CN->getZExtValue(); 322181ad6265SDimitry Andric if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1) 322281ad6265SDimitry Andric return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, 322381ad6265SDimitry Andric FirstOperand->getOperand(0), 322481ad6265SDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 322581ad6265SDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 322681ad6265SDimitry Andric 322781ad6265SDimitry Andric return SDValue(); 322881ad6265SDimitry Andric } 322981ad6265SDimitry Andric 3230753f127fSDimitry Andric static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, 3231753f127fSDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 3232753f127fSDimitry Andric const LoongArchSubtarget &Subtarget) { 3233753f127fSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 3234753f127fSDimitry Andric EVT ValTy = N->getValueType(0); 3235753f127fSDimitry Andric SDValue N0 = N->getOperand(0), N1 = N->getOperand(1); 3236753f127fSDimitry Andric ConstantSDNode *CN0, *CN1; 3237753f127fSDimitry Andric SDLoc DL(N); 3238753f127fSDimitry Andric unsigned ValBits = ValTy.getSizeInBits(); 3239753f127fSDimitry Andric unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1; 3240753f127fSDimitry Andric unsigned Shamt; 3241753f127fSDimitry Andric bool SwapAndRetried = false; 3242753f127fSDimitry Andric 3243753f127fSDimitry Andric if (DCI.isBeforeLegalizeOps()) 3244753f127fSDimitry Andric return SDValue(); 3245753f127fSDimitry Andric 3246753f127fSDimitry Andric if (ValBits != 32 && ValBits != 64) 3247753f127fSDimitry Andric return SDValue(); 3248753f127fSDimitry Andric 3249753f127fSDimitry Andric Retry: 3250753f127fSDimitry Andric // 1st pattern to match BSTRINS: 3251753f127fSDimitry Andric // R = or (and X, mask0), (and (shl Y, lsb), mask1) 3252753f127fSDimitry Andric // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1 3253753f127fSDimitry Andric // => 3254753f127fSDimitry Andric // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1) 3255753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 3256753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 3257753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 3258753f127fSDimitry Andric N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL && 3259753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 3260753f127fSDimitry Andric isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) && 3261753f127fSDimitry Andric MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 && 3262753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 3263753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskIdx0 && 3264753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 3265753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n"); 3266753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 3267753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 3268753f127fSDimitry Andric DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT), 3269753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 3270753f127fSDimitry Andric } 3271753f127fSDimitry Andric 3272753f127fSDimitry Andric // 2nd pattern to match BSTRINS: 3273753f127fSDimitry Andric // R = or (and X, mask0), (shl (and Y, mask1), lsb) 3274753f127fSDimitry Andric // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb) 3275753f127fSDimitry Andric // => 3276753f127fSDimitry Andric // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1) 3277753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 3278753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 3279753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 3280753f127fSDimitry Andric N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND && 3281753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 3282753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskIdx0 && 3283753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 3284753f127fSDimitry Andric isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) && 3285753f127fSDimitry Andric MaskLen0 == MaskLen1 && MaskIdx1 == 0 && 3286753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 3287753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n"); 3288753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 3289753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 3290753f127fSDimitry Andric DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT), 3291753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 3292753f127fSDimitry Andric } 3293753f127fSDimitry Andric 3294753f127fSDimitry Andric // 3rd pattern to match BSTRINS: 3295753f127fSDimitry Andric // R = or (and X, mask0), (and Y, mask1) 3296753f127fSDimitry Andric // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0 3297753f127fSDimitry Andric // => 3298753f127fSDimitry Andric // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb 3299753f127fSDimitry Andric // where msb = lsb + size - 1 3300753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND && 3301753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 3302753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 3303753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= 64) && 3304753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) && 3305753f127fSDimitry Andric (CN1->getSExtValue() & CN0->getSExtValue()) == 0) { 3306753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n"); 3307753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 3308753f127fSDimitry Andric DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1, 3309753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)), 3310753f127fSDimitry Andric DAG.getConstant(ValBits == 32 3311753f127fSDimitry Andric ? (MaskIdx0 + (MaskLen0 & 31) - 1) 3312753f127fSDimitry Andric : (MaskIdx0 + MaskLen0 - 1), 3313753f127fSDimitry Andric DL, GRLenVT), 3314753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 3315753f127fSDimitry Andric } 3316753f127fSDimitry Andric 3317753f127fSDimitry Andric // 4th pattern to match BSTRINS: 3318753f127fSDimitry Andric // R = or (and X, mask), (shl Y, shamt) 3319753f127fSDimitry Andric // where mask = (2**shamt - 1) 3320753f127fSDimitry Andric // => 3321753f127fSDimitry Andric // R = BSTRINS X, Y, ValBits - 1, shamt 3322753f127fSDimitry Andric // where ValBits = 32 or 64 3323753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL && 3324753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 3325753f127fSDimitry Andric isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) && 3326753f127fSDimitry Andric MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 3327753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskLen0 && 3328753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 3329753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n"); 3330753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 3331753f127fSDimitry Andric N1.getOperand(0), 3332753f127fSDimitry Andric DAG.getConstant((ValBits - 1), DL, GRLenVT), 3333753f127fSDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 3334753f127fSDimitry Andric } 3335753f127fSDimitry Andric 3336753f127fSDimitry Andric // 5th pattern to match BSTRINS: 3337753f127fSDimitry Andric // R = or (and X, mask), const 3338753f127fSDimitry Andric // where ~mask = (2**size - 1) << lsb, mask & const = 0 3339753f127fSDimitry Andric // => 3340753f127fSDimitry Andric // R = BSTRINS X, (const >> lsb), msb, lsb 3341753f127fSDimitry Andric // where msb = lsb + size - 1 3342753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 3343753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 3344753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 3345753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1)) && 3346753f127fSDimitry Andric (CN1->getSExtValue() & CN0->getSExtValue()) == 0) { 3347753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n"); 3348753f127fSDimitry Andric return DAG.getNode( 3349753f127fSDimitry Andric LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 3350753f127fSDimitry Andric DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy), 3351439352acSDimitry Andric DAG.getConstant(ValBits == 32 ? (MaskIdx0 + (MaskLen0 & 31) - 1) 3352439352acSDimitry Andric : (MaskIdx0 + MaskLen0 - 1), 3353439352acSDimitry Andric DL, GRLenVT), 3354753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 3355753f127fSDimitry Andric } 3356753f127fSDimitry Andric 3357753f127fSDimitry Andric // 6th pattern. 3358753f127fSDimitry Andric // a = b | ((c & mask) << shamt), where all positions in b to be overwritten 3359753f127fSDimitry Andric // by the incoming bits are known to be zero. 3360753f127fSDimitry Andric // => 3361753f127fSDimitry Andric // a = BSTRINS b, c, shamt + MaskLen - 1, shamt 3362753f127fSDimitry Andric // 3363753f127fSDimitry Andric // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th 3364753f127fSDimitry Andric // pattern is more common than the 1st. So we put the 1st before the 6th in 3365753f127fSDimitry Andric // order to match as many nodes as possible. 3366753f127fSDimitry Andric ConstantSDNode *CNMask, *CNShamt; 3367753f127fSDimitry Andric unsigned MaskIdx, MaskLen; 3368753f127fSDimitry Andric if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND && 3369753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 3370753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) && 3371753f127fSDimitry Andric MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 3372753f127fSDimitry Andric CNShamt->getZExtValue() + MaskLen <= ValBits) { 3373753f127fSDimitry Andric Shamt = CNShamt->getZExtValue(); 3374753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt); 3375753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 3376753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n"); 3377753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 3378753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 3379753f127fSDimitry Andric DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT), 3380753f127fSDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 3381753f127fSDimitry Andric } 3382753f127fSDimitry Andric } 3383753f127fSDimitry Andric 3384753f127fSDimitry Andric // 7th pattern. 3385753f127fSDimitry Andric // a = b | ((c << shamt) & shifted_mask), where all positions in b to be 3386753f127fSDimitry Andric // overwritten by the incoming bits are known to be zero. 3387753f127fSDimitry Andric // => 3388753f127fSDimitry Andric // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx 3389753f127fSDimitry Andric // 3390753f127fSDimitry Andric // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd 3391753f127fSDimitry Andric // before the 7th in order to match as many nodes as possible. 3392753f127fSDimitry Andric if (N1.getOpcode() == ISD::AND && 3393753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 3394753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) && 3395753f127fSDimitry Andric N1.getOperand(0).getOpcode() == ISD::SHL && 3396753f127fSDimitry Andric (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 3397753f127fSDimitry Andric CNShamt->getZExtValue() == MaskIdx) { 3398753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue()); 3399753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 3400753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n"); 3401753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 3402753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 3403753f127fSDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 3404753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)); 3405753f127fSDimitry Andric } 3406753f127fSDimitry Andric } 3407753f127fSDimitry Andric 3408753f127fSDimitry Andric // (or a, b) and (or b, a) are equivalent, so swap the operands and retry. 3409753f127fSDimitry Andric if (!SwapAndRetried) { 3410753f127fSDimitry Andric std::swap(N0, N1); 3411753f127fSDimitry Andric SwapAndRetried = true; 3412753f127fSDimitry Andric goto Retry; 3413753f127fSDimitry Andric } 3414753f127fSDimitry Andric 3415753f127fSDimitry Andric SwapAndRetried = false; 3416753f127fSDimitry Andric Retry2: 3417753f127fSDimitry Andric // 8th pattern. 3418753f127fSDimitry Andric // a = b | (c & shifted_mask), where all positions in b to be overwritten by 3419753f127fSDimitry Andric // the incoming bits are known to be zero. 3420753f127fSDimitry Andric // => 3421753f127fSDimitry Andric // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx 3422753f127fSDimitry Andric // 3423753f127fSDimitry Andric // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So 3424753f127fSDimitry Andric // we put it here in order to match as many nodes as possible or generate less 3425753f127fSDimitry Andric // instructions. 3426753f127fSDimitry Andric if (N1.getOpcode() == ISD::AND && 3427753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 3428753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) { 3429753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue()); 3430753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 3431753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n"); 3432753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 3433753f127fSDimitry Andric DAG.getNode(ISD::SRL, DL, N1->getValueType(0), 3434753f127fSDimitry Andric N1->getOperand(0), 3435753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)), 3436753f127fSDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 3437753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)); 3438753f127fSDimitry Andric } 3439753f127fSDimitry Andric } 3440753f127fSDimitry Andric // Swap N0/N1 and retry. 3441753f127fSDimitry Andric if (!SwapAndRetried) { 3442753f127fSDimitry Andric std::swap(N0, N1); 3443753f127fSDimitry Andric SwapAndRetried = true; 3444753f127fSDimitry Andric goto Retry2; 3445753f127fSDimitry Andric } 3446753f127fSDimitry Andric 3447753f127fSDimitry Andric return SDValue(); 3448753f127fSDimitry Andric } 3449753f127fSDimitry Andric 34500fca6ea1SDimitry Andric static bool checkValueWidth(SDValue V, ISD::LoadExtType &ExtType) { 34510fca6ea1SDimitry Andric ExtType = ISD::NON_EXTLOAD; 34520fca6ea1SDimitry Andric 34530fca6ea1SDimitry Andric switch (V.getNode()->getOpcode()) { 34540fca6ea1SDimitry Andric case ISD::LOAD: { 34550fca6ea1SDimitry Andric LoadSDNode *LoadNode = cast<LoadSDNode>(V.getNode()); 34560fca6ea1SDimitry Andric if ((LoadNode->getMemoryVT() == MVT::i8) || 34570fca6ea1SDimitry Andric (LoadNode->getMemoryVT() == MVT::i16)) { 34580fca6ea1SDimitry Andric ExtType = LoadNode->getExtensionType(); 34590fca6ea1SDimitry Andric return true; 34600fca6ea1SDimitry Andric } 34610fca6ea1SDimitry Andric return false; 34620fca6ea1SDimitry Andric } 34630fca6ea1SDimitry Andric case ISD::AssertSext: { 34640fca6ea1SDimitry Andric VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1)); 34650fca6ea1SDimitry Andric if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) { 34660fca6ea1SDimitry Andric ExtType = ISD::SEXTLOAD; 34670fca6ea1SDimitry Andric return true; 34680fca6ea1SDimitry Andric } 34690fca6ea1SDimitry Andric return false; 34700fca6ea1SDimitry Andric } 34710fca6ea1SDimitry Andric case ISD::AssertZext: { 34720fca6ea1SDimitry Andric VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1)); 34730fca6ea1SDimitry Andric if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) { 34740fca6ea1SDimitry Andric ExtType = ISD::ZEXTLOAD; 34750fca6ea1SDimitry Andric return true; 34760fca6ea1SDimitry Andric } 34770fca6ea1SDimitry Andric return false; 34780fca6ea1SDimitry Andric } 34790fca6ea1SDimitry Andric default: 34800fca6ea1SDimitry Andric return false; 34810fca6ea1SDimitry Andric } 34820fca6ea1SDimitry Andric 34830fca6ea1SDimitry Andric return false; 34840fca6ea1SDimitry Andric } 34850fca6ea1SDimitry Andric 34860fca6ea1SDimitry Andric // Eliminate redundant truncation and zero-extension nodes. 34870fca6ea1SDimitry Andric // * Case 1: 34880fca6ea1SDimitry Andric // +------------+ +------------+ +------------+ 34890fca6ea1SDimitry Andric // | Input1 | | Input2 | | CC | 34900fca6ea1SDimitry Andric // +------------+ +------------+ +------------+ 34910fca6ea1SDimitry Andric // | | | 34920fca6ea1SDimitry Andric // V V +----+ 34930fca6ea1SDimitry Andric // +------------+ +------------+ | 34940fca6ea1SDimitry Andric // | TRUNCATE | | TRUNCATE | | 34950fca6ea1SDimitry Andric // +------------+ +------------+ | 34960fca6ea1SDimitry Andric // | | | 34970fca6ea1SDimitry Andric // V V | 34980fca6ea1SDimitry Andric // +------------+ +------------+ | 34990fca6ea1SDimitry Andric // | ZERO_EXT | | ZERO_EXT | | 35000fca6ea1SDimitry Andric // +------------+ +------------+ | 35010fca6ea1SDimitry Andric // | | | 35020fca6ea1SDimitry Andric // | +-------------+ | 35030fca6ea1SDimitry Andric // V V | | 35040fca6ea1SDimitry Andric // +----------------+ | | 35050fca6ea1SDimitry Andric // | AND | | | 35060fca6ea1SDimitry Andric // +----------------+ | | 35070fca6ea1SDimitry Andric // | | | 35080fca6ea1SDimitry Andric // +---------------+ | | 35090fca6ea1SDimitry Andric // | | | 35100fca6ea1SDimitry Andric // V V V 35110fca6ea1SDimitry Andric // +-------------+ 35120fca6ea1SDimitry Andric // | CMP | 35130fca6ea1SDimitry Andric // +-------------+ 35140fca6ea1SDimitry Andric // * Case 2: 35150fca6ea1SDimitry Andric // +------------+ +------------+ +-------------+ +------------+ +------------+ 35160fca6ea1SDimitry Andric // | Input1 | | Input2 | | Constant -1 | | Constant 0 | | CC | 35170fca6ea1SDimitry Andric // +------------+ +------------+ +-------------+ +------------+ +------------+ 35180fca6ea1SDimitry Andric // | | | | | 35190fca6ea1SDimitry Andric // V | | | | 35200fca6ea1SDimitry Andric // +------------+ | | | | 35210fca6ea1SDimitry Andric // | XOR |<---------------------+ | | 35220fca6ea1SDimitry Andric // +------------+ | | | 35230fca6ea1SDimitry Andric // | | | | 35240fca6ea1SDimitry Andric // V V +---------------+ | 35250fca6ea1SDimitry Andric // +------------+ +------------+ | | 35260fca6ea1SDimitry Andric // | TRUNCATE | | TRUNCATE | | +-------------------------+ 35270fca6ea1SDimitry Andric // +------------+ +------------+ | | 35280fca6ea1SDimitry Andric // | | | | 35290fca6ea1SDimitry Andric // V V | | 35300fca6ea1SDimitry Andric // +------------+ +------------+ | | 35310fca6ea1SDimitry Andric // | ZERO_EXT | | ZERO_EXT | | | 35320fca6ea1SDimitry Andric // +------------+ +------------+ | | 35330fca6ea1SDimitry Andric // | | | | 35340fca6ea1SDimitry Andric // V V | | 35350fca6ea1SDimitry Andric // +----------------+ | | 35360fca6ea1SDimitry Andric // | AND | | | 35370fca6ea1SDimitry Andric // +----------------+ | | 35380fca6ea1SDimitry Andric // | | | 35390fca6ea1SDimitry Andric // +---------------+ | | 35400fca6ea1SDimitry Andric // | | | 35410fca6ea1SDimitry Andric // V V V 35420fca6ea1SDimitry Andric // +-------------+ 35430fca6ea1SDimitry Andric // | CMP | 35440fca6ea1SDimitry Andric // +-------------+ 35450fca6ea1SDimitry Andric static SDValue performSETCCCombine(SDNode *N, SelectionDAG &DAG, 35460fca6ea1SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 35470fca6ea1SDimitry Andric const LoongArchSubtarget &Subtarget) { 35480fca6ea1SDimitry Andric ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get(); 35490fca6ea1SDimitry Andric 35500fca6ea1SDimitry Andric SDNode *AndNode = N->getOperand(0).getNode(); 35510fca6ea1SDimitry Andric if (AndNode->getOpcode() != ISD::AND) 35520fca6ea1SDimitry Andric return SDValue(); 35530fca6ea1SDimitry Andric 35540fca6ea1SDimitry Andric SDValue AndInputValue2 = AndNode->getOperand(1); 35550fca6ea1SDimitry Andric if (AndInputValue2.getOpcode() != ISD::ZERO_EXTEND) 35560fca6ea1SDimitry Andric return SDValue(); 35570fca6ea1SDimitry Andric 35580fca6ea1SDimitry Andric SDValue CmpInputValue = N->getOperand(1); 35590fca6ea1SDimitry Andric SDValue AndInputValue1 = AndNode->getOperand(0); 35600fca6ea1SDimitry Andric if (AndInputValue1.getOpcode() == ISD::XOR) { 35610fca6ea1SDimitry Andric if (CC != ISD::SETEQ && CC != ISD::SETNE) 35620fca6ea1SDimitry Andric return SDValue(); 35630fca6ea1SDimitry Andric ConstantSDNode *CN = dyn_cast<ConstantSDNode>(AndInputValue1.getOperand(1)); 35640fca6ea1SDimitry Andric if (!CN || CN->getSExtValue() != -1) 35650fca6ea1SDimitry Andric return SDValue(); 35660fca6ea1SDimitry Andric CN = dyn_cast<ConstantSDNode>(CmpInputValue); 35670fca6ea1SDimitry Andric if (!CN || CN->getSExtValue() != 0) 35680fca6ea1SDimitry Andric return SDValue(); 35690fca6ea1SDimitry Andric AndInputValue1 = AndInputValue1.getOperand(0); 35700fca6ea1SDimitry Andric if (AndInputValue1.getOpcode() != ISD::ZERO_EXTEND) 35710fca6ea1SDimitry Andric return SDValue(); 35720fca6ea1SDimitry Andric } else if (AndInputValue1.getOpcode() == ISD::ZERO_EXTEND) { 35730fca6ea1SDimitry Andric if (AndInputValue2 != CmpInputValue) 35740fca6ea1SDimitry Andric return SDValue(); 35750fca6ea1SDimitry Andric } else { 35760fca6ea1SDimitry Andric return SDValue(); 35770fca6ea1SDimitry Andric } 35780fca6ea1SDimitry Andric 35790fca6ea1SDimitry Andric SDValue TruncValue1 = AndInputValue1.getNode()->getOperand(0); 35800fca6ea1SDimitry Andric if (TruncValue1.getOpcode() != ISD::TRUNCATE) 35810fca6ea1SDimitry Andric return SDValue(); 35820fca6ea1SDimitry Andric 35830fca6ea1SDimitry Andric SDValue TruncValue2 = AndInputValue2.getNode()->getOperand(0); 35840fca6ea1SDimitry Andric if (TruncValue2.getOpcode() != ISD::TRUNCATE) 35850fca6ea1SDimitry Andric return SDValue(); 35860fca6ea1SDimitry Andric 35870fca6ea1SDimitry Andric SDValue TruncInputValue1 = TruncValue1.getNode()->getOperand(0); 35880fca6ea1SDimitry Andric SDValue TruncInputValue2 = TruncValue2.getNode()->getOperand(0); 35890fca6ea1SDimitry Andric ISD::LoadExtType ExtType1; 35900fca6ea1SDimitry Andric ISD::LoadExtType ExtType2; 35910fca6ea1SDimitry Andric 35920fca6ea1SDimitry Andric if (!checkValueWidth(TruncInputValue1, ExtType1) || 35930fca6ea1SDimitry Andric !checkValueWidth(TruncInputValue2, ExtType2)) 35940fca6ea1SDimitry Andric return SDValue(); 35950fca6ea1SDimitry Andric 35960fca6ea1SDimitry Andric if (TruncInputValue1->getValueType(0) != TruncInputValue2->getValueType(0) || 35970fca6ea1SDimitry Andric AndNode->getValueType(0) != TruncInputValue1->getValueType(0)) 35980fca6ea1SDimitry Andric return SDValue(); 35990fca6ea1SDimitry Andric 36000fca6ea1SDimitry Andric if ((ExtType2 != ISD::ZEXTLOAD) && 36010fca6ea1SDimitry Andric ((ExtType2 != ISD::SEXTLOAD) && (ExtType1 != ISD::SEXTLOAD))) 36020fca6ea1SDimitry Andric return SDValue(); 36030fca6ea1SDimitry Andric 36040fca6ea1SDimitry Andric // These truncation and zero-extension nodes are not necessary, remove them. 36050fca6ea1SDimitry Andric SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N), AndNode->getValueType(0), 36060fca6ea1SDimitry Andric TruncInputValue1, TruncInputValue2); 36070fca6ea1SDimitry Andric SDValue NewSetCC = 36080fca6ea1SDimitry Andric DAG.getSetCC(SDLoc(N), N->getValueType(0), NewAnd, TruncInputValue2, CC); 36090fca6ea1SDimitry Andric DAG.ReplaceAllUsesWith(N, NewSetCC.getNode()); 36100fca6ea1SDimitry Andric return SDValue(N, 0); 36110fca6ea1SDimitry Andric } 36120fca6ea1SDimitry Andric 3613bdd1243dSDimitry Andric // Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b. 3614bdd1243dSDimitry Andric static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG, 3615bdd1243dSDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 3616bdd1243dSDimitry Andric const LoongArchSubtarget &Subtarget) { 3617bdd1243dSDimitry Andric if (DCI.isBeforeLegalizeOps()) 3618bdd1243dSDimitry Andric return SDValue(); 3619bdd1243dSDimitry Andric 3620bdd1243dSDimitry Andric SDValue Src = N->getOperand(0); 3621bdd1243dSDimitry Andric if (Src.getOpcode() != LoongArchISD::REVB_2W) 3622bdd1243dSDimitry Andric return SDValue(); 3623bdd1243dSDimitry Andric 3624bdd1243dSDimitry Andric return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0), 3625bdd1243dSDimitry Andric Src.getOperand(0)); 3626bdd1243dSDimitry Andric } 3627bdd1243dSDimitry Andric 36285f757f3fSDimitry Andric template <unsigned N> 36295f757f3fSDimitry Andric static SDValue legalizeIntrinsicImmArg(SDNode *Node, unsigned ImmOp, 36305f757f3fSDimitry Andric SelectionDAG &DAG, 36315f757f3fSDimitry Andric const LoongArchSubtarget &Subtarget, 36325f757f3fSDimitry Andric bool IsSigned = false) { 36335f757f3fSDimitry Andric SDLoc DL(Node); 36345f757f3fSDimitry Andric auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp)); 36355f757f3fSDimitry Andric // Check the ImmArg. 36365f757f3fSDimitry Andric if ((IsSigned && !isInt<N>(CImm->getSExtValue())) || 36375f757f3fSDimitry Andric (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) { 36385f757f3fSDimitry Andric DAG.getContext()->emitError(Node->getOperationName(0) + 36395f757f3fSDimitry Andric ": argument out of range."); 36405f757f3fSDimitry Andric return DAG.getNode(ISD::UNDEF, DL, Subtarget.getGRLenVT()); 36415f757f3fSDimitry Andric } 36425f757f3fSDimitry Andric return DAG.getConstant(CImm->getZExtValue(), DL, Subtarget.getGRLenVT()); 36435f757f3fSDimitry Andric } 36445f757f3fSDimitry Andric 36455f757f3fSDimitry Andric template <unsigned N> 36465f757f3fSDimitry Andric static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp, 36475f757f3fSDimitry Andric SelectionDAG &DAG, bool IsSigned = false) { 36485f757f3fSDimitry Andric SDLoc DL(Node); 36495f757f3fSDimitry Andric EVT ResTy = Node->getValueType(0); 36505f757f3fSDimitry Andric auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp)); 36515f757f3fSDimitry Andric 36525f757f3fSDimitry Andric // Check the ImmArg. 36535f757f3fSDimitry Andric if ((IsSigned && !isInt<N>(CImm->getSExtValue())) || 36545f757f3fSDimitry Andric (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) { 36555f757f3fSDimitry Andric DAG.getContext()->emitError(Node->getOperationName(0) + 36565f757f3fSDimitry Andric ": argument out of range."); 36575f757f3fSDimitry Andric return DAG.getNode(ISD::UNDEF, DL, ResTy); 36585f757f3fSDimitry Andric } 36595f757f3fSDimitry Andric return DAG.getConstant( 36605f757f3fSDimitry Andric APInt(ResTy.getScalarType().getSizeInBits(), 36615f757f3fSDimitry Andric IsSigned ? CImm->getSExtValue() : CImm->getZExtValue(), IsSigned), 36625f757f3fSDimitry Andric DL, ResTy); 36635f757f3fSDimitry Andric } 36645f757f3fSDimitry Andric 36655f757f3fSDimitry Andric static SDValue truncateVecElts(SDNode *Node, SelectionDAG &DAG) { 36665f757f3fSDimitry Andric SDLoc DL(Node); 36675f757f3fSDimitry Andric EVT ResTy = Node->getValueType(0); 36685f757f3fSDimitry Andric SDValue Vec = Node->getOperand(2); 36695f757f3fSDimitry Andric SDValue Mask = DAG.getConstant(Vec.getScalarValueSizeInBits() - 1, DL, ResTy); 36705f757f3fSDimitry Andric return DAG.getNode(ISD::AND, DL, ResTy, Vec, Mask); 36715f757f3fSDimitry Andric } 36725f757f3fSDimitry Andric 36735f757f3fSDimitry Andric static SDValue lowerVectorBitClear(SDNode *Node, SelectionDAG &DAG) { 36745f757f3fSDimitry Andric SDLoc DL(Node); 36755f757f3fSDimitry Andric EVT ResTy = Node->getValueType(0); 36765f757f3fSDimitry Andric SDValue One = DAG.getConstant(1, DL, ResTy); 36775f757f3fSDimitry Andric SDValue Bit = 36785f757f3fSDimitry Andric DAG.getNode(ISD::SHL, DL, ResTy, One, truncateVecElts(Node, DAG)); 36795f757f3fSDimitry Andric 36805f757f3fSDimitry Andric return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1), 36815f757f3fSDimitry Andric DAG.getNOT(DL, Bit, ResTy)); 36825f757f3fSDimitry Andric } 36835f757f3fSDimitry Andric 36845f757f3fSDimitry Andric template <unsigned N> 36855f757f3fSDimitry Andric static SDValue lowerVectorBitClearImm(SDNode *Node, SelectionDAG &DAG) { 36865f757f3fSDimitry Andric SDLoc DL(Node); 36875f757f3fSDimitry Andric EVT ResTy = Node->getValueType(0); 36885f757f3fSDimitry Andric auto *CImm = cast<ConstantSDNode>(Node->getOperand(2)); 36895f757f3fSDimitry Andric // Check the unsigned ImmArg. 36905f757f3fSDimitry Andric if (!isUInt<N>(CImm->getZExtValue())) { 36915f757f3fSDimitry Andric DAG.getContext()->emitError(Node->getOperationName(0) + 36925f757f3fSDimitry Andric ": argument out of range."); 36935f757f3fSDimitry Andric return DAG.getNode(ISD::UNDEF, DL, ResTy); 36945f757f3fSDimitry Andric } 36955f757f3fSDimitry Andric 36965f757f3fSDimitry Andric APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue(); 36975f757f3fSDimitry Andric SDValue Mask = DAG.getConstant(~BitImm, DL, ResTy); 36985f757f3fSDimitry Andric 36995f757f3fSDimitry Andric return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1), Mask); 37005f757f3fSDimitry Andric } 37015f757f3fSDimitry Andric 37025f757f3fSDimitry Andric template <unsigned N> 37035f757f3fSDimitry Andric static SDValue lowerVectorBitSetImm(SDNode *Node, SelectionDAG &DAG) { 37045f757f3fSDimitry Andric SDLoc DL(Node); 37055f757f3fSDimitry Andric EVT ResTy = Node->getValueType(0); 37065f757f3fSDimitry Andric auto *CImm = cast<ConstantSDNode>(Node->getOperand(2)); 37075f757f3fSDimitry Andric // Check the unsigned ImmArg. 37085f757f3fSDimitry Andric if (!isUInt<N>(CImm->getZExtValue())) { 37095f757f3fSDimitry Andric DAG.getContext()->emitError(Node->getOperationName(0) + 37105f757f3fSDimitry Andric ": argument out of range."); 37115f757f3fSDimitry Andric return DAG.getNode(ISD::UNDEF, DL, ResTy); 37125f757f3fSDimitry Andric } 37135f757f3fSDimitry Andric 37145f757f3fSDimitry Andric APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue(); 37155f757f3fSDimitry Andric SDValue BitImm = DAG.getConstant(Imm, DL, ResTy); 37165f757f3fSDimitry Andric return DAG.getNode(ISD::OR, DL, ResTy, Node->getOperand(1), BitImm); 37175f757f3fSDimitry Andric } 37185f757f3fSDimitry Andric 37195f757f3fSDimitry Andric template <unsigned N> 37205f757f3fSDimitry Andric static SDValue lowerVectorBitRevImm(SDNode *Node, SelectionDAG &DAG) { 37215f757f3fSDimitry Andric SDLoc DL(Node); 37225f757f3fSDimitry Andric EVT ResTy = Node->getValueType(0); 37235f757f3fSDimitry Andric auto *CImm = cast<ConstantSDNode>(Node->getOperand(2)); 37245f757f3fSDimitry Andric // Check the unsigned ImmArg. 37255f757f3fSDimitry Andric if (!isUInt<N>(CImm->getZExtValue())) { 37265f757f3fSDimitry Andric DAG.getContext()->emitError(Node->getOperationName(0) + 37275f757f3fSDimitry Andric ": argument out of range."); 37285f757f3fSDimitry Andric return DAG.getNode(ISD::UNDEF, DL, ResTy); 37295f757f3fSDimitry Andric } 37305f757f3fSDimitry Andric 37315f757f3fSDimitry Andric APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue(); 37325f757f3fSDimitry Andric SDValue BitImm = DAG.getConstant(Imm, DL, ResTy); 37335f757f3fSDimitry Andric return DAG.getNode(ISD::XOR, DL, ResTy, Node->getOperand(1), BitImm); 37345f757f3fSDimitry Andric } 37355f757f3fSDimitry Andric 37365f757f3fSDimitry Andric static SDValue 37375f757f3fSDimitry Andric performINTRINSIC_WO_CHAINCombine(SDNode *N, SelectionDAG &DAG, 37385f757f3fSDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 37395f757f3fSDimitry Andric const LoongArchSubtarget &Subtarget) { 37405f757f3fSDimitry Andric SDLoc DL(N); 37415f757f3fSDimitry Andric switch (N->getConstantOperandVal(0)) { 37425f757f3fSDimitry Andric default: 37435f757f3fSDimitry Andric break; 37445f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vadd_b: 37455f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vadd_h: 37465f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vadd_w: 37475f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vadd_d: 37485f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvadd_b: 37495f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvadd_h: 37505f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvadd_w: 37515f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvadd_d: 37525f757f3fSDimitry Andric return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1), 37535f757f3fSDimitry Andric N->getOperand(2)); 37545f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vaddi_bu: 37555f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vaddi_hu: 37565f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vaddi_wu: 37575f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vaddi_du: 37585f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvaddi_bu: 37595f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvaddi_hu: 37605f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvaddi_wu: 37615f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvaddi_du: 37625f757f3fSDimitry Andric return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1), 37635f757f3fSDimitry Andric lowerVectorSplatImm<5>(N, 2, DAG)); 37645f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsub_b: 37655f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsub_h: 37665f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsub_w: 37675f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsub_d: 37685f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsub_b: 37695f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsub_h: 37705f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsub_w: 37715f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsub_d: 37725f757f3fSDimitry Andric return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1), 37735f757f3fSDimitry Andric N->getOperand(2)); 37745f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsubi_bu: 37755f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsubi_hu: 37765f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsubi_wu: 37775f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsubi_du: 37785f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsubi_bu: 37795f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsubi_hu: 37805f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsubi_wu: 37815f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsubi_du: 37825f757f3fSDimitry Andric return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1), 37835f757f3fSDimitry Andric lowerVectorSplatImm<5>(N, 2, DAG)); 37845f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vneg_b: 37855f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vneg_h: 37865f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vneg_w: 37875f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vneg_d: 37885f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvneg_b: 37895f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvneg_h: 37905f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvneg_w: 37915f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvneg_d: 37925f757f3fSDimitry Andric return DAG.getNode( 37935f757f3fSDimitry Andric ISD::SUB, DL, N->getValueType(0), 37945f757f3fSDimitry Andric DAG.getConstant( 37955f757f3fSDimitry Andric APInt(N->getValueType(0).getScalarType().getSizeInBits(), 0, 37965f757f3fSDimitry Andric /*isSigned=*/true), 37975f757f3fSDimitry Andric SDLoc(N), N->getValueType(0)), 37985f757f3fSDimitry Andric N->getOperand(1)); 37995f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmax_b: 38005f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmax_h: 38015f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmax_w: 38025f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmax_d: 38035f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmax_b: 38045f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmax_h: 38055f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmax_w: 38065f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmax_d: 38075f757f3fSDimitry Andric return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1), 38085f757f3fSDimitry Andric N->getOperand(2)); 38095f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmax_bu: 38105f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmax_hu: 38115f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmax_wu: 38125f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmax_du: 38135f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmax_bu: 38145f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmax_hu: 38155f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmax_wu: 38165f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmax_du: 38175f757f3fSDimitry Andric return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1), 38185f757f3fSDimitry Andric N->getOperand(2)); 38195f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmaxi_b: 38205f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmaxi_h: 38215f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmaxi_w: 38225f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmaxi_d: 38235f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmaxi_b: 38245f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmaxi_h: 38255f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmaxi_w: 38265f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmaxi_d: 38275f757f3fSDimitry Andric return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1), 38285f757f3fSDimitry Andric lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true)); 38295f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmaxi_bu: 38305f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmaxi_hu: 38315f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmaxi_wu: 38325f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmaxi_du: 38335f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmaxi_bu: 38345f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmaxi_hu: 38355f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmaxi_wu: 38365f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmaxi_du: 38375f757f3fSDimitry Andric return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1), 38385f757f3fSDimitry Andric lowerVectorSplatImm<5>(N, 2, DAG)); 38395f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmin_b: 38405f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmin_h: 38415f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmin_w: 38425f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmin_d: 38435f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmin_b: 38445f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmin_h: 38455f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmin_w: 38465f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmin_d: 38475f757f3fSDimitry Andric return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1), 38485f757f3fSDimitry Andric N->getOperand(2)); 38495f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmin_bu: 38505f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmin_hu: 38515f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmin_wu: 38525f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmin_du: 38535f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmin_bu: 38545f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmin_hu: 38555f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmin_wu: 38565f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmin_du: 38575f757f3fSDimitry Andric return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1), 38585f757f3fSDimitry Andric N->getOperand(2)); 38595f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmini_b: 38605f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmini_h: 38615f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmini_w: 38625f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmini_d: 38635f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmini_b: 38645f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmini_h: 38655f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmini_w: 38665f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmini_d: 38675f757f3fSDimitry Andric return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1), 38685f757f3fSDimitry Andric lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true)); 38695f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmini_bu: 38705f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmini_hu: 38715f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmini_wu: 38725f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmini_du: 38735f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmini_bu: 38745f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmini_hu: 38755f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmini_wu: 38765f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmini_du: 38775f757f3fSDimitry Andric return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1), 38785f757f3fSDimitry Andric lowerVectorSplatImm<5>(N, 2, DAG)); 38795f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmul_b: 38805f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmul_h: 38815f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmul_w: 38825f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmul_d: 38835f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmul_b: 38845f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmul_h: 38855f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmul_w: 38865f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmul_d: 38875f757f3fSDimitry Andric return DAG.getNode(ISD::MUL, DL, N->getValueType(0), N->getOperand(1), 38885f757f3fSDimitry Andric N->getOperand(2)); 38895f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmadd_b: 38905f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmadd_h: 38915f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmadd_w: 38925f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmadd_d: 38935f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmadd_b: 38945f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmadd_h: 38955f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmadd_w: 38965f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmadd_d: { 38975f757f3fSDimitry Andric EVT ResTy = N->getValueType(0); 38985f757f3fSDimitry Andric return DAG.getNode(ISD::ADD, SDLoc(N), ResTy, N->getOperand(1), 38995f757f3fSDimitry Andric DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2), 39005f757f3fSDimitry Andric N->getOperand(3))); 39015f757f3fSDimitry Andric } 39025f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmsub_b: 39035f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmsub_h: 39045f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmsub_w: 39055f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmsub_d: 39065f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmsub_b: 39075f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmsub_h: 39085f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmsub_w: 39095f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmsub_d: { 39105f757f3fSDimitry Andric EVT ResTy = N->getValueType(0); 39115f757f3fSDimitry Andric return DAG.getNode(ISD::SUB, SDLoc(N), ResTy, N->getOperand(1), 39125f757f3fSDimitry Andric DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2), 39135f757f3fSDimitry Andric N->getOperand(3))); 39145f757f3fSDimitry Andric } 39155f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vdiv_b: 39165f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vdiv_h: 39175f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vdiv_w: 39185f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vdiv_d: 39195f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvdiv_b: 39205f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvdiv_h: 39215f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvdiv_w: 39225f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvdiv_d: 39235f757f3fSDimitry Andric return DAG.getNode(ISD::SDIV, DL, N->getValueType(0), N->getOperand(1), 39245f757f3fSDimitry Andric N->getOperand(2)); 39255f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vdiv_bu: 39265f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vdiv_hu: 39275f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vdiv_wu: 39285f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vdiv_du: 39295f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvdiv_bu: 39305f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvdiv_hu: 39315f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvdiv_wu: 39325f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvdiv_du: 39335f757f3fSDimitry Andric return DAG.getNode(ISD::UDIV, DL, N->getValueType(0), N->getOperand(1), 39345f757f3fSDimitry Andric N->getOperand(2)); 39355f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmod_b: 39365f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmod_h: 39375f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmod_w: 39385f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmod_d: 39395f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmod_b: 39405f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmod_h: 39415f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmod_w: 39425f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmod_d: 39435f757f3fSDimitry Andric return DAG.getNode(ISD::SREM, DL, N->getValueType(0), N->getOperand(1), 39445f757f3fSDimitry Andric N->getOperand(2)); 39455f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmod_bu: 39465f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmod_hu: 39475f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmod_wu: 39485f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vmod_du: 39495f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmod_bu: 39505f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmod_hu: 39515f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmod_wu: 39525f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvmod_du: 39535f757f3fSDimitry Andric return DAG.getNode(ISD::UREM, DL, N->getValueType(0), N->getOperand(1), 39545f757f3fSDimitry Andric N->getOperand(2)); 39555f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vand_v: 39565f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvand_v: 39575f757f3fSDimitry Andric return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1), 39585f757f3fSDimitry Andric N->getOperand(2)); 39595f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vor_v: 39605f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvor_v: 39615f757f3fSDimitry Andric return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1), 39625f757f3fSDimitry Andric N->getOperand(2)); 39635f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vxor_v: 39645f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvxor_v: 39655f757f3fSDimitry Andric return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1), 39665f757f3fSDimitry Andric N->getOperand(2)); 39675f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vnor_v: 39685f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvnor_v: { 39695f757f3fSDimitry Andric SDValue Res = DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1), 39705f757f3fSDimitry Andric N->getOperand(2)); 39715f757f3fSDimitry Andric return DAG.getNOT(DL, Res, Res->getValueType(0)); 39725f757f3fSDimitry Andric } 39735f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vandi_b: 39745f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvandi_b: 39755f757f3fSDimitry Andric return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1), 39765f757f3fSDimitry Andric lowerVectorSplatImm<8>(N, 2, DAG)); 39775f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vori_b: 39785f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvori_b: 39795f757f3fSDimitry Andric return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1), 39805f757f3fSDimitry Andric lowerVectorSplatImm<8>(N, 2, DAG)); 39815f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vxori_b: 39825f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvxori_b: 39835f757f3fSDimitry Andric return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1), 39845f757f3fSDimitry Andric lowerVectorSplatImm<8>(N, 2, DAG)); 39855f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsll_b: 39865f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsll_h: 39875f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsll_w: 39885f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsll_d: 39895f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsll_b: 39905f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsll_h: 39915f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsll_w: 39925f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsll_d: 39935f757f3fSDimitry Andric return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1), 39945f757f3fSDimitry Andric truncateVecElts(N, DAG)); 39955f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslli_b: 39965f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslli_b: 39975f757f3fSDimitry Andric return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1), 39985f757f3fSDimitry Andric lowerVectorSplatImm<3>(N, 2, DAG)); 39995f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslli_h: 40005f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslli_h: 40015f757f3fSDimitry Andric return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1), 40025f757f3fSDimitry Andric lowerVectorSplatImm<4>(N, 2, DAG)); 40035f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslli_w: 40045f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslli_w: 40055f757f3fSDimitry Andric return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1), 40065f757f3fSDimitry Andric lowerVectorSplatImm<5>(N, 2, DAG)); 40075f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vslli_d: 40085f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvslli_d: 40095f757f3fSDimitry Andric return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1), 40105f757f3fSDimitry Andric lowerVectorSplatImm<6>(N, 2, DAG)); 40115f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrl_b: 40125f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrl_h: 40135f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrl_w: 40145f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrl_d: 40155f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrl_b: 40165f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrl_h: 40175f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrl_w: 40185f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrl_d: 40195f757f3fSDimitry Andric return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1), 40205f757f3fSDimitry Andric truncateVecElts(N, DAG)); 40215f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrli_b: 40225f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrli_b: 40235f757f3fSDimitry Andric return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1), 40245f757f3fSDimitry Andric lowerVectorSplatImm<3>(N, 2, DAG)); 40255f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrli_h: 40265f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrli_h: 40275f757f3fSDimitry Andric return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1), 40285f757f3fSDimitry Andric lowerVectorSplatImm<4>(N, 2, DAG)); 40295f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrli_w: 40305f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrli_w: 40315f757f3fSDimitry Andric return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1), 40325f757f3fSDimitry Andric lowerVectorSplatImm<5>(N, 2, DAG)); 40335f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrli_d: 40345f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrli_d: 40355f757f3fSDimitry Andric return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1), 40365f757f3fSDimitry Andric lowerVectorSplatImm<6>(N, 2, DAG)); 40375f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsra_b: 40385f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsra_h: 40395f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsra_w: 40405f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsra_d: 40415f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsra_b: 40425f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsra_h: 40435f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsra_w: 40445f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsra_d: 40455f757f3fSDimitry Andric return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1), 40465f757f3fSDimitry Andric truncateVecElts(N, DAG)); 40475f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrai_b: 40485f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrai_b: 40495f757f3fSDimitry Andric return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1), 40505f757f3fSDimitry Andric lowerVectorSplatImm<3>(N, 2, DAG)); 40515f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrai_h: 40525f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrai_h: 40535f757f3fSDimitry Andric return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1), 40545f757f3fSDimitry Andric lowerVectorSplatImm<4>(N, 2, DAG)); 40555f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrai_w: 40565f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrai_w: 40575f757f3fSDimitry Andric return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1), 40585f757f3fSDimitry Andric lowerVectorSplatImm<5>(N, 2, DAG)); 40595f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vsrai_d: 40605f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvsrai_d: 40615f757f3fSDimitry Andric return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1), 40625f757f3fSDimitry Andric lowerVectorSplatImm<6>(N, 2, DAG)); 40635f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vclz_b: 40645f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vclz_h: 40655f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vclz_w: 40665f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vclz_d: 40675f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvclz_b: 40685f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvclz_h: 40695f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvclz_w: 40705f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvclz_d: 40715f757f3fSDimitry Andric return DAG.getNode(ISD::CTLZ, DL, N->getValueType(0), N->getOperand(1)); 40725f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpcnt_b: 40735f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpcnt_h: 40745f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpcnt_w: 40755f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vpcnt_d: 40765f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpcnt_b: 40775f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpcnt_h: 40785f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpcnt_w: 40795f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvpcnt_d: 40805f757f3fSDimitry Andric return DAG.getNode(ISD::CTPOP, DL, N->getValueType(0), N->getOperand(1)); 40815f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitclr_b: 40825f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitclr_h: 40835f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitclr_w: 40845f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitclr_d: 40855f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitclr_b: 40865f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitclr_h: 40875f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitclr_w: 40885f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitclr_d: 40895f757f3fSDimitry Andric return lowerVectorBitClear(N, DAG); 40905f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitclri_b: 40915f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitclri_b: 40925f757f3fSDimitry Andric return lowerVectorBitClearImm<3>(N, DAG); 40935f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitclri_h: 40945f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitclri_h: 40955f757f3fSDimitry Andric return lowerVectorBitClearImm<4>(N, DAG); 40965f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitclri_w: 40975f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitclri_w: 40985f757f3fSDimitry Andric return lowerVectorBitClearImm<5>(N, DAG); 40995f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitclri_d: 41005f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitclri_d: 41015f757f3fSDimitry Andric return lowerVectorBitClearImm<6>(N, DAG); 41025f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitset_b: 41035f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitset_h: 41045f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitset_w: 41055f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitset_d: 41065f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitset_b: 41075f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitset_h: 41085f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitset_w: 41095f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitset_d: { 41105f757f3fSDimitry Andric EVT VecTy = N->getValueType(0); 41115f757f3fSDimitry Andric SDValue One = DAG.getConstant(1, DL, VecTy); 41125f757f3fSDimitry Andric return DAG.getNode( 41135f757f3fSDimitry Andric ISD::OR, DL, VecTy, N->getOperand(1), 41145f757f3fSDimitry Andric DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG))); 41155f757f3fSDimitry Andric } 41165f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitseti_b: 41175f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitseti_b: 41185f757f3fSDimitry Andric return lowerVectorBitSetImm<3>(N, DAG); 41195f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitseti_h: 41205f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitseti_h: 41215f757f3fSDimitry Andric return lowerVectorBitSetImm<4>(N, DAG); 41225f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitseti_w: 41235f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitseti_w: 41245f757f3fSDimitry Andric return lowerVectorBitSetImm<5>(N, DAG); 41255f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitseti_d: 41265f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitseti_d: 41275f757f3fSDimitry Andric return lowerVectorBitSetImm<6>(N, DAG); 41285f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitrev_b: 41295f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitrev_h: 41305f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitrev_w: 41315f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitrev_d: 41325f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitrev_b: 41335f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitrev_h: 41345f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitrev_w: 41355f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitrev_d: { 41365f757f3fSDimitry Andric EVT VecTy = N->getValueType(0); 41375f757f3fSDimitry Andric SDValue One = DAG.getConstant(1, DL, VecTy); 41385f757f3fSDimitry Andric return DAG.getNode( 41395f757f3fSDimitry Andric ISD::XOR, DL, VecTy, N->getOperand(1), 41405f757f3fSDimitry Andric DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG))); 41415f757f3fSDimitry Andric } 41425f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitrevi_b: 41435f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitrevi_b: 41445f757f3fSDimitry Andric return lowerVectorBitRevImm<3>(N, DAG); 41455f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitrevi_h: 41465f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitrevi_h: 41475f757f3fSDimitry Andric return lowerVectorBitRevImm<4>(N, DAG); 41485f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitrevi_w: 41495f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitrevi_w: 41505f757f3fSDimitry Andric return lowerVectorBitRevImm<5>(N, DAG); 41515f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vbitrevi_d: 41525f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvbitrevi_d: 41535f757f3fSDimitry Andric return lowerVectorBitRevImm<6>(N, DAG); 41545f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfadd_s: 41555f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfadd_d: 41565f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfadd_s: 41575f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfadd_d: 41585f757f3fSDimitry Andric return DAG.getNode(ISD::FADD, DL, N->getValueType(0), N->getOperand(1), 41595f757f3fSDimitry Andric N->getOperand(2)); 41605f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfsub_s: 41615f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfsub_d: 41625f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfsub_s: 41635f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfsub_d: 41645f757f3fSDimitry Andric return DAG.getNode(ISD::FSUB, DL, N->getValueType(0), N->getOperand(1), 41655f757f3fSDimitry Andric N->getOperand(2)); 41665f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfmul_s: 41675f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfmul_d: 41685f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfmul_s: 41695f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfmul_d: 41705f757f3fSDimitry Andric return DAG.getNode(ISD::FMUL, DL, N->getValueType(0), N->getOperand(1), 41715f757f3fSDimitry Andric N->getOperand(2)); 41725f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfdiv_s: 41735f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfdiv_d: 41745f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfdiv_s: 41755f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfdiv_d: 41765f757f3fSDimitry Andric return DAG.getNode(ISD::FDIV, DL, N->getValueType(0), N->getOperand(1), 41775f757f3fSDimitry Andric N->getOperand(2)); 41785f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfmadd_s: 41795f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vfmadd_d: 41805f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfmadd_s: 41815f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvfmadd_d: 41825f757f3fSDimitry Andric return DAG.getNode(ISD::FMA, DL, N->getValueType(0), N->getOperand(1), 41835f757f3fSDimitry Andric N->getOperand(2), N->getOperand(3)); 41845f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vinsgr2vr_b: 41855f757f3fSDimitry Andric return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0), 41865f757f3fSDimitry Andric N->getOperand(1), N->getOperand(2), 41875f757f3fSDimitry Andric legalizeIntrinsicImmArg<4>(N, 3, DAG, Subtarget)); 41885f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vinsgr2vr_h: 41895f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvinsgr2vr_w: 41905f757f3fSDimitry Andric return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0), 41915f757f3fSDimitry Andric N->getOperand(1), N->getOperand(2), 41925f757f3fSDimitry Andric legalizeIntrinsicImmArg<3>(N, 3, DAG, Subtarget)); 41935f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vinsgr2vr_w: 41945f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvinsgr2vr_d: 41955f757f3fSDimitry Andric return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0), 41965f757f3fSDimitry Andric N->getOperand(1), N->getOperand(2), 41975f757f3fSDimitry Andric legalizeIntrinsicImmArg<2>(N, 3, DAG, Subtarget)); 41985f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vinsgr2vr_d: 41995f757f3fSDimitry Andric return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0), 42005f757f3fSDimitry Andric N->getOperand(1), N->getOperand(2), 42015f757f3fSDimitry Andric legalizeIntrinsicImmArg<1>(N, 3, DAG, Subtarget)); 42025f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplgr2vr_b: 42035f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplgr2vr_h: 42045f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplgr2vr_w: 42055f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplgr2vr_d: 42065f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvreplgr2vr_b: 42075f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvreplgr2vr_h: 42085f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvreplgr2vr_w: 42095f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvreplgr2vr_d: { 42105f757f3fSDimitry Andric EVT ResTy = N->getValueType(0); 42115f757f3fSDimitry Andric SmallVector<SDValue> Ops(ResTy.getVectorNumElements(), N->getOperand(1)); 42125f757f3fSDimitry Andric return DAG.getBuildVector(ResTy, DL, Ops); 42135f757f3fSDimitry Andric } 42145f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplve_b: 42155f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplve_h: 42165f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplve_w: 42175f757f3fSDimitry Andric case Intrinsic::loongarch_lsx_vreplve_d: 42185f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvreplve_b: 42195f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvreplve_h: 42205f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvreplve_w: 42215f757f3fSDimitry Andric case Intrinsic::loongarch_lasx_xvreplve_d: 42225f757f3fSDimitry Andric return DAG.getNode(LoongArchISD::VREPLVE, DL, N->getValueType(0), 42235f757f3fSDimitry Andric N->getOperand(1), 42245f757f3fSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(), 42255f757f3fSDimitry Andric N->getOperand(2))); 42265f757f3fSDimitry Andric } 42275f757f3fSDimitry Andric return SDValue(); 42285f757f3fSDimitry Andric } 42295f757f3fSDimitry Andric 423081ad6265SDimitry Andric SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N, 423181ad6265SDimitry Andric DAGCombinerInfo &DCI) const { 423281ad6265SDimitry Andric SelectionDAG &DAG = DCI.DAG; 423381ad6265SDimitry Andric switch (N->getOpcode()) { 423481ad6265SDimitry Andric default: 423581ad6265SDimitry Andric break; 423681ad6265SDimitry Andric case ISD::AND: 423781ad6265SDimitry Andric return performANDCombine(N, DAG, DCI, Subtarget); 4238753f127fSDimitry Andric case ISD::OR: 4239753f127fSDimitry Andric return performORCombine(N, DAG, DCI, Subtarget); 42400fca6ea1SDimitry Andric case ISD::SETCC: 42410fca6ea1SDimitry Andric return performSETCCCombine(N, DAG, DCI, Subtarget); 424281ad6265SDimitry Andric case ISD::SRL: 424381ad6265SDimitry Andric return performSRLCombine(N, DAG, DCI, Subtarget); 4244bdd1243dSDimitry Andric case LoongArchISD::BITREV_W: 4245bdd1243dSDimitry Andric return performBITREV_WCombine(N, DAG, DCI, Subtarget); 42465f757f3fSDimitry Andric case ISD::INTRINSIC_WO_CHAIN: 42475f757f3fSDimitry Andric return performINTRINSIC_WO_CHAINCombine(N, DAG, DCI, Subtarget); 424881ad6265SDimitry Andric } 424981ad6265SDimitry Andric return SDValue(); 425081ad6265SDimitry Andric } 425181ad6265SDimitry Andric 4252753f127fSDimitry Andric static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI, 4253bdd1243dSDimitry Andric MachineBasicBlock *MBB) { 4254753f127fSDimitry Andric if (!ZeroDivCheck) 4255bdd1243dSDimitry Andric return MBB; 4256753f127fSDimitry Andric 4257753f127fSDimitry Andric // Build instructions: 4258bdd1243dSDimitry Andric // MBB: 4259753f127fSDimitry Andric // div(or mod) $dst, $dividend, $divisor 4260bdd1243dSDimitry Andric // bnez $divisor, SinkMBB 4261bdd1243dSDimitry Andric // BreakMBB: 4262bdd1243dSDimitry Andric // break 7 // BRK_DIVZERO 4263bdd1243dSDimitry Andric // SinkMBB: 4264753f127fSDimitry Andric // fallthrough 4265bdd1243dSDimitry Andric const BasicBlock *LLVM_BB = MBB->getBasicBlock(); 4266bdd1243dSDimitry Andric MachineFunction::iterator It = ++MBB->getIterator(); 4267bdd1243dSDimitry Andric MachineFunction *MF = MBB->getParent(); 4268bdd1243dSDimitry Andric auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB); 4269bdd1243dSDimitry Andric auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB); 4270bdd1243dSDimitry Andric MF->insert(It, BreakMBB); 4271bdd1243dSDimitry Andric MF->insert(It, SinkMBB); 4272bdd1243dSDimitry Andric 4273bdd1243dSDimitry Andric // Transfer the remainder of MBB and its successor edges to SinkMBB. 4274bdd1243dSDimitry Andric SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end()); 4275bdd1243dSDimitry Andric SinkMBB->transferSuccessorsAndUpdatePHIs(MBB); 4276bdd1243dSDimitry Andric 4277bdd1243dSDimitry Andric const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); 4278bdd1243dSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 4279753f127fSDimitry Andric MachineOperand &Divisor = MI.getOperand(2); 4280bdd1243dSDimitry Andric Register DivisorReg = Divisor.getReg(); 4281753f127fSDimitry Andric 4282bdd1243dSDimitry Andric // MBB: 4283bdd1243dSDimitry Andric BuildMI(MBB, DL, TII.get(LoongArch::BNEZ)) 4284bdd1243dSDimitry Andric .addReg(DivisorReg, getKillRegState(Divisor.isKill())) 4285bdd1243dSDimitry Andric .addMBB(SinkMBB); 4286bdd1243dSDimitry Andric MBB->addSuccessor(BreakMBB); 4287bdd1243dSDimitry Andric MBB->addSuccessor(SinkMBB); 4288753f127fSDimitry Andric 4289bdd1243dSDimitry Andric // BreakMBB: 4290753f127fSDimitry Andric // See linux header file arch/loongarch/include/uapi/asm/break.h for the 4291753f127fSDimitry Andric // definition of BRK_DIVZERO. 4292bdd1243dSDimitry Andric BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/); 4293bdd1243dSDimitry Andric BreakMBB->addSuccessor(SinkMBB); 4294753f127fSDimitry Andric 4295753f127fSDimitry Andric // Clear Divisor's kill flag. 4296753f127fSDimitry Andric Divisor.setIsKill(false); 4297753f127fSDimitry Andric 4298bdd1243dSDimitry Andric return SinkMBB; 4299753f127fSDimitry Andric } 4300753f127fSDimitry Andric 43015f757f3fSDimitry Andric static MachineBasicBlock * 43025f757f3fSDimitry Andric emitVecCondBranchPseudo(MachineInstr &MI, MachineBasicBlock *BB, 43035f757f3fSDimitry Andric const LoongArchSubtarget &Subtarget) { 43045f757f3fSDimitry Andric unsigned CondOpc; 43055f757f3fSDimitry Andric switch (MI.getOpcode()) { 43065f757f3fSDimitry Andric default: 43075f757f3fSDimitry Andric llvm_unreachable("Unexpected opcode"); 43085f757f3fSDimitry Andric case LoongArch::PseudoVBZ: 43095f757f3fSDimitry Andric CondOpc = LoongArch::VSETEQZ_V; 43105f757f3fSDimitry Andric break; 43115f757f3fSDimitry Andric case LoongArch::PseudoVBZ_B: 43125f757f3fSDimitry Andric CondOpc = LoongArch::VSETANYEQZ_B; 43135f757f3fSDimitry Andric break; 43145f757f3fSDimitry Andric case LoongArch::PseudoVBZ_H: 43155f757f3fSDimitry Andric CondOpc = LoongArch::VSETANYEQZ_H; 43165f757f3fSDimitry Andric break; 43175f757f3fSDimitry Andric case LoongArch::PseudoVBZ_W: 43185f757f3fSDimitry Andric CondOpc = LoongArch::VSETANYEQZ_W; 43195f757f3fSDimitry Andric break; 43205f757f3fSDimitry Andric case LoongArch::PseudoVBZ_D: 43215f757f3fSDimitry Andric CondOpc = LoongArch::VSETANYEQZ_D; 43225f757f3fSDimitry Andric break; 43235f757f3fSDimitry Andric case LoongArch::PseudoVBNZ: 43245f757f3fSDimitry Andric CondOpc = LoongArch::VSETNEZ_V; 43255f757f3fSDimitry Andric break; 43265f757f3fSDimitry Andric case LoongArch::PseudoVBNZ_B: 43275f757f3fSDimitry Andric CondOpc = LoongArch::VSETALLNEZ_B; 43285f757f3fSDimitry Andric break; 43295f757f3fSDimitry Andric case LoongArch::PseudoVBNZ_H: 43305f757f3fSDimitry Andric CondOpc = LoongArch::VSETALLNEZ_H; 43315f757f3fSDimitry Andric break; 43325f757f3fSDimitry Andric case LoongArch::PseudoVBNZ_W: 43335f757f3fSDimitry Andric CondOpc = LoongArch::VSETALLNEZ_W; 43345f757f3fSDimitry Andric break; 43355f757f3fSDimitry Andric case LoongArch::PseudoVBNZ_D: 43365f757f3fSDimitry Andric CondOpc = LoongArch::VSETALLNEZ_D; 43375f757f3fSDimitry Andric break; 43385f757f3fSDimitry Andric case LoongArch::PseudoXVBZ: 43395f757f3fSDimitry Andric CondOpc = LoongArch::XVSETEQZ_V; 43405f757f3fSDimitry Andric break; 43415f757f3fSDimitry Andric case LoongArch::PseudoXVBZ_B: 43425f757f3fSDimitry Andric CondOpc = LoongArch::XVSETANYEQZ_B; 43435f757f3fSDimitry Andric break; 43445f757f3fSDimitry Andric case LoongArch::PseudoXVBZ_H: 43455f757f3fSDimitry Andric CondOpc = LoongArch::XVSETANYEQZ_H; 43465f757f3fSDimitry Andric break; 43475f757f3fSDimitry Andric case LoongArch::PseudoXVBZ_W: 43485f757f3fSDimitry Andric CondOpc = LoongArch::XVSETANYEQZ_W; 43495f757f3fSDimitry Andric break; 43505f757f3fSDimitry Andric case LoongArch::PseudoXVBZ_D: 43515f757f3fSDimitry Andric CondOpc = LoongArch::XVSETANYEQZ_D; 43525f757f3fSDimitry Andric break; 43535f757f3fSDimitry Andric case LoongArch::PseudoXVBNZ: 43545f757f3fSDimitry Andric CondOpc = LoongArch::XVSETNEZ_V; 43555f757f3fSDimitry Andric break; 43565f757f3fSDimitry Andric case LoongArch::PseudoXVBNZ_B: 43575f757f3fSDimitry Andric CondOpc = LoongArch::XVSETALLNEZ_B; 43585f757f3fSDimitry Andric break; 43595f757f3fSDimitry Andric case LoongArch::PseudoXVBNZ_H: 43605f757f3fSDimitry Andric CondOpc = LoongArch::XVSETALLNEZ_H; 43615f757f3fSDimitry Andric break; 43625f757f3fSDimitry Andric case LoongArch::PseudoXVBNZ_W: 43635f757f3fSDimitry Andric CondOpc = LoongArch::XVSETALLNEZ_W; 43645f757f3fSDimitry Andric break; 43655f757f3fSDimitry Andric case LoongArch::PseudoXVBNZ_D: 43665f757f3fSDimitry Andric CondOpc = LoongArch::XVSETALLNEZ_D; 43675f757f3fSDimitry Andric break; 43685f757f3fSDimitry Andric } 43695f757f3fSDimitry Andric 43705f757f3fSDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 43715f757f3fSDimitry Andric const BasicBlock *LLVM_BB = BB->getBasicBlock(); 43725f757f3fSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 43735f757f3fSDimitry Andric MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); 43745f757f3fSDimitry Andric MachineFunction::iterator It = ++BB->getIterator(); 43755f757f3fSDimitry Andric 43765f757f3fSDimitry Andric MachineFunction *F = BB->getParent(); 43775f757f3fSDimitry Andric MachineBasicBlock *FalseBB = F->CreateMachineBasicBlock(LLVM_BB); 43785f757f3fSDimitry Andric MachineBasicBlock *TrueBB = F->CreateMachineBasicBlock(LLVM_BB); 43795f757f3fSDimitry Andric MachineBasicBlock *SinkBB = F->CreateMachineBasicBlock(LLVM_BB); 43805f757f3fSDimitry Andric 43815f757f3fSDimitry Andric F->insert(It, FalseBB); 43825f757f3fSDimitry Andric F->insert(It, TrueBB); 43835f757f3fSDimitry Andric F->insert(It, SinkBB); 43845f757f3fSDimitry Andric 43855f757f3fSDimitry Andric // Transfer the remainder of MBB and its successor edges to Sink. 43865f757f3fSDimitry Andric SinkBB->splice(SinkBB->end(), BB, std::next(MI.getIterator()), BB->end()); 43875f757f3fSDimitry Andric SinkBB->transferSuccessorsAndUpdatePHIs(BB); 43885f757f3fSDimitry Andric 43895f757f3fSDimitry Andric // Insert the real instruction to BB. 43905f757f3fSDimitry Andric Register FCC = MRI.createVirtualRegister(&LoongArch::CFRRegClass); 43915f757f3fSDimitry Andric BuildMI(BB, DL, TII->get(CondOpc), FCC).addReg(MI.getOperand(1).getReg()); 43925f757f3fSDimitry Andric 43935f757f3fSDimitry Andric // Insert branch. 43945f757f3fSDimitry Andric BuildMI(BB, DL, TII->get(LoongArch::BCNEZ)).addReg(FCC).addMBB(TrueBB); 43955f757f3fSDimitry Andric BB->addSuccessor(FalseBB); 43965f757f3fSDimitry Andric BB->addSuccessor(TrueBB); 43975f757f3fSDimitry Andric 43985f757f3fSDimitry Andric // FalseBB. 43995f757f3fSDimitry Andric Register RD1 = MRI.createVirtualRegister(&LoongArch::GPRRegClass); 44005f757f3fSDimitry Andric BuildMI(FalseBB, DL, TII->get(LoongArch::ADDI_W), RD1) 44015f757f3fSDimitry Andric .addReg(LoongArch::R0) 44025f757f3fSDimitry Andric .addImm(0); 44035f757f3fSDimitry Andric BuildMI(FalseBB, DL, TII->get(LoongArch::PseudoBR)).addMBB(SinkBB); 44045f757f3fSDimitry Andric FalseBB->addSuccessor(SinkBB); 44055f757f3fSDimitry Andric 44065f757f3fSDimitry Andric // TrueBB. 44075f757f3fSDimitry Andric Register RD2 = MRI.createVirtualRegister(&LoongArch::GPRRegClass); 44085f757f3fSDimitry Andric BuildMI(TrueBB, DL, TII->get(LoongArch::ADDI_W), RD2) 44095f757f3fSDimitry Andric .addReg(LoongArch::R0) 44105f757f3fSDimitry Andric .addImm(1); 44115f757f3fSDimitry Andric TrueBB->addSuccessor(SinkBB); 44125f757f3fSDimitry Andric 44135f757f3fSDimitry Andric // SinkBB: merge the results. 44145f757f3fSDimitry Andric BuildMI(*SinkBB, SinkBB->begin(), DL, TII->get(LoongArch::PHI), 44155f757f3fSDimitry Andric MI.getOperand(0).getReg()) 44165f757f3fSDimitry Andric .addReg(RD1) 44175f757f3fSDimitry Andric .addMBB(FalseBB) 44185f757f3fSDimitry Andric .addReg(RD2) 44195f757f3fSDimitry Andric .addMBB(TrueBB); 44205f757f3fSDimitry Andric 44215f757f3fSDimitry Andric // The pseudo instruction is gone now. 44225f757f3fSDimitry Andric MI.eraseFromParent(); 44235f757f3fSDimitry Andric return SinkBB; 44245f757f3fSDimitry Andric } 44255f757f3fSDimitry Andric 44265f757f3fSDimitry Andric static MachineBasicBlock * 44275f757f3fSDimitry Andric emitPseudoXVINSGR2VR(MachineInstr &MI, MachineBasicBlock *BB, 44285f757f3fSDimitry Andric const LoongArchSubtarget &Subtarget) { 44295f757f3fSDimitry Andric unsigned InsOp; 44305f757f3fSDimitry Andric unsigned HalfSize; 44315f757f3fSDimitry Andric switch (MI.getOpcode()) { 44325f757f3fSDimitry Andric default: 44335f757f3fSDimitry Andric llvm_unreachable("Unexpected opcode"); 44345f757f3fSDimitry Andric case LoongArch::PseudoXVINSGR2VR_B: 44355f757f3fSDimitry Andric HalfSize = 16; 44365f757f3fSDimitry Andric InsOp = LoongArch::VINSGR2VR_B; 44375f757f3fSDimitry Andric break; 44385f757f3fSDimitry Andric case LoongArch::PseudoXVINSGR2VR_H: 44395f757f3fSDimitry Andric HalfSize = 8; 44405f757f3fSDimitry Andric InsOp = LoongArch::VINSGR2VR_H; 44415f757f3fSDimitry Andric break; 44425f757f3fSDimitry Andric } 44435f757f3fSDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 44445f757f3fSDimitry Andric const TargetRegisterClass *RC = &LoongArch::LASX256RegClass; 44455f757f3fSDimitry Andric const TargetRegisterClass *SubRC = &LoongArch::LSX128RegClass; 44465f757f3fSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 44475f757f3fSDimitry Andric MachineRegisterInfo &MRI = BB->getParent()->getRegInfo(); 44485f757f3fSDimitry Andric // XDst = vector_insert XSrc, Elt, Idx 44495f757f3fSDimitry Andric Register XDst = MI.getOperand(0).getReg(); 44505f757f3fSDimitry Andric Register XSrc = MI.getOperand(1).getReg(); 44515f757f3fSDimitry Andric Register Elt = MI.getOperand(2).getReg(); 44525f757f3fSDimitry Andric unsigned Idx = MI.getOperand(3).getImm(); 44535f757f3fSDimitry Andric 44545f757f3fSDimitry Andric Register ScratchReg1 = XSrc; 44555f757f3fSDimitry Andric if (Idx >= HalfSize) { 44565f757f3fSDimitry Andric ScratchReg1 = MRI.createVirtualRegister(RC); 44575f757f3fSDimitry Andric BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), ScratchReg1) 44585f757f3fSDimitry Andric .addReg(XSrc) 44595f757f3fSDimitry Andric .addReg(XSrc) 44605f757f3fSDimitry Andric .addImm(1); 44615f757f3fSDimitry Andric } 44625f757f3fSDimitry Andric 44635f757f3fSDimitry Andric Register ScratchSubReg1 = MRI.createVirtualRegister(SubRC); 44645f757f3fSDimitry Andric Register ScratchSubReg2 = MRI.createVirtualRegister(SubRC); 44655f757f3fSDimitry Andric BuildMI(*BB, MI, DL, TII->get(LoongArch::COPY), ScratchSubReg1) 44665f757f3fSDimitry Andric .addReg(ScratchReg1, 0, LoongArch::sub_128); 44675f757f3fSDimitry Andric BuildMI(*BB, MI, DL, TII->get(InsOp), ScratchSubReg2) 44685f757f3fSDimitry Andric .addReg(ScratchSubReg1) 44695f757f3fSDimitry Andric .addReg(Elt) 44705f757f3fSDimitry Andric .addImm(Idx >= HalfSize ? Idx - HalfSize : Idx); 44715f757f3fSDimitry Andric 44725f757f3fSDimitry Andric Register ScratchReg2 = XDst; 44735f757f3fSDimitry Andric if (Idx >= HalfSize) 44745f757f3fSDimitry Andric ScratchReg2 = MRI.createVirtualRegister(RC); 44755f757f3fSDimitry Andric 44765f757f3fSDimitry Andric BuildMI(*BB, MI, DL, TII->get(LoongArch::SUBREG_TO_REG), ScratchReg2) 44775f757f3fSDimitry Andric .addImm(0) 44785f757f3fSDimitry Andric .addReg(ScratchSubReg2) 44795f757f3fSDimitry Andric .addImm(LoongArch::sub_128); 44805f757f3fSDimitry Andric 44815f757f3fSDimitry Andric if (Idx >= HalfSize) 44825f757f3fSDimitry Andric BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), XDst) 44835f757f3fSDimitry Andric .addReg(XSrc) 44845f757f3fSDimitry Andric .addReg(ScratchReg2) 44855f757f3fSDimitry Andric .addImm(2); 44865f757f3fSDimitry Andric 44875f757f3fSDimitry Andric MI.eraseFromParent(); 44885f757f3fSDimitry Andric return BB; 44895f757f3fSDimitry Andric } 44905f757f3fSDimitry Andric 4491753f127fSDimitry Andric MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter( 4492753f127fSDimitry Andric MachineInstr &MI, MachineBasicBlock *BB) const { 4493bdd1243dSDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 4494bdd1243dSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 4495753f127fSDimitry Andric 4496753f127fSDimitry Andric switch (MI.getOpcode()) { 4497753f127fSDimitry Andric default: 4498753f127fSDimitry Andric llvm_unreachable("Unexpected instr type to insert"); 4499753f127fSDimitry Andric case LoongArch::DIV_W: 4500753f127fSDimitry Andric case LoongArch::DIV_WU: 4501753f127fSDimitry Andric case LoongArch::MOD_W: 4502753f127fSDimitry Andric case LoongArch::MOD_WU: 4503753f127fSDimitry Andric case LoongArch::DIV_D: 4504753f127fSDimitry Andric case LoongArch::DIV_DU: 4505753f127fSDimitry Andric case LoongArch::MOD_D: 4506753f127fSDimitry Andric case LoongArch::MOD_DU: 4507bdd1243dSDimitry Andric return insertDivByZeroTrap(MI, BB); 4508753f127fSDimitry Andric break; 4509bdd1243dSDimitry Andric case LoongArch::WRFCSR: { 4510bdd1243dSDimitry Andric BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR), 4511bdd1243dSDimitry Andric LoongArch::FCSR0 + MI.getOperand(0).getImm()) 4512bdd1243dSDimitry Andric .addReg(MI.getOperand(1).getReg()); 4513bdd1243dSDimitry Andric MI.eraseFromParent(); 4514bdd1243dSDimitry Andric return BB; 4515bdd1243dSDimitry Andric } 4516bdd1243dSDimitry Andric case LoongArch::RDFCSR: { 4517bdd1243dSDimitry Andric MachineInstr *ReadFCSR = 4518bdd1243dSDimitry Andric BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR), 4519bdd1243dSDimitry Andric MI.getOperand(0).getReg()) 4520bdd1243dSDimitry Andric .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm()); 4521bdd1243dSDimitry Andric ReadFCSR->getOperand(1).setIsUndef(); 4522bdd1243dSDimitry Andric MI.eraseFromParent(); 4523bdd1243dSDimitry Andric return BB; 4524bdd1243dSDimitry Andric } 45255f757f3fSDimitry Andric case LoongArch::PseudoVBZ: 45265f757f3fSDimitry Andric case LoongArch::PseudoVBZ_B: 45275f757f3fSDimitry Andric case LoongArch::PseudoVBZ_H: 45285f757f3fSDimitry Andric case LoongArch::PseudoVBZ_W: 45295f757f3fSDimitry Andric case LoongArch::PseudoVBZ_D: 45305f757f3fSDimitry Andric case LoongArch::PseudoVBNZ: 45315f757f3fSDimitry Andric case LoongArch::PseudoVBNZ_B: 45325f757f3fSDimitry Andric case LoongArch::PseudoVBNZ_H: 45335f757f3fSDimitry Andric case LoongArch::PseudoVBNZ_W: 45345f757f3fSDimitry Andric case LoongArch::PseudoVBNZ_D: 45355f757f3fSDimitry Andric case LoongArch::PseudoXVBZ: 45365f757f3fSDimitry Andric case LoongArch::PseudoXVBZ_B: 45375f757f3fSDimitry Andric case LoongArch::PseudoXVBZ_H: 45385f757f3fSDimitry Andric case LoongArch::PseudoXVBZ_W: 45395f757f3fSDimitry Andric case LoongArch::PseudoXVBZ_D: 45405f757f3fSDimitry Andric case LoongArch::PseudoXVBNZ: 45415f757f3fSDimitry Andric case LoongArch::PseudoXVBNZ_B: 45425f757f3fSDimitry Andric case LoongArch::PseudoXVBNZ_H: 45435f757f3fSDimitry Andric case LoongArch::PseudoXVBNZ_W: 45445f757f3fSDimitry Andric case LoongArch::PseudoXVBNZ_D: 45455f757f3fSDimitry Andric return emitVecCondBranchPseudo(MI, BB, Subtarget); 45465f757f3fSDimitry Andric case LoongArch::PseudoXVINSGR2VR_B: 45475f757f3fSDimitry Andric case LoongArch::PseudoXVINSGR2VR_H: 45485f757f3fSDimitry Andric return emitPseudoXVINSGR2VR(MI, BB, Subtarget); 4549753f127fSDimitry Andric } 4550753f127fSDimitry Andric } 4551753f127fSDimitry Andric 455206c3fb27SDimitry Andric bool LoongArchTargetLowering::allowsMisalignedMemoryAccesses( 455306c3fb27SDimitry Andric EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags, 455406c3fb27SDimitry Andric unsigned *Fast) const { 455506c3fb27SDimitry Andric if (!Subtarget.hasUAL()) 455606c3fb27SDimitry Andric return false; 455706c3fb27SDimitry Andric 455806c3fb27SDimitry Andric // TODO: set reasonable speed number. 455906c3fb27SDimitry Andric if (Fast) 456006c3fb27SDimitry Andric *Fast = 1; 456106c3fb27SDimitry Andric return true; 456206c3fb27SDimitry Andric } 456306c3fb27SDimitry Andric 456481ad6265SDimitry Andric const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const { 456581ad6265SDimitry Andric switch ((LoongArchISD::NodeType)Opcode) { 456681ad6265SDimitry Andric case LoongArchISD::FIRST_NUMBER: 456781ad6265SDimitry Andric break; 456881ad6265SDimitry Andric 456981ad6265SDimitry Andric #define NODE_NAME_CASE(node) \ 457081ad6265SDimitry Andric case LoongArchISD::node: \ 457181ad6265SDimitry Andric return "LoongArchISD::" #node; 457281ad6265SDimitry Andric 457381ad6265SDimitry Andric // TODO: Add more target-dependent nodes later. 4574753f127fSDimitry Andric NODE_NAME_CASE(CALL) 45751db9f3b2SDimitry Andric NODE_NAME_CASE(CALL_MEDIUM) 45761db9f3b2SDimitry Andric NODE_NAME_CASE(CALL_LARGE) 457781ad6265SDimitry Andric NODE_NAME_CASE(RET) 4578bdd1243dSDimitry Andric NODE_NAME_CASE(TAIL) 45791db9f3b2SDimitry Andric NODE_NAME_CASE(TAIL_MEDIUM) 45801db9f3b2SDimitry Andric NODE_NAME_CASE(TAIL_LARGE) 458181ad6265SDimitry Andric NODE_NAME_CASE(SLL_W) 458281ad6265SDimitry Andric NODE_NAME_CASE(SRA_W) 458381ad6265SDimitry Andric NODE_NAME_CASE(SRL_W) 4584753f127fSDimitry Andric NODE_NAME_CASE(BSTRINS) 458581ad6265SDimitry Andric NODE_NAME_CASE(BSTRPICK) 4586753f127fSDimitry Andric NODE_NAME_CASE(MOVGR2FR_W_LA64) 4587753f127fSDimitry Andric NODE_NAME_CASE(MOVFR2GR_S_LA64) 4588753f127fSDimitry Andric NODE_NAME_CASE(FTINT) 4589bdd1243dSDimitry Andric NODE_NAME_CASE(REVB_2H) 4590bdd1243dSDimitry Andric NODE_NAME_CASE(REVB_2W) 4591bdd1243dSDimitry Andric NODE_NAME_CASE(BITREV_4B) 4592bdd1243dSDimitry Andric NODE_NAME_CASE(BITREV_W) 4593bdd1243dSDimitry Andric NODE_NAME_CASE(ROTR_W) 4594bdd1243dSDimitry Andric NODE_NAME_CASE(ROTL_W) 45950fca6ea1SDimitry Andric NODE_NAME_CASE(DIV_WU) 45960fca6ea1SDimitry Andric NODE_NAME_CASE(MOD_WU) 4597bdd1243dSDimitry Andric NODE_NAME_CASE(CLZ_W) 4598bdd1243dSDimitry Andric NODE_NAME_CASE(CTZ_W) 4599bdd1243dSDimitry Andric NODE_NAME_CASE(DBAR) 4600bdd1243dSDimitry Andric NODE_NAME_CASE(IBAR) 4601bdd1243dSDimitry Andric NODE_NAME_CASE(BREAK) 4602bdd1243dSDimitry Andric NODE_NAME_CASE(SYSCALL) 4603bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_B_W) 4604bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_H_W) 4605bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_W_W) 4606bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_D_W) 4607bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_B_W) 4608bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_H_W) 4609bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_W_W) 4610bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_D_W) 4611bdd1243dSDimitry Andric NODE_NAME_CASE(CSRRD) 4612bdd1243dSDimitry Andric NODE_NAME_CASE(CSRWR) 4613bdd1243dSDimitry Andric NODE_NAME_CASE(CSRXCHG) 4614bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_B) 4615bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_H) 4616bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_W) 4617bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_D) 4618bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_B) 4619bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_H) 4620bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_W) 4621bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_D) 4622bdd1243dSDimitry Andric NODE_NAME_CASE(CPUCFG) 4623bdd1243dSDimitry Andric NODE_NAME_CASE(MOVGR2FCSR) 4624bdd1243dSDimitry Andric NODE_NAME_CASE(MOVFCSR2GR) 4625bdd1243dSDimitry Andric NODE_NAME_CASE(CACOP_D) 4626bdd1243dSDimitry Andric NODE_NAME_CASE(CACOP_W) 46270fca6ea1SDimitry Andric NODE_NAME_CASE(VSHUF) 46280fca6ea1SDimitry Andric NODE_NAME_CASE(VPICKEV) 46290fca6ea1SDimitry Andric NODE_NAME_CASE(VPICKOD) 46300fca6ea1SDimitry Andric NODE_NAME_CASE(VPACKEV) 46310fca6ea1SDimitry Andric NODE_NAME_CASE(VPACKOD) 46320fca6ea1SDimitry Andric NODE_NAME_CASE(VILVL) 46330fca6ea1SDimitry Andric NODE_NAME_CASE(VILVH) 46340fca6ea1SDimitry Andric NODE_NAME_CASE(VSHUF4I) 46350fca6ea1SDimitry Andric NODE_NAME_CASE(VREPLVEI) 46360fca6ea1SDimitry Andric NODE_NAME_CASE(XVPERMI) 46375f757f3fSDimitry Andric NODE_NAME_CASE(VPICK_SEXT_ELT) 46385f757f3fSDimitry Andric NODE_NAME_CASE(VPICK_ZEXT_ELT) 46395f757f3fSDimitry Andric NODE_NAME_CASE(VREPLVE) 46405f757f3fSDimitry Andric NODE_NAME_CASE(VALL_ZERO) 46415f757f3fSDimitry Andric NODE_NAME_CASE(VANY_ZERO) 46425f757f3fSDimitry Andric NODE_NAME_CASE(VALL_NONZERO) 46435f757f3fSDimitry Andric NODE_NAME_CASE(VANY_NONZERO) 464481ad6265SDimitry Andric } 464581ad6265SDimitry Andric #undef NODE_NAME_CASE 464681ad6265SDimitry Andric return nullptr; 464781ad6265SDimitry Andric } 464881ad6265SDimitry Andric 464981ad6265SDimitry Andric //===----------------------------------------------------------------------===// 465081ad6265SDimitry Andric // Calling Convention Implementation 465181ad6265SDimitry Andric //===----------------------------------------------------------------------===// 4652bdd1243dSDimitry Andric 4653bdd1243dSDimitry Andric // Eight general-purpose registers a0-a7 used for passing integer arguments, 4654bdd1243dSDimitry Andric // with a0-a1 reused to return values. Generally, the GPRs are used to pass 4655bdd1243dSDimitry Andric // fixed-point arguments, and floating-point arguments when no FPR is available 4656bdd1243dSDimitry Andric // or with soft float ABI. 465781ad6265SDimitry Andric const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6, 465881ad6265SDimitry Andric LoongArch::R7, LoongArch::R8, LoongArch::R9, 465981ad6265SDimitry Andric LoongArch::R10, LoongArch::R11}; 4660bdd1243dSDimitry Andric // Eight floating-point registers fa0-fa7 used for passing floating-point 4661bdd1243dSDimitry Andric // arguments, and fa0-fa1 are also used to return values. 466281ad6265SDimitry Andric const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2, 466381ad6265SDimitry Andric LoongArch::F3, LoongArch::F4, LoongArch::F5, 466481ad6265SDimitry Andric LoongArch::F6, LoongArch::F7}; 4665bdd1243dSDimitry Andric // FPR32 and FPR64 alias each other. 466681ad6265SDimitry Andric const MCPhysReg ArgFPR64s[] = { 466781ad6265SDimitry Andric LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64, 466881ad6265SDimitry Andric LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64}; 466981ad6265SDimitry Andric 46705f757f3fSDimitry Andric const MCPhysReg ArgVRs[] = {LoongArch::VR0, LoongArch::VR1, LoongArch::VR2, 46715f757f3fSDimitry Andric LoongArch::VR3, LoongArch::VR4, LoongArch::VR5, 46725f757f3fSDimitry Andric LoongArch::VR6, LoongArch::VR7}; 46735f757f3fSDimitry Andric 46745f757f3fSDimitry Andric const MCPhysReg ArgXRs[] = {LoongArch::XR0, LoongArch::XR1, LoongArch::XR2, 46755f757f3fSDimitry Andric LoongArch::XR3, LoongArch::XR4, LoongArch::XR5, 46765f757f3fSDimitry Andric LoongArch::XR6, LoongArch::XR7}; 46775f757f3fSDimitry Andric 4678bdd1243dSDimitry Andric // Pass a 2*GRLen argument that has been split into two GRLen values through 4679bdd1243dSDimitry Andric // registers or the stack as necessary. 4680bdd1243dSDimitry Andric static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State, 4681bdd1243dSDimitry Andric CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1, 4682bdd1243dSDimitry Andric unsigned ValNo2, MVT ValVT2, MVT LocVT2, 4683bdd1243dSDimitry Andric ISD::ArgFlagsTy ArgFlags2) { 4684bdd1243dSDimitry Andric unsigned GRLenInBytes = GRLen / 8; 4685bdd1243dSDimitry Andric if (Register Reg = State.AllocateReg(ArgGPRs)) { 4686bdd1243dSDimitry Andric // At least one half can be passed via register. 4687bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg, 4688bdd1243dSDimitry Andric VA1.getLocVT(), CCValAssign::Full)); 4689bdd1243dSDimitry Andric } else { 4690bdd1243dSDimitry Andric // Both halves must be passed on the stack, with proper alignment. 4691bdd1243dSDimitry Andric Align StackAlign = 4692bdd1243dSDimitry Andric std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign()); 4693bdd1243dSDimitry Andric State.addLoc( 4694bdd1243dSDimitry Andric CCValAssign::getMem(VA1.getValNo(), VA1.getValVT(), 4695bdd1243dSDimitry Andric State.AllocateStack(GRLenInBytes, StackAlign), 4696bdd1243dSDimitry Andric VA1.getLocVT(), CCValAssign::Full)); 4697bdd1243dSDimitry Andric State.addLoc(CCValAssign::getMem( 4698bdd1243dSDimitry Andric ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)), 4699bdd1243dSDimitry Andric LocVT2, CCValAssign::Full)); 4700bdd1243dSDimitry Andric return false; 4701bdd1243dSDimitry Andric } 4702bdd1243dSDimitry Andric if (Register Reg = State.AllocateReg(ArgGPRs)) { 4703bdd1243dSDimitry Andric // The second half can also be passed via register. 4704bdd1243dSDimitry Andric State.addLoc( 4705bdd1243dSDimitry Andric CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full)); 4706bdd1243dSDimitry Andric } else { 4707bdd1243dSDimitry Andric // The second half is passed via the stack, without additional alignment. 4708bdd1243dSDimitry Andric State.addLoc(CCValAssign::getMem( 4709bdd1243dSDimitry Andric ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)), 4710bdd1243dSDimitry Andric LocVT2, CCValAssign::Full)); 4711bdd1243dSDimitry Andric } 471281ad6265SDimitry Andric return false; 471381ad6265SDimitry Andric } 471481ad6265SDimitry Andric 4715bdd1243dSDimitry Andric // Implements the LoongArch calling convention. Returns true upon failure. 4716bdd1243dSDimitry Andric static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI, 4717bdd1243dSDimitry Andric unsigned ValNo, MVT ValVT, 4718bdd1243dSDimitry Andric CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, 4719bdd1243dSDimitry Andric CCState &State, bool IsFixed, bool IsRet, 4720bdd1243dSDimitry Andric Type *OrigTy) { 4721bdd1243dSDimitry Andric unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits(); 4722bdd1243dSDimitry Andric assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen"); 4723bdd1243dSDimitry Andric MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64; 4724bdd1243dSDimitry Andric MVT LocVT = ValVT; 4725bdd1243dSDimitry Andric 4726bdd1243dSDimitry Andric // Any return value split into more than two values can't be returned 4727bdd1243dSDimitry Andric // directly. 4728bdd1243dSDimitry Andric if (IsRet && ValNo > 1) 472981ad6265SDimitry Andric return true; 4730bdd1243dSDimitry Andric 4731bdd1243dSDimitry Andric // If passing a variadic argument, or if no FPR is available. 4732bdd1243dSDimitry Andric bool UseGPRForFloat = true; 4733bdd1243dSDimitry Andric 4734bdd1243dSDimitry Andric switch (ABI) { 4735bdd1243dSDimitry Andric default: 4736bdd1243dSDimitry Andric llvm_unreachable("Unexpected ABI"); 47370fca6ea1SDimitry Andric break; 4738bdd1243dSDimitry Andric case LoongArchABI::ABI_ILP32F: 4739bdd1243dSDimitry Andric case LoongArchABI::ABI_LP64F: 4740bdd1243dSDimitry Andric case LoongArchABI::ABI_ILP32D: 4741bdd1243dSDimitry Andric case LoongArchABI::ABI_LP64D: 4742bdd1243dSDimitry Andric UseGPRForFloat = !IsFixed; 4743bdd1243dSDimitry Andric break; 47440fca6ea1SDimitry Andric case LoongArchABI::ABI_ILP32S: 474506c3fb27SDimitry Andric case LoongArchABI::ABI_LP64S: 474606c3fb27SDimitry Andric break; 4747bdd1243dSDimitry Andric } 4748bdd1243dSDimitry Andric 4749bdd1243dSDimitry Andric // FPR32 and FPR64 alias each other. 4750bdd1243dSDimitry Andric if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s)) 4751bdd1243dSDimitry Andric UseGPRForFloat = true; 4752bdd1243dSDimitry Andric 4753bdd1243dSDimitry Andric if (UseGPRForFloat && ValVT == MVT::f32) { 4754bdd1243dSDimitry Andric LocVT = GRLenVT; 4755bdd1243dSDimitry Andric LocInfo = CCValAssign::BCvt; 4756bdd1243dSDimitry Andric } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) { 4757bdd1243dSDimitry Andric LocVT = MVT::i64; 4758bdd1243dSDimitry Andric LocInfo = CCValAssign::BCvt; 4759bdd1243dSDimitry Andric } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) { 4760bdd1243dSDimitry Andric // TODO: Handle passing f64 on LA32 with D feature. 4761bdd1243dSDimitry Andric report_fatal_error("Passing f64 with GPR on LA32 is undefined"); 4762bdd1243dSDimitry Andric } 4763bdd1243dSDimitry Andric 4764bdd1243dSDimitry Andric // If this is a variadic argument, the LoongArch calling convention requires 4765bdd1243dSDimitry Andric // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8 4766bdd1243dSDimitry Andric // byte alignment. An aligned register should be used regardless of whether 4767bdd1243dSDimitry Andric // the original argument was split during legalisation or not. The argument 4768bdd1243dSDimitry Andric // will not be passed by registers if the original type is larger than 4769bdd1243dSDimitry Andric // 2*GRLen, so the register alignment rule does not apply. 4770bdd1243dSDimitry Andric unsigned TwoGRLenInBytes = (2 * GRLen) / 8; 4771bdd1243dSDimitry Andric if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes && 4772bdd1243dSDimitry Andric DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) { 4773bdd1243dSDimitry Andric unsigned RegIdx = State.getFirstUnallocated(ArgGPRs); 4774bdd1243dSDimitry Andric // Skip 'odd' register if necessary. 4775bdd1243dSDimitry Andric if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1) 4776bdd1243dSDimitry Andric State.AllocateReg(ArgGPRs); 4777bdd1243dSDimitry Andric } 4778bdd1243dSDimitry Andric 4779bdd1243dSDimitry Andric SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs(); 4780bdd1243dSDimitry Andric SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags = 4781bdd1243dSDimitry Andric State.getPendingArgFlags(); 4782bdd1243dSDimitry Andric 4783bdd1243dSDimitry Andric assert(PendingLocs.size() == PendingArgFlags.size() && 4784bdd1243dSDimitry Andric "PendingLocs and PendingArgFlags out of sync"); 4785bdd1243dSDimitry Andric 4786bdd1243dSDimitry Andric // Split arguments might be passed indirectly, so keep track of the pending 4787bdd1243dSDimitry Andric // values. 4788bdd1243dSDimitry Andric if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) { 4789bdd1243dSDimitry Andric LocVT = GRLenVT; 4790bdd1243dSDimitry Andric LocInfo = CCValAssign::Indirect; 4791bdd1243dSDimitry Andric PendingLocs.push_back( 4792bdd1243dSDimitry Andric CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo)); 4793bdd1243dSDimitry Andric PendingArgFlags.push_back(ArgFlags); 4794bdd1243dSDimitry Andric if (!ArgFlags.isSplitEnd()) { 4795bdd1243dSDimitry Andric return false; 4796bdd1243dSDimitry Andric } 4797bdd1243dSDimitry Andric } 4798bdd1243dSDimitry Andric 4799bdd1243dSDimitry Andric // If the split argument only had two elements, it should be passed directly 4800bdd1243dSDimitry Andric // in registers or on the stack. 4801bdd1243dSDimitry Andric if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() && 4802bdd1243dSDimitry Andric PendingLocs.size() <= 2) { 4803bdd1243dSDimitry Andric assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()"); 4804bdd1243dSDimitry Andric // Apply the normal calling convention rules to the first half of the 4805bdd1243dSDimitry Andric // split argument. 4806bdd1243dSDimitry Andric CCValAssign VA = PendingLocs[0]; 4807bdd1243dSDimitry Andric ISD::ArgFlagsTy AF = PendingArgFlags[0]; 4808bdd1243dSDimitry Andric PendingLocs.clear(); 4809bdd1243dSDimitry Andric PendingArgFlags.clear(); 4810bdd1243dSDimitry Andric return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT, 4811bdd1243dSDimitry Andric ArgFlags); 4812bdd1243dSDimitry Andric } 4813bdd1243dSDimitry Andric 4814bdd1243dSDimitry Andric // Allocate to a register if possible, or else a stack slot. 4815bdd1243dSDimitry Andric Register Reg; 4816bdd1243dSDimitry Andric unsigned StoreSizeBytes = GRLen / 8; 4817bdd1243dSDimitry Andric Align StackAlign = Align(GRLen / 8); 4818bdd1243dSDimitry Andric 4819bdd1243dSDimitry Andric if (ValVT == MVT::f32 && !UseGPRForFloat) 4820bdd1243dSDimitry Andric Reg = State.AllocateReg(ArgFPR32s); 4821bdd1243dSDimitry Andric else if (ValVT == MVT::f64 && !UseGPRForFloat) 4822bdd1243dSDimitry Andric Reg = State.AllocateReg(ArgFPR64s); 48235f757f3fSDimitry Andric else if (ValVT.is128BitVector()) 48245f757f3fSDimitry Andric Reg = State.AllocateReg(ArgVRs); 48255f757f3fSDimitry Andric else if (ValVT.is256BitVector()) 48265f757f3fSDimitry Andric Reg = State.AllocateReg(ArgXRs); 4827bdd1243dSDimitry Andric else 4828bdd1243dSDimitry Andric Reg = State.AllocateReg(ArgGPRs); 4829bdd1243dSDimitry Andric 4830bdd1243dSDimitry Andric unsigned StackOffset = 4831bdd1243dSDimitry Andric Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign); 4832bdd1243dSDimitry Andric 4833bdd1243dSDimitry Andric // If we reach this point and PendingLocs is non-empty, we must be at the 4834bdd1243dSDimitry Andric // end of a split argument that must be passed indirectly. 4835bdd1243dSDimitry Andric if (!PendingLocs.empty()) { 4836bdd1243dSDimitry Andric assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()"); 4837bdd1243dSDimitry Andric assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()"); 4838bdd1243dSDimitry Andric for (auto &It : PendingLocs) { 4839bdd1243dSDimitry Andric if (Reg) 4840bdd1243dSDimitry Andric It.convertToReg(Reg); 4841bdd1243dSDimitry Andric else 4842bdd1243dSDimitry Andric It.convertToMem(StackOffset); 4843bdd1243dSDimitry Andric State.addLoc(It); 4844bdd1243dSDimitry Andric } 4845bdd1243dSDimitry Andric PendingLocs.clear(); 4846bdd1243dSDimitry Andric PendingArgFlags.clear(); 4847bdd1243dSDimitry Andric return false; 4848bdd1243dSDimitry Andric } 4849bdd1243dSDimitry Andric assert((!UseGPRForFloat || LocVT == GRLenVT) && 4850bdd1243dSDimitry Andric "Expected an GRLenVT at this stage"); 4851bdd1243dSDimitry Andric 4852bdd1243dSDimitry Andric if (Reg) { 4853bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 4854bdd1243dSDimitry Andric return false; 4855bdd1243dSDimitry Andric } 4856bdd1243dSDimitry Andric 4857bdd1243dSDimitry Andric // When a floating-point value is passed on the stack, no bit-cast is needed. 4858bdd1243dSDimitry Andric if (ValVT.isFloatingPoint()) { 4859bdd1243dSDimitry Andric LocVT = ValVT; 4860bdd1243dSDimitry Andric LocInfo = CCValAssign::Full; 4861bdd1243dSDimitry Andric } 4862bdd1243dSDimitry Andric 4863bdd1243dSDimitry Andric State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo)); 4864bdd1243dSDimitry Andric return false; 486581ad6265SDimitry Andric } 486681ad6265SDimitry Andric 486781ad6265SDimitry Andric void LoongArchTargetLowering::analyzeInputArgs( 4868bdd1243dSDimitry Andric MachineFunction &MF, CCState &CCInfo, 4869bdd1243dSDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet, 487081ad6265SDimitry Andric LoongArchCCAssignFn Fn) const { 4871bdd1243dSDimitry Andric FunctionType *FType = MF.getFunction().getFunctionType(); 487281ad6265SDimitry Andric for (unsigned i = 0, e = Ins.size(); i != e; ++i) { 487381ad6265SDimitry Andric MVT ArgVT = Ins[i].VT; 4874bdd1243dSDimitry Andric Type *ArgTy = nullptr; 4875bdd1243dSDimitry Andric if (IsRet) 4876bdd1243dSDimitry Andric ArgTy = FType->getReturnType(); 4877bdd1243dSDimitry Andric else if (Ins[i].isOrigArg()) 4878bdd1243dSDimitry Andric ArgTy = FType->getParamType(Ins[i].getOrigArgIndex()); 4879bdd1243dSDimitry Andric LoongArchABI::ABI ABI = 4880bdd1243dSDimitry Andric MF.getSubtarget<LoongArchSubtarget>().getTargetABI(); 4881bdd1243dSDimitry Andric if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags, 4882bdd1243dSDimitry Andric CCInfo, /*IsFixed=*/true, IsRet, ArgTy)) { 488306c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT 488406c3fb27SDimitry Andric << '\n'); 488581ad6265SDimitry Andric llvm_unreachable(""); 488681ad6265SDimitry Andric } 488781ad6265SDimitry Andric } 488881ad6265SDimitry Andric } 488981ad6265SDimitry Andric 489081ad6265SDimitry Andric void LoongArchTargetLowering::analyzeOutputArgs( 4891bdd1243dSDimitry Andric MachineFunction &MF, CCState &CCInfo, 4892bdd1243dSDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet, 4893bdd1243dSDimitry Andric CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const { 489481ad6265SDimitry Andric for (unsigned i = 0, e = Outs.size(); i != e; ++i) { 489581ad6265SDimitry Andric MVT ArgVT = Outs[i].VT; 4896bdd1243dSDimitry Andric Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr; 4897bdd1243dSDimitry Andric LoongArchABI::ABI ABI = 4898bdd1243dSDimitry Andric MF.getSubtarget<LoongArchSubtarget>().getTargetABI(); 4899bdd1243dSDimitry Andric if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags, 4900bdd1243dSDimitry Andric CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) { 490106c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT 490206c3fb27SDimitry Andric << "\n"); 490381ad6265SDimitry Andric llvm_unreachable(""); 490481ad6265SDimitry Andric } 490581ad6265SDimitry Andric } 490681ad6265SDimitry Andric } 490781ad6265SDimitry Andric 4908bdd1243dSDimitry Andric // Convert Val to a ValVT. Should not be called for CCValAssign::Indirect 4909bdd1243dSDimitry Andric // values. 4910bdd1243dSDimitry Andric static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, 4911bdd1243dSDimitry Andric const CCValAssign &VA, const SDLoc &DL) { 4912bdd1243dSDimitry Andric switch (VA.getLocInfo()) { 4913bdd1243dSDimitry Andric default: 4914bdd1243dSDimitry Andric llvm_unreachable("Unexpected CCValAssign::LocInfo"); 4915bdd1243dSDimitry Andric case CCValAssign::Full: 4916bdd1243dSDimitry Andric case CCValAssign::Indirect: 4917bdd1243dSDimitry Andric break; 4918bdd1243dSDimitry Andric case CCValAssign::BCvt: 4919bdd1243dSDimitry Andric if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) 4920bdd1243dSDimitry Andric Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val); 4921bdd1243dSDimitry Andric else 4922bdd1243dSDimitry Andric Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val); 4923bdd1243dSDimitry Andric break; 4924bdd1243dSDimitry Andric } 4925bdd1243dSDimitry Andric return Val; 4926bdd1243dSDimitry Andric } 4927bdd1243dSDimitry Andric 492881ad6265SDimitry Andric static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain, 492981ad6265SDimitry Andric const CCValAssign &VA, const SDLoc &DL, 49300fca6ea1SDimitry Andric const ISD::InputArg &In, 493181ad6265SDimitry Andric const LoongArchTargetLowering &TLI) { 493281ad6265SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 493381ad6265SDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 493481ad6265SDimitry Andric EVT LocVT = VA.getLocVT(); 4935bdd1243dSDimitry Andric SDValue Val; 493681ad6265SDimitry Andric const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT()); 493781ad6265SDimitry Andric Register VReg = RegInfo.createVirtualRegister(RC); 493881ad6265SDimitry Andric RegInfo.addLiveIn(VA.getLocReg(), VReg); 4939bdd1243dSDimitry Andric Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT); 494081ad6265SDimitry Andric 49410fca6ea1SDimitry Andric // If input is sign extended from 32 bits, note it for the OptW pass. 49420fca6ea1SDimitry Andric if (In.isOrigArg()) { 49430fca6ea1SDimitry Andric Argument *OrigArg = MF.getFunction().getArg(In.getOrigArgIndex()); 49440fca6ea1SDimitry Andric if (OrigArg->getType()->isIntegerTy()) { 49450fca6ea1SDimitry Andric unsigned BitWidth = OrigArg->getType()->getIntegerBitWidth(); 49460fca6ea1SDimitry Andric // An input zero extended from i31 can also be considered sign extended. 49470fca6ea1SDimitry Andric if ((BitWidth <= 32 && In.Flags.isSExt()) || 49480fca6ea1SDimitry Andric (BitWidth < 32 && In.Flags.isZExt())) { 49490fca6ea1SDimitry Andric LoongArchMachineFunctionInfo *LAFI = 49500fca6ea1SDimitry Andric MF.getInfo<LoongArchMachineFunctionInfo>(); 49510fca6ea1SDimitry Andric LAFI->addSExt32Register(VReg); 49520fca6ea1SDimitry Andric } 49530fca6ea1SDimitry Andric } 49540fca6ea1SDimitry Andric } 49550fca6ea1SDimitry Andric 4956bdd1243dSDimitry Andric return convertLocVTToValVT(DAG, Val, VA, DL); 4957bdd1243dSDimitry Andric } 4958bdd1243dSDimitry Andric 4959bdd1243dSDimitry Andric // The caller is responsible for loading the full value if the argument is 4960bdd1243dSDimitry Andric // passed with CCValAssign::Indirect. 4961bdd1243dSDimitry Andric static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, 4962bdd1243dSDimitry Andric const CCValAssign &VA, const SDLoc &DL) { 4963bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 4964bdd1243dSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 4965bdd1243dSDimitry Andric EVT ValVT = VA.getValVT(); 4966bdd1243dSDimitry Andric int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(), 4967bdd1243dSDimitry Andric /*IsImmutable=*/true); 4968bdd1243dSDimitry Andric SDValue FIN = DAG.getFrameIndex( 4969bdd1243dSDimitry Andric FI, MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0))); 4970bdd1243dSDimitry Andric 4971bdd1243dSDimitry Andric ISD::LoadExtType ExtType; 4972bdd1243dSDimitry Andric switch (VA.getLocInfo()) { 4973bdd1243dSDimitry Andric default: 4974bdd1243dSDimitry Andric llvm_unreachable("Unexpected CCValAssign::LocInfo"); 4975bdd1243dSDimitry Andric case CCValAssign::Full: 4976bdd1243dSDimitry Andric case CCValAssign::Indirect: 4977bdd1243dSDimitry Andric case CCValAssign::BCvt: 4978bdd1243dSDimitry Andric ExtType = ISD::NON_EXTLOAD; 4979bdd1243dSDimitry Andric break; 4980bdd1243dSDimitry Andric } 4981bdd1243dSDimitry Andric return DAG.getExtLoad( 4982bdd1243dSDimitry Andric ExtType, DL, VA.getLocVT(), Chain, FIN, 4983bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT); 4984bdd1243dSDimitry Andric } 4985bdd1243dSDimitry Andric 4986bdd1243dSDimitry Andric static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, 4987bdd1243dSDimitry Andric const CCValAssign &VA, const SDLoc &DL) { 4988bdd1243dSDimitry Andric EVT LocVT = VA.getLocVT(); 4989bdd1243dSDimitry Andric 4990bdd1243dSDimitry Andric switch (VA.getLocInfo()) { 4991bdd1243dSDimitry Andric default: 4992bdd1243dSDimitry Andric llvm_unreachable("Unexpected CCValAssign::LocInfo"); 4993bdd1243dSDimitry Andric case CCValAssign::Full: 4994bdd1243dSDimitry Andric break; 4995bdd1243dSDimitry Andric case CCValAssign::BCvt: 4996bdd1243dSDimitry Andric if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) 4997bdd1243dSDimitry Andric Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val); 4998bdd1243dSDimitry Andric else 4999bdd1243dSDimitry Andric Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val); 5000bdd1243dSDimitry Andric break; 5001bdd1243dSDimitry Andric } 5002bdd1243dSDimitry Andric return Val; 5003bdd1243dSDimitry Andric } 5004bdd1243dSDimitry Andric 5005bdd1243dSDimitry Andric static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, 5006bdd1243dSDimitry Andric CCValAssign::LocInfo LocInfo, 5007bdd1243dSDimitry Andric ISD::ArgFlagsTy ArgFlags, CCState &State) { 5008bdd1243dSDimitry Andric if (LocVT == MVT::i32 || LocVT == MVT::i64) { 5009bdd1243dSDimitry Andric // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim 5010bdd1243dSDimitry Andric // s0 s1 s2 s3 s4 s5 s6 s7 s8 5011bdd1243dSDimitry Andric static const MCPhysReg GPRList[] = { 501206c3fb27SDimitry Andric LoongArch::R23, LoongArch::R24, LoongArch::R25, 501306c3fb27SDimitry Andric LoongArch::R26, LoongArch::R27, LoongArch::R28, 501406c3fb27SDimitry Andric LoongArch::R29, LoongArch::R30, LoongArch::R31}; 5015bdd1243dSDimitry Andric if (unsigned Reg = State.AllocateReg(GPRList)) { 5016bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 5017bdd1243dSDimitry Andric return false; 5018bdd1243dSDimitry Andric } 5019bdd1243dSDimitry Andric } 5020bdd1243dSDimitry Andric 5021bdd1243dSDimitry Andric if (LocVT == MVT::f32) { 5022bdd1243dSDimitry Andric // Pass in STG registers: F1, F2, F3, F4 5023bdd1243dSDimitry Andric // fs0,fs1,fs2,fs3 5024bdd1243dSDimitry Andric static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25, 5025bdd1243dSDimitry Andric LoongArch::F26, LoongArch::F27}; 5026bdd1243dSDimitry Andric if (unsigned Reg = State.AllocateReg(FPR32List)) { 5027bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 5028bdd1243dSDimitry Andric return false; 5029bdd1243dSDimitry Andric } 5030bdd1243dSDimitry Andric } 5031bdd1243dSDimitry Andric 5032bdd1243dSDimitry Andric if (LocVT == MVT::f64) { 5033bdd1243dSDimitry Andric // Pass in STG registers: D1, D2, D3, D4 5034bdd1243dSDimitry Andric // fs4,fs5,fs6,fs7 5035bdd1243dSDimitry Andric static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64, 5036bdd1243dSDimitry Andric LoongArch::F30_64, LoongArch::F31_64}; 5037bdd1243dSDimitry Andric if (unsigned Reg = State.AllocateReg(FPR64List)) { 5038bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 5039bdd1243dSDimitry Andric return false; 5040bdd1243dSDimitry Andric } 5041bdd1243dSDimitry Andric } 5042bdd1243dSDimitry Andric 5043bdd1243dSDimitry Andric report_fatal_error("No registers left in GHC calling convention"); 5044bdd1243dSDimitry Andric return true; 504581ad6265SDimitry Andric } 504681ad6265SDimitry Andric 504781ad6265SDimitry Andric // Transform physical registers into virtual registers. 504881ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerFormalArguments( 504981ad6265SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 505081ad6265SDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 505181ad6265SDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 505281ad6265SDimitry Andric 505381ad6265SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 505481ad6265SDimitry Andric 505581ad6265SDimitry Andric switch (CallConv) { 505681ad6265SDimitry Andric default: 505781ad6265SDimitry Andric llvm_unreachable("Unsupported calling convention"); 505881ad6265SDimitry Andric case CallingConv::C: 5059bdd1243dSDimitry Andric case CallingConv::Fast: 506081ad6265SDimitry Andric break; 5061bdd1243dSDimitry Andric case CallingConv::GHC: 506206c3fb27SDimitry Andric if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) || 506306c3fb27SDimitry Andric !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD)) 5064bdd1243dSDimitry Andric report_fatal_error( 5065bdd1243dSDimitry Andric "GHC calling convention requires the F and D extensions"); 506681ad6265SDimitry Andric } 506781ad6265SDimitry Andric 5068bdd1243dSDimitry Andric EVT PtrVT = getPointerTy(DAG.getDataLayout()); 5069bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 5070bdd1243dSDimitry Andric unsigned GRLenInBytes = Subtarget.getGRLen() / 8; 5071bdd1243dSDimitry Andric // Used with varargs to acumulate store chains. 5072bdd1243dSDimitry Andric std::vector<SDValue> OutChains; 5073bdd1243dSDimitry Andric 507481ad6265SDimitry Andric // Assign locations to all of the incoming arguments. 507581ad6265SDimitry Andric SmallVector<CCValAssign> ArgLocs; 507681ad6265SDimitry Andric CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 507781ad6265SDimitry Andric 5078bdd1243dSDimitry Andric if (CallConv == CallingConv::GHC) 5079bdd1243dSDimitry Andric CCInfo.AnalyzeFormalArguments(Ins, CC_LoongArch_GHC); 5080bdd1243dSDimitry Andric else 5081bdd1243dSDimitry Andric analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch); 508281ad6265SDimitry Andric 5083bdd1243dSDimitry Andric for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { 5084bdd1243dSDimitry Andric CCValAssign &VA = ArgLocs[i]; 5085bdd1243dSDimitry Andric SDValue ArgValue; 5086bdd1243dSDimitry Andric if (VA.isRegLoc()) 50870fca6ea1SDimitry Andric ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, Ins[i], *this); 5088bdd1243dSDimitry Andric else 5089bdd1243dSDimitry Andric ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL); 5090bdd1243dSDimitry Andric if (VA.getLocInfo() == CCValAssign::Indirect) { 5091bdd1243dSDimitry Andric // If the original argument was split and passed by reference, we need to 5092bdd1243dSDimitry Andric // load all parts of it here (using the same address). 5093bdd1243dSDimitry Andric InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue, 5094bdd1243dSDimitry Andric MachinePointerInfo())); 5095bdd1243dSDimitry Andric unsigned ArgIndex = Ins[i].OrigArgIndex; 5096bdd1243dSDimitry Andric unsigned ArgPartOffset = Ins[i].PartOffset; 5097bdd1243dSDimitry Andric assert(ArgPartOffset == 0); 5098bdd1243dSDimitry Andric while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) { 5099bdd1243dSDimitry Andric CCValAssign &PartVA = ArgLocs[i + 1]; 5100bdd1243dSDimitry Andric unsigned PartOffset = Ins[i + 1].PartOffset - ArgPartOffset; 5101bdd1243dSDimitry Andric SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL); 5102bdd1243dSDimitry Andric SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset); 5103bdd1243dSDimitry Andric InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address, 5104bdd1243dSDimitry Andric MachinePointerInfo())); 5105bdd1243dSDimitry Andric ++i; 5106bdd1243dSDimitry Andric } 5107bdd1243dSDimitry Andric continue; 5108bdd1243dSDimitry Andric } 5109bdd1243dSDimitry Andric InVals.push_back(ArgValue); 5110bdd1243dSDimitry Andric } 5111bdd1243dSDimitry Andric 5112bdd1243dSDimitry Andric if (IsVarArg) { 5113bdd1243dSDimitry Andric ArrayRef<MCPhysReg> ArgRegs = ArrayRef(ArgGPRs); 5114bdd1243dSDimitry Andric unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs); 5115bdd1243dSDimitry Andric const TargetRegisterClass *RC = &LoongArch::GPRRegClass; 5116bdd1243dSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 5117bdd1243dSDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 5118bdd1243dSDimitry Andric auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); 5119bdd1243dSDimitry Andric 5120bdd1243dSDimitry Andric // Offset of the first variable argument from stack pointer, and size of 5121bdd1243dSDimitry Andric // the vararg save area. For now, the varargs save area is either zero or 5122bdd1243dSDimitry Andric // large enough to hold a0-a7. 5123bdd1243dSDimitry Andric int VaArgOffset, VarArgsSaveSize; 5124bdd1243dSDimitry Andric 5125bdd1243dSDimitry Andric // If all registers are allocated, then all varargs must be passed on the 5126bdd1243dSDimitry Andric // stack and we don't need to save any argregs. 5127bdd1243dSDimitry Andric if (ArgRegs.size() == Idx) { 512806c3fb27SDimitry Andric VaArgOffset = CCInfo.getStackSize(); 5129bdd1243dSDimitry Andric VarArgsSaveSize = 0; 5130bdd1243dSDimitry Andric } else { 5131bdd1243dSDimitry Andric VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx); 5132bdd1243dSDimitry Andric VaArgOffset = -VarArgsSaveSize; 5133bdd1243dSDimitry Andric } 5134bdd1243dSDimitry Andric 5135bdd1243dSDimitry Andric // Record the frame index of the first variable argument 5136bdd1243dSDimitry Andric // which is a value necessary to VASTART. 5137bdd1243dSDimitry Andric int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true); 5138bdd1243dSDimitry Andric LoongArchFI->setVarArgsFrameIndex(FI); 5139bdd1243dSDimitry Andric 5140bdd1243dSDimitry Andric // If saving an odd number of registers then create an extra stack slot to 5141bdd1243dSDimitry Andric // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures 5142bdd1243dSDimitry Andric // offsets to even-numbered registered remain 2*GRLen-aligned. 5143bdd1243dSDimitry Andric if (Idx % 2) { 5144bdd1243dSDimitry Andric MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes, 5145bdd1243dSDimitry Andric true); 5146bdd1243dSDimitry Andric VarArgsSaveSize += GRLenInBytes; 5147bdd1243dSDimitry Andric } 5148bdd1243dSDimitry Andric 5149bdd1243dSDimitry Andric // Copy the integer registers that may have been used for passing varargs 5150bdd1243dSDimitry Andric // to the vararg save area. 5151bdd1243dSDimitry Andric for (unsigned I = Idx; I < ArgRegs.size(); 5152bdd1243dSDimitry Andric ++I, VaArgOffset += GRLenInBytes) { 5153bdd1243dSDimitry Andric const Register Reg = RegInfo.createVirtualRegister(RC); 5154bdd1243dSDimitry Andric RegInfo.addLiveIn(ArgRegs[I], Reg); 5155bdd1243dSDimitry Andric SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT); 5156bdd1243dSDimitry Andric FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true); 5157bdd1243dSDimitry Andric SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 5158bdd1243dSDimitry Andric SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff, 5159bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(MF, FI)); 5160bdd1243dSDimitry Andric cast<StoreSDNode>(Store.getNode()) 5161bdd1243dSDimitry Andric ->getMemOperand() 5162bdd1243dSDimitry Andric ->setValue((Value *)nullptr); 5163bdd1243dSDimitry Andric OutChains.push_back(Store); 5164bdd1243dSDimitry Andric } 5165bdd1243dSDimitry Andric LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize); 5166bdd1243dSDimitry Andric } 5167bdd1243dSDimitry Andric 5168bdd1243dSDimitry Andric // All stores are grouped in one node to allow the matching between 5169bdd1243dSDimitry Andric // the size of Ins and InVals. This only happens for vararg functions. 5170bdd1243dSDimitry Andric if (!OutChains.empty()) { 5171bdd1243dSDimitry Andric OutChains.push_back(Chain); 5172bdd1243dSDimitry Andric Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); 5173bdd1243dSDimitry Andric } 517481ad6265SDimitry Andric 517581ad6265SDimitry Andric return Chain; 517681ad6265SDimitry Andric } 517781ad6265SDimitry Andric 5178bdd1243dSDimitry Andric bool LoongArchTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const { 5179bdd1243dSDimitry Andric return CI->isTailCall(); 5180bdd1243dSDimitry Andric } 5181bdd1243dSDimitry Andric 518206c3fb27SDimitry Andric // Check if the return value is used as only a return value, as otherwise 518306c3fb27SDimitry Andric // we can't perform a tail-call. 518406c3fb27SDimitry Andric bool LoongArchTargetLowering::isUsedByReturnOnly(SDNode *N, 518506c3fb27SDimitry Andric SDValue &Chain) const { 518606c3fb27SDimitry Andric if (N->getNumValues() != 1) 518706c3fb27SDimitry Andric return false; 518806c3fb27SDimitry Andric if (!N->hasNUsesOfValue(1, 0)) 518906c3fb27SDimitry Andric return false; 519006c3fb27SDimitry Andric 519106c3fb27SDimitry Andric SDNode *Copy = *N->use_begin(); 519206c3fb27SDimitry Andric if (Copy->getOpcode() != ISD::CopyToReg) 519306c3fb27SDimitry Andric return false; 519406c3fb27SDimitry Andric 519506c3fb27SDimitry Andric // If the ISD::CopyToReg has a glue operand, we conservatively assume it 519606c3fb27SDimitry Andric // isn't safe to perform a tail call. 519706c3fb27SDimitry Andric if (Copy->getGluedNode()) 519806c3fb27SDimitry Andric return false; 519906c3fb27SDimitry Andric 520006c3fb27SDimitry Andric // The copy must be used by a LoongArchISD::RET, and nothing else. 520106c3fb27SDimitry Andric bool HasRet = false; 520206c3fb27SDimitry Andric for (SDNode *Node : Copy->uses()) { 520306c3fb27SDimitry Andric if (Node->getOpcode() != LoongArchISD::RET) 520406c3fb27SDimitry Andric return false; 520506c3fb27SDimitry Andric HasRet = true; 520606c3fb27SDimitry Andric } 520706c3fb27SDimitry Andric 520806c3fb27SDimitry Andric if (!HasRet) 520906c3fb27SDimitry Andric return false; 521006c3fb27SDimitry Andric 521106c3fb27SDimitry Andric Chain = Copy->getOperand(0); 521206c3fb27SDimitry Andric return true; 521306c3fb27SDimitry Andric } 521406c3fb27SDimitry Andric 5215bdd1243dSDimitry Andric // Check whether the call is eligible for tail call optimization. 5216bdd1243dSDimitry Andric bool LoongArchTargetLowering::isEligibleForTailCallOptimization( 5217bdd1243dSDimitry Andric CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF, 5218bdd1243dSDimitry Andric const SmallVectorImpl<CCValAssign> &ArgLocs) const { 5219bdd1243dSDimitry Andric 5220bdd1243dSDimitry Andric auto CalleeCC = CLI.CallConv; 5221bdd1243dSDimitry Andric auto &Outs = CLI.Outs; 5222bdd1243dSDimitry Andric auto &Caller = MF.getFunction(); 5223bdd1243dSDimitry Andric auto CallerCC = Caller.getCallingConv(); 5224bdd1243dSDimitry Andric 5225bdd1243dSDimitry Andric // Do not tail call opt if the stack is used to pass parameters. 522606c3fb27SDimitry Andric if (CCInfo.getStackSize() != 0) 5227bdd1243dSDimitry Andric return false; 5228bdd1243dSDimitry Andric 5229bdd1243dSDimitry Andric // Do not tail call opt if any parameters need to be passed indirectly. 5230bdd1243dSDimitry Andric for (auto &VA : ArgLocs) 5231bdd1243dSDimitry Andric if (VA.getLocInfo() == CCValAssign::Indirect) 5232bdd1243dSDimitry Andric return false; 5233bdd1243dSDimitry Andric 5234bdd1243dSDimitry Andric // Do not tail call opt if either caller or callee uses struct return 5235bdd1243dSDimitry Andric // semantics. 5236bdd1243dSDimitry Andric auto IsCallerStructRet = Caller.hasStructRetAttr(); 5237bdd1243dSDimitry Andric auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet(); 5238bdd1243dSDimitry Andric if (IsCallerStructRet || IsCalleeStructRet) 5239bdd1243dSDimitry Andric return false; 5240bdd1243dSDimitry Andric 5241bdd1243dSDimitry Andric // Do not tail call opt if either the callee or caller has a byval argument. 5242bdd1243dSDimitry Andric for (auto &Arg : Outs) 5243bdd1243dSDimitry Andric if (Arg.Flags.isByVal()) 5244bdd1243dSDimitry Andric return false; 5245bdd1243dSDimitry Andric 5246bdd1243dSDimitry Andric // The callee has to preserve all registers the caller needs to preserve. 5247bdd1243dSDimitry Andric const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo(); 5248bdd1243dSDimitry Andric const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC); 5249bdd1243dSDimitry Andric if (CalleeCC != CallerCC) { 5250bdd1243dSDimitry Andric const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC); 5251bdd1243dSDimitry Andric if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved)) 5252bdd1243dSDimitry Andric return false; 5253bdd1243dSDimitry Andric } 5254bdd1243dSDimitry Andric return true; 5255bdd1243dSDimitry Andric } 5256bdd1243dSDimitry Andric 5257bdd1243dSDimitry Andric static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG) { 5258bdd1243dSDimitry Andric return DAG.getDataLayout().getPrefTypeAlign( 5259bdd1243dSDimitry Andric VT.getTypeForEVT(*DAG.getContext())); 5260bdd1243dSDimitry Andric } 5261bdd1243dSDimitry Andric 5262753f127fSDimitry Andric // Lower a call to a callseq_start + CALL + callseq_end chain, and add input 5263753f127fSDimitry Andric // and output parameter nodes. 5264753f127fSDimitry Andric SDValue 5265753f127fSDimitry Andric LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI, 5266753f127fSDimitry Andric SmallVectorImpl<SDValue> &InVals) const { 5267753f127fSDimitry Andric SelectionDAG &DAG = CLI.DAG; 5268753f127fSDimitry Andric SDLoc &DL = CLI.DL; 5269753f127fSDimitry Andric SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; 5270753f127fSDimitry Andric SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; 5271753f127fSDimitry Andric SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; 5272753f127fSDimitry Andric SDValue Chain = CLI.Chain; 5273753f127fSDimitry Andric SDValue Callee = CLI.Callee; 5274753f127fSDimitry Andric CallingConv::ID CallConv = CLI.CallConv; 5275753f127fSDimitry Andric bool IsVarArg = CLI.IsVarArg; 5276753f127fSDimitry Andric EVT PtrVT = getPointerTy(DAG.getDataLayout()); 5277bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 5278bdd1243dSDimitry Andric bool &IsTailCall = CLI.IsTailCall; 5279753f127fSDimitry Andric 5280753f127fSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 5281753f127fSDimitry Andric 5282753f127fSDimitry Andric // Analyze the operands of the call, assigning locations to each operand. 5283753f127fSDimitry Andric SmallVector<CCValAssign> ArgLocs; 5284753f127fSDimitry Andric CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 5285753f127fSDimitry Andric 5286bdd1243dSDimitry Andric if (CallConv == CallingConv::GHC) 5287bdd1243dSDimitry Andric ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC); 5288bdd1243dSDimitry Andric else 5289bdd1243dSDimitry Andric analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch); 5290bdd1243dSDimitry Andric 5291bdd1243dSDimitry Andric // Check if it's really possible to do a tail call. 5292bdd1243dSDimitry Andric if (IsTailCall) 5293bdd1243dSDimitry Andric IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs); 5294bdd1243dSDimitry Andric 5295bdd1243dSDimitry Andric if (IsTailCall) 5296bdd1243dSDimitry Andric ++NumTailCalls; 5297bdd1243dSDimitry Andric else if (CLI.CB && CLI.CB->isMustTailCall()) 5298bdd1243dSDimitry Andric report_fatal_error("failed to perform tail call elimination on a call " 5299bdd1243dSDimitry Andric "site marked musttail"); 5300753f127fSDimitry Andric 5301753f127fSDimitry Andric // Get a count of how many bytes are to be pushed on the stack. 530206c3fb27SDimitry Andric unsigned NumBytes = ArgCCInfo.getStackSize(); 5303753f127fSDimitry Andric 5304bdd1243dSDimitry Andric // Create local copies for byval args. 5305bdd1243dSDimitry Andric SmallVector<SDValue> ByValArgs; 5306bdd1243dSDimitry Andric for (unsigned i = 0, e = Outs.size(); i != e; ++i) { 5307bdd1243dSDimitry Andric ISD::ArgFlagsTy Flags = Outs[i].Flags; 5308bdd1243dSDimitry Andric if (!Flags.isByVal()) 5309753f127fSDimitry Andric continue; 5310bdd1243dSDimitry Andric 5311bdd1243dSDimitry Andric SDValue Arg = OutVals[i]; 5312bdd1243dSDimitry Andric unsigned Size = Flags.getByValSize(); 5313bdd1243dSDimitry Andric Align Alignment = Flags.getNonZeroByValAlign(); 5314bdd1243dSDimitry Andric 5315bdd1243dSDimitry Andric int FI = 5316bdd1243dSDimitry Andric MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false); 5317bdd1243dSDimitry Andric SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 5318bdd1243dSDimitry Andric SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT); 5319bdd1243dSDimitry Andric 5320bdd1243dSDimitry Andric Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment, 5321bdd1243dSDimitry Andric /*IsVolatile=*/false, 53220fca6ea1SDimitry Andric /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt, 5323bdd1243dSDimitry Andric MachinePointerInfo(), MachinePointerInfo()); 5324bdd1243dSDimitry Andric ByValArgs.push_back(FIPtr); 5325753f127fSDimitry Andric } 5326753f127fSDimitry Andric 5327bdd1243dSDimitry Andric if (!IsTailCall) 5328753f127fSDimitry Andric Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL); 5329753f127fSDimitry Andric 5330753f127fSDimitry Andric // Copy argument values to their designated locations. 5331753f127fSDimitry Andric SmallVector<std::pair<Register, SDValue>> RegsToPass; 5332bdd1243dSDimitry Andric SmallVector<SDValue> MemOpChains; 5333bdd1243dSDimitry Andric SDValue StackPtr; 5334bdd1243dSDimitry Andric for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) { 5335753f127fSDimitry Andric CCValAssign &VA = ArgLocs[i]; 5336753f127fSDimitry Andric SDValue ArgValue = OutVals[i]; 5337bdd1243dSDimitry Andric ISD::ArgFlagsTy Flags = Outs[i].Flags; 5338753f127fSDimitry Andric 5339753f127fSDimitry Andric // Promote the value if needed. 5340bdd1243dSDimitry Andric // For now, only handle fully promoted and indirect arguments. 5341bdd1243dSDimitry Andric if (VA.getLocInfo() == CCValAssign::Indirect) { 5342bdd1243dSDimitry Andric // Store the argument in a stack slot and pass its address. 5343bdd1243dSDimitry Andric Align StackAlign = 5344bdd1243dSDimitry Andric std::max(getPrefTypeAlign(Outs[i].ArgVT, DAG), 5345bdd1243dSDimitry Andric getPrefTypeAlign(ArgValue.getValueType(), DAG)); 5346bdd1243dSDimitry Andric TypeSize StoredSize = ArgValue.getValueType().getStoreSize(); 5347bdd1243dSDimitry Andric // If the original argument was split and passed by reference, we need to 5348bdd1243dSDimitry Andric // store the required parts of it here (and pass just one address). 5349bdd1243dSDimitry Andric unsigned ArgIndex = Outs[i].OrigArgIndex; 5350bdd1243dSDimitry Andric unsigned ArgPartOffset = Outs[i].PartOffset; 5351bdd1243dSDimitry Andric assert(ArgPartOffset == 0); 5352bdd1243dSDimitry Andric // Calculate the total size to store. We don't have access to what we're 5353bdd1243dSDimitry Andric // actually storing other than performing the loop and collecting the 5354bdd1243dSDimitry Andric // info. 5355bdd1243dSDimitry Andric SmallVector<std::pair<SDValue, SDValue>> Parts; 5356bdd1243dSDimitry Andric while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) { 5357bdd1243dSDimitry Andric SDValue PartValue = OutVals[i + 1]; 5358bdd1243dSDimitry Andric unsigned PartOffset = Outs[i + 1].PartOffset - ArgPartOffset; 5359bdd1243dSDimitry Andric SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL); 5360bdd1243dSDimitry Andric EVT PartVT = PartValue.getValueType(); 5361bdd1243dSDimitry Andric 5362bdd1243dSDimitry Andric StoredSize += PartVT.getStoreSize(); 5363bdd1243dSDimitry Andric StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG)); 5364bdd1243dSDimitry Andric Parts.push_back(std::make_pair(PartValue, Offset)); 5365bdd1243dSDimitry Andric ++i; 5366bdd1243dSDimitry Andric } 5367bdd1243dSDimitry Andric SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign); 5368bdd1243dSDimitry Andric int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex(); 5369bdd1243dSDimitry Andric MemOpChains.push_back( 5370bdd1243dSDimitry Andric DAG.getStore(Chain, DL, ArgValue, SpillSlot, 5371bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(MF, FI))); 5372bdd1243dSDimitry Andric for (const auto &Part : Parts) { 5373bdd1243dSDimitry Andric SDValue PartValue = Part.first; 5374bdd1243dSDimitry Andric SDValue PartOffset = Part.second; 5375bdd1243dSDimitry Andric SDValue Address = 5376bdd1243dSDimitry Andric DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset); 5377bdd1243dSDimitry Andric MemOpChains.push_back( 5378bdd1243dSDimitry Andric DAG.getStore(Chain, DL, PartValue, Address, 5379bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(MF, FI))); 5380bdd1243dSDimitry Andric } 5381bdd1243dSDimitry Andric ArgValue = SpillSlot; 5382bdd1243dSDimitry Andric } else { 5383bdd1243dSDimitry Andric ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL); 5384bdd1243dSDimitry Andric } 5385bdd1243dSDimitry Andric 5386bdd1243dSDimitry Andric // Use local copy if it is a byval arg. 5387bdd1243dSDimitry Andric if (Flags.isByVal()) 5388bdd1243dSDimitry Andric ArgValue = ByValArgs[j++]; 5389753f127fSDimitry Andric 5390753f127fSDimitry Andric if (VA.isRegLoc()) { 5391753f127fSDimitry Andric // Queue up the argument copies and emit them at the end. 5392753f127fSDimitry Andric RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); 5393753f127fSDimitry Andric } else { 5394bdd1243dSDimitry Andric assert(VA.isMemLoc() && "Argument not register or memory"); 5395bdd1243dSDimitry Andric assert(!IsTailCall && "Tail call not allowed if stack is used " 5396bdd1243dSDimitry Andric "for passing parameters"); 5397bdd1243dSDimitry Andric 5398bdd1243dSDimitry Andric // Work out the address of the stack slot. 5399bdd1243dSDimitry Andric if (!StackPtr.getNode()) 5400bdd1243dSDimitry Andric StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT); 5401bdd1243dSDimitry Andric SDValue Address = 5402bdd1243dSDimitry Andric DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, 5403bdd1243dSDimitry Andric DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); 5404bdd1243dSDimitry Andric 5405bdd1243dSDimitry Andric // Emit the store. 5406bdd1243dSDimitry Andric MemOpChains.push_back( 5407bdd1243dSDimitry Andric DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo())); 5408753f127fSDimitry Andric } 5409753f127fSDimitry Andric } 5410753f127fSDimitry Andric 5411bdd1243dSDimitry Andric // Join the stores, which are independent of one another. 5412bdd1243dSDimitry Andric if (!MemOpChains.empty()) 5413bdd1243dSDimitry Andric Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); 5414bdd1243dSDimitry Andric 5415753f127fSDimitry Andric SDValue Glue; 5416753f127fSDimitry Andric 5417753f127fSDimitry Andric // Build a sequence of copy-to-reg nodes, chained and glued together. 5418753f127fSDimitry Andric for (auto &Reg : RegsToPass) { 5419753f127fSDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue); 5420753f127fSDimitry Andric Glue = Chain.getValue(1); 5421753f127fSDimitry Andric } 5422753f127fSDimitry Andric 5423753f127fSDimitry Andric // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a 5424753f127fSDimitry Andric // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't 5425753f127fSDimitry Andric // split it and then direct call can be matched by PseudoCALL. 5426bdd1243dSDimitry Andric if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) { 5427bdd1243dSDimitry Andric const GlobalValue *GV = S->getGlobal(); 54280fca6ea1SDimitry Andric unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(GV) 5429bdd1243dSDimitry Andric ? LoongArchII::MO_CALL 5430bdd1243dSDimitry Andric : LoongArchII::MO_CALL_PLT; 5431bdd1243dSDimitry Andric Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags); 5432bdd1243dSDimitry Andric } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { 54330fca6ea1SDimitry Andric unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(nullptr) 5434bdd1243dSDimitry Andric ? LoongArchII::MO_CALL 5435bdd1243dSDimitry Andric : LoongArchII::MO_CALL_PLT; 5436bdd1243dSDimitry Andric Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags); 5437bdd1243dSDimitry Andric } 5438753f127fSDimitry Andric 5439753f127fSDimitry Andric // The first call operand is the chain and the second is the target address. 5440753f127fSDimitry Andric SmallVector<SDValue> Ops; 5441753f127fSDimitry Andric Ops.push_back(Chain); 5442753f127fSDimitry Andric Ops.push_back(Callee); 5443753f127fSDimitry Andric 5444753f127fSDimitry Andric // Add argument registers to the end of the list so that they are 5445753f127fSDimitry Andric // known live into the call. 5446753f127fSDimitry Andric for (auto &Reg : RegsToPass) 5447753f127fSDimitry Andric Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType())); 5448753f127fSDimitry Andric 5449bdd1243dSDimitry Andric if (!IsTailCall) { 5450753f127fSDimitry Andric // Add a register mask operand representing the call-preserved registers. 5451753f127fSDimitry Andric const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); 5452753f127fSDimitry Andric const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv); 5453753f127fSDimitry Andric assert(Mask && "Missing call preserved mask for calling convention"); 5454753f127fSDimitry Andric Ops.push_back(DAG.getRegisterMask(Mask)); 5455bdd1243dSDimitry Andric } 5456753f127fSDimitry Andric 5457753f127fSDimitry Andric // Glue the call to the argument copies, if any. 5458753f127fSDimitry Andric if (Glue.getNode()) 5459753f127fSDimitry Andric Ops.push_back(Glue); 5460753f127fSDimitry Andric 5461753f127fSDimitry Andric // Emit the call. 5462753f127fSDimitry Andric SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); 54631db9f3b2SDimitry Andric unsigned Op; 54641db9f3b2SDimitry Andric switch (DAG.getTarget().getCodeModel()) { 54651db9f3b2SDimitry Andric default: 54661db9f3b2SDimitry Andric report_fatal_error("Unsupported code model"); 54671db9f3b2SDimitry Andric case CodeModel::Small: 54681db9f3b2SDimitry Andric Op = IsTailCall ? LoongArchISD::TAIL : LoongArchISD::CALL; 54691db9f3b2SDimitry Andric break; 54701db9f3b2SDimitry Andric case CodeModel::Medium: 54711db9f3b2SDimitry Andric assert(Subtarget.is64Bit() && "Medium code model requires LA64"); 54721db9f3b2SDimitry Andric Op = IsTailCall ? LoongArchISD::TAIL_MEDIUM : LoongArchISD::CALL_MEDIUM; 54731db9f3b2SDimitry Andric break; 54741db9f3b2SDimitry Andric case CodeModel::Large: 54751db9f3b2SDimitry Andric assert(Subtarget.is64Bit() && "Large code model requires LA64"); 54761db9f3b2SDimitry Andric Op = IsTailCall ? LoongArchISD::TAIL_LARGE : LoongArchISD::CALL_LARGE; 54771db9f3b2SDimitry Andric break; 54781db9f3b2SDimitry Andric } 5479753f127fSDimitry Andric 5480bdd1243dSDimitry Andric if (IsTailCall) { 5481bdd1243dSDimitry Andric MF.getFrameInfo().setHasTailCall(); 54821db9f3b2SDimitry Andric SDValue Ret = DAG.getNode(Op, DL, NodeTys, Ops); 548306c3fb27SDimitry Andric DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge); 548406c3fb27SDimitry Andric return Ret; 5485bdd1243dSDimitry Andric } 5486bdd1243dSDimitry Andric 54871db9f3b2SDimitry Andric Chain = DAG.getNode(Op, DL, NodeTys, Ops); 5488753f127fSDimitry Andric DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge); 5489753f127fSDimitry Andric Glue = Chain.getValue(1); 5490753f127fSDimitry Andric 5491753f127fSDimitry Andric // Mark the end of the call, which is glued to the call itself. 5492bdd1243dSDimitry Andric Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL); 5493753f127fSDimitry Andric Glue = Chain.getValue(1); 5494753f127fSDimitry Andric 5495753f127fSDimitry Andric // Assign locations to each value returned by this call. 5496753f127fSDimitry Andric SmallVector<CCValAssign> RVLocs; 5497753f127fSDimitry Andric CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); 5498bdd1243dSDimitry Andric analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch); 5499753f127fSDimitry Andric 5500753f127fSDimitry Andric // Copy all of the result registers out of their specified physreg. 5501753f127fSDimitry Andric for (auto &VA : RVLocs) { 5502753f127fSDimitry Andric // Copy the value out. 5503753f127fSDimitry Andric SDValue RetValue = 5504753f127fSDimitry Andric DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue); 5505bdd1243dSDimitry Andric // Glue the RetValue to the end of the call sequence. 5506753f127fSDimitry Andric Chain = RetValue.getValue(1); 5507753f127fSDimitry Andric Glue = RetValue.getValue(2); 5508753f127fSDimitry Andric 5509bdd1243dSDimitry Andric RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL); 5510bdd1243dSDimitry Andric 5511bdd1243dSDimitry Andric InVals.push_back(RetValue); 5512753f127fSDimitry Andric } 5513753f127fSDimitry Andric 5514753f127fSDimitry Andric return Chain; 5515753f127fSDimitry Andric } 5516753f127fSDimitry Andric 551781ad6265SDimitry Andric bool LoongArchTargetLowering::CanLowerReturn( 551881ad6265SDimitry Andric CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, 551981ad6265SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { 5520bdd1243dSDimitry Andric SmallVector<CCValAssign> RVLocs; 5521bdd1243dSDimitry Andric CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); 5522bdd1243dSDimitry Andric 5523bdd1243dSDimitry Andric for (unsigned i = 0, e = Outs.size(); i != e; ++i) { 5524bdd1243dSDimitry Andric LoongArchABI::ABI ABI = 5525bdd1243dSDimitry Andric MF.getSubtarget<LoongArchSubtarget>().getTargetABI(); 5526bdd1243dSDimitry Andric if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full, 5527bdd1243dSDimitry Andric Outs[i].Flags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true, 5528bdd1243dSDimitry Andric nullptr)) 5529bdd1243dSDimitry Andric return false; 5530bdd1243dSDimitry Andric } 5531bdd1243dSDimitry Andric return true; 553281ad6265SDimitry Andric } 553381ad6265SDimitry Andric 553481ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerReturn( 553581ad6265SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 553681ad6265SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, 553781ad6265SDimitry Andric const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, 553881ad6265SDimitry Andric SelectionDAG &DAG) const { 553981ad6265SDimitry Andric // Stores the assignment of the return value to a location. 554081ad6265SDimitry Andric SmallVector<CCValAssign> RVLocs; 554181ad6265SDimitry Andric 554281ad6265SDimitry Andric // Info about the registers and stack slot. 554381ad6265SDimitry Andric CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, 554481ad6265SDimitry Andric *DAG.getContext()); 554581ad6265SDimitry Andric 5546bdd1243dSDimitry Andric analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true, 5547bdd1243dSDimitry Andric nullptr, CC_LoongArch); 5548bdd1243dSDimitry Andric if (CallConv == CallingConv::GHC && !RVLocs.empty()) 5549bdd1243dSDimitry Andric report_fatal_error("GHC functions return void only"); 555081ad6265SDimitry Andric SDValue Glue; 555181ad6265SDimitry Andric SmallVector<SDValue, 4> RetOps(1, Chain); 555281ad6265SDimitry Andric 555381ad6265SDimitry Andric // Copy the result values into the output registers. 555481ad6265SDimitry Andric for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) { 555581ad6265SDimitry Andric CCValAssign &VA = RVLocs[i]; 555681ad6265SDimitry Andric assert(VA.isRegLoc() && "Can only return in registers!"); 555781ad6265SDimitry Andric 555881ad6265SDimitry Andric // Handle a 'normal' return. 5559bdd1243dSDimitry Andric SDValue Val = convertValVTToLocVT(DAG, OutVals[i], VA, DL); 5560bdd1243dSDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue); 556181ad6265SDimitry Andric 556281ad6265SDimitry Andric // Guarantee that all emitted copies are stuck together. 556381ad6265SDimitry Andric Glue = Chain.getValue(1); 556481ad6265SDimitry Andric RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); 556581ad6265SDimitry Andric } 556681ad6265SDimitry Andric 556781ad6265SDimitry Andric RetOps[0] = Chain; // Update chain. 556881ad6265SDimitry Andric 556981ad6265SDimitry Andric // Add the glue node if we have it. 557081ad6265SDimitry Andric if (Glue.getNode()) 557181ad6265SDimitry Andric RetOps.push_back(Glue); 557281ad6265SDimitry Andric 557381ad6265SDimitry Andric return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps); 557481ad6265SDimitry Andric } 5575753f127fSDimitry Andric 5576753f127fSDimitry Andric bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, 5577753f127fSDimitry Andric bool ForCodeSize) const { 5578bdd1243dSDimitry Andric // TODO: Maybe need more checks here after vector extension is supported. 5579753f127fSDimitry Andric if (VT == MVT::f32 && !Subtarget.hasBasicF()) 5580753f127fSDimitry Andric return false; 5581753f127fSDimitry Andric if (VT == MVT::f64 && !Subtarget.hasBasicD()) 5582753f127fSDimitry Andric return false; 5583753f127fSDimitry Andric return (Imm.isZero() || Imm.isExactlyValue(+1.0)); 5584753f127fSDimitry Andric } 5585bdd1243dSDimitry Andric 5586bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCttz(Type *) const { 5587bdd1243dSDimitry Andric return true; 5588bdd1243dSDimitry Andric } 5589bdd1243dSDimitry Andric 5590bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCtlz(Type *) const { 5591bdd1243dSDimitry Andric return true; 5592bdd1243dSDimitry Andric } 5593bdd1243dSDimitry Andric 5594bdd1243dSDimitry Andric bool LoongArchTargetLowering::shouldInsertFencesForAtomic( 5595bdd1243dSDimitry Andric const Instruction *I) const { 5596bdd1243dSDimitry Andric if (!Subtarget.is64Bit()) 5597bdd1243dSDimitry Andric return isa<LoadInst>(I) || isa<StoreInst>(I); 5598bdd1243dSDimitry Andric 5599bdd1243dSDimitry Andric if (isa<LoadInst>(I)) 5600bdd1243dSDimitry Andric return true; 5601bdd1243dSDimitry Andric 5602bdd1243dSDimitry Andric // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not 5603bdd1243dSDimitry Andric // require fences beacuse we can use amswap_db.[w/d]. 5604*6e516c87SDimitry Andric Type *Ty = I->getOperand(0)->getType(); 5605*6e516c87SDimitry Andric if (isa<StoreInst>(I) && Ty->isIntegerTy()) { 5606*6e516c87SDimitry Andric unsigned Size = Ty->getIntegerBitWidth(); 5607bdd1243dSDimitry Andric return (Size == 8 || Size == 16); 5608bdd1243dSDimitry Andric } 5609bdd1243dSDimitry Andric 5610bdd1243dSDimitry Andric return false; 5611bdd1243dSDimitry Andric } 5612bdd1243dSDimitry Andric 5613bdd1243dSDimitry Andric EVT LoongArchTargetLowering::getSetCCResultType(const DataLayout &DL, 5614bdd1243dSDimitry Andric LLVMContext &Context, 5615bdd1243dSDimitry Andric EVT VT) const { 5616bdd1243dSDimitry Andric if (!VT.isVector()) 5617bdd1243dSDimitry Andric return getPointerTy(DL); 5618bdd1243dSDimitry Andric return VT.changeVectorElementTypeToInteger(); 5619bdd1243dSDimitry Andric } 5620bdd1243dSDimitry Andric 5621bdd1243dSDimitry Andric bool LoongArchTargetLowering::hasAndNot(SDValue Y) const { 5622bdd1243dSDimitry Andric // TODO: Support vectors. 5623bdd1243dSDimitry Andric return Y.getValueType().isScalarInteger() && !isa<ConstantSDNode>(Y); 5624bdd1243dSDimitry Andric } 5625bdd1243dSDimitry Andric 5626bdd1243dSDimitry Andric bool LoongArchTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, 5627bdd1243dSDimitry Andric const CallInst &I, 5628bdd1243dSDimitry Andric MachineFunction &MF, 5629bdd1243dSDimitry Andric unsigned Intrinsic) const { 5630bdd1243dSDimitry Andric switch (Intrinsic) { 5631bdd1243dSDimitry Andric default: 5632bdd1243dSDimitry Andric return false; 5633bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_xchg_i32: 5634bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_add_i32: 5635bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_sub_i32: 5636bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_nand_i32: 5637bdd1243dSDimitry Andric Info.opc = ISD::INTRINSIC_W_CHAIN; 5638bdd1243dSDimitry Andric Info.memVT = MVT::i32; 5639bdd1243dSDimitry Andric Info.ptrVal = I.getArgOperand(0); 5640bdd1243dSDimitry Andric Info.offset = 0; 5641bdd1243dSDimitry Andric Info.align = Align(4); 5642bdd1243dSDimitry Andric Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore | 5643bdd1243dSDimitry Andric MachineMemOperand::MOVolatile; 5644bdd1243dSDimitry Andric return true; 5645bdd1243dSDimitry Andric // TODO: Add more Intrinsics later. 5646bdd1243dSDimitry Andric } 5647bdd1243dSDimitry Andric } 5648bdd1243dSDimitry Andric 5649bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind 5650bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { 5651bdd1243dSDimitry Andric // TODO: Add more AtomicRMWInst that needs to be extended. 5652bdd1243dSDimitry Andric 5653bdd1243dSDimitry Andric // Since floating-point operation requires a non-trivial set of data 5654bdd1243dSDimitry Andric // operations, use CmpXChg to expand. 5655bdd1243dSDimitry Andric if (AI->isFloatingPointOperation() || 5656bdd1243dSDimitry Andric AI->getOperation() == AtomicRMWInst::UIncWrap || 5657bdd1243dSDimitry Andric AI->getOperation() == AtomicRMWInst::UDecWrap) 5658bdd1243dSDimitry Andric return AtomicExpansionKind::CmpXChg; 5659bdd1243dSDimitry Andric 5660bdd1243dSDimitry Andric unsigned Size = AI->getType()->getPrimitiveSizeInBits(); 5661bdd1243dSDimitry Andric if (Size == 8 || Size == 16) 5662bdd1243dSDimitry Andric return AtomicExpansionKind::MaskedIntrinsic; 5663bdd1243dSDimitry Andric return AtomicExpansionKind::None; 5664bdd1243dSDimitry Andric } 5665bdd1243dSDimitry Andric 5666bdd1243dSDimitry Andric static Intrinsic::ID 5667bdd1243dSDimitry Andric getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen, 5668bdd1243dSDimitry Andric AtomicRMWInst::BinOp BinOp) { 5669bdd1243dSDimitry Andric if (GRLen == 64) { 5670bdd1243dSDimitry Andric switch (BinOp) { 5671bdd1243dSDimitry Andric default: 5672bdd1243dSDimitry Andric llvm_unreachable("Unexpected AtomicRMW BinOp"); 5673bdd1243dSDimitry Andric case AtomicRMWInst::Xchg: 5674bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_xchg_i64; 5675bdd1243dSDimitry Andric case AtomicRMWInst::Add: 5676bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_add_i64; 5677bdd1243dSDimitry Andric case AtomicRMWInst::Sub: 5678bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_sub_i64; 5679bdd1243dSDimitry Andric case AtomicRMWInst::Nand: 5680bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_nand_i64; 5681bdd1243dSDimitry Andric case AtomicRMWInst::UMax: 5682bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_umax_i64; 5683bdd1243dSDimitry Andric case AtomicRMWInst::UMin: 5684bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_umin_i64; 5685bdd1243dSDimitry Andric case AtomicRMWInst::Max: 5686bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_max_i64; 5687bdd1243dSDimitry Andric case AtomicRMWInst::Min: 5688bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_min_i64; 5689bdd1243dSDimitry Andric // TODO: support other AtomicRMWInst. 5690bdd1243dSDimitry Andric } 5691bdd1243dSDimitry Andric } 5692bdd1243dSDimitry Andric 5693bdd1243dSDimitry Andric if (GRLen == 32) { 5694bdd1243dSDimitry Andric switch (BinOp) { 5695bdd1243dSDimitry Andric default: 5696bdd1243dSDimitry Andric llvm_unreachable("Unexpected AtomicRMW BinOp"); 5697bdd1243dSDimitry Andric case AtomicRMWInst::Xchg: 5698bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_xchg_i32; 5699bdd1243dSDimitry Andric case AtomicRMWInst::Add: 5700bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_add_i32; 5701bdd1243dSDimitry Andric case AtomicRMWInst::Sub: 5702bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_sub_i32; 5703bdd1243dSDimitry Andric case AtomicRMWInst::Nand: 5704bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_nand_i32; 5705bdd1243dSDimitry Andric // TODO: support other AtomicRMWInst. 5706bdd1243dSDimitry Andric } 5707bdd1243dSDimitry Andric } 5708bdd1243dSDimitry Andric 5709bdd1243dSDimitry Andric llvm_unreachable("Unexpected GRLen\n"); 5710bdd1243dSDimitry Andric } 5711bdd1243dSDimitry Andric 5712bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind 5713bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicCmpXchgInIR( 5714bdd1243dSDimitry Andric AtomicCmpXchgInst *CI) const { 5715bdd1243dSDimitry Andric unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits(); 5716bdd1243dSDimitry Andric if (Size == 8 || Size == 16) 5717bdd1243dSDimitry Andric return AtomicExpansionKind::MaskedIntrinsic; 5718bdd1243dSDimitry Andric return AtomicExpansionKind::None; 5719bdd1243dSDimitry Andric } 5720bdd1243dSDimitry Andric 5721bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicCmpXchgIntrinsic( 5722bdd1243dSDimitry Andric IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, 5723bdd1243dSDimitry Andric Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const { 57245f757f3fSDimitry Andric AtomicOrdering FailOrd = CI->getFailureOrdering(); 57255f757f3fSDimitry Andric Value *FailureOrdering = 57265f757f3fSDimitry Andric Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(FailOrd)); 5727bdd1243dSDimitry Andric 5728bdd1243dSDimitry Andric // TODO: Support cmpxchg on LA32. 5729bdd1243dSDimitry Andric Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64; 5730bdd1243dSDimitry Andric CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty()); 5731bdd1243dSDimitry Andric NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty()); 5732bdd1243dSDimitry Andric Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty()); 5733bdd1243dSDimitry Andric Type *Tys[] = {AlignedAddr->getType()}; 5734bdd1243dSDimitry Andric Function *MaskedCmpXchg = 5735bdd1243dSDimitry Andric Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys); 5736bdd1243dSDimitry Andric Value *Result = Builder.CreateCall( 57375f757f3fSDimitry Andric MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, FailureOrdering}); 5738bdd1243dSDimitry Andric Result = Builder.CreateTrunc(Result, Builder.getInt32Ty()); 5739bdd1243dSDimitry Andric return Result; 5740bdd1243dSDimitry Andric } 5741bdd1243dSDimitry Andric 5742bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicRMWIntrinsic( 5743bdd1243dSDimitry Andric IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr, 5744bdd1243dSDimitry Andric Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const { 57455f757f3fSDimitry Andric // In the case of an atomicrmw xchg with a constant 0/-1 operand, replace 57465f757f3fSDimitry Andric // the atomic instruction with an AtomicRMWInst::And/Or with appropriate 57475f757f3fSDimitry Andric // mask, as this produces better code than the LL/SC loop emitted by 57485f757f3fSDimitry Andric // int_loongarch_masked_atomicrmw_xchg. 57495f757f3fSDimitry Andric if (AI->getOperation() == AtomicRMWInst::Xchg && 57505f757f3fSDimitry Andric isa<ConstantInt>(AI->getValOperand())) { 57515f757f3fSDimitry Andric ConstantInt *CVal = cast<ConstantInt>(AI->getValOperand()); 57525f757f3fSDimitry Andric if (CVal->isZero()) 57535f757f3fSDimitry Andric return Builder.CreateAtomicRMW(AtomicRMWInst::And, AlignedAddr, 57545f757f3fSDimitry Andric Builder.CreateNot(Mask, "Inv_Mask"), 57555f757f3fSDimitry Andric AI->getAlign(), Ord); 57565f757f3fSDimitry Andric if (CVal->isMinusOne()) 57575f757f3fSDimitry Andric return Builder.CreateAtomicRMW(AtomicRMWInst::Or, AlignedAddr, Mask, 57585f757f3fSDimitry Andric AI->getAlign(), Ord); 57595f757f3fSDimitry Andric } 57605f757f3fSDimitry Andric 5761bdd1243dSDimitry Andric unsigned GRLen = Subtarget.getGRLen(); 5762bdd1243dSDimitry Andric Value *Ordering = 5763bdd1243dSDimitry Andric Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering())); 5764bdd1243dSDimitry Andric Type *Tys[] = {AlignedAddr->getType()}; 5765bdd1243dSDimitry Andric Function *LlwOpScwLoop = Intrinsic::getDeclaration( 5766bdd1243dSDimitry Andric AI->getModule(), 5767bdd1243dSDimitry Andric getIntrinsicForMaskedAtomicRMWBinOp(GRLen, AI->getOperation()), Tys); 5768bdd1243dSDimitry Andric 5769bdd1243dSDimitry Andric if (GRLen == 64) { 5770bdd1243dSDimitry Andric Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty()); 5771bdd1243dSDimitry Andric Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty()); 5772bdd1243dSDimitry Andric ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty()); 5773bdd1243dSDimitry Andric } 5774bdd1243dSDimitry Andric 5775bdd1243dSDimitry Andric Value *Result; 5776bdd1243dSDimitry Andric 5777bdd1243dSDimitry Andric // Must pass the shift amount needed to sign extend the loaded value prior 5778bdd1243dSDimitry Andric // to performing a signed comparison for min/max. ShiftAmt is the number of 5779bdd1243dSDimitry Andric // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which 5780bdd1243dSDimitry Andric // is the number of bits to left+right shift the value in order to 5781bdd1243dSDimitry Andric // sign-extend. 5782bdd1243dSDimitry Andric if (AI->getOperation() == AtomicRMWInst::Min || 5783bdd1243dSDimitry Andric AI->getOperation() == AtomicRMWInst::Max) { 57840fca6ea1SDimitry Andric const DataLayout &DL = AI->getDataLayout(); 5785bdd1243dSDimitry Andric unsigned ValWidth = 5786bdd1243dSDimitry Andric DL.getTypeStoreSizeInBits(AI->getValOperand()->getType()); 5787bdd1243dSDimitry Andric Value *SextShamt = 5788bdd1243dSDimitry Andric Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt); 5789bdd1243dSDimitry Andric Result = Builder.CreateCall(LlwOpScwLoop, 5790bdd1243dSDimitry Andric {AlignedAddr, Incr, Mask, SextShamt, Ordering}); 5791bdd1243dSDimitry Andric } else { 5792bdd1243dSDimitry Andric Result = 5793bdd1243dSDimitry Andric Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering}); 5794bdd1243dSDimitry Andric } 5795bdd1243dSDimitry Andric 5796bdd1243dSDimitry Andric if (GRLen == 64) 5797bdd1243dSDimitry Andric Result = Builder.CreateTrunc(Result, Builder.getInt32Ty()); 5798bdd1243dSDimitry Andric return Result; 5799bdd1243dSDimitry Andric } 5800bdd1243dSDimitry Andric 5801bdd1243dSDimitry Andric bool LoongArchTargetLowering::isFMAFasterThanFMulAndFAdd( 5802bdd1243dSDimitry Andric const MachineFunction &MF, EVT VT) const { 5803bdd1243dSDimitry Andric VT = VT.getScalarType(); 5804bdd1243dSDimitry Andric 5805bdd1243dSDimitry Andric if (!VT.isSimple()) 5806bdd1243dSDimitry Andric return false; 5807bdd1243dSDimitry Andric 5808bdd1243dSDimitry Andric switch (VT.getSimpleVT().SimpleTy) { 5809bdd1243dSDimitry Andric case MVT::f32: 5810bdd1243dSDimitry Andric case MVT::f64: 5811bdd1243dSDimitry Andric return true; 5812bdd1243dSDimitry Andric default: 5813bdd1243dSDimitry Andric break; 5814bdd1243dSDimitry Andric } 5815bdd1243dSDimitry Andric 5816bdd1243dSDimitry Andric return false; 5817bdd1243dSDimitry Andric } 5818bdd1243dSDimitry Andric 5819bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionPointerRegister( 5820bdd1243dSDimitry Andric const Constant *PersonalityFn) const { 5821bdd1243dSDimitry Andric return LoongArch::R4; 5822bdd1243dSDimitry Andric } 5823bdd1243dSDimitry Andric 5824bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionSelectorRegister( 5825bdd1243dSDimitry Andric const Constant *PersonalityFn) const { 5826bdd1243dSDimitry Andric return LoongArch::R5; 5827bdd1243dSDimitry Andric } 5828bdd1243dSDimitry Andric 5829bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 5830bdd1243dSDimitry Andric // LoongArch Inline Assembly Support 5831bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 5832bdd1243dSDimitry Andric 5833bdd1243dSDimitry Andric LoongArchTargetLowering::ConstraintType 5834bdd1243dSDimitry Andric LoongArchTargetLowering::getConstraintType(StringRef Constraint) const { 5835bdd1243dSDimitry Andric // LoongArch specific constraints in GCC: config/loongarch/constraints.md 5836bdd1243dSDimitry Andric // 5837bdd1243dSDimitry Andric // 'f': A floating-point register (if available). 5838bdd1243dSDimitry Andric // 'k': A memory operand whose address is formed by a base register and 5839bdd1243dSDimitry Andric // (optionally scaled) index register. 5840bdd1243dSDimitry Andric // 'l': A signed 16-bit constant. 5841bdd1243dSDimitry Andric // 'm': A memory operand whose address is formed by a base register and 5842bdd1243dSDimitry Andric // offset that is suitable for use in instructions with the same 5843bdd1243dSDimitry Andric // addressing mode as st.w and ld.w. 5844bdd1243dSDimitry Andric // 'I': A signed 12-bit constant (for arithmetic instructions). 5845bdd1243dSDimitry Andric // 'J': Integer zero. 5846bdd1243dSDimitry Andric // 'K': An unsigned 12-bit constant (for logic instructions). 5847bdd1243dSDimitry Andric // "ZB": An address that is held in a general-purpose register. The offset is 5848bdd1243dSDimitry Andric // zero. 5849bdd1243dSDimitry Andric // "ZC": A memory operand whose address is formed by a base register and 5850bdd1243dSDimitry Andric // offset that is suitable for use in instructions with the same 5851bdd1243dSDimitry Andric // addressing mode as ll.w and sc.w. 5852bdd1243dSDimitry Andric if (Constraint.size() == 1) { 5853bdd1243dSDimitry Andric switch (Constraint[0]) { 5854bdd1243dSDimitry Andric default: 5855bdd1243dSDimitry Andric break; 5856bdd1243dSDimitry Andric case 'f': 5857bdd1243dSDimitry Andric return C_RegisterClass; 5858bdd1243dSDimitry Andric case 'l': 5859bdd1243dSDimitry Andric case 'I': 5860bdd1243dSDimitry Andric case 'J': 5861bdd1243dSDimitry Andric case 'K': 5862bdd1243dSDimitry Andric return C_Immediate; 5863bdd1243dSDimitry Andric case 'k': 5864bdd1243dSDimitry Andric return C_Memory; 5865bdd1243dSDimitry Andric } 5866bdd1243dSDimitry Andric } 5867bdd1243dSDimitry Andric 5868bdd1243dSDimitry Andric if (Constraint == "ZC" || Constraint == "ZB") 5869bdd1243dSDimitry Andric return C_Memory; 5870bdd1243dSDimitry Andric 5871bdd1243dSDimitry Andric // 'm' is handled here. 5872bdd1243dSDimitry Andric return TargetLowering::getConstraintType(Constraint); 5873bdd1243dSDimitry Andric } 5874bdd1243dSDimitry Andric 58755f757f3fSDimitry Andric InlineAsm::ConstraintCode LoongArchTargetLowering::getInlineAsmMemConstraint( 5876bdd1243dSDimitry Andric StringRef ConstraintCode) const { 58775f757f3fSDimitry Andric return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode) 58785f757f3fSDimitry Andric .Case("k", InlineAsm::ConstraintCode::k) 58795f757f3fSDimitry Andric .Case("ZB", InlineAsm::ConstraintCode::ZB) 58805f757f3fSDimitry Andric .Case("ZC", InlineAsm::ConstraintCode::ZC) 5881bdd1243dSDimitry Andric .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode)); 5882bdd1243dSDimitry Andric } 5883bdd1243dSDimitry Andric 5884bdd1243dSDimitry Andric std::pair<unsigned, const TargetRegisterClass *> 5885bdd1243dSDimitry Andric LoongArchTargetLowering::getRegForInlineAsmConstraint( 5886bdd1243dSDimitry Andric const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { 5887bdd1243dSDimitry Andric // First, see if this is a constraint that directly corresponds to a LoongArch 5888bdd1243dSDimitry Andric // register class. 5889bdd1243dSDimitry Andric if (Constraint.size() == 1) { 5890bdd1243dSDimitry Andric switch (Constraint[0]) { 5891bdd1243dSDimitry Andric case 'r': 5892bdd1243dSDimitry Andric // TODO: Support fixed vectors up to GRLen? 5893bdd1243dSDimitry Andric if (VT.isVector()) 5894bdd1243dSDimitry Andric break; 5895bdd1243dSDimitry Andric return std::make_pair(0U, &LoongArch::GPRRegClass); 5896bdd1243dSDimitry Andric case 'f': 5897bdd1243dSDimitry Andric if (Subtarget.hasBasicF() && VT == MVT::f32) 5898bdd1243dSDimitry Andric return std::make_pair(0U, &LoongArch::FPR32RegClass); 5899bdd1243dSDimitry Andric if (Subtarget.hasBasicD() && VT == MVT::f64) 5900bdd1243dSDimitry Andric return std::make_pair(0U, &LoongArch::FPR64RegClass); 590106c3fb27SDimitry Andric if (Subtarget.hasExtLSX() && 590206c3fb27SDimitry Andric TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT)) 590306c3fb27SDimitry Andric return std::make_pair(0U, &LoongArch::LSX128RegClass); 590406c3fb27SDimitry Andric if (Subtarget.hasExtLASX() && 590506c3fb27SDimitry Andric TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT)) 590606c3fb27SDimitry Andric return std::make_pair(0U, &LoongArch::LASX256RegClass); 5907bdd1243dSDimitry Andric break; 5908bdd1243dSDimitry Andric default: 5909bdd1243dSDimitry Andric break; 5910bdd1243dSDimitry Andric } 5911bdd1243dSDimitry Andric } 5912bdd1243dSDimitry Andric 5913bdd1243dSDimitry Andric // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen 5914bdd1243dSDimitry Andric // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm 5915bdd1243dSDimitry Andric // constraints while the official register name is prefixed with a '$'. So we 5916bdd1243dSDimitry Andric // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.) 5917bdd1243dSDimitry Andric // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is 5918bdd1243dSDimitry Andric // case insensitive, so no need to convert the constraint to upper case here. 5919bdd1243dSDimitry Andric // 5920bdd1243dSDimitry Andric // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly 5921bdd1243dSDimitry Andric // decode the usage of register name aliases into their official names. And 5922bdd1243dSDimitry Andric // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use 5923bdd1243dSDimitry Andric // official register names. 59245f757f3fSDimitry Andric if (Constraint.starts_with("{$r") || Constraint.starts_with("{$f") || 59255f757f3fSDimitry Andric Constraint.starts_with("{$vr") || Constraint.starts_with("{$xr")) { 5926bdd1243dSDimitry Andric bool IsFP = Constraint[2] == 'f'; 5927bdd1243dSDimitry Andric std::pair<StringRef, StringRef> Temp = Constraint.split('$'); 5928bdd1243dSDimitry Andric std::pair<unsigned, const TargetRegisterClass *> R; 5929bdd1243dSDimitry Andric R = TargetLowering::getRegForInlineAsmConstraint( 5930bdd1243dSDimitry Andric TRI, join_items("", Temp.first, Temp.second), VT); 5931bdd1243dSDimitry Andric // Match those names to the widest floating point register type available. 5932bdd1243dSDimitry Andric if (IsFP) { 5933bdd1243dSDimitry Andric unsigned RegNo = R.first; 5934bdd1243dSDimitry Andric if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) { 5935bdd1243dSDimitry Andric if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) { 5936bdd1243dSDimitry Andric unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64; 5937bdd1243dSDimitry Andric return std::make_pair(DReg, &LoongArch::FPR64RegClass); 5938bdd1243dSDimitry Andric } 5939bdd1243dSDimitry Andric } 5940bdd1243dSDimitry Andric } 5941bdd1243dSDimitry Andric return R; 5942bdd1243dSDimitry Andric } 5943bdd1243dSDimitry Andric 5944bdd1243dSDimitry Andric return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); 5945bdd1243dSDimitry Andric } 5946bdd1243dSDimitry Andric 5947bdd1243dSDimitry Andric void LoongArchTargetLowering::LowerAsmOperandForConstraint( 59485f757f3fSDimitry Andric SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops, 5949bdd1243dSDimitry Andric SelectionDAG &DAG) const { 5950bdd1243dSDimitry Andric // Currently only support length 1 constraints. 59515f757f3fSDimitry Andric if (Constraint.size() == 1) { 5952bdd1243dSDimitry Andric switch (Constraint[0]) { 5953bdd1243dSDimitry Andric case 'l': 5954bdd1243dSDimitry Andric // Validate & create a 16-bit signed immediate operand. 5955bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) { 5956bdd1243dSDimitry Andric uint64_t CVal = C->getSExtValue(); 5957bdd1243dSDimitry Andric if (isInt<16>(CVal)) 5958bdd1243dSDimitry Andric Ops.push_back( 5959bdd1243dSDimitry Andric DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT())); 5960bdd1243dSDimitry Andric } 5961bdd1243dSDimitry Andric return; 5962bdd1243dSDimitry Andric case 'I': 5963bdd1243dSDimitry Andric // Validate & create a 12-bit signed immediate operand. 5964bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) { 5965bdd1243dSDimitry Andric uint64_t CVal = C->getSExtValue(); 5966bdd1243dSDimitry Andric if (isInt<12>(CVal)) 5967bdd1243dSDimitry Andric Ops.push_back( 5968bdd1243dSDimitry Andric DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT())); 5969bdd1243dSDimitry Andric } 5970bdd1243dSDimitry Andric return; 5971bdd1243dSDimitry Andric case 'J': 5972bdd1243dSDimitry Andric // Validate & create an integer zero operand. 5973bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) 5974bdd1243dSDimitry Andric if (C->getZExtValue() == 0) 5975bdd1243dSDimitry Andric Ops.push_back( 5976bdd1243dSDimitry Andric DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT())); 5977bdd1243dSDimitry Andric return; 5978bdd1243dSDimitry Andric case 'K': 5979bdd1243dSDimitry Andric // Validate & create a 12-bit unsigned immediate operand. 5980bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) { 5981bdd1243dSDimitry Andric uint64_t CVal = C->getZExtValue(); 5982bdd1243dSDimitry Andric if (isUInt<12>(CVal)) 5983bdd1243dSDimitry Andric Ops.push_back( 5984bdd1243dSDimitry Andric DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT())); 5985bdd1243dSDimitry Andric } 5986bdd1243dSDimitry Andric return; 5987bdd1243dSDimitry Andric default: 5988bdd1243dSDimitry Andric break; 5989bdd1243dSDimitry Andric } 5990bdd1243dSDimitry Andric } 5991bdd1243dSDimitry Andric TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); 5992bdd1243dSDimitry Andric } 5993bdd1243dSDimitry Andric 5994bdd1243dSDimitry Andric #define GET_REGISTER_MATCHER 5995bdd1243dSDimitry Andric #include "LoongArchGenAsmMatcher.inc" 5996bdd1243dSDimitry Andric 5997bdd1243dSDimitry Andric Register 5998bdd1243dSDimitry Andric LoongArchTargetLowering::getRegisterByName(const char *RegName, LLT VT, 5999bdd1243dSDimitry Andric const MachineFunction &MF) const { 6000bdd1243dSDimitry Andric std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$'); 6001bdd1243dSDimitry Andric std::string NewRegName = Name.second.str(); 6002bdd1243dSDimitry Andric Register Reg = MatchRegisterAltName(NewRegName); 6003bdd1243dSDimitry Andric if (Reg == LoongArch::NoRegister) 6004bdd1243dSDimitry Andric Reg = MatchRegisterName(NewRegName); 6005bdd1243dSDimitry Andric if (Reg == LoongArch::NoRegister) 6006bdd1243dSDimitry Andric report_fatal_error( 6007bdd1243dSDimitry Andric Twine("Invalid register name \"" + StringRef(RegName) + "\".")); 6008bdd1243dSDimitry Andric BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF); 6009bdd1243dSDimitry Andric if (!ReservedRegs.test(Reg)) 6010bdd1243dSDimitry Andric report_fatal_error(Twine("Trying to obtain non-reserved register \"" + 6011bdd1243dSDimitry Andric StringRef(RegName) + "\".")); 6012bdd1243dSDimitry Andric return Reg; 6013bdd1243dSDimitry Andric } 6014bdd1243dSDimitry Andric 6015bdd1243dSDimitry Andric bool LoongArchTargetLowering::decomposeMulByConstant(LLVMContext &Context, 6016bdd1243dSDimitry Andric EVT VT, SDValue C) const { 6017bdd1243dSDimitry Andric // TODO: Support vectors. 6018bdd1243dSDimitry Andric if (!VT.isScalarInteger()) 6019bdd1243dSDimitry Andric return false; 6020bdd1243dSDimitry Andric 6021bdd1243dSDimitry Andric // Omit the optimization if the data size exceeds GRLen. 6022bdd1243dSDimitry Andric if (VT.getSizeInBits() > Subtarget.getGRLen()) 6023bdd1243dSDimitry Andric return false; 6024bdd1243dSDimitry Andric 6025bdd1243dSDimitry Andric if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) { 6026bdd1243dSDimitry Andric const APInt &Imm = ConstNode->getAPIntValue(); 602706c3fb27SDimitry Andric // Break MUL into (SLLI + ADD/SUB) or ALSL. 6028bdd1243dSDimitry Andric if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() || 6029bdd1243dSDimitry Andric (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2()) 6030bdd1243dSDimitry Andric return true; 603106c3fb27SDimitry Andric // Break MUL into (ALSL x, (SLLI x, imm0), imm1). 603206c3fb27SDimitry Andric if (ConstNode->hasOneUse() && 603306c3fb27SDimitry Andric ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() || 603406c3fb27SDimitry Andric (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2())) 603506c3fb27SDimitry Andric return true; 603606c3fb27SDimitry Andric // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)), 603706c3fb27SDimitry Andric // in which the immediate has two set bits. Or Break (MUL x, imm) 603806c3fb27SDimitry Andric // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate 603906c3fb27SDimitry Andric // equals to (1 << s0) - (1 << s1). 604006c3fb27SDimitry Andric if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) { 604106c3fb27SDimitry Andric unsigned Shifts = Imm.countr_zero(); 604206c3fb27SDimitry Andric // Reject immediates which can be composed via a single LUI. 604306c3fb27SDimitry Andric if (Shifts >= 12) 604406c3fb27SDimitry Andric return false; 604506c3fb27SDimitry Andric // Reject multiplications can be optimized to 604606c3fb27SDimitry Andric // (SLLI (ALSL x, x, 1/2/3/4), s). 604706c3fb27SDimitry Andric APInt ImmPop = Imm.ashr(Shifts); 604806c3fb27SDimitry Andric if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17) 604906c3fb27SDimitry Andric return false; 605006c3fb27SDimitry Andric // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`, 605106c3fb27SDimitry Andric // since it needs one more instruction than other 3 cases. 605206c3fb27SDimitry Andric APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true); 605306c3fb27SDimitry Andric if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() || 605406c3fb27SDimitry Andric (ImmSmall - Imm).isPowerOf2()) 605506c3fb27SDimitry Andric return true; 605606c3fb27SDimitry Andric } 6057bdd1243dSDimitry Andric } 6058bdd1243dSDimitry Andric 6059bdd1243dSDimitry Andric return false; 6060bdd1243dSDimitry Andric } 606106c3fb27SDimitry Andric 606206c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalAddressingMode(const DataLayout &DL, 606306c3fb27SDimitry Andric const AddrMode &AM, 606406c3fb27SDimitry Andric Type *Ty, unsigned AS, 606506c3fb27SDimitry Andric Instruction *I) const { 606606c3fb27SDimitry Andric // LoongArch has four basic addressing modes: 606706c3fb27SDimitry Andric // 1. reg 606806c3fb27SDimitry Andric // 2. reg + 12-bit signed offset 606906c3fb27SDimitry Andric // 3. reg + 14-bit signed offset left-shifted by 2 607006c3fb27SDimitry Andric // 4. reg1 + reg2 607106c3fb27SDimitry Andric // TODO: Add more checks after support vector extension. 607206c3fb27SDimitry Andric 607306c3fb27SDimitry Andric // No global is ever allowed as a base. 607406c3fb27SDimitry Andric if (AM.BaseGV) 607506c3fb27SDimitry Andric return false; 607606c3fb27SDimitry Andric 60770fca6ea1SDimitry Andric // Require a 12-bit signed offset or 14-bit signed offset left-shifted by 2 60780fca6ea1SDimitry Andric // with `UAL` feature. 60790fca6ea1SDimitry Andric if (!isInt<12>(AM.BaseOffs) && 60800fca6ea1SDimitry Andric !(isShiftedInt<14, 2>(AM.BaseOffs) && Subtarget.hasUAL())) 608106c3fb27SDimitry Andric return false; 608206c3fb27SDimitry Andric 608306c3fb27SDimitry Andric switch (AM.Scale) { 608406c3fb27SDimitry Andric case 0: 60850fca6ea1SDimitry Andric // "r+i" or just "i", depending on HasBaseReg. 608606c3fb27SDimitry Andric break; 608706c3fb27SDimitry Andric case 1: 608806c3fb27SDimitry Andric // "r+r+i" is not allowed. 60890fca6ea1SDimitry Andric if (AM.HasBaseReg && AM.BaseOffs) 609006c3fb27SDimitry Andric return false; 609106c3fb27SDimitry Andric // Otherwise we have "r+r" or "r+i". 609206c3fb27SDimitry Andric break; 609306c3fb27SDimitry Andric case 2: 609406c3fb27SDimitry Andric // "2*r+r" or "2*r+i" is not allowed. 609506c3fb27SDimitry Andric if (AM.HasBaseReg || AM.BaseOffs) 609606c3fb27SDimitry Andric return false; 60970fca6ea1SDimitry Andric // Allow "2*r" as "r+r". 609806c3fb27SDimitry Andric break; 609906c3fb27SDimitry Andric default: 610006c3fb27SDimitry Andric return false; 610106c3fb27SDimitry Andric } 610206c3fb27SDimitry Andric 610306c3fb27SDimitry Andric return true; 610406c3fb27SDimitry Andric } 610506c3fb27SDimitry Andric 610606c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalICmpImmediate(int64_t Imm) const { 610706c3fb27SDimitry Andric return isInt<12>(Imm); 610806c3fb27SDimitry Andric } 610906c3fb27SDimitry Andric 611006c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalAddImmediate(int64_t Imm) const { 611106c3fb27SDimitry Andric return isInt<12>(Imm); 611206c3fb27SDimitry Andric } 611306c3fb27SDimitry Andric 611406c3fb27SDimitry Andric bool LoongArchTargetLowering::isZExtFree(SDValue Val, EVT VT2) const { 611506c3fb27SDimitry Andric // Zexts are free if they can be combined with a load. 611606c3fb27SDimitry Andric // Don't advertise i32->i64 zextload as being free for LA64. It interacts 611706c3fb27SDimitry Andric // poorly with type legalization of compares preferring sext. 611806c3fb27SDimitry Andric if (auto *LD = dyn_cast<LoadSDNode>(Val)) { 611906c3fb27SDimitry Andric EVT MemVT = LD->getMemoryVT(); 612006c3fb27SDimitry Andric if ((MemVT == MVT::i8 || MemVT == MVT::i16) && 612106c3fb27SDimitry Andric (LD->getExtensionType() == ISD::NON_EXTLOAD || 612206c3fb27SDimitry Andric LD->getExtensionType() == ISD::ZEXTLOAD)) 612306c3fb27SDimitry Andric return true; 612406c3fb27SDimitry Andric } 612506c3fb27SDimitry Andric 612606c3fb27SDimitry Andric return TargetLowering::isZExtFree(Val, VT2); 612706c3fb27SDimitry Andric } 612806c3fb27SDimitry Andric 61290fca6ea1SDimitry Andric bool LoongArchTargetLowering::isSExtCheaperThanZExt(EVT SrcVT, 61300fca6ea1SDimitry Andric EVT DstVT) const { 613106c3fb27SDimitry Andric return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64; 613206c3fb27SDimitry Andric } 613306c3fb27SDimitry Andric 61340fca6ea1SDimitry Andric bool LoongArchTargetLowering::signExtendConstant(const ConstantInt *CI) const { 61350fca6ea1SDimitry Andric return Subtarget.is64Bit() && CI->getType()->isIntegerTy(32); 61360fca6ea1SDimitry Andric } 61370fca6ea1SDimitry Andric 613806c3fb27SDimitry Andric bool LoongArchTargetLowering::hasAndNotCompare(SDValue Y) const { 613906c3fb27SDimitry Andric // TODO: Support vectors. 614006c3fb27SDimitry Andric if (Y.getValueType().isVector()) 614106c3fb27SDimitry Andric return false; 614206c3fb27SDimitry Andric 614306c3fb27SDimitry Andric return !isa<ConstantSDNode>(Y); 614406c3fb27SDimitry Andric } 6145439352acSDimitry Andric 6146439352acSDimitry Andric ISD::NodeType LoongArchTargetLowering::getExtendForAtomicCmpSwapArg() const { 6147439352acSDimitry Andric // TODO: LAMCAS will use amcas{_DB,}.[bhwd] which does not require extension. 6148439352acSDimitry Andric return ISD::SIGN_EXTEND; 6149439352acSDimitry Andric } 61500fca6ea1SDimitry Andric 61510fca6ea1SDimitry Andric bool LoongArchTargetLowering::shouldSignExtendTypeInLibCall( 61520fca6ea1SDimitry Andric EVT Type, bool IsSigned) const { 61530fca6ea1SDimitry Andric if (Subtarget.is64Bit() && Type == MVT::i32) 61540fca6ea1SDimitry Andric return true; 61550fca6ea1SDimitry Andric 61560fca6ea1SDimitry Andric return IsSigned; 61570fca6ea1SDimitry Andric } 61580fca6ea1SDimitry Andric 61590fca6ea1SDimitry Andric bool LoongArchTargetLowering::shouldExtendTypeInLibCall(EVT Type) const { 61600fca6ea1SDimitry Andric // Return false to suppress the unnecessary extensions if the LibCall 61610fca6ea1SDimitry Andric // arguments or return value is a float narrower than GRLEN on a soft FP ABI. 61620fca6ea1SDimitry Andric if (Subtarget.isSoftFPABI() && (Type.isFloatingPoint() && !Type.isVector() && 61630fca6ea1SDimitry Andric Type.getSizeInBits() < Subtarget.getGRLen())) 61640fca6ea1SDimitry Andric return false; 61650fca6ea1SDimitry Andric return true; 61660fca6ea1SDimitry Andric } 6167