[committed] RISC-V: Merged extension string tables and their version tables into one.

Message ID 20210917083618.11821-1-nelson.chu@sifive.com
State New
Headers show
Series
  • [committed] RISC-V: Merged extension string tables and their version tables into one.
Related show

Commit Message

Nelson Chu Sept. 17, 2021, 8:36 a.m.
There are two main reasons for this patch,

* In the past we had two extension tables, one is used to record all
supported extensions in bfd/elfxx-riscv.c, another is used to get the
default extension versions in gas/config/tc-riscv.c.  It is hard to
maintain lots of tables in different files, but in fact we can merge
them into just one table.  Therefore, we now define many riscv_supported_std*
tables, which record names and versions for all supported extensions.
We not only use these tables to initialize the riscv_ext_order, but
also use them to get the default versions of extensions, and decide if
the extensions should be enbaled by default.

* We add a new filed `default_enable' for the riscv_supported_std* tables,
to decide if the extension should be enabled by default.  For now if the
`default_enable' field of the extension is set to EXT_DEFAULT, then we
should enable the extension when the -march and elf architecture attributes
are not set.  In the future, I suppose the `default_enable' can be set
to lots of EXT_<VENDOR>, each vendor can decide to open which extensions,
when the target triple of vendor is chosen.

The elf/linux regression tests of riscv-gnu-toolchain are passed.

bfd/
	* elfnn-riscv.c (cpu-riscv.h): Removed sine it is included in
	bfd/elfxx-riscv.h.
	(riscv_merge_std_ext): Updated since the field of rpe is changed.
	* elfxx-riscv.c (cpu-riscv.h): Removed.
	(riscv_implicit_subsets): Added implicit extensions for g.
	(struct riscv_supported_ext): Used to be riscv_ext_version.  Moved
	from gas/config/tc-riscv.c, and added new field `default_enable' to
	decide if the extension should be enabled by default.
	(EXT_DEFAULT): Defined for `default_enable' field.
	(riscv_supported_std_ext): It used to return the supported standard
	architecture string, but now we move ext_version_table from
	gas/config/tc-riscv.c to here, and rename it to riscv_supported_std_ext.
	Currently we not only use the table to initialize riscv_ext_order, but
	also get the default versions of extensions, and decide if the extensions
	should be enbaled by default.
	(riscv_supported_std_z_ext): Likewise, but is used for z* extensions.
	(riscv_supported_std_s_ext): Likewise, but is used for s* extensions.
	(riscv_supported_std_h_ext): Likewise, but is used for h* extensions.
	(riscv_supported_std_zxm_ext): Likewise, but is used for zxm* extensions.
	(riscv_all_supported_ext): Includes all supported extension tables.
	(riscv_known_prefixed_ext): Updated.
	(riscv_valid_prefixed_ext): Updated.
	(riscv_init_ext_order): Init the riscv_ext_order table according to
	riscv_supported_std_ext.
	(riscv_get_default_ext_version): Moved from gas/config/tc-riscv.c.
	Get the versions of extensions from riscv_supported_std* tables.
	(riscv_parse_add_subset): Updated.
	(riscv_parse_std_ext): Updated.
	(riscv_set_default_arch): Set the default subset list according to
	the default_enable field of riscv_supported_*ext tables.
	(riscv_parse_subset): If the input ARCH is NULL, then we call
	riscv_set_default_arch to set the default subset list.
	* elfxx-riscv.h (cpu-riscv.h): Included.
	(riscv_parse_subset_t): Removed get_default_version field, and added
	isa_spec field to replace it.
	(extern riscv_supported_std_ext): Removed.
gas/
	* (bfd/cpu-riscv.h): Removed.
	(struct riscv_ext_version): Renamed and moved to bfd/elfxx-riscv.c.
	(ext_version_table): Likewise.
	(riscv_get_default_ext_version): Likewise.
	(ext_version_hash): Removed.
	(init_ext_version_hash): Removed.
	(riscv_set_arch): Updated since the field of rps is changed.  Besides,
	report error when the architecture string is empty.
	(riscv_after_parse_args): Updated.
---
 bfd/elfnn-riscv.c     |   7 +-
 bfd/elfxx-riscv.c     | 350 +++++++++++++++++++++++++++---------------
 bfd/elfxx-riscv.h     |   8 +-
 gas/config/tc-riscv.c | 126 +--------------
 4 files changed, 235 insertions(+), 256 deletions(-)

-- 
2.30.2

Patch

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index a10384cd4d3..2e8df72fa2a 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -32,7 +32,6 @@ 
 #include "elf/riscv.h"
 #include "opcode/riscv.h"
 #include "objalloc.h"
-#include "cpu-riscv.h"
 
 #include <limits.h>
 #ifndef CHAR_BIT
@@ -3443,7 +3442,7 @@  riscv_merge_std_ext (bfd *ibfd,
 		     struct riscv_subset_t **pin,
 		     struct riscv_subset_t **pout)
 {
-  const char *standard_exts = riscv_supported_std_ext ();
+  const char *standard_exts = "mafdqlcbjtpvn";
   const char *p;
   struct riscv_subset_t *in = *pin;
   struct riscv_subset_t *out = *pout;
@@ -3587,13 +3586,13 @@  riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch)
   rpe_in.subset_list = &in_subsets;
   rpe_in.error_handler = _bfd_error_handler;
   rpe_in.xlen = &xlen_in;
-  rpe_in.get_default_version = NULL;
+  rpe_in.isa_spec = ISA_SPEC_CLASS_NONE;
   rpe_in.check_unknown_prefixed_ext = false;
 
   rpe_out.subset_list = &out_subsets;
   rpe_out.error_handler = _bfd_error_handler;
   rpe_out.xlen = &xlen_out;
-  rpe_out.get_default_version = NULL;
+  rpe_out.isa_spec = ISA_SPEC_CLASS_NONE;
   rpe_out.check_unknown_prefixed_ext = false;
 
   if (in_arch == NULL && out_arch == NULL)
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index ddcf872d63c..b467bceb919 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -29,7 +29,6 @@ 
 #include "libiberty.h"
 #include "elfxx-riscv.h"
 #include "safe-ctype.h"
-#include "cpu-riscv.h"
 
 #define MINUS_ONE ((bfd_vma)0 - 1)
 
@@ -1066,6 +1065,11 @@  static struct riscv_implicit_subset riscv_implicit_subsets[] =
   {"e", "i",		check_implicit_always},
   {"i", "zicsr",	check_implicit_for_i},
   {"i", "zifencei",	check_implicit_for_i},
+  {"g", "i",		check_implicit_always},
+  {"g", "m",		check_implicit_always},
+  {"g", "a",		check_implicit_always},
+  {"g", "f",		check_implicit_always},
+  {"g", "d",		check_implicit_always},
   {"g", "zicsr",	check_implicit_always},
   {"g", "zifencei",	check_implicit_always},
   {"q", "d",		check_implicit_always},
@@ -1074,31 +1078,98 @@  static struct riscv_implicit_subset riscv_implicit_subsets[] =
   {NULL, NULL, NULL}
 };
 
-/* Lists of prefixed class extensions that binutils should know about.
-   Whether or not a particular entry is in these lists will dictate if
-   gas/ld will accept its presence in the architecture string.
+/* For default_enable field, decide if the extension should
+   be enbaled by default.  */
 
-   Please add the extensions to the lists in lower case.  However, keep
-   these subsets in alphabetical order in these tables is recommended,
-   although there is no impact on the current implementation.  */
+#define EXT_DEFAULT   0x1
 
-static const char * const riscv_std_z_ext_strtab[] =
+/* List all extensions that binutils should know about.  */
+
+struct riscv_supported_ext
 {
-  "zba", "zbb", "zbc", "zicsr", "zifencei", "zihintpause", NULL
+  const char *name;
+  enum riscv_spec_class isa_spec_class;
+  int major_version;
+  int minor_version;
+  unsigned long default_enable;
 };
 
-static const char * const riscv_std_s_ext_strtab[] =
+/* The standard extensions must be added in canonical order.  */
+
+static struct riscv_supported_ext riscv_supported_std_ext[] =
 {
-  NULL
+  {"e",		ISA_SPEC_CLASS_20191213,	1, 9, 0 },
+  {"e",		ISA_SPEC_CLASS_20190608,	1, 9, 0 },
+  {"e",		ISA_SPEC_CLASS_2P2,		1, 9, 0 },
+  {"i",		ISA_SPEC_CLASS_20191213,	2, 1, 0 },
+  {"i",		ISA_SPEC_CLASS_20190608,	2, 1, 0 },
+  {"i",		ISA_SPEC_CLASS_2P2,		2, 0, 0 },
+  /* The g is a special case which we don't want to output it,
+     but still need it when adding implicit extensions.  */
+  {"g",		ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, EXT_DEFAULT },
+  {"m",		ISA_SPEC_CLASS_20191213,	2, 0, 0 },
+  {"m",		ISA_SPEC_CLASS_20190608,	2, 0, 0 },
+  {"m",		ISA_SPEC_CLASS_2P2,		2, 0, 0 },
+  {"a",		ISA_SPEC_CLASS_20191213,	2, 1, 0 },
+  {"a",		ISA_SPEC_CLASS_20190608,	2, 0, 0 },
+  {"a",		ISA_SPEC_CLASS_2P2,		2, 0, 0 },
+  {"f",		ISA_SPEC_CLASS_20191213,	2, 2, 0 },
+  {"f",		ISA_SPEC_CLASS_20190608,	2, 2, 0 },
+  {"f",		ISA_SPEC_CLASS_2P2,		2, 0, 0 },
+  {"d",		ISA_SPEC_CLASS_20191213,	2, 2, 0 },
+  {"d",		ISA_SPEC_CLASS_20190608,	2, 2, 0 },
+  {"d",		ISA_SPEC_CLASS_2P2,		2, 0, 0 },
+  {"q",		ISA_SPEC_CLASS_20191213,	2, 2, 0 },
+  {"q",		ISA_SPEC_CLASS_20190608,	2, 2, 0 },
+  {"q",		ISA_SPEC_CLASS_2P2,		2, 0, 0 },
+  {"l",		ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+  {"c",		ISA_SPEC_CLASS_20191213,	2, 0, 0 },
+  {"c",		ISA_SPEC_CLASS_20190608,	2, 0, 0 },
+  {"c",		ISA_SPEC_CLASS_2P2,		2, 0, 0 },
+  {"b",		ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+  {"j",		ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+  {"t",		ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+  {"p",		ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+  {"v",		ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+  {"n",		ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+  {NULL, 0, 0, 0, 0}
 };
 
-static const char * const riscv_std_h_ext_strtab[] =
+static struct riscv_supported_ext riscv_supported_std_z_ext[] =
 {
-  NULL
+  {"zicsr",		ISA_SPEC_CLASS_20191213,	2, 0,  0 },
+  {"zicsr",		ISA_SPEC_CLASS_20190608,	2, 0,  0 },
+  {"zifencei",		ISA_SPEC_CLASS_20191213,	2, 0,  0 },
+  {"zifencei",		ISA_SPEC_CLASS_20190608,	2, 0,  0 },
+  {"zihintpause",	ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
+  {"zbb",		ISA_SPEC_CLASS_DRAFT,		0, 93, 0 },
+  {"zba",		ISA_SPEC_CLASS_DRAFT,		0, 93, 0 },
+  {"zbc",		ISA_SPEC_CLASS_DRAFT,		0, 93, 0 },
+  {NULL, 0, 0, 0, 0}
+};
+
+static struct riscv_supported_ext riscv_supported_std_s_ext[] =
+{
+  {NULL, 0, 0, 0, 0}
+};
+
+static struct riscv_supported_ext riscv_supported_std_h_ext[] =
+{
+  {NULL, 0, 0, 0, 0}
 };
 
-static const char * const riscv_std_zxm_ext_strtab[] =
+static struct riscv_supported_ext riscv_supported_std_zxm_ext[] =
 {
+  {NULL, 0, 0, 0, 0}
+};
+
+const struct riscv_supported_ext *riscv_all_supported_ext[] =
+{
+  riscv_supported_std_ext,
+  riscv_supported_std_z_ext,
+  riscv_supported_std_s_ext,
+  riscv_supported_std_h_ext,
+  riscv_supported_std_zxm_ext,
   NULL
 };
 
@@ -1156,11 +1227,11 @@  riscv_get_prefix_class (const char *arch)
 
 static bool
 riscv_known_prefixed_ext (const char *ext,
-			  const char *const *known_exts)
+			  struct riscv_supported_ext *known_exts)
 {
   size_t i;
-  for (i = 0; known_exts[i]; ++i)
-    if (strcmp (ext, known_exts[i]) == 0)
+  for (i = 0; known_exts[i].name != NULL; ++i)
+    if (strcmp (ext, known_exts[i].name) == 0)
       return true;
   return false;
 }
@@ -1175,13 +1246,13 @@  riscv_valid_prefixed_ext (const char *ext)
   switch (class)
   {
   case RV_ISA_CLASS_Z:
-    return riscv_known_prefixed_ext (ext, riscv_std_z_ext_strtab);
+    return riscv_known_prefixed_ext (ext, riscv_supported_std_z_ext);
   case RV_ISA_CLASS_ZXM:
-    return riscv_known_prefixed_ext (ext, riscv_std_zxm_ext_strtab);
+    return riscv_known_prefixed_ext (ext, riscv_supported_std_zxm_ext);
   case RV_ISA_CLASS_S:
-    return riscv_known_prefixed_ext (ext, riscv_std_s_ext_strtab);
+    return riscv_known_prefixed_ext (ext, riscv_supported_std_s_ext);
   case RV_ISA_CLASS_H:
-    return riscv_known_prefixed_ext (ext, riscv_std_h_ext_strtab);
+    return riscv_known_prefixed_ext (ext, riscv_supported_std_h_ext);
   case RV_ISA_CLASS_X:
     /* Only the single x is invalid.  */
     if (strcmp (ext, "x") != 0)
@@ -1201,24 +1272,22 @@  static void
 riscv_init_ext_order (void)
 {
   static bool inited = false;
-  const char *std_base_exts = "eig";
-  const char *std_remain_exts = riscv_supported_std_ext ();
-  const char *ext;
-  int order;
-
   if (inited)
     return;
 
   /* The orders of all standard extensions are positive.  */
-  order = 1;
-
-  /* Init the standard base extensions first.  */
-  for (ext = std_base_exts; *ext; ext++)
-    riscv_ext_order[(*ext - 'a')] = order++;
+  int order = 1;
 
-  /* Init the standard remaining extensions.  */
-  for (ext = std_remain_exts; *ext; ext++)
-    riscv_ext_order[(*ext - 'a')] = order++;
+  int i = 0;
+  while (riscv_supported_std_ext[i].name != NULL)
+    {
+      const char *ext = riscv_supported_std_ext[i].name;
+      riscv_ext_order[(*ext - 'a')] = order++;
+      i++;
+      while (riscv_supported_std_ext[i].name
+	     && strcmp (ext, riscv_supported_std_ext[i].name) == 0)
+	i++;
+    }
 
   /* Some of the prefixed keyword are not single letter, so we set
      their prefixed orders in the riscv_compare_subsets directly,
@@ -1345,6 +1414,46 @@  riscv_add_subset (riscv_subset_list_t *subset_list,
     subset_list->tail = new;
 }
 
+/* Get the default versions from the riscv_supported_*ext tables.  */
+
+static void
+riscv_get_default_ext_version (enum riscv_spec_class default_isa_spec,
+			       const char *name,
+			       int *major_version,
+			       int *minor_version)
+{
+  if (name == NULL || default_isa_spec == ISA_SPEC_CLASS_NONE)
+    return;
+
+  struct riscv_supported_ext *table = NULL;
+  enum riscv_prefix_ext_class class = riscv_get_prefix_class (name);
+  switch (class)
+    {
+    case RV_ISA_CLASS_ZXM: table = riscv_supported_std_zxm_ext; break;
+    case RV_ISA_CLASS_Z: table = riscv_supported_std_z_ext; break;
+    case RV_ISA_CLASS_S: table = riscv_supported_std_s_ext; break;
+    case RV_ISA_CLASS_H: table = riscv_supported_std_h_ext; break;
+    case RV_ISA_CLASS_X:
+      break;
+    default:
+      table = riscv_supported_std_ext;
+    }
+
+  int i = 0;
+  while (table != NULL && table[i].name != NULL)
+    {
+      if (strcmp (table[i].name, name) == 0
+	  && (table[i].isa_spec_class == ISA_SPEC_CLASS_DRAFT
+	      || table[i].isa_spec_class == default_isa_spec))
+	{
+	  *major_version = table[i].major_version;
+	  *minor_version = table[i].minor_version;
+	  return;
+	}
+      i++;
+    }
+}
+
 /* 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.  */
@@ -1359,10 +1468,10 @@  riscv_parse_add_subset (riscv_parse_subset_t *rps,
   int major_version = major;
   int minor_version = minor;
 
-  if ((major_version == RISCV_UNKNOWN_VERSION
+  if (major_version == RISCV_UNKNOWN_VERSION
        || minor_version == RISCV_UNKNOWN_VERSION)
-      && rps->get_default_version != NULL)
-    rps->get_default_version (subset, &major_version, &minor_version);
+    riscv_get_default_ext_version (rps->isa_spec, subset,
+				   &major_version, &minor_version);
 
   /* We don't care the versions of the implicit extensions.  */
   if (!implicit
@@ -1476,15 +1585,6 @@  riscv_parsing_subset_version (riscv_parse_subset_t *rps,
   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:
@@ -1500,59 +1600,13 @@  riscv_parse_std_ext (riscv_parse_subset_t *rps,
 		     const char *arch,
 		     const char *p)
 {
-  const char *all_std_exts = riscv_supported_std_ext ();
-  const char *std_exts = all_std_exts;
-  int major_version;
-  int minor_version;
-  char subset[2] = {0, 0};
-
   /* First letter must start with i, e or g.  */
-  switch (*p)
+  if (*p != 'e' && *p != 'i' && *p != 'g')
     {
-      case 'i':
-	p = riscv_parsing_subset_version (rps, arch, ++p,
-					  &major_version,
-					  &minor_version, true);
-	riscv_parse_add_subset (rps, "i",
-				major_version,
-				minor_version, false);
-	break;
-
-      case 'e':
-	p = riscv_parsing_subset_version (rps, arch, ++p,
-					  &major_version,
-					  &minor_version, true);
-	riscv_parse_add_subset (rps, "e",
-				major_version,
-				minor_version, false);
-	break;
-
-      case 'g':
-	p = riscv_parsing_subset_version (rps, arch, ++p,
-					  &major_version,
-					  &minor_version, true);
-	/* Expand g to imafd.  */
-	riscv_parse_add_subset (rps, "i",
-				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, false);
-	  }
-	/* Add g as an implicit extension.  */
-	riscv_parse_add_subset (rps, "g",
-				RISCV_UNKNOWN_VERSION,
-				RISCV_UNKNOWN_VERSION, true);
-	break;
-
-      default:
-	rps->error_handler
-	  (_("%s: first ISA extension must be `e', `i' or `g'"),
-	   arch);
-	return NULL;
+      rps->error_handler
+	(_("%s: first ISA extension must be `e', `i' or `g'"),
+	 arch);
+      return NULL;
     }
 
   while (p != NULL && *p != '\0')
@@ -1568,32 +1622,41 @@  riscv_parse_std_ext (riscv_parse_subset_t *rps,
 	  continue;
 	}
 
-      /* Checking canonical order.  */
-      char std_ext = *p;
-      while (*std_exts && std_ext != *std_exts)
-	std_exts++;
+      bool implicit = false;
+      int major = RISCV_UNKNOWN_VERSION;
+      int minor = RISCV_UNKNOWN_VERSION;
+      char subset[2] = {0, 0};
+
+      subset[0] = *p;
 
-      if (std_ext != *std_exts)
+      /* Check if the standard extension is supported.  */
+      if (riscv_ext_order[(subset[0] - 'a')] == 0)
 	{
-	  if (riscv_ext_order[(std_ext - 'a')] == 0)
-	    rps->error_handler
-	      (_("%s: unknown standard ISA extension `%c'"),
-	       arch, std_ext);
-	  else
-	    rps->error_handler
-	      (_("%s: standard ISA extension `%c' is not "
-		 "in canonical order"), arch, std_ext);
+	  rps->error_handler
+	    (_("%s: unknown standard ISA extension `%c'"),
+	     arch, subset[0]);
 	  return NULL;
 	}
 
-      std_exts++;
-      subset[0] = std_ext;
-      p = riscv_parsing_subset_version (rps, arch, ++p,
-					&major_version,
-					&minor_version, true);
-      riscv_parse_add_subset (rps, subset,
-			      major_version,
-			      minor_version, false);
+      /* Checking canonical order.  */
+      if (rps->subset_list->tail != NULL
+	  && riscv_compare_subsets (rps->subset_list->tail->name, subset) > 0)
+	{
+	  rps->error_handler
+	    (_("%s: standard ISA extension `%c' is not "
+	       "in canonical order"), arch, subset[0]);
+	  return NULL;
+	}
+
+      p = riscv_parsing_subset_version (rps, arch, ++p, &major, &minor, true);
+      /* Added g as an implicit extension.  */
+      if (subset[0] == 'g')
+	{
+	  implicit = true;
+	  major = RISCV_UNKNOWN_VERSION;
+	  minor = RISCV_UNKNOWN_VERSION;
+	}
+      riscv_parse_add_subset (rps, subset, major, minor, implicit);
     }
 
   return p;
@@ -1761,6 +1824,30 @@  riscv_parse_check_conflicts (riscv_parse_subset_t *rps)
   return no_conflict;
 }
 
+/* Set the default subset list according to the default_enable field
+   of riscv_supported_*ext tables.  */
+
+static void
+riscv_set_default_arch (riscv_parse_subset_t *rps)
+{
+  unsigned long enable = EXT_DEFAULT;
+  int i, j;
+  for (i = 0; riscv_all_supported_ext[i] != NULL; i++)
+    {
+      const struct riscv_supported_ext *table = riscv_all_supported_ext[i];
+      for (j = 0; table[j].name != NULL; j++)
+	{
+	  bool implicit = false;
+	  if (strcmp (table[j].name, "g") == 0)
+	    implicit = true;
+	  if (table[j].default_enable & enable)
+	    riscv_parse_add_subset (rps, table[j].name,
+				    RISCV_UNKNOWN_VERSION,
+				    RISCV_UNKNOWN_VERSION, implicit);
+	}
+    }
+}
+
 /* Function for parsing ISA string.
 
    Return Value:
@@ -1776,6 +1863,17 @@  riscv_parse_subset (riscv_parse_subset_t *rps,
 {
   const char *p;
 
+  /* Init the riscv_ext_order array to compare the order of extensions
+     quickly.  */
+  riscv_init_ext_order ();
+
+  if (arch == NULL)
+    {
+      riscv_set_default_arch (rps);
+      riscv_parse_add_implicit_subsets (rps);
+      return riscv_parse_check_conflicts (rps);
+    }
+
   for (p = arch; *p != '\0'; p++)
     {
       if (ISUPPER (*p))
@@ -1800,11 +1898,13 @@  riscv_parse_subset (riscv_parse_subset_t *rps,
     }
   else
     {
-      /* ISA string shouldn't be NULL or empty here.  However,
-	 it might be empty only when we failed to merge the ISA
-	 string in the riscv_merge_attributes.  We have already
-	 issued the correct error message in another side, so do
-	 not issue this error when the ISA string is empty.  */
+      /* ISA string shouldn't be NULL or empty here.  For linker,
+	 it might be empty when we failed to merge the ISA string
+	 in the riscv_merge_attributes.  For assembler, we might
+	 give an empty string by .attribute arch, "" or -march=.
+	 However, We have already issued the correct error message
+	 in another side, so do not issue this error when the ISA
+	 string is empty.  */
       if (strlen (arch))
 	rps->error_handler (
 	  _("%s: ISA string must begin with rv32 or rv64"),
@@ -1812,10 +1912,6 @@  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);
 
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index 6a2501b7be8..e691a97ecda 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -23,6 +23,7 @@ 
 #include "elf/common.h"
 #include "elf/internal.h"
 #include "opcode/riscv.h"
+#include "cpu-riscv.h"
 
 #define RISCV_UNKNOWN_VERSION -1
 
@@ -71,9 +72,7 @@  typedef struct
   void (*error_handler) (const char *,
 			 ...) ATTRIBUTE_PRINTF_1;
   unsigned *xlen;
-  void (*get_default_version) (const char *,
-			       int *,
-			       int *);
+  enum riscv_spec_class isa_spec;
   bool check_unknown_prefixed_ext;
 } riscv_parse_subset_t;
 
@@ -81,9 +80,6 @@  extern bool
 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/config/tc-riscv.c b/gas/config/tc-riscv.c
index 1dbc4d85b86..e7b733a4e6d 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -29,7 +29,6 @@ 
 #include "dwarf2dbg.h"
 #include "dw2gencfi.h"
 
-#include "bfd/cpu-riscv.h"
 #include "bfd/elfxx-riscv.h"
 #include "elf/riscv.h"
 #include "opcode/riscv.h"
@@ -88,65 +87,6 @@  struct riscv_csr_extra
   struct riscv_csr_extra *next;
 };
 
-/* All standard/Z* extensions defined in all supported ISA spec.  */
-struct riscv_ext_version
-{
-  const char *name;
-  enum riscv_spec_class isa_spec_class;
-  int major_version;
-  int minor_version;
-};
-
-static const struct riscv_ext_version ext_version_table[] =
-{
-  {"e", ISA_SPEC_CLASS_20191213, 1, 9},
-  {"e", ISA_SPEC_CLASS_20190608, 1, 9},
-  {"e", ISA_SPEC_CLASS_2P2,      1, 9},
-
-  {"i", ISA_SPEC_CLASS_20191213, 2, 1},
-  {"i", ISA_SPEC_CLASS_20190608, 2, 1},
-  {"i", ISA_SPEC_CLASS_2P2,      2, 0},
-
-  {"m", ISA_SPEC_CLASS_20191213, 2, 0},
-  {"m", ISA_SPEC_CLASS_20190608, 2, 0},
-  {"m", ISA_SPEC_CLASS_2P2,      2, 0},
-
-  {"a", ISA_SPEC_CLASS_20191213, 2, 1},
-  {"a", ISA_SPEC_CLASS_20190608, 2, 0},
-  {"a", ISA_SPEC_CLASS_2P2,      2, 0},
-
-  {"f", ISA_SPEC_CLASS_20191213, 2, 2},
-  {"f", ISA_SPEC_CLASS_20190608, 2, 2},
-  {"f", ISA_SPEC_CLASS_2P2,      2, 0},
-
-  {"d", ISA_SPEC_CLASS_20191213, 2, 2},
-  {"d", ISA_SPEC_CLASS_20190608, 2, 2},
-  {"d", ISA_SPEC_CLASS_2P2,      2, 0},
-
-  {"q", ISA_SPEC_CLASS_20191213, 2, 2},
-  {"q", ISA_SPEC_CLASS_20190608, 2, 2},
-  {"q", ISA_SPEC_CLASS_2P2,      2, 0},
-
-  {"c", ISA_SPEC_CLASS_20191213, 2, 0},
-  {"c", ISA_SPEC_CLASS_20190608, 2, 0},
-  {"c", ISA_SPEC_CLASS_2P2,      2, 0},
-
-  {"zicsr", ISA_SPEC_CLASS_20191213, 2, 0},
-  {"zicsr", ISA_SPEC_CLASS_20190608, 2, 0},
-
-  {"zifencei", ISA_SPEC_CLASS_20191213, 2, 0},
-  {"zifencei", ISA_SPEC_CLASS_20190608, 2, 0},
-
-  {"zihintpause", ISA_SPEC_CLASS_DRAFT, 1, 0},
-
-  {"zbb",   ISA_SPEC_CLASS_DRAFT, 0, 93},
-  {"zba",   ISA_SPEC_CLASS_DRAFT, 0, 93},
-  {"zbc",   ISA_SPEC_CLASS_DRAFT, 0, 93},
-
-  /* Terminate the list.  */
-  {NULL, 0, 0, 0}
-};
-
 #ifndef DEFAULT_ARCH
 #define DEFAULT_ARCH "riscv64"
 #endif
@@ -349,57 +289,6 @@  riscv_multi_subset_supports (enum riscv_insn_class insn_class)
     }
 }
 
-/* Handle of the extension with version hash table.  */
-static htab_t ext_version_hash = NULL;
-
-static htab_t
-init_ext_version_hash (void)
-{
-  const struct riscv_ext_version *table = ext_version_table;
-  htab_t hash = str_htab_create ();
-  int i = 0;
-
-  while (table[i].name)
-    {
-      const char *name = table[i].name;
-      if (str_hash_insert (hash, name, &table[i], 0) != NULL)
-	as_fatal (_("internal: duplicate %s"), name);
-
-      i++;
-      while (table[i].name
-	     && strcmp (table[i].name, name) == 0)
-       i++;
-    }
-
-  return hash;
-}
-
-static void
-riscv_get_default_ext_version (const char *name,
-			       int *major_version,
-			       int *minor_version)
-{
-  struct riscv_ext_version *ext;
-
-  if (name == NULL || default_isa_spec == ISA_SPEC_CLASS_NONE)
-    return;
-
-  ext = (struct riscv_ext_version *) str_hash_find (ext_version_hash, name);
-  while (ext
-	 && ext->name
-	 && strcmp (ext->name, name) == 0)
-    {
-      if (ext->isa_spec_class == ISA_SPEC_CLASS_DRAFT
-	  || ext->isa_spec_class == default_isa_spec)
-	{
-	  *major_version = ext->major_version;
-	  *minor_version = ext->minor_version;
-	  return;
-	}
-      ext++;
-    }
-}
-
 /* Set which ISA and extensions are available.  */
 
 static void
@@ -409,11 +298,15 @@  riscv_set_arch (const char *s)
   rps.subset_list = &riscv_subsets;
   rps.error_handler = as_bad;
   rps.xlen = &xlen;
-  rps.get_default_version = riscv_get_default_ext_version;
+  rps.isa_spec = default_isa_spec;
   rps.check_unknown_prefixed_ext = true;
 
-  if (s == NULL)
-    return;
+  if (s != NULL && strcmp (s, "") == 0)
+    {
+      as_bad (_("the architecture string of -march and elf architecture "
+		"attributes cannot be empty"));
+      return;
+    }
 
   riscv_release_subset_list (&riscv_subsets);
   riscv_parse_subset (&rps, s);
@@ -3137,11 +3030,6 @@  riscv_after_parse_args (void)
       else
 	as_bad ("unknown default architecture `%s'", default_arch);
     }
-  if (default_arch_with_ext == NULL)
-    default_arch_with_ext = xlen == 64 ? "rv64g" : "rv32g";
-
-  /* Initialize the hash table for extensions with default version.  */
-  ext_version_hash = init_ext_version_hash ();
 
   /* Set default specs.  */
   if (default_isa_spec == ISA_SPEC_CLASS_NONE)