Files
archived-llvm/lib/Target/ARM/ARMCallLowering.cpp
Tim Northover 244264d050 GlobalISel: correctly handle varargs
Some platforms (notably iOS) use a different calling convention for unnamed vs
named parameters in varargs functions, so we need to keep track of this
information when translating calls.

Since not many platforms are involved, the guts of the special handling is in
the ValueHandler class (with a generic implementation that should work for most
targets).

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@292283 91177308-0d34-0410-b5e6-96231b3b80d8
2017-01-17 22:30:10 +00:00

206 lines
6.8 KiB
C++

//===-- llvm/lib/Target/ARM/ARMCallLowering.cpp - Call lowering -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file implements the lowering of LLVM calls to machine code calls for
/// GlobalISel.
///
//===----------------------------------------------------------------------===//
#include "ARMCallLowering.h"
#include "ARMBaseInstrInfo.h"
#include "ARMISelLowering.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
using namespace llvm;
#ifndef LLVM_BUILD_GLOBAL_ISEL
#error "This shouldn't be built without GISel"
#endif
ARMCallLowering::ARMCallLowering(const ARMTargetLowering &TLI)
: CallLowering(&TLI) {}
static bool isSupportedType(const DataLayout &DL, const ARMTargetLowering &TLI,
Type *T) {
EVT VT = TLI.getValueType(DL, T);
if (!VT.isSimple() || !VT.isInteger() || VT.isVector())
return false;
unsigned VTSize = VT.getSimpleVT().getSizeInBits();
return VTSize == 8 || VTSize == 16 || VTSize == 32;
}
namespace {
struct FuncReturnHandler : public CallLowering::ValueHandler {
FuncReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
MachineInstrBuilder &MIB, CCAssignFn *AssignFn)
: ValueHandler(MIRBuilder, MRI, AssignFn), MIB(MIB) {}
unsigned getStackAddress(uint64_t Size, int64_t Offset,
MachinePointerInfo &MPO) override {
llvm_unreachable("Don't know how to get a stack address yet");
}
void assignValueToReg(unsigned ValVReg, unsigned PhysReg,
CCValAssign &VA) override {
assert(VA.isRegLoc() && "Value shouldn't be assigned to reg");
assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?");
assert(VA.getValVT().getSizeInBits() <= 32 && "Unsupported value size");
assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size");
assert(VA.getLocInfo() != CCValAssign::SExt &&
VA.getLocInfo() != CCValAssign::ZExt &&
"ABI extensions not supported yet");
MIRBuilder.buildCopy(PhysReg, ValVReg);
MIB.addUse(PhysReg, RegState::Implicit);
}
void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
MachinePointerInfo &MPO, CCValAssign &VA) override {
llvm_unreachable("Don't know how to assign a value to an address yet");
}
MachineInstrBuilder &MIB;
};
} // End anonymous namespace.
/// Lower the return value for the already existing \p Ret. This assumes that
/// \p MIRBuilder's insertion point is correct.
bool ARMCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
const Value *Val, unsigned VReg,
MachineInstrBuilder &Ret) const {
if (!Val)
// Nothing to do here.
return true;
auto &MF = MIRBuilder.getMF();
const auto &F = *MF.getFunction();
auto DL = MF.getDataLayout();
auto &TLI = *getTLI<ARMTargetLowering>();
if (!isSupportedType(DL, TLI, Val->getType()))
return false;
CCAssignFn *AssignFn =
TLI.CCAssignFnForReturn(F.getCallingConv(), F.isVarArg());
ArgInfo RetInfo(VReg, Val->getType());
setArgFlags(RetInfo, AttributeSet::ReturnIndex, DL, F);
FuncReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret, AssignFn);
return handleAssignments(MIRBuilder, RetInfo, RetHandler);
}
bool ARMCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
const Value *Val, unsigned VReg) const {
assert(!Val == !VReg && "Return value without a vreg");
auto Ret = MIRBuilder.buildInstrNoInsert(ARM::BX_RET).add(predOps(ARMCC::AL));
if (!lowerReturnVal(MIRBuilder, Val, VReg, Ret))
return false;
MIRBuilder.insertInstr(Ret);
return true;
}
namespace {
struct FormalArgHandler : public CallLowering::ValueHandler {
FormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
CCAssignFn AssignFn)
: ValueHandler(MIRBuilder, MRI, AssignFn) {}
unsigned getStackAddress(uint64_t Size, int64_t Offset,
MachinePointerInfo &MPO) override {
assert(Size == 4 && "Unsupported size");
auto &MFI = MIRBuilder.getMF().getFrameInfo();
int FI = MFI.CreateFixedObject(Size, Offset, true);
MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
unsigned AddrReg =
MRI.createGenericVirtualRegister(LLT::pointer(MPO.getAddrSpace(), 32));
MIRBuilder.buildFrameIndex(AddrReg, FI);
return AddrReg;
}
void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
MachinePointerInfo &MPO, CCValAssign &VA) override {
assert(Size == 4 && "Unsupported size");
auto MMO = MIRBuilder.getMF().getMachineMemOperand(
MPO, MachineMemOperand::MOLoad, Size, /* Alignment */ 0);
MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
}
void assignValueToReg(unsigned ValVReg, unsigned PhysReg,
CCValAssign &VA) override {
assert(VA.isRegLoc() && "Value shouldn't be assigned to reg");
assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?");
assert(VA.getValVT().getSizeInBits() <= 32 && "Unsupported value size");
assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size");
MIRBuilder.getMBB().addLiveIn(PhysReg);
MIRBuilder.buildCopy(ValVReg, PhysReg);
}
};
} // End anonymous namespace
bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
const Function &F,
ArrayRef<unsigned> VRegs) const {
// Quick exit if there aren't any args
if (F.arg_empty())
return true;
if (F.isVarArg())
return false;
auto DL = MIRBuilder.getMF().getDataLayout();
auto &TLI = *getTLI<ARMTargetLowering>();
auto &Args = F.getArgumentList();
unsigned ArgIdx = 0;
for (auto &Arg : Args) {
ArgIdx++;
if (!isSupportedType(DL, TLI, Arg.getType()))
return false;
// FIXME: This check as well as ArgIdx are going away as soon as we support
// loading values < 32 bits.
if (ArgIdx > 4 && Arg.getType()->getIntegerBitWidth() != 32)
return false;
}
CCAssignFn *AssignFn =
TLI.CCAssignFnForCall(F.getCallingConv(), F.isVarArg());
SmallVector<ArgInfo, 8> ArgInfos;
unsigned Idx = 0;
for (auto &Arg : Args) {
ArgInfo AInfo(VRegs[Idx], Arg.getType());
setArgFlags(AInfo, Idx + 1, DL, F);
ArgInfos.push_back(AInfo);
Idx++;
}
FormalArgHandler ArgHandler(MIRBuilder, MIRBuilder.getMF().getRegInfo(),
AssignFn);
return handleAssignments(MIRBuilder, ArgInfos, ArgHandler);
}