[v2,3/4] PR 34029: bpf: add %dR/%sR register format specifiers

Message ID 20260331204212.3992270-4-vineet.gupta@linux.dev
State New
Headers
Series bpf gas updates |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed

Commit Message

Vineet Gupta March 31, 2026, 8:42 p.m. UTC
  These accept either r or w prefix registers during assembly
(pseudoc dialect), while disassembling canonically as r registers.

This eliminates the need for duplicate opcode table entries for
instructions that accept both w and r register forms.

Signed-off-by: Vineet Gupta <vineet.gupta@linux.dev>
---
 gas/config/tc-bpf.c  | 16 ++++++++++++----
 include/opcode/bpf.h |  4 +++-
 opcodes/bpf-dis.c    |  6 ++++--
 3 files changed, 19 insertions(+), 7 deletions(-)
  

Comments

Jose E. Marchesi April 2, 2026, 10:58 a.m. UTC | #1
Hi Vineet.

> These accept either r or w prefix registers during assembly
> (pseudoc dialect), while disassembling canonically as r registers.
>
> This eliminates the need for duplicate opcode table entries for
> instructions that accept both w and r register forms.

Nicely done.  Thank you for the patch.

I suppose this will be tested when the corresponding load/store
instructions get updated and their respective new tests.

OK.

>
> Signed-off-by: Vineet Gupta <vineet.gupta@linux.dev>
> ---
>  gas/config/tc-bpf.c  | 16 ++++++++++++----
>  include/opcode/bpf.h |  4 +++-
>  opcodes/bpf-dis.c    |  6 ++++--
>  3 files changed, 19 insertions(+), 7 deletions(-)
>
> diff --git a/gas/config/tc-bpf.c b/gas/config/tc-bpf.c
> index ecb6c5a70535..8d48b128fb90 100644
> --- a/gas/config/tc-bpf.c
> +++ b/gas/config/tc-bpf.c
> @@ -1525,12 +1525,16 @@ md_assemble (char *str ATTRIBUTE_UNUSED)
>                    p += 2;
>                  }
>                else if (strncmp (p, "%dr", 3) == 0
> -                       || strncmp (p, "%dw", 3) == 0)
> +                       || strncmp (p, "%dw", 3) == 0
> +                       || strncmp (p, "%dR", 3) == 0)
>                  {
>                    char rw = *(p + 2);
>                    uint8_t regno;
> -                  char *news = parse_bpf_register (s, rw, &regno);
> +                  char *news = parse_bpf_register (s, rw == 'R' ? 'r' : rw,
> +                                                   &regno);
>  
> +                  if (rw == 'R' && news == NULL)
> +                    news = parse_bpf_register (s, 'w', &regno);
>                    if (news == NULL || (insn.has_dst && regno != insn.dst))
>                      {
>                        if (news != NULL)
> @@ -1546,12 +1550,16 @@ md_assemble (char *str ATTRIBUTE_UNUSED)
>                    p += 3;
>                  }
>                else if (strncmp (p, "%sr", 3) == 0
> -                       || strncmp (p, "%sw", 3) == 0)
> +                       || strncmp (p, "%sw", 3) == 0
> +                       || strncmp (p, "%sR", 3) == 0)
>                  {
>                    char rw = *(p + 2);
>                    uint8_t regno;
> -                  char *news = parse_bpf_register (s, rw, &regno);
> +                  char *news = parse_bpf_register (s, rw == 'R' ? 'r' : rw,
> +                                                   &regno);
>  
> +                  if (rw == 'R' && news == NULL)
> +                    news = parse_bpf_register (s, 'w', &regno);
>                    if (news == NULL || (insn.has_src && regno != insn.src))
>                      {
>                        if (news != NULL)
> diff --git a/include/opcode/bpf.h b/include/opcode/bpf.h
> index e4ccd430f0ce..e17ca2fdd2c1 100644
> --- a/include/opcode/bpf.h
> +++ b/include/opcode/bpf.h
> @@ -252,8 +252,10 @@ struct bpf_opcode
>       %% - literal %.
>       %dr - destination 64-bit register.
>       %dw - destination 32-bit register.
> +     %dR - destination register, either r or w prefix accepted.
>       %sr - source 64-bit register.
>       %sw - source 32-bit register.
> +     %sR - source register, either r or w prefix accepted.
>       %d32 - 32-bit signed displacement (in 64-bit words minus one.)
>       %d16 - 16-bit signed displacement (in 64-bit words minus one.)
>       %o16 - 16-bit signed offset (in bytes.)
> @@ -268,7 +270,7 @@ struct bpf_opcode
>       denote something like `[%r3 + 10]', please use a template like `[
>       %sr %o16]' instead of `[ %sr + %o16 ]'.
>       
> -     If %dr, %dw, %sr or %sw are found multiple times in a template,
> +     If %dr, %dw, %dR, %sr, %sw or %sR are found multiple times in a template,
>       they refer to the same register, i.e. `%rd = le64 %rd' denotes
>       `r2 = le64 r2', but not `r2 = le64 r1'.
>  
> diff --git a/opcodes/bpf-dis.c b/opcodes/bpf-dis.c
> index de8d417dcd38..07aacb621a3b 100644
> --- a/opcodes/bpf-dis.c
> +++ b/opcodes/bpf-dis.c
> @@ -215,13 +215,15 @@ print_insn_bpf (bfd_vma pc, disassemble_info *info)
>                    p += 2;
>                  }
>                else if (strncmp (p, "%dr", 3) == 0
> -                       || strncmp (p, "%dw", 3) == 0)
> +                       || strncmp (p, "%dw", 3) == 0
> +                       || strncmp (p, "%dR", 3) == 0)
>                  {
>                    print_register (info, p, bpf_extract_dst (word, endian));
>                    p += 3;
>                  }
>                else if (strncmp (p, "%sr", 3) == 0
> -                       || strncmp (p, "%sw", 3) == 0)
> +                       || strncmp (p, "%sw", 3) == 0
> +                       || strncmp (p, "%sR", 3) == 0)
>                  {
>                    print_register (info, p, bpf_extract_src (word, endian));
>                    p += 3;
  
Vineet Gupta April 2, 2026, 3:45 p.m. UTC | #2
On 4/2/26 3:58 AM, Jose E. Marchesi wrote:
> Hi Vineet.
>
>> These accept either r or w prefix registers during assembly
>> (pseudoc dialect), while disassembling canonically as r registers.
>>
>> This eliminates the need for duplicate opcode table entries for
>> instructions that accept both w and r register forms.
> Nicely done.  Thank you for the patch.

Thx for the quick review.


> I suppose this will be tested when the corresponding load/store
> instructions get updated and their respective new tests.

We decided to not update gcc to generate the new forms [1]
But nonetheless since llvm supports these forms and user can technically 
specify them in asm/inline-asm, hence the patch.


> OK.

I haven' pushed to sourceware in a while, can you commit them whenever 
you get a chance please !

Thx,
-Vineet

[1] https://gcc.gnu.org/pipermail/bpf/2026-March/000085.html
  
Jose E. Marchesi April 2, 2026, 4:35 p.m. UTC | #3
> On 4/2/26 3:58 AM, Jose E. Marchesi wrote:
>> Hi Vineet.
>>
>>> These accept either r or w prefix registers during assembly
>>> (pseudoc dialect), while disassembling canonically as r registers.
>>>
>>> This eliminates the need for duplicate opcode table entries for
>>> instructions that accept both w and r register forms.
>> Nicely done.  Thank you for the patch.
>
> Thx for the quick review.
>
>
>> I suppose this will be tested when the corresponding load/store
>> instructions get updated and their respective new tests.
>
> We decided to not update gcc to generate the new forms [1]
> But nonetheless since llvm supports these forms and user can
> technically specify them in asm/inline-asm, hence the patch.

I was referring to tests in GAS.  Then I saw these were added in the
commit that adds the new entries in the opcodes table.

>
>> OK.
>
> I haven' pushed to sourceware in a while, can you commit them whenever
> you get a chance please !

Just pushed the series on your behalf.
Thanks.

>
> Thx,
> -Vineet
>
> [1] https://gcc.gnu.org/pipermail/bpf/2026-March/000085.html
  

Patch

diff --git a/gas/config/tc-bpf.c b/gas/config/tc-bpf.c
index ecb6c5a70535..8d48b128fb90 100644
--- a/gas/config/tc-bpf.c
+++ b/gas/config/tc-bpf.c
@@ -1525,12 +1525,16 @@  md_assemble (char *str ATTRIBUTE_UNUSED)
                   p += 2;
                 }
               else if (strncmp (p, "%dr", 3) == 0
-                       || strncmp (p, "%dw", 3) == 0)
+                       || strncmp (p, "%dw", 3) == 0
+                       || strncmp (p, "%dR", 3) == 0)
                 {
                   char rw = *(p + 2);
                   uint8_t regno;
-                  char *news = parse_bpf_register (s, rw, &regno);
+                  char *news = parse_bpf_register (s, rw == 'R' ? 'r' : rw,
+                                                   &regno);
 
+                  if (rw == 'R' && news == NULL)
+                    news = parse_bpf_register (s, 'w', &regno);
                   if (news == NULL || (insn.has_dst && regno != insn.dst))
                     {
                       if (news != NULL)
@@ -1546,12 +1550,16 @@  md_assemble (char *str ATTRIBUTE_UNUSED)
                   p += 3;
                 }
               else if (strncmp (p, "%sr", 3) == 0
-                       || strncmp (p, "%sw", 3) == 0)
+                       || strncmp (p, "%sw", 3) == 0
+                       || strncmp (p, "%sR", 3) == 0)
                 {
                   char rw = *(p + 2);
                   uint8_t regno;
-                  char *news = parse_bpf_register (s, rw, &regno);
+                  char *news = parse_bpf_register (s, rw == 'R' ? 'r' : rw,
+                                                   &regno);
 
+                  if (rw == 'R' && news == NULL)
+                    news = parse_bpf_register (s, 'w', &regno);
                   if (news == NULL || (insn.has_src && regno != insn.src))
                     {
                       if (news != NULL)
diff --git a/include/opcode/bpf.h b/include/opcode/bpf.h
index e4ccd430f0ce..e17ca2fdd2c1 100644
--- a/include/opcode/bpf.h
+++ b/include/opcode/bpf.h
@@ -252,8 +252,10 @@  struct bpf_opcode
      %% - literal %.
      %dr - destination 64-bit register.
      %dw - destination 32-bit register.
+     %dR - destination register, either r or w prefix accepted.
      %sr - source 64-bit register.
      %sw - source 32-bit register.
+     %sR - source register, either r or w prefix accepted.
      %d32 - 32-bit signed displacement (in 64-bit words minus one.)
      %d16 - 16-bit signed displacement (in 64-bit words minus one.)
      %o16 - 16-bit signed offset (in bytes.)
@@ -268,7 +270,7 @@  struct bpf_opcode
      denote something like `[%r3 + 10]', please use a template like `[
      %sr %o16]' instead of `[ %sr + %o16 ]'.
      
-     If %dr, %dw, %sr or %sw are found multiple times in a template,
+     If %dr, %dw, %dR, %sr, %sw or %sR are found multiple times in a template,
      they refer to the same register, i.e. `%rd = le64 %rd' denotes
      `r2 = le64 r2', but not `r2 = le64 r1'.
 
diff --git a/opcodes/bpf-dis.c b/opcodes/bpf-dis.c
index de8d417dcd38..07aacb621a3b 100644
--- a/opcodes/bpf-dis.c
+++ b/opcodes/bpf-dis.c
@@ -215,13 +215,15 @@  print_insn_bpf (bfd_vma pc, disassemble_info *info)
                   p += 2;
                 }
               else if (strncmp (p, "%dr", 3) == 0
-                       || strncmp (p, "%dw", 3) == 0)
+                       || strncmp (p, "%dw", 3) == 0
+                       || strncmp (p, "%dR", 3) == 0)
                 {
                   print_register (info, p, bpf_extract_dst (word, endian));
                   p += 3;
                 }
               else if (strncmp (p, "%sr", 3) == 0
-                       || strncmp (p, "%sw", 3) == 0)
+                       || strncmp (p, "%sw", 3) == 0
+                       || strncmp (p, "%sR", 3) == 0)
                 {
                   print_register (info, p, bpf_extract_src (word, endian));
                   p += 3;