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-19  Srinath Parvathaneni  <srinath.parvathan...@arm.com>

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;
 }
 
@@ -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 76ecea550f3..4874207d7eb 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
@@ -22091,6 +22092,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..0c3f06172f0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/acle/asm-inlined-sysreg-1.c
@@ -0,0 +1,28 @@
+/* { dg-do assemble { target aarch64*-*-elf* aarch64*-*-linux* } } */
+/* { 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..c5b25fbb8bc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/acle/asm-inlined-sysreg-2.c
@@ -0,0 +1,29 @@
+/* { dg-do assemble { target aarch64*-*-elf* aarch64*-*-linux* } } */
+/* { 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..8aadefc8850 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*-*-elf] || [istarget aarch64*-*-linux*] } {
+       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

Reply via email to