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" 23*06c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 2481ad6265SDimitry Andric #include "llvm/CodeGen/ISDOpcodes.h" 25bdd1243dSDimitry Andric #include "llvm/CodeGen/RuntimeLibcalls.h" 26*06c3fb27SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h" 27bdd1243dSDimitry Andric #include "llvm/IR/IRBuilder.h" 28bdd1243dSDimitry Andric #include "llvm/IR/IntrinsicsLoongArch.h" 29*06c3fb27SDimitry Andric #include "llvm/Support/CodeGen.h" 3081ad6265SDimitry Andric #include "llvm/Support/Debug.h" 31*06c3fb27SDimitry 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 41*06c3fb27SDimitry 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(); 5081ad6265SDimitry Andric // Set up the register classes. 5181ad6265SDimitry Andric addRegisterClass(GRLenVT, &LoongArch::GPRRegClass); 5281ad6265SDimitry Andric if (Subtarget.hasBasicF()) 5381ad6265SDimitry Andric addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass); 5481ad6265SDimitry Andric if (Subtarget.hasBasicD()) 5581ad6265SDimitry Andric addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass); 56*06c3fb27SDimitry Andric if (Subtarget.hasExtLSX()) 57*06c3fb27SDimitry Andric for (auto VT : {MVT::v4f32, MVT::v2f64, MVT::v16i8, MVT::v8i16, MVT::v4i32, 58*06c3fb27SDimitry Andric MVT::v2i64}) 59*06c3fb27SDimitry Andric addRegisterClass(VT, &LoongArch::LSX128RegClass); 60*06c3fb27SDimitry Andric if (Subtarget.hasExtLASX()) 61*06c3fb27SDimitry Andric for (auto VT : {MVT::v8f32, MVT::v4f64, MVT::v32i8, MVT::v16i16, MVT::v8i32, 62*06c3fb27SDimitry Andric MVT::v4i64}) 63*06c3fb27SDimitry Andric addRegisterClass(VT, &LoongArch::LASX256RegClass); 6481ad6265SDimitry Andric 65753f127fSDimitry Andric setLoadExtAction({ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}, GRLenVT, 66753f127fSDimitry Andric MVT::i1, Promote); 67753f127fSDimitry Andric 6881ad6265SDimitry Andric // TODO: add necessary setOperationAction calls later. 6981ad6265SDimitry Andric setOperationAction(ISD::SHL_PARTS, GRLenVT, Custom); 7081ad6265SDimitry Andric setOperationAction(ISD::SRA_PARTS, GRLenVT, Custom); 7181ad6265SDimitry Andric setOperationAction(ISD::SRL_PARTS, GRLenVT, Custom); 72753f127fSDimitry Andric setOperationAction(ISD::FP_TO_SINT, GRLenVT, Custom); 73bdd1243dSDimitry Andric setOperationAction(ISD::ROTL, GRLenVT, Expand); 74bdd1243dSDimitry Andric setOperationAction(ISD::CTPOP, GRLenVT, Expand); 75bdd1243dSDimitry Andric setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); 76bdd1243dSDimitry Andric setOperationAction(ISD::TRAP, MVT::Other, Legal); 77bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); 78bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); 79753f127fSDimitry Andric 80bdd1243dSDimitry Andric setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool, 81bdd1243dSDimitry Andric ISD::JumpTable}, 82bdd1243dSDimitry Andric GRLenVT, Custom); 83bdd1243dSDimitry Andric 84bdd1243dSDimitry Andric setOperationAction(ISD::GlobalTLSAddress, GRLenVT, Custom); 85bdd1243dSDimitry Andric 86bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); 87bdd1243dSDimitry Andric 88bdd1243dSDimitry Andric setOperationAction(ISD::EH_DWARF_CFA, MVT::i32, Custom); 89bdd1243dSDimitry Andric if (Subtarget.is64Bit()) 90bdd1243dSDimitry Andric setOperationAction(ISD::EH_DWARF_CFA, MVT::i64, Custom); 91bdd1243dSDimitry Andric 92bdd1243dSDimitry Andric setOperationAction(ISD::DYNAMIC_STACKALLOC, GRLenVT, Expand); 93bdd1243dSDimitry Andric setOperationAction({ISD::STACKSAVE, ISD::STACKRESTORE}, MVT::Other, Expand); 94bdd1243dSDimitry Andric setOperationAction(ISD::VASTART, MVT::Other, Custom); 95bdd1243dSDimitry Andric setOperationAction({ISD::VAARG, ISD::VACOPY, ISD::VAEND}, MVT::Other, Expand); 9681ad6265SDimitry Andric 9781ad6265SDimitry Andric if (Subtarget.is64Bit()) { 9881ad6265SDimitry Andric setOperationAction(ISD::SHL, MVT::i32, Custom); 9981ad6265SDimitry Andric setOperationAction(ISD::SRA, MVT::i32, Custom); 10081ad6265SDimitry Andric setOperationAction(ISD::SRL, MVT::i32, Custom); 101753f127fSDimitry Andric setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); 102753f127fSDimitry Andric setOperationAction(ISD::BITCAST, MVT::i32, Custom); 103bdd1243dSDimitry Andric setOperationAction(ISD::ROTR, MVT::i32, Custom); 104bdd1243dSDimitry Andric setOperationAction(ISD::ROTL, MVT::i32, Custom); 105bdd1243dSDimitry Andric setOperationAction(ISD::CTTZ, MVT::i32, Custom); 106bdd1243dSDimitry Andric setOperationAction(ISD::CTLZ, MVT::i32, Custom); 107bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom); 108bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i32, Custom); 109bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); 110bdd1243dSDimitry Andric setOperationAction(ISD::READ_REGISTER, MVT::i32, Custom); 111bdd1243dSDimitry Andric setOperationAction(ISD::WRITE_REGISTER, MVT::i32, Custom); 112753f127fSDimitry Andric if (Subtarget.hasBasicF() && !Subtarget.hasBasicD()) 113753f127fSDimitry Andric setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); 114bdd1243dSDimitry Andric if (Subtarget.hasBasicF()) 115bdd1243dSDimitry Andric setOperationAction(ISD::FRINT, MVT::f32, Legal); 116bdd1243dSDimitry Andric if (Subtarget.hasBasicD()) 117bdd1243dSDimitry Andric setOperationAction(ISD::FRINT, MVT::f64, Legal); 11881ad6265SDimitry Andric } 11981ad6265SDimitry Andric 120bdd1243dSDimitry Andric // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and 121bdd1243dSDimitry Andric // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16 122bdd1243dSDimitry Andric // and i32 could still be byte-swapped relatively cheaply. 123bdd1243dSDimitry Andric setOperationAction(ISD::BSWAP, MVT::i16, Custom); 124bdd1243dSDimitry Andric if (Subtarget.is64Bit()) { 125bdd1243dSDimitry Andric setOperationAction(ISD::BSWAP, MVT::i32, Custom); 126bdd1243dSDimitry Andric } 127bdd1243dSDimitry Andric 128bdd1243dSDimitry Andric // Expand bitreverse.i16 with native-width bitrev and shift for now, before 129bdd1243dSDimitry Andric // we get to know which of sll and revb.2h is faster. 130bdd1243dSDimitry Andric setOperationAction(ISD::BITREVERSE, MVT::i8, Custom); 131bdd1243dSDimitry Andric if (Subtarget.is64Bit()) { 132bdd1243dSDimitry Andric setOperationAction(ISD::BITREVERSE, MVT::i32, Custom); 133bdd1243dSDimitry Andric setOperationAction(ISD::BITREVERSE, MVT::i64, Legal); 134bdd1243dSDimitry Andric } else { 135bdd1243dSDimitry Andric setOperationAction(ISD::BITREVERSE, MVT::i32, Legal); 136bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom); 137bdd1243dSDimitry Andric setOperationAction(ISD::READ_REGISTER, MVT::i64, Custom); 138bdd1243dSDimitry Andric setOperationAction(ISD::WRITE_REGISTER, MVT::i64, Custom); 139bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); 140bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_VOID, MVT::i64, Custom); 141bdd1243dSDimitry Andric } 142bdd1243dSDimitry Andric 143bdd1243dSDimitry Andric static const ISD::CondCode FPCCToExpand[] = { 144bdd1243dSDimitry Andric ISD::SETOGT, ISD::SETOGE, ISD::SETUGT, ISD::SETUGE, 145bdd1243dSDimitry Andric ISD::SETGE, ISD::SETNE, ISD::SETGT}; 14681ad6265SDimitry Andric 14781ad6265SDimitry Andric if (Subtarget.hasBasicF()) { 14881ad6265SDimitry Andric setCondCodeAction(FPCCToExpand, MVT::f32, Expand); 14981ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::f32, Expand); 150bdd1243dSDimitry Andric setOperationAction(ISD::BR_CC, MVT::f32, Expand); 151bdd1243dSDimitry Andric setOperationAction(ISD::FMA, MVT::f32, Legal); 152bdd1243dSDimitry Andric setOperationAction(ISD::FMINNUM_IEEE, MVT::f32, Legal); 153bdd1243dSDimitry Andric setOperationAction(ISD::FMAXNUM_IEEE, MVT::f32, Legal); 154bdd1243dSDimitry Andric setOperationAction(ISD::STRICT_FSETCCS, MVT::f32, Legal); 155bdd1243dSDimitry Andric setOperationAction(ISD::STRICT_FSETCC, MVT::f32, Legal); 156bdd1243dSDimitry Andric setOperationAction(ISD::FSIN, MVT::f32, Expand); 157bdd1243dSDimitry Andric setOperationAction(ISD::FCOS, MVT::f32, Expand); 158bdd1243dSDimitry Andric setOperationAction(ISD::FSINCOS, MVT::f32, Expand); 159bdd1243dSDimitry Andric setOperationAction(ISD::FPOW, MVT::f32, Expand); 160bdd1243dSDimitry Andric setOperationAction(ISD::FREM, MVT::f32, Expand); 16181ad6265SDimitry Andric } 16281ad6265SDimitry Andric if (Subtarget.hasBasicD()) { 16381ad6265SDimitry Andric setCondCodeAction(FPCCToExpand, MVT::f64, Expand); 16481ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::f64, Expand); 165bdd1243dSDimitry Andric setOperationAction(ISD::BR_CC, MVT::f64, Expand); 166bdd1243dSDimitry Andric setOperationAction(ISD::STRICT_FSETCCS, MVT::f64, Legal); 167bdd1243dSDimitry Andric setOperationAction(ISD::STRICT_FSETCC, MVT::f64, Legal); 168753f127fSDimitry Andric setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); 169bdd1243dSDimitry Andric setOperationAction(ISD::FMA, MVT::f64, Legal); 170bdd1243dSDimitry Andric setOperationAction(ISD::FMINNUM_IEEE, MVT::f64, Legal); 171bdd1243dSDimitry Andric setOperationAction(ISD::FMAXNUM_IEEE, MVT::f64, Legal); 172bdd1243dSDimitry Andric setOperationAction(ISD::FSIN, MVT::f64, Expand); 173bdd1243dSDimitry Andric setOperationAction(ISD::FCOS, MVT::f64, Expand); 174bdd1243dSDimitry Andric setOperationAction(ISD::FSINCOS, MVT::f64, Expand); 175bdd1243dSDimitry Andric setOperationAction(ISD::FPOW, MVT::f64, Expand); 176bdd1243dSDimitry Andric setOperationAction(ISD::FREM, MVT::f64, Expand); 177bdd1243dSDimitry Andric setTruncStoreAction(MVT::f64, MVT::f32, Expand); 17881ad6265SDimitry Andric } 17981ad6265SDimitry Andric 180bdd1243dSDimitry Andric setOperationAction(ISD::BR_JT, MVT::Other, Expand); 181bdd1243dSDimitry Andric 182753f127fSDimitry Andric setOperationAction(ISD::BR_CC, GRLenVT, Expand); 18381ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, GRLenVT, Expand); 18481ad6265SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); 185753f127fSDimitry Andric setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, GRLenVT, Expand); 186753f127fSDimitry Andric if (!Subtarget.is64Bit()) 187753f127fSDimitry Andric setLibcallName(RTLIB::MUL_I128, nullptr); 188753f127fSDimitry Andric 189753f127fSDimitry Andric setOperationAction(ISD::FP_TO_UINT, GRLenVT, Custom); 190bdd1243dSDimitry Andric setOperationAction(ISD::UINT_TO_FP, GRLenVT, Expand); 191bdd1243dSDimitry Andric if ((Subtarget.is64Bit() && Subtarget.hasBasicF() && 192bdd1243dSDimitry Andric !Subtarget.hasBasicD())) { 193bdd1243dSDimitry Andric setOperationAction(ISD::SINT_TO_FP, GRLenVT, Custom); 194753f127fSDimitry Andric setOperationAction(ISD::UINT_TO_FP, GRLenVT, Custom); 195bdd1243dSDimitry Andric } 19681ad6265SDimitry Andric 19781ad6265SDimitry Andric // Compute derived properties from the register classes. 198*06c3fb27SDimitry Andric computeRegisterProperties(Subtarget.getRegisterInfo()); 19981ad6265SDimitry Andric 20081ad6265SDimitry Andric setStackPointerRegisterToSaveRestore(LoongArch::R3); 20181ad6265SDimitry Andric 20281ad6265SDimitry Andric setBooleanContents(ZeroOrOneBooleanContent); 20381ad6265SDimitry Andric 204753f127fSDimitry Andric setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen()); 205753f127fSDimitry Andric 206bdd1243dSDimitry Andric setMinCmpXchgSizeInBits(32); 207bdd1243dSDimitry Andric 20881ad6265SDimitry Andric // Function alignments. 209*06c3fb27SDimitry Andric setMinFunctionAlignment(Align(4)); 210*06c3fb27SDimitry Andric // Set preferred alignments. 211*06c3fb27SDimitry Andric setPrefFunctionAlignment(Subtarget.getPrefFunctionAlignment()); 212*06c3fb27SDimitry Andric setPrefLoopAlignment(Subtarget.getPrefLoopAlignment()); 213*06c3fb27SDimitry Andric setMaxBytesForAlignment(Subtarget.getMaxBytesForAlignment()); 21481ad6265SDimitry Andric 21581ad6265SDimitry Andric setTargetDAGCombine(ISD::AND); 216753f127fSDimitry Andric setTargetDAGCombine(ISD::OR); 21781ad6265SDimitry Andric setTargetDAGCombine(ISD::SRL); 21881ad6265SDimitry Andric } 21981ad6265SDimitry Andric 220bdd1243dSDimitry Andric bool LoongArchTargetLowering::isOffsetFoldingLegal( 221bdd1243dSDimitry Andric const GlobalAddressSDNode *GA) const { 222bdd1243dSDimitry Andric // In order to maximise the opportunity for common subexpression elimination, 223bdd1243dSDimitry Andric // keep a separate ADD node for the global address offset instead of folding 224bdd1243dSDimitry Andric // it in the global address node. Later peephole optimisations may choose to 225bdd1243dSDimitry Andric // fold it back in when profitable. 226bdd1243dSDimitry Andric return false; 227bdd1243dSDimitry Andric } 228bdd1243dSDimitry Andric 22981ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerOperation(SDValue Op, 23081ad6265SDimitry Andric SelectionDAG &DAG) const { 23181ad6265SDimitry Andric switch (Op.getOpcode()) { 232bdd1243dSDimitry Andric case ISD::EH_DWARF_CFA: 233bdd1243dSDimitry Andric return lowerEH_DWARF_CFA(Op, DAG); 234753f127fSDimitry Andric case ISD::GlobalAddress: 235753f127fSDimitry Andric return lowerGlobalAddress(Op, DAG); 236bdd1243dSDimitry Andric case ISD::GlobalTLSAddress: 237bdd1243dSDimitry Andric return lowerGlobalTLSAddress(Op, DAG); 238bdd1243dSDimitry Andric case ISD::INTRINSIC_WO_CHAIN: 239bdd1243dSDimitry Andric return lowerINTRINSIC_WO_CHAIN(Op, DAG); 240bdd1243dSDimitry Andric case ISD::INTRINSIC_W_CHAIN: 241bdd1243dSDimitry Andric return lowerINTRINSIC_W_CHAIN(Op, DAG); 242bdd1243dSDimitry Andric case ISD::INTRINSIC_VOID: 243bdd1243dSDimitry Andric return lowerINTRINSIC_VOID(Op, DAG); 244bdd1243dSDimitry Andric case ISD::BlockAddress: 245bdd1243dSDimitry Andric return lowerBlockAddress(Op, DAG); 246bdd1243dSDimitry Andric case ISD::JumpTable: 247bdd1243dSDimitry Andric return lowerJumpTable(Op, DAG); 24881ad6265SDimitry Andric case ISD::SHL_PARTS: 24981ad6265SDimitry Andric return lowerShiftLeftParts(Op, DAG); 25081ad6265SDimitry Andric case ISD::SRA_PARTS: 25181ad6265SDimitry Andric return lowerShiftRightParts(Op, DAG, true); 25281ad6265SDimitry Andric case ISD::SRL_PARTS: 25381ad6265SDimitry Andric return lowerShiftRightParts(Op, DAG, false); 254753f127fSDimitry Andric case ISD::ConstantPool: 255753f127fSDimitry Andric return lowerConstantPool(Op, DAG); 256753f127fSDimitry Andric case ISD::FP_TO_SINT: 257753f127fSDimitry Andric return lowerFP_TO_SINT(Op, DAG); 258753f127fSDimitry Andric case ISD::BITCAST: 259753f127fSDimitry Andric return lowerBITCAST(Op, DAG); 260753f127fSDimitry Andric case ISD::UINT_TO_FP: 261753f127fSDimitry Andric return lowerUINT_TO_FP(Op, DAG); 262bdd1243dSDimitry Andric case ISD::SINT_TO_FP: 263bdd1243dSDimitry Andric return lowerSINT_TO_FP(Op, DAG); 264bdd1243dSDimitry Andric case ISD::VASTART: 265bdd1243dSDimitry Andric return lowerVASTART(Op, DAG); 266bdd1243dSDimitry Andric case ISD::FRAMEADDR: 267bdd1243dSDimitry Andric return lowerFRAMEADDR(Op, DAG); 268bdd1243dSDimitry Andric case ISD::RETURNADDR: 269bdd1243dSDimitry Andric return lowerRETURNADDR(Op, DAG); 270bdd1243dSDimitry Andric case ISD::WRITE_REGISTER: 271bdd1243dSDimitry Andric return lowerWRITE_REGISTER(Op, DAG); 27281ad6265SDimitry Andric } 273bdd1243dSDimitry Andric return SDValue(); 274bdd1243dSDimitry Andric } 275bdd1243dSDimitry Andric 276bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op, 277bdd1243dSDimitry Andric SelectionDAG &DAG) const { 278bdd1243dSDimitry Andric 279bdd1243dSDimitry Andric if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) { 280bdd1243dSDimitry Andric DAG.getContext()->emitError( 281bdd1243dSDimitry Andric "On LA64, only 64-bit registers can be written."); 282bdd1243dSDimitry Andric return Op.getOperand(0); 283bdd1243dSDimitry Andric } 284bdd1243dSDimitry Andric 285bdd1243dSDimitry Andric if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) { 286bdd1243dSDimitry Andric DAG.getContext()->emitError( 287bdd1243dSDimitry Andric "On LA32, only 32-bit registers can be written."); 288bdd1243dSDimitry Andric return Op.getOperand(0); 289bdd1243dSDimitry Andric } 290bdd1243dSDimitry Andric 291bdd1243dSDimitry Andric return Op; 292bdd1243dSDimitry Andric } 293bdd1243dSDimitry Andric 294bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op, 295bdd1243dSDimitry Andric SelectionDAG &DAG) const { 296bdd1243dSDimitry Andric if (!isa<ConstantSDNode>(Op.getOperand(0))) { 297bdd1243dSDimitry Andric DAG.getContext()->emitError("argument to '__builtin_frame_address' must " 298bdd1243dSDimitry Andric "be a constant integer"); 299bdd1243dSDimitry Andric return SDValue(); 300bdd1243dSDimitry Andric } 301bdd1243dSDimitry Andric 302bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 303bdd1243dSDimitry Andric MF.getFrameInfo().setFrameAddressIsTaken(true); 304bdd1243dSDimitry Andric Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF); 305bdd1243dSDimitry Andric EVT VT = Op.getValueType(); 306bdd1243dSDimitry Andric SDLoc DL(Op); 307bdd1243dSDimitry Andric SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT); 308bdd1243dSDimitry Andric unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); 309bdd1243dSDimitry Andric int GRLenInBytes = Subtarget.getGRLen() / 8; 310bdd1243dSDimitry Andric 311bdd1243dSDimitry Andric while (Depth--) { 312bdd1243dSDimitry Andric int Offset = -(GRLenInBytes * 2); 313bdd1243dSDimitry Andric SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr, 314bdd1243dSDimitry Andric DAG.getIntPtrConstant(Offset, DL)); 315bdd1243dSDimitry Andric FrameAddr = 316bdd1243dSDimitry Andric DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo()); 317bdd1243dSDimitry Andric } 318bdd1243dSDimitry Andric return FrameAddr; 319bdd1243dSDimitry Andric } 320bdd1243dSDimitry Andric 321bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op, 322bdd1243dSDimitry Andric SelectionDAG &DAG) const { 323bdd1243dSDimitry Andric if (verifyReturnAddressArgumentIsConstant(Op, DAG)) 324bdd1243dSDimitry Andric return SDValue(); 325bdd1243dSDimitry Andric 326bdd1243dSDimitry Andric // Currently only support lowering return address for current frame. 327bdd1243dSDimitry Andric if (cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() != 0) { 328bdd1243dSDimitry Andric DAG.getContext()->emitError( 329bdd1243dSDimitry Andric "return address can only be determined for the current frame"); 330bdd1243dSDimitry Andric return SDValue(); 331bdd1243dSDimitry Andric } 332bdd1243dSDimitry Andric 333bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 334bdd1243dSDimitry Andric MF.getFrameInfo().setReturnAddressIsTaken(true); 335bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 336bdd1243dSDimitry Andric 337bdd1243dSDimitry Andric // Return the value of the return address register, marking it an implicit 338bdd1243dSDimitry Andric // live-in. 339bdd1243dSDimitry Andric Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(), 340bdd1243dSDimitry Andric getRegClassFor(GRLenVT)); 341bdd1243dSDimitry Andric return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT); 342bdd1243dSDimitry Andric } 343bdd1243dSDimitry Andric 344bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op, 345bdd1243dSDimitry Andric SelectionDAG &DAG) const { 346bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 347bdd1243dSDimitry Andric auto Size = Subtarget.getGRLen() / 8; 348bdd1243dSDimitry Andric auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false); 349bdd1243dSDimitry Andric return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 350bdd1243dSDimitry Andric } 351bdd1243dSDimitry Andric 352bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op, 353bdd1243dSDimitry Andric SelectionDAG &DAG) const { 354bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 355bdd1243dSDimitry Andric auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>(); 356bdd1243dSDimitry Andric 357bdd1243dSDimitry Andric SDLoc DL(Op); 358bdd1243dSDimitry Andric SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), 359bdd1243dSDimitry Andric getPointerTy(MF.getDataLayout())); 360bdd1243dSDimitry Andric 361bdd1243dSDimitry Andric // vastart just stores the address of the VarArgsFrameIndex slot into the 362bdd1243dSDimitry Andric // memory location argument. 363bdd1243dSDimitry Andric const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); 364bdd1243dSDimitry Andric return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1), 365bdd1243dSDimitry Andric MachinePointerInfo(SV)); 36681ad6265SDimitry Andric } 36781ad6265SDimitry Andric 368753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op, 369753f127fSDimitry Andric SelectionDAG &DAG) const { 370bdd1243dSDimitry Andric assert(Subtarget.is64Bit() && Subtarget.hasBasicF() && 371bdd1243dSDimitry Andric !Subtarget.hasBasicD() && "unexpected target features"); 372753f127fSDimitry Andric 373753f127fSDimitry Andric SDLoc DL(Op); 374bdd1243dSDimitry Andric SDValue Op0 = Op.getOperand(0); 375bdd1243dSDimitry Andric if (Op0->getOpcode() == ISD::AND) { 376bdd1243dSDimitry Andric auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1)); 377bdd1243dSDimitry Andric if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF)) 378753f127fSDimitry Andric return Op; 379bdd1243dSDimitry Andric } 380bdd1243dSDimitry Andric 381bdd1243dSDimitry Andric if (Op0->getOpcode() == LoongArchISD::BSTRPICK && 382bdd1243dSDimitry Andric Op0.getConstantOperandVal(1) < UINT64_C(0X1F) && 383bdd1243dSDimitry Andric Op0.getConstantOperandVal(2) == UINT64_C(0)) 384bdd1243dSDimitry Andric return Op; 385bdd1243dSDimitry Andric 386bdd1243dSDimitry Andric if (Op0.getOpcode() == ISD::AssertZext && 387bdd1243dSDimitry Andric dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32)) 388bdd1243dSDimitry Andric return Op; 389bdd1243dSDimitry Andric 390bdd1243dSDimitry Andric EVT OpVT = Op0.getValueType(); 391bdd1243dSDimitry Andric EVT RetVT = Op.getValueType(); 392bdd1243dSDimitry Andric RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT); 393bdd1243dSDimitry Andric MakeLibCallOptions CallOptions; 394bdd1243dSDimitry Andric CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true); 395bdd1243dSDimitry Andric SDValue Chain = SDValue(); 396bdd1243dSDimitry Andric SDValue Result; 397bdd1243dSDimitry Andric std::tie(Result, Chain) = 398bdd1243dSDimitry Andric makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain); 399bdd1243dSDimitry Andric return Result; 400bdd1243dSDimitry Andric } 401bdd1243dSDimitry Andric 402bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op, 403bdd1243dSDimitry Andric SelectionDAG &DAG) const { 404bdd1243dSDimitry Andric assert(Subtarget.is64Bit() && Subtarget.hasBasicF() && 405bdd1243dSDimitry Andric !Subtarget.hasBasicD() && "unexpected target features"); 406bdd1243dSDimitry Andric 407bdd1243dSDimitry Andric SDLoc DL(Op); 408bdd1243dSDimitry Andric SDValue Op0 = Op.getOperand(0); 409bdd1243dSDimitry Andric 410bdd1243dSDimitry Andric if ((Op0.getOpcode() == ISD::AssertSext || 411bdd1243dSDimitry Andric Op0.getOpcode() == ISD::SIGN_EXTEND_INREG) && 412bdd1243dSDimitry Andric dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32)) 413bdd1243dSDimitry Andric return Op; 414bdd1243dSDimitry Andric 415bdd1243dSDimitry Andric EVT OpVT = Op0.getValueType(); 416bdd1243dSDimitry Andric EVT RetVT = Op.getValueType(); 417bdd1243dSDimitry Andric RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT); 418bdd1243dSDimitry Andric MakeLibCallOptions CallOptions; 419bdd1243dSDimitry Andric CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true); 420bdd1243dSDimitry Andric SDValue Chain = SDValue(); 421bdd1243dSDimitry Andric SDValue Result; 422bdd1243dSDimitry Andric std::tie(Result, Chain) = 423bdd1243dSDimitry Andric makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain); 424bdd1243dSDimitry Andric return Result; 425753f127fSDimitry Andric } 426753f127fSDimitry Andric 427753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op, 428753f127fSDimitry Andric SelectionDAG &DAG) const { 429753f127fSDimitry Andric 430753f127fSDimitry Andric SDLoc DL(Op); 431753f127fSDimitry Andric SDValue Op0 = Op.getOperand(0); 432753f127fSDimitry Andric 433753f127fSDimitry Andric if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 && 434753f127fSDimitry Andric Subtarget.is64Bit() && Subtarget.hasBasicF()) { 435753f127fSDimitry Andric SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0); 436753f127fSDimitry Andric return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0); 437753f127fSDimitry Andric } 438753f127fSDimitry Andric return Op; 439753f127fSDimitry Andric } 440753f127fSDimitry Andric 441753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op, 442753f127fSDimitry Andric SelectionDAG &DAG) const { 443753f127fSDimitry Andric 444753f127fSDimitry Andric SDLoc DL(Op); 445753f127fSDimitry Andric 446753f127fSDimitry Andric if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() && 447753f127fSDimitry Andric !Subtarget.hasBasicD()) { 448753f127fSDimitry Andric SDValue Dst = 449753f127fSDimitry Andric DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0)); 450753f127fSDimitry Andric return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst); 451753f127fSDimitry Andric } 452753f127fSDimitry Andric 453753f127fSDimitry Andric EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits()); 454753f127fSDimitry Andric SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0)); 455753f127fSDimitry Andric return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc); 456753f127fSDimitry Andric } 457753f127fSDimitry Andric 458bdd1243dSDimitry Andric static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty, 459bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 460bdd1243dSDimitry Andric return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags); 461bdd1243dSDimitry Andric } 462bdd1243dSDimitry Andric 463bdd1243dSDimitry Andric static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty, 464bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 465bdd1243dSDimitry Andric return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(), 466bdd1243dSDimitry Andric Flags); 467bdd1243dSDimitry Andric } 468bdd1243dSDimitry Andric 469bdd1243dSDimitry Andric static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty, 470bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 471bdd1243dSDimitry Andric return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(), 472bdd1243dSDimitry Andric N->getOffset(), Flags); 473bdd1243dSDimitry Andric } 474bdd1243dSDimitry Andric 475bdd1243dSDimitry Andric static SDValue getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty, 476bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 477bdd1243dSDimitry Andric return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags); 478bdd1243dSDimitry Andric } 479bdd1243dSDimitry Andric 480bdd1243dSDimitry Andric template <class NodeTy> 481bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG, 482bdd1243dSDimitry Andric bool IsLocal) const { 483bdd1243dSDimitry Andric SDLoc DL(N); 484bdd1243dSDimitry Andric EVT Ty = getPointerTy(DAG.getDataLayout()); 485bdd1243dSDimitry Andric SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0); 486*06c3fb27SDimitry Andric 487*06c3fb27SDimitry Andric switch (DAG.getTarget().getCodeModel()) { 488*06c3fb27SDimitry Andric default: 489*06c3fb27SDimitry Andric report_fatal_error("Unsupported code model"); 490*06c3fb27SDimitry Andric 491*06c3fb27SDimitry Andric case CodeModel::Large: { 492*06c3fb27SDimitry Andric assert(Subtarget.is64Bit() && "Large code model requires LA64"); 493*06c3fb27SDimitry Andric 494*06c3fb27SDimitry Andric // This is not actually used, but is necessary for successfully matching 495*06c3fb27SDimitry Andric // the PseudoLA_*_LARGE nodes. 496*06c3fb27SDimitry Andric SDValue Tmp = DAG.getConstant(0, DL, Ty); 497*06c3fb27SDimitry Andric if (IsLocal) 498*06c3fb27SDimitry Andric // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that 499*06c3fb27SDimitry Andric // eventually becomes the desired 5-insn code sequence. 500*06c3fb27SDimitry Andric return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty, 501*06c3fb27SDimitry Andric Tmp, Addr), 502*06c3fb27SDimitry Andric 0); 503*06c3fb27SDimitry Andric 504*06c3fb27SDimitry Andric // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that eventually 505*06c3fb27SDimitry Andric // becomes the desired 5-insn code sequence. 506*06c3fb27SDimitry Andric return SDValue( 507*06c3fb27SDimitry Andric DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr), 508*06c3fb27SDimitry Andric 0); 509*06c3fb27SDimitry Andric } 510*06c3fb27SDimitry Andric 511*06c3fb27SDimitry Andric case CodeModel::Small: 512*06c3fb27SDimitry Andric case CodeModel::Medium: 513bdd1243dSDimitry Andric if (IsLocal) 514bdd1243dSDimitry Andric // This generates the pattern (PseudoLA_PCREL sym), which expands to 515bdd1243dSDimitry Andric // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)). 516*06c3fb27SDimitry Andric return SDValue( 517*06c3fb27SDimitry Andric DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0); 518bdd1243dSDimitry Andric 519bdd1243dSDimitry Andric // This generates the pattern (PseudoLA_GOT sym), which expands to (ld.w/d 520bdd1243dSDimitry Andric // (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)). 521*06c3fb27SDimitry Andric return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 522*06c3fb27SDimitry Andric 0); 523*06c3fb27SDimitry Andric } 524bdd1243dSDimitry Andric } 525bdd1243dSDimitry Andric 526bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op, 527bdd1243dSDimitry Andric SelectionDAG &DAG) const { 528bdd1243dSDimitry Andric return getAddr(cast<BlockAddressSDNode>(Op), DAG); 529bdd1243dSDimitry Andric } 530bdd1243dSDimitry Andric 531bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op, 532bdd1243dSDimitry Andric SelectionDAG &DAG) const { 533bdd1243dSDimitry Andric return getAddr(cast<JumpTableSDNode>(Op), DAG); 534bdd1243dSDimitry Andric } 535bdd1243dSDimitry Andric 536753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op, 537753f127fSDimitry Andric SelectionDAG &DAG) const { 538bdd1243dSDimitry Andric return getAddr(cast<ConstantPoolSDNode>(Op), DAG); 539753f127fSDimitry Andric } 540753f127fSDimitry Andric 541753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op, 542753f127fSDimitry Andric SelectionDAG &DAG) const { 543bdd1243dSDimitry Andric GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); 544bdd1243dSDimitry Andric assert(N->getOffset() == 0 && "unexpected offset in global node"); 545bdd1243dSDimitry Andric return getAddr(N, DAG, N->getGlobal()->isDSOLocal()); 546bdd1243dSDimitry Andric } 547753f127fSDimitry Andric 548bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N, 549bdd1243dSDimitry Andric SelectionDAG &DAG, 550*06c3fb27SDimitry Andric unsigned Opc, 551*06c3fb27SDimitry Andric bool Large) const { 552bdd1243dSDimitry Andric SDLoc DL(N); 553bdd1243dSDimitry Andric EVT Ty = getPointerTy(DAG.getDataLayout()); 554bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 555bdd1243dSDimitry Andric 556*06c3fb27SDimitry Andric // This is not actually used, but is necessary for successfully matching the 557*06c3fb27SDimitry Andric // PseudoLA_*_LARGE nodes. 558*06c3fb27SDimitry Andric SDValue Tmp = DAG.getConstant(0, DL, Ty); 559bdd1243dSDimitry Andric SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0); 560*06c3fb27SDimitry Andric SDValue Offset = Large 561*06c3fb27SDimitry Andric ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0) 562*06c3fb27SDimitry Andric : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0); 563bdd1243dSDimitry Andric 564bdd1243dSDimitry Andric // Add the thread pointer. 565bdd1243dSDimitry Andric return DAG.getNode(ISD::ADD, DL, Ty, Offset, 566bdd1243dSDimitry Andric DAG.getRegister(LoongArch::R2, GRLenVT)); 567bdd1243dSDimitry Andric } 568bdd1243dSDimitry Andric 569bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N, 570bdd1243dSDimitry Andric SelectionDAG &DAG, 571*06c3fb27SDimitry Andric unsigned Opc, 572*06c3fb27SDimitry Andric bool Large) const { 573bdd1243dSDimitry Andric SDLoc DL(N); 574bdd1243dSDimitry Andric EVT Ty = getPointerTy(DAG.getDataLayout()); 575bdd1243dSDimitry Andric IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits()); 576bdd1243dSDimitry Andric 577*06c3fb27SDimitry Andric // This is not actually used, but is necessary for successfully matching the 578*06c3fb27SDimitry Andric // PseudoLA_*_LARGE nodes. 579*06c3fb27SDimitry Andric SDValue Tmp = DAG.getConstant(0, DL, Ty); 580*06c3fb27SDimitry Andric 581bdd1243dSDimitry Andric // Use a PC-relative addressing mode to access the dynamic GOT address. 582bdd1243dSDimitry Andric SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0); 583*06c3fb27SDimitry Andric SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0) 584*06c3fb27SDimitry Andric : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0); 585bdd1243dSDimitry Andric 586bdd1243dSDimitry Andric // Prepare argument list to generate call. 587bdd1243dSDimitry Andric ArgListTy Args; 588bdd1243dSDimitry Andric ArgListEntry Entry; 589bdd1243dSDimitry Andric Entry.Node = Load; 590bdd1243dSDimitry Andric Entry.Ty = CallTy; 591bdd1243dSDimitry Andric Args.push_back(Entry); 592bdd1243dSDimitry Andric 593bdd1243dSDimitry Andric // Setup call to __tls_get_addr. 594bdd1243dSDimitry Andric TargetLowering::CallLoweringInfo CLI(DAG); 595bdd1243dSDimitry Andric CLI.setDebugLoc(DL) 596bdd1243dSDimitry Andric .setChain(DAG.getEntryNode()) 597bdd1243dSDimitry Andric .setLibCallee(CallingConv::C, CallTy, 598bdd1243dSDimitry Andric DAG.getExternalSymbol("__tls_get_addr", Ty), 599bdd1243dSDimitry Andric std::move(Args)); 600bdd1243dSDimitry Andric 601bdd1243dSDimitry Andric return LowerCallTo(CLI).first; 602bdd1243dSDimitry Andric } 603bdd1243dSDimitry Andric 604bdd1243dSDimitry Andric SDValue 605bdd1243dSDimitry Andric LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op, 606bdd1243dSDimitry Andric SelectionDAG &DAG) const { 607bdd1243dSDimitry Andric if (DAG.getMachineFunction().getFunction().getCallingConv() == 608bdd1243dSDimitry Andric CallingConv::GHC) 609bdd1243dSDimitry Andric report_fatal_error("In GHC calling convention TLS is not supported"); 610bdd1243dSDimitry Andric 611*06c3fb27SDimitry Andric bool Large = DAG.getTarget().getCodeModel() == CodeModel::Large; 612*06c3fb27SDimitry Andric assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64"); 613*06c3fb27SDimitry Andric 614bdd1243dSDimitry Andric GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); 615bdd1243dSDimitry Andric assert(N->getOffset() == 0 && "unexpected offset in global node"); 616bdd1243dSDimitry Andric 617bdd1243dSDimitry Andric SDValue Addr; 618bdd1243dSDimitry Andric switch (getTargetMachine().getTLSModel(N->getGlobal())) { 619bdd1243dSDimitry Andric case TLSModel::GeneralDynamic: 620bdd1243dSDimitry Andric // In this model, application code calls the dynamic linker function 621bdd1243dSDimitry Andric // __tls_get_addr to locate TLS offsets into the dynamic thread vector at 622bdd1243dSDimitry Andric // runtime. 623*06c3fb27SDimitry Andric Addr = getDynamicTLSAddr(N, DAG, 624*06c3fb27SDimitry Andric Large ? LoongArch::PseudoLA_TLS_GD_LARGE 625*06c3fb27SDimitry Andric : LoongArch::PseudoLA_TLS_GD, 626*06c3fb27SDimitry Andric Large); 627bdd1243dSDimitry Andric break; 628bdd1243dSDimitry Andric case TLSModel::LocalDynamic: 629bdd1243dSDimitry Andric // Same as GeneralDynamic, except for assembly modifiers and relocation 630bdd1243dSDimitry Andric // records. 631*06c3fb27SDimitry Andric Addr = getDynamicTLSAddr(N, DAG, 632*06c3fb27SDimitry Andric Large ? LoongArch::PseudoLA_TLS_LD_LARGE 633*06c3fb27SDimitry Andric : LoongArch::PseudoLA_TLS_LD, 634*06c3fb27SDimitry Andric Large); 635bdd1243dSDimitry Andric break; 636bdd1243dSDimitry Andric case TLSModel::InitialExec: 637bdd1243dSDimitry Andric // This model uses the GOT to resolve TLS offsets. 638*06c3fb27SDimitry Andric Addr = getStaticTLSAddr(N, DAG, 639*06c3fb27SDimitry Andric Large ? LoongArch::PseudoLA_TLS_IE_LARGE 640*06c3fb27SDimitry Andric : LoongArch::PseudoLA_TLS_IE, 641*06c3fb27SDimitry Andric Large); 642bdd1243dSDimitry Andric break; 643bdd1243dSDimitry Andric case TLSModel::LocalExec: 644bdd1243dSDimitry Andric // This model is used when static linking as the TLS offsets are resolved 645bdd1243dSDimitry Andric // during program linking. 646*06c3fb27SDimitry Andric // 647*06c3fb27SDimitry Andric // This node doesn't need an extra argument for the large code model. 648bdd1243dSDimitry Andric Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE); 649bdd1243dSDimitry Andric break; 650bdd1243dSDimitry Andric } 651bdd1243dSDimitry Andric 652753f127fSDimitry Andric return Addr; 653753f127fSDimitry Andric } 654bdd1243dSDimitry Andric 655bdd1243dSDimitry Andric SDValue 656bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, 657bdd1243dSDimitry Andric SelectionDAG &DAG) const { 658bdd1243dSDimitry Andric switch (Op.getConstantOperandVal(0)) { 659bdd1243dSDimitry Andric default: 660bdd1243dSDimitry Andric return SDValue(); // Don't custom lower most intrinsics. 661bdd1243dSDimitry Andric case Intrinsic::thread_pointer: { 662bdd1243dSDimitry Andric EVT PtrVT = getPointerTy(DAG.getDataLayout()); 663bdd1243dSDimitry Andric return DAG.getRegister(LoongArch::R2, PtrVT); 664bdd1243dSDimitry Andric } 665bdd1243dSDimitry Andric } 666bdd1243dSDimitry Andric } 667bdd1243dSDimitry Andric 668*06c3fb27SDimitry Andric // Helper function that emits error message for intrinsics with chain and return 669*06c3fb27SDimitry Andric // merge values of a UNDEF and the chain. 670bdd1243dSDimitry Andric static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op, 671bdd1243dSDimitry Andric StringRef ErrorMsg, 672bdd1243dSDimitry Andric SelectionDAG &DAG) { 673*06c3fb27SDimitry Andric DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + "."); 674bdd1243dSDimitry Andric return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, 675bdd1243dSDimitry Andric SDLoc(Op)); 676bdd1243dSDimitry Andric } 677bdd1243dSDimitry Andric 678bdd1243dSDimitry Andric SDValue 679bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op, 680bdd1243dSDimitry Andric SelectionDAG &DAG) const { 681bdd1243dSDimitry Andric SDLoc DL(Op); 682bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 683*06c3fb27SDimitry Andric EVT VT = Op.getValueType(); 684*06c3fb27SDimitry Andric SDValue Chain = Op.getOperand(0); 685*06c3fb27SDimitry Andric const StringRef ErrorMsgOOR = "argument out of range"; 686*06c3fb27SDimitry Andric const StringRef ErrorMsgReqLA64 = "requires loongarch64"; 687*06c3fb27SDimitry Andric const StringRef ErrorMsgReqF = "requires basic 'f' target feature"; 688bdd1243dSDimitry Andric 689bdd1243dSDimitry Andric switch (Op.getConstantOperandVal(1)) { 690bdd1243dSDimitry Andric default: 691bdd1243dSDimitry Andric return Op; 692bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_b_w: 693bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_h_w: 694bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_w_w: 695bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_d_w: 696bdd1243dSDimitry Andric case Intrinsic::loongarch_crcc_w_b_w: 697bdd1243dSDimitry Andric case Intrinsic::loongarch_crcc_w_h_w: 698bdd1243dSDimitry Andric case Intrinsic::loongarch_crcc_w_w_w: 699*06c3fb27SDimitry Andric case Intrinsic::loongarch_crcc_w_d_w: 700*06c3fb27SDimitry Andric return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG); 701bdd1243dSDimitry Andric case Intrinsic::loongarch_csrrd_w: 702bdd1243dSDimitry Andric case Intrinsic::loongarch_csrrd_d: { 703bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue(); 704*06c3fb27SDimitry Andric return !isUInt<14>(Imm) 705*06c3fb27SDimitry Andric ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG) 706*06c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other}, 707*06c3fb27SDimitry Andric {Chain, DAG.getConstant(Imm, DL, GRLenVT)}); 708bdd1243dSDimitry Andric } 709bdd1243dSDimitry Andric case Intrinsic::loongarch_csrwr_w: 710bdd1243dSDimitry Andric case Intrinsic::loongarch_csrwr_d: { 711bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue(); 712*06c3fb27SDimitry Andric return !isUInt<14>(Imm) 713*06c3fb27SDimitry Andric ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG) 714*06c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other}, 715*06c3fb27SDimitry Andric {Chain, Op.getOperand(2), 716*06c3fb27SDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)}); 717bdd1243dSDimitry Andric } 718bdd1243dSDimitry Andric case Intrinsic::loongarch_csrxchg_w: 719bdd1243dSDimitry Andric case Intrinsic::loongarch_csrxchg_d: { 720bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(4))->getZExtValue(); 721*06c3fb27SDimitry Andric return !isUInt<14>(Imm) 722*06c3fb27SDimitry Andric ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG) 723*06c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other}, 724*06c3fb27SDimitry Andric {Chain, Op.getOperand(2), Op.getOperand(3), 725*06c3fb27SDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)}); 726bdd1243dSDimitry Andric } 727bdd1243dSDimitry Andric case Intrinsic::loongarch_iocsrrd_d: { 728*06c3fb27SDimitry Andric return DAG.getNode( 729*06c3fb27SDimitry Andric LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other}, 730*06c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))}); 731bdd1243dSDimitry Andric } 732bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE) \ 733bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 734*06c3fb27SDimitry Andric return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other}, \ 735*06c3fb27SDimitry Andric {Chain, Op.getOperand(2)}); \ 736bdd1243dSDimitry Andric } 737bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B); 738bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H); 739bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W); 740bdd1243dSDimitry Andric #undef IOCSRRD_CASE 741bdd1243dSDimitry Andric case Intrinsic::loongarch_cpucfg: { 742*06c3fb27SDimitry Andric return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other}, 743*06c3fb27SDimitry Andric {Chain, Op.getOperand(2)}); 744bdd1243dSDimitry Andric } 745bdd1243dSDimitry Andric case Intrinsic::loongarch_lddir_d: { 746bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue(); 747*06c3fb27SDimitry Andric return !isUInt<8>(Imm) 748*06c3fb27SDimitry Andric ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG) 749*06c3fb27SDimitry Andric : Op; 750bdd1243dSDimitry Andric } 751bdd1243dSDimitry Andric case Intrinsic::loongarch_movfcsr2gr: { 752*06c3fb27SDimitry Andric if (!Subtarget.hasBasicF()) 753*06c3fb27SDimitry Andric return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG); 754bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue(); 755*06c3fb27SDimitry Andric return !isUInt<2>(Imm) 756*06c3fb27SDimitry Andric ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG) 757*06c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other}, 758*06c3fb27SDimitry Andric {Chain, DAG.getConstant(Imm, DL, GRLenVT)}); 759bdd1243dSDimitry Andric } 760bdd1243dSDimitry Andric } 761bdd1243dSDimitry Andric } 762bdd1243dSDimitry Andric 763bdd1243dSDimitry Andric // Helper function that emits error message for intrinsics with void return 764*06c3fb27SDimitry Andric // value and return the chain. 765bdd1243dSDimitry Andric static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg, 766bdd1243dSDimitry Andric SelectionDAG &DAG) { 767bdd1243dSDimitry Andric 768*06c3fb27SDimitry Andric DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + "."); 769bdd1243dSDimitry Andric return Op.getOperand(0); 770bdd1243dSDimitry Andric } 771bdd1243dSDimitry Andric 772bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op, 773bdd1243dSDimitry Andric SelectionDAG &DAG) const { 774bdd1243dSDimitry Andric SDLoc DL(Op); 775bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 776*06c3fb27SDimitry Andric SDValue Chain = Op.getOperand(0); 777bdd1243dSDimitry Andric uint64_t IntrinsicEnum = Op.getConstantOperandVal(1); 778bdd1243dSDimitry Andric SDValue Op2 = Op.getOperand(2); 779*06c3fb27SDimitry Andric const StringRef ErrorMsgOOR = "argument out of range"; 780*06c3fb27SDimitry Andric const StringRef ErrorMsgReqLA64 = "requires loongarch64"; 781*06c3fb27SDimitry Andric const StringRef ErrorMsgReqLA32 = "requires loongarch32"; 782*06c3fb27SDimitry Andric const StringRef ErrorMsgReqF = "requires basic 'f' target feature"; 783bdd1243dSDimitry Andric 784bdd1243dSDimitry Andric switch (IntrinsicEnum) { 785bdd1243dSDimitry Andric default: 786bdd1243dSDimitry Andric // TODO: Add more Intrinsics. 787bdd1243dSDimitry Andric return SDValue(); 788bdd1243dSDimitry Andric case Intrinsic::loongarch_cacop_d: 789bdd1243dSDimitry Andric case Intrinsic::loongarch_cacop_w: { 790*06c3fb27SDimitry Andric if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit()) 791*06c3fb27SDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG); 792*06c3fb27SDimitry Andric if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit()) 793*06c3fb27SDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG); 794bdd1243dSDimitry Andric // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12) 795bdd1243dSDimitry Andric unsigned Imm1 = cast<ConstantSDNode>(Op2)->getZExtValue(); 796*06c3fb27SDimitry Andric int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue(); 797*06c3fb27SDimitry Andric if (!isUInt<5>(Imm1) || !isInt<12>(Imm2)) 798bdd1243dSDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG); 799bdd1243dSDimitry Andric return Op; 800bdd1243dSDimitry Andric } 801bdd1243dSDimitry Andric case Intrinsic::loongarch_dbar: { 802bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 803*06c3fb27SDimitry Andric return !isUInt<15>(Imm) 804*06c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 805*06c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain, 806bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 807bdd1243dSDimitry Andric } 808bdd1243dSDimitry Andric case Intrinsic::loongarch_ibar: { 809bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 810*06c3fb27SDimitry Andric return !isUInt<15>(Imm) 811*06c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 812*06c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain, 813bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 814bdd1243dSDimitry Andric } 815bdd1243dSDimitry Andric case Intrinsic::loongarch_break: { 816bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 817*06c3fb27SDimitry Andric return !isUInt<15>(Imm) 818*06c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 819*06c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain, 820bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 821bdd1243dSDimitry Andric } 822bdd1243dSDimitry Andric case Intrinsic::loongarch_movgr2fcsr: { 823*06c3fb27SDimitry Andric if (!Subtarget.hasBasicF()) 824*06c3fb27SDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG); 825bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 826*06c3fb27SDimitry Andric return !isUInt<2>(Imm) 827*06c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 828*06c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain, 829bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT), 830*06c3fb27SDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, 831*06c3fb27SDimitry Andric Op.getOperand(3))); 832bdd1243dSDimitry Andric } 833bdd1243dSDimitry Andric case Intrinsic::loongarch_syscall: { 834bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 835*06c3fb27SDimitry Andric return !isUInt<15>(Imm) 836*06c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 837*06c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain, 838bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 839bdd1243dSDimitry Andric } 840bdd1243dSDimitry Andric #define IOCSRWR_CASE(NAME, NODE) \ 841bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 842bdd1243dSDimitry Andric SDValue Op3 = Op.getOperand(3); \ 843*06c3fb27SDimitry Andric return Subtarget.is64Bit() \ 844*06c3fb27SDimitry Andric ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, \ 845bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \ 846*06c3fb27SDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)) \ 847*06c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2, \ 848*06c3fb27SDimitry Andric Op3); \ 849bdd1243dSDimitry Andric } 850bdd1243dSDimitry Andric IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B); 851bdd1243dSDimitry Andric IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H); 852bdd1243dSDimitry Andric IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W); 853bdd1243dSDimitry Andric #undef IOCSRWR_CASE 854bdd1243dSDimitry Andric case Intrinsic::loongarch_iocsrwr_d: { 855*06c3fb27SDimitry Andric return !Subtarget.is64Bit() 856*06c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) 857*06c3fb27SDimitry Andric : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain, 858*06c3fb27SDimitry Andric Op2, 859*06c3fb27SDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, 860*06c3fb27SDimitry Andric Op.getOperand(3))); 861bdd1243dSDimitry Andric } 862bdd1243dSDimitry Andric #define ASRT_LE_GT_CASE(NAME) \ 863bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 864*06c3fb27SDimitry Andric return !Subtarget.is64Bit() \ 865*06c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) \ 866*06c3fb27SDimitry Andric : Op; \ 867bdd1243dSDimitry Andric } 868bdd1243dSDimitry Andric ASRT_LE_GT_CASE(asrtle_d) 869bdd1243dSDimitry Andric ASRT_LE_GT_CASE(asrtgt_d) 870bdd1243dSDimitry Andric #undef ASRT_LE_GT_CASE 871bdd1243dSDimitry Andric case Intrinsic::loongarch_ldpte_d: { 872bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue(); 873*06c3fb27SDimitry Andric return !Subtarget.is64Bit() 874*06c3fb27SDimitry Andric ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) 875*06c3fb27SDimitry Andric : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG) 876*06c3fb27SDimitry Andric : Op; 877bdd1243dSDimitry Andric } 878bdd1243dSDimitry Andric } 879753f127fSDimitry Andric } 880753f127fSDimitry Andric 88181ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op, 88281ad6265SDimitry Andric SelectionDAG &DAG) const { 88381ad6265SDimitry Andric SDLoc DL(Op); 88481ad6265SDimitry Andric SDValue Lo = Op.getOperand(0); 88581ad6265SDimitry Andric SDValue Hi = Op.getOperand(1); 88681ad6265SDimitry Andric SDValue Shamt = Op.getOperand(2); 88781ad6265SDimitry Andric EVT VT = Lo.getValueType(); 88881ad6265SDimitry Andric 88981ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 89081ad6265SDimitry Andric // Lo = Lo << Shamt 89181ad6265SDimitry Andric // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt)) 89281ad6265SDimitry Andric // else: 89381ad6265SDimitry Andric // Lo = 0 89481ad6265SDimitry Andric // Hi = Lo << (Shamt-GRLen) 89581ad6265SDimitry Andric 89681ad6265SDimitry Andric SDValue Zero = DAG.getConstant(0, DL, VT); 89781ad6265SDimitry Andric SDValue One = DAG.getConstant(1, DL, VT); 89881ad6265SDimitry Andric SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT); 89981ad6265SDimitry Andric SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT); 90081ad6265SDimitry Andric SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen); 90181ad6265SDimitry Andric SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1); 90281ad6265SDimitry Andric 90381ad6265SDimitry Andric SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt); 90481ad6265SDimitry Andric SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One); 90581ad6265SDimitry Andric SDValue ShiftRightLo = 90681ad6265SDimitry Andric DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt); 90781ad6265SDimitry Andric SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt); 90881ad6265SDimitry Andric SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo); 90981ad6265SDimitry Andric SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen); 91081ad6265SDimitry Andric 91181ad6265SDimitry Andric SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT); 91281ad6265SDimitry Andric 91381ad6265SDimitry Andric Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero); 91481ad6265SDimitry Andric Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); 91581ad6265SDimitry Andric 91681ad6265SDimitry Andric SDValue Parts[2] = {Lo, Hi}; 91781ad6265SDimitry Andric return DAG.getMergeValues(Parts, DL); 91881ad6265SDimitry Andric } 91981ad6265SDimitry Andric 92081ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op, 92181ad6265SDimitry Andric SelectionDAG &DAG, 92281ad6265SDimitry Andric bool IsSRA) const { 92381ad6265SDimitry Andric SDLoc DL(Op); 92481ad6265SDimitry Andric SDValue Lo = Op.getOperand(0); 92581ad6265SDimitry Andric SDValue Hi = Op.getOperand(1); 92681ad6265SDimitry Andric SDValue Shamt = Op.getOperand(2); 92781ad6265SDimitry Andric EVT VT = Lo.getValueType(); 92881ad6265SDimitry Andric 92981ad6265SDimitry Andric // SRA expansion: 93081ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 93181ad6265SDimitry Andric // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1)) 93281ad6265SDimitry Andric // Hi = Hi >>s Shamt 93381ad6265SDimitry Andric // else: 93481ad6265SDimitry Andric // Lo = Hi >>s (Shamt-GRLen); 93581ad6265SDimitry Andric // Hi = Hi >>s (GRLen-1) 93681ad6265SDimitry Andric // 93781ad6265SDimitry Andric // SRL expansion: 93881ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 93981ad6265SDimitry Andric // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1)) 94081ad6265SDimitry Andric // Hi = Hi >>u Shamt 94181ad6265SDimitry Andric // else: 94281ad6265SDimitry Andric // Lo = Hi >>u (Shamt-GRLen); 94381ad6265SDimitry Andric // Hi = 0; 94481ad6265SDimitry Andric 94581ad6265SDimitry Andric unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL; 94681ad6265SDimitry Andric 94781ad6265SDimitry Andric SDValue Zero = DAG.getConstant(0, DL, VT); 94881ad6265SDimitry Andric SDValue One = DAG.getConstant(1, DL, VT); 94981ad6265SDimitry Andric SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT); 95081ad6265SDimitry Andric SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT); 95181ad6265SDimitry Andric SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen); 95281ad6265SDimitry Andric SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1); 95381ad6265SDimitry Andric 95481ad6265SDimitry Andric SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt); 95581ad6265SDimitry Andric SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One); 95681ad6265SDimitry Andric SDValue ShiftLeftHi = 95781ad6265SDimitry Andric DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt); 95881ad6265SDimitry Andric SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi); 95981ad6265SDimitry Andric SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt); 96081ad6265SDimitry Andric SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen); 96181ad6265SDimitry Andric SDValue HiFalse = 96281ad6265SDimitry Andric IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero; 96381ad6265SDimitry Andric 96481ad6265SDimitry Andric SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT); 96581ad6265SDimitry Andric 96681ad6265SDimitry Andric Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse); 96781ad6265SDimitry Andric Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); 96881ad6265SDimitry Andric 96981ad6265SDimitry Andric SDValue Parts[2] = {Lo, Hi}; 97081ad6265SDimitry Andric return DAG.getMergeValues(Parts, DL); 97181ad6265SDimitry Andric } 97281ad6265SDimitry Andric 97381ad6265SDimitry Andric // Returns the opcode of the target-specific SDNode that implements the 32-bit 97481ad6265SDimitry Andric // form of the given Opcode. 97581ad6265SDimitry Andric static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode) { 97681ad6265SDimitry Andric switch (Opcode) { 97781ad6265SDimitry Andric default: 97881ad6265SDimitry Andric llvm_unreachable("Unexpected opcode"); 97981ad6265SDimitry Andric case ISD::SHL: 98081ad6265SDimitry Andric return LoongArchISD::SLL_W; 98181ad6265SDimitry Andric case ISD::SRA: 98281ad6265SDimitry Andric return LoongArchISD::SRA_W; 98381ad6265SDimitry Andric case ISD::SRL: 98481ad6265SDimitry Andric return LoongArchISD::SRL_W; 985bdd1243dSDimitry Andric case ISD::ROTR: 986bdd1243dSDimitry Andric return LoongArchISD::ROTR_W; 987bdd1243dSDimitry Andric case ISD::ROTL: 988bdd1243dSDimitry Andric return LoongArchISD::ROTL_W; 989bdd1243dSDimitry Andric case ISD::CTTZ: 990bdd1243dSDimitry Andric return LoongArchISD::CTZ_W; 991bdd1243dSDimitry Andric case ISD::CTLZ: 992bdd1243dSDimitry Andric return LoongArchISD::CLZ_W; 99381ad6265SDimitry Andric } 99481ad6265SDimitry Andric } 99581ad6265SDimitry Andric 99681ad6265SDimitry Andric // Converts the given i8/i16/i32 operation to a target-specific SelectionDAG 99781ad6265SDimitry Andric // node. Because i8/i16/i32 isn't a legal type for LA64, these operations would 99881ad6265SDimitry Andric // otherwise be promoted to i64, making it difficult to select the 99981ad6265SDimitry Andric // SLL_W/.../*W later one because the fact the operation was originally of 100081ad6265SDimitry Andric // type i8/i16/i32 is lost. 1001bdd1243dSDimitry Andric static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp, 100281ad6265SDimitry Andric unsigned ExtOpc = ISD::ANY_EXTEND) { 100381ad6265SDimitry Andric SDLoc DL(N); 100481ad6265SDimitry Andric LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode()); 1005bdd1243dSDimitry Andric SDValue NewOp0, NewRes; 1006bdd1243dSDimitry Andric 1007bdd1243dSDimitry Andric switch (NumOp) { 1008bdd1243dSDimitry Andric default: 1009bdd1243dSDimitry Andric llvm_unreachable("Unexpected NumOp"); 1010bdd1243dSDimitry Andric case 1: { 1011bdd1243dSDimitry Andric NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0)); 1012bdd1243dSDimitry Andric NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0); 1013bdd1243dSDimitry Andric break; 1014bdd1243dSDimitry Andric } 1015bdd1243dSDimitry Andric case 2: { 1016bdd1243dSDimitry Andric NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0)); 101781ad6265SDimitry Andric SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1)); 1018bdd1243dSDimitry Andric NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1); 1019bdd1243dSDimitry Andric break; 1020bdd1243dSDimitry Andric } 1021bdd1243dSDimitry Andric // TODO:Handle more NumOp. 1022bdd1243dSDimitry Andric } 1023bdd1243dSDimitry Andric 1024bdd1243dSDimitry Andric // ReplaceNodeResults requires we maintain the same type for the return 1025bdd1243dSDimitry Andric // value. 102681ad6265SDimitry Andric return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes); 102781ad6265SDimitry Andric } 102881ad6265SDimitry Andric 1029*06c3fb27SDimitry Andric // Helper function that emits error message for intrinsics with chain and return 1030*06c3fb27SDimitry Andric // a UNDEF and the chain as the results. 1031*06c3fb27SDimitry Andric static void emitErrorAndReplaceIntrinsicWithChainResults( 1032*06c3fb27SDimitry Andric SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG, 1033*06c3fb27SDimitry Andric StringRef ErrorMsg) { 1034*06c3fb27SDimitry Andric DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + "."); 1035*06c3fb27SDimitry Andric Results.push_back(DAG.getUNDEF(N->getValueType(0))); 1036*06c3fb27SDimitry Andric Results.push_back(N->getOperand(0)); 1037*06c3fb27SDimitry Andric } 1038*06c3fb27SDimitry Andric 103981ad6265SDimitry Andric void LoongArchTargetLowering::ReplaceNodeResults( 104081ad6265SDimitry Andric SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const { 104181ad6265SDimitry Andric SDLoc DL(N); 1042bdd1243dSDimitry Andric EVT VT = N->getValueType(0); 104381ad6265SDimitry Andric switch (N->getOpcode()) { 104481ad6265SDimitry Andric default: 104581ad6265SDimitry Andric llvm_unreachable("Don't know how to legalize this operation"); 104681ad6265SDimitry Andric case ISD::SHL: 104781ad6265SDimitry Andric case ISD::SRA: 104881ad6265SDimitry Andric case ISD::SRL: 1049bdd1243dSDimitry Andric case ISD::ROTR: 1050bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 105181ad6265SDimitry Andric "Unexpected custom legalisation"); 105281ad6265SDimitry Andric if (N->getOperand(1).getOpcode() != ISD::Constant) { 1053bdd1243dSDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG, 2)); 1054bdd1243dSDimitry Andric break; 1055bdd1243dSDimitry Andric } 1056bdd1243dSDimitry Andric break; 1057bdd1243dSDimitry Andric case ISD::ROTL: 1058bdd1243dSDimitry Andric ConstantSDNode *CN; 1059bdd1243dSDimitry Andric if ((CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) { 1060bdd1243dSDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG, 2)); 106181ad6265SDimitry Andric break; 106281ad6265SDimitry Andric } 106381ad6265SDimitry Andric break; 1064753f127fSDimitry Andric case ISD::FP_TO_SINT: { 1065bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 1066753f127fSDimitry Andric "Unexpected custom legalisation"); 1067753f127fSDimitry Andric SDValue Src = N->getOperand(0); 1068bdd1243dSDimitry Andric EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0)); 1069bdd1243dSDimitry Andric if (getTypeAction(*DAG.getContext(), Src.getValueType()) != 1070bdd1243dSDimitry Andric TargetLowering::TypeSoftenFloat) { 1071bdd1243dSDimitry Andric SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src); 1072bdd1243dSDimitry Andric Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst)); 1073bdd1243dSDimitry Andric return; 1074bdd1243dSDimitry Andric } 1075bdd1243dSDimitry Andric // If the FP type needs to be softened, emit a library call using the 'si' 1076bdd1243dSDimitry Andric // version. If we left it to default legalization we'd end up with 'di'. 1077bdd1243dSDimitry Andric RTLIB::Libcall LC; 1078bdd1243dSDimitry Andric LC = RTLIB::getFPTOSINT(Src.getValueType(), VT); 1079bdd1243dSDimitry Andric MakeLibCallOptions CallOptions; 1080bdd1243dSDimitry Andric EVT OpVT = Src.getValueType(); 1081bdd1243dSDimitry Andric CallOptions.setTypeListBeforeSoften(OpVT, VT, true); 1082bdd1243dSDimitry Andric SDValue Chain = SDValue(); 1083bdd1243dSDimitry Andric SDValue Result; 1084bdd1243dSDimitry Andric std::tie(Result, Chain) = 1085bdd1243dSDimitry Andric makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain); 1086bdd1243dSDimitry Andric Results.push_back(Result); 1087753f127fSDimitry Andric break; 1088753f127fSDimitry Andric } 1089753f127fSDimitry Andric case ISD::BITCAST: { 1090753f127fSDimitry Andric SDValue Src = N->getOperand(0); 1091753f127fSDimitry Andric EVT SrcVT = Src.getValueType(); 1092753f127fSDimitry Andric if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() && 1093753f127fSDimitry Andric Subtarget.hasBasicF()) { 1094753f127fSDimitry Andric SDValue Dst = 1095753f127fSDimitry Andric DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src); 1096753f127fSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst)); 1097753f127fSDimitry Andric } 1098753f127fSDimitry Andric break; 1099753f127fSDimitry Andric } 1100753f127fSDimitry Andric case ISD::FP_TO_UINT: { 1101bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 1102753f127fSDimitry Andric "Unexpected custom legalisation"); 1103753f127fSDimitry Andric auto &TLI = DAG.getTargetLoweringInfo(); 1104753f127fSDimitry Andric SDValue Tmp1, Tmp2; 1105753f127fSDimitry Andric TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG); 1106753f127fSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1)); 1107753f127fSDimitry Andric break; 1108753f127fSDimitry Andric } 1109bdd1243dSDimitry Andric case ISD::BSWAP: { 1110bdd1243dSDimitry Andric SDValue Src = N->getOperand(0); 1111bdd1243dSDimitry Andric assert((VT == MVT::i16 || VT == MVT::i32) && 1112bdd1243dSDimitry Andric "Unexpected custom legalization"); 1113bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 1114bdd1243dSDimitry Andric SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src); 1115bdd1243dSDimitry Andric SDValue Tmp; 1116bdd1243dSDimitry Andric switch (VT.getSizeInBits()) { 1117bdd1243dSDimitry Andric default: 1118bdd1243dSDimitry Andric llvm_unreachable("Unexpected operand width"); 1119bdd1243dSDimitry Andric case 16: 1120bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc); 1121bdd1243dSDimitry Andric break; 1122bdd1243dSDimitry Andric case 32: 1123bdd1243dSDimitry Andric // Only LA64 will get to here due to the size mismatch between VT and 1124bdd1243dSDimitry Andric // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo. 1125bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc); 1126bdd1243dSDimitry Andric break; 1127bdd1243dSDimitry Andric } 1128bdd1243dSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp)); 1129bdd1243dSDimitry Andric break; 1130bdd1243dSDimitry Andric } 1131bdd1243dSDimitry Andric case ISD::BITREVERSE: { 1132bdd1243dSDimitry Andric SDValue Src = N->getOperand(0); 1133bdd1243dSDimitry Andric assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) && 1134bdd1243dSDimitry Andric "Unexpected custom legalization"); 1135bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 1136bdd1243dSDimitry Andric SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src); 1137bdd1243dSDimitry Andric SDValue Tmp; 1138bdd1243dSDimitry Andric switch (VT.getSizeInBits()) { 1139bdd1243dSDimitry Andric default: 1140bdd1243dSDimitry Andric llvm_unreachable("Unexpected operand width"); 1141bdd1243dSDimitry Andric case 8: 1142bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc); 1143bdd1243dSDimitry Andric break; 1144bdd1243dSDimitry Andric case 32: 1145bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc); 1146bdd1243dSDimitry Andric break; 1147bdd1243dSDimitry Andric } 1148bdd1243dSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp)); 1149bdd1243dSDimitry Andric break; 1150bdd1243dSDimitry Andric } 1151bdd1243dSDimitry Andric case ISD::CTLZ: 1152bdd1243dSDimitry Andric case ISD::CTTZ: { 1153bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 1154bdd1243dSDimitry Andric "Unexpected custom legalisation"); 1155bdd1243dSDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG, 1)); 1156bdd1243dSDimitry Andric break; 1157bdd1243dSDimitry Andric } 1158bdd1243dSDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 1159*06c3fb27SDimitry Andric SDValue Chain = N->getOperand(0); 1160bdd1243dSDimitry Andric SDValue Op2 = N->getOperand(2); 1161*06c3fb27SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 1162*06c3fb27SDimitry Andric const StringRef ErrorMsgOOR = "argument out of range"; 1163*06c3fb27SDimitry Andric const StringRef ErrorMsgReqLA64 = "requires loongarch64"; 1164*06c3fb27SDimitry Andric const StringRef ErrorMsgReqF = "requires basic 'f' target feature"; 1165bdd1243dSDimitry Andric 1166*06c3fb27SDimitry Andric switch (N->getConstantOperandVal(1)) { 1167bdd1243dSDimitry Andric default: 1168bdd1243dSDimitry Andric llvm_unreachable("Unexpected Intrinsic."); 1169*06c3fb27SDimitry Andric case Intrinsic::loongarch_movfcsr2gr: { 1170*06c3fb27SDimitry Andric if (!Subtarget.hasBasicF()) { 1171*06c3fb27SDimitry Andric emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG, 1172*06c3fb27SDimitry Andric ErrorMsgReqF); 1173*06c3fb27SDimitry Andric return; 1174*06c3fb27SDimitry Andric } 1175*06c3fb27SDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 1176*06c3fb27SDimitry Andric if (!isUInt<2>(Imm)) { 1177*06c3fb27SDimitry Andric emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG, 1178*06c3fb27SDimitry Andric ErrorMsgOOR); 1179*06c3fb27SDimitry Andric return; 1180*06c3fb27SDimitry Andric } 1181*06c3fb27SDimitry Andric SDValue MOVFCSR2GRResults = DAG.getNode( 1182*06c3fb27SDimitry Andric LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other}, 1183*06c3fb27SDimitry Andric {Chain, DAG.getConstant(Imm, DL, GRLenVT)}); 1184*06c3fb27SDimitry Andric Results.push_back( 1185*06c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0))); 1186*06c3fb27SDimitry Andric Results.push_back(MOVFCSR2GRResults.getValue(1)); 1187*06c3fb27SDimitry Andric break; 1188*06c3fb27SDimitry Andric } 1189bdd1243dSDimitry Andric #define CRC_CASE_EXT_BINARYOP(NAME, NODE) \ 1190bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 1191*06c3fb27SDimitry Andric SDValue NODE = DAG.getNode( \ 1192*06c3fb27SDimitry Andric LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \ 1193*06c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \ 1194*06c3fb27SDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \ 1195*06c3fb27SDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \ 1196*06c3fb27SDimitry Andric Results.push_back(NODE.getValue(1)); \ 1197bdd1243dSDimitry Andric break; \ 1198bdd1243dSDimitry Andric } 1199bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W) 1200bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W) 1201bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W) 1202bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W) 1203bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W) 1204bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W) 1205bdd1243dSDimitry Andric #undef CRC_CASE_EXT_BINARYOP 1206bdd1243dSDimitry Andric 1207bdd1243dSDimitry Andric #define CRC_CASE_EXT_UNARYOP(NAME, NODE) \ 1208bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 1209*06c3fb27SDimitry Andric SDValue NODE = DAG.getNode( \ 1210*06c3fb27SDimitry Andric LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \ 1211*06c3fb27SDimitry Andric {Chain, Op2, \ 1212*06c3fb27SDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \ 1213*06c3fb27SDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \ 1214*06c3fb27SDimitry Andric Results.push_back(NODE.getValue(1)); \ 1215bdd1243dSDimitry Andric break; \ 1216bdd1243dSDimitry Andric } 1217bdd1243dSDimitry Andric CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W) 1218bdd1243dSDimitry Andric CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W) 1219bdd1243dSDimitry Andric #undef CRC_CASE_EXT_UNARYOP 1220bdd1243dSDimitry Andric #define CSR_CASE(ID) \ 1221bdd1243dSDimitry Andric case Intrinsic::loongarch_##ID: { \ 1222*06c3fb27SDimitry Andric if (!Subtarget.is64Bit()) \ 1223*06c3fb27SDimitry Andric emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG, \ 1224*06c3fb27SDimitry Andric ErrorMsgReqLA64); \ 1225bdd1243dSDimitry Andric break; \ 1226bdd1243dSDimitry Andric } 1227bdd1243dSDimitry Andric CSR_CASE(csrrd_d); 1228bdd1243dSDimitry Andric CSR_CASE(csrwr_d); 1229bdd1243dSDimitry Andric CSR_CASE(csrxchg_d); 1230bdd1243dSDimitry Andric CSR_CASE(iocsrrd_d); 1231bdd1243dSDimitry Andric #undef CSR_CASE 1232bdd1243dSDimitry Andric case Intrinsic::loongarch_csrrd_w: { 1233bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 1234bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) { 1235*06c3fb27SDimitry Andric emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG, 1236*06c3fb27SDimitry Andric ErrorMsgOOR); 1237*06c3fb27SDimitry Andric return; 1238bdd1243dSDimitry Andric } 1239*06c3fb27SDimitry Andric SDValue CSRRDResults = 1240*06c3fb27SDimitry Andric DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other}, 1241*06c3fb27SDimitry Andric {Chain, DAG.getConstant(Imm, DL, GRLenVT)}); 1242bdd1243dSDimitry Andric Results.push_back( 1243*06c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0))); 1244*06c3fb27SDimitry Andric Results.push_back(CSRRDResults.getValue(1)); 1245bdd1243dSDimitry Andric break; 1246bdd1243dSDimitry Andric } 1247bdd1243dSDimitry Andric case Intrinsic::loongarch_csrwr_w: { 1248bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(); 1249bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) { 1250*06c3fb27SDimitry Andric emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG, 1251*06c3fb27SDimitry Andric ErrorMsgOOR); 1252*06c3fb27SDimitry Andric return; 1253bdd1243dSDimitry Andric } 1254*06c3fb27SDimitry Andric SDValue CSRWRResults = 1255*06c3fb27SDimitry Andric DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other}, 1256*06c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), 1257*06c3fb27SDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)}); 1258*06c3fb27SDimitry Andric Results.push_back( 1259*06c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0))); 1260*06c3fb27SDimitry Andric Results.push_back(CSRWRResults.getValue(1)); 1261bdd1243dSDimitry Andric break; 1262bdd1243dSDimitry Andric } 1263bdd1243dSDimitry Andric case Intrinsic::loongarch_csrxchg_w: { 1264bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(N->getOperand(4))->getZExtValue(); 1265bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) { 1266*06c3fb27SDimitry Andric emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG, 1267*06c3fb27SDimitry Andric ErrorMsgOOR); 1268*06c3fb27SDimitry Andric return; 1269bdd1243dSDimitry Andric } 1270*06c3fb27SDimitry Andric SDValue CSRXCHGResults = DAG.getNode( 1271*06c3fb27SDimitry Andric LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other}, 1272*06c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), 1273bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)), 1274*06c3fb27SDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)}); 1275*06c3fb27SDimitry Andric Results.push_back( 1276*06c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0))); 1277*06c3fb27SDimitry Andric Results.push_back(CSRXCHGResults.getValue(1)); 1278bdd1243dSDimitry Andric break; 1279bdd1243dSDimitry Andric } 1280bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE) \ 1281bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 1282*06c3fb27SDimitry Andric SDValue IOCSRRDResults = \ 1283*06c3fb27SDimitry Andric DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \ 1284*06c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \ 1285*06c3fb27SDimitry Andric Results.push_back( \ 1286*06c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0))); \ 1287*06c3fb27SDimitry Andric Results.push_back(IOCSRRDResults.getValue(1)); \ 1288bdd1243dSDimitry Andric break; \ 1289bdd1243dSDimitry Andric } 1290bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B); 1291bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H); 1292bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W); 1293bdd1243dSDimitry Andric #undef IOCSRRD_CASE 1294bdd1243dSDimitry Andric case Intrinsic::loongarch_cpucfg: { 1295*06c3fb27SDimitry Andric SDValue CPUCFGResults = 1296*06c3fb27SDimitry Andric DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other}, 1297*06c3fb27SDimitry Andric {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); 1298*06c3fb27SDimitry Andric Results.push_back( 1299*06c3fb27SDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0))); 1300*06c3fb27SDimitry Andric Results.push_back(CPUCFGResults.getValue(1)); 1301bdd1243dSDimitry Andric break; 1302bdd1243dSDimitry Andric } 1303bdd1243dSDimitry Andric case Intrinsic::loongarch_lddir_d: { 1304bdd1243dSDimitry Andric if (!Subtarget.is64Bit()) { 1305*06c3fb27SDimitry Andric emitErrorAndReplaceIntrinsicWithChainResults(N, Results, DAG, 1306*06c3fb27SDimitry Andric ErrorMsgReqLA64); 1307*06c3fb27SDimitry Andric return; 1308bdd1243dSDimitry Andric } 1309bdd1243dSDimitry Andric break; 1310bdd1243dSDimitry Andric } 1311bdd1243dSDimitry Andric } 1312bdd1243dSDimitry Andric break; 1313bdd1243dSDimitry Andric } 1314bdd1243dSDimitry Andric case ISD::READ_REGISTER: { 1315bdd1243dSDimitry Andric if (Subtarget.is64Bit()) 1316bdd1243dSDimitry Andric DAG.getContext()->emitError( 1317bdd1243dSDimitry Andric "On LA64, only 64-bit registers can be read."); 1318bdd1243dSDimitry Andric else 1319bdd1243dSDimitry Andric DAG.getContext()->emitError( 1320bdd1243dSDimitry Andric "On LA32, only 32-bit registers can be read."); 1321bdd1243dSDimitry Andric Results.push_back(DAG.getUNDEF(VT)); 1322bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 1323bdd1243dSDimitry Andric break; 1324bdd1243dSDimitry Andric } 132581ad6265SDimitry Andric } 132681ad6265SDimitry Andric } 132781ad6265SDimitry Andric 132881ad6265SDimitry Andric static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, 132981ad6265SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 133081ad6265SDimitry Andric const LoongArchSubtarget &Subtarget) { 133181ad6265SDimitry Andric if (DCI.isBeforeLegalizeOps()) 133281ad6265SDimitry Andric return SDValue(); 133381ad6265SDimitry Andric 133481ad6265SDimitry Andric SDValue FirstOperand = N->getOperand(0); 133581ad6265SDimitry Andric SDValue SecondOperand = N->getOperand(1); 133681ad6265SDimitry Andric unsigned FirstOperandOpc = FirstOperand.getOpcode(); 133781ad6265SDimitry Andric EVT ValTy = N->getValueType(0); 133881ad6265SDimitry Andric SDLoc DL(N); 133981ad6265SDimitry Andric uint64_t lsb, msb; 134081ad6265SDimitry Andric unsigned SMIdx, SMLen; 134181ad6265SDimitry Andric ConstantSDNode *CN; 134281ad6265SDimitry Andric SDValue NewOperand; 134381ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 134481ad6265SDimitry Andric 134581ad6265SDimitry Andric // Op's second operand must be a shifted mask. 134681ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) || 134781ad6265SDimitry Andric !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen)) 134881ad6265SDimitry Andric return SDValue(); 134981ad6265SDimitry Andric 135081ad6265SDimitry Andric if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) { 135181ad6265SDimitry Andric // Pattern match BSTRPICK. 135281ad6265SDimitry Andric // $dst = and ((sra or srl) $src , lsb), (2**len - 1) 135381ad6265SDimitry Andric // => BSTRPICK $dst, $src, msb, lsb 135481ad6265SDimitry Andric // where msb = lsb + len - 1 135581ad6265SDimitry Andric 135681ad6265SDimitry Andric // The second operand of the shift must be an immediate. 135781ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1)))) 135881ad6265SDimitry Andric return SDValue(); 135981ad6265SDimitry Andric 136081ad6265SDimitry Andric lsb = CN->getZExtValue(); 136181ad6265SDimitry Andric 136281ad6265SDimitry Andric // Return if the shifted mask does not start at bit 0 or the sum of its 136381ad6265SDimitry Andric // length and lsb exceeds the word's size. 136481ad6265SDimitry Andric if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits()) 136581ad6265SDimitry Andric return SDValue(); 136681ad6265SDimitry Andric 136781ad6265SDimitry Andric NewOperand = FirstOperand.getOperand(0); 136881ad6265SDimitry Andric } else { 136981ad6265SDimitry Andric // Pattern match BSTRPICK. 137081ad6265SDimitry Andric // $dst = and $src, (2**len- 1) , if len > 12 137181ad6265SDimitry Andric // => BSTRPICK $dst, $src, msb, lsb 137281ad6265SDimitry Andric // where lsb = 0 and msb = len - 1 137381ad6265SDimitry Andric 137481ad6265SDimitry Andric // If the mask is <= 0xfff, andi can be used instead. 137581ad6265SDimitry Andric if (CN->getZExtValue() <= 0xfff) 137681ad6265SDimitry Andric return SDValue(); 137781ad6265SDimitry Andric 1378*06c3fb27SDimitry Andric // Return if the MSB exceeds. 1379*06c3fb27SDimitry Andric if (SMIdx + SMLen > ValTy.getSizeInBits()) 138081ad6265SDimitry Andric return SDValue(); 138181ad6265SDimitry Andric 1382*06c3fb27SDimitry Andric if (SMIdx > 0) { 1383*06c3fb27SDimitry Andric // Omit if the constant has more than 2 uses. This a conservative 1384*06c3fb27SDimitry Andric // decision. Whether it is a win depends on the HW microarchitecture. 1385*06c3fb27SDimitry Andric // However it should always be better for 1 and 2 uses. 1386*06c3fb27SDimitry Andric if (CN->use_size() > 2) 1387*06c3fb27SDimitry Andric return SDValue(); 1388*06c3fb27SDimitry Andric // Return if the constant can be composed by a single LU12I.W. 1389*06c3fb27SDimitry Andric if ((CN->getZExtValue() & 0xfff) == 0) 1390*06c3fb27SDimitry Andric return SDValue(); 1391*06c3fb27SDimitry Andric // Return if the constand can be composed by a single ADDI with 1392*06c3fb27SDimitry Andric // the zero register. 1393*06c3fb27SDimitry Andric if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0) 1394*06c3fb27SDimitry Andric return SDValue(); 1395*06c3fb27SDimitry Andric } 1396*06c3fb27SDimitry Andric 1397*06c3fb27SDimitry Andric lsb = SMIdx; 139881ad6265SDimitry Andric NewOperand = FirstOperand; 139981ad6265SDimitry Andric } 1400*06c3fb27SDimitry Andric 140181ad6265SDimitry Andric msb = lsb + SMLen - 1; 1402*06c3fb27SDimitry Andric SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand, 140381ad6265SDimitry Andric DAG.getConstant(msb, DL, GRLenVT), 140481ad6265SDimitry Andric DAG.getConstant(lsb, DL, GRLenVT)); 1405*06c3fb27SDimitry Andric if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0) 1406*06c3fb27SDimitry Andric return NR0; 1407*06c3fb27SDimitry Andric // Try to optimize to 1408*06c3fb27SDimitry Andric // bstrpick $Rd, $Rs, msb, lsb 1409*06c3fb27SDimitry Andric // slli $Rd, $Rd, lsb 1410*06c3fb27SDimitry Andric return DAG.getNode(ISD::SHL, DL, ValTy, NR0, 1411*06c3fb27SDimitry Andric DAG.getConstant(lsb, DL, GRLenVT)); 141281ad6265SDimitry Andric } 141381ad6265SDimitry Andric 141481ad6265SDimitry Andric static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, 141581ad6265SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 141681ad6265SDimitry Andric const LoongArchSubtarget &Subtarget) { 141781ad6265SDimitry Andric if (DCI.isBeforeLegalizeOps()) 141881ad6265SDimitry Andric return SDValue(); 141981ad6265SDimitry Andric 142081ad6265SDimitry Andric // $dst = srl (and $src, Mask), Shamt 142181ad6265SDimitry Andric // => 142281ad6265SDimitry Andric // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt 142381ad6265SDimitry Andric // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1 142481ad6265SDimitry Andric // 142581ad6265SDimitry Andric 142681ad6265SDimitry Andric SDValue FirstOperand = N->getOperand(0); 142781ad6265SDimitry Andric ConstantSDNode *CN; 142881ad6265SDimitry Andric EVT ValTy = N->getValueType(0); 142981ad6265SDimitry Andric SDLoc DL(N); 143081ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 143181ad6265SDimitry Andric unsigned MaskIdx, MaskLen; 143281ad6265SDimitry Andric uint64_t Shamt; 143381ad6265SDimitry Andric 143481ad6265SDimitry Andric // The first operand must be an AND and the second operand of the AND must be 143581ad6265SDimitry Andric // a shifted mask. 143681ad6265SDimitry Andric if (FirstOperand.getOpcode() != ISD::AND || 143781ad6265SDimitry Andric !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) || 143881ad6265SDimitry Andric !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen)) 143981ad6265SDimitry Andric return SDValue(); 144081ad6265SDimitry Andric 144181ad6265SDimitry Andric // The second operand (shift amount) must be an immediate. 144281ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) 144381ad6265SDimitry Andric return SDValue(); 144481ad6265SDimitry Andric 144581ad6265SDimitry Andric Shamt = CN->getZExtValue(); 144681ad6265SDimitry Andric if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1) 144781ad6265SDimitry Andric return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, 144881ad6265SDimitry Andric FirstOperand->getOperand(0), 144981ad6265SDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 145081ad6265SDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 145181ad6265SDimitry Andric 145281ad6265SDimitry Andric return SDValue(); 145381ad6265SDimitry Andric } 145481ad6265SDimitry Andric 1455753f127fSDimitry Andric static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, 1456753f127fSDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 1457753f127fSDimitry Andric const LoongArchSubtarget &Subtarget) { 1458753f127fSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 1459753f127fSDimitry Andric EVT ValTy = N->getValueType(0); 1460753f127fSDimitry Andric SDValue N0 = N->getOperand(0), N1 = N->getOperand(1); 1461753f127fSDimitry Andric ConstantSDNode *CN0, *CN1; 1462753f127fSDimitry Andric SDLoc DL(N); 1463753f127fSDimitry Andric unsigned ValBits = ValTy.getSizeInBits(); 1464753f127fSDimitry Andric unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1; 1465753f127fSDimitry Andric unsigned Shamt; 1466753f127fSDimitry Andric bool SwapAndRetried = false; 1467753f127fSDimitry Andric 1468753f127fSDimitry Andric if (DCI.isBeforeLegalizeOps()) 1469753f127fSDimitry Andric return SDValue(); 1470753f127fSDimitry Andric 1471753f127fSDimitry Andric if (ValBits != 32 && ValBits != 64) 1472753f127fSDimitry Andric return SDValue(); 1473753f127fSDimitry Andric 1474753f127fSDimitry Andric Retry: 1475753f127fSDimitry Andric // 1st pattern to match BSTRINS: 1476753f127fSDimitry Andric // R = or (and X, mask0), (and (shl Y, lsb), mask1) 1477753f127fSDimitry Andric // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1 1478753f127fSDimitry Andric // => 1479753f127fSDimitry Andric // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1) 1480753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 1481753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 1482753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 1483753f127fSDimitry Andric N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL && 1484753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1485753f127fSDimitry Andric isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) && 1486753f127fSDimitry Andric MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 && 1487753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 1488753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskIdx0 && 1489753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 1490753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n"); 1491753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 1492753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 1493753f127fSDimitry Andric DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT), 1494753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 1495753f127fSDimitry Andric } 1496753f127fSDimitry Andric 1497753f127fSDimitry Andric // 2nd pattern to match BSTRINS: 1498753f127fSDimitry Andric // R = or (and X, mask0), (shl (and Y, mask1), lsb) 1499753f127fSDimitry Andric // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb) 1500753f127fSDimitry Andric // => 1501753f127fSDimitry Andric // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1) 1502753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 1503753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 1504753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 1505753f127fSDimitry Andric N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND && 1506753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1507753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskIdx0 && 1508753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 1509753f127fSDimitry Andric isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) && 1510753f127fSDimitry Andric MaskLen0 == MaskLen1 && MaskIdx1 == 0 && 1511753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 1512753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n"); 1513753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 1514753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 1515753f127fSDimitry Andric DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT), 1516753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 1517753f127fSDimitry Andric } 1518753f127fSDimitry Andric 1519753f127fSDimitry Andric // 3rd pattern to match BSTRINS: 1520753f127fSDimitry Andric // R = or (and X, mask0), (and Y, mask1) 1521753f127fSDimitry Andric // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0 1522753f127fSDimitry Andric // => 1523753f127fSDimitry Andric // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb 1524753f127fSDimitry Andric // where msb = lsb + size - 1 1525753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND && 1526753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 1527753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 1528753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= 64) && 1529753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) && 1530753f127fSDimitry Andric (CN1->getSExtValue() & CN0->getSExtValue()) == 0) { 1531753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n"); 1532753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 1533753f127fSDimitry Andric DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1, 1534753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)), 1535753f127fSDimitry Andric DAG.getConstant(ValBits == 32 1536753f127fSDimitry Andric ? (MaskIdx0 + (MaskLen0 & 31) - 1) 1537753f127fSDimitry Andric : (MaskIdx0 + MaskLen0 - 1), 1538753f127fSDimitry Andric DL, GRLenVT), 1539753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 1540753f127fSDimitry Andric } 1541753f127fSDimitry Andric 1542753f127fSDimitry Andric // 4th pattern to match BSTRINS: 1543753f127fSDimitry Andric // R = or (and X, mask), (shl Y, shamt) 1544753f127fSDimitry Andric // where mask = (2**shamt - 1) 1545753f127fSDimitry Andric // => 1546753f127fSDimitry Andric // R = BSTRINS X, Y, ValBits - 1, shamt 1547753f127fSDimitry Andric // where ValBits = 32 or 64 1548753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL && 1549753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 1550753f127fSDimitry Andric isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) && 1551753f127fSDimitry Andric MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1552753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskLen0 && 1553753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 1554753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n"); 1555753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 1556753f127fSDimitry Andric N1.getOperand(0), 1557753f127fSDimitry Andric DAG.getConstant((ValBits - 1), DL, GRLenVT), 1558753f127fSDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 1559753f127fSDimitry Andric } 1560753f127fSDimitry Andric 1561753f127fSDimitry Andric // 5th pattern to match BSTRINS: 1562753f127fSDimitry Andric // R = or (and X, mask), const 1563753f127fSDimitry Andric // where ~mask = (2**size - 1) << lsb, mask & const = 0 1564753f127fSDimitry Andric // => 1565753f127fSDimitry Andric // R = BSTRINS X, (const >> lsb), msb, lsb 1566753f127fSDimitry Andric // where msb = lsb + size - 1 1567753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 1568753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 1569753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 1570753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1)) && 1571753f127fSDimitry Andric (CN1->getSExtValue() & CN0->getSExtValue()) == 0) { 1572753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n"); 1573753f127fSDimitry Andric return DAG.getNode( 1574753f127fSDimitry Andric LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 1575753f127fSDimitry Andric DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy), 1576753f127fSDimitry Andric DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT), 1577753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 1578753f127fSDimitry Andric } 1579753f127fSDimitry Andric 1580753f127fSDimitry Andric // 6th pattern. 1581753f127fSDimitry Andric // a = b | ((c & mask) << shamt), where all positions in b to be overwritten 1582753f127fSDimitry Andric // by the incoming bits are known to be zero. 1583753f127fSDimitry Andric // => 1584753f127fSDimitry Andric // a = BSTRINS b, c, shamt + MaskLen - 1, shamt 1585753f127fSDimitry Andric // 1586753f127fSDimitry Andric // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th 1587753f127fSDimitry Andric // pattern is more common than the 1st. So we put the 1st before the 6th in 1588753f127fSDimitry Andric // order to match as many nodes as possible. 1589753f127fSDimitry Andric ConstantSDNode *CNMask, *CNShamt; 1590753f127fSDimitry Andric unsigned MaskIdx, MaskLen; 1591753f127fSDimitry Andric if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND && 1592753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 1593753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) && 1594753f127fSDimitry Andric MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1595753f127fSDimitry Andric CNShamt->getZExtValue() + MaskLen <= ValBits) { 1596753f127fSDimitry Andric Shamt = CNShamt->getZExtValue(); 1597753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt); 1598753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 1599753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n"); 1600753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 1601753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 1602753f127fSDimitry Andric DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT), 1603753f127fSDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 1604753f127fSDimitry Andric } 1605753f127fSDimitry Andric } 1606753f127fSDimitry Andric 1607753f127fSDimitry Andric // 7th pattern. 1608753f127fSDimitry Andric // a = b | ((c << shamt) & shifted_mask), where all positions in b to be 1609753f127fSDimitry Andric // overwritten by the incoming bits are known to be zero. 1610753f127fSDimitry Andric // => 1611753f127fSDimitry Andric // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx 1612753f127fSDimitry Andric // 1613753f127fSDimitry Andric // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd 1614753f127fSDimitry Andric // before the 7th in order to match as many nodes as possible. 1615753f127fSDimitry Andric if (N1.getOpcode() == ISD::AND && 1616753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1617753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) && 1618753f127fSDimitry Andric N1.getOperand(0).getOpcode() == ISD::SHL && 1619753f127fSDimitry Andric (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 1620753f127fSDimitry Andric CNShamt->getZExtValue() == MaskIdx) { 1621753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue()); 1622753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 1623753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n"); 1624753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 1625753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 1626753f127fSDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 1627753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)); 1628753f127fSDimitry Andric } 1629753f127fSDimitry Andric } 1630753f127fSDimitry Andric 1631753f127fSDimitry Andric // (or a, b) and (or b, a) are equivalent, so swap the operands and retry. 1632753f127fSDimitry Andric if (!SwapAndRetried) { 1633753f127fSDimitry Andric std::swap(N0, N1); 1634753f127fSDimitry Andric SwapAndRetried = true; 1635753f127fSDimitry Andric goto Retry; 1636753f127fSDimitry Andric } 1637753f127fSDimitry Andric 1638753f127fSDimitry Andric SwapAndRetried = false; 1639753f127fSDimitry Andric Retry2: 1640753f127fSDimitry Andric // 8th pattern. 1641753f127fSDimitry Andric // a = b | (c & shifted_mask), where all positions in b to be overwritten by 1642753f127fSDimitry Andric // the incoming bits are known to be zero. 1643753f127fSDimitry Andric // => 1644753f127fSDimitry Andric // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx 1645753f127fSDimitry Andric // 1646753f127fSDimitry Andric // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So 1647753f127fSDimitry Andric // we put it here in order to match as many nodes as possible or generate less 1648753f127fSDimitry Andric // instructions. 1649753f127fSDimitry Andric if (N1.getOpcode() == ISD::AND && 1650753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1651753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) { 1652753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue()); 1653753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 1654753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n"); 1655753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 1656753f127fSDimitry Andric DAG.getNode(ISD::SRL, DL, N1->getValueType(0), 1657753f127fSDimitry Andric N1->getOperand(0), 1658753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)), 1659753f127fSDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 1660753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)); 1661753f127fSDimitry Andric } 1662753f127fSDimitry Andric } 1663753f127fSDimitry Andric // Swap N0/N1 and retry. 1664753f127fSDimitry Andric if (!SwapAndRetried) { 1665753f127fSDimitry Andric std::swap(N0, N1); 1666753f127fSDimitry Andric SwapAndRetried = true; 1667753f127fSDimitry Andric goto Retry2; 1668753f127fSDimitry Andric } 1669753f127fSDimitry Andric 1670753f127fSDimitry Andric return SDValue(); 1671753f127fSDimitry Andric } 1672753f127fSDimitry Andric 1673bdd1243dSDimitry Andric // Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b. 1674bdd1243dSDimitry Andric static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG, 1675bdd1243dSDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 1676bdd1243dSDimitry Andric const LoongArchSubtarget &Subtarget) { 1677bdd1243dSDimitry Andric if (DCI.isBeforeLegalizeOps()) 1678bdd1243dSDimitry Andric return SDValue(); 1679bdd1243dSDimitry Andric 1680bdd1243dSDimitry Andric SDValue Src = N->getOperand(0); 1681bdd1243dSDimitry Andric if (Src.getOpcode() != LoongArchISD::REVB_2W) 1682bdd1243dSDimitry Andric return SDValue(); 1683bdd1243dSDimitry Andric 1684bdd1243dSDimitry Andric return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0), 1685bdd1243dSDimitry Andric Src.getOperand(0)); 1686bdd1243dSDimitry Andric } 1687bdd1243dSDimitry Andric 168881ad6265SDimitry Andric SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N, 168981ad6265SDimitry Andric DAGCombinerInfo &DCI) const { 169081ad6265SDimitry Andric SelectionDAG &DAG = DCI.DAG; 169181ad6265SDimitry Andric switch (N->getOpcode()) { 169281ad6265SDimitry Andric default: 169381ad6265SDimitry Andric break; 169481ad6265SDimitry Andric case ISD::AND: 169581ad6265SDimitry Andric return performANDCombine(N, DAG, DCI, Subtarget); 1696753f127fSDimitry Andric case ISD::OR: 1697753f127fSDimitry Andric return performORCombine(N, DAG, DCI, Subtarget); 169881ad6265SDimitry Andric case ISD::SRL: 169981ad6265SDimitry Andric return performSRLCombine(N, DAG, DCI, Subtarget); 1700bdd1243dSDimitry Andric case LoongArchISD::BITREV_W: 1701bdd1243dSDimitry Andric return performBITREV_WCombine(N, DAG, DCI, Subtarget); 170281ad6265SDimitry Andric } 170381ad6265SDimitry Andric return SDValue(); 170481ad6265SDimitry Andric } 170581ad6265SDimitry Andric 1706753f127fSDimitry Andric static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI, 1707bdd1243dSDimitry Andric MachineBasicBlock *MBB) { 1708753f127fSDimitry Andric if (!ZeroDivCheck) 1709bdd1243dSDimitry Andric return MBB; 1710753f127fSDimitry Andric 1711753f127fSDimitry Andric // Build instructions: 1712bdd1243dSDimitry Andric // MBB: 1713753f127fSDimitry Andric // div(or mod) $dst, $dividend, $divisor 1714bdd1243dSDimitry Andric // bnez $divisor, SinkMBB 1715bdd1243dSDimitry Andric // BreakMBB: 1716bdd1243dSDimitry Andric // break 7 // BRK_DIVZERO 1717bdd1243dSDimitry Andric // SinkMBB: 1718753f127fSDimitry Andric // fallthrough 1719bdd1243dSDimitry Andric const BasicBlock *LLVM_BB = MBB->getBasicBlock(); 1720bdd1243dSDimitry Andric MachineFunction::iterator It = ++MBB->getIterator(); 1721bdd1243dSDimitry Andric MachineFunction *MF = MBB->getParent(); 1722bdd1243dSDimitry Andric auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB); 1723bdd1243dSDimitry Andric auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB); 1724bdd1243dSDimitry Andric MF->insert(It, BreakMBB); 1725bdd1243dSDimitry Andric MF->insert(It, SinkMBB); 1726bdd1243dSDimitry Andric 1727bdd1243dSDimitry Andric // Transfer the remainder of MBB and its successor edges to SinkMBB. 1728bdd1243dSDimitry Andric SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end()); 1729bdd1243dSDimitry Andric SinkMBB->transferSuccessorsAndUpdatePHIs(MBB); 1730bdd1243dSDimitry Andric 1731bdd1243dSDimitry Andric const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); 1732bdd1243dSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 1733753f127fSDimitry Andric MachineOperand &Divisor = MI.getOperand(2); 1734bdd1243dSDimitry Andric Register DivisorReg = Divisor.getReg(); 1735753f127fSDimitry Andric 1736bdd1243dSDimitry Andric // MBB: 1737bdd1243dSDimitry Andric BuildMI(MBB, DL, TII.get(LoongArch::BNEZ)) 1738bdd1243dSDimitry Andric .addReg(DivisorReg, getKillRegState(Divisor.isKill())) 1739bdd1243dSDimitry Andric .addMBB(SinkMBB); 1740bdd1243dSDimitry Andric MBB->addSuccessor(BreakMBB); 1741bdd1243dSDimitry Andric MBB->addSuccessor(SinkMBB); 1742753f127fSDimitry Andric 1743bdd1243dSDimitry Andric // BreakMBB: 1744753f127fSDimitry Andric // See linux header file arch/loongarch/include/uapi/asm/break.h for the 1745753f127fSDimitry Andric // definition of BRK_DIVZERO. 1746bdd1243dSDimitry Andric BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/); 1747bdd1243dSDimitry Andric BreakMBB->addSuccessor(SinkMBB); 1748753f127fSDimitry Andric 1749753f127fSDimitry Andric // Clear Divisor's kill flag. 1750753f127fSDimitry Andric Divisor.setIsKill(false); 1751753f127fSDimitry Andric 1752bdd1243dSDimitry Andric return SinkMBB; 1753753f127fSDimitry Andric } 1754753f127fSDimitry Andric 1755753f127fSDimitry Andric MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter( 1756753f127fSDimitry Andric MachineInstr &MI, MachineBasicBlock *BB) const { 1757bdd1243dSDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 1758bdd1243dSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 1759753f127fSDimitry Andric 1760753f127fSDimitry Andric switch (MI.getOpcode()) { 1761753f127fSDimitry Andric default: 1762753f127fSDimitry Andric llvm_unreachable("Unexpected instr type to insert"); 1763753f127fSDimitry Andric case LoongArch::DIV_W: 1764753f127fSDimitry Andric case LoongArch::DIV_WU: 1765753f127fSDimitry Andric case LoongArch::MOD_W: 1766753f127fSDimitry Andric case LoongArch::MOD_WU: 1767753f127fSDimitry Andric case LoongArch::DIV_D: 1768753f127fSDimitry Andric case LoongArch::DIV_DU: 1769753f127fSDimitry Andric case LoongArch::MOD_D: 1770753f127fSDimitry Andric case LoongArch::MOD_DU: 1771bdd1243dSDimitry Andric return insertDivByZeroTrap(MI, BB); 1772753f127fSDimitry Andric break; 1773bdd1243dSDimitry Andric case LoongArch::WRFCSR: { 1774bdd1243dSDimitry Andric BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR), 1775bdd1243dSDimitry Andric LoongArch::FCSR0 + MI.getOperand(0).getImm()) 1776bdd1243dSDimitry Andric .addReg(MI.getOperand(1).getReg()); 1777bdd1243dSDimitry Andric MI.eraseFromParent(); 1778bdd1243dSDimitry Andric return BB; 1779bdd1243dSDimitry Andric } 1780bdd1243dSDimitry Andric case LoongArch::RDFCSR: { 1781bdd1243dSDimitry Andric MachineInstr *ReadFCSR = 1782bdd1243dSDimitry Andric BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR), 1783bdd1243dSDimitry Andric MI.getOperand(0).getReg()) 1784bdd1243dSDimitry Andric .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm()); 1785bdd1243dSDimitry Andric ReadFCSR->getOperand(1).setIsUndef(); 1786bdd1243dSDimitry Andric MI.eraseFromParent(); 1787bdd1243dSDimitry Andric return BB; 1788bdd1243dSDimitry Andric } 1789753f127fSDimitry Andric } 1790753f127fSDimitry Andric } 1791753f127fSDimitry Andric 1792*06c3fb27SDimitry Andric bool LoongArchTargetLowering::allowsMisalignedMemoryAccesses( 1793*06c3fb27SDimitry Andric EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags, 1794*06c3fb27SDimitry Andric unsigned *Fast) const { 1795*06c3fb27SDimitry Andric if (!Subtarget.hasUAL()) 1796*06c3fb27SDimitry Andric return false; 1797*06c3fb27SDimitry Andric 1798*06c3fb27SDimitry Andric // TODO: set reasonable speed number. 1799*06c3fb27SDimitry Andric if (Fast) 1800*06c3fb27SDimitry Andric *Fast = 1; 1801*06c3fb27SDimitry Andric return true; 1802*06c3fb27SDimitry Andric } 1803*06c3fb27SDimitry Andric 180481ad6265SDimitry Andric const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const { 180581ad6265SDimitry Andric switch ((LoongArchISD::NodeType)Opcode) { 180681ad6265SDimitry Andric case LoongArchISD::FIRST_NUMBER: 180781ad6265SDimitry Andric break; 180881ad6265SDimitry Andric 180981ad6265SDimitry Andric #define NODE_NAME_CASE(node) \ 181081ad6265SDimitry Andric case LoongArchISD::node: \ 181181ad6265SDimitry Andric return "LoongArchISD::" #node; 181281ad6265SDimitry Andric 181381ad6265SDimitry Andric // TODO: Add more target-dependent nodes later. 1814753f127fSDimitry Andric NODE_NAME_CASE(CALL) 181581ad6265SDimitry Andric NODE_NAME_CASE(RET) 1816bdd1243dSDimitry Andric NODE_NAME_CASE(TAIL) 181781ad6265SDimitry Andric NODE_NAME_CASE(SLL_W) 181881ad6265SDimitry Andric NODE_NAME_CASE(SRA_W) 181981ad6265SDimitry Andric NODE_NAME_CASE(SRL_W) 1820753f127fSDimitry Andric NODE_NAME_CASE(BSTRINS) 182181ad6265SDimitry Andric NODE_NAME_CASE(BSTRPICK) 1822753f127fSDimitry Andric NODE_NAME_CASE(MOVGR2FR_W_LA64) 1823753f127fSDimitry Andric NODE_NAME_CASE(MOVFR2GR_S_LA64) 1824753f127fSDimitry Andric NODE_NAME_CASE(FTINT) 1825bdd1243dSDimitry Andric NODE_NAME_CASE(REVB_2H) 1826bdd1243dSDimitry Andric NODE_NAME_CASE(REVB_2W) 1827bdd1243dSDimitry Andric NODE_NAME_CASE(BITREV_4B) 1828bdd1243dSDimitry Andric NODE_NAME_CASE(BITREV_W) 1829bdd1243dSDimitry Andric NODE_NAME_CASE(ROTR_W) 1830bdd1243dSDimitry Andric NODE_NAME_CASE(ROTL_W) 1831bdd1243dSDimitry Andric NODE_NAME_CASE(CLZ_W) 1832bdd1243dSDimitry Andric NODE_NAME_CASE(CTZ_W) 1833bdd1243dSDimitry Andric NODE_NAME_CASE(DBAR) 1834bdd1243dSDimitry Andric NODE_NAME_CASE(IBAR) 1835bdd1243dSDimitry Andric NODE_NAME_CASE(BREAK) 1836bdd1243dSDimitry Andric NODE_NAME_CASE(SYSCALL) 1837bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_B_W) 1838bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_H_W) 1839bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_W_W) 1840bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_D_W) 1841bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_B_W) 1842bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_H_W) 1843bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_W_W) 1844bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_D_W) 1845bdd1243dSDimitry Andric NODE_NAME_CASE(CSRRD) 1846bdd1243dSDimitry Andric NODE_NAME_CASE(CSRWR) 1847bdd1243dSDimitry Andric NODE_NAME_CASE(CSRXCHG) 1848bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_B) 1849bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_H) 1850bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_W) 1851bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_D) 1852bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_B) 1853bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_H) 1854bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_W) 1855bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_D) 1856bdd1243dSDimitry Andric NODE_NAME_CASE(CPUCFG) 1857bdd1243dSDimitry Andric NODE_NAME_CASE(MOVGR2FCSR) 1858bdd1243dSDimitry Andric NODE_NAME_CASE(MOVFCSR2GR) 1859bdd1243dSDimitry Andric NODE_NAME_CASE(CACOP_D) 1860bdd1243dSDimitry Andric NODE_NAME_CASE(CACOP_W) 186181ad6265SDimitry Andric } 186281ad6265SDimitry Andric #undef NODE_NAME_CASE 186381ad6265SDimitry Andric return nullptr; 186481ad6265SDimitry Andric } 186581ad6265SDimitry Andric 186681ad6265SDimitry Andric //===----------------------------------------------------------------------===// 186781ad6265SDimitry Andric // Calling Convention Implementation 186881ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1869bdd1243dSDimitry Andric 1870bdd1243dSDimitry Andric // Eight general-purpose registers a0-a7 used for passing integer arguments, 1871bdd1243dSDimitry Andric // with a0-a1 reused to return values. Generally, the GPRs are used to pass 1872bdd1243dSDimitry Andric // fixed-point arguments, and floating-point arguments when no FPR is available 1873bdd1243dSDimitry Andric // or with soft float ABI. 187481ad6265SDimitry Andric const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6, 187581ad6265SDimitry Andric LoongArch::R7, LoongArch::R8, LoongArch::R9, 187681ad6265SDimitry Andric LoongArch::R10, LoongArch::R11}; 1877bdd1243dSDimitry Andric // Eight floating-point registers fa0-fa7 used for passing floating-point 1878bdd1243dSDimitry Andric // arguments, and fa0-fa1 are also used to return values. 187981ad6265SDimitry Andric const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2, 188081ad6265SDimitry Andric LoongArch::F3, LoongArch::F4, LoongArch::F5, 188181ad6265SDimitry Andric LoongArch::F6, LoongArch::F7}; 1882bdd1243dSDimitry Andric // FPR32 and FPR64 alias each other. 188381ad6265SDimitry Andric const MCPhysReg ArgFPR64s[] = { 188481ad6265SDimitry Andric LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64, 188581ad6265SDimitry Andric LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64}; 188681ad6265SDimitry Andric 1887bdd1243dSDimitry Andric // Pass a 2*GRLen argument that has been split into two GRLen values through 1888bdd1243dSDimitry Andric // registers or the stack as necessary. 1889bdd1243dSDimitry Andric static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State, 1890bdd1243dSDimitry Andric CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1, 1891bdd1243dSDimitry Andric unsigned ValNo2, MVT ValVT2, MVT LocVT2, 1892bdd1243dSDimitry Andric ISD::ArgFlagsTy ArgFlags2) { 1893bdd1243dSDimitry Andric unsigned GRLenInBytes = GRLen / 8; 1894bdd1243dSDimitry Andric if (Register Reg = State.AllocateReg(ArgGPRs)) { 1895bdd1243dSDimitry Andric // At least one half can be passed via register. 1896bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg, 1897bdd1243dSDimitry Andric VA1.getLocVT(), CCValAssign::Full)); 1898bdd1243dSDimitry Andric } else { 1899bdd1243dSDimitry Andric // Both halves must be passed on the stack, with proper alignment. 1900bdd1243dSDimitry Andric Align StackAlign = 1901bdd1243dSDimitry Andric std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign()); 1902bdd1243dSDimitry Andric State.addLoc( 1903bdd1243dSDimitry Andric CCValAssign::getMem(VA1.getValNo(), VA1.getValVT(), 1904bdd1243dSDimitry Andric State.AllocateStack(GRLenInBytes, StackAlign), 1905bdd1243dSDimitry Andric VA1.getLocVT(), CCValAssign::Full)); 1906bdd1243dSDimitry Andric State.addLoc(CCValAssign::getMem( 1907bdd1243dSDimitry Andric ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)), 1908bdd1243dSDimitry Andric LocVT2, CCValAssign::Full)); 1909bdd1243dSDimitry Andric return false; 1910bdd1243dSDimitry Andric } 1911bdd1243dSDimitry Andric if (Register Reg = State.AllocateReg(ArgGPRs)) { 1912bdd1243dSDimitry Andric // The second half can also be passed via register. 1913bdd1243dSDimitry Andric State.addLoc( 1914bdd1243dSDimitry Andric CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full)); 1915bdd1243dSDimitry Andric } else { 1916bdd1243dSDimitry Andric // The second half is passed via the stack, without additional alignment. 1917bdd1243dSDimitry Andric State.addLoc(CCValAssign::getMem( 1918bdd1243dSDimitry Andric ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)), 1919bdd1243dSDimitry Andric LocVT2, CCValAssign::Full)); 1920bdd1243dSDimitry Andric } 192181ad6265SDimitry Andric return false; 192281ad6265SDimitry Andric } 192381ad6265SDimitry Andric 1924bdd1243dSDimitry Andric // Implements the LoongArch calling convention. Returns true upon failure. 1925bdd1243dSDimitry Andric static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI, 1926bdd1243dSDimitry Andric unsigned ValNo, MVT ValVT, 1927bdd1243dSDimitry Andric CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, 1928bdd1243dSDimitry Andric CCState &State, bool IsFixed, bool IsRet, 1929bdd1243dSDimitry Andric Type *OrigTy) { 1930bdd1243dSDimitry Andric unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits(); 1931bdd1243dSDimitry Andric assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen"); 1932bdd1243dSDimitry Andric MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64; 1933bdd1243dSDimitry Andric MVT LocVT = ValVT; 1934bdd1243dSDimitry Andric 1935bdd1243dSDimitry Andric // Any return value split into more than two values can't be returned 1936bdd1243dSDimitry Andric // directly. 1937bdd1243dSDimitry Andric if (IsRet && ValNo > 1) 193881ad6265SDimitry Andric return true; 1939bdd1243dSDimitry Andric 1940bdd1243dSDimitry Andric // If passing a variadic argument, or if no FPR is available. 1941bdd1243dSDimitry Andric bool UseGPRForFloat = true; 1942bdd1243dSDimitry Andric 1943bdd1243dSDimitry Andric switch (ABI) { 1944bdd1243dSDimitry Andric default: 1945bdd1243dSDimitry Andric llvm_unreachable("Unexpected ABI"); 1946bdd1243dSDimitry Andric case LoongArchABI::ABI_ILP32S: 1947bdd1243dSDimitry Andric case LoongArchABI::ABI_ILP32F: 1948bdd1243dSDimitry Andric case LoongArchABI::ABI_LP64F: 1949bdd1243dSDimitry Andric report_fatal_error("Unimplemented ABI"); 1950bdd1243dSDimitry Andric break; 1951bdd1243dSDimitry Andric case LoongArchABI::ABI_ILP32D: 1952bdd1243dSDimitry Andric case LoongArchABI::ABI_LP64D: 1953bdd1243dSDimitry Andric UseGPRForFloat = !IsFixed; 1954bdd1243dSDimitry Andric break; 1955*06c3fb27SDimitry Andric case LoongArchABI::ABI_LP64S: 1956*06c3fb27SDimitry Andric break; 1957bdd1243dSDimitry Andric } 1958bdd1243dSDimitry Andric 1959bdd1243dSDimitry Andric // FPR32 and FPR64 alias each other. 1960bdd1243dSDimitry Andric if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s)) 1961bdd1243dSDimitry Andric UseGPRForFloat = true; 1962bdd1243dSDimitry Andric 1963bdd1243dSDimitry Andric if (UseGPRForFloat && ValVT == MVT::f32) { 1964bdd1243dSDimitry Andric LocVT = GRLenVT; 1965bdd1243dSDimitry Andric LocInfo = CCValAssign::BCvt; 1966bdd1243dSDimitry Andric } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) { 1967bdd1243dSDimitry Andric LocVT = MVT::i64; 1968bdd1243dSDimitry Andric LocInfo = CCValAssign::BCvt; 1969bdd1243dSDimitry Andric } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) { 1970bdd1243dSDimitry Andric // TODO: Handle passing f64 on LA32 with D feature. 1971bdd1243dSDimitry Andric report_fatal_error("Passing f64 with GPR on LA32 is undefined"); 1972bdd1243dSDimitry Andric } 1973bdd1243dSDimitry Andric 1974bdd1243dSDimitry Andric // If this is a variadic argument, the LoongArch calling convention requires 1975bdd1243dSDimitry Andric // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8 1976bdd1243dSDimitry Andric // byte alignment. An aligned register should be used regardless of whether 1977bdd1243dSDimitry Andric // the original argument was split during legalisation or not. The argument 1978bdd1243dSDimitry Andric // will not be passed by registers if the original type is larger than 1979bdd1243dSDimitry Andric // 2*GRLen, so the register alignment rule does not apply. 1980bdd1243dSDimitry Andric unsigned TwoGRLenInBytes = (2 * GRLen) / 8; 1981bdd1243dSDimitry Andric if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes && 1982bdd1243dSDimitry Andric DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) { 1983bdd1243dSDimitry Andric unsigned RegIdx = State.getFirstUnallocated(ArgGPRs); 1984bdd1243dSDimitry Andric // Skip 'odd' register if necessary. 1985bdd1243dSDimitry Andric if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1) 1986bdd1243dSDimitry Andric State.AllocateReg(ArgGPRs); 1987bdd1243dSDimitry Andric } 1988bdd1243dSDimitry Andric 1989bdd1243dSDimitry Andric SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs(); 1990bdd1243dSDimitry Andric SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags = 1991bdd1243dSDimitry Andric State.getPendingArgFlags(); 1992bdd1243dSDimitry Andric 1993bdd1243dSDimitry Andric assert(PendingLocs.size() == PendingArgFlags.size() && 1994bdd1243dSDimitry Andric "PendingLocs and PendingArgFlags out of sync"); 1995bdd1243dSDimitry Andric 1996bdd1243dSDimitry Andric // Split arguments might be passed indirectly, so keep track of the pending 1997bdd1243dSDimitry Andric // values. 1998bdd1243dSDimitry Andric if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) { 1999bdd1243dSDimitry Andric LocVT = GRLenVT; 2000bdd1243dSDimitry Andric LocInfo = CCValAssign::Indirect; 2001bdd1243dSDimitry Andric PendingLocs.push_back( 2002bdd1243dSDimitry Andric CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo)); 2003bdd1243dSDimitry Andric PendingArgFlags.push_back(ArgFlags); 2004bdd1243dSDimitry Andric if (!ArgFlags.isSplitEnd()) { 2005bdd1243dSDimitry Andric return false; 2006bdd1243dSDimitry Andric } 2007bdd1243dSDimitry Andric } 2008bdd1243dSDimitry Andric 2009bdd1243dSDimitry Andric // If the split argument only had two elements, it should be passed directly 2010bdd1243dSDimitry Andric // in registers or on the stack. 2011bdd1243dSDimitry Andric if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() && 2012bdd1243dSDimitry Andric PendingLocs.size() <= 2) { 2013bdd1243dSDimitry Andric assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()"); 2014bdd1243dSDimitry Andric // Apply the normal calling convention rules to the first half of the 2015bdd1243dSDimitry Andric // split argument. 2016bdd1243dSDimitry Andric CCValAssign VA = PendingLocs[0]; 2017bdd1243dSDimitry Andric ISD::ArgFlagsTy AF = PendingArgFlags[0]; 2018bdd1243dSDimitry Andric PendingLocs.clear(); 2019bdd1243dSDimitry Andric PendingArgFlags.clear(); 2020bdd1243dSDimitry Andric return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT, 2021bdd1243dSDimitry Andric ArgFlags); 2022bdd1243dSDimitry Andric } 2023bdd1243dSDimitry Andric 2024bdd1243dSDimitry Andric // Allocate to a register if possible, or else a stack slot. 2025bdd1243dSDimitry Andric Register Reg; 2026bdd1243dSDimitry Andric unsigned StoreSizeBytes = GRLen / 8; 2027bdd1243dSDimitry Andric Align StackAlign = Align(GRLen / 8); 2028bdd1243dSDimitry Andric 2029bdd1243dSDimitry Andric if (ValVT == MVT::f32 && !UseGPRForFloat) 2030bdd1243dSDimitry Andric Reg = State.AllocateReg(ArgFPR32s); 2031bdd1243dSDimitry Andric else if (ValVT == MVT::f64 && !UseGPRForFloat) 2032bdd1243dSDimitry Andric Reg = State.AllocateReg(ArgFPR64s); 2033bdd1243dSDimitry Andric else 2034bdd1243dSDimitry Andric Reg = State.AllocateReg(ArgGPRs); 2035bdd1243dSDimitry Andric 2036bdd1243dSDimitry Andric unsigned StackOffset = 2037bdd1243dSDimitry Andric Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign); 2038bdd1243dSDimitry Andric 2039bdd1243dSDimitry Andric // If we reach this point and PendingLocs is non-empty, we must be at the 2040bdd1243dSDimitry Andric // end of a split argument that must be passed indirectly. 2041bdd1243dSDimitry Andric if (!PendingLocs.empty()) { 2042bdd1243dSDimitry Andric assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()"); 2043bdd1243dSDimitry Andric assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()"); 2044bdd1243dSDimitry Andric for (auto &It : PendingLocs) { 2045bdd1243dSDimitry Andric if (Reg) 2046bdd1243dSDimitry Andric It.convertToReg(Reg); 2047bdd1243dSDimitry Andric else 2048bdd1243dSDimitry Andric It.convertToMem(StackOffset); 2049bdd1243dSDimitry Andric State.addLoc(It); 2050bdd1243dSDimitry Andric } 2051bdd1243dSDimitry Andric PendingLocs.clear(); 2052bdd1243dSDimitry Andric PendingArgFlags.clear(); 2053bdd1243dSDimitry Andric return false; 2054bdd1243dSDimitry Andric } 2055bdd1243dSDimitry Andric assert((!UseGPRForFloat || LocVT == GRLenVT) && 2056bdd1243dSDimitry Andric "Expected an GRLenVT at this stage"); 2057bdd1243dSDimitry Andric 2058bdd1243dSDimitry Andric if (Reg) { 2059bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 2060bdd1243dSDimitry Andric return false; 2061bdd1243dSDimitry Andric } 2062bdd1243dSDimitry Andric 2063bdd1243dSDimitry Andric // When a floating-point value is passed on the stack, no bit-cast is needed. 2064bdd1243dSDimitry Andric if (ValVT.isFloatingPoint()) { 2065bdd1243dSDimitry Andric LocVT = ValVT; 2066bdd1243dSDimitry Andric LocInfo = CCValAssign::Full; 2067bdd1243dSDimitry Andric } 2068bdd1243dSDimitry Andric 2069bdd1243dSDimitry Andric State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo)); 2070bdd1243dSDimitry Andric return false; 207181ad6265SDimitry Andric } 207281ad6265SDimitry Andric 207381ad6265SDimitry Andric void LoongArchTargetLowering::analyzeInputArgs( 2074bdd1243dSDimitry Andric MachineFunction &MF, CCState &CCInfo, 2075bdd1243dSDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet, 207681ad6265SDimitry Andric LoongArchCCAssignFn Fn) const { 2077bdd1243dSDimitry Andric FunctionType *FType = MF.getFunction().getFunctionType(); 207881ad6265SDimitry Andric for (unsigned i = 0, e = Ins.size(); i != e; ++i) { 207981ad6265SDimitry Andric MVT ArgVT = Ins[i].VT; 2080bdd1243dSDimitry Andric Type *ArgTy = nullptr; 2081bdd1243dSDimitry Andric if (IsRet) 2082bdd1243dSDimitry Andric ArgTy = FType->getReturnType(); 2083bdd1243dSDimitry Andric else if (Ins[i].isOrigArg()) 2084bdd1243dSDimitry Andric ArgTy = FType->getParamType(Ins[i].getOrigArgIndex()); 2085bdd1243dSDimitry Andric LoongArchABI::ABI ABI = 2086bdd1243dSDimitry Andric MF.getSubtarget<LoongArchSubtarget>().getTargetABI(); 2087bdd1243dSDimitry Andric if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags, 2088bdd1243dSDimitry Andric CCInfo, /*IsFixed=*/true, IsRet, ArgTy)) { 2089*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT 2090*06c3fb27SDimitry Andric << '\n'); 209181ad6265SDimitry Andric llvm_unreachable(""); 209281ad6265SDimitry Andric } 209381ad6265SDimitry Andric } 209481ad6265SDimitry Andric } 209581ad6265SDimitry Andric 209681ad6265SDimitry Andric void LoongArchTargetLowering::analyzeOutputArgs( 2097bdd1243dSDimitry Andric MachineFunction &MF, CCState &CCInfo, 2098bdd1243dSDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet, 2099bdd1243dSDimitry Andric CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const { 210081ad6265SDimitry Andric for (unsigned i = 0, e = Outs.size(); i != e; ++i) { 210181ad6265SDimitry Andric MVT ArgVT = Outs[i].VT; 2102bdd1243dSDimitry Andric Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr; 2103bdd1243dSDimitry Andric LoongArchABI::ABI ABI = 2104bdd1243dSDimitry Andric MF.getSubtarget<LoongArchSubtarget>().getTargetABI(); 2105bdd1243dSDimitry Andric if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags, 2106bdd1243dSDimitry Andric CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) { 2107*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT 2108*06c3fb27SDimitry Andric << "\n"); 210981ad6265SDimitry Andric llvm_unreachable(""); 211081ad6265SDimitry Andric } 211181ad6265SDimitry Andric } 211281ad6265SDimitry Andric } 211381ad6265SDimitry Andric 2114bdd1243dSDimitry Andric // Convert Val to a ValVT. Should not be called for CCValAssign::Indirect 2115bdd1243dSDimitry Andric // values. 2116bdd1243dSDimitry Andric static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, 2117bdd1243dSDimitry Andric const CCValAssign &VA, const SDLoc &DL) { 2118bdd1243dSDimitry Andric switch (VA.getLocInfo()) { 2119bdd1243dSDimitry Andric default: 2120bdd1243dSDimitry Andric llvm_unreachable("Unexpected CCValAssign::LocInfo"); 2121bdd1243dSDimitry Andric case CCValAssign::Full: 2122bdd1243dSDimitry Andric case CCValAssign::Indirect: 2123bdd1243dSDimitry Andric break; 2124bdd1243dSDimitry Andric case CCValAssign::BCvt: 2125bdd1243dSDimitry Andric if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) 2126bdd1243dSDimitry Andric Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val); 2127bdd1243dSDimitry Andric else 2128bdd1243dSDimitry Andric Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val); 2129bdd1243dSDimitry Andric break; 2130bdd1243dSDimitry Andric } 2131bdd1243dSDimitry Andric return Val; 2132bdd1243dSDimitry Andric } 2133bdd1243dSDimitry Andric 213481ad6265SDimitry Andric static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain, 213581ad6265SDimitry Andric const CCValAssign &VA, const SDLoc &DL, 213681ad6265SDimitry Andric const LoongArchTargetLowering &TLI) { 213781ad6265SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 213881ad6265SDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 213981ad6265SDimitry Andric EVT LocVT = VA.getLocVT(); 2140bdd1243dSDimitry Andric SDValue Val; 214181ad6265SDimitry Andric const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT()); 214281ad6265SDimitry Andric Register VReg = RegInfo.createVirtualRegister(RC); 214381ad6265SDimitry Andric RegInfo.addLiveIn(VA.getLocReg(), VReg); 2144bdd1243dSDimitry Andric Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT); 214581ad6265SDimitry Andric 2146bdd1243dSDimitry Andric return convertLocVTToValVT(DAG, Val, VA, DL); 2147bdd1243dSDimitry Andric } 2148bdd1243dSDimitry Andric 2149bdd1243dSDimitry Andric // The caller is responsible for loading the full value if the argument is 2150bdd1243dSDimitry Andric // passed with CCValAssign::Indirect. 2151bdd1243dSDimitry Andric static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, 2152bdd1243dSDimitry Andric const CCValAssign &VA, const SDLoc &DL) { 2153bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 2154bdd1243dSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 2155bdd1243dSDimitry Andric EVT ValVT = VA.getValVT(); 2156bdd1243dSDimitry Andric int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(), 2157bdd1243dSDimitry Andric /*IsImmutable=*/true); 2158bdd1243dSDimitry Andric SDValue FIN = DAG.getFrameIndex( 2159bdd1243dSDimitry Andric FI, MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0))); 2160bdd1243dSDimitry Andric 2161bdd1243dSDimitry Andric ISD::LoadExtType ExtType; 2162bdd1243dSDimitry Andric switch (VA.getLocInfo()) { 2163bdd1243dSDimitry Andric default: 2164bdd1243dSDimitry Andric llvm_unreachable("Unexpected CCValAssign::LocInfo"); 2165bdd1243dSDimitry Andric case CCValAssign::Full: 2166bdd1243dSDimitry Andric case CCValAssign::Indirect: 2167bdd1243dSDimitry Andric case CCValAssign::BCvt: 2168bdd1243dSDimitry Andric ExtType = ISD::NON_EXTLOAD; 2169bdd1243dSDimitry Andric break; 2170bdd1243dSDimitry Andric } 2171bdd1243dSDimitry Andric return DAG.getExtLoad( 2172bdd1243dSDimitry Andric ExtType, DL, VA.getLocVT(), Chain, FIN, 2173bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT); 2174bdd1243dSDimitry Andric } 2175bdd1243dSDimitry Andric 2176bdd1243dSDimitry Andric static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, 2177bdd1243dSDimitry Andric const CCValAssign &VA, const SDLoc &DL) { 2178bdd1243dSDimitry Andric EVT LocVT = VA.getLocVT(); 2179bdd1243dSDimitry Andric 2180bdd1243dSDimitry Andric switch (VA.getLocInfo()) { 2181bdd1243dSDimitry Andric default: 2182bdd1243dSDimitry Andric llvm_unreachable("Unexpected CCValAssign::LocInfo"); 2183bdd1243dSDimitry Andric case CCValAssign::Full: 2184bdd1243dSDimitry Andric break; 2185bdd1243dSDimitry Andric case CCValAssign::BCvt: 2186bdd1243dSDimitry Andric if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) 2187bdd1243dSDimitry Andric Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val); 2188bdd1243dSDimitry Andric else 2189bdd1243dSDimitry Andric Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val); 2190bdd1243dSDimitry Andric break; 2191bdd1243dSDimitry Andric } 2192bdd1243dSDimitry Andric return Val; 2193bdd1243dSDimitry Andric } 2194bdd1243dSDimitry Andric 2195bdd1243dSDimitry Andric static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, 2196bdd1243dSDimitry Andric CCValAssign::LocInfo LocInfo, 2197bdd1243dSDimitry Andric ISD::ArgFlagsTy ArgFlags, CCState &State) { 2198bdd1243dSDimitry Andric if (LocVT == MVT::i32 || LocVT == MVT::i64) { 2199bdd1243dSDimitry Andric // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim 2200bdd1243dSDimitry Andric // s0 s1 s2 s3 s4 s5 s6 s7 s8 2201bdd1243dSDimitry Andric static const MCPhysReg GPRList[] = { 2202*06c3fb27SDimitry Andric LoongArch::R23, LoongArch::R24, LoongArch::R25, 2203*06c3fb27SDimitry Andric LoongArch::R26, LoongArch::R27, LoongArch::R28, 2204*06c3fb27SDimitry Andric LoongArch::R29, LoongArch::R30, LoongArch::R31}; 2205bdd1243dSDimitry Andric if (unsigned Reg = State.AllocateReg(GPRList)) { 2206bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 2207bdd1243dSDimitry Andric return false; 2208bdd1243dSDimitry Andric } 2209bdd1243dSDimitry Andric } 2210bdd1243dSDimitry Andric 2211bdd1243dSDimitry Andric if (LocVT == MVT::f32) { 2212bdd1243dSDimitry Andric // Pass in STG registers: F1, F2, F3, F4 2213bdd1243dSDimitry Andric // fs0,fs1,fs2,fs3 2214bdd1243dSDimitry Andric static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25, 2215bdd1243dSDimitry Andric LoongArch::F26, LoongArch::F27}; 2216bdd1243dSDimitry Andric if (unsigned Reg = State.AllocateReg(FPR32List)) { 2217bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 2218bdd1243dSDimitry Andric return false; 2219bdd1243dSDimitry Andric } 2220bdd1243dSDimitry Andric } 2221bdd1243dSDimitry Andric 2222bdd1243dSDimitry Andric if (LocVT == MVT::f64) { 2223bdd1243dSDimitry Andric // Pass in STG registers: D1, D2, D3, D4 2224bdd1243dSDimitry Andric // fs4,fs5,fs6,fs7 2225bdd1243dSDimitry Andric static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64, 2226bdd1243dSDimitry Andric LoongArch::F30_64, LoongArch::F31_64}; 2227bdd1243dSDimitry Andric if (unsigned Reg = State.AllocateReg(FPR64List)) { 2228bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 2229bdd1243dSDimitry Andric return false; 2230bdd1243dSDimitry Andric } 2231bdd1243dSDimitry Andric } 2232bdd1243dSDimitry Andric 2233bdd1243dSDimitry Andric report_fatal_error("No registers left in GHC calling convention"); 2234bdd1243dSDimitry Andric return true; 223581ad6265SDimitry Andric } 223681ad6265SDimitry Andric 223781ad6265SDimitry Andric // Transform physical registers into virtual registers. 223881ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerFormalArguments( 223981ad6265SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 224081ad6265SDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 224181ad6265SDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 224281ad6265SDimitry Andric 224381ad6265SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 224481ad6265SDimitry Andric 224581ad6265SDimitry Andric switch (CallConv) { 224681ad6265SDimitry Andric default: 224781ad6265SDimitry Andric llvm_unreachable("Unsupported calling convention"); 224881ad6265SDimitry Andric case CallingConv::C: 2249bdd1243dSDimitry Andric case CallingConv::Fast: 225081ad6265SDimitry Andric break; 2251bdd1243dSDimitry Andric case CallingConv::GHC: 2252*06c3fb27SDimitry Andric if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) || 2253*06c3fb27SDimitry Andric !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD)) 2254bdd1243dSDimitry Andric report_fatal_error( 2255bdd1243dSDimitry Andric "GHC calling convention requires the F and D extensions"); 225681ad6265SDimitry Andric } 225781ad6265SDimitry Andric 2258bdd1243dSDimitry Andric EVT PtrVT = getPointerTy(DAG.getDataLayout()); 2259bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 2260bdd1243dSDimitry Andric unsigned GRLenInBytes = Subtarget.getGRLen() / 8; 2261bdd1243dSDimitry Andric // Used with varargs to acumulate store chains. 2262bdd1243dSDimitry Andric std::vector<SDValue> OutChains; 2263bdd1243dSDimitry Andric 226481ad6265SDimitry Andric // Assign locations to all of the incoming arguments. 226581ad6265SDimitry Andric SmallVector<CCValAssign> ArgLocs; 226681ad6265SDimitry Andric CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 226781ad6265SDimitry Andric 2268bdd1243dSDimitry Andric if (CallConv == CallingConv::GHC) 2269bdd1243dSDimitry Andric CCInfo.AnalyzeFormalArguments(Ins, CC_LoongArch_GHC); 2270bdd1243dSDimitry Andric else 2271bdd1243dSDimitry Andric analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch); 227281ad6265SDimitry Andric 2273bdd1243dSDimitry Andric for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { 2274bdd1243dSDimitry Andric CCValAssign &VA = ArgLocs[i]; 2275bdd1243dSDimitry Andric SDValue ArgValue; 2276bdd1243dSDimitry Andric if (VA.isRegLoc()) 2277bdd1243dSDimitry Andric ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, *this); 2278bdd1243dSDimitry Andric else 2279bdd1243dSDimitry Andric ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL); 2280bdd1243dSDimitry Andric if (VA.getLocInfo() == CCValAssign::Indirect) { 2281bdd1243dSDimitry Andric // If the original argument was split and passed by reference, we need to 2282bdd1243dSDimitry Andric // load all parts of it here (using the same address). 2283bdd1243dSDimitry Andric InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue, 2284bdd1243dSDimitry Andric MachinePointerInfo())); 2285bdd1243dSDimitry Andric unsigned ArgIndex = Ins[i].OrigArgIndex; 2286bdd1243dSDimitry Andric unsigned ArgPartOffset = Ins[i].PartOffset; 2287bdd1243dSDimitry Andric assert(ArgPartOffset == 0); 2288bdd1243dSDimitry Andric while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) { 2289bdd1243dSDimitry Andric CCValAssign &PartVA = ArgLocs[i + 1]; 2290bdd1243dSDimitry Andric unsigned PartOffset = Ins[i + 1].PartOffset - ArgPartOffset; 2291bdd1243dSDimitry Andric SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL); 2292bdd1243dSDimitry Andric SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset); 2293bdd1243dSDimitry Andric InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address, 2294bdd1243dSDimitry Andric MachinePointerInfo())); 2295bdd1243dSDimitry Andric ++i; 2296bdd1243dSDimitry Andric } 2297bdd1243dSDimitry Andric continue; 2298bdd1243dSDimitry Andric } 2299bdd1243dSDimitry Andric InVals.push_back(ArgValue); 2300bdd1243dSDimitry Andric } 2301bdd1243dSDimitry Andric 2302bdd1243dSDimitry Andric if (IsVarArg) { 2303bdd1243dSDimitry Andric ArrayRef<MCPhysReg> ArgRegs = ArrayRef(ArgGPRs); 2304bdd1243dSDimitry Andric unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs); 2305bdd1243dSDimitry Andric const TargetRegisterClass *RC = &LoongArch::GPRRegClass; 2306bdd1243dSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 2307bdd1243dSDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 2308bdd1243dSDimitry Andric auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); 2309bdd1243dSDimitry Andric 2310bdd1243dSDimitry Andric // Offset of the first variable argument from stack pointer, and size of 2311bdd1243dSDimitry Andric // the vararg save area. For now, the varargs save area is either zero or 2312bdd1243dSDimitry Andric // large enough to hold a0-a7. 2313bdd1243dSDimitry Andric int VaArgOffset, VarArgsSaveSize; 2314bdd1243dSDimitry Andric 2315bdd1243dSDimitry Andric // If all registers are allocated, then all varargs must be passed on the 2316bdd1243dSDimitry Andric // stack and we don't need to save any argregs. 2317bdd1243dSDimitry Andric if (ArgRegs.size() == Idx) { 2318*06c3fb27SDimitry Andric VaArgOffset = CCInfo.getStackSize(); 2319bdd1243dSDimitry Andric VarArgsSaveSize = 0; 2320bdd1243dSDimitry Andric } else { 2321bdd1243dSDimitry Andric VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx); 2322bdd1243dSDimitry Andric VaArgOffset = -VarArgsSaveSize; 2323bdd1243dSDimitry Andric } 2324bdd1243dSDimitry Andric 2325bdd1243dSDimitry Andric // Record the frame index of the first variable argument 2326bdd1243dSDimitry Andric // which is a value necessary to VASTART. 2327bdd1243dSDimitry Andric int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true); 2328bdd1243dSDimitry Andric LoongArchFI->setVarArgsFrameIndex(FI); 2329bdd1243dSDimitry Andric 2330bdd1243dSDimitry Andric // If saving an odd number of registers then create an extra stack slot to 2331bdd1243dSDimitry Andric // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures 2332bdd1243dSDimitry Andric // offsets to even-numbered registered remain 2*GRLen-aligned. 2333bdd1243dSDimitry Andric if (Idx % 2) { 2334bdd1243dSDimitry Andric MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes, 2335bdd1243dSDimitry Andric true); 2336bdd1243dSDimitry Andric VarArgsSaveSize += GRLenInBytes; 2337bdd1243dSDimitry Andric } 2338bdd1243dSDimitry Andric 2339bdd1243dSDimitry Andric // Copy the integer registers that may have been used for passing varargs 2340bdd1243dSDimitry Andric // to the vararg save area. 2341bdd1243dSDimitry Andric for (unsigned I = Idx; I < ArgRegs.size(); 2342bdd1243dSDimitry Andric ++I, VaArgOffset += GRLenInBytes) { 2343bdd1243dSDimitry Andric const Register Reg = RegInfo.createVirtualRegister(RC); 2344bdd1243dSDimitry Andric RegInfo.addLiveIn(ArgRegs[I], Reg); 2345bdd1243dSDimitry Andric SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT); 2346bdd1243dSDimitry Andric FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true); 2347bdd1243dSDimitry Andric SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 2348bdd1243dSDimitry Andric SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff, 2349bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(MF, FI)); 2350bdd1243dSDimitry Andric cast<StoreSDNode>(Store.getNode()) 2351bdd1243dSDimitry Andric ->getMemOperand() 2352bdd1243dSDimitry Andric ->setValue((Value *)nullptr); 2353bdd1243dSDimitry Andric OutChains.push_back(Store); 2354bdd1243dSDimitry Andric } 2355bdd1243dSDimitry Andric LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize); 2356bdd1243dSDimitry Andric } 2357bdd1243dSDimitry Andric 2358bdd1243dSDimitry Andric // All stores are grouped in one node to allow the matching between 2359bdd1243dSDimitry Andric // the size of Ins and InVals. This only happens for vararg functions. 2360bdd1243dSDimitry Andric if (!OutChains.empty()) { 2361bdd1243dSDimitry Andric OutChains.push_back(Chain); 2362bdd1243dSDimitry Andric Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); 2363bdd1243dSDimitry Andric } 236481ad6265SDimitry Andric 236581ad6265SDimitry Andric return Chain; 236681ad6265SDimitry Andric } 236781ad6265SDimitry Andric 2368bdd1243dSDimitry Andric bool LoongArchTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const { 2369bdd1243dSDimitry Andric return CI->isTailCall(); 2370bdd1243dSDimitry Andric } 2371bdd1243dSDimitry Andric 2372*06c3fb27SDimitry Andric // Check if the return value is used as only a return value, as otherwise 2373*06c3fb27SDimitry Andric // we can't perform a tail-call. 2374*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isUsedByReturnOnly(SDNode *N, 2375*06c3fb27SDimitry Andric SDValue &Chain) const { 2376*06c3fb27SDimitry Andric if (N->getNumValues() != 1) 2377*06c3fb27SDimitry Andric return false; 2378*06c3fb27SDimitry Andric if (!N->hasNUsesOfValue(1, 0)) 2379*06c3fb27SDimitry Andric return false; 2380*06c3fb27SDimitry Andric 2381*06c3fb27SDimitry Andric SDNode *Copy = *N->use_begin(); 2382*06c3fb27SDimitry Andric if (Copy->getOpcode() != ISD::CopyToReg) 2383*06c3fb27SDimitry Andric return false; 2384*06c3fb27SDimitry Andric 2385*06c3fb27SDimitry Andric // If the ISD::CopyToReg has a glue operand, we conservatively assume it 2386*06c3fb27SDimitry Andric // isn't safe to perform a tail call. 2387*06c3fb27SDimitry Andric if (Copy->getGluedNode()) 2388*06c3fb27SDimitry Andric return false; 2389*06c3fb27SDimitry Andric 2390*06c3fb27SDimitry Andric // The copy must be used by a LoongArchISD::RET, and nothing else. 2391*06c3fb27SDimitry Andric bool HasRet = false; 2392*06c3fb27SDimitry Andric for (SDNode *Node : Copy->uses()) { 2393*06c3fb27SDimitry Andric if (Node->getOpcode() != LoongArchISD::RET) 2394*06c3fb27SDimitry Andric return false; 2395*06c3fb27SDimitry Andric HasRet = true; 2396*06c3fb27SDimitry Andric } 2397*06c3fb27SDimitry Andric 2398*06c3fb27SDimitry Andric if (!HasRet) 2399*06c3fb27SDimitry Andric return false; 2400*06c3fb27SDimitry Andric 2401*06c3fb27SDimitry Andric Chain = Copy->getOperand(0); 2402*06c3fb27SDimitry Andric return true; 2403*06c3fb27SDimitry Andric } 2404*06c3fb27SDimitry Andric 2405bdd1243dSDimitry Andric // Check whether the call is eligible for tail call optimization. 2406bdd1243dSDimitry Andric bool LoongArchTargetLowering::isEligibleForTailCallOptimization( 2407bdd1243dSDimitry Andric CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF, 2408bdd1243dSDimitry Andric const SmallVectorImpl<CCValAssign> &ArgLocs) const { 2409bdd1243dSDimitry Andric 2410bdd1243dSDimitry Andric auto CalleeCC = CLI.CallConv; 2411bdd1243dSDimitry Andric auto &Outs = CLI.Outs; 2412bdd1243dSDimitry Andric auto &Caller = MF.getFunction(); 2413bdd1243dSDimitry Andric auto CallerCC = Caller.getCallingConv(); 2414bdd1243dSDimitry Andric 2415bdd1243dSDimitry Andric // Do not tail call opt if the stack is used to pass parameters. 2416*06c3fb27SDimitry Andric if (CCInfo.getStackSize() != 0) 2417bdd1243dSDimitry Andric return false; 2418bdd1243dSDimitry Andric 2419bdd1243dSDimitry Andric // Do not tail call opt if any parameters need to be passed indirectly. 2420bdd1243dSDimitry Andric for (auto &VA : ArgLocs) 2421bdd1243dSDimitry Andric if (VA.getLocInfo() == CCValAssign::Indirect) 2422bdd1243dSDimitry Andric return false; 2423bdd1243dSDimitry Andric 2424bdd1243dSDimitry Andric // Do not tail call opt if either caller or callee uses struct return 2425bdd1243dSDimitry Andric // semantics. 2426bdd1243dSDimitry Andric auto IsCallerStructRet = Caller.hasStructRetAttr(); 2427bdd1243dSDimitry Andric auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet(); 2428bdd1243dSDimitry Andric if (IsCallerStructRet || IsCalleeStructRet) 2429bdd1243dSDimitry Andric return false; 2430bdd1243dSDimitry Andric 2431bdd1243dSDimitry Andric // Do not tail call opt if either the callee or caller has a byval argument. 2432bdd1243dSDimitry Andric for (auto &Arg : Outs) 2433bdd1243dSDimitry Andric if (Arg.Flags.isByVal()) 2434bdd1243dSDimitry Andric return false; 2435bdd1243dSDimitry Andric 2436bdd1243dSDimitry Andric // The callee has to preserve all registers the caller needs to preserve. 2437bdd1243dSDimitry Andric const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo(); 2438bdd1243dSDimitry Andric const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC); 2439bdd1243dSDimitry Andric if (CalleeCC != CallerCC) { 2440bdd1243dSDimitry Andric const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC); 2441bdd1243dSDimitry Andric if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved)) 2442bdd1243dSDimitry Andric return false; 2443bdd1243dSDimitry Andric } 2444bdd1243dSDimitry Andric return true; 2445bdd1243dSDimitry Andric } 2446bdd1243dSDimitry Andric 2447bdd1243dSDimitry Andric static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG) { 2448bdd1243dSDimitry Andric return DAG.getDataLayout().getPrefTypeAlign( 2449bdd1243dSDimitry Andric VT.getTypeForEVT(*DAG.getContext())); 2450bdd1243dSDimitry Andric } 2451bdd1243dSDimitry Andric 2452753f127fSDimitry Andric // Lower a call to a callseq_start + CALL + callseq_end chain, and add input 2453753f127fSDimitry Andric // and output parameter nodes. 2454753f127fSDimitry Andric SDValue 2455753f127fSDimitry Andric LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI, 2456753f127fSDimitry Andric SmallVectorImpl<SDValue> &InVals) const { 2457753f127fSDimitry Andric SelectionDAG &DAG = CLI.DAG; 2458753f127fSDimitry Andric SDLoc &DL = CLI.DL; 2459753f127fSDimitry Andric SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; 2460753f127fSDimitry Andric SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; 2461753f127fSDimitry Andric SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; 2462753f127fSDimitry Andric SDValue Chain = CLI.Chain; 2463753f127fSDimitry Andric SDValue Callee = CLI.Callee; 2464753f127fSDimitry Andric CallingConv::ID CallConv = CLI.CallConv; 2465753f127fSDimitry Andric bool IsVarArg = CLI.IsVarArg; 2466753f127fSDimitry Andric EVT PtrVT = getPointerTy(DAG.getDataLayout()); 2467bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 2468bdd1243dSDimitry Andric bool &IsTailCall = CLI.IsTailCall; 2469753f127fSDimitry Andric 2470753f127fSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 2471753f127fSDimitry Andric 2472753f127fSDimitry Andric // Analyze the operands of the call, assigning locations to each operand. 2473753f127fSDimitry Andric SmallVector<CCValAssign> ArgLocs; 2474753f127fSDimitry Andric CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 2475753f127fSDimitry Andric 2476bdd1243dSDimitry Andric if (CallConv == CallingConv::GHC) 2477bdd1243dSDimitry Andric ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC); 2478bdd1243dSDimitry Andric else 2479bdd1243dSDimitry Andric analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch); 2480bdd1243dSDimitry Andric 2481bdd1243dSDimitry Andric // Check if it's really possible to do a tail call. 2482bdd1243dSDimitry Andric if (IsTailCall) 2483bdd1243dSDimitry Andric IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs); 2484bdd1243dSDimitry Andric 2485bdd1243dSDimitry Andric if (IsTailCall) 2486bdd1243dSDimitry Andric ++NumTailCalls; 2487bdd1243dSDimitry Andric else if (CLI.CB && CLI.CB->isMustTailCall()) 2488bdd1243dSDimitry Andric report_fatal_error("failed to perform tail call elimination on a call " 2489bdd1243dSDimitry Andric "site marked musttail"); 2490753f127fSDimitry Andric 2491753f127fSDimitry Andric // Get a count of how many bytes are to be pushed on the stack. 2492*06c3fb27SDimitry Andric unsigned NumBytes = ArgCCInfo.getStackSize(); 2493753f127fSDimitry Andric 2494bdd1243dSDimitry Andric // Create local copies for byval args. 2495bdd1243dSDimitry Andric SmallVector<SDValue> ByValArgs; 2496bdd1243dSDimitry Andric for (unsigned i = 0, e = Outs.size(); i != e; ++i) { 2497bdd1243dSDimitry Andric ISD::ArgFlagsTy Flags = Outs[i].Flags; 2498bdd1243dSDimitry Andric if (!Flags.isByVal()) 2499753f127fSDimitry Andric continue; 2500bdd1243dSDimitry Andric 2501bdd1243dSDimitry Andric SDValue Arg = OutVals[i]; 2502bdd1243dSDimitry Andric unsigned Size = Flags.getByValSize(); 2503bdd1243dSDimitry Andric Align Alignment = Flags.getNonZeroByValAlign(); 2504bdd1243dSDimitry Andric 2505bdd1243dSDimitry Andric int FI = 2506bdd1243dSDimitry Andric MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false); 2507bdd1243dSDimitry Andric SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 2508bdd1243dSDimitry Andric SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT); 2509bdd1243dSDimitry Andric 2510bdd1243dSDimitry Andric Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment, 2511bdd1243dSDimitry Andric /*IsVolatile=*/false, 2512bdd1243dSDimitry Andric /*AlwaysInline=*/false, /*isTailCall=*/IsTailCall, 2513bdd1243dSDimitry Andric MachinePointerInfo(), MachinePointerInfo()); 2514bdd1243dSDimitry Andric ByValArgs.push_back(FIPtr); 2515753f127fSDimitry Andric } 2516753f127fSDimitry Andric 2517bdd1243dSDimitry Andric if (!IsTailCall) 2518753f127fSDimitry Andric Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL); 2519753f127fSDimitry Andric 2520753f127fSDimitry Andric // Copy argument values to their designated locations. 2521753f127fSDimitry Andric SmallVector<std::pair<Register, SDValue>> RegsToPass; 2522bdd1243dSDimitry Andric SmallVector<SDValue> MemOpChains; 2523bdd1243dSDimitry Andric SDValue StackPtr; 2524bdd1243dSDimitry Andric for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) { 2525753f127fSDimitry Andric CCValAssign &VA = ArgLocs[i]; 2526753f127fSDimitry Andric SDValue ArgValue = OutVals[i]; 2527bdd1243dSDimitry Andric ISD::ArgFlagsTy Flags = Outs[i].Flags; 2528753f127fSDimitry Andric 2529753f127fSDimitry Andric // Promote the value if needed. 2530bdd1243dSDimitry Andric // For now, only handle fully promoted and indirect arguments. 2531bdd1243dSDimitry Andric if (VA.getLocInfo() == CCValAssign::Indirect) { 2532bdd1243dSDimitry Andric // Store the argument in a stack slot and pass its address. 2533bdd1243dSDimitry Andric Align StackAlign = 2534bdd1243dSDimitry Andric std::max(getPrefTypeAlign(Outs[i].ArgVT, DAG), 2535bdd1243dSDimitry Andric getPrefTypeAlign(ArgValue.getValueType(), DAG)); 2536bdd1243dSDimitry Andric TypeSize StoredSize = ArgValue.getValueType().getStoreSize(); 2537bdd1243dSDimitry Andric // If the original argument was split and passed by reference, we need to 2538bdd1243dSDimitry Andric // store the required parts of it here (and pass just one address). 2539bdd1243dSDimitry Andric unsigned ArgIndex = Outs[i].OrigArgIndex; 2540bdd1243dSDimitry Andric unsigned ArgPartOffset = Outs[i].PartOffset; 2541bdd1243dSDimitry Andric assert(ArgPartOffset == 0); 2542bdd1243dSDimitry Andric // Calculate the total size to store. We don't have access to what we're 2543bdd1243dSDimitry Andric // actually storing other than performing the loop and collecting the 2544bdd1243dSDimitry Andric // info. 2545bdd1243dSDimitry Andric SmallVector<std::pair<SDValue, SDValue>> Parts; 2546bdd1243dSDimitry Andric while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) { 2547bdd1243dSDimitry Andric SDValue PartValue = OutVals[i + 1]; 2548bdd1243dSDimitry Andric unsigned PartOffset = Outs[i + 1].PartOffset - ArgPartOffset; 2549bdd1243dSDimitry Andric SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL); 2550bdd1243dSDimitry Andric EVT PartVT = PartValue.getValueType(); 2551bdd1243dSDimitry Andric 2552bdd1243dSDimitry Andric StoredSize += PartVT.getStoreSize(); 2553bdd1243dSDimitry Andric StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG)); 2554bdd1243dSDimitry Andric Parts.push_back(std::make_pair(PartValue, Offset)); 2555bdd1243dSDimitry Andric ++i; 2556bdd1243dSDimitry Andric } 2557bdd1243dSDimitry Andric SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign); 2558bdd1243dSDimitry Andric int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex(); 2559bdd1243dSDimitry Andric MemOpChains.push_back( 2560bdd1243dSDimitry Andric DAG.getStore(Chain, DL, ArgValue, SpillSlot, 2561bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(MF, FI))); 2562bdd1243dSDimitry Andric for (const auto &Part : Parts) { 2563bdd1243dSDimitry Andric SDValue PartValue = Part.first; 2564bdd1243dSDimitry Andric SDValue PartOffset = Part.second; 2565bdd1243dSDimitry Andric SDValue Address = 2566bdd1243dSDimitry Andric DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset); 2567bdd1243dSDimitry Andric MemOpChains.push_back( 2568bdd1243dSDimitry Andric DAG.getStore(Chain, DL, PartValue, Address, 2569bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(MF, FI))); 2570bdd1243dSDimitry Andric } 2571bdd1243dSDimitry Andric ArgValue = SpillSlot; 2572bdd1243dSDimitry Andric } else { 2573bdd1243dSDimitry Andric ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL); 2574bdd1243dSDimitry Andric } 2575bdd1243dSDimitry Andric 2576bdd1243dSDimitry Andric // Use local copy if it is a byval arg. 2577bdd1243dSDimitry Andric if (Flags.isByVal()) 2578bdd1243dSDimitry Andric ArgValue = ByValArgs[j++]; 2579753f127fSDimitry Andric 2580753f127fSDimitry Andric if (VA.isRegLoc()) { 2581753f127fSDimitry Andric // Queue up the argument copies and emit them at the end. 2582753f127fSDimitry Andric RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); 2583753f127fSDimitry Andric } else { 2584bdd1243dSDimitry Andric assert(VA.isMemLoc() && "Argument not register or memory"); 2585bdd1243dSDimitry Andric assert(!IsTailCall && "Tail call not allowed if stack is used " 2586bdd1243dSDimitry Andric "for passing parameters"); 2587bdd1243dSDimitry Andric 2588bdd1243dSDimitry Andric // Work out the address of the stack slot. 2589bdd1243dSDimitry Andric if (!StackPtr.getNode()) 2590bdd1243dSDimitry Andric StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT); 2591bdd1243dSDimitry Andric SDValue Address = 2592bdd1243dSDimitry Andric DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, 2593bdd1243dSDimitry Andric DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); 2594bdd1243dSDimitry Andric 2595bdd1243dSDimitry Andric // Emit the store. 2596bdd1243dSDimitry Andric MemOpChains.push_back( 2597bdd1243dSDimitry Andric DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo())); 2598753f127fSDimitry Andric } 2599753f127fSDimitry Andric } 2600753f127fSDimitry Andric 2601bdd1243dSDimitry Andric // Join the stores, which are independent of one another. 2602bdd1243dSDimitry Andric if (!MemOpChains.empty()) 2603bdd1243dSDimitry Andric Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); 2604bdd1243dSDimitry Andric 2605753f127fSDimitry Andric SDValue Glue; 2606753f127fSDimitry Andric 2607753f127fSDimitry Andric // Build a sequence of copy-to-reg nodes, chained and glued together. 2608753f127fSDimitry Andric for (auto &Reg : RegsToPass) { 2609753f127fSDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue); 2610753f127fSDimitry Andric Glue = Chain.getValue(1); 2611753f127fSDimitry Andric } 2612753f127fSDimitry Andric 2613753f127fSDimitry Andric // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a 2614753f127fSDimitry Andric // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't 2615753f127fSDimitry Andric // split it and then direct call can be matched by PseudoCALL. 2616bdd1243dSDimitry Andric if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) { 2617bdd1243dSDimitry Andric const GlobalValue *GV = S->getGlobal(); 2618bdd1243dSDimitry Andric unsigned OpFlags = 2619bdd1243dSDimitry Andric getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV) 2620bdd1243dSDimitry Andric ? LoongArchII::MO_CALL 2621bdd1243dSDimitry Andric : LoongArchII::MO_CALL_PLT; 2622bdd1243dSDimitry Andric Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags); 2623bdd1243dSDimitry Andric } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { 2624bdd1243dSDimitry Andric unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal( 2625bdd1243dSDimitry Andric *MF.getFunction().getParent(), nullptr) 2626bdd1243dSDimitry Andric ? LoongArchII::MO_CALL 2627bdd1243dSDimitry Andric : LoongArchII::MO_CALL_PLT; 2628bdd1243dSDimitry Andric Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags); 2629bdd1243dSDimitry Andric } 2630753f127fSDimitry Andric 2631753f127fSDimitry Andric // The first call operand is the chain and the second is the target address. 2632753f127fSDimitry Andric SmallVector<SDValue> Ops; 2633753f127fSDimitry Andric Ops.push_back(Chain); 2634753f127fSDimitry Andric Ops.push_back(Callee); 2635753f127fSDimitry Andric 2636753f127fSDimitry Andric // Add argument registers to the end of the list so that they are 2637753f127fSDimitry Andric // known live into the call. 2638753f127fSDimitry Andric for (auto &Reg : RegsToPass) 2639753f127fSDimitry Andric Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType())); 2640753f127fSDimitry Andric 2641bdd1243dSDimitry Andric if (!IsTailCall) { 2642753f127fSDimitry Andric // Add a register mask operand representing the call-preserved registers. 2643753f127fSDimitry Andric const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); 2644753f127fSDimitry Andric const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv); 2645753f127fSDimitry Andric assert(Mask && "Missing call preserved mask for calling convention"); 2646753f127fSDimitry Andric Ops.push_back(DAG.getRegisterMask(Mask)); 2647bdd1243dSDimitry Andric } 2648753f127fSDimitry Andric 2649753f127fSDimitry Andric // Glue the call to the argument copies, if any. 2650753f127fSDimitry Andric if (Glue.getNode()) 2651753f127fSDimitry Andric Ops.push_back(Glue); 2652753f127fSDimitry Andric 2653753f127fSDimitry Andric // Emit the call. 2654753f127fSDimitry Andric SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); 2655753f127fSDimitry Andric 2656bdd1243dSDimitry Andric if (IsTailCall) { 2657bdd1243dSDimitry Andric MF.getFrameInfo().setHasTailCall(); 2658*06c3fb27SDimitry Andric SDValue Ret = DAG.getNode(LoongArchISD::TAIL, DL, NodeTys, Ops); 2659*06c3fb27SDimitry Andric DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge); 2660*06c3fb27SDimitry Andric return Ret; 2661bdd1243dSDimitry Andric } 2662bdd1243dSDimitry Andric 2663753f127fSDimitry Andric Chain = DAG.getNode(LoongArchISD::CALL, DL, NodeTys, Ops); 2664753f127fSDimitry Andric DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge); 2665753f127fSDimitry Andric Glue = Chain.getValue(1); 2666753f127fSDimitry Andric 2667753f127fSDimitry Andric // Mark the end of the call, which is glued to the call itself. 2668bdd1243dSDimitry Andric Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL); 2669753f127fSDimitry Andric Glue = Chain.getValue(1); 2670753f127fSDimitry Andric 2671753f127fSDimitry Andric // Assign locations to each value returned by this call. 2672753f127fSDimitry Andric SmallVector<CCValAssign> RVLocs; 2673753f127fSDimitry Andric CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); 2674bdd1243dSDimitry Andric analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch); 2675753f127fSDimitry Andric 2676753f127fSDimitry Andric // Copy all of the result registers out of their specified physreg. 2677753f127fSDimitry Andric for (auto &VA : RVLocs) { 2678753f127fSDimitry Andric // Copy the value out. 2679753f127fSDimitry Andric SDValue RetValue = 2680753f127fSDimitry Andric DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue); 2681bdd1243dSDimitry Andric // Glue the RetValue to the end of the call sequence. 2682753f127fSDimitry Andric Chain = RetValue.getValue(1); 2683753f127fSDimitry Andric Glue = RetValue.getValue(2); 2684753f127fSDimitry Andric 2685bdd1243dSDimitry Andric RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL); 2686bdd1243dSDimitry Andric 2687bdd1243dSDimitry Andric InVals.push_back(RetValue); 2688753f127fSDimitry Andric } 2689753f127fSDimitry Andric 2690753f127fSDimitry Andric return Chain; 2691753f127fSDimitry Andric } 2692753f127fSDimitry Andric 269381ad6265SDimitry Andric bool LoongArchTargetLowering::CanLowerReturn( 269481ad6265SDimitry Andric CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, 269581ad6265SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { 2696bdd1243dSDimitry Andric SmallVector<CCValAssign> RVLocs; 2697bdd1243dSDimitry Andric CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); 2698bdd1243dSDimitry Andric 2699bdd1243dSDimitry Andric for (unsigned i = 0, e = Outs.size(); i != e; ++i) { 2700bdd1243dSDimitry Andric LoongArchABI::ABI ABI = 2701bdd1243dSDimitry Andric MF.getSubtarget<LoongArchSubtarget>().getTargetABI(); 2702bdd1243dSDimitry Andric if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full, 2703bdd1243dSDimitry Andric Outs[i].Flags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true, 2704bdd1243dSDimitry Andric nullptr)) 2705bdd1243dSDimitry Andric return false; 2706bdd1243dSDimitry Andric } 2707bdd1243dSDimitry Andric return true; 270881ad6265SDimitry Andric } 270981ad6265SDimitry Andric 271081ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerReturn( 271181ad6265SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 271281ad6265SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, 271381ad6265SDimitry Andric const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, 271481ad6265SDimitry Andric SelectionDAG &DAG) const { 271581ad6265SDimitry Andric // Stores the assignment of the return value to a location. 271681ad6265SDimitry Andric SmallVector<CCValAssign> RVLocs; 271781ad6265SDimitry Andric 271881ad6265SDimitry Andric // Info about the registers and stack slot. 271981ad6265SDimitry Andric CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, 272081ad6265SDimitry Andric *DAG.getContext()); 272181ad6265SDimitry Andric 2722bdd1243dSDimitry Andric analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true, 2723bdd1243dSDimitry Andric nullptr, CC_LoongArch); 2724bdd1243dSDimitry Andric if (CallConv == CallingConv::GHC && !RVLocs.empty()) 2725bdd1243dSDimitry Andric report_fatal_error("GHC functions return void only"); 272681ad6265SDimitry Andric SDValue Glue; 272781ad6265SDimitry Andric SmallVector<SDValue, 4> RetOps(1, Chain); 272881ad6265SDimitry Andric 272981ad6265SDimitry Andric // Copy the result values into the output registers. 273081ad6265SDimitry Andric for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) { 273181ad6265SDimitry Andric CCValAssign &VA = RVLocs[i]; 273281ad6265SDimitry Andric assert(VA.isRegLoc() && "Can only return in registers!"); 273381ad6265SDimitry Andric 273481ad6265SDimitry Andric // Handle a 'normal' return. 2735bdd1243dSDimitry Andric SDValue Val = convertValVTToLocVT(DAG, OutVals[i], VA, DL); 2736bdd1243dSDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue); 273781ad6265SDimitry Andric 273881ad6265SDimitry Andric // Guarantee that all emitted copies are stuck together. 273981ad6265SDimitry Andric Glue = Chain.getValue(1); 274081ad6265SDimitry Andric RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); 274181ad6265SDimitry Andric } 274281ad6265SDimitry Andric 274381ad6265SDimitry Andric RetOps[0] = Chain; // Update chain. 274481ad6265SDimitry Andric 274581ad6265SDimitry Andric // Add the glue node if we have it. 274681ad6265SDimitry Andric if (Glue.getNode()) 274781ad6265SDimitry Andric RetOps.push_back(Glue); 274881ad6265SDimitry Andric 274981ad6265SDimitry Andric return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps); 275081ad6265SDimitry Andric } 2751753f127fSDimitry Andric 2752753f127fSDimitry Andric bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, 2753753f127fSDimitry Andric bool ForCodeSize) const { 2754bdd1243dSDimitry Andric // TODO: Maybe need more checks here after vector extension is supported. 2755753f127fSDimitry Andric if (VT == MVT::f32 && !Subtarget.hasBasicF()) 2756753f127fSDimitry Andric return false; 2757753f127fSDimitry Andric if (VT == MVT::f64 && !Subtarget.hasBasicD()) 2758753f127fSDimitry Andric return false; 2759753f127fSDimitry Andric return (Imm.isZero() || Imm.isExactlyValue(+1.0)); 2760753f127fSDimitry Andric } 2761bdd1243dSDimitry Andric 2762bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCttz(Type *) const { 2763bdd1243dSDimitry Andric return true; 2764bdd1243dSDimitry Andric } 2765bdd1243dSDimitry Andric 2766bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCtlz(Type *) const { 2767bdd1243dSDimitry Andric return true; 2768bdd1243dSDimitry Andric } 2769bdd1243dSDimitry Andric 2770bdd1243dSDimitry Andric bool LoongArchTargetLowering::shouldInsertFencesForAtomic( 2771bdd1243dSDimitry Andric const Instruction *I) const { 2772bdd1243dSDimitry Andric if (!Subtarget.is64Bit()) 2773bdd1243dSDimitry Andric return isa<LoadInst>(I) || isa<StoreInst>(I); 2774bdd1243dSDimitry Andric 2775bdd1243dSDimitry Andric if (isa<LoadInst>(I)) 2776bdd1243dSDimitry Andric return true; 2777bdd1243dSDimitry Andric 2778bdd1243dSDimitry Andric // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not 2779bdd1243dSDimitry Andric // require fences beacuse we can use amswap_db.[w/d]. 2780bdd1243dSDimitry Andric if (isa<StoreInst>(I)) { 2781bdd1243dSDimitry Andric unsigned Size = I->getOperand(0)->getType()->getIntegerBitWidth(); 2782bdd1243dSDimitry Andric return (Size == 8 || Size == 16); 2783bdd1243dSDimitry Andric } 2784bdd1243dSDimitry Andric 2785bdd1243dSDimitry Andric return false; 2786bdd1243dSDimitry Andric } 2787bdd1243dSDimitry Andric 2788bdd1243dSDimitry Andric EVT LoongArchTargetLowering::getSetCCResultType(const DataLayout &DL, 2789bdd1243dSDimitry Andric LLVMContext &Context, 2790bdd1243dSDimitry Andric EVT VT) const { 2791bdd1243dSDimitry Andric if (!VT.isVector()) 2792bdd1243dSDimitry Andric return getPointerTy(DL); 2793bdd1243dSDimitry Andric return VT.changeVectorElementTypeToInteger(); 2794bdd1243dSDimitry Andric } 2795bdd1243dSDimitry Andric 2796bdd1243dSDimitry Andric bool LoongArchTargetLowering::hasAndNot(SDValue Y) const { 2797bdd1243dSDimitry Andric // TODO: Support vectors. 2798bdd1243dSDimitry Andric return Y.getValueType().isScalarInteger() && !isa<ConstantSDNode>(Y); 2799bdd1243dSDimitry Andric } 2800bdd1243dSDimitry Andric 2801bdd1243dSDimitry Andric bool LoongArchTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, 2802bdd1243dSDimitry Andric const CallInst &I, 2803bdd1243dSDimitry Andric MachineFunction &MF, 2804bdd1243dSDimitry Andric unsigned Intrinsic) const { 2805bdd1243dSDimitry Andric switch (Intrinsic) { 2806bdd1243dSDimitry Andric default: 2807bdd1243dSDimitry Andric return false; 2808bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_xchg_i32: 2809bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_add_i32: 2810bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_sub_i32: 2811bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_nand_i32: 2812bdd1243dSDimitry Andric Info.opc = ISD::INTRINSIC_W_CHAIN; 2813bdd1243dSDimitry Andric Info.memVT = MVT::i32; 2814bdd1243dSDimitry Andric Info.ptrVal = I.getArgOperand(0); 2815bdd1243dSDimitry Andric Info.offset = 0; 2816bdd1243dSDimitry Andric Info.align = Align(4); 2817bdd1243dSDimitry Andric Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore | 2818bdd1243dSDimitry Andric MachineMemOperand::MOVolatile; 2819bdd1243dSDimitry Andric return true; 2820bdd1243dSDimitry Andric // TODO: Add more Intrinsics later. 2821bdd1243dSDimitry Andric } 2822bdd1243dSDimitry Andric } 2823bdd1243dSDimitry Andric 2824bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind 2825bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { 2826bdd1243dSDimitry Andric // TODO: Add more AtomicRMWInst that needs to be extended. 2827bdd1243dSDimitry Andric 2828bdd1243dSDimitry Andric // Since floating-point operation requires a non-trivial set of data 2829bdd1243dSDimitry Andric // operations, use CmpXChg to expand. 2830bdd1243dSDimitry Andric if (AI->isFloatingPointOperation() || 2831bdd1243dSDimitry Andric AI->getOperation() == AtomicRMWInst::UIncWrap || 2832bdd1243dSDimitry Andric AI->getOperation() == AtomicRMWInst::UDecWrap) 2833bdd1243dSDimitry Andric return AtomicExpansionKind::CmpXChg; 2834bdd1243dSDimitry Andric 2835bdd1243dSDimitry Andric unsigned Size = AI->getType()->getPrimitiveSizeInBits(); 2836bdd1243dSDimitry Andric if (Size == 8 || Size == 16) 2837bdd1243dSDimitry Andric return AtomicExpansionKind::MaskedIntrinsic; 2838bdd1243dSDimitry Andric return AtomicExpansionKind::None; 2839bdd1243dSDimitry Andric } 2840bdd1243dSDimitry Andric 2841bdd1243dSDimitry Andric static Intrinsic::ID 2842bdd1243dSDimitry Andric getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen, 2843bdd1243dSDimitry Andric AtomicRMWInst::BinOp BinOp) { 2844bdd1243dSDimitry Andric if (GRLen == 64) { 2845bdd1243dSDimitry Andric switch (BinOp) { 2846bdd1243dSDimitry Andric default: 2847bdd1243dSDimitry Andric llvm_unreachable("Unexpected AtomicRMW BinOp"); 2848bdd1243dSDimitry Andric case AtomicRMWInst::Xchg: 2849bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_xchg_i64; 2850bdd1243dSDimitry Andric case AtomicRMWInst::Add: 2851bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_add_i64; 2852bdd1243dSDimitry Andric case AtomicRMWInst::Sub: 2853bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_sub_i64; 2854bdd1243dSDimitry Andric case AtomicRMWInst::Nand: 2855bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_nand_i64; 2856bdd1243dSDimitry Andric case AtomicRMWInst::UMax: 2857bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_umax_i64; 2858bdd1243dSDimitry Andric case AtomicRMWInst::UMin: 2859bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_umin_i64; 2860bdd1243dSDimitry Andric case AtomicRMWInst::Max: 2861bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_max_i64; 2862bdd1243dSDimitry Andric case AtomicRMWInst::Min: 2863bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_min_i64; 2864bdd1243dSDimitry Andric // TODO: support other AtomicRMWInst. 2865bdd1243dSDimitry Andric } 2866bdd1243dSDimitry Andric } 2867bdd1243dSDimitry Andric 2868bdd1243dSDimitry Andric if (GRLen == 32) { 2869bdd1243dSDimitry Andric switch (BinOp) { 2870bdd1243dSDimitry Andric default: 2871bdd1243dSDimitry Andric llvm_unreachable("Unexpected AtomicRMW BinOp"); 2872bdd1243dSDimitry Andric case AtomicRMWInst::Xchg: 2873bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_xchg_i32; 2874bdd1243dSDimitry Andric case AtomicRMWInst::Add: 2875bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_add_i32; 2876bdd1243dSDimitry Andric case AtomicRMWInst::Sub: 2877bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_sub_i32; 2878bdd1243dSDimitry Andric case AtomicRMWInst::Nand: 2879bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_nand_i32; 2880bdd1243dSDimitry Andric // TODO: support other AtomicRMWInst. 2881bdd1243dSDimitry Andric } 2882bdd1243dSDimitry Andric } 2883bdd1243dSDimitry Andric 2884bdd1243dSDimitry Andric llvm_unreachable("Unexpected GRLen\n"); 2885bdd1243dSDimitry Andric } 2886bdd1243dSDimitry Andric 2887bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind 2888bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicCmpXchgInIR( 2889bdd1243dSDimitry Andric AtomicCmpXchgInst *CI) const { 2890bdd1243dSDimitry Andric unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits(); 2891bdd1243dSDimitry Andric if (Size == 8 || Size == 16) 2892bdd1243dSDimitry Andric return AtomicExpansionKind::MaskedIntrinsic; 2893bdd1243dSDimitry Andric return AtomicExpansionKind::None; 2894bdd1243dSDimitry Andric } 2895bdd1243dSDimitry Andric 2896bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicCmpXchgIntrinsic( 2897bdd1243dSDimitry Andric IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, 2898bdd1243dSDimitry Andric Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const { 2899bdd1243dSDimitry Andric Value *Ordering = 2900bdd1243dSDimitry Andric Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(Ord)); 2901bdd1243dSDimitry Andric 2902bdd1243dSDimitry Andric // TODO: Support cmpxchg on LA32. 2903bdd1243dSDimitry Andric Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64; 2904bdd1243dSDimitry Andric CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty()); 2905bdd1243dSDimitry Andric NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty()); 2906bdd1243dSDimitry Andric Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty()); 2907bdd1243dSDimitry Andric Type *Tys[] = {AlignedAddr->getType()}; 2908bdd1243dSDimitry Andric Function *MaskedCmpXchg = 2909bdd1243dSDimitry Andric Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys); 2910bdd1243dSDimitry Andric Value *Result = Builder.CreateCall( 2911bdd1243dSDimitry Andric MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, Ordering}); 2912bdd1243dSDimitry Andric Result = Builder.CreateTrunc(Result, Builder.getInt32Ty()); 2913bdd1243dSDimitry Andric return Result; 2914bdd1243dSDimitry Andric } 2915bdd1243dSDimitry Andric 2916bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicRMWIntrinsic( 2917bdd1243dSDimitry Andric IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr, 2918bdd1243dSDimitry Andric Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const { 2919bdd1243dSDimitry Andric unsigned GRLen = Subtarget.getGRLen(); 2920bdd1243dSDimitry Andric Value *Ordering = 2921bdd1243dSDimitry Andric Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering())); 2922bdd1243dSDimitry Andric Type *Tys[] = {AlignedAddr->getType()}; 2923bdd1243dSDimitry Andric Function *LlwOpScwLoop = Intrinsic::getDeclaration( 2924bdd1243dSDimitry Andric AI->getModule(), 2925bdd1243dSDimitry Andric getIntrinsicForMaskedAtomicRMWBinOp(GRLen, AI->getOperation()), Tys); 2926bdd1243dSDimitry Andric 2927bdd1243dSDimitry Andric if (GRLen == 64) { 2928bdd1243dSDimitry Andric Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty()); 2929bdd1243dSDimitry Andric Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty()); 2930bdd1243dSDimitry Andric ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty()); 2931bdd1243dSDimitry Andric } 2932bdd1243dSDimitry Andric 2933bdd1243dSDimitry Andric Value *Result; 2934bdd1243dSDimitry Andric 2935bdd1243dSDimitry Andric // Must pass the shift amount needed to sign extend the loaded value prior 2936bdd1243dSDimitry Andric // to performing a signed comparison for min/max. ShiftAmt is the number of 2937bdd1243dSDimitry Andric // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which 2938bdd1243dSDimitry Andric // is the number of bits to left+right shift the value in order to 2939bdd1243dSDimitry Andric // sign-extend. 2940bdd1243dSDimitry Andric if (AI->getOperation() == AtomicRMWInst::Min || 2941bdd1243dSDimitry Andric AI->getOperation() == AtomicRMWInst::Max) { 2942bdd1243dSDimitry Andric const DataLayout &DL = AI->getModule()->getDataLayout(); 2943bdd1243dSDimitry Andric unsigned ValWidth = 2944bdd1243dSDimitry Andric DL.getTypeStoreSizeInBits(AI->getValOperand()->getType()); 2945bdd1243dSDimitry Andric Value *SextShamt = 2946bdd1243dSDimitry Andric Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt); 2947bdd1243dSDimitry Andric Result = Builder.CreateCall(LlwOpScwLoop, 2948bdd1243dSDimitry Andric {AlignedAddr, Incr, Mask, SextShamt, Ordering}); 2949bdd1243dSDimitry Andric } else { 2950bdd1243dSDimitry Andric Result = 2951bdd1243dSDimitry Andric Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering}); 2952bdd1243dSDimitry Andric } 2953bdd1243dSDimitry Andric 2954bdd1243dSDimitry Andric if (GRLen == 64) 2955bdd1243dSDimitry Andric Result = Builder.CreateTrunc(Result, Builder.getInt32Ty()); 2956bdd1243dSDimitry Andric return Result; 2957bdd1243dSDimitry Andric } 2958bdd1243dSDimitry Andric 2959bdd1243dSDimitry Andric bool LoongArchTargetLowering::isFMAFasterThanFMulAndFAdd( 2960bdd1243dSDimitry Andric const MachineFunction &MF, EVT VT) const { 2961bdd1243dSDimitry Andric VT = VT.getScalarType(); 2962bdd1243dSDimitry Andric 2963bdd1243dSDimitry Andric if (!VT.isSimple()) 2964bdd1243dSDimitry Andric return false; 2965bdd1243dSDimitry Andric 2966bdd1243dSDimitry Andric switch (VT.getSimpleVT().SimpleTy) { 2967bdd1243dSDimitry Andric case MVT::f32: 2968bdd1243dSDimitry Andric case MVT::f64: 2969bdd1243dSDimitry Andric return true; 2970bdd1243dSDimitry Andric default: 2971bdd1243dSDimitry Andric break; 2972bdd1243dSDimitry Andric } 2973bdd1243dSDimitry Andric 2974bdd1243dSDimitry Andric return false; 2975bdd1243dSDimitry Andric } 2976bdd1243dSDimitry Andric 2977bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionPointerRegister( 2978bdd1243dSDimitry Andric const Constant *PersonalityFn) const { 2979bdd1243dSDimitry Andric return LoongArch::R4; 2980bdd1243dSDimitry Andric } 2981bdd1243dSDimitry Andric 2982bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionSelectorRegister( 2983bdd1243dSDimitry Andric const Constant *PersonalityFn) const { 2984bdd1243dSDimitry Andric return LoongArch::R5; 2985bdd1243dSDimitry Andric } 2986bdd1243dSDimitry Andric 2987bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 2988bdd1243dSDimitry Andric // LoongArch Inline Assembly Support 2989bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 2990bdd1243dSDimitry Andric 2991bdd1243dSDimitry Andric LoongArchTargetLowering::ConstraintType 2992bdd1243dSDimitry Andric LoongArchTargetLowering::getConstraintType(StringRef Constraint) const { 2993bdd1243dSDimitry Andric // LoongArch specific constraints in GCC: config/loongarch/constraints.md 2994bdd1243dSDimitry Andric // 2995bdd1243dSDimitry Andric // 'f': A floating-point register (if available). 2996bdd1243dSDimitry Andric // 'k': A memory operand whose address is formed by a base register and 2997bdd1243dSDimitry Andric // (optionally scaled) index register. 2998bdd1243dSDimitry Andric // 'l': A signed 16-bit constant. 2999bdd1243dSDimitry Andric // 'm': A memory operand whose address is formed by a base register and 3000bdd1243dSDimitry Andric // offset that is suitable for use in instructions with the same 3001bdd1243dSDimitry Andric // addressing mode as st.w and ld.w. 3002bdd1243dSDimitry Andric // 'I': A signed 12-bit constant (for arithmetic instructions). 3003bdd1243dSDimitry Andric // 'J': Integer zero. 3004bdd1243dSDimitry Andric // 'K': An unsigned 12-bit constant (for logic instructions). 3005bdd1243dSDimitry Andric // "ZB": An address that is held in a general-purpose register. The offset is 3006bdd1243dSDimitry Andric // zero. 3007bdd1243dSDimitry Andric // "ZC": A memory operand whose address is formed by a base register and 3008bdd1243dSDimitry Andric // offset that is suitable for use in instructions with the same 3009bdd1243dSDimitry Andric // addressing mode as ll.w and sc.w. 3010bdd1243dSDimitry Andric if (Constraint.size() == 1) { 3011bdd1243dSDimitry Andric switch (Constraint[0]) { 3012bdd1243dSDimitry Andric default: 3013bdd1243dSDimitry Andric break; 3014bdd1243dSDimitry Andric case 'f': 3015bdd1243dSDimitry Andric return C_RegisterClass; 3016bdd1243dSDimitry Andric case 'l': 3017bdd1243dSDimitry Andric case 'I': 3018bdd1243dSDimitry Andric case 'J': 3019bdd1243dSDimitry Andric case 'K': 3020bdd1243dSDimitry Andric return C_Immediate; 3021bdd1243dSDimitry Andric case 'k': 3022bdd1243dSDimitry Andric return C_Memory; 3023bdd1243dSDimitry Andric } 3024bdd1243dSDimitry Andric } 3025bdd1243dSDimitry Andric 3026bdd1243dSDimitry Andric if (Constraint == "ZC" || Constraint == "ZB") 3027bdd1243dSDimitry Andric return C_Memory; 3028bdd1243dSDimitry Andric 3029bdd1243dSDimitry Andric // 'm' is handled here. 3030bdd1243dSDimitry Andric return TargetLowering::getConstraintType(Constraint); 3031bdd1243dSDimitry Andric } 3032bdd1243dSDimitry Andric 3033bdd1243dSDimitry Andric unsigned LoongArchTargetLowering::getInlineAsmMemConstraint( 3034bdd1243dSDimitry Andric StringRef ConstraintCode) const { 3035bdd1243dSDimitry Andric return StringSwitch<unsigned>(ConstraintCode) 3036bdd1243dSDimitry Andric .Case("k", InlineAsm::Constraint_k) 3037bdd1243dSDimitry Andric .Case("ZB", InlineAsm::Constraint_ZB) 3038bdd1243dSDimitry Andric .Case("ZC", InlineAsm::Constraint_ZC) 3039bdd1243dSDimitry Andric .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode)); 3040bdd1243dSDimitry Andric } 3041bdd1243dSDimitry Andric 3042bdd1243dSDimitry Andric std::pair<unsigned, const TargetRegisterClass *> 3043bdd1243dSDimitry Andric LoongArchTargetLowering::getRegForInlineAsmConstraint( 3044bdd1243dSDimitry Andric const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { 3045bdd1243dSDimitry Andric // First, see if this is a constraint that directly corresponds to a LoongArch 3046bdd1243dSDimitry Andric // register class. 3047bdd1243dSDimitry Andric if (Constraint.size() == 1) { 3048bdd1243dSDimitry Andric switch (Constraint[0]) { 3049bdd1243dSDimitry Andric case 'r': 3050bdd1243dSDimitry Andric // TODO: Support fixed vectors up to GRLen? 3051bdd1243dSDimitry Andric if (VT.isVector()) 3052bdd1243dSDimitry Andric break; 3053bdd1243dSDimitry Andric return std::make_pair(0U, &LoongArch::GPRRegClass); 3054bdd1243dSDimitry Andric case 'f': 3055bdd1243dSDimitry Andric if (Subtarget.hasBasicF() && VT == MVT::f32) 3056bdd1243dSDimitry Andric return std::make_pair(0U, &LoongArch::FPR32RegClass); 3057bdd1243dSDimitry Andric if (Subtarget.hasBasicD() && VT == MVT::f64) 3058bdd1243dSDimitry Andric return std::make_pair(0U, &LoongArch::FPR64RegClass); 3059*06c3fb27SDimitry Andric if (Subtarget.hasExtLSX() && 3060*06c3fb27SDimitry Andric TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT)) 3061*06c3fb27SDimitry Andric return std::make_pair(0U, &LoongArch::LSX128RegClass); 3062*06c3fb27SDimitry Andric if (Subtarget.hasExtLASX() && 3063*06c3fb27SDimitry Andric TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT)) 3064*06c3fb27SDimitry Andric return std::make_pair(0U, &LoongArch::LASX256RegClass); 3065bdd1243dSDimitry Andric break; 3066bdd1243dSDimitry Andric default: 3067bdd1243dSDimitry Andric break; 3068bdd1243dSDimitry Andric } 3069bdd1243dSDimitry Andric } 3070bdd1243dSDimitry Andric 3071bdd1243dSDimitry Andric // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen 3072bdd1243dSDimitry Andric // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm 3073bdd1243dSDimitry Andric // constraints while the official register name is prefixed with a '$'. So we 3074bdd1243dSDimitry Andric // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.) 3075bdd1243dSDimitry Andric // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is 3076bdd1243dSDimitry Andric // case insensitive, so no need to convert the constraint to upper case here. 3077bdd1243dSDimitry Andric // 3078bdd1243dSDimitry Andric // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly 3079bdd1243dSDimitry Andric // decode the usage of register name aliases into their official names. And 3080bdd1243dSDimitry Andric // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use 3081bdd1243dSDimitry Andric // official register names. 3082*06c3fb27SDimitry Andric if (Constraint.startswith("{$r") || Constraint.startswith("{$f") || 3083*06c3fb27SDimitry Andric Constraint.startswith("{$vr") || Constraint.startswith("{$xr")) { 3084bdd1243dSDimitry Andric bool IsFP = Constraint[2] == 'f'; 3085bdd1243dSDimitry Andric std::pair<StringRef, StringRef> Temp = Constraint.split('$'); 3086bdd1243dSDimitry Andric std::pair<unsigned, const TargetRegisterClass *> R; 3087bdd1243dSDimitry Andric R = TargetLowering::getRegForInlineAsmConstraint( 3088bdd1243dSDimitry Andric TRI, join_items("", Temp.first, Temp.second), VT); 3089bdd1243dSDimitry Andric // Match those names to the widest floating point register type available. 3090bdd1243dSDimitry Andric if (IsFP) { 3091bdd1243dSDimitry Andric unsigned RegNo = R.first; 3092bdd1243dSDimitry Andric if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) { 3093bdd1243dSDimitry Andric if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) { 3094bdd1243dSDimitry Andric unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64; 3095bdd1243dSDimitry Andric return std::make_pair(DReg, &LoongArch::FPR64RegClass); 3096bdd1243dSDimitry Andric } 3097bdd1243dSDimitry Andric } 3098bdd1243dSDimitry Andric } 3099bdd1243dSDimitry Andric return R; 3100bdd1243dSDimitry Andric } 3101bdd1243dSDimitry Andric 3102bdd1243dSDimitry Andric return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); 3103bdd1243dSDimitry Andric } 3104bdd1243dSDimitry Andric 3105bdd1243dSDimitry Andric void LoongArchTargetLowering::LowerAsmOperandForConstraint( 3106bdd1243dSDimitry Andric SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops, 3107bdd1243dSDimitry Andric SelectionDAG &DAG) const { 3108bdd1243dSDimitry Andric // Currently only support length 1 constraints. 3109bdd1243dSDimitry Andric if (Constraint.length() == 1) { 3110bdd1243dSDimitry Andric switch (Constraint[0]) { 3111bdd1243dSDimitry Andric case 'l': 3112bdd1243dSDimitry Andric // Validate & create a 16-bit signed immediate operand. 3113bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) { 3114bdd1243dSDimitry Andric uint64_t CVal = C->getSExtValue(); 3115bdd1243dSDimitry Andric if (isInt<16>(CVal)) 3116bdd1243dSDimitry Andric Ops.push_back( 3117bdd1243dSDimitry Andric DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT())); 3118bdd1243dSDimitry Andric } 3119bdd1243dSDimitry Andric return; 3120bdd1243dSDimitry Andric case 'I': 3121bdd1243dSDimitry Andric // Validate & create a 12-bit signed immediate operand. 3122bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) { 3123bdd1243dSDimitry Andric uint64_t CVal = C->getSExtValue(); 3124bdd1243dSDimitry Andric if (isInt<12>(CVal)) 3125bdd1243dSDimitry Andric Ops.push_back( 3126bdd1243dSDimitry Andric DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT())); 3127bdd1243dSDimitry Andric } 3128bdd1243dSDimitry Andric return; 3129bdd1243dSDimitry Andric case 'J': 3130bdd1243dSDimitry Andric // Validate & create an integer zero operand. 3131bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) 3132bdd1243dSDimitry Andric if (C->getZExtValue() == 0) 3133bdd1243dSDimitry Andric Ops.push_back( 3134bdd1243dSDimitry Andric DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT())); 3135bdd1243dSDimitry Andric return; 3136bdd1243dSDimitry Andric case 'K': 3137bdd1243dSDimitry Andric // Validate & create a 12-bit unsigned immediate operand. 3138bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) { 3139bdd1243dSDimitry Andric uint64_t CVal = C->getZExtValue(); 3140bdd1243dSDimitry Andric if (isUInt<12>(CVal)) 3141bdd1243dSDimitry Andric Ops.push_back( 3142bdd1243dSDimitry Andric DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT())); 3143bdd1243dSDimitry Andric } 3144bdd1243dSDimitry Andric return; 3145bdd1243dSDimitry Andric default: 3146bdd1243dSDimitry Andric break; 3147bdd1243dSDimitry Andric } 3148bdd1243dSDimitry Andric } 3149bdd1243dSDimitry Andric TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); 3150bdd1243dSDimitry Andric } 3151bdd1243dSDimitry Andric 3152bdd1243dSDimitry Andric #define GET_REGISTER_MATCHER 3153bdd1243dSDimitry Andric #include "LoongArchGenAsmMatcher.inc" 3154bdd1243dSDimitry Andric 3155bdd1243dSDimitry Andric Register 3156bdd1243dSDimitry Andric LoongArchTargetLowering::getRegisterByName(const char *RegName, LLT VT, 3157bdd1243dSDimitry Andric const MachineFunction &MF) const { 3158bdd1243dSDimitry Andric std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$'); 3159bdd1243dSDimitry Andric std::string NewRegName = Name.second.str(); 3160bdd1243dSDimitry Andric Register Reg = MatchRegisterAltName(NewRegName); 3161bdd1243dSDimitry Andric if (Reg == LoongArch::NoRegister) 3162bdd1243dSDimitry Andric Reg = MatchRegisterName(NewRegName); 3163bdd1243dSDimitry Andric if (Reg == LoongArch::NoRegister) 3164bdd1243dSDimitry Andric report_fatal_error( 3165bdd1243dSDimitry Andric Twine("Invalid register name \"" + StringRef(RegName) + "\".")); 3166bdd1243dSDimitry Andric BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF); 3167bdd1243dSDimitry Andric if (!ReservedRegs.test(Reg)) 3168bdd1243dSDimitry Andric report_fatal_error(Twine("Trying to obtain non-reserved register \"" + 3169bdd1243dSDimitry Andric StringRef(RegName) + "\".")); 3170bdd1243dSDimitry Andric return Reg; 3171bdd1243dSDimitry Andric } 3172bdd1243dSDimitry Andric 3173bdd1243dSDimitry Andric bool LoongArchTargetLowering::decomposeMulByConstant(LLVMContext &Context, 3174bdd1243dSDimitry Andric EVT VT, SDValue C) const { 3175bdd1243dSDimitry Andric // TODO: Support vectors. 3176bdd1243dSDimitry Andric if (!VT.isScalarInteger()) 3177bdd1243dSDimitry Andric return false; 3178bdd1243dSDimitry Andric 3179bdd1243dSDimitry Andric // Omit the optimization if the data size exceeds GRLen. 3180bdd1243dSDimitry Andric if (VT.getSizeInBits() > Subtarget.getGRLen()) 3181bdd1243dSDimitry Andric return false; 3182bdd1243dSDimitry Andric 3183bdd1243dSDimitry Andric if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) { 3184bdd1243dSDimitry Andric const APInt &Imm = ConstNode->getAPIntValue(); 3185*06c3fb27SDimitry Andric // Break MUL into (SLLI + ADD/SUB) or ALSL. 3186bdd1243dSDimitry Andric if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() || 3187bdd1243dSDimitry Andric (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2()) 3188bdd1243dSDimitry Andric return true; 3189*06c3fb27SDimitry Andric // Break MUL into (ALSL x, (SLLI x, imm0), imm1). 3190*06c3fb27SDimitry Andric if (ConstNode->hasOneUse() && 3191*06c3fb27SDimitry Andric ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() || 3192*06c3fb27SDimitry Andric (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2())) 3193*06c3fb27SDimitry Andric return true; 3194*06c3fb27SDimitry Andric // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)), 3195*06c3fb27SDimitry Andric // in which the immediate has two set bits. Or Break (MUL x, imm) 3196*06c3fb27SDimitry Andric // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate 3197*06c3fb27SDimitry Andric // equals to (1 << s0) - (1 << s1). 3198*06c3fb27SDimitry Andric if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) { 3199*06c3fb27SDimitry Andric unsigned Shifts = Imm.countr_zero(); 3200*06c3fb27SDimitry Andric // Reject immediates which can be composed via a single LUI. 3201*06c3fb27SDimitry Andric if (Shifts >= 12) 3202*06c3fb27SDimitry Andric return false; 3203*06c3fb27SDimitry Andric // Reject multiplications can be optimized to 3204*06c3fb27SDimitry Andric // (SLLI (ALSL x, x, 1/2/3/4), s). 3205*06c3fb27SDimitry Andric APInt ImmPop = Imm.ashr(Shifts); 3206*06c3fb27SDimitry Andric if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17) 3207*06c3fb27SDimitry Andric return false; 3208*06c3fb27SDimitry Andric // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`, 3209*06c3fb27SDimitry Andric // since it needs one more instruction than other 3 cases. 3210*06c3fb27SDimitry Andric APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true); 3211*06c3fb27SDimitry Andric if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() || 3212*06c3fb27SDimitry Andric (ImmSmall - Imm).isPowerOf2()) 3213*06c3fb27SDimitry Andric return true; 3214*06c3fb27SDimitry Andric } 3215bdd1243dSDimitry Andric } 3216bdd1243dSDimitry Andric 3217bdd1243dSDimitry Andric return false; 3218bdd1243dSDimitry Andric } 3219*06c3fb27SDimitry Andric 3220*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalAddressingMode(const DataLayout &DL, 3221*06c3fb27SDimitry Andric const AddrMode &AM, 3222*06c3fb27SDimitry Andric Type *Ty, unsigned AS, 3223*06c3fb27SDimitry Andric Instruction *I) const { 3224*06c3fb27SDimitry Andric // LoongArch has four basic addressing modes: 3225*06c3fb27SDimitry Andric // 1. reg 3226*06c3fb27SDimitry Andric // 2. reg + 12-bit signed offset 3227*06c3fb27SDimitry Andric // 3. reg + 14-bit signed offset left-shifted by 2 3228*06c3fb27SDimitry Andric // 4. reg1 + reg2 3229*06c3fb27SDimitry Andric // TODO: Add more checks after support vector extension. 3230*06c3fb27SDimitry Andric 3231*06c3fb27SDimitry Andric // No global is ever allowed as a base. 3232*06c3fb27SDimitry Andric if (AM.BaseGV) 3233*06c3fb27SDimitry Andric return false; 3234*06c3fb27SDimitry Andric 3235*06c3fb27SDimitry Andric // Require a 12 or 14 bit signed offset. 3236*06c3fb27SDimitry Andric if (!isInt<12>(AM.BaseOffs) || !isShiftedInt<14, 2>(AM.BaseOffs)) 3237*06c3fb27SDimitry Andric return false; 3238*06c3fb27SDimitry Andric 3239*06c3fb27SDimitry Andric switch (AM.Scale) { 3240*06c3fb27SDimitry Andric case 0: 3241*06c3fb27SDimitry Andric // "i" is not allowed. 3242*06c3fb27SDimitry Andric if (!AM.HasBaseReg) 3243*06c3fb27SDimitry Andric return false; 3244*06c3fb27SDimitry Andric // Otherwise we have "r+i". 3245*06c3fb27SDimitry Andric break; 3246*06c3fb27SDimitry Andric case 1: 3247*06c3fb27SDimitry Andric // "r+r+i" is not allowed. 3248*06c3fb27SDimitry Andric if (AM.HasBaseReg && AM.BaseOffs != 0) 3249*06c3fb27SDimitry Andric return false; 3250*06c3fb27SDimitry Andric // Otherwise we have "r+r" or "r+i". 3251*06c3fb27SDimitry Andric break; 3252*06c3fb27SDimitry Andric case 2: 3253*06c3fb27SDimitry Andric // "2*r+r" or "2*r+i" is not allowed. 3254*06c3fb27SDimitry Andric if (AM.HasBaseReg || AM.BaseOffs) 3255*06c3fb27SDimitry Andric return false; 3256*06c3fb27SDimitry Andric // Otherwise we have "r+r". 3257*06c3fb27SDimitry Andric break; 3258*06c3fb27SDimitry Andric default: 3259*06c3fb27SDimitry Andric return false; 3260*06c3fb27SDimitry Andric } 3261*06c3fb27SDimitry Andric 3262*06c3fb27SDimitry Andric return true; 3263*06c3fb27SDimitry Andric } 3264*06c3fb27SDimitry Andric 3265*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalICmpImmediate(int64_t Imm) const { 3266*06c3fb27SDimitry Andric return isInt<12>(Imm); 3267*06c3fb27SDimitry Andric } 3268*06c3fb27SDimitry Andric 3269*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isLegalAddImmediate(int64_t Imm) const { 3270*06c3fb27SDimitry Andric return isInt<12>(Imm); 3271*06c3fb27SDimitry Andric } 3272*06c3fb27SDimitry Andric 3273*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isZExtFree(SDValue Val, EVT VT2) const { 3274*06c3fb27SDimitry Andric // Zexts are free if they can be combined with a load. 3275*06c3fb27SDimitry Andric // Don't advertise i32->i64 zextload as being free for LA64. It interacts 3276*06c3fb27SDimitry Andric // poorly with type legalization of compares preferring sext. 3277*06c3fb27SDimitry Andric if (auto *LD = dyn_cast<LoadSDNode>(Val)) { 3278*06c3fb27SDimitry Andric EVT MemVT = LD->getMemoryVT(); 3279*06c3fb27SDimitry Andric if ((MemVT == MVT::i8 || MemVT == MVT::i16) && 3280*06c3fb27SDimitry Andric (LD->getExtensionType() == ISD::NON_EXTLOAD || 3281*06c3fb27SDimitry Andric LD->getExtensionType() == ISD::ZEXTLOAD)) 3282*06c3fb27SDimitry Andric return true; 3283*06c3fb27SDimitry Andric } 3284*06c3fb27SDimitry Andric 3285*06c3fb27SDimitry Andric return TargetLowering::isZExtFree(Val, VT2); 3286*06c3fb27SDimitry Andric } 3287*06c3fb27SDimitry Andric 3288*06c3fb27SDimitry Andric bool LoongArchTargetLowering::isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const { 3289*06c3fb27SDimitry Andric return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64; 3290*06c3fb27SDimitry Andric } 3291*06c3fb27SDimitry Andric 3292*06c3fb27SDimitry Andric bool LoongArchTargetLowering::hasAndNotCompare(SDValue Y) const { 3293*06c3fb27SDimitry Andric // TODO: Support vectors. 3294*06c3fb27SDimitry Andric if (Y.getValueType().isVector()) 3295*06c3fb27SDimitry Andric return false; 3296*06c3fb27SDimitry Andric 3297*06c3fb27SDimitry Andric return !isa<ConstantSDNode>(Y); 3298*06c3fb27SDimitry Andric } 3299