[PATCH 1/2] RISC-V: Accept version, supervisor ext and more than one NSE for -march.
Kito Cheng
kito.cheng@gmail.com
Wed Feb 13 07:19:00 GMT 2019
Sorry for annoying, this patch should appear in gcc-patches@gcc.gnu.org. :(
On Wed, Feb 13, 2019 at 3:15 PM Kito Cheng <kito@andestech.com> wrote:
>
> From: Kito Cheng <kito.cheng@gmail.com>
>
> Kito Cheng <kito.cheng@gmail.com>
> Monk Chiang <sh.chiang04@gmail.com>
>
> ChangeLog:
> gcc:
> * common/config/riscv/riscv-common.c:
> Include config/riscv/riscv-protos.h.
> (INCLUDE_STRING): Defined.
> (RISCV_DONT_CARE_VERSION): Defined.
> (riscv_subset_t): Declare.
> (riscv_subset_list): Declare.
> (riscv_subset_list::riscv_subset_list): New.
> (riscv_subset_list::~riscv_subset_list): Likewise.
> (riscv_subset_list::parsing_subset_version): Likewise.
> (riscv_subset_list::parse_std_ext): Likewise.
> (riscv_subset_list::parse_sv_or_non_std_ext): Likewise.
> (riscv_subset_list::add): Likewise.
> (riscv_subset_list::lookup): Likewise.
> (riscv_subset_list::xlen): Likewise.
> (riscv_subset_list::parse): Likewise.
> (riscv_supported_std_ext): Likewise.
> (current_subset_list): Likewise.
> (riscv_parse_arch_string): Using riscv_subset_list::parse to
> parse.
>
> gcc/testsuite:
> * gcc.target/riscv/arch-1.c: New.
> * gcc.target/riscv/arch-2.c: Likewise.
> * gcc.target/riscv/arch-3.c: Likewise.
> * gcc.target/riscv/arch-4.c: Likewise.
> ---
> gcc/common/config/riscv/riscv-common.c | 530 ++++++++++++++++++++++++++++----
> gcc/testsuite/gcc.target/riscv/arch-1.c | 7 +
> gcc/testsuite/gcc.target/riscv/arch-2.c | 6 +
> gcc/testsuite/gcc.target/riscv/arch-3.c | 6 +
> gcc/testsuite/gcc.target/riscv/arch-4.c | 6 +
> 5 files changed, 496 insertions(+), 59 deletions(-)
> create mode 100644 gcc/testsuite/gcc.target/riscv/arch-1.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/arch-2.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/arch-3.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/arch-4.c
>
> diff --git a/gcc/common/config/riscv/riscv-common.c b/gcc/common/config/riscv/riscv-common.c
> index cb5bb7f..e412acb 100644
> --- a/gcc/common/config/riscv/riscv-common.c
> +++ b/gcc/common/config/riscv/riscv-common.c
> @@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License
> along with GCC; see the file COPYING3. If not see
> <http://www.gnu.org/licenses/>. */
>
> +#define INCLUDE_STRING
> #include "config.h"
> #include "system.h"
> #include "coretypes.h"
> @@ -26,99 +27,510 @@ along with GCC; see the file COPYING3. If not see
> #include "opts.h"
> #include "flags.h"
> #include "diagnostic-core.h"
> +#include "config/riscv/riscv-protos.h"
>
> -/* 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. */
> +#define RISCV_DONT_CARE_VERSION -1
>
> -static void
> -riscv_parse_arch_string (const char *isa, int *flags, location_t loc)
> +/* Subset info. */
> +struct riscv_subset_t {
> + riscv_subset_t ();
> +
> + std::string name;
> + int major_version;
> + int minor_version;
> + struct riscv_subset_t *next;
> +};
> +
> +/* Subset list. */
> +class riscv_subset_list {
> +private:
> + /* Original arch string. */
> + const char *m_arch;
> +
> + /* Localtion of arch string, used for report error. */
> + location_t m_loc;
> +
> + /* Head of subset info list. */
> + riscv_subset_t *m_head;
> +
> + /* Tail of subset info list. */
> + riscv_subset_t *m_tail;
> +
> + /* X-len of m_arch. */
> + unsigned m_xlen;
> +
> + riscv_subset_list (const char *, location_t);
> +
> + const char *parsing_subset_version (const char *, unsigned *, unsigned *,
> + unsigned, unsigned, bool);
> +
> + const char *parse_std_ext (const char *);
> +
> + const char *parse_sv_or_non_std_ext (const char *, const char *,
> + const char *);
> +
> +public:
> + ~riscv_subset_list ();
> +
> + void add (const char *, int, int);
> +
> + riscv_subset_t *lookup (const char *,
> + int major_version = RISCV_DONT_CARE_VERSION,
> + int minor_version = RISCV_DONT_CARE_VERSION) const;
> +
> + unsigned xlen() const {return m_xlen;};
> +
> + static riscv_subset_list *parse (const char *, location_t);
> +
> +};
> +
> +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)
> {
> - const char *p = isa;
> +}
>
> - if (strncmp (p, "rv32", 4) == 0)
> - *flags &= ~MASK_64BIT, p += 4;
> - else if (strncmp (p, "rv64", 4) == 0)
> - *flags |= MASK_64BIT, p += 4;
> - else
> +riscv_subset_list::riscv_subset_list (const char *arch, location_t loc)
> +: m_arch (arch), m_loc(loc), m_head (NULL), m_tail (NULL), m_xlen(0)
> +{
> +}
> +
> +riscv_subset_list::~riscv_subset_list()
> +{
> + if (!m_head)
> + return;
> +
> + riscv_subset_t *item = this->m_head->next;
> + while (item != NULL)
> {
> - error_at (loc, "-march=%s: ISA string must begin with rv32 or rv64", isa);
> - return;
> + riscv_subset_t *next = item->next;
> + delete item;
> + item = next;
> }
> +}
>
> - if (*p == 'g')
> - {
> - p++;
> +/* Add new subset to list. */
>
> - *flags &= ~MASK_RVE;
> +void riscv_subset_list::add (const char *subset,
> + int major_version,
> + int minor_version)
> +{
> + riscv_subset_t *s = new riscv_subset_t ();
>
> - *flags |= MASK_MUL;
> - *flags |= MASK_ATOMIC;
> - *flags |= MASK_HARD_FLOAT;
> - *flags |= MASK_DOUBLE_FLOAT;
> - }
> - else if (*p == 'i')
> - {
> - p++;
> + if (m_head == NULL)
> + m_head = s;
> +
> + s->name = subset;
> + s->major_version = major_version;
> + s->minor_version = minor_version;
> + s->next = NULL;
> +
> + if (m_tail != NULL)
> + m_tail->next = s;
> +
> + m_tail = s;
> +}
>
> - *flags &= ~MASK_RVE;
> +/* Find subset in list without version checking, return NULL if not found. */
>
> - *flags &= ~MASK_MUL;
> - if (*p == 'm')
> - *flags |= MASK_MUL, p++;
> +riscv_subset_t *riscv_subset_list::lookup (const char *subset,
> + int major_version,
> + int minor_version) const
> +{
> + riscv_subset_t *s;
> +
> + for (s = m_head; s != NULL; s = s->next)
> + if (strcasecmp (s->name.c_str(), subset) == 0)
> + {
> + if ((major_version != RISCV_DONT_CARE_VERSION)
> + && (s->major_version != major_version))
> + return NULL;
> +
> + if ((minor_version != RISCV_DONT_CARE_VERSION)
> + && (s->minor_version != minor_version))
> + return NULL;
>
> - *flags &= ~MASK_ATOMIC;
> - if (*p == 'a')
> - *flags |= MASK_ATOMIC, p++;
> + return s;
> + }
> +
> + return s;
> +}
> +
> +/* Return string which contain all supported standard extensions in
> + canonical order. */
> +
> +static const char *
> +riscv_supported_std_ext (void)
> +{
> + return "mafdqlcbjtpvn";
> +}
> +
> +/* Parsing subset version.
> +
> + Return Value:
> + Points to the end of version
> +
> + Arguments:
> + `p`: Curent 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. */
> +
> +const char *
> +riscv_subset_list::parsing_subset_version (const char *p,
> + unsigned *major_version,
> + unsigned *minor_version,
> + unsigned default_major_version,
> + unsigned default_minor_version,
> + bool std_ext_p)
> +{
> + bool major_p = true;
> + unsigned version = 0;
> + unsigned major = 0;
> + unsigned minor = 0;
> + char np;
>
> - *flags &= ~(MASK_HARD_FLOAT | MASK_DOUBLE_FLOAT);
> - if (*p == 'f')
> + for (;*p; ++p)
> + {
> + if (*p == 'p')
> {
> - *flags |= MASK_HARD_FLOAT, p++;
> + np = *(p + 1);
>
> - if (*p == 'd')
> + if (!ISDIGIT (np))
> {
> - *flags |= MASK_DOUBLE_FLOAT;
> - p++;
> + /* Might be beginning of `p` extension. */
> + if (std_ext_p)
> + {
> + *major_version = version;
> + *minor_version = 0;
> + return p;
> + }
> + else
> + {
> + error_at (m_loc, "-march=%s: Expect number after `%dp'.",
> + m_arch, version);
> + return NULL;
> + }
> }
> +
> + major = version;
> + major_p = false;
> + version = 0;
> }
> + else if (ISDIGIT (*p))
> + version = (version * 10) + (*p - '0');
> + else
> + break;
> }
> - else if (*p == 'e')
> +
> + if (major_p)
> + major = version;
> + else
> + minor = version;
> +
> + if (major == 0 && minor == 0)
> {
> - p++;
> + /* We don't found any version string, use default version. */
> + *major_version = default_major_version;
> + *minor_version = default_minor_version;
> + }
> + else
> + {
> + *major_version = major;
> + *minor_version = minor;
> + }
> + return p;
> +}
> +
> +/* Parsing function for standard extensions.
> +
> + Return Value:
> + Points to the end of extensions.
> +
> + Arguments:
> + `p`: Curent parsing position. */
>
> - *flags |= MASK_RVE;
> +const char *
> +riscv_subset_list::parse_std_ext (const char *p)
> +{
> + const char *all_std_exts = riscv_supported_std_ext ();
> + const char *std_exts = all_std_exts;
> +
> + unsigned major_version = 0;
> + unsigned minor_version = 0;
> + char std_ext = '\0';
> +
> + /* First letter must start with i, e or g. */
> + switch (*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);
> + add ("i", major_version, minor_version);
> + break;
>
> - if (*flags & MASK_64BIT)
> + case 'e':
> + p++;
> + p = parsing_subset_version (
> + p, &major_version, &minor_version,
> + /* default_major_version= */ 1,
> + /* default_minor_version= */ 9,
> + /* std_ext_p= */true);
> +
> + add ("e", major_version, minor_version);
> +
> + if (m_xlen > 32)
> + {
> + error_at (m_loc, "-march=%s: rv%de is not a valid base ISA",
> + m_arch, m_xlen);
> + return NULL;
> + }
> +
> + break;
> +
> + case 'g':
> + 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);
> +
> + for ( ; *std_exts != 'q'; std_exts++)
> + {
> + const char subset[] = {*std_exts, '\0'};
> + add (subset, major_version, minor_version);
> + }
> + break;
> +
> + default:
> + error_at (m_loc, "-march=%s: first ISA subset must be `e', `i' or `g'",
> + m_arch);
> + return NULL;
> + }
> +
> + while (*p)
> + {
> + char subset[2] = {0, 0};
> +
> + if (*p == 'x' || *p == 's')
> + break;
> +
> + if (*p == '_')
> {
> - error ("RV64E is not a valid base ISA");
> - return;
> + p++;
> + continue;
> }
>
> - *flags &= ~MASK_MUL;
> - if (*p == 'm')
> - *flags |= MASK_MUL, p++;
> + std_ext = *p;
> +
> + /* Checking canonical order. */
> + while (*std_exts && std_ext != *std_exts) std_exts++;
> +
> + if (std_ext != *std_exts)
> + {
> + if (strchr (all_std_exts, std_ext) == NULL)
> + error_at (m_loc, "-march=%s: unsupported ISA subset `%c'",
> + m_arch, *p);
> + else
> + error_at (m_loc,
> + "-march=%s: ISA string is not in canonical order. `%c'",
> + m_arch, *p);
> + return NULL;
> + }
>
> - *flags &= ~MASK_ATOMIC;
> - if (*p == 'a')
> - *flags |= MASK_ATOMIC, p++;
> + std_exts++;
>
> - *flags &= ~(MASK_HARD_FLOAT | MASK_DOUBLE_FLOAT);
> + p++;
> + p = parsing_subset_version (
> + p, &major_version, &minor_version,
> + /* default_major_version= */ 2,
> + /* default_minor_version= */ 0,
> + /* std_ext_p= */true);
> +
> + subset[0] = std_ext;
> +
> + add (subset, major_version, minor_version);
> }
> - else
> + return p;
> +}
> +
> +/* Parsing function for non-standard and supervisor extensions.
> +
> + Return Value:
> + Points to the end of extensions.
> +
> + Arguments:
> + `p`: Curent parsing position.
> + `ext_type`: What kind of extensions, 'x', 's' or 'sx'.
> + `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)
> +{
> + unsigned major_version = 0;
> + unsigned minor_version = 0;
> + size_t ext_type_len = strlen (ext_type);
> +
> + while (*p)
> {
> - error_at (loc, "-march=%s: invalid ISA string", isa);
> - return;
> + if (*p == '_')
> + {
> + p++;
> + continue;
> + }
> +
> + 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;
> +
> + while (*++q != '\0' && *q != '_' && !ISDIGIT (*q))
> + ;
> +
> + end_of_version =
> + parsing_subset_version (
> + q, &major_version, &minor_version,
> + /* default_major_version= */ 2,
> + /* default_minor_version= */ 0,
> + /* std_ext_p= */FALSE);
> +
> + *q = '\0';
> +
> + add (subset, major_version, minor_version);
> + free (subset);
> + p += end_of_version - subset;
> +
> + if (*p != '\0' && *p != '_')
> + {
> + error_at (m_loc, "-march=%s: %s must seperate with _",
> + m_arch, ext_type_str);
> + return NULL;
> + }
> }
>
> - *flags &= ~MASK_RVC;
> - if (*p == 'c')
> - *flags |= MASK_RVC, p++;
> + return p;
> +}
> +
> +/* Parsing arch string to subset list, return NULL if parsing failed. */
>
> - if (*p)
> +riscv_subset_list *
> +riscv_subset_list::parse (const char *arch, location_t loc)
> +{
> + riscv_subset_list *subset_list = new riscv_subset_list (arch, loc);
> + const char *p = arch;
> + if (strncmp (p, "rv32", 4) == 0)
> {
> - error_at (loc, "-march=%s: unsupported ISA substring %qs", isa, p);
> - return;
> + subset_list->m_xlen = 32;
> + p += 4;
> }
> + else if (strncmp (p, "rv64", 4) == 0)
> + {
> + subset_list->m_xlen = 64;
> + p += 4;
> + }
> + else
> + {
> + error_at (loc, "-march=%s: ISA string must begin with rv32 or rv64",
> + arch);
> + goto fail;
> + }
> +
> + /* Parsing standard extension. */
> + p = subset_list->parse_std_ext (p);
> +
> + if (p == NULL)
> + goto fail;
> +
> + /* Parsing non-standard extension. */
> + p = subset_list->parse_sv_or_non_std_ext (
> + p, "x", "non-standard extension");
> +
> + if (p == NULL)
> + goto fail;
> +
> + /* Parsing supervisor extension. */
> + p = subset_list->parse_sv_or_non_std_ext (
> + p, "s", "supervisor 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");
> +
> + if (p == NULL)
> + goto fail;
> +
> + return subset_list;
> +
> +fail:
> + delete subset_list;
> + return NULL;
> +}
> +
> +/* 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. */
> +
> +static void
> +riscv_parse_arch_string (const char *isa, int *flags, location_t loc)
> +{
> + riscv_subset_list *subset_list;
> + subset_list = riscv_subset_list::parse (isa, loc);
> + if (!subset_list)
> + return;
> +
> + if (subset_list->xlen () == 32)
> + *flags &= ~MASK_64BIT;
> + else if (subset_list->xlen () == 64)
> + *flags |= MASK_64BIT;
> +
> + *flags &= ~MASK_RVE;
> + if (subset_list->lookup ("e"))
> + *flags |= MASK_RVE;
> +
> + *flags &= ~MASK_MUL;
> + if (subset_list->lookup ("m"))
> + *flags |= MASK_MUL;
> +
> + *flags &= ~MASK_ATOMIC;
> + if (subset_list->lookup ("a"))
> + *flags |= MASK_ATOMIC;
> +
> + *flags &= ~(MASK_HARD_FLOAT | MASK_DOUBLE_FLOAT);
> + if (subset_list->lookup ("f"))
> + *flags |= MASK_HARD_FLOAT;
> +
> + if (subset_list->lookup ("d"))
> + *flags |= MASK_DOUBLE_FLOAT;
> +
> + if (current_subset_list)
> + delete current_subset_list;
> +
> + current_subset_list = subset_list;
> }
>
> /* Implement TARGET_HANDLE_OPTION. */
> diff --git a/gcc/testsuite/gcc.target/riscv/arch-1.c b/gcc/testsuite/gcc.target/riscv/arch-1.c
> new file mode 100644
> index 0000000..e7c8738
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/arch-1.c
> @@ -0,0 +1,7 @@
> +/* Verify the return instruction is mret. */
> +/* { dg-do compile } */
> +/* { dg-options "-O -march=rv32I -mabi=ilp32" } */
> +int foo()
> +{
> +}
> +/* { dg-error ".-march=rv32I: first ISA subset must be `e', `i' or `g'" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.target/riscv/arch-2.c b/gcc/testsuite/gcc.target/riscv/arch-2.c
> new file mode 100644
> index 0000000..ed90e2f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/arch-2.c
> @@ -0,0 +1,6 @@
> +/* Verify the return instruction is mret. */
> +/* { dg-do compile } */
> +/* { dg-options "-O -march=rv32ixabc_xfoo -mabi=ilp32" } */
> +int foo()
> +{
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/arch-3.c b/gcc/testsuite/gcc.target/riscv/arch-3.c
> new file mode 100644
> index 0000000..55908dd
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/arch-3.c
> @@ -0,0 +1,6 @@
> +/* Verify the return instruction is mret. */
> +/* { dg-do compile } */
> +/* { dg-options "-O -march=rv32ixbar_sabc_sxfoo -mabi=ilp32" } */
> +int foo()
> +{
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/arch-4.c b/gcc/testsuite/gcc.target/riscv/arch-4.c
> new file mode 100644
> index 0000000..3c9e1c1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/arch-4.c
> @@ -0,0 +1,6 @@
> +/* Verify the return instruction is mret. */
> +/* { dg-do compile } */
> +/* { dg-options "-O -march=rv32i2p3_m4p2 -mabi=ilp32" } */
> +int foo()
> +{
> +}
> --
> 1.8.3.1
>
More information about the Binutils
mailing list