summaryrefslogtreecommitdiff
path: root/bfd/elfxx-riscv.c
diff options
context:
space:
mode:
authorNelson Chu <nelson.chu@sifive.com>2021-09-16 14:36:54 +0800
committerNelson Chu <nelson.chu@sifive.com>2021-09-17 16:33:54 +0800
commitc9f279910113d6a10cb64d81aba2c1af9f3c228c (patch)
treef6c97bc6b142ac2025b70fba59dd491251509310 /bfd/elfxx-riscv.c
parent648d5dc4e6032c66f76638604cd577c529f84bc5 (diff)
RISC-V: Merged extension string tables and their version tables into one.
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.
Diffstat (limited to 'bfd/elfxx-riscv.c')
-rw-r--r--bfd/elfxx-riscv.c350
1 files changed, 223 insertions, 127 deletions
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index ddcf872d63..b467bceb91 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);