[ARM] GlobalISel: Lower call returns

Introduce a common ValueHandler for call returns and formal arguments, and
inherit two different versions for handling the differences (at the moment the
only difference is the way physical registers are marked as used).

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@295973 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Diana Picus 2017-02-23 14:18:41 +00:00
parent bfa45208ee
commit 31d09e83a5
2 changed files with 92 additions and 31 deletions

View File

@ -175,9 +175,11 @@ bool ARMCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
}
namespace {
struct FormalArgHandler : public CallLowering::ValueHandler {
FormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
CCAssignFn AssignFn)
/// Helper class for values coming in through an ABI boundary (used for handling
/// formal arguments and call return values).
struct IncomingValueHandler : public CallLowering::ValueHandler {
IncomingValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
CCAssignFn AssignFn)
: ValueHandler(MIRBuilder, MRI, AssignFn) {}
unsigned getStackAddress(uint64_t Size, int64_t Offset,
@ -204,8 +206,8 @@ struct FormalArgHandler : public CallLowering::ValueHandler {
if (VA.getLocInfo() == CCValAssign::SExt ||
VA.getLocInfo() == CCValAssign::ZExt) {
// If the argument is zero- or sign-extended by the caller, its size
// becomes 4 bytes, so that's what we should load.
// If the value is zero- or sign-extended, its size becomes 4 bytes, so
// that's what we should load.
Size = 4;
assert(MRI.getType(ValVReg).isScalar() && "Only scalars supported atm");
MRI.setType(ValVReg, LLT::scalar(32));
@ -224,8 +226,9 @@ struct FormalArgHandler : public CallLowering::ValueHandler {
assert(VA.getValVT().getSizeInBits() <= 64 && "Unsupported value size");
assert(VA.getLocVT().getSizeInBits() <= 64 && "Unsupported location size");
// The caller should handle all necesary extensions.
MIRBuilder.getMBB().addLiveIn(PhysReg);
// The necesary extensions are handled on the other side of the ABI
// boundary.
markPhysRegUsed(PhysReg);
MIRBuilder.buildCopy(ValVReg, PhysReg);
}
@ -259,6 +262,21 @@ struct FormalArgHandler : public CallLowering::ValueHandler {
return 1;
}
/// Marking a physical register as used is different between formal
/// parameters, where it's a basic block live-in, and call returns, where it's
/// an implicit-def of the call instruction.
virtual void markPhysRegUsed(unsigned PhysReg) = 0;
};
struct FormalArgHandler : public IncomingValueHandler {
FormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
CCAssignFn AssignFn)
: IncomingValueHandler(MIRBuilder, MRI, AssignFn) {}
void markPhysRegUsed(unsigned PhysReg) override {
MIRBuilder.getMBB().addLiveIn(PhysReg);
}
};
} // End anonymous namespace
@ -307,6 +325,20 @@ bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
return handleAssignments(MIRBuilder, ArgInfos, ArgHandler);
}
namespace {
struct CallReturnHandler : public IncomingValueHandler {
CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
MachineInstrBuilder MIB, CCAssignFn *AssignFn)
: IncomingValueHandler(MIRBuilder, MRI, AssignFn), MIB(MIB) {}
void markPhysRegUsed(unsigned PhysReg) override {
MIB.addDef(PhysReg, RegState::Implicit);
}
MachineInstrBuilder MIB;
};
} // End anonymous namespace.
bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
const MachineOperand &Callee,
const ArgInfo &OrigRet,
@ -320,10 +352,6 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
if (MF.getSubtarget<ARMSubtarget>().genLongCalls())
return false;
// FIXME: Support calling functions with return types.
if (!OrigRet.Ty->isVoidTy())
return false;
MIRBuilder.buildInstr(ARM::ADJCALLSTACKDOWN)
.addImm(0)
.add(predOps(ARMCC::AL));
@ -356,6 +384,19 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
// Now we can add the actual call instruction to the correct basic block.
MIRBuilder.insertInstr(MIB);
if (!OrigRet.Ty->isVoidTy()) {
if (!isSupportedType(DL, TLI, OrigRet.Ty))
return false;
ArgInfos.clear();
splitToValueTypes(OrigRet, ArgInfos, DL, MRI);
auto RetAssignFn = TLI.CCAssignFnForReturn(CallConv, /*IsVarArg=*/false);
CallReturnHandler RetHandler(MIRBuilder, MRI, MIB, RetAssignFn);
if (!handleAssignments(MIRBuilder, ArgInfos, RetHandler))
return false;
}
MIRBuilder.buildInstr(ARM::ADJCALLSTACKUP)
.addImm(0)
.addImm(0)

View File

@ -359,25 +359,28 @@ entry:
ret void
}
declare arm_aapcscc void @simple_params_target(i32, i32*)
declare arm_aapcscc i32* @simple_params_target(i32, i32*)
define arm_aapcscc void @test_call_simple_params(i32 *%a, i32 %b) {
define arm_aapcscc i32* @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: BLX @simple_params_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %r0, implicit %r1, implicit-def %r0
; CHECK: [[RVREG:%[0-9]+]](p0) = COPY %r0
; CHECK: ADJCALLSTACKUP 0, 0, 14, _, implicit-def %sp, implicit %sp
; CHECK: %r0 = COPY [[RVREG]]
; CHECK: BX_RET 14, _, implicit %r0
entry:
notail call arm_aapcscc void @simple_params_target(i32 %b, i32 *%a)
ret void
%r = notail call arm_aapcscc i32 *@simple_params_target(i32 %b, i32 *%a)
ret i32 *%r
}
declare arm_aapcscc void @ext_target(i8 signext, i8 zeroext, i16 signext, i16 zeroext)
declare arm_aapcscc signext i16 @ext_target(i8 signext, i8 zeroext, i16 signext, i16 zeroext)
define arm_aapcscc void @test_call_ext_params(i8 %a, i16 %b) {
define arm_aapcscc signext i16 @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
@ -390,32 +393,39 @@ define arm_aapcscc void @test_call_ext_params(i8 %a, i16 %b) {
; 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: BLX @ext_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %r0, implicit %r1, implicit %r2, implicit %r3, implicit-def %r0
; CHECK: [[RVREG:%[0-9]+]](s16) = COPY %r0
; CHECK: ADJCALLSTACKUP 0, 0, 14, _, implicit-def %sp, implicit %sp
; CHECK: [[RExtVREG:%[0-9]+]](s32) = G_SEXT [[RVREG]]
; CHECK: %r0 = COPY [[RExtVREG]]
; CHECK: BX_RET 14, _, implicit %r0
entry:
notail call arm_aapcscc void @ext_target(i8 signext %a, i8 zeroext %a, i16 signext %b, i16 zeroext %b)
ret void
%r = notail call arm_aapcscc signext i16 @ext_target(i8 signext %a, i8 zeroext %a, i16 signext %b, i16 zeroext %b)
ret i16 %r
}
declare arm_aapcs_vfpcc void @vfpcc_fp_target(float, double)
declare arm_aapcs_vfpcc double @vfpcc_fp_target(float, double)
define arm_aapcs_vfpcc void @test_call_vfpcc_fp_params(double %a, float %b) {
define arm_aapcs_vfpcc double @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: BLX @vfpcc_fp_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %s0, implicit %d1, implicit-def %d0
; CHECK: [[RVREG:%[0-9]+]](s64) = COPY %d0
; CHECK: ADJCALLSTACKUP 0, 0, 14, _, implicit-def %sp, implicit %sp
; CHECK: %d0 = COPY [[RVREG]]
; CHECK: BX_RET 14, _, implicit %d0
entry:
notail call arm_aapcs_vfpcc void @vfpcc_fp_target(float %b, double %a)
ret void
%r = notail call arm_aapcs_vfpcc double @vfpcc_fp_target(float %b, double %a)
ret double %r
}
declare arm_aapcscc void @aapcscc_fp_target(float, double)
declare arm_aapcscc double @aapcscc_fp_target(float, double)
define arm_aapcscc void @test_call_aapcs_fp_params(double %a, float %b) {
define arm_aapcscc double @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
@ -429,9 +439,19 @@ define arm_aapcscc void @test_call_aapcs_fp_params(double %a, float %b) {
; 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: BLX @aapcscc_fp_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %r0, implicit %r2, implicit %r3, implicit-def %r0, implicit-def %r1
; CHECK-DAG: [[R1:%[0-9]+]](s32) = COPY %r0
; CHECK-DAG: [[R2:%[0-9]+]](s32) = COPY %r1
; LITTLE: [[RVREG:%[0-9]+]](s64) = G_SEQUENCE [[R1]](s32), 0, [[R2]](s32), 32
; BIG: [[RVREG:%[0-9]+]](s64) = G_SEQUENCE [[R2]](s32), 0, [[R1]](s32), 32
; CHECK: ADJCALLSTACKUP 0, 0, 14, _, implicit-def %sp, implicit %sp
; CHECK: [[R1:%[0-9]+]](s32), [[R2:%[0-9]+]](s32) = G_EXTRACT [[RVREG]](s64), 0, 32
; LITTLE-DAG: %r0 = COPY [[R1]]
; LITTLE-DAG: %r1 = COPY [[R2]]
; BIG-DAG: %r0 = COPY [[R2]]
; BIG-DAG: %r1 = COPY [[R1]]
; CHECK: BX_RET 14, _, implicit %r0, implicit %r1
entry:
notail call arm_aapcscc void @aapcscc_fp_target(float %b, double %a)
ret void
%r = notail call arm_aapcscc double @aapcscc_fp_target(float %b, double %a)
ret double %r
}