static bool
aarch64_function_ok_for_sibcall (tree, tree exp)
{
- if (crtl->abi->id () != expr_callee_abi (exp).id ())
+ auto from_abi = crtl->abi->id ();
+ auto to_abi = expr_callee_abi (exp).id ();
+
+ /* ARM_PCS_SVE preserves strictly more than ARM_PCS_SIMD, which in
+ turn preserves strictly more than the base PCS. The callee must
+ preserve everything that the caller is required to preserve. */
+ if (from_abi != to_abi && to_abi == ARM_PCS_SVE)
+ to_abi = ARM_PCS_SIMD;
+ if (from_abi != to_abi && to_abi == ARM_PCS_SIMD)
+ to_abi = ARM_PCS_AAPCS64;
+ if (from_abi != to_abi)
return false;
tree fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (exp)));
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" "" { target { le } } } } */
+
+#define SIMD [[gnu::aarch64_vector_pcs]]
+
+void callee_base (void);
+void callee_simd (void) SIMD;
+void callee_sve (__SVBool_t);
+
+/*
+** base_to_base:
+** b callee_base
+*/
+void base_to_base (void) { return callee_base (); }
+
+/*
+** base_to_simd:
+** b callee_simd
+*/
+void base_to_simd (void) { return callee_simd (); }
+
+/*
+** base_to_sve:
+** ldr p0, \[x0\]
+** b callee_sve
+*/
+void base_to_sve (__SVBool_t *ptr) { return callee_sve (*ptr); }
+
+/*
+** simd_to_base:
+** stp x29, x30, [^\n]+
+** ...
+** bl callee_base
+** ...
+** ldp x29, x30, [^\n]+
+** ret
+*/
+void simd_to_base (void) SIMD { return callee_base (); }
+
+/*
+** simd_to_simd:
+** b callee_simd
+*/
+void simd_to_simd (void) SIMD { return callee_simd (); }
+
+/*
+** simd_to_sve:
+** ldr p0, \[x0\]
+** b callee_sve
+*/
+void simd_to_sve (__SVBool_t *ptr) SIMD { return callee_sve (*ptr); }
+
+/*
+** sve_to_base:
+** stp x29, x30, [^\n]+
+** ...
+** bl callee_base
+** ...
+** ldp x29, x30, [^\n]+
+** ret
+*/
+void sve_to_base (__SVBool_t pg) { return callee_base (); }
+
+/*
+** sve_to_simd:
+** stp x29, x30, [^\n]+
+** ...
+** bl callee_simd
+** ...
+** ldp x29, x30, [^\n]+
+** ret
+*/
+void sve_to_simd (__SVBool_t pg) { return callee_simd (); }
+
+/*
+** sve_to_sve:
+** b callee_sve
+*/
+void sve_to_sve (__SVBool_t pg) { return callee_sve (pg); }