1 //===- MipsCallLowering.cpp -------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 /// \file
11 /// This file implements the lowering of LLVM calls to machine code calls for
12 /// GlobalISel.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "MipsCallLowering.h"
17 #include "MipsCCState.h"
18 #include "MipsTargetMachine.h"
19 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
20 
21 using namespace llvm;
22 
MipsCallLowering(const MipsTargetLowering & TLI)23 MipsCallLowering::MipsCallLowering(const MipsTargetLowering &TLI)
24     : CallLowering(&TLI) {}
25 
assign(const CCValAssign & VA,unsigned vreg)26 bool MipsCallLowering::MipsHandler::assign(const CCValAssign &VA,
27                                            unsigned vreg) {
28   if (VA.isRegLoc()) {
29     assignValueToReg(vreg, VA.getLocReg());
30   } else if (VA.isMemLoc()) {
31     unsigned Size = alignTo(VA.getValVT().getSizeInBits(), 8) / 8;
32     unsigned Offset = VA.getLocMemOffset();
33     MachinePointerInfo MPO;
34     unsigned StackAddr = getStackAddress(Size, Offset, MPO);
35     assignValueToAddress(vreg, StackAddr, Size, MPO);
36   } else {
37     return false;
38   }
39   return true;
40 }
41 
42 namespace {
43 class IncomingValueHandler : public MipsCallLowering::MipsHandler {
44 public:
IncomingValueHandler(MachineIRBuilder & MIRBuilder,MachineRegisterInfo & MRI)45   IncomingValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
46       : MipsHandler(MIRBuilder, MRI) {}
47 
48   bool handle(ArrayRef<CCValAssign> ArgLocs,
49               ArrayRef<CallLowering::ArgInfo> Args);
50 
51 private:
52   void assignValueToReg(unsigned ValVReg, unsigned PhysReg) override;
53 
54   unsigned getStackAddress(uint64_t Size, int64_t Offset,
55                            MachinePointerInfo &MPO) override;
56 
57   void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
58                             MachinePointerInfo &MPO) override;
59 
markPhysRegUsed(unsigned PhysReg)60   virtual void markPhysRegUsed(unsigned PhysReg) {
61     MIRBuilder.getMBB().addLiveIn(PhysReg);
62   }
63 
buildLoad(unsigned Val,unsigned Addr,uint64_t Size,unsigned Alignment,MachinePointerInfo & MPO)64   void buildLoad(unsigned Val, unsigned Addr, uint64_t Size, unsigned Alignment,
65                  MachinePointerInfo &MPO) {
66     MachineMemOperand *MMO = MIRBuilder.getMF().getMachineMemOperand(
67         MPO, MachineMemOperand::MOLoad, Size, Alignment);
68     MIRBuilder.buildLoad(Val, Addr, *MMO);
69   }
70 };
71 
72 class CallReturnHandler : public IncomingValueHandler {
73 public:
CallReturnHandler(MachineIRBuilder & MIRBuilder,MachineRegisterInfo & MRI,MachineInstrBuilder & MIB)74   CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
75                     MachineInstrBuilder &MIB)
76       : IncomingValueHandler(MIRBuilder, MRI), MIB(MIB) {}
77 
78 private:
markPhysRegUsed(unsigned PhysReg)79   void markPhysRegUsed(unsigned PhysReg) override {
80     MIB.addDef(PhysReg, RegState::Implicit);
81   }
82 
83   MachineInstrBuilder &MIB;
84 };
85 
86 } // end anonymous namespace
87 
assignValueToReg(unsigned ValVReg,unsigned PhysReg)88 void IncomingValueHandler::assignValueToReg(unsigned ValVReg,
89                                             unsigned PhysReg) {
90   MIRBuilder.buildCopy(ValVReg, PhysReg);
91   markPhysRegUsed(PhysReg);
92 }
93 
getStackAddress(uint64_t Size,int64_t Offset,MachinePointerInfo & MPO)94 unsigned IncomingValueHandler::getStackAddress(uint64_t Size, int64_t Offset,
95                                                MachinePointerInfo &MPO) {
96   MachineFrameInfo &MFI = MIRBuilder.getMF().getFrameInfo();
97 
98   int FI = MFI.CreateFixedObject(Size, Offset, true);
99   MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
100 
101   unsigned AddrReg = MRI.createGenericVirtualRegister(LLT::pointer(0, 32));
102   MIRBuilder.buildFrameIndex(AddrReg, FI);
103 
104   return AddrReg;
105 }
106 
assignValueToAddress(unsigned ValVReg,unsigned Addr,uint64_t Size,MachinePointerInfo & MPO)107 void IncomingValueHandler::assignValueToAddress(unsigned ValVReg, unsigned Addr,
108                                                 uint64_t Size,
109                                                 MachinePointerInfo &MPO) {
110   // If the value is not extended, a simple load will suffice.
111   buildLoad(ValVReg, Addr, Size, /* Alignment */ 0, MPO);
112 }
113 
handle(ArrayRef<CCValAssign> ArgLocs,ArrayRef<CallLowering::ArgInfo> Args)114 bool IncomingValueHandler::handle(ArrayRef<CCValAssign> ArgLocs,
115                                   ArrayRef<CallLowering::ArgInfo> Args) {
116   for (unsigned i = 0, ArgsSize = Args.size(); i < ArgsSize; ++i) {
117     if (!assign(ArgLocs[i], Args[i].Reg))
118       return false;
119   }
120   return true;
121 }
122 
123 namespace {
124 class OutgoingValueHandler : public MipsCallLowering::MipsHandler {
125 public:
OutgoingValueHandler(MachineIRBuilder & MIRBuilder,MachineRegisterInfo & MRI,MachineInstrBuilder & MIB)126   OutgoingValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
127                        MachineInstrBuilder &MIB)
128       : MipsHandler(MIRBuilder, MRI), MIB(MIB) {}
129 
130   bool handle(ArrayRef<CCValAssign> ArgLocs,
131               ArrayRef<CallLowering::ArgInfo> Args);
132 
133 private:
134   void assignValueToReg(unsigned ValVReg, unsigned PhysReg) override;
135 
136   unsigned getStackAddress(uint64_t Size, int64_t Offset,
137                            MachinePointerInfo &MPO) override;
138 
139   void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
140                             MachinePointerInfo &MPO) override;
141 
142   MachineInstrBuilder &MIB;
143 };
144 } // end anonymous namespace
145 
assignValueToReg(unsigned ValVReg,unsigned PhysReg)146 void OutgoingValueHandler::assignValueToReg(unsigned ValVReg,
147                                             unsigned PhysReg) {
148   MIRBuilder.buildCopy(PhysReg, ValVReg);
149   MIB.addUse(PhysReg, RegState::Implicit);
150 }
151 
getStackAddress(uint64_t Size,int64_t Offset,MachinePointerInfo & MPO)152 unsigned OutgoingValueHandler::getStackAddress(uint64_t Size, int64_t Offset,
153                                                MachinePointerInfo &MPO) {
154   LLT p0 = LLT::pointer(0, 32);
155   LLT s32 = LLT::scalar(32);
156   unsigned SPReg = MRI.createGenericVirtualRegister(p0);
157   MIRBuilder.buildCopy(SPReg, Mips::SP);
158 
159   unsigned OffsetReg = MRI.createGenericVirtualRegister(s32);
160   MIRBuilder.buildConstant(OffsetReg, Offset);
161 
162   unsigned AddrReg = MRI.createGenericVirtualRegister(p0);
163   MIRBuilder.buildGEP(AddrReg, SPReg, OffsetReg);
164 
165   MPO = MachinePointerInfo::getStack(MIRBuilder.getMF(), Offset);
166   return AddrReg;
167 }
168 
assignValueToAddress(unsigned ValVReg,unsigned Addr,uint64_t Size,MachinePointerInfo & MPO)169 void OutgoingValueHandler::assignValueToAddress(unsigned ValVReg, unsigned Addr,
170                                                 uint64_t Size,
171                                                 MachinePointerInfo &MPO) {
172   MachineMemOperand *MMO = MIRBuilder.getMF().getMachineMemOperand(
173       MPO, MachineMemOperand::MOStore, Size, /* Alignment */ 0);
174   MIRBuilder.buildStore(ValVReg, Addr, *MMO);
175 }
176 
handle(ArrayRef<CCValAssign> ArgLocs,ArrayRef<CallLowering::ArgInfo> Args)177 bool OutgoingValueHandler::handle(ArrayRef<CCValAssign> ArgLocs,
178                                   ArrayRef<CallLowering::ArgInfo> Args) {
179   for (unsigned i = 0; i < Args.size(); ++i) {
180     if (!assign(ArgLocs[i], Args[i].Reg))
181       return false;
182   }
183   return true;
184 }
185 
isSupportedType(Type * T)186 static bool isSupportedType(Type *T) {
187   if (T->isIntegerTy() && T->getScalarSizeInBits() == 32)
188     return true;
189   if (T->isPointerTy())
190     return true;
191   return false;
192 }
193 
lowerReturn(MachineIRBuilder & MIRBuilder,const Value * Val,unsigned VReg) const194 bool MipsCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
195                                    const Value *Val, unsigned VReg) const {
196 
197   MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(Mips::RetRA);
198 
199   if (Val != nullptr) {
200     if (!isSupportedType(Val->getType()))
201       return false;
202 
203     MachineFunction &MF = MIRBuilder.getMF();
204     const Function &F = MF.getFunction();
205     const DataLayout &DL = MF.getDataLayout();
206     const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
207 
208     SmallVector<ArgInfo, 8> RetInfos;
209     SmallVector<unsigned, 8> OrigArgIndices;
210 
211     ArgInfo ArgRetInfo(VReg, Val->getType());
212     setArgFlags(ArgRetInfo, AttributeList::ReturnIndex, DL, F);
213     splitToValueTypes(ArgRetInfo, 0, RetInfos, OrigArgIndices);
214 
215     SmallVector<ISD::OutputArg, 8> Outs;
216     subTargetRegTypeForCallingConv(
217         MIRBuilder, RetInfos, OrigArgIndices,
218         [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used,
219             unsigned origIdx, unsigned partOffs) {
220           Outs.emplace_back(flags, vt, argvt, used, origIdx, partOffs);
221         });
222 
223     SmallVector<CCValAssign, 16> ArgLocs;
224     MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
225                        F.getContext());
226     CCInfo.AnalyzeReturn(Outs, TLI.CCAssignFnForReturn());
227 
228     OutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret);
229     if (!RetHandler.handle(ArgLocs, RetInfos)) {
230       return false;
231     }
232   }
233   MIRBuilder.insertInstr(Ret);
234   return true;
235 }
236 
lowerFormalArguments(MachineIRBuilder & MIRBuilder,const Function & F,ArrayRef<unsigned> VRegs) const237 bool MipsCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
238                                             const Function &F,
239                                             ArrayRef<unsigned> VRegs) const {
240 
241   // Quick exit if there aren't any args.
242   if (F.arg_empty())
243     return true;
244 
245   if (F.isVarArg()) {
246     return false;
247   }
248 
249   for (auto &Arg : F.args()) {
250     if (!isSupportedType(Arg.getType()))
251       return false;
252   }
253 
254   MachineFunction &MF = MIRBuilder.getMF();
255   const DataLayout &DL = MF.getDataLayout();
256   const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
257 
258   SmallVector<ArgInfo, 8> ArgInfos;
259   SmallVector<unsigned, 8> OrigArgIndices;
260   unsigned i = 0;
261   for (auto &Arg : F.args()) {
262     ArgInfo AInfo(VRegs[i], Arg.getType());
263     setArgFlags(AInfo, i + AttributeList::FirstArgIndex, DL, F);
264     splitToValueTypes(AInfo, i, ArgInfos, OrigArgIndices);
265     ++i;
266   }
267 
268   SmallVector<ISD::InputArg, 8> Ins;
269   subTargetRegTypeForCallingConv(
270       MIRBuilder, ArgInfos, OrigArgIndices,
271       [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used, unsigned origIdx,
272           unsigned partOffs) {
273         Ins.emplace_back(flags, vt, argvt, used, origIdx, partOffs);
274       });
275 
276   SmallVector<CCValAssign, 16> ArgLocs;
277   MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
278                      F.getContext());
279 
280   const MipsTargetMachine &TM =
281       static_cast<const MipsTargetMachine &>(MF.getTarget());
282   const MipsABIInfo &ABI = TM.getABI();
283   CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(F.getCallingConv()),
284                        1);
285   CCInfo.AnalyzeFormalArguments(Ins, TLI.CCAssignFnForCall());
286 
287   IncomingValueHandler Handler(MIRBuilder, MF.getRegInfo());
288   if (!Handler.handle(ArgLocs, ArgInfos))
289     return false;
290 
291   return true;
292 }
293 
lowerCall(MachineIRBuilder & MIRBuilder,CallingConv::ID CallConv,const MachineOperand & Callee,const ArgInfo & OrigRet,ArrayRef<ArgInfo> OrigArgs) const294 bool MipsCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
295                                  CallingConv::ID CallConv,
296                                  const MachineOperand &Callee,
297                                  const ArgInfo &OrigRet,
298                                  ArrayRef<ArgInfo> OrigArgs) const {
299 
300   if (CallConv != CallingConv::C)
301     return false;
302 
303   for (auto &Arg : OrigArgs) {
304     if (!isSupportedType(Arg.Ty))
305       return false;
306     if (Arg.Flags.isByVal() || Arg.Flags.isSRet())
307       return false;
308   }
309   if (OrigRet.Reg && !isSupportedType(OrigRet.Ty))
310     return false;
311 
312   MachineFunction &MF = MIRBuilder.getMF();
313   const Function &F = MF.getFunction();
314   const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
315   const MipsTargetMachine &TM =
316       static_cast<const MipsTargetMachine &>(MF.getTarget());
317   const MipsABIInfo &ABI = TM.getABI();
318 
319   MachineInstrBuilder CallSeqStart =
320       MIRBuilder.buildInstr(Mips::ADJCALLSTACKDOWN);
321 
322   // FIXME: Add support for pic calling sequences, long call sequences for O32,
323   //       N32 and N64. First handle the case when Callee.isReg().
324   if (Callee.isReg())
325     return false;
326 
327   MachineInstrBuilder MIB = MIRBuilder.buildInstrNoInsert(Mips::JAL);
328   MIB.addDef(Mips::SP, RegState::Implicit);
329   MIB.add(Callee);
330   const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
331   MIB.addRegMask(TRI->getCallPreservedMask(MF, F.getCallingConv()));
332 
333   TargetLowering::ArgListTy FuncOrigArgs;
334   FuncOrigArgs.reserve(OrigArgs.size());
335 
336   SmallVector<ArgInfo, 8> ArgInfos;
337   SmallVector<unsigned, 8> OrigArgIndices;
338   unsigned i = 0;
339   for (auto &Arg : OrigArgs) {
340 
341     TargetLowering::ArgListEntry Entry;
342     Entry.Ty = Arg.Ty;
343     FuncOrigArgs.push_back(Entry);
344 
345     splitToValueTypes(Arg, i, ArgInfos, OrigArgIndices);
346     ++i;
347   }
348 
349   SmallVector<ISD::OutputArg, 8> Outs;
350   subTargetRegTypeForCallingConv(
351       MIRBuilder, ArgInfos, OrigArgIndices,
352       [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used, unsigned origIdx,
353           unsigned partOffs) {
354         Outs.emplace_back(flags, vt, argvt, used, origIdx, partOffs);
355       });
356 
357   SmallVector<CCValAssign, 8> ArgLocs;
358   MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
359                      F.getContext());
360 
361   CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(CallConv), 1);
362   const char *Call = Callee.isSymbol() ? Callee.getSymbolName() : nullptr;
363   CCInfo.AnalyzeCallOperands(Outs, TLI.CCAssignFnForCall(), FuncOrigArgs, Call);
364 
365   OutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), MIB);
366   if (!RetHandler.handle(ArgLocs, ArgInfos)) {
367     return false;
368   }
369 
370   unsigned NextStackOffset = CCInfo.getNextStackOffset();
371   const TargetFrameLowering *TFL = MF.getSubtarget().getFrameLowering();
372   unsigned StackAlignment = TFL->getStackAlignment();
373   NextStackOffset = alignTo(NextStackOffset, StackAlignment);
374   CallSeqStart.addImm(NextStackOffset).addImm(0);
375 
376   MIRBuilder.insertInstr(MIB);
377 
378   if (OrigRet.Reg) {
379 
380     ArgInfos.clear();
381     SmallVector<unsigned, 8> OrigRetIndices;
382 
383     splitToValueTypes(OrigRet, 0, ArgInfos, OrigRetIndices);
384 
385     SmallVector<ISD::InputArg, 8> Ins;
386     subTargetRegTypeForCallingConv(
387         MIRBuilder, ArgInfos, OrigRetIndices,
388         [&](ISD::ArgFlagsTy flags, EVT vt, EVT argvt, bool used,
389             unsigned origIdx, unsigned partOffs) {
390           Ins.emplace_back(flags, vt, argvt, used, origIdx, partOffs);
391         });
392 
393     SmallVector<CCValAssign, 8> ArgLocs;
394     MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
395                        F.getContext());
396 
397     CCInfo.AnalyzeCallResult(Ins, TLI.CCAssignFnForReturn(), OrigRet.Ty, Call);
398 
399     CallReturnHandler Handler(MIRBuilder, MF.getRegInfo(), MIB);
400     if (!Handler.handle(ArgLocs, ArgInfos))
401       return false;
402   }
403 
404   MIRBuilder.buildInstr(Mips::ADJCALLSTACKUP).addImm(NextStackOffset).addImm(0);
405 
406   return true;
407 }
408 
subTargetRegTypeForCallingConv(MachineIRBuilder & MIRBuilder,ArrayRef<ArgInfo> Args,ArrayRef<unsigned> OrigArgIndices,const FunTy & PushBack) const409 void MipsCallLowering::subTargetRegTypeForCallingConv(
410     MachineIRBuilder &MIRBuilder, ArrayRef<ArgInfo> Args,
411     ArrayRef<unsigned> OrigArgIndices, const FunTy &PushBack) const {
412   MachineFunction &MF = MIRBuilder.getMF();
413   const Function &F = MF.getFunction();
414   const DataLayout &DL = F.getParent()->getDataLayout();
415   const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
416 
417   unsigned ArgNo = 0;
418   for (auto &Arg : Args) {
419 
420     EVT VT = TLI.getValueType(DL, Arg.Ty);
421     MVT RegisterVT = TLI.getRegisterTypeForCallingConv(F.getContext(),
422                                                        F.getCallingConv(), VT);
423 
424     ISD::ArgFlagsTy Flags = Arg.Flags;
425     Flags.setOrigAlign(TLI.getABIAlignmentForCallingConv(Arg.Ty, DL));
426 
427     PushBack(Flags, RegisterVT, VT, true, OrigArgIndices[ArgNo], 0);
428 
429     ++ArgNo;
430   }
431 }
432 
splitToValueTypes(const ArgInfo & OrigArg,unsigned OriginalIndex,SmallVectorImpl<ArgInfo> & SplitArgs,SmallVectorImpl<unsigned> & SplitArgsOrigIndices) const433 void MipsCallLowering::splitToValueTypes(
434     const ArgInfo &OrigArg, unsigned OriginalIndex,
435     SmallVectorImpl<ArgInfo> &SplitArgs,
436     SmallVectorImpl<unsigned> &SplitArgsOrigIndices) const {
437 
438   // TODO : perform structure and array split. For now we only deal with
439   // types that pass isSupportedType check.
440   SplitArgs.push_back(OrigArg);
441   SplitArgsOrigIndices.push_back(OriginalIndex);
442 }
443