Index: lib/Target/AArch64/AArch64CallingConvention.td =================================================================== --- lib/Target/AArch64/AArch64CallingConvention.td +++ lib/Target/AArch64/AArch64CallingConvention.td @@ -310,3 +310,11 @@ (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, 14))>; + +// Same as CSR_AArch64_RT_MostRegs, but saves all 64-bit SIMD/FP registers. +def CSR_AArch64_RT_AllRegs : CalleeSavedRegs<(add CSR_AArch64_RT_MostRegs, + (sequence "D%u", 0, 31))>; + Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -2455,6 +2455,8 @@ return CC_AArch64_GHC; case CallingConv::C: case CallingConv::Fast: + case CallingConv::PreserveMost: + case CallingConv::PreserveAll: if (!Subtarget->isTargetDarwin()) return CC_AArch64_AAPCS; return IsVarArg ? CC_AArch64_DarwinPCS_VarArg : CC_AArch64_DarwinPCS; Index: lib/Target/AArch64/AArch64RegisterInfo.cpp =================================================================== --- lib/Target/AArch64/AArch64RegisterInfo.cpp +++ lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -51,6 +51,10 @@ 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; + if (MF->getFunction()->getCallingConv() == CallingConv::PreserveAll) + return CSR_AArch64_RT_AllRegs_SaveList; else return CSR_AArch64_AAPCS_SaveList; } @@ -74,6 +78,10 @@ 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; + if (CC == CallingConv::PreserveAll) + return CSR_AArch64_RT_AllRegs_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,10 @@ case CallingConv::ARM_APCS: case CallingConv::GHC: return CC; + case CallingConv::PreserveMost: + return CallingConv::PreserveMost; + case CallingConv::PreserveAll: + return CallingConv::PreserveAll; case CallingConv::ARM_AAPCS_VFP: return isVarArg ? CallingConv::ARM_AAPCS : CallingConv::ARM_AAPCS_VFP; case CallingConv::C: @@ -1420,6 +1424,10 @@ 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); + case CallingConv::PreserveAll: + return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS); } } Index: test/CodeGen/AArch64/preserve_allcc.ll =================================================================== --- test/CodeGen/AArch64/preserve_allcc.ll +++ test/CodeGen/AArch64/preserve_allcc.ll @@ -0,0 +1,101 @@ +; RUN: llc < %s -mtriple=arm64-apple-ios-8.0.0 | FileCheck %s + +declare void @standard_cc_func() +declare preserve_mostcc void @preserve_mostcc_func() +declare preserve_allcc void @preserve_allcc_func() + +; Registers r9-r14, d0-d7, d16-d31 should be saved before the call of a function +; with a standard calling convention. +define preserve_allcc void @preserve_allcc1() nounwind { +entry: +;CHECK-LABEL: preserve_allcc1 +;CHECK-NOT: stp +;CHECK: stp d31, d30, +;CHECK: stp d29, d28, +;CHECK: stp d27, d26, +;CHECK: stp d25, d24, +;CHECK: stp d23, d22, +;CHECK: stp d21, d20, +;CHECK: stp d19, d18, +;CHECK: stp d17, d16, +;CHECK: stp d7, d6, +;CHECK: stp d5, d4, +;CHECK: stp d3, d2, +;CHECK: stp d1, d0, +;CHECK: stp x14, x13, +;CHECK: stp x12, x11, +;CHECK: stp x10, x9, +;CHECK: stp x29, x30, +;CHECK: bl _standard_cc_func + call void @standard_cc_func() +;CHECK: ldp x29, x30, +;CHECK: ldp x10, x9, +;CHECK: ldp x12, x11, +;CHECK: ldp x14, x13, +;CHECK: ldp d1, d0, +;CHECK: ldp d3, d2, +;CHECK: ldp d5, d4, +;CHECK: ldp d7, d6, +;CHECK: ldp d17, d16, +;CHECK: ldp d19, d18, +;CHECK: ldp d21, d20, +;CHECK: ldp d23, d22, +;CHECK: ldp d25, d24, +;CHECK: ldp d27, d26, +;CHECK: ldp d29, d28, +;CHECK: ldp d31, d30, + ret void +} + +; Registers r9-r14 and d0-d7, d16-d31 don't need to be saved if one +; function with preserve_allcc calling convention calls another +; function with preserve_allcc calling convention, because the +; callee wil save these registers anyways. +define preserve_allcc void @preserve_allcc2() nounwind { +entry: +;CHECK-LABEL: preserve_allcc2 +;CHECK-NOT: x14 +;CHECK: stp x29, x30, [sp, #-16]! +;CHECK-NOT: x14 +;CHECK: bl _preserve_allcc_func + call preserve_allcc void @preserve_allcc_func() + ret void +} + +; Registers d0-d7 and d16-d31 should be saved before the call of a function +; with a preserve_mostcc calling convention. +define preserve_allcc void @preserve_allcc3() nounwind { +entry: +;CHECK-LABEL: preserve_allcc3 +;CHECK-NOT: stp +;CHECK: stp d31, d30, +;CHECK: stp d29, d28, +;CHECK: stp d27, d26, +;CHECK: stp d25, d24, +;CHECK: stp d23, d22, +;CHECK: stp d21, d20, +;CHECK: stp d19, d18, +;CHECK: stp d17, d16, +;CHECK: stp d7, d6, +;CHECK: stp d5, d4, +;CHECK: stp d3, d2, +;CHECK: stp d1, d0, +;CHECK: stp x29, x30, +;CHECK: bl _preserve_mostcc_func + call preserve_mostcc void @preserve_mostcc_func() +;CHECK: ldp x29, x30, +;CHECK: ldp d1, d0, +;CHECK: ldp d3, d2, +;CHECK: ldp d5, d4, +;CHECK: ldp d7, d6, +;CHECK: ldp d17, d16, +;CHECK: ldp d19, d18, +;CHECK: ldp d21, d20, +;CHECK: ldp d23, d22, +;CHECK: ldp d25, d24, +;CHECK: ldp d27, d26, +;CHECK: ldp d29, d28, +;CHECK: ldp d31, d30, + ret void +} + 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 +} +