RISC-V: Accept version, supervisor ext and more than one NSE for -march.
authorJim Wilson <jimw@sifive.com>
Mon, 3 Dec 2018 21:59:44 +0000 (13:59 -0800)
committerJim Wilson <jimw@sifive.com>
Mon, 3 Dec 2018 22:05:17 +0000 (14:05 -0800)
This patch moves all -march parsing logic into bfd, because we will use this
code in ELF attributes.

bfd/
* elfxx-riscv.h (RISCV_DONT_CARE_VERSION): New macro.
(struct riscv_subset_t): New structure.
(riscv_subset_t): New typedef.
(riscv_subset_list_t): New structure.
(riscv_release_subset_list): New prototype.
(riscv_add_subset): Likewise.
(riscv_lookup_subset): Likewise.
(riscv_lookup_subset_version): Likewise.
(riscv_release_subset_list): Likewise.
* elfxx-riscv.c: Include safe-ctype.h.
(riscv_parsing_subset_version): New function.
(riscv_supported_std_ext): Likewise.
(riscv_parse_std_ext): Likewise.
(riscv_parse_sv_or_non_std_ext): Likewise.
(riscv_parse_subset): Likewise.
(riscv_add_subset): Likewise.
(riscv_lookup_subset): Likewise.
(riscv_lookup_subset_version): Likewise.
(riscv_release_subset_list): Likewise.
gas/
* config/tc-riscv.c: Include elfxx-riscv.h.
(struct riscv_subset): Removed.
(riscv_subsets): Change type to riscv_subset_list_t.
(riscv_subset_supports): Removed argument: xlen_required and move
logic into libbfd.
(riscv_multi_subset_supports): Removed argument: xlen_required.
(riscv_clear_subsets): Removed.
(riscv_add_subset): Ditto.
(riscv_set_arch): Extract parsing logic into libbfd.
(riscv_ip): Update argument for riscv_multi_subset_supports and
riscv_subset_supports. Update riscv_subsets due to struct definition
changed.
(riscv_after_parse_args): Update riscv_subsets due to struct
definition changed, update and argument for riscv_subset_supports.
* testsuite/gas/riscv/empty.s: New.
* testsuite/gas/riscv/march-fail-rv32ef.d: Likewise.
* testsuite/gas/riscv/march-fail-rv32ef.l: Likewise.
* testsuite/gas/riscv/march-fail-rv32i.d: Likewise.
* testsuite/gas/riscv/march-fail-rv32i.l: Likewise.
* testsuite/gas/riscv/march-fail-rv32iam.d: Likewise.
* testsuite/gas/riscv/march-fail-rv32iam.l: Likewise.
* testsuite/gas/riscv/march-fail-rv32ic.d: Likewise.
* testsuite/gas/riscv/march-fail-rv32ic.l: Likewise.
* testsuite/gas/riscv/march-fail-rv32icx2p.d: Likewise.
* testsuite/gas/riscv/march-fail-rv32icx2p.l: Likewise.
* testsuite/gas/riscv/march-fail-rv32imc.d: Likewise.
* testsuite/gas/riscv/march-fail-rv32imc.l: Likewise.
* testsuite/gas/riscv/march-fail-rv64I.d: Likewise.
* testsuite/gas/riscv/march-fail-rv64I.l: Likewise.
* testsuite/gas/riscv/march-fail-rv64e.d: Likewise.
* testsuite/gas/riscv/march-fail-rv64e.l: Likewise.
* testsuite/gas/riscv/march-ok-g2.d: Likewise.
* testsuite/gas/riscv/march-ok-g2p0.d: Likewise.
* testsuite/gas/riscv/march-ok-i2p0.d: Likewise.
* testsuite/gas/riscv/march-ok-nse-with-version.: Likewise.d
* testsuite/gas/riscv/march-ok-s-with-version.d: Likewise.
* testsuite/gas/riscv/march-ok-s.d: Likewise.
* testsuite/gas/riscv/march-ok-sx.d: Likewise.
* testsuite/gas/riscv/march-ok-two-nse.d: Likewise.
* testsuite/gas/riscv/march-ok-g2_p1.d: Likewise.
* testsuite/gas/riscv/march-ok-i2p0m2_a2f2.d: Likewise.
include/
* opcode/riscv.h (riscv_opcode): Change type of xlen_requirement to
unsigned.
opcodes/
* riscv-opc.c: Change the type of xlen, because type of
xlen_requirement changed.

36 files changed:
bfd/ChangeLog
bfd/elfxx-riscv.c
bfd/elfxx-riscv.h
gas/ChangeLog
gas/config/tc-riscv.c
gas/testsuite/gas/riscv/empty.s [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32ef.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32ef.l [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32i.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32i.l [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32iam.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32iam.l [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32ic.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32ic.l [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32icx2p.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32icx2p.l [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32imc.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv32imc.l [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv64I.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv64I.l [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv64e.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-fail-rv64e.l [new file with mode: 0644]
gas/testsuite/gas/riscv/march-ok-g2.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-ok-g2_p1.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-ok-g2p0.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-ok-i2p0.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-ok-i2p0m2_a2f2.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-ok-nse-with-version.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-ok-s-with-version.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-ok-s.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-ok-sx.d [new file with mode: 0644]
gas/testsuite/gas/riscv/march-ok-two-nse.d [new file with mode: 0644]
include/ChangeLog
include/opcode/riscv.h
opcodes/ChangeLog
opcodes/riscv-dis.c

index 3210b0c380aa28692babad962370318063e65415..30616eb787983533dba87d461cffe8ed9858b67a 100644 (file)
@@ -1,3 +1,25 @@
+2018-12-03  Kito Cheng  <kito@andestech.com>
+
+       * elfxx-riscv.h (RISCV_DONT_CARE_VERSION): New macro.
+       (struct riscv_subset_t): New structure.
+       (riscv_subset_t): New typedef.
+       (riscv_subset_list_t): New structure.
+       (riscv_release_subset_list): New prototype.
+       (riscv_add_subset): Likewise.
+       (riscv_lookup_subset): Likewise.
+       (riscv_lookup_subset_version): Likewise.
+       (riscv_release_subset_list): Likewise.
+       * elfxx-riscv.c: Include safe-ctype.h.
+       (riscv_parsing_subset_version): New function.
+       (riscv_supported_std_ext): Likewise.
+       (riscv_parse_std_ext): Likewise.
+       (riscv_parse_sv_or_non_std_ext): Likewise.
+       (riscv_parse_subset): Likewise.
+       (riscv_add_subset): Likewise.
+       (riscv_lookup_subset): Likewise.
+       (riscv_lookup_subset_version): Likewise.
+       (riscv_release_subset_list): Likewise.
+
 2018-12-01  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR ld/23930
index 7d4f59f1a0f723e7d9d147cda7ad9b196f4c1c8f..a88c7fa2e7630b29a4df608f153927bc236a1436 100644 (file)
@@ -28,6 +28,7 @@
 #include "opcode/riscv.h"
 #include "libiberty.h"
 #include "elfxx-riscv.h"
+#include "safe-ctype.h"
 #include <stdint.h>
 
 #define MINUS_ONE ((bfd_vma)0 - 1)
@@ -1010,3 +1011,477 @@ riscv_elf_add_sub_reloc (bfd *abfd,
 
   return bfd_reloc_ok;
 }
+
+/* Parsing subset version.
+
+   Return Value:
+     Points to the end of version
+
+   Arguments:
+     `rps`: Hooks and status for parsing subset.
+     `march`: Full arch string.
+     `p`: Curent parsing position.
+     `major_version`: Parsing result of major version, using
+      default_major_version if version is not present in arch string.
+     `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.  */
+
+static const char *
+riscv_parsing_subset_version (riscv_parse_subset_t *rps,
+                             const char *march,
+                             const char *p,
+                             unsigned *major_version,
+                             unsigned *minor_version,
+                             unsigned default_major_version,
+                             unsigned default_minor_version,
+                             bfd_boolean std_ext_p)
+{
+  bfd_boolean major_p = TRUE;
+  unsigned version = 0;
+  unsigned major = 0;
+  unsigned minor = 0;
+  char np;
+
+  for (;*p; ++p)
+    {
+      if (*p == 'p')
+       {
+         np = *(p + 1);
+
+         if (!ISDIGIT (np))
+           {
+             /* Might be beginning of `p` extension.  */
+             if (std_ext_p)
+               {
+                 *major_version = version;
+                 *minor_version = 0;
+                 return p;
+               }
+             else
+               {
+                 rps->error_handler ("-march=%s: Expect number after `%dp'.",
+                                     march, version);
+                 return NULL;
+               }
+           }
+
+         major = version;
+         major_p = FALSE;
+         version = 0;
+       }
+      else if (ISDIGIT (*p))
+       version = (version * 10) + (*p - '0');
+      else
+       break;
+    }
+
+  if (major_p)
+    major = version;
+  else
+    minor = 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;
+    }
+  return p;
+}
+
+/* Return string which contain all supported standard extensions in
+   canonical order.  */
+
+const char *
+riscv_supported_std_ext (void)
+{
+  return "mafdqlcbjtpvn";
+}
+
+/* Parsing function for standard extensions.
+
+   Return Value:
+     Points to the end of extensions.
+
+   Arguments:
+     `rps`: Hooks and status for parsing subset.
+     `march`: Full arch string.
+     `p`: Curent parsing position.  */
+
+static const char *
+riscv_parse_std_ext (riscv_parse_subset_t *rps,
+                    const char *march, const char *p)
+{
+  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';
+
+  /* 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);
+       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);
+
+       if (*rps->xlen > 32)
+         {
+           rps->error_handler ("-march=%s: rv%de is not a valid base ISA",
+                               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);
+
+       for ( ; *std_exts != 'q'; std_exts++)
+         {
+           const char subset[] = {*std_exts, '\0'};
+           riscv_add_subset (
+             rps->subset_list, subset, major_version, minor_version);
+         }
+       break;
+
+      default:
+       rps->error_handler (
+         "-march=%s: first ISA subset must be `e', `i' or `g'", march);
+       return NULL;
+    }
+
+  while (*p)
+    {
+      char subset[2] = {0, 0};
+
+      if (*p == 'x' || *p == 's')
+       break;
+
+      if (*p == '_')
+       {
+         p++;
+         continue;
+       }
+
+      std_ext = *p;
+
+      /* Checking canonical order.  */
+      while (*std_exts && std_ext != *std_exts) std_exts++;
+
+      if (std_ext != *std_exts)
+       {
+         if (strchr (all_std_exts, std_ext) == NULL)
+           rps->error_handler (
+             "-march=%s: unsupported ISA subset `%c'", march, *p);
+         else
+           rps->error_handler (
+             "-march=%s: ISA string is not in canonical order. `%c'",
+             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);
+
+      subset[0] = std_ext;
+
+      riscv_add_subset (rps->subset_list, subset, major_version, minor_version);
+    }
+  return p;
+}
+
+/* Parsing function for non-standard and supervisor extensions.
+
+   Return Value:
+     Points to the end of extensions.
+
+   Arguments:
+     `rps`: Hooks and status for parsing subset.
+     `march`: Full arch string.
+     `p`: Curent parsing position.
+     `ext_type`: What kind of extensions, 'x', 's' or 'sx'.
+     `ext_type_str`: Full name for kind of extension.  */
+
+static const char *
+riscv_parse_sv_or_non_std_ext (riscv_parse_subset_t *rps,
+                              const char *march,
+                              const char *p,
+                              const char *ext_type,
+                              const char *ext_type_str)
+{
+  unsigned major_version = 0;
+  unsigned minor_version = 0;
+  size_t ext_type_len = strlen (ext_type);
+
+  while (*p)
+    {
+      if (*p == '_')
+       {
+         p++;
+         continue;
+       }
+
+      if (strncmp (p, ext_type, ext_type_len) != 0)
+       break;
+
+      /* It's non-standard supervisor extension if it prefix with sx.  */
+      if ((ext_type[0] == 's') && (ext_type_len == 1)
+         && (*(p + 1) == 'x'))
+       break;
+
+      char *subset = xstrdup (p);
+      char *q = subset;
+      const char *end_of_version;
+
+      while (*++q != '\0' && *q != '_' && !ISDIGIT (*q))
+       ;
+
+      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);
+
+      *q = '\0';
+
+      riscv_add_subset (rps->subset_list, subset, major_version, minor_version);
+      free (subset);
+      p += end_of_version - subset;
+
+      if (*p != '\0' && *p != '_')
+       {
+         rps->error_handler ("-march=%s: %s must seperate with _",
+                             march, ext_type_str);
+         return NULL;
+       }
+    }
+
+  return p;
+}
+
+/* Function for parsing arch string.
+
+   Return Value:
+     Return TRUE on success.
+
+   Arguments:
+     `rps`: Hooks and status for parsing subset.
+     `arch`: Arch string.  */
+
+bfd_boolean
+riscv_parse_subset (riscv_parse_subset_t *rps,
+                   const char *arch)
+{
+  const char *p = arch;
+
+  if (strncmp (p, "rv32", 4) == 0)
+    {
+      *rps->xlen = 32;
+      p += 4;
+    }
+  else if (strncmp (p, "rv64", 4) == 0)
+    {
+      *rps->xlen = 64;
+      p += 4;
+    }
+  else
+    {
+      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);
+
+  if (p == NULL)
+    return FALSE;
+
+  /* Parsing non-standard extension.  */
+  p = riscv_parse_sv_or_non_std_ext (
+       rps, arch, p, "x", "non-standard extension");
+
+  if (p == NULL)
+    return FALSE;
+
+  /* Parsing supervisor extension.  */
+  p = riscv_parse_sv_or_non_std_ext (
+       rps, arch, p, "s", "supervisor extension");
+
+  if (p == NULL)
+    return FALSE;
+
+  /* Parsing non-standard supervisor extension.  */
+  p = riscv_parse_sv_or_non_std_ext (
+       rps, arch, p, "sx", "non-standard supervisor extension");
+
+  if (p == NULL)
+    return FALSE;
+
+  if (*p != '\0')
+    {
+      rps->error_handler ("-march=%s: unexpected ISA string at end: %s",
+                         arch, p);
+      return FALSE;
+    }
+
+  if (riscv_lookup_subset (rps->subset_list, "e")
+      && riscv_lookup_subset (rps->subset_list, "f"))
+    {
+      rps->error_handler ("-march=%s: rv32e does not support the `f' extension",
+                         arch);
+      return FALSE;
+    }
+
+  if (riscv_lookup_subset (rps->subset_list, "d")
+      && !riscv_lookup_subset (rps->subset_list, "f"))
+    {
+      rps->error_handler ("-march=%s: `d' extension requires `f' extension",
+                         arch);
+      return FALSE;
+    }
+
+  if (riscv_lookup_subset (rps->subset_list, "q")
+      && !riscv_lookup_subset (rps->subset_list, "d"))
+    {
+      rps->error_handler ("-march=%s: `q' extension requires `d' extension",
+                         arch);
+      return FALSE;
+    }
+
+  if (riscv_lookup_subset (rps->subset_list, "q") && *rps->xlen < 64)
+    {
+      rps->error_handler ("-march=%s: rv32 does not support the `q' extension",
+                         arch);
+      return FALSE;
+    }
+  return TRUE;
+}
+
+/* Add new subset to list.  */
+
+void
+riscv_add_subset (riscv_subset_list_t *subset_list,
+                 const char *subset,
+                 int major, int minor)
+{
+  riscv_subset_t *s = xmalloc (sizeof *s);
+
+  if (subset_list->head == NULL)
+    subset_list->head = s;
+
+  s->name = xstrdup (subset);
+  s->major_version = major;
+  s->minor_version = minor;
+  s->next = NULL;
+
+  if (subset_list->tail != NULL)
+    subset_list->tail->next = s;
+
+  subset_list->tail = s;
+}
+
+/* Find subset in list without version checking, return NULL if not found.  */
+
+riscv_subset_t *
+riscv_lookup_subset (const riscv_subset_list_t *subset_list,
+                    const char *subset)
+{
+  return riscv_lookup_subset_version (
+          subset_list, subset,
+          RISCV_DONT_CARE_VERSION,
+          RISCV_DONT_CARE_VERSION);
+}
+
+/* Find subset in list with version checking, return NULL if not found.  */
+
+riscv_subset_t *
+riscv_lookup_subset_version (const riscv_subset_list_t *subset_list,
+                            const char *subset,
+                            int major, int minor)
+{
+  riscv_subset_t *s;
+
+  for (s = subset_list->head; s != NULL; s = s->next)
+    if (strcasecmp (s->name, subset) == 0)
+      {
+       if ((major != RISCV_DONT_CARE_VERSION)
+           && (s->major_version != major))
+         return NULL;
+
+       if ((minor != RISCV_DONT_CARE_VERSION)
+           && (s->minor_version != minor))
+         return NULL;
+
+       return s;
+      }
+
+  return NULL;
+}
+
+/* Release subset list.  */
+
+void
+riscv_release_subset_list (riscv_subset_list_t *subset_list)
+{
+   while (subset_list->head != NULL)
+    {
+      riscv_subset_t *next = subset_list->head->next;
+      free ((void *)subset_list->head->name);
+      free (subset_list->head);
+      subset_list->head = next;
+    }
+
+  subset_list->tail = NULL;
+}
index 836f05db5209509fe4e03e22f6063af6ac26e727..64e41b80cc02002d123dc8104df09a00f621596e 100644 (file)
@@ -31,3 +31,55 @@ riscv_reloc_type_lookup (bfd *, bfd_reloc_code_real_type);
 
 extern reloc_howto_type *
 riscv_elf_rtype_to_howto (bfd *, unsigned int r_type);
+
+#define RISCV_DONT_CARE_VERSION -1
+
+/* The information of architecture attribute.  */
+struct riscv_subset_t
+{
+  const char *name;
+  int major_version;
+  int minor_version;
+  struct riscv_subset_t *next;
+};
+
+typedef struct riscv_subset_t riscv_subset_t;
+
+typedef struct {
+  riscv_subset_t *head;
+  riscv_subset_t *tail;
+} riscv_subset_list_t;
+
+extern void
+riscv_release_subset_list (riscv_subset_list_t *);
+
+extern void
+riscv_add_subset (riscv_subset_list_t *,
+                 const char *,
+                 int, int);
+
+extern riscv_subset_t *
+riscv_lookup_subset (const riscv_subset_list_t *,
+                    const char *);
+
+extern riscv_subset_t *
+riscv_lookup_subset_version (const riscv_subset_list_t *,
+                            const char *,
+                            int, int);
+
+typedef struct {
+  riscv_subset_list_t *subset_list;
+  void (*error_handler) (const char *,
+                        ...) ATTRIBUTE_PRINTF_1;
+  unsigned *xlen;
+} riscv_parse_subset_t;
+
+extern bfd_boolean
+riscv_parse_subset (riscv_parse_subset_t *,
+                   const char *);
+
+extern const char *
+riscv_supported_std_ext (void);
+
+extern void
+riscv_release_subset_list (riscv_subset_list_t *);
index a7bcfee82fb525f0355c414be7b5f86256f1fc97..ba4aa15c03f14a336cc6be0a69e9c4c3fb098d66 100644 (file)
@@ -1,4 +1,48 @@
-2018-12-03  Egeyar Bagcioglu  <egeyar.bagcioglu@oracle.com>
+2018-12-03  Kito Cheng  <kito@andestech.com>
+
+       * config/tc-riscv.c: Include elfxx-riscv.h.
+       (struct riscv_subset): Removed.
+       (riscv_subsets): Change type to riscv_subset_list_t.
+       (riscv_subset_supports): Removed argument: xlen_required and move
+       logic into libbfd.
+       (riscv_multi_subset_supports): Removed argument: xlen_required.
+       (riscv_clear_subsets): Removed.
+       (riscv_add_subset): Ditto.
+       (riscv_set_arch): Extract parsing logic into libbfd.
+       (riscv_ip): Update argument for riscv_multi_subset_supports and
+       riscv_subset_supports. Update riscv_subsets due to struct definition
+       changed.
+       (riscv_after_parse_args): Update riscv_subsets due to struct
+       definition changed, update and argument for riscv_subset_supports.
+       * testsuite/gas/riscv/empty.s: New.
+       * testsuite/gas/riscv/march-fail-rv32ef.d: Likewise.
+       * testsuite/gas/riscv/march-fail-rv32ef.l: Likewise.
+       * testsuite/gas/riscv/march-fail-rv32i.d: Likewise.
+       * testsuite/gas/riscv/march-fail-rv32i.l: Likewise.
+       * testsuite/gas/riscv/march-fail-rv32iam.d: Likewise.
+       * testsuite/gas/riscv/march-fail-rv32iam.l: Likewise.
+       * testsuite/gas/riscv/march-fail-rv32ic.d: Likewise.
+       * testsuite/gas/riscv/march-fail-rv32ic.l: Likewise.
+       * testsuite/gas/riscv/march-fail-rv32icx2p.d: Likewise.
+       * testsuite/gas/riscv/march-fail-rv32icx2p.l: Likewise.
+       * testsuite/gas/riscv/march-fail-rv32imc.d: Likewise.
+       * testsuite/gas/riscv/march-fail-rv32imc.l: Likewise.
+       * testsuite/gas/riscv/march-fail-rv64I.d: Likewise.
+       * testsuite/gas/riscv/march-fail-rv64I.l: Likewise.
+       * testsuite/gas/riscv/march-fail-rv64e.d: Likewise.
+       * testsuite/gas/riscv/march-fail-rv64e.l: Likewise.
+       * testsuite/gas/riscv/march-ok-g2.d: Likewise.
+       * testsuite/gas/riscv/march-ok-g2p0.d: Likewise.
+       * testsuite/gas/riscv/march-ok-i2p0.d: Likewise.
+       * testsuite/gas/riscv/march-ok-nse-with-version.: Likewise.d
+       * testsuite/gas/riscv/march-ok-s-with-version.d: Likewise.
+       * testsuite/gas/riscv/march-ok-s.d: Likewise.
+       * testsuite/gas/riscv/march-ok-sx.d: Likewise.
+       * testsuite/gas/riscv/march-ok-two-nse.d: Likewise.
+       * testsuite/gas/riscv/march-ok-g2_p1.d: Likewise.
+       * testsuite/gas/riscv/march-ok-i2p0m2_a2f2.d: Likewise.
+
+018-12-03  Egeyar Bagcioglu  <egeyar.bagcioglu@oracle.com>
 
        PR 23193
        PR 19721
index 426343c693a22b7a2268af68bc83cf718b3c343a..92ddf80cb41a2f331979c020a1710381578fbed1 100644 (file)
@@ -29,6 +29,7 @@
 #include "dwarf2dbg.h"
 #include "dw2gencfi.h"
 
+#include "bfd/elfxx-riscv.h"
 #include "elf/riscv.h"
 #include "opcode/riscv.h"
 
@@ -102,160 +103,41 @@ riscv_set_rve (bfd_boolean rve_value)
   riscv_opts.rve = rve_value;
 }
 
-struct riscv_subset
-{
-  const char *name;
-
-  struct riscv_subset *next;
-};
-
-static struct riscv_subset *riscv_subsets;
+static riscv_subset_list_t riscv_subsets;
 
 static bfd_boolean
-riscv_subset_supports (unsigned xlen_required, const char *feature)
+riscv_subset_supports (const char *feature)
 {
-  struct riscv_subset *s;
-
-  if (xlen_required && xlen != xlen_required)
-    return FALSE;
-
-  for (s = riscv_subsets; s != NULL; s = s->next)
-    if (strcasecmp (s->name, feature) == 0)
-      return TRUE;
+  if (riscv_opts.rvc && (strcasecmp (feature, "c") == 0))
+    return TRUE;
 
-  return FALSE;
+  return riscv_lookup_subset (&riscv_subsets, feature) != NULL;
 }
 
 static bfd_boolean
-riscv_multi_subset_supports (unsigned xlen_required, const char *features[])
+riscv_multi_subset_supports (const char *features[])
 {
   unsigned i = 0;
   bfd_boolean supported = TRUE;
 
   for (;features[i]; ++i)
-    supported = supported && riscv_subset_supports (xlen_required, features[i]);
+    supported = supported && riscv_subset_supports (features[i]);
 
   return supported;
 }
 
-static void
-riscv_clear_subsets (void)
-{
-  while (riscv_subsets != NULL)
-    {
-      struct riscv_subset *next = riscv_subsets->next;
-      free ((void *) riscv_subsets->name);
-      free (riscv_subsets);
-      riscv_subsets = next;
-    }
-}
-
-static void
-riscv_add_subset (const char *subset)
-{
-  struct riscv_subset *s = xmalloc (sizeof *s);
-
-  s->name = xstrdup (subset);
-  s->next = riscv_subsets;
-  riscv_subsets = s;
-}
-
 /* Set which ISA and extensions are available.  */
 
 static void
 riscv_set_arch (const char *s)
 {
-  const char *all_subsets = "imafdqc";
-  char *extension = NULL;
-  const char *p = s;
-
-  riscv_clear_subsets();
+  riscv_parse_subset_t rps;
+  rps.subset_list = &riscv_subsets;
+  rps.error_handler = as_fatal;
+  rps.xlen = &xlen;
 
-  if (strncmp (p, "rv32", 4) == 0)
-    {
-      xlen = 32;
-      p += 4;
-    }
-  else if (strncmp (p, "rv64", 4) == 0)
-    {
-      xlen = 64;
-      p += 4;
-    }
-  else
-    as_fatal ("-march=%s: ISA string must begin with rv32 or rv64", s);
-
-  switch (*p)
-    {
-      case 'i':
-       break;
-
-      case 'e':
-       p++;
-       riscv_add_subset ("e");
-       riscv_add_subset ("i");
-
-       if (xlen > 32)
-         as_fatal ("-march=%s: rv%de is not a valid base ISA", s, xlen);
-
-       break;
-
-      case 'g':
-       p++;
-       for ( ; *all_subsets != 'q'; all_subsets++)
-         {
-           const char subset[] = {*all_subsets, '\0'};
-           riscv_add_subset (subset);
-         }
-       break;
-
-      default:
-       as_fatal ("-march=%s: first ISA subset must be `e', `i' or `g'", s);
-    }
-
-  while (*p)
-    {
-      if (*p == 'x')
-       {
-         char *subset = xstrdup (p);
-         char *q = subset;
-
-         while (*++q != '\0' && *q != '_')
-           ;
-         *q = '\0';
-
-         if (extension)
-           as_fatal ("-march=%s: only one non-standard extension is supported"
-                     " (found `%s' and `%s')", s, extension, subset);
-         extension = subset;
-         riscv_add_subset (subset);
-         p += strlen (subset);
-       }
-      else if (*p == '_')
-       p++;
-      else if ((all_subsets = strchr (all_subsets, *p)) != NULL)
-       {
-         const char subset[] = {*p, 0};
-         riscv_add_subset (subset);
-         all_subsets++;
-         p++;
-       }
-      else
-       as_fatal ("-march=%s: unsupported ISA subset `%c'", s, *p);
-    }
-
-  if (riscv_subset_supports (0, "e") && riscv_subset_supports (0, "f"))
-    as_fatal ("-march=%s: rv32e does not support the `f' extension", s);
-
-  if (riscv_subset_supports (0, "d") && !riscv_subset_supports (0, "f"))
-    as_fatal ("-march=%s: `d' extension requires `f' extension", s);
-
-  if (riscv_subset_supports (0, "q") && !riscv_subset_supports (0, "d"))
-    as_fatal ("-march=%s: `q' extension requires `d' extension", s);
-
-  if (riscv_subset_supports (0, "q") && xlen < 64)
-    as_fatal ("-march=%s: rv32 does not support the `q' extension", s);
-
-  free (extension);
+  riscv_release_subset_list (&riscv_subsets);
+  riscv_parse_subset (&rps, s);
 }
 
 /* Handle of the OPCODE hash table.  */
@@ -1491,7 +1373,10 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
   argsStart = s;
   for ( ; insn && insn->name && strcmp (insn->name, str) == 0; insn++)
     {
-      if (!riscv_multi_subset_supports (insn->xlen_requirement, insn->subset))
+      if ((insn->xlen_requirement != 0) && (xlen != insn->xlen_requirement))
+       continue;
+
+      if (!riscv_multi_subset_supports (insn->subset))
        continue;
 
       create_insn (ip, insn);
@@ -2332,19 +2217,17 @@ riscv_after_parse_args (void)
        as_bad ("unknown default architecture `%s'", default_arch);
     }
 
-  if (riscv_subsets == NULL)
+  if (riscv_subsets.head == NULL)
     riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g");
 
   /* Add the RVC extension, regardless of -march, to support .option rvc.  */
   riscv_set_rvc (FALSE);
-  if (riscv_subset_supports (0, "c"))
+  if (riscv_subset_supports ("c"))
     riscv_set_rvc (TRUE);
-  else
-    riscv_add_subset ("c");
 
   /* Enable RVE if specified by the -march option.  */
   riscv_set_rve (FALSE);
-  if (riscv_subset_supports (0, "e"))
+  if (riscv_subset_supports ("e"))
     riscv_set_rve (TRUE);
 
   /* Infer ABI from ISA if not specified on command line.  */
@@ -2357,12 +2240,12 @@ riscv_after_parse_args (void)
 
   if (float_abi == FLOAT_ABI_DEFAULT)
     {
-      struct riscv_subset *subset;
+      riscv_subset_t *subset;
 
       /* Assume soft-float unless D extension is present.  */
       float_abi = FLOAT_ABI_SOFT;
 
-      for (subset = riscv_subsets; subset != NULL; subset = subset->next)
+      for (subset = riscv_subsets.head; subset != NULL; subset = subset->next)
        {
          if (strcasecmp (subset->name, "D") == 0)
            float_abi = FLOAT_ABI_DOUBLE;
diff --git a/gas/testsuite/gas/riscv/empty.s b/gas/testsuite/gas/riscv/empty.s
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32ef.d b/gas/testsuite/gas/riscv/march-fail-rv32ef.d
new file mode 100644 (file)
index 0000000..d7b51c3
--- /dev/null
@@ -0,0 +1,3 @@
+#as: -march=rv32ef
+#source: empty.s
+#error_output: march-fail-rv32ef.l
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32ef.l b/gas/testsuite/gas/riscv/march-fail-rv32ef.l
new file mode 100644 (file)
index 0000000..15e56c8
--- /dev/null
@@ -0,0 +1,2 @@
+Assembler messages:
+Fatal error: -march=rv32ef: rv32e does not support the `f' extension
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32i.d b/gas/testsuite/gas/riscv/march-fail-rv32i.d
new file mode 100644 (file)
index 0000000..1e6e9e0
--- /dev/null
@@ -0,0 +1,3 @@
+#as: -march=rv32I
+#source: empty.s
+#error_output: march-fail-rv32i.l
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32i.l b/gas/testsuite/gas/riscv/march-fail-rv32i.l
new file mode 100644 (file)
index 0000000..1977aed
--- /dev/null
@@ -0,0 +1,2 @@
+Assembler messages:
+Fatal error: -march=rv32I: first ISA subset must be `e', `i' or `g'
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32iam.d b/gas/testsuite/gas/riscv/march-fail-rv32iam.d
new file mode 100644 (file)
index 0000000..054cf4d
--- /dev/null
@@ -0,0 +1,3 @@
+#as: -march=rv32iam
+#source: empty.s
+#error_output: march-fail-rv32iam.l
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32iam.l b/gas/testsuite/gas/riscv/march-fail-rv32iam.l
new file mode 100644 (file)
index 0000000..c7786f8
--- /dev/null
@@ -0,0 +1,2 @@
+Assembler messages:
+Fatal error: -march=rv32iam: ISA string is not in canonical order. `m'
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32ic.d b/gas/testsuite/gas/riscv/march-fail-rv32ic.d
new file mode 100644 (file)
index 0000000..b419a65
--- /dev/null
@@ -0,0 +1,3 @@
+#as: -march=rv32iC
+#source: empty.s
+#error_output: march-fail-rv32ic.l
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32ic.l b/gas/testsuite/gas/riscv/march-fail-rv32ic.l
new file mode 100644 (file)
index 0000000..d24ea2f
--- /dev/null
@@ -0,0 +1,2 @@
+Assembler messages:
+Fatal error: -march=rv32iC: unsupported ISA subset `C'
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32icx2p.d b/gas/testsuite/gas/riscv/march-fail-rv32icx2p.d
new file mode 100644 (file)
index 0000000..5198090
--- /dev/null
@@ -0,0 +1,3 @@
+#as: -march=rv32icx2p
+#source: empty.s
+#error_output: march-fail-rv32icx2p.l
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32icx2p.l b/gas/testsuite/gas/riscv/march-fail-rv32icx2p.l
new file mode 100644 (file)
index 0000000..25627d4
--- /dev/null
@@ -0,0 +1,2 @@
+Assembler messages:
+Fatal error: -march=rv32icx2p: Expect number after `2p'.
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32imc.d b/gas/testsuite/gas/riscv/march-fail-rv32imc.d
new file mode 100644 (file)
index 0000000..1cb4d9e
--- /dev/null
@@ -0,0 +1,3 @@
+#as: -march=rv32iamfd
+#source: empty.s
+#error_output: march-fail-rv32imc.l
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32imc.l b/gas/testsuite/gas/riscv/march-fail-rv32imc.l
new file mode 100644 (file)
index 0000000..d922e9d
--- /dev/null
@@ -0,0 +1,2 @@
+Assembler messages:
+Fatal error: -march=rv32iamfd: ISA string is not in canonical order. `m'
diff --git a/gas/testsuite/gas/riscv/march-fail-rv64I.d b/gas/testsuite/gas/riscv/march-fail-rv64I.d
new file mode 100644 (file)
index 0000000..e00a6f8
--- /dev/null
@@ -0,0 +1,3 @@
+#as: -march=rv64I
+#source: empty.s
+#error_output: march-fail-rv64I.l
diff --git a/gas/testsuite/gas/riscv/march-fail-rv64I.l b/gas/testsuite/gas/riscv/march-fail-rv64I.l
new file mode 100644 (file)
index 0000000..5b46e77
--- /dev/null
@@ -0,0 +1,2 @@
+Assembler messages:
+Fatal error: -march=rv64I: first ISA subset must be `e', `i' or `g'
diff --git a/gas/testsuite/gas/riscv/march-fail-rv64e.d b/gas/testsuite/gas/riscv/march-fail-rv64e.d
new file mode 100644 (file)
index 0000000..38d73db
--- /dev/null
@@ -0,0 +1,3 @@
+#as: -march=rv64e
+#source: empty.s
+#error_output: march-fail-rv64e.l
diff --git a/gas/testsuite/gas/riscv/march-fail-rv64e.l b/gas/testsuite/gas/riscv/march-fail-rv64e.l
new file mode 100644 (file)
index 0000000..85f7554
--- /dev/null
@@ -0,0 +1,2 @@
+Assembler messages:
+Fatal error: -march=rv64e: rv64e is not a valid base ISA
diff --git a/gas/testsuite/gas/riscv/march-ok-g2.d b/gas/testsuite/gas/riscv/march-ok-g2.d
new file mode 100644 (file)
index 0000000..38541ad
--- /dev/null
@@ -0,0 +1,5 @@
+#as: -march=rv32g2
+#objdump: -dr
+#source: empty.s
+
+.*:     file format elf32-littleriscv
diff --git a/gas/testsuite/gas/riscv/march-ok-g2_p1.d b/gas/testsuite/gas/riscv/march-ok-g2_p1.d
new file mode 100644 (file)
index 0000000..cd9e127
--- /dev/null
@@ -0,0 +1,5 @@
+#as: -march=rv32g2_p1
+#objdump: -dr
+#source: empty.s
+
+.*:     file format elf32-littleriscv
diff --git a/gas/testsuite/gas/riscv/march-ok-g2p0.d b/gas/testsuite/gas/riscv/march-ok-g2p0.d
new file mode 100644 (file)
index 0000000..b439314
--- /dev/null
@@ -0,0 +1,5 @@
+#as: -march=rv32g2p0
+#objdump: -dr
+#source: empty.s
+
+.*:     file format elf32-littleriscv
diff --git a/gas/testsuite/gas/riscv/march-ok-i2p0.d b/gas/testsuite/gas/riscv/march-ok-i2p0.d
new file mode 100644 (file)
index 0000000..eb8309c
--- /dev/null
@@ -0,0 +1,5 @@
+#as: -march=rv32i2p0
+#objdump: -dr
+#source: empty.s
+
+.*:     file format elf32-littleriscv
diff --git a/gas/testsuite/gas/riscv/march-ok-i2p0m2_a2f2.d b/gas/testsuite/gas/riscv/march-ok-i2p0m2_a2f2.d
new file mode 100644 (file)
index 0000000..6658417
--- /dev/null
@@ -0,0 +1,5 @@
+#as: -march=rv32i2p0m2_a2f2
+#objdump: -dr
+#source: empty.s
+
+.*:     file format elf32-littleriscv
diff --git a/gas/testsuite/gas/riscv/march-ok-nse-with-version.d b/gas/testsuite/gas/riscv/march-ok-nse-with-version.d
new file mode 100644 (file)
index 0000000..bdca7fb
--- /dev/null
@@ -0,0 +1,5 @@
+#as: -march=rv32imafd_xargle2p0
+#objdump: -dr
+#source: empty.s
+
+.*:     file format elf32-littleriscv
diff --git a/gas/testsuite/gas/riscv/march-ok-s-with-version.d b/gas/testsuite/gas/riscv/march-ok-s-with-version.d
new file mode 100644 (file)
index 0000000..6296a15
--- /dev/null
@@ -0,0 +1,5 @@
+#as: -march=rv32isfoo3p4
+#objdump: -dr
+#source: empty.s
+
+.*:     file format elf32-littleriscv
diff --git a/gas/testsuite/gas/riscv/march-ok-s.d b/gas/testsuite/gas/riscv/march-ok-s.d
new file mode 100644 (file)
index 0000000..7daa0a1
--- /dev/null
@@ -0,0 +1,5 @@
+#as: -march=rv32isfoo
+#objdump: -dr
+#source: empty.s
+
+.*:     file format elf32-littleriscv
diff --git a/gas/testsuite/gas/riscv/march-ok-sx.d b/gas/testsuite/gas/riscv/march-ok-sx.d
new file mode 100644 (file)
index 0000000..e2172f2
--- /dev/null
@@ -0,0 +1,5 @@
+#as: -march=rv32isfoo_sxbar
+#objdump: -dr
+#source: empty.s
+
+.*:     file format elf32-littleriscv
diff --git a/gas/testsuite/gas/riscv/march-ok-two-nse.d b/gas/testsuite/gas/riscv/march-ok-two-nse.d
new file mode 100644 (file)
index 0000000..0fe5037
--- /dev/null
@@ -0,0 +1,5 @@
+#as: -march=rv32imafd_xargle_xbargle
+#objdump: -dr
+#source: empty.s
+
+.*:     file format elf32-littleriscv
index 64245968e434650c2c9873e8245108cab04b9e34..7375bacc414d5047ae43dad476a65349c4ee51ea 100644 (file)
@@ -1,3 +1,8 @@
+2018-12-03  Kito Cheng  <kito@andestech.com>
+
+       * opcode/riscv.h (riscv_opcode): Change type of xlen_requirement to
+       unsigned.
+
 2018-11-27  Jim Wilson  <jimw@sifive.com>
 
        * opcode/riscv.h (OP_MASK_CFUNCT6, OP_SH_CFUNCT6): New.
index 10c5f3d6e61db69cd954e4468398d867758ffa3c..12cb4ca4544697045943d8af65b668013ddf3dab 100644 (file)
@@ -295,7 +295,7 @@ struct riscv_opcode
   /* The name of the instruction.  */
   const char *name;
   /* The requirement of xlen for the instruction, 0 if no requirement.  */
-  int xlen_requirement;
+  unsigned xlen_requirement;
   /* An array of ISA subset name (I, M, A, F, D, Xextension), must ended
      with a NULL pointer sential.  */
   const char *subset[MAX_SUBSET_NUM];
index a9bdb2fed889a29bc0e3e6e5dc437e2c59643135..b04cf0e89706e5d3070db670e25f4c3acfaa508c 100644 (file)
@@ -1,3 +1,8 @@
+2018-12-03  Kito Cheng <kito@andestech.com>
+
+       * riscv-opc.c: Change the type of xlen, because type of
+       xlen_requirement changed.
+
 2018-12-03  Egeyar Bagcioglu <egeyar.bagcioglu@oracle.com>
 
        PR 23193
index 890f1f8e697c06a51c12115160414c6ca8fab3d0..979082094833e051da827f7c4a32e54c1e651236 100644 (file)
@@ -408,7 +408,7 @@ riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
   op = riscv_hash[OP_HASH_IDX (word)];
   if (op != NULL)
     {
-      int xlen = 0;
+      unsigned xlen = 0;
 
       /* If XLEN is not known, get its value from the ELF class.  */
       if (info->mach == bfd_mach_riscv64)