diff options
author | Nelson Chu <nelson.chu@sifive.com> | 2021-11-19 17:11:06 +0800 |
---|---|---|
committer | Nelson Chu <nelson.chu@sifive.com> | 2021-11-19 18:50:27 +0800 |
commit | d3ffd7f77654adafe5f1989bdfdbe4a337ff2e8b (patch) | |
tree | 4175e17a9569dcc539f92e32ed3ec098328217ee /bfd | |
parent | fd0ff19bf435b267caae6a1ae04e7b4a4ba64f5b (diff) | |
download | gdb-d3ffd7f77654adafe5f1989bdfdbe4a337ff2e8b.zip gdb-d3ffd7f77654adafe5f1989bdfdbe4a337ff2e8b.tar.gz gdb-d3ffd7f77654adafe5f1989bdfdbe4a337ff2e8b.tar.bz2 |
RISC-V: Support new .option arch directive.
https://github.com/riscv/riscv-asm-manual/pull/67
Format:
.option arch, +<extension><version>, ...
.option arch, -<extension>
.option arch, =<ISA string>
The new direcitve is used to enable/disable extensions for the specific
code region. For example,
.attribute arch, "rv64ic" # arch = rv64i2p0_c2p0
.option push
.option arch, +d2p0, -c # arch = rv64i2p0_f2p0_d2p0, f is added implied
.option arch, =rv32gc # arch = rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0
.option pop # arch = rv64i2p0_c2p0
Note that,
1. ".option rvc/norvc" have the same behavior as ".option arch +c/-c".
2. ".option arch -i" is illegal, since we cannot remove base i extension.
3. If arch=rv64i2p0, then ".option arch, +i3p0" will update the i's version
from 2.0 to 3.0.
4. If arch=rv64i3p0, then ".option arch, +i" will update the i's version
from 2.0 to the default one according to the chosen isa spec.
bfd/
* elfxx-riscv.c (riscv_add_subset): If the subset is already added,
and the new versions are not RISCV_UNKNOWN_VERSION, then update the
versions to the subset list.
(riscv_copy_subset): New function. Copy the subset from list.
(riscv_copy_subset_list): New function. Return the new copyed list.
(riscv_update_subset): Updated to make .option arch directives workable.
* elfxx-riscv.h: Updated.
gas/
* config/tc-riscv.c (riscv_subsets): Defined as a pointer.
(riscv_rps_as): Init the subset_list to NULL, we will set it later
once riscv_opts_stack is created or updated.
(struct riscv_option_stack, riscv_opts_stack): Moved forward.
(riscv_set_arch): Updated.
(s_riscv_option): Support new .option arch directive, to add, remove
or update subsets for the specific code region.
(riscv_write_out_attrs): Updated.
* doc/c-riscv.texi: Added document for new .option arch directive.
* testsuite/gas/riscv/option-arch-01a.d: New testcase.
* testsuite/gas/riscv/option-arch-01b.d: Likewise.
* testsuite/gas/riscv/option-arch-01.s: Likewise..
* testsuite/gas/riscv/option-arch-02.d: Likewise.
* testsuite/gas/riscv/option-arch-02.s: Likewise.
* testsuite/gas/riscv/option-arch-fail.d: Likewise.
* testsuite/gas/riscv/option-arch-fail.l: Likewise.
* testsuite/gas/riscv/option-arch-fail.s: Likewise.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/elfxx-riscv.c | 158 | ||||
-rw-r--r-- | bfd/elfxx-riscv.h | 5 |
2 files changed, 138 insertions, 25 deletions
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c index 91afd4c..b8da40c 100644 --- a/bfd/elfxx-riscv.c +++ b/bfd/elfxx-riscv.c @@ -1468,7 +1468,15 @@ riscv_add_subset (riscv_subset_list_t *subset_list, riscv_subset_t *current, *new; if (riscv_lookup_subset (subset_list, subset, ¤t)) - return; + { + if (major != RISCV_UNKNOWN_VERSION + && minor != RISCV_UNKNOWN_VERSION) + { + current->major_version = major; + current->minor_version = minor; + } + return; + } new = xmalloc (sizeof *new); new->name = xstrdup (subset); @@ -2138,6 +2146,37 @@ riscv_arch_str (unsigned xlen, const riscv_subset_list_t *subset) return attr_str; } +/* Copy the subset in the subset list. */ + +static struct riscv_subset_t * +riscv_copy_subset (riscv_subset_list_t *subset_list, + riscv_subset_t *subset) +{ + if (subset == NULL) + return NULL; + + riscv_subset_t *new = xmalloc (sizeof *new); + new->name = xstrdup (subset->name); + new->major_version = subset->major_version; + new->minor_version = subset->minor_version; + new->next = riscv_copy_subset (subset_list, subset->next); + + if (subset->next == NULL) + subset_list->tail = new; + + return new; +} + +/* Copy the subset list. */ + +riscv_subset_list_t * +riscv_copy_subset_list (riscv_subset_list_t *subset_list) +{ + riscv_subset_list_t *new = xmalloc (sizeof *new); + new->head = riscv_copy_subset (new, subset_list->head); + return new; +} + /* Remove the SUBSET from the subset list. */ static void @@ -2164,40 +2203,111 @@ riscv_remove_subset (riscv_subset_list_t *subset_list, } /* Add/Remove an extension to/from the subset list. This is used for - the .option rvc or norvc. */ + the .option rvc or norvc, and .option arch directives. */ bool riscv_update_subset (riscv_parse_subset_t *rps, - const char *subset, - bool removed) + const char *str) { - if (strlen (subset) == 0 - || (strlen (subset) == 1 - && riscv_ext_order[(*subset - 'a')] == 0) - || (strlen (subset) > 1 - && rps->check_unknown_prefixed_ext - && !riscv_recognized_prefixed_ext (subset))) - { - rps->error_handler - (_("riscv_update_subset: unknown ISA extension `%s'"), subset); - return false; - } + const char *p = str; - if (removed) + do { - if (strcmp (subset, "i") == 0) + int major_version = RISCV_UNKNOWN_VERSION; + int minor_version = RISCV_UNKNOWN_VERSION; + + bool removed = false; + switch (*p++) + { + case '+': removed = false; break; + case '-': removed = true; break; + case '=': + riscv_release_subset_list (rps->subset_list); + return riscv_parse_subset (rps, p); + default: + rps->error_handler + (_("extensions must begin with +/-/= in .option arch `%s'"), str); + return false; + } + + char *subset = xstrdup (p); + char *q = subset; + const char *end_of_version; + /* Extract the whole prefixed extension by ','. */ + while (*q != '\0' && *q != ',') + q++; + /* Look forward to the first letter which is not <major>p<minor>. */ + bool find_any_version = false; + bool find_minor_version = false; + while (1) + { + q--; + if (ISDIGIT (*q)) + find_any_version = true; + else if (find_any_version + && !find_minor_version + && *q == 'p' + && ISDIGIT (*(q - 1))) + find_minor_version = true; + else + break; + } + q++; + /* Check if the end of extension is 'p' or not. If yes, then + the second letter from the end cannot be number. */ + if (*(q - 1) == 'p' && ISDIGIT (*(q - 2))) + { + *q = '\0'; + rps->error_handler + (_("invalid ISA extension ends with <number>p " + "in .option arch `%s'"), str); + free (subset); + return false; + } + end_of_version = + riscv_parsing_subset_version (q, &major_version, &minor_version); + *q = '\0'; + if (end_of_version == NULL) + { + free (subset); + return false; + } + + if (strlen (subset) == 0 + || (strlen (subset) == 1 + && riscv_ext_order[(*subset - 'a')] == 0) + || (strlen (subset) > 1 + && rps->check_unknown_prefixed_ext + && !riscv_recognized_prefixed_ext (subset))) { rps->error_handler - (_("riscv_update_subset: cannot remove extension i from " - "the subset list")); + (_("unknown ISA extension `%s' in .option arch `%s'"), + subset, str); + free (subset); return false; } - riscv_remove_subset (rps->subset_list, subset); + + if (removed) + { + if (strcmp (subset, "i") == 0) + { + rps->error_handler + (_("cannot remove extension `i' in .option arch `%s'"), str); + free (subset); + return false; + } + riscv_remove_subset (rps->subset_list, subset); + } + else + riscv_parse_add_subset (rps, subset, major_version, minor_version, true); + p += end_of_version - subset; + free (subset); } - else - riscv_parse_add_subset (rps, subset, - RISCV_UNKNOWN_VERSION, - RISCV_UNKNOWN_VERSION, true); + while (*p++ == ','); + + if (*(--p) != '\0') + rps->error_handler + (_("unexpected value in .option arch `%s'"), str); riscv_parse_add_implicit_subsets (rps); return riscv_parse_check_conflicts (rps); diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h index 8de9adc..ea7edc4 100644 --- a/bfd/elfxx-riscv.h +++ b/bfd/elfxx-riscv.h @@ -92,8 +92,11 @@ riscv_estimate_digit (unsigned); extern int riscv_compare_subsets (const char *, const char *); +extern riscv_subset_list_t * +riscv_copy_subset_list (riscv_subset_list_t *); + extern bool -riscv_update_subset (riscv_parse_subset_t *, const char *, bool); +riscv_update_subset (riscv_parse_subset_t *, const char *); extern bool riscv_subset_supports (riscv_parse_subset_t *, const char *); |