10b57cec5SDimitry Andric //===- llvm/lib/Target/ARM/ARMCallLowering.cpp - Call lowering ------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements the lowering of LLVM calls to machine code calls for
110b57cec5SDimitry Andric /// GlobalISel.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric
150b57cec5SDimitry Andric #include "ARMCallLowering.h"
160b57cec5SDimitry Andric #include "ARMBaseInstrInfo.h"
170b57cec5SDimitry Andric #include "ARMISelLowering.h"
180b57cec5SDimitry Andric #include "ARMSubtarget.h"
190b57cec5SDimitry Andric #include "Utils/ARMBaseInfo.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/Analysis.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/CallingConvLower.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h"
2506c3fb27SDimitry Andric #include "llvm/CodeGen/LowLevelTypeUtils.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h"
310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
330b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
340b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
350b57cec5SDimitry Andric #include "llvm/CodeGen/ValueTypes.h"
360fca6ea1SDimitry Andric #include "llvm/CodeGenTypes/LowLevelType.h"
370fca6ea1SDimitry Andric #include "llvm/CodeGenTypes/MachineValueType.h"
380b57cec5SDimitry Andric #include "llvm/IR/Attributes.h"
390b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h"
400b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
410b57cec5SDimitry Andric #include "llvm/IR/Function.h"
420b57cec5SDimitry Andric #include "llvm/IR/Type.h"
430b57cec5SDimitry Andric #include "llvm/IR/Value.h"
440b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
450b57cec5SDimitry Andric #include <algorithm>
460b57cec5SDimitry Andric #include <cassert>
470b57cec5SDimitry Andric #include <cstdint>
48349cc55cSDimitry Andric #include <functional>
490b57cec5SDimitry Andric #include <utility>
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric using namespace llvm;
520b57cec5SDimitry Andric
53*62987288SDimitry Andric // Whether Big-endian GISel is enabled, defaults to off, can be enabled for
54*62987288SDimitry Andric // testing.
55*62987288SDimitry Andric static cl::opt<bool>
56*62987288SDimitry Andric EnableGISelBigEndian("enable-arm-gisel-bigendian", cl::Hidden,
57*62987288SDimitry Andric cl::init(false),
58*62987288SDimitry Andric cl::desc("Enable Global-ISel Big Endian Lowering"));
59*62987288SDimitry Andric
ARMCallLowering(const ARMTargetLowering & TLI)600b57cec5SDimitry Andric ARMCallLowering::ARMCallLowering(const ARMTargetLowering &TLI)
610b57cec5SDimitry Andric : CallLowering(&TLI) {}
620b57cec5SDimitry Andric
isSupportedType(const DataLayout & DL,const ARMTargetLowering & TLI,Type * T)630b57cec5SDimitry Andric static bool isSupportedType(const DataLayout &DL, const ARMTargetLowering &TLI,
640b57cec5SDimitry Andric Type *T) {
650b57cec5SDimitry Andric if (T->isArrayTy())
660b57cec5SDimitry Andric return isSupportedType(DL, TLI, T->getArrayElementType());
670b57cec5SDimitry Andric
680b57cec5SDimitry Andric if (T->isStructTy()) {
690b57cec5SDimitry Andric // For now we only allow homogeneous structs that we can manipulate with
700b57cec5SDimitry Andric // G_MERGE_VALUES and G_UNMERGE_VALUES
710b57cec5SDimitry Andric auto StructT = cast<StructType>(T);
720b57cec5SDimitry Andric for (unsigned i = 1, e = StructT->getNumElements(); i != e; ++i)
730b57cec5SDimitry Andric if (StructT->getElementType(i) != StructT->getElementType(0))
740b57cec5SDimitry Andric return false;
750b57cec5SDimitry Andric return isSupportedType(DL, TLI, StructT->getElementType(0));
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric EVT VT = TLI.getValueType(DL, T, true);
790b57cec5SDimitry Andric if (!VT.isSimple() || VT.isVector() ||
800b57cec5SDimitry Andric !(VT.isInteger() || VT.isFloatingPoint()))
810b57cec5SDimitry Andric return false;
820b57cec5SDimitry Andric
830b57cec5SDimitry Andric unsigned VTSize = VT.getSimpleVT().getSizeInBits();
840b57cec5SDimitry Andric
850b57cec5SDimitry Andric if (VTSize == 64)
860b57cec5SDimitry Andric // FIXME: Support i64 too
870b57cec5SDimitry Andric return VT.isFloatingPoint();
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric return VTSize == 1 || VTSize == 8 || VTSize == 16 || VTSize == 32;
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric
920b57cec5SDimitry Andric namespace {
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric /// Helper class for values going out through an ABI boundary (used for handling
950b57cec5SDimitry Andric /// function return values and call parameters).
96e8d8bef9SDimitry Andric struct ARMOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
ARMOutgoingValueHandler__anon5229aa980111::ARMOutgoingValueHandler97e8d8bef9SDimitry Andric ARMOutgoingValueHandler(MachineIRBuilder &MIRBuilder,
98fe6060f1SDimitry Andric MachineRegisterInfo &MRI, MachineInstrBuilder &MIB)
99fe6060f1SDimitry Andric : OutgoingValueHandler(MIRBuilder, MRI), MIB(MIB) {}
1008bcb0991SDimitry Andric
getStackAddress__anon5229aa980111::ARMOutgoingValueHandler1010b57cec5SDimitry Andric Register getStackAddress(uint64_t Size, int64_t Offset,
102fe6060f1SDimitry Andric MachinePointerInfo &MPO,
103fe6060f1SDimitry Andric ISD::ArgFlagsTy Flags) override {
1040b57cec5SDimitry Andric assert((Size == 1 || Size == 2 || Size == 4 || Size == 8) &&
1050b57cec5SDimitry Andric "Unsupported size");
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric LLT p0 = LLT::pointer(0, 32);
1080b57cec5SDimitry Andric LLT s32 = LLT::scalar(32);
1095ffd83dbSDimitry Andric auto SPReg = MIRBuilder.buildCopy(p0, Register(ARM::SP));
1100b57cec5SDimitry Andric
1115ffd83dbSDimitry Andric auto OffsetReg = MIRBuilder.buildConstant(s32, Offset);
1120b57cec5SDimitry Andric
1135ffd83dbSDimitry Andric auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg);
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric MPO = MachinePointerInfo::getStack(MIRBuilder.getMF(), Offset);
1165ffd83dbSDimitry Andric return AddrReg.getReg(0);
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric
assignValueToReg__anon5229aa980111::ARMOutgoingValueHandler1190b57cec5SDimitry Andric void assignValueToReg(Register ValVReg, Register PhysReg,
1205f757f3fSDimitry Andric const CCValAssign &VA) override {
1210b57cec5SDimitry Andric assert(VA.isRegLoc() && "Value shouldn't be assigned to reg");
1220b57cec5SDimitry Andric assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?");
1230b57cec5SDimitry Andric
1240b57cec5SDimitry Andric assert(VA.getValVT().getSizeInBits() <= 64 && "Unsupported value size");
1250b57cec5SDimitry Andric assert(VA.getLocVT().getSizeInBits() <= 64 && "Unsupported location size");
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric Register ExtReg = extendRegister(ValVReg, VA);
1280b57cec5SDimitry Andric MIRBuilder.buildCopy(PhysReg, ExtReg);
1290b57cec5SDimitry Andric MIB.addUse(PhysReg, RegState::Implicit);
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric
assignValueToAddress__anon5229aa980111::ARMOutgoingValueHandler132fe6060f1SDimitry Andric void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
1335f757f3fSDimitry Andric const MachinePointerInfo &MPO,
1345f757f3fSDimitry Andric const CCValAssign &VA) override {
1350b57cec5SDimitry Andric Register ExtReg = extendRegister(ValVReg, VA);
1360b57cec5SDimitry Andric auto MMO = MIRBuilder.getMF().getMachineMemOperand(
137fe6060f1SDimitry Andric MPO, MachineMemOperand::MOStore, MemTy, Align(1));
1380b57cec5SDimitry Andric MIRBuilder.buildStore(ExtReg, Addr, *MMO);
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric
assignCustomValue__anon5229aa980111::ARMOutgoingValueHandler141fe6060f1SDimitry Andric unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
142349cc55cSDimitry Andric ArrayRef<CCValAssign> VAs,
143349cc55cSDimitry Andric std::function<void()> *Thunk) override {
1440b57cec5SDimitry Andric assert(Arg.Regs.size() == 1 && "Can't handle multple regs yet");
1450b57cec5SDimitry Andric
1465f757f3fSDimitry Andric const CCValAssign &VA = VAs[0];
1470b57cec5SDimitry Andric assert(VA.needsCustom() && "Value doesn't need custom handling");
1485ffd83dbSDimitry Andric
1495ffd83dbSDimitry Andric // Custom lowering for other types, such as f16, is currently not supported
1505ffd83dbSDimitry Andric if (VA.getValVT() != MVT::f64)
1515ffd83dbSDimitry Andric return 0;
1520b57cec5SDimitry Andric
1535f757f3fSDimitry Andric const CCValAssign &NextVA = VAs[1];
1540b57cec5SDimitry Andric assert(NextVA.needsCustom() && "Value doesn't need custom handling");
1550b57cec5SDimitry Andric assert(NextVA.getValVT() == MVT::f64 && "Unsupported type");
1560b57cec5SDimitry Andric
1570b57cec5SDimitry Andric assert(VA.getValNo() == NextVA.getValNo() &&
1580b57cec5SDimitry Andric "Values belong to different arguments");
1590b57cec5SDimitry Andric
1600b57cec5SDimitry Andric assert(VA.isRegLoc() && "Value should be in reg");
1610b57cec5SDimitry Andric assert(NextVA.isRegLoc() && "Value should be in reg");
1620b57cec5SDimitry Andric
1630b57cec5SDimitry Andric Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
1640b57cec5SDimitry Andric MRI.createGenericVirtualRegister(LLT::scalar(32))};
1650b57cec5SDimitry Andric MIRBuilder.buildUnmerge(NewRegs, Arg.Regs[0]);
1660b57cec5SDimitry Andric
1670b57cec5SDimitry Andric bool IsLittle = MIRBuilder.getMF().getSubtarget<ARMSubtarget>().isLittle();
1680b57cec5SDimitry Andric if (!IsLittle)
1690b57cec5SDimitry Andric std::swap(NewRegs[0], NewRegs[1]);
1700b57cec5SDimitry Andric
171349cc55cSDimitry Andric if (Thunk) {
172349cc55cSDimitry Andric *Thunk = [=]() {
1730b57cec5SDimitry Andric assignValueToReg(NewRegs[0], VA.getLocReg(), VA);
1740b57cec5SDimitry Andric assignValueToReg(NewRegs[1], NextVA.getLocReg(), NextVA);
175349cc55cSDimitry Andric };
1767a6dacacSDimitry Andric return 2;
177349cc55cSDimitry Andric }
178349cc55cSDimitry Andric assignValueToReg(NewRegs[0], VA.getLocReg(), VA);
179349cc55cSDimitry Andric assignValueToReg(NewRegs[1], NextVA.getLocReg(), NextVA);
1807a6dacacSDimitry Andric return 2;
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric
183fe6060f1SDimitry Andric MachineInstrBuilder MIB;
1840b57cec5SDimitry Andric };
1850b57cec5SDimitry Andric
1860b57cec5SDimitry Andric } // end anonymous namespace
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric /// Lower the return value for the already existing \p Ret. This assumes that
1890b57cec5SDimitry Andric /// \p MIRBuilder's insertion point is correct.
lowerReturnVal(MachineIRBuilder & MIRBuilder,const Value * Val,ArrayRef<Register> VRegs,MachineInstrBuilder & Ret) const1900b57cec5SDimitry Andric bool ARMCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
1910b57cec5SDimitry Andric const Value *Val, ArrayRef<Register> VRegs,
1920b57cec5SDimitry Andric MachineInstrBuilder &Ret) const {
1930b57cec5SDimitry Andric if (!Val)
1940b57cec5SDimitry Andric // Nothing to do here.
1950b57cec5SDimitry Andric return true;
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric auto &MF = MIRBuilder.getMF();
1980b57cec5SDimitry Andric const auto &F = MF.getFunction();
1990b57cec5SDimitry Andric
200fe6060f1SDimitry Andric const auto &DL = MF.getDataLayout();
2010b57cec5SDimitry Andric auto &TLI = *getTLI<ARMTargetLowering>();
2020b57cec5SDimitry Andric if (!isSupportedType(DL, TLI, Val->getType()))
2030b57cec5SDimitry Andric return false;
2040b57cec5SDimitry Andric
205fe6060f1SDimitry Andric ArgInfo OrigRetInfo(VRegs, Val->getType(), 0);
2060b57cec5SDimitry Andric setArgFlags(OrigRetInfo, AttributeList::ReturnIndex, DL, F);
2070b57cec5SDimitry Andric
2080b57cec5SDimitry Andric SmallVector<ArgInfo, 4> SplitRetInfos;
209fe6060f1SDimitry Andric splitToValueTypes(OrigRetInfo, SplitRetInfos, DL, F.getCallingConv());
2100b57cec5SDimitry Andric
2110b57cec5SDimitry Andric CCAssignFn *AssignFn =
2120b57cec5SDimitry Andric TLI.CCAssignFnForReturn(F.getCallingConv(), F.isVarArg());
2130b57cec5SDimitry Andric
214fe6060f1SDimitry Andric OutgoingValueAssigner RetAssigner(AssignFn);
215fe6060f1SDimitry Andric ARMOutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret);
216fe6060f1SDimitry Andric return determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos,
217fe6060f1SDimitry Andric MIRBuilder, F.getCallingConv(),
218fe6060f1SDimitry Andric F.isVarArg());
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric
lowerReturn(MachineIRBuilder & MIRBuilder,const Value * Val,ArrayRef<Register> VRegs,FunctionLoweringInfo & FLI) const2210b57cec5SDimitry Andric bool ARMCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
222e8d8bef9SDimitry Andric const Value *Val, ArrayRef<Register> VRegs,
223e8d8bef9SDimitry Andric FunctionLoweringInfo &FLI) const {
2240b57cec5SDimitry Andric assert(!Val == VRegs.empty() && "Return value without a vreg");
2250b57cec5SDimitry Andric
2260b57cec5SDimitry Andric auto const &ST = MIRBuilder.getMF().getSubtarget<ARMSubtarget>();
2270b57cec5SDimitry Andric unsigned Opcode = ST.getReturnOpcode();
2280b57cec5SDimitry Andric auto Ret = MIRBuilder.buildInstrNoInsert(Opcode).add(predOps(ARMCC::AL));
2290b57cec5SDimitry Andric
2300b57cec5SDimitry Andric if (!lowerReturnVal(MIRBuilder, Val, VRegs, Ret))
2310b57cec5SDimitry Andric return false;
2320b57cec5SDimitry Andric
2330b57cec5SDimitry Andric MIRBuilder.insertInstr(Ret);
2340b57cec5SDimitry Andric return true;
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric
2370b57cec5SDimitry Andric namespace {
2380b57cec5SDimitry Andric
2390b57cec5SDimitry Andric /// Helper class for values coming in through an ABI boundary (used for handling
2400b57cec5SDimitry Andric /// formal arguments and call return values).
241e8d8bef9SDimitry Andric struct ARMIncomingValueHandler : public CallLowering::IncomingValueHandler {
ARMIncomingValueHandler__anon5229aa980311::ARMIncomingValueHandler242e8d8bef9SDimitry Andric ARMIncomingValueHandler(MachineIRBuilder &MIRBuilder,
243fe6060f1SDimitry Andric MachineRegisterInfo &MRI)
244fe6060f1SDimitry Andric : IncomingValueHandler(MIRBuilder, MRI) {}
2450b57cec5SDimitry Andric
getStackAddress__anon5229aa980311::ARMIncomingValueHandler2460b57cec5SDimitry Andric Register getStackAddress(uint64_t Size, int64_t Offset,
247fe6060f1SDimitry Andric MachinePointerInfo &MPO,
248fe6060f1SDimitry Andric ISD::ArgFlagsTy Flags) override {
2490b57cec5SDimitry Andric assert((Size == 1 || Size == 2 || Size == 4 || Size == 8) &&
2500b57cec5SDimitry Andric "Unsupported size");
2510b57cec5SDimitry Andric
2520b57cec5SDimitry Andric auto &MFI = MIRBuilder.getMF().getFrameInfo();
2530b57cec5SDimitry Andric
254fe6060f1SDimitry Andric // Byval is assumed to be writable memory, but other stack passed arguments
255fe6060f1SDimitry Andric // are not.
256fe6060f1SDimitry Andric const bool IsImmutable = !Flags.isByVal();
257fe6060f1SDimitry Andric
258fe6060f1SDimitry Andric int FI = MFI.CreateFixedObject(Size, Offset, IsImmutable);
2590b57cec5SDimitry Andric MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
2600b57cec5SDimitry Andric
2615ffd83dbSDimitry Andric return MIRBuilder.buildFrameIndex(LLT::pointer(MPO.getAddrSpace(), 32), FI)
2625ffd83dbSDimitry Andric .getReg(0);
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric
assignValueToAddress__anon5229aa980311::ARMIncomingValueHandler265fe6060f1SDimitry Andric void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
2665f757f3fSDimitry Andric const MachinePointerInfo &MPO,
2675f757f3fSDimitry Andric const CCValAssign &VA) override {
2680b57cec5SDimitry Andric if (VA.getLocInfo() == CCValAssign::SExt ||
2690b57cec5SDimitry Andric VA.getLocInfo() == CCValAssign::ZExt) {
2700b57cec5SDimitry Andric // If the value is zero- or sign-extended, its size becomes 4 bytes, so
2710b57cec5SDimitry Andric // that's what we should load.
272fe6060f1SDimitry Andric MemTy = LLT::scalar(32);
2730b57cec5SDimitry Andric assert(MRI.getType(ValVReg).isScalar() && "Only scalars supported atm");
2740b57cec5SDimitry Andric
275fe6060f1SDimitry Andric auto LoadVReg = buildLoad(LLT::scalar(32), Addr, MemTy, MPO);
2760b57cec5SDimitry Andric MIRBuilder.buildTrunc(ValVReg, LoadVReg);
2770b57cec5SDimitry Andric } else {
2780b57cec5SDimitry Andric // If the value is not extended, a simple load will suffice.
279fe6060f1SDimitry Andric buildLoad(ValVReg, Addr, MemTy, MPO);
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric }
2820b57cec5SDimitry Andric
buildLoad__anon5229aa980311::ARMIncomingValueHandler283fe6060f1SDimitry Andric MachineInstrBuilder buildLoad(const DstOp &Res, Register Addr, LLT MemTy,
2845f757f3fSDimitry Andric const MachinePointerInfo &MPO) {
2855ffd83dbSDimitry Andric MachineFunction &MF = MIRBuilder.getMF();
2865ffd83dbSDimitry Andric
287fe6060f1SDimitry Andric auto MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOLoad, MemTy,
2885ffd83dbSDimitry Andric inferAlignFromPtrInfo(MF, MPO));
2895ffd83dbSDimitry Andric return MIRBuilder.buildLoad(Res, Addr, *MMO);
2900b57cec5SDimitry Andric }
2910b57cec5SDimitry Andric
assignValueToReg__anon5229aa980311::ARMIncomingValueHandler2920b57cec5SDimitry Andric void assignValueToReg(Register ValVReg, Register PhysReg,
2935f757f3fSDimitry Andric const CCValAssign &VA) override {
2940b57cec5SDimitry Andric assert(VA.isRegLoc() && "Value shouldn't be assigned to reg");
2950b57cec5SDimitry Andric assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?");
2960b57cec5SDimitry Andric
297e8d8bef9SDimitry Andric uint64_t ValSize = VA.getValVT().getFixedSizeInBits();
298e8d8bef9SDimitry Andric uint64_t LocSize = VA.getLocVT().getFixedSizeInBits();
2990b57cec5SDimitry Andric
3000b57cec5SDimitry Andric assert(ValSize <= 64 && "Unsupported value size");
3010b57cec5SDimitry Andric assert(LocSize <= 64 && "Unsupported location size");
3020b57cec5SDimitry Andric
3030b57cec5SDimitry Andric markPhysRegUsed(PhysReg);
3040b57cec5SDimitry Andric if (ValSize == LocSize) {
3050b57cec5SDimitry Andric MIRBuilder.buildCopy(ValVReg, PhysReg);
3060b57cec5SDimitry Andric } else {
3070b57cec5SDimitry Andric assert(ValSize < LocSize && "Extensions not supported");
3080b57cec5SDimitry Andric
3090b57cec5SDimitry Andric // We cannot create a truncating copy, nor a trunc of a physical register.
3100b57cec5SDimitry Andric // Therefore, we need to copy the content of the physical register into a
3110b57cec5SDimitry Andric // virtual one and then truncate that.
3125ffd83dbSDimitry Andric auto PhysRegToVReg = MIRBuilder.buildCopy(LLT::scalar(LocSize), PhysReg);
3130b57cec5SDimitry Andric MIRBuilder.buildTrunc(ValVReg, PhysRegToVReg);
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric
assignCustomValue__anon5229aa980311::ARMIncomingValueHandler317fe6060f1SDimitry Andric unsigned assignCustomValue(ARMCallLowering::ArgInfo &Arg,
318349cc55cSDimitry Andric ArrayRef<CCValAssign> VAs,
319349cc55cSDimitry Andric std::function<void()> *Thunk) override {
3200b57cec5SDimitry Andric assert(Arg.Regs.size() == 1 && "Can't handle multple regs yet");
3210b57cec5SDimitry Andric
3225f757f3fSDimitry Andric const CCValAssign &VA = VAs[0];
3230b57cec5SDimitry Andric assert(VA.needsCustom() && "Value doesn't need custom handling");
3245ffd83dbSDimitry Andric
3255ffd83dbSDimitry Andric // Custom lowering for other types, such as f16, is currently not supported
3265ffd83dbSDimitry Andric if (VA.getValVT() != MVT::f64)
3275ffd83dbSDimitry Andric return 0;
3280b57cec5SDimitry Andric
3295f757f3fSDimitry Andric const CCValAssign &NextVA = VAs[1];
3300b57cec5SDimitry Andric assert(NextVA.needsCustom() && "Value doesn't need custom handling");
3310b57cec5SDimitry Andric assert(NextVA.getValVT() == MVT::f64 && "Unsupported type");
3320b57cec5SDimitry Andric
3330b57cec5SDimitry Andric assert(VA.getValNo() == NextVA.getValNo() &&
3340b57cec5SDimitry Andric "Values belong to different arguments");
3350b57cec5SDimitry Andric
3360b57cec5SDimitry Andric assert(VA.isRegLoc() && "Value should be in reg");
3370b57cec5SDimitry Andric assert(NextVA.isRegLoc() && "Value should be in reg");
3380b57cec5SDimitry Andric
3390b57cec5SDimitry Andric Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
3400b57cec5SDimitry Andric MRI.createGenericVirtualRegister(LLT::scalar(32))};
3410b57cec5SDimitry Andric
3420b57cec5SDimitry Andric assignValueToReg(NewRegs[0], VA.getLocReg(), VA);
3430b57cec5SDimitry Andric assignValueToReg(NewRegs[1], NextVA.getLocReg(), NextVA);
3440b57cec5SDimitry Andric
3450b57cec5SDimitry Andric bool IsLittle = MIRBuilder.getMF().getSubtarget<ARMSubtarget>().isLittle();
3460b57cec5SDimitry Andric if (!IsLittle)
3470b57cec5SDimitry Andric std::swap(NewRegs[0], NewRegs[1]);
3480b57cec5SDimitry Andric
349bdd1243dSDimitry Andric MIRBuilder.buildMergeLikeInstr(Arg.Regs[0], NewRegs);
3500b57cec5SDimitry Andric
3517a6dacacSDimitry Andric return 2;
3520b57cec5SDimitry Andric }
3530b57cec5SDimitry Andric
3540b57cec5SDimitry Andric /// Marking a physical register as used is different between formal
3550b57cec5SDimitry Andric /// parameters, where it's a basic block live-in, and call returns, where it's
3560b57cec5SDimitry Andric /// an implicit-def of the call instruction.
3570b57cec5SDimitry Andric virtual void markPhysRegUsed(unsigned PhysReg) = 0;
3580b57cec5SDimitry Andric };
3590b57cec5SDimitry Andric
360e8d8bef9SDimitry Andric struct FormalArgHandler : public ARMIncomingValueHandler {
FormalArgHandler__anon5229aa980311::FormalArgHandler361fe6060f1SDimitry Andric FormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
362fe6060f1SDimitry Andric : ARMIncomingValueHandler(MIRBuilder, MRI) {}
3630b57cec5SDimitry Andric
markPhysRegUsed__anon5229aa980311::FormalArgHandler3640b57cec5SDimitry Andric void markPhysRegUsed(unsigned PhysReg) override {
3658bcb0991SDimitry Andric MIRBuilder.getMRI()->addLiveIn(PhysReg);
3660b57cec5SDimitry Andric MIRBuilder.getMBB().addLiveIn(PhysReg);
3670b57cec5SDimitry Andric }
3680b57cec5SDimitry Andric };
3690b57cec5SDimitry Andric
3700b57cec5SDimitry Andric } // end anonymous namespace
3710b57cec5SDimitry Andric
lowerFormalArguments(MachineIRBuilder & MIRBuilder,const Function & F,ArrayRef<ArrayRef<Register>> VRegs,FunctionLoweringInfo & FLI) const372e8d8bef9SDimitry Andric bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
373e8d8bef9SDimitry Andric const Function &F,
374e8d8bef9SDimitry Andric ArrayRef<ArrayRef<Register>> VRegs,
375e8d8bef9SDimitry Andric FunctionLoweringInfo &FLI) const {
3760b57cec5SDimitry Andric auto &TLI = *getTLI<ARMTargetLowering>();
3770b57cec5SDimitry Andric auto Subtarget = TLI.getSubtarget();
3780b57cec5SDimitry Andric
3790b57cec5SDimitry Andric if (Subtarget->isThumb1Only())
3800b57cec5SDimitry Andric return false;
3810b57cec5SDimitry Andric
3820b57cec5SDimitry Andric // Quick exit if there aren't any args
3830b57cec5SDimitry Andric if (F.arg_empty())
3840b57cec5SDimitry Andric return true;
3850b57cec5SDimitry Andric
3860b57cec5SDimitry Andric if (F.isVarArg())
3870b57cec5SDimitry Andric return false;
3880b57cec5SDimitry Andric
3890b57cec5SDimitry Andric auto &MF = MIRBuilder.getMF();
3900b57cec5SDimitry Andric auto &MBB = MIRBuilder.getMBB();
391fe6060f1SDimitry Andric const auto &DL = MF.getDataLayout();
3920b57cec5SDimitry Andric
3930b57cec5SDimitry Andric for (auto &Arg : F.args()) {
3940b57cec5SDimitry Andric if (!isSupportedType(DL, TLI, Arg.getType()))
3950b57cec5SDimitry Andric return false;
396e8d8bef9SDimitry Andric if (Arg.hasPassPointeeByValueCopyAttr())
3970b57cec5SDimitry Andric return false;
3980b57cec5SDimitry Andric }
3990b57cec5SDimitry Andric
4000b57cec5SDimitry Andric CCAssignFn *AssignFn =
4010b57cec5SDimitry Andric TLI.CCAssignFnForCall(F.getCallingConv(), F.isVarArg());
4020b57cec5SDimitry Andric
403fe6060f1SDimitry Andric OutgoingValueAssigner ArgAssigner(AssignFn);
404fe6060f1SDimitry Andric FormalArgHandler ArgHandler(MIRBuilder, MIRBuilder.getMF().getRegInfo());
4050b57cec5SDimitry Andric
4060b57cec5SDimitry Andric SmallVector<ArgInfo, 8> SplitArgInfos;
4070b57cec5SDimitry Andric unsigned Idx = 0;
4080b57cec5SDimitry Andric for (auto &Arg : F.args()) {
409fe6060f1SDimitry Andric ArgInfo OrigArgInfo(VRegs[Idx], Arg.getType(), Idx);
4100b57cec5SDimitry Andric
4110b57cec5SDimitry Andric setArgFlags(OrigArgInfo, Idx + AttributeList::FirstArgIndex, DL, F);
412fe6060f1SDimitry Andric splitToValueTypes(OrigArgInfo, SplitArgInfos, DL, F.getCallingConv());
4130b57cec5SDimitry Andric
4140b57cec5SDimitry Andric Idx++;
4150b57cec5SDimitry Andric }
4160b57cec5SDimitry Andric
4170b57cec5SDimitry Andric if (!MBB.empty())
4180b57cec5SDimitry Andric MIRBuilder.setInstr(*MBB.begin());
4190b57cec5SDimitry Andric
420fe6060f1SDimitry Andric if (!determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgInfos,
421fe6060f1SDimitry Andric MIRBuilder, F.getCallingConv(),
422fe6060f1SDimitry Andric F.isVarArg()))
4230b57cec5SDimitry Andric return false;
4240b57cec5SDimitry Andric
4250b57cec5SDimitry Andric // Move back to the end of the basic block.
4260b57cec5SDimitry Andric MIRBuilder.setMBB(MBB);
4270b57cec5SDimitry Andric return true;
4280b57cec5SDimitry Andric }
4290b57cec5SDimitry Andric
4300b57cec5SDimitry Andric namespace {
4310b57cec5SDimitry Andric
432e8d8bef9SDimitry Andric struct CallReturnHandler : public ARMIncomingValueHandler {
CallReturnHandler__anon5229aa980411::CallReturnHandler4330b57cec5SDimitry Andric CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
434fe6060f1SDimitry Andric MachineInstrBuilder MIB)
435fe6060f1SDimitry Andric : ARMIncomingValueHandler(MIRBuilder, MRI), MIB(MIB) {}
4360b57cec5SDimitry Andric
markPhysRegUsed__anon5229aa980411::CallReturnHandler4370b57cec5SDimitry Andric void markPhysRegUsed(unsigned PhysReg) override {
4380b57cec5SDimitry Andric MIB.addDef(PhysReg, RegState::Implicit);
4390b57cec5SDimitry Andric }
4400b57cec5SDimitry Andric
4410b57cec5SDimitry Andric MachineInstrBuilder MIB;
4420b57cec5SDimitry Andric };
4430b57cec5SDimitry Andric
4440b57cec5SDimitry Andric // FIXME: This should move to the ARMSubtarget when it supports all the opcodes.
getCallOpcode(const MachineFunction & MF,const ARMSubtarget & STI,bool isDirect)445e8d8bef9SDimitry Andric unsigned getCallOpcode(const MachineFunction &MF, const ARMSubtarget &STI,
446e8d8bef9SDimitry Andric bool isDirect) {
4470b57cec5SDimitry Andric if (isDirect)
4480b57cec5SDimitry Andric return STI.isThumb() ? ARM::tBL : ARM::BL;
4490b57cec5SDimitry Andric
4500b57cec5SDimitry Andric if (STI.isThumb())
451e8d8bef9SDimitry Andric return gettBLXrOpcode(MF);
4520b57cec5SDimitry Andric
4530b57cec5SDimitry Andric if (STI.hasV5TOps())
454e8d8bef9SDimitry Andric return getBLXOpcode(MF);
4550b57cec5SDimitry Andric
4560b57cec5SDimitry Andric if (STI.hasV4TOps())
4570b57cec5SDimitry Andric return ARM::BX_CALL;
4580b57cec5SDimitry Andric
4590b57cec5SDimitry Andric return ARM::BMOVPCRX_CALL;
4600b57cec5SDimitry Andric }
4610b57cec5SDimitry Andric } // end anonymous namespace
4620b57cec5SDimitry Andric
lowerCall(MachineIRBuilder & MIRBuilder,CallLoweringInfo & Info) const4638bcb0991SDimitry Andric bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, CallLoweringInfo &Info) const {
4640b57cec5SDimitry Andric MachineFunction &MF = MIRBuilder.getMF();
4650b57cec5SDimitry Andric const auto &TLI = *getTLI<ARMTargetLowering>();
4660b57cec5SDimitry Andric const auto &DL = MF.getDataLayout();
4670b57cec5SDimitry Andric const auto &STI = MF.getSubtarget<ARMSubtarget>();
4680b57cec5SDimitry Andric const TargetRegisterInfo *TRI = STI.getRegisterInfo();
4690b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo();
4700b57cec5SDimitry Andric
4710b57cec5SDimitry Andric if (STI.genLongCalls())
4720b57cec5SDimitry Andric return false;
4730b57cec5SDimitry Andric
4740b57cec5SDimitry Andric if (STI.isThumb1Only())
4750b57cec5SDimitry Andric return false;
4760b57cec5SDimitry Andric
4770b57cec5SDimitry Andric auto CallSeqStart = MIRBuilder.buildInstr(ARM::ADJCALLSTACKDOWN);
4780b57cec5SDimitry Andric
4790b57cec5SDimitry Andric // Create the call instruction so we can add the implicit uses of arg
4800b57cec5SDimitry Andric // registers, but don't insert it yet.
4818bcb0991SDimitry Andric bool IsDirect = !Info.Callee.isReg();
482e8d8bef9SDimitry Andric auto CallOpcode = getCallOpcode(MF, STI, IsDirect);
4830b57cec5SDimitry Andric auto MIB = MIRBuilder.buildInstrNoInsert(CallOpcode);
4840b57cec5SDimitry Andric
4850b57cec5SDimitry Andric bool IsThumb = STI.isThumb();
4860b57cec5SDimitry Andric if (IsThumb)
4870b57cec5SDimitry Andric MIB.add(predOps(ARMCC::AL));
4880b57cec5SDimitry Andric
4898bcb0991SDimitry Andric MIB.add(Info.Callee);
4900b57cec5SDimitry Andric if (!IsDirect) {
4918bcb0991SDimitry Andric auto CalleeReg = Info.Callee.getReg();
492bdd1243dSDimitry Andric if (CalleeReg && !CalleeReg.isPhysical()) {
4930b57cec5SDimitry Andric unsigned CalleeIdx = IsThumb ? 2 : 0;
4940b57cec5SDimitry Andric MIB->getOperand(CalleeIdx).setReg(constrainOperandRegClass(
4950b57cec5SDimitry Andric MF, *TRI, MRI, *STI.getInstrInfo(), *STI.getRegBankInfo(),
4968bcb0991SDimitry Andric *MIB.getInstr(), MIB->getDesc(), Info.Callee, CalleeIdx));
4970b57cec5SDimitry Andric }
4980b57cec5SDimitry Andric }
4990b57cec5SDimitry Andric
5008bcb0991SDimitry Andric MIB.addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv));
5010b57cec5SDimitry Andric
5020b57cec5SDimitry Andric SmallVector<ArgInfo, 8> ArgInfos;
5038bcb0991SDimitry Andric for (auto Arg : Info.OrigArgs) {
5040b57cec5SDimitry Andric if (!isSupportedType(DL, TLI, Arg.Ty))
5050b57cec5SDimitry Andric return false;
5060b57cec5SDimitry Andric
5078bcb0991SDimitry Andric if (Arg.Flags[0].isByVal())
5080b57cec5SDimitry Andric return false;
5090b57cec5SDimitry Andric
510fe6060f1SDimitry Andric splitToValueTypes(Arg, ArgInfos, DL, Info.CallConv);
5110b57cec5SDimitry Andric }
5120b57cec5SDimitry Andric
513e8d8bef9SDimitry Andric auto ArgAssignFn = TLI.CCAssignFnForCall(Info.CallConv, Info.IsVarArg);
514fe6060f1SDimitry Andric OutgoingValueAssigner ArgAssigner(ArgAssignFn);
515fe6060f1SDimitry Andric ARMOutgoingValueHandler ArgHandler(MIRBuilder, MRI, MIB);
516fe6060f1SDimitry Andric if (!determineAndHandleAssignments(ArgHandler, ArgAssigner, ArgInfos,
517fe6060f1SDimitry Andric MIRBuilder, Info.CallConv, Info.IsVarArg))
5180b57cec5SDimitry Andric return false;
5190b57cec5SDimitry Andric
5200b57cec5SDimitry Andric // Now we can add the actual call instruction to the correct basic block.
5210b57cec5SDimitry Andric MIRBuilder.insertInstr(MIB);
5220b57cec5SDimitry Andric
5238bcb0991SDimitry Andric if (!Info.OrigRet.Ty->isVoidTy()) {
5248bcb0991SDimitry Andric if (!isSupportedType(DL, TLI, Info.OrigRet.Ty))
5250b57cec5SDimitry Andric return false;
5260b57cec5SDimitry Andric
5270b57cec5SDimitry Andric ArgInfos.clear();
528fe6060f1SDimitry Andric splitToValueTypes(Info.OrigRet, ArgInfos, DL, Info.CallConv);
529e8d8bef9SDimitry Andric auto RetAssignFn = TLI.CCAssignFnForReturn(Info.CallConv, Info.IsVarArg);
530fe6060f1SDimitry Andric OutgoingValueAssigner Assigner(RetAssignFn);
531fe6060f1SDimitry Andric CallReturnHandler RetHandler(MIRBuilder, MRI, MIB);
532fe6060f1SDimitry Andric if (!determineAndHandleAssignments(RetHandler, Assigner, ArgInfos,
533fe6060f1SDimitry Andric MIRBuilder, Info.CallConv,
534fe6060f1SDimitry Andric Info.IsVarArg))
5350b57cec5SDimitry Andric return false;
5360b57cec5SDimitry Andric }
5370b57cec5SDimitry Andric
5380b57cec5SDimitry Andric // We now know the size of the stack - update the ADJCALLSTACKDOWN
5390b57cec5SDimitry Andric // accordingly.
54006c3fb27SDimitry Andric CallSeqStart.addImm(ArgAssigner.StackSize).addImm(0).add(predOps(ARMCC::AL));
5410b57cec5SDimitry Andric
5420b57cec5SDimitry Andric MIRBuilder.buildInstr(ARM::ADJCALLSTACKUP)
54306c3fb27SDimitry Andric .addImm(ArgAssigner.StackSize)
54404eeddc0SDimitry Andric .addImm(-1ULL)
5450b57cec5SDimitry Andric .add(predOps(ARMCC::AL));
5460b57cec5SDimitry Andric
5470b57cec5SDimitry Andric return true;
5480b57cec5SDimitry Andric }
549*62987288SDimitry Andric
enableBigEndian() const550*62987288SDimitry Andric bool ARMCallLowering::enableBigEndian() const { return EnableGISelBigEndian; }