diff --git a/gcc/common/config/aarch64/aarch64-common.cc b/gcc/common/config/aarch64/aarch64-common.cc
index 0c6d25eb233..e5c83547bb2 100644
--- a/gcc/common/config/aarch64/aarch64-common.cc
+++ b/gcc/common/config/aarch64/aarch64-common.cc
@@ -30,6 +30,7 @@
 #include "opts.h"
 #include "flags.h"
 #include "diagnostic.h"
+#include "config/aarch64/aarch64-feature-deps.h"
 
 #ifdef  TARGET_BIG_ENDIAN_DEFAULT
 #undef  TARGET_DEFAULT_TARGET_FLAGS
@@ -138,9 +139,12 @@ struct aarch64_option_extension
 /* ISA extensions in AArch64.  */
 static const struct aarch64_option_extension all_extensions[] =
 {
-#define AARCH64_OPT_EXTENSION(NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, \
-			      SYNTHETIC, Z) \
-  {NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, SYNTHETIC},
+#define AARCH64_OPT_EXTENSION(NAME, IDENT, C, D, E, F) \
+  {NAME, AARCH64_FL_##IDENT, \
+   feature_deps::IDENT ().explicit_on & ~AARCH64_FL_##IDENT, \
+   feature_deps::get_flags_off (feature_deps::root_off_##IDENT) \
+   & ~AARCH64_FL_##IDENT, \
+   AARCH64_FL_##IDENT == AARCH64_FL_CRYPTO},
 #include "config/aarch64/aarch64-option-extensions.def"
   {NULL, 0, 0, 0, false}
 };
@@ -149,9 +153,12 @@ static const struct aarch64_option_extension all_extensions[] =
    bits and extension turned on.  Cached for efficiency.  */
 static struct aarch64_option_extension all_extensions_by_on[] =
 {
-#define AARCH64_OPT_EXTENSION(NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, \
-			      SYNTHETIC, Z) \
-  {NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, SYNTHETIC},
+#define AARCH64_OPT_EXTENSION(NAME, IDENT, C, D, E, F) \
+  {NAME, AARCH64_FL_##IDENT, \
+   feature_deps::IDENT ().explicit_on & ~AARCH64_FL_##IDENT, \
+   feature_deps::get_flags_off (feature_deps::root_off_##IDENT) \
+   & ~AARCH64_FL_##IDENT, \
+   AARCH64_FL_##IDENT == AARCH64_FL_CRYPTO},
 #include "config/aarch64/aarch64-option-extensions.def"
   {NULL, 0, 0, 0, false}
 };
@@ -174,18 +181,18 @@ struct arch_to_arch_name
    the default set of architectural feature flags they support.  */
 static const struct processor_name_to_arch all_cores[] =
 {
-#define AARCH64_CORE(NAME, X, IDENT, ARCH_IDENT, FLAGS, COSTS, IMP, PART, VARIANT) \
-  {NAME, AARCH64_ARCH_##ARCH_IDENT, AARCH64_FL_FOR_##ARCH_IDENT | FLAGS},
+#define AARCH64_CORE(NAME, CORE_IDENT, C, ARCH_IDENT, E, F, G, H, I) \
+  {NAME, AARCH64_ARCH_##ARCH_IDENT, feature_deps::cpu_##CORE_IDENT},
 #include "config/aarch64/aarch64-cores.def"
-  {"generic", AARCH64_ARCH_V8A, AARCH64_FL_FOR_V8A},
+  {"generic", AARCH64_ARCH_V8A, feature_deps::V8A ().enable},
   {"", aarch64_no_arch, 0}
 };
 
 /* Map architecture revisions to their string representation.  */
 static const struct arch_to_arch_name all_architectures[] =
 {
-#define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH, FLAGS) \
-  {AARCH64_ARCH_##ARCH_IDENT, NAME, FLAGS},
+#define AARCH64_ARCH(NAME, B, ARCH_IDENT, D, E)	\
+  {AARCH64_ARCH_##ARCH_IDENT, NAME, feature_deps::ARCH_IDENT ().enable},
 #include "config/aarch64/aarch64-arches.def"
   {aarch64_no_arch, "", 0}
 };
diff --git a/gcc/config/aarch64/aarch64-arches.def b/gcc/config/aarch64/aarch64-arches.def
index ece96e22a70..9f82466181d 100644
--- a/gcc/config/aarch64/aarch64-arches.def
+++ b/gcc/config/aarch64/aarch64-arches.def
@@ -30,19 +30,19 @@
    Due to the assumptions about the positions of these fields in config.gcc,
    NAME should be kept as the first argument.  */
 
-AARCH64_ARCH("armv8-a",	      generic,	     V8A,	8,  AARCH64_FL_FOR_V8A)
-AARCH64_ARCH("armv8.1-a",     generic,	     V8_1A,	8,  AARCH64_FL_FOR_V8_1A)
-AARCH64_ARCH("armv8.2-a",     generic,	     V8_2A,	8,  AARCH64_FL_FOR_V8_2A)
-AARCH64_ARCH("armv8.3-a",     generic,	     V8_3A,	8,  AARCH64_FL_FOR_V8_3A)
-AARCH64_ARCH("armv8.4-a",     generic,	     V8_4A,	8,  AARCH64_FL_FOR_V8_4A)
-AARCH64_ARCH("armv8.5-a",     generic,	     V8_5A,	8,  AARCH64_FL_FOR_V8_5A)
-AARCH64_ARCH("armv8.6-a",     generic,	     V8_6A,	8,  AARCH64_FL_FOR_V8_6A)
-AARCH64_ARCH("armv8.7-a",     generic,       V8_7A,     8,  AARCH64_FL_FOR_V8_7A)
-AARCH64_ARCH("armv8.8-a",     generic,       V8_8A,     8,  AARCH64_FL_FOR_V8_8A)
-AARCH64_ARCH("armv8-r",       generic,	     V8R  ,	8,  AARCH64_FL_FOR_V8R)
-AARCH64_ARCH("armv9-a",       generic,	     V9A  ,	9,  AARCH64_FL_FOR_V9A)
-AARCH64_ARCH("armv9.1-a",     generic,       V9_1A,     9,  AARCH64_FL_FOR_V9_1A)
-AARCH64_ARCH("armv9.2-a",     generic,       V9_2A,     9,  AARCH64_FL_FOR_V9_2A)
-AARCH64_ARCH("armv9.3-a",     generic,       V9_3A,     9,  AARCH64_FL_FOR_V9_3A)
+AARCH64_ARCH("armv8-a",       generic,       V8A,       8,  (SIMD))
+AARCH64_ARCH("armv8.1-a",     generic,       V8_1A,     8,  (V8A, LSE, CRC, RDMA))
+AARCH64_ARCH("armv8.2-a",     generic,       V8_2A,     8,  (V8_1A))
+AARCH64_ARCH("armv8.3-a",     generic,       V8_3A,     8,  (V8_2A, PAUTH))
+AARCH64_ARCH("armv8.4-a",     generic,       V8_4A,     8,  (V8_3A, F16FML, DOTPROD, FLAGM))
+AARCH64_ARCH("armv8.5-a",     generic,       V8_5A,     8,  (V8_4A, SB, SSBS, PREDRES))
+AARCH64_ARCH("armv8.6-a",     generic,       V8_6A,     8,  (V8_5A, I8MM, BF16))
+AARCH64_ARCH("armv8.7-a",     generic,       V8_7A,     8,  (V8_6A, LS64))
+AARCH64_ARCH("armv8.8-a",     generic,       V8_8A,     8,  (V8_7A, MOPS))
+AARCH64_ARCH("armv8-r",       generic,       V8R  ,     8,  (V8_4A))
+AARCH64_ARCH("armv9-a",       generic,       V9A  ,     9,  (V8_5A, SVE2))
+AARCH64_ARCH("armv9.1-a",     generic,       V9_1A,     9,  (V8_6A, V9A))
+AARCH64_ARCH("armv9.2-a",     generic,       V9_2A,     9,  (V8_7A, V9_1A))
+AARCH64_ARCH("armv9.3-a",     generic,       V9_3A,     9,  (V8_8A, V9_2A))
 
 #undef AARCH64_ARCH
diff --git a/gcc/config/aarch64/aarch64-cores.def b/gcc/config/aarch64/aarch64-cores.def
index cf500d0a981..60299160bb6 100644
--- a/gcc/config/aarch64/aarch64-cores.def
+++ b/gcc/config/aarch64/aarch64-cores.def
@@ -46,132 +46,132 @@
 /* ARMv8-A Architecture Processors.  */
 
 /* ARM ('A') cores. */
-AARCH64_CORE("cortex-a34",  cortexa34, cortexa53, V8A,  AARCH64_FL_CRC, cortexa35, 0x41, 0xd02, -1)
-AARCH64_CORE("cortex-a35",  cortexa35, cortexa53, V8A,  AARCH64_FL_CRC, cortexa35, 0x41, 0xd04, -1)
-AARCH64_CORE("cortex-a53",  cortexa53, cortexa53, V8A,  AARCH64_FL_CRC, cortexa53, 0x41, 0xd03, -1)
-AARCH64_CORE("cortex-a57",  cortexa57, cortexa57, V8A,  AARCH64_FL_CRC, cortexa57, 0x41, 0xd07, -1)
-AARCH64_CORE("cortex-a72",  cortexa72, cortexa57, V8A,  AARCH64_FL_CRC, cortexa72, 0x41, 0xd08, -1)
-AARCH64_CORE("cortex-a73",  cortexa73, cortexa57, V8A,  AARCH64_FL_CRC, cortexa73, 0x41, 0xd09, -1)
+AARCH64_CORE("cortex-a34",  cortexa34, cortexa53, V8A,  (CRC), cortexa35, 0x41, 0xd02, -1)
+AARCH64_CORE("cortex-a35",  cortexa35, cortexa53, V8A,  (CRC), cortexa35, 0x41, 0xd04, -1)
+AARCH64_CORE("cortex-a53",  cortexa53, cortexa53, V8A,  (CRC), cortexa53, 0x41, 0xd03, -1)
+AARCH64_CORE("cortex-a57",  cortexa57, cortexa57, V8A,  (CRC), cortexa57, 0x41, 0xd07, -1)
+AARCH64_CORE("cortex-a72",  cortexa72, cortexa57, V8A,  (CRC), cortexa72, 0x41, 0xd08, -1)
+AARCH64_CORE("cortex-a73",  cortexa73, cortexa57, V8A,  (CRC), cortexa73, 0x41, 0xd09, -1)
 
 /* Cavium ('C') cores. */
-AARCH64_CORE("thunderx",      thunderx,      thunderx,  V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO, thunderx,  0x43, 0x0a0, -1)
+AARCH64_CORE("thunderx",      thunderx,      thunderx,  V8A,  (CRC, CRYPTO), thunderx,  0x43, 0x0a0, -1)
 /* Do not swap around "thunderxt88p1" and "thunderxt88",
    this order is required to handle variant correctly. */
-AARCH64_CORE("thunderxt88p1", thunderxt88p1, thunderx,  V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO,	thunderxt88,  0x43, 0x0a1, 0)
-AARCH64_CORE("thunderxt88",   thunderxt88,   thunderx,  V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO, thunderxt88,  0x43, 0x0a1, -1)
+AARCH64_CORE("thunderxt88p1", thunderxt88p1, thunderx,  V8A,  (CRC, CRYPTO),	thunderxt88,  0x43, 0x0a1, 0)
+AARCH64_CORE("thunderxt88",   thunderxt88,   thunderx,  V8A,  (CRC, CRYPTO), thunderxt88,  0x43, 0x0a1, -1)
 
 /* OcteonTX is the official name for T81/T83. */
-AARCH64_CORE("octeontx",      octeontx,      thunderx,  V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO, thunderx,  0x43, 0x0a0, -1)
-AARCH64_CORE("octeontx81",    octeontxt81,   thunderx,  V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO, thunderx,  0x43, 0x0a2, -1)
-AARCH64_CORE("octeontx83",    octeontxt83,   thunderx,  V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO, thunderx,  0x43, 0x0a3, -1)
+AARCH64_CORE("octeontx",      octeontx,      thunderx,  V8A,  (CRC, CRYPTO), thunderx,  0x43, 0x0a0, -1)
+AARCH64_CORE("octeontx81",    octeontxt81,   thunderx,  V8A,  (CRC, CRYPTO), thunderx,  0x43, 0x0a2, -1)
+AARCH64_CORE("octeontx83",    octeontxt83,   thunderx,  V8A,  (CRC, CRYPTO), thunderx,  0x43, 0x0a3, -1)
 
-AARCH64_CORE("thunderxt81",   thunderxt81,   thunderx,  V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO, thunderx,  0x43, 0x0a2, -1)
-AARCH64_CORE("thunderxt83",   thunderxt83,   thunderx,  V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO, thunderx,  0x43, 0x0a3, -1)
+AARCH64_CORE("thunderxt81",   thunderxt81,   thunderx,  V8A,  (CRC, CRYPTO), thunderx,  0x43, 0x0a2, -1)
+AARCH64_CORE("thunderxt83",   thunderxt83,   thunderx,  V8A,  (CRC, CRYPTO), thunderx,  0x43, 0x0a3, -1)
 
 /* Ampere Computing ('\xC0') cores. */
-AARCH64_CORE("ampere1", ampere1, cortexa57, V8_6A, 0, ampere1, 0xC0, 0xac3, -1)
+AARCH64_CORE("ampere1", ampere1, cortexa57, V8_6A, (), ampere1, 0xC0, 0xac3, -1)
 /* Do not swap around "emag" and "xgene1",
    this order is required to handle variant correctly. */
-AARCH64_CORE("emag",        emag,      xgene1,    V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO, emag, 0x50, 0x000, 3)
+AARCH64_CORE("emag",        emag,      xgene1,    V8A,  (CRC, CRYPTO), emag, 0x50, 0x000, 3)
 
 /* APM ('P') cores. */
-AARCH64_CORE("xgene1",      xgene1,    xgene1,    V8A,  0, xgene1, 0x50, 0x000, -1)
+AARCH64_CORE("xgene1",      xgene1,    xgene1,    V8A,  (), xgene1, 0x50, 0x000, -1)
 
 /* Qualcomm ('Q') cores. */
-AARCH64_CORE("falkor",      falkor,    falkor,    V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO | AARCH64_FL_RDMA, qdf24xx,   0x51, 0xC00, -1)
-AARCH64_CORE("qdf24xx",     qdf24xx,   falkor,    V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO | AARCH64_FL_RDMA, qdf24xx,   0x51, 0xC00, -1)
+AARCH64_CORE("falkor",      falkor,    falkor,    V8A,  (CRC, CRYPTO, RDMA), qdf24xx,   0x51, 0xC00, -1)
+AARCH64_CORE("qdf24xx",     qdf24xx,   falkor,    V8A,  (CRC, CRYPTO, RDMA), qdf24xx,   0x51, 0xC00, -1)
 
 /* Samsung ('S') cores. */
-AARCH64_CORE("exynos-m1",   exynosm1,  exynosm1,  V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO, exynosm1,  0x53, 0x001, -1)
+AARCH64_CORE("exynos-m1",   exynosm1,  exynosm1,  V8A,  (CRC, CRYPTO), exynosm1,  0x53, 0x001, -1)
 
 /* HXT ('h') cores. */
-AARCH64_CORE("phecda",      phecda,    falkor,    V8A,  AARCH64_FL_CRC | AARCH64_FL_CRYPTO, qdf24xx,   0x68, 0x000, -1)
+AARCH64_CORE("phecda",      phecda,    falkor,    V8A,  (CRC, CRYPTO), qdf24xx,   0x68, 0x000, -1)
 
 /* ARMv8.1-A Architecture Processors.  */
 
 /* Broadcom ('B') cores. */
-AARCH64_CORE("thunderx2t99p1",  thunderx2t99p1, thunderx2t99, V8_1A,  AARCH64_FL_CRYPTO, thunderx2t99, 0x42, 0x516, -1)
-AARCH64_CORE("vulcan",  vulcan, thunderx2t99, V8_1A,  AARCH64_FL_CRYPTO, thunderx2t99, 0x42, 0x516, -1)
+AARCH64_CORE("thunderx2t99p1",  thunderx2t99p1, thunderx2t99, V8_1A,  (CRYPTO), thunderx2t99, 0x42, 0x516, -1)
+AARCH64_CORE("vulcan",  vulcan, thunderx2t99, V8_1A,  (CRYPTO), thunderx2t99, 0x42, 0x516, -1)
 
 /* Cavium ('C') cores. */
-AARCH64_CORE("thunderx2t99",  thunderx2t99,  thunderx2t99, V8_1A,  AARCH64_FL_CRYPTO, thunderx2t99, 0x43, 0x0af, -1)
+AARCH64_CORE("thunderx2t99",  thunderx2t99,  thunderx2t99, V8_1A,  (CRYPTO), thunderx2t99, 0x43, 0x0af, -1)
 
 /* ARMv8.2-A Architecture Processors.  */
 
 /* ARM ('A') cores. */
-AARCH64_CORE("cortex-a55",  cortexa55, cortexa53, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD, cortexa53, 0x41, 0xd05, -1)
-AARCH64_CORE("cortex-a75",  cortexa75, cortexa57, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD, cortexa73, 0x41, 0xd0a, -1)
-AARCH64_CORE("cortex-a76",  cortexa76, cortexa57, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD, neoversen1, 0x41, 0xd0b, -1)
-AARCH64_CORE("cortex-a76ae",  cortexa76ae, cortexa57, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD | AARCH64_FL_SSBS, neoversen1, 0x41, 0xd0e, -1)
-AARCH64_CORE("cortex-a77",  cortexa77, cortexa57, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD | AARCH64_FL_SSBS, neoversen1, 0x41, 0xd0d, -1)
-AARCH64_CORE("cortex-a78",  cortexa78, cortexa57, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD | AARCH64_FL_SSBS | AARCH64_FL_PROFILE, neoversen1, 0x41, 0xd41, -1)
-AARCH64_CORE("cortex-a78ae",  cortexa78ae, cortexa57, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD | AARCH64_FL_SSBS | AARCH64_FL_PROFILE, neoversen1, 0x41, 0xd42, -1)
-AARCH64_CORE("cortex-a78c",  cortexa78c, cortexa57, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD | AARCH64_FL_SSBS | AARCH64_FL_PROFILE | AARCH64_FL_FLAGM | AARCH64_FL_PAUTH, neoversen1, 0x41, 0xd4b, -1)
-AARCH64_CORE("cortex-a65",  cortexa65, cortexa53, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD | AARCH64_FL_SSBS, cortexa73, 0x41, 0xd06, -1)
-AARCH64_CORE("cortex-a65ae",  cortexa65ae, cortexa53, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD | AARCH64_FL_SSBS, cortexa73, 0x41, 0xd43, -1)
-AARCH64_CORE("cortex-x1",  cortexx1, cortexa57, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD | AARCH64_FL_SSBS | AARCH64_FL_PROFILE, neoversen1, 0x41, 0xd44, -1)
-AARCH64_CORE("ares",  ares, cortexa57, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD | AARCH64_FL_PROFILE, neoversen1, 0x41, 0xd0c, -1)
-AARCH64_CORE("neoverse-n1",  neoversen1, cortexa57, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD | AARCH64_FL_PROFILE, neoversen1, 0x41, 0xd0c, -1)
-AARCH64_CORE("neoverse-e1",  neoversee1, cortexa53, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD | AARCH64_FL_SSBS, cortexa73, 0x41, 0xd4a, -1)
+AARCH64_CORE("cortex-a55",  cortexa55, cortexa53, V8_2A,  (F16, RCPC, DOTPROD), cortexa53, 0x41, 0xd05, -1)
+AARCH64_CORE("cortex-a75",  cortexa75, cortexa57, V8_2A,  (F16, RCPC, DOTPROD), cortexa73, 0x41, 0xd0a, -1)
+AARCH64_CORE("cortex-a76",  cortexa76, cortexa57, V8_2A,  (F16, RCPC, DOTPROD), neoversen1, 0x41, 0xd0b, -1)
+AARCH64_CORE("cortex-a76ae",  cortexa76ae, cortexa57, V8_2A,  (F16, RCPC, DOTPROD, SSBS), neoversen1, 0x41, 0xd0e, -1)
+AARCH64_CORE("cortex-a77",  cortexa77, cortexa57, V8_2A,  (F16, RCPC, DOTPROD, SSBS), neoversen1, 0x41, 0xd0d, -1)
+AARCH64_CORE("cortex-a78",  cortexa78, cortexa57, V8_2A,  (F16, RCPC, DOTPROD, SSBS, PROFILE), neoversen1, 0x41, 0xd41, -1)
+AARCH64_CORE("cortex-a78ae",  cortexa78ae, cortexa57, V8_2A,  (F16, RCPC, DOTPROD, SSBS, PROFILE), neoversen1, 0x41, 0xd42, -1)
+AARCH64_CORE("cortex-a78c",  cortexa78c, cortexa57, V8_2A,  (F16, RCPC, DOTPROD, SSBS, PROFILE, FLAGM, PAUTH), neoversen1, 0x41, 0xd4b, -1)
+AARCH64_CORE("cortex-a65",  cortexa65, cortexa53, V8_2A,  (F16, RCPC, DOTPROD, SSBS), cortexa73, 0x41, 0xd06, -1)
+AARCH64_CORE("cortex-a65ae",  cortexa65ae, cortexa53, V8_2A,  (F16, RCPC, DOTPROD, SSBS), cortexa73, 0x41, 0xd43, -1)
+AARCH64_CORE("cortex-x1",  cortexx1, cortexa57, V8_2A,  (F16, RCPC, DOTPROD, SSBS, PROFILE), neoversen1, 0x41, 0xd44, -1)
+AARCH64_CORE("ares",  ares, cortexa57, V8_2A,  (F16, RCPC, DOTPROD, PROFILE), neoversen1, 0x41, 0xd0c, -1)
+AARCH64_CORE("neoverse-n1",  neoversen1, cortexa57, V8_2A,  (F16, RCPC, DOTPROD, PROFILE), neoversen1, 0x41, 0xd0c, -1)
+AARCH64_CORE("neoverse-e1",  neoversee1, cortexa53, V8_2A,  (F16, RCPC, DOTPROD, SSBS), cortexa73, 0x41, 0xd4a, -1)
 
 /* Cavium ('C') cores. */
-AARCH64_CORE("octeontx2",      octeontx2,      cortexa57, V8_2A,  AARCH64_FL_CRYPTO | AARCH64_FL_PROFILE, cortexa57, 0x43, 0x0b0, -1)
-AARCH64_CORE("octeontx2t98",   octeontx2t98,   cortexa57, V8_2A,  AARCH64_FL_CRYPTO | AARCH64_FL_PROFILE, cortexa57, 0x43, 0x0b1, -1)
-AARCH64_CORE("octeontx2t96",   octeontx2t96,   cortexa57, V8_2A,  AARCH64_FL_CRYPTO | AARCH64_FL_PROFILE, cortexa57, 0x43, 0x0b2, -1)
+AARCH64_CORE("octeontx2",      octeontx2,      cortexa57, V8_2A,  (CRYPTO, PROFILE), cortexa57, 0x43, 0x0b0, -1)
+AARCH64_CORE("octeontx2t98",   octeontx2t98,   cortexa57, V8_2A,  (CRYPTO, PROFILE), cortexa57, 0x43, 0x0b1, -1)
+AARCH64_CORE("octeontx2t96",   octeontx2t96,   cortexa57, V8_2A,  (CRYPTO, PROFILE), cortexa57, 0x43, 0x0b2, -1)
 /* Note OcteonTX2 T93 is an alias to OcteonTX2 T96. */
-AARCH64_CORE("octeontx2t93",   octeontx2t93,   cortexa57, V8_2A,  AARCH64_FL_CRYPTO | AARCH64_FL_PROFILE, cortexa57, 0x43, 0x0b2, -1)
-AARCH64_CORE("octeontx2f95",   octeontx2f95,   cortexa57, V8_2A,  AARCH64_FL_CRYPTO | AARCH64_FL_PROFILE, cortexa57, 0x43, 0x0b3, -1)
-AARCH64_CORE("octeontx2f95n",  octeontx2f95n,  cortexa57, V8_2A,  AARCH64_FL_CRYPTO | AARCH64_FL_PROFILE, cortexa57, 0x43, 0x0b4, -1)
-AARCH64_CORE("octeontx2f95mm", octeontx2f95mm, cortexa57, V8_2A,  AARCH64_FL_CRYPTO | AARCH64_FL_PROFILE, cortexa57, 0x43, 0x0b5, -1)
+AARCH64_CORE("octeontx2t93",   octeontx2t93,   cortexa57, V8_2A,  (CRYPTO, PROFILE), cortexa57, 0x43, 0x0b2, -1)
+AARCH64_CORE("octeontx2f95",   octeontx2f95,   cortexa57, V8_2A,  (CRYPTO, PROFILE), cortexa57, 0x43, 0x0b3, -1)
+AARCH64_CORE("octeontx2f95n",  octeontx2f95n,  cortexa57, V8_2A,  (CRYPTO, PROFILE), cortexa57, 0x43, 0x0b4, -1)
+AARCH64_CORE("octeontx2f95mm", octeontx2f95mm, cortexa57, V8_2A,  (CRYPTO, PROFILE), cortexa57, 0x43, 0x0b5, -1)
 
 /* Fujitsu ('F') cores. */
-AARCH64_CORE("a64fx", a64fx, a64fx, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_SVE, a64fx, 0x46, 0x001, -1)
+AARCH64_CORE("a64fx", a64fx, a64fx, V8_2A,  (F16, SVE), a64fx, 0x46, 0x001, -1)
 
 /* HiSilicon ('H') cores. */
-AARCH64_CORE("tsv110",  tsv110, tsv110, V8_2A,  AARCH64_FL_CRYPTO | AARCH64_FL_F16 | AARCH64_FL_AES | AARCH64_FL_SHA2, tsv110,   0x48, 0xd01, -1)
+AARCH64_CORE("tsv110",  tsv110, tsv110, V8_2A,  (CRYPTO, F16), tsv110,   0x48, 0xd01, -1)
 
 /* ARMv8.3-A Architecture Processors.  */
 
 /* Marvell cores (TX3). */
-AARCH64_CORE("thunderx3t110",  thunderx3t110,  thunderx3t110, V8_3A,  AARCH64_FL_CRYPTO | AARCH64_FL_RCPC | AARCH64_FL_SM4 | AARCH64_FL_SHA3 | AARCH64_FL_F16FML, thunderx3t110, 0x43, 0x0b8, 0x0a)
+AARCH64_CORE("thunderx3t110",  thunderx3t110,  thunderx3t110, V8_3A,  (CRYPTO, RCPC, SM4, SHA3, F16FML), thunderx3t110, 0x43, 0x0b8, 0x0a)
 
 /* ARMv8.4-A Architecture Processors.  */
 
 /* Arm ('A') cores.  */
-AARCH64_CORE("zeus", zeus, cortexa57, V8_4A,  AARCH64_FL_SVE | AARCH64_FL_RCPC | AARCH64_FL_I8MM | AARCH64_FL_BF16 | AARCH64_FL_F16 | AARCH64_FL_PROFILE | AARCH64_FL_SSBS | AARCH64_FL_RNG, neoversev1, 0x41, 0xd40, -1)
-AARCH64_CORE("neoverse-v1", neoversev1, cortexa57, V8_4A,  AARCH64_FL_SVE | AARCH64_FL_RCPC | AARCH64_FL_I8MM | AARCH64_FL_BF16 | AARCH64_FL_F16 | AARCH64_FL_PROFILE | AARCH64_FL_SSBS | AARCH64_FL_RNG, neoversev1, 0x41, 0xd40, -1)
-AARCH64_CORE("neoverse-512tvb", neoverse512tvb, cortexa57, V8_4A,  AARCH64_FL_SVE | AARCH64_FL_RCPC | AARCH64_FL_I8MM | AARCH64_FL_BF16 | AARCH64_FL_F16 | AARCH64_FL_PROFILE | AARCH64_FL_SSBS | AARCH64_FL_RNG, neoverse512tvb, INVALID_IMP, INVALID_CORE, -1)
+AARCH64_CORE("zeus", zeus, cortexa57, V8_4A,  (SVE, RCPC, I8MM, BF16, PROFILE, SSBS, RNG), neoversev1, 0x41, 0xd40, -1)
+AARCH64_CORE("neoverse-v1", neoversev1, cortexa57, V8_4A,  (SVE, RCPC, I8MM, BF16, PROFILE, SSBS, RNG), neoversev1, 0x41, 0xd40, -1)
+AARCH64_CORE("neoverse-512tvb", neoverse512tvb, cortexa57, V8_4A,  (SVE, RCPC, I8MM, BF16, PROFILE, SSBS, RNG), neoverse512tvb, INVALID_IMP, INVALID_CORE, -1)
 
 /* Qualcomm ('Q') cores. */
-AARCH64_CORE("saphira",     saphira,    saphira,    V8_4A,  AARCH64_FL_CRYPTO | AARCH64_FL_RCPC, saphira,   0x51, 0xC01, -1)
+AARCH64_CORE("saphira",     saphira,    saphira,    V8_4A,  (CRYPTO, RCPC), saphira,   0x51, 0xC01, -1)
 
 /* ARMv8-A big.LITTLE implementations.  */
 
-AARCH64_CORE("cortex-a57.cortex-a53",  cortexa57cortexa53, cortexa53, V8A,  AARCH64_FL_CRC, cortexa57, 0x41, AARCH64_BIG_LITTLE (0xd07, 0xd03), -1)
-AARCH64_CORE("cortex-a72.cortex-a53",  cortexa72cortexa53, cortexa53, V8A,  AARCH64_FL_CRC, cortexa72, 0x41, AARCH64_BIG_LITTLE (0xd08, 0xd03), -1)
-AARCH64_CORE("cortex-a73.cortex-a35",  cortexa73cortexa35, cortexa53, V8A,  AARCH64_FL_CRC, cortexa73, 0x41, AARCH64_BIG_LITTLE (0xd09, 0xd04), -1)
-AARCH64_CORE("cortex-a73.cortex-a53",  cortexa73cortexa53, cortexa53, V8A,  AARCH64_FL_CRC, cortexa73, 0x41, AARCH64_BIG_LITTLE (0xd09, 0xd03), -1)
+AARCH64_CORE("cortex-a57.cortex-a53",  cortexa57cortexa53, cortexa53, V8A,  (CRC), cortexa57, 0x41, AARCH64_BIG_LITTLE (0xd07, 0xd03), -1)
+AARCH64_CORE("cortex-a72.cortex-a53",  cortexa72cortexa53, cortexa53, V8A,  (CRC), cortexa72, 0x41, AARCH64_BIG_LITTLE (0xd08, 0xd03), -1)
+AARCH64_CORE("cortex-a73.cortex-a35",  cortexa73cortexa35, cortexa53, V8A,  (CRC), cortexa73, 0x41, AARCH64_BIG_LITTLE (0xd09, 0xd04), -1)
+AARCH64_CORE("cortex-a73.cortex-a53",  cortexa73cortexa53, cortexa53, V8A,  (CRC), cortexa73, 0x41, AARCH64_BIG_LITTLE (0xd09, 0xd03), -1)
 
 /* ARM DynamIQ big.LITTLE configurations.  */
 
-AARCH64_CORE("cortex-a75.cortex-a55",  cortexa75cortexa55, cortexa53, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD, cortexa73, 0x41, AARCH64_BIG_LITTLE (0xd0a, 0xd05), -1)
-AARCH64_CORE("cortex-a76.cortex-a55",  cortexa76cortexa55, cortexa53, V8_2A,  AARCH64_FL_F16 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD, neoversen1, 0x41, AARCH64_BIG_LITTLE (0xd0b, 0xd05), -1)
+AARCH64_CORE("cortex-a75.cortex-a55",  cortexa75cortexa55, cortexa53, V8_2A,  (F16, RCPC, DOTPROD), cortexa73, 0x41, AARCH64_BIG_LITTLE (0xd0a, 0xd05), -1)
+AARCH64_CORE("cortex-a76.cortex-a55",  cortexa76cortexa55, cortexa53, V8_2A,  (F16, RCPC, DOTPROD), neoversen1, 0x41, AARCH64_BIG_LITTLE (0xd0b, 0xd05), -1)
 
 /* Armv8-R Architecture Processors.  */
-AARCH64_CORE("cortex-r82", cortexr82, cortexa53, V8R, 0, cortexa53, 0x41, 0xd15, -1)
+AARCH64_CORE("cortex-r82", cortexr82, cortexa53, V8R, (), cortexa53, 0x41, 0xd15, -1)
 
 /* Armv9.0-A Architecture Processors.  */
 
 /* Arm ('A') cores. */
-AARCH64_CORE("cortex-a510",  cortexa510, cortexa55, V9A,  AARCH64_FL_SVE2_BITPERM | AARCH64_FL_MEMTAG | AARCH64_FL_I8MM | AARCH64_FL_BF16, cortexa53, 0x41, 0xd46, -1)
+AARCH64_CORE("cortex-a510",  cortexa510, cortexa55, V9A,  (SVE2_BITPERM, MEMTAG, I8MM, BF16), cortexa53, 0x41, 0xd46, -1)
 
-AARCH64_CORE("cortex-a710",  cortexa710, cortexa57, V9A,  AARCH64_FL_SVE2_BITPERM | AARCH64_FL_MEMTAG | AARCH64_FL_I8MM | AARCH64_FL_BF16, neoversen2, 0x41, 0xd47, -1)
+AARCH64_CORE("cortex-a710",  cortexa710, cortexa57, V9A,  (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd47, -1)
 
-AARCH64_CORE("cortex-x2",  cortexx2, cortexa57, V9A,  AARCH64_FL_SVE2_BITPERM | AARCH64_FL_MEMTAG | AARCH64_FL_I8MM | AARCH64_FL_BF16, neoversen2, 0x41, 0xd48, -1)
+AARCH64_CORE("cortex-x2",  cortexx2, cortexa57, V9A,  (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd48, -1)
 
-AARCH64_CORE("neoverse-n2", neoversen2, cortexa57, V9A, AARCH64_FL_I8MM | AARCH64_FL_BF16 | AARCH64_FL_SVE2_BITPERM | AARCH64_FL_RNG | AARCH64_FL_MEMTAG | AARCH64_FL_PROFILE, neoversen2, 0x41, 0xd49, -1)
+AARCH64_CORE("neoverse-n2", neoversen2, cortexa57, V9A, (I8MM, BF16, SVE2_BITPERM, RNG, MEMTAG, PROFILE), neoversen2, 0x41, 0xd49, -1)
 
-AARCH64_CORE("demeter", demeter, cortexa57, V9A, AARCH64_FL_I8MM | AARCH64_FL_BF16 | AARCH64_FL_SVE2_BITPERM | AARCH64_FL_RNG | AARCH64_FL_MEMTAG | AARCH64_FL_PROFILE, neoversev2, 0x41, 0xd4f, -1)
-AARCH64_CORE("neoverse-v2", neoversev2, cortexa57, V9A, AARCH64_FL_I8MM | AARCH64_FL_BF16 | AARCH64_FL_SVE2_BITPERM | AARCH64_FL_RNG | AARCH64_FL_MEMTAG | AARCH64_FL_PROFILE, neoversev2, 0x41, 0xd4f, -1)
+AARCH64_CORE("demeter", demeter, cortexa57, V9A, (I8MM, BF16, SVE2_BITPERM, RNG, MEMTAG, PROFILE), neoversev2, 0x41, 0xd4f, -1)
+AARCH64_CORE("neoverse-v2", neoversev2, cortexa57, V9A, (I8MM, BF16, SVE2_BITPERM, RNG, MEMTAG, PROFILE), neoversev2, 0x41, 0xd4f, -1)
 
 #undef AARCH64_CORE
diff --git a/gcc/config/aarch64/aarch64-feature-deps.h b/gcc/config/aarch64/aarch64-feature-deps.h
new file mode 100644
index 00000000000..3e33cb2ce84
--- /dev/null
+++ b/gcc/config/aarch64/aarch64-feature-deps.h
@@ -0,0 +1,121 @@
+/* Feature dependency helpers for AArch64.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef AARCH64_FEATURE_DEPS_H
+#define AARCH64_FEATURE_DEPS_H 1
+
+namespace {
+namespace feature_deps {
+
+/* Together, these definitions of get_flags take a list of
+   feature names (representing functions that are defined below)
+   and return the set of associated flags.  */
+constexpr aarch64_feature_flags get_flags () { return 0; }
+
+template<typename T1, typename ...Ts>
+constexpr aarch64_feature_flags
+get_flags (T1 i, Ts... args)
+{
+  return i ().flag | get_flags (args...);
+}
+
+/* Like get_flags, but return the transitive closure of those features
+   and the ones that they rely on.  */
+constexpr aarch64_feature_flags get_enable () { return 0; }
+
+template<typename T1, typename ...Ts>
+constexpr aarch64_feature_flags
+get_enable (T1 i, Ts... args)
+{
+  return i ().enable | get_enable (args...);
+}
+
+/* Define info<FEATURE> such that it has the following static constant
+   variables:
+
+   - flag: the aarch64_feature_flags bit associated with FEATURE
+
+   - enable: the transitive closure of the features that FEATURE requires,
+     plus FLAG itself
+
+   - explicit_on: the transitive closure of the features that an
+     explicit +FEATURE enables, including FLAG itself.  This is
+     always a superset of ENABLE
+
+   Also define a function FEATURE () that returns an info<FEATURE>
+   (which is an empty structure, since all members are static).
+
+   Building up the list feature-by-feature ensures that the definition
+   files are in topological order.  */
+template<aarch64_feature> struct info;
+
+#define HANDLE(IDENT, REQUIRES, EXPLICIT_ON)				\
+  template<> struct info<aarch64_feature::IDENT> {			\
+    static constexpr auto flag = AARCH64_FL_##IDENT;			\
+    static constexpr auto enable = flag | get_enable REQUIRES;		\
+    static constexpr auto explicit_on = enable | get_enable EXPLICIT_ON; \
+  };									\
+  constexpr info<aarch64_feature::IDENT> IDENT ()			\
+  {									\
+    return info<aarch64_feature::IDENT> ();				\
+  }
+#define AARCH64_OPT_EXTENSION(A, IDENT, REQUIRES, EXPLICIT_ON, E, F) \
+  HANDLE (IDENT, REQUIRES, EXPLICIT_ON)
+#define AARCH64_ARCH(A, B, IDENT, D, REQUIRES) HANDLE (IDENT, REQUIRES, ())
+#include "config/aarch64/aarch64-option-extensions.def"
+#include "config/aarch64/aarch64-arches.def"
+#undef HANDLE
+
+/* Return the set of all features that would need to be disabled if
+   the features in MASK are disabled.
+
+   Note that the size of the expression varies linearly with the number
+   of features, which means that invoking this function once per feature
+   is quadratic in the number of features.  However, collecting the same
+   information at compiler start-up is likely to be quadratic too, so
+   we're better off paying the cost once per compiler build rather than
+   once per compiler run.  */
+constexpr aarch64_feature_flags
+get_flags_off (aarch64_feature_flags mask)
+{
+  return (0
+#define AARCH64_OPT_EXTENSION(A, IDENT, C, D, E, F) \
+	  | (feature_deps::IDENT ().enable & mask ? AARCH64_FL_##IDENT : 0)
+#include "config/aarch64/aarch64-option-extensions.def"
+	  );
+}
+
+/* Define root_off_<IDENT> variables for each feature, giving the set of
+   features that must be turned off by +noIDENT.  This set is not transitively
+   closed; use get_flags_off to complete the closure.  */
+#define AARCH64_OPT_EXTENSION(A, IDENT, C, D, EXPLICIT_OFF, F) \
+  constexpr auto root_off_##IDENT \
+    = AARCH64_FL_##IDENT | get_flags EXPLICIT_OFF;
+#include "config/aarch64/aarch64-option-extensions.def"
+
+/* Define cpu_<NAME> variables for each CPU, giving the transitive
+   closure of all the features that the CPU supports.  */
+#define AARCH64_CORE(A, CORE_IDENT, C, ARCH_IDENT, FEATURES, F, G, H, I) \
+  constexpr auto cpu_##CORE_IDENT = ARCH_IDENT ().enable | get_enable FEATURES;
+#include "config/aarch64/aarch64-cores.def"
+
+}
+}
+
+#endif
diff --git a/gcc/config/aarch64/aarch64-option-extensions.def b/gcc/config/aarch64/aarch64-option-extensions.def
index df2c8d19b8d..bdf4baf309c 100644
--- a/gcc/config/aarch64/aarch64-option-extensions.def
+++ b/gcc/config/aarch64/aarch64-option-extensions.def
@@ -21,23 +21,34 @@
 
    Before using #include to read this file, define a macro:
 
-      AARCH64_OPT_EXTENSION(EXT_NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF,
-			    SYNTHETIC, FEATURE_STRING)
-
-   - EXT_NAME is the name of the extension, represented as a string constant.
-   - FLAGS_CANONICAL is the canonical internal name for this flag.
-   - FLAGS_ON are the bitwise-or of the features that enabling the extension
-     adds, or zero if enabling this extension has no effect on other features.
-   - FLAGS_OFF are the bitwise-or of the features that disabling the extension
-     removes, or zero if disabling this extension has no effect on other
-     features.
-   - SYNTHETIC is a boolean to indicate whether the option is a purely synthetic
-     grouping of options and that the option itself has no feature bit (e.g.
-     crypto).  This is used to determine when sum of the individual options in
-     FLAGS_ON can be replaced by FLAG_CANONICAL in options minimization.  If the
-     group is synthetic then they can be replaced when all options in FLAGS_ON
-     are enabled, otherwise they can only be replaced when
-     FLAGS_ON | FLAG_CANONICAL are enabled.
+      AARCH64_OPT_EXTENSION(NAME, IDENT, REQUIRES, EXPLICIT_ON,
+			    EXPLICIT_OFF, FEATURE_STRING)
+
+   - NAME is the name of the extension, represented as a string constant.
+
+   - IDENT is the canonical internal name for this flag.
+
+   - REQUIRES is a list of features that must be enabled whenever this
+     feature is enabled.  The relationship is implicitly transitive:
+     if A appears in B's REQUIRES and B appears in C's REQUIRES then
+     A and B must be enabled whenever C is.  Thus, turning on C also
+     turns on A and B, while turning off A or B also turns off C.
+
+   - EXPLICIT_ON is a list of features that are enabled by an explicit
+     +NAME specification, in addition to those listed in REQUIRES.
+     Usually this is an empty list; comments below explain the exceptions.
+     The list is implicitly transitively closed wrt REQUIRES (but *not*
+     to EXPLICIT_ON, since NAME is the only thing explicit in +NAME).
+     Thus if A is in B's REQUIRES and B is in C's EXPLICIT_ON, +C will
+     enable both B and A.  B's EXPLICIT_ON has no effect on +C.
+
+   - EXPLICIT_OFF is a list of features that are disabled by an explicit
+     +noNAME specification, in addition to the features that are transitively
+     dependent on NAME (according to REQUIRES).  As with EXPLICIT_ON,
+     this is usually an empty list; comments below explain the exceptions.
+     If a feature A appears in this list then the list implicitly includes
+     any features that are transitively dependent on A (according to REQUIRES).
+
    - FEAT_STRING is a string containing the entries in the 'Features' field of
      /proc/cpuinfo on a GNU/Linux system that correspond to this architecture
      extension being available.  Sometimes multiple entries are needed to enable
@@ -47,197 +58,95 @@
      that are required.  Their order is not important.  An empty string means
      do not detect this feature during auto detection.
 
-     NOTE: Any changes to the AARCH64_OPT_EXTENSION macro need to be mirrored in
-     config.gcc.  */
-
-/* Enabling "fp" just enables "fp".
-   Disabling "fp" also disables "simd", "crypto", "fp16", "aes", "sha2",
-   "sha3", sm3/sm4, "sve", "sve2", "sve2-aes", "sve2-sha3", "sve2-sm4",
-   "sve2-bitperm", "i8mm", "f32mm", "f64mm", and "bf16".  */
-AARCH64_OPT_EXTENSION("fp", AARCH64_FL_FP, 0, AARCH64_FL_SIMD | \
-		      AARCH64_FL_CRYPTO | AARCH64_FL_F16 | AARCH64_FL_AES | \
-		      AARCH64_FL_SHA2 | AARCH64_FL_SHA3 | AARCH64_FL_SM4 | \
-		      AARCH64_FL_SVE | AARCH64_FL_SVE2 | AARCH64_FL_SVE2_AES | \
-		      AARCH64_FL_SVE2_SHA3 | AARCH64_FL_SVE2_SM4 | \
-		      AARCH64_FL_SVE2_BITPERM | AARCH64_FL_I8MM | \
-		      AARCH64_FL_F32MM | AARCH64_FL_F64MM | AARCH64_FL_BF16,
-		       false, "fp")
-
-/* Enabling "simd" also enables "fp".
-   Disabling "simd" also disables "crypto", "dotprod", "aes", "sha2", "sha3",
-   "sm3/sm4", "sve", "sve2", "sve2-aes", "sve2-sha3", "sve2-sm4",
-   "sve2-bitperm", "i8mm", "f32mm" and "f64mm".  */
-AARCH64_OPT_EXTENSION("simd", AARCH64_FL_SIMD, AARCH64_FL_FP, \
-		      AARCH64_FL_CRYPTO | AARCH64_FL_DOTPROD | \
-		      AARCH64_FL_AES | AARCH64_FL_SHA2 | AARCH64_FL_SHA3 | \
-		      AARCH64_FL_SM4 | AARCH64_FL_SVE | AARCH64_FL_SVE2 | \
-		      AARCH64_FL_SVE2_AES | AARCH64_FL_SVE2_SHA3 | \
-		      AARCH64_FL_SVE2_SM4 | AARCH64_FL_SVE2_BITPERM | \
-		      AARCH64_FL_I8MM | AARCH64_FL_F32MM | AARCH64_FL_F64MM, \
-		      false, "asimd")
-
-/* Enabling or disabling "crc" only changes "crc".  */
-AARCH64_OPT_EXTENSION("crc", AARCH64_FL_CRC, 0, 0, false, "crc32")
-
-/* Enabling or disabling "lse" only changes "lse".  */
-AARCH64_OPT_EXTENSION("lse", AARCH64_FL_LSE, 0, 0, false, "atomics")
-
-/* Enabling "fp16" also enables "fp".
-   Disabling "fp16" disables "fp16", "fp16fml", "sve", "sve2",
-   "sve2-aes", "sve2-sha3", "sve2-sm4", "sve2-bitperm", "f32mm" and
-    "f64mm".  */
-AARCH64_OPT_EXTENSION("fp16", AARCH64_FL_F16, AARCH64_FL_FP, \
-		      AARCH64_FL_F16FML | AARCH64_FL_SVE | AARCH64_FL_F32MM | \
-		      AARCH64_FL_F64MM | AARCH64_FL_SVE2 | \
-		      AARCH64_FL_SVE2_AES | AARCH64_FL_SVE2_SHA3 | \
-		      AARCH64_FL_SVE2_SM4 | AARCH64_FL_SVE2_BITPERM, false, \
-		      "fphp asimdhp")
-
-/* Enabling or disabling "rcpc" only changes "rcpc".  */
-AARCH64_OPT_EXTENSION("rcpc", AARCH64_FL_RCPC, 0, 0, false, "lrcpc")
-
-/* Enabling "rdma" also enables "fp", "simd".
-   Disabling "rdma" just disables "rdma".  */
-AARCH64_OPT_EXTENSION("rdma", AARCH64_FL_RDMA, \
-		      AARCH64_FL_FP | AARCH64_FL_SIMD, 0, false, "asimdrdm")
-
-/* Enabling "dotprod" also enables "simd".
-   Disabling "dotprod" only disables "dotprod".  */
-AARCH64_OPT_EXTENSION("dotprod", AARCH64_FL_DOTPROD, AARCH64_FL_FPSIMD, 0, \
-		      false, "asimddp")
-
-/* Enabling "aes" also enables "simd".
-   Disabling "aes" disables "aes" and "sve2-aes'.  */
-AARCH64_OPT_EXTENSION("aes", AARCH64_FL_AES, AARCH64_FL_FPSIMD, \
-		      AARCH64_FL_SVE2_AES | AARCH64_FL_CRYPTO, false, "aes")
-
-/* Enabling "sha2" also enables "simd".
-   Disabling "sha2" just disables "sha2".  */
-AARCH64_OPT_EXTENSION("sha2", AARCH64_FL_SHA2, AARCH64_FL_FPSIMD, \
-		      AARCH64_FL_CRYPTO | AARCH64_FL_SHA3 | \
-		      AARCH64_FL_SVE2_SHA3, false, "sha1 sha2")
-
-/* Enabling "crypto" also enables "fp", "simd", "aes" and "sha2".
-   Disabling "crypto" disables "crypto", "aes", "sha2", "sha3" and "sm3/sm4",
-   "sve2-aes", "sve2-sha3", "sve2-sm4".  */
-AARCH64_OPT_EXTENSION("crypto", AARCH64_FL_CRYPTO, AARCH64_FL_FP | \
-		      AARCH64_FL_SIMD | AARCH64_FL_AES | AARCH64_FL_SHA2, \
-		      AARCH64_FL_AES | AARCH64_FL_SHA2 | AARCH64_FL_SHA3 | \
-		      AARCH64_FL_SM4 | AARCH64_FL_SVE2_AES | \
-		      AARCH64_FL_SVE2_SHA3 | AARCH64_FL_SVE2_SM4, true, \
+   The list of features must follow topological order wrt REQUIRES
+   and EXPLICIT_ON.  For example, if A is in B's REQUIRES list, A must
+   come before B.  This is enforced by aarch64-feature-deps.h.
+
+   NOTE: Any changes to the AARCH64_OPT_EXTENSION macro need to be mirrored in
+   config.gcc.  */
+
+AARCH64_OPT_EXTENSION("fp", FP, (), (), (), "fp")
+
+AARCH64_OPT_EXTENSION("simd", SIMD, (FP), (), (), "asimd")
+
+AARCH64_OPT_EXTENSION("crc", CRC, (), (), (), "crc32")
+
+AARCH64_OPT_EXTENSION("lse", LSE, (), (), (), "atomics")
+
+/* +nofp16 disables an implicit F16FML, even though an implicit F16FML
+   does not imply F16.  See F16FML for more details.  */
+AARCH64_OPT_EXTENSION("fp16", F16, (FP), (), (F16FML), "fphp asimdhp")
+
+AARCH64_OPT_EXTENSION("rcpc", RCPC, (), (), (), "lrcpc")
+
+/* An explicit +rdma implies +simd, but +rdma+nosimd still enables scalar
+   RDMA instructions.  */
+AARCH64_OPT_EXTENSION("rdma", RDMA, (), (SIMD), (), "asimdrdm")
+
+AARCH64_OPT_EXTENSION("dotprod", DOTPROD, (SIMD), (), (), "asimddp")
+
+AARCH64_OPT_EXTENSION("aes", AES, (SIMD), (), (), "aes")
+
+AARCH64_OPT_EXTENSION("sha2", SHA2, (SIMD), (), (), "sha1 sha2")
+
+/* +nocrypto disables AES, SHA2 and SM4, and anything that depends on them
+   (such as SHA3 and the SVE2 crypto extensions).  */
+AARCH64_OPT_EXTENSION("crypto", CRYPTO, (AES, SHA2), (), (AES, SHA2, SM4),
 		      "aes pmull sha1 sha2")
 
-/* Enabling "sha3" enables "simd" and "sha2".
-   Disabling "sha3" disables "sha3" and "sve2-sha3".  */
-AARCH64_OPT_EXTENSION("sha3", AARCH64_FL_SHA3, AARCH64_FL_FPSIMD | \
-		      AARCH64_FL_SHA2, AARCH64_FL_SVE2_SHA3, false, \
-		      "sha3 sha512")
-
-/* Enabling "sm4" also enables "simd".
-   Disabling "sm4" disables "sm4" and "sve2-sm4".  */
-AARCH64_OPT_EXTENSION("sm4", AARCH64_FL_SM4, AARCH64_FL_FPSIMD, \
-		      AARCH64_FL_SVE2_SM4, false, "sm3 sm4")
-
-/* Enabling "fp16fml" also enables "fp" and "fp16".
-   Disabling "fp16fml" just disables "fp16fml".  */
-AARCH64_OPT_EXTENSION("fp16fml", AARCH64_FL_F16FML, \
-		      AARCH64_FL_FP | AARCH64_FL_F16, 0, false, "asimdfhm")
-
-/* Enabling "sve" also enables "fp16", "fp" and "simd".
-   Disabling "sve" disables "sve", "f32mm", "f64mm", "sve2", "sve2-aes",
-   "sve2-sha3", "sve2-sm4" and "sve2-bitperm".  */
-AARCH64_OPT_EXTENSION("sve", AARCH64_FL_SVE, AARCH64_FL_FP | AARCH64_FL_SIMD | \
-		      AARCH64_FL_F16, AARCH64_FL_F32MM | AARCH64_FL_F64MM | \
-		      AARCH64_FL_SVE2 | AARCH64_FL_SVE2_AES | \
-		      AARCH64_FL_SVE2_SHA3 | AARCH64_FL_SVE2_SM4 | \
-		      AARCH64_FL_SVE2_BITPERM, false, "sve")
-
-/* Enabling/Disabling "profile" does not enable/disable any other feature.  */
-AARCH64_OPT_EXTENSION("profile", AARCH64_FL_PROFILE, 0, 0, false, "")
-
-/* Enabling/Disabling "rng" only changes "rng".  */
-AARCH64_OPT_EXTENSION("rng", AARCH64_FL_RNG, 0, 0, false, "rng")
-
-/* Enabling/Disabling "memtag" only changes "memtag".  */
-AARCH64_OPT_EXTENSION("memtag", AARCH64_FL_MEMTAG, 0, 0, false, "")
-
-/* Enabling/Disabling "sb" only changes "sb".  */
-AARCH64_OPT_EXTENSION("sb", AARCH64_FL_SB, 0, 0, false, "sb")
-
-/* Enabling/Disabling "ssbs" only changes "ssbs".  */
-AARCH64_OPT_EXTENSION("ssbs", AARCH64_FL_SSBS, 0, 0, false, "ssbs")
-
-/* Enabling/Disabling "predres" only changes "predres".  */
-AARCH64_OPT_EXTENSION("predres", AARCH64_FL_PREDRES, 0, 0, false, "")
-
-/* Enabling "sve2" also enables "sve", "fp16", "fp", and "simd".
-   Disabling "sve2" disables "sve2", "sve2-aes", "sve2-sha3", "sve2-sm4", and
-   "sve2-bitperm".  */
-AARCH64_OPT_EXTENSION("sve2", AARCH64_FL_SVE2, AARCH64_FL_SVE | \
-		      AARCH64_FL_FP | AARCH64_FL_SIMD | AARCH64_FL_F16, \
-		      AARCH64_FL_SVE2_AES | AARCH64_FL_SVE2_SHA3 | \
-		      AARCH64_FL_SVE2_SM4 | AARCH64_FL_SVE2_BITPERM, false, "sve2")
-
-/* Enabling "sve2-sm4" also enables "sm4", "simd", "fp16", "fp", "sve", and
-   "sve2". Disabling "sve2-sm4" just disables "sve2-sm4".  */
-AARCH64_OPT_EXTENSION("sve2-sm4", AARCH64_FL_SVE2_SM4, AARCH64_FL_SM4 | \
-		      AARCH64_FL_SIMD | AARCH64_FL_F16 | AARCH64_FL_FP | \
-		      AARCH64_FL_SVE | AARCH64_FL_SVE2, 0, false, "svesm4")
-
-/* Enabling "sve2-aes" also enables "aes", "simd", "fp16", "fp", "sve", and
-   "sve2". Disabling "sve2-aes" just disables "sve2-aes".  */
-AARCH64_OPT_EXTENSION("sve2-aes", AARCH64_FL_SVE2_AES, AARCH64_FL_AES | \
-		      AARCH64_FL_SIMD | AARCH64_FL_F16 | AARCH64_FL_FP | \
-		      AARCH64_FL_SVE | AARCH64_FL_SVE2, 0, false, "sveaes")
-
-/* Enabling "sve2-sha3" also enables "sha3", "simd", "fp16", "fp", "sve", and
-   "sve2". Disabling "sve2-sha3" just disables "sve2-sha3".  */
-AARCH64_OPT_EXTENSION("sve2-sha3", AARCH64_FL_SVE2_SHA3, AARCH64_FL_SHA3 | \
-		      AARCH64_FL_SHA2 | \
-		      AARCH64_FL_SIMD | AARCH64_FL_F16 | AARCH64_FL_FP | \
-		      AARCH64_FL_SVE | AARCH64_FL_SVE2, 0, false, "svesha3")
-
-/* Enabling "sve2-bitperm" also enables "simd", "fp16", "fp", "sve", and
-   "sve2".  Disabling "sve2-bitperm" just disables "sve2-bitperm".  */
-AARCH64_OPT_EXTENSION("sve2-bitperm", AARCH64_FL_SVE2_BITPERM, AARCH64_FL_SIMD | \
-		      AARCH64_FL_F16 | AARCH64_FL_FP | AARCH64_FL_SVE | \
-		      AARCH64_FL_SVE2, 0, false, "svebitperm")
-
-/* Enabling or disabling "tme" only changes "tme".  */
-AARCH64_OPT_EXTENSION("tme", AARCH64_FL_TME, 0, 0, false, "")
-
-/* Enabling "i8mm" also enables "simd" and "fp".
-   Disabling "i8mm" only disables "i8mm".  */
-AARCH64_OPT_EXTENSION("i8mm", AARCH64_FL_I8MM, \
-		      AARCH64_FL_SIMD | AARCH64_FL_FP, 0, false, "i8mm")
-
-/* Enabling "f32mm" also enables "sve", "fp16", "fp", and "simd".
-   Disabling "f32mm" only disables "f32mm".  */
-AARCH64_OPT_EXTENSION("f32mm", AARCH64_FL_F32MM, \
-		      AARCH64_FL_SVE | AARCH64_FL_F16 | AARCH64_FL_FP | \
-		      AARCH64_FL_SIMD, 0, false, "f32mm")
-
-/* Enabling "f64mm" also enables "sve", "fp16", "fp", and "simd".
-   Disabling "f64mm" only disables "f64mm".  */
-AARCH64_OPT_EXTENSION("f64mm", AARCH64_FL_F64MM, \
-		      AARCH64_FL_SVE | AARCH64_FL_F16 | AARCH64_FL_FP | \
-		      AARCH64_FL_SIMD, 0, false, "f64mm")
-
-/* Enabling "bf16" also enables "simd" and "fp".
-   Disabling "bf16" only disables "bf16".  */
-AARCH64_OPT_EXTENSION("bf16", AARCH64_FL_BF16, \
-		      AARCH64_FL_SIMD | AARCH64_FL_FP, 0, false, "bf16")
-
-/* Enabling/Disabling "flagm" only changes "flagm".  */
-AARCH64_OPT_EXTENSION("flagm", AARCH64_FL_FLAGM, 0, 0, false, "flagm")
-
-/* Enabling/Disabling "pauth" only changes "pauth".  */
-AARCH64_OPT_EXTENSION("pauth", AARCH64_FL_PAUTH, 0, 0, false, "paca pacg")
-
-/* Enabling/Disabling "ls64" only changes "ls64".  */
-AARCH64_OPT_EXTENSION("ls64", AARCH64_FL_LS64, 0, 0, false, "")
-
-/* Enabling/disabling "mops" only changes "mops".  */
-AARCH64_OPT_EXTENSION("mops", AARCH64_FL_MOPS, 0, 0, false, "")
+AARCH64_OPT_EXTENSION("sha3", SHA3, (SHA2), (), (), "sha3 sha512")
+
+AARCH64_OPT_EXTENSION("sm4", SM4, (SIMD), (), (), "sm3 sm4")
+
+/* An explicit +fp16fml implies +fp16, but a dependence on it does not.
+   Thus -march=armv8.4-a implies F16FML but not F16.  -march=armv8.4-a+fp16
+   and -march=armv8.4-a+fp16fml are equivalent and enable both F16FML and F16.
+   -march=armv8.4-a+nofp16+fp16 enables F16 but not F16FML.  */
+AARCH64_OPT_EXTENSION("fp16fml", F16FML, (), (F16), (), "asimdfhm")
+
+AARCH64_OPT_EXTENSION("sve", SVE, (SIMD, F16), (), (), "sve")
+
+AARCH64_OPT_EXTENSION("profile", PROFILE, (), (), (), "")
+
+AARCH64_OPT_EXTENSION("rng", RNG, (), (), (), "rng")
+
+AARCH64_OPT_EXTENSION("memtag", MEMTAG, (), (), (), "")
+
+AARCH64_OPT_EXTENSION("sb", SB, (), (), (), "sb")
+
+AARCH64_OPT_EXTENSION("ssbs", SSBS, (), (), (), "ssbs")
+
+AARCH64_OPT_EXTENSION("predres", PREDRES, (), (), (), "")
+
+AARCH64_OPT_EXTENSION("sve2", SVE2, (SVE), (), (), "sve2")
+
+AARCH64_OPT_EXTENSION("sve2-sm4", SVE2_SM4, (SVE2, SM4), (), (), "svesm4")
+
+AARCH64_OPT_EXTENSION("sve2-aes", SVE2_AES, (SVE2, AES), (), (), "sveaes")
+
+AARCH64_OPT_EXTENSION("sve2-sha3", SVE2_SHA3, (SVE2, SHA3), (), (), "svesha3")
+
+AARCH64_OPT_EXTENSION("sve2-bitperm", SVE2_BITPERM, (SVE2), (), (),
+		      "svebitperm")
+
+AARCH64_OPT_EXTENSION("tme", TME, (), (), (), "")
+
+AARCH64_OPT_EXTENSION("i8mm", I8MM, (SIMD), (), (), "i8mm")
+
+AARCH64_OPT_EXTENSION("f32mm", F32MM, (SVE), (), (), "f32mm")
+
+AARCH64_OPT_EXTENSION("f64mm", F64MM, (SVE), (), (), "f64mm")
+
+/* An explicit +bf16 implies +simd, but +bf16+nosimd still enables scalar BF16
+   instructions.  */
+AARCH64_OPT_EXTENSION("bf16", BF16, (FP), (SIMD), (), "bf16")
+
+AARCH64_OPT_EXTENSION("flagm", FLAGM, (), (), (), "flagm")
+
+AARCH64_OPT_EXTENSION("pauth", PAUTH, (), (), (), "paca pacg")
+
+AARCH64_OPT_EXTENSION("ls64", LS64, (), (), (), "")
+
+AARCH64_OPT_EXTENSION("mops", MOPS, (), (), (), "")
 
 #undef AARCH64_OPT_EXTENSION
diff --git a/gcc/config/aarch64/aarch64-opts.h b/gcc/config/aarch64/aarch64-opts.h
index 421648a156a..ba23c90c411 100644
--- a/gcc/config/aarch64/aarch64-opts.h
+++ b/gcc/config/aarch64/aarch64-opts.h
@@ -22,6 +22,10 @@
 #ifndef GCC_AARCH64_OPTS_H
 #define GCC_AARCH64_OPTS_H
 
+#ifndef USED_FOR_TARGET
+typedef uint64_t aarch64_feature_flags;
+#endif
+
 /* The various cores that implement AArch64.  */
 enum aarch64_processor
 {
diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc
index 12d9beee4da..c06e99339e3 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins.cc
@@ -701,9 +701,8 @@ check_required_extensions (location_t location, tree fndecl,
     return check_required_registers (location, fndecl);
 
   static const struct { uint64_t flag; const char *name; } extensions[] = {
-#define AARCH64_OPT_EXTENSION(EXT_NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, \
-			      SYNTHETIC, FEATURE_STRING) \
-    { FLAG_CANONICAL, EXT_NAME },
+#define AARCH64_OPT_EXTENSION(EXT_NAME, IDENT, C, D, E, F) \
+    { AARCH64_FL_##IDENT, EXT_NAME },
 #include "aarch64-option-extensions.def"
   };
 
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index a5c48514adc..398232433ce 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -81,6 +81,7 @@
 #include "rtlanal.h"
 #include "tree-dfa.h"
 #include "asan.h"
+#include "aarch64-feature-deps.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -2681,8 +2682,9 @@ struct processor
 /* Architectures implementing AArch64.  */
 static const struct processor all_architectures[] =
 {
-#define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH_REV, FLAGS) \
-  {NAME, CORE, CORE, AARCH64_ARCH_##ARCH_IDENT, FLAGS, NULL},
+#define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, D, E) \
+  {NAME, CORE, CORE, AARCH64_ARCH_##ARCH_IDENT, \
+   feature_deps::ARCH_IDENT ().enable, NULL},
 #include "aarch64-arches.def"
   {NULL, aarch64_none, aarch64_none, aarch64_no_arch, 0, NULL}
 };
@@ -2690,12 +2692,12 @@ static const struct processor all_architectures[] =
 /* Processor cores implementing AArch64.  */
 static const struct processor all_cores[] =
 {
-#define AARCH64_CORE(NAME, IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART, VARIANT) \
-  {NAME, IDENT, SCHED, AARCH64_ARCH_##ARCH,				\
-  AARCH64_FL_FOR_##ARCH | FLAGS, &COSTS##_tunings},
+#define AARCH64_CORE(NAME, IDENT, SCHED, ARCH, E, COSTS, G, H, I) \
+  {NAME, IDENT, SCHED, AARCH64_ARCH_##ARCH, \
+   feature_deps::cpu_##IDENT, &COSTS##_tunings},
 #include "aarch64-cores.def"
   {"generic", generic, cortexa53, AARCH64_ARCH_V8A,
-    AARCH64_FL_FOR_V8A, &generic_tunings},
+   feature_deps::V8A ().enable, &generic_tunings},
   {NULL, aarch64_none, aarch64_none, aarch64_no_arch, 0, NULL}
 };
 
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index 8ea8e2a3913..97da721d094 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -144,149 +144,27 @@
 
 #define PCC_BITFIELD_TYPE_MATTERS	1
 
-/* Instruction tuning/selection flags.  */
-
-/* Bit values used to identify processor capabilities.  */
-#define AARCH64_FL_SIMD       (1 << 0)	/* Has SIMD instructions.  */
-#define AARCH64_FL_FP         (1 << 1)	/* Has FP.  */
-#define AARCH64_FL_CRYPTO     (1 << 2)	/* Has crypto.  */
-#define AARCH64_FL_CRC        (1 << 3)	/* Has CRC.  */
-/* ARMv8.1-A architecture extensions.  */
-#define AARCH64_FL_LSE	      (1 << 4)  /* Has Large System Extensions.  */
-#define AARCH64_FL_RDMA       (1 << 5)  /* Has Round Double Multiply Add.  */
-#define AARCH64_FL_V8_1A      (1 << 6)  /* Has ARMv8.1-A extensions.  */
-/* Armv8-R.  */
-#define AARCH64_FL_V8R        (1 << 7)  /* Armv8-R AArch64.  */
-/* ARMv8.2-A architecture extensions.  */
-#define AARCH64_FL_V8_2A      (1 << 8)  /* Has ARMv8.2-A features.  */
-#define AARCH64_FL_F16	      (1 << 9)  /* Has ARMv8.2-A FP16 extensions.  */
-#define AARCH64_FL_SVE        (1 << 10) /* Has Scalable Vector Extensions.  */
-/* ARMv8.3-A architecture extensions.  */
-#define AARCH64_FL_V8_3A      (1 << 11)  /* Has ARMv8.3-A features.  */
-#define AARCH64_FL_RCPC       (1 << 12)  /* Has support for RCpc model.  */
-#define AARCH64_FL_DOTPROD    (1 << 13)  /* Has ARMv8.2-A Dot Product ins.  */
-/* New flags to split crypto into aes and sha2.  */
-#define AARCH64_FL_AES	      (1 << 14)  /* Has Crypto AES.  */
-#define AARCH64_FL_SHA2	      (1 << 15)  /* Has Crypto SHA2.  */
-/* ARMv8.4-A architecture extensions.  */
-#define AARCH64_FL_V8_4A      (1 << 16)  /* Has ARMv8.4-A features.  */
-#define AARCH64_FL_SM4	      (1 << 17)  /* Has ARMv8.4-A SM3 and SM4.  */
-#define AARCH64_FL_SHA3	      (1 << 18)  /* Has ARMv8.4-a SHA3 and SHA512.  */
-#define AARCH64_FL_F16FML     (1 << 19)  /* Has ARMv8.4-a FP16 extensions.  */
-
-/* Statistical Profiling extensions.  */
-#define AARCH64_FL_PROFILE    (1 << 21)
-
-/* ARMv8.5-A architecture extensions.  */
-#define AARCH64_FL_V8_5A      (1 << 22)  /* Has ARMv8.5-A features.  */
-#define AARCH64_FL_RNG	      (1 << 23)  /* ARMv8.5-A Random Number Insns.  */
-#define AARCH64_FL_MEMTAG     (1 << 24)  /* ARMv8.5-A Memory Tagging
-					    Extensions.  */
-
-/* Speculation Barrier instruction supported.  */
-#define AARCH64_FL_SB	      (1 << 25)
-
-/* Speculative Store Bypass Safe instruction supported.  */
-#define AARCH64_FL_SSBS	      (1 << 26)
-
-/* Execution and Data Prediction Restriction instructions supported.  */
-#define AARCH64_FL_PREDRES    (1 << 27)
-
-/* SVE2 instruction supported.  */
-#define AARCH64_FL_SVE2		(1 << 28)
-#define AARCH64_FL_SVE2_AES	(1 << 29)
-#define AARCH64_FL_SVE2_SM4	(1 << 30)
-#define AARCH64_FL_SVE2_SHA3	(1ULL << 31)
-#define AARCH64_FL_SVE2_BITPERM	(1ULL << 32)
-
-/* Transactional Memory Extension.  */
-#define AARCH64_FL_TME	      (1ULL << 33)  /* Has TME instructions.  */
-
-/* Armv8.6-A architecture extensions.  */
-#define AARCH64_FL_V8_6A      (1ULL << 34)
-
-/* 8-bit Integer Matrix Multiply (I8MM) extensions.  */
-#define AARCH64_FL_I8MM	      (1ULL << 35)
-
-/* Brain half-precision floating-point (BFloat16) Extension.  */
-#define AARCH64_FL_BF16	      (1ULL << 36)
-
-/* 32-bit Floating-point Matrix Multiply (F32MM) extensions.  */
-#define AARCH64_FL_F32MM      (1ULL << 37)
-
-/* 64-bit Floating-point Matrix Multiply (F64MM) extensions.  */
-#define AARCH64_FL_F64MM      (1ULL << 38)
-
-/* Flag Manipulation Instructions (FLAGM) extension.  */
-#define AARCH64_FL_FLAGM      (1ULL << 39)
-
-/* Pointer Authentication (PAUTH) extension.  */
-#define AARCH64_FL_PAUTH      (1ULL << 40)
-
-/* Armv9.0-A.  */
-#define AARCH64_FL_V9A        (1ULL << 41)  /* Armv9.0-A Architecture.  */
-
-/* 64-byte atomic load/store extensions.  */
-#define AARCH64_FL_LS64      (1ULL << 42)
-
-/* Armv8.7-a architecture extensions.  */
-#define AARCH64_FL_V8_7A      (1ULL << 43)
-
-/* Hardware memory operation instructions.  */
-#define AARCH64_FL_MOPS       (1ULL << 44)
-
-/* Armv8.8-a architecture extensions.  */
-#define AARCH64_FL_V8_8A      (1ULL << 45)
-
-/* Armv9.1-A.  */
-#define AARCH64_FL_V9_1A      (1ULL << 46)
-
-/* Armv9.2-A.  */
-#define AARCH64_FL_V9_2A      (1ULL << 47)
-
-/* Armv9.3-A.  */
-#define AARCH64_FL_V9_3A      (1ULL << 48)
-
-/* Has FP and SIMD.  */
-#define AARCH64_FL_FPSIMD     (AARCH64_FL_FP | AARCH64_FL_SIMD)
-
-/* Has FP without SIMD.  */
-#define AARCH64_FL_FPQ16      (AARCH64_FL_FP & ~AARCH64_FL_SIMD)
-
-/* Architecture flags that effect instruction selection.  */
-#define AARCH64_FL_FOR_V8A       (AARCH64_FL_FPSIMD)
-#define AARCH64_FL_FOR_V8_1A			       \
-  (AARCH64_FL_FOR_V8A | AARCH64_FL_LSE | AARCH64_FL_CRC \
-   | AARCH64_FL_RDMA | AARCH64_FL_V8_1A)
-#define AARCH64_FL_FOR_V8_2A			\
-  (AARCH64_FL_FOR_V8_1A | AARCH64_FL_V8_2A)
-#define AARCH64_FL_FOR_V8_3A			\
-  (AARCH64_FL_FOR_V8_2A | AARCH64_FL_V8_3A | AARCH64_FL_PAUTH)
-#define AARCH64_FL_FOR_V8_4A			\
-  (AARCH64_FL_FOR_V8_3A | AARCH64_FL_V8_4A | AARCH64_FL_F16FML \
-   | AARCH64_FL_DOTPROD | AARCH64_FL_FLAGM)
-#define AARCH64_FL_FOR_V8_5A			\
-  (AARCH64_FL_FOR_V8_4A | AARCH64_FL_V8_5A	\
-   | AARCH64_FL_SB | AARCH64_FL_SSBS | AARCH64_FL_PREDRES)
-#define AARCH64_FL_FOR_V8_6A			\
-  (AARCH64_FL_FOR_V8_5A | AARCH64_FL_V8_6A | AARCH64_FL_FPSIMD \
-   | AARCH64_FL_I8MM | AARCH64_FL_BF16)
-#define AARCH64_FL_FOR_V8_7A			\
-  (AARCH64_FL_FOR_V8_6A | AARCH64_FL_V8_7A | AARCH64_FL_LS64)
-#define AARCH64_FL_FOR_V8_8A			\
-  (AARCH64_FL_FOR_V8_7A | AARCH64_FL_V8_8A | AARCH64_FL_MOPS)
-
-#define AARCH64_FL_FOR_V8R     \
-  (AARCH64_FL_FOR_V8_4A | AARCH64_FL_V8R)
-#define AARCH64_FL_FOR_V9A       \
-  (AARCH64_FL_FOR_V8_5A | AARCH64_FL_SVE | AARCH64_FL_SVE2 | AARCH64_FL_V9A \
-   | AARCH64_FL_F16)
-#define AARCH64_FL_FOR_V9_1A	\
-  (AARCH64_FL_FOR_V9A | AARCH64_FL_FOR_V8_6A | AARCH64_FL_V9_1A)
-#define AARCH64_FL_FOR_V9_2A	\
-  (AARCH64_FL_FOR_V9_1A | AARCH64_FL_FOR_V8_7A | AARCH64_FL_V9_2A)
-#define AARCH64_FL_FOR_V9_3A	\
-  (AARCH64_FL_FOR_V9_2A | AARCH64_FL_FOR_V8_8A | AARCH64_FL_V9_3A)
+#ifndef USED_FOR_TARGET
+
+/* Define an enum of all features (architectures and extensions).  */
+enum class aarch64_feature : unsigned char {
+#define AARCH64_OPT_EXTENSION(A, IDENT, C, D, E, F) IDENT,
+#define AARCH64_ARCH(A, B, IDENT, D, E) IDENT,
+#include "aarch64-option-extensions.def"
+#include "aarch64-arches.def"
+};
+
+/* Define unique flags for each of the above.  */
+#define HANDLE(IDENT) \
+  constexpr auto AARCH64_FL_##IDENT \
+    = aarch64_feature_flags (1) << int (aarch64_feature::IDENT);
+#define AARCH64_OPT_EXTENSION(A, IDENT, C, D, E, F) HANDLE (IDENT)
+#define AARCH64_ARCH(A, B, IDENT, D, E) HANDLE (IDENT)
+#include "aarch64-option-extensions.def"
+#include "aarch64-arches.def"
+#undef HANDLE
+
+#endif
 
 /* Macros to test ISA flags.  */
 
diff --git a/gcc/config/aarch64/driver-aarch64.cc b/gcc/config/aarch64/driver-aarch64.cc
index 2d74964ea47..1c86d62ef80 100644
--- a/gcc/config/aarch64/driver-aarch64.cc
+++ b/gcc/config/aarch64/driver-aarch64.cc
@@ -26,6 +26,7 @@
 #include "coretypes.h"
 #include "tm.h"
 #include "aarch64-protos.h"
+#include "aarch64-feature-deps.h"
 
 struct aarch64_arch_extension
 {
@@ -34,9 +35,8 @@ struct aarch64_arch_extension
   const char *feat_string;
 };
 
-#define AARCH64_OPT_EXTENSION(EXT_NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, \
-			      SYNTHETIC, FEATURE_STRING) \
-  { EXT_NAME, FLAG_CANONICAL, FEATURE_STRING },
+#define AARCH64_OPT_EXTENSION(EXT_NAME, IDENT, C, D, E, FEATURE_STRING) \
+  { EXT_NAME, AARCH64_FL_##IDENT, FEATURE_STRING },
 static struct aarch64_arch_extension aarch64_extensions[] =
 {
 #include "aarch64-option-extensions.def"
@@ -62,7 +62,7 @@ struct aarch64_core_data
 #define DEFAULT_ARCH "8A"
 
 #define AARCH64_CORE(CORE_NAME, CORE_IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART, VARIANT) \
-  { CORE_NAME, #ARCH, IMP, PART, VARIANT, AARCH64_FL_FOR_##ARCH | FLAGS },
+  { CORE_NAME, #ARCH, IMP, PART, VARIANT, feature_deps::cpu_##CORE_IDENT },
 
 static struct aarch64_core_data aarch64_cpu_data[] =
 {
@@ -80,7 +80,7 @@ struct aarch64_arch_driver_info
 
 /* Skip the leading "V" in the architecture name.  */
 #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH_REV, FLAGS) \
-  { #ARCH_IDENT + 1, NAME, FLAGS },
+  { #ARCH_IDENT + 1, NAME, feature_deps::ARCH_IDENT ().enable },
 
 static struct aarch64_arch_driver_info aarch64_arches[] =
 {
