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" 20*bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h" 21753f127fSDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h" 2281ad6265SDimitry Andric #include "llvm/ADT/Statistic.h" 2381ad6265SDimitry Andric #include "llvm/CodeGen/ISDOpcodes.h" 24*bdd1243dSDimitry Andric #include "llvm/CodeGen/RuntimeLibcalls.h" 25*bdd1243dSDimitry Andric #include "llvm/IR/IRBuilder.h" 26*bdd1243dSDimitry Andric #include "llvm/IR/IntrinsicsLoongArch.h" 2781ad6265SDimitry Andric #include "llvm/Support/Debug.h" 28753f127fSDimitry Andric #include "llvm/Support/KnownBits.h" 29*bdd1243dSDimitry Andric #include "llvm/Support/MathExtras.h" 3081ad6265SDimitry Andric 3181ad6265SDimitry Andric using namespace llvm; 3281ad6265SDimitry Andric 3381ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-isel-lowering" 3481ad6265SDimitry Andric 35*bdd1243dSDimitry Andric STATISTIC(NumTailCalls, "Number of tail calls"); 36*bdd1243dSDimitry Andric 37753f127fSDimitry Andric static cl::opt<bool> ZeroDivCheck( 38753f127fSDimitry Andric "loongarch-check-zero-division", cl::Hidden, 39753f127fSDimitry Andric cl::desc("Trap on integer division by zero."), 40753f127fSDimitry Andric cl::init(false)); 41753f127fSDimitry Andric 4281ad6265SDimitry Andric LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM, 4381ad6265SDimitry Andric const LoongArchSubtarget &STI) 4481ad6265SDimitry Andric : TargetLowering(TM), Subtarget(STI) { 4581ad6265SDimitry Andric 4681ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 4781ad6265SDimitry Andric // Set up the register classes. 4881ad6265SDimitry Andric addRegisterClass(GRLenVT, &LoongArch::GPRRegClass); 4981ad6265SDimitry Andric if (Subtarget.hasBasicF()) 5081ad6265SDimitry Andric addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass); 5181ad6265SDimitry Andric if (Subtarget.hasBasicD()) 5281ad6265SDimitry Andric addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass); 5381ad6265SDimitry Andric 54753f127fSDimitry Andric setLoadExtAction({ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}, GRLenVT, 55753f127fSDimitry Andric MVT::i1, Promote); 56753f127fSDimitry Andric 5781ad6265SDimitry Andric // TODO: add necessary setOperationAction calls later. 5881ad6265SDimitry Andric setOperationAction(ISD::SHL_PARTS, GRLenVT, Custom); 5981ad6265SDimitry Andric setOperationAction(ISD::SRA_PARTS, GRLenVT, Custom); 6081ad6265SDimitry Andric setOperationAction(ISD::SRL_PARTS, GRLenVT, Custom); 61753f127fSDimitry Andric setOperationAction(ISD::FP_TO_SINT, GRLenVT, Custom); 62*bdd1243dSDimitry Andric setOperationAction(ISD::ROTL, GRLenVT, Expand); 63*bdd1243dSDimitry Andric setOperationAction(ISD::CTPOP, GRLenVT, Expand); 64*bdd1243dSDimitry Andric setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); 65*bdd1243dSDimitry Andric setOperationAction(ISD::TRAP, MVT::Other, Legal); 66*bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); 67*bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); 68753f127fSDimitry Andric 69*bdd1243dSDimitry Andric setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool, 70*bdd1243dSDimitry Andric ISD::JumpTable}, 71*bdd1243dSDimitry Andric GRLenVT, Custom); 72*bdd1243dSDimitry Andric 73*bdd1243dSDimitry Andric setOperationAction(ISD::GlobalTLSAddress, GRLenVT, Custom); 74*bdd1243dSDimitry Andric 75*bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); 76*bdd1243dSDimitry Andric 77*bdd1243dSDimitry Andric setOperationAction(ISD::EH_DWARF_CFA, MVT::i32, Custom); 78*bdd1243dSDimitry Andric if (Subtarget.is64Bit()) 79*bdd1243dSDimitry Andric setOperationAction(ISD::EH_DWARF_CFA, MVT::i64, Custom); 80*bdd1243dSDimitry Andric 81*bdd1243dSDimitry Andric setOperationAction(ISD::DYNAMIC_STACKALLOC, GRLenVT, Expand); 82*bdd1243dSDimitry Andric setOperationAction({ISD::STACKSAVE, ISD::STACKRESTORE}, MVT::Other, Expand); 83*bdd1243dSDimitry Andric setOperationAction(ISD::VASTART, MVT::Other, Custom); 84*bdd1243dSDimitry Andric setOperationAction({ISD::VAARG, ISD::VACOPY, ISD::VAEND}, MVT::Other, Expand); 8581ad6265SDimitry Andric 8681ad6265SDimitry Andric if (Subtarget.is64Bit()) { 8781ad6265SDimitry Andric setOperationAction(ISD::SHL, MVT::i32, Custom); 8881ad6265SDimitry Andric setOperationAction(ISD::SRA, MVT::i32, Custom); 8981ad6265SDimitry Andric setOperationAction(ISD::SRL, MVT::i32, Custom); 90753f127fSDimitry Andric setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); 91753f127fSDimitry Andric setOperationAction(ISD::BITCAST, MVT::i32, Custom); 92*bdd1243dSDimitry Andric setOperationAction(ISD::ROTR, MVT::i32, Custom); 93*bdd1243dSDimitry Andric setOperationAction(ISD::ROTL, MVT::i32, Custom); 94*bdd1243dSDimitry Andric setOperationAction(ISD::CTTZ, MVT::i32, Custom); 95*bdd1243dSDimitry Andric setOperationAction(ISD::CTLZ, MVT::i32, Custom); 96*bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom); 97*bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i32, Custom); 98*bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); 99*bdd1243dSDimitry Andric setOperationAction(ISD::READ_REGISTER, MVT::i32, Custom); 100*bdd1243dSDimitry Andric setOperationAction(ISD::WRITE_REGISTER, MVT::i32, Custom); 101753f127fSDimitry Andric if (Subtarget.hasBasicF() && !Subtarget.hasBasicD()) 102753f127fSDimitry Andric setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); 103*bdd1243dSDimitry Andric if (Subtarget.hasBasicF()) 104*bdd1243dSDimitry Andric setOperationAction(ISD::FRINT, MVT::f32, Legal); 105*bdd1243dSDimitry Andric if (Subtarget.hasBasicD()) 106*bdd1243dSDimitry Andric setOperationAction(ISD::FRINT, MVT::f64, Legal); 10781ad6265SDimitry Andric } 10881ad6265SDimitry Andric 109*bdd1243dSDimitry Andric // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and 110*bdd1243dSDimitry Andric // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16 111*bdd1243dSDimitry Andric // and i32 could still be byte-swapped relatively cheaply. 112*bdd1243dSDimitry Andric setOperationAction(ISD::BSWAP, MVT::i16, Custom); 113*bdd1243dSDimitry Andric if (Subtarget.is64Bit()) { 114*bdd1243dSDimitry Andric setOperationAction(ISD::BSWAP, MVT::i32, Custom); 115*bdd1243dSDimitry Andric } 116*bdd1243dSDimitry Andric 117*bdd1243dSDimitry Andric // Expand bitreverse.i16 with native-width bitrev and shift for now, before 118*bdd1243dSDimitry Andric // we get to know which of sll and revb.2h is faster. 119*bdd1243dSDimitry Andric setOperationAction(ISD::BITREVERSE, MVT::i8, Custom); 120*bdd1243dSDimitry Andric if (Subtarget.is64Bit()) { 121*bdd1243dSDimitry Andric setOperationAction(ISD::BITREVERSE, MVT::i32, Custom); 122*bdd1243dSDimitry Andric setOperationAction(ISD::BITREVERSE, MVT::i64, Legal); 123*bdd1243dSDimitry Andric } else { 124*bdd1243dSDimitry Andric setOperationAction(ISD::BITREVERSE, MVT::i32, Legal); 125*bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom); 126*bdd1243dSDimitry Andric setOperationAction(ISD::READ_REGISTER, MVT::i64, Custom); 127*bdd1243dSDimitry Andric setOperationAction(ISD::WRITE_REGISTER, MVT::i64, Custom); 128*bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); 129*bdd1243dSDimitry Andric setOperationAction(ISD::INTRINSIC_VOID, MVT::i64, Custom); 130*bdd1243dSDimitry Andric } 131*bdd1243dSDimitry Andric 132*bdd1243dSDimitry Andric static const ISD::CondCode FPCCToExpand[] = { 133*bdd1243dSDimitry Andric ISD::SETOGT, ISD::SETOGE, ISD::SETUGT, ISD::SETUGE, 134*bdd1243dSDimitry Andric ISD::SETGE, ISD::SETNE, ISD::SETGT}; 13581ad6265SDimitry Andric 13681ad6265SDimitry Andric if (Subtarget.hasBasicF()) { 13781ad6265SDimitry Andric setCondCodeAction(FPCCToExpand, MVT::f32, Expand); 13881ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::f32, Expand); 139*bdd1243dSDimitry Andric setOperationAction(ISD::BR_CC, MVT::f32, Expand); 140*bdd1243dSDimitry Andric setOperationAction(ISD::FMA, MVT::f32, Legal); 141*bdd1243dSDimitry Andric setOperationAction(ISD::FMINNUM_IEEE, MVT::f32, Legal); 142*bdd1243dSDimitry Andric setOperationAction(ISD::FMAXNUM_IEEE, MVT::f32, Legal); 143*bdd1243dSDimitry Andric setOperationAction(ISD::STRICT_FSETCCS, MVT::f32, Legal); 144*bdd1243dSDimitry Andric setOperationAction(ISD::STRICT_FSETCC, MVT::f32, Legal); 145*bdd1243dSDimitry Andric setOperationAction(ISD::FSIN, MVT::f32, Expand); 146*bdd1243dSDimitry Andric setOperationAction(ISD::FCOS, MVT::f32, Expand); 147*bdd1243dSDimitry Andric setOperationAction(ISD::FSINCOS, MVT::f32, Expand); 148*bdd1243dSDimitry Andric setOperationAction(ISD::FPOW, MVT::f32, Expand); 149*bdd1243dSDimitry Andric setOperationAction(ISD::FREM, MVT::f32, Expand); 15081ad6265SDimitry Andric } 15181ad6265SDimitry Andric if (Subtarget.hasBasicD()) { 15281ad6265SDimitry Andric setCondCodeAction(FPCCToExpand, MVT::f64, Expand); 15381ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::f64, Expand); 154*bdd1243dSDimitry Andric setOperationAction(ISD::BR_CC, MVT::f64, Expand); 155*bdd1243dSDimitry Andric setOperationAction(ISD::STRICT_FSETCCS, MVT::f64, Legal); 156*bdd1243dSDimitry Andric setOperationAction(ISD::STRICT_FSETCC, MVT::f64, Legal); 157753f127fSDimitry Andric setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); 158*bdd1243dSDimitry Andric setOperationAction(ISD::FMA, MVT::f64, Legal); 159*bdd1243dSDimitry Andric setOperationAction(ISD::FMINNUM_IEEE, MVT::f64, Legal); 160*bdd1243dSDimitry Andric setOperationAction(ISD::FMAXNUM_IEEE, MVT::f64, Legal); 161*bdd1243dSDimitry Andric setOperationAction(ISD::FSIN, MVT::f64, Expand); 162*bdd1243dSDimitry Andric setOperationAction(ISD::FCOS, MVT::f64, Expand); 163*bdd1243dSDimitry Andric setOperationAction(ISD::FSINCOS, MVT::f64, Expand); 164*bdd1243dSDimitry Andric setOperationAction(ISD::FPOW, MVT::f64, Expand); 165*bdd1243dSDimitry Andric setOperationAction(ISD::FREM, MVT::f64, Expand); 166*bdd1243dSDimitry Andric setTruncStoreAction(MVT::f64, MVT::f32, Expand); 16781ad6265SDimitry Andric } 16881ad6265SDimitry Andric 169*bdd1243dSDimitry Andric setOperationAction(ISD::BR_JT, MVT::Other, Expand); 170*bdd1243dSDimitry Andric 171753f127fSDimitry Andric setOperationAction(ISD::BR_CC, GRLenVT, Expand); 17281ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, GRLenVT, Expand); 17381ad6265SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); 174753f127fSDimitry Andric setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, GRLenVT, Expand); 175753f127fSDimitry Andric if (!Subtarget.is64Bit()) 176753f127fSDimitry Andric setLibcallName(RTLIB::MUL_I128, nullptr); 177753f127fSDimitry Andric 178753f127fSDimitry Andric setOperationAction(ISD::FP_TO_UINT, GRLenVT, Custom); 179*bdd1243dSDimitry Andric setOperationAction(ISD::UINT_TO_FP, GRLenVT, Expand); 180*bdd1243dSDimitry Andric if ((Subtarget.is64Bit() && Subtarget.hasBasicF() && 181*bdd1243dSDimitry Andric !Subtarget.hasBasicD())) { 182*bdd1243dSDimitry Andric setOperationAction(ISD::SINT_TO_FP, GRLenVT, Custom); 183753f127fSDimitry Andric setOperationAction(ISD::UINT_TO_FP, GRLenVT, Custom); 184*bdd1243dSDimitry Andric } 18581ad6265SDimitry Andric 18681ad6265SDimitry Andric // Compute derived properties from the register classes. 18781ad6265SDimitry Andric computeRegisterProperties(STI.getRegisterInfo()); 18881ad6265SDimitry Andric 18981ad6265SDimitry Andric setStackPointerRegisterToSaveRestore(LoongArch::R3); 19081ad6265SDimitry Andric 19181ad6265SDimitry Andric setBooleanContents(ZeroOrOneBooleanContent); 19281ad6265SDimitry Andric 193753f127fSDimitry Andric setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen()); 194753f127fSDimitry Andric 195*bdd1243dSDimitry Andric setMinCmpXchgSizeInBits(32); 196*bdd1243dSDimitry Andric 19781ad6265SDimitry Andric // Function alignments. 19881ad6265SDimitry Andric const Align FunctionAlignment(4); 19981ad6265SDimitry Andric setMinFunctionAlignment(FunctionAlignment); 20081ad6265SDimitry Andric 20181ad6265SDimitry Andric setTargetDAGCombine(ISD::AND); 202753f127fSDimitry Andric setTargetDAGCombine(ISD::OR); 20381ad6265SDimitry Andric setTargetDAGCombine(ISD::SRL); 20481ad6265SDimitry Andric } 20581ad6265SDimitry Andric 206*bdd1243dSDimitry Andric bool LoongArchTargetLowering::isOffsetFoldingLegal( 207*bdd1243dSDimitry Andric const GlobalAddressSDNode *GA) const { 208*bdd1243dSDimitry Andric // In order to maximise the opportunity for common subexpression elimination, 209*bdd1243dSDimitry Andric // keep a separate ADD node for the global address offset instead of folding 210*bdd1243dSDimitry Andric // it in the global address node. Later peephole optimisations may choose to 211*bdd1243dSDimitry Andric // fold it back in when profitable. 212*bdd1243dSDimitry Andric return false; 213*bdd1243dSDimitry Andric } 214*bdd1243dSDimitry Andric 21581ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerOperation(SDValue Op, 21681ad6265SDimitry Andric SelectionDAG &DAG) const { 21781ad6265SDimitry Andric switch (Op.getOpcode()) { 218*bdd1243dSDimitry Andric case ISD::EH_DWARF_CFA: 219*bdd1243dSDimitry Andric return lowerEH_DWARF_CFA(Op, DAG); 220753f127fSDimitry Andric case ISD::GlobalAddress: 221753f127fSDimitry Andric return lowerGlobalAddress(Op, DAG); 222*bdd1243dSDimitry Andric case ISD::GlobalTLSAddress: 223*bdd1243dSDimitry Andric return lowerGlobalTLSAddress(Op, DAG); 224*bdd1243dSDimitry Andric case ISD::INTRINSIC_WO_CHAIN: 225*bdd1243dSDimitry Andric return lowerINTRINSIC_WO_CHAIN(Op, DAG); 226*bdd1243dSDimitry Andric case ISD::INTRINSIC_W_CHAIN: 227*bdd1243dSDimitry Andric return lowerINTRINSIC_W_CHAIN(Op, DAG); 228*bdd1243dSDimitry Andric case ISD::INTRINSIC_VOID: 229*bdd1243dSDimitry Andric return lowerINTRINSIC_VOID(Op, DAG); 230*bdd1243dSDimitry Andric case ISD::BlockAddress: 231*bdd1243dSDimitry Andric return lowerBlockAddress(Op, DAG); 232*bdd1243dSDimitry Andric case ISD::JumpTable: 233*bdd1243dSDimitry Andric return lowerJumpTable(Op, DAG); 23481ad6265SDimitry Andric case ISD::SHL_PARTS: 23581ad6265SDimitry Andric return lowerShiftLeftParts(Op, DAG); 23681ad6265SDimitry Andric case ISD::SRA_PARTS: 23781ad6265SDimitry Andric return lowerShiftRightParts(Op, DAG, true); 23881ad6265SDimitry Andric case ISD::SRL_PARTS: 23981ad6265SDimitry Andric return lowerShiftRightParts(Op, DAG, false); 240753f127fSDimitry Andric case ISD::ConstantPool: 241753f127fSDimitry Andric return lowerConstantPool(Op, DAG); 242753f127fSDimitry Andric case ISD::FP_TO_SINT: 243753f127fSDimitry Andric return lowerFP_TO_SINT(Op, DAG); 244753f127fSDimitry Andric case ISD::BITCAST: 245753f127fSDimitry Andric return lowerBITCAST(Op, DAG); 246753f127fSDimitry Andric case ISD::UINT_TO_FP: 247753f127fSDimitry Andric return lowerUINT_TO_FP(Op, DAG); 248*bdd1243dSDimitry Andric case ISD::SINT_TO_FP: 249*bdd1243dSDimitry Andric return lowerSINT_TO_FP(Op, DAG); 250*bdd1243dSDimitry Andric case ISD::VASTART: 251*bdd1243dSDimitry Andric return lowerVASTART(Op, DAG); 252*bdd1243dSDimitry Andric case ISD::FRAMEADDR: 253*bdd1243dSDimitry Andric return lowerFRAMEADDR(Op, DAG); 254*bdd1243dSDimitry Andric case ISD::RETURNADDR: 255*bdd1243dSDimitry Andric return lowerRETURNADDR(Op, DAG); 256*bdd1243dSDimitry Andric case ISD::WRITE_REGISTER: 257*bdd1243dSDimitry Andric return lowerWRITE_REGISTER(Op, DAG); 25881ad6265SDimitry Andric } 259*bdd1243dSDimitry Andric return SDValue(); 260*bdd1243dSDimitry Andric } 261*bdd1243dSDimitry Andric 262*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op, 263*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 264*bdd1243dSDimitry Andric 265*bdd1243dSDimitry Andric if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) { 266*bdd1243dSDimitry Andric DAG.getContext()->emitError( 267*bdd1243dSDimitry Andric "On LA64, only 64-bit registers can be written."); 268*bdd1243dSDimitry Andric return Op.getOperand(0); 269*bdd1243dSDimitry Andric } 270*bdd1243dSDimitry Andric 271*bdd1243dSDimitry Andric if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) { 272*bdd1243dSDimitry Andric DAG.getContext()->emitError( 273*bdd1243dSDimitry Andric "On LA32, only 32-bit registers can be written."); 274*bdd1243dSDimitry Andric return Op.getOperand(0); 275*bdd1243dSDimitry Andric } 276*bdd1243dSDimitry Andric 277*bdd1243dSDimitry Andric return Op; 278*bdd1243dSDimitry Andric } 279*bdd1243dSDimitry Andric 280*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op, 281*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 282*bdd1243dSDimitry Andric if (!isa<ConstantSDNode>(Op.getOperand(0))) { 283*bdd1243dSDimitry Andric DAG.getContext()->emitError("argument to '__builtin_frame_address' must " 284*bdd1243dSDimitry Andric "be a constant integer"); 285*bdd1243dSDimitry Andric return SDValue(); 286*bdd1243dSDimitry Andric } 287*bdd1243dSDimitry Andric 288*bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 289*bdd1243dSDimitry Andric MF.getFrameInfo().setFrameAddressIsTaken(true); 290*bdd1243dSDimitry Andric Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF); 291*bdd1243dSDimitry Andric EVT VT = Op.getValueType(); 292*bdd1243dSDimitry Andric SDLoc DL(Op); 293*bdd1243dSDimitry Andric SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT); 294*bdd1243dSDimitry Andric unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); 295*bdd1243dSDimitry Andric int GRLenInBytes = Subtarget.getGRLen() / 8; 296*bdd1243dSDimitry Andric 297*bdd1243dSDimitry Andric while (Depth--) { 298*bdd1243dSDimitry Andric int Offset = -(GRLenInBytes * 2); 299*bdd1243dSDimitry Andric SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr, 300*bdd1243dSDimitry Andric DAG.getIntPtrConstant(Offset, DL)); 301*bdd1243dSDimitry Andric FrameAddr = 302*bdd1243dSDimitry Andric DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo()); 303*bdd1243dSDimitry Andric } 304*bdd1243dSDimitry Andric return FrameAddr; 305*bdd1243dSDimitry Andric } 306*bdd1243dSDimitry Andric 307*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op, 308*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 309*bdd1243dSDimitry Andric if (verifyReturnAddressArgumentIsConstant(Op, DAG)) 310*bdd1243dSDimitry Andric return SDValue(); 311*bdd1243dSDimitry Andric 312*bdd1243dSDimitry Andric // Currently only support lowering return address for current frame. 313*bdd1243dSDimitry Andric if (cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() != 0) { 314*bdd1243dSDimitry Andric DAG.getContext()->emitError( 315*bdd1243dSDimitry Andric "return address can only be determined for the current frame"); 316*bdd1243dSDimitry Andric return SDValue(); 317*bdd1243dSDimitry Andric } 318*bdd1243dSDimitry Andric 319*bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 320*bdd1243dSDimitry Andric MF.getFrameInfo().setReturnAddressIsTaken(true); 321*bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 322*bdd1243dSDimitry Andric 323*bdd1243dSDimitry Andric // Return the value of the return address register, marking it an implicit 324*bdd1243dSDimitry Andric // live-in. 325*bdd1243dSDimitry Andric Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(), 326*bdd1243dSDimitry Andric getRegClassFor(GRLenVT)); 327*bdd1243dSDimitry Andric return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT); 328*bdd1243dSDimitry Andric } 329*bdd1243dSDimitry Andric 330*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op, 331*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 332*bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 333*bdd1243dSDimitry Andric auto Size = Subtarget.getGRLen() / 8; 334*bdd1243dSDimitry Andric auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false); 335*bdd1243dSDimitry Andric return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 336*bdd1243dSDimitry Andric } 337*bdd1243dSDimitry Andric 338*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op, 339*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 340*bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 341*bdd1243dSDimitry Andric auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>(); 342*bdd1243dSDimitry Andric 343*bdd1243dSDimitry Andric SDLoc DL(Op); 344*bdd1243dSDimitry Andric SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), 345*bdd1243dSDimitry Andric getPointerTy(MF.getDataLayout())); 346*bdd1243dSDimitry Andric 347*bdd1243dSDimitry Andric // vastart just stores the address of the VarArgsFrameIndex slot into the 348*bdd1243dSDimitry Andric // memory location argument. 349*bdd1243dSDimitry Andric const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); 350*bdd1243dSDimitry Andric return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1), 351*bdd1243dSDimitry Andric MachinePointerInfo(SV)); 35281ad6265SDimitry Andric } 35381ad6265SDimitry Andric 354753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op, 355753f127fSDimitry Andric SelectionDAG &DAG) const { 356*bdd1243dSDimitry Andric assert(Subtarget.is64Bit() && Subtarget.hasBasicF() && 357*bdd1243dSDimitry Andric !Subtarget.hasBasicD() && "unexpected target features"); 358753f127fSDimitry Andric 359753f127fSDimitry Andric SDLoc DL(Op); 360*bdd1243dSDimitry Andric SDValue Op0 = Op.getOperand(0); 361*bdd1243dSDimitry Andric if (Op0->getOpcode() == ISD::AND) { 362*bdd1243dSDimitry Andric auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1)); 363*bdd1243dSDimitry Andric if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF)) 364753f127fSDimitry Andric return Op; 365*bdd1243dSDimitry Andric } 366*bdd1243dSDimitry Andric 367*bdd1243dSDimitry Andric if (Op0->getOpcode() == LoongArchISD::BSTRPICK && 368*bdd1243dSDimitry Andric Op0.getConstantOperandVal(1) < UINT64_C(0X1F) && 369*bdd1243dSDimitry Andric Op0.getConstantOperandVal(2) == UINT64_C(0)) 370*bdd1243dSDimitry Andric return Op; 371*bdd1243dSDimitry Andric 372*bdd1243dSDimitry Andric if (Op0.getOpcode() == ISD::AssertZext && 373*bdd1243dSDimitry Andric dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32)) 374*bdd1243dSDimitry Andric return Op; 375*bdd1243dSDimitry Andric 376*bdd1243dSDimitry Andric EVT OpVT = Op0.getValueType(); 377*bdd1243dSDimitry Andric EVT RetVT = Op.getValueType(); 378*bdd1243dSDimitry Andric RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT); 379*bdd1243dSDimitry Andric MakeLibCallOptions CallOptions; 380*bdd1243dSDimitry Andric CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true); 381*bdd1243dSDimitry Andric SDValue Chain = SDValue(); 382*bdd1243dSDimitry Andric SDValue Result; 383*bdd1243dSDimitry Andric std::tie(Result, Chain) = 384*bdd1243dSDimitry Andric makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain); 385*bdd1243dSDimitry Andric return Result; 386*bdd1243dSDimitry Andric } 387*bdd1243dSDimitry Andric 388*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op, 389*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 390*bdd1243dSDimitry Andric assert(Subtarget.is64Bit() && Subtarget.hasBasicF() && 391*bdd1243dSDimitry Andric !Subtarget.hasBasicD() && "unexpected target features"); 392*bdd1243dSDimitry Andric 393*bdd1243dSDimitry Andric SDLoc DL(Op); 394*bdd1243dSDimitry Andric SDValue Op0 = Op.getOperand(0); 395*bdd1243dSDimitry Andric 396*bdd1243dSDimitry Andric if ((Op0.getOpcode() == ISD::AssertSext || 397*bdd1243dSDimitry Andric Op0.getOpcode() == ISD::SIGN_EXTEND_INREG) && 398*bdd1243dSDimitry Andric dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32)) 399*bdd1243dSDimitry Andric return Op; 400*bdd1243dSDimitry Andric 401*bdd1243dSDimitry Andric EVT OpVT = Op0.getValueType(); 402*bdd1243dSDimitry Andric EVT RetVT = Op.getValueType(); 403*bdd1243dSDimitry Andric RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT); 404*bdd1243dSDimitry Andric MakeLibCallOptions CallOptions; 405*bdd1243dSDimitry Andric CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true); 406*bdd1243dSDimitry Andric SDValue Chain = SDValue(); 407*bdd1243dSDimitry Andric SDValue Result; 408*bdd1243dSDimitry Andric std::tie(Result, Chain) = 409*bdd1243dSDimitry Andric makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain); 410*bdd1243dSDimitry Andric return Result; 411753f127fSDimitry Andric } 412753f127fSDimitry Andric 413753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op, 414753f127fSDimitry Andric SelectionDAG &DAG) const { 415753f127fSDimitry Andric 416753f127fSDimitry Andric SDLoc DL(Op); 417753f127fSDimitry Andric SDValue Op0 = Op.getOperand(0); 418753f127fSDimitry Andric 419753f127fSDimitry Andric if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 && 420753f127fSDimitry Andric Subtarget.is64Bit() && Subtarget.hasBasicF()) { 421753f127fSDimitry Andric SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0); 422753f127fSDimitry Andric return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0); 423753f127fSDimitry Andric } 424753f127fSDimitry Andric return Op; 425753f127fSDimitry Andric } 426753f127fSDimitry Andric 427753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op, 428753f127fSDimitry Andric SelectionDAG &DAG) const { 429753f127fSDimitry Andric 430753f127fSDimitry Andric SDLoc DL(Op); 431753f127fSDimitry Andric 432753f127fSDimitry Andric if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() && 433753f127fSDimitry Andric !Subtarget.hasBasicD()) { 434753f127fSDimitry Andric SDValue Dst = 435753f127fSDimitry Andric DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0)); 436753f127fSDimitry Andric return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst); 437753f127fSDimitry Andric } 438753f127fSDimitry Andric 439753f127fSDimitry Andric EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits()); 440753f127fSDimitry Andric SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0)); 441753f127fSDimitry Andric return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc); 442753f127fSDimitry Andric } 443753f127fSDimitry Andric 444*bdd1243dSDimitry Andric static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty, 445*bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 446*bdd1243dSDimitry Andric return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags); 447*bdd1243dSDimitry Andric } 448*bdd1243dSDimitry Andric 449*bdd1243dSDimitry Andric static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty, 450*bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 451*bdd1243dSDimitry Andric return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(), 452*bdd1243dSDimitry Andric Flags); 453*bdd1243dSDimitry Andric } 454*bdd1243dSDimitry Andric 455*bdd1243dSDimitry Andric static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty, 456*bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 457*bdd1243dSDimitry Andric return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(), 458*bdd1243dSDimitry Andric N->getOffset(), Flags); 459*bdd1243dSDimitry Andric } 460*bdd1243dSDimitry Andric 461*bdd1243dSDimitry Andric static SDValue getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty, 462*bdd1243dSDimitry Andric SelectionDAG &DAG, unsigned Flags) { 463*bdd1243dSDimitry Andric return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags); 464*bdd1243dSDimitry Andric } 465*bdd1243dSDimitry Andric 466*bdd1243dSDimitry Andric template <class NodeTy> 467*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG, 468*bdd1243dSDimitry Andric bool IsLocal) const { 469*bdd1243dSDimitry Andric SDLoc DL(N); 470*bdd1243dSDimitry Andric EVT Ty = getPointerTy(DAG.getDataLayout()); 471*bdd1243dSDimitry Andric SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0); 472*bdd1243dSDimitry Andric // TODO: Check CodeModel. 473*bdd1243dSDimitry Andric if (IsLocal) 474*bdd1243dSDimitry Andric // This generates the pattern (PseudoLA_PCREL sym), which expands to 475*bdd1243dSDimitry Andric // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)). 476*bdd1243dSDimitry Andric return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 477*bdd1243dSDimitry Andric 0); 478*bdd1243dSDimitry Andric 479*bdd1243dSDimitry Andric // This generates the pattern (PseudoLA_GOT sym), which expands to (ld.w/d 480*bdd1243dSDimitry Andric // (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)). 481*bdd1243dSDimitry Andric return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0); 482*bdd1243dSDimitry Andric } 483*bdd1243dSDimitry Andric 484*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op, 485*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 486*bdd1243dSDimitry Andric return getAddr(cast<BlockAddressSDNode>(Op), DAG); 487*bdd1243dSDimitry Andric } 488*bdd1243dSDimitry Andric 489*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op, 490*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 491*bdd1243dSDimitry Andric return getAddr(cast<JumpTableSDNode>(Op), DAG); 492*bdd1243dSDimitry Andric } 493*bdd1243dSDimitry Andric 494753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op, 495753f127fSDimitry Andric SelectionDAG &DAG) const { 496*bdd1243dSDimitry Andric return getAddr(cast<ConstantPoolSDNode>(Op), DAG); 497753f127fSDimitry Andric } 498753f127fSDimitry Andric 499753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op, 500753f127fSDimitry Andric SelectionDAG &DAG) const { 501*bdd1243dSDimitry Andric GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); 502*bdd1243dSDimitry Andric assert(N->getOffset() == 0 && "unexpected offset in global node"); 503*bdd1243dSDimitry Andric return getAddr(N, DAG, N->getGlobal()->isDSOLocal()); 504*bdd1243dSDimitry Andric } 505753f127fSDimitry Andric 506*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N, 507*bdd1243dSDimitry Andric SelectionDAG &DAG, 508*bdd1243dSDimitry Andric unsigned Opc) const { 509*bdd1243dSDimitry Andric SDLoc DL(N); 510*bdd1243dSDimitry Andric EVT Ty = getPointerTy(DAG.getDataLayout()); 511*bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 512*bdd1243dSDimitry Andric 513*bdd1243dSDimitry Andric SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0); 514*bdd1243dSDimitry Andric SDValue Offset = SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0); 515*bdd1243dSDimitry Andric 516*bdd1243dSDimitry Andric // Add the thread pointer. 517*bdd1243dSDimitry Andric return DAG.getNode(ISD::ADD, DL, Ty, Offset, 518*bdd1243dSDimitry Andric DAG.getRegister(LoongArch::R2, GRLenVT)); 519*bdd1243dSDimitry Andric } 520*bdd1243dSDimitry Andric 521*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N, 522*bdd1243dSDimitry Andric SelectionDAG &DAG, 523*bdd1243dSDimitry Andric unsigned Opc) const { 524*bdd1243dSDimitry Andric SDLoc DL(N); 525*bdd1243dSDimitry Andric EVT Ty = getPointerTy(DAG.getDataLayout()); 526*bdd1243dSDimitry Andric IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits()); 527*bdd1243dSDimitry Andric 528*bdd1243dSDimitry Andric // Use a PC-relative addressing mode to access the dynamic GOT address. 529*bdd1243dSDimitry Andric SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0); 530*bdd1243dSDimitry Andric SDValue Load = SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0); 531*bdd1243dSDimitry Andric 532*bdd1243dSDimitry Andric // Prepare argument list to generate call. 533*bdd1243dSDimitry Andric ArgListTy Args; 534*bdd1243dSDimitry Andric ArgListEntry Entry; 535*bdd1243dSDimitry Andric Entry.Node = Load; 536*bdd1243dSDimitry Andric Entry.Ty = CallTy; 537*bdd1243dSDimitry Andric Args.push_back(Entry); 538*bdd1243dSDimitry Andric 539*bdd1243dSDimitry Andric // Setup call to __tls_get_addr. 540*bdd1243dSDimitry Andric TargetLowering::CallLoweringInfo CLI(DAG); 541*bdd1243dSDimitry Andric CLI.setDebugLoc(DL) 542*bdd1243dSDimitry Andric .setChain(DAG.getEntryNode()) 543*bdd1243dSDimitry Andric .setLibCallee(CallingConv::C, CallTy, 544*bdd1243dSDimitry Andric DAG.getExternalSymbol("__tls_get_addr", Ty), 545*bdd1243dSDimitry Andric std::move(Args)); 546*bdd1243dSDimitry Andric 547*bdd1243dSDimitry Andric return LowerCallTo(CLI).first; 548*bdd1243dSDimitry Andric } 549*bdd1243dSDimitry Andric 550*bdd1243dSDimitry Andric SDValue 551*bdd1243dSDimitry Andric LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op, 552*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 553*bdd1243dSDimitry Andric if (DAG.getMachineFunction().getFunction().getCallingConv() == 554*bdd1243dSDimitry Andric CallingConv::GHC) 555*bdd1243dSDimitry Andric report_fatal_error("In GHC calling convention TLS is not supported"); 556*bdd1243dSDimitry Andric 557*bdd1243dSDimitry Andric GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); 558*bdd1243dSDimitry Andric assert(N->getOffset() == 0 && "unexpected offset in global node"); 559*bdd1243dSDimitry Andric 560*bdd1243dSDimitry Andric SDValue Addr; 561*bdd1243dSDimitry Andric switch (getTargetMachine().getTLSModel(N->getGlobal())) { 562*bdd1243dSDimitry Andric case TLSModel::GeneralDynamic: 563*bdd1243dSDimitry Andric // In this model, application code calls the dynamic linker function 564*bdd1243dSDimitry Andric // __tls_get_addr to locate TLS offsets into the dynamic thread vector at 565*bdd1243dSDimitry Andric // runtime. 566*bdd1243dSDimitry Andric Addr = getDynamicTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_GD); 567*bdd1243dSDimitry Andric break; 568*bdd1243dSDimitry Andric case TLSModel::LocalDynamic: 569*bdd1243dSDimitry Andric // Same as GeneralDynamic, except for assembly modifiers and relocation 570*bdd1243dSDimitry Andric // records. 571*bdd1243dSDimitry Andric Addr = getDynamicTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LD); 572*bdd1243dSDimitry Andric break; 573*bdd1243dSDimitry Andric case TLSModel::InitialExec: 574*bdd1243dSDimitry Andric // This model uses the GOT to resolve TLS offsets. 575*bdd1243dSDimitry Andric Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_IE); 576*bdd1243dSDimitry Andric break; 577*bdd1243dSDimitry Andric case TLSModel::LocalExec: 578*bdd1243dSDimitry Andric // This model is used when static linking as the TLS offsets are resolved 579*bdd1243dSDimitry Andric // during program linking. 580*bdd1243dSDimitry Andric Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE); 581*bdd1243dSDimitry Andric break; 582*bdd1243dSDimitry Andric } 583*bdd1243dSDimitry Andric 584753f127fSDimitry Andric return Addr; 585753f127fSDimitry Andric } 586*bdd1243dSDimitry Andric 587*bdd1243dSDimitry Andric SDValue 588*bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, 589*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 590*bdd1243dSDimitry Andric switch (Op.getConstantOperandVal(0)) { 591*bdd1243dSDimitry Andric default: 592*bdd1243dSDimitry Andric return SDValue(); // Don't custom lower most intrinsics. 593*bdd1243dSDimitry Andric case Intrinsic::thread_pointer: { 594*bdd1243dSDimitry Andric EVT PtrVT = getPointerTy(DAG.getDataLayout()); 595*bdd1243dSDimitry Andric return DAG.getRegister(LoongArch::R2, PtrVT); 596*bdd1243dSDimitry Andric } 597*bdd1243dSDimitry Andric } 598*bdd1243dSDimitry Andric } 599*bdd1243dSDimitry Andric 600*bdd1243dSDimitry Andric // Helper function that emits error message for intrinsics with chain. 601*bdd1243dSDimitry Andric static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op, 602*bdd1243dSDimitry Andric StringRef ErrorMsg, 603*bdd1243dSDimitry Andric SelectionDAG &DAG) { 604*bdd1243dSDimitry Andric 605*bdd1243dSDimitry Andric DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + "' " + 606*bdd1243dSDimitry Andric ErrorMsg); 607*bdd1243dSDimitry Andric return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, 608*bdd1243dSDimitry Andric SDLoc(Op)); 609*bdd1243dSDimitry Andric } 610*bdd1243dSDimitry Andric 611*bdd1243dSDimitry Andric SDValue 612*bdd1243dSDimitry Andric LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op, 613*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 614*bdd1243dSDimitry Andric SDLoc DL(Op); 615*bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 616*bdd1243dSDimitry Andric SDValue Op0 = Op.getOperand(0); 617*bdd1243dSDimitry Andric std::string Name = Op->getOperationName(0); 618*bdd1243dSDimitry Andric const StringRef ErrorMsgOOR = "out of range"; 619*bdd1243dSDimitry Andric 620*bdd1243dSDimitry Andric switch (Op.getConstantOperandVal(1)) { 621*bdd1243dSDimitry Andric default: 622*bdd1243dSDimitry Andric return Op; 623*bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_b_w: 624*bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_h_w: 625*bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_w_w: 626*bdd1243dSDimitry Andric case Intrinsic::loongarch_crc_w_d_w: 627*bdd1243dSDimitry Andric case Intrinsic::loongarch_crcc_w_b_w: 628*bdd1243dSDimitry Andric case Intrinsic::loongarch_crcc_w_h_w: 629*bdd1243dSDimitry Andric case Intrinsic::loongarch_crcc_w_w_w: 630*bdd1243dSDimitry Andric case Intrinsic::loongarch_crcc_w_d_w: { 631*bdd1243dSDimitry Andric std::string Name = Op->getOperationName(0); 632*bdd1243dSDimitry Andric DAG.getContext()->emitError(Name + " requires target: loongarch64"); 633*bdd1243dSDimitry Andric return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL); 634*bdd1243dSDimitry Andric } 635*bdd1243dSDimitry Andric case Intrinsic::loongarch_csrrd_w: 636*bdd1243dSDimitry Andric case Intrinsic::loongarch_csrrd_d: { 637*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue(); 638*bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) 639*bdd1243dSDimitry Andric return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG); 640*bdd1243dSDimitry Andric return DAG.getMergeValues( 641*bdd1243dSDimitry Andric {DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0, 642*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)), 643*bdd1243dSDimitry Andric Op0}, 644*bdd1243dSDimitry Andric DL); 645*bdd1243dSDimitry Andric } 646*bdd1243dSDimitry Andric case Intrinsic::loongarch_csrwr_w: 647*bdd1243dSDimitry Andric case Intrinsic::loongarch_csrwr_d: { 648*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue(); 649*bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) 650*bdd1243dSDimitry Andric return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG); 651*bdd1243dSDimitry Andric return DAG.getMergeValues( 652*bdd1243dSDimitry Andric {DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0, Op.getOperand(2), 653*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)), 654*bdd1243dSDimitry Andric Op0}, 655*bdd1243dSDimitry Andric DL); 656*bdd1243dSDimitry Andric } 657*bdd1243dSDimitry Andric case Intrinsic::loongarch_csrxchg_w: 658*bdd1243dSDimitry Andric case Intrinsic::loongarch_csrxchg_d: { 659*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(4))->getZExtValue(); 660*bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) 661*bdd1243dSDimitry Andric return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG); 662*bdd1243dSDimitry Andric return DAG.getMergeValues( 663*bdd1243dSDimitry Andric {DAG.getNode(LoongArchISD::CSRXCHG, DL, GRLenVT, Op0, Op.getOperand(2), 664*bdd1243dSDimitry Andric Op.getOperand(3), DAG.getConstant(Imm, DL, GRLenVT)), 665*bdd1243dSDimitry Andric Op0}, 666*bdd1243dSDimitry Andric DL); 667*bdd1243dSDimitry Andric } 668*bdd1243dSDimitry Andric case Intrinsic::loongarch_iocsrrd_d: { 669*bdd1243dSDimitry Andric if (Subtarget.is64Bit()) 670*bdd1243dSDimitry Andric return DAG.getMergeValues( 671*bdd1243dSDimitry Andric {DAG.getNode( 672*bdd1243dSDimitry Andric LoongArchISD::IOCSRRD_D, DL, GRLenVT, Op0, 673*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))), 674*bdd1243dSDimitry Andric Op0}, 675*bdd1243dSDimitry Andric DL); 676*bdd1243dSDimitry Andric else { 677*bdd1243dSDimitry Andric DAG.getContext()->emitError( 678*bdd1243dSDimitry Andric "llvm.loongarch.crc.w.d.w requires target: loongarch64"); 679*bdd1243dSDimitry Andric return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL); 680*bdd1243dSDimitry Andric } 681*bdd1243dSDimitry Andric } 682*bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE) \ 683*bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 684*bdd1243dSDimitry Andric return DAG.getMergeValues( \ 685*bdd1243dSDimitry Andric {DAG.getNode(LoongArchISD::NODE, DL, GRLenVT, Op0, Op.getOperand(2)), \ 686*bdd1243dSDimitry Andric Op0}, \ 687*bdd1243dSDimitry Andric DL); \ 688*bdd1243dSDimitry Andric } 689*bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B); 690*bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H); 691*bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W); 692*bdd1243dSDimitry Andric #undef IOCSRRD_CASE 693*bdd1243dSDimitry Andric case Intrinsic::loongarch_cpucfg: { 694*bdd1243dSDimitry Andric return DAG.getMergeValues( 695*bdd1243dSDimitry Andric {DAG.getNode(LoongArchISD::CPUCFG, DL, GRLenVT, Op0, Op.getOperand(2)), 696*bdd1243dSDimitry Andric Op0}, 697*bdd1243dSDimitry Andric DL); 698*bdd1243dSDimitry Andric } 699*bdd1243dSDimitry Andric case Intrinsic::loongarch_lddir_d: { 700*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue(); 701*bdd1243dSDimitry Andric if (!isUInt<8>(Imm)) { 702*bdd1243dSDimitry Andric DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + 703*bdd1243dSDimitry Andric "' out of range"); 704*bdd1243dSDimitry Andric return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL); 705*bdd1243dSDimitry Andric } 706*bdd1243dSDimitry Andric 707*bdd1243dSDimitry Andric return Op; 708*bdd1243dSDimitry Andric } 709*bdd1243dSDimitry Andric case Intrinsic::loongarch_movfcsr2gr: { 710*bdd1243dSDimitry Andric if (!Subtarget.hasBasicF()) { 711*bdd1243dSDimitry Andric DAG.getContext()->emitError( 712*bdd1243dSDimitry Andric "llvm.loongarch.movfcsr2gr expects basic f target feature"); 713*bdd1243dSDimitry Andric return DAG.getMergeValues( 714*bdd1243dSDimitry Andric {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op)); 715*bdd1243dSDimitry Andric } 716*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue(); 717*bdd1243dSDimitry Andric if (!isUInt<2>(Imm)) { 718*bdd1243dSDimitry Andric DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + 719*bdd1243dSDimitry Andric "' " + ErrorMsgOOR); 720*bdd1243dSDimitry Andric return DAG.getMergeValues( 721*bdd1243dSDimitry Andric {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op)); 722*bdd1243dSDimitry Andric } 723*bdd1243dSDimitry Andric return DAG.getMergeValues( 724*bdd1243dSDimitry Andric {DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, Op.getValueType(), 725*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)), 726*bdd1243dSDimitry Andric Op.getOperand(0)}, 727*bdd1243dSDimitry Andric DL); 728*bdd1243dSDimitry Andric } 729*bdd1243dSDimitry Andric } 730*bdd1243dSDimitry Andric } 731*bdd1243dSDimitry Andric 732*bdd1243dSDimitry Andric // Helper function that emits error message for intrinsics with void return 733*bdd1243dSDimitry Andric // value. 734*bdd1243dSDimitry Andric static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg, 735*bdd1243dSDimitry Andric SelectionDAG &DAG) { 736*bdd1243dSDimitry Andric 737*bdd1243dSDimitry Andric DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + "' " + 738*bdd1243dSDimitry Andric ErrorMsg); 739*bdd1243dSDimitry Andric return Op.getOperand(0); 740*bdd1243dSDimitry Andric } 741*bdd1243dSDimitry Andric 742*bdd1243dSDimitry Andric SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op, 743*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 744*bdd1243dSDimitry Andric SDLoc DL(Op); 745*bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 746*bdd1243dSDimitry Andric SDValue Op0 = Op.getOperand(0); 747*bdd1243dSDimitry Andric uint64_t IntrinsicEnum = Op.getConstantOperandVal(1); 748*bdd1243dSDimitry Andric SDValue Op2 = Op.getOperand(2); 749*bdd1243dSDimitry Andric const StringRef ErrorMsgOOR = "out of range"; 750*bdd1243dSDimitry Andric 751*bdd1243dSDimitry Andric switch (IntrinsicEnum) { 752*bdd1243dSDimitry Andric default: 753*bdd1243dSDimitry Andric // TODO: Add more Intrinsics. 754*bdd1243dSDimitry Andric return SDValue(); 755*bdd1243dSDimitry Andric case Intrinsic::loongarch_cacop_d: 756*bdd1243dSDimitry Andric case Intrinsic::loongarch_cacop_w: { 757*bdd1243dSDimitry Andric if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit()) { 758*bdd1243dSDimitry Andric DAG.getContext()->emitError( 759*bdd1243dSDimitry Andric "llvm.loongarch.cacop.d requires target: loongarch64"); 760*bdd1243dSDimitry Andric return Op.getOperand(0); 761*bdd1243dSDimitry Andric } 762*bdd1243dSDimitry Andric if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit()) { 763*bdd1243dSDimitry Andric DAG.getContext()->emitError( 764*bdd1243dSDimitry Andric "llvm.loongarch.cacop.w requires target: loongarch32"); 765*bdd1243dSDimitry Andric return Op.getOperand(0); 766*bdd1243dSDimitry Andric } 767*bdd1243dSDimitry Andric // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12) 768*bdd1243dSDimitry Andric unsigned Imm1 = cast<ConstantSDNode>(Op2)->getZExtValue(); 769*bdd1243dSDimitry Andric if (!isUInt<5>(Imm1)) 770*bdd1243dSDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG); 771*bdd1243dSDimitry Andric SDValue Op4 = Op.getOperand(4); 772*bdd1243dSDimitry Andric int Imm2 = cast<ConstantSDNode>(Op4)->getSExtValue(); 773*bdd1243dSDimitry Andric if (!isInt<12>(Imm2)) 774*bdd1243dSDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG); 775*bdd1243dSDimitry Andric 776*bdd1243dSDimitry Andric return Op; 777*bdd1243dSDimitry Andric } 778*bdd1243dSDimitry Andric 779*bdd1243dSDimitry Andric case Intrinsic::loongarch_dbar: { 780*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 781*bdd1243dSDimitry Andric if (!isUInt<15>(Imm)) 782*bdd1243dSDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG); 783*bdd1243dSDimitry Andric 784*bdd1243dSDimitry Andric return DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Op0, 785*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 786*bdd1243dSDimitry Andric } 787*bdd1243dSDimitry Andric case Intrinsic::loongarch_ibar: { 788*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 789*bdd1243dSDimitry Andric if (!isUInt<15>(Imm)) 790*bdd1243dSDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG); 791*bdd1243dSDimitry Andric 792*bdd1243dSDimitry Andric return DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Op0, 793*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 794*bdd1243dSDimitry Andric } 795*bdd1243dSDimitry Andric case Intrinsic::loongarch_break: { 796*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 797*bdd1243dSDimitry Andric if (!isUInt<15>(Imm)) 798*bdd1243dSDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG); 799*bdd1243dSDimitry Andric 800*bdd1243dSDimitry Andric return DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Op0, 801*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 802*bdd1243dSDimitry Andric } 803*bdd1243dSDimitry Andric case Intrinsic::loongarch_movgr2fcsr: { 804*bdd1243dSDimitry Andric if (!Subtarget.hasBasicF()) { 805*bdd1243dSDimitry Andric DAG.getContext()->emitError( 806*bdd1243dSDimitry Andric "llvm.loongarch.movgr2fcsr expects basic f target feature"); 807*bdd1243dSDimitry Andric return Op0; 808*bdd1243dSDimitry Andric } 809*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 810*bdd1243dSDimitry Andric if (!isUInt<2>(Imm)) 811*bdd1243dSDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG); 812*bdd1243dSDimitry Andric 813*bdd1243dSDimitry Andric return DAG.getNode( 814*bdd1243dSDimitry Andric LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Op0, 815*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT), 816*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Op.getOperand(3))); 817*bdd1243dSDimitry Andric } 818*bdd1243dSDimitry Andric case Intrinsic::loongarch_syscall: { 819*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 820*bdd1243dSDimitry Andric if (!isUInt<15>(Imm)) 821*bdd1243dSDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG); 822*bdd1243dSDimitry Andric 823*bdd1243dSDimitry Andric return DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Op0, 824*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)); 825*bdd1243dSDimitry Andric } 826*bdd1243dSDimitry Andric #define IOCSRWR_CASE(NAME, NODE) \ 827*bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 828*bdd1243dSDimitry Andric SDValue Op3 = Op.getOperand(3); \ 829*bdd1243dSDimitry Andric if (Subtarget.is64Bit()) \ 830*bdd1243dSDimitry Andric return DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Op0, \ 831*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \ 832*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)); \ 833*bdd1243dSDimitry Andric else \ 834*bdd1243dSDimitry Andric return DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Op0, Op2, Op3); \ 835*bdd1243dSDimitry Andric } 836*bdd1243dSDimitry Andric IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B); 837*bdd1243dSDimitry Andric IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H); 838*bdd1243dSDimitry Andric IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W); 839*bdd1243dSDimitry Andric #undef IOCSRWR_CASE 840*bdd1243dSDimitry Andric case Intrinsic::loongarch_iocsrwr_d: { 841*bdd1243dSDimitry Andric if (Subtarget.is64Bit()) 842*bdd1243dSDimitry Andric return DAG.getNode( 843*bdd1243dSDimitry Andric LoongArchISD::IOCSRWR_D, DL, MVT::Other, Op0, Op2, 844*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(3))); 845*bdd1243dSDimitry Andric else { 846*bdd1243dSDimitry Andric DAG.getContext()->emitError( 847*bdd1243dSDimitry Andric "llvm.loongarch.iocsrwr.d requires target: loongarch64"); 848*bdd1243dSDimitry Andric return Op.getOperand(0); 849*bdd1243dSDimitry Andric } 850*bdd1243dSDimitry Andric } 851*bdd1243dSDimitry Andric #define ASRT_LE_GT_CASE(NAME) \ 852*bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 853*bdd1243dSDimitry Andric if (!Subtarget.is64Bit()) { \ 854*bdd1243dSDimitry Andric DAG.getContext()->emitError(Op->getOperationName(0) + \ 855*bdd1243dSDimitry Andric " requires target: loongarch64"); \ 856*bdd1243dSDimitry Andric return Op.getOperand(0); \ 857*bdd1243dSDimitry Andric } \ 858*bdd1243dSDimitry Andric return Op; \ 859*bdd1243dSDimitry Andric } 860*bdd1243dSDimitry Andric ASRT_LE_GT_CASE(asrtle_d) 861*bdd1243dSDimitry Andric ASRT_LE_GT_CASE(asrtgt_d) 862*bdd1243dSDimitry Andric #undef ASRT_LE_GT_CASE 863*bdd1243dSDimitry Andric case Intrinsic::loongarch_ldpte_d: { 864*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue(); 865*bdd1243dSDimitry Andric if (!isUInt<8>(Imm)) 866*bdd1243dSDimitry Andric return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG); 867*bdd1243dSDimitry Andric if (!Subtarget.is64Bit()) { 868*bdd1243dSDimitry Andric DAG.getContext()->emitError(Op->getOperationName(0) + 869*bdd1243dSDimitry Andric " requires target: loongarch64"); 870*bdd1243dSDimitry Andric return Op.getOperand(0); 871*bdd1243dSDimitry Andric } 872*bdd1243dSDimitry Andric return Op; 873*bdd1243dSDimitry Andric } 874*bdd1243dSDimitry Andric } 875753f127fSDimitry Andric } 876753f127fSDimitry Andric 87781ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op, 87881ad6265SDimitry Andric SelectionDAG &DAG) const { 87981ad6265SDimitry Andric SDLoc DL(Op); 88081ad6265SDimitry Andric SDValue Lo = Op.getOperand(0); 88181ad6265SDimitry Andric SDValue Hi = Op.getOperand(1); 88281ad6265SDimitry Andric SDValue Shamt = Op.getOperand(2); 88381ad6265SDimitry Andric EVT VT = Lo.getValueType(); 88481ad6265SDimitry Andric 88581ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 88681ad6265SDimitry Andric // Lo = Lo << Shamt 88781ad6265SDimitry Andric // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt)) 88881ad6265SDimitry Andric // else: 88981ad6265SDimitry Andric // Lo = 0 89081ad6265SDimitry Andric // Hi = Lo << (Shamt-GRLen) 89181ad6265SDimitry Andric 89281ad6265SDimitry Andric SDValue Zero = DAG.getConstant(0, DL, VT); 89381ad6265SDimitry Andric SDValue One = DAG.getConstant(1, DL, VT); 89481ad6265SDimitry Andric SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT); 89581ad6265SDimitry Andric SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT); 89681ad6265SDimitry Andric SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen); 89781ad6265SDimitry Andric SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1); 89881ad6265SDimitry Andric 89981ad6265SDimitry Andric SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt); 90081ad6265SDimitry Andric SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One); 90181ad6265SDimitry Andric SDValue ShiftRightLo = 90281ad6265SDimitry Andric DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt); 90381ad6265SDimitry Andric SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt); 90481ad6265SDimitry Andric SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo); 90581ad6265SDimitry Andric SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen); 90681ad6265SDimitry Andric 90781ad6265SDimitry Andric SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT); 90881ad6265SDimitry Andric 90981ad6265SDimitry Andric Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero); 91081ad6265SDimitry Andric Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); 91181ad6265SDimitry Andric 91281ad6265SDimitry Andric SDValue Parts[2] = {Lo, Hi}; 91381ad6265SDimitry Andric return DAG.getMergeValues(Parts, DL); 91481ad6265SDimitry Andric } 91581ad6265SDimitry Andric 91681ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op, 91781ad6265SDimitry Andric SelectionDAG &DAG, 91881ad6265SDimitry Andric bool IsSRA) const { 91981ad6265SDimitry Andric SDLoc DL(Op); 92081ad6265SDimitry Andric SDValue Lo = Op.getOperand(0); 92181ad6265SDimitry Andric SDValue Hi = Op.getOperand(1); 92281ad6265SDimitry Andric SDValue Shamt = Op.getOperand(2); 92381ad6265SDimitry Andric EVT VT = Lo.getValueType(); 92481ad6265SDimitry Andric 92581ad6265SDimitry Andric // SRA expansion: 92681ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 92781ad6265SDimitry Andric // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1)) 92881ad6265SDimitry Andric // Hi = Hi >>s Shamt 92981ad6265SDimitry Andric // else: 93081ad6265SDimitry Andric // Lo = Hi >>s (Shamt-GRLen); 93181ad6265SDimitry Andric // Hi = Hi >>s (GRLen-1) 93281ad6265SDimitry Andric // 93381ad6265SDimitry Andric // SRL expansion: 93481ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 93581ad6265SDimitry Andric // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1)) 93681ad6265SDimitry Andric // Hi = Hi >>u Shamt 93781ad6265SDimitry Andric // else: 93881ad6265SDimitry Andric // Lo = Hi >>u (Shamt-GRLen); 93981ad6265SDimitry Andric // Hi = 0; 94081ad6265SDimitry Andric 94181ad6265SDimitry Andric unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL; 94281ad6265SDimitry Andric 94381ad6265SDimitry Andric SDValue Zero = DAG.getConstant(0, DL, VT); 94481ad6265SDimitry Andric SDValue One = DAG.getConstant(1, DL, VT); 94581ad6265SDimitry Andric SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT); 94681ad6265SDimitry Andric SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT); 94781ad6265SDimitry Andric SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen); 94881ad6265SDimitry Andric SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1); 94981ad6265SDimitry Andric 95081ad6265SDimitry Andric SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt); 95181ad6265SDimitry Andric SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One); 95281ad6265SDimitry Andric SDValue ShiftLeftHi = 95381ad6265SDimitry Andric DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt); 95481ad6265SDimitry Andric SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi); 95581ad6265SDimitry Andric SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt); 95681ad6265SDimitry Andric SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen); 95781ad6265SDimitry Andric SDValue HiFalse = 95881ad6265SDimitry Andric IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero; 95981ad6265SDimitry Andric 96081ad6265SDimitry Andric SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT); 96181ad6265SDimitry Andric 96281ad6265SDimitry Andric Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse); 96381ad6265SDimitry Andric Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); 96481ad6265SDimitry Andric 96581ad6265SDimitry Andric SDValue Parts[2] = {Lo, Hi}; 96681ad6265SDimitry Andric return DAG.getMergeValues(Parts, DL); 96781ad6265SDimitry Andric } 96881ad6265SDimitry Andric 96981ad6265SDimitry Andric // Returns the opcode of the target-specific SDNode that implements the 32-bit 97081ad6265SDimitry Andric // form of the given Opcode. 97181ad6265SDimitry Andric static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode) { 97281ad6265SDimitry Andric switch (Opcode) { 97381ad6265SDimitry Andric default: 97481ad6265SDimitry Andric llvm_unreachable("Unexpected opcode"); 97581ad6265SDimitry Andric case ISD::SHL: 97681ad6265SDimitry Andric return LoongArchISD::SLL_W; 97781ad6265SDimitry Andric case ISD::SRA: 97881ad6265SDimitry Andric return LoongArchISD::SRA_W; 97981ad6265SDimitry Andric case ISD::SRL: 98081ad6265SDimitry Andric return LoongArchISD::SRL_W; 981*bdd1243dSDimitry Andric case ISD::ROTR: 982*bdd1243dSDimitry Andric return LoongArchISD::ROTR_W; 983*bdd1243dSDimitry Andric case ISD::ROTL: 984*bdd1243dSDimitry Andric return LoongArchISD::ROTL_W; 985*bdd1243dSDimitry Andric case ISD::CTTZ: 986*bdd1243dSDimitry Andric return LoongArchISD::CTZ_W; 987*bdd1243dSDimitry Andric case ISD::CTLZ: 988*bdd1243dSDimitry Andric return LoongArchISD::CLZ_W; 98981ad6265SDimitry Andric } 99081ad6265SDimitry Andric } 99181ad6265SDimitry Andric 99281ad6265SDimitry Andric // Converts the given i8/i16/i32 operation to a target-specific SelectionDAG 99381ad6265SDimitry Andric // node. Because i8/i16/i32 isn't a legal type for LA64, these operations would 99481ad6265SDimitry Andric // otherwise be promoted to i64, making it difficult to select the 99581ad6265SDimitry Andric // SLL_W/.../*W later one because the fact the operation was originally of 99681ad6265SDimitry Andric // type i8/i16/i32 is lost. 997*bdd1243dSDimitry Andric static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp, 99881ad6265SDimitry Andric unsigned ExtOpc = ISD::ANY_EXTEND) { 99981ad6265SDimitry Andric SDLoc DL(N); 100081ad6265SDimitry Andric LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode()); 1001*bdd1243dSDimitry Andric SDValue NewOp0, NewRes; 1002*bdd1243dSDimitry Andric 1003*bdd1243dSDimitry Andric switch (NumOp) { 1004*bdd1243dSDimitry Andric default: 1005*bdd1243dSDimitry Andric llvm_unreachable("Unexpected NumOp"); 1006*bdd1243dSDimitry Andric case 1: { 1007*bdd1243dSDimitry Andric NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0)); 1008*bdd1243dSDimitry Andric NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0); 1009*bdd1243dSDimitry Andric break; 1010*bdd1243dSDimitry Andric } 1011*bdd1243dSDimitry Andric case 2: { 1012*bdd1243dSDimitry Andric NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0)); 101381ad6265SDimitry Andric SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1)); 1014*bdd1243dSDimitry Andric NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1); 1015*bdd1243dSDimitry Andric break; 1016*bdd1243dSDimitry Andric } 1017*bdd1243dSDimitry Andric // TODO:Handle more NumOp. 1018*bdd1243dSDimitry Andric } 1019*bdd1243dSDimitry Andric 1020*bdd1243dSDimitry Andric // ReplaceNodeResults requires we maintain the same type for the return 1021*bdd1243dSDimitry Andric // value. 102281ad6265SDimitry Andric return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes); 102381ad6265SDimitry Andric } 102481ad6265SDimitry Andric 102581ad6265SDimitry Andric void LoongArchTargetLowering::ReplaceNodeResults( 102681ad6265SDimitry Andric SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const { 102781ad6265SDimitry Andric SDLoc DL(N); 1028*bdd1243dSDimitry Andric EVT VT = N->getValueType(0); 102981ad6265SDimitry Andric switch (N->getOpcode()) { 103081ad6265SDimitry Andric default: 103181ad6265SDimitry Andric llvm_unreachable("Don't know how to legalize this operation"); 103281ad6265SDimitry Andric case ISD::SHL: 103381ad6265SDimitry Andric case ISD::SRA: 103481ad6265SDimitry Andric case ISD::SRL: 1035*bdd1243dSDimitry Andric case ISD::ROTR: 1036*bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 103781ad6265SDimitry Andric "Unexpected custom legalisation"); 103881ad6265SDimitry Andric if (N->getOperand(1).getOpcode() != ISD::Constant) { 1039*bdd1243dSDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG, 2)); 1040*bdd1243dSDimitry Andric break; 1041*bdd1243dSDimitry Andric } 1042*bdd1243dSDimitry Andric break; 1043*bdd1243dSDimitry Andric case ISD::ROTL: 1044*bdd1243dSDimitry Andric ConstantSDNode *CN; 1045*bdd1243dSDimitry Andric if ((CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) { 1046*bdd1243dSDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG, 2)); 104781ad6265SDimitry Andric break; 104881ad6265SDimitry Andric } 104981ad6265SDimitry Andric break; 1050753f127fSDimitry Andric case ISD::FP_TO_SINT: { 1051*bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 1052753f127fSDimitry Andric "Unexpected custom legalisation"); 1053753f127fSDimitry Andric SDValue Src = N->getOperand(0); 1054*bdd1243dSDimitry Andric EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0)); 1055*bdd1243dSDimitry Andric if (getTypeAction(*DAG.getContext(), Src.getValueType()) != 1056*bdd1243dSDimitry Andric TargetLowering::TypeSoftenFloat) { 1057*bdd1243dSDimitry Andric SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src); 1058*bdd1243dSDimitry Andric Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst)); 1059*bdd1243dSDimitry Andric return; 1060*bdd1243dSDimitry Andric } 1061*bdd1243dSDimitry Andric // If the FP type needs to be softened, emit a library call using the 'si' 1062*bdd1243dSDimitry Andric // version. If we left it to default legalization we'd end up with 'di'. 1063*bdd1243dSDimitry Andric RTLIB::Libcall LC; 1064*bdd1243dSDimitry Andric LC = RTLIB::getFPTOSINT(Src.getValueType(), VT); 1065*bdd1243dSDimitry Andric MakeLibCallOptions CallOptions; 1066*bdd1243dSDimitry Andric EVT OpVT = Src.getValueType(); 1067*bdd1243dSDimitry Andric CallOptions.setTypeListBeforeSoften(OpVT, VT, true); 1068*bdd1243dSDimitry Andric SDValue Chain = SDValue(); 1069*bdd1243dSDimitry Andric SDValue Result; 1070*bdd1243dSDimitry Andric std::tie(Result, Chain) = 1071*bdd1243dSDimitry Andric makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain); 1072*bdd1243dSDimitry Andric Results.push_back(Result); 1073753f127fSDimitry Andric break; 1074753f127fSDimitry Andric } 1075753f127fSDimitry Andric case ISD::BITCAST: { 1076753f127fSDimitry Andric SDValue Src = N->getOperand(0); 1077753f127fSDimitry Andric EVT SrcVT = Src.getValueType(); 1078753f127fSDimitry Andric if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() && 1079753f127fSDimitry Andric Subtarget.hasBasicF()) { 1080753f127fSDimitry Andric SDValue Dst = 1081753f127fSDimitry Andric DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src); 1082753f127fSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst)); 1083753f127fSDimitry Andric } 1084753f127fSDimitry Andric break; 1085753f127fSDimitry Andric } 1086753f127fSDimitry Andric case ISD::FP_TO_UINT: { 1087*bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 1088753f127fSDimitry Andric "Unexpected custom legalisation"); 1089753f127fSDimitry Andric auto &TLI = DAG.getTargetLoweringInfo(); 1090753f127fSDimitry Andric SDValue Tmp1, Tmp2; 1091753f127fSDimitry Andric TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG); 1092753f127fSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1)); 1093753f127fSDimitry Andric break; 1094753f127fSDimitry Andric } 1095*bdd1243dSDimitry Andric case ISD::BSWAP: { 1096*bdd1243dSDimitry Andric SDValue Src = N->getOperand(0); 1097*bdd1243dSDimitry Andric assert((VT == MVT::i16 || VT == MVT::i32) && 1098*bdd1243dSDimitry Andric "Unexpected custom legalization"); 1099*bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 1100*bdd1243dSDimitry Andric SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src); 1101*bdd1243dSDimitry Andric SDValue Tmp; 1102*bdd1243dSDimitry Andric switch (VT.getSizeInBits()) { 1103*bdd1243dSDimitry Andric default: 1104*bdd1243dSDimitry Andric llvm_unreachable("Unexpected operand width"); 1105*bdd1243dSDimitry Andric case 16: 1106*bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc); 1107*bdd1243dSDimitry Andric break; 1108*bdd1243dSDimitry Andric case 32: 1109*bdd1243dSDimitry Andric // Only LA64 will get to here due to the size mismatch between VT and 1110*bdd1243dSDimitry Andric // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo. 1111*bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc); 1112*bdd1243dSDimitry Andric break; 1113*bdd1243dSDimitry Andric } 1114*bdd1243dSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp)); 1115*bdd1243dSDimitry Andric break; 1116*bdd1243dSDimitry Andric } 1117*bdd1243dSDimitry Andric case ISD::BITREVERSE: { 1118*bdd1243dSDimitry Andric SDValue Src = N->getOperand(0); 1119*bdd1243dSDimitry Andric assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) && 1120*bdd1243dSDimitry Andric "Unexpected custom legalization"); 1121*bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 1122*bdd1243dSDimitry Andric SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src); 1123*bdd1243dSDimitry Andric SDValue Tmp; 1124*bdd1243dSDimitry Andric switch (VT.getSizeInBits()) { 1125*bdd1243dSDimitry Andric default: 1126*bdd1243dSDimitry Andric llvm_unreachable("Unexpected operand width"); 1127*bdd1243dSDimitry Andric case 8: 1128*bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc); 1129*bdd1243dSDimitry Andric break; 1130*bdd1243dSDimitry Andric case 32: 1131*bdd1243dSDimitry Andric Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc); 1132*bdd1243dSDimitry Andric break; 1133*bdd1243dSDimitry Andric } 1134*bdd1243dSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp)); 1135*bdd1243dSDimitry Andric break; 1136*bdd1243dSDimitry Andric } 1137*bdd1243dSDimitry Andric case ISD::CTLZ: 1138*bdd1243dSDimitry Andric case ISD::CTTZ: { 1139*bdd1243dSDimitry Andric assert(VT == MVT::i32 && Subtarget.is64Bit() && 1140*bdd1243dSDimitry Andric "Unexpected custom legalisation"); 1141*bdd1243dSDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG, 1)); 1142*bdd1243dSDimitry Andric break; 1143*bdd1243dSDimitry Andric } 1144*bdd1243dSDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 1145*bdd1243dSDimitry Andric SDValue Op0 = N->getOperand(0); 1146*bdd1243dSDimitry Andric EVT VT = N->getValueType(0); 1147*bdd1243dSDimitry Andric uint64_t Op1 = N->getConstantOperandVal(1); 1148*bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 1149*bdd1243dSDimitry Andric if (Op1 == Intrinsic::loongarch_movfcsr2gr) { 1150*bdd1243dSDimitry Andric if (!Subtarget.hasBasicF()) { 1151*bdd1243dSDimitry Andric DAG.getContext()->emitError( 1152*bdd1243dSDimitry Andric "llvm.loongarch.movfcsr2gr expects basic f target feature"); 1153*bdd1243dSDimitry Andric Results.push_back(DAG.getMergeValues( 1154*bdd1243dSDimitry Andric {DAG.getUNDEF(N->getValueType(0)), N->getOperand(0)}, SDLoc(N))); 1155*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 1156*bdd1243dSDimitry Andric return; 1157*bdd1243dSDimitry Andric } 1158*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(); 1159*bdd1243dSDimitry Andric if (!isUInt<2>(Imm)) { 1160*bdd1243dSDimitry Andric DAG.getContext()->emitError("argument to '" + N->getOperationName(0) + 1161*bdd1243dSDimitry Andric "' " + "out of range"); 1162*bdd1243dSDimitry Andric Results.push_back(DAG.getMergeValues( 1163*bdd1243dSDimitry Andric {DAG.getUNDEF(N->getValueType(0)), N->getOperand(0)}, SDLoc(N))); 1164*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 1165*bdd1243dSDimitry Andric return; 1166*bdd1243dSDimitry Andric } 1167*bdd1243dSDimitry Andric Results.push_back( 1168*bdd1243dSDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, 1169*bdd1243dSDimitry Andric DAG.getNode(LoongArchISD::MOVFCSR2GR, SDLoc(N), MVT::i64, 1170*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)))); 1171*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 1172*bdd1243dSDimitry Andric return; 1173*bdd1243dSDimitry Andric } 1174*bdd1243dSDimitry Andric SDValue Op2 = N->getOperand(2); 1175*bdd1243dSDimitry Andric std::string Name = N->getOperationName(0); 1176*bdd1243dSDimitry Andric 1177*bdd1243dSDimitry Andric switch (Op1) { 1178*bdd1243dSDimitry Andric default: 1179*bdd1243dSDimitry Andric llvm_unreachable("Unexpected Intrinsic."); 1180*bdd1243dSDimitry Andric #define CRC_CASE_EXT_BINARYOP(NAME, NODE) \ 1181*bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 1182*bdd1243dSDimitry Andric Results.push_back(DAG.getNode( \ 1183*bdd1243dSDimitry Andric ISD::TRUNCATE, DL, VT, \ 1184*bdd1243dSDimitry Andric DAG.getNode( \ 1185*bdd1243dSDimitry Andric LoongArchISD::NODE, DL, MVT::i64, \ 1186*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \ 1187*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))))); \ 1188*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); \ 1189*bdd1243dSDimitry Andric break; \ 1190*bdd1243dSDimitry Andric } 1191*bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W) 1192*bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W) 1193*bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W) 1194*bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W) 1195*bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W) 1196*bdd1243dSDimitry Andric CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W) 1197*bdd1243dSDimitry Andric #undef CRC_CASE_EXT_BINARYOP 1198*bdd1243dSDimitry Andric 1199*bdd1243dSDimitry Andric #define CRC_CASE_EXT_UNARYOP(NAME, NODE) \ 1200*bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 1201*bdd1243dSDimitry Andric Results.push_back( \ 1202*bdd1243dSDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, \ 1203*bdd1243dSDimitry Andric DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op2, \ 1204*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, \ 1205*bdd1243dSDimitry Andric N->getOperand(3))))); \ 1206*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); \ 1207*bdd1243dSDimitry Andric break; \ 1208*bdd1243dSDimitry Andric } 1209*bdd1243dSDimitry Andric CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W) 1210*bdd1243dSDimitry Andric CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W) 1211*bdd1243dSDimitry Andric #undef CRC_CASE_EXT_UNARYOP 1212*bdd1243dSDimitry Andric #define CSR_CASE(ID) \ 1213*bdd1243dSDimitry Andric case Intrinsic::loongarch_##ID: { \ 1214*bdd1243dSDimitry Andric if (!Subtarget.is64Bit()) { \ 1215*bdd1243dSDimitry Andric DAG.getContext()->emitError(Name + " requires target: loongarch64"); \ 1216*bdd1243dSDimitry Andric Results.push_back(DAG.getUNDEF(VT)); \ 1217*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); \ 1218*bdd1243dSDimitry Andric } \ 1219*bdd1243dSDimitry Andric break; \ 1220*bdd1243dSDimitry Andric } 1221*bdd1243dSDimitry Andric CSR_CASE(csrrd_d); 1222*bdd1243dSDimitry Andric CSR_CASE(csrwr_d); 1223*bdd1243dSDimitry Andric CSR_CASE(csrxchg_d); 1224*bdd1243dSDimitry Andric CSR_CASE(iocsrrd_d); 1225*bdd1243dSDimitry Andric #undef CSR_CASE 1226*bdd1243dSDimitry Andric case Intrinsic::loongarch_csrrd_w: { 1227*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue(); 1228*bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) { 1229*bdd1243dSDimitry Andric DAG.getContext()->emitError("argument to '" + Name + "' out of range"); 1230*bdd1243dSDimitry Andric Results.push_back(DAG.getUNDEF(VT)); 1231*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 1232*bdd1243dSDimitry Andric break; 1233*bdd1243dSDimitry Andric } 1234*bdd1243dSDimitry Andric 1235*bdd1243dSDimitry Andric Results.push_back( 1236*bdd1243dSDimitry Andric DAG.getNode(ISD::TRUNCATE, DL, VT, 1237*bdd1243dSDimitry Andric DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0, 1238*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)))); 1239*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 1240*bdd1243dSDimitry Andric break; 1241*bdd1243dSDimitry Andric } 1242*bdd1243dSDimitry Andric case Intrinsic::loongarch_csrwr_w: { 1243*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(); 1244*bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) { 1245*bdd1243dSDimitry Andric DAG.getContext()->emitError("argument to '" + Name + "' out of range"); 1246*bdd1243dSDimitry Andric Results.push_back(DAG.getUNDEF(VT)); 1247*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 1248*bdd1243dSDimitry Andric break; 1249*bdd1243dSDimitry Andric } 1250*bdd1243dSDimitry Andric 1251*bdd1243dSDimitry Andric Results.push_back(DAG.getNode( 1252*bdd1243dSDimitry Andric ISD::TRUNCATE, DL, VT, 1253*bdd1243dSDimitry Andric DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0, 1254*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), 1255*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)))); 1256*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 1257*bdd1243dSDimitry Andric break; 1258*bdd1243dSDimitry Andric } 1259*bdd1243dSDimitry Andric case Intrinsic::loongarch_csrxchg_w: { 1260*bdd1243dSDimitry Andric unsigned Imm = cast<ConstantSDNode>(N->getOperand(4))->getZExtValue(); 1261*bdd1243dSDimitry Andric if (!isUInt<14>(Imm)) { 1262*bdd1243dSDimitry Andric DAG.getContext()->emitError("argument to '" + Name + "' out of range"); 1263*bdd1243dSDimitry Andric Results.push_back(DAG.getUNDEF(VT)); 1264*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 1265*bdd1243dSDimitry Andric break; 1266*bdd1243dSDimitry Andric } 1267*bdd1243dSDimitry Andric 1268*bdd1243dSDimitry Andric Results.push_back(DAG.getNode( 1269*bdd1243dSDimitry Andric ISD::TRUNCATE, DL, VT, 1270*bdd1243dSDimitry Andric DAG.getNode( 1271*bdd1243dSDimitry Andric LoongArchISD::CSRXCHG, DL, GRLenVT, Op0, 1272*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), 1273*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)), 1274*bdd1243dSDimitry Andric DAG.getConstant(Imm, DL, GRLenVT)))); 1275*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 1276*bdd1243dSDimitry Andric break; 1277*bdd1243dSDimitry Andric } 1278*bdd1243dSDimitry Andric #define IOCSRRD_CASE(NAME, NODE) \ 1279*bdd1243dSDimitry Andric case Intrinsic::loongarch_##NAME: { \ 1280*bdd1243dSDimitry Andric Results.push_back(DAG.getNode( \ 1281*bdd1243dSDimitry Andric ISD::TRUNCATE, DL, N->getValueType(0), \ 1282*bdd1243dSDimitry Andric DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op0, \ 1283*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)))); \ 1284*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); \ 1285*bdd1243dSDimitry Andric break; \ 1286*bdd1243dSDimitry Andric } 1287*bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B); 1288*bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H); 1289*bdd1243dSDimitry Andric IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W); 1290*bdd1243dSDimitry Andric #undef IOCSRRD_CASE 1291*bdd1243dSDimitry Andric case Intrinsic::loongarch_cpucfg: { 1292*bdd1243dSDimitry Andric Results.push_back(DAG.getNode( 1293*bdd1243dSDimitry Andric ISD::TRUNCATE, DL, VT, 1294*bdd1243dSDimitry Andric DAG.getNode(LoongArchISD::CPUCFG, DL, GRLenVT, Op0, 1295*bdd1243dSDimitry Andric DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)))); 1296*bdd1243dSDimitry Andric Results.push_back(Op0); 1297*bdd1243dSDimitry Andric break; 1298*bdd1243dSDimitry Andric } 1299*bdd1243dSDimitry Andric case Intrinsic::loongarch_lddir_d: { 1300*bdd1243dSDimitry Andric if (!Subtarget.is64Bit()) { 1301*bdd1243dSDimitry Andric DAG.getContext()->emitError(N->getOperationName(0) + 1302*bdd1243dSDimitry Andric " requires target: loongarch64"); 1303*bdd1243dSDimitry Andric Results.push_back(DAG.getUNDEF(VT)); 1304*bdd1243dSDimitry Andric Results.push_back(Op0); 1305*bdd1243dSDimitry Andric break; 1306*bdd1243dSDimitry Andric } 1307*bdd1243dSDimitry Andric break; 1308*bdd1243dSDimitry Andric } 1309*bdd1243dSDimitry Andric } 1310*bdd1243dSDimitry Andric break; 1311*bdd1243dSDimitry Andric } 1312*bdd1243dSDimitry Andric case ISD::READ_REGISTER: { 1313*bdd1243dSDimitry Andric if (Subtarget.is64Bit()) 1314*bdd1243dSDimitry Andric DAG.getContext()->emitError( 1315*bdd1243dSDimitry Andric "On LA64, only 64-bit registers can be read."); 1316*bdd1243dSDimitry Andric else 1317*bdd1243dSDimitry Andric DAG.getContext()->emitError( 1318*bdd1243dSDimitry Andric "On LA32, only 32-bit registers can be read."); 1319*bdd1243dSDimitry Andric Results.push_back(DAG.getUNDEF(VT)); 1320*bdd1243dSDimitry Andric Results.push_back(N->getOperand(0)); 1321*bdd1243dSDimitry Andric break; 1322*bdd1243dSDimitry Andric } 132381ad6265SDimitry Andric } 132481ad6265SDimitry Andric } 132581ad6265SDimitry Andric 132681ad6265SDimitry Andric static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, 132781ad6265SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 132881ad6265SDimitry Andric const LoongArchSubtarget &Subtarget) { 132981ad6265SDimitry Andric if (DCI.isBeforeLegalizeOps()) 133081ad6265SDimitry Andric return SDValue(); 133181ad6265SDimitry Andric 133281ad6265SDimitry Andric SDValue FirstOperand = N->getOperand(0); 133381ad6265SDimitry Andric SDValue SecondOperand = N->getOperand(1); 133481ad6265SDimitry Andric unsigned FirstOperandOpc = FirstOperand.getOpcode(); 133581ad6265SDimitry Andric EVT ValTy = N->getValueType(0); 133681ad6265SDimitry Andric SDLoc DL(N); 133781ad6265SDimitry Andric uint64_t lsb, msb; 133881ad6265SDimitry Andric unsigned SMIdx, SMLen; 133981ad6265SDimitry Andric ConstantSDNode *CN; 134081ad6265SDimitry Andric SDValue NewOperand; 134181ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 134281ad6265SDimitry Andric 134381ad6265SDimitry Andric // Op's second operand must be a shifted mask. 134481ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) || 134581ad6265SDimitry Andric !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen)) 134681ad6265SDimitry Andric return SDValue(); 134781ad6265SDimitry Andric 134881ad6265SDimitry Andric if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) { 134981ad6265SDimitry Andric // Pattern match BSTRPICK. 135081ad6265SDimitry Andric // $dst = and ((sra or srl) $src , lsb), (2**len - 1) 135181ad6265SDimitry Andric // => BSTRPICK $dst, $src, msb, lsb 135281ad6265SDimitry Andric // where msb = lsb + len - 1 135381ad6265SDimitry Andric 135481ad6265SDimitry Andric // The second operand of the shift must be an immediate. 135581ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1)))) 135681ad6265SDimitry Andric return SDValue(); 135781ad6265SDimitry Andric 135881ad6265SDimitry Andric lsb = CN->getZExtValue(); 135981ad6265SDimitry Andric 136081ad6265SDimitry Andric // Return if the shifted mask does not start at bit 0 or the sum of its 136181ad6265SDimitry Andric // length and lsb exceeds the word's size. 136281ad6265SDimitry Andric if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits()) 136381ad6265SDimitry Andric return SDValue(); 136481ad6265SDimitry Andric 136581ad6265SDimitry Andric NewOperand = FirstOperand.getOperand(0); 136681ad6265SDimitry Andric } else { 136781ad6265SDimitry Andric // Pattern match BSTRPICK. 136881ad6265SDimitry Andric // $dst = and $src, (2**len- 1) , if len > 12 136981ad6265SDimitry Andric // => BSTRPICK $dst, $src, msb, lsb 137081ad6265SDimitry Andric // where lsb = 0 and msb = len - 1 137181ad6265SDimitry Andric 137281ad6265SDimitry Andric // If the mask is <= 0xfff, andi can be used instead. 137381ad6265SDimitry Andric if (CN->getZExtValue() <= 0xfff) 137481ad6265SDimitry Andric return SDValue(); 137581ad6265SDimitry Andric 137681ad6265SDimitry Andric // Return if the mask doesn't start at position 0. 137781ad6265SDimitry Andric if (SMIdx) 137881ad6265SDimitry Andric return SDValue(); 137981ad6265SDimitry Andric 138081ad6265SDimitry Andric lsb = 0; 138181ad6265SDimitry Andric NewOperand = FirstOperand; 138281ad6265SDimitry Andric } 138381ad6265SDimitry Andric msb = lsb + SMLen - 1; 138481ad6265SDimitry Andric return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand, 138581ad6265SDimitry Andric DAG.getConstant(msb, DL, GRLenVT), 138681ad6265SDimitry Andric DAG.getConstant(lsb, DL, GRLenVT)); 138781ad6265SDimitry Andric } 138881ad6265SDimitry Andric 138981ad6265SDimitry Andric static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, 139081ad6265SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 139181ad6265SDimitry Andric const LoongArchSubtarget &Subtarget) { 139281ad6265SDimitry Andric if (DCI.isBeforeLegalizeOps()) 139381ad6265SDimitry Andric return SDValue(); 139481ad6265SDimitry Andric 139581ad6265SDimitry Andric // $dst = srl (and $src, Mask), Shamt 139681ad6265SDimitry Andric // => 139781ad6265SDimitry Andric // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt 139881ad6265SDimitry Andric // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1 139981ad6265SDimitry Andric // 140081ad6265SDimitry Andric 140181ad6265SDimitry Andric SDValue FirstOperand = N->getOperand(0); 140281ad6265SDimitry Andric ConstantSDNode *CN; 140381ad6265SDimitry Andric EVT ValTy = N->getValueType(0); 140481ad6265SDimitry Andric SDLoc DL(N); 140581ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 140681ad6265SDimitry Andric unsigned MaskIdx, MaskLen; 140781ad6265SDimitry Andric uint64_t Shamt; 140881ad6265SDimitry Andric 140981ad6265SDimitry Andric // The first operand must be an AND and the second operand of the AND must be 141081ad6265SDimitry Andric // a shifted mask. 141181ad6265SDimitry Andric if (FirstOperand.getOpcode() != ISD::AND || 141281ad6265SDimitry Andric !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) || 141381ad6265SDimitry Andric !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen)) 141481ad6265SDimitry Andric return SDValue(); 141581ad6265SDimitry Andric 141681ad6265SDimitry Andric // The second operand (shift amount) must be an immediate. 141781ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) 141881ad6265SDimitry Andric return SDValue(); 141981ad6265SDimitry Andric 142081ad6265SDimitry Andric Shamt = CN->getZExtValue(); 142181ad6265SDimitry Andric if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1) 142281ad6265SDimitry Andric return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, 142381ad6265SDimitry Andric FirstOperand->getOperand(0), 142481ad6265SDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 142581ad6265SDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 142681ad6265SDimitry Andric 142781ad6265SDimitry Andric return SDValue(); 142881ad6265SDimitry Andric } 142981ad6265SDimitry Andric 1430753f127fSDimitry Andric static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, 1431753f127fSDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 1432753f127fSDimitry Andric const LoongArchSubtarget &Subtarget) { 1433753f127fSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 1434753f127fSDimitry Andric EVT ValTy = N->getValueType(0); 1435753f127fSDimitry Andric SDValue N0 = N->getOperand(0), N1 = N->getOperand(1); 1436753f127fSDimitry Andric ConstantSDNode *CN0, *CN1; 1437753f127fSDimitry Andric SDLoc DL(N); 1438753f127fSDimitry Andric unsigned ValBits = ValTy.getSizeInBits(); 1439753f127fSDimitry Andric unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1; 1440753f127fSDimitry Andric unsigned Shamt; 1441753f127fSDimitry Andric bool SwapAndRetried = false; 1442753f127fSDimitry Andric 1443753f127fSDimitry Andric if (DCI.isBeforeLegalizeOps()) 1444753f127fSDimitry Andric return SDValue(); 1445753f127fSDimitry Andric 1446753f127fSDimitry Andric if (ValBits != 32 && ValBits != 64) 1447753f127fSDimitry Andric return SDValue(); 1448753f127fSDimitry Andric 1449753f127fSDimitry Andric Retry: 1450753f127fSDimitry Andric // 1st pattern to match BSTRINS: 1451753f127fSDimitry Andric // R = or (and X, mask0), (and (shl Y, lsb), mask1) 1452753f127fSDimitry Andric // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1 1453753f127fSDimitry Andric // => 1454753f127fSDimitry Andric // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1) 1455753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 1456753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 1457753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 1458753f127fSDimitry Andric N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL && 1459753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1460753f127fSDimitry Andric isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) && 1461753f127fSDimitry Andric MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 && 1462753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 1463753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskIdx0 && 1464753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 1465753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n"); 1466753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 1467753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 1468753f127fSDimitry Andric DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT), 1469753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 1470753f127fSDimitry Andric } 1471753f127fSDimitry Andric 1472753f127fSDimitry Andric // 2nd pattern to match BSTRINS: 1473753f127fSDimitry Andric // R = or (and X, mask0), (shl (and Y, mask1), lsb) 1474753f127fSDimitry Andric // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb) 1475753f127fSDimitry Andric // => 1476753f127fSDimitry Andric // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1) 1477753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 1478753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 1479753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 1480753f127fSDimitry Andric N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND && 1481753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1482753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskIdx0 && 1483753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 1484753f127fSDimitry Andric isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) && 1485753f127fSDimitry Andric MaskLen0 == MaskLen1 && MaskIdx1 == 0 && 1486753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 1487753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n"); 1488753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 1489753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 1490753f127fSDimitry Andric DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT), 1491753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 1492753f127fSDimitry Andric } 1493753f127fSDimitry Andric 1494753f127fSDimitry Andric // 3rd pattern to match BSTRINS: 1495753f127fSDimitry Andric // R = or (and X, mask0), (and Y, mask1) 1496753f127fSDimitry Andric // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0 1497753f127fSDimitry Andric // => 1498753f127fSDimitry Andric // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb 1499753f127fSDimitry Andric // where msb = lsb + size - 1 1500753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND && 1501753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 1502753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 1503753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= 64) && 1504753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) && 1505753f127fSDimitry Andric (CN1->getSExtValue() & CN0->getSExtValue()) == 0) { 1506753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n"); 1507753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 1508753f127fSDimitry Andric DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1, 1509753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)), 1510753f127fSDimitry Andric DAG.getConstant(ValBits == 32 1511753f127fSDimitry Andric ? (MaskIdx0 + (MaskLen0 & 31) - 1) 1512753f127fSDimitry Andric : (MaskIdx0 + MaskLen0 - 1), 1513753f127fSDimitry Andric DL, GRLenVT), 1514753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 1515753f127fSDimitry Andric } 1516753f127fSDimitry Andric 1517753f127fSDimitry Andric // 4th pattern to match BSTRINS: 1518753f127fSDimitry Andric // R = or (and X, mask), (shl Y, shamt) 1519753f127fSDimitry Andric // where mask = (2**shamt - 1) 1520753f127fSDimitry Andric // => 1521753f127fSDimitry Andric // R = BSTRINS X, Y, ValBits - 1, shamt 1522753f127fSDimitry Andric // where ValBits = 32 or 64 1523753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL && 1524753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 1525753f127fSDimitry Andric isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) && 1526753f127fSDimitry Andric MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1527753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskLen0 && 1528753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 1529753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n"); 1530753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 1531753f127fSDimitry Andric N1.getOperand(0), 1532753f127fSDimitry Andric DAG.getConstant((ValBits - 1), DL, GRLenVT), 1533753f127fSDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 1534753f127fSDimitry Andric } 1535753f127fSDimitry Andric 1536753f127fSDimitry Andric // 5th pattern to match BSTRINS: 1537753f127fSDimitry Andric // R = or (and X, mask), const 1538753f127fSDimitry Andric // where ~mask = (2**size - 1) << lsb, mask & const = 0 1539753f127fSDimitry Andric // => 1540753f127fSDimitry Andric // R = BSTRINS X, (const >> lsb), msb, lsb 1541753f127fSDimitry Andric // where msb = lsb + size - 1 1542753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 1543753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 1544753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 1545753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1)) && 1546753f127fSDimitry Andric (CN1->getSExtValue() & CN0->getSExtValue()) == 0) { 1547753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n"); 1548753f127fSDimitry Andric return DAG.getNode( 1549753f127fSDimitry Andric LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 1550753f127fSDimitry Andric DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy), 1551753f127fSDimitry Andric DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT), 1552753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 1553753f127fSDimitry Andric } 1554753f127fSDimitry Andric 1555753f127fSDimitry Andric // 6th pattern. 1556753f127fSDimitry Andric // a = b | ((c & mask) << shamt), where all positions in b to be overwritten 1557753f127fSDimitry Andric // by the incoming bits are known to be zero. 1558753f127fSDimitry Andric // => 1559753f127fSDimitry Andric // a = BSTRINS b, c, shamt + MaskLen - 1, shamt 1560753f127fSDimitry Andric // 1561753f127fSDimitry Andric // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th 1562753f127fSDimitry Andric // pattern is more common than the 1st. So we put the 1st before the 6th in 1563753f127fSDimitry Andric // order to match as many nodes as possible. 1564753f127fSDimitry Andric ConstantSDNode *CNMask, *CNShamt; 1565753f127fSDimitry Andric unsigned MaskIdx, MaskLen; 1566753f127fSDimitry Andric if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND && 1567753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 1568753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) && 1569753f127fSDimitry Andric MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1570753f127fSDimitry Andric CNShamt->getZExtValue() + MaskLen <= ValBits) { 1571753f127fSDimitry Andric Shamt = CNShamt->getZExtValue(); 1572753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt); 1573753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 1574753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n"); 1575753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 1576753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 1577753f127fSDimitry Andric DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT), 1578753f127fSDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 1579753f127fSDimitry Andric } 1580753f127fSDimitry Andric } 1581753f127fSDimitry Andric 1582753f127fSDimitry Andric // 7th pattern. 1583753f127fSDimitry Andric // a = b | ((c << shamt) & shifted_mask), where all positions in b to be 1584753f127fSDimitry Andric // overwritten by the incoming bits are known to be zero. 1585753f127fSDimitry Andric // => 1586753f127fSDimitry Andric // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx 1587753f127fSDimitry Andric // 1588753f127fSDimitry Andric // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd 1589753f127fSDimitry Andric // before the 7th in order to match as many nodes as possible. 1590753f127fSDimitry Andric if (N1.getOpcode() == ISD::AND && 1591753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1592753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) && 1593753f127fSDimitry Andric N1.getOperand(0).getOpcode() == ISD::SHL && 1594753f127fSDimitry Andric (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 1595753f127fSDimitry Andric CNShamt->getZExtValue() == MaskIdx) { 1596753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue()); 1597753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 1598753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n"); 1599753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 1600753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 1601753f127fSDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 1602753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)); 1603753f127fSDimitry Andric } 1604753f127fSDimitry Andric } 1605753f127fSDimitry Andric 1606753f127fSDimitry Andric // (or a, b) and (or b, a) are equivalent, so swap the operands and retry. 1607753f127fSDimitry Andric if (!SwapAndRetried) { 1608753f127fSDimitry Andric std::swap(N0, N1); 1609753f127fSDimitry Andric SwapAndRetried = true; 1610753f127fSDimitry Andric goto Retry; 1611753f127fSDimitry Andric } 1612753f127fSDimitry Andric 1613753f127fSDimitry Andric SwapAndRetried = false; 1614753f127fSDimitry Andric Retry2: 1615753f127fSDimitry Andric // 8th pattern. 1616753f127fSDimitry Andric // a = b | (c & shifted_mask), where all positions in b to be overwritten by 1617753f127fSDimitry Andric // the incoming bits are known to be zero. 1618753f127fSDimitry Andric // => 1619753f127fSDimitry Andric // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx 1620753f127fSDimitry Andric // 1621753f127fSDimitry Andric // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So 1622753f127fSDimitry Andric // we put it here in order to match as many nodes as possible or generate less 1623753f127fSDimitry Andric // instructions. 1624753f127fSDimitry Andric if (N1.getOpcode() == ISD::AND && 1625753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 1626753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) { 1627753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue()); 1628753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 1629753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n"); 1630753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 1631753f127fSDimitry Andric DAG.getNode(ISD::SRL, DL, N1->getValueType(0), 1632753f127fSDimitry Andric N1->getOperand(0), 1633753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)), 1634753f127fSDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 1635753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)); 1636753f127fSDimitry Andric } 1637753f127fSDimitry Andric } 1638753f127fSDimitry Andric // Swap N0/N1 and retry. 1639753f127fSDimitry Andric if (!SwapAndRetried) { 1640753f127fSDimitry Andric std::swap(N0, N1); 1641753f127fSDimitry Andric SwapAndRetried = true; 1642753f127fSDimitry Andric goto Retry2; 1643753f127fSDimitry Andric } 1644753f127fSDimitry Andric 1645753f127fSDimitry Andric return SDValue(); 1646753f127fSDimitry Andric } 1647753f127fSDimitry Andric 1648*bdd1243dSDimitry Andric // Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b. 1649*bdd1243dSDimitry Andric static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG, 1650*bdd1243dSDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 1651*bdd1243dSDimitry Andric const LoongArchSubtarget &Subtarget) { 1652*bdd1243dSDimitry Andric if (DCI.isBeforeLegalizeOps()) 1653*bdd1243dSDimitry Andric return SDValue(); 1654*bdd1243dSDimitry Andric 1655*bdd1243dSDimitry Andric SDValue Src = N->getOperand(0); 1656*bdd1243dSDimitry Andric if (Src.getOpcode() != LoongArchISD::REVB_2W) 1657*bdd1243dSDimitry Andric return SDValue(); 1658*bdd1243dSDimitry Andric 1659*bdd1243dSDimitry Andric return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0), 1660*bdd1243dSDimitry Andric Src.getOperand(0)); 1661*bdd1243dSDimitry Andric } 1662*bdd1243dSDimitry Andric 166381ad6265SDimitry Andric SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N, 166481ad6265SDimitry Andric DAGCombinerInfo &DCI) const { 166581ad6265SDimitry Andric SelectionDAG &DAG = DCI.DAG; 166681ad6265SDimitry Andric switch (N->getOpcode()) { 166781ad6265SDimitry Andric default: 166881ad6265SDimitry Andric break; 166981ad6265SDimitry Andric case ISD::AND: 167081ad6265SDimitry Andric return performANDCombine(N, DAG, DCI, Subtarget); 1671753f127fSDimitry Andric case ISD::OR: 1672753f127fSDimitry Andric return performORCombine(N, DAG, DCI, Subtarget); 167381ad6265SDimitry Andric case ISD::SRL: 167481ad6265SDimitry Andric return performSRLCombine(N, DAG, DCI, Subtarget); 1675*bdd1243dSDimitry Andric case LoongArchISD::BITREV_W: 1676*bdd1243dSDimitry Andric return performBITREV_WCombine(N, DAG, DCI, Subtarget); 167781ad6265SDimitry Andric } 167881ad6265SDimitry Andric return SDValue(); 167981ad6265SDimitry Andric } 168081ad6265SDimitry Andric 1681753f127fSDimitry Andric static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI, 1682*bdd1243dSDimitry Andric MachineBasicBlock *MBB) { 1683753f127fSDimitry Andric if (!ZeroDivCheck) 1684*bdd1243dSDimitry Andric return MBB; 1685753f127fSDimitry Andric 1686753f127fSDimitry Andric // Build instructions: 1687*bdd1243dSDimitry Andric // MBB: 1688753f127fSDimitry Andric // div(or mod) $dst, $dividend, $divisor 1689*bdd1243dSDimitry Andric // bnez $divisor, SinkMBB 1690*bdd1243dSDimitry Andric // BreakMBB: 1691*bdd1243dSDimitry Andric // break 7 // BRK_DIVZERO 1692*bdd1243dSDimitry Andric // SinkMBB: 1693753f127fSDimitry Andric // fallthrough 1694*bdd1243dSDimitry Andric const BasicBlock *LLVM_BB = MBB->getBasicBlock(); 1695*bdd1243dSDimitry Andric MachineFunction::iterator It = ++MBB->getIterator(); 1696*bdd1243dSDimitry Andric MachineFunction *MF = MBB->getParent(); 1697*bdd1243dSDimitry Andric auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB); 1698*bdd1243dSDimitry Andric auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB); 1699*bdd1243dSDimitry Andric MF->insert(It, BreakMBB); 1700*bdd1243dSDimitry Andric MF->insert(It, SinkMBB); 1701*bdd1243dSDimitry Andric 1702*bdd1243dSDimitry Andric // Transfer the remainder of MBB and its successor edges to SinkMBB. 1703*bdd1243dSDimitry Andric SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end()); 1704*bdd1243dSDimitry Andric SinkMBB->transferSuccessorsAndUpdatePHIs(MBB); 1705*bdd1243dSDimitry Andric 1706*bdd1243dSDimitry Andric const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); 1707*bdd1243dSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 1708753f127fSDimitry Andric MachineOperand &Divisor = MI.getOperand(2); 1709*bdd1243dSDimitry Andric Register DivisorReg = Divisor.getReg(); 1710753f127fSDimitry Andric 1711*bdd1243dSDimitry Andric // MBB: 1712*bdd1243dSDimitry Andric BuildMI(MBB, DL, TII.get(LoongArch::BNEZ)) 1713*bdd1243dSDimitry Andric .addReg(DivisorReg, getKillRegState(Divisor.isKill())) 1714*bdd1243dSDimitry Andric .addMBB(SinkMBB); 1715*bdd1243dSDimitry Andric MBB->addSuccessor(BreakMBB); 1716*bdd1243dSDimitry Andric MBB->addSuccessor(SinkMBB); 1717753f127fSDimitry Andric 1718*bdd1243dSDimitry Andric // BreakMBB: 1719753f127fSDimitry Andric // See linux header file arch/loongarch/include/uapi/asm/break.h for the 1720753f127fSDimitry Andric // definition of BRK_DIVZERO. 1721*bdd1243dSDimitry Andric BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/); 1722*bdd1243dSDimitry Andric BreakMBB->addSuccessor(SinkMBB); 1723753f127fSDimitry Andric 1724753f127fSDimitry Andric // Clear Divisor's kill flag. 1725753f127fSDimitry Andric Divisor.setIsKill(false); 1726753f127fSDimitry Andric 1727*bdd1243dSDimitry Andric return SinkMBB; 1728753f127fSDimitry Andric } 1729753f127fSDimitry Andric 1730753f127fSDimitry Andric MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter( 1731753f127fSDimitry Andric MachineInstr &MI, MachineBasicBlock *BB) const { 1732*bdd1243dSDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 1733*bdd1243dSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 1734753f127fSDimitry Andric 1735753f127fSDimitry Andric switch (MI.getOpcode()) { 1736753f127fSDimitry Andric default: 1737753f127fSDimitry Andric llvm_unreachable("Unexpected instr type to insert"); 1738753f127fSDimitry Andric case LoongArch::DIV_W: 1739753f127fSDimitry Andric case LoongArch::DIV_WU: 1740753f127fSDimitry Andric case LoongArch::MOD_W: 1741753f127fSDimitry Andric case LoongArch::MOD_WU: 1742753f127fSDimitry Andric case LoongArch::DIV_D: 1743753f127fSDimitry Andric case LoongArch::DIV_DU: 1744753f127fSDimitry Andric case LoongArch::MOD_D: 1745753f127fSDimitry Andric case LoongArch::MOD_DU: 1746*bdd1243dSDimitry Andric return insertDivByZeroTrap(MI, BB); 1747753f127fSDimitry Andric break; 1748*bdd1243dSDimitry Andric case LoongArch::WRFCSR: { 1749*bdd1243dSDimitry Andric BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR), 1750*bdd1243dSDimitry Andric LoongArch::FCSR0 + MI.getOperand(0).getImm()) 1751*bdd1243dSDimitry Andric .addReg(MI.getOperand(1).getReg()); 1752*bdd1243dSDimitry Andric MI.eraseFromParent(); 1753*bdd1243dSDimitry Andric return BB; 1754*bdd1243dSDimitry Andric } 1755*bdd1243dSDimitry Andric case LoongArch::RDFCSR: { 1756*bdd1243dSDimitry Andric MachineInstr *ReadFCSR = 1757*bdd1243dSDimitry Andric BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR), 1758*bdd1243dSDimitry Andric MI.getOperand(0).getReg()) 1759*bdd1243dSDimitry Andric .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm()); 1760*bdd1243dSDimitry Andric ReadFCSR->getOperand(1).setIsUndef(); 1761*bdd1243dSDimitry Andric MI.eraseFromParent(); 1762*bdd1243dSDimitry Andric return BB; 1763*bdd1243dSDimitry Andric } 1764753f127fSDimitry Andric } 1765753f127fSDimitry Andric } 1766753f127fSDimitry Andric 176781ad6265SDimitry Andric const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const { 176881ad6265SDimitry Andric switch ((LoongArchISD::NodeType)Opcode) { 176981ad6265SDimitry Andric case LoongArchISD::FIRST_NUMBER: 177081ad6265SDimitry Andric break; 177181ad6265SDimitry Andric 177281ad6265SDimitry Andric #define NODE_NAME_CASE(node) \ 177381ad6265SDimitry Andric case LoongArchISD::node: \ 177481ad6265SDimitry Andric return "LoongArchISD::" #node; 177581ad6265SDimitry Andric 177681ad6265SDimitry Andric // TODO: Add more target-dependent nodes later. 1777753f127fSDimitry Andric NODE_NAME_CASE(CALL) 177881ad6265SDimitry Andric NODE_NAME_CASE(RET) 1779*bdd1243dSDimitry Andric NODE_NAME_CASE(TAIL) 178081ad6265SDimitry Andric NODE_NAME_CASE(SLL_W) 178181ad6265SDimitry Andric NODE_NAME_CASE(SRA_W) 178281ad6265SDimitry Andric NODE_NAME_CASE(SRL_W) 1783753f127fSDimitry Andric NODE_NAME_CASE(BSTRINS) 178481ad6265SDimitry Andric NODE_NAME_CASE(BSTRPICK) 1785753f127fSDimitry Andric NODE_NAME_CASE(MOVGR2FR_W_LA64) 1786753f127fSDimitry Andric NODE_NAME_CASE(MOVFR2GR_S_LA64) 1787753f127fSDimitry Andric NODE_NAME_CASE(FTINT) 1788*bdd1243dSDimitry Andric NODE_NAME_CASE(REVB_2H) 1789*bdd1243dSDimitry Andric NODE_NAME_CASE(REVB_2W) 1790*bdd1243dSDimitry Andric NODE_NAME_CASE(BITREV_4B) 1791*bdd1243dSDimitry Andric NODE_NAME_CASE(BITREV_W) 1792*bdd1243dSDimitry Andric NODE_NAME_CASE(ROTR_W) 1793*bdd1243dSDimitry Andric NODE_NAME_CASE(ROTL_W) 1794*bdd1243dSDimitry Andric NODE_NAME_CASE(CLZ_W) 1795*bdd1243dSDimitry Andric NODE_NAME_CASE(CTZ_W) 1796*bdd1243dSDimitry Andric NODE_NAME_CASE(DBAR) 1797*bdd1243dSDimitry Andric NODE_NAME_CASE(IBAR) 1798*bdd1243dSDimitry Andric NODE_NAME_CASE(BREAK) 1799*bdd1243dSDimitry Andric NODE_NAME_CASE(SYSCALL) 1800*bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_B_W) 1801*bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_H_W) 1802*bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_W_W) 1803*bdd1243dSDimitry Andric NODE_NAME_CASE(CRC_W_D_W) 1804*bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_B_W) 1805*bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_H_W) 1806*bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_W_W) 1807*bdd1243dSDimitry Andric NODE_NAME_CASE(CRCC_W_D_W) 1808*bdd1243dSDimitry Andric NODE_NAME_CASE(CSRRD) 1809*bdd1243dSDimitry Andric NODE_NAME_CASE(CSRWR) 1810*bdd1243dSDimitry Andric NODE_NAME_CASE(CSRXCHG) 1811*bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_B) 1812*bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_H) 1813*bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_W) 1814*bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRRD_D) 1815*bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_B) 1816*bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_H) 1817*bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_W) 1818*bdd1243dSDimitry Andric NODE_NAME_CASE(IOCSRWR_D) 1819*bdd1243dSDimitry Andric NODE_NAME_CASE(CPUCFG) 1820*bdd1243dSDimitry Andric NODE_NAME_CASE(MOVGR2FCSR) 1821*bdd1243dSDimitry Andric NODE_NAME_CASE(MOVFCSR2GR) 1822*bdd1243dSDimitry Andric NODE_NAME_CASE(CACOP_D) 1823*bdd1243dSDimitry Andric NODE_NAME_CASE(CACOP_W) 182481ad6265SDimitry Andric } 182581ad6265SDimitry Andric #undef NODE_NAME_CASE 182681ad6265SDimitry Andric return nullptr; 182781ad6265SDimitry Andric } 182881ad6265SDimitry Andric 182981ad6265SDimitry Andric //===----------------------------------------------------------------------===// 183081ad6265SDimitry Andric // Calling Convention Implementation 183181ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1832*bdd1243dSDimitry Andric 1833*bdd1243dSDimitry Andric // Eight general-purpose registers a0-a7 used for passing integer arguments, 1834*bdd1243dSDimitry Andric // with a0-a1 reused to return values. Generally, the GPRs are used to pass 1835*bdd1243dSDimitry Andric // fixed-point arguments, and floating-point arguments when no FPR is available 1836*bdd1243dSDimitry Andric // or with soft float ABI. 183781ad6265SDimitry Andric const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6, 183881ad6265SDimitry Andric LoongArch::R7, LoongArch::R8, LoongArch::R9, 183981ad6265SDimitry Andric LoongArch::R10, LoongArch::R11}; 1840*bdd1243dSDimitry Andric // Eight floating-point registers fa0-fa7 used for passing floating-point 1841*bdd1243dSDimitry Andric // arguments, and fa0-fa1 are also used to return values. 184281ad6265SDimitry Andric const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2, 184381ad6265SDimitry Andric LoongArch::F3, LoongArch::F4, LoongArch::F5, 184481ad6265SDimitry Andric LoongArch::F6, LoongArch::F7}; 1845*bdd1243dSDimitry Andric // FPR32 and FPR64 alias each other. 184681ad6265SDimitry Andric const MCPhysReg ArgFPR64s[] = { 184781ad6265SDimitry Andric LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64, 184881ad6265SDimitry Andric LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64}; 184981ad6265SDimitry Andric 1850*bdd1243dSDimitry Andric // Pass a 2*GRLen argument that has been split into two GRLen values through 1851*bdd1243dSDimitry Andric // registers or the stack as necessary. 1852*bdd1243dSDimitry Andric static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State, 1853*bdd1243dSDimitry Andric CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1, 1854*bdd1243dSDimitry Andric unsigned ValNo2, MVT ValVT2, MVT LocVT2, 1855*bdd1243dSDimitry Andric ISD::ArgFlagsTy ArgFlags2) { 1856*bdd1243dSDimitry Andric unsigned GRLenInBytes = GRLen / 8; 1857*bdd1243dSDimitry Andric if (Register Reg = State.AllocateReg(ArgGPRs)) { 1858*bdd1243dSDimitry Andric // At least one half can be passed via register. 1859*bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg, 1860*bdd1243dSDimitry Andric VA1.getLocVT(), CCValAssign::Full)); 1861*bdd1243dSDimitry Andric } else { 1862*bdd1243dSDimitry Andric // Both halves must be passed on the stack, with proper alignment. 1863*bdd1243dSDimitry Andric Align StackAlign = 1864*bdd1243dSDimitry Andric std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign()); 1865*bdd1243dSDimitry Andric State.addLoc( 1866*bdd1243dSDimitry Andric CCValAssign::getMem(VA1.getValNo(), VA1.getValVT(), 1867*bdd1243dSDimitry Andric State.AllocateStack(GRLenInBytes, StackAlign), 1868*bdd1243dSDimitry Andric VA1.getLocVT(), CCValAssign::Full)); 1869*bdd1243dSDimitry Andric State.addLoc(CCValAssign::getMem( 1870*bdd1243dSDimitry Andric ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)), 1871*bdd1243dSDimitry Andric LocVT2, CCValAssign::Full)); 1872*bdd1243dSDimitry Andric return false; 1873*bdd1243dSDimitry Andric } 1874*bdd1243dSDimitry Andric if (Register Reg = State.AllocateReg(ArgGPRs)) { 1875*bdd1243dSDimitry Andric // The second half can also be passed via register. 1876*bdd1243dSDimitry Andric State.addLoc( 1877*bdd1243dSDimitry Andric CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full)); 1878*bdd1243dSDimitry Andric } else { 1879*bdd1243dSDimitry Andric // The second half is passed via the stack, without additional alignment. 1880*bdd1243dSDimitry Andric State.addLoc(CCValAssign::getMem( 1881*bdd1243dSDimitry Andric ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)), 1882*bdd1243dSDimitry Andric LocVT2, CCValAssign::Full)); 1883*bdd1243dSDimitry Andric } 188481ad6265SDimitry Andric return false; 188581ad6265SDimitry Andric } 188681ad6265SDimitry Andric 1887*bdd1243dSDimitry Andric // Implements the LoongArch calling convention. Returns true upon failure. 1888*bdd1243dSDimitry Andric static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI, 1889*bdd1243dSDimitry Andric unsigned ValNo, MVT ValVT, 1890*bdd1243dSDimitry Andric CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, 1891*bdd1243dSDimitry Andric CCState &State, bool IsFixed, bool IsRet, 1892*bdd1243dSDimitry Andric Type *OrigTy) { 1893*bdd1243dSDimitry Andric unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits(); 1894*bdd1243dSDimitry Andric assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen"); 1895*bdd1243dSDimitry Andric MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64; 1896*bdd1243dSDimitry Andric MVT LocVT = ValVT; 1897*bdd1243dSDimitry Andric 1898*bdd1243dSDimitry Andric // Any return value split into more than two values can't be returned 1899*bdd1243dSDimitry Andric // directly. 1900*bdd1243dSDimitry Andric if (IsRet && ValNo > 1) 190181ad6265SDimitry Andric return true; 1902*bdd1243dSDimitry Andric 1903*bdd1243dSDimitry Andric // If passing a variadic argument, or if no FPR is available. 1904*bdd1243dSDimitry Andric bool UseGPRForFloat = true; 1905*bdd1243dSDimitry Andric 1906*bdd1243dSDimitry Andric switch (ABI) { 1907*bdd1243dSDimitry Andric default: 1908*bdd1243dSDimitry Andric llvm_unreachable("Unexpected ABI"); 1909*bdd1243dSDimitry Andric case LoongArchABI::ABI_ILP32S: 1910*bdd1243dSDimitry Andric case LoongArchABI::ABI_LP64S: 1911*bdd1243dSDimitry Andric case LoongArchABI::ABI_ILP32F: 1912*bdd1243dSDimitry Andric case LoongArchABI::ABI_LP64F: 1913*bdd1243dSDimitry Andric report_fatal_error("Unimplemented ABI"); 1914*bdd1243dSDimitry Andric break; 1915*bdd1243dSDimitry Andric case LoongArchABI::ABI_ILP32D: 1916*bdd1243dSDimitry Andric case LoongArchABI::ABI_LP64D: 1917*bdd1243dSDimitry Andric UseGPRForFloat = !IsFixed; 1918*bdd1243dSDimitry Andric break; 1919*bdd1243dSDimitry Andric } 1920*bdd1243dSDimitry Andric 1921*bdd1243dSDimitry Andric // FPR32 and FPR64 alias each other. 1922*bdd1243dSDimitry Andric if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s)) 1923*bdd1243dSDimitry Andric UseGPRForFloat = true; 1924*bdd1243dSDimitry Andric 1925*bdd1243dSDimitry Andric if (UseGPRForFloat && ValVT == MVT::f32) { 1926*bdd1243dSDimitry Andric LocVT = GRLenVT; 1927*bdd1243dSDimitry Andric LocInfo = CCValAssign::BCvt; 1928*bdd1243dSDimitry Andric } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) { 1929*bdd1243dSDimitry Andric LocVT = MVT::i64; 1930*bdd1243dSDimitry Andric LocInfo = CCValAssign::BCvt; 1931*bdd1243dSDimitry Andric } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) { 1932*bdd1243dSDimitry Andric // TODO: Handle passing f64 on LA32 with D feature. 1933*bdd1243dSDimitry Andric report_fatal_error("Passing f64 with GPR on LA32 is undefined"); 1934*bdd1243dSDimitry Andric } 1935*bdd1243dSDimitry Andric 1936*bdd1243dSDimitry Andric // If this is a variadic argument, the LoongArch calling convention requires 1937*bdd1243dSDimitry Andric // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8 1938*bdd1243dSDimitry Andric // byte alignment. An aligned register should be used regardless of whether 1939*bdd1243dSDimitry Andric // the original argument was split during legalisation or not. The argument 1940*bdd1243dSDimitry Andric // will not be passed by registers if the original type is larger than 1941*bdd1243dSDimitry Andric // 2*GRLen, so the register alignment rule does not apply. 1942*bdd1243dSDimitry Andric unsigned TwoGRLenInBytes = (2 * GRLen) / 8; 1943*bdd1243dSDimitry Andric if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes && 1944*bdd1243dSDimitry Andric DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) { 1945*bdd1243dSDimitry Andric unsigned RegIdx = State.getFirstUnallocated(ArgGPRs); 1946*bdd1243dSDimitry Andric // Skip 'odd' register if necessary. 1947*bdd1243dSDimitry Andric if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1) 1948*bdd1243dSDimitry Andric State.AllocateReg(ArgGPRs); 1949*bdd1243dSDimitry Andric } 1950*bdd1243dSDimitry Andric 1951*bdd1243dSDimitry Andric SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs(); 1952*bdd1243dSDimitry Andric SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags = 1953*bdd1243dSDimitry Andric State.getPendingArgFlags(); 1954*bdd1243dSDimitry Andric 1955*bdd1243dSDimitry Andric assert(PendingLocs.size() == PendingArgFlags.size() && 1956*bdd1243dSDimitry Andric "PendingLocs and PendingArgFlags out of sync"); 1957*bdd1243dSDimitry Andric 1958*bdd1243dSDimitry Andric // Split arguments might be passed indirectly, so keep track of the pending 1959*bdd1243dSDimitry Andric // values. 1960*bdd1243dSDimitry Andric if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) { 1961*bdd1243dSDimitry Andric LocVT = GRLenVT; 1962*bdd1243dSDimitry Andric LocInfo = CCValAssign::Indirect; 1963*bdd1243dSDimitry Andric PendingLocs.push_back( 1964*bdd1243dSDimitry Andric CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo)); 1965*bdd1243dSDimitry Andric PendingArgFlags.push_back(ArgFlags); 1966*bdd1243dSDimitry Andric if (!ArgFlags.isSplitEnd()) { 1967*bdd1243dSDimitry Andric return false; 1968*bdd1243dSDimitry Andric } 1969*bdd1243dSDimitry Andric } 1970*bdd1243dSDimitry Andric 1971*bdd1243dSDimitry Andric // If the split argument only had two elements, it should be passed directly 1972*bdd1243dSDimitry Andric // in registers or on the stack. 1973*bdd1243dSDimitry Andric if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() && 1974*bdd1243dSDimitry Andric PendingLocs.size() <= 2) { 1975*bdd1243dSDimitry Andric assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()"); 1976*bdd1243dSDimitry Andric // Apply the normal calling convention rules to the first half of the 1977*bdd1243dSDimitry Andric // split argument. 1978*bdd1243dSDimitry Andric CCValAssign VA = PendingLocs[0]; 1979*bdd1243dSDimitry Andric ISD::ArgFlagsTy AF = PendingArgFlags[0]; 1980*bdd1243dSDimitry Andric PendingLocs.clear(); 1981*bdd1243dSDimitry Andric PendingArgFlags.clear(); 1982*bdd1243dSDimitry Andric return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT, 1983*bdd1243dSDimitry Andric ArgFlags); 1984*bdd1243dSDimitry Andric } 1985*bdd1243dSDimitry Andric 1986*bdd1243dSDimitry Andric // Allocate to a register if possible, or else a stack slot. 1987*bdd1243dSDimitry Andric Register Reg; 1988*bdd1243dSDimitry Andric unsigned StoreSizeBytes = GRLen / 8; 1989*bdd1243dSDimitry Andric Align StackAlign = Align(GRLen / 8); 1990*bdd1243dSDimitry Andric 1991*bdd1243dSDimitry Andric if (ValVT == MVT::f32 && !UseGPRForFloat) 1992*bdd1243dSDimitry Andric Reg = State.AllocateReg(ArgFPR32s); 1993*bdd1243dSDimitry Andric else if (ValVT == MVT::f64 && !UseGPRForFloat) 1994*bdd1243dSDimitry Andric Reg = State.AllocateReg(ArgFPR64s); 1995*bdd1243dSDimitry Andric else 1996*bdd1243dSDimitry Andric Reg = State.AllocateReg(ArgGPRs); 1997*bdd1243dSDimitry Andric 1998*bdd1243dSDimitry Andric unsigned StackOffset = 1999*bdd1243dSDimitry Andric Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign); 2000*bdd1243dSDimitry Andric 2001*bdd1243dSDimitry Andric // If we reach this point and PendingLocs is non-empty, we must be at the 2002*bdd1243dSDimitry Andric // end of a split argument that must be passed indirectly. 2003*bdd1243dSDimitry Andric if (!PendingLocs.empty()) { 2004*bdd1243dSDimitry Andric assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()"); 2005*bdd1243dSDimitry Andric assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()"); 2006*bdd1243dSDimitry Andric for (auto &It : PendingLocs) { 2007*bdd1243dSDimitry Andric if (Reg) 2008*bdd1243dSDimitry Andric It.convertToReg(Reg); 2009*bdd1243dSDimitry Andric else 2010*bdd1243dSDimitry Andric It.convertToMem(StackOffset); 2011*bdd1243dSDimitry Andric State.addLoc(It); 2012*bdd1243dSDimitry Andric } 2013*bdd1243dSDimitry Andric PendingLocs.clear(); 2014*bdd1243dSDimitry Andric PendingArgFlags.clear(); 2015*bdd1243dSDimitry Andric return false; 2016*bdd1243dSDimitry Andric } 2017*bdd1243dSDimitry Andric assert((!UseGPRForFloat || LocVT == GRLenVT) && 2018*bdd1243dSDimitry Andric "Expected an GRLenVT at this stage"); 2019*bdd1243dSDimitry Andric 2020*bdd1243dSDimitry Andric if (Reg) { 2021*bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 2022*bdd1243dSDimitry Andric return false; 2023*bdd1243dSDimitry Andric } 2024*bdd1243dSDimitry Andric 2025*bdd1243dSDimitry Andric // When a floating-point value is passed on the stack, no bit-cast is needed. 2026*bdd1243dSDimitry Andric if (ValVT.isFloatingPoint()) { 2027*bdd1243dSDimitry Andric LocVT = ValVT; 2028*bdd1243dSDimitry Andric LocInfo = CCValAssign::Full; 2029*bdd1243dSDimitry Andric } 2030*bdd1243dSDimitry Andric 2031*bdd1243dSDimitry Andric State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo)); 2032*bdd1243dSDimitry Andric return false; 203381ad6265SDimitry Andric } 203481ad6265SDimitry Andric 203581ad6265SDimitry Andric void LoongArchTargetLowering::analyzeInputArgs( 2036*bdd1243dSDimitry Andric MachineFunction &MF, CCState &CCInfo, 2037*bdd1243dSDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet, 203881ad6265SDimitry Andric LoongArchCCAssignFn Fn) const { 2039*bdd1243dSDimitry Andric FunctionType *FType = MF.getFunction().getFunctionType(); 204081ad6265SDimitry Andric for (unsigned i = 0, e = Ins.size(); i != e; ++i) { 204181ad6265SDimitry Andric MVT ArgVT = Ins[i].VT; 2042*bdd1243dSDimitry Andric Type *ArgTy = nullptr; 2043*bdd1243dSDimitry Andric if (IsRet) 2044*bdd1243dSDimitry Andric ArgTy = FType->getReturnType(); 2045*bdd1243dSDimitry Andric else if (Ins[i].isOrigArg()) 2046*bdd1243dSDimitry Andric ArgTy = FType->getParamType(Ins[i].getOrigArgIndex()); 2047*bdd1243dSDimitry Andric LoongArchABI::ABI ABI = 2048*bdd1243dSDimitry Andric MF.getSubtarget<LoongArchSubtarget>().getTargetABI(); 2049*bdd1243dSDimitry Andric if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags, 2050*bdd1243dSDimitry Andric CCInfo, /*IsFixed=*/true, IsRet, ArgTy)) { 205181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " 205281ad6265SDimitry Andric << EVT(ArgVT).getEVTString() << '\n'); 205381ad6265SDimitry Andric llvm_unreachable(""); 205481ad6265SDimitry Andric } 205581ad6265SDimitry Andric } 205681ad6265SDimitry Andric } 205781ad6265SDimitry Andric 205881ad6265SDimitry Andric void LoongArchTargetLowering::analyzeOutputArgs( 2059*bdd1243dSDimitry Andric MachineFunction &MF, CCState &CCInfo, 2060*bdd1243dSDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet, 2061*bdd1243dSDimitry Andric CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const { 206281ad6265SDimitry Andric for (unsigned i = 0, e = Outs.size(); i != e; ++i) { 206381ad6265SDimitry Andric MVT ArgVT = Outs[i].VT; 2064*bdd1243dSDimitry Andric Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr; 2065*bdd1243dSDimitry Andric LoongArchABI::ABI ABI = 2066*bdd1243dSDimitry Andric MF.getSubtarget<LoongArchSubtarget>().getTargetABI(); 2067*bdd1243dSDimitry Andric if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags, 2068*bdd1243dSDimitry Andric CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) { 206981ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " 207081ad6265SDimitry Andric << EVT(ArgVT).getEVTString() << "\n"); 207181ad6265SDimitry Andric llvm_unreachable(""); 207281ad6265SDimitry Andric } 207381ad6265SDimitry Andric } 207481ad6265SDimitry Andric } 207581ad6265SDimitry Andric 2076*bdd1243dSDimitry Andric // Convert Val to a ValVT. Should not be called for CCValAssign::Indirect 2077*bdd1243dSDimitry Andric // values. 2078*bdd1243dSDimitry Andric static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, 2079*bdd1243dSDimitry Andric const CCValAssign &VA, const SDLoc &DL) { 2080*bdd1243dSDimitry Andric switch (VA.getLocInfo()) { 2081*bdd1243dSDimitry Andric default: 2082*bdd1243dSDimitry Andric llvm_unreachable("Unexpected CCValAssign::LocInfo"); 2083*bdd1243dSDimitry Andric case CCValAssign::Full: 2084*bdd1243dSDimitry Andric case CCValAssign::Indirect: 2085*bdd1243dSDimitry Andric break; 2086*bdd1243dSDimitry Andric case CCValAssign::BCvt: 2087*bdd1243dSDimitry Andric if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) 2088*bdd1243dSDimitry Andric Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val); 2089*bdd1243dSDimitry Andric else 2090*bdd1243dSDimitry Andric Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val); 2091*bdd1243dSDimitry Andric break; 2092*bdd1243dSDimitry Andric } 2093*bdd1243dSDimitry Andric return Val; 2094*bdd1243dSDimitry Andric } 2095*bdd1243dSDimitry Andric 209681ad6265SDimitry Andric static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain, 209781ad6265SDimitry Andric const CCValAssign &VA, const SDLoc &DL, 209881ad6265SDimitry Andric const LoongArchTargetLowering &TLI) { 209981ad6265SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 210081ad6265SDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 210181ad6265SDimitry Andric EVT LocVT = VA.getLocVT(); 2102*bdd1243dSDimitry Andric SDValue Val; 210381ad6265SDimitry Andric const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT()); 210481ad6265SDimitry Andric Register VReg = RegInfo.createVirtualRegister(RC); 210581ad6265SDimitry Andric RegInfo.addLiveIn(VA.getLocReg(), VReg); 2106*bdd1243dSDimitry Andric Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT); 210781ad6265SDimitry Andric 2108*bdd1243dSDimitry Andric return convertLocVTToValVT(DAG, Val, VA, DL); 2109*bdd1243dSDimitry Andric } 2110*bdd1243dSDimitry Andric 2111*bdd1243dSDimitry Andric // The caller is responsible for loading the full value if the argument is 2112*bdd1243dSDimitry Andric // passed with CCValAssign::Indirect. 2113*bdd1243dSDimitry Andric static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, 2114*bdd1243dSDimitry Andric const CCValAssign &VA, const SDLoc &DL) { 2115*bdd1243dSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 2116*bdd1243dSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 2117*bdd1243dSDimitry Andric EVT ValVT = VA.getValVT(); 2118*bdd1243dSDimitry Andric int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(), 2119*bdd1243dSDimitry Andric /*IsImmutable=*/true); 2120*bdd1243dSDimitry Andric SDValue FIN = DAG.getFrameIndex( 2121*bdd1243dSDimitry Andric FI, MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0))); 2122*bdd1243dSDimitry Andric 2123*bdd1243dSDimitry Andric ISD::LoadExtType ExtType; 2124*bdd1243dSDimitry Andric switch (VA.getLocInfo()) { 2125*bdd1243dSDimitry Andric default: 2126*bdd1243dSDimitry Andric llvm_unreachable("Unexpected CCValAssign::LocInfo"); 2127*bdd1243dSDimitry Andric case CCValAssign::Full: 2128*bdd1243dSDimitry Andric case CCValAssign::Indirect: 2129*bdd1243dSDimitry Andric case CCValAssign::BCvt: 2130*bdd1243dSDimitry Andric ExtType = ISD::NON_EXTLOAD; 2131*bdd1243dSDimitry Andric break; 2132*bdd1243dSDimitry Andric } 2133*bdd1243dSDimitry Andric return DAG.getExtLoad( 2134*bdd1243dSDimitry Andric ExtType, DL, VA.getLocVT(), Chain, FIN, 2135*bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT); 2136*bdd1243dSDimitry Andric } 2137*bdd1243dSDimitry Andric 2138*bdd1243dSDimitry Andric static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, 2139*bdd1243dSDimitry Andric const CCValAssign &VA, const SDLoc &DL) { 2140*bdd1243dSDimitry Andric EVT LocVT = VA.getLocVT(); 2141*bdd1243dSDimitry Andric 2142*bdd1243dSDimitry Andric switch (VA.getLocInfo()) { 2143*bdd1243dSDimitry Andric default: 2144*bdd1243dSDimitry Andric llvm_unreachable("Unexpected CCValAssign::LocInfo"); 2145*bdd1243dSDimitry Andric case CCValAssign::Full: 2146*bdd1243dSDimitry Andric break; 2147*bdd1243dSDimitry Andric case CCValAssign::BCvt: 2148*bdd1243dSDimitry Andric if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) 2149*bdd1243dSDimitry Andric Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val); 2150*bdd1243dSDimitry Andric else 2151*bdd1243dSDimitry Andric Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val); 2152*bdd1243dSDimitry Andric break; 2153*bdd1243dSDimitry Andric } 2154*bdd1243dSDimitry Andric return Val; 2155*bdd1243dSDimitry Andric } 2156*bdd1243dSDimitry Andric 2157*bdd1243dSDimitry Andric static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, 2158*bdd1243dSDimitry Andric CCValAssign::LocInfo LocInfo, 2159*bdd1243dSDimitry Andric ISD::ArgFlagsTy ArgFlags, CCState &State) { 2160*bdd1243dSDimitry Andric if (LocVT == MVT::i32 || LocVT == MVT::i64) { 2161*bdd1243dSDimitry Andric // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim 2162*bdd1243dSDimitry Andric // s0 s1 s2 s3 s4 s5 s6 s7 s8 2163*bdd1243dSDimitry Andric static const MCPhysReg GPRList[] = { 2164*bdd1243dSDimitry Andric LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26, LoongArch::R27, 2165*bdd1243dSDimitry Andric LoongArch::R28, LoongArch::R29, LoongArch::R30, LoongArch::R31}; 2166*bdd1243dSDimitry Andric if (unsigned Reg = State.AllocateReg(GPRList)) { 2167*bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 2168*bdd1243dSDimitry Andric return false; 2169*bdd1243dSDimitry Andric } 2170*bdd1243dSDimitry Andric } 2171*bdd1243dSDimitry Andric 2172*bdd1243dSDimitry Andric if (LocVT == MVT::f32) { 2173*bdd1243dSDimitry Andric // Pass in STG registers: F1, F2, F3, F4 2174*bdd1243dSDimitry Andric // fs0,fs1,fs2,fs3 2175*bdd1243dSDimitry Andric static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25, 2176*bdd1243dSDimitry Andric LoongArch::F26, LoongArch::F27}; 2177*bdd1243dSDimitry Andric if (unsigned Reg = State.AllocateReg(FPR32List)) { 2178*bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 2179*bdd1243dSDimitry Andric return false; 2180*bdd1243dSDimitry Andric } 2181*bdd1243dSDimitry Andric } 2182*bdd1243dSDimitry Andric 2183*bdd1243dSDimitry Andric if (LocVT == MVT::f64) { 2184*bdd1243dSDimitry Andric // Pass in STG registers: D1, D2, D3, D4 2185*bdd1243dSDimitry Andric // fs4,fs5,fs6,fs7 2186*bdd1243dSDimitry Andric static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64, 2187*bdd1243dSDimitry Andric LoongArch::F30_64, LoongArch::F31_64}; 2188*bdd1243dSDimitry Andric if (unsigned Reg = State.AllocateReg(FPR64List)) { 2189*bdd1243dSDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 2190*bdd1243dSDimitry Andric return false; 2191*bdd1243dSDimitry Andric } 2192*bdd1243dSDimitry Andric } 2193*bdd1243dSDimitry Andric 2194*bdd1243dSDimitry Andric report_fatal_error("No registers left in GHC calling convention"); 2195*bdd1243dSDimitry Andric return true; 219681ad6265SDimitry Andric } 219781ad6265SDimitry Andric 219881ad6265SDimitry Andric // Transform physical registers into virtual registers. 219981ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerFormalArguments( 220081ad6265SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 220181ad6265SDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 220281ad6265SDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 220381ad6265SDimitry Andric 220481ad6265SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 220581ad6265SDimitry Andric 220681ad6265SDimitry Andric switch (CallConv) { 220781ad6265SDimitry Andric default: 220881ad6265SDimitry Andric llvm_unreachable("Unsupported calling convention"); 220981ad6265SDimitry Andric case CallingConv::C: 2210*bdd1243dSDimitry Andric case CallingConv::Fast: 221181ad6265SDimitry Andric break; 2212*bdd1243dSDimitry Andric case CallingConv::GHC: 2213*bdd1243dSDimitry Andric if (!MF.getSubtarget().getFeatureBits()[LoongArch::FeatureBasicF] || 2214*bdd1243dSDimitry Andric !MF.getSubtarget().getFeatureBits()[LoongArch::FeatureBasicD]) 2215*bdd1243dSDimitry Andric report_fatal_error( 2216*bdd1243dSDimitry Andric "GHC calling convention requires the F and D extensions"); 221781ad6265SDimitry Andric } 221881ad6265SDimitry Andric 2219*bdd1243dSDimitry Andric EVT PtrVT = getPointerTy(DAG.getDataLayout()); 2220*bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 2221*bdd1243dSDimitry Andric unsigned GRLenInBytes = Subtarget.getGRLen() / 8; 2222*bdd1243dSDimitry Andric // Used with varargs to acumulate store chains. 2223*bdd1243dSDimitry Andric std::vector<SDValue> OutChains; 2224*bdd1243dSDimitry Andric 222581ad6265SDimitry Andric // Assign locations to all of the incoming arguments. 222681ad6265SDimitry Andric SmallVector<CCValAssign> ArgLocs; 222781ad6265SDimitry Andric CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 222881ad6265SDimitry Andric 2229*bdd1243dSDimitry Andric if (CallConv == CallingConv::GHC) 2230*bdd1243dSDimitry Andric CCInfo.AnalyzeFormalArguments(Ins, CC_LoongArch_GHC); 2231*bdd1243dSDimitry Andric else 2232*bdd1243dSDimitry Andric analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch); 223381ad6265SDimitry Andric 2234*bdd1243dSDimitry Andric for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { 2235*bdd1243dSDimitry Andric CCValAssign &VA = ArgLocs[i]; 2236*bdd1243dSDimitry Andric SDValue ArgValue; 2237*bdd1243dSDimitry Andric if (VA.isRegLoc()) 2238*bdd1243dSDimitry Andric ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, *this); 2239*bdd1243dSDimitry Andric else 2240*bdd1243dSDimitry Andric ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL); 2241*bdd1243dSDimitry Andric if (VA.getLocInfo() == CCValAssign::Indirect) { 2242*bdd1243dSDimitry Andric // If the original argument was split and passed by reference, we need to 2243*bdd1243dSDimitry Andric // load all parts of it here (using the same address). 2244*bdd1243dSDimitry Andric InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue, 2245*bdd1243dSDimitry Andric MachinePointerInfo())); 2246*bdd1243dSDimitry Andric unsigned ArgIndex = Ins[i].OrigArgIndex; 2247*bdd1243dSDimitry Andric unsigned ArgPartOffset = Ins[i].PartOffset; 2248*bdd1243dSDimitry Andric assert(ArgPartOffset == 0); 2249*bdd1243dSDimitry Andric while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) { 2250*bdd1243dSDimitry Andric CCValAssign &PartVA = ArgLocs[i + 1]; 2251*bdd1243dSDimitry Andric unsigned PartOffset = Ins[i + 1].PartOffset - ArgPartOffset; 2252*bdd1243dSDimitry Andric SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL); 2253*bdd1243dSDimitry Andric SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset); 2254*bdd1243dSDimitry Andric InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address, 2255*bdd1243dSDimitry Andric MachinePointerInfo())); 2256*bdd1243dSDimitry Andric ++i; 2257*bdd1243dSDimitry Andric } 2258*bdd1243dSDimitry Andric continue; 2259*bdd1243dSDimitry Andric } 2260*bdd1243dSDimitry Andric InVals.push_back(ArgValue); 2261*bdd1243dSDimitry Andric } 2262*bdd1243dSDimitry Andric 2263*bdd1243dSDimitry Andric if (IsVarArg) { 2264*bdd1243dSDimitry Andric ArrayRef<MCPhysReg> ArgRegs = ArrayRef(ArgGPRs); 2265*bdd1243dSDimitry Andric unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs); 2266*bdd1243dSDimitry Andric const TargetRegisterClass *RC = &LoongArch::GPRRegClass; 2267*bdd1243dSDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 2268*bdd1243dSDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 2269*bdd1243dSDimitry Andric auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>(); 2270*bdd1243dSDimitry Andric 2271*bdd1243dSDimitry Andric // Offset of the first variable argument from stack pointer, and size of 2272*bdd1243dSDimitry Andric // the vararg save area. For now, the varargs save area is either zero or 2273*bdd1243dSDimitry Andric // large enough to hold a0-a7. 2274*bdd1243dSDimitry Andric int VaArgOffset, VarArgsSaveSize; 2275*bdd1243dSDimitry Andric 2276*bdd1243dSDimitry Andric // If all registers are allocated, then all varargs must be passed on the 2277*bdd1243dSDimitry Andric // stack and we don't need to save any argregs. 2278*bdd1243dSDimitry Andric if (ArgRegs.size() == Idx) { 2279*bdd1243dSDimitry Andric VaArgOffset = CCInfo.getNextStackOffset(); 2280*bdd1243dSDimitry Andric VarArgsSaveSize = 0; 2281*bdd1243dSDimitry Andric } else { 2282*bdd1243dSDimitry Andric VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx); 2283*bdd1243dSDimitry Andric VaArgOffset = -VarArgsSaveSize; 2284*bdd1243dSDimitry Andric } 2285*bdd1243dSDimitry Andric 2286*bdd1243dSDimitry Andric // Record the frame index of the first variable argument 2287*bdd1243dSDimitry Andric // which is a value necessary to VASTART. 2288*bdd1243dSDimitry Andric int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true); 2289*bdd1243dSDimitry Andric LoongArchFI->setVarArgsFrameIndex(FI); 2290*bdd1243dSDimitry Andric 2291*bdd1243dSDimitry Andric // If saving an odd number of registers then create an extra stack slot to 2292*bdd1243dSDimitry Andric // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures 2293*bdd1243dSDimitry Andric // offsets to even-numbered registered remain 2*GRLen-aligned. 2294*bdd1243dSDimitry Andric if (Idx % 2) { 2295*bdd1243dSDimitry Andric MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes, 2296*bdd1243dSDimitry Andric true); 2297*bdd1243dSDimitry Andric VarArgsSaveSize += GRLenInBytes; 2298*bdd1243dSDimitry Andric } 2299*bdd1243dSDimitry Andric 2300*bdd1243dSDimitry Andric // Copy the integer registers that may have been used for passing varargs 2301*bdd1243dSDimitry Andric // to the vararg save area. 2302*bdd1243dSDimitry Andric for (unsigned I = Idx; I < ArgRegs.size(); 2303*bdd1243dSDimitry Andric ++I, VaArgOffset += GRLenInBytes) { 2304*bdd1243dSDimitry Andric const Register Reg = RegInfo.createVirtualRegister(RC); 2305*bdd1243dSDimitry Andric RegInfo.addLiveIn(ArgRegs[I], Reg); 2306*bdd1243dSDimitry Andric SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT); 2307*bdd1243dSDimitry Andric FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true); 2308*bdd1243dSDimitry Andric SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 2309*bdd1243dSDimitry Andric SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff, 2310*bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(MF, FI)); 2311*bdd1243dSDimitry Andric cast<StoreSDNode>(Store.getNode()) 2312*bdd1243dSDimitry Andric ->getMemOperand() 2313*bdd1243dSDimitry Andric ->setValue((Value *)nullptr); 2314*bdd1243dSDimitry Andric OutChains.push_back(Store); 2315*bdd1243dSDimitry Andric } 2316*bdd1243dSDimitry Andric LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize); 2317*bdd1243dSDimitry Andric } 2318*bdd1243dSDimitry Andric 2319*bdd1243dSDimitry Andric // All stores are grouped in one node to allow the matching between 2320*bdd1243dSDimitry Andric // the size of Ins and InVals. This only happens for vararg functions. 2321*bdd1243dSDimitry Andric if (!OutChains.empty()) { 2322*bdd1243dSDimitry Andric OutChains.push_back(Chain); 2323*bdd1243dSDimitry Andric Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); 2324*bdd1243dSDimitry Andric } 232581ad6265SDimitry Andric 232681ad6265SDimitry Andric return Chain; 232781ad6265SDimitry Andric } 232881ad6265SDimitry Andric 2329*bdd1243dSDimitry Andric bool LoongArchTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const { 2330*bdd1243dSDimitry Andric return CI->isTailCall(); 2331*bdd1243dSDimitry Andric } 2332*bdd1243dSDimitry Andric 2333*bdd1243dSDimitry Andric // Check whether the call is eligible for tail call optimization. 2334*bdd1243dSDimitry Andric bool LoongArchTargetLowering::isEligibleForTailCallOptimization( 2335*bdd1243dSDimitry Andric CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF, 2336*bdd1243dSDimitry Andric const SmallVectorImpl<CCValAssign> &ArgLocs) const { 2337*bdd1243dSDimitry Andric 2338*bdd1243dSDimitry Andric auto CalleeCC = CLI.CallConv; 2339*bdd1243dSDimitry Andric auto &Outs = CLI.Outs; 2340*bdd1243dSDimitry Andric auto &Caller = MF.getFunction(); 2341*bdd1243dSDimitry Andric auto CallerCC = Caller.getCallingConv(); 2342*bdd1243dSDimitry Andric 2343*bdd1243dSDimitry Andric // Do not tail call opt if the stack is used to pass parameters. 2344*bdd1243dSDimitry Andric if (CCInfo.getNextStackOffset() != 0) 2345*bdd1243dSDimitry Andric return false; 2346*bdd1243dSDimitry Andric 2347*bdd1243dSDimitry Andric // Do not tail call opt if any parameters need to be passed indirectly. 2348*bdd1243dSDimitry Andric for (auto &VA : ArgLocs) 2349*bdd1243dSDimitry Andric if (VA.getLocInfo() == CCValAssign::Indirect) 2350*bdd1243dSDimitry Andric return false; 2351*bdd1243dSDimitry Andric 2352*bdd1243dSDimitry Andric // Do not tail call opt if either caller or callee uses struct return 2353*bdd1243dSDimitry Andric // semantics. 2354*bdd1243dSDimitry Andric auto IsCallerStructRet = Caller.hasStructRetAttr(); 2355*bdd1243dSDimitry Andric auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet(); 2356*bdd1243dSDimitry Andric if (IsCallerStructRet || IsCalleeStructRet) 2357*bdd1243dSDimitry Andric return false; 2358*bdd1243dSDimitry Andric 2359*bdd1243dSDimitry Andric // Do not tail call opt if either the callee or caller has a byval argument. 2360*bdd1243dSDimitry Andric for (auto &Arg : Outs) 2361*bdd1243dSDimitry Andric if (Arg.Flags.isByVal()) 2362*bdd1243dSDimitry Andric return false; 2363*bdd1243dSDimitry Andric 2364*bdd1243dSDimitry Andric // The callee has to preserve all registers the caller needs to preserve. 2365*bdd1243dSDimitry Andric const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo(); 2366*bdd1243dSDimitry Andric const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC); 2367*bdd1243dSDimitry Andric if (CalleeCC != CallerCC) { 2368*bdd1243dSDimitry Andric const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC); 2369*bdd1243dSDimitry Andric if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved)) 2370*bdd1243dSDimitry Andric return false; 2371*bdd1243dSDimitry Andric } 2372*bdd1243dSDimitry Andric return true; 2373*bdd1243dSDimitry Andric } 2374*bdd1243dSDimitry Andric 2375*bdd1243dSDimitry Andric static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG) { 2376*bdd1243dSDimitry Andric return DAG.getDataLayout().getPrefTypeAlign( 2377*bdd1243dSDimitry Andric VT.getTypeForEVT(*DAG.getContext())); 2378*bdd1243dSDimitry Andric } 2379*bdd1243dSDimitry Andric 2380753f127fSDimitry Andric // Lower a call to a callseq_start + CALL + callseq_end chain, and add input 2381753f127fSDimitry Andric // and output parameter nodes. 2382753f127fSDimitry Andric SDValue 2383753f127fSDimitry Andric LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI, 2384753f127fSDimitry Andric SmallVectorImpl<SDValue> &InVals) const { 2385753f127fSDimitry Andric SelectionDAG &DAG = CLI.DAG; 2386753f127fSDimitry Andric SDLoc &DL = CLI.DL; 2387753f127fSDimitry Andric SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; 2388753f127fSDimitry Andric SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; 2389753f127fSDimitry Andric SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; 2390753f127fSDimitry Andric SDValue Chain = CLI.Chain; 2391753f127fSDimitry Andric SDValue Callee = CLI.Callee; 2392753f127fSDimitry Andric CallingConv::ID CallConv = CLI.CallConv; 2393753f127fSDimitry Andric bool IsVarArg = CLI.IsVarArg; 2394753f127fSDimitry Andric EVT PtrVT = getPointerTy(DAG.getDataLayout()); 2395*bdd1243dSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 2396*bdd1243dSDimitry Andric bool &IsTailCall = CLI.IsTailCall; 2397753f127fSDimitry Andric 2398753f127fSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 2399753f127fSDimitry Andric 2400753f127fSDimitry Andric // Analyze the operands of the call, assigning locations to each operand. 2401753f127fSDimitry Andric SmallVector<CCValAssign> ArgLocs; 2402753f127fSDimitry Andric CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 2403753f127fSDimitry Andric 2404*bdd1243dSDimitry Andric if (CallConv == CallingConv::GHC) 2405*bdd1243dSDimitry Andric ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC); 2406*bdd1243dSDimitry Andric else 2407*bdd1243dSDimitry Andric analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch); 2408*bdd1243dSDimitry Andric 2409*bdd1243dSDimitry Andric // Check if it's really possible to do a tail call. 2410*bdd1243dSDimitry Andric if (IsTailCall) 2411*bdd1243dSDimitry Andric IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs); 2412*bdd1243dSDimitry Andric 2413*bdd1243dSDimitry Andric if (IsTailCall) 2414*bdd1243dSDimitry Andric ++NumTailCalls; 2415*bdd1243dSDimitry Andric else if (CLI.CB && CLI.CB->isMustTailCall()) 2416*bdd1243dSDimitry Andric report_fatal_error("failed to perform tail call elimination on a call " 2417*bdd1243dSDimitry Andric "site marked musttail"); 2418753f127fSDimitry Andric 2419753f127fSDimitry Andric // Get a count of how many bytes are to be pushed on the stack. 2420753f127fSDimitry Andric unsigned NumBytes = ArgCCInfo.getNextStackOffset(); 2421753f127fSDimitry Andric 2422*bdd1243dSDimitry Andric // Create local copies for byval args. 2423*bdd1243dSDimitry Andric SmallVector<SDValue> ByValArgs; 2424*bdd1243dSDimitry Andric for (unsigned i = 0, e = Outs.size(); i != e; ++i) { 2425*bdd1243dSDimitry Andric ISD::ArgFlagsTy Flags = Outs[i].Flags; 2426*bdd1243dSDimitry Andric if (!Flags.isByVal()) 2427753f127fSDimitry Andric continue; 2428*bdd1243dSDimitry Andric 2429*bdd1243dSDimitry Andric SDValue Arg = OutVals[i]; 2430*bdd1243dSDimitry Andric unsigned Size = Flags.getByValSize(); 2431*bdd1243dSDimitry Andric Align Alignment = Flags.getNonZeroByValAlign(); 2432*bdd1243dSDimitry Andric 2433*bdd1243dSDimitry Andric int FI = 2434*bdd1243dSDimitry Andric MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false); 2435*bdd1243dSDimitry Andric SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 2436*bdd1243dSDimitry Andric SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT); 2437*bdd1243dSDimitry Andric 2438*bdd1243dSDimitry Andric Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment, 2439*bdd1243dSDimitry Andric /*IsVolatile=*/false, 2440*bdd1243dSDimitry Andric /*AlwaysInline=*/false, /*isTailCall=*/IsTailCall, 2441*bdd1243dSDimitry Andric MachinePointerInfo(), MachinePointerInfo()); 2442*bdd1243dSDimitry Andric ByValArgs.push_back(FIPtr); 2443753f127fSDimitry Andric } 2444753f127fSDimitry Andric 2445*bdd1243dSDimitry Andric if (!IsTailCall) 2446753f127fSDimitry Andric Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL); 2447753f127fSDimitry Andric 2448753f127fSDimitry Andric // Copy argument values to their designated locations. 2449753f127fSDimitry Andric SmallVector<std::pair<Register, SDValue>> RegsToPass; 2450*bdd1243dSDimitry Andric SmallVector<SDValue> MemOpChains; 2451*bdd1243dSDimitry Andric SDValue StackPtr; 2452*bdd1243dSDimitry Andric for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) { 2453753f127fSDimitry Andric CCValAssign &VA = ArgLocs[i]; 2454753f127fSDimitry Andric SDValue ArgValue = OutVals[i]; 2455*bdd1243dSDimitry Andric ISD::ArgFlagsTy Flags = Outs[i].Flags; 2456753f127fSDimitry Andric 2457753f127fSDimitry Andric // Promote the value if needed. 2458*bdd1243dSDimitry Andric // For now, only handle fully promoted and indirect arguments. 2459*bdd1243dSDimitry Andric if (VA.getLocInfo() == CCValAssign::Indirect) { 2460*bdd1243dSDimitry Andric // Store the argument in a stack slot and pass its address. 2461*bdd1243dSDimitry Andric Align StackAlign = 2462*bdd1243dSDimitry Andric std::max(getPrefTypeAlign(Outs[i].ArgVT, DAG), 2463*bdd1243dSDimitry Andric getPrefTypeAlign(ArgValue.getValueType(), DAG)); 2464*bdd1243dSDimitry Andric TypeSize StoredSize = ArgValue.getValueType().getStoreSize(); 2465*bdd1243dSDimitry Andric // If the original argument was split and passed by reference, we need to 2466*bdd1243dSDimitry Andric // store the required parts of it here (and pass just one address). 2467*bdd1243dSDimitry Andric unsigned ArgIndex = Outs[i].OrigArgIndex; 2468*bdd1243dSDimitry Andric unsigned ArgPartOffset = Outs[i].PartOffset; 2469*bdd1243dSDimitry Andric assert(ArgPartOffset == 0); 2470*bdd1243dSDimitry Andric // Calculate the total size to store. We don't have access to what we're 2471*bdd1243dSDimitry Andric // actually storing other than performing the loop and collecting the 2472*bdd1243dSDimitry Andric // info. 2473*bdd1243dSDimitry Andric SmallVector<std::pair<SDValue, SDValue>> Parts; 2474*bdd1243dSDimitry Andric while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) { 2475*bdd1243dSDimitry Andric SDValue PartValue = OutVals[i + 1]; 2476*bdd1243dSDimitry Andric unsigned PartOffset = Outs[i + 1].PartOffset - ArgPartOffset; 2477*bdd1243dSDimitry Andric SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL); 2478*bdd1243dSDimitry Andric EVT PartVT = PartValue.getValueType(); 2479*bdd1243dSDimitry Andric 2480*bdd1243dSDimitry Andric StoredSize += PartVT.getStoreSize(); 2481*bdd1243dSDimitry Andric StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG)); 2482*bdd1243dSDimitry Andric Parts.push_back(std::make_pair(PartValue, Offset)); 2483*bdd1243dSDimitry Andric ++i; 2484*bdd1243dSDimitry Andric } 2485*bdd1243dSDimitry Andric SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign); 2486*bdd1243dSDimitry Andric int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex(); 2487*bdd1243dSDimitry Andric MemOpChains.push_back( 2488*bdd1243dSDimitry Andric DAG.getStore(Chain, DL, ArgValue, SpillSlot, 2489*bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(MF, FI))); 2490*bdd1243dSDimitry Andric for (const auto &Part : Parts) { 2491*bdd1243dSDimitry Andric SDValue PartValue = Part.first; 2492*bdd1243dSDimitry Andric SDValue PartOffset = Part.second; 2493*bdd1243dSDimitry Andric SDValue Address = 2494*bdd1243dSDimitry Andric DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset); 2495*bdd1243dSDimitry Andric MemOpChains.push_back( 2496*bdd1243dSDimitry Andric DAG.getStore(Chain, DL, PartValue, Address, 2497*bdd1243dSDimitry Andric MachinePointerInfo::getFixedStack(MF, FI))); 2498*bdd1243dSDimitry Andric } 2499*bdd1243dSDimitry Andric ArgValue = SpillSlot; 2500*bdd1243dSDimitry Andric } else { 2501*bdd1243dSDimitry Andric ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL); 2502*bdd1243dSDimitry Andric } 2503*bdd1243dSDimitry Andric 2504*bdd1243dSDimitry Andric // Use local copy if it is a byval arg. 2505*bdd1243dSDimitry Andric if (Flags.isByVal()) 2506*bdd1243dSDimitry Andric ArgValue = ByValArgs[j++]; 2507753f127fSDimitry Andric 2508753f127fSDimitry Andric if (VA.isRegLoc()) { 2509753f127fSDimitry Andric // Queue up the argument copies and emit them at the end. 2510753f127fSDimitry Andric RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); 2511753f127fSDimitry Andric } else { 2512*bdd1243dSDimitry Andric assert(VA.isMemLoc() && "Argument not register or memory"); 2513*bdd1243dSDimitry Andric assert(!IsTailCall && "Tail call not allowed if stack is used " 2514*bdd1243dSDimitry Andric "for passing parameters"); 2515*bdd1243dSDimitry Andric 2516*bdd1243dSDimitry Andric // Work out the address of the stack slot. 2517*bdd1243dSDimitry Andric if (!StackPtr.getNode()) 2518*bdd1243dSDimitry Andric StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT); 2519*bdd1243dSDimitry Andric SDValue Address = 2520*bdd1243dSDimitry Andric DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, 2521*bdd1243dSDimitry Andric DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); 2522*bdd1243dSDimitry Andric 2523*bdd1243dSDimitry Andric // Emit the store. 2524*bdd1243dSDimitry Andric MemOpChains.push_back( 2525*bdd1243dSDimitry Andric DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo())); 2526753f127fSDimitry Andric } 2527753f127fSDimitry Andric } 2528753f127fSDimitry Andric 2529*bdd1243dSDimitry Andric // Join the stores, which are independent of one another. 2530*bdd1243dSDimitry Andric if (!MemOpChains.empty()) 2531*bdd1243dSDimitry Andric Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); 2532*bdd1243dSDimitry Andric 2533753f127fSDimitry Andric SDValue Glue; 2534753f127fSDimitry Andric 2535753f127fSDimitry Andric // Build a sequence of copy-to-reg nodes, chained and glued together. 2536753f127fSDimitry Andric for (auto &Reg : RegsToPass) { 2537753f127fSDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue); 2538753f127fSDimitry Andric Glue = Chain.getValue(1); 2539753f127fSDimitry Andric } 2540753f127fSDimitry Andric 2541753f127fSDimitry Andric // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a 2542753f127fSDimitry Andric // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't 2543753f127fSDimitry Andric // split it and then direct call can be matched by PseudoCALL. 2544*bdd1243dSDimitry Andric if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) { 2545*bdd1243dSDimitry Andric const GlobalValue *GV = S->getGlobal(); 2546*bdd1243dSDimitry Andric unsigned OpFlags = 2547*bdd1243dSDimitry Andric getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV) 2548*bdd1243dSDimitry Andric ? LoongArchII::MO_CALL 2549*bdd1243dSDimitry Andric : LoongArchII::MO_CALL_PLT; 2550*bdd1243dSDimitry Andric Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags); 2551*bdd1243dSDimitry Andric } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { 2552*bdd1243dSDimitry Andric unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal( 2553*bdd1243dSDimitry Andric *MF.getFunction().getParent(), nullptr) 2554*bdd1243dSDimitry Andric ? LoongArchII::MO_CALL 2555*bdd1243dSDimitry Andric : LoongArchII::MO_CALL_PLT; 2556*bdd1243dSDimitry Andric Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags); 2557*bdd1243dSDimitry Andric } 2558753f127fSDimitry Andric 2559753f127fSDimitry Andric // The first call operand is the chain and the second is the target address. 2560753f127fSDimitry Andric SmallVector<SDValue> Ops; 2561753f127fSDimitry Andric Ops.push_back(Chain); 2562753f127fSDimitry Andric Ops.push_back(Callee); 2563753f127fSDimitry Andric 2564753f127fSDimitry Andric // Add argument registers to the end of the list so that they are 2565753f127fSDimitry Andric // known live into the call. 2566753f127fSDimitry Andric for (auto &Reg : RegsToPass) 2567753f127fSDimitry Andric Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType())); 2568753f127fSDimitry Andric 2569*bdd1243dSDimitry Andric if (!IsTailCall) { 2570753f127fSDimitry Andric // Add a register mask operand representing the call-preserved registers. 2571753f127fSDimitry Andric const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); 2572753f127fSDimitry Andric const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv); 2573753f127fSDimitry Andric assert(Mask && "Missing call preserved mask for calling convention"); 2574753f127fSDimitry Andric Ops.push_back(DAG.getRegisterMask(Mask)); 2575*bdd1243dSDimitry Andric } 2576753f127fSDimitry Andric 2577753f127fSDimitry Andric // Glue the call to the argument copies, if any. 2578753f127fSDimitry Andric if (Glue.getNode()) 2579753f127fSDimitry Andric Ops.push_back(Glue); 2580753f127fSDimitry Andric 2581753f127fSDimitry Andric // Emit the call. 2582753f127fSDimitry Andric SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); 2583753f127fSDimitry Andric 2584*bdd1243dSDimitry Andric if (IsTailCall) { 2585*bdd1243dSDimitry Andric MF.getFrameInfo().setHasTailCall(); 2586*bdd1243dSDimitry Andric return DAG.getNode(LoongArchISD::TAIL, DL, NodeTys, Ops); 2587*bdd1243dSDimitry Andric } 2588*bdd1243dSDimitry Andric 2589753f127fSDimitry Andric Chain = DAG.getNode(LoongArchISD::CALL, DL, NodeTys, Ops); 2590753f127fSDimitry Andric DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge); 2591753f127fSDimitry Andric Glue = Chain.getValue(1); 2592753f127fSDimitry Andric 2593753f127fSDimitry Andric // Mark the end of the call, which is glued to the call itself. 2594*bdd1243dSDimitry Andric Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL); 2595753f127fSDimitry Andric Glue = Chain.getValue(1); 2596753f127fSDimitry Andric 2597753f127fSDimitry Andric // Assign locations to each value returned by this call. 2598753f127fSDimitry Andric SmallVector<CCValAssign> RVLocs; 2599753f127fSDimitry Andric CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); 2600*bdd1243dSDimitry Andric analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch); 2601753f127fSDimitry Andric 2602753f127fSDimitry Andric // Copy all of the result registers out of their specified physreg. 2603753f127fSDimitry Andric for (auto &VA : RVLocs) { 2604753f127fSDimitry Andric // Copy the value out. 2605753f127fSDimitry Andric SDValue RetValue = 2606753f127fSDimitry Andric DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue); 2607*bdd1243dSDimitry Andric // Glue the RetValue to the end of the call sequence. 2608753f127fSDimitry Andric Chain = RetValue.getValue(1); 2609753f127fSDimitry Andric Glue = RetValue.getValue(2); 2610753f127fSDimitry Andric 2611*bdd1243dSDimitry Andric RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL); 2612*bdd1243dSDimitry Andric 2613*bdd1243dSDimitry Andric InVals.push_back(RetValue); 2614753f127fSDimitry Andric } 2615753f127fSDimitry Andric 2616753f127fSDimitry Andric return Chain; 2617753f127fSDimitry Andric } 2618753f127fSDimitry Andric 261981ad6265SDimitry Andric bool LoongArchTargetLowering::CanLowerReturn( 262081ad6265SDimitry Andric CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, 262181ad6265SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { 2622*bdd1243dSDimitry Andric SmallVector<CCValAssign> RVLocs; 2623*bdd1243dSDimitry Andric CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); 2624*bdd1243dSDimitry Andric 2625*bdd1243dSDimitry Andric for (unsigned i = 0, e = Outs.size(); i != e; ++i) { 2626*bdd1243dSDimitry Andric LoongArchABI::ABI ABI = 2627*bdd1243dSDimitry Andric MF.getSubtarget<LoongArchSubtarget>().getTargetABI(); 2628*bdd1243dSDimitry Andric if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full, 2629*bdd1243dSDimitry Andric Outs[i].Flags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true, 2630*bdd1243dSDimitry Andric nullptr)) 2631*bdd1243dSDimitry Andric return false; 2632*bdd1243dSDimitry Andric } 2633*bdd1243dSDimitry Andric return true; 263481ad6265SDimitry Andric } 263581ad6265SDimitry Andric 263681ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerReturn( 263781ad6265SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 263881ad6265SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, 263981ad6265SDimitry Andric const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, 264081ad6265SDimitry Andric SelectionDAG &DAG) const { 264181ad6265SDimitry Andric // Stores the assignment of the return value to a location. 264281ad6265SDimitry Andric SmallVector<CCValAssign> RVLocs; 264381ad6265SDimitry Andric 264481ad6265SDimitry Andric // Info about the registers and stack slot. 264581ad6265SDimitry Andric CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, 264681ad6265SDimitry Andric *DAG.getContext()); 264781ad6265SDimitry Andric 2648*bdd1243dSDimitry Andric analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true, 2649*bdd1243dSDimitry Andric nullptr, CC_LoongArch); 2650*bdd1243dSDimitry Andric if (CallConv == CallingConv::GHC && !RVLocs.empty()) 2651*bdd1243dSDimitry Andric report_fatal_error("GHC functions return void only"); 265281ad6265SDimitry Andric SDValue Glue; 265381ad6265SDimitry Andric SmallVector<SDValue, 4> RetOps(1, Chain); 265481ad6265SDimitry Andric 265581ad6265SDimitry Andric // Copy the result values into the output registers. 265681ad6265SDimitry Andric for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) { 265781ad6265SDimitry Andric CCValAssign &VA = RVLocs[i]; 265881ad6265SDimitry Andric assert(VA.isRegLoc() && "Can only return in registers!"); 265981ad6265SDimitry Andric 266081ad6265SDimitry Andric // Handle a 'normal' return. 2661*bdd1243dSDimitry Andric SDValue Val = convertValVTToLocVT(DAG, OutVals[i], VA, DL); 2662*bdd1243dSDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue); 266381ad6265SDimitry Andric 266481ad6265SDimitry Andric // Guarantee that all emitted copies are stuck together. 266581ad6265SDimitry Andric Glue = Chain.getValue(1); 266681ad6265SDimitry Andric RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); 266781ad6265SDimitry Andric } 266881ad6265SDimitry Andric 266981ad6265SDimitry Andric RetOps[0] = Chain; // Update chain. 267081ad6265SDimitry Andric 267181ad6265SDimitry Andric // Add the glue node if we have it. 267281ad6265SDimitry Andric if (Glue.getNode()) 267381ad6265SDimitry Andric RetOps.push_back(Glue); 267481ad6265SDimitry Andric 267581ad6265SDimitry Andric return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps); 267681ad6265SDimitry Andric } 2677753f127fSDimitry Andric 2678753f127fSDimitry Andric bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, 2679753f127fSDimitry Andric bool ForCodeSize) const { 2680*bdd1243dSDimitry Andric // TODO: Maybe need more checks here after vector extension is supported. 2681753f127fSDimitry Andric if (VT == MVT::f32 && !Subtarget.hasBasicF()) 2682753f127fSDimitry Andric return false; 2683753f127fSDimitry Andric if (VT == MVT::f64 && !Subtarget.hasBasicD()) 2684753f127fSDimitry Andric return false; 2685753f127fSDimitry Andric return (Imm.isZero() || Imm.isExactlyValue(+1.0)); 2686753f127fSDimitry Andric } 2687*bdd1243dSDimitry Andric 2688*bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCttz(Type *) const { 2689*bdd1243dSDimitry Andric return true; 2690*bdd1243dSDimitry Andric } 2691*bdd1243dSDimitry Andric 2692*bdd1243dSDimitry Andric bool LoongArchTargetLowering::isCheapToSpeculateCtlz(Type *) const { 2693*bdd1243dSDimitry Andric return true; 2694*bdd1243dSDimitry Andric } 2695*bdd1243dSDimitry Andric 2696*bdd1243dSDimitry Andric bool LoongArchTargetLowering::shouldInsertFencesForAtomic( 2697*bdd1243dSDimitry Andric const Instruction *I) const { 2698*bdd1243dSDimitry Andric if (!Subtarget.is64Bit()) 2699*bdd1243dSDimitry Andric return isa<LoadInst>(I) || isa<StoreInst>(I); 2700*bdd1243dSDimitry Andric 2701*bdd1243dSDimitry Andric if (isa<LoadInst>(I)) 2702*bdd1243dSDimitry Andric return true; 2703*bdd1243dSDimitry Andric 2704*bdd1243dSDimitry Andric // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not 2705*bdd1243dSDimitry Andric // require fences beacuse we can use amswap_db.[w/d]. 2706*bdd1243dSDimitry Andric if (isa<StoreInst>(I)) { 2707*bdd1243dSDimitry Andric unsigned Size = I->getOperand(0)->getType()->getIntegerBitWidth(); 2708*bdd1243dSDimitry Andric return (Size == 8 || Size == 16); 2709*bdd1243dSDimitry Andric } 2710*bdd1243dSDimitry Andric 2711*bdd1243dSDimitry Andric return false; 2712*bdd1243dSDimitry Andric } 2713*bdd1243dSDimitry Andric 2714*bdd1243dSDimitry Andric EVT LoongArchTargetLowering::getSetCCResultType(const DataLayout &DL, 2715*bdd1243dSDimitry Andric LLVMContext &Context, 2716*bdd1243dSDimitry Andric EVT VT) const { 2717*bdd1243dSDimitry Andric if (!VT.isVector()) 2718*bdd1243dSDimitry Andric return getPointerTy(DL); 2719*bdd1243dSDimitry Andric return VT.changeVectorElementTypeToInteger(); 2720*bdd1243dSDimitry Andric } 2721*bdd1243dSDimitry Andric 2722*bdd1243dSDimitry Andric bool LoongArchTargetLowering::hasAndNot(SDValue Y) const { 2723*bdd1243dSDimitry Andric // TODO: Support vectors. 2724*bdd1243dSDimitry Andric return Y.getValueType().isScalarInteger() && !isa<ConstantSDNode>(Y); 2725*bdd1243dSDimitry Andric } 2726*bdd1243dSDimitry Andric 2727*bdd1243dSDimitry Andric bool LoongArchTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, 2728*bdd1243dSDimitry Andric const CallInst &I, 2729*bdd1243dSDimitry Andric MachineFunction &MF, 2730*bdd1243dSDimitry Andric unsigned Intrinsic) const { 2731*bdd1243dSDimitry Andric switch (Intrinsic) { 2732*bdd1243dSDimitry Andric default: 2733*bdd1243dSDimitry Andric return false; 2734*bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_xchg_i32: 2735*bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_add_i32: 2736*bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_sub_i32: 2737*bdd1243dSDimitry Andric case Intrinsic::loongarch_masked_atomicrmw_nand_i32: 2738*bdd1243dSDimitry Andric Info.opc = ISD::INTRINSIC_W_CHAIN; 2739*bdd1243dSDimitry Andric Info.memVT = MVT::i32; 2740*bdd1243dSDimitry Andric Info.ptrVal = I.getArgOperand(0); 2741*bdd1243dSDimitry Andric Info.offset = 0; 2742*bdd1243dSDimitry Andric Info.align = Align(4); 2743*bdd1243dSDimitry Andric Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore | 2744*bdd1243dSDimitry Andric MachineMemOperand::MOVolatile; 2745*bdd1243dSDimitry Andric return true; 2746*bdd1243dSDimitry Andric // TODO: Add more Intrinsics later. 2747*bdd1243dSDimitry Andric } 2748*bdd1243dSDimitry Andric } 2749*bdd1243dSDimitry Andric 2750*bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind 2751*bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { 2752*bdd1243dSDimitry Andric // TODO: Add more AtomicRMWInst that needs to be extended. 2753*bdd1243dSDimitry Andric 2754*bdd1243dSDimitry Andric // Since floating-point operation requires a non-trivial set of data 2755*bdd1243dSDimitry Andric // operations, use CmpXChg to expand. 2756*bdd1243dSDimitry Andric if (AI->isFloatingPointOperation() || 2757*bdd1243dSDimitry Andric AI->getOperation() == AtomicRMWInst::UIncWrap || 2758*bdd1243dSDimitry Andric AI->getOperation() == AtomicRMWInst::UDecWrap) 2759*bdd1243dSDimitry Andric return AtomicExpansionKind::CmpXChg; 2760*bdd1243dSDimitry Andric 2761*bdd1243dSDimitry Andric unsigned Size = AI->getType()->getPrimitiveSizeInBits(); 2762*bdd1243dSDimitry Andric if (Size == 8 || Size == 16) 2763*bdd1243dSDimitry Andric return AtomicExpansionKind::MaskedIntrinsic; 2764*bdd1243dSDimitry Andric return AtomicExpansionKind::None; 2765*bdd1243dSDimitry Andric } 2766*bdd1243dSDimitry Andric 2767*bdd1243dSDimitry Andric static Intrinsic::ID 2768*bdd1243dSDimitry Andric getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen, 2769*bdd1243dSDimitry Andric AtomicRMWInst::BinOp BinOp) { 2770*bdd1243dSDimitry Andric if (GRLen == 64) { 2771*bdd1243dSDimitry Andric switch (BinOp) { 2772*bdd1243dSDimitry Andric default: 2773*bdd1243dSDimitry Andric llvm_unreachable("Unexpected AtomicRMW BinOp"); 2774*bdd1243dSDimitry Andric case AtomicRMWInst::Xchg: 2775*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_xchg_i64; 2776*bdd1243dSDimitry Andric case AtomicRMWInst::Add: 2777*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_add_i64; 2778*bdd1243dSDimitry Andric case AtomicRMWInst::Sub: 2779*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_sub_i64; 2780*bdd1243dSDimitry Andric case AtomicRMWInst::Nand: 2781*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_nand_i64; 2782*bdd1243dSDimitry Andric case AtomicRMWInst::UMax: 2783*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_umax_i64; 2784*bdd1243dSDimitry Andric case AtomicRMWInst::UMin: 2785*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_umin_i64; 2786*bdd1243dSDimitry Andric case AtomicRMWInst::Max: 2787*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_max_i64; 2788*bdd1243dSDimitry Andric case AtomicRMWInst::Min: 2789*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_min_i64; 2790*bdd1243dSDimitry Andric // TODO: support other AtomicRMWInst. 2791*bdd1243dSDimitry Andric } 2792*bdd1243dSDimitry Andric } 2793*bdd1243dSDimitry Andric 2794*bdd1243dSDimitry Andric if (GRLen == 32) { 2795*bdd1243dSDimitry Andric switch (BinOp) { 2796*bdd1243dSDimitry Andric default: 2797*bdd1243dSDimitry Andric llvm_unreachable("Unexpected AtomicRMW BinOp"); 2798*bdd1243dSDimitry Andric case AtomicRMWInst::Xchg: 2799*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_xchg_i32; 2800*bdd1243dSDimitry Andric case AtomicRMWInst::Add: 2801*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_add_i32; 2802*bdd1243dSDimitry Andric case AtomicRMWInst::Sub: 2803*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_sub_i32; 2804*bdd1243dSDimitry Andric case AtomicRMWInst::Nand: 2805*bdd1243dSDimitry Andric return Intrinsic::loongarch_masked_atomicrmw_nand_i32; 2806*bdd1243dSDimitry Andric // TODO: support other AtomicRMWInst. 2807*bdd1243dSDimitry Andric } 2808*bdd1243dSDimitry Andric } 2809*bdd1243dSDimitry Andric 2810*bdd1243dSDimitry Andric llvm_unreachable("Unexpected GRLen\n"); 2811*bdd1243dSDimitry Andric } 2812*bdd1243dSDimitry Andric 2813*bdd1243dSDimitry Andric TargetLowering::AtomicExpansionKind 2814*bdd1243dSDimitry Andric LoongArchTargetLowering::shouldExpandAtomicCmpXchgInIR( 2815*bdd1243dSDimitry Andric AtomicCmpXchgInst *CI) const { 2816*bdd1243dSDimitry Andric unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits(); 2817*bdd1243dSDimitry Andric if (Size == 8 || Size == 16) 2818*bdd1243dSDimitry Andric return AtomicExpansionKind::MaskedIntrinsic; 2819*bdd1243dSDimitry Andric return AtomicExpansionKind::None; 2820*bdd1243dSDimitry Andric } 2821*bdd1243dSDimitry Andric 2822*bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicCmpXchgIntrinsic( 2823*bdd1243dSDimitry Andric IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, 2824*bdd1243dSDimitry Andric Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const { 2825*bdd1243dSDimitry Andric Value *Ordering = 2826*bdd1243dSDimitry Andric Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(Ord)); 2827*bdd1243dSDimitry Andric 2828*bdd1243dSDimitry Andric // TODO: Support cmpxchg on LA32. 2829*bdd1243dSDimitry Andric Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64; 2830*bdd1243dSDimitry Andric CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty()); 2831*bdd1243dSDimitry Andric NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty()); 2832*bdd1243dSDimitry Andric Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty()); 2833*bdd1243dSDimitry Andric Type *Tys[] = {AlignedAddr->getType()}; 2834*bdd1243dSDimitry Andric Function *MaskedCmpXchg = 2835*bdd1243dSDimitry Andric Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys); 2836*bdd1243dSDimitry Andric Value *Result = Builder.CreateCall( 2837*bdd1243dSDimitry Andric MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, Ordering}); 2838*bdd1243dSDimitry Andric Result = Builder.CreateTrunc(Result, Builder.getInt32Ty()); 2839*bdd1243dSDimitry Andric return Result; 2840*bdd1243dSDimitry Andric } 2841*bdd1243dSDimitry Andric 2842*bdd1243dSDimitry Andric Value *LoongArchTargetLowering::emitMaskedAtomicRMWIntrinsic( 2843*bdd1243dSDimitry Andric IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr, 2844*bdd1243dSDimitry Andric Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const { 2845*bdd1243dSDimitry Andric unsigned GRLen = Subtarget.getGRLen(); 2846*bdd1243dSDimitry Andric Value *Ordering = 2847*bdd1243dSDimitry Andric Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering())); 2848*bdd1243dSDimitry Andric Type *Tys[] = {AlignedAddr->getType()}; 2849*bdd1243dSDimitry Andric Function *LlwOpScwLoop = Intrinsic::getDeclaration( 2850*bdd1243dSDimitry Andric AI->getModule(), 2851*bdd1243dSDimitry Andric getIntrinsicForMaskedAtomicRMWBinOp(GRLen, AI->getOperation()), Tys); 2852*bdd1243dSDimitry Andric 2853*bdd1243dSDimitry Andric if (GRLen == 64) { 2854*bdd1243dSDimitry Andric Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty()); 2855*bdd1243dSDimitry Andric Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty()); 2856*bdd1243dSDimitry Andric ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty()); 2857*bdd1243dSDimitry Andric } 2858*bdd1243dSDimitry Andric 2859*bdd1243dSDimitry Andric Value *Result; 2860*bdd1243dSDimitry Andric 2861*bdd1243dSDimitry Andric // Must pass the shift amount needed to sign extend the loaded value prior 2862*bdd1243dSDimitry Andric // to performing a signed comparison for min/max. ShiftAmt is the number of 2863*bdd1243dSDimitry Andric // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which 2864*bdd1243dSDimitry Andric // is the number of bits to left+right shift the value in order to 2865*bdd1243dSDimitry Andric // sign-extend. 2866*bdd1243dSDimitry Andric if (AI->getOperation() == AtomicRMWInst::Min || 2867*bdd1243dSDimitry Andric AI->getOperation() == AtomicRMWInst::Max) { 2868*bdd1243dSDimitry Andric const DataLayout &DL = AI->getModule()->getDataLayout(); 2869*bdd1243dSDimitry Andric unsigned ValWidth = 2870*bdd1243dSDimitry Andric DL.getTypeStoreSizeInBits(AI->getValOperand()->getType()); 2871*bdd1243dSDimitry Andric Value *SextShamt = 2872*bdd1243dSDimitry Andric Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt); 2873*bdd1243dSDimitry Andric Result = Builder.CreateCall(LlwOpScwLoop, 2874*bdd1243dSDimitry Andric {AlignedAddr, Incr, Mask, SextShamt, Ordering}); 2875*bdd1243dSDimitry Andric } else { 2876*bdd1243dSDimitry Andric Result = 2877*bdd1243dSDimitry Andric Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering}); 2878*bdd1243dSDimitry Andric } 2879*bdd1243dSDimitry Andric 2880*bdd1243dSDimitry Andric if (GRLen == 64) 2881*bdd1243dSDimitry Andric Result = Builder.CreateTrunc(Result, Builder.getInt32Ty()); 2882*bdd1243dSDimitry Andric return Result; 2883*bdd1243dSDimitry Andric } 2884*bdd1243dSDimitry Andric 2885*bdd1243dSDimitry Andric bool LoongArchTargetLowering::isFMAFasterThanFMulAndFAdd( 2886*bdd1243dSDimitry Andric const MachineFunction &MF, EVT VT) const { 2887*bdd1243dSDimitry Andric VT = VT.getScalarType(); 2888*bdd1243dSDimitry Andric 2889*bdd1243dSDimitry Andric if (!VT.isSimple()) 2890*bdd1243dSDimitry Andric return false; 2891*bdd1243dSDimitry Andric 2892*bdd1243dSDimitry Andric switch (VT.getSimpleVT().SimpleTy) { 2893*bdd1243dSDimitry Andric case MVT::f32: 2894*bdd1243dSDimitry Andric case MVT::f64: 2895*bdd1243dSDimitry Andric return true; 2896*bdd1243dSDimitry Andric default: 2897*bdd1243dSDimitry Andric break; 2898*bdd1243dSDimitry Andric } 2899*bdd1243dSDimitry Andric 2900*bdd1243dSDimitry Andric return false; 2901*bdd1243dSDimitry Andric } 2902*bdd1243dSDimitry Andric 2903*bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionPointerRegister( 2904*bdd1243dSDimitry Andric const Constant *PersonalityFn) const { 2905*bdd1243dSDimitry Andric return LoongArch::R4; 2906*bdd1243dSDimitry Andric } 2907*bdd1243dSDimitry Andric 2908*bdd1243dSDimitry Andric Register LoongArchTargetLowering::getExceptionSelectorRegister( 2909*bdd1243dSDimitry Andric const Constant *PersonalityFn) const { 2910*bdd1243dSDimitry Andric return LoongArch::R5; 2911*bdd1243dSDimitry Andric } 2912*bdd1243dSDimitry Andric 2913*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 2914*bdd1243dSDimitry Andric // LoongArch Inline Assembly Support 2915*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 2916*bdd1243dSDimitry Andric 2917*bdd1243dSDimitry Andric LoongArchTargetLowering::ConstraintType 2918*bdd1243dSDimitry Andric LoongArchTargetLowering::getConstraintType(StringRef Constraint) const { 2919*bdd1243dSDimitry Andric // LoongArch specific constraints in GCC: config/loongarch/constraints.md 2920*bdd1243dSDimitry Andric // 2921*bdd1243dSDimitry Andric // 'f': A floating-point register (if available). 2922*bdd1243dSDimitry Andric // 'k': A memory operand whose address is formed by a base register and 2923*bdd1243dSDimitry Andric // (optionally scaled) index register. 2924*bdd1243dSDimitry Andric // 'l': A signed 16-bit constant. 2925*bdd1243dSDimitry Andric // 'm': A memory operand whose address is formed by a base register and 2926*bdd1243dSDimitry Andric // offset that is suitable for use in instructions with the same 2927*bdd1243dSDimitry Andric // addressing mode as st.w and ld.w. 2928*bdd1243dSDimitry Andric // 'I': A signed 12-bit constant (for arithmetic instructions). 2929*bdd1243dSDimitry Andric // 'J': Integer zero. 2930*bdd1243dSDimitry Andric // 'K': An unsigned 12-bit constant (for logic instructions). 2931*bdd1243dSDimitry Andric // "ZB": An address that is held in a general-purpose register. The offset is 2932*bdd1243dSDimitry Andric // zero. 2933*bdd1243dSDimitry Andric // "ZC": A memory operand whose address is formed by a base register and 2934*bdd1243dSDimitry Andric // offset that is suitable for use in instructions with the same 2935*bdd1243dSDimitry Andric // addressing mode as ll.w and sc.w. 2936*bdd1243dSDimitry Andric if (Constraint.size() == 1) { 2937*bdd1243dSDimitry Andric switch (Constraint[0]) { 2938*bdd1243dSDimitry Andric default: 2939*bdd1243dSDimitry Andric break; 2940*bdd1243dSDimitry Andric case 'f': 2941*bdd1243dSDimitry Andric return C_RegisterClass; 2942*bdd1243dSDimitry Andric case 'l': 2943*bdd1243dSDimitry Andric case 'I': 2944*bdd1243dSDimitry Andric case 'J': 2945*bdd1243dSDimitry Andric case 'K': 2946*bdd1243dSDimitry Andric return C_Immediate; 2947*bdd1243dSDimitry Andric case 'k': 2948*bdd1243dSDimitry Andric return C_Memory; 2949*bdd1243dSDimitry Andric } 2950*bdd1243dSDimitry Andric } 2951*bdd1243dSDimitry Andric 2952*bdd1243dSDimitry Andric if (Constraint == "ZC" || Constraint == "ZB") 2953*bdd1243dSDimitry Andric return C_Memory; 2954*bdd1243dSDimitry Andric 2955*bdd1243dSDimitry Andric // 'm' is handled here. 2956*bdd1243dSDimitry Andric return TargetLowering::getConstraintType(Constraint); 2957*bdd1243dSDimitry Andric } 2958*bdd1243dSDimitry Andric 2959*bdd1243dSDimitry Andric unsigned LoongArchTargetLowering::getInlineAsmMemConstraint( 2960*bdd1243dSDimitry Andric StringRef ConstraintCode) const { 2961*bdd1243dSDimitry Andric return StringSwitch<unsigned>(ConstraintCode) 2962*bdd1243dSDimitry Andric .Case("k", InlineAsm::Constraint_k) 2963*bdd1243dSDimitry Andric .Case("ZB", InlineAsm::Constraint_ZB) 2964*bdd1243dSDimitry Andric .Case("ZC", InlineAsm::Constraint_ZC) 2965*bdd1243dSDimitry Andric .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode)); 2966*bdd1243dSDimitry Andric } 2967*bdd1243dSDimitry Andric 2968*bdd1243dSDimitry Andric std::pair<unsigned, const TargetRegisterClass *> 2969*bdd1243dSDimitry Andric LoongArchTargetLowering::getRegForInlineAsmConstraint( 2970*bdd1243dSDimitry Andric const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { 2971*bdd1243dSDimitry Andric // First, see if this is a constraint that directly corresponds to a LoongArch 2972*bdd1243dSDimitry Andric // register class. 2973*bdd1243dSDimitry Andric if (Constraint.size() == 1) { 2974*bdd1243dSDimitry Andric switch (Constraint[0]) { 2975*bdd1243dSDimitry Andric case 'r': 2976*bdd1243dSDimitry Andric // TODO: Support fixed vectors up to GRLen? 2977*bdd1243dSDimitry Andric if (VT.isVector()) 2978*bdd1243dSDimitry Andric break; 2979*bdd1243dSDimitry Andric return std::make_pair(0U, &LoongArch::GPRRegClass); 2980*bdd1243dSDimitry Andric case 'f': 2981*bdd1243dSDimitry Andric if (Subtarget.hasBasicF() && VT == MVT::f32) 2982*bdd1243dSDimitry Andric return std::make_pair(0U, &LoongArch::FPR32RegClass); 2983*bdd1243dSDimitry Andric if (Subtarget.hasBasicD() && VT == MVT::f64) 2984*bdd1243dSDimitry Andric return std::make_pair(0U, &LoongArch::FPR64RegClass); 2985*bdd1243dSDimitry Andric break; 2986*bdd1243dSDimitry Andric default: 2987*bdd1243dSDimitry Andric break; 2988*bdd1243dSDimitry Andric } 2989*bdd1243dSDimitry Andric } 2990*bdd1243dSDimitry Andric 2991*bdd1243dSDimitry Andric // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen 2992*bdd1243dSDimitry Andric // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm 2993*bdd1243dSDimitry Andric // constraints while the official register name is prefixed with a '$'. So we 2994*bdd1243dSDimitry Andric // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.) 2995*bdd1243dSDimitry Andric // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is 2996*bdd1243dSDimitry Andric // case insensitive, so no need to convert the constraint to upper case here. 2997*bdd1243dSDimitry Andric // 2998*bdd1243dSDimitry Andric // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly 2999*bdd1243dSDimitry Andric // decode the usage of register name aliases into their official names. And 3000*bdd1243dSDimitry Andric // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use 3001*bdd1243dSDimitry Andric // official register names. 3002*bdd1243dSDimitry Andric if (Constraint.startswith("{$r") || Constraint.startswith("{$f")) { 3003*bdd1243dSDimitry Andric bool IsFP = Constraint[2] == 'f'; 3004*bdd1243dSDimitry Andric std::pair<StringRef, StringRef> Temp = Constraint.split('$'); 3005*bdd1243dSDimitry Andric std::pair<unsigned, const TargetRegisterClass *> R; 3006*bdd1243dSDimitry Andric R = TargetLowering::getRegForInlineAsmConstraint( 3007*bdd1243dSDimitry Andric TRI, join_items("", Temp.first, Temp.second), VT); 3008*bdd1243dSDimitry Andric // Match those names to the widest floating point register type available. 3009*bdd1243dSDimitry Andric if (IsFP) { 3010*bdd1243dSDimitry Andric unsigned RegNo = R.first; 3011*bdd1243dSDimitry Andric if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) { 3012*bdd1243dSDimitry Andric if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) { 3013*bdd1243dSDimitry Andric unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64; 3014*bdd1243dSDimitry Andric return std::make_pair(DReg, &LoongArch::FPR64RegClass); 3015*bdd1243dSDimitry Andric } 3016*bdd1243dSDimitry Andric } 3017*bdd1243dSDimitry Andric } 3018*bdd1243dSDimitry Andric return R; 3019*bdd1243dSDimitry Andric } 3020*bdd1243dSDimitry Andric 3021*bdd1243dSDimitry Andric return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); 3022*bdd1243dSDimitry Andric } 3023*bdd1243dSDimitry Andric 3024*bdd1243dSDimitry Andric void LoongArchTargetLowering::LowerAsmOperandForConstraint( 3025*bdd1243dSDimitry Andric SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops, 3026*bdd1243dSDimitry Andric SelectionDAG &DAG) const { 3027*bdd1243dSDimitry Andric // Currently only support length 1 constraints. 3028*bdd1243dSDimitry Andric if (Constraint.length() == 1) { 3029*bdd1243dSDimitry Andric switch (Constraint[0]) { 3030*bdd1243dSDimitry Andric case 'l': 3031*bdd1243dSDimitry Andric // Validate & create a 16-bit signed immediate operand. 3032*bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) { 3033*bdd1243dSDimitry Andric uint64_t CVal = C->getSExtValue(); 3034*bdd1243dSDimitry Andric if (isInt<16>(CVal)) 3035*bdd1243dSDimitry Andric Ops.push_back( 3036*bdd1243dSDimitry Andric DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT())); 3037*bdd1243dSDimitry Andric } 3038*bdd1243dSDimitry Andric return; 3039*bdd1243dSDimitry Andric case 'I': 3040*bdd1243dSDimitry Andric // Validate & create a 12-bit signed immediate operand. 3041*bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) { 3042*bdd1243dSDimitry Andric uint64_t CVal = C->getSExtValue(); 3043*bdd1243dSDimitry Andric if (isInt<12>(CVal)) 3044*bdd1243dSDimitry Andric Ops.push_back( 3045*bdd1243dSDimitry Andric DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT())); 3046*bdd1243dSDimitry Andric } 3047*bdd1243dSDimitry Andric return; 3048*bdd1243dSDimitry Andric case 'J': 3049*bdd1243dSDimitry Andric // Validate & create an integer zero operand. 3050*bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) 3051*bdd1243dSDimitry Andric if (C->getZExtValue() == 0) 3052*bdd1243dSDimitry Andric Ops.push_back( 3053*bdd1243dSDimitry Andric DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT())); 3054*bdd1243dSDimitry Andric return; 3055*bdd1243dSDimitry Andric case 'K': 3056*bdd1243dSDimitry Andric // Validate & create a 12-bit unsigned immediate operand. 3057*bdd1243dSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Op)) { 3058*bdd1243dSDimitry Andric uint64_t CVal = C->getZExtValue(); 3059*bdd1243dSDimitry Andric if (isUInt<12>(CVal)) 3060*bdd1243dSDimitry Andric Ops.push_back( 3061*bdd1243dSDimitry Andric DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT())); 3062*bdd1243dSDimitry Andric } 3063*bdd1243dSDimitry Andric return; 3064*bdd1243dSDimitry Andric default: 3065*bdd1243dSDimitry Andric break; 3066*bdd1243dSDimitry Andric } 3067*bdd1243dSDimitry Andric } 3068*bdd1243dSDimitry Andric TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); 3069*bdd1243dSDimitry Andric } 3070*bdd1243dSDimitry Andric 3071*bdd1243dSDimitry Andric #define GET_REGISTER_MATCHER 3072*bdd1243dSDimitry Andric #include "LoongArchGenAsmMatcher.inc" 3073*bdd1243dSDimitry Andric 3074*bdd1243dSDimitry Andric Register 3075*bdd1243dSDimitry Andric LoongArchTargetLowering::getRegisterByName(const char *RegName, LLT VT, 3076*bdd1243dSDimitry Andric const MachineFunction &MF) const { 3077*bdd1243dSDimitry Andric std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$'); 3078*bdd1243dSDimitry Andric std::string NewRegName = Name.second.str(); 3079*bdd1243dSDimitry Andric Register Reg = MatchRegisterAltName(NewRegName); 3080*bdd1243dSDimitry Andric if (Reg == LoongArch::NoRegister) 3081*bdd1243dSDimitry Andric Reg = MatchRegisterName(NewRegName); 3082*bdd1243dSDimitry Andric if (Reg == LoongArch::NoRegister) 3083*bdd1243dSDimitry Andric report_fatal_error( 3084*bdd1243dSDimitry Andric Twine("Invalid register name \"" + StringRef(RegName) + "\".")); 3085*bdd1243dSDimitry Andric BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF); 3086*bdd1243dSDimitry Andric if (!ReservedRegs.test(Reg)) 3087*bdd1243dSDimitry Andric report_fatal_error(Twine("Trying to obtain non-reserved register \"" + 3088*bdd1243dSDimitry Andric StringRef(RegName) + "\".")); 3089*bdd1243dSDimitry Andric return Reg; 3090*bdd1243dSDimitry Andric } 3091*bdd1243dSDimitry Andric 3092*bdd1243dSDimitry Andric bool LoongArchTargetLowering::decomposeMulByConstant(LLVMContext &Context, 3093*bdd1243dSDimitry Andric EVT VT, SDValue C) const { 3094*bdd1243dSDimitry Andric // TODO: Support vectors. 3095*bdd1243dSDimitry Andric if (!VT.isScalarInteger()) 3096*bdd1243dSDimitry Andric return false; 3097*bdd1243dSDimitry Andric 3098*bdd1243dSDimitry Andric // Omit the optimization if the data size exceeds GRLen. 3099*bdd1243dSDimitry Andric if (VT.getSizeInBits() > Subtarget.getGRLen()) 3100*bdd1243dSDimitry Andric return false; 3101*bdd1243dSDimitry Andric 3102*bdd1243dSDimitry Andric // Break MUL into (SLLI + ADD/SUB) or ALSL. 3103*bdd1243dSDimitry Andric if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) { 3104*bdd1243dSDimitry Andric const APInt &Imm = ConstNode->getAPIntValue(); 3105*bdd1243dSDimitry Andric if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() || 3106*bdd1243dSDimitry Andric (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2()) 3107*bdd1243dSDimitry Andric return true; 3108*bdd1243dSDimitry Andric } 3109*bdd1243dSDimitry Andric 3110*bdd1243dSDimitry Andric return false; 3111*bdd1243dSDimitry Andric } 3112