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