On Mon, Sep 22, 2025 at 12:53:12PM +0100, Srinath Parvathaneni wrote:
> v4 -> v5 changes:
>
> * Modify check_effective_target_aarch64_sysreg_guarding_ok
> to check all the ELF targets have the require assembler
> support for -menable-sysreg-checking flag.
> * Update the dg-do directive in the tests.
> -----------------
> v3 -> v4 changes:
>
> * Fixed target in check_effective_target_aarch64_sysreg_guarding_ok
> ------------------
> v2 -> v3 changes:
>
> * Replaced the explicit bool cast with a != 0 check when testing
> bitmasks.
> * Restricted the inlined assembly tests to run only on ELF and
> Linux targets.
> * Added an effective-target check to ensure the assembler (binutils)
> supports the -menable-sysreg-checking flag before running the
> inlined assembly tests.
> -------------------
> v1 -> v2 changes:
>
> * Fixed the wrong conditional check.
> * Fixed the typos in the testcases.
> * Added support for inline assembly checking.
> * Added new tests for inline assembly sysreg checking.
> -------------------
>
> Hi All,
>
> In the current Binutils we have disabled the feature gating for sysreg
> by default and we have introduced a new flag "-meanble-sysreg-checking"
> to renable some of this checking.
>
> However in GCC, we have disabled the feature gating of sysreg to read/write
> intrinsics __arm_[wr]sr* and we have not added any mechanism to check the
> feature gating if needed similar to Binutils.
>
> This patch adds the support for the flag "-meanble-sysreg-checking" which
> renables some of the feature checking of sysreg to read/write intrinsics
> __arm_[wr]sr* similar to Binutils.
>
> For inline assembly, sysreg checks are not performed by CC1 and are
> instead delegated to the assembler. By default, the assembler does not
> perform these checks either. With this patch, the -menable-sysreg-checking
> flag passed to the compiler will also be propagated to the assembler,
> enabling sysreg checking for inline assembly.
>
> Regression tested on aarch64-none-elf and aarch64-linux-gnu and
> found no regressions.
>
> Ok for trunk?
>
> Regards,
> Srinath.
>
> 2025-09-22 Srinath Parvathaneni <[email protected]>
>
> gcc/ChangeLog:
>
> * config/aarch64/aarch64-elf.h (ASM_SPEC): Update the macro.
> * config/aarch64/aarch64.cc (aarch64_valid_sysreg_name_p):
> Add feature check condition.
> (aarch64_retrieve_sysreg): Likewise.
> * config/aarch64/aarch64.opt (menable-sysreg-checking):
> Define new flag.
> * doc/invoke.texi (menable-sysreg-checking): Document new flag.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/aarch64/acle/asm-inlined-sysreg-1.c: New test.
> * gcc.target/aarch64/acle/asm-inlined-sysreg-2.c: Likewise.
> * gcc.target/aarch64/acle/rwsr-gated-1.c: Likewise.
> * gcc.target/aarch64/acle/rwsr-gated-2.c: Likewise.
> * lib/target-supports.exp
> (check_effective_target_aarch64_sysreg_guarding_ok): Check
> assembler support of -menable-sysreg-checking flag.
> ---
> gcc/config/aarch64/aarch64-elf.h | 1 +
> gcc/config/aarch64/aarch64.cc | 6 ++++
> gcc/config/aarch64/aarch64.opt | 5 ++++
> gcc/doc/invoke.texi | 6 ++++
> .../aarch64/acle/asm-inlined-sysreg-1.c | 28 ++++++++++++++++++
> .../aarch64/acle/asm-inlined-sysreg-2.c | 29 +++++++++++++++++++
> .../gcc.target/aarch64/acle/rwsr-gated-1.c | 14 +++++++++
> .../gcc.target/aarch64/acle/rwsr-gated-2.c | 14 +++++++++
> gcc/testsuite/lib/target-supports.exp | 10 +++++++
> 9 files changed, 113 insertions(+)
> create mode 100644
> gcc/testsuite/gcc.target/aarch64/acle/asm-inlined-sysreg-1.c
> create mode 100644
> gcc/testsuite/gcc.target/aarch64/acle/asm-inlined-sysreg-2.c
> create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-gated-1.c
> create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-gated-2.c
>
> diff --git a/gcc/config/aarch64/aarch64-elf.h
> b/gcc/config/aarch64/aarch64-elf.h
> index f6ebb723715..57c5a319d7c 100644
> --- a/gcc/config/aarch64/aarch64-elf.h
> +++ b/gcc/config/aarch64/aarch64-elf.h
> @@ -136,6 +136,7 @@
> #define ASM_SPEC "\
> %{mbig-endian:-EB} \
> %{mlittle-endian:-EL} \
> +%{menable-sysreg-checking} \
> %(asm_cpu_spec)" \
> ASM_MABI_SPEC
> #endif
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index ef9c16598c0..badde353fde 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -31702,6 +31702,9 @@ aarch64_valid_sysreg_name_p (const char *regname)
> const sysreg_t *sysreg = aarch64_lookup_sysreg_map (regname);
> if (sysreg == NULL)
> return aarch64_is_implem_def_reg (regname);
> + if (aarch64_enable_sysreg_guarding
> + && ((~aarch64_isa_flags & sysreg->arch_reqs) != 0))
> + return (aarch64_isa_flags & sysreg->arch_reqs) != 0;
> return true;
This condition is still wrong. It can be fixed (and simplified) by replacing
these last four lines with:
return (!aarch64_enable_sysreg_guarding
|| (~aarch64_isa_flags & sysreg->arch_reqs == 0));
Alice
> }
>
> @@ -31725,6 +31728,9 @@ aarch64_retrieve_sysreg (const char *regname, bool
> write_p, bool is128op)
> if ((write_p && (sysreg->properties & F_REG_READ))
> || (!write_p && (sysreg->properties & F_REG_WRITE)))
> return NULL;
> + if (aarch64_enable_sysreg_guarding
> + && ((~aarch64_isa_flags & sysreg->arch_reqs) != 0))
> + return NULL;
> return sysreg->encoding;
> }
>
> diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt
> index 9ca753e6a88..5df5a159459 100644
> --- a/gcc/config/aarch64/aarch64.opt
> +++ b/gcc/config/aarch64/aarch64.opt
> @@ -82,6 +82,11 @@ mbig-endian
> Target RejectNegative Mask(BIG_END)
> Assume target CPU is configured as big endian.
>
> +menable-sysreg-checking
> +Target RejectNegative Var(aarch64_enable_sysreg_guarding) Init(0)
> +Generates an error message if an attempt is made to access a system register
> +which will not execute on the target architecture.
> +
> mgeneral-regs-only
> Target RejectNegative Mask(GENERAL_REGS_ONLY) Save
> Generate code which uses only the general registers.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 2eab5140bc2..b742e671cb6 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -823,6 +823,7 @@ Objective-C and Objective-C++ Dialects}.
>
> @emph{AArch64 Options} (@ref{AArch64 Options})
> @gccoptlist{-mabi=@var{name} -mbig-endian -mlittle-endian
> +-menable-sysreg-checking
> -mgeneral-regs-only
> -mcmodel=tiny -mcmodel=small -mcmodel=large
> -mstrict-align -mno-strict-align
> @@ -22095,6 +22096,11 @@ The @samp{ilp32} model is deprecated.
> Generate big-endian code. This is the default when GCC is configured for an
> @samp{aarch64_be-*-*} target.
>
> +@opindex menable-sysreg-checking
> +@item -menable-sysreg-checking
> +Generates an error message if an attempt is made to access a system register
> +which will not execute on the target architecture.
> +
> @opindex mgeneral-regs-only
> @item -mgeneral-regs-only
> Generate code which uses only the general-purpose registers. This will
> prevent
> diff --git a/gcc/testsuite/gcc.target/aarch64/acle/asm-inlined-sysreg-1.c
> b/gcc/testsuite/gcc.target/aarch64/acle/asm-inlined-sysreg-1.c
> new file mode 100644
> index 00000000000..3912c75b315
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/acle/asm-inlined-sysreg-1.c
> @@ -0,0 +1,28 @@
> +/* { dg-do assemble { target elf } } */
> +/* { dg-require-effective-target aarch64_sysreg_guarding_ok } */
> +/* { dg-additional-options "-march=armv8-a -menable-sysreg-checking -###" }
> */
> +/* Ensure the system registers passed through inline assembly are rejected by
> + assembler when guarding is enabled through "-menable-sysreg-checking"
> command
> + line flag and proper feature flags are not passed. */
> +
> +#define INPUT 1
> +
> +static inline void
> +read_write_using_sysreg (int mode)
> +{
> + int b;
> +
> + /* write to gcspr_el0. */
> + asm volatile ("msr gcspr_el0, %[r]" ::[r] "r" (mode):);
> +
> + /* Read from gcspr_el0. */
> + asm volatile ("mrs %[r], gcspr_el0" :[r] "=r"(b)::);
> +}
> +
> +int main()
> +{
> + read_write_using_sysreg (INPUT);
> + return 0;
> +}
> +/* { dg-prune-output "^(COMPILER_PATH|LIBRARY_PATH|COLLECT_GCC_OPTIONS)=.*"
> } */
> +/* { dg-message ".*\/.*as .*-menable-sysreg-checking" "assembler options"
> {target aarch64-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.target/aarch64/acle/asm-inlined-sysreg-2.c
> b/gcc/testsuite/gcc.target/aarch64/acle/asm-inlined-sysreg-2.c
> new file mode 100644
> index 00000000000..e6c96005705
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/acle/asm-inlined-sysreg-2.c
> @@ -0,0 +1,29 @@
> +/* { dg-do assemble { target elf} } */
> +/* { dg-require-effective-target aarch64_sysreg_guarding_ok } */
> +/* { dg-options "-save-temps -O2 -menable-sysreg-checking
> -march=armv8-a+gcs" } */
> +/* Ensure that system registers passed through inline assembly are properly
> + gated on the feature flags, when the guarding is enabled through
> + "-menable-sysreg-checking" command line flag. */
> +
> +#define INPUT 1
> +
> +static inline void
> +read_write_using_sysreg (int mode)
> +{
> + int b;
> +
> + /* write to gcspr_el0. */
> + asm volatile ("msr gcspr_el0, %[r]" ::[r] "r" (mode):);
> +
> + /* Read from gcspr_el0. */
> + asm volatile ("mrs %[r], gcspr_el0" :[r] "=r"(b)::);
> +}
> +
> +int main()
> +{
> + read_write_using_sysreg (INPUT);
> + return 0;
> +}
> +
> +/* { { dg-final { scan-assembler {msr\s+gcspr_el0,\s+x0} } } */
> +/* { { dg-final { scan-assembler {mrs\s+x0,\s+gcspr_el0} } } */
> diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rwsr-gated-1.c
> b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-gated-1.c
> new file mode 100644
> index 00000000000..35a54597cd8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-gated-1.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-menable-sysreg-checking -march=armv8-a+sve2+sme" } */
> +/* Ensure that system registers are properly gated on the feature flags, when
> + the guarding is enabled through "-menable-sysreg-checking" command line
> + flag. */
> +
> +#include <arm_acle.h>
> +
> +uint64_t
> +foo (uint64_t a)
> +{
> + __arm_wsr64 ("zcr_el1", a); /* { { dg-final { scan-assembler
> "msr\ts3_0_c1_c2_0, x0" } } */
> + return __arm_rsr64 ("smcr_el1"); /* { { dg-final { scan-assembler
> "mrs\tx0, s3_0_c1_c2_6" } } */
> +}
> diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rwsr-gated-2.c
> b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-gated-2.c
> new file mode 100644
> index 00000000000..49e9769f710
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-gated-2.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-menable-sysreg-checking -march=armv8-a" } */
> +/* Ensure the system registers are rejected by compiler when guarding is
> + enabled through "-menable-sysreg-checking" command line flag and proper
> + feature flags are not passed. */
> +
> +#include <arm_acle.h>
> +
> +uint64_t
> +foo (uint64_t a)
> +{
> + __arm_wsr64 ("zcr_el1", a); /* { dg-error "invalid system register name
> 'zcr_el1'" } */
> + return __arm_rsr64 ("smcr_el1"); /* { dg-error "invalid system register
> name 'smcr_el1'" } */
> +}
> diff --git a/gcc/testsuite/lib/target-supports.exp
> b/gcc/testsuite/lib/target-supports.exp
> index 1acfb373beb..490bdf3ecda 100644
> --- a/gcc/testsuite/lib/target-supports.exp
> +++ b/gcc/testsuite/lib/target-supports.exp
> @@ -12584,6 +12584,16 @@ foreach { aarch64_ext } $exts_sve2 {
> }]
> }
>
> +proc check_effective_target_aarch64_sysreg_guarding_ok { } {
> + if { [istarget aarch64*-*-*] && [check_effective_target_elf] } {
> + return [check_no_compiler_messages aarch64_assembler object {
> + __asm__ ("msr\ts3_3_c9_c13_4, x0");
> + } "-menable-sysreg-checking"]
> + } else {
> + return 0
> + }
> +}
> +
> proc check_effective_target_aarch64_asm_sve2p1_ok { } {
> if { [istarget aarch64*-*-*] } {
> return [check_no_compiler_messages aarch64_sve2p1_assembler object {
> --
> 2.25.1
>