1*81ad6265SDimitry Andric //=- LoongArchISelLowering.cpp - LoongArch DAG Lowering Implementation ---===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric // 9*81ad6265SDimitry Andric // This file defines the interfaces that LoongArch uses to lower LLVM code into 10*81ad6265SDimitry Andric // a selection DAG. 11*81ad6265SDimitry Andric // 12*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 13*81ad6265SDimitry Andric 14*81ad6265SDimitry Andric #include "LoongArchISelLowering.h" 15*81ad6265SDimitry Andric #include "LoongArch.h" 16*81ad6265SDimitry Andric #include "LoongArchMachineFunctionInfo.h" 17*81ad6265SDimitry Andric #include "LoongArchRegisterInfo.h" 18*81ad6265SDimitry Andric #include "LoongArchSubtarget.h" 19*81ad6265SDimitry Andric #include "LoongArchTargetMachine.h" 20*81ad6265SDimitry Andric #include "llvm/ADT/Statistic.h" 21*81ad6265SDimitry Andric #include "llvm/CodeGen/ISDOpcodes.h" 22*81ad6265SDimitry Andric #include "llvm/Support/Debug.h" 23*81ad6265SDimitry Andric 24*81ad6265SDimitry Andric using namespace llvm; 25*81ad6265SDimitry Andric 26*81ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-isel-lowering" 27*81ad6265SDimitry Andric 28*81ad6265SDimitry Andric LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM, 29*81ad6265SDimitry Andric const LoongArchSubtarget &STI) 30*81ad6265SDimitry Andric : TargetLowering(TM), Subtarget(STI) { 31*81ad6265SDimitry Andric 32*81ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 33*81ad6265SDimitry Andric // Set up the register classes. 34*81ad6265SDimitry Andric addRegisterClass(GRLenVT, &LoongArch::GPRRegClass); 35*81ad6265SDimitry Andric if (Subtarget.hasBasicF()) 36*81ad6265SDimitry Andric addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass); 37*81ad6265SDimitry Andric if (Subtarget.hasBasicD()) 38*81ad6265SDimitry Andric addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass); 39*81ad6265SDimitry Andric 40*81ad6265SDimitry Andric // TODO: add necessary setOperationAction calls later. 41*81ad6265SDimitry Andric setOperationAction(ISD::SHL_PARTS, GRLenVT, Custom); 42*81ad6265SDimitry Andric setOperationAction(ISD::SRA_PARTS, GRLenVT, Custom); 43*81ad6265SDimitry Andric setOperationAction(ISD::SRL_PARTS, GRLenVT, Custom); 44*81ad6265SDimitry Andric 45*81ad6265SDimitry Andric if (Subtarget.is64Bit()) { 46*81ad6265SDimitry Andric setOperationAction(ISD::SHL, MVT::i32, Custom); 47*81ad6265SDimitry Andric setOperationAction(ISD::SRA, MVT::i32, Custom); 48*81ad6265SDimitry Andric setOperationAction(ISD::SRL, MVT::i32, Custom); 49*81ad6265SDimitry Andric } 50*81ad6265SDimitry Andric 51*81ad6265SDimitry Andric static const ISD::CondCode FPCCToExpand[] = {ISD::SETOGT, ISD::SETOGE, 52*81ad6265SDimitry Andric ISD::SETUGT, ISD::SETUGE}; 53*81ad6265SDimitry Andric 54*81ad6265SDimitry Andric if (Subtarget.hasBasicF()) { 55*81ad6265SDimitry Andric setCondCodeAction(FPCCToExpand, MVT::f32, Expand); 56*81ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::f32, Expand); 57*81ad6265SDimitry Andric } 58*81ad6265SDimitry Andric if (Subtarget.hasBasicD()) { 59*81ad6265SDimitry Andric setCondCodeAction(FPCCToExpand, MVT::f64, Expand); 60*81ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::f64, Expand); 61*81ad6265SDimitry Andric } 62*81ad6265SDimitry Andric 63*81ad6265SDimitry Andric setOperationAction(ISD::SELECT_CC, GRLenVT, Expand); 64*81ad6265SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); 65*81ad6265SDimitry Andric 66*81ad6265SDimitry Andric // Compute derived properties from the register classes. 67*81ad6265SDimitry Andric computeRegisterProperties(STI.getRegisterInfo()); 68*81ad6265SDimitry Andric 69*81ad6265SDimitry Andric setStackPointerRegisterToSaveRestore(LoongArch::R3); 70*81ad6265SDimitry Andric 71*81ad6265SDimitry Andric setBooleanContents(ZeroOrOneBooleanContent); 72*81ad6265SDimitry Andric 73*81ad6265SDimitry Andric // Function alignments. 74*81ad6265SDimitry Andric const Align FunctionAlignment(4); 75*81ad6265SDimitry Andric setMinFunctionAlignment(FunctionAlignment); 76*81ad6265SDimitry Andric 77*81ad6265SDimitry Andric setTargetDAGCombine(ISD::AND); 78*81ad6265SDimitry Andric setTargetDAGCombine(ISD::SRL); 79*81ad6265SDimitry Andric } 80*81ad6265SDimitry Andric 81*81ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerOperation(SDValue Op, 82*81ad6265SDimitry Andric SelectionDAG &DAG) const { 83*81ad6265SDimitry Andric switch (Op.getOpcode()) { 84*81ad6265SDimitry Andric default: 85*81ad6265SDimitry Andric report_fatal_error("unimplemented operand"); 86*81ad6265SDimitry Andric case ISD::SHL_PARTS: 87*81ad6265SDimitry Andric return lowerShiftLeftParts(Op, DAG); 88*81ad6265SDimitry Andric case ISD::SRA_PARTS: 89*81ad6265SDimitry Andric return lowerShiftRightParts(Op, DAG, true); 90*81ad6265SDimitry Andric case ISD::SRL_PARTS: 91*81ad6265SDimitry Andric return lowerShiftRightParts(Op, DAG, false); 92*81ad6265SDimitry Andric case ISD::SHL: 93*81ad6265SDimitry Andric case ISD::SRA: 94*81ad6265SDimitry Andric case ISD::SRL: 95*81ad6265SDimitry Andric // This can be called for an i32 shift amount that needs to be promoted. 96*81ad6265SDimitry Andric assert(Op.getOperand(1).getValueType() == MVT::i32 && Subtarget.is64Bit() && 97*81ad6265SDimitry Andric "Unexpected custom legalisation"); 98*81ad6265SDimitry Andric return SDValue(); 99*81ad6265SDimitry Andric } 100*81ad6265SDimitry Andric } 101*81ad6265SDimitry Andric 102*81ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op, 103*81ad6265SDimitry Andric SelectionDAG &DAG) const { 104*81ad6265SDimitry Andric SDLoc DL(Op); 105*81ad6265SDimitry Andric SDValue Lo = Op.getOperand(0); 106*81ad6265SDimitry Andric SDValue Hi = Op.getOperand(1); 107*81ad6265SDimitry Andric SDValue Shamt = Op.getOperand(2); 108*81ad6265SDimitry Andric EVT VT = Lo.getValueType(); 109*81ad6265SDimitry Andric 110*81ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 111*81ad6265SDimitry Andric // Lo = Lo << Shamt 112*81ad6265SDimitry Andric // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt)) 113*81ad6265SDimitry Andric // else: 114*81ad6265SDimitry Andric // Lo = 0 115*81ad6265SDimitry Andric // Hi = Lo << (Shamt-GRLen) 116*81ad6265SDimitry Andric 117*81ad6265SDimitry Andric SDValue Zero = DAG.getConstant(0, DL, VT); 118*81ad6265SDimitry Andric SDValue One = DAG.getConstant(1, DL, VT); 119*81ad6265SDimitry Andric SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT); 120*81ad6265SDimitry Andric SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT); 121*81ad6265SDimitry Andric SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen); 122*81ad6265SDimitry Andric SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1); 123*81ad6265SDimitry Andric 124*81ad6265SDimitry Andric SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt); 125*81ad6265SDimitry Andric SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One); 126*81ad6265SDimitry Andric SDValue ShiftRightLo = 127*81ad6265SDimitry Andric DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt); 128*81ad6265SDimitry Andric SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt); 129*81ad6265SDimitry Andric SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo); 130*81ad6265SDimitry Andric SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen); 131*81ad6265SDimitry Andric 132*81ad6265SDimitry Andric SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT); 133*81ad6265SDimitry Andric 134*81ad6265SDimitry Andric Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero); 135*81ad6265SDimitry Andric Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); 136*81ad6265SDimitry Andric 137*81ad6265SDimitry Andric SDValue Parts[2] = {Lo, Hi}; 138*81ad6265SDimitry Andric return DAG.getMergeValues(Parts, DL); 139*81ad6265SDimitry Andric } 140*81ad6265SDimitry Andric 141*81ad6265SDimitry Andric SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op, 142*81ad6265SDimitry Andric SelectionDAG &DAG, 143*81ad6265SDimitry Andric bool IsSRA) const { 144*81ad6265SDimitry Andric SDLoc DL(Op); 145*81ad6265SDimitry Andric SDValue Lo = Op.getOperand(0); 146*81ad6265SDimitry Andric SDValue Hi = Op.getOperand(1); 147*81ad6265SDimitry Andric SDValue Shamt = Op.getOperand(2); 148*81ad6265SDimitry Andric EVT VT = Lo.getValueType(); 149*81ad6265SDimitry Andric 150*81ad6265SDimitry Andric // SRA expansion: 151*81ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 152*81ad6265SDimitry Andric // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1)) 153*81ad6265SDimitry Andric // Hi = Hi >>s Shamt 154*81ad6265SDimitry Andric // else: 155*81ad6265SDimitry Andric // Lo = Hi >>s (Shamt-GRLen); 156*81ad6265SDimitry Andric // Hi = Hi >>s (GRLen-1) 157*81ad6265SDimitry Andric // 158*81ad6265SDimitry Andric // SRL expansion: 159*81ad6265SDimitry Andric // if Shamt-GRLen < 0: // Shamt < GRLen 160*81ad6265SDimitry Andric // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1)) 161*81ad6265SDimitry Andric // Hi = Hi >>u Shamt 162*81ad6265SDimitry Andric // else: 163*81ad6265SDimitry Andric // Lo = Hi >>u (Shamt-GRLen); 164*81ad6265SDimitry Andric // Hi = 0; 165*81ad6265SDimitry Andric 166*81ad6265SDimitry Andric unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL; 167*81ad6265SDimitry Andric 168*81ad6265SDimitry Andric SDValue Zero = DAG.getConstant(0, DL, VT); 169*81ad6265SDimitry Andric SDValue One = DAG.getConstant(1, DL, VT); 170*81ad6265SDimitry Andric SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT); 171*81ad6265SDimitry Andric SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT); 172*81ad6265SDimitry Andric SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen); 173*81ad6265SDimitry Andric SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1); 174*81ad6265SDimitry Andric 175*81ad6265SDimitry Andric SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt); 176*81ad6265SDimitry Andric SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One); 177*81ad6265SDimitry Andric SDValue ShiftLeftHi = 178*81ad6265SDimitry Andric DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt); 179*81ad6265SDimitry Andric SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi); 180*81ad6265SDimitry Andric SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt); 181*81ad6265SDimitry Andric SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen); 182*81ad6265SDimitry Andric SDValue HiFalse = 183*81ad6265SDimitry Andric IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero; 184*81ad6265SDimitry Andric 185*81ad6265SDimitry Andric SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT); 186*81ad6265SDimitry Andric 187*81ad6265SDimitry Andric Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse); 188*81ad6265SDimitry Andric Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); 189*81ad6265SDimitry Andric 190*81ad6265SDimitry Andric SDValue Parts[2] = {Lo, Hi}; 191*81ad6265SDimitry Andric return DAG.getMergeValues(Parts, DL); 192*81ad6265SDimitry Andric } 193*81ad6265SDimitry Andric 194*81ad6265SDimitry Andric // Returns the opcode of the target-specific SDNode that implements the 32-bit 195*81ad6265SDimitry Andric // form of the given Opcode. 196*81ad6265SDimitry Andric static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode) { 197*81ad6265SDimitry Andric switch (Opcode) { 198*81ad6265SDimitry Andric default: 199*81ad6265SDimitry Andric llvm_unreachable("Unexpected opcode"); 200*81ad6265SDimitry Andric case ISD::SHL: 201*81ad6265SDimitry Andric return LoongArchISD::SLL_W; 202*81ad6265SDimitry Andric case ISD::SRA: 203*81ad6265SDimitry Andric return LoongArchISD::SRA_W; 204*81ad6265SDimitry Andric case ISD::SRL: 205*81ad6265SDimitry Andric return LoongArchISD::SRL_W; 206*81ad6265SDimitry Andric } 207*81ad6265SDimitry Andric } 208*81ad6265SDimitry Andric 209*81ad6265SDimitry Andric // Converts the given i8/i16/i32 operation to a target-specific SelectionDAG 210*81ad6265SDimitry Andric // node. Because i8/i16/i32 isn't a legal type for LA64, these operations would 211*81ad6265SDimitry Andric // otherwise be promoted to i64, making it difficult to select the 212*81ad6265SDimitry Andric // SLL_W/.../*W later one because the fact the operation was originally of 213*81ad6265SDimitry Andric // type i8/i16/i32 is lost. 214*81ad6265SDimitry Andric static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, 215*81ad6265SDimitry Andric unsigned ExtOpc = ISD::ANY_EXTEND) { 216*81ad6265SDimitry Andric SDLoc DL(N); 217*81ad6265SDimitry Andric LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode()); 218*81ad6265SDimitry Andric SDValue NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0)); 219*81ad6265SDimitry Andric SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1)); 220*81ad6265SDimitry Andric SDValue NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1); 221*81ad6265SDimitry Andric // ReplaceNodeResults requires we maintain the same type for the return value. 222*81ad6265SDimitry Andric return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes); 223*81ad6265SDimitry Andric } 224*81ad6265SDimitry Andric 225*81ad6265SDimitry Andric void LoongArchTargetLowering::ReplaceNodeResults( 226*81ad6265SDimitry Andric SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const { 227*81ad6265SDimitry Andric SDLoc DL(N); 228*81ad6265SDimitry Andric switch (N->getOpcode()) { 229*81ad6265SDimitry Andric default: 230*81ad6265SDimitry Andric llvm_unreachable("Don't know how to legalize this operation"); 231*81ad6265SDimitry Andric case ISD::SHL: 232*81ad6265SDimitry Andric case ISD::SRA: 233*81ad6265SDimitry Andric case ISD::SRL: 234*81ad6265SDimitry Andric assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && 235*81ad6265SDimitry Andric "Unexpected custom legalisation"); 236*81ad6265SDimitry Andric if (N->getOperand(1).getOpcode() != ISD::Constant) { 237*81ad6265SDimitry Andric Results.push_back(customLegalizeToWOp(N, DAG)); 238*81ad6265SDimitry Andric break; 239*81ad6265SDimitry Andric } 240*81ad6265SDimitry Andric break; 241*81ad6265SDimitry Andric } 242*81ad6265SDimitry Andric } 243*81ad6265SDimitry Andric 244*81ad6265SDimitry Andric static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, 245*81ad6265SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 246*81ad6265SDimitry Andric const LoongArchSubtarget &Subtarget) { 247*81ad6265SDimitry Andric if (DCI.isBeforeLegalizeOps()) 248*81ad6265SDimitry Andric return SDValue(); 249*81ad6265SDimitry Andric 250*81ad6265SDimitry Andric SDValue FirstOperand = N->getOperand(0); 251*81ad6265SDimitry Andric SDValue SecondOperand = N->getOperand(1); 252*81ad6265SDimitry Andric unsigned FirstOperandOpc = FirstOperand.getOpcode(); 253*81ad6265SDimitry Andric EVT ValTy = N->getValueType(0); 254*81ad6265SDimitry Andric SDLoc DL(N); 255*81ad6265SDimitry Andric uint64_t lsb, msb; 256*81ad6265SDimitry Andric unsigned SMIdx, SMLen; 257*81ad6265SDimitry Andric ConstantSDNode *CN; 258*81ad6265SDimitry Andric SDValue NewOperand; 259*81ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 260*81ad6265SDimitry Andric 261*81ad6265SDimitry Andric // Op's second operand must be a shifted mask. 262*81ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) || 263*81ad6265SDimitry Andric !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen)) 264*81ad6265SDimitry Andric return SDValue(); 265*81ad6265SDimitry Andric 266*81ad6265SDimitry Andric if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) { 267*81ad6265SDimitry Andric // Pattern match BSTRPICK. 268*81ad6265SDimitry Andric // $dst = and ((sra or srl) $src , lsb), (2**len - 1) 269*81ad6265SDimitry Andric // => BSTRPICK $dst, $src, msb, lsb 270*81ad6265SDimitry Andric // where msb = lsb + len - 1 271*81ad6265SDimitry Andric 272*81ad6265SDimitry Andric // The second operand of the shift must be an immediate. 273*81ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1)))) 274*81ad6265SDimitry Andric return SDValue(); 275*81ad6265SDimitry Andric 276*81ad6265SDimitry Andric lsb = CN->getZExtValue(); 277*81ad6265SDimitry Andric 278*81ad6265SDimitry Andric // Return if the shifted mask does not start at bit 0 or the sum of its 279*81ad6265SDimitry Andric // length and lsb exceeds the word's size. 280*81ad6265SDimitry Andric if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits()) 281*81ad6265SDimitry Andric return SDValue(); 282*81ad6265SDimitry Andric 283*81ad6265SDimitry Andric NewOperand = FirstOperand.getOperand(0); 284*81ad6265SDimitry Andric } else { 285*81ad6265SDimitry Andric // Pattern match BSTRPICK. 286*81ad6265SDimitry Andric // $dst = and $src, (2**len- 1) , if len > 12 287*81ad6265SDimitry Andric // => BSTRPICK $dst, $src, msb, lsb 288*81ad6265SDimitry Andric // where lsb = 0 and msb = len - 1 289*81ad6265SDimitry Andric 290*81ad6265SDimitry Andric // If the mask is <= 0xfff, andi can be used instead. 291*81ad6265SDimitry Andric if (CN->getZExtValue() <= 0xfff) 292*81ad6265SDimitry Andric return SDValue(); 293*81ad6265SDimitry Andric 294*81ad6265SDimitry Andric // Return if the mask doesn't start at position 0. 295*81ad6265SDimitry Andric if (SMIdx) 296*81ad6265SDimitry Andric return SDValue(); 297*81ad6265SDimitry Andric 298*81ad6265SDimitry Andric lsb = 0; 299*81ad6265SDimitry Andric NewOperand = FirstOperand; 300*81ad6265SDimitry Andric } 301*81ad6265SDimitry Andric msb = lsb + SMLen - 1; 302*81ad6265SDimitry Andric return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand, 303*81ad6265SDimitry Andric DAG.getConstant(msb, DL, GRLenVT), 304*81ad6265SDimitry Andric DAG.getConstant(lsb, DL, GRLenVT)); 305*81ad6265SDimitry Andric } 306*81ad6265SDimitry Andric 307*81ad6265SDimitry Andric static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, 308*81ad6265SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 309*81ad6265SDimitry Andric const LoongArchSubtarget &Subtarget) { 310*81ad6265SDimitry Andric if (DCI.isBeforeLegalizeOps()) 311*81ad6265SDimitry Andric return SDValue(); 312*81ad6265SDimitry Andric 313*81ad6265SDimitry Andric // $dst = srl (and $src, Mask), Shamt 314*81ad6265SDimitry Andric // => 315*81ad6265SDimitry Andric // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt 316*81ad6265SDimitry Andric // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1 317*81ad6265SDimitry Andric // 318*81ad6265SDimitry Andric 319*81ad6265SDimitry Andric SDValue FirstOperand = N->getOperand(0); 320*81ad6265SDimitry Andric ConstantSDNode *CN; 321*81ad6265SDimitry Andric EVT ValTy = N->getValueType(0); 322*81ad6265SDimitry Andric SDLoc DL(N); 323*81ad6265SDimitry Andric MVT GRLenVT = Subtarget.getGRLenVT(); 324*81ad6265SDimitry Andric unsigned MaskIdx, MaskLen; 325*81ad6265SDimitry Andric uint64_t Shamt; 326*81ad6265SDimitry Andric 327*81ad6265SDimitry Andric // The first operand must be an AND and the second operand of the AND must be 328*81ad6265SDimitry Andric // a shifted mask. 329*81ad6265SDimitry Andric if (FirstOperand.getOpcode() != ISD::AND || 330*81ad6265SDimitry Andric !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) || 331*81ad6265SDimitry Andric !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen)) 332*81ad6265SDimitry Andric return SDValue(); 333*81ad6265SDimitry Andric 334*81ad6265SDimitry Andric // The second operand (shift amount) must be an immediate. 335*81ad6265SDimitry Andric if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) 336*81ad6265SDimitry Andric return SDValue(); 337*81ad6265SDimitry Andric 338*81ad6265SDimitry Andric Shamt = CN->getZExtValue(); 339*81ad6265SDimitry Andric if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1) 340*81ad6265SDimitry Andric return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, 341*81ad6265SDimitry Andric FirstOperand->getOperand(0), 342*81ad6265SDimitry Andric DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT), 343*81ad6265SDimitry Andric DAG.getConstant(Shamt, DL, GRLenVT)); 344*81ad6265SDimitry Andric 345*81ad6265SDimitry Andric return SDValue(); 346*81ad6265SDimitry Andric } 347*81ad6265SDimitry Andric 348*81ad6265SDimitry Andric SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N, 349*81ad6265SDimitry Andric DAGCombinerInfo &DCI) const { 350*81ad6265SDimitry Andric SelectionDAG &DAG = DCI.DAG; 351*81ad6265SDimitry Andric switch (N->getOpcode()) { 352*81ad6265SDimitry Andric default: 353*81ad6265SDimitry Andric break; 354*81ad6265SDimitry Andric case ISD::AND: 355*81ad6265SDimitry Andric return performANDCombine(N, DAG, DCI, Subtarget); 356*81ad6265SDimitry Andric case ISD::SRL: 357*81ad6265SDimitry Andric return performSRLCombine(N, DAG, DCI, Subtarget); 358*81ad6265SDimitry Andric } 359*81ad6265SDimitry Andric return SDValue(); 360*81ad6265SDimitry Andric } 361*81ad6265SDimitry Andric 362*81ad6265SDimitry Andric const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const { 363*81ad6265SDimitry Andric switch ((LoongArchISD::NodeType)Opcode) { 364*81ad6265SDimitry Andric case LoongArchISD::FIRST_NUMBER: 365*81ad6265SDimitry Andric break; 366*81ad6265SDimitry Andric 367*81ad6265SDimitry Andric #define NODE_NAME_CASE(node) \ 368*81ad6265SDimitry Andric case LoongArchISD::node: \ 369*81ad6265SDimitry Andric return "LoongArchISD::" #node; 370*81ad6265SDimitry Andric 371*81ad6265SDimitry Andric // TODO: Add more target-dependent nodes later. 372*81ad6265SDimitry Andric NODE_NAME_CASE(RET) 373*81ad6265SDimitry Andric NODE_NAME_CASE(SLL_W) 374*81ad6265SDimitry Andric NODE_NAME_CASE(SRA_W) 375*81ad6265SDimitry Andric NODE_NAME_CASE(SRL_W) 376*81ad6265SDimitry Andric NODE_NAME_CASE(BSTRPICK) 377*81ad6265SDimitry Andric } 378*81ad6265SDimitry Andric #undef NODE_NAME_CASE 379*81ad6265SDimitry Andric return nullptr; 380*81ad6265SDimitry Andric } 381*81ad6265SDimitry Andric 382*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 383*81ad6265SDimitry Andric // Calling Convention Implementation 384*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 385*81ad6265SDimitry Andric // FIXME: Now, we only support CallingConv::C with fixed arguments which are 386*81ad6265SDimitry Andric // passed with integer or floating-point registers. 387*81ad6265SDimitry Andric const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6, 388*81ad6265SDimitry Andric LoongArch::R7, LoongArch::R8, LoongArch::R9, 389*81ad6265SDimitry Andric LoongArch::R10, LoongArch::R11}; 390*81ad6265SDimitry Andric const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2, 391*81ad6265SDimitry Andric LoongArch::F3, LoongArch::F4, LoongArch::F5, 392*81ad6265SDimitry Andric LoongArch::F6, LoongArch::F7}; 393*81ad6265SDimitry Andric const MCPhysReg ArgFPR64s[] = { 394*81ad6265SDimitry Andric LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64, 395*81ad6265SDimitry Andric LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64}; 396*81ad6265SDimitry Andric 397*81ad6265SDimitry Andric // Implements the LoongArch calling convention. Returns true upon failure. 398*81ad6265SDimitry Andric static bool CC_LoongArch(unsigned ValNo, MVT ValVT, 399*81ad6265SDimitry Andric CCValAssign::LocInfo LocInfo, CCState &State) { 400*81ad6265SDimitry Andric // Allocate to a register if possible. 401*81ad6265SDimitry Andric Register Reg; 402*81ad6265SDimitry Andric 403*81ad6265SDimitry Andric if (ValVT == MVT::f32) 404*81ad6265SDimitry Andric Reg = State.AllocateReg(ArgFPR32s); 405*81ad6265SDimitry Andric else if (ValVT == MVT::f64) 406*81ad6265SDimitry Andric Reg = State.AllocateReg(ArgFPR64s); 407*81ad6265SDimitry Andric else 408*81ad6265SDimitry Andric Reg = State.AllocateReg(ArgGPRs); 409*81ad6265SDimitry Andric if (Reg) { 410*81ad6265SDimitry Andric State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, ValVT, LocInfo)); 411*81ad6265SDimitry Andric return false; 412*81ad6265SDimitry Andric } 413*81ad6265SDimitry Andric 414*81ad6265SDimitry Andric // TODO: Handle arguments passed without register. 415*81ad6265SDimitry Andric return true; 416*81ad6265SDimitry Andric } 417*81ad6265SDimitry Andric 418*81ad6265SDimitry Andric void LoongArchTargetLowering::analyzeInputArgs( 419*81ad6265SDimitry Andric CCState &CCInfo, const SmallVectorImpl<ISD::InputArg> &Ins, 420*81ad6265SDimitry Andric LoongArchCCAssignFn Fn) const { 421*81ad6265SDimitry Andric for (unsigned i = 0, e = Ins.size(); i != e; ++i) { 422*81ad6265SDimitry Andric MVT ArgVT = Ins[i].VT; 423*81ad6265SDimitry Andric 424*81ad6265SDimitry Andric if (Fn(i, ArgVT, CCValAssign::Full, CCInfo)) { 425*81ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " 426*81ad6265SDimitry Andric << EVT(ArgVT).getEVTString() << '\n'); 427*81ad6265SDimitry Andric llvm_unreachable(""); 428*81ad6265SDimitry Andric } 429*81ad6265SDimitry Andric } 430*81ad6265SDimitry Andric } 431*81ad6265SDimitry Andric 432*81ad6265SDimitry Andric void LoongArchTargetLowering::analyzeOutputArgs( 433*81ad6265SDimitry Andric CCState &CCInfo, const SmallVectorImpl<ISD::OutputArg> &Outs, 434*81ad6265SDimitry Andric LoongArchCCAssignFn Fn) const { 435*81ad6265SDimitry Andric for (unsigned i = 0, e = Outs.size(); i != e; ++i) { 436*81ad6265SDimitry Andric MVT ArgVT = Outs[i].VT; 437*81ad6265SDimitry Andric 438*81ad6265SDimitry Andric if (Fn(i, ArgVT, CCValAssign::Full, CCInfo)) { 439*81ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " 440*81ad6265SDimitry Andric << EVT(ArgVT).getEVTString() << "\n"); 441*81ad6265SDimitry Andric llvm_unreachable(""); 442*81ad6265SDimitry Andric } 443*81ad6265SDimitry Andric } 444*81ad6265SDimitry Andric } 445*81ad6265SDimitry Andric 446*81ad6265SDimitry Andric static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain, 447*81ad6265SDimitry Andric const CCValAssign &VA, const SDLoc &DL, 448*81ad6265SDimitry Andric const LoongArchTargetLowering &TLI) { 449*81ad6265SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 450*81ad6265SDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 451*81ad6265SDimitry Andric EVT LocVT = VA.getLocVT(); 452*81ad6265SDimitry Andric const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT()); 453*81ad6265SDimitry Andric Register VReg = RegInfo.createVirtualRegister(RC); 454*81ad6265SDimitry Andric RegInfo.addLiveIn(VA.getLocReg(), VReg); 455*81ad6265SDimitry Andric 456*81ad6265SDimitry Andric return DAG.getCopyFromReg(Chain, DL, VReg, LocVT); 457*81ad6265SDimitry Andric } 458*81ad6265SDimitry Andric 459*81ad6265SDimitry Andric // Transform physical registers into virtual registers. 460*81ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerFormalArguments( 461*81ad6265SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 462*81ad6265SDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 463*81ad6265SDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 464*81ad6265SDimitry Andric 465*81ad6265SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 466*81ad6265SDimitry Andric 467*81ad6265SDimitry Andric switch (CallConv) { 468*81ad6265SDimitry Andric default: 469*81ad6265SDimitry Andric llvm_unreachable("Unsupported calling convention"); 470*81ad6265SDimitry Andric case CallingConv::C: 471*81ad6265SDimitry Andric break; 472*81ad6265SDimitry Andric } 473*81ad6265SDimitry Andric 474*81ad6265SDimitry Andric // Assign locations to all of the incoming arguments. 475*81ad6265SDimitry Andric SmallVector<CCValAssign> ArgLocs; 476*81ad6265SDimitry Andric CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 477*81ad6265SDimitry Andric 478*81ad6265SDimitry Andric analyzeInputArgs(CCInfo, Ins, CC_LoongArch); 479*81ad6265SDimitry Andric 480*81ad6265SDimitry Andric for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) 481*81ad6265SDimitry Andric InVals.push_back(unpackFromRegLoc(DAG, Chain, ArgLocs[i], DL, *this)); 482*81ad6265SDimitry Andric 483*81ad6265SDimitry Andric return Chain; 484*81ad6265SDimitry Andric } 485*81ad6265SDimitry Andric 486*81ad6265SDimitry Andric bool LoongArchTargetLowering::CanLowerReturn( 487*81ad6265SDimitry Andric CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, 488*81ad6265SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { 489*81ad6265SDimitry Andric // Any return value split in to more than two values can't be returned 490*81ad6265SDimitry Andric // directly. 491*81ad6265SDimitry Andric return Outs.size() <= 2; 492*81ad6265SDimitry Andric } 493*81ad6265SDimitry Andric 494*81ad6265SDimitry Andric SDValue LoongArchTargetLowering::LowerReturn( 495*81ad6265SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 496*81ad6265SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, 497*81ad6265SDimitry Andric const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, 498*81ad6265SDimitry Andric SelectionDAG &DAG) const { 499*81ad6265SDimitry Andric // Stores the assignment of the return value to a location. 500*81ad6265SDimitry Andric SmallVector<CCValAssign> RVLocs; 501*81ad6265SDimitry Andric 502*81ad6265SDimitry Andric // Info about the registers and stack slot. 503*81ad6265SDimitry Andric CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, 504*81ad6265SDimitry Andric *DAG.getContext()); 505*81ad6265SDimitry Andric 506*81ad6265SDimitry Andric analyzeOutputArgs(CCInfo, Outs, CC_LoongArch); 507*81ad6265SDimitry Andric 508*81ad6265SDimitry Andric SDValue Glue; 509*81ad6265SDimitry Andric SmallVector<SDValue, 4> RetOps(1, Chain); 510*81ad6265SDimitry Andric 511*81ad6265SDimitry Andric // Copy the result values into the output registers. 512*81ad6265SDimitry Andric for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) { 513*81ad6265SDimitry Andric CCValAssign &VA = RVLocs[i]; 514*81ad6265SDimitry Andric assert(VA.isRegLoc() && "Can only return in registers!"); 515*81ad6265SDimitry Andric 516*81ad6265SDimitry Andric // Handle a 'normal' return. 517*81ad6265SDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Glue); 518*81ad6265SDimitry Andric 519*81ad6265SDimitry Andric // Guarantee that all emitted copies are stuck together. 520*81ad6265SDimitry Andric Glue = Chain.getValue(1); 521*81ad6265SDimitry Andric RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); 522*81ad6265SDimitry Andric } 523*81ad6265SDimitry Andric 524*81ad6265SDimitry Andric RetOps[0] = Chain; // Update chain. 525*81ad6265SDimitry Andric 526*81ad6265SDimitry Andric // Add the glue node if we have it. 527*81ad6265SDimitry Andric if (Glue.getNode()) 528*81ad6265SDimitry Andric RetOps.push_back(Glue); 529*81ad6265SDimitry Andric 530*81ad6265SDimitry Andric return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps); 531*81ad6265SDimitry Andric } 532