@@ -25,6 +25,8 @@
#ifndef USED_FOR_TARGET
#include "bbitmap.h"
+constexpr unsigned int AARCH64_NUM_ABI_ATTRIBUTES = 1;
+
typedef uint64_t aarch64_isa_mode;
constexpr unsigned int AARCH64_NUM_ISA_MODES = (0
@@ -853,7 +853,7 @@ bool aarch64_emit_approx_div (rtx, rtx, rtx);
bool aarch64_emit_approx_sqrt (rtx, rtx, bool);
bool aarch64_emit_opt_vec_rotate (rtx, rtx, rtx);
tree aarch64_vector_load_decl (tree);
-rtx aarch64_gen_callee_cookie (aarch64_isa_mode, arm_pcs);
+rtx aarch64_gen_callee_cookie (aarch64_isa_mode, arm_pcs, bool);
void aarch64_expand_call (rtx, rtx, rtx, bool);
bool aarch64_expand_cpymem_mops (rtx *, bool);
bool aarch64_expand_cpymem (rtx *, bool);
@@ -863,6 +863,7 @@ static const attribute_spec aarch64_gnu_attributes[] =
affects_type_identity, handler, exclude } */
{ "aarch64_vector_pcs", 0, 0, false, true, true, true,
handle_aarch64_vector_pcs_attribute, NULL },
+ { "indirect_return", 0, 0, false, true, true, true, NULL, NULL },
{ "arm_sve_vector_bits", 1, 1, false, true, false, true,
aarch64_sve::handle_arm_sve_vector_bits_attribute,
NULL },
@@ -2483,11 +2484,14 @@ aarch64_reg_save_mode (unsigned int regno)
return the CONST_INT that should be placed in an UNSPEC_CALLEE_ABI rtx. */
rtx
-aarch64_gen_callee_cookie (aarch64_isa_mode isa_mode, arm_pcs pcs_variant)
+aarch64_gen_callee_cookie (aarch64_isa_mode isa_mode, arm_pcs pcs_variant,
+ bool indirect_return)
{
- return gen_int_mode ((unsigned int) isa_mode
- | (unsigned int) pcs_variant << AARCH64_NUM_ISA_MODES,
- DImode);
+ unsigned int im = (unsigned int) isa_mode;
+ unsigned int ir = (indirect_return ? 1 : 0) << AARCH64_NUM_ISA_MODES;
+ unsigned int pv = (unsigned int) pcs_variant
+ << (AARCH64_NUM_ABI_ATTRIBUTES + AARCH64_NUM_ISA_MODES);
+ return gen_int_mode (im | ir | pv, DImode);
}
/* COOKIE is a CONST_INT from an UNSPEC_CALLEE_ABI rtx. Return the
@@ -2496,7 +2500,8 @@ aarch64_gen_callee_cookie (aarch64_isa_mode isa_mode, arm_pcs pcs_variant)
static const predefined_function_abi &
aarch64_callee_abi (rtx cookie)
{
- return function_abis[UINTVAL (cookie) >> AARCH64_NUM_ISA_MODES];
+ return function_abis[UINTVAL (cookie)
+ >> (AARCH64_NUM_ABI_ATTRIBUTES + AARCH64_NUM_ISA_MODES)];
}
/* COOKIE is a CONST_INT from an UNSPEC_CALLEE_ABI rtx. Return the
@@ -2509,6 +2514,15 @@ aarch64_callee_isa_mode (rtx cookie)
return UINTVAL (cookie) & ((1 << AARCH64_NUM_ISA_MODES) - 1);
}
+/* COOKIE is a CONST_INT from an UNSPEC_CALLEE_ABI rtx. Return
+ whether function was marked with indirect_return attribute. */
+
+static bool
+aarch64_callee_indirect_return (rtx cookie)
+{
+ return (UINTVAL (cookie) >> AARCH64_NUM_ISA_MODES) & 1 == 1;
+}
+
/* INSN is a call instruction. Return the CONST_INT stored in its
UNSPEC_CALLEE_ABI rtx. */
@@ -2523,6 +2537,16 @@ aarch64_insn_callee_cookie (const rtx_insn *insn)
return XVECEXP (unspec, 0, 0);
}
+/* INSN is a call instruction. Check if function associated with
+ INSN has indirect return attribute declared in its cookie. */
+
+bool
+aarch_fun_is_indirect_return (rtx_insn *insn)
+{
+ rtx cookie = aarch64_insn_callee_cookie (insn);
+ return aarch64_callee_indirect_return (cookie);
+}
+
/* Implement TARGET_INSN_CALLEE_ABI. */
const predefined_function_abi &
@@ -6459,6 +6483,14 @@ aarch64_function_ok_for_sibcall (tree, tree exp)
if (bool (aarch64_cfun_shared_flags (state))
!= bool (aarch64_fntype_shared_flags (fntype, state)))
return false;
+
+ /* BTI J is needed where indirect_return functions may return
+ if bti is enabled there. */
+ if (lookup_attribute ("indirect_return", TYPE_ATTRIBUTES (fntype))
+ && !lookup_attribute ("indirect_return",
+ TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl))))
+ return false;
+
return true;
}
@@ -7288,7 +7320,8 @@ aarch64_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
if (arg.end_marker_p ())
{
rtx abi_cookie = aarch64_gen_callee_cookie (pcum->isa_mode,
- pcum->pcs_variant);
+ pcum->pcs_variant,
+ pcum->indirect_return);
rtx sme_mode_switch_args = aarch64_finish_sme_mode_switch_args (pcum);
rtx shared_za_flags = gen_int_mode (pcum->shared_za_flags, SImode);
rtx shared_zt0_flags = gen_int_mode (pcum->shared_zt0_flags, SImode);
@@ -7320,11 +7353,13 @@ aarch64_init_cumulative_args (CUMULATIVE_ARGS *pcum,
{
pcum->pcs_variant = (arm_pcs) fntype_abi (fntype).id ();
pcum->isa_mode = aarch64_fntype_isa_mode (fntype);
+ pcum->indirect_return = lookup_attribute ("indirect_return", TYPE_ATTRIBUTES (fntype));
}
else
{
pcum->pcs_variant = ARM_PCS_AAPCS64;
pcum->isa_mode = AARCH64_DEFAULT_ISA_MODE;
+ pcum->indirect_return = false;
}
pcum->aapcs_reg = NULL_RTX;
pcum->aapcs_arg_processed = false;
@@ -10227,7 +10262,9 @@ aarch64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
auto isa_mode = aarch64_fntype_isa_mode (TREE_TYPE (function));
auto pcs_variant = arm_pcs (fndecl_abi (function).id ());
- rtx callee_abi = aarch64_gen_callee_cookie (isa_mode, pcs_variant);
+ bool ir = lookup_attribute ("indirect_return",
+ TYPE_ATTRIBUTES (TREE_TYPE (function)));
+ rtx callee_abi = aarch64_gen_callee_cookie (isa_mode, pcs_variant, ir);
insn = emit_call_insn (gen_sibcall (funexp, const0_rtx, callee_abi));
SIBLING_CALL_P (insn) = 1;
@@ -29286,6 +29323,8 @@ aarch64_comp_type_attributes (const_tree type1, const_tree type2)
if (!check_attr ("gnu", "aarch64_vector_pcs"))
return 0;
+ if (!check_attr ("gnu", "indirect_return"))
+ return 0;
if (!check_attr ("gnu", "Advanced SIMD type"))
return 0;
if (!check_attr ("gnu", "SVE type"))
@@ -1131,6 +1131,7 @@ typedef struct
{
enum arm_pcs pcs_variant;
aarch64_isa_mode isa_mode;
+ bool indirect_return; /* Whether function is marked with indirect_return attribute. */
int aapcs_arg_processed; /* No need to lay out this argument again. */
int aapcs_ncrn; /* Next Core register number. */
int aapcs_nextncrn; /* Next next core register number. */
@@ -7692,7 +7692,8 @@ (define_expand "tlsdesc_small_<mode>"
if (TARGET_SVE)
{
rtx abi = aarch64_gen_callee_cookie (AARCH64_ISA_MODE,
- aarch64_tlsdesc_abi_id ());
+ aarch64_tlsdesc_abi_id (),
+ false);
rtx_insn *call
= emit_call_insn (gen_tlsdesc_small_sve_<mode> (operands[0], abi));
RTL_CONST_CALL_P (call) = 1;
@@ -92,6 +92,22 @@ const pass_data pass_data_insert_bti =
0, /* todo_flags_finish. */
};
+/* Decide if BTI J is needed after a call instruction. */
+static bool
+call_needs_bti_j (rtx_insn *insn)
+{
+ /* Call returns twice, one of which may be indirect. */
+ if (find_reg_note (insn, REG_SETJMP, NULL))
+ return true;
+
+ /* Tail call does not return. */
+ if (SIBLING_CALL_P (insn))
+ return false;
+
+ /* Check if the function is marked to return indirectly. */
+ return aarch_fun_is_indirect_return(insn);
+}
+
/* Insert the BTI instruction. */
/* This is implemented as a late RTL pass that runs before branch
shortening and does the following. */
@@ -147,10 +163,9 @@ rest_of_insert_bti (void)
}
}
- /* Also look for calls to setjmp () which would be marked with
- REG_SETJMP note and put a BTI J after. This is where longjump ()
- will return. */
- if (CALL_P (insn) && (find_reg_note (insn, REG_SETJMP, NULL)))
+ /* Also look for calls that may return indirectly, such as setjmp,
+ and put a BTI J after them. */
+ if (CALL_P (insn) && call_needs_bti_j (insn))
{
bti_insn = aarch_gen_bti_j ();
emit_insn_after (bti_insn, insn);
@@ -48,6 +48,7 @@ extern bool aarch_bti_j_insn_p (rtx_insn *);
extern bool aarch_pac_insn_p (rtx);
extern rtx aarch_gen_bti_c (void);
extern rtx aarch_gen_bti_j (void);
+extern bool aarch_fun_is_indirect_return (rtx_insn *);
/* RTX cost table definitions. These are used when tuning for speed rather
than for size and should reflect the _additional_ cost over the cost
@@ -33492,6 +33492,15 @@ aarch_gen_bti_j (void)
return gen_bti_nop ();
}
+/* For Arm, we always return false because indirect_return attribute
+ is only supported on AArch64 targets. */
+
+bool
+aarch_fun_is_indirect_return (rtx_insn *)
+{
+ return false;
+}
+
/* Implement TARGET_SCHED_CAN_SPECULATE_INSN. Return true if INSN can be
scheduled for speculative execution. Reject the long-running division
and square-root instructions. */
From: Szabolcs Nagy <szabolcs.nagy@arm.com> Tail calls of indirect_return functions from non-indirect_return functions are disallowed even if BTI is disabled, since the call site may have BTI enabled. Following x86, mismatching attribute on function pointers is not a type error even though this can lead to bugs. Needed for swapcontext within the same function when GCS is enabled. gcc/ChangeLog: * config/aarch64/aarch64.cc (aarch64_gnu_attributes): Add indirect_return. (aarch64_gen_callee_cookie): Use indirect_return attribute. (aarch64_callee_indirect_return): New. (aarch_fun_is_indirect_return): New. (aarch64_function_ok_for_sibcall): Disallow tail calls if caller is non-indirect_return but callee is indirect_return. (aarch64_function_arg): Add indirect_return to cookie. (aarch64_init_cumulative_args): Record indirect_return in CUMULATIVE_ARGS. (aarch64_comp_type_attributes): Check indirect_return attribute. (aarch64_output_mi_thunk): Add indirect_return to cookie. * config/aarch64/aarch64.h (CUMULATIVE_ARGS): Add new field indirect_return. * config/aarch64/aarch64.md (tlsdesc_small_<mode>): Update. * config/aarch64/aarch64-opts.h (AARCH64_NUM_ABI_ATTRIBUTES): New. * config/aarch64/aarch64-protos.h (aarch64_gen_callee_cookie): Update. * config/arm/aarch-bti-insert.cc (call_needs_bti_j): New. (rest_of_insert_bti): Use call_needs_bti_j. * config/arm/aarch-common-protos.h (aarch_fun_is_indirect_return): New. * config/arm/arm.cc (aarch_fun_is_indirect_return): New. Co-authored-by: Yury Khrustalev <yury.khrustalev@arm.com> --- gcc/config/aarch64/aarch64-opts.h | 2 ++ gcc/config/aarch64/aarch64-protos.h | 2 +- gcc/config/aarch64/aarch64.cc | 53 ++++++++++++++++++++++++---- gcc/config/aarch64/aarch64.h | 1 + gcc/config/aarch64/aarch64.md | 3 +- gcc/config/arm/aarch-bti-insert.cc | 23 +++++++++--- gcc/config/arm/aarch-common-protos.h | 1 + gcc/config/arm/arm.cc | 9 +++++ 8 files changed, 81 insertions(+), 13 deletions(-)