[PATCH v2 3/9] RISC-V: Support GAS option -misa-spec to set ISA versions.

Nelson Chu nelson.chu@sifive.com
Tue May 19 09:07:48 GMT 2020


PING :)

On Wed, May 6, 2020 at 10:55 AM Nelson Chu <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 option to make it easiler.
>
> * -misa-spec = [2.2|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 do not set in
> the ELF arch attributes or -march option.
>
> The default ISA spec is set to 2.2 rather than the lastest version, if
> the -misa-spec is not set.  The reason is that compiler generates the ISA
> string with fixed 2p0 verisons only for the RISCV ELF architecture attributes,
> but not for the -march option.  We should resolve this in the future patches.
>
>         gas/
>         * config/tc-riscv.c (default_arch_with_ext, default_isa_spec):
>         Static variables which are used to set the ISA extensions. You can
>         use -march (or ELF build attributes) and -misa-spec to set them,
>         respectively.
>
>         (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): Set the callback function.
>
>         (enum options, struct option md_longopts): Add new option -misa-spec.
>         (md_parse_option): Do not call riscv_set_arch for -march.  We will
>         call it later in riscv_after_parse_args.  Call riscv_get_isa_spec_class
>         to set default_isa_spec class.
>         (riscv_after_parse_args): Call init_ext_version_hash to initialize the
>         ext_version_hash, and then call riscv_set_arch to set the architecture
>         with versions according to default_arch_with_ext.
>
>         * testsuite/gas/riscv/attribute-02.d: Set 0p0 as default version for
>         x extensions.
>         * testsuite/gas/riscv/attribute-03.d: Likewise.
>         * testsuite/gas/riscv/attribute-09.d: New testcase.  For i-ext, we
>         already set it's version to 2p1 by march, so no need to use the default
>         2p2 version.  For m-ext, we do not set the version by -march and ELF arch
>         attribute, so set the default 2p0 to it.  For zicsr, it is not defined in
>         ISA spec 2p2, so set 0p0 to it.
>         * testsuite/gas/riscv/attribute-10.d: New testcase.  The version of
>         zicsr is 2p0 according to ISA spec 20191213.
>
>         bfd/
>         * elfxx-riscv.h (riscv_parse_subset_t): Add new callback function
>         get_default_version.  It is used to find the default version for
>         the specific extension.
>
>         * 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_parse_std_ext): 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): Likewise.
>         (riscv_std_z_ext_strtab): Support Zicsr extensions.
>
>         * elfnn-riscv.c (riscv_merge_std_ext): Use strcasecmp to compare the
>         strings rather than characters.
>         riscv_merge_arch_attr_info): The callback function get_default_version
>         is only needed for assembler, so set it to NULL int the linker.
>
>         include/
>         * opcode/riscv.h: Include "bfd.h" to support bfd_boolean.
>         (enum riscv_isa_spec_class): New enum class.  All supported ISA spec
>         belong to one of the class
>         (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.
>         (struct isa_spec_t, isa_specs): List for all supported ISA spec
>         classes and the corresponding strings.
>         (riscv_get_isa_spec_class): New function.  Get the corresponding ISA
>         spec class by giving a ISA spec string.
> ---
>  bfd/elfnn-riscv.c                      |   6 +-
>  bfd/elfxx-riscv.c                      | 203 +++++++++++++++++++--------------
>  bfd/elfxx-riscv.h                      |   3 +
>  gas/config/tc-riscv.c                  | 100 +++++++++++++++-
>  gas/testsuite/gas/riscv/attribute-02.d |   2 +-
>  gas/testsuite/gas/riscv/attribute-03.d |   2 +-
>  gas/testsuite/gas/riscv/attribute-09.d |   6 +
>  gas/testsuite/gas/riscv/attribute-10.d |   6 +
>  include/opcode/riscv.h                 |  26 +++++
>  opcodes/riscv-opc.c                    |  93 +++++++++++++++
>  10 files changed, 355 insertions(+), 92 deletions(-)
>  create mode 100644 gas/testsuite/gas/riscv/attribute-09.d
>  create mode 100644 gas/testsuite/gas/riscv/attribute-10.d
>
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index 473bf50..2b5e713 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
> @@ -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;
> diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
> index b15fdee..e025689 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;
>  }
>
> @@ -1122,38 +1113,58 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,
>  {
>    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);
> +
> +       /* Find the default version if needed.  */
> +       if (use_default_version
> +           && rps->get_default_version != NULL)
> +         rps->get_default_version ("i",
> +                                   &major_version,
> +                                   &minor_version);
> +       riscv_add_subset (rps->subset_list, "i",
> +                         major_version, minor_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);
> +
> +       /* Find the default version if needed.  */
> +       if (use_default_version
> +           && rps->get_default_version != NULL)
> +         rps->get_default_version ("e",
> +                                   &major_version,
> +                                   &minor_version);
> +       riscv_add_subset (rps->subset_list, "e",
> +                         major_version, minor_version);
> +
> +       /* i-ext must be enabled.  */
> +       if (rps->get_default_version != NULL)
> +         rps->get_default_version ("i",
> +                                   &major_version,
> +                                   &minor_version);
> +       riscv_add_subset (rps->subset_list, "i",
> +                         major_version, minor_version);
>
>         if (*rps->xlen > 32)
>           {
> @@ -1161,25 +1172,36 @@ 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);
> +
> +       /* i-ext must be enabled.  */
> +       if (rps->get_default_version != NULL)
> +         rps->get_default_version ("i",
> +                                   &major_version,
> +                                   &minor_version);
> +       riscv_add_subset (rps->subset_list, "i",
> +                         major_version, minor_version);
>
>         for ( ; *std_exts != 'q'; std_exts++)
>           {
>             const char subset[] = {*std_exts, '\0'};
> -           riscv_add_subset (
> -             rps->subset_list, subset, major_version, minor_version);
> +           if (rps->get_default_version != NULL)
> +             rps->get_default_version (subset,
> +                                       &major_version,
> +                                       &minor_version);
> +           riscv_add_subset (rps->subset_list, subset,
> +                             major_version, minor_version);
>           }
>         break;
>
> @@ -1189,7 +1211,9 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,
>         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 +1242,26 @@ 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;
> -
> -      riscv_add_subset (rps->subset_list, subset, major_version, minor_version);
> +      p = riscv_parsing_subset_version (rps,
> +                                       march,
> +                                       ++p,
> +                                       &major_version,
> +                                       &minor_version,
> +                                       TRUE,
> +                                       &use_default_version);
> +
> +      /* Find the default version if needed.  */
> +      if (use_default_version
> +         && rps->get_default_version != NULL)
> +       rps->get_default_version (subset,
> +                                 &major_version,
> +                                 &minor_version);
> +      riscv_add_subset (rps->subset_list, subset,
> +                       major_version, minor_version);
>      }
>    return p;
>  }
> @@ -1272,9 +1301,10 @@ 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,
> +   `rps`: Hooks and status for parsing subset.
> +   `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.  */
>
>  static const char *
> @@ -1287,6 +1317,7 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
>    unsigned minor_version = 0;
>    const char *last_name;
>    riscv_isa_ext_class_t class;
> +  bfd_boolean use_default_version;
>
>    while (*p)
>      {
> @@ -1309,15 +1340,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.
> @@ -1337,7 +1364,6 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
>
>        /* Check that the last item is not the same as this.  */
>        last_name = rps->subset_list->tail->name;
> -
>        if (!strcasecmp (last_name, subset))
>         {
>           rps->error_handler ("-march=%s: Duplicate %s ISA extension: \'%s\'",
> @@ -1357,7 +1383,15 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
>           return NULL;
>         }
>
> -      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 != NULL)
> +       rps->get_default_version (subset,
> +                                 &major_version,
> +                                 &minor_version);
> +      riscv_add_subset (rps->subset_list, subset,
> +                       major_version, minor_version);
> +
>        free (subset);
>        p += end_of_version - subset;
>
> @@ -1384,7 +1418,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.  */
> @@ -1490,7 +1524,6 @@ riscv_parse_subset (riscv_parse_subset_t *rps,
>      return FALSE;
>
>    /* 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]);
>
> diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
> index 76ee274..cbafd28 100644
> --- a/bfd/elfxx-riscv.h
> +++ b/bfd/elfxx-riscv.h
> @@ -72,6 +72,9 @@ typedef struct {
>    void (*error_handler) (const char *,
>                          ...) ATTRIBUTE_PRINTF_1;
>    unsigned *xlen;
> +  void (*get_default_version) (const char *,
> +                              unsigned int *,
> +                              unsigned int *);
>  } riscv_parse_subset_t;
>
>  extern bfd_boolean
> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> index 168561e..5ef257e 100644
> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -64,6 +64,8 @@ struct riscv_cl_insn
>  #endif
>
>  static const char default_arch[] = DEFAULT_ARCH;
> +static const char *default_arch_with_ext = NULL;
> +static enum riscv_isa_spec_class default_isa_spec = ISA_SPEC_CLASS_NONE;
>
>  static unsigned xlen = 0; /* width of an x-register */
>  static unsigned abi_xlen = 0; /* width of a pointer in the ABI */
> @@ -147,6 +149,67 @@ 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,
> +                              unsigned int *major_version,
> +                              unsigned int *minor_version)
> +{
> +  struct riscv_ext_version *ext;
> +
> +  *major_version = 0;
> +  *minor_version = 0;
> +
> +  if (name == NULL || default_isa_spec == ISA_SPEC_CLASS_NONE)
> +    return;
> +
> +  ext = (struct riscv_ext_version *) hash_find (ext_version_hash, name);
> +  while (ext
> +        && ext->name
> +        && strcmp (ext->name, name) == 0)
> +    {
> +      if (ext->isa_spec_class == default_isa_spec)
> +       {
> +         *major_version = ext->major_version;
> +         *minor_version = ext->minor_version;
> +         return;
> +       }
> +      ext++;
> +    }
> +}
> +
>  /* Set which ISA and extensions are available.  */
>
>  static void
> @@ -156,6 +219,10 @@ riscv_set_arch (const char *s)
>    rps.subset_list = &riscv_subsets;
>    rps.error_handler = as_fatal;
>    rps.xlen = &xlen;
> +  rps.get_default_version = riscv_get_default_ext_version;
> +
> +  if (s == NULL)
> +    return;
>
>    riscv_release_subset_list (&riscv_subsets);
>    riscv_parse_subset (&rps, s);
> @@ -2348,6 +2415,7 @@ enum options
>    OPTION_NO_ARCH_ATTR,
>    OPTION_CSR_CHECK,
>    OPTION_NO_CSR_CHECK,
> +  OPTION_MISA_SPEC,
>    OPTION_END_OF_ENUM
>  };
>
> @@ -2364,6 +2432,7 @@ 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},
>
>    {NULL, no_argument, NULL, 0}
>  };
> @@ -2392,7 +2461,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 +2521,14 @@ md_parse_option (int c, const char *arg)
>        riscv_opts.csr_check = FALSE;
>        break;
>
> +    case OPTION_MISA_SPEC:
> +      if (!riscv_get_isa_spec_class (arg, &default_isa_spec))
> +       {
> +         as_bad ("Unknown default ISA spec `%s' set by -misa-spec", arg);
> +         return 0;
> +       }
> +      break;
> +
>      default:
>        return 0;
>      }
> @@ -2469,9 +2548,22 @@ riscv_after_parse_args (void)
>        else
>         as_bad ("unknown default architecture `%s'", default_arch);
>      }
> -
> -  if (riscv_subsets.head == NULL)
> -    riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g");
> +  if (default_arch_with_ext == NULL)
> +    default_arch_with_ext = xlen == 64 ? "rv64g" : "rv32g";
> +
> +  /* Initialize the hash table for extensions with default version.  */
> +  ext_version_hash = init_ext_version_hash (riscv_ext_version_table);
> +
> +  /* The default ISA spec is set to 2.2 rather than the lastest version.
> +     The reason is that compiler generates the ISA string with fixed 2p0
> +     verisons only for the RISCV ELF architecture attributes, but not for
> +     the -march option.  Therefore, we should update the compiler or linker
> +     to resolve this problem.  */
> +  if (default_isa_spec == ISA_SPEC_CLASS_NONE)
> +    default_isa_spec = ISA_SPEC_CLASS_2P2;
> +
> +  /* Set the architecture according to -march.  */
> +  riscv_set_arch (default_arch_with_ext);
>
>    /* Add the RVC extension, regardless of -march, to support .option rvc.  */
>    riscv_set_rvc (FALSE);
> diff --git a/gas/testsuite/gas/riscv/attribute-02.d b/gas/testsuite/gas/riscv/attribute-02.d
> index bc3295b..e1e8ce3 100644
> --- a/gas/testsuite/gas/riscv/attribute-02.d
> +++ b/gas/testsuite/gas/riscv/attribute-02.d
> @@ -3,4 +3,4 @@
>  #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..fa38bf3 100644
> --- a/gas/testsuite/gas/riscv/attribute-03.d
> +++ b/gas/testsuite/gas/riscv/attribute-03.d
> @@ -3,4 +3,4 @@
>  #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-09.d b/gas/testsuite/gas/riscv/attribute-09.d
> new file mode 100644
> index 0000000..cad1713
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/attribute-09.d
> @@ -0,0 +1,6 @@
> +#as: -march-attr -march=rv32i2p1m_zicsr -misa-spec=2.2
> +#readelf: -A
> +#source: empty.s
> +Attribute Section: riscv
> +File Attributes
> +  Tag_RISCV_arch: "rv32i2p1_m2p0_zicsr0p0"
> diff --git a/gas/testsuite/gas/riscv/attribute-10.d b/gas/testsuite/gas/riscv/attribute-10.d
> new file mode 100644
> index 0000000..ba903d1
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/attribute-10.d
> @@ -0,0 +1,6 @@
> +#as: -march-attr -march=rv32gc_zicsr -misa-spec=20191213
> +#readelf: -A
> +#source: empty.s
> +Attribute Section: riscv
> +File Attributes
> +  Tag_RISCV_arch: "rv32i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0"
> diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
> index ac6e861..d83e9ca 100644
> --- a/include/opcode/riscv.h
> +++ b/include/opcode/riscv.h
> @@ -24,6 +24,7 @@
>  #include "riscv-opc.h"
>  #include <stdlib.h>
>  #include <stdint.h>
> +#include "bfd.h"
>
>  typedef uint64_t insn_t;
>
> @@ -343,6 +344,27 @@ struct riscv_opcode
>    unsigned long pinfo;
>  };
>
> +/* The current supported ISA spec versions.  */
> +
> +enum riscv_isa_spec_class
> +{
> +  ISA_SPEC_CLASS_NONE,
> +
> +  ISA_SPEC_CLASS_2P2,
> +  ISA_SPEC_CLASS_20190608,
> +  ISA_SPEC_CLASS_20191213
> +};
> +
> +/* This structure holds version information for specific ISA.  */
> +
> +struct riscv_ext_version
> +{
> +  const char *name;
> +  enum riscv_isa_spec_class isa_spec_class;
> +  unsigned int major_version;
> +  unsigned int minor_version;
> +};
> +
>  /* Instruction is a simple alias (e.g. "mv" for "addi").  */
>  #define        INSN_ALIAS              0x00000001
>
> @@ -420,5 +442,9 @@ 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[];
> +
> +extern bfd_boolean
> +riscv_get_isa_spec_class (const char *, enum riscv_isa_spec_class *);
>
>  #endif /* _RISCV_H_ */
> diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
> index ceedcaf..f08b15e 100644
> --- a/opcodes/riscv-opc.c
> +++ b/opcodes/riscv-opc.c
> @@ -884,3 +884,96 @@ const struct riscv_opcode riscv_insn_types[] =
>  /* Terminate the list.  */
>  {0, 0, INSN_CLASS_NONE, 0, 0, 0, 0, 0}
>  };
> +
> +/* All standard extensions defined in all supported ISA spec.  */
> +const struct riscv_ext_version riscv_ext_version_table[] =
> +{
> +/* name, ISA spec, major version, minor_version.  */
> +{"e", ISA_SPEC_CLASS_20191213, 1, 9},
> +{"e", ISA_SPEC_CLASS_20190608, 1, 9},
> +{"e", ISA_SPEC_CLASS_2P2,      1, 9},
> +
> +{"i", ISA_SPEC_CLASS_20191213, 2, 1},
> +{"i", ISA_SPEC_CLASS_20190608, 2, 1},
> +{"i", ISA_SPEC_CLASS_2P2,      2, 0},
> +
> +{"m", ISA_SPEC_CLASS_20191213, 2, 0},
> +{"m", ISA_SPEC_CLASS_20190608, 2, 0},
> +{"m", ISA_SPEC_CLASS_2P2,      2, 0},
> +
> +{"a", ISA_SPEC_CLASS_20191213, 2, 1},
> +{"a", ISA_SPEC_CLASS_20190608, 2, 0},
> +{"a", ISA_SPEC_CLASS_2P2,      2, 0},
> +
> +{"f", ISA_SPEC_CLASS_20191213, 2, 2},
> +{"f", ISA_SPEC_CLASS_20190608, 2, 2},
> +{"f", ISA_SPEC_CLASS_2P2,      2, 0},
> +
> +{"d", ISA_SPEC_CLASS_20191213, 2, 2},
> +{"d", ISA_SPEC_CLASS_20190608, 2, 2},
> +{"d", ISA_SPEC_CLASS_2P2,      2, 0},
> +
> +{"q", ISA_SPEC_CLASS_20191213, 2, 2},
> +{"q", ISA_SPEC_CLASS_20190608, 2, 2},
> +{"q", ISA_SPEC_CLASS_2P2,      2, 0},
> +
> +{"c", ISA_SPEC_CLASS_20191213, 2, 0},
> +{"c", ISA_SPEC_CLASS_20190608, 2, 0},
> +{"c", ISA_SPEC_CLASS_2P2,      2, 0},
> +
> +{"p", ISA_SPEC_CLASS_20191213, 0, 2},
> +{"p", ISA_SPEC_CLASS_20190608, 0, 2},
> +{"p", ISA_SPEC_CLASS_2P2,      0, 1},
> +
> +{"v", ISA_SPEC_CLASS_20191213, 0, 7},
> +{"v", ISA_SPEC_CLASS_20190608, 0, 7},
> +{"v", ISA_SPEC_CLASS_2P2,      0, 7},
> +
> +{"n", ISA_SPEC_CLASS_20190608, 1, 1},
> +{"n", ISA_SPEC_CLASS_2P2,      1, 1},
> +
> +{"zicsr", ISA_SPEC_CLASS_20191213, 2, 0},
> +{"zicsr", ISA_SPEC_CLASS_20190608, 2, 0},
> +
> +/* Terminate the list.  */
> +{NULL, 0, 0, 0}
> +};
> +
> +struct isa_spec_t
> +{
> +  const char *name;
> +  enum riscv_isa_spec_class class;
> +};
> +
> +/* List for all supported ISA spec versions.  */
> +static const struct isa_spec_t isa_specs[] =
> +{
> +  {"2.2",      ISA_SPEC_CLASS_2P2},
> +  {"20190608", ISA_SPEC_CLASS_20190608},
> +  {"20191213", ISA_SPEC_CLASS_20191213},
> +
> +/* Terminate the list.  */
> +  {NULL, 0}
> +};
> +
> +/* Get the corresponding ISA spec class by giving a ISA spec string.  */
> +
> +bfd_boolean
> +riscv_get_isa_spec_class (const char *s,
> +                         enum riscv_isa_spec_class *class)
> +{
> +  const struct isa_spec_t *version;
> +
> +  if (s == NULL)
> +    return FALSE;
> +
> +  for (version = &isa_specs[0]; version->name != NULL; ++version)
> +    if (strcmp (version->name, s) == 0)
> +      {
> +       *class = version->class;
> +       return TRUE;
> +      }
> +
> +  /* Can not find the supported ISA spec.  */
> +  return FALSE;
> +}
> --
> 2.7.4
>


More information about the Binutils mailing list