diff mbox

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

Message ID 59600e14bb54f8be75d6e697e379cecb48d2c531.1497004220.git.Richard.Earnshaw@arm.com
State New
Headers show

Commit Message

Richard Earnshaw (lists) June 9, 2017, 12:53 p.m. UTC
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(-)
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 42f29e1..a1615bf 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 premitted
+   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