Re: [PATCH 3/7] RISC-V: Support new GAS options and configure options to set ISA versions.

Palmer Dabbelt
2020-04-23T22:59:02Z

On Sat, 18 Apr 2020 04:07:51 PDT (-0700), nelson.chu@sifive.com wrote:
> For now, we can only use the GAS option -march and ELF arch attribute to set
> the versions for ISA extensions. It seems not so friendly for user.
> Therefore, we support new GAS options and configure options to make it easiler
> for user.
>
> New Assembler Options,
>
> * -misa-spec = [2p0|2p1|2p2|20190608|20191213]
> You can simply choose the ISA spec by this option, and then assembler will set
> the version for the standard extensions if you don’t set in the ELF arch
> attributes or -march option.

This makes sense.

> * -mriscv-isa-version = <ISA-string>
> The syntax of <ISA-string> is same as -march option, but without rv32 or rv64
> prefix. There are two reasons that you may need this option,
>
> 1. Some versions of extensions defined in the ISA spec are not matched to the
> toolchain’s implementation. For example, V-ext is defined to version 0.7 in
> ISA spec, but we only have implementations for 0.8 and 0.9. Therefore, you
> have to use this option to choose the correct version for V-ext.
>
> 2. You want to update the version for the specific standard extensions if the
> version are not set in the ELF arch attributes and -march option.

I don't buy the argument for this. The V extension stuff isn't relevant: those
are all draft versions, and this is a perfect reason why we don't want to take
drafts upstream. When we have a defined V ISA it'll be part of a versioned
RISC-V specification and any users that want it can just use at least that ISA
spec.

For the second argument, why not just provide those via -march? I can buy that
it's a pain to build up valid -march strings in build scripts, but this just
fixes a specific instance of that problem (and that's not going to be that
common, as most users just want a single ISA version).

I haven't really looked at the code, as dropping this will change the patches
pretty drasticly.

> New Default Configure Options,
>
> * --with-arch = <ISA-string>
> The syntax of <ISA-string> is same as -march option. Assembler will check this
> if -march option and ELF arch attributes aren’t set.

Ya, we should have had that a while ago :)

> * --with-isa-spec = [2p0|2p1|2p2|20190608|20191213]
> The syntax is same as -misa-spec option. Assembler will check this if
> -misa-spec option isn’t set.
>
> * --with-riscv-isa-version = <ISA-string>
> The syntax of <ISA-string> is same as -mriscv-isa-version option. Assembler
> will check this if -mriscv-isa-version option isn’t set.
>
> The Priority of these options,
>
> * ELF arch attributes > Assembler options > Default configure options
> * For GAS options, -march > -mriscv-isa-version > -misa-spec
> * For configure options, --with-arch > --with-riscv-isa-version > --with-isa-spec
>
> gas/
> * config/tc-riscv.c (DEFAULT_ARCH_WITH_EXT, DEFAULT_ISA_SPEC,
> DEFAULT_RISCV_ISA_VERSION): Default configure option settings.
> You can set them by new configure options --with-arch,
> --with-isa-spec and --with-riscv-isa-version.
>
> (default_arch_with_ext, default_isa_spec, default_riscv_isa_version):
> const char strings which are used to set the ISA extensions. You can
> use gas options -march (or ELF build attributes), and new gas options
> -misa-spec and -mriscv-isa-version to set them, respectively. If the
> gas options and attributes are not set, then assembler will check the
> default configure option settings.
>
> (ext_version_hash): The hash table used to handle the extensions
> with versions.
> (init_ext_version_hash): Initialize the ext_version_hash according
> to riscv_ext_version_table.
>
> (riscv_get_default_ext_version): The callback function of
> riscv_parse_subset_t. According to the choosed ISA spec,
> get the default version for the specific extension.
>
> (riscv_set_arch): Add new bfd_boolean parameter update_version.
> The update_version is TRUE means we just want to update the version
> according to default_riscv_isa_version, so don't call the
> riscv_release_subset_list to reset the subset list. Pass two new
> arguments to riscv_parse_subset, one is update_version mentioned above,
> the other is the default_isa_spec. We use the default_isa_spec to
> choose the default version for the extensions.
>
> (enum options, struct option md_longopts): Add new gas options,
> -misa-spec and -mriscv-isa-version.
> (md_parse_option): Handle the above new gas options.
> (riscv_after_parse_args): Call init_ext_version_hash to initialize the
> ext_version_hash, and then always call riscv_set_arch twice to set and
> update the architecture with versions according to default_arch_with_ext
> and default_riscv_isa_version.
> (s_riscv_attribute): Same as riscv_after_parse_args, we need to call
> riscv_set_arch twice.
>
> * testsuite/gas/riscv/attribute-01.d: Add -misa-spec=2p2. Set 0p0
> as default version for x extensions.
> * testsuite/gas/riscv/attribute-02.d: Likewise.
> * testsuite/gas/riscv/attribute-03.d: Likewise.
> * testsuite/gas/riscv/attribute-04.d: Likewise.
> * testsuite/gas/riscv/attribute-05.d: Likewise.
> * testsuite/gas/riscv/attribute-06.d: Likewise.
> * testsuite/gas/riscv/attribute-07.d: Likewise.
> * testsuite/gas/riscv/attribute-08.d: Likewise.
> * testsuite/gas/riscv/attribute-09.d: New testcase. For i-ext, we
> already set the version 1p9 in elf attribute, so -misa-spec and
> -mriscv-isa-version don't update the version to 2p0 and 2p1.
> For f-ext, we don't set the version to it, so use the default version
> 2p0 according to the ISA spec 2p2. For v-ext, the default version is
> 0p7 according to ISA spec 2p2, but we use -mriscv-isa-version to update
> it to 0p9. For a-ext, it isn't enabled by -march or elf attribute, so
> we don't update it's version even if -mriscv-isa-version is set.
> As for the zicsr extension, it is defined in the lastest ISA spec
> rather than 2p2, so set it's version to 0p0.
> * testsuite/gas/riscv/attribute-09.s: Likewise.
> * testsuite/gas/riscv/attribute-10.d: New testcase. The version of
> zicsr is 2p0 according to ISA spec 20191213.
> * testsuite/gas/riscv/attribute-11.d: New testcase. We can also update
> the z* extension by -mriscv-isa-version.
>
> * configure.ac: Add new configure options, --with-arch, --with-isa-spec
> and --with-riscv-isa-version.
> * configure: Regenerated.
> * config.in: Regenerated.
>
> bfd/
> * elfxx-riscv.h (struct riscv_subset_t): Add new bfd_boolean field
> use_default_version, which is used to record whether the default
> version is used for the extension.
> (struct riscv_parse_subset_t): Add new callback function
> get_default_version. It is used to find the default version for
> the specific extension.
> (riscv_add_subset, riscv_parse_subset): Update function declaration.
>
> * elfxx-riscv.c (riscv_parsing_subset_version): Remove the parameters
> default_major_version and default_minor_version. Add new bfd_boolean
> parameter *use_default_version. Set it to TRUE if we need to call
> the callback rps->get_default_version to find the default version.
>
> (riscv_update_subset_version): Only update the version of existin
> standard extensions and their Z* sub extensions, if -mriscv-isa-version
> or --with-riscv-isa-version are set, and the default version are used.
>
> (riscv_add_subset): New parameter use_default_version. Record whether
> the default version is used. riscv_update_subset_version only update
> the version of extensions if the default versions are used.
>
> (riscv_parse_subset): Add two parameters isa_spec_name and
> update_version. Pass them to riscv_parse_std_ext and
> riscv_parse_prefixed_ext. The string set by -mriscv-isa-version or
> --with-riscv-isa-version doesn't have to start with rv32/rv64, so
> skip the checking if update_version is TRUE.
> (riscv_parse_std_ext): If update_version is TRUE, then we just call
> riscv_update_subset_version to update the default version. Otherwise,
> Call rps->get_default_version if we fail to find the default version
> in riscv_parsing_subset_version, and then call riscv_add_subset to add
> the subset into subset list.
> (riscv_parse_prefixed_ext): Same as the riscv_parse_std_ext.
> (riscv_std_z_ext_strtab): Support Zicsr extensions.
>
> * elfnn-riscv.c (riscv_merge_std_ext, riscv_merge_multi_letter_ext):
> Updated. Pass update_version as FALSE to riscv_add_subset, the
> update_version is only needed for assembler, not linker.
> (riscv_merge_arch_attr_info): The callback function get_default_version
> is only needed for assembler, so set it to NULL in linker. Also, Pass
> isa_spec_name as NULL and update_version as FALSE to riscv_parse_subset.
>
> include/
> * opcode/riscv.h (struct riscv_ext_version): New structure holds
> version information for the specific ISA.
>
> opcodes/
> * riscv-opc.c (riscv_ext_version_table): The table used to store
> all information about the supported spec and the corresponding ISA
> versions. Currently, only Zicsr is supported to verify the
> correctness of Z sub extension settings. Others will be supported
> in the future patches.
> ---
> bfd/elfnn-riscv.c | 24 ++-
> bfd/elfxx-riscv.c | 350 ++++++++++++++++++++++++---------
> bfd/elfxx-riscv.h | 12 +-
> gas/config.in | 9 +
> gas/config/tc-riscv.c | 128 +++++++++++-
> gas/configure | 53 ++++-
> gas/configure.ac | 35 +++-
> gas/testsuite/gas/riscv/attribute-01.d | 2 +-
> gas/testsuite/gas/riscv/attribute-02.d | 4 +-
> gas/testsuite/gas/riscv/attribute-03.d | 4 +-
> gas/testsuite/gas/riscv/attribute-04.d | 2 +-
> gas/testsuite/gas/riscv/attribute-05.d | 2 +-
> gas/testsuite/gas/riscv/attribute-06.d | 2 +-
> gas/testsuite/gas/riscv/attribute-07.d | 2 +-
> gas/testsuite/gas/riscv/attribute-08.d | 2 +-
> gas/testsuite/gas/riscv/attribute-09.d | 6 +
> gas/testsuite/gas/riscv/attribute-09.s | 1 +
> gas/testsuite/gas/riscv/attribute-10.d | 6 +
> gas/testsuite/gas/riscv/attribute-11.d | 6 +
> include/opcode/riscv.h | 11 ++
> opcodes/riscv-opc.c | 53 +++++
> 21 files changed, 585 insertions(+), 129 deletions(-)
> create mode 100644 gas/testsuite/gas/riscv/attribute-09.d
> create mode 100644 gas/testsuite/gas/riscv/attribute-09.s
> create mode 100644 gas/testsuite/gas/riscv/attribute-10.d
> create mode 100644 gas/testsuite/gas/riscv/attribute-11.d
>
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index 8fcb106..4ca49e0 100644
> --- a/bfd/elfnn-riscv.c
> +++ b/bfd/elfnn-riscv.c
> @@ -2802,7 +2802,7 @@ riscv_merge_std_ext (bfd *ibfd,
> if (!riscv_i_or_e_p (ibfd, out_arch, out))
> return FALSE;
>
> - if (in->name[0] != out->name[0])
> + if (strcasecmp (in->name, out->name) != 0)
> {
> /* TODO: We might allow merge 'i' with 'e'. */
> _bfd_error_handler
> @@ -2818,8 +2818,8 @@ riscv_merge_std_ext (bfd *ibfd,
> return FALSE;
> }
> else
> - riscv_add_subset (&merged_subsets,
> - in->name, in->major_version, in->minor_version);
> + riscv_add_subset (&merged_subsets, in->name, in->major_version,
> + in->minor_version, FALSE);
>
> in = in->next;
> out = out->next;
> @@ -2848,7 +2848,7 @@ riscv_merge_std_ext (bfd *ibfd,
>
> struct riscv_subset_t *merged = find_in ? find_in : find_out;
> riscv_add_subset (&merged_subsets, merged->name,
> - merged->major_version, merged->minor_version);
> + merged->major_version, merged->minor_version, FALSE);
> }
>
> /* Skip all standard extensions. */
> @@ -2917,14 +2917,14 @@ riscv_merge_multi_letter_ext (bfd *ibfd,
> {
> /* `in' comes before `out', append `in' and increment. */
> riscv_add_subset (&merged_subsets, in->name, in->major_version,
> - in->minor_version);
> + in->minor_version, FALSE);
> in = in->next;
> }
> else if (cmp > 0)
> {
> /* `out' comes before `in', append `out' and increment. */
> riscv_add_subset (&merged_subsets, out->name, out->major_version,
> - out->minor_version);
> + out->minor_version, FALSE);
> out = out->next;
> }
> else
> @@ -2938,7 +2938,7 @@ riscv_merge_multi_letter_ext (bfd *ibfd,
> }
>
> riscv_add_subset (&merged_subsets, out->name, out->major_version,
> - out->minor_version);
> + out->minor_version, FALSE);
> out = out->next;
> in = in->next;
> }
> @@ -2952,7 +2952,7 @@ riscv_merge_multi_letter_ext (bfd *ibfd,
> while (tail)
> {
> riscv_add_subset (&merged_subsets, tail->name, tail->major_version,
> - tail->minor_version);
> + tail->minor_version, FALSE);
> tail = tail->next;
> }
> }
> @@ -2975,13 +2975,17 @@ riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch)
> riscv_parse_subset_t rpe_in;
> riscv_parse_subset_t rpe_out;
>
> + /* Only assembler needs to check the default version of ISA, so just set
> + the rpe_in.get_default_version and rpe_out.get_default_version to NULL. */
> rpe_in.subset_list = &in_subsets;
> rpe_in.error_handler = _bfd_error_handler;
> rpe_in.xlen = &xlen_in;
> + rpe_in.get_default_version = NULL;
>
> rpe_out.subset_list = &out_subsets;
> rpe_out.error_handler = _bfd_error_handler;
> rpe_out.xlen = &xlen_out;
> + rpe_out.get_default_version = NULL;
>
> if (in_arch == NULL && out_arch == NULL)
> return NULL;
> @@ -2993,10 +2997,10 @@ riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch)
> return in_arch;
>
> /* Parse subset from arch string. */
> - if (!riscv_parse_subset (&rpe_in, in_arch))
> + if (!riscv_parse_subset (&rpe_in, in_arch, NULL, FALSE))
> return NULL;
>
> - if (!riscv_parse_subset (&rpe_out, out_arch))
> + if (!riscv_parse_subset (&rpe_out, out_arch, NULL, FALSE))
> return NULL;
>
> /* Checking XLEN. */
> diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
> index b15fdee..3a6aaf3 100644
> --- a/bfd/elfxx-riscv.c
> +++ b/bfd/elfxx-riscv.c
> @@ -1025,9 +1025,8 @@ riscv_elf_add_sub_reloc (bfd *abfd,
> `minor_version`: Parsing result of minor version, set to 0 if version is
> not present in arch string, but set to `default_minor_version` if
> `major_version` using default_major_version.
> - `default_major_version`: Default major version.
> - `default_minor_version`: Default minor version.
> - `std_ext_p`: True if parsing std extension. */
> + `std_ext_p`: True if parsing std extension.
> + `use_default_version`: Set it to True if we need the default version. */
>
> static const char *
> riscv_parsing_subset_version (riscv_parse_subset_t *rps,
> @@ -1035,17 +1034,16 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps,
> const char *p,
> unsigned *major_version,
> unsigned *minor_version,
> - unsigned default_major_version,
> - unsigned default_minor_version,
> - bfd_boolean std_ext_p)
> + bfd_boolean std_ext_p,
> + bfd_boolean *use_default_version)
> {
> bfd_boolean major_p = TRUE;
> unsigned version = 0;
> - unsigned major = 0;
> - unsigned minor = 0;
> char np;
>
> - for (;*p; ++p)
> + *major_version = 0;
> + *minor_version = 0;
> + for (; *p; ++p)
> {
> if (*p == 'p')
> {
> @@ -1057,7 +1055,6 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps,
> if (std_ext_p)
> {
> *major_version = version;
> - *minor_version = 0;
> return p;
> }
> else
> @@ -1068,7 +1065,7 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps,
> }
> }
>
> - major = version;
> + *major_version = version;
> major_p = FALSE;
> version = 0;
> }
> @@ -1079,21 +1076,15 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps,
> }
>
> if (major_p)
> - major = version;
> + *major_version = version;
> else
> - minor = version;
> + *minor_version = version;
>
> - if (major == 0 && minor == 0)
> - {
> - /* We don't found any version string, use default version. */
> - *major_version = default_major_version;
> - *minor_version = default_minor_version;
> - }
> - else
> - {
> - *major_version = major;
> - *minor_version = minor;
> - }
> + /* We can not find any version in string, need to parse default version. */
> + if (use_default_version != NULL
> + && *major_version == 0
> + && *minor_version == 0)
> + *use_default_version = TRUE;
> return p;
> }
>
> @@ -1106,6 +1097,41 @@ riscv_supported_std_ext (void)
> return "mafdqlcbjtpvn";
> }
>
> +/* Update the version of standard extensions and their Z* sub extensions
> + if -mriscv-isa-version is set. */
> +
> +static bfd_boolean
> +riscv_update_subset_version (riscv_parse_subset_t *rps,
> + const char *ext_with_version,
> + char *ext,
> + unsigned major_version,
> + unsigned minor_version,
> + bfd_boolean use_default_version)
> +{
> + riscv_subset_t *subset = riscv_lookup_subset (rps->subset_list, ext);;
> +
> + /* The extension doesn't exist, so just return. */
> + if (subset == NULL)
> + return TRUE;
> +
> + /* This means we can not find the version in the string. */
> + if (use_default_version)
> + {
> + rps->error_handler ("-mriscv-isa-version=%s: unexpected version "
> + "setting for subset `%s'", ext_with_version, ext);
> + return FALSE;
> + }
> +
> + /* We only update the extension which use the default version. */
> + if (subset->use_default_version)
> + {
> + subset->major_version = major_version;
> + subset->minor_version = minor_version;
> + }
> +
> + return TRUE;
> +}
> +
> /* Parsing function for standard extensions.
>
> Return Value:
> @@ -1114,46 +1140,95 @@ riscv_supported_std_ext (void)
> Arguments:
> `rps`: Hooks and status for parsing subset.
> `march`: Full arch string.
> - `p`: Curent parsing position. */
> + `p`: Curent parsing position.
> + `isa_spec_name`: The ISA spec name. We set the default ISA versions
> + according to it.
> + `update_version`: True if the -mriscv-isa-version is set, and we need
> + to update the version for the existing extensions. */
>
> static const char *
> riscv_parse_std_ext (riscv_parse_subset_t *rps,
> - const char *march, const char *p)
> + const char *march,
> + const char *p,
> + const char *isa_spec_name,
> + bfd_boolean update_version)
> {
> const char *all_std_exts = riscv_supported_std_ext ();
> const char *std_exts = all_std_exts;
> -
> unsigned major_version = 0;
> unsigned minor_version = 0;
> char std_ext = '\0';
> + bfd_boolean use_default_version = FALSE;
>
> /* First letter must start with i, e or g. */
> switch (*p)
> {
> case 'i':
> - p++;
> - p = riscv_parsing_subset_version (
> - rps,
> - march,
> - p, &major_version, &minor_version,
> - /* default_major_version= */ 2,
> - /* default_minor_version= */ 0,
> - /* std_ext_p= */TRUE);
> - riscv_add_subset (rps->subset_list, "i", major_version, minor_version);
> + p = riscv_parsing_subset_version (rps,
> + march,
> + ++p,
> + &major_version,
> + &minor_version,
> + /* std_ext_p= */TRUE,
> + &use_default_version);
> +
> + /* Update the version for exsiting extension. */
> + if (update_version)
> + {
> + if (!riscv_update_subset_version (rps, march, "i",
> + major_version,
> + minor_version,
> + use_default_version))
> + return NULL;
> + break;
> + }
> +
> + /* Find the default version if needed. */
> + if (use_default_version)
> + rps->get_default_version ("i",
> + isa_spec_name,
> + &major_version,
> + &minor_version);
> + riscv_add_subset (rps->subset_list, "i", major_version, minor_version,
> + use_default_version);
> break;
>
> case 'e':
> - p++;
> - p = riscv_parsing_subset_version (
> - rps,
> - march,
> - p, &major_version, &minor_version,
> - /* default_major_version= */ 1,
> - /* default_minor_version= */ 9,
> - /* std_ext_p= */TRUE);
> -
> - riscv_add_subset (rps->subset_list, "e", major_version, minor_version);
> - riscv_add_subset (rps->subset_list, "i", 2, 0);
> + p = riscv_parsing_subset_version (rps,
> + march,
> + ++p,
> + &major_version,
> + &minor_version,
> + /* std_ext_p= */TRUE,
> + &use_default_version);
> +
> + /* Update the version for exsiting extension. */
> + if (update_version)
> + {
> + if (!riscv_update_subset_version (rps, march, "e",
> + major_version,
> + minor_version,
> + use_default_version))
> + return NULL;
> + break;
> + }
> +
> + /* Find the default version if needed. */
> + if (use_default_version)
> + rps->get_default_version ("e",
> + isa_spec_name,
> + &major_version,
> + &minor_version);
> + riscv_add_subset (rps->subset_list, "e", major_version, minor_version,
> + use_default_version);
> +
> + /* i-ext must be enabled. */
> + rps->get_default_version ("i",
> + isa_spec_name,
> + &major_version,
> + &minor_version);
> + riscv_add_subset (rps->subset_list, "i", major_version, minor_version,
> + TRUE);
>
> if (*rps->xlen > 32)
> {
> @@ -1161,35 +1236,58 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,
> march, *rps->xlen);
> return NULL;
> }
> -
> break;
>
> case 'g':
> - p++;
> - p = riscv_parsing_subset_version (
> - rps,
> - march,
> - p, &major_version, &minor_version,
> - /* default_major_version= */ 2,
> - /* default_minor_version= */ 0,
> - /* std_ext_p= */TRUE);
> - riscv_add_subset (rps->subset_list, "i", major_version, minor_version);
> + /* The g-ext shouldn't has the version, so we just skip the setting if
> + user set a version to it. */
> + p = riscv_parsing_subset_version (rps,
> + march,
> + ++p,
> + &major_version,
> + &minor_version,
> + TRUE,
> + &use_default_version);
> +
> + /* Set the version of g in -mriscv-isa-version is meaningless,
> + so just skip it. */
> + if (update_version)
> + break;
> +
> + /* i-ext must be enabled. */
> + rps->get_default_version ("i",
> + isa_spec_name,
> + &major_version,
> + &minor_version);
> + riscv_add_subset (rps->subset_list, "i", major_version, minor_version,
> + TRUE);
>
> for ( ; *std_exts != 'q'; std_exts++)
> {
> const char subset[] = {*std_exts, '\0'};
> - riscv_add_subset (
> - rps->subset_list, subset, major_version, minor_version);
> + rps->get_default_version (subset,
> + isa_spec_name,
> + &major_version,
> + &minor_version);
> + riscv_add_subset (rps->subset_list, subset, major_version,
> + minor_version, TRUE);
> }
> break;
>
> default:
> - rps->error_handler (
> - "-march=%s: first ISA subset must be `e', `i' or `g'", march);
> - return NULL;
> + /* The first ISA subset of -mriscv-isa-version will not necessarily
> + be e/i/g. */
> + if (!update_version)
> + {
> + rps->error_handler (
> + "-march=%s: first ISA subset must be `e', `i' or `g'", march);
> + return NULL;
> + }
> }
>
> - while (*p)
> + /* The riscv_parsing_subset_version may set `p` to NULL, so I think we should
> + skip parsing the string if `p` is NULL or value of `p` is `\0`. */
> + while (p != NULL && *p != '\0')
> {
> char subset[2] = {0, 0};
>
> @@ -1218,21 +1316,37 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,
> march, *p);
> return NULL;
> }
> -
> std_exts++;
>
> - p++;
> - p = riscv_parsing_subset_version (
> - rps,
> - march,
> - p, &major_version, &minor_version,
> - /* default_major_version= */ 2,
> - /* default_minor_version= */ 0,
> - /* std_ext_p= */TRUE);
> -
> + use_default_version = FALSE;
> subset[0] = std_ext;
> + p = riscv_parsing_subset_version (rps,
> + march,
> + ++p,
> + &major_version,
> + &minor_version,
> + TRUE,
> + &use_default_version);
> +
> + /* Update the version for exsiting extension. */
> + if (update_version)
> + {
> + if (!riscv_update_subset_version (rps, march, subset,
> + major_version,
> + minor_version,
> + use_default_version))
> + return NULL;
> + continue;
> + }
>
> - riscv_add_subset (rps->subset_list, subset, major_version, minor_version);
> + /* Find the default version if needed. */
> + if (use_default_version)
> + rps->get_default_version (subset,
> + isa_spec_name,
> + &major_version,
> + &minor_version);
> + riscv_add_subset (rps->subset_list, subset, major_version, minor_version,
> + use_default_version);
> }
> return p;
> }
> @@ -1272,21 +1386,28 @@ typedef struct riscv_parse_config
> } riscv_parse_config_t;
>
> /* Parse a generic prefixed extension.
> - march: The full architecture string as passed in by "-march=...".
> - p: Point from which to start parsing the -march string.
> - config: What class of extensions to parse, predicate funcs,
> - and strings to use in error reporting. */
> + `march`: The full architecture string as passed in by "-march=...".
> + `p`: Point from which to start parsing the -march string.
> + `config`: What class of extensions to parse, predicate funcs,
> + and strings to use in error reporting.
> + `isa_spec_name`: ISA spec name. We set the default ISA versions
> + according to it.
> + `update_version`: True if the -mriscv-isa-version is set, and we need
> + update the version for the existing extensions. */
>
> static const char *
> riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
> const char *march,
> const char *p,
> - const riscv_parse_config_t *config)
> + const riscv_parse_config_t *config,
> + const char *isa_spec_name,
> + bfd_boolean update_version)
> {
> unsigned major_version = 0;
> unsigned minor_version = 0;
> const char *last_name;
> riscv_isa_ext_class_t class;
> + bfd_boolean use_default_version;
>
> while (*p)
> {
> @@ -1309,15 +1430,11 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
> while (*++q != '\0' && *q != '_' && !ISDIGIT (*q))
> ;
>
> + use_default_version = FALSE;
> end_of_version =
> - riscv_parsing_subset_version (
> - rps,
> - march,
> - q, &major_version, &minor_version,
> - /* default_major_version= */ 2,
> - /* default_minor_version= */ 0,
> - /* std_ext_p= */FALSE);
> -
> + riscv_parsing_subset_version (rps, march, q, &major_version,
> + &minor_version, FALSE,
> + &use_default_version);
> *q = '\0';
>
> /* Check that the name is valid.
> @@ -1335,10 +1452,11 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
> return NULL;
> }
>
> - /* Check that the last item is not the same as this. */
> + /* Check that the last item is not the same as this. Just skip this
> + check when updating the version. */
> last_name = rps->subset_list->tail->name;
> -
> - if (!strcasecmp (last_name, subset))
> + if (!update_version
> + && !strcasecmp (last_name, subset))
> {
> rps->error_handler ("-march=%s: Duplicate %s ISA extension: \'%s\'",
> march, config->prefix, subset);
> @@ -1357,7 +1475,30 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
> return NULL;
> }
>
> - riscv_add_subset (rps->subset_list, subset, major_version, minor_version);
> + if (update_version)
> + {
> + /* Update the version for exsiting extension. */
> + if (!riscv_update_subset_version (rps, march, subset,
> + major_version,
> + minor_version,
> + use_default_version))
> + {
> + free (subset);
> + return NULL;
> + }
> + }
> + else
> + {
> + /* Find the default version if needed. */
> + if (use_default_version)
> + rps->get_default_version (subset,
> + isa_spec_name,
> + &major_version,
> + &minor_version);
> + riscv_add_subset (rps->subset_list, subset, major_version,
> + minor_version, use_default_version);
> + }
> +
> free (subset);
> p += end_of_version - subset;
>
> @@ -1384,7 +1525,7 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
>
> static const char * const riscv_std_z_ext_strtab[] =
> {
> - NULL
> + "zicsr", NULL
> };
>
> /* Same as `riscv_std_z_ext_strtab', but for S-class extensions. */
> @@ -1457,11 +1598,17 @@ static const riscv_parse_config_t parse_config[] =
>
> Arguments:
> `rps`: Hooks and status for parsing subset.
> - `arch`: Arch string. */
> + `arch`: Arch string.
> + `isa_spec_name`: The ISA spec name. We set the default ISA versions
> + according to it.
> + `update_version`: True if the -mriscv-isa-version is set, and we need
> + update the version for the existing extensions. */
>
> bfd_boolean
> riscv_parse_subset (riscv_parse_subset_t *rps,
> - const char *arch)
> + const char *arch,
> + const char *isa_spec_name,
> + bfd_boolean update_version)
> {
> const char *p = arch;
> size_t i;
> @@ -1476,15 +1623,17 @@ riscv_parse_subset (riscv_parse_subset_t *rps,
> *rps->xlen = 64;
> p += 4;
> }
> - else
> + else if (!update_version)
> {
> + /* The string set by -mriscv-isa-version doesn't have to start
> + with rv32/rv64. */
> rps->error_handler ("-march=%s: ISA string must begin with rv32 or rv64",
> arch);
> return FALSE;
> }
>
> /* Parsing standard extension. */
> - p = riscv_parse_std_ext (rps, arch, p);
> + p = riscv_parse_std_ext (rps, arch, p, isa_spec_name, update_version);
>
> if (p == NULL)
> return FALSE;
> @@ -1492,7 +1641,8 @@ riscv_parse_subset (riscv_parse_subset_t *rps,
> /* Parse the different classes of extensions in the specified order. */
>
> for (i = 0; i < ARRAY_SIZE (parse_config); ++i) {
> - p = riscv_parse_prefixed_ext (rps, arch, p, &parse_config[i]);
> + p = riscv_parse_prefixed_ext (rps, arch, p, &parse_config[i],
> + isa_spec_name, update_version);
>
> if (p == NULL)
> return FALSE;
> @@ -1543,7 +1693,8 @@ riscv_parse_subset (riscv_parse_subset_t *rps,
> void
> riscv_add_subset (riscv_subset_list_t *subset_list,
> const char *subset,
> - int major, int minor)
> + int major, int minor,
> + bfd_boolean use_default_version)
> {
> riscv_subset_t *s = xmalloc (sizeof *s);
>
> @@ -1553,6 +1704,9 @@ riscv_add_subset (riscv_subset_list_t *subset_list,
> s->name = xstrdup (subset);
> s->major_version = major;
> s->minor_version = minor;
> + /* Record whether the default version is used. The -mriscv-isa-version
> + only update the ISA which use the default version. */
> + s->use_default_version = use_default_version;
> s->next = NULL;
>
> if (subset_list->tail != NULL)
> diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
> index 76ee274..e3d5177 100644
> --- a/bfd/elfxx-riscv.h
> +++ b/bfd/elfxx-riscv.h
> @@ -40,6 +40,7 @@ struct riscv_subset_t
> const char *name;
> int major_version;
> int minor_version;
> + bfd_boolean use_default_version;
> struct riscv_subset_t *next;
> };
>
> @@ -56,7 +57,8 @@ riscv_release_subset_list (riscv_subset_list_t *);
> extern void
> riscv_add_subset (riscv_subset_list_t *,
> const char *,
> - int, int);
> + int, int,
> + bfd_boolean);
>
> extern riscv_subset_t *
> riscv_lookup_subset (const riscv_subset_list_t *,
> @@ -72,11 +74,17 @@ typedef struct {
> void (*error_handler) (const char *,
> ...) ATTRIBUTE_PRINTF_1;
> unsigned *xlen;
> + void (*get_default_version) (const char *,
> + const char *,
> + unsigned int *,
> + unsigned int *);
> } riscv_parse_subset_t;
>
> extern bfd_boolean
> riscv_parse_subset (riscv_parse_subset_t *,
> - const char *);
> + const char *,
> + const char *,
> + bfd_boolean);
>
> extern const char *
> riscv_supported_std_ext (void);
> diff --git a/gas/config.in b/gas/config.in
> index 8724eb1..935bd9b 100644
> --- a/gas/config.in
> +++ b/gas/config.in
> @@ -30,6 +30,9 @@
> /* Default architecture. */
> #undef DEFAULT_ARCH
>
> +/* Define default value for -march */
> +#undef DEFAULT_ARCH_WITH_EXT
> +
> /* Default CRIS architecture. */
> #undef DEFAULT_CRIS_ARCH
>
> @@ -50,12 +53,18 @@
> /* Define to 1 if you want to generate x86 relax relocations by default. */
> #undef DEFAULT_GENERATE_X86_RELAX_RELOCATIONS
>
> +/* Define default value for -misa-spec */
> +#undef DEFAULT_ISA_SPEC
> +
> /* Define to 1 if you want to fix Loongson3 LLSC Errata by default. */
> #undef DEFAULT_MIPS_FIX_LOONGSON3_LLSC
>
> /* Define to 1 if you want to generate RISC-V arch attribute by default. */
> #undef DEFAULT_RISCV_ATTR
>
> +/* Define default isa version which are not covered by --with-isa-spec */
> +#undef DEFAULT_RISCV_ISA_VERSION
> +
> /* Define to 1 if you want to generate GNU x86 used ISA and feature properties
> by default. */
> #undef DEFAULT_X86_USED_NOTE
> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> index 168561e..bfcf2f0 100644
> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -63,7 +63,22 @@ struct riscv_cl_insn
> #define DEFAULT_RISCV_ATTR 0
> #endif
>
> +#ifndef DEFAULT_ARCH_WITH_EXT
> +#define DEFAULT_ARCH_WITH_EXT NULL
> +#endif
> +
> +#ifndef DEFAULT_ISA_SPEC
> +#define DEFAULT_ISA_SPEC "2p2"
> +#endif
> +
> +#ifndef DEFAULT_RISCV_ISA_VERSION
> +#define DEFAULT_RISCV_ISA_VERSION NULL
> +#endif
> +
> static const char default_arch[] = DEFAULT_ARCH;
> +static const char *default_arch_with_ext = DEFAULT_ARCH_WITH_EXT;
> +static const char *default_isa_spec = DEFAULT_ISA_SPEC;
> +static const char *default_riscv_isa_version = DEFAULT_RISCV_ISA_VERSION;
>
> static unsigned xlen = 0; /* width of an x-register */
> static unsigned abi_xlen = 0; /* width of a pointer in the ABI */
> @@ -147,18 +162,87 @@ riscv_multi_subset_supports (enum riscv_insn_class insn_class)
> }
> }
>
> +/* Handle of the extension with version hash table. */
> +static struct hash_control *ext_version_hash = NULL;
> +
> +static struct hash_control *
> +init_ext_version_hash (const struct riscv_ext_version *table)
> +{
> + int i = 0;
> + struct hash_control *hash = hash_new ();
> +
> + while (table[i].name)
> + {
> + const char *name = table[i].name;
> + const char *hash_error =
> + hash_insert (hash, name, (void *) &table[i]);
> +
> + if (hash_error != NULL)
> + {
> + fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
> + table[i].name, hash_error);
> + /* Probably a memory allocation problem? Give up now. */
> + as_fatal (_("Broken assembler. No assembly attempted."));
> + return NULL;
> + }
> +
> + i++;
> + while (table[i].name
> + && strcmp (table[i].name, name) == 0)
> + i++;
> + }
> +
> + return hash;
> +}
> +
> +static void
> +riscv_get_default_ext_version (const char *name,
> + const char *spec_name,
> + unsigned int *major_version,
> + unsigned int *minor_version)
> +{
> + struct riscv_ext_version *ext;
> +
> + *major_version = 0;
> + *minor_version = 0;
> +
> + if (name == NULL
> + || spec_name == NULL)
> + return;
> +
> + ext = (struct riscv_ext_version *) hash_find (ext_version_hash, name);
> + while (ext
> + && ext->name
> + && strcmp (ext->name, name) == 0)
> + {
> + if (ext->spec_name
> + && strcmp (ext->spec_name, spec_name) == 0)
> + {
> + *major_version = ext->major_version;
> + *minor_version = ext->minor_version;
> + return;
> + }
> + ext++;
> + }
> +}
> +
> /* Set which ISA and extensions are available. */
>
> static void
> -riscv_set_arch (const char *s)
> +riscv_set_arch (const char *s, bfd_boolean update_version)
> {
> riscv_parse_subset_t rps;
> rps.subset_list = &riscv_subsets;
> rps.error_handler = as_fatal;
> rps.xlen = &xlen;
> + rps.get_default_version = riscv_get_default_ext_version;
>
> - riscv_release_subset_list (&riscv_subsets);
> - riscv_parse_subset (&rps, s);
> + if (s == NULL)
> + return;
> +
> + if (!update_version)
> + riscv_release_subset_list (&riscv_subsets);
> + riscv_parse_subset (&rps, s, default_isa_spec, update_version);
> }
>
> /* Handle of the OPCODE hash table. */
> @@ -2348,6 +2432,8 @@ enum options
> OPTION_NO_ARCH_ATTR,
> OPTION_CSR_CHECK,
> OPTION_NO_CSR_CHECK,
> + OPTION_MISA_SPEC,
> + OPTION_MRISCV_ISA_VERSION,
> OPTION_END_OF_ENUM
> };
>
> @@ -2364,6 +2450,8 @@ struct option md_longopts[] =
> {"mno-arch-attr", no_argument, NULL, OPTION_NO_ARCH_ATTR},
> {"mcsr-check", no_argument, NULL, OPTION_CSR_CHECK},
> {"mno-csr-check", no_argument, NULL, OPTION_NO_CSR_CHECK},
> + {"misa-spec", required_argument, NULL, OPTION_MISA_SPEC},
> + {"mriscv-isa-version", required_argument, NULL, OPTION_MRISCV_ISA_VERSION},
>
> {NULL, no_argument, NULL, 0}
> };
> @@ -2392,7 +2480,9 @@ md_parse_option (int c, const char *arg)
> switch (c)
> {
> case OPTION_MARCH:
> - riscv_set_arch (arg);
> + /* riscv_after_parse_args will call riscv_set_arch to parse
> + the architecture. */
> + default_arch_with_ext = arg;
> break;
>
> case OPTION_NO_PIC:
> @@ -2450,6 +2540,14 @@ md_parse_option (int c, const char *arg)
> riscv_opts.csr_check = FALSE;
> break;
>
> + case OPTION_MISA_SPEC:
> + default_isa_spec = arg;
> + break;
> +
> + case OPTION_MRISCV_ISA_VERSION:
> + default_riscv_isa_version = arg;
> + break;
> +
> default:
> return 0;
> }
> @@ -2460,6 +2558,13 @@ md_parse_option (int c, const char *arg)
> void
> riscv_after_parse_args (void)
> {
> + /* Initialize the hash table for extensions with default version. */
> + ext_version_hash = init_ext_version_hash (riscv_ext_version_table);
> +
> + /* The --with-arch is optional for now, so we have to set the xlen
> + according to the default_arch, which is set by the --targte, first.
> + Then, we use the xlen to set the default_arch_with_ext if the
> + -march and --with-arch are not set. */
> if (xlen == 0)
> {
> if (strcmp (default_arch, "riscv32") == 0)
> @@ -2469,9 +2574,15 @@ riscv_after_parse_args (void)
> else
> as_bad ("unknown default architecture `%s'", default_arch);
> }
> + if (default_arch_with_ext == NULL)
> + default_arch_with_ext = xlen == 64 ? "rv64g" : "rv32g";
> +
> + /* Set the architecture according to -march or --with-arch. */
> + riscv_set_arch (default_arch_with_ext, FALSE);
>
> - if (riscv_subsets.head == NULL)
> - riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g");
> + /* Update the version info according to -mriscv-isa-spec or
> + --with-riscv-isa-spec. */
> + riscv_set_arch (default_riscv_isa_version, TRUE);
>
> /* Add the RVC extension, regardless of -march, to support .option rvc. */
> riscv_set_rvc (FALSE);
> @@ -3366,7 +3477,7 @@ s_riscv_attribute (int ignored ATTRIBUTE_UNUSED)
> obj_attribute *attr;
> attr = elf_known_obj_attributes_proc (stdoutput);
> if (!start_assemble)
> - riscv_set_arch (attr[Tag_RISCV_arch].s);
> + riscv_set_arch (attr[Tag_RISCV_arch].s, FALSE);
> else
> as_fatal (_(".attribute arch must set before any instructions"));
>
> @@ -3379,6 +3490,9 @@ s_riscv_attribute (int ignored ATTRIBUTE_UNUSED)
> if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach))
> as_warn (_("Could not set architecture and machine"));
> }
> +
> + /* We also need to update the version of ISA here. */
> + riscv_set_arch (default_riscv_isa_version, TRUE);
> }
> }
>
> diff --git a/gas/configure b/gas/configure
> index 1515787..bce847a 100755
> --- a/gas/configure
> +++ b/gas/configure
> @@ -13009,7 +13009,7 @@ $as_echo "#define NDS32_DEFAULT_ZOL_EXT 1" >>confdefs.h
> $as_echo "$enable_zol_ext" >&6; }
> ;;
>
> - aarch64 | i386 | riscv | s390 | sparc)
> + aarch64 | i386 | s390 | sparc)
> if test $this_target = $target ; then
>
> cat >>confdefs.h <<_ACEOF
> @@ -13019,6 +13019,57 @@ _ACEOF
> fi
> ;;
>
> + riscv)
> + # --target=riscv[32|64]-*-*. */
> + if test $this_target = $target ; then
> +
> +cat >>confdefs.h <<_ACEOF
> +#define DEFAULT_ARCH "${arch}"
> +_ACEOF
> +
> + fi
> +
> + # --with-arch=<value>. The syntax of <value> is same as Gas option -march.
> + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for default configuration of --with-arch" >&5
> +$as_echo_n "checking for default configuration of --with-arch... " >&6; }
> + if test "x${with_arch}" != x; then
> +
> +cat >>confdefs.h <<_ACEOF
> +#define DEFAULT_ARCH_WITH_EXT "$with_arch"
> +_ACEOF
> +
> + fi
> + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_arch" >&5
> +$as_echo "$with_arch" >&6; }
> +
> + # --with-isa-spec=[2p0|2p1|2p2|20190608|20191213].
> + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for default configuration of --with-isa-spec" >&5
> +$as_echo_n "checking for default configuration of --with-isa-spec... " >&6; }
> + if test "x${with_isa_spec}" != x; then
> +
> +cat >>confdefs.h <<_ACEOF
> +#define DEFAULT_ISA_SPEC "$with_isa_spec"
> +_ACEOF
> +
> + fi
> + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_isa_spec" >&5
> +$as_echo "$with_isa_spec" >&6; }
> +
> + # --with-riscv-isa-version=<value>. The syntax of <value> is same as Gas
> + # -march, but without the rv[32|64] prefix.
> + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for default configuration of --with-riscv-isa-version" >&5
> +$as_echo_n "checking for default configuration of --with-riscv-isa-version... " >&6; }
> + if test "x${with_riscv_isa_version}" != x; then
> +
> +cat >>confdefs.h <<_ACEOF
> +#define DEFAULT_RISCV_ISA_VERSION "$with_riscv_isa_version"
> +_ACEOF
> +
> + fi
> + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_riscv_isa_version" >&5
> +$as_echo "$with_riscv_isa_version" >&6; }
> + ;;
> +
> rl78)
> f=rl78-parse.o
> case " $extra_objects " in
> diff --git a/gas/configure.ac b/gas/configure.ac
> index 6f32e55..be4ba20 100644
> --- a/gas/configure.ac
> +++ b/gas/configure.ac
> @@ -569,12 +569,45 @@ changequote([,])dnl
> AC_MSG_RESULT($enable_zol_ext)
> ;;
>
> - aarch64 | i386 | riscv | s390 | sparc)
> + aarch64 | i386 | s390 | sparc)
> if test $this_target = $target ; then
> AC_DEFINE_UNQUOTED(DEFAULT_ARCH, "${arch}", [Default architecture.])
> fi
> ;;
>
> + riscv)
> + # --target=riscv[32|64]-*-*. */
> + if test $this_target = $target ; then
> + AC_DEFINE_UNQUOTED(DEFAULT_ARCH, "${arch}", [Default architecture.])
> + fi
> +
> + # --with-arch=<value>. The syntax of <value> is same as Gas option -march.
> + AC_MSG_CHECKING(for default configuration of --with-arch)
> + if test "x${with_arch}" != x; then
> + AC_DEFINE_UNQUOTED(DEFAULT_ARCH_WITH_EXT, "$with_arch",
> + [Define default value for -march])
> + fi
> + AC_MSG_RESULT($with_arch)
> +
> + # --with-isa-spec=[2p0|2p1|2p2|20190608|20191213].
> + AC_MSG_CHECKING(for default configuration of --with-isa-spec)
> + if test "x${with_isa_spec}" != x; then
> + AC_DEFINE_UNQUOTED(DEFAULT_ISA_SPEC, "$with_isa_spec",
> + [Define default value for -misa-spec])
> + fi
> + AC_MSG_RESULT($with_isa_spec)
> +
> + # --with-riscv-isa-version=<value>. The syntax of <value> is same as Gas
> + # -march, but without the rv[32|64] prefix.
> + AC_MSG_CHECKING(for default configuration of --with-riscv-isa-version)
> + if test "x${with_riscv_isa_version}" != x; then
> + AC_DEFINE_UNQUOTED(DEFAULT_RISCV_ISA_VERSION, "$with_riscv_isa_version",
> + [Define default isa version which are not
> + covered by --with-isa-spec])
> + fi
> + AC_MSG_RESULT($with_riscv_isa_version)
> + ;;
> +
> rl78)
> f=rl78-parse.o
> case " $extra_objects " in
> diff --git a/gas/testsuite/gas/riscv/attribute-01.d b/gas/testsuite/gas/riscv/attribute-01.d
> index e22773e..3f9e841 100644
> --- a/gas/testsuite/gas/riscv/attribute-01.d
> +++ b/gas/testsuite/gas/riscv/attribute-01.d
> @@ -1,4 +1,4 @@
> -#as: -march=rv32g -march-attr
> +#as: -march=rv32g -march-attr -misa-spec=2p2
> #readelf: -A
> #source: empty.s
> Attribute Section: riscv
> diff --git a/gas/testsuite/gas/riscv/attribute-02.d b/gas/testsuite/gas/riscv/attribute-02.d
> index bc3295b..a58248e 100644
> --- a/gas/testsuite/gas/riscv/attribute-02.d
> +++ b/gas/testsuite/gas/riscv/attribute-02.d
> @@ -1,6 +1,6 @@
> -#as: -march=rv32gxargle -march-attr
> +#as: -march=rv32gxargle -march-attr -misa-spec=2p2
> #readelf: -A
> #source: empty.s
> Attribute Section: riscv
> File Attributes
> - Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle2p0"
> + Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle0p0"
> diff --git a/gas/testsuite/gas/riscv/attribute-03.d b/gas/testsuite/gas/riscv/attribute-03.d
> index 78b706a..04b9ab5 100644
> --- a/gas/testsuite/gas/riscv/attribute-03.d
> +++ b/gas/testsuite/gas/riscv/attribute-03.d
> @@ -1,6 +1,6 @@
> -#as: -march=rv32gxargle_xfoo -march-attr
> +#as: -march=rv32gxargle_xfoo -march-attr -misa-spec=2p2
> #readelf: -A
> #source: empty.s
> Attribute Section: riscv
> File Attributes
> - Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle2p0_xfoo2p0"
> + Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle0p0_xfoo0p0"
> diff --git a/gas/testsuite/gas/riscv/attribute-04.d b/gas/testsuite/gas/riscv/attribute-04.d
> index c97bf03..8a3f51b 100644
> --- a/gas/testsuite/gas/riscv/attribute-04.d
> +++ b/gas/testsuite/gas/riscv/attribute-04.d
> @@ -1,4 +1,4 @@
> -#as: -march-attr
> +#as: -march-attr -misa-spec=2p2
> #readelf: -A
> #source: attribute-04.s
> Attribute Section: riscv
> diff --git a/gas/testsuite/gas/riscv/attribute-05.d b/gas/testsuite/gas/riscv/attribute-05.d
> index f9b65f2..3309ff3 100644
> --- a/gas/testsuite/gas/riscv/attribute-05.d
> +++ b/gas/testsuite/gas/riscv/attribute-05.d
> @@ -1,4 +1,4 @@
> -#as: -march-attr
> +#as: -march-attr -misa-spec=2p2
> #readelf: -A
> #source: attribute-05.s
> Attribute Section: riscv
> diff --git a/gas/testsuite/gas/riscv/attribute-06.d b/gas/testsuite/gas/riscv/attribute-06.d
> index 1abeb47..5c8a5c6 100644
> --- a/gas/testsuite/gas/riscv/attribute-06.d
> +++ b/gas/testsuite/gas/riscv/attribute-06.d
> @@ -1,4 +1,4 @@
> -#as: -march=rv32g2p0 -march-attr
> +#as: -march=rv32g2p1 -march-attr -misa-spec=2p2
> #readelf: -A
> #source: attribute-06.s
> Attribute Section: riscv
> diff --git a/gas/testsuite/gas/riscv/attribute-07.d b/gas/testsuite/gas/riscv/attribute-07.d
> index dfd7e6b..20ac9be 100644
> --- a/gas/testsuite/gas/riscv/attribute-07.d
> +++ b/gas/testsuite/gas/riscv/attribute-07.d
> @@ -1,4 +1,4 @@
> -#as: -march=rv64g2p0 -march-attr
> +#as: -march=rv64g2p1 -march-attr -misa-spec=2p2
> #readelf: -A
> #source: attribute-07.s
> Attribute Section: riscv
> diff --git a/gas/testsuite/gas/riscv/attribute-08.d b/gas/testsuite/gas/riscv/attribute-08.d
> index c10ac0c..7f580d3 100644
> --- a/gas/testsuite/gas/riscv/attribute-08.d
> +++ b/gas/testsuite/gas/riscv/attribute-08.d
> @@ -1,4 +1,4 @@
> -#as: -march-attr
> +#as: -march-attr -misa-spec=2p2
> #readelf: -A
> #source: attribute-08.s
> Attribute Section: riscv
> diff --git a/gas/testsuite/gas/riscv/attribute-09.d b/gas/testsuite/gas/riscv/attribute-09.d
> new file mode 100644
> index 0000000..77c7ef3
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/attribute-09.d
> @@ -0,0 +1,6 @@
> +#as: -march-attr -misa-spec=2p2 -mriscv-isa-version=i2p1a2p1v0p9
> +#readelf: -A
> +#source: attribute-09.s
> +Attribute Section: riscv
> +File Attributes
> + Tag_RISCV_arch: "rv32i1p9_f2p0_v0p9_zicsr0p0"
> diff --git a/gas/testsuite/gas/riscv/attribute-09.s b/gas/testsuite/gas/riscv/attribute-09.s
> new file mode 100644
> index 0000000..0b1b16c
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/attribute-09.s
> @@ -0,0 +1 @@
> + .attribute arch, "rv32i1p9fv_zicsr"
> diff --git a/gas/testsuite/gas/riscv/attribute-10.d b/gas/testsuite/gas/riscv/attribute-10.d
> new file mode 100644
> index 0000000..9c72035
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/attribute-10.d
> @@ -0,0 +1,6 @@
> +#as: -march-attr -march=rv32i_zicsr -misa-spec=20191213
> +#readelf: -A
> +#source: empty.s
> +Attribute Section: riscv
> +File Attributes
> + Tag_RISCV_arch: "rv32i2p1_zicsr2p0"
> diff --git a/gas/testsuite/gas/riscv/attribute-11.d b/gas/testsuite/gas/riscv/attribute-11.d
> new file mode 100644
> index 0000000..bc7f986
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/attribute-11.d
> @@ -0,0 +1,6 @@
> +#as: -march-attr -march=rv32i_zicsr -misa-spec=20191213 -mriscv-isa-version=zicsr2p1
> +#readelf: -A
> +#source: empty.s
> +Attribute Section: riscv
> +File Attributes
> + Tag_RISCV_arch: "rv32i2p1_zicsr2p1"
> diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
> index ac6e861..f8b0de3 100644
> --- a/include/opcode/riscv.h
> +++ b/include/opcode/riscv.h
> @@ -343,6 +343,16 @@ struct riscv_opcode
> unsigned long pinfo;
> };
>
> +/* This structure holds version information for specific ISA. */
> +
> +struct riscv_ext_version
> +{
> + const char *name;
> + const char *spec_name;
> + unsigned int major_version;
> + unsigned int minor_version;
> +};
> +
> /* Instruction is a simple alias (e.g. "mv" for "addi"). */
> #define INSN_ALIAS 0x00000001
>
> @@ -420,5 +430,6 @@ extern const char * const riscv_fpr_names_abi[NFPR];
>
> extern const struct riscv_opcode riscv_opcodes[];
> extern const struct riscv_opcode riscv_insn_types[];
> +extern const struct riscv_ext_version riscv_ext_version_table[];
>
> #endif /* _RISCV_H_ */
> diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
> index ceedcaf..7b885bf 100644
> --- a/opcodes/riscv-opc.c
> +++ b/opcodes/riscv-opc.c
> @@ -884,3 +884,56 @@ const struct riscv_opcode riscv_insn_types[] =
> /* Terminate the list. */
> {0, 0, INSN_CLASS_NONE, 0, 0, 0, 0, 0}
> };
> +
> +const struct riscv_ext_version riscv_ext_version_table[] =
> +{
> +/* name, spec name, major, minor. */
> +{"e", "20191213", 1, 9},
> +{"e", "20190608", 1, 9},
> +{"e", "2p2", 1, 9},
> +
> +{"i", "20191213", 2, 1},
> +{"i", "20190608", 2, 1},
> +{"i", "2p2", 2, 0},
> +
> +{"m", "20191213", 2, 0},
> +{"m", "20190608", 2, 0},
> +{"m", "2p2", 2, 0},
> +
> +{"a", "20191213", 2, 1},
> +{"a", "20190608", 2, 0},
> +{"a", "2p2", 2, 0},
> +
> +{"f", "20191213", 2, 2},
> +{"f", "20190608", 2, 2},
> +{"f", "2p2", 2, 0},
> +
> +{"d", "20191213", 2, 2},
> +{"d", "20190608", 2, 2},
> +{"d", "2p2", 2, 0},
> +
> +{"q", "20191213", 2, 2},
> +{"q", "20190608", 2, 2},
> +{"q", "2p2", 2, 0},
> +
> +{"c", "20191213", 2, 0},
> +{"c", "20190608", 2, 0},
> +{"c", "2p2", 2, 0},
> +
> +{"p", "20191213", 0, 2},
> +{"p", "20190608", 0, 2},
> +{"p", "2p2", 0, 1},
> +
> +{"v", "20191213", 0, 7},
> +{"v", "20190608", 0, 7},
> +{"v", "2p2", 0, 7},
> +
> +{"n", "20190608", 1, 1},
> +{"n", "2p2", 1, 1},
> +
> +{"zicsr","20191213", 2, 0},
> +{"zicsr","20190608", 2, 0},
> +
> +/* Terminate the list. */
> +{NULL, NULL, 0, 0}
> +};