From ca813880dcaae71f664d8f386b1a584cfefbbd4b Mon Sep 17 00:00:00 2001 From: liuhongt Date: Tue, 10 Nov 2020 13:01:32 +0800 Subject: Support Intel AVX VNNI 2020-10-13 Hongtao Liu Hongyu Wang gcc/ * common/config/i386/cpuinfo.h (get_available_features): Detect AVXVNNI. * common/config/i386/i386-common.c (OPTION_MASK_ISA2_AVXVNNI_SET, OPTION_MASK_ISA2_AVXVNNI_UNSET): New. (OPTION_MASK_ISA2_AVX2_UNSET): Add AVXVNNI. (ix86_hanlde_option): Handle -mavxvnni, unset avxvnni when avx2 is disabled. * common/config/i386/i386-cpuinfo.h (enum processor_features): Add FEATURE_AVXVNNI. * common/config/i386/i386-isas.h: Add ISA_NAMES_TABLE_ENTRY for avxvnni. * config.gcc: Add avxvnniintrin.h. * config/i386/avx512vnnivlintrin.h: Reimplement 128/256 bit non-mask intrinsics with macros to support unified interface. * config/i386/avxvnniintrin.h: New header file. * config/i386/cpuid.h (bit_AVXVNNI): New. * config/i386/i386-builtins.c (def_builtin): Handle AVXVNNI mask for unified builtin. * config/i386/i386-builtin.def (BDESC): Adjust AVX512VNNI builtins for AVXVNNI. * config/i386/i386-c.c (ix86_target_macros_internal): Define __AVXVNNI__. * config/i386/i386-expand.c (ix86_expand_builtin): Handle bisa for AVXVNNI to support unified intrinsic name, since there is no dependency between AVX512VNNI and AVXVNNI. * config/i386/i386-options.c (isa2_opts): Add -mavxvnni. (ix86_valid_target_attribute_inner_p): Handle avxnnni. (ix86_option_override_internal): Ditto. * config/i386/i386.h (TARGET_AVXVNNI, TARGET_AVXVNNI_P, TARGET_AVXVNNI_P, PTA_AVXVNNI): New. (PTA_SAPPHIRERAPIDS): Add AVX_VNNI. (PTA_ALDERLAKE): Likewise. * config/i386/i386.md ("isa"): Add avxvnni, avx512vnnivl. ("enabled"): Adjust for avxvnni and avx512vnnivl. * config/i386/i386.opt: Add option -mavxvnni. * config/i386/immintrin.h: Include avxvnniintrin.h. * config/i386/sse.md (vpdpbusd_): Adjust for AVXVNNI. (vpdpbusds_): Likewise. (vpdpwssd_): Likewise. (vpdpwssds_): Likewise. (vpdpbusd_v16si): New. (vpdpbusds_v16si): Likewise. (vpdpwssd_v16si): Likewise. (vpdpwssds_v16si): Likewise. * doc/invoke.texi: Document -mavxvnni. * doc/extend.texi: Document avxvnni. * doc/sourcebuild.texi: Document target avxvnni. gcc/testsuite/ * gcc.target/i386/avx512vl-vnni-1.c: Rename.. * gcc.target/i386/avx512vl-vnni-1a.c: To This. * gcc.target/i386/avx512vl-vnni-1b.c: New test. * gcc.target/i386/avx512vl-vnni-2.c: Ditto. * gcc.target/i386/avx512vl-vnni-3.c: Ditto. * gcc.target/i386/avx-vnni-1.c: Ditto. * gcc.target/i386/avx-vnni-2.c: Ditto. * gcc.target/i386/avx-vnni-3.c: Ditto. * gcc.target/i386/avx-vnni-4.c: Ditto. * gcc.target/i386/avx-vnni-5.c: Ditto. * gcc.target/i386/avx-vnni-6.c: Ditto. * gcc.target/i386/avx-vpdpbusd-2.c: Ditto. * gcc.target/i386/avx-vpdpbusds-2.c: Ditto. * gcc.target/i386/avx-vpdpwssd-2.c: Ditto. * gcc.target/i386/avx-vpdpwssds-2.c: Ditto. * gcc.target/i386/vnni_inline_error.c: Ditto. * gcc.target/i386/avx512vnnivl-builtin.c: Ditto. * gcc.target/i386/avxvnni-builtin.c: Ditto. * gcc.target/i386/funcspec-56.inc: Add new target attribute. * gcc.target/i386/sse-12.c: Add -mavxvnni. * gcc.target/i386/sse-13.c: Ditto. * gcc.target/i386/sse-14.c: Ditto. * gcc.target/i386/sse-22.c: Ditto. * gcc.target/i386/sse-23.c: Ditto. * g++.dg/other/i386-2.C: Ditto. * g++.dg/other/i386-3.C: Ditto. * lib/target-supports.exp (check_effective_target_avxvnni): New proc. --- gcc/common/config/i386/cpuinfo.h | 2 ++ gcc/common/config/i386/i386-common.c | 20 +++++++++++++++++++- gcc/common/config/i386/i386-cpuinfo.h | 1 + gcc/common/config/i386/i386-isas.h | 1 + 4 files changed, 23 insertions(+), 1 deletion(-) (limited to 'gcc/common') diff --git a/gcc/common/config/i386/cpuinfo.h b/gcc/common/config/i386/cpuinfo.h index 7a93e17..41728a2 100644 --- a/gcc/common/config/i386/cpuinfo.h +++ b/gcc/common/config/i386/cpuinfo.h @@ -713,6 +713,8 @@ get_available_features (struct __processor_model *cpu_model, set_feature (FEATURE_AVX512BF16); if (eax & bit_HRESET) set_feature (FEATURE_HRESET); + if (eax & bit_AVXVNNI) + set_feature (FEATURE_AVXVNNI); } } diff --git a/gcc/common/config/i386/i386-common.c b/gcc/common/config/i386/i386-common.c index e29320d..8f809c1 100644 --- a/gcc/common/config/i386/i386-common.c +++ b/gcc/common/config/i386/i386-common.c @@ -84,6 +84,7 @@ along with GCC; see the file COPYING3. If not see (OPTION_MASK_ISA_AVX512VBMI2 | OPTION_MASK_ISA_AVX512F_SET) #define OPTION_MASK_ISA_AVX512VNNI_SET \ (OPTION_MASK_ISA_AVX512VNNI | OPTION_MASK_ISA_AVX512F_SET) +#define OPTION_MASK_ISA2_AVXVNNI_SET OPTION_MASK_ISA2_AVXVNNI #define OPTION_MASK_ISA_AVX512VPOPCNTDQ_SET \ (OPTION_MASK_ISA_AVX512VPOPCNTDQ | OPTION_MASK_ISA_AVX512F_SET) #define OPTION_MASK_ISA_AVX512BITALG_SET \ @@ -206,6 +207,8 @@ along with GCC; see the file COPYING3. If not see #define OPTION_MASK_ISA_XSAVEOPT_UNSET OPTION_MASK_ISA_XSAVEOPT #define OPTION_MASK_ISA_AVX2_UNSET \ (OPTION_MASK_ISA_AVX2 | OPTION_MASK_ISA_AVX512F_UNSET) +#define OPTION_MASK_ISA2_AVX2_UNSET \ + (OPTION_MASK_ISA2_AVXVNNI_UNSET | OPTION_MASK_ISA2_AVX512F_UNSET) #define OPTION_MASK_ISA_AVX512F_UNSET \ (OPTION_MASK_ISA_AVX512F | OPTION_MASK_ISA_AVX512CD_UNSET \ | OPTION_MASK_ISA_AVX512PF_UNSET | OPTION_MASK_ISA_AVX512ER_UNSET \ @@ -228,6 +231,7 @@ along with GCC; see the file COPYING3. If not see #define OPTION_MASK_ISA2_AVX5124VNNIW_UNSET OPTION_MASK_ISA2_AVX5124VNNIW #define OPTION_MASK_ISA_AVX512VBMI2_UNSET OPTION_MASK_ISA_AVX512VBMI2 #define OPTION_MASK_ISA_AVX512VNNI_UNSET OPTION_MASK_ISA_AVX512VNNI +#define OPTION_MASK_ISA2_AVXVNNI_UNSET OPTION_MASK_ISA2_AVXVNNI #define OPTION_MASK_ISA_AVX512VPOPCNTDQ_UNSET OPTION_MASK_ISA_AVX512VPOPCNTDQ #define OPTION_MASK_ISA_AVX512BITALG_UNSET OPTION_MASK_ISA_AVX512BITALG #define OPTION_MASK_ISA2_AVX512BF16_UNSET OPTION_MASK_ISA2_AVX512BF16 @@ -310,7 +314,6 @@ along with GCC; see the file COPYING3. If not see | OPTION_MASK_ISA2_AVX512VP2INTERSECT_UNSET) #define OPTION_MASK_ISA2_GENERAL_REGS_ONLY_UNSET \ (OPTION_MASK_ISA2_AVX512F_UNSET) -#define OPTION_MASK_ISA2_AVX2_UNSET OPTION_MASK_ISA2_AVX512F_UNSET #define OPTION_MASK_ISA2_AVX_UNSET OPTION_MASK_ISA2_AVX2_UNSET #define OPTION_MASK_ISA2_SSE4_2_UNSET OPTION_MASK_ISA2_AVX_UNSET #define OPTION_MASK_ISA2_SSE4_1_UNSET OPTION_MASK_ISA2_SSE4_2_UNSET @@ -882,6 +885,21 @@ ix86_handle_option (struct gcc_options *opts, } return true; + case OPT_mavxvnni: + if (value) + { + opts->x_ix86_isa_flags2 |= OPTION_MASK_ISA2_AVXVNNI_SET; + opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA2_AVXVNNI_SET; + opts->x_ix86_isa_flags |= OPTION_MASK_ISA_AVX2_SET; + opts->x_ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX2_SET; + } + else + { + opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA2_AVXVNNI_UNSET; + opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA2_AVXVNNI_UNSET; + } + return true; + case OPT_msgx: if (value) { diff --git a/gcc/common/config/i386/i386-cpuinfo.h b/gcc/common/config/i386/i386-cpuinfo.h index 2138220..af02be5 100644 --- a/gcc/common/config/i386/i386-cpuinfo.h +++ b/gcc/common/config/i386/i386-cpuinfo.h @@ -224,6 +224,7 @@ enum processor_features FEATURE_KL, FEATURE_AESKLE, FEATURE_WIDEKL, + FEATURE_AVXVNNI, CPU_FEATURE_MAX }; diff --git a/gcc/common/config/i386/i386-isas.h b/gcc/common/config/i386/i386-isas.h index 921db06..c4fd036 100644 --- a/gcc/common/config/i386/i386-isas.h +++ b/gcc/common/config/i386/i386-isas.h @@ -168,4 +168,5 @@ ISA_NAMES_TABLE_START ISA_NAMES_TABLE_ENTRY("kl", FEATURE_KL, P_NONE, "-mkl") ISA_NAMES_TABLE_ENTRY("aeskle", FEATURE_AESKLE, P_NONE, NULL) ISA_NAMES_TABLE_ENTRY("widekl", FEATURE_WIDEKL, P_NONE, "-mwidekl") + ISA_NAMES_TABLE_ENTRY("avxvnni", FEATURE_AVXVNNI, P_NONE, "-mavxvnni") ISA_NAMES_TABLE_END -- cgit v1.1 From 6a5bb4705fb75fd3afdde938193c59938cc7bfde Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Mon, 3 Aug 2020 14:01:39 +0800 Subject: RISC-V: Handle implied extension in canonical ordering. - ISA spec has specify the order between multi-letter extensions, implied extension also need to follow store in canonical ordering, so most easy way is we keep that in-order during insertion. gcc/ChangeLog: * common/config/riscv/riscv-common.c (single_letter_subset_rank): New. (multi_letter_subset_rank): Ditto. (subset_cmp): Ditto. (riscv_subset_list::add): Insert subext in canonical ordering. (riscv_subset_list::parse_std_ext): Move handle_implied_ext to ... (riscv_subset_list::parse): ... here. --- gcc/common/config/riscv/riscv-common.c | 177 ++++++++++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 5 deletions(-) (limited to 'gcc/common') diff --git a/gcc/common/config/riscv/riscv-common.c b/gcc/common/config/riscv/riscv-common.c index 9a576eb..f5f7be3 100644 --- a/gcc/common/config/riscv/riscv-common.c +++ b/gcc/common/config/riscv/riscv-common.c @@ -145,6 +145,129 @@ riscv_subset_list::~riscv_subset_list () } } +/* Get the rank for single-letter subsets, lower value meaning higher + priority. */ + +static int +single_letter_subset_rank (char ext) +{ + int rank; + + switch (ext) + { + case 'i': + return 0; + case 'e': + return 1; + default: + break; + } + + const char *all_ext = riscv_supported_std_ext (); + const char *ext_pos = strchr (all_ext, ext); + if (ext_pos == NULL) + /* If got an unknown extension letter, then give it an alphabetical + order, but after all known standard extension. */ + rank = strlen (all_ext) + ext - 'a'; + else + rank = (int)(ext_pos - all_ext) + 2 /* e and i has higher rank. */; + + return rank; +} + +/* Get the rank for multi-letter subsets, lower value meaning higher + priority. */ + +static int +multi_letter_subset_rank (const std::string &subset) +{ + gcc_assert (subset.length () >= 2); + int high_order = -1; + int low_order = 0; + /* The order between multi-char extensions: s -> h -> z -> x. */ + char multiletter_class = subset[0]; + switch (multiletter_class) + { + case 's': + high_order = 0; + break; + case 'h': + high_order = 1; + break; + case 'z': + gcc_assert (subset.length () > 2); + high_order = 2; + break; + case 'x': + high_order = 3; + break; + default: + gcc_unreachable (); + return -1; + } + + if (multiletter_class == 'z') + /* Order for z extension on spec: If multiple "Z" extensions are named, they + should be ordered first by category, then alphabetically within a + category - for example, "Zicsr_Zifencei_Zam". */ + low_order = single_letter_subset_rank (subset[1]); + else + low_order = 0; + + return (high_order << 8) + low_order; +} + +/* subset compare + + Returns an integral value indicating the relationship between the subsets: + Return value indicates + -1 B has higher order than A. + 0 A and B are same subset. + 1 A has higher order than B. + +*/ + +static int +subset_cmp (const std::string &a, const std::string &b) +{ + if (a == b) + return 0; + + size_t a_len = a.length (); + size_t b_len = b.length (); + + /* Single-letter extension always get higher order than + multi-letter extension. */ + if (a_len == 1 && b_len != 1) + return 1; + + if (a_len != 1 && b_len == 1) + return -1; + + if (a_len == 1 && b_len == 1) + { + int rank_a = single_letter_subset_rank (a[0]); + int rank_b = single_letter_subset_rank (b[0]); + + if (rank_a < rank_b) + return 1; + else + return -1; + } + else + { + int rank_a = multi_letter_subset_rank(a); + int rank_b = multi_letter_subset_rank(b); + + /* Using alphabetical/lexicographical order if they have same rank. */ + if (rank_a == rank_b) + /* The return value of strcmp has opposite meaning. */ + return -strcmp (a.c_str (), b.c_str ()); + else + return (rank_a < rank_b) ? 1 : -1; + } +} + /* Add new subset to list. */ void @@ -152,6 +275,7 @@ riscv_subset_list::add (const char *subset, int major_version, int minor_version, bool explicit_version_p) { riscv_subset_t *s = new riscv_subset_t (); + riscv_subset_t *itr; if (m_head == NULL) m_head = s; @@ -162,9 +286,45 @@ riscv_subset_list::add (const char *subset, int major_version, s->explicit_version_p = explicit_version_p; s->next = NULL; - if (m_tail != NULL) - m_tail->next = s; + if (m_tail == NULL) + { + m_tail = s; + return; + } + + /* e, i or g should be first subext, never come here. */ + gcc_assert (subset[0] != 'e' + && subset[0] != 'i' + && subset[0] != 'g'); + + if (m_tail == m_head) + { + gcc_assert (m_head->next == NULL); + m_head->next = s; + m_tail = s; + return; + } + + gcc_assert (m_head->next != NULL); + + /* Subset list must in canonical order, but implied subset won't + add in canonical order. */ + for (itr = m_head; itr->next != NULL; itr = itr->next) + { + riscv_subset_t *next = itr->next; + int cmp = subset_cmp (s->name, next->name); + gcc_assert (cmp != 0); + + if (cmp > 0) + { + s->next = next; + itr->next = s; + return; + } + } + /* Insert at tail of the list. */ + itr->next = s; m_tail = s; } @@ -441,9 +601,6 @@ riscv_subset_list::parse_std_ext (const char *p) subset[0] = std_ext; - handle_implied_ext (subset, major_version, - minor_version, explicit_version_p); - add (subset, major_version, minor_version, explicit_version_p); } return p; @@ -553,6 +710,7 @@ riscv_subset_list * riscv_subset_list::parse (const char *arch, location_t loc) { riscv_subset_list *subset_list = new riscv_subset_list (arch, loc); + riscv_subset_t *itr; const char *p = arch; if (strncmp (p, "rv32", 4) == 0) { @@ -608,6 +766,15 @@ riscv_subset_list::parse (const char *arch, location_t loc) goto fail; } + 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); + } + return subset_list; fail: -- cgit v1.1 From b03be74bad08c382da47e048007a78fa3fb4ef49 Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Wed, 11 Nov 2020 14:04:34 +0800 Subject: RISC-V: Support zicsr and zifencei extension for -march. - CSR related instructions and fence instructions has to be splitted from baseline ISA, zicsr and zifencei are corresponding sub-extension. gcc/ChangeLog: * common/config/riscv/riscv-common.c (riscv_implied_info): d and f implied zicsr. (riscv_ext_flag_table): Handle zicsr and zifencei. * config/riscv/riscv-opts.h (MASK_ZICSR): New. (MASK_ZIFENCEI): Ditto. (TARGET_ZICSR): Ditto. (TARGET_ZIFENCEI): Ditto. * config/riscv/riscv.md (clear_cache): Check TARGET_ZIFENCEI. (fence_i): Ditto. * config/riscv/riscv.opt (riscv_zi_subext): New. gcc/testsuite/ChangeLog: * gcc.target/riscv/arch-8.c: New. * gcc.target/riscv/attribute-14.c: Ditto. --- gcc/common/config/riscv/riscv-common.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/common') diff --git a/gcc/common/config/riscv/riscv-common.c b/gcc/common/config/riscv/riscv-common.c index f5f7be3..ca88ca1 100644 --- a/gcc/common/config/riscv/riscv-common.c +++ b/gcc/common/config/riscv/riscv-common.c @@ -57,6 +57,8 @@ struct riscv_implied_info_t static const riscv_implied_info_t riscv_implied_info[] = { {"d", "f"}, + {"f", "zicsr"}, + {"d", "zicsr"}, {NULL, NULL} }; @@ -812,6 +814,10 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {"f", &gcc_options::x_target_flags, MASK_HARD_FLOAT}, {"d", &gcc_options::x_target_flags, MASK_DOUBLE_FLOAT}, {"c", &gcc_options::x_target_flags, MASK_RVC}, + + {"zicsr", &gcc_options::x_riscv_zi_subext, MASK_ZICSR}, + {"zifencei", &gcc_options::x_riscv_zi_subext, MASK_ZIFENCEI}, + {NULL, NULL, 0} }; -- cgit v1.1 From 4b81528241ca682025d92558ff6aeec91dafdca8 Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Wed, 11 Nov 2020 16:33:57 +0800 Subject: 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. --- gcc/common/config/riscv/riscv-common.c | 287 ++++++++++++++++++++++++--------- 1 file changed, 215 insertions(+), 72 deletions(-) (limited to 'gcc/common') 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; -- cgit v1.1