aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Wilson <jimw@sifive.com>2018-12-03 13:59:44 -0800
committerJim Wilson <jimw@sifive.com>2018-12-03 14:05:17 -0800
commit1080bf78c05b220f5f4bbc5c50d6a0ef6490d738 (patch)
tree13e723b5e05e1858e2208b713d5bf94b38801439
parent57b64c4103ffeadd524eb80b4a7d61be8c8ec871 (diff)
downloadbinutils-1080bf78c05b220f5f4bbc5c50d6a0ef6490d738.zip
binutils-1080bf78c05b220f5f4bbc5c50d6a0ef6490d738.tar.gz
binutils-1080bf78c05b220f5f4bbc5c50d6a0ef6490d738.tar.bz2
RISC-V: Accept version, supervisor ext and more than one NSE for -march.
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.
-rw-r--r--bfd/ChangeLog22
-rw-r--r--bfd/elfxx-riscv.c475
-rw-r--r--bfd/elfxx-riscv.h52
-rw-r--r--gas/ChangeLog46
-rw-r--r--gas/config/tc-riscv.c163
-rw-r--r--gas/testsuite/gas/riscv/empty.s1
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32ef.d3
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32ef.l2
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32i.d3
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32i.l2
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32iam.d3
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32iam.l2
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32ic.d3
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32ic.l2
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32icx2p.d3
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32icx2p.l2
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32imc.d3
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32imc.l2
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv64I.d3
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv64I.l2
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv64e.d3
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv64e.l2
-rw-r--r--gas/testsuite/gas/riscv/march-ok-g2.d5
-rw-r--r--gas/testsuite/gas/riscv/march-ok-g2_p1.d5
-rw-r--r--gas/testsuite/gas/riscv/march-ok-g2p0.d5
-rw-r--r--gas/testsuite/gas/riscv/march-ok-i2p0.d5
-rw-r--r--gas/testsuite/gas/riscv/march-ok-i2p0m2_a2f2.d5
-rw-r--r--gas/testsuite/gas/riscv/march-ok-nse-with-version.d5
-rw-r--r--gas/testsuite/gas/riscv/march-ok-s-with-version.d5
-rw-r--r--gas/testsuite/gas/riscv/march-ok-s.d5
-rw-r--r--gas/testsuite/gas/riscv/march-ok-sx.d5
-rw-r--r--gas/testsuite/gas/riscv/march-ok-two-nse.d5
-rw-r--r--include/ChangeLog5
-rw-r--r--include/opcode/riscv.h2
-rw-r--r--opcodes/ChangeLog5
-rw-r--r--opcodes/riscv-dis.c2
36 files changed, 720 insertions, 143 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 3210b0c..30616eb 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 7d4f59f..a88c7fa 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -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;
+}
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index 836f05d..64e41b8 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -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 *);
diff --git a/gas/ChangeLog b/gas/ChangeLog
index a7bcfee..ba4aa15 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -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
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 426343c..92ddf80 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -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
index 0000000..8b13789
--- /dev/null
+++ b/gas/testsuite/gas/riscv/empty.s
@@ -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
index 0000000..d7b51c3
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32ef.d
@@ -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
index 0000000..15e56c8
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32ef.l
@@ -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
index 0000000..1e6e9e0
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32i.d
@@ -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
index 0000000..1977aed
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32i.l
@@ -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
index 0000000..054cf4d
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32iam.d
@@ -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
index 0000000..c7786f8
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32iam.l
@@ -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
index 0000000..b419a65
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32ic.d
@@ -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
index 0000000..d24ea2f
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32ic.l
@@ -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
index 0000000..5198090
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32icx2p.d
@@ -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
index 0000000..25627d4
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32icx2p.l
@@ -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
index 0000000..1cb4d9e
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32imc.d
@@ -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
index 0000000..d922e9d
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv32imc.l
@@ -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
index 0000000..e00a6f8
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv64I.d
@@ -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
index 0000000..5b46e77
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv64I.l
@@ -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
index 0000000..38d73db
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv64e.d
@@ -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
index 0000000..85f7554
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-fail-rv64e.l
@@ -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
index 0000000..38541ad
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-ok-g2.d
@@ -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
index 0000000..cd9e127
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-ok-g2_p1.d
@@ -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
index 0000000..b439314
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-ok-g2p0.d
@@ -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
index 0000000..eb8309c
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-ok-i2p0.d
@@ -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
index 0000000..6658417
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-ok-i2p0m2_a2f2.d
@@ -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
index 0000000..bdca7fb
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-ok-nse-with-version.d
@@ -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
index 0000000..6296a15
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-ok-s-with-version.d
@@ -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
index 0000000..7daa0a1
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-ok-s.d
@@ -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
index 0000000..e2172f2
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-ok-sx.d
@@ -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
index 0000000..0fe5037
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-ok-two-nse.d
@@ -0,0 +1,5 @@
+#as: -march=rv32imafd_xargle_xbargle
+#objdump: -dr
+#source: empty.s
+
+.*: file format elf32-littleriscv
diff --git a/include/ChangeLog b/include/ChangeLog
index 6424596..7375bac 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -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.
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index 10c5f3d..12cb4ca 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -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];
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index a9bdb2f..b04cf0e 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -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
diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index 890f1f8..9790820 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -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)