#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"
#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;
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