[v6,02/15] RISC-V: Add support for the Zvbc extension

Message ID 20230701052104.4018352-3-christoph.muellner@vrull.eu
State Accepted
Headers
Series RISC-V: Add support for vector crypto extensions |

Checks

Context Check Description
snail/binutils-gdb-check success Github commit url

Commit Message

Christoph Müllner July 1, 2023, 5:20 a.m. UTC
  From: Nathan Huckleberry via Binutils <binutils@sourceware.org>

Zvbc is part of the crypto vector extensions.

This extension adds the following instructions:
- vclmul.[vv,vx]
- vclmulh.[vv,vx]

bfd/ChangeLog:

	* elfxx-riscv.c (riscv_multi_subset_supports): Add instruction
	class support for Zvbc.
	(riscv_multi_subset_supports_ext): Likewise.

gas/ChangeLog:

	* testsuite/gas/riscv/zvbc.d: New test.
	* testsuite/gas/riscv/zvbc.s: New test.

include/ChangeLog:

	* opcode/riscv-opc.h (MATCH_VCLMUL_VV): New.
	(MASK_VCLMUL_VV): New.
	(MATCH_VCLMUL_VX): New.
	(MASK_VCLMUL_VX): New.
	(MATCH_VCLMULH_VV): New.
	(MASK_VCLMULH_VV): New.
	(MATCH_VCLMULH_VX): New.
	(MASK_VCLMULH_VX): New.
	(DECLARE_INSN): New.
	* opcode/riscv.h (enum riscv_insn_class): Add instruction class
	  support for Zvbc.

opcodes/ChangeLog:

	* riscv-opc.c: Add Zvbc instruction.

Signed-off-by: Nathan Huckleberry <nhuck@google.com>
Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 bfd/elfxx-riscv.c              |  5 +++++
 gas/testsuite/gas/riscv/zvbc.d | 16 ++++++++++++++++
 gas/testsuite/gas/riscv/zvbc.s |  8 ++++++++
 include/opcode/riscv-opc.h     | 14 ++++++++++++++
 include/opcode/riscv.h         |  1 +
 opcodes/riscv-opc.c            |  6 ++++++
 6 files changed, 50 insertions(+)
 create mode 100644 gas/testsuite/gas/riscv/zvbc.d
 create mode 100644 gas/testsuite/gas/riscv/zvbc.s
  

Comments

Jan Beulich July 17, 2023, 7:02 a.m. UTC | #1
On 01.07.2023 07:20, Christoph Muellner wrote:
> --- a/opcodes/riscv-opc.c
> +++ b/opcodes/riscv-opc.c
> @@ -1902,6 +1902,12 @@ const struct riscv_opcode riscv_opcodes[] =
>  {"vwsll.vx",    0, INSN_CLASS_ZVBB, "Vd,Vt,sVm", MATCH_VWSLL_VX, MASK_VWSLL_VX, match_opcode, 0},
>  {"vwsll.vi",    0, INSN_CLASS_ZVBB, "Vd,Vt,VjVm", MATCH_VWSLL_VI, MASK_VWSLL_VI, match_opcode, 0},
>  
> +/* Zvbc instructions.  */
> +{"vclmul.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMUL_VV, MASK_VCLMUL_VV, match_opcode, 0},
> +{"vclmul.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMUL_VX, MASK_VCLMUL_VX, match_opcode, 0},

I realize this is more a spec question than an implementation one, but
implementation might be affected by the answer to the question: What
exactly are this and ...

> +{"vclmulh.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMULH_VV, MASK_VCLMULH_VV, match_opcode, 0},
> +{"vclmulh.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMULH_VX, MASK_VCLMULH_VX, match_opcode, 0},

... this insn doing in RV32 mode? There are no 64 bits to take from
the GPR, yet that's what the doc presently says. Is the value coming
from a pair of GPRs, or is it sign- or zero-extended? Or is this an
RV64-only insn? (Note how the doc explicitly describes the behavior
for vandn's scalar-source form; the only thing left to be implied
there is that truncation / sign-extension are to - I assume - element
size, but maybe that's said somewhere in more general terms.)

As a nit: The two vclmulh lines have one too many blanks, resulting
in columns to not be aligned.

Jan
  
Philipp Tomsich July 17, 2023, 7:11 a.m. UTC | #2
On Mon, 17 Jul 2023 at 09:02, Jan Beulich <jbeulich@suse.com> wrote:
>
> On 01.07.2023 07:20, Christoph Muellner wrote:
> > --- a/opcodes/riscv-opc.c
> > +++ b/opcodes/riscv-opc.c
> > @@ -1902,6 +1902,12 @@ const struct riscv_opcode riscv_opcodes[] =
> >  {"vwsll.vx",    0, INSN_CLASS_ZVBB, "Vd,Vt,sVm", MATCH_VWSLL_VX, MASK_VWSLL_VX, match_opcode, 0},
> >  {"vwsll.vi",    0, INSN_CLASS_ZVBB, "Vd,Vt,VjVm", MATCH_VWSLL_VI, MASK_VWSLL_VI, match_opcode, 0},
> >
> > +/* Zvbc instructions.  */
> > +{"vclmul.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMUL_VV, MASK_VCLMUL_VV, match_opcode, 0},
> > +{"vclmul.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMUL_VX, MASK_VCLMUL_VX, match_opcode, 0},
>
> I realize this is more a spec question than an implementation one, but
> implementation might be affected by the answer to the question: What
> exactly are this and ...
>
> > +{"vclmulh.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMULH_VV, MASK_VCLMULH_VV, match_opcode, 0},
> > +{"vclmulh.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMULH_VX, MASK_VCLMULH_VX, match_opcode, 0},
>
> ... this insn doing in RV32 mode? There are no 64 bits to take from
> the GPR, yet that's what the doc presently says. Is the value coming
> from a pair of GPRs, or is it sign- or zero-extended? Or is this an
> RV64-only insn? (Note how the doc explicitly describes the behavior
> for vandn's scalar-source form; the only thing left to be implied
> there is that truncation / sign-extension are to - I assume - element
> size, but maybe that's said somewhere in more general terms.


According to the pull-request for the SAIL model (which will in the
future be auto-generated into the specification documents and often
clarifies on parts of the specification where the English text is
ambiguous or imprecise), these are defined for RV64 only:
>
> +mapping clause encdec = RISCV_VCLMULH_VV(vm, vs1, vs2, vd) if (haveRVV() & haveZvbc() & sizeof(xlen) == 64)
> + <-> 0b001101 @ vm @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111    if (haveRVV() & haveZvbc() & sizeof(xlen) == 64)

Consequently, these should only be allowed for RV64.
Thanks for catching this!

Philipp.

>
> As a nit: The two vclmulh lines have one too many blanks, resulting
> in columns to not be aligned.
>
> Jan
  
Christoph Müllner July 17, 2023, 7:20 a.m. UTC | #3
+Ken Dockser
+Nicolas Brunie

I've added Ken and Nicolas (spec authors) to give an authoritative answer, and
because this looks like a valid public-review comment for the specification.

The spec indeed mentions "the 64-bit value from integer register rs1
(vector-scalar)",
which is unclear for RV32.

BR
Christoph

On Mon, Jul 17, 2023 at 9:02 AM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 01.07.2023 07:20, Christoph Muellner wrote:
> > --- a/opcodes/riscv-opc.c
> > +++ b/opcodes/riscv-opc.c
> > @@ -1902,6 +1902,12 @@ const struct riscv_opcode riscv_opcodes[] =
> >  {"vwsll.vx",    0, INSN_CLASS_ZVBB, "Vd,Vt,sVm", MATCH_VWSLL_VX, MASK_VWSLL_VX, match_opcode, 0},
> >  {"vwsll.vi",    0, INSN_CLASS_ZVBB, "Vd,Vt,VjVm", MATCH_VWSLL_VI, MASK_VWSLL_VI, match_opcode, 0},
> >
> > +/* Zvbc instructions.  */
> > +{"vclmul.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMUL_VV, MASK_VCLMUL_VV, match_opcode, 0},
> > +{"vclmul.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMUL_VX, MASK_VCLMUL_VX, match_opcode, 0},
>
> I realize this is more a spec question than an implementation one, but
> implementation might be affected by the answer to the question: What
> exactly are this and ...
>
> > +{"vclmulh.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMULH_VV, MASK_VCLMULH_VV, match_opcode, 0},
> > +{"vclmulh.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMULH_VX, MASK_VCLMULH_VX, match_opcode, 0},
>
> ... this insn doing in RV32 mode? There are no 64 bits to take from
> the GPR, yet that's what the doc presently says. Is the value coming
> from a pair of GPRs, or is it sign- or zero-extended? Or is this an
> RV64-only insn? (Note how the doc explicitly describes the behavior
> for vandn's scalar-source form; the only thing left to be implied
> there is that truncation / sign-extension are to - I assume - element
> size, but maybe that's said somewhere in more general terms.)
>
> As a nit: The two vclmulh lines have one too many blanks, resulting
> in columns to not be aligned.
>
> Jan
  
Jan Beulich July 17, 2023, 7:26 a.m. UTC | #4
On 17.07.2023 09:11, Philipp Tomsich wrote:
> On Mon, 17 Jul 2023 at 09:02, Jan Beulich <jbeulich@suse.com> wrote:
>>
>> On 01.07.2023 07:20, Christoph Muellner wrote:
>>> --- a/opcodes/riscv-opc.c
>>> +++ b/opcodes/riscv-opc.c
>>> @@ -1902,6 +1902,12 @@ const struct riscv_opcode riscv_opcodes[] =
>>>  {"vwsll.vx",    0, INSN_CLASS_ZVBB, "Vd,Vt,sVm", MATCH_VWSLL_VX, MASK_VWSLL_VX, match_opcode, 0},
>>>  {"vwsll.vi",    0, INSN_CLASS_ZVBB, "Vd,Vt,VjVm", MATCH_VWSLL_VI, MASK_VWSLL_VI, match_opcode, 0},
>>>
>>> +/* Zvbc instructions.  */
>>> +{"vclmul.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMUL_VV, MASK_VCLMUL_VV, match_opcode, 0},
>>> +{"vclmul.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMUL_VX, MASK_VCLMUL_VX, match_opcode, 0},
>>
>> I realize this is more a spec question than an implementation one, but
>> implementation might be affected by the answer to the question: What
>> exactly are this and ...
>>
>>> +{"vclmulh.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMULH_VV, MASK_VCLMULH_VV, match_opcode, 0},
>>> +{"vclmulh.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMULH_VX, MASK_VCLMULH_VX, match_opcode, 0},
>>
>> ... this insn doing in RV32 mode? There are no 64 bits to take from
>> the GPR, yet that's what the doc presently says. Is the value coming
>> from a pair of GPRs, or is it sign- or zero-extended? Or is this an
>> RV64-only insn? (Note how the doc explicitly describes the behavior
>> for vandn's scalar-source form; the only thing left to be implied
>> there is that truncation / sign-extension are to - I assume - element
>> size, but maybe that's said somewhere in more general terms.
> 
> 
> According to the pull-request for the SAIL model (which will in the
> future be auto-generated into the specification documents and often
> clarifies on parts of the specification where the English text is
> ambiguous or imprecise), these are defined for RV64 only:
>>
>> +mapping clause encdec = RISCV_VCLMULH_VV(vm, vs1, vs2, vd) if (haveRVV() & haveZvbc() & sizeof(xlen) == 64)
>> + <-> 0b001101 @ vm @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111    if (haveRVV() & haveZvbc() & sizeof(xlen) == 64)
> 
> Consequently, these should only be allowed for RV64.

Oh, even the .vv insn is RV64 only (I had asked about the .vx one)? Plus
then why not sizeof(xlen) >= 64?

Jan
  
Philipp Tomsich July 17, 2023, 7:28 a.m. UTC | #5
Same on the .vv:
>
> +mapping clause encdec = RISCV_VCLMULH_VV(vm, vs1, vs2, vd) if (haveRVV() & have Zvbc() & sizeof(xlen) == 64)
+ <-> 0b001101 @ vm @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111    if
(haveRVV() & have Zvbc() & sizeof(xlen) == 64)


On Mon, 17 Jul 2023 at 09:26, Jan Beulich <jbeulich@suse.com> wrote:
>
> On 17.07.2023 09:11, Philipp Tomsich wrote:
> > On Mon, 17 Jul 2023 at 09:02, Jan Beulich <jbeulich@suse.com> wrote:
> >>
> >> On 01.07.2023 07:20, Christoph Muellner wrote:
> >>> --- a/opcodes/riscv-opc.c
> >>> +++ b/opcodes/riscv-opc.c
> >>> @@ -1902,6 +1902,12 @@ const struct riscv_opcode riscv_opcodes[] =
> >>>  {"vwsll.vx",    0, INSN_CLASS_ZVBB, "Vd,Vt,sVm", MATCH_VWSLL_VX, MASK_VWSLL_VX, match_opcode, 0},
> >>>  {"vwsll.vi",    0, INSN_CLASS_ZVBB, "Vd,Vt,VjVm", MATCH_VWSLL_VI, MASK_VWSLL_VI, match_opcode, 0},
> >>>
> >>> +/* Zvbc instructions.  */
> >>> +{"vclmul.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMUL_VV, MASK_VCLMUL_VV, match_opcode, 0},
> >>> +{"vclmul.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMUL_VX, MASK_VCLMUL_VX, match_opcode, 0},
> >>
> >> I realize this is more a spec question than an implementation one, but
> >> implementation might be affected by the answer to the question: What
> >> exactly are this and ...
> >>
> >>> +{"vclmulh.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMULH_VV, MASK_VCLMULH_VV, match_opcode, 0},
> >>> +{"vclmulh.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMULH_VX, MASK_VCLMULH_VX, match_opcode, 0},
> >>
> >> ... this insn doing in RV32 mode? There are no 64 bits to take from
> >> the GPR, yet that's what the doc presently says. Is the value coming
> >> from a pair of GPRs, or is it sign- or zero-extended? Or is this an
> >> RV64-only insn? (Note how the doc explicitly describes the behavior
> >> for vandn's scalar-source form; the only thing left to be implied
> >> there is that truncation / sign-extension are to - I assume - element
> >> size, but maybe that's said somewhere in more general terms.
> >
> >
> > According to the pull-request for the SAIL model (which will in the
> > future be auto-generated into the specification documents and often
> > clarifies on parts of the specification where the English text is
> > ambiguous or imprecise), these are defined for RV64 only:
> >>
> >> +mapping clause encdec = RISCV_VCLMULH_VV(vm, vs1, vs2, vd) if (haveRVV() & haveZvbc() & sizeof(xlen) == 64)
> >> + <-> 0b001101 @ vm @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111    if (haveRVV() & haveZvbc() & sizeof(xlen) == 64)
> >
> > Consequently, these should only be allowed for RV64.
>
> Oh, even the .vv insn is RV64 only (I had asked about the .vx one)? Plus
> then why not sizeof(xlen) >= 64?
>
> Jan
  
Ken Dockser July 24, 2023, 9:12 p.m. UTC | #6
Hi,

This instruction is supported in RV32. The answer is in the pseudo code:

let op1 : bits (64) = if suffix =="vv" then get_velem(vs1,i)
                      else zext_or_truncate_to_sew(X(vs1));

The xv form of the instruction reads X(vs2) and zero-extends it to SEW=64.
When you need something other than 0s in the upper 32 bits of the vs1
operand, the vx form will not be very useful in RV32. However, the vv form
will continue to operate.


It looks like the SAIL code needs to be updated to match the spec.


Thanks,

Ken

On Mon, Jul 17, 2023 at 2:20 AM Christoph Müllner <
christoph.muellner@vrull.eu> wrote:

> +Ken Dockser
> +Nicolas Brunie
>
> I've added Ken and Nicolas (spec authors) to give an authoritative answer,
> and
> because this looks like a valid public-review comment for the
> specification.
>
> The spec indeed mentions "the 64-bit value from integer register rs1
> (vector-scalar)",
> which is unclear for RV32.
>
> BR
> Christoph
>
> On Mon, Jul 17, 2023 at 9:02 AM Jan Beulich <jbeulich@suse.com> wrote:
> >
> > On 01.07.2023 07:20, Christoph Muellner wrote:
> > > --- a/opcodes/riscv-opc.c
> > > +++ b/opcodes/riscv-opc.c
> > > @@ -1902,6 +1902,12 @@ const struct riscv_opcode riscv_opcodes[] =
> > >  {"vwsll.vx",    0, INSN_CLASS_ZVBB, "Vd,Vt,sVm", MATCH_VWSLL_VX,
> MASK_VWSLL_VX, match_opcode, 0},
> > >  {"vwsll.vi",    0, INSN_CLASS_ZVBB, "Vd,Vt,VjVm", MATCH_VWSLL_VI,
> MASK_VWSLL_VI, match_opcode, 0},
> > >
> > > +/* Zvbc instructions.  */
> > > +{"vclmul.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMUL_VV,
> MASK_VCLMUL_VV, match_opcode, 0},
> > > +{"vclmul.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMUL_VX,
> MASK_VCLMUL_VX, match_opcode, 0},
> >
> > I realize this is more a spec question than an implementation one, but
> > implementation might be affected by the answer to the question: What
> > exactly are this and ...
> >
> > > +{"vclmulh.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMULH_VV,
> MASK_VCLMULH_VV, match_opcode, 0},
> > > +{"vclmulh.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMULH_VX,
> MASK_VCLMULH_VX, match_opcode, 0},
> >
> > ... this insn doing in RV32 mode? There are no 64 bits to take from
> > the GPR, yet that's what the doc presently says. Is the value coming
> > from a pair of GPRs, or is it sign- or zero-extended? Or is this an
> > RV64-only insn? (Note how the doc explicitly describes the behavior
> > for vandn's scalar-source form; the only thing left to be implied
> > there is that truncation / sign-extension are to - I assume - element
> > size, but maybe that's said somewhere in more general terms.)
> >
> > As a nit: The two vclmulh lines have one too many blanks, resulting
> > in columns to not be aligned.
> >
> > Jan
>
  

Patch

diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 21a4dc8ae8b..295e0d2c942 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -1263,6 +1263,7 @@  static struct riscv_supported_ext riscv_supported_std_z_ext[] =
   {"zve64f",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
   {"zve64d",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
   {"zvbb",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
+  {"zvbc",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
   {"zvl32b",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
   {"zvl64b",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
   {"zvl128b",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
@@ -2430,6 +2431,8 @@  riscv_multi_subset_supports (riscv_parse_subset_t *rps,
 	      || riscv_subset_supports (rps, "zve32f"));
     case INSN_CLASS_ZVBB:
       return riscv_subset_supports (rps, "zvbb");
+    case INSN_CLASS_ZVBC:
+      return riscv_subset_supports (rps, "zvbc");
     case INSN_CLASS_SVINVAL:
       return riscv_subset_supports (rps, "svinval");
     case INSN_CLASS_H:
@@ -2620,6 +2623,8 @@  riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
       return _("v' or `zve64d' or `zve64f' or `zve32f");
     case INSN_CLASS_ZVBB:
       return _("zvbb");
+    case INSN_CLASS_ZVBC:
+      return _("zvbc");
     case INSN_CLASS_SVINVAL:
       return "svinval";
     case INSN_CLASS_H:
diff --git a/gas/testsuite/gas/riscv/zvbc.d b/gas/testsuite/gas/riscv/zvbc.d
new file mode 100644
index 00000000000..d9213b25b01
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zvbc.d
@@ -0,0 +1,16 @@ 
+#as: -march=rv64gc_zvbc
+#objdump: -dr
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+0+000 <.text>:
+[ 	]+[0-9a-f]+:[ 	]+32862257[ 	]+vclmul.vv[ 	]+v4,v8,v12
+[ 	]+[0-9a-f]+:[ 	]+30862257[ 	]+vclmul.vv[ 	]+v4,v8,v12,v0.t
+[ 	]+[0-9a-f]+:[ 	]+3285e257[ 	]+vclmul.vx[ 	]+v4,v8,a1
+[ 	]+[0-9a-f]+:[ 	]+3085e257[ 	]+vclmul.vx[ 	]+v4,v8,a1,v0.t
+[ 	]+[0-9a-f]+:[ 	]+36862257[ 	]+vclmulh.vv[ 	]+v4,v8,v12
+[ 	]+[0-9a-f]+:[ 	]+34862257[ 	]+vclmulh.vv[ 	]+v4,v8,v12,v0.t
+[ 	]+[0-9a-f]+:[ 	]+3685e257[ 	]+vclmulh.vx[ 	]+v4,v8,a1
+[ 	]+[0-9a-f]+:[ 	]+3485e257[ 	]+vclmulh.vx[ 	]+v4,v8,a1,v0.t
diff --git a/gas/testsuite/gas/riscv/zvbc.s b/gas/testsuite/gas/riscv/zvbc.s
new file mode 100644
index 00000000000..c302d1eb011
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zvbc.s
@@ -0,0 +1,8 @@ 
+	vclmul.vv v4, v8, v12
+	vclmul.vv v4, v8, v12, v0.t
+	vclmul.vx v4, v8, a1
+	vclmul.vx v4, v8, a1, v0.t
+	vclmulh.vv v4, v8, v12
+	vclmulh.vv v4, v8, v12, v0.t
+	vclmulh.vx v4, v8, a1
+	vclmulh.vx v4, v8, a1, v0.t
diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
index 9003200d2d4..6102feaa557 100644
--- a/include/opcode/riscv-opc.h
+++ b/include/opcode/riscv-opc.h
@@ -2154,6 +2154,15 @@ 
 #define MASK_VWSLL_VV 0xfc00707f
 #define MATCH_VWSLL_VX 0xd4004057
 #define MASK_VWSLL_VX 0xfc00707f
+/* Zvbc instructions. */
+#define MATCH_VCLMUL_VV 0x30002057
+#define MASK_VCLMUL_VV 0xfc00707f
+#define MATCH_VCLMUL_VX 0x30006057
+#define MASK_VCLMUL_VX 0xfc00707f
+#define MATCH_VCLMULH_VV 0x34002057
+#define MASK_VCLMULH_VV 0xfc00707f
+#define MATCH_VCLMULH_VX 0x34006057
+#define MASK_VCLMULH_VX 0xfc00707f
 /* Svinval instruction.  */
 #define MATCH_SINVAL_VMA 0x16000073
 #define MASK_SINVAL_VMA 0xfe007fff
@@ -3280,6 +3289,11 @@  DECLARE_INSN(vror_vx, MATCH_VROR_VX, MASK_VROR_VX)
 DECLARE_INSN(vwsll_vi, MATCH_VWSLL_VI, MASK_VWSLL_VI)
 DECLARE_INSN(vwsll_vv, MATCH_VWSLL_VV, MASK_VWSLL_VV)
 DECLARE_INSN(vwsll_vx, MATCH_VWSLL_VX, MASK_VWSLL_VX)
+/* Zvbc instructions.  */
+DECLARE_INSN(vclmul_vv, MATCH_VCLMUL_VV, MASK_VCLMUL_VV)
+DECLARE_INSN(vclmul_vx, MATCH_VCLMUL_VX, MASK_VCLMUL_VX)
+DECLARE_INSN(vclmulh_vv, MATCH_VCLMULH_VV, MASK_VCLMULH_VV)
+DECLARE_INSN(vclmulh_vx, MATCH_VCLMULH_VX, MASK_VCLMULH_VX)
 /* Vendor-specific (T-Head) XTheadBa instructions.  */
 DECLARE_INSN(th_addsl, MATCH_TH_ADDSL, MASK_TH_ADDSL)
 /* Vendor-specific (T-Head) XTheadBb instructions.  */
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index 487856478f3..783b1c01e52 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -415,6 +415,7 @@  enum riscv_insn_class
   INSN_CLASS_V,
   INSN_CLASS_ZVEF,
   INSN_CLASS_ZVBB,
+  INSN_CLASS_ZVBC,
   INSN_CLASS_SVINVAL,
   INSN_CLASS_ZICBOM,
   INSN_CLASS_ZICBOP,
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index 6e8313bac16..19a72903510 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -1902,6 +1902,12 @@  const struct riscv_opcode riscv_opcodes[] =
 {"vwsll.vx",    0, INSN_CLASS_ZVBB, "Vd,Vt,sVm", MATCH_VWSLL_VX, MASK_VWSLL_VX, match_opcode, 0},
 {"vwsll.vi",    0, INSN_CLASS_ZVBB, "Vd,Vt,VjVm", MATCH_VWSLL_VI, MASK_VWSLL_VI, match_opcode, 0},
 
+/* Zvbc instructions.  */
+{"vclmul.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMUL_VV, MASK_VCLMUL_VV, match_opcode, 0},
+{"vclmul.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMUL_VX, MASK_VCLMUL_VX, match_opcode, 0},
+{"vclmulh.vv",   0, INSN_CLASS_ZVBC, "Vd,Vt,VsVm", MATCH_VCLMULH_VV, MASK_VCLMULH_VV, match_opcode, 0},
+{"vclmulh.vx",   0, INSN_CLASS_ZVBC, "Vd,Vt,sVm", MATCH_VCLMULH_VX, MASK_VCLMULH_VX, match_opcode, 0},
+
 /* Supervisor instructions.  */
 {"csrr",       0, INSN_CLASS_ZICSR, "d,E",   MATCH_CSRRS, MASK_CSRRS|MASK_RS1, match_opcode, INSN_ALIAS },
 {"csrw",       0, INSN_CLASS_ZICSR, "E,s",   MATCH_CSRRW, MASK_CSRRW|MASK_RD, match_opcode, INSN_ALIAS },