xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/CSKY/CSKYISelLowering.cpp (revision 0eae32dcef82f6f06de6419a0d623d7def0cc8f6)
1349cc55cSDimitry Andric //===-- CSKYISelLowering.cpp - CSKY DAG Lowering Implementation  ----------===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric //
9349cc55cSDimitry Andric // This file defines the interfaces that CSKY uses to lower LLVM code into a
10349cc55cSDimitry Andric // selection DAG.
11349cc55cSDimitry Andric //
12349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
13349cc55cSDimitry Andric 
14349cc55cSDimitry Andric #include "CSKYISelLowering.h"
15349cc55cSDimitry Andric #include "CSKYCallingConv.h"
16349cc55cSDimitry Andric #include "CSKYMachineFunctionInfo.h"
17349cc55cSDimitry Andric #include "CSKYRegisterInfo.h"
18349cc55cSDimitry Andric #include "CSKYSubtarget.h"
19349cc55cSDimitry Andric #include "llvm/ADT/Statistic.h"
20349cc55cSDimitry Andric #include "llvm/CodeGen/CallingConvLower.h"
21349cc55cSDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h"
22349cc55cSDimitry Andric #include "llvm/Support/Debug.h"
23349cc55cSDimitry Andric 
24349cc55cSDimitry Andric using namespace llvm;
25349cc55cSDimitry Andric 
26349cc55cSDimitry Andric #define DEBUG_TYPE "csky-isel-lowering"
27349cc55cSDimitry Andric 
28349cc55cSDimitry Andric STATISTIC(NumTailCalls, "Number of tail calls");
29349cc55cSDimitry Andric 
30349cc55cSDimitry Andric #include "CSKYGenCallingConv.inc"
31349cc55cSDimitry Andric 
32349cc55cSDimitry Andric static const MCPhysReg GPRArgRegs[] = {CSKY::R0, CSKY::R1, CSKY::R2, CSKY::R3};
33349cc55cSDimitry Andric 
34349cc55cSDimitry Andric CSKYTargetLowering::CSKYTargetLowering(const TargetMachine &TM,
35349cc55cSDimitry Andric                                        const CSKYSubtarget &STI)
36349cc55cSDimitry Andric     : TargetLowering(TM), Subtarget(STI) {
37349cc55cSDimitry Andric   // Register Class
38349cc55cSDimitry Andric   addRegisterClass(MVT::i32, &CSKY::GPRRegClass);
39349cc55cSDimitry Andric 
40*0eae32dcSDimitry Andric   setOperationAction(ISD::ADDCARRY, MVT::i32, Legal);
41*0eae32dcSDimitry Andric   setOperationAction(ISD::SUBCARRY, MVT::i32, Legal);
42*0eae32dcSDimitry Andric   setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
43*0eae32dcSDimitry Andric 
44*0eae32dcSDimitry Andric   setOperationAction(ISD::SREM, MVT::i32, Expand);
45*0eae32dcSDimitry Andric   setOperationAction(ISD::UREM, MVT::i32, Expand);
46*0eae32dcSDimitry Andric   setOperationAction(ISD::UDIVREM, MVT::i32, Expand);
47*0eae32dcSDimitry Andric   setOperationAction(ISD::SDIVREM, MVT::i32, Expand);
48*0eae32dcSDimitry Andric   setOperationAction(ISD::CTTZ, MVT::i32, Expand);
49*0eae32dcSDimitry Andric   setOperationAction(ISD::CTPOP, MVT::i32, Expand);
50*0eae32dcSDimitry Andric   setOperationAction(ISD::ROTR, MVT::i32, Expand);
51*0eae32dcSDimitry Andric   setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
52*0eae32dcSDimitry Andric   setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
53*0eae32dcSDimitry Andric   setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
54*0eae32dcSDimitry Andric   setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
55*0eae32dcSDimitry Andric   setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
56*0eae32dcSDimitry Andric   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand);
57*0eae32dcSDimitry Andric   setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
58*0eae32dcSDimitry Andric   setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
59*0eae32dcSDimitry Andric   setOperationAction(ISD::MULHS, MVT::i32, Expand);
60*0eae32dcSDimitry Andric   setOperationAction(ISD::MULHU, MVT::i32, Expand);
61*0eae32dcSDimitry Andric 
62*0eae32dcSDimitry Andric   setLoadExtAction(ISD::EXTLOAD, MVT::i32, MVT::i1, Promote);
63*0eae32dcSDimitry Andric   setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i1, Promote);
64*0eae32dcSDimitry Andric   setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, MVT::i1, Promote);
65*0eae32dcSDimitry Andric 
66*0eae32dcSDimitry Andric   if (!Subtarget.hasE2()) {
67*0eae32dcSDimitry Andric     setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i8, Expand);
68*0eae32dcSDimitry Andric     setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i16, Expand);
69*0eae32dcSDimitry Andric     setOperationAction(ISD::CTLZ, MVT::i32, Expand);
70*0eae32dcSDimitry Andric     setOperationAction(ISD::BSWAP, MVT::i32, Expand);
71*0eae32dcSDimitry Andric   }
72*0eae32dcSDimitry Andric 
73*0eae32dcSDimitry Andric   if (!Subtarget.has2E3()) {
74*0eae32dcSDimitry Andric     setOperationAction(ISD::ABS, MVT::i32, Expand);
75*0eae32dcSDimitry Andric     setOperationAction(ISD::BITREVERSE, MVT::i32, Expand);
76*0eae32dcSDimitry Andric     setOperationAction(ISD::SDIV, MVT::i32, Expand);
77*0eae32dcSDimitry Andric     setOperationAction(ISD::UDIV, MVT::i32, Expand);
78*0eae32dcSDimitry Andric   }
79*0eae32dcSDimitry Andric 
80349cc55cSDimitry Andric   // Compute derived properties from the register classes.
81349cc55cSDimitry Andric   computeRegisterProperties(STI.getRegisterInfo());
82349cc55cSDimitry Andric 
83349cc55cSDimitry Andric   setBooleanContents(UndefinedBooleanContent);
84349cc55cSDimitry Andric   setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
85349cc55cSDimitry Andric 
86349cc55cSDimitry Andric   // TODO: Add atomic support fully.
87349cc55cSDimitry Andric   setMaxAtomicSizeInBitsSupported(0);
88349cc55cSDimitry Andric 
89349cc55cSDimitry Andric   setStackPointerRegisterToSaveRestore(CSKY::R14);
90349cc55cSDimitry Andric   const Align FunctionAlignment(2);
91349cc55cSDimitry Andric   setMinFunctionAlignment(FunctionAlignment);
92349cc55cSDimitry Andric   setSchedulingPreference(Sched::Source);
93349cc55cSDimitry Andric }
94349cc55cSDimitry Andric 
95349cc55cSDimitry Andric EVT CSKYTargetLowering::getSetCCResultType(const DataLayout &DL,
96349cc55cSDimitry Andric                                            LLVMContext &Context, EVT VT) const {
97349cc55cSDimitry Andric   if (!VT.isVector())
98349cc55cSDimitry Andric     return MVT::i32;
99349cc55cSDimitry Andric 
100349cc55cSDimitry Andric   return VT.changeVectorElementTypeToInteger();
101349cc55cSDimitry Andric }
102349cc55cSDimitry Andric 
103349cc55cSDimitry Andric static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
104349cc55cSDimitry Andric                                    const CCValAssign &VA, const SDLoc &DL) {
105349cc55cSDimitry Andric   EVT LocVT = VA.getLocVT();
106349cc55cSDimitry Andric 
107349cc55cSDimitry Andric   switch (VA.getLocInfo()) {
108349cc55cSDimitry Andric   default:
109349cc55cSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
110349cc55cSDimitry Andric   case CCValAssign::Full:
111349cc55cSDimitry Andric     break;
112349cc55cSDimitry Andric   case CCValAssign::BCvt:
113349cc55cSDimitry Andric     Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
114349cc55cSDimitry Andric     break;
115349cc55cSDimitry Andric   }
116349cc55cSDimitry Andric   return Val;
117349cc55cSDimitry Andric }
118349cc55cSDimitry Andric 
119349cc55cSDimitry Andric static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val,
120349cc55cSDimitry Andric                                    const CCValAssign &VA, const SDLoc &DL) {
121349cc55cSDimitry Andric   switch (VA.getLocInfo()) {
122349cc55cSDimitry Andric   default:
123349cc55cSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
124349cc55cSDimitry Andric   case CCValAssign::Full:
125349cc55cSDimitry Andric     break;
126349cc55cSDimitry Andric   case CCValAssign::BCvt:
127349cc55cSDimitry Andric     Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
128349cc55cSDimitry Andric     break;
129349cc55cSDimitry Andric   }
130349cc55cSDimitry Andric   return Val;
131349cc55cSDimitry Andric }
132349cc55cSDimitry Andric 
133349cc55cSDimitry Andric static SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget,
134349cc55cSDimitry Andric                                 SelectionDAG &DAG, SDValue Chain,
135349cc55cSDimitry Andric                                 const CCValAssign &VA, const SDLoc &DL) {
136349cc55cSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
137349cc55cSDimitry Andric   MachineRegisterInfo &RegInfo = MF.getRegInfo();
138349cc55cSDimitry Andric   EVT LocVT = VA.getLocVT();
139349cc55cSDimitry Andric   SDValue Val;
140349cc55cSDimitry Andric   const TargetRegisterClass *RC;
141349cc55cSDimitry Andric 
142349cc55cSDimitry Andric   switch (LocVT.getSimpleVT().SimpleTy) {
143349cc55cSDimitry Andric   default:
144349cc55cSDimitry Andric     llvm_unreachable("Unexpected register type");
145349cc55cSDimitry Andric   case MVT::i32:
146349cc55cSDimitry Andric     RC = &CSKY::GPRRegClass;
147349cc55cSDimitry Andric     break;
148349cc55cSDimitry Andric   }
149349cc55cSDimitry Andric 
150349cc55cSDimitry Andric   Register VReg = RegInfo.createVirtualRegister(RC);
151349cc55cSDimitry Andric   RegInfo.addLiveIn(VA.getLocReg(), VReg);
152349cc55cSDimitry Andric   Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
153349cc55cSDimitry Andric 
154349cc55cSDimitry Andric   return convertLocVTToValVT(DAG, Val, VA, DL);
155349cc55cSDimitry Andric }
156349cc55cSDimitry Andric 
157349cc55cSDimitry Andric static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain,
158349cc55cSDimitry Andric                                 const CCValAssign &VA, const SDLoc &DL) {
159349cc55cSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
160349cc55cSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
161349cc55cSDimitry Andric   EVT LocVT = VA.getLocVT();
162349cc55cSDimitry Andric   EVT ValVT = VA.getValVT();
163349cc55cSDimitry Andric   EVT PtrVT = MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0));
164349cc55cSDimitry Andric   int FI = MFI.CreateFixedObject(ValVT.getSizeInBits() / 8,
165349cc55cSDimitry Andric                                  VA.getLocMemOffset(), /*Immutable=*/true);
166349cc55cSDimitry Andric   SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
167349cc55cSDimitry Andric   SDValue Val;
168349cc55cSDimitry Andric 
169349cc55cSDimitry Andric   ISD::LoadExtType ExtType;
170349cc55cSDimitry Andric   switch (VA.getLocInfo()) {
171349cc55cSDimitry Andric   default:
172349cc55cSDimitry Andric     llvm_unreachable("Unexpected CCValAssign::LocInfo");
173349cc55cSDimitry Andric   case CCValAssign::Full:
174349cc55cSDimitry Andric   case CCValAssign::BCvt:
175349cc55cSDimitry Andric     ExtType = ISD::NON_EXTLOAD;
176349cc55cSDimitry Andric     break;
177349cc55cSDimitry Andric   }
178349cc55cSDimitry Andric   Val = DAG.getExtLoad(
179349cc55cSDimitry Andric       ExtType, DL, LocVT, Chain, FIN,
180349cc55cSDimitry Andric       MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT);
181349cc55cSDimitry Andric   return Val;
182349cc55cSDimitry Andric }
183349cc55cSDimitry Andric 
184349cc55cSDimitry Andric // Transform physical registers into virtual registers.
185349cc55cSDimitry Andric SDValue CSKYTargetLowering::LowerFormalArguments(
186349cc55cSDimitry Andric     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
187349cc55cSDimitry Andric     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
188349cc55cSDimitry Andric     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
189349cc55cSDimitry Andric 
190349cc55cSDimitry Andric   switch (CallConv) {
191349cc55cSDimitry Andric   default:
192349cc55cSDimitry Andric     report_fatal_error("Unsupported calling convention");
193349cc55cSDimitry Andric   case CallingConv::C:
194349cc55cSDimitry Andric   case CallingConv::Fast:
195349cc55cSDimitry Andric     break;
196349cc55cSDimitry Andric   }
197349cc55cSDimitry Andric 
198349cc55cSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
199349cc55cSDimitry Andric 
200349cc55cSDimitry Andric   // Used with vargs to acumulate store chains.
201349cc55cSDimitry Andric   std::vector<SDValue> OutChains;
202349cc55cSDimitry Andric 
203349cc55cSDimitry Andric   // Assign locations to all of the incoming arguments.
204349cc55cSDimitry Andric   SmallVector<CCValAssign, 16> ArgLocs;
205349cc55cSDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
206349cc55cSDimitry Andric 
207349cc55cSDimitry Andric   CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, IsVarArg));
208349cc55cSDimitry Andric 
209349cc55cSDimitry Andric   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
210349cc55cSDimitry Andric     CCValAssign &VA = ArgLocs[i];
211349cc55cSDimitry Andric     SDValue ArgValue;
212349cc55cSDimitry Andric 
213349cc55cSDimitry Andric     if (VA.isRegLoc())
214349cc55cSDimitry Andric       ArgValue = unpackFromRegLoc(Subtarget, DAG, Chain, VA, DL);
215349cc55cSDimitry Andric     else
216349cc55cSDimitry Andric       ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
217349cc55cSDimitry Andric 
218349cc55cSDimitry Andric     InVals.push_back(ArgValue);
219349cc55cSDimitry Andric   }
220349cc55cSDimitry Andric 
221349cc55cSDimitry Andric   if (IsVarArg) {
222349cc55cSDimitry Andric     const unsigned XLenInBytes = 4;
223349cc55cSDimitry Andric     const MVT XLenVT = MVT::i32;
224349cc55cSDimitry Andric 
225349cc55cSDimitry Andric     ArrayRef<MCPhysReg> ArgRegs = makeArrayRef(GPRArgRegs);
226349cc55cSDimitry Andric     unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
227349cc55cSDimitry Andric     const TargetRegisterClass *RC = &CSKY::GPRRegClass;
228349cc55cSDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
229349cc55cSDimitry Andric     MachineRegisterInfo &RegInfo = MF.getRegInfo();
230349cc55cSDimitry Andric     CSKYMachineFunctionInfo *CSKYFI = MF.getInfo<CSKYMachineFunctionInfo>();
231349cc55cSDimitry Andric 
232349cc55cSDimitry Andric     // Offset of the first variable argument from stack pointer, and size of
233349cc55cSDimitry Andric     // the vararg save area. For now, the varargs save area is either zero or
234349cc55cSDimitry Andric     // large enough to hold a0-a4.
235349cc55cSDimitry Andric     int VaArgOffset, VarArgsSaveSize;
236349cc55cSDimitry Andric 
237349cc55cSDimitry Andric     // If all registers are allocated, then all varargs must be passed on the
238349cc55cSDimitry Andric     // stack and we don't need to save any argregs.
239349cc55cSDimitry Andric     if (ArgRegs.size() == Idx) {
240349cc55cSDimitry Andric       VaArgOffset = CCInfo.getNextStackOffset();
241349cc55cSDimitry Andric       VarArgsSaveSize = 0;
242349cc55cSDimitry Andric     } else {
243349cc55cSDimitry Andric       VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx);
244349cc55cSDimitry Andric       VaArgOffset = -VarArgsSaveSize;
245349cc55cSDimitry Andric     }
246349cc55cSDimitry Andric 
247349cc55cSDimitry Andric     // Record the frame index of the first variable argument
248349cc55cSDimitry Andric     // which is a value necessary to VASTART.
249349cc55cSDimitry Andric     int FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
250349cc55cSDimitry Andric     CSKYFI->setVarArgsFrameIndex(FI);
251349cc55cSDimitry Andric 
252349cc55cSDimitry Andric     // Copy the integer registers that may have been used for passing varargs
253349cc55cSDimitry Andric     // to the vararg save area.
254349cc55cSDimitry Andric     for (unsigned I = Idx; I < ArgRegs.size();
255349cc55cSDimitry Andric          ++I, VaArgOffset += XLenInBytes) {
256349cc55cSDimitry Andric       const Register Reg = RegInfo.createVirtualRegister(RC);
257349cc55cSDimitry Andric       RegInfo.addLiveIn(ArgRegs[I], Reg);
258349cc55cSDimitry Andric       SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, XLenVT);
259349cc55cSDimitry Andric       FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
260349cc55cSDimitry Andric       SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
261349cc55cSDimitry Andric       SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
262349cc55cSDimitry Andric                                    MachinePointerInfo::getFixedStack(MF, FI));
263349cc55cSDimitry Andric       cast<StoreSDNode>(Store.getNode())
264349cc55cSDimitry Andric           ->getMemOperand()
265349cc55cSDimitry Andric           ->setValue((Value *)nullptr);
266349cc55cSDimitry Andric       OutChains.push_back(Store);
267349cc55cSDimitry Andric     }
268349cc55cSDimitry Andric     CSKYFI->setVarArgsSaveSize(VarArgsSaveSize);
269349cc55cSDimitry Andric   }
270349cc55cSDimitry Andric 
271349cc55cSDimitry Andric   // All stores are grouped in one node to allow the matching between
272349cc55cSDimitry Andric   // the size of Ins and InVals. This only happens for vararg functions.
273349cc55cSDimitry Andric   if (!OutChains.empty()) {
274349cc55cSDimitry Andric     OutChains.push_back(Chain);
275349cc55cSDimitry Andric     Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
276349cc55cSDimitry Andric   }
277349cc55cSDimitry Andric 
278349cc55cSDimitry Andric   return Chain;
279349cc55cSDimitry Andric }
280349cc55cSDimitry Andric 
281349cc55cSDimitry Andric bool CSKYTargetLowering::CanLowerReturn(
282349cc55cSDimitry Andric     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
283349cc55cSDimitry Andric     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
284349cc55cSDimitry Andric   SmallVector<CCValAssign, 16> CSKYLocs;
285349cc55cSDimitry Andric   CCState CCInfo(CallConv, IsVarArg, MF, CSKYLocs, Context);
286349cc55cSDimitry Andric   return CCInfo.CheckReturn(Outs, CCAssignFnForReturn(CallConv, IsVarArg));
287349cc55cSDimitry Andric }
288349cc55cSDimitry Andric 
289349cc55cSDimitry Andric SDValue
290349cc55cSDimitry Andric CSKYTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
291349cc55cSDimitry Andric                                 bool IsVarArg,
292349cc55cSDimitry Andric                                 const SmallVectorImpl<ISD::OutputArg> &Outs,
293349cc55cSDimitry Andric                                 const SmallVectorImpl<SDValue> &OutVals,
294349cc55cSDimitry Andric                                 const SDLoc &DL, SelectionDAG &DAG) const {
295349cc55cSDimitry Andric   // Stores the assignment of the return value to a location.
296349cc55cSDimitry Andric   SmallVector<CCValAssign, 16> CSKYLocs;
297349cc55cSDimitry Andric 
298349cc55cSDimitry Andric   // Info about the registers and stack slot.
299349cc55cSDimitry Andric   CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), CSKYLocs,
300349cc55cSDimitry Andric                  *DAG.getContext());
301349cc55cSDimitry Andric   CCInfo.AnalyzeReturn(Outs, CCAssignFnForReturn(CallConv, IsVarArg));
302349cc55cSDimitry Andric 
303349cc55cSDimitry Andric   SDValue Glue;
304349cc55cSDimitry Andric   SmallVector<SDValue, 4> RetOps(1, Chain);
305349cc55cSDimitry Andric 
306349cc55cSDimitry Andric   // Copy the result values into the output registers.
307349cc55cSDimitry Andric   for (unsigned i = 0, e = CSKYLocs.size(); i < e; ++i) {
308349cc55cSDimitry Andric     SDValue Val = OutVals[i];
309349cc55cSDimitry Andric     CCValAssign &VA = CSKYLocs[i];
310349cc55cSDimitry Andric     assert(VA.isRegLoc() && "Can only return in registers!");
311349cc55cSDimitry Andric 
312349cc55cSDimitry Andric     bool IsF64OnCSKY = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64;
313349cc55cSDimitry Andric 
314349cc55cSDimitry Andric     if (IsF64OnCSKY) {
315349cc55cSDimitry Andric 
316349cc55cSDimitry Andric       assert(VA.isRegLoc() && "Expected return via registers");
317349cc55cSDimitry Andric       SDValue Split64 = DAG.getNode(CSKYISD::BITCAST_TO_LOHI, DL,
318349cc55cSDimitry Andric                                     DAG.getVTList(MVT::i32, MVT::i32), Val);
319349cc55cSDimitry Andric       SDValue Lo = Split64.getValue(0);
320349cc55cSDimitry Andric       SDValue Hi = Split64.getValue(1);
321349cc55cSDimitry Andric 
322349cc55cSDimitry Andric       Register RegLo = VA.getLocReg();
323349cc55cSDimitry Andric       assert(RegLo < CSKY::R31 && "Invalid register pair");
324349cc55cSDimitry Andric       Register RegHi = RegLo + 1;
325349cc55cSDimitry Andric 
326349cc55cSDimitry Andric       Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue);
327349cc55cSDimitry Andric       Glue = Chain.getValue(1);
328349cc55cSDimitry Andric       RetOps.push_back(DAG.getRegister(RegLo, MVT::i32));
329349cc55cSDimitry Andric       Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue);
330349cc55cSDimitry Andric       Glue = Chain.getValue(1);
331349cc55cSDimitry Andric       RetOps.push_back(DAG.getRegister(RegHi, MVT::i32));
332349cc55cSDimitry Andric     } else {
333349cc55cSDimitry Andric       // Handle a 'normal' return.
334349cc55cSDimitry Andric       Val = convertValVTToLocVT(DAG, Val, VA, DL);
335349cc55cSDimitry Andric       Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
336349cc55cSDimitry Andric 
337349cc55cSDimitry Andric       // Guarantee that all emitted copies are stuck together.
338349cc55cSDimitry Andric       Glue = Chain.getValue(1);
339349cc55cSDimitry Andric       RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
340349cc55cSDimitry Andric     }
341349cc55cSDimitry Andric   }
342349cc55cSDimitry Andric 
343349cc55cSDimitry Andric   RetOps[0] = Chain; // Update chain.
344349cc55cSDimitry Andric 
345349cc55cSDimitry Andric   // Add the glue node if we have it.
346349cc55cSDimitry Andric   if (Glue.getNode()) {
347349cc55cSDimitry Andric     RetOps.push_back(Glue);
348349cc55cSDimitry Andric   }
349349cc55cSDimitry Andric 
350349cc55cSDimitry Andric   // Interrupt service routines use different return instructions.
351349cc55cSDimitry Andric   if (DAG.getMachineFunction().getFunction().hasFnAttribute("interrupt"))
352349cc55cSDimitry Andric     return DAG.getNode(CSKYISD::NIR, DL, MVT::Other, RetOps);
353349cc55cSDimitry Andric 
354349cc55cSDimitry Andric   return DAG.getNode(CSKYISD::RET, DL, MVT::Other, RetOps);
355349cc55cSDimitry Andric }
356349cc55cSDimitry Andric 
357349cc55cSDimitry Andric CCAssignFn *CSKYTargetLowering::CCAssignFnForReturn(CallingConv::ID CC,
358349cc55cSDimitry Andric                                                     bool IsVarArg) const {
359349cc55cSDimitry Andric   if (IsVarArg || !Subtarget.useHardFloatABI())
360349cc55cSDimitry Andric     return RetCC_CSKY_ABIV2_SOFT;
361349cc55cSDimitry Andric   else
362349cc55cSDimitry Andric     return RetCC_CSKY_ABIV2_FP;
363349cc55cSDimitry Andric }
364349cc55cSDimitry Andric 
365349cc55cSDimitry Andric CCAssignFn *CSKYTargetLowering::CCAssignFnForCall(CallingConv::ID CC,
366349cc55cSDimitry Andric                                                   bool IsVarArg) const {
367349cc55cSDimitry Andric   if (IsVarArg || !Subtarget.useHardFloatABI())
368349cc55cSDimitry Andric     return CC_CSKY_ABIV2_SOFT;
369349cc55cSDimitry Andric   else
370349cc55cSDimitry Andric     return CC_CSKY_ABIV2_FP;
371349cc55cSDimitry Andric }
372349cc55cSDimitry Andric 
373349cc55cSDimitry Andric const char *CSKYTargetLowering::getTargetNodeName(unsigned Opcode) const {
374349cc55cSDimitry Andric   switch (Opcode) {
375349cc55cSDimitry Andric   default:
376349cc55cSDimitry Andric     llvm_unreachable("unknown CSKYISD node");
377349cc55cSDimitry Andric   case CSKYISD::NIE:
378349cc55cSDimitry Andric     return "CSKYISD::NIE";
379349cc55cSDimitry Andric   case CSKYISD::NIR:
380349cc55cSDimitry Andric     return "CSKYISD::NIR";
381349cc55cSDimitry Andric   case CSKYISD::RET:
382349cc55cSDimitry Andric     return "CSKYISD::RET";
383349cc55cSDimitry Andric   case CSKYISD::BITCAST_TO_LOHI:
384349cc55cSDimitry Andric     return "CSKYISD::BITCAST_TO_LOHI";
385349cc55cSDimitry Andric   }
386349cc55cSDimitry Andric }
387