aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog31
-rw-r--r--bfd/elfnn-riscv.c21
-rw-r--r--bfd/elfxx-riscv.c267
-rw-r--r--bfd/elfxx-riscv.h5
-rw-r--r--gas/ChangeLog15
-rw-r--r--gas/config/tc-riscv.c4
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32id.d3
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32id.l2
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv32iq.l1
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv64iq.d3
-rw-r--r--gas/testsuite/gas/riscv/march-fail-rv64iq.l2
-rw-r--r--gas/testsuite/gas/riscv/march-imply-d.d6
-rw-r--r--gas/testsuite/gas/riscv/march-imply-f.d6
-rw-r--r--gas/testsuite/gas/riscv/march-imply-i2p0.d6
-rw-r--r--gas/testsuite/gas/riscv/march-imply-i2p1.d6
-rw-r--r--gas/testsuite/gas/riscv/march-imply-q.d6
16 files changed, 315 insertions, 69 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 807e004..927e688 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,36 @@
2020-12-01 Nelson Chu <nelson.chu@sifive.com>
+ * elfnn-riscv.c (riscv_merge_std_ext): Updated since
+ riscv_lookup_subset is changed.
+ * elfxx-riscv.c (riscv_ext_order): New Array used to compare the
+ extensions' order quickly.
+ (riscv_init_ext_order): New function. Init the riscv_ext_order
+ according to the riscv_supported_std_ext and parse_config[i].class
+ automatically.
+ (riscv_compare_subsets): New function. Similar to the strcmp, but
+ compare the subsets with the specific order.
+ (riscv_lookup_subset): Return TRUE and set `current` to the subset
+ if it is found. Otherwise, return FALSE and set `current` to the
+ place where we should insert the subset.
+ (riscv_add_implicit_subset): New function. Search the list first,
+ and then find the right place to add the implicit_subset.
+ (riscv_parse_add_subset): Since We have to add all arch string
+ extensions first, and then start to add their implicit extensions.
+ We can add arch string extensions in order by the original
+ riscv_add_subset, and then add the implicit subsets by the
+ riscv_add_implicit_subset. Besides, do not add the implicit
+ extensions if we failed to find their default versions.
+ (riscv_parse_std_ext): Updated.
+ (riscv_parse_add_implicit_subsets): New function. Add all implicit
+ extensions according to the arch string extensions.
+ (riscv_parse_subset): Call riscv_init_ext_order and
+ riscv_parse_add_implicit_subsets, before and after parsing the
+ arch string. Remove parts of the ISA conflict checking since
+ the implicit extensions are added.
+ * elfxx-riscv.h (riscv_lookup_subset): Updated.
+
+2020-12-01 Nelson Chu <nelson.chu@sifive.com>
+
* elfxx-riscv.c (riscv_lookup_subset): Moved to front.
(riscv_add_subset): Likewise.
(riscv_release_subset_list): Likewise.
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 4e87140..20944c8 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -3380,21 +3380,24 @@ riscv_merge_std_ext (bfd *ibfd,
/* Handle standard extension first. */
for (p = standard_exts; *p; ++p)
{
+ struct riscv_subset_t *ext_in, *ext_out, *ext_merged;
char find_ext[2] = {*p, '\0'};
- struct riscv_subset_t *find_in =
- riscv_lookup_subset (&in_subsets, find_ext);
- struct riscv_subset_t *find_out =
- riscv_lookup_subset (&out_subsets, find_ext);
+ bfd_boolean find_in, find_out;
- if (find_in == NULL && find_out == NULL)
+ find_in = riscv_lookup_subset (&in_subsets, find_ext, &ext_in);
+ find_out = riscv_lookup_subset (&out_subsets, find_ext, &ext_out);
+
+ if (!find_in && !find_out)
continue;
- if (!riscv_version_mismatch (ibfd, find_in, find_out))
+ if (find_in
+ && find_out
+ && !riscv_version_mismatch (ibfd, ext_in, ext_out))
return FALSE;
- struct riscv_subset_t *merged = find_out ? find_out : find_in;
- riscv_add_subset (&merged_subsets, merged->name,
- merged->major_version, merged->minor_version);
+ ext_merged = find_out ? ext_out : ext_in;
+ riscv_add_subset (&merged_subsets, ext_merged->name,
+ ext_merged->major_version, ext_merged->minor_version);
}
/* Skip all standard extensions. */
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 4ec429d..6244967 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -1025,22 +1025,75 @@ riscv_elf_add_sub_reloc (bfd *abfd,
return bfd_reloc_ok;
}
-/* Find subset in list, return NULL if not found. */
+/* Array is used to compare the all extensions' order quickly.
-riscv_subset_t *
-riscv_lookup_subset (const riscv_subset_list_t *subset_list,
- const char *subset)
+ Zero number means it is a preserved keyword.
+ Negative number means it is a prefix keyword (s, h, x, z).
+ Positive number means it is a standard extension. */
+
+static int riscv_ext_order[26] = {0};
+
+/* Similar to the strcmp. It returns an integer less than, equal to,
+ or greater than zero if `subset2` is found, respectively, to be less
+ than, to match, or be greater than `subset1`. */
+
+static int
+riscv_compare_subsets (const char *subset1, const char *subset2)
{
- riscv_subset_t *s;
+ int order1 = riscv_ext_order[(*subset1 - 'a')];
+ int order2 = riscv_ext_order[(*subset2 - 'a')];
- for (s = subset_list->head; s != NULL; s = s->next)
- if (strcasecmp (s->name, subset) == 0)
- return s;
+ /* Compare the standard extension first. */
+ if (order1 > 0 && order2 > 0)
+ return order1 - order2;
- return NULL;
+ if (order1 == order2 && order1 < 0)
+ {
+ /* Compare the standard addition z extensions. */
+ if (*subset1 == 'z')
+ {
+ order1 = riscv_ext_order[(*++subset1 - 'a')];
+ order2 = riscv_ext_order[(*++subset2 - 'a')];
+ if (order1 != order2)
+ return order1 - order2;
+ }
+ return strcasecmp (++subset1, ++subset2);
+ }
+
+ return order2 - order1;
}
-/* Add extension to the subset list. */
+/* Find subset in the list. Return TRUE and set `current` to the subset
+ if it is found. Otherwise, return FALSE and set `current` to the place
+ where we should insert the subset. However, return FALSE with the NULL
+ `current` means we should insert the subset at the head of subset list,
+ if needed. */
+
+bfd_boolean
+riscv_lookup_subset (const riscv_subset_list_t *subset_list,
+ const char *subset,
+ riscv_subset_t **current)
+{
+ riscv_subset_t *s, *pre_s = NULL;
+
+ for (s = subset_list->head;
+ s != NULL;
+ pre_s = s, s = s->next)
+ {
+ int cmp = riscv_compare_subsets (s->name, subset);
+ if (cmp == 0)
+ {
+ *current = s;
+ return TRUE;
+ }
+ else if (cmp > 0)
+ break;
+ }
+ *current = pre_s;
+ return FALSE;
+}
+
+/* Add arch string extension to the last of the subset list. */
void
riscv_add_subset (riscv_subset_list_t *subset_list,
@@ -1063,7 +1116,44 @@ riscv_add_subset (riscv_subset_list_t *subset_list,
subset_list->tail = s;
}
-/* Find the default versions for the extension before adding them to
+/* Add the implicit extension to the subset list. Search the
+ list first, and then find the right place to add. */
+
+static void
+riscv_add_implicit_subset (riscv_subset_list_t *subset_list,
+ const char *subset,
+ int major,
+ int minor)
+{
+ riscv_subset_t *current, *new;
+
+ if (riscv_lookup_subset (subset_list, subset, &current))
+ return;
+
+ new = xmalloc (sizeof *new);
+ new->name = xstrdup (subset);
+ new->major_version = major;
+ new->minor_version = minor;
+ new->next = NULL;
+
+ if (current != NULL)
+ {
+ new->next = current->next;
+ current->next = new;
+ }
+ else
+ {
+ new->next = subset_list->head;
+ subset_list->head = new;
+ }
+}
+
+/* We have to add all arch string extensions first, and then start to
+ add their implicit extensions. The arch string extensions must be
+ set in order, so we can add them to the last of the subset list
+ directly, without searching.
+
+ Find the default versions for the extension before adding them to
the subset list, if their versions are RISCV_UNKNOWN_VERSION.
Afterwards, report errors if we can not find their default versions. */
@@ -1071,7 +1161,8 @@ static void
riscv_parse_add_subset (riscv_parse_subset_t *rps,
const char *subset,
int major,
- int minor)
+ int minor,
+ bfd_boolean implicit)
{
int major_version = major;
int minor_version = minor;
@@ -1081,8 +1172,9 @@ riscv_parse_add_subset (riscv_parse_subset_t *rps,
&& rps->get_default_version != NULL)
rps->get_default_version (subset, &major_version, &minor_version);
- if (major_version == RISCV_UNKNOWN_VERSION
- || minor_version == RISCV_UNKNOWN_VERSION)
+ if (!implicit
+ && (major_version == RISCV_UNKNOWN_VERSION
+ || minor_version == RISCV_UNKNOWN_VERSION))
{
if (subset[0] == 'x')
rps->error_handler
@@ -1095,8 +1187,15 @@ riscv_parse_add_subset (riscv_parse_subset_t *rps,
return;
}
- riscv_add_subset (rps->subset_list, subset,
- major_version, minor_version);
+ if (!implicit)
+ riscv_add_subset (rps->subset_list, subset,
+ major_version, minor_version);
+ else if (major_version != RISCV_UNKNOWN_VERSION
+ && minor_version != RISCV_UNKNOWN_VERSION)
+ /* We only add the implicit extension if it is supported in the
+ chosen ISA spec. */
+ riscv_add_implicit_subset (rps->subset_list, subset,
+ major_version, minor_version);
}
/* Release subset list. */
@@ -1230,7 +1329,7 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,
&minor_version, TRUE);
riscv_parse_add_subset (rps, "i",
major_version,
- minor_version);
+ minor_version, FALSE);
break;
case 'e':
@@ -1239,11 +1338,11 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,
&minor_version, TRUE);
riscv_parse_add_subset (rps, "e",
major_version,
- minor_version);
+ minor_version, FALSE);
/* i-ext must be enabled. */
riscv_parse_add_subset (rps, "i",
RISCV_UNKNOWN_VERSION,
- RISCV_UNKNOWN_VERSION);
+ RISCV_UNKNOWN_VERSION, FALSE);
if (*rps->xlen > 32)
{
@@ -1263,13 +1362,13 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,
/* i-ext must be enabled. */
riscv_parse_add_subset (rps, "i",
RISCV_UNKNOWN_VERSION,
- RISCV_UNKNOWN_VERSION);
+ RISCV_UNKNOWN_VERSION, FALSE);
for ( ; *std_exts != 'q'; std_exts++)
{
subset[0] = *std_exts;
riscv_parse_add_subset (rps, subset,
RISCV_UNKNOWN_VERSION,
- RISCV_UNKNOWN_VERSION);
+ RISCV_UNKNOWN_VERSION, FALSE);
}
break;
@@ -1316,7 +1415,7 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,
&minor_version, TRUE);
riscv_parse_add_subset (rps, subset,
major_version,
- minor_version);
+ minor_version, FALSE);
}
return p;
@@ -1453,7 +1552,7 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
riscv_parse_add_subset (rps, subset,
major_version,
- minor_version);
+ minor_version, FALSE);
free (subset);
p += end_of_version - subset;
@@ -1559,6 +1658,92 @@ static const riscv_parse_config_t parse_config[] =
{RV_ISA_CLASS_UNKNOWN, NULL, NULL}
};
+/* Init the riscv_ext_order array. */
+
+static void
+riscv_init_ext_order (void)
+{
+ static bfd_boolean inited = FALSE;
+ const char *std_base_exts = "eig";
+ const char *std_remain_exts = riscv_supported_std_ext ();
+ const char *ext;
+ unsigned int i;
+ int order;
+
+ if (inited)
+ return;
+
+ /* All standard extensions' orders are positive numbers. */
+ order = 1;
+
+ /* Init the standard base extensions first. */
+ for (ext = std_base_exts; *ext; ext++)
+ riscv_ext_order[(*ext - 'a')] = order++;
+
+ /* Init the standard remaining extensions. */
+ for (ext = std_remain_exts; *ext; ext++)
+ riscv_ext_order[(*ext - 'a')] = order++;
+
+ /* Init the order for prefixed keywords. The orders are
+ negative numbers. */
+ order = -1;
+ for (i = 0; parse_config[i].class != RV_ISA_CLASS_UNKNOWN; i++)
+ {
+ ext = parse_config[i].prefix;
+ riscv_ext_order[(*ext - 'a')] = order--;
+ }
+
+ inited = TRUE;
+}
+
+/* Add the implicit extensions according to the arch string extensions. */
+
+static void
+riscv_parse_add_implicit_subsets (riscv_parse_subset_t *rps)
+{
+ riscv_subset_t *subset = NULL;
+
+ /* Add the zicsr and zifencei only when the i's version less than 2.1. */
+ if ((riscv_lookup_subset (rps->subset_list, "i", &subset))
+ && (subset->major_version < 2
+ || (subset->major_version == 2
+ && subset->minor_version < 1)))
+ {
+ riscv_parse_add_subset (rps, "zicsr",
+ RISCV_UNKNOWN_VERSION,
+ RISCV_UNKNOWN_VERSION, TRUE);
+ riscv_parse_add_subset (rps, "zifencei",
+ RISCV_UNKNOWN_VERSION,
+ RISCV_UNKNOWN_VERSION, TRUE);
+ }
+
+ if ((riscv_lookup_subset (rps->subset_list, "q", &subset)))
+ {
+ riscv_parse_add_subset (rps, "d",
+ RISCV_UNKNOWN_VERSION,
+ RISCV_UNKNOWN_VERSION, TRUE);
+ riscv_parse_add_subset (rps, "f",
+ RISCV_UNKNOWN_VERSION,
+ RISCV_UNKNOWN_VERSION, TRUE);
+ riscv_parse_add_subset (rps, "zicsr",
+ RISCV_UNKNOWN_VERSION,
+ RISCV_UNKNOWN_VERSION, TRUE);
+ }
+ else if ((riscv_lookup_subset (rps->subset_list, "d", &subset)))
+ {
+ riscv_parse_add_subset (rps, "f",
+ RISCV_UNKNOWN_VERSION,
+ RISCV_UNKNOWN_VERSION, TRUE);
+ riscv_parse_add_subset (rps, "zicsr",
+ RISCV_UNKNOWN_VERSION,
+ RISCV_UNKNOWN_VERSION, TRUE);
+ }
+ else if ((riscv_lookup_subset (rps->subset_list, "f", &subset)))
+ riscv_parse_add_subset (rps, "zicsr",
+ RISCV_UNKNOWN_VERSION,
+ RISCV_UNKNOWN_VERSION, TRUE);
+}
+
/* Function for parsing arch string.
Return Value:
@@ -1572,6 +1757,7 @@ bfd_boolean
riscv_parse_subset (riscv_parse_subset_t *rps,
const char *arch)
{
+ riscv_subset_t *subset = NULL;
const char *p;
size_t i;
bfd_boolean no_conflict = TRUE;
@@ -1612,6 +1798,10 @@ riscv_parse_subset (riscv_parse_subset_t *rps,
return FALSE;
}
+ /* Init the riscv_ext_order array to compare the order of extensions
+ quickly. */
+ riscv_init_ext_order ();
+
/* Parsing standard extension. */
p = riscv_parse_std_ext (rps, arch, p);
@@ -1634,42 +1824,27 @@ riscv_parse_subset (riscv_parse_subset_t *rps,
return FALSE;
}
+ /* Finally add implicit extensions according to the current
+ extensions. */
+ riscv_parse_add_implicit_subsets (rps);
+
/* Check the conflicts. */
- if (riscv_lookup_subset (rps->subset_list, "e")
- && riscv_lookup_subset (rps->subset_list, "f"))
+ if (riscv_lookup_subset (rps->subset_list, "e", &subset)
+ && riscv_lookup_subset (rps->subset_list, "f", &subset))
{
rps->error_handler
(_("-march=%s: rv32e does not support the `f' extension"),
arch);
no_conflict = FALSE;
}
-
- if (riscv_lookup_subset (rps->subset_list, "q") && *rps->xlen < 64)
+ if (riscv_lookup_subset (rps->subset_list, "q", &subset)
+ && *rps->xlen < 64)
{
rps->error_handler
(_("-march=%s: rv32 does not support the `q' extension"),
arch);
no_conflict = 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);
- no_conflict = 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);
- no_conflict = FALSE;
- }
-
return no_conflict;
}
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index 45705ce..89d4abb 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -60,9 +60,10 @@ riscv_add_subset (riscv_subset_list_t *,
const char *,
int, int);
-extern riscv_subset_t *
+extern bfd_boolean
riscv_lookup_subset (const riscv_subset_list_t *,
- const char *);
+ const char *,
+ riscv_subset_t **);
typedef struct
{
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 2b45509..0cf20e6 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,20 @@
2020-12-01 Nelson Chu <nelson.chu@sifive.com>
+ * config/tc-riscv.c (riscv_subset_supports): Updated.
+ * testsuite/gas/riscv/march-imply-i2p0.d: New testcase. Need to
+ add the implicit zicsr and zifencei when i's version less than 2.1.
+ * testsuite/gas/riscv/march-imply-i2p1.d: New testcase.
+ * testsuite/gas/riscv/march-imply-d.d: Likewise.
+ * testsuite/gas/riscv/march-imply-f.d: Likewise.
+ * testsuite/gas/riscv/march-imply-q.d: Likewise.
+ * testsuite/gas/riscv/march-fail-rv32iq.l: Updated.
+ * testsuite/gas/riscv/march-fail-rv32id.d: Removed.
+ * testsuite/gas/riscv/march-fail-rv32id.l: Likewise.
+ * testsuite/gas/riscv/march-fail-rv64iq.d: Likewise.
+ * testsuite/gas/riscv/march-fail-rv64iq.l: Likewise.
+
+2020-12-01 Nelson Chu <nelson.chu@sifive.com>
+
* config/tc-riscv.c (riscv_get_default_ext_version):
Change the version type from unsigned to int.
(riscv_set_arch): Use as_bad rather than as_fatal to
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 236a858..5e140fe 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -218,10 +218,12 @@ static riscv_subset_list_t riscv_subsets;
static bfd_boolean
riscv_subset_supports (const char *feature)
{
+ struct riscv_subset_t *subset;
+
if (riscv_opts.rvc && (strcasecmp (feature, "c") == 0))
return TRUE;
- return riscv_lookup_subset (&riscv_subsets, feature) != NULL;
+ return riscv_lookup_subset (&riscv_subsets, feature, &subset);
}
static bfd_boolean
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32id.d b/gas/testsuite/gas/riscv/march-fail-rv32id.d
deleted file mode 100644
index de741cb..0000000
--- a/gas/testsuite/gas/riscv/march-fail-rv32id.d
+++ /dev/null
@@ -1,3 +0,0 @@
-#as: -march=rv32id
-#source: empty.s
-#error_output: march-fail-rv32id.l
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32id.l b/gas/testsuite/gas/riscv/march-fail-rv32id.l
deleted file mode 100644
index c5f990c..0000000
--- a/gas/testsuite/gas/riscv/march-fail-rv32id.l
+++ /dev/null
@@ -1,2 +0,0 @@
-.*Assembler messages:
-.*Error: .*`d' extension requires `f' extension
diff --git a/gas/testsuite/gas/riscv/march-fail-rv32iq.l b/gas/testsuite/gas/riscv/march-fail-rv32iq.l
index 8143dd4..dc201b3 100644
--- a/gas/testsuite/gas/riscv/march-fail-rv32iq.l
+++ b/gas/testsuite/gas/riscv/march-fail-rv32iq.l
@@ -1,3 +1,2 @@
.*Assembler messages:
.*Error: .*rv32 does not support the `q' extension
-.*Error: .*`q' extension requires `d' extension
diff --git a/gas/testsuite/gas/riscv/march-fail-rv64iq.d b/gas/testsuite/gas/riscv/march-fail-rv64iq.d
deleted file mode 100644
index c97a812..0000000
--- a/gas/testsuite/gas/riscv/march-fail-rv64iq.d
+++ /dev/null
@@ -1,3 +0,0 @@
-#as: -march=rv64iq
-#source: empty.s
-#error_output: march-fail-rv64iq.l
diff --git a/gas/testsuite/gas/riscv/march-fail-rv64iq.l b/gas/testsuite/gas/riscv/march-fail-rv64iq.l
deleted file mode 100644
index 787f46d..0000000
--- a/gas/testsuite/gas/riscv/march-fail-rv64iq.l
+++ /dev/null
@@ -1,2 +0,0 @@
-.*Assembler messages:
-.*Error: .*`q' extension requires `d' extension
diff --git a/gas/testsuite/gas/riscv/march-imply-d.d b/gas/testsuite/gas/riscv/march-imply-d.d
new file mode 100644
index 0000000..ce2b479
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-imply-d.d
@@ -0,0 +1,6 @@
+#as: -march=rv32id -march-attr -misa-spec=20191213
+#readelf: -A
+#source: empty.s
+Attribute Section: riscv
+File Attributes
+ Tag_RISCV_arch: "rv32i2p1_f2p2_d2p2_zicsr2p0"
diff --git a/gas/testsuite/gas/riscv/march-imply-f.d b/gas/testsuite/gas/riscv/march-imply-f.d
new file mode 100644
index 0000000..bc372ae
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-imply-f.d
@@ -0,0 +1,6 @@
+#as: -march=rv32if -march-attr -misa-spec=20191213
+#readelf: -A
+#source: empty.s
+Attribute Section: riscv
+File Attributes
+ Tag_RISCV_arch: "rv32i2p1_f2p2_zicsr2p0"
diff --git a/gas/testsuite/gas/riscv/march-imply-i2p0.d b/gas/testsuite/gas/riscv/march-imply-i2p0.d
new file mode 100644
index 0000000..17fcc7a
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-imply-i2p0.d
@@ -0,0 +1,6 @@
+#as: -march=rv32i2p0 -march-attr -misa-spec=20191213
+#readelf: -A
+#source: empty.s
+Attribute Section: riscv
+File Attributes
+ Tag_RISCV_arch: "rv32i2p0_zicsr2p0_zifencei2p0"
diff --git a/gas/testsuite/gas/riscv/march-imply-i2p1.d b/gas/testsuite/gas/riscv/march-imply-i2p1.d
new file mode 100644
index 0000000..0e9a464
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-imply-i2p1.d
@@ -0,0 +1,6 @@
+#as: -march=rv32i -march-attr -misa-spec=20191213
+#readelf: -A
+#source: empty.s
+Attribute Section: riscv
+File Attributes
+ Tag_RISCV_arch: "rv32i2p1"
diff --git a/gas/testsuite/gas/riscv/march-imply-q.d b/gas/testsuite/gas/riscv/march-imply-q.d
new file mode 100644
index 0000000..d631d6f
--- /dev/null
+++ b/gas/testsuite/gas/riscv/march-imply-q.d
@@ -0,0 +1,6 @@
+#as: -march=rv64iq -march-attr -misa-spec=20191213
+#readelf: -A
+#source: empty.s
+Attribute Section: riscv
+File Attributes
+ Tag_RISCV_arch: "rv64i2p1_f2p2_d2p2_q2p2_zicsr2p0"