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*753f127fSDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h" 2181ad6265SDimitry Andric #include "llvm/ADT/Statistic.h" 2281ad6265SDimitry Andric #include "llvm/CodeGen/ISDOpcodes.h" 2381ad6265SDimitry Andric #include "llvm/Support/Debug.h" 24*753f127fSDimitry Andric #include "llvm/Support/KnownBits.h" 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric using namespace llvm; 2781ad6265SDimitry Andric 2881ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-isel-lowering" 2981ad6265SDimitry Andric 30*753f127fSDimitry Andric static cl::opt<bool> ZeroDivCheck( 31*753f127fSDimitry Andric "loongarch-check-zero-division", cl::Hidden, 32*753f127fSDimitry Andric cl::desc("Trap on integer division by zero."), 33*753f127fSDimitry Andric cl::init(false)); 34*753f127fSDimitry Andric 3581ad6265SDimitry Andric LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM, 3681ad6265SDimitry Andric const LoongArchSubtarget &STI) 3781ad6265SDimitry Andric : TargetLowering(TM), Subtarget(STI) { 3881ad6265SDimitry Andric 3981ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 4081ad6265SDimitry Andric // Set up the register classes. 4181ad6265SDimitry Andric addRegisterClass(GRLenVT, &LoongArch::GPRRegClass); 4281ad6265SDimitry Andric if (Subtarget.hasBasicF()) 4381ad6265SDimitry Andric addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass); 4481ad6265SDimitry Andric if (Subtarget.hasBasicD()) 4581ad6265SDimitry Andric addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass); 4681ad6265SDimitry Andric 47*753f127fSDimitry Andric setLoadExtAction({ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}, GRLenVT, 48*753f127fSDimitry Andric MVT::i1, Promote); 49*753f127fSDimitry Andric 5081ad6265SDimitry Andric // TODO: add necessary setOperationAction calls later. 5181ad6265SDimitry Andric setOperationAction(ISD::SHL_PARTS, GRLenVT, Custom); 5281ad6265SDimitry Andric setOperationAction(ISD::SRA_PARTS, GRLenVT, Custom); 5381ad6265SDimitry Andric setOperationAction(ISD::SRL_PARTS, GRLenVT, Custom); 54*753f127fSDimitry Andric setOperationAction(ISD::FP_TO_SINT, GRLenVT, Custom); 55*753f127fSDimitry Andric 56*753f127fSDimitry Andric setOperationAction({ISD::GlobalAddress, ISD::ConstantPool}, GRLenVT, Custom); 5781ad6265SDimitry Andric 5881ad6265SDimitry Andric if (Subtarget.is64Bit()) { 5981ad6265SDimitry Andric setOperationAction(ISD::SHL, MVT::i32, Custom); 6081ad6265SDimitry Andric setOperationAction(ISD::SRA, MVT::i32, Custom); 6181ad6265SDimitry Andric setOperationAction(ISD::SRL, MVT::i32, Custom); 62*753f127fSDimitry Andric setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); 63*753f127fSDimitry Andric setOperationAction(ISD::BITCAST, MVT::i32, Custom); 64*753f127fSDimitry Andric if (Subtarget.hasBasicF() && !Subtarget.hasBasicD()) 65*753f127fSDimitry Andric setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); 6681ad6265SDimitry Andric } 6781ad6265SDimitry Andric 6881ad6265SDimitry Andric static const ISD::CondCode FPCCToExpand[] = {ISD::SETOGT, ISD::SETOGE, 6981ad6265SDimitry Andric ISD::SETUGT, ISD::SETUGE}; 7081ad6265SDimitry Andric 7181ad6265SDimitry Andric if (Subtarget.hasBasicF()) { 7281ad6265SDimitry Andric setCondCodeAction(FPCCToExpand, MVT::f32, Expand); 7381ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::f32, Expand); 7481ad6265SDimitry Andric } 7581ad6265SDimitry Andric if (Subtarget.hasBasicD()) { 7681ad6265SDimitry Andric setCondCodeAction(FPCCToExpand, MVT::f64, Expand); 7781ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::f64, Expand); 78*753f127fSDimitry Andric setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); 79*753f127fSDimitry Andric setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); 8081ad6265SDimitry Andric } 8181ad6265SDimitry Andric 82*753f127fSDimitry Andric setOperationAction(ISD::BR_CC, GRLenVT, Expand); 8381ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, GRLenVT, Expand); 8481ad6265SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); 85*753f127fSDimitry Andric setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, GRLenVT, Expand); 86*753f127fSDimitry Andric if (!Subtarget.is64Bit()) 87*753f127fSDimitry Andric setLibcallName(RTLIB::MUL_I128, nullptr); 88*753f127fSDimitry Andric 89*753f127fSDimitry Andric setOperationAction(ISD::FP_TO_UINT, GRLenVT, Custom); 90*753f127fSDimitry Andric setOperationAction(ISD::UINT_TO_FP, GRLenVT, Custom); 9181ad6265SDimitry Andric 9281ad6265SDimitry Andric // Compute derived properties from the register classes. 9381ad6265SDimitry Andric computeRegisterProperties(STI.getRegisterInfo()); 9481ad6265SDimitry Andric 9581ad6265SDimitry Andric setStackPointerRegisterToSaveRestore(LoongArch::R3); 9681ad6265SDimitry Andric 9781ad6265SDimitry Andric setBooleanContents(ZeroOrOneBooleanContent); 9881ad6265SDimitry Andric 99*753f127fSDimitry Andric setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen()); 100*753f127fSDimitry Andric 10181ad6265SDimitry Andric // Function alignments. 10281ad6265SDimitry Andric const Align FunctionAlignment(4); 10381ad6265SDimitry Andric setMinFunctionAlignment(FunctionAlignment); 10481ad6265SDimitry Andric 10581ad6265SDimitry Andric setTargetDAGCombine(ISD::AND); 106*753f127fSDimitry Andric setTargetDAGCombine(ISD::OR); 10781ad6265SDimitry Andric setTargetDAGCombine(ISD::SRL); 10881ad6265SDimitry Andric } 10981ad6265SDimitry Andric 11081ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerOperation(SDValue Op, 11181ad6265SDimitry Andric SelectionDAG &DAG) const { 11281ad6265SDimitry Andric switch (Op.getOpcode()) { 11381ad6265SDimitry Andric default: 11481ad6265SDimitry Andric report_fatal_error("unimplemented operand"); 115*753f127fSDimitry Andric case ISD::GlobalAddress: 116*753f127fSDimitry Andric return lowerGlobalAddress(Op, DAG); 11781ad6265SDimitry Andric case ISD::SHL_PARTS: 11881ad6265SDimitry Andric return lowerShiftLeftParts(Op, DAG); 11981ad6265SDimitry Andric case ISD::SRA_PARTS: 12081ad6265SDimitry Andric return lowerShiftRightParts(Op, DAG, true); 12181ad6265SDimitry Andric case ISD::SRL_PARTS: 12281ad6265SDimitry Andric return lowerShiftRightParts(Op, DAG, false); 12381ad6265SDimitry Andric case ISD::SHL: 12481ad6265SDimitry Andric case ISD::SRA: 12581ad6265SDimitry Andric case ISD::SRL: 12681ad6265SDimitry Andric // This can be called for an i32 shift amount that needs to be promoted. 12781ad6265SDimitry Andric assert(Op.getOperand(1).getValueType() == MVT::i32 && Subtarget.is64Bit() && 12881ad6265SDimitry Andric "Unexpected custom legalisation"); 12981ad6265SDimitry Andric return SDValue(); 130*753f127fSDimitry Andric case ISD::ConstantPool: 131*753f127fSDimitry Andric return lowerConstantPool(Op, DAG); 132*753f127fSDimitry Andric case ISD::FP_TO_SINT: 133*753f127fSDimitry Andric return lowerFP_TO_SINT(Op, DAG); 134*753f127fSDimitry Andric case ISD::BITCAST: 135*753f127fSDimitry Andric return lowerBITCAST(Op, DAG); 136*753f127fSDimitry Andric case ISD::FP_TO_UINT: 137*753f127fSDimitry Andric return SDValue(); 138*753f127fSDimitry Andric case ISD::UINT_TO_FP: 139*753f127fSDimitry Andric return lowerUINT_TO_FP(Op, DAG); 14081ad6265SDimitry Andric } 14181ad6265SDimitry Andric } 14281ad6265SDimitry Andric 143*753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op, 144*753f127fSDimitry Andric SelectionDAG &DAG) const { 145*753f127fSDimitry Andric 146*753f127fSDimitry Andric SDLoc DL(Op); 147*753f127fSDimitry Andric auto &TLI = DAG.getTargetLoweringInfo(); 148*753f127fSDimitry Andric SDValue Tmp1, Tmp2; 149*753f127fSDimitry Andric SDValue Op1 = Op.getOperand(0); 150*753f127fSDimitry Andric if (Op1->getOpcode() == ISD::AssertZext || 151*753f127fSDimitry Andric Op1->getOpcode() == ISD::AssertSext) 152*753f127fSDimitry Andric return Op; 153*753f127fSDimitry Andric SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Op.getOperand(0)); 154*753f127fSDimitry Andric SDValue Res = DAG.getNode(ISD::UINT_TO_FP, DL, MVT::f64, Trunc); 155*753f127fSDimitry Andric SDNode *N = Res.getNode(); 156*753f127fSDimitry Andric TLI.expandUINT_TO_FP(N, Tmp1, Tmp2, DAG); 157*753f127fSDimitry Andric return Tmp1; 158*753f127fSDimitry Andric } 159*753f127fSDimitry Andric 160*753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op, 161*753f127fSDimitry Andric SelectionDAG &DAG) const { 162*753f127fSDimitry Andric 163*753f127fSDimitry Andric SDLoc DL(Op); 164*753f127fSDimitry Andric SDValue Op0 = Op.getOperand(0); 165*753f127fSDimitry Andric 166*753f127fSDimitry Andric if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 && 167*753f127fSDimitry Andric Subtarget.is64Bit() && Subtarget.hasBasicF()) { 168*753f127fSDimitry Andric SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0); 169*753f127fSDimitry Andric return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0); 170*753f127fSDimitry Andric } 171*753f127fSDimitry Andric return Op; 172*753f127fSDimitry Andric } 173*753f127fSDimitry Andric 174*753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op, 175*753f127fSDimitry Andric SelectionDAG &DAG) const { 176*753f127fSDimitry Andric 177*753f127fSDimitry Andric SDLoc DL(Op); 178*753f127fSDimitry Andric 179*753f127fSDimitry Andric if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() && 180*753f127fSDimitry Andric !Subtarget.hasBasicD()) { 181*753f127fSDimitry Andric SDValue Dst = 182*753f127fSDimitry Andric DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0)); 183*753f127fSDimitry Andric return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst); 184*753f127fSDimitry Andric } 185*753f127fSDimitry Andric 186*753f127fSDimitry Andric EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits()); 187*753f127fSDimitry Andric SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0)); 188*753f127fSDimitry Andric return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc); 189*753f127fSDimitry Andric } 190*753f127fSDimitry Andric 191*753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op, 192*753f127fSDimitry Andric SelectionDAG &DAG) const { 193*753f127fSDimitry Andric SDLoc DL(Op); 194*753f127fSDimitry Andric EVT Ty = Op.getValueType(); 195*753f127fSDimitry Andric ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); 196*753f127fSDimitry Andric 197*753f127fSDimitry Andric // FIXME: Only support PC-relative addressing to access the symbol. 198*753f127fSDimitry Andric // Target flags will be added later. 199*753f127fSDimitry Andric if (!isPositionIndependent()) { 200*753f127fSDimitry Andric SDValue ConstantN = DAG.getTargetConstantPool( 201*753f127fSDimitry Andric N->getConstVal(), Ty, N->getAlign(), N->getOffset()); 202*753f127fSDimitry Andric SDValue AddrHi(DAG.getMachineNode(LoongArch::PCALAU12I, DL, Ty, ConstantN), 203*753f127fSDimitry Andric 0); 204*753f127fSDimitry Andric SDValue Addr(DAG.getMachineNode(Subtarget.is64Bit() ? LoongArch::ADDI_D 205*753f127fSDimitry Andric : LoongArch::ADDI_W, 206*753f127fSDimitry Andric DL, Ty, AddrHi, ConstantN), 207*753f127fSDimitry Andric 0); 208*753f127fSDimitry Andric return Addr; 209*753f127fSDimitry Andric } 210*753f127fSDimitry Andric report_fatal_error("Unable to lower ConstantPool"); 211*753f127fSDimitry Andric } 212*753f127fSDimitry Andric 213*753f127fSDimitry Andric SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op, 214*753f127fSDimitry Andric SelectionDAG &DAG) const { 215*753f127fSDimitry Andric SDLoc DL(Op); 216*753f127fSDimitry Andric EVT Ty = getPointerTy(DAG.getDataLayout()); 217*753f127fSDimitry Andric const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); 218*753f127fSDimitry Andric unsigned ADDIOp = Subtarget.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; 219*753f127fSDimitry Andric 220*753f127fSDimitry Andric // FIXME: Only support PC-relative addressing to access the symbol. 221*753f127fSDimitry Andric // TODO: Add target flags. 222*753f127fSDimitry Andric if (!isPositionIndependent()) { 223*753f127fSDimitry Andric SDValue GA = DAG.getTargetGlobalAddress(GV, DL, Ty); 224*753f127fSDimitry Andric SDValue AddrHi(DAG.getMachineNode(LoongArch::PCALAU12I, DL, Ty, GA), 0); 225*753f127fSDimitry Andric SDValue Addr(DAG.getMachineNode(ADDIOp, DL, Ty, AddrHi, GA), 0); 226*753f127fSDimitry Andric return Addr; 227*753f127fSDimitry Andric } 228*753f127fSDimitry Andric report_fatal_error("Unable to lowerGlobalAddress"); 229*753f127fSDimitry Andric } 230*753f127fSDimitry Andric 23181ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op, 23281ad6265SDimitry Andric SelectionDAG &DAG) const { 23381ad6265SDimitry Andric SDLoc DL(Op); 23481ad6265SDimitry Andric SDValue Lo = Op.getOperand(0); 23581ad6265SDimitry Andric SDValue Hi = Op.getOperand(1); 23681ad6265SDimitry Andric SDValue Shamt = Op.getOperand(2); 23781ad6265SDimitry Andric EVT VT = Lo.getValueType(); 23881ad6265SDimitry Andric 23981ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 24081ad6265SDimitry Andric // Lo = Lo << Shamt 24181ad6265SDimitry Andric // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt)) 24281ad6265SDimitry Andric // else: 24381ad6265SDimitry Andric // Lo = 0 24481ad6265SDimitry Andric // Hi = Lo << (Shamt-GRLen) 24581ad6265SDimitry Andric 24681ad6265SDimitry Andric SDValue Zero = DAG.getConstant(0, DL, VT); 24781ad6265SDimitry Andric SDValue One = DAG.getConstant(1, DL, VT); 24881ad6265SDimitry Andric SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT); 24981ad6265SDimitry Andric SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT); 25081ad6265SDimitry Andric SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen); 25181ad6265SDimitry Andric SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1); 25281ad6265SDimitry Andric 25381ad6265SDimitry Andric SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt); 25481ad6265SDimitry Andric SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One); 25581ad6265SDimitry Andric SDValue ShiftRightLo = 25681ad6265SDimitry Andric DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt); 25781ad6265SDimitry Andric SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt); 25881ad6265SDimitry Andric SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo); 25981ad6265SDimitry Andric SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen); 26081ad6265SDimitry Andric 26181ad6265SDimitry Andric SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT); 26281ad6265SDimitry Andric 26381ad6265SDimitry Andric Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero); 26481ad6265SDimitry Andric Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); 26581ad6265SDimitry Andric 26681ad6265SDimitry Andric SDValue Parts[2] = {Lo, Hi}; 26781ad6265SDimitry Andric return DAG.getMergeValues(Parts, DL); 26881ad6265SDimitry Andric } 26981ad6265SDimitry Andric 27081ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op, 27181ad6265SDimitry Andric SelectionDAG &DAG, 27281ad6265SDimitry Andric bool IsSRA) const { 27381ad6265SDimitry Andric SDLoc DL(Op); 27481ad6265SDimitry Andric SDValue Lo = Op.getOperand(0); 27581ad6265SDimitry Andric SDValue Hi = Op.getOperand(1); 27681ad6265SDimitry Andric SDValue Shamt = Op.getOperand(2); 27781ad6265SDimitry Andric EVT VT = Lo.getValueType(); 27881ad6265SDimitry Andric 27981ad6265SDimitry Andric // SRA expansion: 28081ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 28181ad6265SDimitry Andric // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1)) 28281ad6265SDimitry Andric // Hi = Hi >>s Shamt 28381ad6265SDimitry Andric // else: 28481ad6265SDimitry Andric // Lo = Hi >>s (Shamt-GRLen); 28581ad6265SDimitry Andric // Hi = Hi >>s (GRLen-1) 28681ad6265SDimitry Andric // 28781ad6265SDimitry Andric // SRL expansion: 28881ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 28981ad6265SDimitry Andric // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1)) 29081ad6265SDimitry Andric // Hi = Hi >>u Shamt 29181ad6265SDimitry Andric // else: 29281ad6265SDimitry Andric // Lo = Hi >>u (Shamt-GRLen); 29381ad6265SDimitry Andric // Hi = 0; 29481ad6265SDimitry Andric 29581ad6265SDimitry Andric unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL; 29681ad6265SDimitry Andric 29781ad6265SDimitry Andric SDValue Zero = DAG.getConstant(0, DL, VT); 29881ad6265SDimitry Andric SDValue One = DAG.getConstant(1, DL, VT); 29981ad6265SDimitry Andric SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT); 30081ad6265SDimitry Andric SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT); 30181ad6265SDimitry Andric SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen); 30281ad6265SDimitry Andric SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1); 30381ad6265SDimitry Andric 30481ad6265SDimitry Andric SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt); 30581ad6265SDimitry Andric SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One); 30681ad6265SDimitry Andric SDValue ShiftLeftHi = 30781ad6265SDimitry Andric DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt); 30881ad6265SDimitry Andric SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi); 30981ad6265SDimitry Andric SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt); 31081ad6265SDimitry Andric SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen); 31181ad6265SDimitry Andric SDValue HiFalse = 31281ad6265SDimitry Andric IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero; 31381ad6265SDimitry Andric 31481ad6265SDimitry Andric SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT); 31581ad6265SDimitry Andric 31681ad6265SDimitry Andric Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse); 31781ad6265SDimitry Andric Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); 31881ad6265SDimitry Andric 31981ad6265SDimitry Andric SDValue Parts[2] = {Lo, Hi}; 32081ad6265SDimitry Andric return DAG.getMergeValues(Parts, DL); 32181ad6265SDimitry Andric } 32281ad6265SDimitry Andric 32381ad6265SDimitry Andric // Returns the opcode of the target-specific SDNode that implements the 32-bit 32481ad6265SDimitry Andric // form of the given Opcode. 32581ad6265SDimitry Andric static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode) { 32681ad6265SDimitry Andric switch (Opcode) { 32781ad6265SDimitry Andric default: 32881ad6265SDimitry Andric llvm_unreachable("Unexpected opcode"); 32981ad6265SDimitry Andric case ISD::SHL: 33081ad6265SDimitry Andric return LoongArchISD::SLL_W; 33181ad6265SDimitry Andric case ISD::SRA: 33281ad6265SDimitry Andric return LoongArchISD::SRA_W; 33381ad6265SDimitry Andric case ISD::SRL: 33481ad6265SDimitry Andric return LoongArchISD::SRL_W; 33581ad6265SDimitry Andric } 33681ad6265SDimitry Andric } 33781ad6265SDimitry Andric 33881ad6265SDimitry Andric // Converts the given i8/i16/i32 operation to a target-specific SelectionDAG 33981ad6265SDimitry Andric // node. Because i8/i16/i32 isn't a legal type for LA64, these operations would 34081ad6265SDimitry Andric // otherwise be promoted to i64, making it difficult to select the 34181ad6265SDimitry Andric // SLL_W/.../*W later one because the fact the operation was originally of 34281ad6265SDimitry Andric // type i8/i16/i32 is lost. 34381ad6265SDimitry Andric static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, 34481ad6265SDimitry Andric unsigned ExtOpc = ISD::ANY_EXTEND) { 34581ad6265SDimitry Andric SDLoc DL(N); 34681ad6265SDimitry Andric LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode()); 34781ad6265SDimitry Andric SDValue NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0)); 34881ad6265SDimitry Andric SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1)); 34981ad6265SDimitry Andric SDValue NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1); 35081ad6265SDimitry Andric // ReplaceNodeResults requires we maintain the same type for the return value. 35181ad6265SDimitry Andric return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes); 35281ad6265SDimitry Andric } 35381ad6265SDimitry Andric 35481ad6265SDimitry Andric void LoongArchTargetLowering::ReplaceNodeResults( 35581ad6265SDimitry Andric SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const { 35681ad6265SDimitry Andric SDLoc DL(N); 35781ad6265SDimitry Andric switch (N->getOpcode()) { 35881ad6265SDimitry Andric default: 35981ad6265SDimitry Andric llvm_unreachable("Don't know how to legalize this operation"); 36081ad6265SDimitry Andric case ISD::SHL: 36181ad6265SDimitry Andric case ISD::SRA: 36281ad6265SDimitry Andric case ISD::SRL: 36381ad6265SDimitry Andric assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && 36481ad6265SDimitry Andric "Unexpected custom legalisation"); 36581ad6265SDimitry Andric if (N->getOperand(1).getOpcode() != ISD::Constant) { 36681ad6265SDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG)); 36781ad6265SDimitry Andric break; 36881ad6265SDimitry Andric } 36981ad6265SDimitry Andric break; 370*753f127fSDimitry Andric case ISD::FP_TO_SINT: { 371*753f127fSDimitry Andric assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && 372*753f127fSDimitry Andric "Unexpected custom legalisation"); 373*753f127fSDimitry Andric SDValue Src = N->getOperand(0); 374*753f127fSDimitry Andric EVT VT = EVT::getFloatingPointVT(N->getValueSizeInBits(0)); 375*753f127fSDimitry Andric SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, VT, Src); 376*753f127fSDimitry Andric Results.push_back(DAG.getNode(ISD::BITCAST, DL, N->getValueType(0), Dst)); 377*753f127fSDimitry Andric break; 378*753f127fSDimitry Andric } 379*753f127fSDimitry Andric case ISD::BITCAST: { 380*753f127fSDimitry Andric EVT VT = N->getValueType(0); 381*753f127fSDimitry Andric SDValue Src = N->getOperand(0); 382*753f127fSDimitry Andric EVT SrcVT = Src.getValueType(); 383*753f127fSDimitry Andric if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() && 384*753f127fSDimitry Andric Subtarget.hasBasicF()) { 385*753f127fSDimitry Andric SDValue Dst = 386*753f127fSDimitry Andric DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src); 387*753f127fSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst)); 388*753f127fSDimitry Andric } 389*753f127fSDimitry Andric break; 390*753f127fSDimitry Andric } 391*753f127fSDimitry Andric case ISD::FP_TO_UINT: { 392*753f127fSDimitry Andric assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && 393*753f127fSDimitry Andric "Unexpected custom legalisation"); 394*753f127fSDimitry Andric auto &TLI = DAG.getTargetLoweringInfo(); 395*753f127fSDimitry Andric SDValue Tmp1, Tmp2; 396*753f127fSDimitry Andric TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG); 397*753f127fSDimitry Andric Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1)); 398*753f127fSDimitry Andric break; 399*753f127fSDimitry Andric } 40081ad6265SDimitry Andric } 40181ad6265SDimitry Andric } 40281ad6265SDimitry Andric 40381ad6265SDimitry Andric static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, 40481ad6265SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 40581ad6265SDimitry Andric const LoongArchSubtarget &Subtarget) { 40681ad6265SDimitry Andric if (DCI.isBeforeLegalizeOps()) 40781ad6265SDimitry Andric return SDValue(); 40881ad6265SDimitry Andric 40981ad6265SDimitry Andric SDValue FirstOperand = N->getOperand(0); 41081ad6265SDimitry Andric SDValue SecondOperand = N->getOperand(1); 41181ad6265SDimitry Andric unsigned FirstOperandOpc = FirstOperand.getOpcode(); 41281ad6265SDimitry Andric EVT ValTy = N->getValueType(0); 41381ad6265SDimitry Andric SDLoc DL(N); 41481ad6265SDimitry Andric uint64_t lsb, msb; 41581ad6265SDimitry Andric unsigned SMIdx, SMLen; 41681ad6265SDimitry Andric ConstantSDNode *CN; 41781ad6265SDimitry Andric SDValue NewOperand; 41881ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 41981ad6265SDimitry Andric 42081ad6265SDimitry Andric // Op's second operand must be a shifted mask. 42181ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) || 42281ad6265SDimitry Andric !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen)) 42381ad6265SDimitry Andric return SDValue(); 42481ad6265SDimitry Andric 42581ad6265SDimitry Andric if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) { 42681ad6265SDimitry Andric // Pattern match BSTRPICK. 42781ad6265SDimitry Andric // $dst = and ((sra or srl) $src , lsb), (2**len - 1) 42881ad6265SDimitry Andric // => BSTRPICK $dst, $src, msb, lsb 42981ad6265SDimitry Andric // where msb = lsb + len - 1 43081ad6265SDimitry Andric 43181ad6265SDimitry Andric // The second operand of the shift must be an immediate. 43281ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1)))) 43381ad6265SDimitry Andric return SDValue(); 43481ad6265SDimitry Andric 43581ad6265SDimitry Andric lsb = CN->getZExtValue(); 43681ad6265SDimitry Andric 43781ad6265SDimitry Andric // Return if the shifted mask does not start at bit 0 or the sum of its 43881ad6265SDimitry Andric // length and lsb exceeds the word's size. 43981ad6265SDimitry Andric if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits()) 44081ad6265SDimitry Andric return SDValue(); 44181ad6265SDimitry Andric 44281ad6265SDimitry Andric NewOperand = FirstOperand.getOperand(0); 44381ad6265SDimitry Andric } else { 44481ad6265SDimitry Andric // Pattern match BSTRPICK. 44581ad6265SDimitry Andric // $dst = and $src, (2**len- 1) , if len > 12 44681ad6265SDimitry Andric // => BSTRPICK $dst, $src, msb, lsb 44781ad6265SDimitry Andric // where lsb = 0 and msb = len - 1 44881ad6265SDimitry Andric 44981ad6265SDimitry Andric // If the mask is <= 0xfff, andi can be used instead. 45081ad6265SDimitry Andric if (CN->getZExtValue() <= 0xfff) 45181ad6265SDimitry Andric return SDValue(); 45281ad6265SDimitry Andric 45381ad6265SDimitry Andric // Return if the mask doesn't start at position 0. 45481ad6265SDimitry Andric if (SMIdx) 45581ad6265SDimitry Andric return SDValue(); 45681ad6265SDimitry Andric 45781ad6265SDimitry Andric lsb = 0; 45881ad6265SDimitry Andric NewOperand = FirstOperand; 45981ad6265SDimitry Andric } 46081ad6265SDimitry Andric msb = lsb + SMLen - 1; 46181ad6265SDimitry Andric return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand, 46281ad6265SDimitry Andric DAG.getConstant(msb, DL, GRLenVT), 46381ad6265SDimitry Andric DAG.getConstant(lsb, DL, GRLenVT)); 46481ad6265SDimitry Andric } 46581ad6265SDimitry Andric 46681ad6265SDimitry Andric static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, 46781ad6265SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 46881ad6265SDimitry Andric const LoongArchSubtarget &Subtarget) { 46981ad6265SDimitry Andric if (DCI.isBeforeLegalizeOps()) 47081ad6265SDimitry Andric return SDValue(); 47181ad6265SDimitry Andric 47281ad6265SDimitry Andric // $dst = srl (and $src, Mask), Shamt 47381ad6265SDimitry Andric // => 47481ad6265SDimitry Andric // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt 47581ad6265SDimitry Andric // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1 47681ad6265SDimitry Andric // 47781ad6265SDimitry Andric 47881ad6265SDimitry Andric SDValue FirstOperand = N->getOperand(0); 47981ad6265SDimitry Andric ConstantSDNode *CN; 48081ad6265SDimitry Andric EVT ValTy = N->getValueType(0); 48181ad6265SDimitry Andric SDLoc DL(N); 48281ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 48381ad6265SDimitry Andric unsigned MaskIdx, MaskLen; 48481ad6265SDimitry Andric uint64_t Shamt; 48581ad6265SDimitry Andric 48681ad6265SDimitry Andric // The first operand must be an AND and the second operand of the AND must be 48781ad6265SDimitry Andric // a shifted mask. 48881ad6265SDimitry Andric if (FirstOperand.getOpcode() != ISD::AND || 48981ad6265SDimitry Andric !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) || 49081ad6265SDimitry Andric !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen)) 49181ad6265SDimitry Andric return SDValue(); 49281ad6265SDimitry Andric 49381ad6265SDimitry Andric // The second operand (shift amount) must be an immediate. 49481ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) 49581ad6265SDimitry Andric return SDValue(); 49681ad6265SDimitry Andric 49781ad6265SDimitry Andric Shamt = CN->getZExtValue(); 49881ad6265SDimitry Andric if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1) 49981ad6265SDimitry Andric return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, 50081ad6265SDimitry Andric FirstOperand->getOperand(0), 50181ad6265SDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 50281ad6265SDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 50381ad6265SDimitry Andric 50481ad6265SDimitry Andric return SDValue(); 50581ad6265SDimitry Andric } 50681ad6265SDimitry Andric 507*753f127fSDimitry Andric static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, 508*753f127fSDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 509*753f127fSDimitry Andric const LoongArchSubtarget &Subtarget) { 510*753f127fSDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 511*753f127fSDimitry Andric EVT ValTy = N->getValueType(0); 512*753f127fSDimitry Andric SDValue N0 = N->getOperand(0), N1 = N->getOperand(1); 513*753f127fSDimitry Andric ConstantSDNode *CN0, *CN1; 514*753f127fSDimitry Andric SDLoc DL(N); 515*753f127fSDimitry Andric unsigned ValBits = ValTy.getSizeInBits(); 516*753f127fSDimitry Andric unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1; 517*753f127fSDimitry Andric unsigned Shamt; 518*753f127fSDimitry Andric bool SwapAndRetried = false; 519*753f127fSDimitry Andric 520*753f127fSDimitry Andric if (DCI.isBeforeLegalizeOps()) 521*753f127fSDimitry Andric return SDValue(); 522*753f127fSDimitry Andric 523*753f127fSDimitry Andric if (ValBits != 32 && ValBits != 64) 524*753f127fSDimitry Andric return SDValue(); 525*753f127fSDimitry Andric 526*753f127fSDimitry Andric Retry: 527*753f127fSDimitry Andric // 1st pattern to match BSTRINS: 528*753f127fSDimitry Andric // R = or (and X, mask0), (and (shl Y, lsb), mask1) 529*753f127fSDimitry Andric // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1 530*753f127fSDimitry Andric // => 531*753f127fSDimitry Andric // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1) 532*753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 533*753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 534*753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 535*753f127fSDimitry Andric N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL && 536*753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 537*753f127fSDimitry Andric isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) && 538*753f127fSDimitry Andric MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 && 539*753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 540*753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskIdx0 && 541*753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 542*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n"); 543*753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 544*753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 545*753f127fSDimitry Andric DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT), 546*753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 547*753f127fSDimitry Andric } 548*753f127fSDimitry Andric 549*753f127fSDimitry Andric // 2nd pattern to match BSTRINS: 550*753f127fSDimitry Andric // R = or (and X, mask0), (shl (and Y, mask1), lsb) 551*753f127fSDimitry Andric // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb) 552*753f127fSDimitry Andric // => 553*753f127fSDimitry Andric // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1) 554*753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 555*753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 556*753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 557*753f127fSDimitry Andric N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND && 558*753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 559*753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskIdx0 && 560*753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 561*753f127fSDimitry Andric isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) && 562*753f127fSDimitry Andric MaskLen0 == MaskLen1 && MaskIdx1 == 0 && 563*753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 564*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n"); 565*753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 566*753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 567*753f127fSDimitry Andric DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT), 568*753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 569*753f127fSDimitry Andric } 570*753f127fSDimitry Andric 571*753f127fSDimitry Andric // 3rd pattern to match BSTRINS: 572*753f127fSDimitry Andric // R = or (and X, mask0), (and Y, mask1) 573*753f127fSDimitry Andric // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0 574*753f127fSDimitry Andric // => 575*753f127fSDimitry Andric // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb 576*753f127fSDimitry Andric // where msb = lsb + size - 1 577*753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND && 578*753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 579*753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 580*753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= 64) && 581*753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) && 582*753f127fSDimitry Andric (CN1->getSExtValue() & CN0->getSExtValue()) == 0) { 583*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n"); 584*753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 585*753f127fSDimitry Andric DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1, 586*753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)), 587*753f127fSDimitry Andric DAG.getConstant(ValBits == 32 588*753f127fSDimitry Andric ? (MaskIdx0 + (MaskLen0 & 31) - 1) 589*753f127fSDimitry Andric : (MaskIdx0 + MaskLen0 - 1), 590*753f127fSDimitry Andric DL, GRLenVT), 591*753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 592*753f127fSDimitry Andric } 593*753f127fSDimitry Andric 594*753f127fSDimitry Andric // 4th pattern to match BSTRINS: 595*753f127fSDimitry Andric // R = or (and X, mask), (shl Y, shamt) 596*753f127fSDimitry Andric // where mask = (2**shamt - 1) 597*753f127fSDimitry Andric // => 598*753f127fSDimitry Andric // R = BSTRINS X, Y, ValBits - 1, shamt 599*753f127fSDimitry Andric // where ValBits = 32 or 64 600*753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL && 601*753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 602*753f127fSDimitry Andric isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) && 603*753f127fSDimitry Andric MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 604*753f127fSDimitry Andric (Shamt = CN1->getZExtValue()) == MaskLen0 && 605*753f127fSDimitry Andric (MaskIdx0 + MaskLen0 <= ValBits)) { 606*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n"); 607*753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 608*753f127fSDimitry Andric N1.getOperand(0), 609*753f127fSDimitry Andric DAG.getConstant((ValBits - 1), DL, GRLenVT), 610*753f127fSDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 611*753f127fSDimitry Andric } 612*753f127fSDimitry Andric 613*753f127fSDimitry Andric // 5th pattern to match BSTRINS: 614*753f127fSDimitry Andric // R = or (and X, mask), const 615*753f127fSDimitry Andric // where ~mask = (2**size - 1) << lsb, mask & const = 0 616*753f127fSDimitry Andric // => 617*753f127fSDimitry Andric // R = BSTRINS X, (const >> lsb), msb, lsb 618*753f127fSDimitry Andric // where msb = lsb + size - 1 619*753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && 620*753f127fSDimitry Andric (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) && 621*753f127fSDimitry Andric isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) && 622*753f127fSDimitry Andric (CN1 = dyn_cast<ConstantSDNode>(N1)) && 623*753f127fSDimitry Andric (CN1->getSExtValue() & CN0->getSExtValue()) == 0) { 624*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n"); 625*753f127fSDimitry Andric return DAG.getNode( 626*753f127fSDimitry Andric LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0), 627*753f127fSDimitry Andric DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy), 628*753f127fSDimitry Andric DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT), 629*753f127fSDimitry Andric DAG.getConstant(MaskIdx0, DL, GRLenVT)); 630*753f127fSDimitry Andric } 631*753f127fSDimitry Andric 632*753f127fSDimitry Andric // 6th pattern. 633*753f127fSDimitry Andric // a = b | ((c & mask) << shamt), where all positions in b to be overwritten 634*753f127fSDimitry Andric // by the incoming bits are known to be zero. 635*753f127fSDimitry Andric // => 636*753f127fSDimitry Andric // a = BSTRINS b, c, shamt + MaskLen - 1, shamt 637*753f127fSDimitry Andric // 638*753f127fSDimitry Andric // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th 639*753f127fSDimitry Andric // pattern is more common than the 1st. So we put the 1st before the 6th in 640*753f127fSDimitry Andric // order to match as many nodes as possible. 641*753f127fSDimitry Andric ConstantSDNode *CNMask, *CNShamt; 642*753f127fSDimitry Andric unsigned MaskIdx, MaskLen; 643*753f127fSDimitry Andric if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND && 644*753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 645*753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) && 646*753f127fSDimitry Andric MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 647*753f127fSDimitry Andric CNShamt->getZExtValue() + MaskLen <= ValBits) { 648*753f127fSDimitry Andric Shamt = CNShamt->getZExtValue(); 649*753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt); 650*753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 651*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n"); 652*753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 653*753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 654*753f127fSDimitry Andric DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT), 655*753f127fSDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 656*753f127fSDimitry Andric } 657*753f127fSDimitry Andric } 658*753f127fSDimitry Andric 659*753f127fSDimitry Andric // 7th pattern. 660*753f127fSDimitry Andric // a = b | ((c << shamt) & shifted_mask), where all positions in b to be 661*753f127fSDimitry Andric // overwritten by the incoming bits are known to be zero. 662*753f127fSDimitry Andric // => 663*753f127fSDimitry Andric // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx 664*753f127fSDimitry Andric // 665*753f127fSDimitry Andric // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd 666*753f127fSDimitry Andric // before the 7th in order to match as many nodes as possible. 667*753f127fSDimitry Andric if (N1.getOpcode() == ISD::AND && 668*753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 669*753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) && 670*753f127fSDimitry Andric N1.getOperand(0).getOpcode() == ISD::SHL && 671*753f127fSDimitry Andric (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) && 672*753f127fSDimitry Andric CNShamt->getZExtValue() == MaskIdx) { 673*753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue()); 674*753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 675*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n"); 676*753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 677*753f127fSDimitry Andric N1.getOperand(0).getOperand(0), 678*753f127fSDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 679*753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)); 680*753f127fSDimitry Andric } 681*753f127fSDimitry Andric } 682*753f127fSDimitry Andric 683*753f127fSDimitry Andric // (or a, b) and (or b, a) are equivalent, so swap the operands and retry. 684*753f127fSDimitry Andric if (!SwapAndRetried) { 685*753f127fSDimitry Andric std::swap(N0, N1); 686*753f127fSDimitry Andric SwapAndRetried = true; 687*753f127fSDimitry Andric goto Retry; 688*753f127fSDimitry Andric } 689*753f127fSDimitry Andric 690*753f127fSDimitry Andric SwapAndRetried = false; 691*753f127fSDimitry Andric Retry2: 692*753f127fSDimitry Andric // 8th pattern. 693*753f127fSDimitry Andric // a = b | (c & shifted_mask), where all positions in b to be overwritten by 694*753f127fSDimitry Andric // the incoming bits are known to be zero. 695*753f127fSDimitry Andric // => 696*753f127fSDimitry Andric // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx 697*753f127fSDimitry Andric // 698*753f127fSDimitry Andric // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So 699*753f127fSDimitry Andric // we put it here in order to match as many nodes as possible or generate less 700*753f127fSDimitry Andric // instructions. 701*753f127fSDimitry Andric if (N1.getOpcode() == ISD::AND && 702*753f127fSDimitry Andric (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) && 703*753f127fSDimitry Andric isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) { 704*753f127fSDimitry Andric APInt ShMask(ValBits, CNMask->getZExtValue()); 705*753f127fSDimitry Andric if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) { 706*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n"); 707*753f127fSDimitry Andric return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0, 708*753f127fSDimitry Andric DAG.getNode(ISD::SRL, DL, N1->getValueType(0), 709*753f127fSDimitry Andric N1->getOperand(0), 710*753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)), 711*753f127fSDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 712*753f127fSDimitry Andric DAG.getConstant(MaskIdx, DL, GRLenVT)); 713*753f127fSDimitry Andric } 714*753f127fSDimitry Andric } 715*753f127fSDimitry Andric // Swap N0/N1 and retry. 716*753f127fSDimitry Andric if (!SwapAndRetried) { 717*753f127fSDimitry Andric std::swap(N0, N1); 718*753f127fSDimitry Andric SwapAndRetried = true; 719*753f127fSDimitry Andric goto Retry2; 720*753f127fSDimitry Andric } 721*753f127fSDimitry Andric 722*753f127fSDimitry Andric return SDValue(); 723*753f127fSDimitry Andric } 724*753f127fSDimitry Andric 72581ad6265SDimitry Andric SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N, 72681ad6265SDimitry Andric DAGCombinerInfo &DCI) const { 72781ad6265SDimitry Andric SelectionDAG &DAG = DCI.DAG; 72881ad6265SDimitry Andric switch (N->getOpcode()) { 72981ad6265SDimitry Andric default: 73081ad6265SDimitry Andric break; 73181ad6265SDimitry Andric case ISD::AND: 73281ad6265SDimitry Andric return performANDCombine(N, DAG, DCI, Subtarget); 733*753f127fSDimitry Andric case ISD::OR: 734*753f127fSDimitry Andric return performORCombine(N, DAG, DCI, Subtarget); 73581ad6265SDimitry Andric case ISD::SRL: 73681ad6265SDimitry Andric return performSRLCombine(N, DAG, DCI, Subtarget); 73781ad6265SDimitry Andric } 73881ad6265SDimitry Andric return SDValue(); 73981ad6265SDimitry Andric } 74081ad6265SDimitry Andric 741*753f127fSDimitry Andric static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI, 742*753f127fSDimitry Andric MachineBasicBlock &MBB, 743*753f127fSDimitry Andric const TargetInstrInfo &TII) { 744*753f127fSDimitry Andric if (!ZeroDivCheck) 745*753f127fSDimitry Andric return &MBB; 746*753f127fSDimitry Andric 747*753f127fSDimitry Andric // Build instructions: 748*753f127fSDimitry Andric // div(or mod) $dst, $dividend, $divisor 749*753f127fSDimitry Andric // bnez $divisor, 8 750*753f127fSDimitry Andric // break 7 751*753f127fSDimitry Andric // fallthrough 752*753f127fSDimitry Andric MachineOperand &Divisor = MI.getOperand(2); 753*753f127fSDimitry Andric auto FallThrough = std::next(MI.getIterator()); 754*753f127fSDimitry Andric 755*753f127fSDimitry Andric BuildMI(MBB, FallThrough, MI.getDebugLoc(), TII.get(LoongArch::BNEZ)) 756*753f127fSDimitry Andric .addReg(Divisor.getReg(), getKillRegState(Divisor.isKill())) 757*753f127fSDimitry Andric .addImm(8); 758*753f127fSDimitry Andric 759*753f127fSDimitry Andric // See linux header file arch/loongarch/include/uapi/asm/break.h for the 760*753f127fSDimitry Andric // definition of BRK_DIVZERO. 761*753f127fSDimitry Andric BuildMI(MBB, FallThrough, MI.getDebugLoc(), TII.get(LoongArch::BREAK)) 762*753f127fSDimitry Andric .addImm(7/*BRK_DIVZERO*/); 763*753f127fSDimitry Andric 764*753f127fSDimitry Andric // Clear Divisor's kill flag. 765*753f127fSDimitry Andric Divisor.setIsKill(false); 766*753f127fSDimitry Andric 767*753f127fSDimitry Andric return &MBB; 768*753f127fSDimitry Andric } 769*753f127fSDimitry Andric 770*753f127fSDimitry Andric MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter( 771*753f127fSDimitry Andric MachineInstr &MI, MachineBasicBlock *BB) const { 772*753f127fSDimitry Andric 773*753f127fSDimitry Andric switch (MI.getOpcode()) { 774*753f127fSDimitry Andric default: 775*753f127fSDimitry Andric llvm_unreachable("Unexpected instr type to insert"); 776*753f127fSDimitry Andric case LoongArch::DIV_W: 777*753f127fSDimitry Andric case LoongArch::DIV_WU: 778*753f127fSDimitry Andric case LoongArch::MOD_W: 779*753f127fSDimitry Andric case LoongArch::MOD_WU: 780*753f127fSDimitry Andric case LoongArch::DIV_D: 781*753f127fSDimitry Andric case LoongArch::DIV_DU: 782*753f127fSDimitry Andric case LoongArch::MOD_D: 783*753f127fSDimitry Andric case LoongArch::MOD_DU: 784*753f127fSDimitry Andric return insertDivByZeroTrap(MI, *BB, *Subtarget.getInstrInfo()); 785*753f127fSDimitry Andric break; 786*753f127fSDimitry Andric } 787*753f127fSDimitry Andric } 788*753f127fSDimitry Andric 78981ad6265SDimitry Andric const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const { 79081ad6265SDimitry Andric switch ((LoongArchISD::NodeType)Opcode) { 79181ad6265SDimitry Andric case LoongArchISD::FIRST_NUMBER: 79281ad6265SDimitry Andric break; 79381ad6265SDimitry Andric 79481ad6265SDimitry Andric #define NODE_NAME_CASE(node) \ 79581ad6265SDimitry Andric case LoongArchISD::node: \ 79681ad6265SDimitry Andric return "LoongArchISD::" #node; 79781ad6265SDimitry Andric 79881ad6265SDimitry Andric // TODO: Add more target-dependent nodes later. 799*753f127fSDimitry Andric NODE_NAME_CASE(CALL) 80081ad6265SDimitry Andric NODE_NAME_CASE(RET) 80181ad6265SDimitry Andric NODE_NAME_CASE(SLL_W) 80281ad6265SDimitry Andric NODE_NAME_CASE(SRA_W) 80381ad6265SDimitry Andric NODE_NAME_CASE(SRL_W) 804*753f127fSDimitry Andric NODE_NAME_CASE(BSTRINS) 80581ad6265SDimitry Andric NODE_NAME_CASE(BSTRPICK) 806*753f127fSDimitry Andric NODE_NAME_CASE(MOVGR2FR_W_LA64) 807*753f127fSDimitry Andric NODE_NAME_CASE(MOVFR2GR_S_LA64) 808*753f127fSDimitry Andric NODE_NAME_CASE(FTINT) 80981ad6265SDimitry Andric } 81081ad6265SDimitry Andric #undef NODE_NAME_CASE 81181ad6265SDimitry Andric return nullptr; 81281ad6265SDimitry Andric } 81381ad6265SDimitry Andric 81481ad6265SDimitry Andric //===----------------------------------------------------------------------===// 81581ad6265SDimitry Andric // Calling Convention Implementation 81681ad6265SDimitry Andric //===----------------------------------------------------------------------===// 81781ad6265SDimitry Andric // FIXME: Now, we only support CallingConv::C with fixed arguments which are 81881ad6265SDimitry Andric // passed with integer or floating-point registers. 81981ad6265SDimitry Andric const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6, 82081ad6265SDimitry Andric LoongArch::R7, LoongArch::R8, LoongArch::R9, 82181ad6265SDimitry Andric LoongArch::R10, LoongArch::R11}; 82281ad6265SDimitry Andric const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2, 82381ad6265SDimitry Andric LoongArch::F3, LoongArch::F4, LoongArch::F5, 82481ad6265SDimitry Andric LoongArch::F6, LoongArch::F7}; 82581ad6265SDimitry Andric const MCPhysReg ArgFPR64s[] = { 82681ad6265SDimitry Andric LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64, 82781ad6265SDimitry Andric LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64}; 82881ad6265SDimitry Andric 82981ad6265SDimitry Andric // Implements the LoongArch calling convention. Returns true upon failure. 83081ad6265SDimitry Andric static bool CC_LoongArch(unsigned ValNo, MVT ValVT, 83181ad6265SDimitry Andric CCValAssign::LocInfo LocInfo, CCState &State) { 83281ad6265SDimitry Andric // Allocate to a register if possible. 83381ad6265SDimitry Andric Register Reg; 83481ad6265SDimitry Andric 83581ad6265SDimitry Andric if (ValVT == MVT::f32) 83681ad6265SDimitry Andric Reg = State.AllocateReg(ArgFPR32s); 83781ad6265SDimitry Andric else if (ValVT == MVT::f64) 83881ad6265SDimitry Andric Reg = State.AllocateReg(ArgFPR64s); 83981ad6265SDimitry Andric else 84081ad6265SDimitry Andric Reg = State.AllocateReg(ArgGPRs); 84181ad6265SDimitry Andric if (Reg) { 84281ad6265SDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, ValVT, LocInfo)); 84381ad6265SDimitry Andric return false; 84481ad6265SDimitry Andric } 84581ad6265SDimitry Andric 84681ad6265SDimitry Andric // TODO: Handle arguments passed without register. 84781ad6265SDimitry Andric return true; 84881ad6265SDimitry Andric } 84981ad6265SDimitry Andric 85081ad6265SDimitry Andric void LoongArchTargetLowering::analyzeInputArgs( 85181ad6265SDimitry Andric CCState &CCInfo, const SmallVectorImpl<ISD::InputArg> &Ins, 85281ad6265SDimitry Andric LoongArchCCAssignFn Fn) const { 85381ad6265SDimitry Andric for (unsigned i = 0, e = Ins.size(); i != e; ++i) { 85481ad6265SDimitry Andric MVT ArgVT = Ins[i].VT; 85581ad6265SDimitry Andric 85681ad6265SDimitry Andric if (Fn(i, ArgVT, CCValAssign::Full, CCInfo)) { 85781ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " 85881ad6265SDimitry Andric << EVT(ArgVT).getEVTString() << '\n'); 85981ad6265SDimitry Andric llvm_unreachable(""); 86081ad6265SDimitry Andric } 86181ad6265SDimitry Andric } 86281ad6265SDimitry Andric } 86381ad6265SDimitry Andric 86481ad6265SDimitry Andric void LoongArchTargetLowering::analyzeOutputArgs( 86581ad6265SDimitry Andric CCState &CCInfo, const SmallVectorImpl<ISD::OutputArg> &Outs, 86681ad6265SDimitry Andric LoongArchCCAssignFn Fn) const { 86781ad6265SDimitry Andric for (unsigned i = 0, e = Outs.size(); i != e; ++i) { 86881ad6265SDimitry Andric MVT ArgVT = Outs[i].VT; 86981ad6265SDimitry Andric 87081ad6265SDimitry Andric if (Fn(i, ArgVT, CCValAssign::Full, CCInfo)) { 87181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " 87281ad6265SDimitry Andric << EVT(ArgVT).getEVTString() << "\n"); 87381ad6265SDimitry Andric llvm_unreachable(""); 87481ad6265SDimitry Andric } 87581ad6265SDimitry Andric } 87681ad6265SDimitry Andric } 87781ad6265SDimitry Andric 87881ad6265SDimitry Andric static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain, 87981ad6265SDimitry Andric const CCValAssign &VA, const SDLoc &DL, 88081ad6265SDimitry Andric const LoongArchTargetLowering &TLI) { 88181ad6265SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 88281ad6265SDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 88381ad6265SDimitry Andric EVT LocVT = VA.getLocVT(); 88481ad6265SDimitry Andric const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT()); 88581ad6265SDimitry Andric Register VReg = RegInfo.createVirtualRegister(RC); 88681ad6265SDimitry Andric RegInfo.addLiveIn(VA.getLocReg(), VReg); 88781ad6265SDimitry Andric 88881ad6265SDimitry Andric return DAG.getCopyFromReg(Chain, DL, VReg, LocVT); 88981ad6265SDimitry Andric } 89081ad6265SDimitry Andric 89181ad6265SDimitry Andric // Transform physical registers into virtual registers. 89281ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerFormalArguments( 89381ad6265SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 89481ad6265SDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 89581ad6265SDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 89681ad6265SDimitry Andric 89781ad6265SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 89881ad6265SDimitry Andric 89981ad6265SDimitry Andric switch (CallConv) { 90081ad6265SDimitry Andric default: 90181ad6265SDimitry Andric llvm_unreachable("Unsupported calling convention"); 90281ad6265SDimitry Andric case CallingConv::C: 90381ad6265SDimitry Andric break; 90481ad6265SDimitry Andric } 90581ad6265SDimitry Andric 90681ad6265SDimitry Andric // Assign locations to all of the incoming arguments. 90781ad6265SDimitry Andric SmallVector<CCValAssign> ArgLocs; 90881ad6265SDimitry Andric CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 90981ad6265SDimitry Andric 91081ad6265SDimitry Andric analyzeInputArgs(CCInfo, Ins, CC_LoongArch); 91181ad6265SDimitry Andric 91281ad6265SDimitry Andric for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) 91381ad6265SDimitry Andric InVals.push_back(unpackFromRegLoc(DAG, Chain, ArgLocs[i], DL, *this)); 91481ad6265SDimitry Andric 91581ad6265SDimitry Andric return Chain; 91681ad6265SDimitry Andric } 91781ad6265SDimitry Andric 918*753f127fSDimitry Andric // Lower a call to a callseq_start + CALL + callseq_end chain, and add input 919*753f127fSDimitry Andric // and output parameter nodes. 920*753f127fSDimitry Andric SDValue 921*753f127fSDimitry Andric LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI, 922*753f127fSDimitry Andric SmallVectorImpl<SDValue> &InVals) const { 923*753f127fSDimitry Andric SelectionDAG &DAG = CLI.DAG; 924*753f127fSDimitry Andric SDLoc &DL = CLI.DL; 925*753f127fSDimitry Andric SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; 926*753f127fSDimitry Andric SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; 927*753f127fSDimitry Andric SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; 928*753f127fSDimitry Andric SDValue Chain = CLI.Chain; 929*753f127fSDimitry Andric SDValue Callee = CLI.Callee; 930*753f127fSDimitry Andric CallingConv::ID CallConv = CLI.CallConv; 931*753f127fSDimitry Andric bool IsVarArg = CLI.IsVarArg; 932*753f127fSDimitry Andric EVT PtrVT = getPointerTy(DAG.getDataLayout()); 933*753f127fSDimitry Andric CLI.IsTailCall = false; 934*753f127fSDimitry Andric 935*753f127fSDimitry Andric if (IsVarArg) 936*753f127fSDimitry Andric report_fatal_error("LowerCall with varargs not implemented"); 937*753f127fSDimitry Andric 938*753f127fSDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 939*753f127fSDimitry Andric 940*753f127fSDimitry Andric // Analyze the operands of the call, assigning locations to each operand. 941*753f127fSDimitry Andric SmallVector<CCValAssign> ArgLocs; 942*753f127fSDimitry Andric CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 943*753f127fSDimitry Andric 944*753f127fSDimitry Andric analyzeOutputArgs(ArgCCInfo, Outs, CC_LoongArch); 945*753f127fSDimitry Andric 946*753f127fSDimitry Andric // Get a count of how many bytes are to be pushed on the stack. 947*753f127fSDimitry Andric unsigned NumBytes = ArgCCInfo.getNextStackOffset(); 948*753f127fSDimitry Andric 949*753f127fSDimitry Andric for (auto &Arg : Outs) { 950*753f127fSDimitry Andric if (!Arg.Flags.isByVal()) 951*753f127fSDimitry Andric continue; 952*753f127fSDimitry Andric report_fatal_error("Passing arguments byval not implemented"); 953*753f127fSDimitry Andric } 954*753f127fSDimitry Andric 955*753f127fSDimitry Andric Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL); 956*753f127fSDimitry Andric 957*753f127fSDimitry Andric // Copy argument values to their designated locations. 958*753f127fSDimitry Andric SmallVector<std::pair<Register, SDValue>> RegsToPass; 959*753f127fSDimitry Andric for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { 960*753f127fSDimitry Andric CCValAssign &VA = ArgLocs[i]; 961*753f127fSDimitry Andric SDValue ArgValue = OutVals[i]; 962*753f127fSDimitry Andric 963*753f127fSDimitry Andric // Promote the value if needed. 964*753f127fSDimitry Andric // For now, only handle fully promoted arguments. 965*753f127fSDimitry Andric if (VA.getLocInfo() != CCValAssign::Full) 966*753f127fSDimitry Andric report_fatal_error("Unknown loc info"); 967*753f127fSDimitry Andric 968*753f127fSDimitry Andric if (VA.isRegLoc()) { 969*753f127fSDimitry Andric // Queue up the argument copies and emit them at the end. 970*753f127fSDimitry Andric RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); 971*753f127fSDimitry Andric } else { 972*753f127fSDimitry Andric report_fatal_error("Passing arguments via the stack not implemented"); 973*753f127fSDimitry Andric } 974*753f127fSDimitry Andric } 975*753f127fSDimitry Andric 976*753f127fSDimitry Andric SDValue Glue; 977*753f127fSDimitry Andric 978*753f127fSDimitry Andric // Build a sequence of copy-to-reg nodes, chained and glued together. 979*753f127fSDimitry Andric for (auto &Reg : RegsToPass) { 980*753f127fSDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue); 981*753f127fSDimitry Andric Glue = Chain.getValue(1); 982*753f127fSDimitry Andric } 983*753f127fSDimitry Andric 984*753f127fSDimitry Andric // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a 985*753f127fSDimitry Andric // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't 986*753f127fSDimitry Andric // split it and then direct call can be matched by PseudoCALL. 987*753f127fSDimitry Andric // FIXME: Add target flags for relocation. 988*753f127fSDimitry Andric if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) 989*753f127fSDimitry Andric Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT); 990*753f127fSDimitry Andric else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) 991*753f127fSDimitry Andric Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT); 992*753f127fSDimitry Andric 993*753f127fSDimitry Andric // The first call operand is the chain and the second is the target address. 994*753f127fSDimitry Andric SmallVector<SDValue> Ops; 995*753f127fSDimitry Andric Ops.push_back(Chain); 996*753f127fSDimitry Andric Ops.push_back(Callee); 997*753f127fSDimitry Andric 998*753f127fSDimitry Andric // Add argument registers to the end of the list so that they are 999*753f127fSDimitry Andric // known live into the call. 1000*753f127fSDimitry Andric for (auto &Reg : RegsToPass) 1001*753f127fSDimitry Andric Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType())); 1002*753f127fSDimitry Andric 1003*753f127fSDimitry Andric // Add a register mask operand representing the call-preserved registers. 1004*753f127fSDimitry Andric const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); 1005*753f127fSDimitry Andric const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv); 1006*753f127fSDimitry Andric assert(Mask && "Missing call preserved mask for calling convention"); 1007*753f127fSDimitry Andric Ops.push_back(DAG.getRegisterMask(Mask)); 1008*753f127fSDimitry Andric 1009*753f127fSDimitry Andric // Glue the call to the argument copies, if any. 1010*753f127fSDimitry Andric if (Glue.getNode()) 1011*753f127fSDimitry Andric Ops.push_back(Glue); 1012*753f127fSDimitry Andric 1013*753f127fSDimitry Andric // Emit the call. 1014*753f127fSDimitry Andric SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); 1015*753f127fSDimitry Andric 1016*753f127fSDimitry Andric Chain = DAG.getNode(LoongArchISD::CALL, DL, NodeTys, Ops); 1017*753f127fSDimitry Andric DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge); 1018*753f127fSDimitry Andric Glue = Chain.getValue(1); 1019*753f127fSDimitry Andric 1020*753f127fSDimitry Andric // Mark the end of the call, which is glued to the call itself. 1021*753f127fSDimitry Andric Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, DL, PtrVT, true), 1022*753f127fSDimitry Andric DAG.getConstant(0, DL, PtrVT, true), Glue, DL); 1023*753f127fSDimitry Andric Glue = Chain.getValue(1); 1024*753f127fSDimitry Andric 1025*753f127fSDimitry Andric // Assign locations to each value returned by this call. 1026*753f127fSDimitry Andric SmallVector<CCValAssign> RVLocs; 1027*753f127fSDimitry Andric CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); 1028*753f127fSDimitry Andric analyzeInputArgs(RetCCInfo, Ins, CC_LoongArch); 1029*753f127fSDimitry Andric 1030*753f127fSDimitry Andric // Copy all of the result registers out of their specified physreg. 1031*753f127fSDimitry Andric for (auto &VA : RVLocs) { 1032*753f127fSDimitry Andric // Copy the value out. 1033*753f127fSDimitry Andric SDValue RetValue = 1034*753f127fSDimitry Andric DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue); 1035*753f127fSDimitry Andric Chain = RetValue.getValue(1); 1036*753f127fSDimitry Andric Glue = RetValue.getValue(2); 1037*753f127fSDimitry Andric 1038*753f127fSDimitry Andric InVals.push_back(Chain.getValue(0)); 1039*753f127fSDimitry Andric } 1040*753f127fSDimitry Andric 1041*753f127fSDimitry Andric return Chain; 1042*753f127fSDimitry Andric } 1043*753f127fSDimitry Andric 104481ad6265SDimitry Andric bool LoongArchTargetLowering::CanLowerReturn( 104581ad6265SDimitry Andric CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, 104681ad6265SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { 104781ad6265SDimitry Andric // Any return value split in to more than two values can't be returned 104881ad6265SDimitry Andric // directly. 104981ad6265SDimitry Andric return Outs.size() <= 2; 105081ad6265SDimitry Andric } 105181ad6265SDimitry Andric 105281ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerReturn( 105381ad6265SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 105481ad6265SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, 105581ad6265SDimitry Andric const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, 105681ad6265SDimitry Andric SelectionDAG &DAG) const { 105781ad6265SDimitry Andric // Stores the assignment of the return value to a location. 105881ad6265SDimitry Andric SmallVector<CCValAssign> RVLocs; 105981ad6265SDimitry Andric 106081ad6265SDimitry Andric // Info about the registers and stack slot. 106181ad6265SDimitry Andric CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, 106281ad6265SDimitry Andric *DAG.getContext()); 106381ad6265SDimitry Andric 106481ad6265SDimitry Andric analyzeOutputArgs(CCInfo, Outs, CC_LoongArch); 106581ad6265SDimitry Andric 106681ad6265SDimitry Andric SDValue Glue; 106781ad6265SDimitry Andric SmallVector<SDValue, 4> RetOps(1, Chain); 106881ad6265SDimitry Andric 106981ad6265SDimitry Andric // Copy the result values into the output registers. 107081ad6265SDimitry Andric for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) { 107181ad6265SDimitry Andric CCValAssign &VA = RVLocs[i]; 107281ad6265SDimitry Andric assert(VA.isRegLoc() && "Can only return in registers!"); 107381ad6265SDimitry Andric 107481ad6265SDimitry Andric // Handle a 'normal' return. 107581ad6265SDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Glue); 107681ad6265SDimitry Andric 107781ad6265SDimitry Andric // Guarantee that all emitted copies are stuck together. 107881ad6265SDimitry Andric Glue = Chain.getValue(1); 107981ad6265SDimitry Andric RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); 108081ad6265SDimitry Andric } 108181ad6265SDimitry Andric 108281ad6265SDimitry Andric RetOps[0] = Chain; // Update chain. 108381ad6265SDimitry Andric 108481ad6265SDimitry Andric // Add the glue node if we have it. 108581ad6265SDimitry Andric if (Glue.getNode()) 108681ad6265SDimitry Andric RetOps.push_back(Glue); 108781ad6265SDimitry Andric 108881ad6265SDimitry Andric return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps); 108981ad6265SDimitry Andric } 1090*753f127fSDimitry Andric 1091*753f127fSDimitry Andric bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, 1092*753f127fSDimitry Andric bool ForCodeSize) const { 1093*753f127fSDimitry Andric assert((VT == MVT::f32 || VT == MVT::f64) && "Unexpected VT"); 1094*753f127fSDimitry Andric 1095*753f127fSDimitry Andric if (VT == MVT::f32 && !Subtarget.hasBasicF()) 1096*753f127fSDimitry Andric return false; 1097*753f127fSDimitry Andric if (VT == MVT::f64 && !Subtarget.hasBasicD()) 1098*753f127fSDimitry Andric return false; 1099*753f127fSDimitry Andric return (Imm.isZero() || Imm.isExactlyValue(+1.0)); 1100*753f127fSDimitry Andric } 1101