diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 58d2ae3..7673e3a 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -449,6 +449,31 @@ extern int arm_arch_no_volatile_ce;
    than core registers.  */
 extern int prefer_neon_for_64bits;
 
+/* Structure defining the current overall architectural target and tuning.  */
+struct arm_build_target
+{
+  /* Name of the target CPU, if known, or NULL if the target CPU was not
+     specified by the user (and inferred from the -march option).  */
+  const char *core_name;
+  /* Name of the target ARCH.  NULL if there is a selected CPU.  */
+  const char *arch_name;
+  /* Preprocessor substring (never NULL).  */
+  const char *arch_pp_name;
+  /* CPU identifier for the core we're compiling for (architecturally).  */
+  enum processor_type arch_core;
+  /* The base architecture value.  */
+  enum base_architecture base_arch;
+  /* Bitmap encapsulating the isa_bits for the target environment.  */
+  sbitmap isa;
+  /* Flags used for tuning.  Long term, these move into tune_params.  */
+  unsigned int tune_flags;
+  /* Tables with more detailed tuning information.  */
+  const struct tune_params *tune;
+  /* CPU identifier for the tuning target.  */
+  enum processor_type tune_core;
+};
+
+extern struct arm_build_target arm_active_target;
 
 
 #endif /* ! GCC_ARM_PROTOS_H */
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index bf04a06..deab528 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -88,7 +88,7 @@ static void arm_add_gc_roots (void);
 static int arm_gen_constant (enum rtx_code, machine_mode, rtx,
 			     unsigned HOST_WIDE_INT, rtx, rtx, int, int);
 static unsigned bit_count (unsigned long);
-static unsigned feature_count (const arm_feature_set*);
+static unsigned bitmap_popcount (const sbitmap);
 static int arm_address_register_rtx_p (rtx, int);
 static int arm_legitimate_index_p (machine_mode, rtx, RTX_CODE, int);
 static bool is_called_in_ARM_mode (tree);
@@ -791,6 +791,10 @@ unsigned int tune_flags = 0;
    target.  */
 enum base_architecture arm_base_arch = BASE_ARCH_0;
 
+/* Active target architecture and tuning.  */
+
+struct arm_build_target arm_active_target;
+
 /* The following are used in the arm.md file as equivalents to bits
    in the above two flag variables.  */
 
@@ -2376,12 +2380,17 @@ bit_count (unsigned long value)
   return count;
 }
 
-/* Return the number of features in feature-set SET.  */
+/* Return the number of bits set in BMAP.  */
 static unsigned
-feature_count (const arm_feature_set * set)
+bitmap_popcount (const sbitmap bmap)
 {
-  return (bit_count (ARM_FSET_CPU1 (*set))
-	  + bit_count (ARM_FSET_CPU2 (*set)));
+  unsigned int count = 0;
+  unsigned int n = 0;
+  sbitmap_iterator sbi;
+
+  EXECUTE_IF_SET_IN_BITMAP (bmap, 0, n, sbi)
+    count++;
+  return count;
 }
 
 typedef struct
@@ -3038,100 +3047,149 @@ arm_option_override_internal (struct gcc_options *opts,
 #endif
 }
 
-/* Fix up any incompatible options that the user has specified.  */
+/* Convert a static initializer array of feature bits to sbitmap
+   representation.  */
 static void
-arm_option_override (void)
+arm_initialize_isa (sbitmap isa, const enum isa_feature *isa_bits)
+{
+  bitmap_clear (isa);
+  while (*isa_bits != isa_nobit)
+    bitmap_set_bit (isa, *(isa_bits++));
+}
+
+static sbitmap isa_fpubits;
+
+/* Configure a build target TARGET from the user-specified options OPTS and
+   OPTS_SET.  If WARN_COMPATIBLE, emit a diagnostic if both the CPU and
+   architecture have been specified, but the two are not identical.  */
+static void
+arm_configure_build_target (struct arm_build_target *target,
+			    struct gcc_options *opts,
+			    struct gcc_options *opts_set,
+			    bool warn_compatible)
 {
   arm_selected_arch = NULL;
   arm_selected_cpu = NULL;
   arm_selected_tune = NULL;
 
-  if (global_options_set.x_arm_arch_option)
-    arm_selected_arch = &all_architectures[arm_arch_option];
+  bitmap_clear (target->isa);
+  target->core_name = NULL;
+  target->arch_name = NULL;
+
+  if (opts_set->x_arm_arch_option)
+    arm_selected_arch = &all_architectures[opts->x_arm_arch_option];
 
-  if (global_options_set.x_arm_cpu_option)
+  if (opts_set->x_arm_cpu_option)
     {
-      arm_selected_cpu = &all_cores[(int) arm_cpu_option];
-      arm_selected_tune = &all_cores[(int) arm_cpu_option];
+      arm_selected_cpu = &all_cores[(int) opts->x_arm_cpu_option];
+      arm_selected_tune = &all_cores[(int) opts->x_arm_cpu_option];
     }
 
-  if (global_options_set.x_arm_tune_option)
-    arm_selected_tune = &all_cores[(int) arm_tune_option];
-
-#ifdef SUBTARGET_OVERRIDE_OPTIONS
-  SUBTARGET_OVERRIDE_OPTIONS;
-#endif
+  if (opts_set->x_arm_tune_option)
+    arm_selected_tune = &all_cores[(int) opts->x_arm_tune_option];
 
   if (arm_selected_arch)
     {
+      arm_initialize_isa (target->isa, arm_selected_arch->isa_bits);
+
       if (arm_selected_cpu)
 	{
-	  const arm_feature_set tuning_flags = ARM_FSET_MAKE_CPU1 (FL_TUNE);
-	  arm_feature_set selected_flags;
-	  ARM_FSET_XOR (selected_flags, arm_selected_cpu->flags,
-			arm_selected_arch->flags);
-	  ARM_FSET_EXCLUDE (selected_flags, selected_flags, tuning_flags);
-	  /* Check for conflict between mcpu and march.  */
-	  if (!ARM_FSET_IS_EMPTY (selected_flags))
+	  auto_sbitmap cpu_isa (isa_num_bits);
+
+	  arm_initialize_isa (cpu_isa, arm_selected_cpu->isa_bits);
+	  bitmap_xor (cpu_isa, cpu_isa, target->isa);
+	  /* Ignore (for now) any bits that might be set by -mfpu.  */
+	  bitmap_and_compl (cpu_isa, cpu_isa, isa_fpubits);
+
+	  if (!bitmap_empty_p (cpu_isa))
 	    {
-	      warning (0, "switch -mcpu=%s conflicts with -march=%s switch",
-		       arm_selected_cpu->name, arm_selected_arch->name);
+	      if (warn_compatible)
+		warning (0, "switch -mcpu=%s conflicts with -march=%s switch",
+			 arm_selected_cpu->name, arm_selected_arch->name);
 	      /* -march wins for code generation.
-	         -mcpu wins for default tuning.  */
+		 -mcpu wins for default tuning.  */
 	      if (!arm_selected_tune)
 		arm_selected_tune = arm_selected_cpu;
 
 	      arm_selected_cpu = arm_selected_arch;
 	    }
 	  else
-	    /* -mcpu wins.  */
-	    arm_selected_arch = NULL;
+	    {
+	      /* Architecture and CPU are essentially the same.
+		 Prefer the CPU setting.  */
+	      arm_selected_arch = NULL;
+	    }
 	}
       else
-	/* Pick a CPU based on the architecture.  */
-	arm_selected_cpu = arm_selected_arch;
+	{
+	  /* Pick a CPU based on the architecture.  */
+	  arm_selected_cpu = arm_selected_arch;
+	  target->arch_name = arm_selected_arch->name;
+	}
     }
 
   /* If the user did not specify a processor, choose one for them.  */
   if (!arm_selected_cpu)
     {
       const struct processors * sel;
-      arm_feature_set sought = ARM_FSET_EMPTY;;
+      auto_sbitmap sought_isa (isa_num_bits);
+      bitmap_clear (sought_isa);
+      auto_sbitmap default_isa (isa_num_bits);
 
       arm_selected_cpu = &all_cores[TARGET_CPU_DEFAULT];
       gcc_assert (arm_selected_cpu->name);
 
+      /* RWE: All of the selection logic below (to the end of this
+	 'if' clause) looks somewhat suspect.  It appears to be mostly
+	 there to support forcing thumb support when the default CPU
+	 does not have thumb (somewhat dubious in terms of what the
+	 user might be expecting).  I think it should be removed once
+	 support for the pre-thumb era cores is removed.  */
       sel = arm_selected_cpu;
-      insn_flags = sel->flags;
+      arm_initialize_isa (default_isa, sel->isa_bits);
 
-      /* Now check to see if the user has specified some command line
-	 switch that require certain abilities from the cpu.  */
+      /* Now check to see if the user has specified any command line
+	 switches that require certain abilities from the cpu.  */
 
       if (TARGET_INTERWORK || TARGET_THUMB)
 	{
-	  ARM_FSET_ADD_CPU1 (sought, FL_THUMB);
-	  ARM_FSET_ADD_CPU1 (sought, FL_MODE32);
+	  bitmap_set_bit (sought_isa, isa_bit_thumb);
+	  bitmap_set_bit (sought_isa, isa_bit_mode32);
 
 	  /* There are no ARM processors that support both APCS-26 and
-	     interworking.  Therefore we force FL_MODE26 to be removed
-	     from insn_flags here (if it was set), so that the search
-	     below will always be able to find a compatible processor.  */
-	  ARM_FSET_DEL_CPU1 (insn_flags, FL_MODE26);
+	     interworking.  Therefore we forcibly remove MODE26 from
+	     from the isa features here (if it was set), so that the
+	     search below will always be able to find a compatible
+	     processor.  */
+	  bitmap_clear_bit (default_isa, isa_bit_mode26);
 	}
 
-      if (!ARM_FSET_IS_EMPTY (sought)
-	  && !(ARM_FSET_CPU_SUBSET (sought, insn_flags)))
+      /* If there are such requirements and the default CPU does not
+	 satisfy them, we need to run over the complete list of
+	 cores looking for one that is satisfactory.  */
+      if (!bitmap_empty_p (sought_isa)
+	  && !bitmap_subset_p (sought_isa, default_isa))
 	{
+	  auto_sbitmap candidate_isa (isa_num_bits);
+	  /* We're only interested in a CPU with at least the
+	     capabilities of the default CPU and the required
+	     additional features.  */
+	  bitmap_ior (default_isa, default_isa, sought_isa);
+
 	  /* Try to locate a CPU type that supports all of the abilities
 	     of the default CPU, plus the extra abilities requested by
 	     the user.  */
 	  for (sel = all_cores; sel->name != NULL; sel++)
-	    if (ARM_FSET_CPU_SUBSET (sought, sel->flags))
-	      break;
+	    {
+	      arm_initialize_isa (candidate_isa, sel->isa_bits);
+	      /* An exact match?  */
+	      if (bitmap_equal_p (default_isa, candidate_isa))
+		break;
+	    }
 
 	  if (sel->name == NULL)
 	    {
-	      unsigned current_bit_count = 0;
+	      unsigned current_bit_count = isa_num_bits;
 	      const struct processors * best_fit = NULL;
 
 	      /* Ideally we would like to issue an error message here
@@ -3141,32 +3199,34 @@ arm_option_override (void)
 		 ought to use the -mcpu=<name> command line option to
 		 override the default CPU type.
 
-		 If we cannot find a cpu that has both the
-		 characteristics of the default cpu and the given
+		 If we cannot find a CPU that has exactly the
+		 characteristics of the default CPU and the given
 		 command line options we scan the array again looking
-		 for a best match.  */
+		 for a best match.  The best match must have at least
+		 the capabilities of the perfect match.  */
 	      for (sel = all_cores; sel->name != NULL; sel++)
 		{
-		  arm_feature_set required = ARM_FSET_EMPTY;
-		  ARM_FSET_UNION (required, sought, insn_flags);
-		  if (ARM_FSET_CPU_SUBSET (required, sel->flags))
+		  arm_initialize_isa (candidate_isa, sel->isa_bits);
+
+		  if (bitmap_subset_p (default_isa, candidate_isa))
 		    {
 		      unsigned count;
-		      arm_feature_set flags;
-		      ARM_FSET_INTER (flags, sel->flags, insn_flags);
-		      count = feature_count (&flags);
 
-		      if (count >= current_bit_count)
+		      bitmap_and_compl (candidate_isa, candidate_isa,
+					default_isa);
+		      count = bitmap_popcount (candidate_isa);
+
+		      if (count < current_bit_count)
 			{
 			  best_fit = sel;
 			  current_bit_count = count;
 			}
 		    }
+
+		  gcc_assert (best_fit);
+		  sel = best_fit;
 		}
-	      gcc_assert (best_fit);
-	      sel = best_fit;
 	    }
-
 	  arm_selected_cpu = sel;
 	}
     }
@@ -3176,6 +3236,29 @@ arm_option_override (void)
   if (!arm_selected_tune)
     arm_selected_tune = &all_cores[arm_selected_cpu->core];
 
+  target->arch_pp_name = arm_selected_cpu->arch;
+  target->tune_flags = arm_selected_tune->tune_flags;
+  target->tune = arm_selected_tune->tune;
+}
+
+/* Fix up any incompatible options that the user has specified.  */
+static void
+arm_option_override (void)
+{
+  static const enum isa_feature fpu_bitlist[] = { ISA_ALL_FPU, isa_nobit };
+
+  isa_fpubits = sbitmap_alloc (isa_num_bits);
+  arm_initialize_isa (isa_fpubits, fpu_bitlist);
+
+  arm_active_target.isa = sbitmap_alloc (isa_num_bits);
+
+  arm_configure_build_target (&arm_active_target, &global_options,
+			      &global_options_set, true);
+
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+  SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+
   sprintf (arm_arch_name, "__ARM_ARCH_%s__", arm_selected_cpu->arch);
   insn_flags = arm_selected_cpu->flags;
   arm_base_arch = arm_selected_cpu->base_arch;

