public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-6214] aarch64: Implement system register validation tools
@ 2023-12-06 10:41 Victor Do Nascimento
  0 siblings, 0 replies; only message in thread
From: Victor Do Nascimento @ 2023-12-06 10:41 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:7d36ea705712539d2c2cda668feb2e675a74958e

commit r14-6214-g7d36ea705712539d2c2cda668feb2e675a74958e
Author: Victor Do Nascimento <victor.donascimento@arm.com>
Date:   Mon Jun 26 13:10:09 2023 +0100

    aarch64: Implement system register validation tools
    
    Given the implementation of a mechanism of encoding system registers
    into GCC, this patch provides the mechanism of validating their use by
    the compiler.  In particular, this involves:
    
      1. Ensuring a supplied string corresponds to a known system
         register name.  System registers can be accessed either via their
         name (e.g. `SPSR_EL1') or their encoding (e.g. `S3_0_C4_C0_0').
         Register names are validated using a hash map, mapping known
         system register names to its corresponding `sysreg_t' struct,
         which is populated from the `aarch64_system_regs.def' file.
         Register name validation is done via `lookup_sysreg_map', while
         the encoding naming convention is validated via a parser
         implemented in this patch - `is_implem_def_reg'.
      2. Once a given register name is deemed to be valid, it is checked
         against a further 2 criteria:
           a. Is the referenced register implemented in the target
                architecture?  This is achieved by comparing the ARCH field
              in the relevant SYSREG entry from `aarch64_system_regs.def'
              against `aarch64_feature_flags' flags set at compile-time.
           b. Is the register being used correctly?  Check the requested
              operation against the FLAGS specified in SYSREG.
              This prevents operations like writing to a read-only system
              register.
    
    gcc/ChangeLog:
    
            * config/aarch64/aarch64-protos.h (aarch64_valid_sysreg_name_p): New.
            (aarch64_retrieve_sysreg): Likewise.
            * config/aarch64/aarch64.cc (is_implem_def_reg): Likewise.
            (aarch64_valid_sysreg_name_p): Likewise.
            (aarch64_retrieve_sysreg): Likewise.
            (aarch64_register_sysreg): Likewise.
            (aarch64_init_sysregs): Likewise.
            (aarch64_lookup_sysreg_map): Likewise.
            * config/aarch64/predicates.md (aarch64_sysreg_string): New.

Diff:
---
 gcc/config/aarch64/aarch64-protos.h |   2 +
 gcc/config/aarch64/aarch64.cc       | 147 ++++++++++++++++++++++++++++++++++++
 gcc/config/aarch64/predicates.md    |   4 +
 3 files changed, 153 insertions(+)

diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 25a9103f0e7..9e09cf7ee58 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -839,6 +839,8 @@ bool aarch64_simd_shift_imm_p (rtx, machine_mode, bool);
 bool aarch64_sve_ptrue_svpattern_p (rtx, struct simd_immediate_info *);
 bool aarch64_simd_valid_immediate (rtx, struct simd_immediate_info *,
 			enum simd_immediate_check w = AARCH64_CHECK_MOV);
+bool aarch64_valid_sysreg_name_p (const char *);
+const char *aarch64_retrieve_sysreg (const char *, bool);
 rtx aarch64_check_zero_based_sve_index_immediate (rtx);
 bool aarch64_maybe_generate_simd_constant (rtx, rtx, machine_mode);
 bool aarch64_simd_special_constant_p (rtx, machine_mode);
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 91ec1d27558..737fc696def 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -91,6 +91,7 @@
 #include "symbol-summary.h"
 #include "ipa-prop.h"
 #include "ipa-fnsummary.h"
+#include "hash-map.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -510,6 +511,52 @@ const sysreg_t aarch64_sysregs[] =
 
 #undef AARCH64_NO_FEATURES
 
+using sysreg_map_t = hash_map<nofree_string_hash, const sysreg_t *>;
+static sysreg_map_t *sysreg_map = nullptr;
+
+/* Map system register names to their hardware metadata: encoding,
+   feature flags and architectural feature requirements, all of which
+   are encoded in a sysreg_t struct.  */
+void
+aarch64_register_sysreg (const char *name, const sysreg_t *metadata)
+{
+  bool dup = sysreg_map->put (name, metadata);
+  gcc_checking_assert (!dup);
+}
+
+/* Lazily initialize hash table for system register validation,
+   checking the validity of supplied register name and returning
+   register's associated metadata.  */
+static void
+aarch64_init_sysregs (void)
+{
+  gcc_assert (!sysreg_map);
+  sysreg_map = new sysreg_map_t;
+
+
+  for (unsigned i = 0; i < ARRAY_SIZE (aarch64_sysregs); i++)
+    {
+      const sysreg_t *reg = aarch64_sysregs + i;
+      aarch64_register_sysreg (reg->name, reg);
+    }
+}
+
+/* No direct access to the sysreg hash-map should be made.  Doing so
+   risks trying to acess an unitialized hash-map and dereferencing the
+   returned double pointer without due care risks dereferencing a
+   null-pointer.  */
+const sysreg_t *
+aarch64_lookup_sysreg_map (const char *regname)
+{
+  if (!sysreg_map)
+    aarch64_init_sysregs ();
+
+  const sysreg_t **sysreg_entry = sysreg_map->get (regname);
+  if (sysreg_entry != NULL)
+    return *sysreg_entry;
+  return NULL;
+}
+
 /* The current tuning set.  */
 struct tune_params aarch64_tune_params = generic_tunings;
 
@@ -28955,6 +29002,106 @@ make_pass_switch_pstate_sm (gcc::context *ctxt)
   return new pass_switch_pstate_sm (ctxt);
 }
 
+/* Parse an implementation-defined system register name of
+   the form S[0-3]_[0-7]_C[0-15]_C[0-15]_[0-7].
+   Return true if name matched against above pattern, false
+   otherwise.  */
+bool
+aarch64_is_implem_def_reg (const char *regname)
+{
+  unsigned pos = 0;
+  unsigned name_len = strlen (regname);
+  if (name_len < 12 || name_len > 14)
+    return false;
+
+  auto cterm_valid_p = [&]()
+  {
+    bool leading_zero_p = false;
+    unsigned i = 0;
+    char n[3] = {0};
+
+    if (regname[pos] != 'c')
+      return false;
+    pos++;
+    while (regname[pos] != '_')
+      {
+	if (leading_zero_p)
+	  return false;
+	if (i == 0 && regname[pos] == '0')
+	  leading_zero_p = true;
+	if (i > 2)
+	  return false;
+	if (!ISDIGIT (regname[pos]))
+	  return false;
+	n[i++] = regname[pos++];
+      }
+    if (atoi (n) > 15)
+      return false;
+    return true;
+  };
+
+  if (regname[pos] != 's')
+    return false;
+  pos++;
+  if (regname[pos] < '0' || regname[pos] > '3')
+    return false;
+  pos++;
+  if (regname[pos++] != '_')
+    return false;
+  if (regname[pos] < '0' || regname[pos] > '7')
+    return false;
+  pos++;
+  if (regname[pos++] != '_')
+    return false;
+  if (!cterm_valid_p ())
+    return false;
+  if (regname[pos++] != '_')
+    return false;
+  if (!cterm_valid_p ())
+    return false;
+  if (regname[pos++] != '_')
+    return false;
+  if (regname[pos] < '0' || regname[pos] > '7')
+    return false;
+  return true;
+}
+
+/* Return true if REGNAME matches either a known permitted system
+   register name, or a generic sysreg specification.  For use in
+   back-end predicate `aarch64_sysreg_string'.  */
+bool
+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 (sysreg->arch_reqs)
+    return (aarch64_isa_flags & sysreg->arch_reqs);
+  return true;
+}
+
+/* Return the generic sysreg specification for a valid system register
+   name, otherwise NULL.  WRITE_P is true iff the register is being
+   written to.  */
+const char *
+aarch64_retrieve_sysreg (const char *regname, bool write_p)
+{
+  const sysreg_t *sysreg = aarch64_lookup_sysreg_map (regname);
+  if (sysreg == NULL)
+    {
+      if (aarch64_is_implem_def_reg (regname))
+	return regname;
+      else
+	return NULL;
+    }
+  if ((write_p && (sysreg->properties & F_REG_READ))
+      || (!write_p && (sysreg->properties & F_REG_WRITE)))
+    return NULL;
+  if ((~aarch64_isa_flags & sysreg->arch_reqs) != 0)
+    return NULL;
+  return sysreg->encoding;
+}
+
 /* Target-specific selftests.  */
 
 #if CHECKING_P
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index c60a9e19c70..9af28103a74 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -20,6 +20,10 @@
 
 (include "../arm/common.md")
 
+(define_predicate "aarch64_sysreg_string"
+  (and (match_code "const_string")
+       (match_test "aarch64_valid_sysreg_name_p (XSTR (op, 0))")))
+
 (define_special_predicate "cc_register"
   (and (match_code "reg")
        (and (match_test "REGNO (op) == CC_REGNUM")

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-12-06 10:41 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-06 10:41 [gcc r14-6214] aarch64: Implement system register validation tools Victor Do Nascimento

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).