1 | //===- llvm/lib/Target/ARM/ARMCallLowering.cpp - Call lowering ------------===// |
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 | /// \file |
10 | /// This file implements the lowering of LLVM calls to machine code calls for |
11 | /// GlobalISel. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "ARMCallLowering.h" |
16 | #include "ARMBaseInstrInfo.h" |
17 | #include "ARMISelLowering.h" |
18 | #include "ARMSubtarget.h" |
19 | #include "Utils/ARMBaseInfo.h" |
20 | #include "llvm/ADT/SmallVector.h" |
21 | #include "llvm/CodeGen/Analysis.h" |
22 | #include "llvm/CodeGen/CallingConvLower.h" |
23 | #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" |
24 | #include "llvm/CodeGen/GlobalISel/Utils.h" |
25 | #include "llvm/CodeGen/LowLevelTypeUtils.h" |
26 | #include "llvm/CodeGen/MachineBasicBlock.h" |
27 | #include "llvm/CodeGen/MachineFrameInfo.h" |
28 | #include "llvm/CodeGen/MachineFunction.h" |
29 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
30 | #include "llvm/CodeGen/MachineMemOperand.h" |
31 | #include "llvm/CodeGen/MachineOperand.h" |
32 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
33 | #include "llvm/CodeGen/TargetRegisterInfo.h" |
34 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
35 | #include "llvm/CodeGen/ValueTypes.h" |
36 | #include "llvm/CodeGenTypes/LowLevelType.h" |
37 | #include "llvm/CodeGenTypes/MachineValueType.h" |
38 | #include "llvm/IR/Attributes.h" |
39 | #include "llvm/IR/DataLayout.h" |
40 | #include "llvm/IR/DerivedTypes.h" |
41 | #include "llvm/IR/Function.h" |
42 | #include "llvm/IR/Type.h" |
43 | #include "llvm/IR/Value.h" |
44 | #include "llvm/Support/Casting.h" |
45 | #include <algorithm> |
46 | #include <cassert> |
47 | #include <cstdint> |
48 | #include <functional> |
49 | #include <utility> |
50 | |
51 | using namespace llvm; |
52 | |
53 | // Whether Big-endian GISel is enabled, defaults to off, can be enabled for |
54 | // testing. |
55 | static cl::opt<bool> |
56 | EnableGISelBigEndian("enable-arm-gisel-bigendian" , cl::Hidden, |
57 | cl::init(Val: false), |
58 | cl::desc("Enable Global-ISel Big Endian Lowering" )); |
59 | |
60 | ARMCallLowering::ARMCallLowering(const ARMTargetLowering &TLI) |
61 | : CallLowering(&TLI) {} |
62 | |
63 | static bool isSupportedType(const DataLayout &DL, const ARMTargetLowering &TLI, |
64 | Type *T) { |
65 | if (T->isArrayTy()) |
66 | return isSupportedType(DL, TLI, T: T->getArrayElementType()); |
67 | |
68 | if (T->isStructTy()) { |
69 | // For now we only allow homogeneous structs that we can manipulate with |
70 | // G_MERGE_VALUES and G_UNMERGE_VALUES |
71 | auto StructT = cast<StructType>(Val: T); |
72 | for (unsigned i = 1, e = StructT->getNumElements(); i != e; ++i) |
73 | if (StructT->getElementType(N: i) != StructT->getElementType(N: 0)) |
74 | return false; |
75 | return isSupportedType(DL, TLI, T: StructT->getElementType(N: 0)); |
76 | } |
77 | |
78 | EVT VT = TLI.getValueType(DL, Ty: T, AllowUnknown: true); |
79 | if (!VT.isSimple() || VT.isVector() || |
80 | !(VT.isInteger() || VT.isFloatingPoint())) |
81 | return false; |
82 | |
83 | unsigned VTSize = VT.getSimpleVT().getSizeInBits(); |
84 | |
85 | if (VTSize == 64) |
86 | // FIXME: Support i64 too |
87 | return VT.isFloatingPoint(); |
88 | |
89 | return VTSize == 1 || VTSize == 8 || VTSize == 16 || VTSize == 32; |
90 | } |
91 | |
92 | namespace { |
93 | |
94 | /// Helper class for values going out through an ABI boundary (used for handling |
95 | /// function return values and call parameters). |
96 | struct ARMOutgoingValueHandler : public CallLowering::OutgoingValueHandler { |
97 | ARMOutgoingValueHandler(MachineIRBuilder &MIRBuilder, |
98 | MachineRegisterInfo &MRI, MachineInstrBuilder &MIB) |
99 | : OutgoingValueHandler(MIRBuilder, MRI), MIB(MIB) {} |
100 | |
101 | Register getStackAddress(uint64_t Size, int64_t Offset, |
102 | MachinePointerInfo &MPO, |
103 | ISD::ArgFlagsTy Flags) override { |
104 | assert((Size == 1 || Size == 2 || Size == 4 || Size == 8) && |
105 | "Unsupported size" ); |
106 | |
107 | LLT p0 = LLT::pointer(AddressSpace: 0, SizeInBits: 32); |
108 | LLT s32 = LLT::scalar(SizeInBits: 32); |
109 | auto SPReg = MIRBuilder.buildCopy(Res: p0, Op: Register(ARM::SP)); |
110 | |
111 | auto OffsetReg = MIRBuilder.buildConstant(Res: s32, Val: Offset); |
112 | |
113 | auto AddrReg = MIRBuilder.buildPtrAdd(Res: p0, Op0: SPReg, Op1: OffsetReg); |
114 | |
115 | MPO = MachinePointerInfo::getStack(MF&: MIRBuilder.getMF(), Offset); |
116 | return AddrReg.getReg(Idx: 0); |
117 | } |
118 | |
119 | void assignValueToReg(Register ValVReg, Register PhysReg, |
120 | const CCValAssign &VA) override { |
121 | assert(VA.isRegLoc() && "Value shouldn't be assigned to reg" ); |
122 | assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?" ); |
123 | |
124 | assert(VA.getValVT().getSizeInBits() <= 64 && "Unsupported value size" ); |
125 | assert(VA.getLocVT().getSizeInBits() <= 64 && "Unsupported location size" ); |
126 | |
127 | Register ExtReg = extendRegister(ValReg: ValVReg, VA); |
128 | MIRBuilder.buildCopy(Res: PhysReg, Op: ExtReg); |
129 | MIB.addUse(RegNo: PhysReg, Flags: RegState::Implicit); |
130 | } |
131 | |
132 | void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy, |
133 | const MachinePointerInfo &MPO, |
134 | const CCValAssign &VA) override { |
135 | Register ExtReg = extendRegister(ValReg: ValVReg, VA); |
136 | auto MMO = MIRBuilder.getMF().getMachineMemOperand( |
137 | PtrInfo: MPO, f: MachineMemOperand::MOStore, MemTy, base_alignment: Align(1)); |
138 | MIRBuilder.buildStore(Val: ExtReg, Addr, MMO&: *MMO); |
139 | } |
140 | |
141 | unsigned assignCustomValue(CallLowering::ArgInfo &Arg, |
142 | ArrayRef<CCValAssign> VAs, |
143 | std::function<void()> *Thunk) override { |
144 | assert(Arg.Regs.size() == 1 && "Can't handle multple regs yet" ); |
145 | |
146 | const CCValAssign &VA = VAs[0]; |
147 | assert(VA.needsCustom() && "Value doesn't need custom handling" ); |
148 | |
149 | // Custom lowering for other types, such as f16, is currently not supported |
150 | if (VA.getValVT() != MVT::f64) |
151 | return 0; |
152 | |
153 | const CCValAssign &NextVA = VAs[1]; |
154 | assert(NextVA.needsCustom() && "Value doesn't need custom handling" ); |
155 | assert(NextVA.getValVT() == MVT::f64 && "Unsupported type" ); |
156 | |
157 | assert(VA.getValNo() == NextVA.getValNo() && |
158 | "Values belong to different arguments" ); |
159 | |
160 | assert(VA.isRegLoc() && "Value should be in reg" ); |
161 | assert(NextVA.isRegLoc() && "Value should be in reg" ); |
162 | |
163 | Register NewRegs[] = {MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 32)), |
164 | MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 32))}; |
165 | MIRBuilder.buildUnmerge(Res: NewRegs, Op: Arg.Regs[0]); |
166 | |
167 | bool IsLittle = MIRBuilder.getMF().getSubtarget<ARMSubtarget>().isLittle(); |
168 | if (!IsLittle) |
169 | std::swap(a&: NewRegs[0], b&: NewRegs[1]); |
170 | |
171 | if (Thunk) { |
172 | *Thunk = [=]() { |
173 | assignValueToReg(ValVReg: NewRegs[0], PhysReg: VA.getLocReg(), VA); |
174 | assignValueToReg(ValVReg: NewRegs[1], PhysReg: NextVA.getLocReg(), VA: NextVA); |
175 | }; |
176 | return 2; |
177 | } |
178 | assignValueToReg(ValVReg: NewRegs[0], PhysReg: VA.getLocReg(), VA); |
179 | assignValueToReg(ValVReg: NewRegs[1], PhysReg: NextVA.getLocReg(), VA: NextVA); |
180 | return 2; |
181 | } |
182 | |
183 | MachineInstrBuilder MIB; |
184 | }; |
185 | |
186 | } // end anonymous namespace |
187 | |
188 | /// Lower the return value for the already existing \p Ret. This assumes that |
189 | /// \p MIRBuilder's insertion point is correct. |
190 | bool ARMCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder, |
191 | const Value *Val, ArrayRef<Register> VRegs, |
192 | MachineInstrBuilder &Ret) const { |
193 | if (!Val) |
194 | // Nothing to do here. |
195 | return true; |
196 | |
197 | auto &MF = MIRBuilder.getMF(); |
198 | const auto &F = MF.getFunction(); |
199 | |
200 | const auto &DL = MF.getDataLayout(); |
201 | auto &TLI = *getTLI<ARMTargetLowering>(); |
202 | if (!isSupportedType(DL, TLI, T: Val->getType())) |
203 | return false; |
204 | |
205 | ArgInfo OrigRetInfo(VRegs, Val->getType(), 0); |
206 | setArgFlags(Arg&: OrigRetInfo, OpIdx: AttributeList::ReturnIndex, DL, FuncInfo: F); |
207 | |
208 | SmallVector<ArgInfo, 4> SplitRetInfos; |
209 | splitToValueTypes(OrigArgInfo: OrigRetInfo, SplitArgs&: SplitRetInfos, DL, CallConv: F.getCallingConv()); |
210 | |
211 | CCAssignFn *AssignFn = |
212 | TLI.CCAssignFnForReturn(CC: F.getCallingConv(), isVarArg: F.isVarArg()); |
213 | |
214 | OutgoingValueAssigner RetAssigner(AssignFn); |
215 | ARMOutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret); |
216 | return determineAndHandleAssignments(Handler&: RetHandler, Assigner&: RetAssigner, Args&: SplitRetInfos, |
217 | MIRBuilder, CallConv: F.getCallingConv(), |
218 | IsVarArg: F.isVarArg()); |
219 | } |
220 | |
221 | bool ARMCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, |
222 | const Value *Val, ArrayRef<Register> VRegs, |
223 | FunctionLoweringInfo &FLI) const { |
224 | assert(!Val == VRegs.empty() && "Return value without a vreg" ); |
225 | |
226 | auto const &ST = MIRBuilder.getMF().getSubtarget<ARMSubtarget>(); |
227 | unsigned Opcode = ST.getReturnOpcode(); |
228 | auto Ret = MIRBuilder.buildInstrNoInsert(Opcode).add(MOs: predOps(Pred: ARMCC::AL)); |
229 | |
230 | if (!lowerReturnVal(MIRBuilder, Val, VRegs, Ret)) |
231 | return false; |
232 | |
233 | MIRBuilder.insertInstr(MIB: Ret); |
234 | return true; |
235 | } |
236 | |
237 | namespace { |
238 | |
239 | /// Helper class for values coming in through an ABI boundary (used for handling |
240 | /// formal arguments and call return values). |
241 | struct ARMIncomingValueHandler : public CallLowering::IncomingValueHandler { |
242 | ARMIncomingValueHandler(MachineIRBuilder &MIRBuilder, |
243 | MachineRegisterInfo &MRI) |
244 | : IncomingValueHandler(MIRBuilder, MRI) {} |
245 | |
246 | Register getStackAddress(uint64_t Size, int64_t Offset, |
247 | MachinePointerInfo &MPO, |
248 | ISD::ArgFlagsTy Flags) override { |
249 | assert((Size == 1 || Size == 2 || Size == 4 || Size == 8) && |
250 | "Unsupported size" ); |
251 | |
252 | auto &MFI = MIRBuilder.getMF().getFrameInfo(); |
253 | |
254 | // Byval is assumed to be writable memory, but other stack passed arguments |
255 | // are not. |
256 | const bool IsImmutable = !Flags.isByVal(); |
257 | |
258 | int FI = MFI.CreateFixedObject(Size, SPOffset: Offset, IsImmutable); |
259 | MPO = MachinePointerInfo::getFixedStack(MF&: MIRBuilder.getMF(), FI); |
260 | |
261 | return MIRBuilder.buildFrameIndex(Res: LLT::pointer(AddressSpace: MPO.getAddrSpace(), SizeInBits: 32), Idx: FI) |
262 | .getReg(Idx: 0); |
263 | } |
264 | |
265 | void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy, |
266 | const MachinePointerInfo &MPO, |
267 | const CCValAssign &VA) override { |
268 | if (VA.getLocInfo() == CCValAssign::SExt || |
269 | VA.getLocInfo() == CCValAssign::ZExt) { |
270 | // If the value is zero- or sign-extended, its size becomes 4 bytes, so |
271 | // that's what we should load. |
272 | MemTy = LLT::scalar(SizeInBits: 32); |
273 | assert(MRI.getType(ValVReg).isScalar() && "Only scalars supported atm" ); |
274 | |
275 | auto LoadVReg = buildLoad(Res: LLT::scalar(SizeInBits: 32), Addr, MemTy, MPO); |
276 | MIRBuilder.buildTrunc(Res: ValVReg, Op: LoadVReg); |
277 | } else { |
278 | // If the value is not extended, a simple load will suffice. |
279 | buildLoad(Res: ValVReg, Addr, MemTy, MPO); |
280 | } |
281 | } |
282 | |
283 | MachineInstrBuilder buildLoad(const DstOp &Res, Register Addr, LLT MemTy, |
284 | const MachinePointerInfo &MPO) { |
285 | MachineFunction &MF = MIRBuilder.getMF(); |
286 | |
287 | auto MMO = MF.getMachineMemOperand(PtrInfo: MPO, f: MachineMemOperand::MOLoad, MemTy, |
288 | base_alignment: inferAlignFromPtrInfo(MF, MPO)); |
289 | return MIRBuilder.buildLoad(Res, Addr, MMO&: *MMO); |
290 | } |
291 | |
292 | void assignValueToReg(Register ValVReg, Register PhysReg, |
293 | const CCValAssign &VA) override { |
294 | assert(VA.isRegLoc() && "Value shouldn't be assigned to reg" ); |
295 | assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?" ); |
296 | |
297 | uint64_t ValSize = VA.getValVT().getFixedSizeInBits(); |
298 | uint64_t LocSize = VA.getLocVT().getFixedSizeInBits(); |
299 | |
300 | assert(ValSize <= 64 && "Unsupported value size" ); |
301 | assert(LocSize <= 64 && "Unsupported location size" ); |
302 | |
303 | markPhysRegUsed(PhysReg); |
304 | if (ValSize == LocSize) { |
305 | MIRBuilder.buildCopy(Res: ValVReg, Op: PhysReg); |
306 | } else { |
307 | assert(ValSize < LocSize && "Extensions not supported" ); |
308 | |
309 | // We cannot create a truncating copy, nor a trunc of a physical register. |
310 | // Therefore, we need to copy the content of the physical register into a |
311 | // virtual one and then truncate that. |
312 | auto PhysRegToVReg = MIRBuilder.buildCopy(Res: LLT::scalar(SizeInBits: LocSize), Op: PhysReg); |
313 | MIRBuilder.buildTrunc(Res: ValVReg, Op: PhysRegToVReg); |
314 | } |
315 | } |
316 | |
317 | unsigned assignCustomValue(ARMCallLowering::ArgInfo &Arg, |
318 | ArrayRef<CCValAssign> VAs, |
319 | std::function<void()> *Thunk) override { |
320 | assert(Arg.Regs.size() == 1 && "Can't handle multple regs yet" ); |
321 | |
322 | const CCValAssign &VA = VAs[0]; |
323 | assert(VA.needsCustom() && "Value doesn't need custom handling" ); |
324 | |
325 | // Custom lowering for other types, such as f16, is currently not supported |
326 | if (VA.getValVT() != MVT::f64) |
327 | return 0; |
328 | |
329 | const CCValAssign &NextVA = VAs[1]; |
330 | assert(NextVA.needsCustom() && "Value doesn't need custom handling" ); |
331 | assert(NextVA.getValVT() == MVT::f64 && "Unsupported type" ); |
332 | |
333 | assert(VA.getValNo() == NextVA.getValNo() && |
334 | "Values belong to different arguments" ); |
335 | |
336 | assert(VA.isRegLoc() && "Value should be in reg" ); |
337 | assert(NextVA.isRegLoc() && "Value should be in reg" ); |
338 | |
339 | Register NewRegs[] = {MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 32)), |
340 | MRI.createGenericVirtualRegister(Ty: LLT::scalar(SizeInBits: 32))}; |
341 | |
342 | assignValueToReg(ValVReg: NewRegs[0], PhysReg: VA.getLocReg(), VA); |
343 | assignValueToReg(ValVReg: NewRegs[1], PhysReg: NextVA.getLocReg(), VA: NextVA); |
344 | |
345 | bool IsLittle = MIRBuilder.getMF().getSubtarget<ARMSubtarget>().isLittle(); |
346 | if (!IsLittle) |
347 | std::swap(a&: NewRegs[0], b&: NewRegs[1]); |
348 | |
349 | MIRBuilder.buildMergeLikeInstr(Res: Arg.Regs[0], Ops: NewRegs); |
350 | |
351 | return 2; |
352 | } |
353 | |
354 | /// Marking a physical register as used is different between formal |
355 | /// parameters, where it's a basic block live-in, and call returns, where it's |
356 | /// an implicit-def of the call instruction. |
357 | virtual void markPhysRegUsed(unsigned PhysReg) = 0; |
358 | }; |
359 | |
360 | struct FormalArgHandler : public ARMIncomingValueHandler { |
361 | FormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI) |
362 | : ARMIncomingValueHandler(MIRBuilder, MRI) {} |
363 | |
364 | void markPhysRegUsed(unsigned PhysReg) override { |
365 | MIRBuilder.getMRI()->addLiveIn(Reg: PhysReg); |
366 | MIRBuilder.getMBB().addLiveIn(PhysReg); |
367 | } |
368 | }; |
369 | |
370 | } // end anonymous namespace |
371 | |
372 | bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, |
373 | const Function &F, |
374 | ArrayRef<ArrayRef<Register>> VRegs, |
375 | FunctionLoweringInfo &FLI) const { |
376 | auto &TLI = *getTLI<ARMTargetLowering>(); |
377 | auto Subtarget = TLI.getSubtarget(); |
378 | |
379 | if (Subtarget->isThumb1Only()) |
380 | return false; |
381 | |
382 | // Quick exit if there aren't any args |
383 | if (F.arg_empty()) |
384 | return true; |
385 | |
386 | if (F.isVarArg()) |
387 | return false; |
388 | |
389 | auto &MF = MIRBuilder.getMF(); |
390 | auto &MBB = MIRBuilder.getMBB(); |
391 | const auto &DL = MF.getDataLayout(); |
392 | |
393 | for (auto &Arg : F.args()) { |
394 | if (!isSupportedType(DL, TLI, T: Arg.getType())) |
395 | return false; |
396 | if (Arg.hasPassPointeeByValueCopyAttr()) |
397 | return false; |
398 | } |
399 | |
400 | CCAssignFn *AssignFn = |
401 | TLI.CCAssignFnForCall(CC: F.getCallingConv(), isVarArg: F.isVarArg()); |
402 | |
403 | OutgoingValueAssigner ArgAssigner(AssignFn); |
404 | FormalArgHandler ArgHandler(MIRBuilder, MIRBuilder.getMF().getRegInfo()); |
405 | |
406 | SmallVector<ArgInfo, 8> SplitArgInfos; |
407 | unsigned Idx = 0; |
408 | for (auto &Arg : F.args()) { |
409 | ArgInfo OrigArgInfo(VRegs[Idx], Arg.getType(), Idx); |
410 | |
411 | setArgFlags(Arg&: OrigArgInfo, OpIdx: Idx + AttributeList::FirstArgIndex, DL, FuncInfo: F); |
412 | splitToValueTypes(OrigArgInfo, SplitArgs&: SplitArgInfos, DL, CallConv: F.getCallingConv()); |
413 | |
414 | Idx++; |
415 | } |
416 | |
417 | if (!MBB.empty()) |
418 | MIRBuilder.setInstr(*MBB.begin()); |
419 | |
420 | if (!determineAndHandleAssignments(Handler&: ArgHandler, Assigner&: ArgAssigner, Args&: SplitArgInfos, |
421 | MIRBuilder, CallConv: F.getCallingConv(), |
422 | IsVarArg: F.isVarArg())) |
423 | return false; |
424 | |
425 | // Move back to the end of the basic block. |
426 | MIRBuilder.setMBB(MBB); |
427 | return true; |
428 | } |
429 | |
430 | namespace { |
431 | |
432 | struct CallReturnHandler : public ARMIncomingValueHandler { |
433 | CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI, |
434 | MachineInstrBuilder MIB) |
435 | : ARMIncomingValueHandler(MIRBuilder, MRI), MIB(MIB) {} |
436 | |
437 | void markPhysRegUsed(unsigned PhysReg) override { |
438 | MIB.addDef(RegNo: PhysReg, Flags: RegState::Implicit); |
439 | } |
440 | |
441 | MachineInstrBuilder MIB; |
442 | }; |
443 | |
444 | // FIXME: This should move to the ARMSubtarget when it supports all the opcodes. |
445 | unsigned getCallOpcode(const MachineFunction &MF, const ARMSubtarget &STI, |
446 | bool isDirect) { |
447 | if (isDirect) |
448 | return STI.isThumb() ? ARM::tBL : ARM::BL; |
449 | |
450 | if (STI.isThumb()) |
451 | return gettBLXrOpcode(MF); |
452 | |
453 | if (STI.hasV5TOps()) |
454 | return getBLXOpcode(MF); |
455 | |
456 | if (STI.hasV4TOps()) |
457 | return ARM::BX_CALL; |
458 | |
459 | return ARM::BMOVPCRX_CALL; |
460 | } |
461 | } // end anonymous namespace |
462 | |
463 | bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, CallLoweringInfo &Info) const { |
464 | MachineFunction &MF = MIRBuilder.getMF(); |
465 | const auto &TLI = *getTLI<ARMTargetLowering>(); |
466 | const auto &DL = MF.getDataLayout(); |
467 | const auto &STI = MF.getSubtarget<ARMSubtarget>(); |
468 | const TargetRegisterInfo *TRI = STI.getRegisterInfo(); |
469 | MachineRegisterInfo &MRI = MF.getRegInfo(); |
470 | |
471 | if (STI.genLongCalls()) |
472 | return false; |
473 | |
474 | if (STI.isThumb1Only()) |
475 | return false; |
476 | |
477 | auto CallSeqStart = MIRBuilder.buildInstr(Opcode: ARM::ADJCALLSTACKDOWN); |
478 | |
479 | // Create the call instruction so we can add the implicit uses of arg |
480 | // registers, but don't insert it yet. |
481 | bool IsDirect = !Info.Callee.isReg(); |
482 | auto CallOpcode = getCallOpcode(MF, STI, isDirect: IsDirect); |
483 | auto MIB = MIRBuilder.buildInstrNoInsert(Opcode: CallOpcode); |
484 | |
485 | bool IsThumb = STI.isThumb(); |
486 | if (IsThumb) |
487 | MIB.add(MOs: predOps(Pred: ARMCC::AL)); |
488 | |
489 | MIB.add(MO: Info.Callee); |
490 | if (!IsDirect) { |
491 | auto CalleeReg = Info.Callee.getReg(); |
492 | if (CalleeReg && !CalleeReg.isPhysical()) { |
493 | unsigned CalleeIdx = IsThumb ? 2 : 0; |
494 | MIB->getOperand(i: CalleeIdx).setReg(constrainOperandRegClass( |
495 | MF, TRI: *TRI, MRI, TII: *STI.getInstrInfo(), RBI: *STI.getRegBankInfo(), |
496 | InsertPt&: *MIB.getInstr(), II: MIB->getDesc(), RegMO&: Info.Callee, OpIdx: CalleeIdx)); |
497 | } |
498 | } |
499 | |
500 | MIB.addRegMask(Mask: TRI->getCallPreservedMask(MF, Info.CallConv)); |
501 | |
502 | SmallVector<ArgInfo, 8> ArgInfos; |
503 | for (auto Arg : Info.OrigArgs) { |
504 | if (!isSupportedType(DL, TLI, T: Arg.Ty)) |
505 | return false; |
506 | |
507 | if (Arg.Flags[0].isByVal()) |
508 | return false; |
509 | |
510 | splitToValueTypes(OrigArgInfo: Arg, SplitArgs&: ArgInfos, DL, CallConv: Info.CallConv); |
511 | } |
512 | |
513 | auto ArgAssignFn = TLI.CCAssignFnForCall(CC: Info.CallConv, isVarArg: Info.IsVarArg); |
514 | OutgoingValueAssigner ArgAssigner(ArgAssignFn); |
515 | ARMOutgoingValueHandler ArgHandler(MIRBuilder, MRI, MIB); |
516 | if (!determineAndHandleAssignments(Handler&: ArgHandler, Assigner&: ArgAssigner, Args&: ArgInfos, |
517 | MIRBuilder, CallConv: Info.CallConv, IsVarArg: Info.IsVarArg)) |
518 | return false; |
519 | |
520 | // Now we can add the actual call instruction to the correct basic block. |
521 | MIRBuilder.insertInstr(MIB); |
522 | |
523 | if (!Info.OrigRet.Ty->isVoidTy()) { |
524 | if (!isSupportedType(DL, TLI, T: Info.OrigRet.Ty)) |
525 | return false; |
526 | |
527 | ArgInfos.clear(); |
528 | splitToValueTypes(OrigArgInfo: Info.OrigRet, SplitArgs&: ArgInfos, DL, CallConv: Info.CallConv); |
529 | auto RetAssignFn = TLI.CCAssignFnForReturn(CC: Info.CallConv, isVarArg: Info.IsVarArg); |
530 | OutgoingValueAssigner Assigner(RetAssignFn); |
531 | CallReturnHandler RetHandler(MIRBuilder, MRI, MIB); |
532 | if (!determineAndHandleAssignments(Handler&: RetHandler, Assigner, Args&: ArgInfos, |
533 | MIRBuilder, CallConv: Info.CallConv, |
534 | IsVarArg: Info.IsVarArg)) |
535 | return false; |
536 | } |
537 | |
538 | // We now know the size of the stack - update the ADJCALLSTACKDOWN |
539 | // accordingly. |
540 | CallSeqStart.addImm(Val: ArgAssigner.StackSize).addImm(Val: 0).add(MOs: predOps(Pred: ARMCC::AL)); |
541 | |
542 | MIRBuilder.buildInstr(Opcode: ARM::ADJCALLSTACKUP) |
543 | .addImm(Val: ArgAssigner.StackSize) |
544 | .addImm(Val: -1ULL) |
545 | .add(MOs: predOps(Pred: ARMCC::AL)); |
546 | |
547 | return true; |
548 | } |
549 | |
550 | bool ARMCallLowering::enableBigEndian() const { return EnableGISelBigEndian; } |