riscv_subset_list only accept a full arch string before, but we need to parse single extension when supporting target attribute, also we may set a riscv_subset_list directly rather than re-parsing the ISA string again.
gcc/ChangeLog: * config/riscv/riscv-subset.h (riscv_subset_list::parse_single_std_ext): New. (riscv_subset_list::parse_single_multiletter_ext): Ditto. (riscv_subset_list::clone): Ditto. (riscv_subset_list::parse_single_ext): Ditto. (riscv_subset_list::set_loc): Ditto. (riscv_set_arch_by_subset_list): Ditto. * common/config/riscv/riscv-common.cc (riscv_subset_list::parse_single_std_ext): New. (riscv_subset_list::parse_single_multiletter_ext): Ditto. (riscv_subset_list::clone): Ditto. (riscv_subset_list::parse_single_ext): Ditto. (riscv_subset_list::set_loc): Ditto. (riscv_set_arch_by_subset_list): Ditto. --- gcc/common/config/riscv/riscv-common.cc | 210 ++++++++++++++++++++++++ gcc/config/riscv/riscv-subset.h | 11 ++ 2 files changed, 221 insertions(+) diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index 9a0a68fe5db..76a1378874d 100644 --- a/gcc/common/config/riscv/riscv-common.cc +++ b/gcc/common/config/riscv/riscv-common.cc @@ -1036,6 +1036,41 @@ riscv_subset_list::parse_std_ext (const char *p) return p; } +/* Parsing function for one standard extensions. + + Return Value: + Points to the end of extensions. + + Arguments: + `p`: Current parsing position. */ + +const char * +riscv_subset_list::parse_single_std_ext (const char *p) +{ + if (*p == 'x' || *p == 's' || *p == 'z') + { + error_at (m_loc, + "%<-march=%s%>: Not single-letter extension. " + "%<%c%>", + m_arch, *p); + return nullptr; + } + + unsigned major_version = 0; + unsigned minor_version = 0; + bool explicit_version_p = false; + char subset[2] = {0, 0}; + + subset[0] = *p; + + 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. */ void @@ -1138,6 +1173,109 @@ riscv_subset_list::handle_combine_ext () } } +/* Parsing function for multi-letter extensions. + + Return Value: + Points to the end of extensions. + + Arguments: + `p`: Current parsing position. + `ext_type`: What kind of extensions, 's', 'z' or 'x'. + `ext_type_str`: Full name for kind of extension. */ + + +const char * +riscv_subset_list::parse_single_multiletter_ext (const char *p, + const char *ext_type, + const char *ext_type_str) +{ + unsigned major_version = 0; + unsigned minor_version = 0; + size_t ext_type_len = strlen (ext_type); + + { + if (strncmp (p, ext_type, ext_type_len) != 0) + return NULL; + + char *subset = xstrdup (p); + char *q = subset; + const char *end_of_version; + bool explicit_version_p = false; + char *ext; + char backup; + size_t len; + size_t end_of_version_pos, i; + bool found_any_number = false; + bool found_minor_version = false; + + backup = *q; + *q = '\0'; + len = q - subset; + *q = backup; + + end_of_version_pos = len; + /* Find the begin of version string. */ + for (i = len -1; i > 0; --i) + { + if (ISDIGIT (subset[i])) + { + found_any_number = true; + continue; + } + /* Might be version seperator, but need to check one more char, + we only allow <major>p<minor>, so we could stop parsing if found + any more `p`. */ + if (subset[i] == 'p' && + !found_minor_version && + found_any_number && ISDIGIT (subset[i-1])) + { + found_minor_version = true; + continue; + } + + end_of_version_pos = i + 1; + break; + } + + backup = subset[end_of_version_pos]; + subset[end_of_version_pos] = '\0'; + ext = xstrdup (subset); + subset[end_of_version_pos] = backup; + + end_of_version + = parsing_subset_version (ext, subset + end_of_version_pos, &major_version, &minor_version, + /* std_ext_p= */ false, &explicit_version_p); + free (ext); + + if (end_of_version == NULL) + return NULL; + + subset[end_of_version_pos] = '\0'; + + if (strlen (subset) == 1) + { + error_at (m_loc, "%<-march=%s%>: name of %s must be more than 1 letter", + m_arch, ext_type_str); + free (subset); + return NULL; + } + + add (subset, major_version, minor_version, explicit_version_p, false); + p += end_of_version - subset; + free (subset); + + if (*p != '\0' && *p != '_') + { + error_at (m_loc, "%<-march=%s%>: %s must separate with %<_%>", + m_arch, ext_type_str); + return NULL; + } + } + + return p; + +} + /* Parsing function for multi-letter extensions. Return Value: @@ -1250,6 +1388,30 @@ riscv_subset_list::parse_multiletter_ext (const char *p, return p; } +/* Parsing function for a single-letter or multi-letter extensions. + + Return Value: + Points to the end of extensions. + + Arguments: + `p`: Current parsing position. */ + +const char * +riscv_subset_list::parse_single_ext (const char *p) +{ + switch (p[0]) + { + case 'x': + return parse_single_multiletter_ext (p, "x", "non-standard extension"); + case 'z': + return parse_single_multiletter_ext (p, "z", "sub-extension"); + case 's': + return parse_single_multiletter_ext (p, "s", "supervisor extension"); + default: + return parse_single_std_ext (p); + } +} + /* Parsing arch string to subset list, return NULL if parsing failed. */ riscv_subset_list * @@ -1342,6 +1504,26 @@ fail: return NULL; } +/* Clone whole subset list. */ + +riscv_subset_list * +riscv_subset_list::clone () const +{ + riscv_subset_list *new_list = new riscv_subset_list (m_arch, m_loc); + for (riscv_subset_t *itr = m_head; itr != NULL; itr = itr->next) + new_list->add (itr->name.c_str (), itr->major_version, itr->minor_version, + itr->explicit_version_p, true); + + new_list->m_xlen = m_xlen; + return new_list; +} + +void +riscv_subset_list::set_loc (location_t loc) +{ + m_loc = loc; +} + /* Return the current arch string. */ std::string @@ -1498,6 +1680,34 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {NULL, NULL, 0} }; +void +riscv_set_arch_by_subset_list (riscv_subset_list *subset_list, + struct gcc_options *opts) +{ + if (opts) + { + const riscv_ext_flag_table_t *arch_ext_flag_tab; + /* Clean up target flags before we set. */ + for (arch_ext_flag_tab = &riscv_ext_flag_table[0]; arch_ext_flag_tab->ext; + ++arch_ext_flag_tab) + opts->*arch_ext_flag_tab->var_ref &= ~arch_ext_flag_tab->mask; + + if (subset_list->xlen () == 32) + opts->x_target_flags &= ~MASK_64BIT; + else if (subset_list->xlen () == 64) + opts->x_target_flags |= MASK_64BIT; + + for (arch_ext_flag_tab = &riscv_ext_flag_table[0]; arch_ext_flag_tab->ext; + ++arch_ext_flag_tab) + { + if (subset_list->lookup (arch_ext_flag_tab->ext)) + opts->*arch_ext_flag_tab->var_ref |= arch_ext_flag_tab->mask; + } + } + + current_subset_list = subset_list; +} + /* Parse a RISC-V ISA string into an option mask. Must clear or set all arch dependent mask bits, in case more than one -march string is passed. */ diff --git a/gcc/config/riscv/riscv-subset.h b/gcc/config/riscv/riscv-subset.h index dca07284efa..d2a4bd20530 100644 --- a/gcc/config/riscv/riscv-subset.h +++ b/gcc/config/riscv/riscv-subset.h @@ -69,8 +69,12 @@ private: const char *parse_std_ext (const char *); + const char *parse_single_std_ext (const char *); + const char *parse_multiletter_ext (const char *, const char *, const char *); + const char *parse_single_multiletter_ext (const char *, const char *, + const char *); void handle_implied_ext (const char *); bool check_implied_ext (); @@ -91,14 +95,21 @@ public: unsigned xlen () const {return m_xlen;}; + riscv_subset_list *clone () const; + static riscv_subset_list *parse (const char *, location_t); + const char *parse_single_ext (const char *); const riscv_subset_t *begin () const {return m_head;}; const riscv_subset_t *end () const {return NULL;}; int match_score (riscv_subset_list *) const; + + void set_loc (location_t); }; extern const riscv_subset_list *riscv_current_subset_list (void); +extern void +riscv_set_arch_by_subset_list (riscv_subset_list *, struct gcc_options *); #endif /* ! GCC_RISCV_SUBSET_H */ -- 2.34.1