Yury Khrustalev <[email protected]> writes:
> From: Szabolcs Nagy <[email protected]>
>
> Add new builtins for GCS:
>
> void *__builtin_aarch64_gcspr (void)
> uint64_t __builtin_aarch64_gcspopm (void)
> void *__builtin_aarch64_gcsss (void *)
>
> The builtins are always enabled, but should be used behind runtime
> checks in case the target does not support GCS. They are thin
> wrappers around the corresponding instructions.
>
> The GCS pointer is modelled with void * type (normal stores do not
> work on GCS memory, but it is writable via the gcsss operation or
> via GCSSTR if enabled so not const) and an entry on the GCS is
> modelled with uint64_t (since it has fixed size and can be a token
> that's not a pointer).
>
> gcc/ChangeLog:
>
> * config/aarch64/aarch64-builtins.cc (enum aarch64_builtins): Add
> AARCH64_BUILTIN_GCSPR, AARCH64_BUILTIN_GCSPOPM, AARCH64_BUILTIN_GCSSS.
> (aarch64_init_gcs_builtins): New.
> (aarch64_general_init_builtins): Call aarch64_init_gcs_builtins.
> (aarch64_expand_gcs_builtin): New.
> (aarch64_general_expand_builtin): Call aarch64_expand_gcs_builtin.
> ---
> gcc/config/aarch64/aarch64-builtins.cc | 78 ++++++++++++++++++++++++++
> 1 file changed, 78 insertions(+)
>
> diff --git a/gcc/config/aarch64/aarch64-builtins.cc
> b/gcc/config/aarch64/aarch64-builtins.cc
> index e693a14f4f3..6101f252bfd 100644
> --- a/gcc/config/aarch64/aarch64-builtins.cc
> +++ b/gcc/config/aarch64/aarch64-builtins.cc
> @@ -878,6 +878,9 @@ enum aarch64_builtins
> AARCH64_PLIX,
> /* Armv8.9-A / Armv9.4-A builtins. */
> AARCH64_BUILTIN_CHKFEAT,
> + AARCH64_BUILTIN_GCSPR,
> + AARCH64_BUILTIN_GCSPOPM,
> + AARCH64_BUILTIN_GCSSS,
> AARCH64_BUILTIN_MAX
> };
>
> @@ -2240,6 +2243,29 @@ aarch64_init_fpsr_fpcr_builtins (void)
> AARCH64_BUILTIN_SET_FPSR64);
> }
>
> +/* Add builtins for Guarded Control Stack instructions. */
> +
> +static void
> +aarch64_init_gcs_builtins (void)
> +{
> + tree ftype;
> +
> + ftype = build_function_type_list (ptr_type_node, NULL);
> + aarch64_builtin_decls[AARCH64_BUILTIN_GCSPR]
> + = aarch64_general_add_builtin ("__builtin_aarch64_gcspr", ftype,
> + AARCH64_BUILTIN_GCSPR);
> +
> + ftype = build_function_type_list (uint64_type_node, NULL);
> + aarch64_builtin_decls[AARCH64_BUILTIN_GCSPOPM]
> + = aarch64_general_add_builtin ("__builtin_aarch64_gcspopm", ftype,
> + AARCH64_BUILTIN_GCSPOPM);
> +
> + ftype = build_function_type_list (ptr_type_node, ptr_type_node, NULL);
> + aarch64_builtin_decls[AARCH64_BUILTIN_GCSSS]
> + = aarch64_general_add_builtin ("__builtin_aarch64_gcsss", ftype,
> + AARCH64_BUILTIN_GCSSS);
> +}
> +
> /* Initialize all builtins in the AARCH64_BUILTIN_GENERAL group. */
>
> void
> @@ -2287,6 +2313,8 @@ aarch64_general_init_builtins (void)
> = aarch64_general_add_builtin ("__builtin_aarch64_chkfeat",
> ftype_chkfeat,
> AARCH64_BUILTIN_CHKFEAT);
>
> + aarch64_init_gcs_builtins ();
> +
> if (in_lto_p)
> handle_arm_acle_h ();
> }
> @@ -3381,6 +3409,51 @@ aarch64_expand_fpsr_fpcr_getter (enum insn_code icode,
> machine_mode mode,
> return op.value;
> }
>
> +/* Expand GCS builtin EXP with code FCODE, putting the result
> + into TARGET. If IGNORE is true the return value is ignored. */
> +
> +rtx
> +aarch64_expand_gcs_builtin (tree exp, rtx target, int fcode, int ignore)
> +{
> + if (fcode == AARCH64_BUILTIN_GCSPR)
> + {
> + expand_operand op;
> + create_output_operand (&op, target, DImode);
> + expand_insn (CODE_FOR_aarch64_load_gcspr, 1, &op);
> + return op.value;
> + }
> + if (fcode == AARCH64_BUILTIN_GCSPOPM && ignore)
> + {
> + expand_insn (CODE_FOR_aarch64_gcspopm_xzr, 0, 0);
> + return target;
> + }
> + if (fcode == AARCH64_BUILTIN_GCSPOPM)
> + {
> + rtx tmp = gen_reg_rtx (DImode);
> + emit_move_insn (tmp, const0_rtx);
> + expand_operand ops[2];
> + create_output_operand (&ops[0], target, Pmode);
> + create_input_operand (&ops[1], tmp, Pmode);
> + expand_insn (CODE_FOR_aarch64_gcspopm, 2, ops);
> + return ops[0].value;
> + }
Since the instruction use DImode rather than Pmode, we should probably
do the same here.
Also, although it's not much of a simplification, it should be possible
to pass const0_rtx directly to create_input_operand:
if (fcode == AARCH64_BUILTIN_GCSPOPM)
{
expand_operand ops[2];
create_output_operand (&ops[0], target, DImode);
create_input_operand (&ops[1], const0_rtx, DImode);
expand_insn (CODE_FOR_aarch64_gcspopm, 2, ops);
return gen_lowpart (Pmode, ops[0].value);
}
> + if (fcode == AARCH64_BUILTIN_GCSSS)
> + {
> + expand_operand opnd;
> + rtx arg = expand_normal (CALL_EXPR_ARG (exp, 0));
> + create_input_operand (&opnd, arg, Pmode);
> + expand_insn (CODE_FOR_aarch64_gcsss1, 1, &opnd);
> + expand_operand ops[2];
> + rtx tmp = gen_reg_rtx (DImode);
> + emit_move_insn (tmp, const0_rtx);
> + create_output_operand (&ops[0], target, Pmode);
> + create_input_operand (&ops[1], tmp, Pmode);
> + expand_insn (CODE_FOR_aarch64_gcsss2, 2, ops);
> + return ops[0].value;
> + }
Similarly here:
if (fcode == AARCH64_BUILTIN_GCSSS)
{
expand_operand opnd;
rtx arg = expand_normal (CALL_EXPR_ARG (exp, 0));
arg = convert_modes (DImode, Pmode, arg, true);
create_input_operand (&opnd, arg, DImode);
expand_insn (CODE_FOR_aarch64_gcsss1, 1, &opnd);
expand_operand ops[2];
create_output_operand (&ops[0], target, DImode);
create_input_operand (&ops[1], const0_rtx, DImode);
expand_insn (CODE_FOR_aarch64_gcsss2, 2, ops);
return gen_lowpart (Pmode, ops[0].value);
}
Thanks for splitting the instructions up btw. The new version looks good.
Richard
> + gcc_unreachable ();
> +}
> +
> /* Expand an expression EXP that calls built-in function FCODE,
> with result going to TARGET if that's convenient. IGNORE is true
> if the result of the builtin is ignored. */
> @@ -3515,6 +3588,11 @@ aarch64_general_expand_builtin (unsigned int fcode,
> tree exp, rtx target,
> expand_insn (CODE_FOR_aarch64_chkfeat, 0, 0);
> return copy_to_reg (x16_reg);
> }
> +
> + case AARCH64_BUILTIN_GCSPR:
> + case AARCH64_BUILTIN_GCSPOPM:
> + case AARCH64_BUILTIN_GCSSS:
> + return aarch64_expand_gcs_builtin (exp, target, fcode, ignore);
> }
>
> if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <=
> AARCH64_SIMD_BUILTIN_MAX)