diff options
author | Kito Cheng <kito.cheng@sifive.com> | 2020-11-11 16:33:57 +0800 |
---|---|---|
committer | Kito Cheng <kito.cheng@sifive.com> | 2020-11-18 15:02:27 +0800 |
commit | 4b81528241ca682025d92558ff6aeec91dafdca8 (patch) | |
tree | b7ec4b4b7a12b4aaef7f330867fd1e0298391cce /gcc/common | |
parent | b03be74bad08c382da47e048007a78fa3fb4ef49 (diff) | |
download | gcc-4b81528241ca682025d92558ff6aeec91dafdca8.zip gcc-4b81528241ca682025d92558ff6aeec91dafdca8.tar.gz gcc-4b81528241ca682025d92558ff6aeec91dafdca8.tar.bz2 |
RISC-V: Support version controling for ISA standard extensions
- New option -misa-spec support: -misa-spec=[2.2|20190608|20191213] and
corresponding configuration option --with-isa-spec.
- Current default ISA spec set to 2.2, but we intend to bump this to
20191213 or later in next release.
gcc/ChangeLog:
* common/config/riscv/riscv-common.c (riscv_ext_version): New.
(riscv_ext_version_table): Ditto.
(get_default_version): Ditto.
(riscv_subset_t::implied_p): New field.
(riscv_subset_t::riscv_subset_t): Init implied_p.
(riscv_subset_list::add): New.
(riscv_subset_list::handle_implied_ext): Pass riscv_subset_t
instead of separated argument.
(riscv_subset_list::to_string): Handle zifencei and zicsr, and
omit version if version is unknown.
(riscv_subset_list::parsing_subset_version): New argument `ext`,
remove default_major_version and default_minor_version, get
default version info via get_default_version.
(riscv_subset_list::parse_std_ext): Update argument for
parsing_subset_version calls.
Handle 2.2 ISA spec, always enable zicsr and zifencei, they are
included in baseline ISA in that time.
(riscv_subset_list::parse_multiletter_ext): Update argument for
`parsing_subset_version` and `add` calls.
(riscv_subset_list::parse): Adjust argument for
riscv_subset_list::handle_implied_ext call.
* config.gcc (riscv*-*-*): Handle --with-isa-spec=.
* config.in (HAVE_AS_MISA_SPEC): New.
(HAVE_AS_MARCH_ZIFENCEI): Ditto.
* config/riscv/riscv-opts.h (riscv_isa_spec_class): New.
(riscv_isa_spec): Ditto.
* config/riscv/riscv.h (HAVE_AS_MISA_SPEC): New.
(ASM_SPEC): Pass -misa-spec if gas supported.
* config/riscv/riscv.opt (riscv_isa_spec_class) New.
* configure.ac (HAVE_AS_MARCH_ZIFENCEI): New test.
(HAVE_AS_MISA_SPEC): Ditto.
* configure: Regen.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/arch-9.c: New.
* gcc.target/riscv/arch-10.c: Ditto.
* gcc.target/riscv/arch-11.c: Ditto.
* gcc.target/riscv/attribute-6.c: Remove, we don't support G
with version anymore.
* gcc.target/riscv/attribute-8.c: Reorder arch string to fit canonical
ordering.
* gcc.target/riscv/attribute-9.c: We don't emit version for
unknown extensions now.
* gcc.target/riscv/attribute-11.c: Add -misa-spec=2.2 flags.
* gcc.target/riscv/attribute-12.c: Ditto.
* gcc.target/riscv/attribute-13.c: Ditto.
* gcc.target/riscv/attribute-14.c: Ditto.
* gcc.target/riscv/attribute-15.c: New.
* gcc.target/riscv/attribute-16.c: Ditto.
* gcc.target/riscv/attribute-17.c: Ditto.
Diffstat (limited to 'gcc/common')
-rw-r--r-- | gcc/common/config/riscv/riscv-common.c | 287 |
1 files changed, 215 insertions, 72 deletions
diff --git a/gcc/common/config/riscv/riscv-common.c b/gcc/common/config/riscv/riscv-common.c index ca88ca1..5e3ddcf 100644 --- a/gcc/common/config/riscv/riscv-common.c +++ b/gcc/common/config/riscv/riscv-common.c @@ -44,6 +44,7 @@ struct riscv_subset_t struct riscv_subset_t *next; bool explicit_version_p; + bool implied_p; }; /* Type for implied ISA info. */ @@ -62,6 +63,58 @@ static const riscv_implied_info_t riscv_implied_info[] = {NULL, NULL} }; +/* This structure holds version information for specific ISA version. */ + +struct riscv_ext_version +{ + const char *name; + enum riscv_isa_spec_class isa_spec_class; + int major_version; + int minor_version; +}; + +/* All standard extensions defined in all supported ISA spec. */ +static const struct riscv_ext_version riscv_ext_version_table[] = +{ + /* name, ISA spec, major version, minor_version. */ + {"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}, + + {"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}, + + /* Terminate the list. */ + {NULL, ISA_SPEC_CLASS_NONE, 0, 0} +}; + static const riscv_cpu_info riscv_cpu_tables[] = { #define RISCV_CORE(CORE_NAME, ARCH, TUNE) \ @@ -91,20 +144,22 @@ private: riscv_subset_list (const char *, location_t); - const char *parsing_subset_version (const char *, unsigned *, unsigned *, - unsigned, unsigned, bool, bool *); + const char *parsing_subset_version (const char *, const char *, unsigned *, + unsigned *, bool, bool *); const char *parse_std_ext (const char *); const char *parse_multiletter_ext (const char *, const char *, const char *); - void handle_implied_ext (const char *, int, int, bool); + void handle_implied_ext (riscv_subset_t *); public: ~riscv_subset_list (); - void add (const char *, int, int, bool); + void add (const char *, int, int, bool, bool); + + void add (const char *, bool); riscv_subset_t *lookup (const char *, int major_version = RISCV_DONT_CARE_VERSION, @@ -124,7 +179,7 @@ static riscv_subset_list *current_subset_list = NULL; riscv_subset_t::riscv_subset_t () : name (), major_version (0), minor_version (0), next (NULL), - explicit_version_p (false) + explicit_version_p (false), implied_p (false) { } @@ -274,8 +329,31 @@ subset_cmp (const std::string &a, const std::string &b) void riscv_subset_list::add (const char *subset, int major_version, - int minor_version, bool explicit_version_p) + int minor_version, bool explicit_version_p, + bool implied_p) { + riscv_subset_t *ext = lookup (subset); + + if (ext) + { + if (ext->implied_p) + { + /* We won't add impiled `ext` if it already in list. */ + gcc_assert (!implied_p); + ext->implied_p = implied_p; + ext->major_version = major_version; + ext->minor_version = minor_version; + } + else + error_at ( + m_loc, + "%<-march=%s%>: Extension `%s' appear more than one time.", + m_arch, + subset); + + return; + } + riscv_subset_t *s = new riscv_subset_t (); riscv_subset_t *itr; @@ -286,6 +364,7 @@ riscv_subset_list::add (const char *subset, int major_version, s->major_version = major_version; s->minor_version = minor_version; s->explicit_version_p = explicit_version_p; + s->implied_p = implied_p; s->next = NULL; if (m_tail == NULL) @@ -330,6 +409,43 @@ riscv_subset_list::add (const char *subset, int major_version, m_tail = s; } +static void +get_default_version (const char *ext, + unsigned int *major_version, + unsigned int *minor_version) +{ + const riscv_ext_version *ext_ver; + for (ext_ver = &riscv_ext_version_table[0]; + ext_ver->name != NULL; + ++ext_ver) + if (strcmp (ext, ext_ver->name) == 0) + { + if ((ext_ver->isa_spec_class == riscv_isa_spec) || + (ext_ver->isa_spec_class == ISA_SPEC_CLASS_NONE)) + { + *major_version = ext_ver->major_version; + *minor_version = ext_ver->minor_version; + return; + } + } + + /* Not found version info. */ + *major_version = 0; + *minor_version = 0; +} + +/* Add new subset to list, but using default version from ISA spec version. */ + +void +riscv_subset_list::add (const char *subset, bool implied_p) +{ + unsigned int major_version = 0, minor_version = 0; + + get_default_version (subset, &major_version, &minor_version); + + add (subset, major_version, minor_version, false, implied_p); +} + /* Convert subset info to string with explicit version info, VERSION_P to determine append version info or not. */ @@ -340,10 +456,37 @@ riscv_subset_list::to_string (bool version_p) const oss << "rv" << m_xlen; bool first = true; - riscv_subset_t *subset = m_head; + riscv_subset_t *subset; + + bool skip_zifencei = false; + bool skip_zicsr = false; + + /* For RISC-V ISA version 2.2 or earlier version, zicsr and zifencei is + included in the base ISA. */ + if (riscv_isa_spec == ISA_SPEC_CLASS_2P2) + { + skip_zifencei = true; + skip_zicsr = true; + } - while (subset != NULL) +#ifndef HAVE_AS_MISA_SPEC + /* Skip since older binutils doesn't recognize zicsr. */ + skip_zicsr = true; +#endif +#ifndef HAVE_AS_MARCH_ZIFENCE + /* Skip since older binutils doesn't recognize zifencei, we made + a mistake in that binutils 2.35 supports zicsr but not zifencei. */ + skip_zifencei = true; +#endif + + for (subset = m_head; subset != NULL; subset = subset->next) { + if (subset->implied_p && skip_zifencei && subset->name == "zifencei") + continue; + + if (subset->implied_p && skip_zicsr && subset->name == "zicsr") + continue; + /* For !version_p, we only separate extension with underline for multi-letter extension. */ if (!first && @@ -355,12 +498,12 @@ riscv_subset_list::to_string (bool version_p) const oss << subset->name; - if (version_p || subset->explicit_version_p) + /* Let binutils decide the extension version if we don't know. */ + if ((version_p || subset->explicit_version_p) && + (subset->major_version != 0 || subset->minor_version != 0)) oss << subset->major_version << 'p' << subset->minor_version; - - subset = subset->next; } return oss.str (); @@ -408,23 +551,21 @@ riscv_supported_std_ext (void) Points to the end of version Arguments: + `ext`: This extension. `p`: Current 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. `explicit_version_p`: True if this subset is not using default version. */ const char * -riscv_subset_list::parsing_subset_version (const char *p, +riscv_subset_list::parsing_subset_version (const char *ext, + const char *p, unsigned *major_version, unsigned *minor_version, - unsigned default_major_version, - unsigned default_minor_version, bool std_ext_p, bool *explicit_version_p) { @@ -475,11 +616,7 @@ riscv_subset_list::parsing_subset_version (const char *p, minor = version; if (major == 0 && minor == 0) - { - /* We didn't find any version string, use default version. */ - *major_version = default_major_version; - *minor_version = default_minor_version; - } + get_default_version (ext, major_version, minor_version); else { *explicit_version_p = true; @@ -513,23 +650,17 @@ riscv_subset_list::parse_std_ext (const char *p) { case 'i': p++; - p = parsing_subset_version (p, &major_version, &minor_version, - /* default_major_version= */ 2, - /* default_minor_version= */ 0, - /* std_ext_p= */ true, - &explicit_version_p); - add ("i", major_version, minor_version, explicit_version_p); + p = parsing_subset_version ("i", p, &major_version, &minor_version, + /* std_ext_p= */ true, &explicit_version_p); + add ("i", major_version, minor_version, explicit_version_p, false); break; case 'e': p++; - p = parsing_subset_version (p, &major_version, &minor_version, - /* default_major_version= */ 1, - /* default_minor_version= */ 9, - /* std_ext_p= */ true, - &explicit_version_p); + p = parsing_subset_version ("e", p, &major_version, &minor_version, + /* std_ext_p= */ true, &explicit_version_p); - add ("e", major_version, minor_version, explicit_version_p); + add ("e", major_version, minor_version, explicit_version_p, false); if (m_xlen > 32) { @@ -541,18 +672,26 @@ riscv_subset_list::parse_std_ext (const char *p) case 'g': p++; - p = parsing_subset_version (p, &major_version, &minor_version, - /* default_major_version= */ 2, - /* default_minor_version= */ 0, - /* std_ext_p= */ true, - &explicit_version_p); - add ("i", major_version, minor_version, explicit_version_p); - - for (; *std_exts != 'q'; std_exts++) + p = parsing_subset_version ("g", p, &major_version, &minor_version, + /* std_ext_p= */ true, &explicit_version_p); + if (major_version != 0 || minor_version != 0) { - const char subset[] = {*std_exts, '\0'}; - add (subset, major_version, minor_version, explicit_version_p); + warning_at (m_loc, 0, "version of `g` will be omitted, please " + "specify version for individual extension."); } + + /* We have special rule for G, we disallow rv32gm2p but allow rv32g_zicsr + here, basically we treating G expand to imafd and implied zicsr and + zifencei. */ + + add ("i", false); + add ("m", false); + add ("a", false); + add ("f", false); + add ("d", false); + add ("zicsr", true); + add ("zifencei", true); + break; default: @@ -595,44 +734,47 @@ riscv_subset_list::parse_std_ext (const char *p) std_exts++; p++; - p = parsing_subset_version (p, &major_version, &minor_version, - /* default_major_version= */ 2, - /* default_minor_version= */ 0, - /* std_ext_p= */ true, - &explicit_version_p); - subset[0] = std_ext; - add (subset, major_version, minor_version, explicit_version_p); + p = parsing_subset_version (subset, p, &major_version, &minor_version, + /* std_ext_p= */ true, &explicit_version_p); + + add (subset, major_version, minor_version, explicit_version_p, false); } return p; } -/* Check any implied extensions for EXT with version - MAJOR_VERSION.MINOR_VERSION, EXPLICIT_VERSION_P indicate the version is - explicitly given by user or not. */ +/* Check any implied extensions for EXT. */ void -riscv_subset_list::handle_implied_ext (const char *ext, - int major_version, - int minor_version, - bool explicit_version_p) +riscv_subset_list::handle_implied_ext (riscv_subset_t *ext) { const riscv_implied_info_t *implied_info; for (implied_info = &riscv_implied_info[0]; implied_info->ext; ++implied_info) { - if (strcmp (ext, implied_info->ext) != 0) + if (strcmp (ext->name.c_str (), implied_info->ext) != 0) continue; /* Skip if implied extension already present. */ if (lookup (implied_info->implied_ext)) continue; - /* TODO: Implied extension might use different version. */ - add (implied_info->implied_ext, major_version, minor_version, - explicit_version_p); + /* Version of implied extension will get from current ISA spec + version. */ + add (implied_info->implied_ext, true); + } + + /* For RISC-V ISA version 2.2 or earlier version, zicsr and zifence is + included in the base ISA. */ + if (riscv_isa_spec == ISA_SPEC_CLASS_2P2) + { + if (lookup ("zicsr") == NULL) + add ("zicsr", true); + + if (lookup ("zifencei") == NULL) + add ("zifencei", true); } } @@ -670,16 +812,21 @@ riscv_subset_list::parse_multiletter_ext (const char *p, char *q = subset; const char *end_of_version; bool explicit_version_p = false; + char *ext; + char backup; while (*++q != '\0' && *q != '_' && !ISDIGIT (*q)) ; + backup = *q; + *q = '\0'; + ext = xstrdup (subset); + *q = backup; + end_of_version - = parsing_subset_version (q, &major_version, &minor_version, - /* default_major_version= */ 2, - /* default_minor_version= */ 0, - /* std_ext_p= */ FALSE, - &explicit_version_p); + = parsing_subset_version (ext, q, &major_version, &minor_version, + /* std_ext_p= */ false, &explicit_version_p); + free (ext); *q = '\0'; @@ -691,7 +838,7 @@ riscv_subset_list::parse_multiletter_ext (const char *p, return NULL; } - add (subset, major_version, minor_version, explicit_version_p); + add (subset, major_version, minor_version, explicit_version_p, false); free (subset); p += end_of_version - subset; @@ -770,11 +917,7 @@ riscv_subset_list::parse (const char *arch, location_t loc) for (itr = subset_list->m_head; itr != NULL; itr = itr->next) { - subset_list->handle_implied_ext ( - itr->name.c_str (), - itr->major_version, - itr->minor_version, - itr->explicit_version_p); + subset_list->handle_implied_ext (itr); } return subset_list; |