1fac93e28SPetar Jovanovic //===- MipsCallLowering.cpp -------------------------------------*- C++ -*-===//
2fac93e28SPetar Jovanovic //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fac93e28SPetar Jovanovic //
7fac93e28SPetar Jovanovic //===----------------------------------------------------------------------===//
8fac93e28SPetar Jovanovic //
9fac93e28SPetar Jovanovic /// \file
10fac93e28SPetar Jovanovic /// This file implements the lowering of LLVM calls to machine code calls for
11fac93e28SPetar Jovanovic /// GlobalISel.
12fac93e28SPetar Jovanovic //
13fac93e28SPetar Jovanovic //===----------------------------------------------------------------------===//
14fac93e28SPetar Jovanovic 
15fac93e28SPetar Jovanovic #include "MipsCallLowering.h"
16366857a2SPetar Jovanovic #include "MipsCCState.h"
17efcd3c00SPetar Avramovic #include "MipsMachineFunction.h"
18326ec324SPetar Jovanovic #include "MipsTargetMachine.h"
1949168f67SAlexander Ivchenko #include "llvm/CodeGen/Analysis.h"
20fac93e28SPetar Jovanovic #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
21989f1c72Sserge-sans-paille #include "llvm/CodeGen/MachineFrameInfo.h"
22fac93e28SPetar Jovanovic 
23fac93e28SPetar Jovanovic using namespace llvm;
24fac93e28SPetar Jovanovic 
MipsCallLowering(const MipsTargetLowering & TLI)25fac93e28SPetar Jovanovic MipsCallLowering::MipsCallLowering(const MipsTargetLowering &TLI)
26fac93e28SPetar Jovanovic     : CallLowering(&TLI) {}
27fac93e28SPetar Jovanovic 
289b8b1645SBenjamin Kramer namespace {
29121541fdSMatt Arsenault struct MipsOutgoingValueAssigner : public CallLowering::OutgoingValueAssigner {
30121541fdSMatt Arsenault   /// This is the name of the function being called
31121541fdSMatt Arsenault   /// FIXME: Relying on this is unsound
32121541fdSMatt Arsenault   const char *Func = nullptr;
33366857a2SPetar Jovanovic 
34121541fdSMatt Arsenault   /// Is this a return value, or an outgoing call operand.
35121541fdSMatt Arsenault   bool IsReturn;
36ff1bc621SPetar Jovanovic 
MipsOutgoingValueAssigner__anonbef6db3a0111::MipsOutgoingValueAssigner37121541fdSMatt Arsenault   MipsOutgoingValueAssigner(CCAssignFn *AssignFn_, const char *Func,
38121541fdSMatt Arsenault                             bool IsReturn)
39121541fdSMatt Arsenault       : OutgoingValueAssigner(AssignFn_), Func(Func), IsReturn(IsReturn) {}
40ff1bc621SPetar Jovanovic 
assignArg__anonbef6db3a0111::MipsOutgoingValueAssigner41121541fdSMatt Arsenault   bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
42121541fdSMatt Arsenault                  CCValAssign::LocInfo LocInfo,
43121541fdSMatt Arsenault                  const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
44121541fdSMatt Arsenault                  CCState &State_) override {
45121541fdSMatt Arsenault     MipsCCState &State = static_cast<MipsCCState &>(State_);
46ff1bc621SPetar Jovanovic 
47121541fdSMatt Arsenault     if (IsReturn)
48121541fdSMatt Arsenault       State.PreAnalyzeReturnValue(EVT::getEVT(Info.Ty));
49121541fdSMatt Arsenault     else
50121541fdSMatt Arsenault       State.PreAnalyzeCallOperand(Info.Ty, Info.IsFixed, Func);
5169ce1c13SDiana Picus 
52121541fdSMatt Arsenault     return CallLowering::OutgoingValueAssigner::assignArg(
53121541fdSMatt Arsenault         ValNo, OrigVT, ValVT, LocVT, LocInfo, Info, Flags, State);
54121541fdSMatt Arsenault   }
55121541fdSMatt Arsenault };
56ff1bc621SPetar Jovanovic 
57121541fdSMatt Arsenault struct MipsIncomingValueAssigner : public CallLowering::IncomingValueAssigner {
58121541fdSMatt Arsenault   /// This is the name of the function being called
59121541fdSMatt Arsenault   /// FIXME: Relying on this is unsound
60121541fdSMatt Arsenault   const char *Func = nullptr;
61121541fdSMatt Arsenault 
62121541fdSMatt Arsenault   /// Is this a call return value, or an incoming function argument.
63121541fdSMatt Arsenault   bool IsReturn;
64121541fdSMatt Arsenault 
MipsIncomingValueAssigner__anonbef6db3a0111::MipsIncomingValueAssigner65121541fdSMatt Arsenault   MipsIncomingValueAssigner(CCAssignFn *AssignFn_, const char *Func,
66121541fdSMatt Arsenault                             bool IsReturn)
67121541fdSMatt Arsenault       : IncomingValueAssigner(AssignFn_), Func(Func), IsReturn(IsReturn) {}
68121541fdSMatt Arsenault 
assignArg__anonbef6db3a0111::MipsIncomingValueAssigner69121541fdSMatt Arsenault   bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
70121541fdSMatt Arsenault                  CCValAssign::LocInfo LocInfo,
71121541fdSMatt Arsenault                  const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,
72121541fdSMatt Arsenault                  CCState &State_) override {
73121541fdSMatt Arsenault     MipsCCState &State = static_cast<MipsCCState &>(State_);
74121541fdSMatt Arsenault 
75121541fdSMatt Arsenault     if (IsReturn)
76121541fdSMatt Arsenault       State.PreAnalyzeCallResult(Info.Ty, Func);
77121541fdSMatt Arsenault     else
78121541fdSMatt Arsenault       State.PreAnalyzeFormalArgument(Info.Ty, Flags);
79121541fdSMatt Arsenault 
80121541fdSMatt Arsenault     return CallLowering::IncomingValueAssigner::assignArg(
81121541fdSMatt Arsenault         ValNo, OrigVT, ValVT, LocVT, LocInfo, Info, Flags, State);
82ff1bc621SPetar Jovanovic   }
83121541fdSMatt Arsenault };
84ff1bc621SPetar Jovanovic 
85121541fdSMatt Arsenault class MipsIncomingValueHandler : public CallLowering::IncomingValueHandler {
86121541fdSMatt Arsenault   const MipsSubtarget &STI;
87121541fdSMatt Arsenault 
88366857a2SPetar Jovanovic public:
MipsIncomingValueHandler(MachineIRBuilder & MIRBuilder,MachineRegisterInfo & MRI)890c92bfa4SMatt Arsenault   MipsIncomingValueHandler(MachineIRBuilder &MIRBuilder,
900c92bfa4SMatt Arsenault                            MachineRegisterInfo &MRI)
91121541fdSMatt Arsenault       : IncomingValueHandler(MIRBuilder, MRI),
92121541fdSMatt Arsenault         STI(MIRBuilder.getMF().getSubtarget<MipsSubtarget>()) {}
93366857a2SPetar Jovanovic 
94366857a2SPetar Jovanovic private:
95121541fdSMatt Arsenault   void assignValueToReg(Register ValVReg, Register PhysReg,
968bde5e58SAmara Emerson                         CCValAssign VA) override;
97226e6117SPetar Jovanovic 
98121541fdSMatt Arsenault   Register getStackAddress(uint64_t Size, int64_t Offset,
99121541fdSMatt Arsenault                            MachinePointerInfo &MPO,
100121541fdSMatt Arsenault                            ISD::ArgFlagsTy Flags) override;
101121541fdSMatt Arsenault   void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
102121541fdSMatt Arsenault                             MachinePointerInfo &MPO, CCValAssign &VA) override;
103226e6117SPetar Jovanovic 
104121541fdSMatt Arsenault   unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
1058bde5e58SAmara Emerson                              ArrayRef<CCValAssign> VAs,
1068bde5e58SAmara Emerson                              std::function<void()> *Thunk = nullptr) override;
107ff1bc621SPetar Jovanovic 
markPhysRegUsed(unsigned PhysReg)108326ec324SPetar Jovanovic   virtual void markPhysRegUsed(unsigned PhysReg) {
109522fb7eeSTim Northover     MIRBuilder.getMRI()->addLiveIn(PhysReg);
110366857a2SPetar Jovanovic     MIRBuilder.getMBB().addLiveIn(PhysReg);
111366857a2SPetar Jovanovic   }
112366857a2SPetar Jovanovic };
113326ec324SPetar Jovanovic 
1140c92bfa4SMatt Arsenault class CallReturnHandler : public MipsIncomingValueHandler {
115326ec324SPetar Jovanovic public:
CallReturnHandler(MachineIRBuilder & MIRBuilder,MachineRegisterInfo & MRI,MachineInstrBuilder & MIB)116326ec324SPetar Jovanovic   CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
117326ec324SPetar Jovanovic                     MachineInstrBuilder &MIB)
1180c92bfa4SMatt Arsenault       : MipsIncomingValueHandler(MIRBuilder, MRI), MIB(MIB) {}
119326ec324SPetar Jovanovic 
120326ec324SPetar Jovanovic private:
markPhysRegUsed(unsigned PhysReg)121226e6117SPetar Jovanovic   void markPhysRegUsed(unsigned PhysReg) override {
122326ec324SPetar Jovanovic     MIB.addDef(PhysReg, RegState::Implicit);
123326ec324SPetar Jovanovic   }
124326ec324SPetar Jovanovic 
125326ec324SPetar Jovanovic   MachineInstrBuilder &MIB;
126326ec324SPetar Jovanovic };
127326ec324SPetar Jovanovic 
128366857a2SPetar Jovanovic } // end anonymous namespace
129366857a2SPetar Jovanovic 
assignValueToReg(Register ValVReg,Register PhysReg,CCValAssign VA)1300c92bfa4SMatt Arsenault void MipsIncomingValueHandler::assignValueToReg(Register ValVReg,
131121541fdSMatt Arsenault                                                 Register PhysReg,
1328bde5e58SAmara Emerson                                                 CCValAssign VA) {
1335a457e08SPetar Avramovic   markPhysRegUsed(PhysReg);
134121541fdSMatt Arsenault   IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA);
1355a457e08SPetar Avramovic }
136366857a2SPetar Jovanovic 
getStackAddress(uint64_t Size,int64_t Offset,MachinePointerInfo & MPO,ISD::ArgFlagsTy Flags)137121541fdSMatt Arsenault Register MipsIncomingValueHandler::getStackAddress(uint64_t Size,
138121541fdSMatt Arsenault                                                    int64_t Offset,
139121541fdSMatt Arsenault                                                    MachinePointerInfo &MPO,
140121541fdSMatt Arsenault                                                    ISD::ArgFlagsTy Flags) {
141121541fdSMatt Arsenault 
1422a64598eSMatt Arsenault   MachineFunction &MF = MIRBuilder.getMF();
1432a64598eSMatt Arsenault   MachineFrameInfo &MFI = MF.getFrameInfo();
144226e6117SPetar Jovanovic 
1456b76d828SMatt Arsenault   // FIXME: This should only be immutable for non-byval memory arguments.
146226e6117SPetar Jovanovic   int FI = MFI.CreateFixedObject(Size, Offset, true);
147121541fdSMatt Arsenault   MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
148226e6117SPetar Jovanovic 
1492a1b5af2SJay Foad   return MIRBuilder.buildFrameIndex(LLT::pointer(0, 32), FI).getReg(0);
150226e6117SPetar Jovanovic }
151226e6117SPetar Jovanovic 
assignValueToAddress(Register ValVReg,Register Addr,LLT MemTy,MachinePointerInfo & MPO,CCValAssign & VA)1520c92bfa4SMatt Arsenault void MipsIncomingValueHandler::assignValueToAddress(Register ValVReg,
153121541fdSMatt Arsenault                                                     Register Addr, LLT MemTy,
154121541fdSMatt Arsenault                                                     MachinePointerInfo &MPO,
155121541fdSMatt Arsenault                                                     CCValAssign &VA) {
156121541fdSMatt Arsenault   MachineFunction &MF = MIRBuilder.getMF();
157121541fdSMatt Arsenault   auto MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOLoad, MemTy,
158121541fdSMatt Arsenault                                      inferAlignFromPtrInfo(MF, MPO));
159121541fdSMatt Arsenault   MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
160226e6117SPetar Jovanovic }
161226e6117SPetar Jovanovic 
162121541fdSMatt Arsenault /// Handle cases when f64 is split into 2 32-bit GPRs. This is a custom
163121541fdSMatt Arsenault /// assignment because generic code assumes getNumRegistersForCallingConv is
164121541fdSMatt Arsenault /// accurate. In this case it is not because the type/number are context
165121541fdSMatt Arsenault /// dependent on other arguments.
166121541fdSMatt Arsenault unsigned
assignCustomValue(CallLowering::ArgInfo & Arg,ArrayRef<CCValAssign> VAs,std::function<void ()> * Thunk)167121541fdSMatt Arsenault MipsIncomingValueHandler::assignCustomValue(CallLowering::ArgInfo &Arg,
1688bde5e58SAmara Emerson                                             ArrayRef<CCValAssign> VAs,
1698bde5e58SAmara Emerson                                             std::function<void()> *Thunk) {
170121541fdSMatt Arsenault   const CCValAssign &VALo = VAs[0];
171121541fdSMatt Arsenault   const CCValAssign &VAHi = VAs[1];
172121541fdSMatt Arsenault 
173121541fdSMatt Arsenault   assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
174121541fdSMatt Arsenault          VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
175121541fdSMatt Arsenault          "unexpected custom value");
176121541fdSMatt Arsenault 
177121541fdSMatt Arsenault   auto CopyLo = MIRBuilder.buildCopy(LLT::scalar(32), VALo.getLocReg());
178121541fdSMatt Arsenault   auto CopyHi = MIRBuilder.buildCopy(LLT::scalar(32), VAHi.getLocReg());
179121541fdSMatt Arsenault   if (!STI.isLittle())
180121541fdSMatt Arsenault     std::swap(CopyLo, CopyHi);
181121541fdSMatt Arsenault 
182121541fdSMatt Arsenault   Arg.OrigRegs.assign(Arg.Regs.begin(), Arg.Regs.end());
183121541fdSMatt Arsenault   Arg.Regs = { CopyLo.getReg(0), CopyHi.getReg(0) };
184121541fdSMatt Arsenault   MIRBuilder.buildMerge(Arg.OrigRegs[0], {CopyLo, CopyHi});
185121541fdSMatt Arsenault 
186121541fdSMatt Arsenault   markPhysRegUsed(VALo.getLocReg());
187121541fdSMatt Arsenault   markPhysRegUsed(VAHi.getLocReg());
188121541fdSMatt Arsenault   return 2;
189366857a2SPetar Jovanovic }
190366857a2SPetar Jovanovic 
191366857a2SPetar Jovanovic namespace {
192121541fdSMatt Arsenault class MipsOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
193121541fdSMatt Arsenault   const MipsSubtarget &STI;
194121541fdSMatt Arsenault 
195366857a2SPetar Jovanovic public:
MipsOutgoingValueHandler(MachineIRBuilder & MIRBuilder,MachineRegisterInfo & MRI,MachineInstrBuilder & MIB)1960c92bfa4SMatt Arsenault   MipsOutgoingValueHandler(MachineIRBuilder &MIRBuilder,
1970c92bfa4SMatt Arsenault                            MachineRegisterInfo &MRI, MachineInstrBuilder &MIB)
198121541fdSMatt Arsenault       : OutgoingValueHandler(MIRBuilder, MRI),
199121541fdSMatt Arsenault         STI(MIRBuilder.getMF().getSubtarget<MipsSubtarget>()), MIB(MIB) {}
200366857a2SPetar Jovanovic 
201366857a2SPetar Jovanovic private:
202121541fdSMatt Arsenault   void assignValueToReg(Register ValVReg, Register PhysReg,
2038bde5e58SAmara Emerson                         CCValAssign VA) override;
204226e6117SPetar Jovanovic 
205121541fdSMatt Arsenault   Register getStackAddress(uint64_t Size, int64_t Offset,
206121541fdSMatt Arsenault                            MachinePointerInfo &MPO,
207121541fdSMatt Arsenault                            ISD::ArgFlagsTy Flags) override;
208226e6117SPetar Jovanovic 
209121541fdSMatt Arsenault   void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
210121541fdSMatt Arsenault                             MachinePointerInfo &MPO, CCValAssign &VA) override;
211121541fdSMatt Arsenault   unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
2128bde5e58SAmara Emerson                              ArrayRef<CCValAssign> VAs,
2138bde5e58SAmara Emerson                              std::function<void()> *Thunk) override;
214366857a2SPetar Jovanovic 
215366857a2SPetar Jovanovic   MachineInstrBuilder &MIB;
216366857a2SPetar Jovanovic };
217366857a2SPetar Jovanovic } // end anonymous namespace
218366857a2SPetar Jovanovic 
assignValueToReg(Register ValVReg,Register PhysReg,CCValAssign VA)2190c92bfa4SMatt Arsenault void MipsOutgoingValueHandler::assignValueToReg(Register ValVReg,
220121541fdSMatt Arsenault                                                 Register PhysReg,
2218bde5e58SAmara Emerson                                                 CCValAssign VA) {
222faeaedf8SMatt Arsenault   Register ExtReg = extendRegister(ValVReg, VA);
22365d463bdSPetar Jovanovic   MIRBuilder.buildCopy(PhysReg, ExtReg);
224366857a2SPetar Jovanovic   MIB.addUse(PhysReg, RegState::Implicit);
225366857a2SPetar Jovanovic }
226366857a2SPetar Jovanovic 
getStackAddress(uint64_t Size,int64_t Offset,MachinePointerInfo & MPO,ISD::ArgFlagsTy Flags)227121541fdSMatt Arsenault Register MipsOutgoingValueHandler::getStackAddress(uint64_t Size,
228121541fdSMatt Arsenault                                                    int64_t Offset,
229121541fdSMatt Arsenault                                                    MachinePointerInfo &MPO,
230121541fdSMatt Arsenault                                                    ISD::ArgFlagsTy Flags) {
2312a64598eSMatt Arsenault   MachineFunction &MF = MIRBuilder.getMF();
232121541fdSMatt Arsenault   MPO = MachinePointerInfo::getStack(MF, Offset);
2332a64598eSMatt Arsenault 
234226e6117SPetar Jovanovic   LLT p0 = LLT::pointer(0, 32);
235226e6117SPetar Jovanovic   LLT s32 = LLT::scalar(32);
2362a1b5af2SJay Foad   auto SPReg = MIRBuilder.buildCopy(p0, Register(Mips::SP));
237226e6117SPetar Jovanovic 
2382a1b5af2SJay Foad   auto OffsetReg = MIRBuilder.buildConstant(s32, Offset);
2392a1b5af2SJay Foad   auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg);
2402a1b5af2SJay Foad   return AddrReg.getReg(0);
241226e6117SPetar Jovanovic }
242226e6117SPetar Jovanovic 
assignValueToAddress(Register ValVReg,Register Addr,LLT MemTy,MachinePointerInfo & MPO,CCValAssign & VA)2430c92bfa4SMatt Arsenault void MipsOutgoingValueHandler::assignValueToAddress(Register ValVReg,
244121541fdSMatt Arsenault                                                     Register Addr, LLT MemTy,
245121541fdSMatt Arsenault                                                     MachinePointerInfo &MPO,
246121541fdSMatt Arsenault                                                     CCValAssign &VA) {
247121541fdSMatt Arsenault   MachineFunction &MF = MIRBuilder.getMF();
248121541fdSMatt Arsenault   uint64_t LocMemOffset = VA.getLocMemOffset();
249121541fdSMatt Arsenault 
250121541fdSMatt Arsenault   auto MMO = MF.getMachineMemOperand(
251121541fdSMatt Arsenault       MPO, MachineMemOperand::MOStore, MemTy,
252121541fdSMatt Arsenault       commonAlignment(STI.getStackAlignment(), LocMemOffset));
253121541fdSMatt Arsenault 
254faeaedf8SMatt Arsenault   Register ExtReg = extendRegister(ValVReg, VA);
25565d463bdSPetar Jovanovic   MIRBuilder.buildStore(ExtReg, Addr, *MMO);
25665d463bdSPetar Jovanovic }
25765d463bdSPetar Jovanovic 
258121541fdSMatt Arsenault unsigned
assignCustomValue(CallLowering::ArgInfo & Arg,ArrayRef<CCValAssign> VAs,std::function<void ()> * Thunk)259121541fdSMatt Arsenault MipsOutgoingValueHandler::assignCustomValue(CallLowering::ArgInfo &Arg,
2608bde5e58SAmara Emerson                                             ArrayRef<CCValAssign> VAs,
2618bde5e58SAmara Emerson                                             std::function<void()> *Thunk) {
262121541fdSMatt Arsenault   const CCValAssign &VALo = VAs[0];
263121541fdSMatt Arsenault   const CCValAssign &VAHi = VAs[1];
264226e6117SPetar Jovanovic 
265121541fdSMatt Arsenault   assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
266121541fdSMatt Arsenault          VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
267121541fdSMatt Arsenault          "unexpected custom value");
268ff1bc621SPetar Jovanovic 
269121541fdSMatt Arsenault   auto Unmerge =
270121541fdSMatt Arsenault       MIRBuilder.buildUnmerge({LLT::scalar(32), LLT::scalar(32)}, Arg.Regs[0]);
271121541fdSMatt Arsenault   Register Lo = Unmerge.getReg(0);
272121541fdSMatt Arsenault   Register Hi = Unmerge.getReg(1);
273121541fdSMatt Arsenault 
274121541fdSMatt Arsenault   Arg.OrigRegs.assign(Arg.Regs.begin(), Arg.Regs.end());
275121541fdSMatt Arsenault   Arg.Regs = { Lo, Hi };
276121541fdSMatt Arsenault   if (!STI.isLittle())
277121541fdSMatt Arsenault     std::swap(Lo, Hi);
278121541fdSMatt Arsenault 
2798bde5e58SAmara Emerson   // If we can return a thunk, just include the register copies. The unmerge can
2808bde5e58SAmara Emerson   // be emitted earlier.
2818bde5e58SAmara Emerson   if (Thunk) {
2828bde5e58SAmara Emerson     *Thunk = [=]() {
2838bde5e58SAmara Emerson       MIRBuilder.buildCopy(VALo.getLocReg(), Lo);
2848bde5e58SAmara Emerson       MIRBuilder.buildCopy(VAHi.getLocReg(), Hi);
2858bde5e58SAmara Emerson     };
2868bde5e58SAmara Emerson     return 2;
2878bde5e58SAmara Emerson   }
288121541fdSMatt Arsenault   MIRBuilder.buildCopy(VALo.getLocReg(), Lo);
289121541fdSMatt Arsenault   MIRBuilder.buildCopy(VAHi.getLocReg(), Hi);
290121541fdSMatt Arsenault   return 2;
291366857a2SPetar Jovanovic }
292366857a2SPetar Jovanovic 
isSupportedArgumentType(Type * T)293ed305191SPetar Avramovic static bool isSupportedArgumentType(Type *T) {
294ff1bc621SPetar Jovanovic   if (T->isIntegerTy())
295366857a2SPetar Jovanovic     return true;
29658c02100SPetar Jovanovic   if (T->isPointerTy())
29758c02100SPetar Jovanovic     return true;
2985a457e08SPetar Avramovic   if (T->isFloatingPointTy())
2995a457e08SPetar Avramovic     return true;
300366857a2SPetar Jovanovic   return false;
301366857a2SPetar Jovanovic }
302366857a2SPetar Jovanovic 
isSupportedReturnType(Type * T)303ed305191SPetar Avramovic static bool isSupportedReturnType(Type *T) {
304ed305191SPetar Avramovic   if (T->isIntegerTy())
305ed305191SPetar Avramovic     return true;
306ed305191SPetar Avramovic   if (T->isPointerTy())
307ed305191SPetar Avramovic     return true;
308ed305191SPetar Avramovic   if (T->isFloatingPointTy())
309ed305191SPetar Avramovic     return true;
310ed305191SPetar Avramovic   if (T->isAggregateType())
311ed305191SPetar Avramovic     return true;
312ed305191SPetar Avramovic   return false;
313ed305191SPetar Avramovic }
314ed305191SPetar Avramovic 
lowerReturn(MachineIRBuilder & MIRBuilder,const Value * Val,ArrayRef<Register> VRegs,FunctionLoweringInfo & FLI) const315fac93e28SPetar Jovanovic bool MipsCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
316d68458bdSChristudasan Devadasan                                    const Value *Val, ArrayRef<Register> VRegs,
317d68458bdSChristudasan Devadasan                                    FunctionLoweringInfo &FLI) const {
318fac93e28SPetar Jovanovic 
319fac93e28SPetar Jovanovic   MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(Mips::RetRA);
320fac93e28SPetar Jovanovic 
321ed305191SPetar Avramovic   if (Val != nullptr && !isSupportedReturnType(Val->getType()))
322fac93e28SPetar Jovanovic     return false;
323366857a2SPetar Jovanovic 
32449168f67SAlexander Ivchenko   if (!VRegs.empty()) {
325366857a2SPetar Jovanovic     MachineFunction &MF = MIRBuilder.getMF();
326366857a2SPetar Jovanovic     const Function &F = MF.getFunction();
327366857a2SPetar Jovanovic     const DataLayout &DL = MF.getDataLayout();
328366857a2SPetar Jovanovic     const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
329366857a2SPetar Jovanovic 
330366857a2SPetar Jovanovic     SmallVector<ArgInfo, 8> RetInfos;
331366857a2SPetar Jovanovic 
332121541fdSMatt Arsenault     ArgInfo ArgRetInfo(VRegs, *Val, 0);
333ed305191SPetar Avramovic     setArgFlags(ArgRetInfo, AttributeList::ReturnIndex, DL, F);
33443f25e61SMatt Arsenault     splitToValueTypes(ArgRetInfo, RetInfos, DL, F.getCallingConv());
335366857a2SPetar Jovanovic 
336366857a2SPetar Jovanovic     SmallVector<CCValAssign, 16> ArgLocs;
337121541fdSMatt Arsenault     SmallVector<ISD::OutputArg, 8> Outs;
338121541fdSMatt Arsenault 
339366857a2SPetar Jovanovic     MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
340366857a2SPetar Jovanovic                        F.getContext());
341366857a2SPetar Jovanovic 
3420c92bfa4SMatt Arsenault     MipsOutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret);
343121541fdSMatt Arsenault     std::string FuncName = F.getName().str();
344121541fdSMatt Arsenault     MipsOutgoingValueAssigner Assigner(TLI.CCAssignFnForReturn(),
345121541fdSMatt Arsenault                                        FuncName.c_str(), /*IsReturn*/ true);
346121541fdSMatt Arsenault 
347121541fdSMatt Arsenault     if (!determineAssignments(Assigner, RetInfos, CCInfo))
348121541fdSMatt Arsenault       return false;
349121541fdSMatt Arsenault 
350121541fdSMatt Arsenault     if (!handleAssignments(RetHandler, RetInfos, CCInfo, ArgLocs, MIRBuilder))
351366857a2SPetar Jovanovic       return false;
352366857a2SPetar Jovanovic   }
353121541fdSMatt Arsenault 
354fac93e28SPetar Jovanovic   MIRBuilder.insertInstr(Ret);
355fac93e28SPetar Jovanovic   return true;
356fac93e28SPetar Jovanovic }
357fac93e28SPetar Jovanovic 
lowerFormalArguments(MachineIRBuilder & MIRBuilder,const Function & F,ArrayRef<ArrayRef<Register>> VRegs,FunctionLoweringInfo & FLI) const358d68458bdSChristudasan Devadasan bool MipsCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
359d68458bdSChristudasan Devadasan                                             const Function &F,
360d68458bdSChristudasan Devadasan                                             ArrayRef<ArrayRef<Register>> VRegs,
361d68458bdSChristudasan Devadasan                                             FunctionLoweringInfo &FLI) const {
362fac93e28SPetar Jovanovic 
363fac93e28SPetar Jovanovic   // Quick exit if there aren't any args.
364fac93e28SPetar Jovanovic   if (F.arg_empty())
365fac93e28SPetar Jovanovic     return true;
366fac93e28SPetar Jovanovic 
367366857a2SPetar Jovanovic   for (auto &Arg : F.args()) {
368ed305191SPetar Avramovic     if (!isSupportedArgumentType(Arg.getType()))
369366857a2SPetar Jovanovic       return false;
370366857a2SPetar Jovanovic   }
371366857a2SPetar Jovanovic 
372366857a2SPetar Jovanovic   MachineFunction &MF = MIRBuilder.getMF();
373366857a2SPetar Jovanovic   const DataLayout &DL = MF.getDataLayout();
374366857a2SPetar Jovanovic   const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
375366857a2SPetar Jovanovic 
376366857a2SPetar Jovanovic   SmallVector<ArgInfo, 8> ArgInfos;
377366857a2SPetar Jovanovic   unsigned i = 0;
378366857a2SPetar Jovanovic   for (auto &Arg : F.args()) {
379121541fdSMatt Arsenault     ArgInfo AInfo(VRegs[i], Arg, i);
380366857a2SPetar Jovanovic     setArgFlags(AInfo, i + AttributeList::FirstArgIndex, DL, F);
381121541fdSMatt Arsenault 
382121541fdSMatt Arsenault     splitToValueTypes(AInfo, ArgInfos, DL, F.getCallingConv());
383366857a2SPetar Jovanovic     ++i;
384366857a2SPetar Jovanovic   }
385366857a2SPetar Jovanovic 
386366857a2SPetar Jovanovic   SmallVector<ISD::InputArg, 8> Ins;
387366857a2SPetar Jovanovic 
388366857a2SPetar Jovanovic   SmallVector<CCValAssign, 16> ArgLocs;
389366857a2SPetar Jovanovic   MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
390366857a2SPetar Jovanovic                      F.getContext());
391366857a2SPetar Jovanovic 
392226e6117SPetar Jovanovic   const MipsTargetMachine &TM =
393226e6117SPetar Jovanovic       static_cast<const MipsTargetMachine &>(MF.getTarget());
394226e6117SPetar Jovanovic   const MipsABIInfo &ABI = TM.getABI();
395226e6117SPetar Jovanovic   CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(F.getCallingConv()),
3961778564fSGuillaume Chatelet                        Align(1));
397121541fdSMatt Arsenault 
398121541fdSMatt Arsenault   const std::string FuncName = F.getName().str();
399121541fdSMatt Arsenault   MipsIncomingValueAssigner Assigner(TLI.CCAssignFnForCall(), FuncName.c_str(),
400121541fdSMatt Arsenault                                      /*IsReturn*/ false);
401121541fdSMatt Arsenault   if (!determineAssignments(Assigner, ArgInfos, CCInfo))
402121541fdSMatt Arsenault     return false;
403366857a2SPetar Jovanovic 
4040c92bfa4SMatt Arsenault   MipsIncomingValueHandler Handler(MIRBuilder, MF.getRegInfo());
405121541fdSMatt Arsenault   if (!handleAssignments(Handler, ArgInfos, CCInfo, ArgLocs, MIRBuilder))
406366857a2SPetar Jovanovic     return false;
407366857a2SPetar Jovanovic 
408c063b0b0SPetar Avramovic   if (F.isVarArg()) {
409c063b0b0SPetar Avramovic     ArrayRef<MCPhysReg> ArgRegs = ABI.GetVarArgRegs();
410c063b0b0SPetar Avramovic     unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
411c063b0b0SPetar Avramovic 
412c063b0b0SPetar Avramovic     int VaArgOffset;
413c063b0b0SPetar Avramovic     unsigned RegSize = 4;
414c063b0b0SPetar Avramovic     if (ArgRegs.size() == Idx)
415c063b0b0SPetar Avramovic       VaArgOffset = alignTo(CCInfo.getNextStackOffset(), RegSize);
416c063b0b0SPetar Avramovic     else {
417c063b0b0SPetar Avramovic       VaArgOffset =
418c063b0b0SPetar Avramovic           (int)ABI.GetCalleeAllocdArgSizeInBytes(CCInfo.getCallingConv()) -
419c063b0b0SPetar Avramovic           (int)(RegSize * (ArgRegs.size() - Idx));
420c063b0b0SPetar Avramovic     }
421c063b0b0SPetar Avramovic 
422c063b0b0SPetar Avramovic     MachineFrameInfo &MFI = MF.getFrameInfo();
423c063b0b0SPetar Avramovic     int FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true);
424c063b0b0SPetar Avramovic     MF.getInfo<MipsFunctionInfo>()->setVarArgsFrameIndex(FI);
425c063b0b0SPetar Avramovic 
426c063b0b0SPetar Avramovic     for (unsigned I = Idx; I < ArgRegs.size(); ++I, VaArgOffset += RegSize) {
427c063b0b0SPetar Avramovic       MIRBuilder.getMBB().addLiveIn(ArgRegs[I]);
4289ad1a499SMatt Arsenault       LLT RegTy = LLT::scalar(RegSize * 8);
429c063b0b0SPetar Avramovic       MachineInstrBuilder Copy =
4309ad1a499SMatt Arsenault           MIRBuilder.buildCopy(RegTy, Register(ArgRegs[I]));
431c063b0b0SPetar Avramovic       FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true);
432c063b0b0SPetar Avramovic       MachinePointerInfo MPO = MachinePointerInfo::getFixedStack(MF, FI);
4339ad1a499SMatt Arsenault 
4349ad1a499SMatt Arsenault       const LLT PtrTy = LLT::pointer(MPO.getAddrSpace(), 32);
4359ad1a499SMatt Arsenault       auto FrameIndex = MIRBuilder.buildFrameIndex(PtrTy, FI);
436c9d5c195SGuillaume Chatelet       MachineMemOperand *MMO = MF.getMachineMemOperand(
4379ad1a499SMatt Arsenault           MPO, MachineMemOperand::MOStore, RegTy, Align(RegSize));
438c063b0b0SPetar Avramovic       MIRBuilder.buildStore(Copy, FrameIndex, *MMO);
439c063b0b0SPetar Avramovic     }
440c063b0b0SPetar Avramovic   }
441c063b0b0SPetar Avramovic 
442366857a2SPetar Jovanovic   return true;
443366857a2SPetar Jovanovic }
444366857a2SPetar Jovanovic 
lowerCall(MachineIRBuilder & MIRBuilder,CallLoweringInfo & Info) const445326ec324SPetar Jovanovic bool MipsCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
446e1a5f668STim Northover                                  CallLoweringInfo &Info) const {
447326ec324SPetar Jovanovic 
448e1a5f668STim Northover   if (Info.CallConv != CallingConv::C)
449326ec324SPetar Jovanovic     return false;
450326ec324SPetar Jovanovic 
451e1a5f668STim Northover   for (auto &Arg : Info.OrigArgs) {
452ed305191SPetar Avramovic     if (!isSupportedArgumentType(Arg.Ty))
453326ec324SPetar Jovanovic       return false;
454d2574d79SPetar Avramovic     if (Arg.Flags[0].isByVal())
455d2574d79SPetar Avramovic       return false;
456d2574d79SPetar Avramovic     if (Arg.Flags[0].isSRet() && !Arg.Ty->isPointerTy())
457326ec324SPetar Jovanovic       return false;
458326ec324SPetar Jovanovic   }
45969ce1c13SDiana Picus 
460ed305191SPetar Avramovic   if (!Info.OrigRet.Ty->isVoidTy() && !isSupportedReturnType(Info.OrigRet.Ty))
461326ec324SPetar Jovanovic     return false;
462326ec324SPetar Jovanovic 
463326ec324SPetar Jovanovic   MachineFunction &MF = MIRBuilder.getMF();
464326ec324SPetar Jovanovic   const Function &F = MF.getFunction();
465ed305191SPetar Avramovic   const DataLayout &DL = MF.getDataLayout();
466326ec324SPetar Jovanovic   const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();
467326ec324SPetar Jovanovic   const MipsTargetMachine &TM =
468326ec324SPetar Jovanovic       static_cast<const MipsTargetMachine &>(MF.getTarget());
469326ec324SPetar Jovanovic   const MipsABIInfo &ABI = TM.getABI();
470326ec324SPetar Jovanovic 
471326ec324SPetar Jovanovic   MachineInstrBuilder CallSeqStart =
472326ec324SPetar Jovanovic       MIRBuilder.buildInstr(Mips::ADJCALLSTACKDOWN);
473326ec324SPetar Jovanovic 
474efcd3c00SPetar Avramovic   const bool IsCalleeGlobalPIC =
475e1a5f668STim Northover       Info.Callee.isGlobal() && TM.isPositionIndependent();
476efcd3c00SPetar Avramovic 
477f4a6dd28SPetar Avramovic   MachineInstrBuilder MIB = MIRBuilder.buildInstrNoInsert(
478e1a5f668STim Northover       Info.Callee.isReg() || IsCalleeGlobalPIC ? Mips::JALRPseudo : Mips::JAL);
479326ec324SPetar Jovanovic   MIB.addDef(Mips::SP, RegState::Implicit);
480efcd3c00SPetar Avramovic   if (IsCalleeGlobalPIC) {
481faeaedf8SMatt Arsenault     Register CalleeReg =
482efcd3c00SPetar Avramovic         MF.getRegInfo().createGenericVirtualRegister(LLT::pointer(0, 32));
483efcd3c00SPetar Avramovic     MachineInstr *CalleeGlobalValue =
484e1a5f668STim Northover         MIRBuilder.buildGlobalValue(CalleeReg, Info.Callee.getGlobal());
485e1a5f668STim Northover     if (!Info.Callee.getGlobal()->hasLocalLinkage())
486efcd3c00SPetar Avramovic       CalleeGlobalValue->getOperand(1).setTargetFlags(MipsII::MO_GOT_CALL);
487efcd3c00SPetar Avramovic     MIB.addUse(CalleeReg);
488efcd3c00SPetar Avramovic   } else
489e1a5f668STim Northover     MIB.add(Info.Callee);
490326ec324SPetar Jovanovic   const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
4912f9504aaSMatt Arsenault   MIB.addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv));
492326ec324SPetar Jovanovic 
493326ec324SPetar Jovanovic   TargetLowering::ArgListTy FuncOrigArgs;
494e1a5f668STim Northover   FuncOrigArgs.reserve(Info.OrigArgs.size());
495326ec324SPetar Jovanovic 
496326ec324SPetar Jovanovic   SmallVector<ArgInfo, 8> ArgInfos;
497121541fdSMatt Arsenault   for (auto &Arg : Info.OrigArgs)
498121541fdSMatt Arsenault     splitToValueTypes(Arg, ArgInfos, DL, Info.CallConv);
499326ec324SPetar Jovanovic 
500326ec324SPetar Jovanovic   SmallVector<CCValAssign, 8> ArgLocs;
501c063b0b0SPetar Avramovic   bool IsCalleeVarArg = false;
502c063b0b0SPetar Avramovic   if (Info.Callee.isGlobal()) {
503c063b0b0SPetar Avramovic     const Function *CF = static_cast<const Function *>(Info.Callee.getGlobal());
504c063b0b0SPetar Avramovic     IsCalleeVarArg = CF->isVarArg();
505c063b0b0SPetar Avramovic   }
506121541fdSMatt Arsenault 
507121541fdSMatt Arsenault   // FIXME: Should use MipsCCState::getSpecialCallingConvForCallee, but it
508121541fdSMatt Arsenault   // depends on looking directly at the call target.
5092f9504aaSMatt Arsenault   MipsCCState CCInfo(Info.CallConv, IsCalleeVarArg, MF, ArgLocs,
510326ec324SPetar Jovanovic                      F.getContext());
511326ec324SPetar Jovanovic 
5121778564fSGuillaume Chatelet   CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(Info.CallConv),
5131778564fSGuillaume Chatelet                        Align(1));
514121541fdSMatt Arsenault 
515e1a5f668STim Northover   const char *Call =
516e1a5f668STim Northover       Info.Callee.isSymbol() ? Info.Callee.getSymbolName() : nullptr;
517326ec324SPetar Jovanovic 
518121541fdSMatt Arsenault   MipsOutgoingValueAssigner Assigner(TLI.CCAssignFnForCall(), Call,
519121541fdSMatt Arsenault                                      /*IsReturn*/ false);
520121541fdSMatt Arsenault   if (!determineAssignments(Assigner, ArgInfos, CCInfo))
521326ec324SPetar Jovanovic     return false;
522121541fdSMatt Arsenault 
523121541fdSMatt Arsenault   MipsOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), MIB);
524121541fdSMatt Arsenault   if (!handleAssignments(ArgHandler, ArgInfos, CCInfo, ArgLocs, MIRBuilder))
525121541fdSMatt Arsenault     return false;
526326ec324SPetar Jovanovic 
527226e6117SPetar Jovanovic   unsigned NextStackOffset = CCInfo.getNextStackOffset();
5283787ee45SNick Desaulniers   unsigned StackAlignment = F.getParent()->getOverrideStackAlignment();
5293787ee45SNick Desaulniers   if (!StackAlignment) {
530226e6117SPetar Jovanovic     const TargetFrameLowering *TFL = MF.getSubtarget().getFrameLowering();
5313787ee45SNick Desaulniers     StackAlignment = TFL->getStackAlignment();
5323787ee45SNick Desaulniers   }
533226e6117SPetar Jovanovic   NextStackOffset = alignTo(NextStackOffset, StackAlignment);
534226e6117SPetar Jovanovic   CallSeqStart.addImm(NextStackOffset).addImm(0);
535226e6117SPetar Jovanovic 
536efcd3c00SPetar Avramovic   if (IsCalleeGlobalPIC) {
537efcd3c00SPetar Avramovic     MIRBuilder.buildCopy(
538faeaedf8SMatt Arsenault       Register(Mips::GP),
539669bb311SMatt Arsenault       MF.getInfo<MipsFunctionInfo>()->getGlobalBaseRegForGlobalISel(MF));
540efcd3c00SPetar Avramovic     MIB.addDef(Mips::GP, RegState::Implicit);
541efcd3c00SPetar Avramovic   }
542326ec324SPetar Jovanovic   MIRBuilder.insertInstr(MIB);
543f4a6dd28SPetar Avramovic   if (MIB->getOpcode() == Mips::JALRPseudo) {
544*ad73ce31SZongwei Lan     const MipsSubtarget &STI = MIRBuilder.getMF().getSubtarget<MipsSubtarget>();
545f4a6dd28SPetar Avramovic     MIB.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),
546f4a6dd28SPetar Avramovic                          *STI.getRegBankInfo());
547f4a6dd28SPetar Avramovic   }
548326ec324SPetar Jovanovic 
549e1a5f668STim Northover   if (!Info.OrigRet.Ty->isVoidTy()) {
550326ec324SPetar Jovanovic     ArgInfos.clear();
551326ec324SPetar Jovanovic 
552121541fdSMatt Arsenault     CallLowering::splitToValueTypes(Info.OrigRet, ArgInfos, DL,
553121541fdSMatt Arsenault                                     F.getCallingConv());
554121541fdSMatt Arsenault 
555121541fdSMatt Arsenault     const std::string FuncName = F.getName().str();
556326ec324SPetar Jovanovic     SmallVector<ISD::InputArg, 8> Ins;
557326ec324SPetar Jovanovic     SmallVector<CCValAssign, 8> ArgLocs;
558121541fdSMatt Arsenault     MipsIncomingValueAssigner Assigner(TLI.CCAssignFnForReturn(),
559121541fdSMatt Arsenault                                        FuncName.c_str(),
560121541fdSMatt Arsenault                                        /*IsReturn*/ true);
561121541fdSMatt Arsenault     CallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), MIB);
562121541fdSMatt Arsenault 
563121541fdSMatt Arsenault     MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,
564326ec324SPetar Jovanovic                        F.getContext());
565326ec324SPetar Jovanovic 
566121541fdSMatt Arsenault     if (!determineAssignments(Assigner, ArgInfos, CCInfo))
567121541fdSMatt Arsenault       return false;
568326ec324SPetar Jovanovic 
569121541fdSMatt Arsenault     if (!handleAssignments(RetHandler, ArgInfos, CCInfo, ArgLocs, MIRBuilder))
570326ec324SPetar Jovanovic       return false;
571326ec324SPetar Jovanovic   }
572326ec324SPetar Jovanovic 
573226e6117SPetar Jovanovic   MIRBuilder.buildInstr(Mips::ADJCALLSTACKUP).addImm(NextStackOffset).addImm(0);
574326ec324SPetar Jovanovic 
575326ec324SPetar Jovanovic   return true;
576326ec324SPetar Jovanovic }
577