Index: lib/Target/AArch64/AArch64CallingConvention.td =================================================================== --- lib/Target/AArch64/AArch64CallingConvention.td +++ lib/Target/AArch64/AArch64CallingConvention.td @@ -310,3 +310,7 @@ (sequence "Q%u", 0, 31))>; def CSR_AArch64_NoRegs : CalleeSavedRegs<(add)>; + +def CSR_AArch64_RT_MostRegs : CalleeSavedRegs<(add CSR_AArch64_AAPCS, + (sequence "X%u", 9, 15))>; + Index: lib/Target/AArch64/AArch64FrameLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64FrameLowering.cpp +++ lib/Target/AArch64/AArch64FrameLowering.cpp @@ -723,10 +723,13 @@ AArch64FunctionInfo *AFI = MF.getInfo(); MachineFrameInfo *MFI = MF.getFrameInfo(); + CallingConv::ID CC = MF.getFunction()->getCallingConv(); unsigned Count = CSI.size(); + (void)CC; // MachO's compact unwind format relies on all registers being stored in // pairs. assert((!MF.getSubtarget().isTargetMachO() || + CC == CallingConv::PreserveMost || (Count & 1) == 0) && "Odd number of callee-saved regs to spill!"); unsigned Offset = AFI->getCalleeSavedStackSize(); @@ -760,6 +763,7 @@ // MachO's compact unwind format relies on all registers being stored in // adjacent register pairs. assert((!MF.getSubtarget().isTargetMachO() || + CC == CallingConv::PreserveMost || (RPI.isPaired() && ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) || RPI.Reg1 + 1 == RPI.Reg2))) && Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -2455,6 +2455,7 @@ return CC_AArch64_GHC; case CallingConv::C: case CallingConv::Fast: + case CallingConv::PreserveMost: if (!Subtarget->isTargetDarwin()) return CC_AArch64_AAPCS; return IsVarArg ? CC_AArch64_DarwinPCS_VarArg : CC_AArch64_DarwinPCS; @@ -2942,7 +2943,8 @@ } bool AArch64TargetLowering::IsTailCallConvention(CallingConv::ID CallCC) const { - return CallCC == CallingConv::Fast; + return CallCC == CallingConv::Fast || + CallCC == CallingConv::PreserveMost; } /// LowerCall - Lower a call to a callseq_start + CALL + callseq_end chain, Index: lib/Target/AArch64/AArch64RegisterInfo.cpp =================================================================== --- lib/Target/AArch64/AArch64RegisterInfo.cpp +++ lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -51,6 +51,8 @@ return MF->getInfo()->isSplitCSR() ? CSR_AArch64_CXX_TLS_Darwin_PE_SaveList : CSR_AArch64_CXX_TLS_Darwin_SaveList; + if (MF->getFunction()->getCallingConv() == CallingConv::PreserveMost) + return CSR_AArch64_RT_MostRegs_SaveList; else return CSR_AArch64_AAPCS_SaveList; } @@ -74,6 +76,8 @@ return CSR_AArch64_AllRegs_RegMask; if (CC == CallingConv::CXX_FAST_TLS) return CSR_AArch64_CXX_TLS_Darwin_RegMask; + if (CC == CallingConv::PreserveMost) + return CSR_AArch64_RT_MostRegs_RegMask; else return CSR_AArch64_AAPCS_RegMask; } Index: lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- lib/Target/ARM/ARMISelLowering.cpp +++ lib/Target/ARM/ARMISelLowering.cpp @@ -1378,6 +1378,8 @@ case CallingConv::ARM_APCS: case CallingConv::GHC: return CC; + case CallingConv::PreserveMost: + return CallingConv::PreserveMost; case CallingConv::ARM_AAPCS_VFP: return isVarArg ? CallingConv::ARM_AAPCS : CallingConv::ARM_AAPCS_VFP; case CallingConv::C: @@ -1420,6 +1422,8 @@ return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS); case CallingConv::GHC: return (Return ? RetCC_ARM_APCS : CC_ARM_APCS_GHC); + case CallingConv::PreserveMost: + return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS); } } Index: test/CodeGen/AArch64/preserve_mostcc.ll =================================================================== --- test/CodeGen/AArch64/preserve_mostcc.ll +++ test/CodeGen/AArch64/preserve_mostcc.ll @@ -0,0 +1,37 @@ +; RUN: llc < %s -mtriple=arm64-apple-ios-8.0.0 | FileCheck %s + +declare void @standard_cc_func() +declare preserve_mostcc void @preserve_mostcc_func() + +; Registers r9-r14 should be saved before the call of a function +; with a standard calling convention. +define preserve_mostcc void @preserve_mostcc1() nounwind { +entry: +;CHECK-LABEL: preserve_mostcc1 +;CHECK-NOT: stp +;CHECK: stp x14, x13, +;CHECK-NEXT: stp x12, x11, +;CHECK-NEXT: stp x10, x9, +;CHECK: bl _standard_cc_func + call void @standard_cc_func() +;CHECK: ldp x10, x9, +;CHECK-NEXT: ldp x12, x11, +;CHECK-NEXT: ldp x14, x13, + ret void +} + +; Registers r9-r14 don't need to be saved if one +; function with preserve_mostcc calling convention calls another +; function with preserve_mostcc calling convention, because the +; callee wil save these registers anyways. +define preserve_mostcc void @preserve_mostcc2() nounwind { +entry: +;CHECK-LABEL: preserve_mostcc2 +;CHECK-NOT: x14 +;CHECK: stp x29, x30, +;CHECK-NOT: x14 +;CHECK: bl _preserve_mostcc_func + call preserve_mostcc void @preserve_mostcc_func() + ret void +} + Index: test/CodeGen/AArch64/tail-call.ll =================================================================== --- test/CodeGen/AArch64/tail-call.ll +++ test/CodeGen/AArch64/tail-call.ll @@ -4,6 +4,8 @@ declare fastcc void @callee_stack8([8 x i32], i64) declare fastcc void @callee_stack16([8 x i32], i64, i64) declare extern_weak fastcc void @callee_weak() +declare void @callee_standard_cc() +declare preserve_mostcc void @callee_preserve_mostcc() define fastcc void @caller_to0_from0() nounwind { ; CHECK-LABEL: caller_to0_from0: @@ -139,3 +141,23 @@ ret { double, [2 x double] } %res.012 } + +define preserve_mostcc void @caller_to_preserve_mostcc_from_preserve_mostcc() { +; CHECK-LABEL: caller_to_preserve_mostcc_from_preserve_mostcc: + + tail call preserve_mostcc void @callee_preserve_mostcc() + ret void + +; CHECK: b callee_preserve_mostcc +} + +define preserve_mostcc void @caller_to_standard_cc_from_preserve_mostcc() { +; CHECK-LABEL: caller_to_standard_cc_from_preserve_mostcc: + + tail call void @callee_standard_cc() + ret void + +; CHECK-NOT: b callee_standard_cc +; CHECK: bl callee_standard_cc +} +