From: Victor Do Nascimento <victor.donascimento@arm.com>
To: <gcc-patches@gcc.gnu.org>
Cc: <kyrylo.tkachov@arm.com>, <richard.sandiford@arm.com>,
<Richard.Earnshaw@arm.com>,
Victor Do Nascimento <victor.donascimento@arm.com>
Subject: [PATCH V3 3/6] aarch64: Implement system register validation tools
Date: Thu, 2 Nov 2023 16:38:31 +0000 [thread overview]
Message-ID: <20231102163852.1860658-4-victor.donascimento@arm.com> (raw)
In-Reply-To: <20231102163852.1860658-1-victor.donascimento@arm.com>
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.
---
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 60a55f4bc19..5d6a1e75700 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -830,6 +830,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_sve_index_immediate_p (rtx);
bool aarch64_sve_arith_immediate_p (machine_mode, rtx, bool);
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index a4a9e2e51ea..eaeab0be436 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -85,6 +85,7 @@
#include "config/arm/aarch-common.h"
#include "config/arm/aarch-common-protos.h"
#include "ssa.h"
+#include "hash-map.h"
/* This file should be included last. */
#include "target-def.h"
@@ -2860,6 +2861,51 @@ const sysreg_t sysreg_structs[] =
const unsigned nsysreg = ARRAY_SIZE (sysreg_structs);
+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 < nsysreg; i++)
+ {
+ const sysreg_t *reg = sysreg_structs + 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;
@@ -28116,6 +28162,107 @@ aarch64_pars_overlap_p (rtx par1, rtx par2)
return false;
}
+/* 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 (sysreg->arch_reqs
+ && !(aarch64_isa_flags & sysreg->arch_reqs))
+ 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 01de4743974..5f0d242e4a8 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")
--
2.41.0
next prev parent reply other threads:[~2023-11-02 16:39 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-02 16:38 [PATCH V3 0/6] aarch64: Add support for __arm_rsr and __arm_wsr ACLE function family Victor Do Nascimento
2023-11-02 16:38 ` [PATCH V3 1/6] aarch64: Sync system register information with Binutils Victor Do Nascimento
2023-11-28 23:21 ` Richard Sandiford
2023-11-02 16:38 ` [PATCH V3 2/6] aarch64: Add support for aarch64-sys-regs.def Victor Do Nascimento
2023-11-28 23:02 ` Richard Sandiford
2023-11-02 16:38 ` Victor Do Nascimento [this message]
2023-11-28 23:00 ` [PATCH V3 3/6] aarch64: Implement system register validation tools Richard Sandiford
2023-11-02 16:38 ` [PATCH V3 4/6] aarch64: Implement system register r/w arm ACLE intrinsic functions Victor Do Nascimento
2023-11-28 23:10 ` Richard Sandiford
2023-11-02 16:38 ` [PATCH V3 5/6] aarch64: Add front-end argument type checking for target builtins Victor Do Nascimento
2023-11-28 23:19 ` Richard Sandiford
2023-11-02 16:38 ` [PATCH V3 6/6] aarch64: Add system register duplication check selftest Victor Do Nascimento
2023-11-28 23:21 ` Richard Sandiford
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231102163852.1860658-4-victor.donascimento@arm.com \
--to=victor.donascimento@arm.com \
--cc=Richard.Earnshaw@arm.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=kyrylo.tkachov@arm.com \
--cc=richard.sandiford@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).