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);
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
}
/* 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);
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 *);
the architecture string. The architecture string can be set by the
-march option, the elf architecture attributes, and the --with-arch
configure option. */
-static riscv_subset_list_t riscv_subsets;
+static riscv_subset_list_t *riscv_subsets = NULL;
static riscv_parse_subset_t riscv_rps_as =
{
- &riscv_subsets, /* subset_list. */
+ NULL, /* subset_list, we will set it later once
+ riscv_opts_stack is created or updated. */
as_bad, /* error_handler. */
&xlen, /* xlen. */
&default_isa_spec, /* isa_spec. */
true, /* check_unknown_prefixed_ext. */
};
+/* This structure is used to hold a stack of .option values. */
+struct riscv_option_stack
+{
+ struct riscv_option_stack *next;
+ struct riscv_set_options options;
+ riscv_subset_list_t *subset_list;
+};
+
+static struct riscv_option_stack *riscv_opts_stack = NULL;
+
/* Set which ISA and extensions are available. */
static void
return;
}
- riscv_release_subset_list (&riscv_subsets);
+ if (riscv_subsets == NULL)
+ {
+ riscv_subsets = XNEW (riscv_subset_list_t);
+ riscv_subsets->head = NULL;
+ riscv_subsets->tail = NULL;
+ riscv_rps_as.subset_list = riscv_subsets;
+ }
+ riscv_release_subset_list (riscv_subsets);
riscv_parse_subset (&riscv_rps_as, s);
riscv_set_rvc (false);
subseg_set (seg, subseg);
}
-/* This structure is used to hold a stack of .option values. */
-struct riscv_option_stack
-{
- struct riscv_option_stack *next;
- struct riscv_set_options options;
-};
-
-static struct riscv_option_stack *riscv_opts_stack;
-
/* Handle the .option pseudo-op. */
static void
if (strcmp (name, "rvc") == 0)
{
- riscv_update_subset (&riscv_rps_as, "c", false);
+ riscv_update_subset (&riscv_rps_as, "+c");
riscv_set_rvc (true);
}
else if (strcmp (name, "norvc") == 0)
{
- riscv_update_subset (&riscv_rps_as, "c", true);
+ riscv_update_subset (&riscv_rps_as, "-c");
riscv_set_rvc (false);
}
else if (strcmp (name, "pic") == 0)
riscv_opts.csr_check = true;
else if (strcmp (name, "no-csr-check") == 0)
riscv_opts.csr_check = false;
+ else if (strncmp (name, "arch,", 5) == 0)
+ {
+ name += 5;
+ if (ISSPACE (*name) && *name != '\0')
+ name++;
+ riscv_update_subset (&riscv_rps_as, name);
+ }
else if (strcmp (name, "push") == 0)
{
struct riscv_option_stack *s;
- s = (struct riscv_option_stack *) xmalloc (sizeof *s);
+ s = XNEW (struct riscv_option_stack);
s->next = riscv_opts_stack;
s->options = riscv_opts;
+ s->subset_list = riscv_subsets;
riscv_opts_stack = s;
+ riscv_subsets = riscv_copy_subset_list (s->subset_list);
+ riscv_rps_as.subset_list = riscv_subsets;
}
else if (strcmp (name, "pop") == 0)
{
as_bad (_(".option pop with no .option push"));
else
{
- riscv_opts = s->options;
+ riscv_subset_list_t *release_subsets = riscv_subsets;
riscv_opts_stack = s->next;
+ riscv_opts = s->options;
+ riscv_subsets = s->subset_list;
+ riscv_rps_as.subset_list = riscv_subsets;
+ riscv_release_subset_list (release_subsets);
free (s);
}
}
unsigned int i;
/* Re-write architecture elf attribute. */
- arch_str = riscv_arch_str (xlen, &riscv_subsets);
+ arch_str = riscv_arch_str (xlen, riscv_subsets);
bfd_elf_add_proc_attr_string (stdoutput, Tag_RISCV_arch, arch_str);
xfree ((void *) arch_str);
@itemx norvc
Enables or disables the generation of compressed instructions. Instructions
are opportunistically compressed by the RISC-V assembler when possible, but
-sometimes this behavior is not desirable.
+sometimes this behavior is not desirable, especially when handling alignments.
@item pic
@itemx nopic
@itemx no-csr-check
Enables or disables the CSR checking.
+@item arch, @var{+extension[version]} [,...,@var{+extension_n[version_n]}]
+@itemx arch, @var{-extension} [,...,@var{-extension_n}]
+@itemx arch, @var{=ISA}
+Enables or disables the extensions for specific code region. For example,
+@samp{.option arch, +m2p0} means add m extension with version 2.0, and
+@samp{.option arch, -f, -d} means remove extensions, f and d, from the
+architecture string. Note that, @samp{.option arch, +c, -c} have the same
+behavior as @samp{.option rvc, norvc}. However, they are also undesirable
+sometimes. Besides, @samp{.option arch, -i} is illegal, since we cannot
+remove the base i extension anytime. If you want to reset the whole ISA
+string, you can also use @samp{.option arch, =rv32imac} to overwrite the
+previous settings.
+
@cindex INSN directives
@item .insn @var{type}, @var{operand} [,...,@var{operand_n}]
@itemx .insn @var{insn_length}, @var{value}
--- /dev/null
+.attribute arch, "rv64ic"
+add a0, a0, a1
+.option push
+.option arch, +d2p0, -c, +xvendor1p0
+add a0, a0, a1
+frcsr a0 # Should add mapping symbol with ISA here, and then dump it to frcsr.
+.option push
+.option arch, +i3p0, +m3p0, +d3p0
+.option pop
+.option pop
--- /dev/null
+#as:
+#source: option-arch-01.s
+#objdump: -d
+
+.*:[ ]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <.text>:
+[ ]+[0-9a-f]+:[ ]+952e[ ]+add[ ]+a0,a0,a1
+[ ]+[0-9a-f]+:[ ]+00b50533[ ]+add[ ]+a0,a0,a1
+[ ]+[0-9a-f]+:[ ]+00302573[ ]+csrr[ ]+a0,fcsr
+#...
--- /dev/null
+#as:
+#readelf: -A
+#source: option-arch-01.s
+
+Attribute Section: riscv
+File Attributes
+ Tag_RISCV_arch: "rv64i2p0_c2p0"
+#...
--- /dev/null
+#as:
+#readelf: -A
+#source: option-arch-02.s
+
+Attribute Section: riscv
+File Attributes
+ Tag_RISCV_arch: "rv64i3p0_m3p0_f2p0_d3p0_c2p0_xvendor32x3p0"
+#...
--- /dev/null
+.attribute arch, "rv64ic"
+add a0, a0, a1
+.option push
+.option arch, +d2p0, -c, +xvendor1p0
+add a0, a0, a1
+frcsr a0
+.option pop
+.option arch, +i3p0, +m3p0, +d3p0, +xvendor32x3p0
--- /dev/null
+#as:
+#readelf: -A
+#source: option-arch-03.s
+
+Attribute Section: riscv
+File Attributes
+ Tag_RISCV_arch: "rv32i2p0_c2p0"
+#...
--- /dev/null
+.attribute arch, "rv64ic"
+.option arch, +d2p0, -c
+.option arch, =rv32ic
--- /dev/null
+#as:
+#source: option-arch-fail.s
+#error_output: option-arch-fail.l
--- /dev/null
+.*Assembler messages:
+.*Error: extensions must begin with \+/\-/\= in .option arch `m2p0'
+.*Error: cannot remove extension `i' in .option arch `\-i'
+.*Error: unknown ISA extension `zsubset' in .option arch `\+zsubset2p0'
+.*Error: unknown ISA extension `f2p0_d' in .option arch `\+f2p0_d2p0'
+.*Error: unknown ISA extension `' in .option arch `\+'
+.*Error: invalid ISA extension ends with <number>p in .option arch `\+xvendor2p'
+.*Error: .option pop with no .option push
--- /dev/null
+.attribute arch, "rv64ic"
+.option push
+.option arch, m2p0
+.option arch, -i
+.option arch, +zsubset2p0
+.option arch, +f2p0_d2p0
+.option arch, +
+.option arch, +xvendor2p
+.option pop
+.option pop