[PATCH] gas: extend \+ support to .rept

Fangrui Song i@maskray.me
Wed May 29 05:21:01 GMT 2024


On Mon, May 27, 2024 at 4:51 AM Jan Beulich <jbeulich@suse.com> wrote:
>
> PR gas/31752
>
> While not quite as macro-like as .irp / .irpc, this perhaps benefits from
> supporting \+ even more than those: It allows, where desired, to get away
> without maintaining an explicit count variable in source code.
>
> Keep .rep (and custom per-arch uses of s_rept() / do_repeat()) behavior
> unaltered.
>
> --- a/gas/NEWS
> +++ b/gas/NEWS
> @@ -1,7 +1,7 @@
>  -*- text -*-
>
> -* Assembler macros as well as the bodies of .irp / .irpc can now use the
> -  syntax \+ to access the number of times a given macro has been executed.
> +* Assembler macros as well as the bodies of .irp / .irpc / .rept can now use
> +  the syntax \+ to access the number of times a given macro has been executed.
>    This is similar to the already existing \@ syntax, except that the count is
>    maintained on a per-macro basis.
>
> --- a/gas/doc/as.texi
> +++ b/gas/doc/as.texi
> @@ -6739,6 +6739,13 @@ is equivalent to assembling
>  A count of zero is allowed, but nothing is generated.  Negative counts are not
>  allowed and if encountered will be treated as if they were zero.
>
> +Much like for macros, @code{.irp}, and @code{.irpc} the @samp{\+} sequence can
> +be used to substitute in the number of iterations done so far.  In such cases,
> +i.e. when any @samp{\+} character sequence is present between @code{.rept} and
> +the corresponding @code{.endr}, other backslashes also need escaping by
> +backslashes.  Naturally the amount of escaping necessary may increase when
> +using nested constructs.
> +
>  @node Sbttl
>  @section @code{.sbttl "@var{subheading}"}
>
> --- a/gas/read.c
> +++ b/gas/read.c
> @@ -482,7 +482,7 @@ static const pseudo_typeS potable[] = {
>    {"quad", cons, 8},
>    {"reloc", s_reloc, 0},
>    {"rep", s_rept, 0},
> -  {"rept", s_rept, 0},
> +  {"rept", s_rept, 1},
>    {"rva", s_rva, 4},
>    {"sbttl", listing_title, 1}, /* Subtitle of listing.  */
>  /* scl  */
> @@ -3066,19 +3066,21 @@ s_bad_end (int endr)
>  /* Handle the .rept pseudo-op.  */
>
>  void
> -s_rept (int ignore ATTRIBUTE_UNUSED)
> +s_rept (int expand_count)
>  {
>    size_t count;
>
>    count = (size_t) get_absolute_expression ();
>
> -  do_repeat (count, "REPT", "ENDR", NULL);
> +  do_repeat (count, "REPT", "ENDR", expand_count ? "" : NULL);
>  }
>
>  /* This function provides a generic repeat block implementation.   It allows
>     different directives to be used as the start/end keys.  Any text matching
>     the optional EXPANDER in the block is replaced by the remaining iteration
> -   count.  */
> +   count.  Except when EXPANDER is the empty string, in which case \+ will
> +   be looked for (as also recognized in macros as well as .irp and .irpc),
> +   where the replacement will be the number of iterations done so far.  */
>
>  void
>  do_repeat (size_t count, const char *start, const char *end,
> @@ -3101,7 +3103,58 @@ do_repeat (size_t count, const char *sta
>        return;
>      }
>
> -  if (expander == NULL || strstr (one.ptr, expander) == NULL)
> +  if (expander != NULL && !*expander && strstr (one.ptr, "\\+") != NULL)
> +    {
> +      /* The 3 here and below are arbitrary, added in an attempt to limit
> +        re-allocation needs in sb_add_...() for moderate repeat counts.  */
> +      sb_build (&many, count * (one.len + 3));
> +
> +      for (size_t done = 0; count-- > 0; ++done)
> +       {
> +         const char *ptr, *bs;
> +         sb processed;
> +
> +         sb_build (&processed, one.len + 3);
> +
> +         for (ptr = one.ptr;
> +              (bs = memchr (ptr, '\\', one.ptr + one.len - ptr)) != NULL; )
> +           {
> +             sb_add_buffer (&processed, ptr, bs - ptr);
> +             switch (bs[1])
> +               {
> +                 char scratch[24];
> +
> +               default:
> +                 sb_add_char (&processed, '\\');
> +                 sb_add_char (&processed, bs[1]);
> +                 ptr = bs + 2;
> +                 break;
> +
> +               case '\0':
> +                 as_warn (_("`\\' at end of line/statement; ignored"));
> +                 ptr = bs + 1;
> +                 break;
> +
> +               case '\\':
> +                 sb_add_char (&processed, '\\');
> +                 ptr = bs + 2;
> +                 break;
> +
> +               case '+':
> +                 snprintf (scratch, ARRAY_SIZE (scratch), "%zu", done);
> +                 sb_add_string (&processed, scratch);
> +                 ptr = bs + 2;
> +                 break;
> +               }
> +           }
> +
> +         sb_add_buffer (&processed, ptr, one.ptr + one.len - ptr);
> +
> +         sb_add_sb (&many, &processed);
> +         sb_kill (&processed);
> +       }
> +    }
> +  else if (expander == NULL || !*expander || strstr (one.ptr, expander) == NULL)
>      {
>        sb_build (&many, count * one.len);
>        while (count-- > 0)
> --- a/gas/testsuite/gas/macros/macros.exp
> +++ b/gas/testsuite/gas/macros/macros.exp
> @@ -105,3 +105,4 @@ run_list_test altmacro
>  run_list_test count
>  run_list_test irp-count
>  run_list_test irpc-quote
> +run_list_test rept-count
> --- /dev/null
> +++ b/gas/testsuite/gas/macros/rept-count.l
> @@ -0,0 +1,15 @@
> +#...
> +>0<
> +>1<
> +>2<
> +>3<
> +>4<
> +>0<
> +>0:0<
> +>0:1<
> +>1<
> +>1:0<
> +>1:1<
> +>2<
> +>2:0<
> +>2:1<
> --- /dev/null
> +++ b/gas/testsuite/gas/macros/rept-count.s
> @@ -0,0 +1,10 @@
> +       .rept 5
> +       .print ">\+<"
> +       .endr

LGTM.

Perhaps this .print directive can be changed to print \+ \+
to show that the \+ expanded value is identical within one iteration.

> +
> +       .rept 3
> +       .print ">\+<"
> +       .rept 2
> +       .print ">\+:\\+<"
> +       .endr
> +       .endr


More information about the Binutils mailing list