xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/CSKY/CSKYISelLowering.cpp (revision 5e801ac66d24704442eba426ed13c3effb8a34e7)
1 //===-- CSKYISelLowering.cpp - CSKY 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 CSKY uses to lower LLVM code into a
10 // selection DAG.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "CSKYISelLowering.h"
15 #include "CSKYCallingConv.h"
16 #include "CSKYMachineFunctionInfo.h"
17 #include "CSKYRegisterInfo.h"
18 #include "CSKYSubtarget.h"
19 #include "llvm/ADT/Statistic.h"
20 #include "llvm/CodeGen/CallingConvLower.h"
21 #include "llvm/CodeGen/MachineJumpTableInfo.h"
22 #include "llvm/Support/Debug.h"
23 
24 using namespace llvm;
25 
26 #define DEBUG_TYPE "csky-isel-lowering"
27 
28 STATISTIC(NumTailCalls, "Number of tail calls");
29 
30 #include "CSKYGenCallingConv.inc"
31 
32 static const MCPhysReg GPRArgRegs[] = {CSKY::R0, CSKY::R1, CSKY::R2, CSKY::R3};
33 
34 CSKYTargetLowering::CSKYTargetLowering(const TargetMachine &TM,
35                                        const CSKYSubtarget &STI)
36     : TargetLowering(TM), Subtarget(STI) {
37   // Register Class
38   addRegisterClass(MVT::i32, &CSKY::GPRRegClass);
39 
40   // Compute derived properties from the register classes.
41   computeRegisterProperties(STI.getRegisterInfo());
42 
43   setBooleanContents(UndefinedBooleanContent);
44   setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
45 
46   // TODO: Add atomic support fully.
47   setMaxAtomicSizeInBitsSupported(0);
48 
49   setStackPointerRegisterToSaveRestore(CSKY::R14);
50   const Align FunctionAlignment(2);
51   setMinFunctionAlignment(FunctionAlignment);
52   setSchedulingPreference(Sched::Source);
53 }
54 
55 EVT CSKYTargetLowering::getSetCCResultType(const DataLayout &DL,
56                                            LLVMContext &Context, EVT VT) const {
57   if (!VT.isVector())
58     return MVT::i32;
59 
60   return VT.changeVectorElementTypeToInteger();
61 }
62 
63 static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
64                                    const CCValAssign &VA, const SDLoc &DL) {
65   EVT LocVT = VA.getLocVT();
66 
67   switch (VA.getLocInfo()) {
68   default:
69     llvm_unreachable("Unexpected CCValAssign::LocInfo");
70   case CCValAssign::Full:
71     break;
72   case CCValAssign::BCvt:
73     Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
74     break;
75   }
76   return Val;
77 }
78 
79 static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val,
80                                    const CCValAssign &VA, const SDLoc &DL) {
81   switch (VA.getLocInfo()) {
82   default:
83     llvm_unreachable("Unexpected CCValAssign::LocInfo");
84   case CCValAssign::Full:
85     break;
86   case CCValAssign::BCvt:
87     Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
88     break;
89   }
90   return Val;
91 }
92 
93 static SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget,
94                                 SelectionDAG &DAG, SDValue Chain,
95                                 const CCValAssign &VA, const SDLoc &DL) {
96   MachineFunction &MF = DAG.getMachineFunction();
97   MachineRegisterInfo &RegInfo = MF.getRegInfo();
98   EVT LocVT = VA.getLocVT();
99   SDValue Val;
100   const TargetRegisterClass *RC;
101 
102   switch (LocVT.getSimpleVT().SimpleTy) {
103   default:
104     llvm_unreachable("Unexpected register type");
105   case MVT::i32:
106     RC = &CSKY::GPRRegClass;
107     break;
108   }
109 
110   Register VReg = RegInfo.createVirtualRegister(RC);
111   RegInfo.addLiveIn(VA.getLocReg(), VReg);
112   Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
113 
114   return convertLocVTToValVT(DAG, Val, VA, DL);
115 }
116 
117 static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain,
118                                 const CCValAssign &VA, const SDLoc &DL) {
119   MachineFunction &MF = DAG.getMachineFunction();
120   MachineFrameInfo &MFI = MF.getFrameInfo();
121   EVT LocVT = VA.getLocVT();
122   EVT ValVT = VA.getValVT();
123   EVT PtrVT = MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0));
124   int FI = MFI.CreateFixedObject(ValVT.getSizeInBits() / 8,
125                                  VA.getLocMemOffset(), /*Immutable=*/true);
126   SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
127   SDValue Val;
128 
129   ISD::LoadExtType ExtType;
130   switch (VA.getLocInfo()) {
131   default:
132     llvm_unreachable("Unexpected CCValAssign::LocInfo");
133   case CCValAssign::Full:
134   case CCValAssign::BCvt:
135     ExtType = ISD::NON_EXTLOAD;
136     break;
137   }
138   Val = DAG.getExtLoad(
139       ExtType, DL, LocVT, Chain, FIN,
140       MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT);
141   return Val;
142 }
143 
144 // Transform physical registers into virtual registers.
145 SDValue CSKYTargetLowering::LowerFormalArguments(
146     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
147     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
148     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
149 
150   switch (CallConv) {
151   default:
152     report_fatal_error("Unsupported calling convention");
153   case CallingConv::C:
154   case CallingConv::Fast:
155     break;
156   }
157 
158   MachineFunction &MF = DAG.getMachineFunction();
159 
160   // Used with vargs to acumulate store chains.
161   std::vector<SDValue> OutChains;
162 
163   // Assign locations to all of the incoming arguments.
164   SmallVector<CCValAssign, 16> ArgLocs;
165   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
166 
167   CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, IsVarArg));
168 
169   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
170     CCValAssign &VA = ArgLocs[i];
171     SDValue ArgValue;
172 
173     if (VA.isRegLoc())
174       ArgValue = unpackFromRegLoc(Subtarget, DAG, Chain, VA, DL);
175     else
176       ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
177 
178     InVals.push_back(ArgValue);
179   }
180 
181   if (IsVarArg) {
182     const unsigned XLenInBytes = 4;
183     const MVT XLenVT = MVT::i32;
184 
185     ArrayRef<MCPhysReg> ArgRegs = makeArrayRef(GPRArgRegs);
186     unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
187     const TargetRegisterClass *RC = &CSKY::GPRRegClass;
188     MachineFrameInfo &MFI = MF.getFrameInfo();
189     MachineRegisterInfo &RegInfo = MF.getRegInfo();
190     CSKYMachineFunctionInfo *CSKYFI = MF.getInfo<CSKYMachineFunctionInfo>();
191 
192     // Offset of the first variable argument from stack pointer, and size of
193     // the vararg save area. For now, the varargs save area is either zero or
194     // large enough to hold a0-a4.
195     int VaArgOffset, VarArgsSaveSize;
196 
197     // If all registers are allocated, then all varargs must be passed on the
198     // stack and we don't need to save any argregs.
199     if (ArgRegs.size() == Idx) {
200       VaArgOffset = CCInfo.getNextStackOffset();
201       VarArgsSaveSize = 0;
202     } else {
203       VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx);
204       VaArgOffset = -VarArgsSaveSize;
205     }
206 
207     // Record the frame index of the first variable argument
208     // which is a value necessary to VASTART.
209     int FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
210     CSKYFI->setVarArgsFrameIndex(FI);
211 
212     // Copy the integer registers that may have been used for passing varargs
213     // to the vararg save area.
214     for (unsigned I = Idx; I < ArgRegs.size();
215          ++I, VaArgOffset += XLenInBytes) {
216       const Register Reg = RegInfo.createVirtualRegister(RC);
217       RegInfo.addLiveIn(ArgRegs[I], Reg);
218       SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, XLenVT);
219       FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
220       SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
221       SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
222                                    MachinePointerInfo::getFixedStack(MF, FI));
223       cast<StoreSDNode>(Store.getNode())
224           ->getMemOperand()
225           ->setValue((Value *)nullptr);
226       OutChains.push_back(Store);
227     }
228     CSKYFI->setVarArgsSaveSize(VarArgsSaveSize);
229   }
230 
231   // All stores are grouped in one node to allow the matching between
232   // the size of Ins and InVals. This only happens for vararg functions.
233   if (!OutChains.empty()) {
234     OutChains.push_back(Chain);
235     Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
236   }
237 
238   return Chain;
239 }
240 
241 bool CSKYTargetLowering::CanLowerReturn(
242     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
243     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
244   SmallVector<CCValAssign, 16> CSKYLocs;
245   CCState CCInfo(CallConv, IsVarArg, MF, CSKYLocs, Context);
246   return CCInfo.CheckReturn(Outs, CCAssignFnForReturn(CallConv, IsVarArg));
247 }
248 
249 SDValue
250 CSKYTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
251                                 bool IsVarArg,
252                                 const SmallVectorImpl<ISD::OutputArg> &Outs,
253                                 const SmallVectorImpl<SDValue> &OutVals,
254                                 const SDLoc &DL, SelectionDAG &DAG) const {
255   // Stores the assignment of the return value to a location.
256   SmallVector<CCValAssign, 16> CSKYLocs;
257 
258   // Info about the registers and stack slot.
259   CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), CSKYLocs,
260                  *DAG.getContext());
261   CCInfo.AnalyzeReturn(Outs, CCAssignFnForReturn(CallConv, IsVarArg));
262 
263   SDValue Glue;
264   SmallVector<SDValue, 4> RetOps(1, Chain);
265 
266   // Copy the result values into the output registers.
267   for (unsigned i = 0, e = CSKYLocs.size(); i < e; ++i) {
268     SDValue Val = OutVals[i];
269     CCValAssign &VA = CSKYLocs[i];
270     assert(VA.isRegLoc() && "Can only return in registers!");
271 
272     bool IsF64OnCSKY = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64;
273 
274     if (IsF64OnCSKY) {
275 
276       assert(VA.isRegLoc() && "Expected return via registers");
277       SDValue Split64 = DAG.getNode(CSKYISD::BITCAST_TO_LOHI, DL,
278                                     DAG.getVTList(MVT::i32, MVT::i32), Val);
279       SDValue Lo = Split64.getValue(0);
280       SDValue Hi = Split64.getValue(1);
281 
282       Register RegLo = VA.getLocReg();
283       assert(RegLo < CSKY::R31 && "Invalid register pair");
284       Register RegHi = RegLo + 1;
285 
286       Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue);
287       Glue = Chain.getValue(1);
288       RetOps.push_back(DAG.getRegister(RegLo, MVT::i32));
289       Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue);
290       Glue = Chain.getValue(1);
291       RetOps.push_back(DAG.getRegister(RegHi, MVT::i32));
292     } else {
293       // Handle a 'normal' return.
294       Val = convertValVTToLocVT(DAG, Val, VA, DL);
295       Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
296 
297       // Guarantee that all emitted copies are stuck together.
298       Glue = Chain.getValue(1);
299       RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
300     }
301   }
302 
303   RetOps[0] = Chain; // Update chain.
304 
305   // Add the glue node if we have it.
306   if (Glue.getNode()) {
307     RetOps.push_back(Glue);
308   }
309 
310   // Interrupt service routines use different return instructions.
311   if (DAG.getMachineFunction().getFunction().hasFnAttribute("interrupt"))
312     return DAG.getNode(CSKYISD::NIR, DL, MVT::Other, RetOps);
313 
314   return DAG.getNode(CSKYISD::RET, DL, MVT::Other, RetOps);
315 }
316 
317 CCAssignFn *CSKYTargetLowering::CCAssignFnForReturn(CallingConv::ID CC,
318                                                     bool IsVarArg) const {
319   if (IsVarArg || !Subtarget.useHardFloatABI())
320     return RetCC_CSKY_ABIV2_SOFT;
321   else
322     return RetCC_CSKY_ABIV2_FP;
323 }
324 
325 CCAssignFn *CSKYTargetLowering::CCAssignFnForCall(CallingConv::ID CC,
326                                                   bool IsVarArg) const {
327   if (IsVarArg || !Subtarget.useHardFloatABI())
328     return CC_CSKY_ABIV2_SOFT;
329   else
330     return CC_CSKY_ABIV2_FP;
331 }
332 
333 const char *CSKYTargetLowering::getTargetNodeName(unsigned Opcode) const {
334   switch (Opcode) {
335   default:
336     llvm_unreachable("unknown CSKYISD node");
337   case CSKYISD::NIE:
338     return "CSKYISD::NIE";
339   case CSKYISD::NIR:
340     return "CSKYISD::NIR";
341   case CSKYISD::RET:
342     return "CSKYISD::RET";
343   case CSKYISD::BITCAST_TO_LOHI:
344     return "CSKYISD::BITCAST_TO_LOHI";
345   }
346 }
347