aboutsummaryrefslogtreecommitdiff
path: root/gcc/common/config/riscv/riscv-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/common/config/riscv/riscv-common.c')
-rw-r--r--gcc/common/config/riscv/riscv-common.c181
1 files changed, 134 insertions, 47 deletions
diff --git a/gcc/common/config/riscv/riscv-common.c b/gcc/common/config/riscv/riscv-common.c
index d2ef83b1..82c5154 100644
--- a/gcc/common/config/riscv/riscv-common.c
+++ b/gcc/common/config/riscv/riscv-common.c
@@ -42,6 +42,22 @@ struct riscv_subset_t
int major_version;
int minor_version;
struct riscv_subset_t *next;
+
+ bool explicit_version_p;
+};
+
+/* Type for implied ISA info. */
+struct riscv_implied_info_t
+{
+ const char *ext;
+ const char *implied_ext;
+};
+
+/* Implied ISA info, must end with NULL sentinel. */
+riscv_implied_info_t riscv_implied_info[] =
+{
+ {"d", "f"},
+ {NULL, NULL}
};
/* Subset list. */
@@ -66,23 +82,25 @@ private:
riscv_subset_list (const char *, location_t);
const char *parsing_subset_version (const char *, unsigned *, unsigned *,
- unsigned, unsigned, bool);
+ unsigned, unsigned, bool, bool *);
const char *parse_std_ext (const char *);
- const char *parse_sv_or_non_std_ext (const char *, const char *,
- const char *);
+ const char *parse_multiletter_ext (const char *, const char *,
+ const char *);
+
+ void handle_implied_ext (const char *, int, int, bool);
public:
~riscv_subset_list ();
- void add (const char *, int, int);
+ void add (const char *, int, int, bool);
riscv_subset_t *lookup (const char *,
int major_version = RISCV_DONT_CARE_VERSION,
int minor_version = RISCV_DONT_CARE_VERSION) const;
- std::string to_string () const;
+ std::string to_string (bool) const;
unsigned xlen() const {return m_xlen;};
@@ -95,7 +113,8 @@ static const char *riscv_supported_std_ext (void);
static riscv_subset_list *current_subset_list = NULL;
riscv_subset_t::riscv_subset_t ()
- : name (), major_version (0), minor_version (0), next (NULL)
+ : name (), major_version (0), minor_version (0), next (NULL),
+ explicit_version_p (false)
{
}
@@ -122,7 +141,7 @@ riscv_subset_list::~riscv_subset_list ()
void
riscv_subset_list::add (const char *subset, int major_version,
- int minor_version)
+ int minor_version, bool explicit_version_p)
{
riscv_subset_t *s = new riscv_subset_t ();
@@ -132,6 +151,7 @@ riscv_subset_list::add (const char *subset, int major_version,
s->name = subset;
s->major_version = major_version;
s->minor_version = minor_version;
+ s->explicit_version_p = explicit_version_p;
s->next = NULL;
if (m_tail != NULL)
@@ -140,10 +160,11 @@ riscv_subset_list::add (const char *subset, int major_version,
m_tail = s;
}
-/* Convert subset info to string with explicit version info. */
+/* Convert subset info to string with explicit version info,
+ VERSION_P to determine append version info or not. */
std::string
-riscv_subset_list::to_string () const
+riscv_subset_list::to_string (bool version_p) const
{
std::ostringstream oss;
oss << "rv" << m_xlen;
@@ -153,14 +174,22 @@ riscv_subset_list::to_string () const
while (subset != NULL)
{
- if (!first)
+ /* For !version_p, we only separate extension with underline for
+ multi-letter extension. */
+ if (!first &&
+ (version_p
+ || subset->explicit_version_p
+ || subset->name.length() > 1))
oss << '_';
first = false;
- oss << subset->name
- << subset->major_version
- << 'p'
- << subset->minor_version;
+ oss << subset->name;
+
+ if (version_p || subset->explicit_version_p)
+ oss << subset->major_version
+ << 'p'
+ << subset->minor_version;
+
subset = subset->next;
}
@@ -217,7 +246,8 @@ riscv_supported_std_ext (void)
`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. */
+ `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,
@@ -225,13 +255,15 @@ riscv_subset_list::parsing_subset_version (const char *p,
unsigned *minor_version,
unsigned default_major_version,
unsigned default_minor_version,
- bool std_ext_p)
+ bool std_ext_p,
+ bool *explicit_version_p)
{
bool major_p = true;
unsigned version = 0;
unsigned major = 0;
unsigned minor = 0;
char np;
+ *explicit_version_p = false;
for (; *p; ++p)
{
@@ -246,6 +278,7 @@ riscv_subset_list::parsing_subset_version (const char *p,
{
*major_version = version;
*minor_version = 0;
+ *explicit_version_p = true;
return p;
}
else
@@ -279,6 +312,7 @@ riscv_subset_list::parsing_subset_version (const char *p,
}
else
{
+ *explicit_version_p = true;
*major_version = major;
*minor_version = minor;
}
@@ -302,6 +336,7 @@ riscv_subset_list::parse_std_ext (const char *p)
unsigned major_version = 0;
unsigned minor_version = 0;
char std_ext = '\0';
+ bool explicit_version_p = false;
/* First letter must start with i, e or g. */
switch (*p)
@@ -311,8 +346,9 @@ riscv_subset_list::parse_std_ext (const char *p)
p = parsing_subset_version (p, &major_version, &minor_version,
/* default_major_version= */ 2,
/* default_minor_version= */ 0,
- /* std_ext_p= */ true);
- add ("i", major_version, minor_version);
+ /* std_ext_p= */ true,
+ &explicit_version_p);
+ add ("i", major_version, minor_version, explicit_version_p);
break;
case 'e':
@@ -320,9 +356,10 @@ riscv_subset_list::parse_std_ext (const char *p)
p = parsing_subset_version (p, &major_version, &minor_version,
/* default_major_version= */ 1,
/* default_minor_version= */ 9,
- /* std_ext_p= */ true);
+ /* std_ext_p= */ true,
+ &explicit_version_p);
- add ("e", major_version, minor_version);
+ add ("e", major_version, minor_version, explicit_version_p);
if (m_xlen > 32)
{
@@ -337,13 +374,14 @@ riscv_subset_list::parse_std_ext (const char *p)
p = parsing_subset_version (p, &major_version, &minor_version,
/* default_major_version= */ 2,
/* default_minor_version= */ 0,
- /* std_ext_p= */ true);
- add ("i", major_version, minor_version);
+ /* std_ext_p= */ true,
+ &explicit_version_p);
+ add ("i", major_version, minor_version, explicit_version_p);
for (; *std_exts != 'q'; std_exts++)
{
const char subset[] = {*std_exts, '\0'};
- add (subset, major_version, minor_version);
+ add (subset, major_version, minor_version, explicit_version_p);
}
break;
@@ -357,7 +395,7 @@ riscv_subset_list::parse_std_ext (const char *p)
{
char subset[2] = {0, 0};
- if (*p == 'x' || *p == 's')
+ if (*p == 'x' || *p == 's' || *p == 'h' || *p == 'z')
break;
if (*p == '_')
@@ -390,29 +428,61 @@ riscv_subset_list::parse_std_ext (const char *p)
p = parsing_subset_version (p, &major_version, &minor_version,
/* default_major_version= */ 2,
/* default_minor_version= */ 0,
- /* std_ext_p= */ true);
+ /* std_ext_p= */ true,
+ &explicit_version_p);
subset[0] = std_ext;
- add (subset, major_version, minor_version);
+ handle_implied_ext (subset, major_version,
+ minor_version, explicit_version_p);
+
+ add (subset, major_version, minor_version, explicit_version_p);
}
return p;
}
-/* Parsing function for non-standard and supervisor extensions.
+
+/* 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. */
+void
+riscv_subset_list::handle_implied_ext (const char *ext,
+ int major_version,
+ int minor_version,
+ bool explicit_version_p)
+{
+ 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)
+ 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);
+ }
+}
+
+/* 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, 'x', 's' or 'sx'.
+ `ext_type`: What kind of extensions, 's', 'h', 'z' or 'x'.
`ext_type_str`: Full name for kind of extension. */
const char *
-riscv_subset_list::parse_sv_or_non_std_ext (const char *p,
- const char *ext_type,
- const char *ext_type_str)
+riscv_subset_list::parse_multiletter_ext (const char *p,
+ const char *ext_type,
+ const char *ext_type_str)
{
unsigned major_version = 0;
unsigned minor_version = 0;
@@ -429,14 +499,10 @@ riscv_subset_list::parse_sv_or_non_std_ext (const char *p,
if (strncmp (p, ext_type, ext_type_len) != 0)
break;
- /* It's non-standard supervisor extension if it prefix with sx. */
- if ((ext_type[0] == 's') && (ext_type_len == 1)
- && (*(p + 1) == 'x'))
- break;
-
char *subset = xstrdup (p);
char *q = subset;
const char *end_of_version;
+ bool explicit_version_p = false;
while (*++q != '\0' && *q != '_' && !ISDIGIT (*q))
;
@@ -445,11 +511,12 @@ riscv_subset_list::parse_sv_or_non_std_ext (const char *p,
= parsing_subset_version (q, &major_version, &minor_version,
/* default_major_version= */ 2,
/* default_minor_version= */ 0,
- /* std_ext_p= */ FALSE);
+ /* std_ext_p= */ FALSE,
+ &explicit_version_p);
*q = '\0';
- add (subset, major_version, minor_version);
+ add (subset, major_version, minor_version, explicit_version_p);
free (subset);
p += end_of_version - subset;
@@ -494,21 +561,26 @@ riscv_subset_list::parse (const char *arch, location_t loc)
if (p == NULL)
goto fail;
- /* Parsing non-standard extension. */
- p = subset_list->parse_sv_or_non_std_ext (p, "x", "non-standard extension");
+ /* Parsing supervisor extension. */
+ p = subset_list->parse_multiletter_ext (p, "s", "supervisor extension");
if (p == NULL)
goto fail;
- /* Parsing supervisor extension. */
- p = subset_list->parse_sv_or_non_std_ext (p, "s", "supervisor extension");
+ /* Parsing hypervisor extension. */
+ p = subset_list->parse_multiletter_ext (p, "h", "hypervisor extension");
if (p == NULL)
goto fail;
- /* Parsing non-standard supervisor extension. */
- p = subset_list->parse_sv_or_non_std_ext
- (p, "sx", "non-standard supervisor extension");
+ /* Parsing sub-extensions. */
+ p = subset_list->parse_multiletter_ext (p, "z", "sub-extension");
+
+ if (p == NULL)
+ goto fail;
+
+ /* Parsing non-standard extension. */
+ p = subset_list->parse_multiletter_ext (p, "x", "non-standard extension");
if (p == NULL)
goto fail;
@@ -530,10 +602,10 @@ fail:
/* Return the current arch string. */
std::string
-riscv_arch_str ()
+riscv_arch_str (bool version_p)
{
gcc_assert (current_subset_list);
- return current_subset_list->to_string ();
+ return current_subset_list->to_string (version_p);
}
/* Parse a RISC-V ISA string into an option mask. Must clear or set all arch
@@ -600,6 +672,21 @@ riscv_handle_option (struct gcc_options *opts,
}
}
+/* Expand arch string with implied extensions. */
+
+const char *
+riscv_expand_arch (int argc ATTRIBUTE_UNUSED,
+ const char **argv)
+{
+ static char *_arch_buf;
+ gcc_assert (argc == 1);
+ int flags;
+ location_t loc = UNKNOWN_LOCATION;
+ riscv_parse_arch_string (argv[0], &flags, loc);
+ _arch_buf = xstrdup (riscv_arch_str (false).c_str ());
+ return _arch_buf;
+}
+
/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
static const struct default_options riscv_option_optimization_table[] =
{