This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH 6/10, GAS/ARM] Rework Tag_CPU_arch build attribute value selection
On 21/06/17 16:04, Thomas Preudhomme wrote:
> Alright, here's the updated description and patch to address your
> comments: the description explains the testsuite expectation change and
> the code contains updated comment to explain the ordering of entries in
> cpu_arch_ver.
>
>
> === Context ===
>
> This patch is part of a patch series to add support for ARMv8-R
> architecture. Its purpose is to rework the Tag_CPU_arch build attribute
> value selection to (i) match architecture or CPU if specified by user
> without any need for hack and (ii) match an architecture with all the
> features used if in autodetection mode or return an error.
>
> === Motivation ===
>
> Currently, Tag_CPU_arch build attribute value selection assumes that an
> architecture is always a superset of architectures released earlier. As
> such, the logic is to browse architectures in chronological order of
> release and selecting the Tag_CPU_arch value of the last one to
> contribute a feature used[1]/requested[2] not contributed by earlier
> architectures.
>
> [1] in case of autodetection mode
> [2] otherwise, ie. in case of -mcpu/-march or associated directives
>
> This logic fails the two objectives mentionned in the Context section.
> First, due to the assumption it does an architecture can be selected
> while not having all the features used/requested which fails the second
> objective. Second, not doing an exact match when an architecture or CPU
> is selected by the user means the wrong value is chosen when a later
> architecture provides a subset of the feature bits of an earlier
> architecture. This is the case for the implementation of ARMv8-R (see
> later patch).
>
> An added benefit of this patch is that it is possible to easily generate
> more consistent build attribute by setting the feature bits from the
> architecture matched in aeabi_set_public_attributes in autodetection
> mode. This is better done as a separate patch because lots of testcase'
> expected results must then be updated accordingly.
>
> === Patch description ===
>
> The patch changes the main logic for Tag_CPU_arch and Tag_CPU_arch_profile
> values selection to:
> - look for an exact match in case an architecture or CPU was specified
> on the command line or in a directive
> - select the first released architecture that provides a superset of the
> feature used in the autodetection case
> - select the most featureful architecture in case of -march=all
> The array cpu_arch_ver is updated to include all architectures in order
> to make the first point work.
>
> Note that when looking for an exact match, the architecture with
> selected extension is tried first and then only the architecture. This
> is because some architectures are exactly equivalent to an earlier
> architecture with its extensions selected. ARMv6S-M (= ARMv6-M + OS
> extension) and ARMv6KZ (ARMv6K + security extension) are two such
> examples.
>
> Other adjustments are also necessary in aeabi_set_public_attributes to
> make this change work.
>
> 1) The logic to set Tag_ARM_ISA_use and Tag_THUMB_ISA_use must check the
> absence of feature bit used/requested to decide whether to give the
> default value for empty files (see EABI attribute defaults test). It was
> previously checking that arch == 0 which would only happen if no feature
> bit could be matched by any architecture, ie there is no feature bit to
> match.
>
> 2) A fallback to a superset match must exist when no_cpu_selected ()
> returns true. This is because aeabi_set_public_attributes is called
> again after relaxation and at this point selected_cpu is set from the
> previous execution of that function. There is therefore no way to check
> whether the user specified an architecture or CPU.
>
> 3) Tag_CPU_arch lines are removed from expected output when the
> detected architecture should be pre-ARMv4, since 0 is the Tag_CPU_arch
> value for pre-ARMv4 architectures and default value for an absent entry
> is 0.
>
OK.
R.
> On 21/06/17 15:40, Richard Earnshaw (lists) wrote:
>> On 21/06/17 15:39, Thomas Preudhomme wrote:
>>> Hi Richard,
>>>
>>> On 21/06/17 15:33, Richard Earnshaw (lists) wrote:
>>>> On 21/06/17 11:12, Thomas Preudhomme wrote:
>>>>> Hi,
>>>>>
>>>>> === Context ===
>>>>>
>>>>> This patch is part of a patch series to add support for ARMv8-R
>>>>> architecture. Its purpose is to rework the Tag_CPU_arch build
>>>>> attribute
>>>>> value selection to (i) match architecture or CPU if specified by user
>>>>> without any need for hack and (ii) match an architecture with all the
>>>>> features used if in autodetection mode or return an error.
>>>>>
>>>>> === Motivation ===
>>>>>
>>>>> Currently, Tag_CPU_arch build attribute value selection assumes
>>>>> that an
>>>>> architecture is always a superset of architectures released
>>>>> earlier. As
>>>>> such, the logic is to browse architectures in chronological order of
>>>>> release and selecting the Tag_CPU_arch value of the last one to
>>>>> contribute a feature used[1]/requested[2] not contributed by earlier
>>>>> architectures.
>>>>>
>>>>> [1] in case of autodetection mode
>>>>> [2] otherwise, ie. in case of -mcpu/-march or associated directives
>>>>>
>>>>> This logic fails the two objectives mentionned in the Context section.
>>>>> First, due to the assumption it does an architecture can be selected
>>>>> while not having all the features used/requested which fails the
>>>>> second
>>>>> objective. Second, not doing an exact match when an architecture or
>>>>> CPU
>>>>> is selected by the user means the wrong value is chosen when a later
>>>>> architecture provides a subset of the feature bits of an earlier
>>>>> architecture. This is the case for the implementation of ARMv8-R (see
>>>>> later patch).
>>>>>
>>>>> An added benefit of this patch is that it is possible to easily
>>>>> generate
>>>>> more consistent build attribute by setting the feature bits from the
>>>>> architecture matched in aeabi_set_public_attributes in autodetection
>>>>> mode. This is better done as a separate patch because lots of
>>>>> testcase'
>>>>> expected results must then be updated accordingly.
>>>>>
>>>>> === Patch description ===
>>>>>
>>>>> The patch changes the main logic for Tag_CPU_arch and
>>>>> Tag_CPU_arch_profile
>>>>> values selection to:
>>>>> - look for an exact match in case an architecture or CPU was specified
>>>>> on the command line or in a directive
>>>>> - select the first released architecture that provides a superset
>>>>> of the
>>>>> feature used in the autodetection case
>>>>> - select the most featureful architecture in case of -march=all
>>>>> The array cpu_arch_ver is updated to include all architectures in
>>>>> order
>>>>> to make the first point work.
>>>>>
>>>>> Note that when looking for an exact match, the architecture with
>>>>> selected extension is tried first and then only the architecture. This
>>>>> is because some architectures are exactly equivalent to an earlier
>>>>> architecture with its extensions selected. ARMv6S-M (= ARMv6-M + OS
>>>>> extension) and ARMv6KZ (ARMv6K + security extension) are two such
>>>>> examples.
>>>>>
>>>>> Other adjustments are also necessary in aeabi_set_public_attributes to
>>>>> make this change work.
>>>>>
>>>>> 1) The logic to set Tag_ARM_ISA_use and Tag_THUMB_ISA_use must
>>>>> check the
>>>>> absence of feature bit used/requested to decide whether to give the
>>>>> default value for empty files (see EABI attribute defaults test).
>>>>> It was
>>>>> previously checking that arch == 0 which would only happen if no
>>>>> feature
>>>>> bit could be matched by any architecture, ie there is no feature
>>>>> bit to
>>>>> match.
>>>>>
>>>>> 2) A fallback to a superset match must exist when no_cpu_selected ()
>>>>> returns true. This is because aeabi_set_public_attributes is called
>>>>> again after relaxation and at this point selected_cpu is set from the
>>>>> previous execution of that function. There is therefore no way to
>>>>> check
>>>>> whether the user specified an architecture or CPU.
>>>>>
>>>>> ChangeLog entries are as follow:
>>>>>
>>>>> *** gas/ChangeLog ***
>>>>>
>>>>> 2017-06-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>
>>>>> * config/tc-arm.c (fpu_any): Defined from FPU_ANY.
>>>>> (cpu_arch_ver): Add all architectures and sort by release date.
>>>>> (have_ext_for_needed_feat_p): New.
>>>>> (get_aeabi_cpu_arch_from_fset): New.
>>>>> (aeabi_set_public_attributes): Call above function to determine
>>>>> Tag_CPU_arch and Tag_CPU_arch_profile values. Adapt
>>>>> Tag_ARM_ISA_use
>>>>> and Tag_THUMB_ISA_use selection logic to check absence of feature
>>>>> bit
>>>>> accordingly.
>>>>> * testsuite/gas/arm/attr-march-armv1.d: Fix expected Tag_CPU_arch
>>>>> build
>>>>> attribute value.
>>>>> * testsuite/gas/arm/attr-march-armv2.d: Likewise.
>>>>> * testsuite/gas/arm/attr-march-armv2a.d: Likewise.
>>>>> * testsuite/gas/arm/attr-march-armv2s.d: Likewise.
>>>>> * testsuite/gas/arm/attr-march-armv3.d: Likewise.
>>>>> * testsuite/gas/arm/attr-march-armv3m.d: Likewise.
>>>>> * testsuite/gas/arm/pr12198-2.d: Likewise.
>>>>>
>>>>> *** include/ChangeLog ***
>>>>>
>>>>> 2017-01-26 Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>
>>>>> * opcode/arm.h (FPU_ANY): New macro.
>>>>>
>>>>> === Testing ===
>>>>>
>>>>> Testsuite shows no regression when run for arm-none-eabi targets.
>>>>>
>>>>> Is this ok for master branch?
>>>>>
>>>>
>>>> I have two issues with this patch...
>>>>
>>>> 1)
>>>>> +/* Mapping from CPU features to EABI CPU arch values. Table must be
>>>> sorted
>>>>> + chronologically for architectures, with an exception for
>>>>> ARMv6-M and
>>>>> + ARMv6S-M due to legacy reasons. No new architecture should have a
>>>>> + special case. */
>>>>
>>>> This comment warrants some justification. We should explain that the
>>>> reason for maintaining chronological order is to avoid the build
>>>> attributes of object files changing as new variant architectures get
>>>> added.
>>>
>>> Indeed. I'll improve the comments in code and cover letter for that
>>> patch.
>>>
>>>>
>>>> 2)
>>>>> File Attributes
>>>>> Tag_CPU_name: "1"
>>>>> - Tag_CPU_arch: v4
>>>>> Tag_ARM_ISA_use: Yes
>>>>
>>>> I think we should always emit a Tag_CPU_arch directive. It's wrong to
>>>> assume that the consumer of an object file will be able to deduce the
>>>> base architecture from a simple CPU name - especially an odd-ball one
>>>> like '1' which isn't an official product name.
>>>>
>>>> Tag_CPU_arch = v4 is probably the right thing to emit here - we don't
>>>> have tags for architectures older than that.
>>>
>>> The document "Addenda to, and Errata in, the ABI® for the ARM
>>> Architecture"(document ID: ARM IHI 0045D) issue E r2.10 says that a
>>> value of 0 is for pre-v4 architectures. Since 0 is the default value
>>> this at least follows the documentation.
>>>
>>
>> Ah, ok, so it 'does' have an architecture. Ignore that then.
>>
>> R.
>>
>>> Best regards,
>>>
>>> Thomas
>>
>
> 06_rework_Tag_CPU_arch_selection_logic.patch
>
>
> diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
> index a62c5f29d98d27fcfb8d4860a46993efdc33bed7..7767aa6dddc0b39431c4ac28549b1a62954f0035 100644
> --- a/gas/config/tc-arm.c
> +++ b/gas/config/tc-arm.c
> @@ -240,6 +240,7 @@ static const arm_feature_set arm_ext_v8_3 =
> ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_3A);
>
> static const arm_feature_set arm_arch_any = ARM_ANY;
> +static const arm_feature_set fpu_any = FPU_ANY;
> static const arm_feature_set arm_arch_full ATTRIBUTE_UNUSED = ARM_FEATURE (-1, -1, -1);
> static const arm_feature_set arm_arch_t2 = ARM_ARCH_THUMB2;
> static const arm_feature_set arm_arch_none = ARM_ARCH_NONE;
> @@ -26558,30 +26559,61 @@ typedef struct
> arm_feature_set flags;
> } cpu_arch_ver_table;
>
> -/* Mapping from CPU features to EABI CPU arch values. As a general rule, table
> - must be sorted least features first but some reordering is needed, eg. for
> - Thumb-2 instructions to be detected as coming from ARMv6T2. */
> +/* Mapping from CPU features to EABI CPU arch values. Table must be sorted
> + chronologically for architectures, with an exception for ARMv6-M and
> + ARMv6S-M due to legacy reasons. No new architecture should have a
> + special case. This allows for build attribute selection results to be
> + stable when new architectures are added. */
> static const cpu_arch_ver_table cpu_arch_ver[] =
> {
> + {0, ARM_ARCH_V1},
> + {0, ARM_ARCH_V2},
> + {0, ARM_ARCH_V2S},
> + {0, ARM_ARCH_V3},
> + {0, ARM_ARCH_V3M},
> + {1, ARM_ARCH_V4xM},
> {1, ARM_ARCH_V4},
> + {2, ARM_ARCH_V4TxM},
> {2, ARM_ARCH_V4T},
> + {3, ARM_ARCH_V5xM},
> {3, ARM_ARCH_V5},
> + {3, ARM_ARCH_V5TxM},
> {3, ARM_ARCH_V5T},
> + {4, ARM_ARCH_V5TExP},
> {4, ARM_ARCH_V5TE},
> {5, ARM_ARCH_V5TEJ},
> {6, ARM_ARCH_V6},
> - {9, ARM_ARCH_V6K},
> {7, ARM_ARCH_V6Z},
> + {7, ARM_ARCH_V6KZ},
> + {9, ARM_ARCH_V6K},
> + {8, ARM_ARCH_V6T2},
> + {8, ARM_ARCH_V6KT2},
> + {8, ARM_ARCH_V6ZT2},
> + {8, ARM_ARCH_V6KZT2},
> +
> + /* When assembling a file with only ARMv6-M or ARMv6S-M instruction, GNU as
> + always selected build attributes to match those of ARMv6-M
> + (resp. ARMv6S-M). However, due to these architectures being a strict
> + subset of ARMv7-M in terms of instructions available, ARMv7-M attributes
> + would be selected when fully respecting chronology of architectures.
> + It is thus necessary to make a special case of ARMv6-M and ARMv6S-M and
> + move them before ARMv7 architectures. */
> {11, ARM_ARCH_V6M},
> {12, ARM_ARCH_V6SM},
> - {8, ARM_ARCH_V6T2},
> - {10, ARM_ARCH_V7VE},
> +
> + {10, ARM_ARCH_V7},
> + {10, ARM_ARCH_V7A},
> {10, ARM_ARCH_V7R},
> {10, ARM_ARCH_V7M},
> + {10, ARM_ARCH_V7VE},
> + {13, ARM_ARCH_V7EM},
> {14, ARM_ARCH_V8A},
> + {14, ARM_ARCH_V8_1A},
> + {14, ARM_ARCH_V8_2A},
> + {14, ARM_ARCH_V8_3A},
> {16, ARM_ARCH_V8M_BASE},
> {17, ARM_ARCH_V8M_MAIN},
> - {0, ARM_ARCH_NONE}
> + {-1, ARM_ARCH_NONE}
> };
>
> /* Set an attribute if it has not already been set by the user. */
> @@ -26603,18 +26635,162 @@ aeabi_set_attribute_string (int tag, const char *value)
> bfd_elf_add_proc_attr_string (stdoutput, tag, value);
> }
>
> +/* Return whether features in the *NEEDED feature set are available via
> + extensions for the architecture whose feature set is *ARCH_FSET. */
> +static bfd_boolean
> +have_ext_for_needed_feat_p (const arm_feature_set *arch_fset,
> + const arm_feature_set *needed)
> +{
> + int i, nb_allowed_archs;
> + arm_feature_set ext_fset;
> + const struct arm_option_extension_value_table *opt;
> +
> + ext_fset = arm_arch_none;
> + for (opt = arm_extensions; opt->name != NULL; opt++)
> + {
> + /* Extension does not provide any feature we need. */
> + if (!ARM_CPU_HAS_FEATURE (*needed, opt->merge_value))
> + continue;
> +
> + nb_allowed_archs =
> + sizeof (opt->allowed_archs) / sizeof (opt->allowed_archs[0]);
> + for (i = 0; i < nb_allowed_archs; i++)
> + {
> + /* Empty entry. */
> + if (ARM_FEATURE_EQUAL (opt->allowed_archs[i], arm_arch_any))
> + break;
> +
> + /* Extension is available, add it. */
> + if (ARM_FSET_CPU_SUBSET (opt->allowed_archs[i], *arch_fset))
> + ARM_MERGE_FEATURE_SETS (ext_fset, ext_fset, opt->merge_value);
> + }
> + }
> +
> + /* Can we enable all features in *needed? */
> + return ARM_FSET_CPU_SUBSET (*needed, ext_fset);
> +}
> +
> +/* Select value for Tag_CPU_arch and Tag_CPU_arch_profile build attributes for
> + a given architecture feature set *ARCH_EXT_FSET including extension feature
> + set *EXT_FSET. Selection logic used depend on EXACT_MATCH:
> + - if true, check for an exact match of the architecture modulo extensions;
> + - otherwise, select build attribute value of the first superset
> + architecture released so that results remains stable when new architectures
> + are added.
> + For -march/-mcpu=all the build attribute value of the most featureful
> + architecture is returned. Tag_CPU_arch_profile result is returned in
> + PROFILE. */
> +static int
> +get_aeabi_cpu_arch_from_fset (const arm_feature_set *arch_ext_fset,
> + const arm_feature_set *ext_fset,
> + char *profile, int exact_match)
> +{
> + arm_feature_set arch_fset;
> + const cpu_arch_ver_table *p_ver, *p_ver_ret = NULL;
> +
> + /* Select most featureful architecture with all its extensions if building
> + for -march=all as the feature sets used to set build attributes. */
> + if (ARM_FEATURE_EQUAL (*arch_ext_fset, arm_arch_any))
> + {
> + /* Force revisiting of decision for each new architecture. */
> + gas_assert (MAX_TAG_CPU_ARCH <= TAG_CPU_ARCH_V8M_MAIN);
> + *profile = 'A';
> + return TAG_CPU_ARCH_V8;
> + }
> +
> + ARM_CLEAR_FEATURE (arch_fset, *arch_ext_fset, *ext_fset);
> +
> + for (p_ver = cpu_arch_ver; p_ver->val != -1; p_ver++)
> + {
> + arm_feature_set known_arch_fset;
> +
> + ARM_CLEAR_FEATURE (known_arch_fset, p_ver->flags, fpu_any);
> + if (exact_match)
> + {
> + /* Base architecture match user-specified architecture and
> + extensions, eg. ARMv6S-M matching -march=armv6-m+os. */
> + if (ARM_FEATURE_EQUAL (*arch_ext_fset, known_arch_fset))
> + {
> + p_ver_ret = p_ver;
> + goto found;
> + }
> + /* Base architecture match user-specified architecture only
> + (eg. ARMv6-M in the same case as above). Record it in case we
> + find a match with above condition. */
> + else if (p_ver_ret == NULL
> + && ARM_FEATURE_EQUAL (arch_fset, known_arch_fset))
> + p_ver_ret = p_ver;
> + }
> + else
> + {
> +
> + /* Architecture has all features wanted. */
> + if (ARM_FSET_CPU_SUBSET (arch_fset, known_arch_fset))
> + {
> + arm_feature_set added_fset;
> +
> + /* Compute features added by this architecture over the one
> + recorded in p_ver_ret. */
> + if (p_ver_ret != NULL)
> + ARM_CLEAR_FEATURE (added_fset, known_arch_fset,
> + p_ver_ret->flags);
> + /* First architecture that match incl. with extensions, or the
> + only difference in features over the recorded match is
> + features that were optional and are now mandatory. */
> + if (p_ver_ret == NULL
> + || ARM_FSET_CPU_SUBSET (added_fset, arch_fset))
> + {
> + p_ver_ret = p_ver;
> + goto found;
> + }
> + }
> + else if (p_ver_ret == NULL)
> + {
> + arm_feature_set needed_ext_fset;
> +
> + ARM_CLEAR_FEATURE (needed_ext_fset, arch_fset, known_arch_fset);
> +
> + /* Architecture has all features needed when using some
> + extensions. Record it and continue searching in case there
> + exist an architecture providing all needed features without
> + the need for extensions (eg. ARMv6S-M Vs ARMv6-M with
> + OS extension). */
> + if (have_ext_for_needed_feat_p (&known_arch_fset,
> + &needed_ext_fset))
> + p_ver_ret = p_ver;
> + }
> + }
> + }
> +
> + if (p_ver_ret == NULL)
> + return -1;
> +
> +found:
> + /* Tag_CPU_arch_profile. */
> + if (ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_v7a)
> + || ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_v8)
> + || (ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_atomics)
> + && !ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_v8m_m_only)))
> + *profile = 'A';
> + else if (ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_v7r))
> + *profile = 'R';
> + else if (ARM_CPU_HAS_FEATURE (p_ver_ret->flags, arm_ext_m))
> + *profile = 'M';
> + else
> + *profile = '\0';
> + return p_ver_ret->val;
> +}
> +
> /* Set the public EABI object attributes. */
> static void
> aeabi_set_public_attributes (void)
> {
> - int arch;
> char profile;
> + int arch = -1;
> int virt_sec = 0;
> int fp16_optional = 0;
> - arm_feature_set flags;
> - arm_feature_set tmp;
> - arm_feature_set arm_arch_v8m_base = ARM_ARCH_V8M_BASE;
> - const cpu_arch_ver_table *p;
> + int skip_exact_match = 0;
> + arm_feature_set flags, flags_arch, flags_ext;
>
> /* Autodetection mode, choose the architecture based the instructions
> actually used. */
> @@ -26647,45 +26823,29 @@ aeabi_set_public_attributes (void)
> /* Allow the user to override the reported architecture. */
> if (object_arch)
> {
> - ARM_CLEAR_FEATURE (flags, flags, arm_arch_any);
> - ARM_MERGE_FEATURE_SETS (flags, flags, *object_arch);
> + ARM_CLEAR_FEATURE (flags_arch, *object_arch, fpu_any);
> + flags_ext = arm_arch_none;
> }
> -
> - tmp = flags;
> - arch = 0;
> - for (p = cpu_arch_ver; p->val; p++)
> + else
> {
> - if (ARM_CPU_HAS_FEATURE (tmp, p->flags))
> - {
> - arch = p->val;
> - ARM_CLEAR_FEATURE (tmp, tmp, p->flags);
> - }
> - }
> -
> - /* The table lookup above finds the last architecture to contribute
> - a new feature. Unfortunately, Tag13 is a subset of the union of
> - v6T2 and v7-M, so it is never seen as contributing a new feature.
> - We can not search for the last entry which is entirely used,
> - because if no CPU is specified we build up only those flags
> - actually used. Perhaps we should separate out the specified
> - and implicit cases. Avoid taking this path for -march=all by
> - checking for contradictory v7-A / v7-M features. */
> - if (arch == TAG_CPU_ARCH_V7
> - && !ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)
> - && ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m)
> - && ARM_CPU_HAS_FEATURE (flags, arm_ext_v6_dsp))
> - arch = TAG_CPU_ARCH_V7E_M;
> -
> - ARM_CLEAR_FEATURE (tmp, flags, arm_arch_v8m_base);
> - if (arch == TAG_CPU_ARCH_V8M_BASE && ARM_CPU_HAS_FEATURE (tmp, arm_arch_any))
> - arch = TAG_CPU_ARCH_V8M_MAIN;
> -
> - /* In cpu_arch_ver ARMv8-A is before ARMv8-M for atomics to be detected as
> - coming from ARMv8-A. However, since ARMv8-A has more instructions than
> - ARMv8-M, -march=all must be detected as ARMv8-A. */
> - if (arch == TAG_CPU_ARCH_V8M_MAIN
> - && ARM_FEATURE_CORE_EQUAL (selected_cpu, arm_arch_any))
> - arch = TAG_CPU_ARCH_V8;
> + ARM_CLEAR_FEATURE (flags_arch, flags, fpu_any);
> + flags_ext = dyn_mcpu_ext_opt ? *dyn_mcpu_ext_opt : arm_arch_none;
> + skip_exact_match = ARM_FEATURE_EQUAL (selected_cpu, arm_arch_any);
> + }
> +
> + /* When this function is run again after relaxation has happened there is no
> + way to determine whether an architecture or CPU was specified by the user:
> + - selected_cpu is set above for relaxation to work;
> + - march_cpu_opt is not set if only -mcpu or .cpu is used;
> + - mcpu_cpu_opt is set to arm_arch_any for autodetection.
> + Therefore, if not in -march=all case we first try an exact match and fall
> + back to autodetection. */
> + if (!skip_exact_match)
> + arch = get_aeabi_cpu_arch_from_fset (&flags_arch, &flags_ext, &profile, 1);
> + if (arch == -1)
> + arch = get_aeabi_cpu_arch_from_fset (&flags_arch, &flags_ext, &profile, 0);
> + if (arch == -1)
> + as_bad (_("no architecture contains all the instructions used\n"));
>
> /* Tag_CPU_name. */
> if (selected_cpu_name[0])
> @@ -26708,18 +26868,6 @@ aeabi_set_public_attributes (void)
> aeabi_set_attribute_int (Tag_CPU_arch, arch);
>
> /* Tag_CPU_arch_profile. */
> - if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a)
> - || ARM_CPU_HAS_FEATURE (flags, arm_ext_v8)
> - || (ARM_CPU_HAS_FEATURE (flags, arm_ext_atomics)
> - && !ARM_CPU_HAS_FEATURE (flags, arm_ext_v8m_m_only)))
> - profile = 'A';
> - else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
> - profile = 'R';
> - else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_m))
> - profile = 'M';
> - else
> - profile = '\0';
> -
> if (profile != '\0')
> aeabi_set_attribute_int (Tag_CPU_arch_profile, profile);
>
> @@ -26727,14 +26875,15 @@ aeabi_set_public_attributes (void)
> if (dyn_mcpu_ext_opt && ARM_CPU_HAS_FEATURE (*dyn_mcpu_ext_opt, arm_ext_dsp))
> aeabi_set_attribute_int (Tag_DSP_extension, 1);
>
> + ARM_CLEAR_FEATURE (flags_arch, flags, fpu_any);
> /* Tag_ARM_ISA_use. */
> if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v1)
> - || arch == 0)
> + || ARM_FEATURE_ZERO (flags_arch))
> aeabi_set_attribute_int (Tag_ARM_ISA_use, 1);
>
> /* Tag_THUMB_ISA_use. */
> if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v4t)
> - || arch == 0)
> + || ARM_FEATURE_ZERO (flags_arch))
> {
> int thumb_isa_use;
>
> diff --git a/gas/testsuite/gas/arm/attr-march-armv1.d b/gas/testsuite/gas/arm/attr-march-armv1.d
> index ac6597743ea4c9e408f656d0b264052a17ae0a66..d9730b5d58bd50c69293926c67f0340dd95e4a02 100644
> --- a/gas/testsuite/gas/arm/attr-march-armv1.d
> +++ b/gas/testsuite/gas/arm/attr-march-armv1.d
> @@ -8,5 +8,4 @@
> Attribute Section: aeabi
> File Attributes
> Tag_CPU_name: "1"
> - Tag_CPU_arch: v4
> Tag_ARM_ISA_use: Yes
> diff --git a/gas/testsuite/gas/arm/attr-march-armv2.d b/gas/testsuite/gas/arm/attr-march-armv2.d
> index 0b574efbbbc59d111232000ddb2e8003419cd6d5..39e337192957a82718da5bbd137ee3fe546a3fe0 100644
> --- a/gas/testsuite/gas/arm/attr-march-armv2.d
> +++ b/gas/testsuite/gas/arm/attr-march-armv2.d
> @@ -8,5 +8,4 @@
> Attribute Section: aeabi
> File Attributes
> Tag_CPU_name: "2"
> - Tag_CPU_arch: v4
> Tag_ARM_ISA_use: Yes
> diff --git a/gas/testsuite/gas/arm/attr-march-armv2a.d b/gas/testsuite/gas/arm/attr-march-armv2a.d
> index 387e4a318041428cb07c914a9980ee4fe5604d80..2c4dd620d3d690474ebb862b1ac340f24d3500de 100644
> --- a/gas/testsuite/gas/arm/attr-march-armv2a.d
> +++ b/gas/testsuite/gas/arm/attr-march-armv2a.d
> @@ -8,5 +8,4 @@
> Attribute Section: aeabi
> File Attributes
> Tag_CPU_name: "2A"
> - Tag_CPU_arch: v4
> Tag_ARM_ISA_use: Yes
> diff --git a/gas/testsuite/gas/arm/attr-march-armv2s.d b/gas/testsuite/gas/arm/attr-march-armv2s.d
> index 3bd06e62f070e1433671bbf2e7a3b6ab0cbf9ce3..dfd17d2b37716ac2d5d167020e0fb957b81b2f85 100644
> --- a/gas/testsuite/gas/arm/attr-march-armv2s.d
> +++ b/gas/testsuite/gas/arm/attr-march-armv2s.d
> @@ -8,5 +8,4 @@
> Attribute Section: aeabi
> File Attributes
> Tag_CPU_name: "2S"
> - Tag_CPU_arch: v4
> Tag_ARM_ISA_use: Yes
> diff --git a/gas/testsuite/gas/arm/attr-march-armv3.d b/gas/testsuite/gas/arm/attr-march-armv3.d
> index 13d5d183946d099a10d3f026d2f1d4aae878cea9..988f896529370f353e2f64d1f56f703c12408eed 100644
> --- a/gas/testsuite/gas/arm/attr-march-armv3.d
> +++ b/gas/testsuite/gas/arm/attr-march-armv3.d
> @@ -8,5 +8,4 @@
> Attribute Section: aeabi
> File Attributes
> Tag_CPU_name: "3"
> - Tag_CPU_arch: v4
> Tag_ARM_ISA_use: Yes
> diff --git a/gas/testsuite/gas/arm/attr-march-armv3m.d b/gas/testsuite/gas/arm/attr-march-armv3m.d
> index 4e2439972d84ea0e385f1b6d1fc24326505eacf0..c946b37177a91bdbae616094cb5671bdc26bd8cf 100644
> --- a/gas/testsuite/gas/arm/attr-march-armv3m.d
> +++ b/gas/testsuite/gas/arm/attr-march-armv3m.d
> @@ -8,5 +8,4 @@
> Attribute Section: aeabi
> File Attributes
> Tag_CPU_name: "3M"
> - Tag_CPU_arch: v4
> Tag_ARM_ISA_use: Yes
> diff --git a/include/opcode/arm.h b/include/opcode/arm.h
> index bb68a78154a41d577ffa293b19b951dcd7085247..5691a85545cf924383f9c73d9ce9a97a3a835cdf 100644
> --- a/include/opcode/arm.h
> +++ b/include/opcode/arm.h
> @@ -285,6 +285,7 @@
> #define ARM_ARCH_NONE ARM_FEATURE_LOW (0, 0)
> #define FPU_NONE ARM_FEATURE_LOW (0, 0)
> #define ARM_ANY ARM_FEATURE (-1, -1, 0) /* Any basic core. */
> +#define FPU_ANY ARM_FEATURE_COPROC (-1) /* Any FPU. */
> #define ARM_FEATURE_ALL ARM_FEATURE (-1, -1, -1)/* All CPU and FPU features. */
> #define FPU_ANY_HARD ARM_FEATURE_COPROC (FPU_FPA | FPU_VFP_HARD | FPU_MAVERICK)
> /* Extensions containing some Thumb-2 instructions. If any is present, Thumb
>