[ARM] GlobalISel: Lower call parameters in regs

Add support for lowering calls with parameters than can fit into regs.  Use the
same ValueHandler that we used for function returns, but rename it to match its
new, extended purpose.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@295971 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Diana Picus 2017-02-23 13:25:43 +00:00
parent 6f30b9797e
commit 5e98318841
2 changed files with 116 additions and 15 deletions

View File

@ -48,10 +48,12 @@ static bool isSupportedType(const DataLayout &DL, const ARMTargetLowering &TLI,
}
namespace {
struct FuncReturnHandler : public CallLowering::ValueHandler {
FuncReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
MachineInstrBuilder &MIB, CCAssignFn *AssignFn)
: ValueHandler(MIRBuilder, MRI, AssignFn), MIB(MIB) {}
/// Helper class for values going out through an ABI boundary (used for handling
/// function return values and call parameters).
struct OutgoingValueHandler : public CallLowering::ValueHandler {
OutgoingValueHandler(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 {
@ -155,7 +157,7 @@ bool ARMCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
CCAssignFn *AssignFn =
TLI.CCAssignFnForReturn(F.getCallingConv(), F.isVarArg());
FuncReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret, AssignFn);
OutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret, AssignFn);
return handleAssignments(MIRBuilder, SplitVTs, RetHandler);
}
@ -227,7 +229,7 @@ struct FormalArgHandler : public CallLowering::ValueHandler {
MIRBuilder.buildCopy(ValVReg, PhysReg);
}
unsigned assignCustomValue(const llvm::ARMCallLowering::ArgInfo &Arg,
unsigned assignCustomValue(const ARMCallLowering::ArgInfo &Arg,
ArrayRef<CCValAssign> VAs) override {
CCValAssign VA = VAs[0];
assert(VA.needsCustom() && "Value doesn't need custom handling");
@ -309,16 +311,15 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
const MachineOperand &Callee,
const ArgInfo &OrigRet,
ArrayRef<ArgInfo> OrigArgs) const {
const MachineFunction &MF = MIRBuilder.getMF();
MachineFunction &MF = MIRBuilder.getMF();
const auto &TLI = *getTLI<ARMTargetLowering>();
const auto &DL = MF.getDataLayout();
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
MachineRegisterInfo &MRI = MF.getRegInfo();
if (MF.getSubtarget<ARMSubtarget>().genLongCalls())
return false;
// FIXME: Support calling functions with arguments.
if (OrigArgs.size() > 0)
return false;
// FIXME: Support calling functions with return types.
if (!OrigRet.Ty->isVoidTy())
return false;
@ -327,10 +328,33 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
.addImm(0)
.add(predOps(ARMCC::AL));
MIRBuilder.buildInstr(ARM::BLX)
.add(Callee)
// FIXME: Don't hardcode the calling conv here...
.addRegMask(TRI->getCallPreservedMask(MF, CallingConv::ARM_AAPCS));
// FIXME: This is the calling convention of the caller - we should use the
// calling convention of the callee instead.
auto CallConv = MF.getFunction()->getCallingConv();
// Create the call instruction so we can add the implicit uses of arg
// registers, but don't insert it yet.
auto MIB = MIRBuilder.buildInstrNoInsert(ARM::BLX).add(Callee).addRegMask(
TRI->getCallPreservedMask(MF, CallConv));
SmallVector<ArgInfo, 8> ArgInfos;
for (auto Arg : OrigArgs) {
if (!isSupportedType(DL, TLI, Arg.Ty))
return false;
if (!Arg.IsFixed)
return false;
splitToValueTypes(Arg, ArgInfos, DL, MRI);
}
auto ArgAssignFn = TLI.CCAssignFnForCall(CallConv, /*IsVarArg=*/false);
OutgoingValueHandler ArgHandler(MIRBuilder, MRI, MIB, ArgAssignFn);
if (!handleAssignments(MIRBuilder, ArgInfos, ArgHandler))
return false;
// Now we can add the actual call instruction to the correct basic block.
MIRBuilder.insertInstr(MIB);
MIRBuilder.buildInstr(ARM::ADJCALLSTACKUP)
.addImm(0)

View File

@ -358,3 +358,80 @@ entry:
notail call arm_aapcscc void @call_target()
ret void
}
declare arm_aapcscc void @simple_params_target(i32, i32*)
define arm_aapcscc void @test_call_simple_params(i32 *%a, i32 %b) {
; CHECK-LABEL: name: test_call_simple_params
; CHECK-DAG: [[AVREG:%[0-9]+]](p0) = COPY %r0
; CHECK-DAG: [[BVREG:%[0-9]+]](s32) = COPY %r1
; CHECK: ADJCALLSTACKDOWN 0, 14, _, implicit-def %sp, implicit %sp
; CHECK-DAG: %r0 = COPY [[BVREG]]
; CHECK-DAG: %r1 = COPY [[AVREG]]
; CHECK: BLX @simple_params_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %r0, implicit %r1
; CHECK: ADJCALLSTACKUP 0, 0, 14, _, implicit-def %sp, implicit %sp
entry:
notail call arm_aapcscc void @simple_params_target(i32 %b, i32 *%a)
ret void
}
declare arm_aapcscc void @ext_target(i8 signext, i8 zeroext, i16 signext, i16 zeroext)
define arm_aapcscc void @test_call_ext_params(i8 %a, i16 %b) {
; CHECK-LABEL: name: test_call_ext_params
; CHECK-DAG: [[AVREG:%[0-9]+]](s8) = COPY %r0
; CHECK-DAG: [[BVREG:%[0-9]+]](s16) = COPY %r1
; CHECK: ADJCALLSTACKDOWN 0, 14, _, implicit-def %sp, implicit %sp
; CHECK-DAG: [[SEXTA:%[0-9]+]](s32) = G_SEXT [[AVREG]](s8)
; CHECK-DAG: %r0 = COPY [[SEXTA]]
; CHECK-DAG: [[ZEXTA:%[0-9]+]](s32) = G_ZEXT [[AVREG]](s8)
; CHECK-DAG: %r1 = COPY [[ZEXTA]]
; CHECK-DAG: [[SEXTB:%[0-9]+]](s32) = G_SEXT [[BVREG]](s16)
; CHECK-DAG: %r2 = COPY [[SEXTB]]
; CHECK-DAG: [[ZEXTB:%[0-9]+]](s32) = G_ZEXT [[BVREG]](s16)
; CHECK-DAG: %r3 = COPY [[ZEXTB]]
; CHECK: BLX @ext_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %r0, implicit %r1, implicit %r2, implicit %r3
; CHECK: ADJCALLSTACKUP 0, 0, 14, _, implicit-def %sp, implicit %sp
entry:
notail call arm_aapcscc void @ext_target(i8 signext %a, i8 zeroext %a, i16 signext %b, i16 zeroext %b)
ret void
}
declare arm_aapcs_vfpcc void @vfpcc_fp_target(float, double)
define arm_aapcs_vfpcc void @test_call_vfpcc_fp_params(double %a, float %b) {
; CHECK-LABEL: name: test_call_vfpcc_fp_params
; CHECK-DAG: [[AVREG:%[0-9]+]](s64) = COPY %d0
; CHECK-DAG: [[BVREG:%[0-9]+]](s32) = COPY %s2
; CHECK: ADJCALLSTACKDOWN 0, 14, _, implicit-def %sp, implicit %sp
; CHECK-DAG: %s0 = COPY [[BVREG]]
; CHECK-DAG: %d1 = COPY [[AVREG]]
; CHECK: BLX @vfpcc_fp_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %s0, implicit %d1
; CHECK: ADJCALLSTACKUP 0, 0, 14, _, implicit-def %sp, implicit %sp
entry:
notail call arm_aapcs_vfpcc void @vfpcc_fp_target(float %b, double %a)
ret void
}
declare arm_aapcscc void @aapcscc_fp_target(float, double)
define arm_aapcscc void @test_call_aapcs_fp_params(double %a, float %b) {
; CHECK-LABEL: name: test_call_aapcs_fp_params
; CHECK-DAG: [[A1:%[0-9]+]](s32) = COPY %r0
; CHECK-DAG: [[A2:%[0-9]+]](s32) = COPY %r1
; LITTLE-DAG: [[AVREG:%[0-9]+]](s64) = G_SEQUENCE [[A1]](s32), 0, [[A2]](s32), 32
; BIG-DAG: [[AVREG:%[0-9]+]](s64) = G_SEQUENCE [[A2]](s32), 0, [[A1]](s32), 32
; CHECK-DAG: [[BVREG:%[0-9]+]](s32) = COPY %r2
; CHECK: ADJCALLSTACKDOWN 0, 14, _, implicit-def %sp, implicit %sp
; CHECK-DAG: %r0 = COPY [[BVREG]]
; CHECK-DAG: [[A1:%[0-9]+]](s32), [[A2:%[0-9]+]](s32) = G_EXTRACT [[AVREG]](s64), 0, 32
; LITTLE-DAG: %r2 = COPY [[A1]]
; LITTLE-DAG: %r3 = COPY [[A2]]
; BIG-DAG: %r2 = COPY [[A2]]
; BIG-DAG: %r3 = COPY [[A1]]
; CHECK: BLX @aapcscc_fp_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %r0, implicit %r2, implicit %r3
; CHECK: ADJCALLSTACKUP 0, 0, 14, _, implicit-def %sp, implicit %sp
entry:
notail call arm_aapcscc void @aapcscc_fp_target(float %b, double %a)
ret void
}