diff options
author | Nelson Chu <nelson.chu@sifive.com> | 2021-09-16 14:36:54 +0800 |
---|---|---|
committer | Nelson Chu <nelson.chu@sifive.com> | 2021-09-17 16:33:54 +0800 |
commit | c9f279910113d6a10cb64d81aba2c1af9f3c228c (patch) | |
tree | f6c97bc6b142ac2025b70fba59dd491251509310 /bfd/elfxx-riscv.c | |
parent | 648d5dc4e6032c66f76638604cd577c529f84bc5 (diff) | |
download | gdb-c9f279910113d6a10cb64d81aba2c1af9f3c228c.zip gdb-c9f279910113d6a10cb64d81aba2c1af9f3c228c.tar.gz gdb-c9f279910113d6a10cb64d81aba2c1af9f3c228c.tar.bz2 |
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.c | 350 |
1 files changed, 223 insertions, 127 deletions
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c index ddcf872..b467bce 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); |