llvm-project/llvm/lib/Target/ARM/ARMCallLowering.cpp

204 lines
6.7 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)
: ValueHandler(MIRBuilder, MRI), 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);
return handleAssignments(MIRBuilder, AssignFn, RetInfo, RetHandler);
}
bool ARMCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
const Value *Val, unsigned VReg) const {
assert(!Val == !VReg && "Return value without a vreg");
auto Ret = AddDefaultPred(MIRBuilder.buildInstrNoInsert(ARM::BX_RET));
if (!lowerReturnVal(MIRBuilder, Val, VReg, Ret))
return false;
MIRBuilder.insertInstr(Ret);
return true;
}
namespace {
struct FormalArgHandler : public CallLowering::ValueHandler {
FormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
: ValueHandler(MIRBuilder, MRI) {}
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());
return handleAssignments(MIRBuilder, AssignFn, ArgInfos, ArgHandler);
}