Index: llvm/lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -4700,7 +4700,15 @@ return In.VT.isScalableVector(); }); - if (CalleeInSVE || CalleeOutSVE) + // We check if the instruction is an invoke, because unwinders may only + // preserve the callee-saved registers as specified in the base ABI over the + // exception edge. This means that the caller needs to preserve additional + // registers for when the call throws an exception and the unwinder has + // tried to recover state. + bool CallNeedsUnwinding = false; + if (const CallBase *CB = CLI.CB) + CallNeedsUnwinding = isa(CB) && !CB->doesNotThrow(); + if (!CallNeedsUnwinding && (CalleeInSVE || CalleeOutSVE)) CallConv = CallingConv::AArch64_SVE_VectorCall; } Index: llvm/test/CodeGen/AArch64/sve-calling-convention.ll =================================================================== --- llvm/test/CodeGen/AArch64/sve-calling-convention.ll +++ llvm/test/CodeGen/AArch64/sve-calling-convention.ll @@ -146,3 +146,44 @@ call void asm sideeffect "nop", "~{z8},~{p4}"() ret void } + +; Unwinders may only preserve the base ABI over the exception edge, +; so the caller needs to ensure all SVE registers are preserved. +; This test checks that the right set of callee-saved-registers is used +; for the call. + +; CHECKCSR-LABEL: name: invoke_callee_may_throw +; CHECK: BL @may_throw, csr_aarch64_aapcs +; CHECK: RET_ReallyLR +define i32 @invoke_callee_may_throw( %v) personality i8 0 { + invoke void @may_throw( %v) to label %.Lcontinue unwind label %.Lunwind +.Lcontinue: + ret i32 0 +.Lunwind: + %lp = landingpad { i8*, i32 } cleanup + ret i32 42; +} + +; CHECKCSR-LABEL: name: call_callee_may_throw +; CHECK: BL @may_throw, csr_aarch64_sve_aapcs +; CHECK: RET_ReallyLR +define void @call_callee_may_throw( %v) { + call void @may_throw( %v) + ret void +} + +declare void @may_throw( %v); + +; CHECKCSR-LABEL: name: invoke_callee_does_not_throw +; CHECK: BL @does_not_throw, csr_aarch64_sve_aapcs +; CHECK: RET_ReallyLR +define i32 @invoke_callee_does_not_throw( %v) personality i8 0 { + invoke void @does_not_throw( %v) to label %.Lcontinue unwind label %.Lunwind +.Lcontinue: + ret i32 0 +.Lunwind: + %lp = landingpad { i8*, i32 } cleanup + ret i32 42; +} + +declare void @does_not_throw( %v) nounwind