xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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