Index: llvm/lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -4700,7 +4700,12 @@ return In.VT.isScalableVector(); }); - if (CalleeInSVE || CalleeOutSVE) + // We check for 'doesNotThrow()' 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. + if (CallerF.doesNotThrow() && (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,18 @@ 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: sve_signature_vec_arg_callee_unwind +; CHECK: BL @may_throw, csr_aarch64_aapcs +; CHECK: RET_ReallyLR +define void @sve_signature_vec_arg_callee_unwind( %v) { + call void @may_throw( %v) + ret void +} + +declare void @may_throw( %v);