1 //===-- llvm/lib/Target/ARM/ARMCallLowering.cpp - Call lowering -----------===//
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 "ARMCallLowering.h"
17 
18 #include "ARMBaseInstrInfo.h"
19 #include "ARMISelLowering.h"
20 
21 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
22 #include "llvm/CodeGen/MachineRegisterInfo.h"
23 
24 using namespace llvm;
25 
26 #ifndef LLVM_BUILD_GLOBAL_ISEL
27 #error "This shouldn't be built without GISel"
28 #endif
29 
30 ARMCallLowering::ARMCallLowering(const ARMTargetLowering &TLI)
31     : CallLowering(&TLI) {}
32 
33 static bool isSupportedType(const DataLayout &DL, const ARMTargetLowering &TLI,
34                             Type *T) {
35   EVT VT = TLI.getValueType(DL, T);
36   if (!VT.isSimple() || !VT.isInteger() || VT.isVector())
37     return false;
38 
39   unsigned VTSize = VT.getSimpleVT().getSizeInBits();
40   return VTSize == 8 || VTSize == 16 || VTSize == 32;
41 }
42 
43 namespace {
44 struct FuncReturnHandler : public CallLowering::ValueHandler {
45   FuncReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
46                     MachineInstrBuilder &MIB, CCAssignFn *AssignFn)
47     : ValueHandler(MIRBuilder, MRI, AssignFn), MIB(MIB) {}
48 
49   unsigned getStackAddress(uint64_t Size, int64_t Offset,
50                            MachinePointerInfo &MPO) override {
51     llvm_unreachable("Don't know how to get a stack address yet");
52   }
53 
54   void assignValueToReg(unsigned ValVReg, unsigned PhysReg,
55                         CCValAssign &VA) override {
56     assert(VA.isRegLoc() && "Value shouldn't be assigned to reg");
57     assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?");
58 
59     assert(VA.getValVT().getSizeInBits() <= 32 && "Unsupported value size");
60     assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size");
61 
62     assert(VA.getLocInfo() != CCValAssign::SExt &&
63            VA.getLocInfo() != CCValAssign::ZExt &&
64            "ABI extensions not supported yet");
65 
66     MIRBuilder.buildCopy(PhysReg, ValVReg);
67     MIB.addUse(PhysReg, RegState::Implicit);
68   }
69 
70   void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
71                             MachinePointerInfo &MPO, CCValAssign &VA) override {
72     llvm_unreachable("Don't know how to assign a value to an address yet");
73   }
74 
75   MachineInstrBuilder &MIB;
76 };
77 } // End anonymous namespace.
78 
79 /// Lower the return value for the already existing \p Ret. This assumes that
80 /// \p MIRBuilder's insertion point is correct.
81 bool ARMCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
82                                      const Value *Val, unsigned VReg,
83                                      MachineInstrBuilder &Ret) const {
84   if (!Val)
85     // Nothing to do here.
86     return true;
87 
88   auto &MF = MIRBuilder.getMF();
89   const auto &F = *MF.getFunction();
90 
91   auto DL = MF.getDataLayout();
92   auto &TLI = *getTLI<ARMTargetLowering>();
93   if (!isSupportedType(DL, TLI, Val->getType()))
94     return false;
95 
96   CCAssignFn *AssignFn =
97       TLI.CCAssignFnForReturn(F.getCallingConv(), F.isVarArg());
98 
99   ArgInfo RetInfo(VReg, Val->getType());
100   setArgFlags(RetInfo, AttributeSet::ReturnIndex, DL, F);
101 
102   FuncReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret, AssignFn);
103   return handleAssignments(MIRBuilder, RetInfo, RetHandler);
104 }
105 
106 bool ARMCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
107                                   const Value *Val, unsigned VReg) const {
108   assert(!Val == !VReg && "Return value without a vreg");
109 
110   auto Ret = MIRBuilder.buildInstrNoInsert(ARM::BX_RET).add(predOps(ARMCC::AL));
111 
112   if (!lowerReturnVal(MIRBuilder, Val, VReg, Ret))
113     return false;
114 
115   MIRBuilder.insertInstr(Ret);
116   return true;
117 }
118 
119 namespace {
120 struct FormalArgHandler : public CallLowering::ValueHandler {
121   FormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
122                    CCAssignFn AssignFn)
123       : ValueHandler(MIRBuilder, MRI, AssignFn) {}
124 
125   unsigned getStackAddress(uint64_t Size, int64_t Offset,
126                            MachinePointerInfo &MPO) override {
127     assert(Size == 4 && "Unsupported size");
128 
129     auto &MFI = MIRBuilder.getMF().getFrameInfo();
130 
131     int FI = MFI.CreateFixedObject(Size, Offset, true);
132     MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
133 
134     unsigned AddrReg =
135         MRI.createGenericVirtualRegister(LLT::pointer(MPO.getAddrSpace(), 32));
136     MIRBuilder.buildFrameIndex(AddrReg, FI);
137 
138     return AddrReg;
139   }
140 
141   void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
142                             MachinePointerInfo &MPO, CCValAssign &VA) override {
143     assert(Size == 4 && "Unsupported size");
144 
145     auto MMO = MIRBuilder.getMF().getMachineMemOperand(
146         MPO, MachineMemOperand::MOLoad, Size, /* Alignment */ 0);
147     MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
148   }
149 
150   void assignValueToReg(unsigned ValVReg, unsigned PhysReg,
151                         CCValAssign &VA) override {
152     assert(VA.isRegLoc() && "Value shouldn't be assigned to reg");
153     assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?");
154 
155     assert(VA.getValVT().getSizeInBits() <= 32 && "Unsupported value size");
156     assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size");
157 
158     MIRBuilder.getMBB().addLiveIn(PhysReg);
159     MIRBuilder.buildCopy(ValVReg, PhysReg);
160   }
161 };
162 } // End anonymous namespace
163 
164 bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
165                                            const Function &F,
166                                            ArrayRef<unsigned> VRegs) const {
167   // Quick exit if there aren't any args
168   if (F.arg_empty())
169     return true;
170 
171   if (F.isVarArg())
172     return false;
173 
174   auto DL = MIRBuilder.getMF().getDataLayout();
175   auto &TLI = *getTLI<ARMTargetLowering>();
176 
177   auto &Args = F.getArgumentList();
178   unsigned ArgIdx = 0;
179   for (auto &Arg : Args) {
180     ArgIdx++;
181     if (!isSupportedType(DL, TLI, Arg.getType()))
182       return false;
183 
184     // FIXME: This check as well as ArgIdx are going away as soon as we support
185     // loading values < 32 bits.
186     if (ArgIdx > 4 && Arg.getType()->getIntegerBitWidth() != 32)
187       return false;
188   }
189 
190   CCAssignFn *AssignFn =
191       TLI.CCAssignFnForCall(F.getCallingConv(), F.isVarArg());
192 
193   SmallVector<ArgInfo, 8> ArgInfos;
194   unsigned Idx = 0;
195   for (auto &Arg : Args) {
196     ArgInfo AInfo(VRegs[Idx], Arg.getType());
197     setArgFlags(AInfo, Idx + 1, DL, F);
198     ArgInfos.push_back(AInfo);
199     Idx++;
200   }
201 
202   FormalArgHandler ArgHandler(MIRBuilder, MIRBuilder.getMF().getRegInfo(),
203                               AssignFn);
204   return handleAssignments(MIRBuilder, ArgInfos, ArgHandler);
205 }
206