diff --git a/lib/Target/ARM/ARMCallLowering.cpp b/lib/Target/ARM/ARMCallLowering.cpp index 7ba859921c2..f4f3b261bf5 100644 --- a/lib/Target/ARM/ARMCallLowering.cpp +++ b/lib/Target/ARM/ARMCallLowering.cpp @@ -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().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) diff --git a/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll b/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll index 4e81316f9a0..31e15bc8fcc 100644 --- a/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll +++ b/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll @@ -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 }