[committed v3] RISC-V: Support new .option arch directive.

Palmer Dabbelt palmer@rivosinc.com
Fri Nov 19 16:01:59 GMT 2021


On Fri, 19 Nov 2021 02:53:53 PST (-0800), Nelson Chu wrote:
> 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.

Should that apply to E as well?  RV32E is as much of a base ISA as RV32I 
is, at least according to the specs, but this allows something like

   .attribute arch, "rv32e"
   .option arch, -e
   add x31, x31, x31

to turn E into I.

It does feel kind of nice to treat E as an extension here, as that would 
allow us to mix in short E-compatible code segments (to try and detect 
the base ISA, for example), but the ISA doesn't treat it that way so 
it's kind of odd to do so in the toolchain.

I'm not really sure I have a case where "-e" is any better than 
"=rv32e", though, so maybe it's better to just play it save and reject 
+/-e?

> 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.
> ---
>  bfd/elfxx-riscv.c                          | 158 ++++++++++++++++++++++++-----
>  bfd/elfxx-riscv.h                          |   5 +-
>  gas/config/tc-riscv.c                      |  57 +++++++----
>  gas/doc/c-riscv.texi                       |  15 ++-
>  gas/testsuite/gas/riscv/option-arch-01.s   |  10 ++
>  gas/testsuite/gas/riscv/option-arch-01a.d  |  14 +++
>  gas/testsuite/gas/riscv/option-arch-01b.d  |   8 ++
>  gas/testsuite/gas/riscv/option-arch-02.d   |   8 ++
>  gas/testsuite/gas/riscv/option-arch-02.s   |   8 ++
>  gas/testsuite/gas/riscv/option-arch-03.d   |   8 ++
>  gas/testsuite/gas/riscv/option-arch-03.s   |   3 +
>  gas/testsuite/gas/riscv/option-arch-fail.d |   3 +
>  gas/testsuite/gas/riscv/option-arch-fail.l |   8 ++
>  gas/testsuite/gas/riscv/option-arch-fail.s |  10 ++
>  14 files changed, 272 insertions(+), 43 deletions(-)
>  create mode 100644 gas/testsuite/gas/riscv/option-arch-01.s
>  create mode 100644 gas/testsuite/gas/riscv/option-arch-01a.d
>  create mode 100644 gas/testsuite/gas/riscv/option-arch-01b.d
>  create mode 100644 gas/testsuite/gas/riscv/option-arch-02.d
>  create mode 100644 gas/testsuite/gas/riscv/option-arch-02.s
>  create mode 100644 gas/testsuite/gas/riscv/option-arch-03.d
>  create mode 100644 gas/testsuite/gas/riscv/option-arch-03.s
>  create mode 100644 gas/testsuite/gas/riscv/option-arch-fail.d
>  create mode 100644 gas/testsuite/gas/riscv/option-arch-fail.l
>  create mode 100644 gas/testsuite/gas/riscv/option-arch-fail.s
>
> 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, &current))
> -    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 *);
> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> index 930cfb2..da3d911 100644
> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -235,16 +235,27 @@ riscv_set_rvc (bool rvc_value)
>     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
> @@ -257,7 +268,14 @@ riscv_set_arch (const char *s)
>        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);
> @@ -3715,15 +3733,6 @@ riscv_pre_output_hook (void)
>    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
> @@ -3738,12 +3747,12 @@ s_riscv_option (int x ATTRIBUTE_UNUSED)
>
>    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)
> @@ -3758,14 +3767,24 @@ s_riscv_option (int x ATTRIBUTE_UNUSED)
>      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)
>      {
> @@ -3776,8 +3795,12 @@ s_riscv_option (int x ATTRIBUTE_UNUSED)
>  	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);
>  	}
>      }
> @@ -4262,7 +4285,7 @@ riscv_write_out_attrs (void)
>    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);
>
> diff --git a/gas/doc/c-riscv.texi b/gas/doc/c-riscv.texi
> index bfbf61d..697be3a 100644
> --- a/gas/doc/c-riscv.texi
> +++ b/gas/doc/c-riscv.texi
> @@ -194,7 +194,7 @@ command-line options are respected for the bulk of the file being assembled.
>  @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
> @@ -212,6 +212,19 @@ desirable.
>  @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}
> diff --git a/gas/testsuite/gas/riscv/option-arch-01.s b/gas/testsuite/gas/riscv/option-arch-01.s
> new file mode 100644
> index 0000000..201f9b3
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/option-arch-01.s
> @@ -0,0 +1,10 @@
> +.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
> diff --git a/gas/testsuite/gas/riscv/option-arch-01a.d b/gas/testsuite/gas/riscv/option-arch-01a.d
> new file mode 100644
> index 0000000..59bc1d2
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/option-arch-01a.d
> @@ -0,0 +1,14 @@
> +#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
> +#...
> diff --git a/gas/testsuite/gas/riscv/option-arch-01b.d b/gas/testsuite/gas/riscv/option-arch-01b.d
> new file mode 100644
> index 0000000..9a6c2c5
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/option-arch-01b.d
> @@ -0,0 +1,8 @@
> +#as:
> +#readelf: -A
> +#source: option-arch-01.s
> +
> +Attribute Section: riscv
> +File Attributes
> +  Tag_RISCV_arch: "rv64i2p0_c2p0"
> +#...
> diff --git a/gas/testsuite/gas/riscv/option-arch-02.d b/gas/testsuite/gas/riscv/option-arch-02.d
> new file mode 100644
> index 0000000..0fe89ec
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/option-arch-02.d
> @@ -0,0 +1,8 @@
> +#as:
> +#readelf: -A
> +#source: option-arch-02.s
> +
> +Attribute Section: riscv
> +File Attributes
> +  Tag_RISCV_arch: "rv64i3p0_m3p0_f2p0_d3p0_c2p0_xvendor32x3p0"
> +#...
> diff --git a/gas/testsuite/gas/riscv/option-arch-02.s b/gas/testsuite/gas/riscv/option-arch-02.s
> new file mode 100644
> index 0000000..f4ceee84
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/option-arch-02.s
> @@ -0,0 +1,8 @@
> +.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
> diff --git a/gas/testsuite/gas/riscv/option-arch-03.d b/gas/testsuite/gas/riscv/option-arch-03.d
> new file mode 100644
> index 0000000..b621d03
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/option-arch-03.d
> @@ -0,0 +1,8 @@
> +#as:
> +#readelf: -A
> +#source: option-arch-03.s
> +
> +Attribute Section: riscv
> +File Attributes
> +  Tag_RISCV_arch: "rv32i2p0_c2p0"
> +#...
> diff --git a/gas/testsuite/gas/riscv/option-arch-03.s b/gas/testsuite/gas/riscv/option-arch-03.s
> new file mode 100644
> index 0000000..7183140
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/option-arch-03.s
> @@ -0,0 +1,3 @@
> +.attribute arch, "rv64ic"
> +.option arch, +d2p0, -c
> +.option arch, =rv32ic
> diff --git a/gas/testsuite/gas/riscv/option-arch-fail.d b/gas/testsuite/gas/riscv/option-arch-fail.d
> new file mode 100644
> index 0000000..bce5d32
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/option-arch-fail.d
> @@ -0,0 +1,3 @@
> +#as:
> +#source: option-arch-fail.s
> +#error_output: option-arch-fail.l
> diff --git a/gas/testsuite/gas/riscv/option-arch-fail.l b/gas/testsuite/gas/riscv/option-arch-fail.l
> new file mode 100644
> index 0000000..3e0599e
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/option-arch-fail.l
> @@ -0,0 +1,8 @@
> +.*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
> diff --git a/gas/testsuite/gas/riscv/option-arch-fail.s b/gas/testsuite/gas/riscv/option-arch-fail.s
> new file mode 100644
> index 0000000..a0b1bde
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/option-arch-fail.s
> @@ -0,0 +1,10 @@
> +.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


More information about the Binutils mailing list