diff mbox

[04/30,arm] Allow +opt on arbitrary cpu and architecture specifications

Message ID 229e7552-4d9f-027a-4d53-9f30535d56db@arm.com
State New
Headers show

Commit Message

Richard Earnshaw (lists) June 13, 2017, 5:14 p.m. UTC
On 09/06/17 13:53, Richard Earnshaw wrote:
> 
> This is the main patch to provide the infrastructure for adding
> feature extensions to CPU and architecture specifications.  It does not,
> however, add all the extensions that we intend to support (just a small
> number to permit some basic testing).  Now, instead of having specific
> entries in the architecture table for variants such as armv8-a+crc, the
> crc extension is specified as an optional component of the armv8-a
> architecture entry.  Similar control can be added to CPU option names.
> In both cases the list of permitted options is controlled by the main
> architecture or CPU name to prevent arbitrary cross-products of options.
> 
> 	* config/arm/arm-cpus.in (armv8-a): Add options crc, simd crypto and
> 	nofp.
> 	(armv8-a+crc): Delete.
> 	(armv8.1-a): Add options simd, crypto and nofp.
> 	(armv8.2-a): Add options fp16, simd, crypto and nofp.
> 	(armv8.2-a+fp16): Delete.
> 	(armv8-m.main): Add option dsp.
> 	(armv8-m.main+dsp): Delete.
> 	(cortex-a8): Add fpu.  Add nofp option.
> 	(cortex-a9): Add fpu.  Add nofp and nosimd options.
> 	* config/arm/parsecpu.awk (gen_data): Generate option tables and
> 	link to main cpu and architecture data structures.
> 	(gen_comm_data): Only put isa attributes from the main architecture
> 	in common tables.
> 	(option): New statement for architecture and CPU entries.
> 	* arm.c (struct cpu_option): New structure.
> 	(struct processors): Add entry for options.
> 	(arm_unrecognized_feature): New function.
> 	(arm_parse_arch_cpu_name): Ignore any characters after the first
> 	'+' character.
> 	(arm_parse_arch_cpu_feature): New function.
> 	(arm_configure_build_target): Separate out any CPU and architecture
> 	features and parse separately.  Don't error out if -mfpu=auto is
> 	used with only an architecture string.
> 	(arm_print_asm_arch_directives): New function.
> 	(arm_file_start): Call it.
> 	* config/arm/arm-cpu-cdata.h: Regenerated.
> 	* config/arm/arm-cpu-data.h: Likewise.
> 	* config/arm/arm-tables.opt: Likewise.
> ---
>  gcc/config/arm/arm-cpu-cdata.h |  51 +++----
>  gcc/config/arm/arm-cpu-data.h  | 305 ++++++++++++++++++++++++++++++++++-------
>  gcc/config/arm/arm-cpus.in     |  39 +++---
>  gcc/config/arm/arm-tables.opt  |  21 +--
>  gcc/config/arm/arm.c           | 191 +++++++++++++++++++++-----
>  gcc/config/arm/parsecpu.awk    | 110 +++++++++++++--
>  6 files changed, 555 insertions(+), 162 deletions(-)
> 

Updated with typo corrected.
diff mbox

Patch

diff --git a/gcc/config/arm/arm-cpu-cdata.h b/gcc/config/arm/arm-cpu-cdata.h
index b388812..878d226 100644
--- a/gcc/config/arm/arm-cpu-cdata.h
+++ b/gcc/config/arm/arm-cpu-cdata.h
@@ -577,6 +577,7 @@  static const struct arm_arch_core_flag arm_arch_core_flags[] =
     "cortex-a8",
     {
       ISA_ARMv7a,
+      ISA_VFPv3,ISA_NEON,
       isa_nobit
     },
   },
@@ -584,6 +585,7 @@  static const struct arm_arch_core_flag arm_arch_core_flags[] =
     "cortex-a9",
     {
       ISA_ARMv7a,
+      ISA_VFPv3,ISA_NEON,
       isa_nobit
     },
   },
@@ -693,63 +695,63 @@  static const struct arm_arch_core_flag arm_arch_core_flags[] =
   {
     "cortex-a32",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
   {
     "cortex-a35",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
   {
     "cortex-a53",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
   {
     "cortex-a57",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
   {
     "cortex-a72",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
   {
     "cortex-a73",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
   {
     "exynos-m1",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
   {
     "falkor",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
   {
     "qdf24xx",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
@@ -763,28 +765,28 @@  static const struct arm_arch_core_flag arm_arch_core_flags[] =
   {
     "cortex-a57.cortex-a53",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
   {
     "cortex-a72.cortex-a53",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
   {
     "cortex-a73.cortex-a35",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
   {
     "cortex-a73.cortex-a53",
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
       isa_nobit
     },
   },
@@ -798,7 +800,7 @@  static const struct arm_arch_core_flag arm_arch_core_flags[] =
   {
     "cortex-m33",
     {
-      ISA_ARMv8m_main,isa_bit_ARMv7em,
+      ISA_ARMv8m_main,
       isa_nobit
     },
   },
@@ -992,13 +994,6 @@  static const struct arm_arch_core_flag arm_arch_core_flags[] =
     },
   },
   {
-    "armv8-a+crc",
-    {
-      ISA_ARMv8a,isa_bit_crc32,
-      isa_nobit
-    },
-  },
-  {
     "armv8.1-a",
     {
       ISA_ARMv8_1a,
@@ -1013,13 +1008,6 @@  static const struct arm_arch_core_flag arm_arch_core_flags[] =
     },
   },
   {
-    "armv8.2-a+fp16",
-    {
-      ISA_ARMv8_2a,isa_bit_fp16,
-      isa_nobit
-    },
-  },
-  {
     "armv8-m.base",
     {
       ISA_ARMv8m_base,
@@ -1034,13 +1022,6 @@  static const struct arm_arch_core_flag arm_arch_core_flags[] =
     },
   },
   {
-    "armv8-m.main+dsp",
-    {
-      ISA_ARMv8m_main,isa_bit_ARMv7em,
-      isa_nobit
-    },
-  },
-  {
     "iwmmxt",
     {
       ISA_ARMv5te,isa_bit_xscale,isa_bit_iwmmxt,
diff --git a/gcc/config/arm/arm-cpu-data.h b/gcc/config/arm/arm-cpu-data.h
index 8d47e7c..e9b7132 100644
--- a/gcc/config/arm/arm-cpu-data.h
+++ b/gcc/config/arm/arm-cpu-data.h
@@ -20,6 +20,26 @@ 
    License along with GCC; see the file COPYING3.  If not see
    <http://www.gnu.org/licenses/>.  */
 
+static const struct cpu_option cpu_opttab_cortexa8[] = {
+  {
+    "nofp", true,
+    { ISA_NEON,ISA_VFPv3, isa_nobit }
+  },
+  { NULL, false, {isa_nobit}}
+};
+
+static const struct cpu_option cpu_opttab_cortexa9[] = {
+  {
+    "nofp", true,
+    { ISA_NEON,ISA_VFPv3, isa_nobit }
+  },
+  {
+    "nosimd", true,
+    { ISA_NEON, isa_nobit }
+  },
+  { NULL, false, {isa_nobit}}
+};
+
 static const struct processors all_cores[] =
 {
   {
@@ -31,6 +51,7 @@  static const struct processors all_cores[] =
       ISA_ARMv2,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -42,6 +63,7 @@  static const struct processors all_cores[] =
       ISA_ARMv2,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -53,6 +75,7 @@  static const struct processors all_cores[] =
       ISA_ARMv2,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -64,6 +87,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -75,6 +99,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -86,6 +111,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -97,6 +123,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -108,6 +135,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -119,6 +147,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -130,6 +159,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -141,6 +171,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -152,6 +183,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -163,6 +195,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -174,6 +207,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -185,6 +219,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -196,6 +231,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -207,6 +243,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -218,6 +255,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -229,6 +267,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -240,6 +279,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_slowmul_tune
   },
   {
@@ -251,6 +291,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3m,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -262,6 +303,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3m,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -273,6 +315,7 @@  static const struct processors all_cores[] =
       ISA_ARMv3m,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -284,6 +327,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -295,6 +339,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -306,6 +351,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_strongarm_tune
   },
   {
@@ -317,6 +363,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_strongarm_tune
   },
   {
@@ -328,6 +375,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_strongarm_tune
   },
   {
@@ -339,6 +387,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_strongarm_tune
   },
   {
@@ -350,6 +399,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -361,6 +411,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -372,6 +423,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -383,6 +435,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -394,6 +447,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -405,6 +459,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -416,6 +471,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -427,6 +483,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -438,6 +495,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -449,6 +507,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -460,6 +519,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -471,6 +531,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -482,6 +543,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -493,6 +555,7 @@  static const struct processors all_cores[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -504,6 +567,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -515,6 +579,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5t,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -526,6 +591,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -537,6 +603,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -548,6 +615,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -559,6 +627,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -570,6 +639,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -581,6 +651,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -592,6 +663,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     &arm_fastmul_tune
   },
   {
@@ -604,6 +676,7 @@  static const struct processors all_cores[] =
       isa_bit_xscale,
       isa_nobit
     },
+    NULL,
     &arm_xscale_tune
   },
   {
@@ -615,6 +688,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,isa_bit_xscale,isa_bit_iwmmxt,
       isa_nobit
     },
+    NULL,
     &arm_xscale_tune
   },
   {
@@ -626,6 +700,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,isa_bit_xscale,isa_bit_iwmmxt,isa_bit_iwmmxt2,
       isa_nobit
     },
+    NULL,
     &arm_xscale_tune
   },
   {
@@ -637,6 +712,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -648,6 +724,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -659,6 +736,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -670,6 +748,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     &arm_fa726te_tune
   },
   {
@@ -681,6 +760,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5tej,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -692,6 +772,7 @@  static const struct processors all_cores[] =
       ISA_ARMv5tej,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -703,6 +784,7 @@  static const struct processors all_cores[] =
       ISA_ARMv6j,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -715,6 +797,7 @@  static const struct processors all_cores[] =
       ISA_VFPv2,ISA_FP_DBL,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -726,6 +809,7 @@  static const struct processors all_cores[] =
       ISA_ARMv6kz,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -738,6 +822,7 @@  static const struct processors all_cores[] =
       ISA_VFPv2,ISA_FP_DBL,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -749,6 +834,7 @@  static const struct processors all_cores[] =
       ISA_ARMv6k,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -761,6 +847,7 @@  static const struct processors all_cores[] =
       ISA_VFPv2,ISA_FP_DBL,
       isa_nobit
     },
+    NULL,
     &arm_9e_tune
   },
   {
@@ -772,6 +859,7 @@  static const struct processors all_cores[] =
       ISA_ARMv6t2,
       isa_nobit
     },
+    NULL,
     &arm_v6t2_tune
   },
   {
@@ -784,6 +872,7 @@  static const struct processors all_cores[] =
       ISA_VFPv2,ISA_FP_DBL,
       isa_nobit
     },
+    NULL,
     &arm_v6t2_tune
   },
   {
@@ -795,6 +884,7 @@  static const struct processors all_cores[] =
       ISA_ARMv6m,
       isa_nobit
     },
+    NULL,
     &arm_v6m_tune
   },
   {
@@ -806,6 +896,7 @@  static const struct processors all_cores[] =
       ISA_ARMv6m,
       isa_nobit
     },
+    NULL,
     &arm_v6m_tune
   },
   {
@@ -817,6 +908,7 @@  static const struct processors all_cores[] =
       ISA_ARMv6m,
       isa_nobit
     },
+    NULL,
     &arm_v6m_tune
   },
   {
@@ -828,6 +920,7 @@  static const struct processors all_cores[] =
       ISA_ARMv6m,
       isa_nobit
     },
+    NULL,
     &arm_v6m_tune
   },
   {
@@ -839,6 +932,7 @@  static const struct processors all_cores[] =
       ISA_ARMv6m,
       isa_nobit
     },
+    NULL,
     &arm_v6m_tune
   },
   {
@@ -850,6 +944,7 @@  static const struct processors all_cores[] =
       ISA_ARMv6m,
       isa_nobit
     },
+    NULL,
     &arm_v6m_tune
   },
   {
@@ -861,6 +956,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7a,
       isa_nobit
     },
+    NULL,
     &arm_cortex_tune
   },
   {
@@ -872,6 +968,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7a,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a5_tune
   },
   {
@@ -883,6 +980,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7ve,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a7_tune
   },
   {
@@ -892,8 +990,10 @@  static const struct processors all_cores[] =
     "7A", BASE_ARCH_7A,
     {
       ISA_ARMv7a,
+      ISA_VFPv3,ISA_NEON,
       isa_nobit
     },
+    cpu_opttab_cortexa8,
     &arm_cortex_a8_tune
   },
   {
@@ -903,8 +1003,10 @@  static const struct processors all_cores[] =
     "7A", BASE_ARCH_7A,
     {
       ISA_ARMv7a,
+      ISA_VFPv3,ISA_NEON,
       isa_nobit
     },
+    cpu_opttab_cortexa9,
     &arm_cortex_a9_tune
   },
   {
@@ -916,6 +1018,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7ve,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a12_tune
   },
   {
@@ -927,6 +1030,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7ve,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a15_tune
   },
   {
@@ -938,6 +1042,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7ve,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a12_tune
   },
   {
@@ -949,6 +1054,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7r,
       isa_nobit
     },
+    NULL,
     &arm_cortex_tune
   },
   {
@@ -960,6 +1066,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7r,
       isa_nobit
     },
+    NULL,
     &arm_cortex_tune
   },
   {
@@ -972,6 +1079,7 @@  static const struct processors all_cores[] =
       isa_bit_adiv,
       isa_nobit
     },
+    NULL,
     &arm_cortex_tune
   },
   {
@@ -984,6 +1092,7 @@  static const struct processors all_cores[] =
       isa_bit_adiv,
       isa_nobit
     },
+    NULL,
     &arm_cortex_tune
   },
   {
@@ -996,6 +1105,7 @@  static const struct processors all_cores[] =
       isa_bit_adiv,
       isa_nobit
     },
+    NULL,
     &arm_cortex_tune
   },
   {
@@ -1008,6 +1118,7 @@  static const struct processors all_cores[] =
       isa_quirk_no_volatile_ce,
       isa_nobit
     },
+    NULL,
     &arm_cortex_m7_tune
   },
   {
@@ -1019,6 +1130,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7em,
       isa_nobit
     },
+    NULL,
     &arm_v7m_tune
   },
   {
@@ -1031,6 +1143,7 @@  static const struct processors all_cores[] =
       isa_quirk_cm3_ldrd,
       isa_nobit
     },
+    NULL,
     &arm_v7m_tune
   },
   {
@@ -1042,6 +1155,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7a,
       isa_nobit
     },
+    NULL,
     &arm_marvell_pj4_tune
   },
   {
@@ -1053,6 +1167,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7ve,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a15_tune
   },
   {
@@ -1064,6 +1179,7 @@  static const struct processors all_cores[] =
       ISA_ARMv7ve,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a12_tune
   },
   {
@@ -1072,9 +1188,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a35_tune
   },
   {
@@ -1083,9 +1201,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a35_tune
   },
   {
@@ -1094,9 +1214,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a53_tune
   },
   {
@@ -1105,9 +1227,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a57_tune
   },
   {
@@ -1116,9 +1240,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a57_tune
   },
   {
@@ -1127,9 +1253,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a73_tune
   },
   {
@@ -1138,9 +1266,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_exynosm1_tune
   },
   {
@@ -1149,9 +1279,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_qdf24xx_tune
   },
   {
@@ -1160,9 +1292,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_qdf24xx_tune
   },
   {
@@ -1174,6 +1308,7 @@  static const struct processors all_cores[] =
       ISA_ARMv8a,
       isa_nobit
     },
+    NULL,
     &arm_xgene1_tune
   },
   {
@@ -1182,9 +1317,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a57_tune
   },
   {
@@ -1193,9 +1330,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a57_tune
   },
   {
@@ -1204,9 +1343,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a73_tune
   },
   {
@@ -1215,9 +1356,11 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8A", BASE_ARCH_8A,
     {
-      ISA_ARMv8a,isa_bit_crc32,
+      ISA_ARMv8a,
+      isa_bit_crc32,
       isa_nobit
     },
+    NULL,
     &arm_cortex_a73_tune
   },
   {
@@ -1229,6 +1372,7 @@  static const struct processors all_cores[] =
       ISA_ARMv8m_base,
       isa_nobit
     },
+    NULL,
     &arm_v6m_tune
   },
   {
@@ -1237,12 +1381,78 @@  static const struct processors all_cores[] =
     (TF_LDSCHED),
     "8M_MAIN", BASE_ARCH_8M_MAIN,
     {
-      ISA_ARMv8m_main,isa_bit_ARMv7em,
+      ISA_ARMv8m_main,
+      isa_bit_ARMv7em,
       isa_nobit
     },
+    NULL,
     &arm_v7m_tune
   },
-  {NULL, TARGET_CPU_arm_none, 0, NULL, BASE_ARCH_0, {isa_nobit}, NULL}
+  {NULL, TARGET_CPU_arm_none, 0, NULL, BASE_ARCH_0, {isa_nobit}, NULL, NULL}
+};
+
+static const struct cpu_option arch_opttab_armv8_a[] = {
+  {
+    "crc", false,
+    { isa_bit_crc32, isa_nobit }
+  },
+  {
+    "simd", false,
+    { ISA_FP_ARMv8,ISA_NEON, isa_nobit }
+  },
+  {
+    "crypto", false,
+    { ISA_FP_ARMv8,ISA_NEON,ISA_CRYPTO, isa_nobit }
+  },
+  {
+    "nofp", true,
+    { ISA_FP_ARMv8,ISA_NEON,ISA_CRYPTO, isa_nobit }
+  },
+  { NULL, false, {isa_nobit}}
+};
+
+static const struct cpu_option arch_opttab_armv8_1_a[] = {
+  {
+    "simd", false,
+    { ISA_FP_ARMv8,ISA_NEON, isa_nobit }
+  },
+  {
+    "crypto", false,
+    { ISA_FP_ARMv8,ISA_NEON,ISA_CRYPTO, isa_nobit }
+  },
+  {
+    "nofp", true,
+    { ISA_FP_ARMv8,ISA_NEON,ISA_CRYPTO, isa_nobit }
+  },
+  { NULL, false, {isa_nobit}}
+};
+
+static const struct cpu_option arch_opttab_armv8_2_a[] = {
+  {
+    "fp16", false,
+    { isa_bit_fp16,ISA_FP_ARMv8,ISA_NEON, isa_nobit }
+  },
+  {
+    "simd", false,
+    { ISA_FP_ARMv8,ISA_NEON, isa_nobit }
+  },
+  {
+    "crypto", false,
+    { ISA_FP_ARMv8,ISA_NEON,ISA_CRYPTO, isa_nobit }
+  },
+  {
+    "nofp", true,
+    { isa_bit_fp16,ISA_FP_ARMv8,ISA_NEON,ISA_CRYPTO, isa_nobit }
+  },
+  { NULL, false, {isa_nobit}}
+};
+
+static const struct cpu_option arch_opttab_armv8_m_main[] = {
+  {
+    "dsp", false,
+    { isa_bit_ARMv7em, isa_nobit }
+  },
+  { NULL, false, {isa_nobit}}
 };
 
 static const struct processors all_architectures[] =
@@ -1255,6 +1465,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv2,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1265,6 +1476,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv2,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1275,6 +1487,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv3,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1285,6 +1498,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv3m,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1295,6 +1509,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv4,isa_bit_mode26,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1305,6 +1520,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv4t,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1315,6 +1531,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv5,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1325,6 +1542,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv5t,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1335,6 +1553,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv5e,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1345,6 +1564,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv5te,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1355,6 +1575,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv5tej,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1365,6 +1586,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv6,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1375,6 +1597,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv6j,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1385,6 +1608,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv6k,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1395,6 +1619,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv6z,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1405,6 +1630,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv6kz,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1415,6 +1641,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv6kz,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1425,6 +1652,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv6t2,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1435,6 +1663,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv6m,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1445,6 +1674,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv6m,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1455,6 +1685,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv7,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1465,6 +1696,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv7a,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1475,6 +1707,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv7ve,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1485,6 +1718,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv7r,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1495,6 +1729,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv7m,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1505,6 +1740,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv7em,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1515,16 +1751,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv8a,
       isa_nobit
     },
-    NULL
-  },
-  {
-    "armv8-a+crc", TARGET_CPU_cortexa53,
-    (TF_CO_PROC),
-    "8A", BASE_ARCH_8A,
-    {
-      ISA_ARMv8a,isa_bit_crc32,
-      isa_nobit
-    },
+    arch_opttab_armv8_a,
     NULL
   },
   {
@@ -1535,6 +1762,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv8_1a,
       isa_nobit
     },
+    arch_opttab_armv8_1_a,
     NULL
   },
   {
@@ -1545,16 +1773,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv8_2a,
       isa_nobit
     },
-    NULL
-  },
-  {
-    "armv8.2-a+fp16", TARGET_CPU_cortexa53,
-    (TF_CO_PROC),
-    "8A", BASE_ARCH_8A,
-    {
-      ISA_ARMv8_2a,isa_bit_fp16,
-      isa_nobit
-    },
+    arch_opttab_armv8_2_a,
     NULL
   },
   {
@@ -1565,6 +1784,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv8m_base,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1575,16 +1795,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv8m_main,
       isa_nobit
     },
-    NULL
-  },
-  {
-    "armv8-m.main+dsp", TARGET_CPU_cortexm33,
-    (TF_CO_PROC),
-    "8M_MAIN", BASE_ARCH_8M_MAIN,
-    {
-      ISA_ARMv8m_main,isa_bit_ARMv7em,
-      isa_nobit
-    },
+    arch_opttab_armv8_m_main,
     NULL
   },
   {
@@ -1595,6 +1806,7 @@  static const struct processors all_architectures[] =
       ISA_ARMv5te,isa_bit_xscale,isa_bit_iwmmxt,
       isa_nobit
     },
+    NULL,
     NULL
   },
   {
@@ -1605,9 +1817,10 @@  static const struct processors all_architectures[] =
       ISA_ARMv5te,isa_bit_xscale,isa_bit_iwmmxt,isa_bit_iwmmxt2,
       isa_nobit
     },
+    NULL,
     NULL
   },
-  {NULL, TARGET_CPU_arm_none, 0, NULL, BASE_ARCH_0, {isa_nobit}, NULL}
+  {NULL, TARGET_CPU_arm_none, 0, NULL, BASE_ARCH_0, {isa_nobit}, NULL, NULL}
 };
 
 const struct arm_fpu_desc all_fpus[] =
diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
index d116b09..021b81b 100644
--- a/gcc/config/arm/arm-cpus.in
+++ b/gcc/config/arm/arm-cpus.in
@@ -237,20 +237,20 @@  begin arch armv8-a
  tune flags CO_PROC
  base 8A
  isa ARMv8a
+ option crc add bit_crc32
+ option simd add FP_ARMv8 NEON
+ option crypto add FP_ARMv8 NEON CRYPTO
+ option nofp remove FP_ARMv8 NEON CRYPTO
 end arch armv8-a
 
-begin arch armv8-a+crc
- tune for cortex-a53
- tune flags CO_PROC
- base 8A
- isa ARMv8a bit_crc32
-end arch armv8-a+crc
-
 begin arch armv8.1-a
  tune for cortex-a53
  tune flags CO_PROC
  base 8A
  isa ARMv8_1a
+ option simd add FP_ARMv8 NEON
+ option crypto add FP_ARMv8 NEON CRYPTO
+ option nofp remove FP_ARMv8 NEON CRYPTO
 end arch armv8.1-a
 
 begin arch armv8.2-a
@@ -258,15 +258,12 @@  begin arch armv8.2-a
  tune flags CO_PROC
  base 8A
  isa ARMv8_2a
+ option fp16 add bit_fp16 FP_ARMv8 NEON
+ option simd add FP_ARMv8 NEON
+ option crypto add FP_ARMv8 NEON CRYPTO
+ option nofp remove bit_fp16 FP_ARMv8 NEON CRYPTO
 end arch armv8.2-a
 
-begin arch armv8.2-a+fp16
- tune for cortex-a53
- tune flags CO_PROC
- base 8A
- isa ARMv8_2a bit_fp16
-end arch armv8.2-a+fp16
-
 begin arch armv8-m.base
  tune for cortex-m23
  base 8M_BASE
@@ -278,15 +275,9 @@  begin arch armv8-m.main
  tune flags CO_PROC
  base 8M_MAIN
  isa ARMv8m_main
+ option dsp add bit_ARMv7em
 end arch armv8-m.main
 
-begin arch armv8-m.main+dsp
- tune for cortex-m33
- tune flags CO_PROC
- base 8M_MAIN
- isa ARMv8m_main bit_ARMv7em
-end arch armv8-m.main+dsp
-
 begin arch iwmmxt
  tune for iwmmxt
  tune flags LDSCHED STRONG XSCALE
@@ -310,6 +301,7 @@  end arch iwmmxt2
 #   architecture <name>
 #   [fpu <name>]
 #   [isa <additional-isa-flags-list>]
+#   [option <name> add|remove <isa-list>]*
 #   [costs <name>]
 # end cpu <name>
 #
@@ -847,6 +839,8 @@  begin cpu cortex-a8
  cname cortexa8
  tune flags LDSCHED
  architecture armv7-a
+ fpu neon-vfpv3
+ option nofp remove NEON VFPv3
  costs cortex_a8
 end cpu cortex-a8
 
@@ -854,6 +848,9 @@  begin cpu cortex-a9
  cname cortexa9
  tune flags LDSCHED
  architecture armv7-a
+ fpu neon-vfpv3
+ option nofp remove NEON VFPv3
+ option nosimd remove NEON
  costs cortex_a9
 end cpu cortex-a9
 
diff --git a/gcc/config/arm/arm-tables.opt b/gcc/config/arm/arm-tables.opt
index cbcd85d..f7b4339 100644
--- a/gcc/config/arm/arm-tables.opt
+++ b/gcc/config/arm/arm-tables.opt
@@ -440,31 +440,22 @@  EnumValue
 Enum(arm_arch) String(armv8-a) Value(26)
 
 EnumValue
-Enum(arm_arch) String(armv8-a+crc) Value(27)
+Enum(arm_arch) String(armv8.1-a) Value(27)
 
 EnumValue
-Enum(arm_arch) String(armv8.1-a) Value(28)
+Enum(arm_arch) String(armv8.2-a) Value(28)
 
 EnumValue
-Enum(arm_arch) String(armv8.2-a) Value(29)
+Enum(arm_arch) String(armv8-m.base) Value(29)
 
 EnumValue
-Enum(arm_arch) String(armv8.2-a+fp16) Value(30)
+Enum(arm_arch) String(armv8-m.main) Value(30)
 
 EnumValue
-Enum(arm_arch) String(armv8-m.base) Value(31)
+Enum(arm_arch) String(iwmmxt) Value(31)
 
 EnumValue
-Enum(arm_arch) String(armv8-m.main) Value(32)
-
-EnumValue
-Enum(arm_arch) String(armv8-m.main+dsp) Value(33)
-
-EnumValue
-Enum(arm_arch) String(iwmmxt) Value(34)
-
-EnumValue
-Enum(arm_arch) String(iwmmxt2) Value(35)
+Enum(arm_arch) String(iwmmxt2) Value(32)
 
 Enum
 Name(arm_fpu) Type(enum fpu_type)
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 5288000..de2c90e 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -975,6 +975,13 @@  int arm_regs_in_sequence[] =
 
 /* Initialization code.  */
 
+struct cpu_option
+{
+  const char *const name;
+  bool remove;
+  const enum isa_feature isa_bits[isa_num_bits];
+};
+
 struct processors
 {
   const char *const name;
@@ -982,7 +989,8 @@  struct processors
   unsigned int tune_flags;
   const char *arch;
   enum base_architecture base_arch;
-  enum isa_feature isa_bits[isa_num_bits];
+  const enum isa_feature isa_bits[isa_num_bits];
+  const struct cpu_option* const opttab;
   const struct tune_params *const tune;
 };
 
@@ -3090,9 +3098,13 @@  arm_parse_arch_cpu_name (const struct processors *list, const char *optname,
 			 const char *target)
 {
   const struct processors *entry;
+  const char *end  = strchr (target, '+');
+  size_t len = end ? end - target : strlen (target);
+
   for (entry = list; entry->name != NULL; entry++)
     {
-      if (streq (entry->name, target))
+      if (strncmp (entry->name, target, len) == 0
+	  && entry->name[len] == '\0')
 	return entry;
     }
 
@@ -3101,6 +3113,92 @@  arm_parse_arch_cpu_name (const struct processors *list, const char *optname,
   return NULL;
 }
 
+/* OPT isn't a recognized feature.  Print a suitable error message and
+   suggest a possible value.  Always print the list of permitted
+   values.  */
+static void
+arm_unrecognized_feature (const char *opt, size_t len,
+			  const struct processors *target)
+{
+  char *this_opt = XALLOCAVEC (char, len+1);
+  auto_vec<const char*> candidates;
+
+  strncpy (this_opt, opt, len);
+  this_opt[len] = 0;
+
+  error_at (input_location, "%qs does not support feature %qs", target->name,
+	    this_opt);
+  for (const cpu_option *list = target->opttab; list->name != NULL; list++)
+    candidates.safe_push (list->name);
+
+  char *s;
+  const char *hint = candidates_list_and_hint (this_opt, s, candidates);
+
+  if (hint)
+    inform (input_location, "valid feature names are: %s; did you mean %qs?",
+	    s, hint);
+  else
+    inform (input_location, "valid feature names are: %s", s);
+
+  XDELETEVEC (s);
+}
+
+/* Parse any feature extensions to add to (or remove from) the
+   permitted ISA selection.  */
+static void
+arm_parse_arch_cpu_features (sbitmap isa, const struct processors *target,
+			     const char *opts_in)
+{
+  const char *opts = opts_in;
+
+  if (!opts)
+    return;
+
+  if (!target->opttab)
+    {
+      error_at (input_location, "%s does not take any feature options",
+		target->name);
+      return;
+    }
+
+  while (opts)
+    {
+      gcc_assert (*opts == '+');
+      const struct cpu_option *entry;
+      const char *end = strchr (++opts, '+');
+      size_t len = end ? end - opts : strlen (opts);
+      bool matched = false;
+
+      for (entry = target->opttab; !matched && entry->name != NULL; entry++)
+	{
+	  if (strncmp (entry->name, opts, len) == 0
+	      && entry->name[len] == '\0')
+	    {
+	      if (isa)
+		{
+		  const enum isa_feature *f = entry->isa_bits;
+		  if (entry->remove)
+		    {
+		      while (*f != isa_nobit)
+			bitmap_clear_bit (isa, *(f++));
+		    }
+		  else
+		    {
+		      while (*f != isa_nobit)
+			bitmap_set_bit (isa, *(f++));
+		    }
+		}
+	      matched = true;
+	    }
+	}
+
+      if (!matched)
+	arm_unrecognized_feature (opts, len, target);
+
+      opts = end;
+    }
+}
+
 static sbitmap isa_all_fpubits;
 static sbitmap isa_quirkbits;
 
@@ -3117,35 +3215,50 @@  arm_configure_build_target (struct arm_build_target *target,
   const struct processors *arm_selected_arch = NULL;
   const struct processors *arm_selected_cpu = NULL;
   const struct arm_fpu_desc *arm_selected_fpu = NULL;
+  const char *tune_opts = NULL;
+  const char *arch_opts = NULL;
+  const char *cpu_opts = NULL;
 
   bitmap_clear (target->isa);
   target->core_name = NULL;
   target->arch_name = NULL;
 
   if (opts_set->x_arm_arch_string)
-    arm_selected_arch = arm_parse_arch_cpu_name (all_architectures,
-						 "-march",
-						 opts->x_arm_arch_string);
+    {
+      arm_selected_arch = arm_parse_arch_cpu_name (all_architectures,
+						   "-march",
+						   opts->x_arm_arch_string);
+      arch_opts = strchr (opts->x_arm_arch_string, '+');
+    }
+
   if (opts_set->x_arm_cpu_string)
     {
       arm_selected_cpu = arm_parse_arch_cpu_name (all_cores, "-mcpu",
 						  opts->x_arm_cpu_string);
+      cpu_opts = strchr (opts->x_arm_cpu_string, '+');
       arm_selected_tune = arm_selected_cpu;
+      /* If taking the tuning from -mcpu, we don't need to rescan the
+	 options for tuning.  */
     }
 
   if (opts_set->x_arm_tune_string)
-    arm_selected_tune = arm_parse_arch_cpu_name (all_cores, "-mtune",
-						 opts->x_arm_tune_string);
+    {
+      arm_selected_tune = arm_parse_arch_cpu_name (all_cores, "-mtune",
+						   opts->x_arm_tune_string);
+      tune_opts = strchr (opts->x_arm_tune_string, '+');
+    }
 
   if (arm_selected_arch)
     {
       arm_initialize_isa (target->isa, arm_selected_arch->isa_bits);
+      arm_parse_arch_cpu_features (target->isa, arm_selected_arch, arch_opts);
 
       if (arm_selected_cpu)
 	{
 	  auto_sbitmap cpu_isa (isa_num_bits);
 
 	  arm_initialize_isa (cpu_isa, arm_selected_cpu->isa_bits);
+	  arm_parse_arch_cpu_features (cpu_isa, arm_selected_cpu, cpu_opts);
 	  bitmap_xor (cpu_isa, cpu_isa, target->isa);
 	  /* Ignore any bits that are quirk bits.  */
 	  bitmap_and_compl (cpu_isa, cpu_isa, isa_quirkbits);
@@ -3185,6 +3298,7 @@  arm_configure_build_target (struct arm_build_target *target,
     {
       target->core_name = arm_selected_cpu->name;
       arm_initialize_isa (target->isa, arm_selected_cpu->isa_bits);
+      arm_parse_arch_cpu_features (target->isa, arm_selected_cpu, cpu_opts);
     }
   /* If the user did not specify a processor, choose one for them.  */
   else
@@ -3305,14 +3419,12 @@  arm_configure_build_target (struct arm_build_target *target,
       bitmap_and_compl (target->isa, target->isa, isa_all_fpubits);
       bitmap_ior (target->isa, target->isa, fpu_bits);
     }
-  else if (target->core_name == NULL)
-    /* To support this we need to be able to parse FPU feature options
-       from the architecture string.  */
-    sorry ("-mfpu=auto not currently supported without an explicit CPU.");
 
   /* The selected cpu may be an architecture, so lookup tuning by core ID.  */
   if (!arm_selected_tune)
     arm_selected_tune = &all_cores[arm_selected_cpu->core];
+  else /* Validate the features passed to -mtune.  */
+    arm_parse_arch_cpu_features (NULL, arm_selected_tune, tune_opts);
 
   /* Finish initializing the target structure.  */
   target->arch_pp_name = arm_selected_cpu->arch;
@@ -26181,6 +26293,39 @@  arm_print_tune_info (void)
 	       (int) current_tune->sched_autopref);
 }
 
+/* Print .arch and .arch_extension directives corresponding to the
+   current architecture configuration.  */
+static void
+arm_print_asm_arch_directives ()
+{
+  const struct processors *arch
+    = arm_parse_arch_cpu_name (all_architectures, "-march",
+			       arm_active_target.arch_name);
+  auto_sbitmap opt_bits (isa_num_bits);
+
+  gcc_assert (arch);
+
+  asm_fprintf (asm_out_file, "\t.arch %s\n", arm_active_target.arch_name);
+  if (!arch->opttab)
+    return;
+
+  for (const struct cpu_option *opt = arch->opttab; opt->name != NULL; opt++)
+    {
+      if (!opt->remove)
+	{
+	  arm_initialize_isa (opt_bits, opt->isa_bits);
+
+	  /* If every feature bit of this option is set in the target
+	     ISA specification, print out the option name.  However,
+	     don't print anything if all the bits are part of the
+	     FPU specification.  */
+	  if (bitmap_subset_p (opt_bits, arm_active_target.isa)
+	      && !bitmap_subset_p (opt_bits, isa_all_fpubits))
+	    asm_fprintf (asm_out_file, "\t.arch_extension %s\n", opt->name);
+	}
+    }
+}
+
 static void
 arm_file_start (void)
 {
@@ -26195,7 +26340,7 @@  arm_file_start (void)
 	 assembler would not need to know about all new CPU names as
 	 they are added.  */
       if (!arm_active_target.core_name)
-        {
+	{
 	  /* armv7ve doesn't support any extensions.  */
 	  if (strcmp (arm_active_target.arch_name, "armv7ve") == 0)
 	    {
@@ -26208,24 +26353,8 @@  arm_file_start (void)
 	      asm_fprintf (asm_out_file, "\t.arch_extension mp\n");
 	    }
 	  else
-	    {
-	      const char* pos = strchr (arm_active_target.arch_name, '+');
-	      if (pos)
-		{
-		  char buf[32];
-		  gcc_assert (strlen (arm_active_target.arch_name)
-			      <= sizeof (buf) / sizeof (*pos));
-		  strncpy (buf, arm_active_target.arch_name,
-			   (pos - arm_active_target.arch_name) * sizeof (*pos));
-		  buf[pos - arm_active_target.arch_name] = '\0';
-		  asm_fprintf (asm_out_file, "\t.arch %s\n", buf);
-		  asm_fprintf (asm_out_file, "\t.arch_extension %s\n", pos + 1);
-		}
-	      else
-		asm_fprintf (asm_out_file, "\t.arch %s\n",
-			     arm_active_target.arch_name);
-	    }
-        }
+	    arm_print_asm_arch_directives ();
+	}
       else if (strncmp (arm_active_target.core_name, "generic", 7) == 0)
 	asm_fprintf (asm_out_file, "\t.arch %s\n",
 		     arm_active_target.core_name + 8);
@@ -26249,7 +26378,7 @@  arm_file_start (void)
 	}
 
       /* Some of these attributes only apply when the corresponding features
-         are used.  However we don't have any easy way of figuring this out.
+	 are used.  However we don't have any easy way of figuring this out.
 	 Conservatively record the setting that would have been used.  */
 
       if (flag_rounding_math)
diff --git a/gcc/config/arm/parsecpu.awk b/gcc/config/arm/parsecpu.awk
index dac11a0..c95d922 100644
--- a/gcc/config/arm/parsecpu.awk
+++ b/gcc/config/arm/parsecpu.awk
@@ -117,11 +117,28 @@  function gen_headers () {
 function gen_data () {
     boilerplate("C")
 
+    ncpus = split (cpu_list, cpus)
+
+    for (n = 1; n <= ncpus; n++) {
+	if (cpus[n] in cpu_opts) {
+	    print "static const struct cpu_option cpu_opttab_" \
+		cpu_cnames[cpus[n]] "[] = {"
+	    nopts = split (cpu_opts[cpus[n]], opts)
+	    for (opt = 1; opt <= nopts; opt++) {
+		print "  {"
+		print "    \"" opts[opt] "\", " \
+		    cpu_opt_remove[cpus[n],opts[opt]] ","
+		print "    { " cpu_opt_isa[cpus[n],opts[opt]] ", isa_nobit }"
+		print "  },"
+	    }
+	    print "  { NULL, false, {isa_nobit}}"
+	    print "};\n"
+	}
+    }
+
     print "static const struct processors all_cores[] ="
     print "{"
 
-    ncpus = split (cpu_list, cpus)
-
     for (n = 1; n <= ncpus; n++) {
 	print "  {"
 	print "    \"" cpus[n] "\","
@@ -137,30 +154,60 @@  function gen_data () {
 	if (cpus[n] in cpu_tune_flags) {
 	    print "    (" cpu_tune_flags[cpus[n]] "),"
 	} else print "    0,"
-	if (! (cpu_arch[cpus[n]] in arch_isa)) {
-	    fatal("unknown arch " cpu_arch[cpus[n]] " for cpu " cpus[n])
+	nfeats = split (cpu_arch[cpus[n]], feats, "+")
+	if (! (feats[1] in arch_isa)) {
+	    fatal("unknown arch " feats[1] " for cpu " cpus[n])
 	}
-	print "    \"" arch_base[cpu_arch[cpus[n]]] "\", BASE_ARCH_" \
-	    arch_base[cpu_arch[cpus[n]]] ","
+	print "    \"" arch_base[feats[1]] "\", BASE_ARCH_" \
+	    arch_base[feats[1]] ","
 	print "    {"
-	print "      " arch_isa[cpu_arch[cpus[n]]] ","
+	print "      " arch_isa[feats[1]] ","
+	for (m = 2; m <= nfeats; m++) {
+	    if (! ((feats[1], feats[m]) in arch_opt_isa)) {
+		fatal("unknown feature " feats[m] " for architecture " feats[1])
+	    }
+	    if (arch_opt_remove[feats[1],feats[m]] == "true") {
+		fatal("cannot remove features from architecture specs")
+	    }
+	    print "      " arch_opt_isa[feats[1],feats[m]] ","
+	}
 	if (cpus[n] in cpu_fpu) print "      " fpu_isa[cpu_fpu[cpus[n]]] ","
 	if (cpus[n] in cpu_isa) print "      " cpu_isa[cpus[n]] ","
 	print "      isa_nobit"
 	print "    },"
+	if (cpus[n] in cpu_opts) {
+	    print "    cpu_opttab_" cpu_cnames[cpus[n]] ","
+	} else print "    NULL,"
 	print "    &arm_" cpu_cost[cpus[n]] "_tune"
 	print "  },"
     }
 
     print "  {NULL, TARGET_CPU_arm_none, 0, NULL, BASE_ARCH_0," \
-	" {isa_nobit}, NULL}"
+	" {isa_nobit}, NULL, NULL}"
     print "};\n"
 
+    narchs = split (arch_list, archs)
+
+    for (n = 1; n <= narchs; n++) {
+	if (archs[n] in arch_opts) {
+	    print "static const struct cpu_option arch_opttab_" \
+		arch_cnames[archs[n]] "[] = {"
+	    nopts = split (arch_opts[archs[n]], opts)
+	    for (opt = 1; opt <= nopts; opt++) {
+		print "  {"
+		print "    \"" opts[opt] "\", " \
+		    arch_opt_remove[archs[n],opts[opt]] ","
+		print "    { " arch_opt_isa[archs[n],opts[opt]] ", isa_nobit }"
+		print "  },"
+	    }
+	    print "  { NULL, false, {isa_nobit}}"
+	    print "};\n"
+	}
+    }
+
     print "static const struct processors all_architectures[] ="
     print "{"
 
-    narchs = split (arch_list, archs)
-
     for (n = 1; n <= narchs; n++) {
 	print "  {"
 	if (! (arch_tune_for[archs[n]] in cpu_cnames)) {
@@ -178,12 +225,15 @@  function gen_data () {
 	print "      " arch_isa[archs[n]] ","
 	print "      isa_nobit"
 	print "    },"
+	if (archs[n] in arch_opts) {
+	    print "    arch_opttab_" arch_cnames[archs[n]] ","
+	} else print "    NULL,"
 	print "    NULL"
 	print "  },"
     }
 
     print "  {NULL, TARGET_CPU_arm_none, 0, NULL, BASE_ARCH_0," \
-	" {isa_nobit}, NULL}"
+	" {isa_nobit}, NULL, NULL}"
     print "};\n"
 
     print "const struct arm_fpu_desc all_fpus[] ="
@@ -215,11 +265,15 @@  function gen_comm_data () {
     for (n = 1; n <= ncpus; n++) {
 	print "  {"
 	print "    \"" cpus[n] "\","
-	if (! (cpu_arch[cpus[n]] in arch_isa)) {
-	    fatal("unknown arch " cpu_arch[cpus[n]] " for cpu " cpus[n])
+	# Just truncate the architecture name at the beginning of the
+	# extensions.  We don't need any of those here (at present).
+	arch_name = cpu_arch[cpus[n]];
+	sub("+.*", "", arch_name)
+	if (! (arch_name in arch_isa)) {
+	    fatal("unknown arch " arch_name " for cpu " cpus[n])
 	}
 	print "    {"
-	print "      " arch_isa[cpu_arch[cpus[n]]] ","
+	print "      " arch_isa[arch_name] ","
 	if (cpus[n] in cpu_fpu)	print "      " fpu_isa[cpu_fpu[cpus[n]]] ","
 	if (cpus[n] in cpu_isa)	print "      " cpu_isa[cpus[n]] ","
 	print "      isa_nobit"
@@ -382,6 +436,8 @@  BEGIN {
 	fatal("arch definition lacks an \"isa\" statement")
     }
     arch_list = arch_list " " arch_name
+    arch_cnames[arch_name] = arch_name
+    gsub(/[-+.]/, "_", arch_cnames[arch_name])
     arch_name = ""
     parse_ok = 1
 }
@@ -453,6 +509,32 @@  BEGIN {
     parse_ok = 1
 }
 
+/^[ 	]*option / {
+    name=$2
+    if ($3 == "add") {
+	remove = "false"
+    } else if ($3 == "remove") {
+	remove = "true"
+    } else fatal("syntax: option <name> add|remove isa-list")
+    flags=""
+    flag_count = NF
+    for (n = 4; n <= flag_count; n++) {
+	if (n == 4) {
+	    flags = isa_pfx($n)
+	} else flags = flags "," isa_pfx($n)
+    }
+    if (cpu_name != "") {
+	cpu_opts[cpu_name] = cpu_opts[cpu_name] " " name
+	cpu_opt_remove[cpu_name,name] = remove
+	cpu_opt_isa[cpu_name,name] = flags
+    } else if (arch_name != "") {
+	arch_opts[arch_name] = arch_opts[arch_name] " " name
+	arch_opt_remove[arch_name,name] = remove
+	arch_opt_isa[arch_name,name] = flags
+    } else fatal("\"option\" outside of cpu or arch block")
+    parse_ok = 1
+}
+
 /^[ 	]*costs / {
     if (cpu_name == "") fatal("\"costs\" outside of cpu block")
     cpu_cost[cpu_name] = $2